Implement most of the remaining logic in __is_literal type trait. This
should now support all of the C++98 types, and all of the C++0x types Clang supports. llvm-svn: 130079
This commit is contained in:
parent
65fa1fd18e
commit
e71d0628f7
|
@ -1479,6 +1479,10 @@ public:
|
|||
bool isPure() const { return IsPure; }
|
||||
void setPure(bool P = true);
|
||||
|
||||
/// Whether this is a constexpr function or constexpr constructor.
|
||||
// FIXME: C++0x: Implement tracking of the constexpr specifier.
|
||||
bool isConstExpr() const { return false; }
|
||||
|
||||
/// Whether this templated function will be late parsed.
|
||||
bool isLateTemplateParsed() const { return IsLateTemplateParsed; }
|
||||
void setLateTemplateParsed(bool ILT = true) { IsLateTemplateParsed = ILT; }
|
||||
|
|
|
@ -316,6 +316,11 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// (or array thereof), each such class has a trivial constructor.
|
||||
bool HasTrivialConstructor : 1;
|
||||
|
||||
/// HasConstExprNonCopyMoveConstructor - True when this class has at least
|
||||
/// one constexpr constructor which is neither the copy nor move
|
||||
/// constructor.
|
||||
bool HasConstExprNonCopyMoveConstructor : 1;
|
||||
|
||||
/// HasTrivialCopyConstructor - True when this class has a trivial copy
|
||||
/// constructor.
|
||||
///
|
||||
|
@ -386,6 +391,10 @@ class CXXRecordDecl : public RecordDecl {
|
|||
/// type (or array thereof), each such class has a trivial destructor.
|
||||
bool HasTrivialDestructor : 1;
|
||||
|
||||
/// HasNonLiteralTypeFieldsOrBases - True when this class contains at least
|
||||
/// one non-static data member or base class of non literal type.
|
||||
bool HasNonLiteralTypeFieldsOrBases : 1;
|
||||
|
||||
/// ComputedVisibleConversions - True when visible conversion functions are
|
||||
/// already computed and are available.
|
||||
bool ComputedVisibleConversions : 1;
|
||||
|
@ -760,6 +769,12 @@ public:
|
|||
// (C++ [class.ctor]p5)
|
||||
bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
|
||||
|
||||
// hasConstExprNonCopyMoveConstructor - Whether this class has at least one
|
||||
// constexpr constructor other than the copy or move constructors
|
||||
bool hasConstExprNonCopyMoveConstructor() const {
|
||||
return data().HasConstExprNonCopyMoveConstructor;
|
||||
}
|
||||
|
||||
// hasTrivialCopyConstructor - Whether this class has a trivial copy
|
||||
// constructor (C++ [class.copy]p6, C++0x [class.copy]p13)
|
||||
bool hasTrivialCopyConstructor() const {
|
||||
|
@ -788,6 +803,12 @@ public:
|
|||
// (C++ [class.dtor]p3)
|
||||
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
|
||||
|
||||
// hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal type
|
||||
// non-static data member or base class.
|
||||
bool hasNonLiteralTypeFieldsOrBases() const {
|
||||
return data().HasNonLiteralTypeFieldsOrBases;
|
||||
}
|
||||
|
||||
// isTriviallyCopyable - Whether this class is considered trivially copyable
|
||||
// (C++0x [class]p5).
|
||||
bool isTriviallyCopyable() const;
|
||||
|
|
|
@ -32,9 +32,11 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
|||
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
||||
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
||||
Abstract(false), HasTrivialConstructor(true),
|
||||
HasConstExprNonCopyMoveConstructor(false),
|
||||
HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
|
||||
HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
|
||||
HasTrivialDestructor(true), ComputedVisibleConversions(false),
|
||||
HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false),
|
||||
ComputedVisibleConversions(false),
|
||||
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
|
||||
DeclaredCopyAssignment(false), DeclaredDestructor(false),
|
||||
NumBases(0), NumVBases(0), Bases(), VBases(),
|
||||
|
@ -118,6 +120,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
|||
if (BaseClassDecl->isPolymorphic())
|
||||
data().Polymorphic = true;
|
||||
|
||||
// Record if this base is the first non-literal field or base.
|
||||
if (!hasNonLiteralTypeFieldsOrBases() && !BaseType->isLiteralType())
|
||||
data().HasNonLiteralTypeFieldsOrBases = true;
|
||||
|
||||
// Now go through all virtual bases of this base and add them.
|
||||
for (CXXRecordDecl::base_class_iterator VBase =
|
||||
BaseClassDecl->vbases_begin(),
|
||||
|
@ -486,6 +492,12 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
|||
data().HasTrivialMoveConstructor = false;
|
||||
}
|
||||
}
|
||||
if (Constructor->isConstExpr() &&
|
||||
!Constructor->isCopyOrMoveConstructor()) {
|
||||
// Record if we see any constexpr constructors which are niether copy
|
||||
// nor move constructors.
|
||||
data().HasConstExprNonCopyMoveConstructor = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -621,6 +633,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
|||
if (T->isReferenceType())
|
||||
data().HasTrivialConstructor = false;
|
||||
|
||||
// Record if this field is the first non-literal field or base.
|
||||
if (!hasNonLiteralTypeFieldsOrBases() && !T->isLiteralType())
|
||||
data().HasNonLiteralTypeFieldsOrBases = true;
|
||||
|
||||
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
|
||||
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
|
||||
if (FieldRec->getDefinition()) {
|
||||
|
|
|
@ -874,32 +874,43 @@ bool Type::isLiteralType() const {
|
|||
|
||||
// C++0x [basic.types]p10:
|
||||
// A type is a literal type if it is:
|
||||
switch (CanonicalType->getTypeClass()) {
|
||||
// We're whitelisting
|
||||
default: return false;
|
||||
|
||||
// -- a scalar type
|
||||
case Builtin:
|
||||
case Complex:
|
||||
case Pointer:
|
||||
case MemberPointer:
|
||||
case Vector:
|
||||
case ExtVector:
|
||||
case ObjCObjectPointer:
|
||||
case Enum:
|
||||
return true;
|
||||
|
||||
// -- a class type with ...
|
||||
case Record:
|
||||
// FIXME: Do the tests
|
||||
return false;
|
||||
|
||||
// [...]
|
||||
// -- an array of literal type
|
||||
// Extension: variable arrays cannot be literal types, since they're
|
||||
// runtime-sized.
|
||||
case ConstantArray:
|
||||
return cast<ArrayType>(CanonicalType)->getElementType()->isLiteralType();
|
||||
if (isArrayType() && !isConstantArrayType())
|
||||
return false;
|
||||
const Type *BaseTy = getBaseElementTypeUnsafe();
|
||||
assert(BaseTy && "NULL element type");
|
||||
|
||||
// C++0x [basic.types]p10:
|
||||
// A type is a literal type if it is:
|
||||
// -- a scalar type; or
|
||||
if (BaseTy->isScalarType()) return true;
|
||||
// -- a reference type; or
|
||||
if (BaseTy->isReferenceType()) return true;
|
||||
// -- a class type that has all of the following properties:
|
||||
if (const RecordType *RT = BaseTy->getAs<RecordType>()) {
|
||||
const CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(RT->getDecl());
|
||||
// -- a trivial destructor,
|
||||
if (!ClassDecl->hasTrivialDestructor()) return false;
|
||||
// -- every constructor call and full-expression in the
|
||||
// brace-or-equal-initializers for non-static data members (if any)
|
||||
// is a constant expression,
|
||||
// FIXME: C++0x: Clang doesn't yet support non-static data member
|
||||
// declarations with initializers, or constexprs.
|
||||
// -- it is an aggregate type or has at least one constexpr
|
||||
// constructor or constructor template that is not a copy or move
|
||||
// constructor, and
|
||||
if (!ClassDecl->isAggregate() &&
|
||||
!ClassDecl->hasConstExprNonCopyMoveConstructor())
|
||||
return false;
|
||||
// -- all non-static data members and base classes of literal types
|
||||
if (ClassDecl->hasNonLiteralTypeFieldsOrBases()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Type::isTrivialType() const {
|
||||
|
|
|
@ -842,11 +842,13 @@ void ASTDeclReader::ReadCXXDefinitionData(
|
|||
Data.Polymorphic = Record[Idx++];
|
||||
Data.Abstract = Record[Idx++];
|
||||
Data.HasTrivialConstructor = Record[Idx++];
|
||||
Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
|
||||
Data.HasTrivialCopyConstructor = Record[Idx++];
|
||||
Data.HasTrivialMoveConstructor = Record[Idx++];
|
||||
Data.HasTrivialCopyAssignment = Record[Idx++];
|
||||
Data.HasTrivialMoveAssignment = Record[Idx++];
|
||||
Data.HasTrivialDestructor = Record[Idx++];
|
||||
Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
|
||||
Data.ComputedVisibleConversions = Record[Idx++];
|
||||
Data.DeclaredDefaultConstructor = Record[Idx++];
|
||||
Data.DeclaredCopyConstructor = Record[Idx++];
|
||||
|
|
|
@ -3794,11 +3794,13 @@ void ASTWriter::AddCXXDefinitionData(const CXXRecordDecl *D, RecordDataImpl &Rec
|
|||
Record.push_back(Data.Polymorphic);
|
||||
Record.push_back(Data.Abstract);
|
||||
Record.push_back(Data.HasTrivialConstructor);
|
||||
Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
|
||||
Record.push_back(Data.HasTrivialCopyConstructor);
|
||||
Record.push_back(Data.HasTrivialMoveConstructor);
|
||||
Record.push_back(Data.HasTrivialCopyAssignment);
|
||||
Record.push_back(Data.HasTrivialMoveAssignment);
|
||||
Record.push_back(Data.HasTrivialDestructor);
|
||||
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
|
||||
Record.push_back(Data.ComputedVisibleConversions);
|
||||
Record.push_back(Data.DeclaredDefaultConstructor);
|
||||
Record.push_back(Data.DeclaredCopyConstructor);
|
||||
|
|
|
@ -8,4 +8,60 @@ static_assert(__is_literal(E), "fail");
|
|||
static_assert(__is_literal(decltype(E1)), "fail");
|
||||
typedef int IAR[10];
|
||||
static_assert(__is_literal(IAR), "fail");
|
||||
// FIXME: Records
|
||||
|
||||
// C++0x [basic.types]p10:
|
||||
// A type is a literal type if it is:
|
||||
// [...]
|
||||
// -- a class type that has all of the following properties:
|
||||
// -- it has a trivial destructor
|
||||
// -- every constructor call and full-expression in the
|
||||
// brace-or-equal-initializers for non-static data members (if an) is
|
||||
// a constant expression,
|
||||
// -- it is an aggregate type or has at least one constexpr constructor
|
||||
// or constructor template that is not a copy or move constructor, and
|
||||
// -- it has all non-static data members and base classes of literal
|
||||
// types
|
||||
struct Empty {};
|
||||
struct LiteralType {
|
||||
int x;
|
||||
E e;
|
||||
IAR arr;
|
||||
Empty empty;
|
||||
int method();
|
||||
};
|
||||
struct HasDtor { ~HasDtor(); };
|
||||
|
||||
class NonAggregate { int x; };
|
||||
struct HasNonLiteralBase : NonAggregate {};
|
||||
struct HasNonLiteralMember { HasDtor x; };
|
||||
|
||||
static_assert(__is_literal(Empty), "fail");
|
||||
static_assert(__is_literal(LiteralType), "fail");
|
||||
static_assert(!__is_literal(HasDtor), "fail");
|
||||
static_assert(!__is_literal(NonAggregate), "fail");
|
||||
static_assert(!__is_literal(HasNonLiteralBase), "fail");
|
||||
static_assert(!__is_literal(HasNonLiteralMember), "fail");
|
||||
|
||||
// FIXME: Test constexpr constructors and non-static members with initializers
|
||||
// when Clang supports them:
|
||||
#if 0
|
||||
extern int f();
|
||||
struct HasNonConstExprMemInit {
|
||||
int x = f();
|
||||
constexpr HasNonConstExprMemInit(int y) {}
|
||||
};
|
||||
static_assert(!__is_literal(HasNonConstExprMemInit), "fail");
|
||||
|
||||
class HasConstExprCtor {
|
||||
int x;
|
||||
public:
|
||||
constexpr HasConstExprCtor(int x) : x(x) {}
|
||||
};
|
||||
template <typename T> class HasConstExprCtorTemplate {
|
||||
T x;
|
||||
public:
|
||||
template <typename U> constexpr HasConstExprCtorTemplate(U y) : x(y) {}
|
||||
};
|
||||
static_assert(__is_literal(HasConstExprCtor), "fail");
|
||||
static_assert(__is_literal(HasConstExprCtorTemplate), "fail");
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue