diff --git a/clang/docs/LanguageExtensions.rst b/clang/docs/LanguageExtensions.rst --- a/clang/docs/LanguageExtensions.rst +++ b/clang/docs/LanguageExtensions.rst @@ -1392,6 +1392,7 @@ * ``__is_array`` (C++, Embarcadero) * ``__is_assignable`` (C++, MSVC 2015) * ``__is_base_of`` (C++, GNU, Microsoft, Embarcadero) +* ``__is_bounded_array`` (C++, GNU, Microsoft, Embarcadero) * ``__is_class`` (C++, GNU, Microsoft, Embarcadero) * ``__is_complete_type(type)`` (Embarcadero): Return ``true`` if ``type`` is a complete type. @@ -1454,6 +1455,7 @@ functionally equivalent to copying the underlying bytes and then dropping the source object on the floor. This is true of trivial types and types which were made trivially relocatable via the ``clang::trivial_abi`` attribute. +* ``__is_unbounded_array`` (C++, GNU, Microsoft, Embarcadero) * ``__is_union`` (C++, GNU, Microsoft, Embarcadero) * ``__is_unsigned`` (C++, Embarcadero): Returns false for enumeration types. Note, before Clang 13, returned true for @@ -4245,7 +4247,7 @@ #pragma clang attribute pop -A single push directive can contain multiple attributes, however, +A single push directive can contain multiple attributes, however, only one syntax style can be used within a single directive: .. code-block:: c++ @@ -4255,7 +4257,7 @@ void function1(); // The function now has the [[noreturn]] and [[noinline]] attributes #pragma clang attribute pop - + #pragma clang attribute push (__attribute((noreturn, noinline)), apply_to = function) void function2(); // The function now has the __attribute((noreturn)) and __attribute((noinline)) attributes diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -147,7 +147,7 @@ "variable length array folded to constant array as an extension">, InGroup; def err_vla_unsupported : Error< - "variable length arrays are not supported for the current target">; + "variable length arrays are not supported for %select{the current target|'%1'}0">; def note_vla_unsupported : Note< "variable length arrays are not supported for the current target">; 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 @@ -518,6 +518,8 @@ // Clang-only C++ Type Traits 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_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 @@ -1579,6 +1579,7 @@ tok::kw___is_array, tok::kw___is_assignable, tok::kw___is_base_of, + tok::kw___is_bounded_array, tok::kw___is_class, tok::kw___is_complete_type, tok::kw___is_compound, @@ -1620,6 +1621,7 @@ tok::kw___is_trivially_assignable, tok::kw___is_trivially_constructible, tok::kw___is_trivially_copyable, + tok::kw___is_unbounded_array, tok::kw___is_union, tok::kw___is_unsigned, tok::kw___is_void, 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,6 +1067,7 @@ 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_class); REVERTIBLE_TYPE_TRAIT(__is_complete_type); @@ -1109,6 +1110,7 @@ REVERTIBLE_TYPE_TRAIT(__is_trivially_assignable); REVERTIBLE_TYPE_TRAIT(__is_trivially_constructible); REVERTIBLE_TYPE_TRAIT(__is_trivially_copyable); + REVERTIBLE_TYPE_TRAIT(__is_unbounded_array); REVERTIBLE_TYPE_TRAIT(__is_union); REVERTIBLE_TYPE_TRAIT(__is_unsigned); REVERTIBLE_TYPE_TRAIT(__is_void); 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 @@ -21,11 +21,13 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Basic/TokenKinds.h" #include "clang/Basic/TypeTraits.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" @@ -4756,6 +4758,7 @@ case UTT_IsIntegral: case UTT_IsFloatingPoint: case UTT_IsArray: + case UTT_IsBoundedArray: case UTT_IsPointer: case UTT_IsLvalueReference: case UTT_IsRvalueReference: @@ -4782,6 +4785,7 @@ case UTT_IsConst: case UTT_IsVolatile: case UTT_IsSigned: + case UTT_IsUnboundedArray: case UTT_IsUnsigned: // This type trait always returns false, checking the type is moot. @@ -4901,6 +4905,22 @@ return T->isFloatingType(); case UTT_IsArray: return T->isArrayType(); + case UTT_IsBoundedArray: + if (!T->isVariableArrayType()) { + return T->isArrayType() && !T->isIncompleteArrayType(); + } + + Self.Diag(KeyLoc, diag::err_vla_unsupported) + << 1 << tok::kw___is_bounded_array; + return false; + case UTT_IsUnboundedArray: + if (!T->isVariableArrayType()) { + return T->isIncompleteArrayType(); + } + + Self.Diag(KeyLoc, diag::err_vla_unsupported) + << 1 << tok::kw___is_unbounded_array; + return false; case UTT_IsPointer: return T->isAnyPointerType(); case UTT_IsLvalueReference: diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -2627,12 +2627,10 @@ if (T->isVariableArrayType() && !Context.getTargetInfo().isVLASupported()) { // CUDA device code and some other targets don't support VLAs. - targetDiag(Loc, (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) - ? diag::err_cuda_vla - : diag::err_vla_unsupported) - << ((getLangOpts().CUDA && getLangOpts().CUDAIsDevice) - ? CurrentCUDATarget() - : CFT_InvalidTarget); + bool IsCUDADevice = (getLangOpts().CUDA && getLangOpts().CUDAIsDevice); + targetDiag(Loc, + IsCUDADevice ? diag::err_cuda_vla : diag::err_vla_unsupported) + << (IsCUDADevice ? CurrentCUDATarget() : 0); } // If this is not C99, diagnose array size modifiers on non-VLAs. 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 @@ -702,6 +702,70 @@ int t31[F(__is_array(cvoid*))]; } +void is_bounded_array(int n) { + static_assert(__is_bounded_array(IntAr), ""); + static_assert(!__is_bounded_array(IntArNB), ""); + static_assert(__is_bounded_array(UnionAr), ""); + + static_assert(!__is_bounded_array(void), ""); + static_assert(!__is_bounded_array(cvoid), ""); + static_assert(!__is_bounded_array(float), ""); + static_assert(!__is_bounded_array(double), ""); + static_assert(!__is_bounded_array(long double), ""); + static_assert(!__is_bounded_array(bool), ""); + static_assert(!__is_bounded_array(char), ""); + static_assert(!__is_bounded_array(signed char), ""); + static_assert(!__is_bounded_array(unsigned char), ""); + static_assert(!__is_bounded_array(wchar_t), ""); + static_assert(!__is_bounded_array(short), ""); + static_assert(!__is_bounded_array(unsigned short), ""); + static_assert(!__is_bounded_array(int), ""); + static_assert(!__is_bounded_array(unsigned int), ""); + static_assert(!__is_bounded_array(long), ""); + static_assert(!__is_bounded_array(unsigned long), ""); + static_assert(!__is_bounded_array(Union), ""); + static_assert(!__is_bounded_array(Derives), ""); + static_assert(!__is_bounded_array(ClassType), ""); + static_assert(!__is_bounded_array(Enum), ""); + static_assert(!__is_bounded_array(void *), ""); + static_assert(!__is_bounded_array(cvoid *), ""); + + int t32[n]; + (void)__is_bounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported for '__is_bounded_array'}} +} + +void is_unbounded_array(int n) { + static_assert(!__is_unbounded_array(IntAr), ""); + static_assert(__is_unbounded_array(IntArNB), ""); + static_assert(!__is_unbounded_array(UnionAr), ""); + + static_assert(!__is_unbounded_array(void), ""); + static_assert(!__is_unbounded_array(cvoid), ""); + static_assert(!__is_unbounded_array(float), ""); + static_assert(!__is_unbounded_array(double), ""); + static_assert(!__is_unbounded_array(long double), ""); + static_assert(!__is_unbounded_array(bool), ""); + static_assert(!__is_unbounded_array(char), ""); + static_assert(!__is_unbounded_array(signed char), ""); + static_assert(!__is_unbounded_array(unsigned char), ""); + static_assert(!__is_unbounded_array(wchar_t), ""); + static_assert(!__is_unbounded_array(short), ""); + static_assert(!__is_unbounded_array(unsigned short), ""); + static_assert(!__is_unbounded_array(int), ""); + static_assert(!__is_unbounded_array(unsigned int), ""); + static_assert(!__is_unbounded_array(long), ""); + static_assert(!__is_unbounded_array(unsigned long), ""); + static_assert(!__is_unbounded_array(Union), ""); + static_assert(!__is_unbounded_array(Derives), ""); + static_assert(!__is_unbounded_array(ClassType), ""); + static_assert(!__is_unbounded_array(Enum), ""); + static_assert(!__is_unbounded_array(void *), ""); + static_assert(!__is_unbounded_array(cvoid *), ""); + + int t32[n]; + (void)__is_unbounded_array(decltype(t32)); // expected-error{{variable length arrays are not supported for '__is_unbounded_array'}} +} + template void tmpl_func(T&) {} template struct type_wrapper {