diff options
author | Nico Weber <nicolasweber@gmx.de> | 2014-09-23 04:09:56 +0000 |
---|---|---|
committer | Nico Weber <nicolasweber@gmx.de> | 2014-09-23 04:09:56 +0000 |
commit | 7c3c5bec07b9523a704bc7ba4bbb4e7995511b1c (patch) | |
tree | b3862175c27c98e98e899b9369c7d72f4fc62678 | |
parent | f6a42580207fd25b6642eaa3aa2a638c2d3f21f2 (diff) | |
download | bcm5719-llvm-7c3c5bec07b9523a704bc7ba4bbb4e7995511b1c.tar.gz bcm5719-llvm-7c3c5bec07b9523a704bc7ba4bbb4e7995511b1c.zip |
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
-rw-r--r-- | clang/include/clang/Parse/Parser.h | 13 | ||||
-rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 36 | ||||
-rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 47 | ||||
-rw-r--r-- | clang/lib/Parse/Parser.cpp | 24 | ||||
-rw-r--r-- | clang/test/PCH/cxx-traits.cpp | 12 | ||||
-rw-r--r-- | clang/test/PCH/cxx-traits.h | 4 |
6 files changed, 85 insertions, 51 deletions
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 7fe2c7a9192..5aaa6cab91b 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -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); diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index b252ed5865c..8ea53966946 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -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(); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 0e4dfb91ad5..2b0daad60f7 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -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)) || diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 808e4266aee..6dcbaf6bb29 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -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 diff --git a/clang/test/PCH/cxx-traits.cpp b/clang/test/PCH/cxx-traits.cpp index ffdfccc6f47..42656a3ad5f 100644 --- a/clang/test/PCH/cxx-traits.cpp +++ b/clang/test/PCH/cxx-traits.cpp @@ -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); diff --git a/clang/test/PCH/cxx-traits.h b/clang/test/PCH/cxx-traits.h index e6f2feb1d11..59ba513ef1d 100644 --- a/clang/test/PCH/cxx-traits.h +++ b/clang/test/PCH/cxx-traits.h @@ -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...); }; + +} |