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,16 @@ return T->isFloatingType(); case UTT_IsArray: return T->isArrayType(); + case UTT_IsBoundedArray: + if (T->isVariableArrayType()) + Self.Diag(KeyLoc, diag::err_vla_unsupported) + << 1 << tok::kw___is_bounded_array; + return T->isArrayType() && !T->isIncompleteArrayType(); + case UTT_IsUnboundedArray: + if (T->isVariableArrayType()) + Self.Diag(KeyLoc, diag::err_vla_unsupported) + << 1 << tok::kw___is_unbounded_array; + return T->isIncompleteArrayType(); 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 {