diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1428,16 +1428,25 @@ * ``__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 --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -520,6 +520,9 @@ 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 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -1605,15 +1605,18 @@ 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 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1067,8 +1067,8 @@ 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 @@ 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 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -4760,11 +4760,14 @@ 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 @@ 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 @@ 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 @@ 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 --- a/clang/test/SemaCXX/type-traits.cpp +++ b/clang/test/SemaCXX/type-traits.cpp @@ -345,11 +345,19 @@ } 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 @@ { 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(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 void tmpl_func(T&) {} template struct type_wrapper { @@ -998,6 +1067,42 @@ 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 @@ } template using decay_t = __decay(T); -template struct dne; void check_decay() { static_assert(__is_same(decay_t, void), ""); @@ -3359,6 +3463,8 @@ static_assert(__is_same(remove_cvref_t, M), ""); static_assert(__is_same(remove_pointer_t, M), ""); static_assert(__is_same(remove_reference_t, M), ""); + + static_assert(!__is_referenceable(M), ""); } };