Skip to content

Commit dac3ea4

Browse files
committed
Add __has_builtin support for builtin function-like type traits.
Summary: Previously __has_builtin(__builtin_*) would return false for __builtin_*s that we modeled as keywords rather than as functions (because they take type arguments). With this patch, all builtins that are called with function-call-like syntax return true from __has_builtin (covering __builtin_* and also the __is_* and __has_* type traits and the handful of similar builtins without such a prefix). Update the documentation on __has_builtin and on type traits to match. While doing this I noticed the type trait documentation was out of date and incomplete; that's fixed here too. Reviewers: aaron.ballman Subscribers: jfb, kristina, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D66100 llvm-svn: 368785
1 parent f1d538c commit dac3ea4

File tree

6 files changed

+273
-88
lines changed

6 files changed

+273
-88
lines changed

clang/docs/LanguageExtensions.rst

Lines changed: 180 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ version checks".
3838
-----------------
3939

4040
This function-like macro takes a single identifier argument that is the name of
41-
a builtin function. It evaluates to 1 if the builtin is supported or 0 if not.
41+
a builtin function, a builtin pseudo-function (taking one or more type
42+
arguments), or a builtin template.
43+
It evaluates to 1 if the builtin is supported or 0 if not.
4244
It can be used like this:
4345

4446
.. code-block:: c++
@@ -55,6 +57,14 @@ It can be used like this:
5557
#endif
5658
...
5759

60+
.. note::
61+
62+
Prior to Clang 10, ``__has_builtin`` could not be used to detect most builtin
63+
pseudo-functions.
64+
65+
``__has_builtin`` should not be used to detect support for a builtin macro;
66+
use ``#ifdef`` instead.
67+
5868
.. _langext-__has_feature-__has_extension:
5969

6070
``__has_feature`` and ``__has_extension``
@@ -1041,8 +1051,8 @@ For example, compiling code with ``-fmodules`` enables the use of Modules.
10411051

10421052
More information could be found `here <https://clang.llvm.org/docs/Modules.html>`_.
10431053

1044-
Checks for Type Trait Primitives
1045-
================================
1054+
Type Trait Primitives
1055+
=====================
10461056

10471057
Type trait primitives are special builtin constant expressions that can be used
10481058
by the standard C++ library to facilitate or simplify the implementation of
@@ -1058,20 +1068,173 @@ the supported set of system headers, currently:
10581068

10591069
Clang supports the `GNU C++ type traits
10601070
<https://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html>`_ and a subset of the
1061-
`Microsoft Visual C++ Type traits
1062-
<https://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx>`_.
1063-
1064-
Feature detection is supported only for some of the primitives at present. User
1065-
code should not use these checks because they bear no direct relation to the
1066-
actual set of type traits supported by the C++ standard library.
1067-
1068-
For type trait ``__X``, ``__has_extension(X)`` indicates the presence of the
1069-
type trait primitive in the compiler. A simplistic usage example as might be
1070-
seen in standard C++ headers follows:
1071-
1072-
.. code-block:: c++
1073-
1074-
#if __has_extension(is_convertible_to)
1071+
`Microsoft Visual C++ type traits
1072+
<https://msdn.microsoft.com/en-us/library/ms177194(v=VS.100).aspx>`_,
1073+
as well as nearly all of the
1074+
`Embarcadero C++ type traits
1075+
<http://docwiki.embarcadero.com/RADStudio/Rio/en/Type_Trait_Functions_(C%2B%2B11)_Index>`_.
1076+
1077+
The following type trait primitives are supported by Clang. Those traits marked
1078+
(C++) provide implementations for type traits specified by the C++ standard;
1079+
``__X(...)`` has the same semantics and constraints as the corresponding
1080+
``std::X_t<...>`` or ``std::X_v<...>`` type trait.
1081+
1082+
* ``__array_rank(type)`` (Embarcadero):
1083+
Returns the number of levels of array in the type ``type``:
1084+
``0`` if ``type`` is not an array type, and
1085+
``__array_rank(element) + 1`` if ``type`` is an array of ``element``.
1086+
* ``__array_extent(type, dim)`` (Embarcadero):
1087+
The ``dim``'th array bound in the type ``type``, or ``0`` if
1088+
``dim >= __array_rank(type)``.
1089+
* ``__has_nothrow_assign`` (GNU, Microsoft, Embarcadero):
1090+
Deprecated, use ``__is_nothrow_assignable`` instead.
1091+
* ``__has_nothrow_move_assign`` (GNU, Microsoft):
1092+
Deprecated, use ``__is_nothrow_assignable`` instead.
1093+
* ``__has_nothrow_copy`` (GNU, Microsoft):
1094+
Deprecated, use ``__is_nothrow_constructible`` instead.
1095+
* ``__has_nothrow_constructor`` (GNU, Microsoft):
1096+
Deprecated, use ``__is_nothrow_constructible`` instead.
1097+
* ``__has_trivial_assign`` (GNU, Microsoft, Embarcadero):
1098+
Deprecated, use ``__is_trivially_assignable`` instead.
1099+
* ``__has_trivial_move_assign`` (GNU, Microsoft):
1100+
Deprecated, use ``__is_trivially_assignable`` instead.
1101+
* ``__has_trivial_copy`` (GNU, Microsoft):
1102+
Deprecated, use ``__is_trivially_constructible`` instead.
1103+
* ``__has_trivial_constructor`` (GNU, Microsoft):
1104+
Deprecated, use ``__is_trivially_constructible`` instead.
1105+
* ``__has_trivial_move_constructor`` (GNU, Microsoft):
1106+
Deprecated, use ``__is_trivially_constructible`` instead.
1107+
* ``__has_trivial_destructor`` (GNU, Microsoft, Embarcadero):
1108+
Deprecated, use ``__is_trivially_destructible`` instead.
1109+
* ``__has_unique_object_representations`` (C++, GNU)
1110+
* ``__has_virtual_destructor`` (C++, GNU, Microsoft, Embarcadero)
1111+
* ``__is_abstract`` (C++, GNU, Microsoft, Embarcadero)
1112+
* ``__is_aggregate`` (C++, GNU, Microsoft)
1113+
* ``__is_arithmetic`` (C++, Embarcadero)
1114+
* ``__is_array`` (C++, Embarcadero)
1115+
* ``__is_assignable`` (C++, MSVC 2015)
1116+
* ``__is_base_of`` (C++, GNU, Microsoft, Embarcadero)
1117+
* ``__is_class`` (C++, GNU, Microsoft, Embarcadero)
1118+
* ``__is_complete_type(type)`` (Embarcadero):
1119+
Return ``true`` if ``type`` is a complete type.
1120+
Warning: this trait is dangerous because it can return different values at
1121+
different points in the same program.
1122+
* ``__is_compound`` (C++, Embarcadero)
1123+
* ``__is_const`` (C++, Embarcadero)
1124+
* ``__is_constructible`` (C++, MSVC 2013)
1125+
* ``__is_convertible`` (C++, Embarcadero)
1126+
* ``__is_convertible_to`` (Microsoft):
1127+
Synonym for ``__is_convertible``.
1128+
* ``__is_destructible`` (C++, MSVC 2013):
1129+
Only available in ``-fms-extensions`` mode.
1130+
* ``__is_empty`` (C++, GNU, Microsoft, Embarcadero)
1131+
* ``__is_enum`` (C++, GNU, Microsoft, Embarcadero)
1132+
* ``__is_final`` (C++, GNU, Microsoft)
1133+
* ``__is_floating_point`` (C++, Embarcadero)
1134+
* ``__is_function`` (C++, Embarcadero)
1135+
* ``__is_fundamental`` (C++, Embarcadero)
1136+
* ``__is_integral`` (C++, Embarcadero)
1137+
* ``__is_interface_class`` (Microsoft):
1138+
Returns ``false``, even for types defined with ``__interface``.
1139+
* ``__is_literal`` (Clang):
1140+
Synonym for ``__is_literal_type``.
1141+
* ``__is_literal_type`` (C++, GNU, Microsoft):
1142+
Note, the corresponding standard trait was deprecated in C++17
1143+
and removed in C++20.
1144+
* ``__is_lvalue_reference`` (C++, Embarcadero)
1145+
* ``__is_member_object_pointer`` (C++, Embarcadero)
1146+
* ``__is_member_function_pointer`` (C++, Embarcadero)
1147+
* ``__is_member_pointer`` (C++, Embarcadero)
1148+
* ``__is_nothrow_assignable`` (C++, MSVC 2013)
1149+
* ``__is_nothrow_constructible`` (C++, MSVC 2013)
1150+
* ``__is_nothrow_destructible`` (C++, MSVC 2013)
1151+
Only available in ``-fms-extensions`` mode.
1152+
* ``__is_object`` (C++, Embarcadero)
1153+
* ``__is_pod`` (C++, GNU, Microsoft, Embarcadero):
1154+
Note, the corresponding standard trait was deprecated in C++20.
1155+
* ``__is_pointer`` (C++, Embarcadero)
1156+
* ``__is_polymorphic`` (C++, GNU, Microsoft, Embarcadero)
1157+
* ``__is_reference`` (C++, Embarcadero)
1158+
* ``__is_rvalue_reference`` (C++, Embarcadero)
1159+
* ``__is_same`` (C++, Embarcadero)
1160+
* ``__is_scalar`` (C++, Embarcadero)
1161+
* ``__is_sealed`` (Microsoft):
1162+
Synonym for ``__is_final``.
1163+
* ``__is_signed`` (C++, Embarcadero):
1164+
Note that this currently returns true for enumeration types if the underlying
1165+
type is signed, and returns false for floating-point types, in violation of
1166+
the requirements for ``std::is_signed``. This behavior is likely to change in
1167+
a future version of Clang.
1168+
* ``__is_standard_layout`` (C++, GNU, Microsoft, Embarcadero)
1169+
* ``__is_trivial`` (C++, GNU, Microsoft, Embarcadero)
1170+
* ``__is_trivially_assignable`` (C++, GNU, Microsoft)
1171+
* ``__is_trivially_constructible`` (C++, GNU, Microsoft)
1172+
* ``__is_trivially_copyable`` (C++, GNU, Microsoft)
1173+
* ``__is_trivially_destructible`` (C++, MSVC 2013)
1174+
* ``__is_union`` (C++, GNU, Microsoft, Embarcadero)
1175+
* ``__is_unsigned`` (C++, Embarcadero)
1176+
Note that this currently returns true for enumeration types if the underlying
1177+
type is unsigned, in violation of the requirements for ``std::is_unsigned``.
1178+
This behavior is likely to change in a future version of Clang.
1179+
* ``__is_void`` (C++, Embarcadero)
1180+
* ``__is_volatile`` (C++, Embarcadero)
1181+
* ``__reference_binds_to_temporary(T, U)`` (Clang): Determines whether a
1182+
reference of type ``T`` bound to an expression of type ``U`` would bind to a
1183+
materialized temporary object. If ``T`` is not a reference type the result
1184+
is false. Note this trait will also return false when the initialization of
1185+
``T`` from ``U`` is ill-formed.
1186+
* ``__underlying_type`` (C++, GNU, Microsoft)
1187+
1188+
In addition, the following expression traits are supported:
1189+
1190+
* ``__is_lvalue_expr(e)`` (Embarcadero):
1191+
Returns true if ``e`` is an lvalue expression.
1192+
Deprecated, use ``__is_lvalue_reference(decltype((e)))`` instead.
1193+
* ``__is_rvalue_expr(e)`` (Embarcadero):
1194+
Returns true if ``e`` is a prvalue expression.
1195+
Deprecated, use ``!__is_reference(decltype((e)))`` instead.
1196+
1197+
There are multiple ways to detect support for a type trait ``__X`` in the
1198+
compiler, depending on the oldest version of Clang you wish to support.
1199+
1200+
* From Clang 10 onwards, ``__has_builtin(__X)`` can be used.
1201+
* From Clang 6 onwards, ``!__is_identifier(__X)`` can be used.
1202+
* From Clang 3 onwards, ``__has_feature(X)`` can be used, but only supports
1203+
the following traits:
1204+
1205+
* ``__has_nothrow_assign``
1206+
* ``__has_nothrow_copy``
1207+
* ``__has_nothrow_constructor``
1208+
* ``__has_trivial_assign``
1209+
* ``__has_trivial_copy``
1210+
* ``__has_trivial_constructor``
1211+
* ``__has_trivial_destructor``
1212+
* ``__has_virtual_destructor``
1213+
* ``__is_abstract``
1214+
* ``__is_base_of``
1215+
* ``__is_class``
1216+
* ``__is_constructible``
1217+
* ``__is_convertible_to``
1218+
* ``__is_empty``
1219+
* ``__is_enum``
1220+
* ``__is_final``
1221+
* ``__is_literal``
1222+
* ``__is_standard_layout``
1223+
* ``__is_pod``
1224+
* ``__is_polymorphic``
1225+
* ``__is_sealed``
1226+
* ``__is_trivial``
1227+
* ``__is_trivially_assignable``
1228+
* ``__is_trivially_constructible``
1229+
* ``__is_trivially_copyable``
1230+
* ``__is_union``
1231+
* ``__underlying_type``
1232+
1233+
A simplistic usage example as might be seen in standard C++ headers follows:
1234+
1235+
.. code-block:: c++
1236+
1237+
#if __has_builtin(__is_convertible_to)
10751238
template<typename From, typename To>
10761239
struct is_convertible_to {
10771240
static const bool value = __is_convertible_to(From, To);
@@ -1080,54 +1243,6 @@ seen in standard C++ headers follows:
10801243
// Emulate type trait for compatibility with other compilers.
10811244
#endif
10821245

1083-
The following type trait primitives are supported by Clang:
1084-
1085-
* ``__has_nothrow_assign`` (GNU, Microsoft)
1086-
* ``__has_nothrow_copy`` (GNU, Microsoft)
1087-
* ``__has_nothrow_constructor`` (GNU, Microsoft)
1088-
* ``__has_trivial_assign`` (GNU, Microsoft)
1089-
* ``__has_trivial_copy`` (GNU, Microsoft)
1090-
* ``__has_trivial_constructor`` (GNU, Microsoft)
1091-
* ``__has_trivial_destructor`` (GNU, Microsoft)
1092-
* ``__has_virtual_destructor`` (GNU, Microsoft)
1093-
* ``__is_abstract`` (GNU, Microsoft)
1094-
* ``__is_aggregate`` (GNU, Microsoft)
1095-
* ``__is_base_of`` (GNU, Microsoft)
1096-
* ``__is_class`` (GNU, Microsoft)
1097-
* ``__is_convertible_to`` (Microsoft)
1098-
* ``__is_empty`` (GNU, Microsoft)
1099-
* ``__is_enum`` (GNU, Microsoft)
1100-
* ``__is_interface_class`` (Microsoft)
1101-
* ``__is_pod`` (GNU, Microsoft)
1102-
* ``__is_polymorphic`` (GNU, Microsoft)
1103-
* ``__is_union`` (GNU, Microsoft)
1104-
* ``__is_literal(type)``: Determines whether the given type is a literal type
1105-
* ``__is_final``: Determines whether the given type is declared with a
1106-
``final`` class-virt-specifier.
1107-
* ``__underlying_type(type)``: Retrieves the underlying type for a given
1108-
``enum`` type. This trait is required to implement the C++11 standard
1109-
library.
1110-
* ``__is_trivially_assignable(totype, fromtype)``: Determines whether a value
1111-
of type ``totype`` can be assigned to from a value of type ``fromtype`` such
1112-
that no non-trivial functions are called as part of that assignment. This
1113-
trait is required to implement the C++11 standard library.
1114-
* ``__is_trivially_constructible(type, argtypes...)``: Determines whether a
1115-
value of type ``type`` can be direct-initialized with arguments of types
1116-
``argtypes...`` such that no non-trivial functions are called as part of
1117-
that initialization. This trait is required to implement the C++11 standard
1118-
library.
1119-
* ``__is_destructible`` (MSVC 2013)
1120-
* ``__is_nothrow_destructible`` (MSVC 2013)
1121-
* ``__is_nothrow_assignable`` (MSVC 2013, clang)
1122-
* ``__is_constructible`` (MSVC 2013, clang)
1123-
* ``__is_nothrow_constructible`` (MSVC 2013, clang)
1124-
* ``__is_assignable`` (MSVC 2015, clang)
1125-
* ``__reference_binds_to_temporary(T, U)`` (Clang): Determines whether a
1126-
reference of type ``T`` bound to an expression of type ``U`` would bind to a
1127-
materialized temporary object. If ``T`` is not a reference type the result
1128-
is false. Note this trait will also return false when the initialization of
1129-
``T`` from ``U`` is ill-formed.
1130-
11311246
Blocks
11321247
======
11331248

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ FEATURE(cxx_variable_templates, LangOpts.CPlusPlus14)
187187
// FEATURE(raw_invocation_type, LangOpts.CPlusPlus)
188188
// Type traits
189189
// N.B. Additional type traits should not be added to the following list.
190-
// Instead, they should be detected by has_extension.
190+
// Instead, they should be detected by has_builtin.
191191
FEATURE(has_nothrow_assign, LangOpts.CPlusPlus)
192192
FEATURE(has_nothrow_copy, LangOpts.CPlusPlus)
193193
FEATURE(has_nothrow_constructor, LangOpts.CPlusPlus)

clang/include/clang/Basic/TokenKinds.def

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -449,16 +449,18 @@ TYPE_TRAIT_N(__is_nothrow_constructible, IsNothrowConstructible, KEYCXX)
449449
// MSVC14.0 / VS2015 Type Traits
450450
TYPE_TRAIT_2(__is_assignable, IsAssignable, KEYCXX)
451451

452+
// MSVC Type Traits of unknown vintage
453+
TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX)
454+
TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX)
455+
TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
456+
452457
// GNU and MS Type Traits
453458
TYPE_TRAIT_1(__has_nothrow_assign, HasNothrowAssign, KEYCXX)
454-
TYPE_TRAIT_1(__has_nothrow_move_assign, HasNothrowMoveAssign, KEYCXX)
455459
TYPE_TRAIT_1(__has_nothrow_copy, HasNothrowCopy, KEYCXX)
456460
TYPE_TRAIT_1(__has_nothrow_constructor, HasNothrowConstructor, KEYCXX)
457461
TYPE_TRAIT_1(__has_trivial_assign, HasTrivialAssign, KEYCXX)
458-
TYPE_TRAIT_1(__has_trivial_move_assign, HasTrivialMoveAssign, KEYCXX)
459462
TYPE_TRAIT_1(__has_trivial_copy, HasTrivialCopy, KEYCXX)
460463
TYPE_TRAIT_1(__has_trivial_constructor, HasTrivialDefaultConstructor, KEYCXX)
461-
TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX)
462464
TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX)
463465
TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX)
464466
TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX)
@@ -475,17 +477,18 @@ TYPE_TRAIT_1(__is_literal, IsLiteral, KEYCXX)
475477
ALIAS("__is_literal_type", __is_literal, KEYCXX)
476478
TYPE_TRAIT_1(__is_pod, IsPOD, KEYCXX)
477479
TYPE_TRAIT_1(__is_polymorphic, IsPolymorphic, KEYCXX)
480+
TYPE_TRAIT_1(__is_standard_layout, IsStandardLayout, KEYCXX)
478481
TYPE_TRAIT_1(__is_trivial, IsTrivial, KEYCXX)
482+
TYPE_TRAIT_2(__is_trivially_assignable, IsTriviallyAssignable, KEYCXX)
483+
TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX)
484+
TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX)
479485
TYPE_TRAIT_1(__is_union, IsUnion, KEYCXX)
480486
TYPE_TRAIT_1(__has_unique_object_representations,
481487
HasUniqueObjectRepresentations, KEYCXX)
488+
KEYWORD(__underlying_type , KEYCXX)
482489

483490
// Clang-only C++ Type Traits
484-
TYPE_TRAIT_N(__is_trivially_constructible, IsTriviallyConstructible, KEYCXX)
485-
TYPE_TRAIT_1(__is_trivially_copyable, IsTriviallyCopyable, KEYCXX)
486-
TYPE_TRAIT_2(__is_trivially_assignable, IsTriviallyAssignable, KEYCXX)
487491
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
488-
KEYWORD(__underlying_type , KEYCXX)
489492

490493
// Embarcadero Expression Traits
491494
KEYWORD(__is_lvalue_expr , KEYCXX)
@@ -512,7 +515,6 @@ TYPE_TRAIT_1(__is_member_function_pointer, IsMemberFunctionPointer, KEYCXX)
512515
TYPE_TRAIT_1(__is_member_pointer, IsMemberPointer, KEYCXX)
513516
TYPE_TRAIT_1(__is_const, IsConst, KEYCXX)
514517
TYPE_TRAIT_1(__is_volatile, IsVolatile, KEYCXX)
515-
TYPE_TRAIT_1(__is_standard_layout, IsStandardLayout, KEYCXX)
516518
TYPE_TRAIT_1(__is_signed, IsSigned, KEYCXX)
517519
TYPE_TRAIT_1(__is_unsigned, IsUnsigned, KEYCXX)
518520

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,21 +1617,38 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
16171617
return true;
16181618
}
16191619
return true;
1620+
} else if (II->getTokenID() != tok::identifier ||
1621+
II->hasRevertedTokenIDToIdentifier()) {
1622+
// Treat all keywords that introduce a custom syntax of the form
1623+
//
1624+
// '__some_keyword' '(' [...] ')'
1625+
//
1626+
// as being "builtin functions", even if the syntax isn't a valid
1627+
// function call (for example, because the builtin takes a type
1628+
// argument).
1629+
if (II->getName().startswith("__builtin_") ||
1630+
II->getName().startswith("__is_") ||
1631+
II->getName().startswith("__has_"))
1632+
return true;
1633+
return llvm::StringSwitch<bool>(II->getName())
1634+
.Case("__array_rank", true)
1635+
.Case("__array_extent", true)
1636+
.Case("__reference_binds_to_temporary", true)
1637+
.Case("__underlying_type", true)
1638+
.Default(false);
16201639
} else {
16211640
return llvm::StringSwitch<bool>(II->getName())
1622-
.Case("__make_integer_seq", LangOpts.CPlusPlus)
1623-
.Case("__type_pack_element", LangOpts.CPlusPlus)
1624-
.Case("__builtin_available", true)
1625-
.Case("__is_target_arch", true)
1626-
.Case("__is_target_vendor", true)
1627-
.Case("__is_target_os", true)
1628-
.Case("__is_target_environment", true)
1629-
.Case("__builtin_LINE", true)
1630-
.Case("__builtin_FILE", true)
1631-
.Case("__builtin_FUNCTION", true)
1632-
.Case("__builtin_COLUMN", true)
1633-
.Case("__builtin_bit_cast", true)
1634-
.Default(false);
1641+
// Report builtin templates as being builtins.
1642+
.Case("__make_integer_seq", LangOpts.CPlusPlus)
1643+
.Case("__type_pack_element", LangOpts.CPlusPlus)
1644+
// Likewise for some builtin preprocessor macros.
1645+
// FIXME: This is inconsistent; we usually suggest detecting
1646+
// builtin macros via #ifdef. Don't add more cases here.
1647+
.Case("__is_target_arch", true)
1648+
.Case("__is_target_vendor", true)
1649+
.Case("__is_target_os", true)
1650+
.Case("__is_target_environment", true)
1651+
.Default(false);
16351652
}
16361653
});
16371654
} else if (II == Ident__is_identifier) {

0 commit comments

Comments
 (0)