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:
Chandler Carruth 2011-04-24 02:49:34 +00:00
parent 65fa1fd18e
commit e71d0628f7
7 changed files with 138 additions and 26 deletions

View File

@ -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; }

View File

@ -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;

View File

@ -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()) {

View File

@ -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 {

View File

@ -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++];

View File

@ -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);

View File

@ -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