From: Douglas Gregor Date: Thu, 30 Aug 2012 20:04:43 +0000 (+0000) Subject: Extend the "__is_pod" hack, which demotes various type trait keywords X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d295970adc93ed4035d18df23673c2a72d124cc8;p=clang Extend the "__is_pod" hack, which demotes various type trait keywords (__is_pod, __is_signed, etc.) to normal identifiers if they are encountered in certain places in the grammar where we know that prior versions of libstdc++ or libc++ use them, to still allow the use of these keywords as type traits. Fixes and PR10184. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@162937 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index a348c6281d..dfe9c28a40 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -164,6 +164,10 @@ class Parser : public CodeCompletionHandler { mutable IdentifierInfo *Ident_final; mutable IdentifierInfo *Ident_override; + // C++ type trait keywords that have can be reverted to identifiers and + // still used as type traits. + llvm::SmallDenseMap RevertableTypeTraits; + OwningPtr AlignHandler; OwningPtr GCCVisibilityHandler; OwningPtr OptionsHandler; diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp index 5c5bc00fe2..524f3ab82c 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -719,22 +719,12 @@ static bool HasFeature(const Preprocessor &PP, const IdentifierInfo *II) { // "struct __is_empty" parsing hack hasn't been needed in this // translation unit. If it has, __is_empty reverts to a normal // identifier and __has_feature(is_empty) evaluates false. - .Case("is_empty", - LangOpts.CPlusPlus && - PP.getIdentifierInfo("__is_empty")->getTokenID() - != tok::identifier) + .Case("is_empty", LangOpts.CPlusPlus) .Case("is_enum", LangOpts.CPlusPlus) .Case("is_final", LangOpts.CPlusPlus) .Case("is_literal", LangOpts.CPlusPlus) .Case("is_standard_layout", LangOpts.CPlusPlus) - // __is_pod is available only if the horrible - // "struct __is_pod" parsing hack hasn't been needed in this - // translation unit. If it has, __is_pod reverts to a normal - // identifier and __has_feature(is_pod) evaluates false. - .Case("is_pod", - LangOpts.CPlusPlus && - PP.getIdentifierInfo("__is_pod")->getTokenID() - != tok::identifier) + .Case("is_pod", LangOpts.CPlusPlus) .Case("is_polymorphic", LangOpts.CPlusPlus) .Case("is_trivial", LangOpts.CPlusPlus) .Case("is_trivially_assignable", LangOpts.CPlusPlus) diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 8df08b8184..855861380d 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -741,6 +741,55 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // Avoid the unnecessary parse-time lookup in the common case // where the syntax forbids a type. const Token &Next = NextToken(); + + // 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 revertable type traits, for future use. + if (RevertableTypeTraits.empty()) { +#define RTT_JOIN2(X) X +#define RTT_JOIN(X,Y) X##Y +#define REVERTABLE_TYPE_TRAIT(Name) \ + RevertableTypeTraits[PP.getIdentifierInfo(#Name)] \ + = RTT_JOIN(tok::kw_,Name) + + REVERTABLE_TYPE_TRAIT(__is_arithmetic); + REVERTABLE_TYPE_TRAIT(__is_convertible); + REVERTABLE_TYPE_TRAIT(__is_empty); + REVERTABLE_TYPE_TRAIT(__is_floating_point); + REVERTABLE_TYPE_TRAIT(__is_function); + REVERTABLE_TYPE_TRAIT(__is_fundamental); + REVERTABLE_TYPE_TRAIT(__is_integral); + REVERTABLE_TYPE_TRAIT(__is_member_function_pointer); + REVERTABLE_TYPE_TRAIT(__is_member_pointer); + REVERTABLE_TYPE_TRAIT(__is_pod); + REVERTABLE_TYPE_TRAIT(__is_pointer); + REVERTABLE_TYPE_TRAIT(__is_same); + REVERTABLE_TYPE_TRAIT(__is_scalar); + REVERTABLE_TYPE_TRAIT(__is_signed); + REVERTABLE_TYPE_TRAIT(__is_unsigned); + REVERTABLE_TYPE_TRAIT(__is_void); +#undef REVERTABLE_TYPE_TRAIT +#undef RTT_JOIN2 +#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 + = RevertableTypeTraits.find(II); + if (Known != RevertableTypeTraits.end()) { + Tok.setKind(Known->second); + return ParseCastExpression(isUnaryExpression, isAddressOfOperand, + NotCastExpr, isTypeCast); + } + } + if (Next.is(tok::coloncolon) || (!ColonIsSacred && Next.is(tok::colon)) || Next.is(tok::less) || @@ -758,7 +807,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, // '.'. IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation ILoc = ConsumeToken(); - + // Support 'Class.property' and 'super.property' notation. if (getLangOpts().ObjC1 && Tok.is(tok::period) && (Actions.getTypeName(II, ILoc, getCurScope()) || diff --git a/test/SemaCXX/libstdcxx_is_pod_hack.cpp b/test/SemaCXX/libstdcxx_is_pod_hack.cpp index 3ac233627c..1ba3721c8c 100644 --- a/test/SemaCXX/libstdcxx_is_pod_hack.cpp +++ b/test/SemaCXX/libstdcxx_is_pod_hack.cpp @@ -8,6 +8,7 @@ template struct __is_pod { + __is_pod() {} }; __is_pod ipi; @@ -28,6 +29,13 @@ struct test_is_signed { bool check_signed = test_is_signed::__is_signed; -#if __has_feature(is_pod) -# error __is_pod won't work now anyway +template struct must_be_true {}; +template<> struct must_be_true; + +void foo() { + bool b = __is_pod(int); + must_be_true<__is_pod(int)> mbt; +} +#if !__has_feature(is_pod) +# error __is_pod should still be available. #endif