From: Alp Toker Date: Tue, 17 Dec 2013 14:12:30 +0000 (+0000) Subject: Simplify RevertibleTypeTraits as a form of contextual keyword X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=19f1317211b0de172e8b1852612e3ac70a6be4cc;p=clang Simplify RevertibleTypeTraits as a form of contextual keyword Now that we emit diagnostics for keyword-as-identifier hacks (-Wkeyword-compat) we can go ahead and simplify some of the old revertible keyword support. This commit adds a TryIdentKeywordUpgrade() function to mirror the recently added TryKeywordIdentFallback() and uses it to replace the hard-coded list of REVERTIBLE_TYPE_TRAITs. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@197496 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 6555fd6613..ddef9dfe84 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -136,9 +136,10 @@ class Parser : public CodeCompletionHandler { mutable IdentifierInfo *Ident_final; mutable IdentifierInfo *Ident_override; - // C++ type trait keywords that can be reverted to identifiers and still be - // used as type traits. - llvm::SmallDenseMap RevertibleTypeTraits; + // Some token kinds such as C++ type traits can be reverted to identifiers and + // still get used as keywords depending on context. + llvm::SmallDenseMap + ContextualKeywords; OwningPtr AlignHandler; OwningPtr GCCVisibilityHandler; @@ -574,6 +575,12 @@ 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/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index b34b1119af..2d6523cfe4 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1180,31 +1180,17 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // C++11 attributes SourceLocation AttrFixitLoc = Tok.getLocation(); - 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); + // 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); + } // Parse the (optional) nested-name-specifier. CXXScopeSpec &SS = DS.getTypeSpecScope(); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 8fb0660b34..5c6ff65841 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -715,48 +715,11 @@ 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()) { - 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::iterator Known - = RevertibleTypeTraits.find(II); - if (Known != RevertibleTypeTraits.end()) { - Tok.setKind(Known->second); - return ParseCastExpression(isUnaryExpression, isAddressOfOperand, - NotCastExpr, isTypeCast); - } - } + if (Next.is(tok::l_paren) && Tok.is(tok::identifier) && + Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier() && + TryIdentKeywordUpgrade()) + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, isTypeCast); if (Next.is(tok::coloncolon) || (!ColonIsSacred && Next.is(tok::colon)) || diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 310105a4ac..f7c0f3f550 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -1517,16 +1517,34 @@ Parser::TryAnnotateName(bool IsAddressOfOperand, } bool Parser::TryKeywordIdentFallback(bool DisableKeyword) { - assert(Tok.isNot(tok::identifier)); + assert(!Tok.is(tok::identifier) && !Tok.isAnnotation()); Diag(Tok, diag::ext_keyword_as_ident) << PP.getSpelling(Tok) << DisableKeyword; - if (DisableKeyword) - Tok.getIdentifierInfo()->RevertTokenIDToIdentifier(); + if (DisableKeyword) { + IdentifierInfo *II = Tok.getIdentifierInfo(); + ContextualKeywords[II] = Tok.getKind(); + II->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::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