Skip to content

Commit 75611ca

Browse files
authored
[Clang] Improve type traits recognition in __has_builtin (#111516)
`__has_builtin` was relying on reversible identifiers and string matching to recognize builtin-type traits, leading to some newer type traits not being recognized. Fixes #111477
1 parent 9f3c559 commit 75611ca

File tree

4 files changed

+44
-21
lines changed

4 files changed

+44
-21
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,8 @@ Bug Fixes to Compiler Builtins
408408

409409
- ``__noop`` can now be used in a constant expression. (#GH102064)
410410

411+
- Fix ``__has_builtin`` incorrectly returning ``false`` for some C++ type traits. (#GH111477)
412+
411413
Bug Fixes to Attribute Support
412414
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
413415

clang/include/clang/Basic/TokenKinds.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@
6464
#ifndef EXPRESSION_TRAIT
6565
#define EXPRESSION_TRAIT(I,E,K) KEYWORD(I,K)
6666
#endif
67+
#ifndef TRANSFORM_TYPE_TRAIT_DEF
68+
#define TRANSFORM_TYPE_TRAIT_DEF(K, Trait) KEYWORD(__##Trait, KEYCXX)
69+
#endif
70+
6771
#ifndef ALIAS
6872
#define ALIAS(X,Y,Z)
6973
#endif
@@ -534,7 +538,6 @@ TYPE_TRAIT_1(__has_unique_object_representations,
534538
TYPE_TRAIT_2(__is_layout_compatible, IsLayoutCompatible, KEYCXX)
535539
TYPE_TRAIT_2(__is_pointer_interconvertible_base_of, IsPointerInterconvertibleBaseOf, KEYCXX)
536540

537-
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) KEYWORD(__##Trait, KEYCXX)
538541
#include "clang/Basic/TransformTypeTraits.def"
539542

540543
// Clang-only C++ Type Traits

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1616,6 +1616,34 @@ asm("_ZNKSt8time_putIcSt19ostreambuf_iteratorIcSt11char_traitsIcEEE3putES3_"
16161616
"RSt8ios_basecPK2tmPKcSB_");
16171617
#endif
16181618

1619+
static bool IsBuiltinTrait(Token &Tok) {
1620+
1621+
#define TYPE_TRAIT_1(Spelling, Name, Key) \
1622+
case tok::kw_##Spelling: \
1623+
return true;
1624+
#define TYPE_TRAIT_2(Spelling, Name, Key) \
1625+
case tok::kw_##Spelling: \
1626+
return true;
1627+
#define TYPE_TRAIT_N(Spelling, Name, Key) \
1628+
case tok::kw_##Spelling: \
1629+
return true;
1630+
#define ARRAY_TYPE_TRAIT(Spelling, Name, Key) \
1631+
case tok::kw_##Spelling: \
1632+
return true;
1633+
#define EXPRESSION_TRAIT(Spelling, Name, Key) \
1634+
case tok::kw_##Spelling: \
1635+
return true;
1636+
#define TRANSFORM_TYPE_TRAIT_DEF(K, Spelling) \
1637+
case tok::kw___##Spelling: \
1638+
return true;
1639+
1640+
switch (Tok.getKind()) {
1641+
default:
1642+
return false;
1643+
#include "clang/Basic/TokenKinds.def"
1644+
}
1645+
}
1646+
16191647
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded
16201648
/// as a builtin macro, handle it and return the next token as 'Tok'.
16211649
void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
@@ -1814,25 +1842,11 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
18141842
getTargetInfo().getTargetOpts().FeatureMap);
18151843
}
18161844
return true;
1817-
} else if (II->getTokenID() != tok::identifier ||
1818-
II->hasRevertedTokenIDToIdentifier()) {
1819-
// Treat all keywords that introduce a custom syntax of the form
1820-
//
1821-
// '__some_keyword' '(' [...] ')'
1822-
//
1823-
// as being "builtin functions", even if the syntax isn't a valid
1824-
// function call (for example, because the builtin takes a type
1825-
// argument).
1826-
if (II->getName().starts_with("__builtin_") ||
1827-
II->getName().starts_with("__is_") ||
1828-
II->getName().starts_with("__has_"))
1829-
return true;
1830-
return llvm::StringSwitch<bool>(II->getName())
1831-
.Case("__array_rank", true)
1832-
.Case("__array_extent", true)
1833-
#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) .Case("__" #Trait, true)
1834-
#include "clang/Basic/TransformTypeTraits.def"
1835-
.Default(false);
1845+
} else if (IsBuiltinTrait(Tok)) {
1846+
return true;
1847+
} else if (II->getTokenID() != tok::identifier &&
1848+
II->getName().starts_with("__builtin_")) {
1849+
return true;
18361850
} else {
18371851
return llvm::StringSwitch<bool>(II->getName())
18381852
// Report builtin templates as being builtins.

clang/test/Preprocessor/feature_tests.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@
3131
!__has_builtin(__underlying_type) || \
3232
!__has_builtin(__is_trivial) || \
3333
!__has_builtin(__is_same_as) || \
34-
!__has_builtin(__has_unique_object_representations)
34+
!__has_builtin(__has_unique_object_representations) || \
35+
!__has_builtin(__is_trivially_equality_comparable) || \
36+
!__has_builtin(__reference_constructs_from_temporary) || \
37+
!__has_builtin(__reference_binds_to_temporary) || \
38+
!__has_builtin(__reference_converts_from_temporary)
3539
#error Clang should have these
3640
#endif
3741

0 commit comments

Comments
 (0)