Index: docs/LanguageExtensions.rst =================================================================== --- docs/LanguageExtensions.rst +++ docs/LanguageExtensions.rst @@ -993,6 +993,7 @@ * ``__has_trivial_destructor`` (GNU, Microsoft) * ``__has_virtual_destructor`` (GNU, Microsoft) * ``__is_abstract`` (GNU, Microsoft) +* ``__is_aggregate`` (GNU, Microsoft) * ``__is_base_of`` (GNU, Microsoft) * ``__is_class`` (GNU, Microsoft) * ``__is_convertible_to`` (Microsoft) Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -432,6 +432,7 @@ TYPE_TRAIT_1(__has_trivial_destructor, HasTrivialDestructor, KEYCXX) TYPE_TRAIT_1(__has_virtual_destructor, HasVirtualDestructor, KEYCXX) TYPE_TRAIT_1(__is_abstract, IsAbstract, KEYCXX) +TYPE_TRAIT_1(__is_aggregate, IsAggregate, KEYCXX) TYPE_TRAIT_2(__is_base_of, IsBaseOf, KEYCXX) TYPE_TRAIT_1(__is_class, IsClass, KEYCXX) TYPE_TRAIT_2(__is_convertible_to, IsConvertibleTo, KEYCXX) Index: include/clang/Basic/TypeTraits.h =================================================================== --- include/clang/Basic/TypeTraits.h +++ include/clang/Basic/TypeTraits.h @@ -31,6 +31,7 @@ UTT_HasTrivialDestructor, UTT_HasVirtualDestructor, UTT_IsAbstract, + UTT_IsAggregate, UTT_IsArithmetic, UTT_IsArray, UTT_IsClass, Index: lib/Parse/ParseDeclCXX.cpp =================================================================== --- lib/Parse/ParseDeclCXX.cpp +++ lib/Parse/ParseDeclCXX.cpp @@ -1406,6 +1406,7 @@ !Tok.isAnnotation() && Tok.getIdentifierInfo() && Tok.isOneOf(tok::kw___is_abstract, + tok::kw___is_aggregate, tok::kw___is_arithmetic, tok::kw___is_array, tok::kw___is_assignable, Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -676,6 +676,7 @@ /// '__is_union' /// /// [Clang] unary-type-trait: +/// '__is_aggregate' /// '__trivially_copyable' /// /// binary-type-trait: @@ -804,6 +805,7 @@ = RTT_JOIN(tok::kw_,Name) REVERTIBLE_TYPE_TRAIT(__is_abstract); + REVERTIBLE_TYPE_TRAIT(__is_aggregate); REVERTIBLE_TYPE_TRAIT(__is_arithmetic); REVERTIBLE_TYPE_TRAIT(__is_array); REVERTIBLE_TYPE_TRAIT(__is_assignable); Index: lib/Sema/SemaExprCXX.cpp =================================================================== --- lib/Sema/SemaExprCXX.cpp +++ lib/Sema/SemaExprCXX.cpp @@ -4055,6 +4055,7 @@ // C++0x [meta.unary.prop] Table 49 requires the following traits to be // applied to a complete type. + case UTT_IsAggregate: case UTT_IsTrivial: case UTT_IsTriviallyCopyable: case UTT_IsStandardLayout: @@ -4229,6 +4230,12 @@ if (const CXXRecordDecl *RD = T->getAsCXXRecordDecl()) return !RD->isUnion() && RD->isAbstract(); return false; + case UTT_IsAggregate: + // Report vector extensions and complex types as aggregates because they + // support aggregate initialization. GCC mirrors this behavior for vectors + // but not _Complex. + return T->isAggregateType() || T->isVectorType() || T->isExtVectorType() || + T->isAnyComplexType(); // __is_interface_class only returns true when CL is invoked in /CLR mode and // even then only when it is used with the 'interface struct ...' syntax // Clang doesn't support /CLR which makes this type trait moot. Index: test/PCH/cxx-traits.h =================================================================== --- test/PCH/cxx-traits.h +++ test/PCH/cxx-traits.h @@ -18,6 +18,7 @@ }; struct __is_abstract {}; // expected-warning {{made available}} +struct __is_aggregate {}; // expected-warning {{made available}} struct __is_arithmetic {}; // expected-warning {{made available}} struct __is_array {}; // expected-warning {{made available}} struct __is_assignable {}; // expected-warning {{made available}} Index: test/PCH/cxx-traits.cpp =================================================================== --- test/PCH/cxx-traits.cpp +++ test/PCH/cxx-traits.cpp @@ -16,6 +16,7 @@ // The built-ins should still work too: bool _is_abstract_result = __is_abstract(int); +bool _is_aggregate_result = __is_aggregate(int); bool _is_arithmetic_result = __is_arithmetic(int); bool _is_array_result = __is_array(int); bool _is_assignable_result = __is_assignable(int, int); Index: test/SemaCXX/type-traits.cpp =================================================================== --- test/SemaCXX/type-traits.cpp +++ test/SemaCXX/type-traits.cpp @@ -1,20 +1,28 @@ // RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++11 -fms-extensions -Wno-microsoft %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++14 -fms-extensions -Wno-microsoft %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -fsyntax-only -verify -std=gnu++1z -fms-extensions -Wno-microsoft %s + #define T(b) (b) ? 1 : -1 #define F(b) (b) ? -1 : 1 struct NonPOD { NonPOD(int); }; +typedef NonPOD NonPODAr[10]; +typedef NonPOD NonPODArNB[]; +typedef NonPOD NonPODArMB[10][2]; // PODs enum Enum { EV }; struct POD { Enum e; int i; float f; NonPOD* p; }; struct Empty {}; typedef Empty EmptyAr[10]; +typedef Empty EmptyArNB[]; +typedef Empty EmptyArMB[1][2]; typedef int Int; typedef Int IntAr[10]; typedef Int IntArNB[]; class Statics { static int priv; static NonPOD np; }; union EmptyUnion {}; -union IncompleteUnion; +union IncompleteUnion; // expected-note {{forward declaration of 'IncompleteUnion'}} union Union { int i; float f; }; struct HasFunc { void f (); }; struct HasOp { void operator *(); }; @@ -31,6 +39,9 @@ typedef int Vector __attribute__((vector_size(16))); typedef int VectorExt __attribute__((ext_vector_type(4))); +using ComplexFloat = _Complex float; +using ComplexInt = _Complex int; + // Not PODs typedef const void cvoid; struct Derives : POD {}; @@ -38,6 +49,10 @@ typedef Derives DerivesArNB[]; struct DerivesEmpty : Empty {}; struct HasCons { HasCons(int); }; +struct HasDefaultCons { HasDefaultCons() = default; }; +struct HasExplicitDefaultCons { explicit HasExplicitDefaultCons() = default; }; +struct HasInheritedCons : HasDefaultCons { using HasDefaultCons::HasDefaultCons; }; +struct HasNoInheritedCons : HasCons {}; struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); }; struct HasMoveAssign { HasMoveAssign operator =(const HasMoveAssign&&); }; struct HasNoThrowMoveAssign { @@ -48,8 +63,15 @@ const HasNoExceptNoThrowMoveAssign&&) noexcept; }; struct HasThrowMoveAssign { - HasThrowMoveAssign& operator=( - const HasThrowMoveAssign&&) throw(POD); }; + HasThrowMoveAssign& operator=(const HasThrowMoveAssign&&) +#if __cplusplus <= 201402L + throw(POD); +#else + noexcept(false); +#endif +}; + + struct HasNoExceptFalseMoveAssign { HasNoExceptFalseMoveAssign& operator=( const HasNoExceptFalseMoveAssign&&) noexcept(false); }; @@ -81,6 +103,7 @@ class HasPriv { int priv; }; class HasProt { protected: int prot; }; struct HasRef { int i; int& ref; HasRef() : i(0), ref(i) {} }; +struct HasRefAggregate { int i; int& ref; }; struct HasNonPOD { NonPOD np; }; struct HasVirt { virtual void Virt() {}; }; typedef NonPOD NonPODAr[10]; @@ -152,7 +175,12 @@ }; struct ThrowingDtor { - ~ThrowingDtor() throw(int); + ~ThrowingDtor() +#if __cplusplus <= 201402L + throw(int); +#else + noexcept(false); +#endif }; struct NoExceptDtor { @@ -163,6 +191,20 @@ ~NoThrowDtor() throw(); }; +struct ACompleteType {}; +struct AnIncompleteType; // expected-note 1+ {{forward declaration of 'AnIncompleteType'}} +typedef AnIncompleteType AnIncompleteTypeAr[42]; +typedef AnIncompleteType AnIncompleteTypeArNB[]; +typedef AnIncompleteType AnIncompleteTypeArMB[1][10]; + +struct HasInClassInit { + int x = 42; +}; + +struct HasPrivateBase : private ACompleteType {}; +struct HasProtectedBase : protected ACompleteType {}; +struct HasVirtBase : virtual ACompleteType {}; + void is_pod() { { int arr[T(__is_pod(int))]; } @@ -452,6 +494,83 @@ int t31[F(__is_floating_point(IntArNB))]; } +template +struct AggregateTemplate { + T value; +}; + +template +struct NonAggregateTemplate { + T value; + NonAggregateTemplate(); +}; + +void is_aggregate() +{ + constexpr bool TrueAfterCpp11 = __cplusplus > 201103L; + constexpr bool TrueAfterCpp14 = __cplusplus > 201402L; + + __is_aggregate(AnIncompleteType); // expected-error {{incomplete type}} + __is_aggregate(AnIncompleteTypeAr); // expected-error {{incomplete type}} + __is_aggregate(AnIncompleteTypeArNB); // expected-error {{incomplete type}} + __is_aggregate(AnIncompleteTypeArMB); // expected-error {{incomplete type}} + __is_aggregate(IncompleteUnion); // expected-error {{incomplete type}} + + static_assert(!__is_aggregate(NonPOD), ""); + static_assert(__is_aggregate(NonPODAr), ""); + static_assert(__is_aggregate(NonPODArNB), ""); + static_assert(__is_aggregate(NonPODArMB), ""); + + static_assert(!__is_aggregate(Enum), ""); + static_assert(__is_aggregate(POD), ""); + static_assert(__is_aggregate(Empty), ""); + static_assert(__is_aggregate(EmptyAr), ""); + static_assert(__is_aggregate(EmptyArNB), ""); + static_assert(__is_aggregate(EmptyArMB), ""); + static_assert(!__is_aggregate(void), ""); + static_assert(!__is_aggregate(const volatile void), ""); + static_assert(!__is_aggregate(int), ""); + static_assert(__is_aggregate(IntAr), ""); + static_assert(__is_aggregate(IntArNB), ""); + static_assert(__is_aggregate(EmptyUnion), ""); + static_assert(__is_aggregate(Union), ""); + static_assert(__is_aggregate(Statics), ""); + static_assert(__is_aggregate(HasFunc), ""); + static_assert(__is_aggregate(HasOp), ""); + static_assert(__is_aggregate(HasAssign), ""); + static_assert(__is_aggregate(HasAnonymousUnion), ""); + + static_assert(__is_aggregate(Derives) == TrueAfterCpp14, ""); + static_assert(__is_aggregate(DerivesAr), ""); + static_assert(__is_aggregate(DerivesArNB), ""); + static_assert(!__is_aggregate(HasCons), ""); + static_assert(__is_aggregate(HasDefaultCons), ""); + static_assert(!__is_aggregate(HasExplicitDefaultCons), ""); + static_assert(!__is_aggregate(HasInheritedCons), ""); + static_assert(__is_aggregate(HasNoInheritedCons) == TrueAfterCpp14, ""); + static_assert(__is_aggregate(HasCopyAssign), ""); + static_assert(!__is_aggregate(NonTrivialDefault), ""); + static_assert(__is_aggregate(HasDest), ""); + static_assert(!__is_aggregate(HasPriv), ""); + static_assert(!__is_aggregate(HasProt), ""); + static_assert(__is_aggregate(HasRefAggregate), ""); + static_assert(__is_aggregate(HasNonPOD), ""); + static_assert(!__is_aggregate(HasVirt), ""); + static_assert(__is_aggregate(VirtAr), ""); + static_assert(__is_aggregate(HasInClassInit) == TrueAfterCpp11, ""); + static_assert(!__is_aggregate(HasPrivateBase), ""); + static_assert(!__is_aggregate(HasProtectedBase), ""); + static_assert(!__is_aggregate(HasVirtBase), ""); + + static_assert(__is_aggregate(AggregateTemplate), ""); + static_assert(!__is_aggregate(NonAggregateTemplate), ""); + + static_assert(__is_aggregate(Vector), ""); // Extension supported by GCC and Clang + static_assert(__is_aggregate(VectorExt), ""); + static_assert(__is_aggregate(ComplexInt), ""); + static_assert(__is_aggregate(ComplexFloat), ""); +} + void is_arithmetic() { int t01[T(__is_arithmetic(float))]; @@ -481,9 +600,6 @@ int t31[F(__is_arithmetic(IntArNB))]; } -struct ACompleteType {}; -struct AnIncompleteType; - void is_complete_type() { int t01[T(__is_complete_type(float))];