diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index ceead8c362e9c1..5dc0f8b7e0bbb8 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -1040,6 +1040,7 @@ Bug Fixes to C++ Support - Clang now correctly handles unexpanded packs in the template parameter list of a generic lambda expression (#GH48937) - Fix a crash when parsing an invalid type-requirement in a requires expression. (#GH51868) +- Fix parsing of built-in type-traits such as ``__is_pointer`` in libstdc++ headers. (#GH95598) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index b4f5270a359569..bb3f08aef0378b 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -1877,6 +1877,10 @@ class Parser : public CodeCompletionHandler { UnaryExprOnly, PrimaryExprOnly }; + + bool isRevertibleTypeTrait(const IdentifierInfo *Id, + clang::tok::TokenKind *Kind = nullptr); + ExprResult ParseCastExpression(CastParseKind ParseKind, bool isAddressOfOperand, bool &NotCastExpr, diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index b98eb70a848e1a..310a38b2cd7866 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -760,6 +760,87 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback { }; } +bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II, + tok::TokenKind *Kind) { + 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_abstract); + REVERTIBLE_TYPE_TRAIT(__is_aggregate); + REVERTIBLE_TYPE_TRAIT(__is_arithmetic); + REVERTIBLE_TYPE_TRAIT(__is_array); + REVERTIBLE_TYPE_TRAIT(__is_assignable); + REVERTIBLE_TYPE_TRAIT(__is_base_of); + REVERTIBLE_TYPE_TRAIT(__is_bounded_array); + REVERTIBLE_TYPE_TRAIT(__is_class); + REVERTIBLE_TYPE_TRAIT(__is_complete_type); + REVERTIBLE_TYPE_TRAIT(__is_compound); + REVERTIBLE_TYPE_TRAIT(__is_const); + REVERTIBLE_TYPE_TRAIT(__is_constructible); + REVERTIBLE_TYPE_TRAIT(__is_convertible); + REVERTIBLE_TYPE_TRAIT(__is_convertible_to); + REVERTIBLE_TYPE_TRAIT(__is_destructible); + REVERTIBLE_TYPE_TRAIT(__is_empty); + REVERTIBLE_TYPE_TRAIT(__is_enum); + REVERTIBLE_TYPE_TRAIT(__is_floating_point); + REVERTIBLE_TYPE_TRAIT(__is_final); + REVERTIBLE_TYPE_TRAIT(__is_function); + REVERTIBLE_TYPE_TRAIT(__is_fundamental); + REVERTIBLE_TYPE_TRAIT(__is_integral); + REVERTIBLE_TYPE_TRAIT(__is_interface_class); + REVERTIBLE_TYPE_TRAIT(__is_layout_compatible); + REVERTIBLE_TYPE_TRAIT(__is_literal); + REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr); + REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference); + REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer); + REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer); + REVERTIBLE_TYPE_TRAIT(__is_member_pointer); + REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable); + REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible); + REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible); + REVERTIBLE_TYPE_TRAIT(__is_nullptr); + REVERTIBLE_TYPE_TRAIT(__is_object); + REVERTIBLE_TYPE_TRAIT(__is_pod); + REVERTIBLE_TYPE_TRAIT(__is_pointer); + REVERTIBLE_TYPE_TRAIT(__is_polymorphic); + REVERTIBLE_TYPE_TRAIT(__is_reference); + REVERTIBLE_TYPE_TRAIT(__is_referenceable); + REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr); + REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference); + REVERTIBLE_TYPE_TRAIT(__is_same); + REVERTIBLE_TYPE_TRAIT(__is_scalar); + REVERTIBLE_TYPE_TRAIT(__is_scoped_enum); + REVERTIBLE_TYPE_TRAIT(__is_sealed); + REVERTIBLE_TYPE_TRAIT(__is_signed); + REVERTIBLE_TYPE_TRAIT(__is_standard_layout); + REVERTIBLE_TYPE_TRAIT(__is_trivial); + REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable); + REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible); + REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable); + REVERTIBLE_TYPE_TRAIT(__is_unbounded_array); + REVERTIBLE_TYPE_TRAIT(__is_union); + REVERTIBLE_TYPE_TRAIT(__is_unsigned); + REVERTIBLE_TYPE_TRAIT(__is_void); + REVERTIBLE_TYPE_TRAIT(__is_volatile); + REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary); +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ + REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait)); +#include "clang/Basic/TransformTypeTraits.def" +#undef REVERTIBLE_TYPE_TRAIT +#undef RTT_JOIN + } + llvm::SmallDenseMap::iterator Known = + RevertibleTypeTraits.find(II); + if (Known != RevertibleTypeTraits.end()) { + if (Kind) + *Kind = Known->second; + return true; + } + return false; +} + /// Parse a cast-expression, or, if \pisUnaryExpression is true, parse /// a unary-expression. /// @@ -1118,85 +1199,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind, else 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_abstract); - REVERTIBLE_TYPE_TRAIT(__is_aggregate); - REVERTIBLE_TYPE_TRAIT(__is_arithmetic); - REVERTIBLE_TYPE_TRAIT(__is_array); - REVERTIBLE_TYPE_TRAIT(__is_assignable); - REVERTIBLE_TYPE_TRAIT(__is_base_of); - REVERTIBLE_TYPE_TRAIT(__is_bounded_array); - REVERTIBLE_TYPE_TRAIT(__is_class); - REVERTIBLE_TYPE_TRAIT(__is_complete_type); - REVERTIBLE_TYPE_TRAIT(__is_compound); - REVERTIBLE_TYPE_TRAIT(__is_const); - REVERTIBLE_TYPE_TRAIT(__is_constructible); - REVERTIBLE_TYPE_TRAIT(__is_convertible); - REVERTIBLE_TYPE_TRAIT(__is_convertible_to); - REVERTIBLE_TYPE_TRAIT(__is_destructible); - REVERTIBLE_TYPE_TRAIT(__is_empty); - REVERTIBLE_TYPE_TRAIT(__is_enum); - REVERTIBLE_TYPE_TRAIT(__is_floating_point); - REVERTIBLE_TYPE_TRAIT(__is_final); - REVERTIBLE_TYPE_TRAIT(__is_function); - REVERTIBLE_TYPE_TRAIT(__is_fundamental); - REVERTIBLE_TYPE_TRAIT(__is_integral); - REVERTIBLE_TYPE_TRAIT(__is_interface_class); - REVERTIBLE_TYPE_TRAIT(__is_layout_compatible); - REVERTIBLE_TYPE_TRAIT(__is_literal); - REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr); - REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference); - REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer); - REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer); - REVERTIBLE_TYPE_TRAIT(__is_member_pointer); - REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable); - REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible); - REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible); - REVERTIBLE_TYPE_TRAIT(__is_nullptr); - REVERTIBLE_TYPE_TRAIT(__is_object); - REVERTIBLE_TYPE_TRAIT(__is_pod); - REVERTIBLE_TYPE_TRAIT(__is_pointer); - REVERTIBLE_TYPE_TRAIT(__is_polymorphic); - REVERTIBLE_TYPE_TRAIT(__is_reference); - REVERTIBLE_TYPE_TRAIT(__is_referenceable); - REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr); - REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference); - REVERTIBLE_TYPE_TRAIT(__is_same); - REVERTIBLE_TYPE_TRAIT(__is_scalar); - REVERTIBLE_TYPE_TRAIT(__is_scoped_enum); - REVERTIBLE_TYPE_TRAIT(__is_sealed); - REVERTIBLE_TYPE_TRAIT(__is_signed); - REVERTIBLE_TYPE_TRAIT(__is_standard_layout); - REVERTIBLE_TYPE_TRAIT(__is_trivial); - REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable); - REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible); - REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable); - REVERTIBLE_TYPE_TRAIT(__is_unbounded_array); - REVERTIBLE_TYPE_TRAIT(__is_union); - REVERTIBLE_TYPE_TRAIT(__is_unsigned); - REVERTIBLE_TYPE_TRAIT(__is_void); - REVERTIBLE_TYPE_TRAIT(__is_volatile); - REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary); -#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \ - REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait)); -#include "clang/Basic/TransformTypeTraits.def" -#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); + tok::TokenKind Kind; + if (isRevertibleTypeTrait(II, &Kind)) { + Tok.setKind(Kind); return ParseCastExpression(ParseKind, isAddressOfOperand, NotCastExpr, isTypeCast, isVectorLiteral, NotPrimaryExpression); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index ea17c3e3252ec2..0142271b8e6d18 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -1385,6 +1385,15 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename, if (!getLangOpts().ObjC && Next.is(tok::identifier)) return TPResult::True; + // If this identifier was reverted from a token ID, and the next token + // is a '(', we assume it to be a use of a type trait, so this + // can never be a type name. + if (Next.is(tok::l_paren) && + Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier() && + isRevertibleTypeTrait(Tok.getIdentifierInfo())) { + return TPResult::False; + } + if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) { // Determine whether this is a valid expression. If not, we will hit // a parse error one way or another. In that case, tell the caller that diff --git a/clang/test/Parser/cxx-template-argument.cpp b/clang/test/Parser/cxx-template-argument.cpp index 667dd8698435b5..3c2169f86d6e74 100644 --- a/clang/test/Parser/cxx-template-argument.cpp +++ b/clang/test/Parser/cxx-template-argument.cpp @@ -141,3 +141,15 @@ namespace r360308_regression { return a == b; } } + +namespace GH95598 { +template +struct __is_pointer {}; +// expected-warning@-1 {{keyword '__is_pointer' will be made available as an identifier for the remainder of the translation unit}} + +template +struct ts{}; + +template + struct is_pointer : ts<__is_pointer(_Tp)> {}; +}