forked from OSchip/llvm-project
[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 llvm-svn: 300116
This commit is contained in:
parent
6eee3a3fca
commit
0736066b0b
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace clang {
|
|||
UTT_HasTrivialDestructor,
|
||||
UTT_HasVirtualDestructor,
|
||||
UTT_IsAbstract,
|
||||
UTT_IsAggregate,
|
||||
UTT_IsArithmetic,
|
||||
UTT_IsArray,
|
||||
UTT_IsClass,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -16,6 +16,7 @@ bool copy_construct_int = n::is_trivially_constructible<int, const int&>::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);
|
||||
|
|
|
@ -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}}
|
||||
|
|
|
@ -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 <class T>
|
||||
struct AggregateTemplate {
|
||||
T value;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
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<int>), "");
|
||||
static_assert(!__is_aggregate(NonAggregateTemplate<int>), "");
|
||||
|
||||
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))];
|
||||
|
|
Loading…
Reference in New Issue