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; }
|
bool isPure() const { return IsPure; }
|
||||||
void setPure(bool P = true);
|
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.
|
/// Whether this templated function will be late parsed.
|
||||||
bool isLateTemplateParsed() const { return IsLateTemplateParsed; }
|
bool isLateTemplateParsed() const { return IsLateTemplateParsed; }
|
||||||
void setLateTemplateParsed(bool ILT = true) { IsLateTemplateParsed = ILT; }
|
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.
|
/// (or array thereof), each such class has a trivial constructor.
|
||||||
bool HasTrivialConstructor : 1;
|
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
|
/// HasTrivialCopyConstructor - True when this class has a trivial copy
|
||||||
/// constructor.
|
/// constructor.
|
||||||
///
|
///
|
||||||
|
@ -386,6 +391,10 @@ class CXXRecordDecl : public RecordDecl {
|
||||||
/// type (or array thereof), each such class has a trivial destructor.
|
/// type (or array thereof), each such class has a trivial destructor.
|
||||||
bool HasTrivialDestructor : 1;
|
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
|
/// ComputedVisibleConversions - True when visible conversion functions are
|
||||||
/// already computed and are available.
|
/// already computed and are available.
|
||||||
bool ComputedVisibleConversions : 1;
|
bool ComputedVisibleConversions : 1;
|
||||||
|
@ -760,6 +769,12 @@ public:
|
||||||
// (C++ [class.ctor]p5)
|
// (C++ [class.ctor]p5)
|
||||||
bool hasTrivialConstructor() const { return data().HasTrivialConstructor; }
|
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
|
// hasTrivialCopyConstructor - Whether this class has a trivial copy
|
||||||
// constructor (C++ [class.copy]p6, C++0x [class.copy]p13)
|
// constructor (C++ [class.copy]p6, C++0x [class.copy]p13)
|
||||||
bool hasTrivialCopyConstructor() const {
|
bool hasTrivialCopyConstructor() const {
|
||||||
|
@ -788,6 +803,12 @@ public:
|
||||||
// (C++ [class.dtor]p3)
|
// (C++ [class.dtor]p3)
|
||||||
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
|
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
|
// isTriviallyCopyable - Whether this class is considered trivially copyable
|
||||||
// (C++0x [class]p5).
|
// (C++0x [class]p5).
|
||||||
bool isTriviallyCopyable() const;
|
bool isTriviallyCopyable() const;
|
||||||
|
|
|
@ -32,9 +32,11 @@ CXXRecordDecl::DefinitionData::DefinitionData(CXXRecordDecl *D)
|
||||||
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false),
|
||||||
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
Aggregate(true), PlainOldData(true), Empty(true), Polymorphic(false),
|
||||||
Abstract(false), HasTrivialConstructor(true),
|
Abstract(false), HasTrivialConstructor(true),
|
||||||
|
HasConstExprNonCopyMoveConstructor(false),
|
||||||
HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
|
HasTrivialCopyConstructor(true), HasTrivialMoveConstructor(true),
|
||||||
HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
|
HasTrivialCopyAssignment(true), HasTrivialMoveAssignment(true),
|
||||||
HasTrivialDestructor(true), ComputedVisibleConversions(false),
|
HasTrivialDestructor(true), HasNonLiteralTypeFieldsOrBases(false),
|
||||||
|
ComputedVisibleConversions(false),
|
||||||
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
|
DeclaredDefaultConstructor(false), DeclaredCopyConstructor(false),
|
||||||
DeclaredCopyAssignment(false), DeclaredDestructor(false),
|
DeclaredCopyAssignment(false), DeclaredDestructor(false),
|
||||||
NumBases(0), NumVBases(0), Bases(), VBases(),
|
NumBases(0), NumVBases(0), Bases(), VBases(),
|
||||||
|
@ -118,6 +120,10 @@ CXXRecordDecl::setBases(CXXBaseSpecifier const * const *Bases,
|
||||||
if (BaseClassDecl->isPolymorphic())
|
if (BaseClassDecl->isPolymorphic())
|
||||||
data().Polymorphic = true;
|
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.
|
// Now go through all virtual bases of this base and add them.
|
||||||
for (CXXRecordDecl::base_class_iterator VBase =
|
for (CXXRecordDecl::base_class_iterator VBase =
|
||||||
BaseClassDecl->vbases_begin(),
|
BaseClassDecl->vbases_begin(),
|
||||||
|
@ -486,6 +492,12 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||||
data().HasTrivialMoveConstructor = false;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -621,6 +633,10 @@ void CXXRecordDecl::addedMember(Decl *D) {
|
||||||
if (T->isReferenceType())
|
if (T->isReferenceType())
|
||||||
data().HasTrivialConstructor = false;
|
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>()) {
|
if (const RecordType *RecordTy = T->getAs<RecordType>()) {
|
||||||
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
|
CXXRecordDecl* FieldRec = cast<CXXRecordDecl>(RecordTy->getDecl());
|
||||||
if (FieldRec->getDefinition()) {
|
if (FieldRec->getDefinition()) {
|
||||||
|
|
|
@ -874,32 +874,43 @@ bool Type::isLiteralType() const {
|
||||||
|
|
||||||
// C++0x [basic.types]p10:
|
// C++0x [basic.types]p10:
|
||||||
// A type is a literal type if it is:
|
// 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
|
// -- an array of literal type
|
||||||
// Extension: variable arrays cannot be literal types, since they're
|
// Extension: variable arrays cannot be literal types, since they're
|
||||||
// runtime-sized.
|
// runtime-sized.
|
||||||
case ConstantArray:
|
if (isArrayType() && !isConstantArrayType())
|
||||||
return cast<ArrayType>(CanonicalType)->getElementType()->isLiteralType();
|
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 {
|
bool Type::isTrivialType() const {
|
||||||
|
|
|
@ -842,11 +842,13 @@ void ASTDeclReader::ReadCXXDefinitionData(
|
||||||
Data.Polymorphic = Record[Idx++];
|
Data.Polymorphic = Record[Idx++];
|
||||||
Data.Abstract = Record[Idx++];
|
Data.Abstract = Record[Idx++];
|
||||||
Data.HasTrivialConstructor = Record[Idx++];
|
Data.HasTrivialConstructor = Record[Idx++];
|
||||||
|
Data.HasConstExprNonCopyMoveConstructor = Record[Idx++];
|
||||||
Data.HasTrivialCopyConstructor = Record[Idx++];
|
Data.HasTrivialCopyConstructor = Record[Idx++];
|
||||||
Data.HasTrivialMoveConstructor = Record[Idx++];
|
Data.HasTrivialMoveConstructor = Record[Idx++];
|
||||||
Data.HasTrivialCopyAssignment = Record[Idx++];
|
Data.HasTrivialCopyAssignment = Record[Idx++];
|
||||||
Data.HasTrivialMoveAssignment = Record[Idx++];
|
Data.HasTrivialMoveAssignment = Record[Idx++];
|
||||||
Data.HasTrivialDestructor = Record[Idx++];
|
Data.HasTrivialDestructor = Record[Idx++];
|
||||||
|
Data.HasNonLiteralTypeFieldsOrBases = Record[Idx++];
|
||||||
Data.ComputedVisibleConversions = Record[Idx++];
|
Data.ComputedVisibleConversions = Record[Idx++];
|
||||||
Data.DeclaredDefaultConstructor = Record[Idx++];
|
Data.DeclaredDefaultConstructor = Record[Idx++];
|
||||||
Data.DeclaredCopyConstructor = 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.Polymorphic);
|
||||||
Record.push_back(Data.Abstract);
|
Record.push_back(Data.Abstract);
|
||||||
Record.push_back(Data.HasTrivialConstructor);
|
Record.push_back(Data.HasTrivialConstructor);
|
||||||
|
Record.push_back(Data.HasConstExprNonCopyMoveConstructor);
|
||||||
Record.push_back(Data.HasTrivialCopyConstructor);
|
Record.push_back(Data.HasTrivialCopyConstructor);
|
||||||
Record.push_back(Data.HasTrivialMoveConstructor);
|
Record.push_back(Data.HasTrivialMoveConstructor);
|
||||||
Record.push_back(Data.HasTrivialCopyAssignment);
|
Record.push_back(Data.HasTrivialCopyAssignment);
|
||||||
Record.push_back(Data.HasTrivialMoveAssignment);
|
Record.push_back(Data.HasTrivialMoveAssignment);
|
||||||
Record.push_back(Data.HasTrivialDestructor);
|
Record.push_back(Data.HasTrivialDestructor);
|
||||||
|
Record.push_back(Data.HasNonLiteralTypeFieldsOrBases);
|
||||||
Record.push_back(Data.ComputedVisibleConversions);
|
Record.push_back(Data.ComputedVisibleConversions);
|
||||||
Record.push_back(Data.DeclaredDefaultConstructor);
|
Record.push_back(Data.DeclaredDefaultConstructor);
|
||||||
Record.push_back(Data.DeclaredCopyConstructor);
|
Record.push_back(Data.DeclaredCopyConstructor);
|
||||||
|
|
|
@ -8,4 +8,60 @@ static_assert(__is_literal(E), "fail");
|
||||||
static_assert(__is_literal(decltype(E1)), "fail");
|
static_assert(__is_literal(decltype(E1)), "fail");
|
||||||
typedef int IAR[10];
|
typedef int IAR[10];
|
||||||
static_assert(__is_literal(IAR), "fail");
|
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