[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