[clang] a089def - [clang] adds `__is_scoped_enum`, `__is_nullptr`, and `__is_referenceable`
Christopher Di Bella via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 10 17:39:13 PDT 2022
Author: Christopher Di Bella
Date: 2022-10-11T00:13:58Z
New Revision: a089defa24dd4050192e1e8d7e704188d2214787
URL: https://github.com/llvm/llvm-project/commit/a089defa24dd4050192e1e8d7e704188d2214787
DIFF: https://github.com/llvm/llvm-project/commit/a089defa24dd4050192e1e8d7e704188d2214787.diff
LOG: [clang] adds `__is_scoped_enum`, `__is_nullptr`, and `__is_referenceable`
... as builtins.
This is information that the compiler already has, and should be exposed
so that the library doesn't need to reimplement the exact same
functionality.
This was originally a part of D116280.
Depends on D135175.
Differential Revision: https://reviews.llvm.org/D135177
Added:
Modified:
clang/docs/LanguageExtensions.rst
clang/include/clang/Basic/TokenKinds.def
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Parse/ParseExpr.cpp
clang/lib/Sema/SemaExprCXX.cpp
clang/test/SemaCXX/type-traits.cpp
Removed:
################################################################################
diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst
index 83f49d9bf13bd..162bcdd9fba70 100644
--- a/clang/docs/LanguageExtensions.rst
+++ b/clang/docs/LanguageExtensions.rst
@@ -1428,16 +1428,25 @@ The following type trait primitives are supported by Clang. Those traits marked
* ``__is_nothrow_constructible`` (C++, MSVC 2013)
* ``__is_nothrow_destructible`` (C++, MSVC 2013)
Only available in ``-fms-extensions`` mode.
+* ``__is_nullptr`` (C++, GNU, Microsoft, Embarcadero):
+ Returns true for ``std::nullptr_t`` and false for everything else. The
+ corresponding standard library feature is ``std::is_null_pointer``, but
+ ``__is_null_pointer`` is already in use by some implementations.
* ``__is_object`` (C++, Embarcadero)
* ``__is_pod`` (C++, GNU, Microsoft, Embarcadero):
Note, the corresponding standard trait was deprecated in C++20.
* ``__is_pointer`` (C++, Embarcadero)
* ``__is_polymorphic`` (C++, GNU, Microsoft, Embarcadero)
* ``__is_reference`` (C++, Embarcadero)
+* ``__is_referenceable`` (C++, GNU, Microsoft, Embarcadero):
+ Returns true if a type is referenceable, and false otherwise. A referenceable
+ type is a type that's either an object type, a reference type, or an unqualified
+ function type.
* ``__is_rvalue_reference`` (C++, Embarcadero)
* ``__is_same`` (C++, Embarcadero)
* ``__is_same_as`` (GCC): Synonym for ``__is_same``.
* ``__is_scalar`` (C++, Embarcadero)
+* ``__is_scoped_enum`` (C++, GNU, Microsoft, Embarcadero)
* ``__is_sealed`` (Microsoft):
Synonym for ``__is_final``.
* ``__is_signed`` (C++, Embarcadero):
diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def
index 747565e7fac4e..4e89752051bdc 100644
--- a/clang/include/clang/Basic/TokenKinds.def
+++ b/clang/include/clang/Basic/TokenKinds.def
@@ -520,6 +520,9 @@ TYPE_TRAIT_1(__has_unique_object_representations,
TYPE_TRAIT_1(__is_trivially_relocatable, IsTriviallyRelocatable, KEYCXX)
TYPE_TRAIT_1(__is_bounded_array, IsBoundedArray, KEYCXX)
TYPE_TRAIT_1(__is_unbounded_array, IsUnboundedArray, KEYCXX)
+TYPE_TRAIT_1(__is_nullptr, IsNullPointer, KEYCXX)
+TYPE_TRAIT_1(__is_scoped_enum, IsScopedEnum, KEYCXX)
+TYPE_TRAIT_1(__is_referenceable, IsReferenceable, KEYCXX)
TYPE_TRAIT_2(__reference_binds_to_temporary, ReferenceBindsToTemporary, KEYCXX)
// Embarcadero Expression Traits
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index 4eeba4787b57d..bbffff5394f04 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1605,15 +1605,18 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
tok::kw___is_nothrow_assignable,
tok::kw___is_nothrow_constructible,
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,
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 956361123f998..b8f351dbbf1e1 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -1067,8 +1067,8 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
REVERTIBLE_TYPE_TRAIT(__is_arithmetic);
REVERTIBLE_TYPE_TRAIT(__is_array);
REVERTIBLE_TYPE_TRAIT(__is_assignable);
- REVERTIBLE_TYPE_TRAIT(__is_bounded_array);
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);
@@ -1094,15 +1094,18 @@ ExprResult Parser::ParseCastExpression(CastParseKind ParseKind,
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);
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index b477ae02ecc74..52f867a4fa389 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -4760,11 +4760,14 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT,
case UTT_IsArray:
case UTT_IsBoundedArray:
case UTT_IsPointer:
+ case UTT_IsNullPointer:
+ case UTT_IsReferenceable:
case UTT_IsLvalueReference:
case UTT_IsRvalueReference:
case UTT_IsMemberFunctionPointer:
case UTT_IsMemberObjectPointer:
case UTT_IsEnum:
+ case UTT_IsScopedEnum:
case UTT_IsUnion:
case UTT_IsClass:
case UTT_IsFunction:
@@ -4923,6 +4926,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return false;
case UTT_IsPointer:
return T->isAnyPointerType();
+ case UTT_IsNullPointer:
+ return T->isNullPtrType();
case UTT_IsLvalueReference:
return T->isLValueReferenceType();
case UTT_IsRvalueReference:
@@ -4933,6 +4938,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return T->isMemberDataPointerType();
case UTT_IsEnum:
return T->isEnumeralType();
+ case UTT_IsScopedEnum:
+ return T->isScopedEnumeralType();
case UTT_IsUnion:
return T->isUnionType();
case UTT_IsClass:
@@ -5304,6 +5311,8 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT,
return C.hasUniqueObjectRepresentations(T);
case UTT_IsTriviallyRelocatable:
return T.isTriviallyRelocatableType(C);
+ case UTT_IsReferenceable:
+ return T.isReferenceable();
}
}
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index e1f8a0c9373da..35e21ee7688b9 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -345,11 +345,19 @@ void is_union()
}
typedef Enum EnumType;
+typedef EnumClass EnumClassType;
void is_enum()
{
{ int arr[T(__is_enum(Enum))]; }
{ int arr[T(__is_enum(EnumType))]; }
+ { int arr[T(__is_enum(SignedEnum))]; }
+ { int arr[T(__is_enum(UnsignedEnum))]; }
+
+ { int arr[T(__is_enum(EnumClass))]; }
+ { int arr[T(__is_enum(EnumClassType))]; }
+ { int arr[T(__is_enum(SignedEnumClass))]; }
+ { int arr[T(__is_enum(UnsignedEnumClass))]; }
{ int arr[F(__is_enum(int))]; }
{ int arr[F(__is_enum(Union))]; }
@@ -361,6 +369,37 @@ void is_enum()
{ int arr[F(__is_enum(cvoid))]; }
{ int arr[F(__is_enum(IntArNB))]; }
{ int arr[F(__is_enum(HasAnonymousUnion))]; }
+ { int arr[F(__is_enum(AnIncompleteType))]; }
+ { int arr[F(__is_enum(AnIncompleteTypeAr))]; }
+ { int arr[F(__is_enum(AnIncompleteTypeArMB))]; }
+ { int arr[F(__is_enum(AnIncompleteTypeArNB))]; }
+}
+
+void is_scoped_enum() {
+ static_assert(!__is_scoped_enum(Enum), "");
+ static_assert(!__is_scoped_enum(EnumType), "");
+ static_assert(!__is_scoped_enum(SignedEnum), "");
+ static_assert(!__is_scoped_enum(UnsignedEnum), "");
+
+ static_assert(__is_scoped_enum(EnumClass), "");
+ static_assert(__is_scoped_enum(EnumClassType), "");
+ static_assert(__is_scoped_enum(SignedEnumClass), "");
+ static_assert(__is_scoped_enum(UnsignedEnumClass), "");
+
+ static_assert(!__is_scoped_enum(int), "");
+ static_assert(!__is_scoped_enum(Union), "");
+ static_assert(!__is_scoped_enum(Int), "");
+ static_assert(!__is_scoped_enum(IntAr), "");
+ static_assert(!__is_scoped_enum(UnionAr), "");
+ static_assert(!__is_scoped_enum(Derives), "");
+ static_assert(!__is_scoped_enum(ClassType), "");
+ static_assert(!__is_scoped_enum(cvoid), "");
+ static_assert(!__is_scoped_enum(IntArNB), "");
+ static_assert(!__is_scoped_enum(HasAnonymousUnion), "");
+ static_assert(!__is_scoped_enum(AnIncompleteType), "");
+ static_assert(!__is_scoped_enum(AnIncompleteTypeAr), "");
+ static_assert(!__is_scoped_enum(AnIncompleteTypeArMB), "");
+ static_assert(!__is_scoped_enum(AnIncompleteTypeArNB), "");
}
struct FinalClass final {
@@ -766,6 +805,36 @@ void is_unbounded_array(int n) {
(void)__is_unbounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported for '__is_unbounded_array'}}
}
+void is_referenceable() {
+ static_assert(__is_referenceable(int), "");
+ static_assert(__is_referenceable(const int), "");
+ static_assert(__is_referenceable(volatile int), "");
+ static_assert(__is_referenceable(const volatile int), "");
+ static_assert(__is_referenceable(int *), "");
+ static_assert(__is_referenceable(int &), "");
+ static_assert(__is_referenceable(int &&), "");
+ static_assert(__is_referenceable(int (*)()), "");
+ static_assert(__is_referenceable(int (&)()), "");
+ static_assert(__is_referenceable(int(&&)()), "");
+ static_assert(__is_referenceable(IntAr), "");
+ static_assert(__is_referenceable(IntArNB), "");
+ static_assert(__is_referenceable(decltype(nullptr)), "");
+ static_assert(__is_referenceable(Empty), "");
+ static_assert(__is_referenceable(Union), "");
+ static_assert(__is_referenceable(Derives), "");
+ static_assert(__is_referenceable(Enum), "");
+ static_assert(__is_referenceable(EnumClass), "");
+ static_assert(__is_referenceable(int Empty::*), "");
+ static_assert(__is_referenceable(int(Empty::*)()), "");
+ static_assert(__is_referenceable(AnIncompleteType), "");
+ static_assert(__is_referenceable(struct AnIncompleteType), "");
+
+ using function_type = void(int);
+ static_assert(__is_referenceable(function_type), "");
+
+ static_assert(!__is_referenceable(void), "");
+}
+
template <typename T> void tmpl_func(T&) {}
template <typename T> struct type_wrapper {
@@ -998,6 +1067,42 @@ void is_pointer()
int t34[F(__is_pointer(void (StructWithMembers::*) ()))];
}
+void is_null_pointer() {
+ StructWithMembers x;
+
+ static_assert(__is_nullptr(decltype(nullptr)), "");
+ static_assert(!__is_nullptr(void *), "");
+ static_assert(!__is_nullptr(cvoid *), "");
+ static_assert(!__is_nullptr(cvoid *), "");
+ static_assert(!__is_nullptr(char *), "");
+ static_assert(!__is_nullptr(int *), "");
+ static_assert(!__is_nullptr(int **), "");
+ static_assert(!__is_nullptr(ClassType *), "");
+ static_assert(!__is_nullptr(Derives *), "");
+ static_assert(!__is_nullptr(Enum *), "");
+ static_assert(!__is_nullptr(IntArNB *), "");
+ static_assert(!__is_nullptr(Union *), "");
+ static_assert(!__is_nullptr(UnionAr *), "");
+ static_assert(!__is_nullptr(StructWithMembers *), "");
+ static_assert(!__is_nullptr(void (*)()), "");
+
+ static_assert(!__is_nullptr(void), "");
+ static_assert(!__is_nullptr(cvoid), "");
+ static_assert(!__is_nullptr(cvoid), "");
+ static_assert(!__is_nullptr(char), "");
+ static_assert(!__is_nullptr(int), "");
+ static_assert(!__is_nullptr(int), "");
+ static_assert(!__is_nullptr(ClassType), "");
+ static_assert(!__is_nullptr(Derives), "");
+ static_assert(!__is_nullptr(Enum), "");
+ static_assert(!__is_nullptr(IntArNB), "");
+ static_assert(!__is_nullptr(Union), "");
+ static_assert(!__is_nullptr(UnionAr), "");
+ static_assert(!__is_nullptr(StructWithMembers), "");
+ static_assert(!__is_nullptr(int StructWithMembers::*), "");
+ static_assert(!__is_nullptr(void(StructWithMembers::*)()), "");
+}
+
void is_member_object_pointer()
{
StructWithMembers x;
@@ -3299,7 +3404,6 @@ void check_remove_cvref() {
}
template <class T> using decay_t = __decay(T);
-template <class T> struct dne;
void check_decay() {
static_assert(__is_same(decay_t<void>, void), "");
@@ -3359,6 +3463,8 @@ struct CheckAbominableFunction<M S::*> {
static_assert(__is_same(remove_cvref_t<M>, M), "");
static_assert(__is_same(remove_pointer_t<M>, M), "");
static_assert(__is_same(remove_reference_t<M>, M), "");
+
+ static_assert(!__is_referenceable(M), "");
}
};
More information about the cfe-commits
mailing list