forked from OSchip/llvm-project
Revert r197496, as it broke REVERTIBLE_TYPE_TRAITs from PCH files.
Also add a test to make sure that this doesn't break again. Fixes PR21036. llvm-svn: 218292
This commit is contained in:
parent
f6a4258020
commit
7c3c5bec07
|
@ -135,10 +135,9 @@ class Parser : public CodeCompletionHandler {
|
|||
mutable IdentifierInfo *Ident_final;
|
||||
mutable IdentifierInfo *Ident_override;
|
||||
|
||||
// Some token kinds such as C++ type traits can be reverted to identifiers and
|
||||
// still get used as keywords depending on context.
|
||||
llvm::SmallDenseMap<const IdentifierInfo *, tok::TokenKind>
|
||||
ContextualKeywords;
|
||||
// C++ type trait keywords that can be reverted to identifiers and still be
|
||||
// used as type traits.
|
||||
llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits;
|
||||
|
||||
std::unique_ptr<PragmaHandler> AlignHandler;
|
||||
std::unique_ptr<PragmaHandler> GCCVisibilityHandler;
|
||||
|
@ -634,12 +633,6 @@ private:
|
|||
/// otherwise emits a diagnostic and returns true.
|
||||
bool TryKeywordIdentFallback(bool DisableKeyword);
|
||||
|
||||
/// TryIdentKeywordUpgrade - Convert the current identifier token back to
|
||||
/// its original kind and return true if it was disabled by
|
||||
/// TryKeywordIdentFallback(), otherwise return false. Use this to
|
||||
/// contextually enable keywords.
|
||||
bool TryIdentKeywordUpgrade();
|
||||
|
||||
/// \brief Get the TemplateIdAnnotation from the token.
|
||||
TemplateIdAnnotation *takeTemplateIdAnnotation(const Token &tok);
|
||||
|
||||
|
|
|
@ -1226,17 +1226,31 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
|
|||
// C++11 attributes
|
||||
SourceLocation AttrFixitLoc = Tok.getLocation();
|
||||
|
||||
// GNU libstdc++ and libc++ use certain intrinsic names as the
|
||||
// name of struct templates, but some are keywords in GCC >= 4.3
|
||||
// MSVC and Clang. For compatibility, convert the token to an identifier
|
||||
// and issue a warning diagnostic.
|
||||
if (TagType == DeclSpec::TST_struct && !Tok.is(tok::identifier) &&
|
||||
!Tok.isAnnotation()) {
|
||||
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
// We rarely end up here so the following check is efficient.
|
||||
if (II && II->getName().startswith("__is_"))
|
||||
TryKeywordIdentFallback(true);
|
||||
}
|
||||
if (TagType == DeclSpec::TST_struct &&
|
||||
!Tok.is(tok::identifier) &&
|
||||
Tok.getIdentifierInfo() &&
|
||||
(Tok.is(tok::kw___is_arithmetic) ||
|
||||
Tok.is(tok::kw___is_convertible) ||
|
||||
Tok.is(tok::kw___is_empty) ||
|
||||
Tok.is(tok::kw___is_floating_point) ||
|
||||
Tok.is(tok::kw___is_function) ||
|
||||
Tok.is(tok::kw___is_fundamental) ||
|
||||
Tok.is(tok::kw___is_integral) ||
|
||||
Tok.is(tok::kw___is_member_function_pointer) ||
|
||||
Tok.is(tok::kw___is_member_pointer) ||
|
||||
Tok.is(tok::kw___is_pod) ||
|
||||
Tok.is(tok::kw___is_pointer) ||
|
||||
Tok.is(tok::kw___is_same) ||
|
||||
Tok.is(tok::kw___is_scalar) ||
|
||||
Tok.is(tok::kw___is_signed) ||
|
||||
Tok.is(tok::kw___is_unsigned) ||
|
||||
Tok.is(tok::kw___is_void)))
|
||||
// GNU libstdc++ 4.2 and libc++ use certain intrinsic names as the
|
||||
// name of struct templates, but some are keywords in GCC >= 4.3
|
||||
// and Clang. Therefore, when we see the token sequence "struct
|
||||
// X", make X into a normal identifier rather than a keyword, to
|
||||
// allow libstdc++ 4.2 and libc++ to work properly.
|
||||
TryKeywordIdentFallback(true);
|
||||
|
||||
// Parse the (optional) nested-name-specifier.
|
||||
CXXScopeSpec &SS = DS.getTypeSpecScope();
|
||||
|
|
|
@ -708,11 +708,48 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
|
|||
// If this identifier was reverted from a token ID, and the next token
|
||||
// is a parenthesis, this is likely to be a use of a type trait. Check
|
||||
// those tokens.
|
||||
if (Next.is(tok::l_paren) && Tok.is(tok::identifier) &&
|
||||
Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier() &&
|
||||
TryIdentKeywordUpgrade())
|
||||
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
|
||||
NotCastExpr, isTypeCast);
|
||||
if (Next.is(tok::l_paren) &&
|
||||
Tok.is(tok::identifier) &&
|
||||
Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
// Build up the mapping of revertible type traits, for future use.
|
||||
if (RevertibleTypeTraits.empty()) {
|
||||
#define RTT_JOIN(X,Y) X##Y
|
||||
#define REVERTIBLE_TYPE_TRAIT(Name) \
|
||||
RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \
|
||||
= RTT_JOIN(tok::kw_,Name)
|
||||
|
||||
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_convertible);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_empty);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_floating_point);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_function);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_fundamental);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_integral);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_pod);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_pointer);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_same);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_scalar);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_signed);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_unsigned);
|
||||
REVERTIBLE_TYPE_TRAIT(__is_void);
|
||||
#undef REVERTIBLE_TYPE_TRAIT
|
||||
#undef RTT_JOIN
|
||||
}
|
||||
|
||||
// If we find that this is in fact the name of a type trait,
|
||||
// update the token kind in place and parse again to treat it as
|
||||
// the appropriate kind of type trait.
|
||||
llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
|
||||
= RevertibleTypeTraits.find(II);
|
||||
if (Known != RevertibleTypeTraits.end()) {
|
||||
Tok.setKind(Known->second);
|
||||
return ParseCastExpression(isUnaryExpression, isAddressOfOperand,
|
||||
NotCastExpr, isTypeCast);
|
||||
}
|
||||
}
|
||||
|
||||
if (Next.is(tok::coloncolon) ||
|
||||
(!ColonIsSacred && Next.is(tok::colon)) ||
|
||||
|
|
|
@ -1431,34 +1431,16 @@ Parser::TryAnnotateName(bool IsAddressOfOperand,
|
|||
}
|
||||
|
||||
bool Parser::TryKeywordIdentFallback(bool DisableKeyword) {
|
||||
assert(!Tok.is(tok::identifier) && !Tok.isAnnotation());
|
||||
assert(Tok.isNot(tok::identifier));
|
||||
Diag(Tok, diag::ext_keyword_as_ident)
|
||||
<< PP.getSpelling(Tok)
|
||||
<< DisableKeyword;
|
||||
if (DisableKeyword) {
|
||||
IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
ContextualKeywords[II] = Tok.getKind();
|
||||
II->RevertTokenIDToIdentifier();
|
||||
}
|
||||
if (DisableKeyword)
|
||||
Tok.getIdentifierInfo()->RevertTokenIDToIdentifier();
|
||||
Tok.setKind(tok::identifier);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Parser::TryIdentKeywordUpgrade() {
|
||||
assert(Tok.is(tok::identifier));
|
||||
const IdentifierInfo *II = Tok.getIdentifierInfo();
|
||||
assert(II->hasRevertedTokenIDToIdentifier());
|
||||
// If we find that this is in fact the name of a type trait,
|
||||
// update the token kind in place and parse again to treat it as
|
||||
// the appropriate kind of type trait.
|
||||
llvm::SmallDenseMap<const IdentifierInfo *, tok::TokenKind>::iterator Known =
|
||||
ContextualKeywords.find(II);
|
||||
if (Known == ContextualKeywords.end())
|
||||
return false;
|
||||
Tok.setKind(Known->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// TryAnnotateTypeOrScopeToken - If the current token position is on a
|
||||
/// typename (possibly qualified in C++) or a C++ scope specifier not followed
|
||||
/// by a typename, TryAnnotateTypeOrScopeToken will replace one or more tokens
|
||||
|
|
|
@ -8,8 +8,12 @@
|
|||
// expected-no-diagnostics
|
||||
#endif
|
||||
|
||||
bool _Is_pod_comparator = __is_pod<int>::__value;
|
||||
bool _Is_empty_check = __is_empty<int>::__value;
|
||||
bool _Is_pod_comparator = n::__is_pod<int>::__value;
|
||||
bool _Is_empty_check = n::__is_empty<int>::__value;
|
||||
|
||||
bool default_construct_int = is_trivially_constructible<int>::value;
|
||||
bool copy_construct_int = is_trivially_constructible<int, const int&>::value;
|
||||
bool default_construct_int = n::is_trivially_constructible<int>::value;
|
||||
bool copy_construct_int = n::is_trivially_constructible<int, const int&>::value;
|
||||
|
||||
// The built-ins should still work too:
|
||||
bool _is_pod_result = __is_pod(int);
|
||||
bool _is_empty_result = __is_empty(int);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// Header for PCH test cxx-traits.cpp
|
||||
|
||||
namespace n {
|
||||
|
||||
template<typename _Tp>
|
||||
struct __is_pod { // expected-warning {{keyword '__is_pod' will be made available as an identifier for the remainder of the translation unit}}
|
||||
enum { __value };
|
||||
|
@ -14,3 +16,5 @@ template<typename T, typename ...Args>
|
|||
struct is_trivially_constructible {
|
||||
static const bool value = __is_trivially_constructible(T, Args...);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue