-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang] Warn when builtin names are used outside of invocations #96097
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
@@ -1673,6 +1673,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { | |||
return II && HasExtension(*this, II->getName()); | |||
}); | |||
} else if (II == Ident__has_builtin) { | |||
EvaluatingHasBuiltinMacro = true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not particularly proud of this workaround, and if reviewers think that we should do this in some other way (e.g. enable backtracking for every __has_builtin
use, and look behind when we see a revertible type trait identifier), I'm open for suggestions.
@llvm/pr-subscribers-clang Author: cor3ntin (cor3ntin) ChangesPatch is 83.35 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/96097.diff 19 Files Affected:
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0f958d213172a..7f026b6f9c953 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -132,6 +132,10 @@ Clang Frontend Potentially Breaking Changes
$ clang --target=<your target triple> -print-target-triple
<the normalized target triple>
+- Clang now issues a deprecation warning when an identifier of a builtin is used
+ for something else than invoking the builtin, e.g. ``struct __is_pointer``.
+ This affects libstdc++ prior to 14.2, and libc++ prior to 3.5.
+
- The ``hasTypeLoc`` AST matcher will no longer match a ``classTemplateSpecializationDecl``;
existing uses should switch to ``templateArgumentLoc`` or ``hasAnyTemplateArgumentLoc`` instead.
diff --git a/clang/include/clang/Basic/DiagnosticLexKinds.td b/clang/include/clang/Basic/DiagnosticLexKinds.td
index 25fbfe83fa2bc..372d549dc59ba 100644
--- a/clang/include/clang/Basic/DiagnosticLexKinds.td
+++ b/clang/include/clang/Basic/DiagnosticLexKinds.td
@@ -85,6 +85,10 @@ def warn_c99_keyword : Warning<"'%0' is a keyword in C99">,
def warn_c23_keyword : Warning<"'%0' is a keyword in C23">,
InGroup<C23Compat>, DefaultIgnore;
+def warn_deprecated_builtin_replacement : Warning<
+ "using the name of the builtin '%0' outside of "
+ "a builtin invocation is deprecated">, InGroup<KeywordCompat>;
+
def ext_unterminated_char_or_string : ExtWarn<
"missing terminating %select{'|'\"'}0 character">, InGroup<InvalidPPToken>;
def ext_empty_character : ExtWarn<"empty character constant">,
diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h
index ae9ebd9f59154..00d1f9b7c9949 100644
--- a/clang/include/clang/Basic/IdentifierTable.h
+++ b/clang/include/clang/Basic/IdentifierTable.h
@@ -196,6 +196,9 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
LLVM_PREFERRED_TYPE(bool)
unsigned IsFinal : 1;
+ LLVM_PREFERRED_TYPE(bool)
+ unsigned IsReusableBuiltinName : 1;
+
// 22 bits left in a 64-bit word.
// Managed by the language front-end.
@@ -213,7 +216,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false),
RevertedTokenID(false), OutOfDate(false), IsModulesImport(false),
IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false),
- IsRestrictExpansion(false), IsFinal(false) {}
+ IsRestrictExpansion(false), IsFinal(false),
+ IsReusableBuiltinName(false) {}
public:
IdentifierInfo(const IdentifierInfo &) = delete;
@@ -332,6 +336,16 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
RevertedTokenID = false;
}
+ bool isReusableBuiltinName() const { return IsReusableBuiltinName; };
+
+ void setIsReusableBuiltinName(bool Val) {
+ IsReusableBuiltinName = Val;
+ if (Val)
+ NeedsHandleIdentifier = true;
+ else
+ RecomputeNeedsHandleIdentifier();
+ };
+
/// Return the preprocessor keyword ID for this identifier.
///
/// For example, "define" will return tok::pp_define.
@@ -569,7 +583,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
void RecomputeNeedsHandleIdentifier() {
NeedsHandleIdentifier = isPoisoned() || hasMacroDefinition() ||
isExtensionToken() || isFutureCompatKeyword() ||
- isOutOfDate() || isModulesImport();
+ isReusableBuiltinName() || isOutOfDate() ||
+ isModulesImport();
}
};
diff --git a/clang/include/clang/Lex/Preprocessor.h b/clang/include/clang/Lex/Preprocessor.h
index 9d8a1aae23df3..810059cd47d03 100644
--- a/clang/include/clang/Lex/Preprocessor.h
+++ b/clang/include/clang/Lex/Preprocessor.h
@@ -1107,6 +1107,9 @@ class Preprocessor {
/// Whether tokens are being skipped until the through header is seen.
bool SkippingUntilPCHThroughHeader = false;
+ /// Whether we're evaluating __has_builtin().
+ bool EvaluatingHasBuiltinMacro = false;
+
/// \{
/// Cache of macro expanders to reduce malloc traffic.
enum { TokenLexerCacheSize = 8 };
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index d054b8cf0d240..ed5d32bf5e076 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -169,10 +169,6 @@ class Parser : public CodeCompletionHandler {
mutable IdentifierInfo *Ident_import;
mutable IdentifierInfo *Ident_module;
- // 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;
std::unique_ptr<PragmaHandler> OptionsHandler;
diff --git a/clang/lib/Basic/IdentifierTable.cpp b/clang/lib/Basic/IdentifierTable.cpp
index feea84544d62f..f2f2fb822a378 100644
--- a/clang/lib/Basic/IdentifierTable.cpp
+++ b/clang/lib/Basic/IdentifierTable.cpp
@@ -246,6 +246,79 @@ static KeywordStatus getKeywordStatus(const LangOptions &LangOpts,
return CurStatus;
}
+static bool isReusableBuiltinName(tok::TokenKind TokenCode) {
+#define RTT_JOIN(X, Y) X##Y
+#define REVERTIBLE_TYPE_TRAIT(Name) \
+ case RTT_JOIN(tok::kw_, Name): \
+ return true;
+
+ switch (TokenCode) {
+ default:
+ return false;
+ 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_nothrow_convertible);
+ 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_trivially_equality_comparable);
+ 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);
+ }
+ return false;
+}
+
/// AddKeyword - This method is used to associate a token ID with specific
/// identifiers because they are language keywords. This causes the lexer to
/// automatically map matching identifiers to specialized token codes.
@@ -261,6 +334,8 @@ static void AddKeyword(StringRef Keyword,
Table.get(Keyword, AddResult == KS_Future ? tok::identifier : TokenCode);
Info.setIsExtensionToken(AddResult == KS_Extension);
Info.setIsFutureCompatKeyword(AddResult == KS_Future);
+ Info.setIsReusableBuiltinName(LangOpts.CPlusPlus &&
+ isReusableBuiltinName(TokenCode));
}
/// AddCXXOperatorKeyword - Register a C++ operator keyword alternative
diff --git a/clang/lib/Lex/PPMacroExpansion.cpp b/clang/lib/Lex/PPMacroExpansion.cpp
index f085b94371644..9b9d06c738aa8 100644
--- a/clang/lib/Lex/PPMacroExpansion.cpp
+++ b/clang/lib/Lex/PPMacroExpansion.cpp
@@ -1673,6 +1673,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
return II && HasExtension(*this, II->getName());
});
} else if (II == Ident__has_builtin) {
+ EvaluatingHasBuiltinMacro = true;
EvaluateFeatureLikeBuiltinMacro(OS, Tok, II, *this, false,
[this](Token &Tok, bool &HasLexedNextToken) -> int {
IdentifierInfo *II = ExpectFeatureIdentifierInfo(Tok, *this,
@@ -1734,6 +1735,7 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
.Default(false);
}
});
+ EvaluatingHasBuiltinMacro = false;
} else if (II == Ident__has_constexpr_builtin) {
EvaluateFeatureLikeBuiltinMacro(
OS, Tok, II, *this, false,
diff --git a/clang/lib/Lex/Preprocessor.cpp b/clang/lib/Lex/Preprocessor.cpp
index 44b69a58f3411..8b32493b4f533 100644
--- a/clang/lib/Lex/Preprocessor.cpp
+++ b/clang/lib/Lex/Preprocessor.cpp
@@ -837,6 +837,16 @@ bool Preprocessor::HandleIdentifier(Token &Identifier) {
II.setIsFutureCompatKeyword(false);
}
+ // Standard libraries used to declare structs with the same (reserved) names
+ // as our builtins for type traits, e.g. __is_pod. This is deprecated, and
+ // we warn when our builtin identifiers are used for something else than
+ // invocation. Notable exception is __has_builtin macro.
+ if (II.isReusableBuiltinName() && !isNextPPTokenLParen() &&
+ !EvaluatingHasBuiltinMacro) {
+ Identifier.setKind(tok::identifier);
+ Diag(Identifier, diag::warn_deprecated_builtin_replacement) << II.getName();
+ }
+
// If this is an extension token, diagnose its use.
// We avoid diagnosing tokens that originate from macro definitions.
// FIXME: This warning is disabled in cases where it shouldn't be,
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index c528917437332..c1dea20e298f0 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -3906,24 +3906,7 @@ void Parser::ParseDeclarationSpecifiers(
continue;
}
-
- case tok::kw___is_signed:
- // GNU libstdc++ 4.4 uses __is_signed as an identifier, but Clang
- // typically treats it as a trait. If we see __is_signed as it appears
- // in libstdc++, e.g.,
- //
- // static const bool __is_signed;
- //
- // then treat __is_signed as an identifier rather than as a keyword.
- if (DS.getTypeSpecType() == TST_bool &&
- DS.getTypeQualifiers() == DeclSpec::TQ_const &&
- DS.getStorageClassSpec() == DeclSpec::SCS_static)
- TryKeywordIdentFallback(true);
-
- // We're done with the declaration-specifiers.
- goto DoneWithDeclSpec;
-
- // typedef-name
+ // typedef-name
case tok::kw___super:
case tok::kw_decltype:
case tok::identifier:
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d02548f6441f9..e863f24770b10 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1718,77 +1718,6 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// C++11 attributes
SourceLocation AttrFixitLoc = Tok.getLocation();
- if (TagType == DeclSpec::TST_struct && Tok.isNot(tok::identifier) &&
- !Tok.isAnnotation() && Tok.getIdentifierInfo() &&
- Tok.isOneOf(
-#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) tok::kw___##Trait,
-#include "clang/Basic/TransformTypeTraits.def"
- tok::kw___is_abstract,
- tok::kw___is_aggregate,
- tok::kw___is_arithmetic,
- tok::kw___is_array,
- tok::kw___is_assignable,
- tok::kw___is_base_of,
- tok::kw___is_bounded_array,
- tok::kw___is_class,
- tok::kw___is_complete_type,
- tok::kw___is_compound,
- tok::kw___is_const,
- tok::kw___is_constructible,
- tok::kw___is_convertible,
- tok::kw___is_convertible_to,
- tok::kw___is_destructible,
- tok::kw___is_empty,
- tok::kw___is_enum,
- tok::kw___is_floating_point,
- tok::kw___is_final,
- tok::kw___is_function,
- tok::kw___is_fundamental,
- tok::kw___is_integral,
- tok::kw___is_interface_class,
- tok::kw___is_literal,
- tok::kw___is_lvalue_expr,
- tok::kw___is_lvalue_reference,
- tok::kw___is_member_function_pointer,
- tok::kw___is_member_object_pointer,
- tok::kw___is_member_pointer,
- tok::kw___is_nothrow_assignable,
- tok::kw___is_nothrow_constructible,
- tok::kw___is_nothrow_convertible,
- tok::kw___is_nothrow_destructible,
- tok::kw___is_nullptr,
- tok::kw___is_object,
- tok::kw___is_pod,
- tok::kw___is_pointer,
- tok::kw___is_polymorphic,
- tok::kw___is_reference,
- tok::kw___is_referenceable,
- tok::kw___is_rvalue_expr,
- tok::kw___is_rvalue_reference,
- tok::kw___is_same,
- tok::kw___is_scalar,
- tok::kw___is_scoped_enum,
- tok::kw___is_sealed,
- tok::kw___is_signed,
- tok::kw___is_standard_layout,
- tok::kw___is_trivial,
- tok::kw___is_trivially_equality_comparable,
- tok::kw___is_trivially_assignable,
- tok::kw___is_trivially_constructible,
- tok::kw___is_trivially_copyable,
- tok::kw___is_unbounded_array,
- tok::kw___is_union,
- tok::kw___is_unsigned,
- tok::kw___is_void,
- tok::kw___is_volatile
- ))
- // 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);
-
struct PreserveAtomicIdentifierInfoRAII {
PreserveAtomicIdentifierInfoRAII(Token &Tok, bool Enabled)
: AtomicII(nullptr) {
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index eb7447fa038e4..baea7df1d88d1 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1097,97 +1097,6 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
isVectorLiteral, NotPrimaryExpression);
}
- // 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.
- 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<IdentifierInfo *, tok::TokenKind>::iterator Known
- = RevertibleTypeTraits.find(II);
- if (Known != RevertibleTypeTraits.end()) {
- Tok.setKind(Known->second);
- return ParseCastExpression(ParseKind, isAddressOfOperand,
- NotCastExpr, isTypeCast,
- isVectorLiteral, NotPrimaryExpression);
- }
- }
-
else if ((!ColonIsSacred && Next.is(tok::colon)) ||
Next.isOneOf(tok::coloncolon, tok::less, tok::l_paren,
tok:...
[truncated]
|
CC @MitalAshok |
To clear potential confusion, Corentin suggested to me offline to take over this PR. I fixed the tests and implemented the workaround for |
Looks like In libc++: 7f302f2 (Pretty easy fix to replace In WIL which seems to be used by a few people: https://github.com/microsoft/wil/blob/68ab8c19ef557e1006cae6b1b84dedf12c91c9d6/include/wil/wistd_config.h#L249 libstdc++, indirectly through a macro: https://gcc.gnu.org/git/?p=gcc.git;a=blobdiff;f=libstdc%2B%2B-v3/include/bits/c%2B%2Bconfig;h=27302ed392eb163954c5a2d367831dbcb0ead3c3;hp=2e6c880ad95a1cc1dfdead2bbcfb977960172ac5;hb=6aa12274007bccbae2691a9d336c37fe167bb535;hpb=6ea5a23766b8077a503362c4fa6f51de92669c11 These will now all report that those things are identifiers and not available as builtins. It can be supported with the same workaround used for llvm-project/clang/docs/LanguageExtensions.rst Line 1693 in 8d4aa1f
Also it doesn't seem ideal to not support things like: #define IS_CLASS __is_class
static_assert(!IS_CLASS(void)); Since these are supported by GCC and MSVC. Could you check again for an lparen after a macro expansion? |
Thank you, I'll make
I can't make it work even on ancient version of Clang on Compiler Explorer, so I wonder if it ever worked.
I think this would require us to abandon the lex approach implemented here. But read on...
Goodness, I think this usage makes lex approach non-viable. Even if libc++ fixes that now, it has been deployed in system headers. |
@zygoloid @cor3ntin @AaronBallman in the light of new data in #96097 (comment), do you think this lex approach to revertible type trait identifiers is still viable? |
Results from CI are not making this any better. |
What if we went in the other direction? We want to deprecate // type template
template<typename T>
struct __is_pointer;
template<typename T>
struct __is_pointer<T*> : true_type {};
__is_pointer<T>::value
// variable template
template<typename T>
inline constexpr bool __is_pointer = ...
__is_pointer<T>
// static members
template<typename T>
struct __numeric_traits_integer {
static const bool __is_signed = ...;
static const int __digits = __is_integer_nonstrict<T>::__width - __is_signed;
static const _Value __min = __is_signed ? -__max - 1 : (T)0;
}
template<typename T> const bool __numeric_traits_integer<T>::__is_signed;
static_assert(__numeric_traits_integer<int>::__is_signed); So only make it an identifier if it is preceded by The downside is if this is used in any new/unforeseen contexts, this might break |
In light of further complexities noted here, I'm abandoning this in favor of #95969 |
This patch adds a deprecation warning when builtin names like
__is_pointer
are used for something else than builtin invocation. For instance, up until a week ago libstdc++ declared their ownstruct __is_pointer
type. libc++ has been doing the same until 3.5. This will be diagnosed now.The implementation is as suggested by Richard in #95969 (comment): if lexer sees a revertible type trait builtin identifier that is not followed by an lparen, it issues a warning. Notable corner case of
__has_builtin(__is_pointer)
is exempted from that, because such usage is perfectly fine.