Skip to content

Commit 1fe406f

Browse files
authored
[Clang] Fix parsing of reversible type traits in template arguments (#95969)
Constructs like `__is_pointer(Foo)` are never considered to be functions declarations. This matches usages in libstdc++, and we can hope no one else redefine these reserved identifiers. Fixes #95598
1 parent 40ed194 commit 1fe406f

File tree

5 files changed

+110
-79
lines changed

5 files changed

+110
-79
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,6 +1040,7 @@ Bug Fixes to C++ Support
10401040
- Clang now correctly handles unexpanded packs in the template parameter list of a generic lambda expression
10411041
(#GH48937)
10421042
- Fix a crash when parsing an invalid type-requirement in a requires expression. (#GH51868)
1043+
- Fix parsing of built-in type-traits such as ``__is_pointer`` in libstdc++ headers. (#GH95598)
10431044

10441045
Bug Fixes to AST Handling
10451046
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Parse/Parser.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1877,6 +1877,10 @@ class Parser : public CodeCompletionHandler {
18771877
UnaryExprOnly,
18781878
PrimaryExprOnly
18791879
};
1880+
1881+
bool isRevertibleTypeTrait(const IdentifierInfo *Id,
1882+
clang::tok::TokenKind *Kind = nullptr);
1883+
18801884
ExprResult ParseCastExpression(CastParseKind ParseKind,
18811885
bool isAddressOfOperand,
18821886
bool &NotCastExpr,

clang/lib/Parse/ParseExpr.cpp

Lines changed: 84 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,87 @@ class CastExpressionIdValidator final : public CorrectionCandidateCallback {
760760
};
761761
}
762762

763+
bool Parser::isRevertibleTypeTrait(const IdentifierInfo *II,
764+
tok::TokenKind *Kind) {
765+
if (RevertibleTypeTraits.empty()) {
766+
#define RTT_JOIN(X, Y) X##Y
767+
#define REVERTIBLE_TYPE_TRAIT(Name) \
768+
RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] = RTT_JOIN(tok::kw_, Name)
769+
770+
REVERTIBLE_TYPE_TRAIT(__is_abstract);
771+
REVERTIBLE_TYPE_TRAIT(__is_aggregate);
772+
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
773+
REVERTIBLE_TYPE_TRAIT(__is_array);
774+
REVERTIBLE_TYPE_TRAIT(__is_assignable);
775+
REVERTIBLE_TYPE_TRAIT(__is_base_of);
776+
REVERTIBLE_TYPE_TRAIT(__is_bounded_array);
777+
REVERTIBLE_TYPE_TRAIT(__is_class);
778+
REVERTIBLE_TYPE_TRAIT(__is_complete_type);
779+
REVERTIBLE_TYPE_TRAIT(__is_compound);
780+
REVERTIBLE_TYPE_TRAIT(__is_const);
781+
REVERTIBLE_TYPE_TRAIT(__is_constructible);
782+
REVERTIBLE_TYPE_TRAIT(__is_convertible);
783+
REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
784+
REVERTIBLE_TYPE_TRAIT(__is_destructible);
785+
REVERTIBLE_TYPE_TRAIT(__is_empty);
786+
REVERTIBLE_TYPE_TRAIT(__is_enum);
787+
REVERTIBLE_TYPE_TRAIT(__is_floating_point);
788+
REVERTIBLE_TYPE_TRAIT(__is_final);
789+
REVERTIBLE_TYPE_TRAIT(__is_function);
790+
REVERTIBLE_TYPE_TRAIT(__is_fundamental);
791+
REVERTIBLE_TYPE_TRAIT(__is_integral);
792+
REVERTIBLE_TYPE_TRAIT(__is_interface_class);
793+
REVERTIBLE_TYPE_TRAIT(__is_layout_compatible);
794+
REVERTIBLE_TYPE_TRAIT(__is_literal);
795+
REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
796+
REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
797+
REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
798+
REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
799+
REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
800+
REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
801+
REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
802+
REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
803+
REVERTIBLE_TYPE_TRAIT(__is_nullptr);
804+
REVERTIBLE_TYPE_TRAIT(__is_object);
805+
REVERTIBLE_TYPE_TRAIT(__is_pod);
806+
REVERTIBLE_TYPE_TRAIT(__is_pointer);
807+
REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
808+
REVERTIBLE_TYPE_TRAIT(__is_reference);
809+
REVERTIBLE_TYPE_TRAIT(__is_referenceable);
810+
REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
811+
REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
812+
REVERTIBLE_TYPE_TRAIT(__is_same);
813+
REVERTIBLE_TYPE_TRAIT(__is_scalar);
814+
REVERTIBLE_TYPE_TRAIT(__is_scoped_enum);
815+
REVERTIBLE_TYPE_TRAIT(__is_sealed);
816+
REVERTIBLE_TYPE_TRAIT(__is_signed);
817+
REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
818+
REVERTIBLE_TYPE_TRAIT(__is_trivial);
819+
REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
820+
REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
821+
REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
822+
REVERTIBLE_TYPE_TRAIT(__is_unbounded_array);
823+
REVERTIBLE_TYPE_TRAIT(__is_union);
824+
REVERTIBLE_TYPE_TRAIT(__is_unsigned);
825+
REVERTIBLE_TYPE_TRAIT(__is_void);
826+
REVERTIBLE_TYPE_TRAIT(__is_volatile);
827+
REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary);
828+
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
829+
REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait));
830+
#include "clang/Basic/TransformTypeTraits.def"
831+
#undef REVERTIBLE_TYPE_TRAIT
832+
#undef RTT_JOIN
833+
}
834+
llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known =
835+
RevertibleTypeTraits.find(II);
836+
if (Known != RevertibleTypeTraits.end()) {
837+
if (Kind)
838+
*Kind = Known->second;
839+
return true;
840+
}
841+
return false;
842+
}
843+
763844
/// Parse a cast-expression, or, if \pisUnaryExpression is true, parse
764845
/// a unary-expression.
765846
///
@@ -1118,85 +1199,9 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
11181199
else if (Next.is(tok::l_paren) && Tok.is(tok::identifier) &&
11191200
Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier()) {
11201201
IdentifierInfo *II = Tok.getIdentifierInfo();
1121-
// Build up the mapping of revertible type traits, for future use.
1122-
if (RevertibleTypeTraits.empty()) {
1123-
#define RTT_JOIN(X,Y) X##Y
1124-
#define REVERTIBLE_TYPE_TRAIT(Name) \
1125-
RevertibleTypeTraits[PP.getIdentifierInfo(#Name)] \
1126-
= RTT_JOIN(tok::kw_,Name)
1127-
1128-
REVERTIBLE_TYPE_TRAIT(__is_abstract);
1129-
REVERTIBLE_TYPE_TRAIT(__is_aggregate);
1130-
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
1131-
REVERTIBLE_TYPE_TRAIT(__is_array);
1132-
REVERTIBLE_TYPE_TRAIT(__is_assignable);
1133-
REVERTIBLE_TYPE_TRAIT(__is_base_of);
1134-
REVERTIBLE_TYPE_TRAIT(__is_bounded_array);
1135-
REVERTIBLE_TYPE_TRAIT(__is_class);
1136-
REVERTIBLE_TYPE_TRAIT(__is_complete_type);
1137-
REVERTIBLE_TYPE_TRAIT(__is_compound);
1138-
REVERTIBLE_TYPE_TRAIT(__is_const);
1139-
REVERTIBLE_TYPE_TRAIT(__is_constructible);
1140-
REVERTIBLE_TYPE_TRAIT(__is_convertible);
1141-
REVERTIBLE_TYPE_TRAIT(__is_convertible_to);
1142-
REVERTIBLE_TYPE_TRAIT(__is_destructible);
1143-
REVERTIBLE_TYPE_TRAIT(__is_empty);
1144-
REVERTIBLE_TYPE_TRAIT(__is_enum);
1145-
REVERTIBLE_TYPE_TRAIT(__is_floating_point);
1146-
REVERTIBLE_TYPE_TRAIT(__is_final);
1147-
REVERTIBLE_TYPE_TRAIT(__is_function);
1148-
REVERTIBLE_TYPE_TRAIT(__is_fundamental);
1149-
REVERTIBLE_TYPE_TRAIT(__is_integral);
1150-
REVERTIBLE_TYPE_TRAIT(__is_interface_class);
1151-
REVERTIBLE_TYPE_TRAIT(__is_layout_compatible);
1152-
REVERTIBLE_TYPE_TRAIT(__is_literal);
1153-
REVERTIBLE_TYPE_TRAIT(__is_lvalue_expr);
1154-
REVERTIBLE_TYPE_TRAIT(__is_lvalue_reference);
1155-
REVERTIBLE_TYPE_TRAIT(__is_member_function_pointer);
1156-
REVERTIBLE_TYPE_TRAIT(__is_member_object_pointer);
1157-
REVERTIBLE_TYPE_TRAIT(__is_member_pointer);
1158-
REVERTIBLE_TYPE_TRAIT(__is_nothrow_assignable);
1159-
REVERTIBLE_TYPE_TRAIT(__is_nothrow_constructible);
1160-
REVERTIBLE_TYPE_TRAIT(__is_nothrow_destructible);
1161-
REVERTIBLE_TYPE_TRAIT(__is_nullptr);
1162-
REVERTIBLE_TYPE_TRAIT(__is_object);
1163-
REVERTIBLE_TYPE_TRAIT(__is_pod);
1164-
REVERTIBLE_TYPE_TRAIT(__is_pointer);
1165-
REVERTIBLE_TYPE_TRAIT(__is_polymorphic);
1166-
REVERTIBLE_TYPE_TRAIT(__is_reference);
1167-
REVERTIBLE_TYPE_TRAIT(__is_referenceable);
1168-
REVERTIBLE_TYPE_TRAIT(__is_rvalue_expr);
1169-
REVERTIBLE_TYPE_TRAIT(__is_rvalue_reference);
1170-
REVERTIBLE_TYPE_TRAIT(__is_same);
1171-
REVERTIBLE_TYPE_TRAIT(__is_scalar);
1172-
REVERTIBLE_TYPE_TRAIT(__is_scoped_enum);
1173-
REVERTIBLE_TYPE_TRAIT(__is_sealed);
1174-
REVERTIBLE_TYPE_TRAIT(__is_signed);
1175-
REVERTIBLE_TYPE_TRAIT(__is_standard_layout);
1176-
REVERTIBLE_TYPE_TRAIT(__is_trivial);
1177-
REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable);
1178-
REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible);
1179-
REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable);
1180-
REVERTIBLE_TYPE_TRAIT(__is_unbounded_array);
1181-
REVERTIBLE_TYPE_TRAIT(__is_union);
1182-
REVERTIBLE_TYPE_TRAIT(__is_unsigned);
1183-
REVERTIBLE_TYPE_TRAIT(__is_void);
1184-
REVERTIBLE_TYPE_TRAIT(__is_volatile);
1185-
REVERTIBLE_TYPE_TRAIT(__reference_binds_to_temporary);
1186-
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) \
1187-
REVERTIBLE_TYPE_TRAIT(RTT_JOIN(__, Trait));
1188-
#include "clang/Basic/TransformTypeTraits.def"
1189-
#undef REVERTIBLE_TYPE_TRAIT
1190-
#undef RTT_JOIN
1191-
}
1192-
1193-
// If we find that this is in fact the name of a type trait,
1194-
// update the token kind in place and parse again to treat it as
1195-
// the appropriate kind of type trait.
1196-
llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind>::iterator Known
1197-
= RevertibleTypeTraits.find(II);
1198-
if (Known != RevertibleTypeTraits.end()) {
1199-
Tok.setKind(Known->second);
1202+
tok::TokenKind Kind;
1203+
if (isRevertibleTypeTrait(II, &Kind)) {
1204+
Tok.setKind(Kind);
12001205
return ParseCastExpression(ParseKind, isAddressOfOperand,
12011206
NotCastExpr, isTypeCast,
12021207
isVectorLiteral, NotPrimaryExpression);

clang/lib/Parse/ParseTentative.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1385,6 +1385,15 @@ Parser::isCXXDeclarationSpecifier(ImplicitTypenameContext AllowImplicitTypename,
13851385
if (!getLangOpts().ObjC && Next.is(tok::identifier))
13861386
return TPResult::True;
13871387

1388+
// If this identifier was reverted from a token ID, and the next token
1389+
// is a '(', we assume it to be a use of a type trait, so this
1390+
// can never be a type name.
1391+
if (Next.is(tok::l_paren) &&
1392+
Tok.getIdentifierInfo()->hasRevertedTokenIDToIdentifier() &&
1393+
isRevertibleTypeTrait(Tok.getIdentifierInfo())) {
1394+
return TPResult::False;
1395+
}
1396+
13881397
if (Next.isNot(tok::coloncolon) && Next.isNot(tok::less)) {
13891398
// Determine whether this is a valid expression. If not, we will hit
13901399
// a parse error one way or another. In that case, tell the caller that

clang/test/Parser/cxx-template-argument.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,15 @@ namespace r360308_regression {
141141
return a == b;
142142
}
143143
}
144+
145+
namespace GH95598 {
146+
template<typename _Tp, bool _IsPtr = __is_pointer(_Tp)>
147+
struct __is_pointer {};
148+
// expected-warning@-1 {{keyword '__is_pointer' will be made available as an identifier for the remainder of the translation unit}}
149+
150+
template<bool>
151+
struct ts{};
152+
153+
template<typename _Tp>
154+
struct is_pointer : ts<__is_pointer(_Tp)> {};
155+
}

0 commit comments

Comments
 (0)