From d4025eed6397919608278caa0e91fe5d5568d070 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Wed, 12 Apr 2017 22:12:15 +0000 Subject: [PATCH] [Sema] Add __is_aggregate type-trait Summary: [LWG 2911](http://cplusplus.github.io/LWG/lwg-defects.html#2911) adds `std::is_aggregate` to the library, which requires a new builtin trait. This patch implements `__is_aggregate`. Reviewers: rsmith, majnemer, aaron.ballman Reviewed By: aaron.ballman Subscribers: STL_MSFT, cfe-commits Differential Revision: https://reviews.llvm.org/D31513 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@300116 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LanguageExtensions.rst | 1 + include/clang/Basic/TokenKinds.def | 1 + include/clang/Basic/TypeTraits.h | 1 + lib/Parse/ParseDeclCXX.cpp | 1 + lib/Parse/ParseExpr.cpp | 2 + lib/Sema/SemaExprCXX.cpp | 7 ++ test/PCH/cxx-traits.cpp | 1 + test/PCH/cxx-traits.h | 1 + test/SemaCXX/type-traits.cpp | 130 +++++++++++++++++++++++++++-- 9 files changed, 138 insertions(+), 7 deletions(-) diff --git a/docs/LanguageExtensions.rst b/docs/LanguageExtensions.rst index 29e971c1bb..a8fb4623b6 100644 --- a/docs/LanguageExtensions.rst +++ b/docs/LanguageExtensions.rst @@ -993,6 +993,7 @@ The following type trait primitives are supported by Clang: * ``__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) diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 04399337e6..48e0c33f0e 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -432,6 +432,7 @@ TYPE_TRAIT_1(__has_trivial_move_constructor, HasTrivialMoveConstructor, KEYCXX) 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) diff --git a/include/clang/Basic/TypeTraits.h b/include/clang/Basic/TypeTraits.h index 730ecba3d4..ffe6255900 100644 --- a/include/clang/Basic/TypeTraits.h +++ b/include/clang/Basic/TypeTraits.h @@ -31,6 +31,7 @@ namespace clang { UTT_HasTrivialDestructor, UTT_HasVirtualDestructor, UTT_IsAbstract, + UTT_IsAggregate, UTT_IsArithmetic, UTT_IsArray, UTT_IsClass, diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index ca60d3ff29..b25152a318 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -1406,6 +1406,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, !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, diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 6a81da753b..ad45ab114f 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -676,6 +676,7 @@ class CastExpressionIdValidator : public CorrectionCandidateCallback { /// '__is_union' /// /// [Clang] unary-type-trait: +/// '__is_aggregate' /// '__trivially_copyable' /// /// binary-type-trait: @@ -804,6 +805,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, = 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); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 1e88384e5a..485d012b6e 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4057,6 +4057,7 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, // 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: @@ -4231,6 +4232,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, 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. diff --git a/test/PCH/cxx-traits.cpp b/test/PCH/cxx-traits.cpp index b0f1d9d2c3..01b9e9302d 100644 --- a/test/PCH/cxx-traits.cpp +++ b/test/PCH/cxx-traits.cpp @@ -16,6 +16,7 @@ bool copy_construct_int = n::is_trivially_constructible::value; // 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); diff --git a/test/PCH/cxx-traits.h b/test/PCH/cxx-traits.h index 1d7d40450f..0a4bd09c36 100644 --- a/test/PCH/cxx-traits.h +++ b/test/PCH/cxx-traits.h @@ -18,6 +18,7 @@ struct is_trivially_constructible { }; 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}} diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index c53b02774a..9da59b93c5 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/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 @@ struct HasAnonymousUnion { 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 DerivesAr[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 @@ struct HasNoExceptNoThrowMoveAssign { 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 @@ struct HasDest { ~HasDest(); }; 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 VariadicCtor { }; struct ThrowingDtor { - ~ThrowingDtor() throw(int); + ~ThrowingDtor() +#if __cplusplus <= 201402L + throw(int); +#else + noexcept(false); +#endif }; struct NoExceptDtor { @@ -163,6 +191,20 @@ struct NoThrowDtor { ~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 @@ void is_floating_point() 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 @@ void is_arithmetic() int t31[F(__is_arithmetic(IntArNB))]; } -struct ACompleteType {}; -struct AnIncompleteType; - void is_complete_type() { int t01[T(__is_complete_type(float))]; -- 2.40.0