[clang] Warn when builtin names are used outside of invocations#96097
[clang] Warn when builtin names are used outside of invocations#96097
Conversation
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
| return II && HasExtension(*this, II->getName()); | ||
| }); | ||
| } else if (II == Ident__has_builtin) { | ||
| EvaluatingHasBuiltinMacro = true; |
There was a problem hiding this comment.
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_pointerare used for something else than builtin invocation. For instance, up until a week ago libstdc++ declared their ownstruct __is_pointertype. 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.