diff options
-rw-r--r-- | include/clang/AST/DeclCXX.h | 17 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 34 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaTemplateInstantiateDecl.cpp | 1 | ||||
-rw-r--r-- | test/SemaCXX/type-traits.cpp | 64 |
8 files changed, 118 insertions, 22 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 2d0edc8418..2c20d585c5 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -290,6 +290,12 @@ class CXXRecordDecl : public RecordDecl { /// PlainOldData - True when this class is a POD-type. bool PlainOldData : 1; + /// Empty - true when this class is empty for traits purposes, i.e. has no + /// data members other than 0-width bit-fields, has no virtual function/base, + /// and doesn't inherit from a non-empty class. Doesn't take union-ness into + /// account. + bool Empty : 1; + /// Polymorphic - True when this class is polymorphic, i.e. has at least one /// virtual member or derives from a polymorphic class. bool Polymorphic : 1; @@ -297,7 +303,7 @@ class CXXRecordDecl : public RecordDecl { /// Abstract - True when this class is abstract, i.e. has at least one /// pure virtual function, (that can come from a base class). bool Abstract : 1; - + /// HasTrivialConstructor - True when this class has a trivial constructor. /// /// C++ [class.ctor]p5. A constructor is trivial if it is an @@ -570,6 +576,15 @@ public: /// setPOD - Set whether this class is a POD-type (C++ [class]p4). void setPOD(bool POD) { PlainOldData = POD; } + /// isEmpty - Whether this class is empty (C++0x [meta.unary.prop]), which + /// means it has a virtual function, virtual base, data member (other than + /// 0-width bit-field) or inherits from a non-empty class. Does NOT include + /// a check for union-ness. + bool isEmpty() const { return Empty; } + + /// Set whether this class is empty (C++0x [meta.unary.prop]) + void setEmpty(bool Emp) { Empty = Emp; } + /// isPolymorphic - Whether this class is polymorphic (C++ [class.virtual]), /// which means that the class contains or inherits a virtual function. bool isPolymorphic() const { return Polymorphic; } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 454dc14b6c..006f69890a 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -223,6 +223,12 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { if (const RecordType *RT = QueriedType->getAs<RecordType>()) return cast<CXXRecordDecl>(RT->getDecl())->isAbstract(); return false; + case UTT_IsEmpty: + if (const RecordType *Record = QueriedType->getAs<RecordType>()) { + return !Record->getDecl()->isUnion() + && cast<CXXRecordDecl>(Record->getDecl())->isEmpty(); + } + return false; case UTT_HasTrivialConstructor: // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: // If __is_pod (type) is true then the trait is true, else if type is diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 6e7deef95d..57604a8dc9 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -815,6 +815,7 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_class: case tok::kw___is_enum: case tok::kw___is_union: + case tok::kw___is_empty: case tok::kw___is_polymorphic: case tok::kw___is_abstract: case tok::kw___has_trivial_constructor: diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index ddd6d7b571..98fa698a8d 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3324,8 +3324,10 @@ public: /// VerifyBitField - verifies that a bit field expression is an ICE and has /// the correct width, and that the field type is valid. /// Returns false on success. + /// Can optionally return whether the bit-field is of width 0 bool VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, - QualType FieldTy, const Expr *BitWidth); + QualType FieldTy, const Expr *BitWidth, + bool *ZeroWidth = 0); //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d75f322aa5..bf1dd91f74 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2536,6 +2536,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, CXXRecordDecl *CurClass = cast<CXXRecordDecl>(DC); CurClass->setAggregate(false); CurClass->setPOD(false); + CurClass->setEmpty(false); CurClass->setPolymorphic(true); CurClass->setHasTrivialConstructor(false); CurClass->setHasTrivialCopyConstructor(false); @@ -4331,8 +4332,12 @@ void Sema::ActOnTagFinishDefinition(Scope *S, DeclPtrTy TagD, // Note that FieldName may be null for anonymous bitfields. bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, - QualType FieldTy, const Expr *BitWidth) { - + QualType FieldTy, const Expr *BitWidth, + bool *ZeroWidth) { + // Default to true; that shouldn't confuse checks for emptiness + if (ZeroWidth) + *ZeroWidth = true; + // C99 6.7.2.1p4 - verify the field type. // C++ 9.6p3: A bit-field shall have integral or enumeration type. if (!FieldTy->isDependentType() && !FieldTy->isIntegralType()) { @@ -4355,6 +4360,9 @@ bool Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, if (VerifyIntegerConstantExpression(BitWidth, &Value)) return true; + if (Value != 0 && ZeroWidth) + *ZeroWidth = false; + // Zero-width bitfield is ok for anonymous field. if (Value == 0 && FieldName) return Diag(FieldLoc, diag::err_bitfield_has_zero_width) << FieldName; @@ -4490,11 +4498,13 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, AbstractFieldType)) InvalidDecl = true; + bool ZeroWidth = false; // If this is declared as a bit-field, check the bit-field. - if (BitWidth && VerifyBitField(Loc, II, T, BitWidth)) { + if (BitWidth && VerifyBitField(Loc, II, T, BitWidth, &ZeroWidth)) { InvalidDecl = true; DeleteExpr(BitWidth); BitWidth = 0; + ZeroWidth = false; } FieldDecl *NewFD = FieldDecl::Create(Context, Record, Loc, II, T, BitWidth, @@ -4511,17 +4521,24 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, if (getLangOptions().CPlusPlus) { QualType EltTy = Context.getBaseElementType(T); + CXXRecordDecl* CXXRecord = cast<CXXRecordDecl>(Record); + + if (!T->isPODType()) + CXXRecord->setPOD(false); + if (!ZeroWidth) + CXXRecord->setEmpty(false); + if (const RecordType *RT = EltTy->getAs<RecordType>()) { CXXRecordDecl* RDecl = cast<CXXRecordDecl>(RT->getDecl()); if (!RDecl->hasTrivialConstructor()) - cast<CXXRecordDecl>(Record)->setHasTrivialConstructor(false); + CXXRecord->setHasTrivialConstructor(false); if (!RDecl->hasTrivialCopyConstructor()) - cast<CXXRecordDecl>(Record)->setHasTrivialCopyConstructor(false); + CXXRecord->setHasTrivialCopyConstructor(false); if (!RDecl->hasTrivialCopyAssignment()) - cast<CXXRecordDecl>(Record)->setHasTrivialCopyAssignment(false); + CXXRecord->setHasTrivialCopyAssignment(false); if (!RDecl->hasTrivialDestructor()) - cast<CXXRecordDecl>(Record)->setHasTrivialDestructor(false); + CXXRecord->setHasTrivialDestructor(false); // C++ 9.5p1: An object of a class with a non-trivial // constructor, a non-trivial copy constructor, a non-trivial @@ -4557,9 +4574,6 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } } - if (getLangOptions().CPlusPlus && !T->isPODType()) - cast<CXXRecordDecl>(Record)->setPOD(false); - // FIXME: We need to pass in the attributes given an AST // representation, not a parser representation. if (D) diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index a8afa4f1de..889d5c91ca 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -383,12 +383,16 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, SpecifierRange)) return 0; - // If the base class is polymorphic, the new one is, too. + // If the base class is polymorphic or isn't empty, the new one is/isn't, too. RecordDecl *BaseDecl = BaseType->getAs<RecordType>()->getDecl(); assert(BaseDecl && "Record type has no declaration"); BaseDecl = BaseDecl->getDefinition(Context); assert(BaseDecl && "Base type is not incomplete, but has no definition"); - if (cast<CXXRecordDecl>(BaseDecl)->isPolymorphic()) + CXXRecordDecl * CXXBaseDecl = cast<CXXRecordDecl>(BaseDecl); + assert(CXXBaseDecl && "Base type is not a C++ type"); + if (!CXXBaseDecl->isEmpty()) + Class->setEmpty(false); + if (CXXBaseDecl->isPolymorphic()) Class->setPolymorphic(true); // C++ [dcl.init.aggr]p1: @@ -409,6 +413,11 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, // A copy assignment operator is trivial if its class has no virtual // base classes. Class->setHasTrivialCopyAssignment(false); + + // C++0x [meta.unary.prop] is_empty: + // T is a class type, but not a union type, with ... no virtual base + // classes + Class->setEmpty(false); } else { // C++ [class.ctor]p5: // A constructor is trivial if all the direct base classes of its diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index 3212923194..b216ec18bf 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -749,6 +749,7 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, New->setVirtualAsWritten(true); Record->setAggregate(false); Record->setPOD(false); + Record->setEmpty(false); Record->setPolymorphic(true); } if (Tmpl->isPure()) { diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 758dfe71e5..340c0ae489 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -7,14 +7,23 @@ struct NonPOD { NonPOD(int); }; // PODs enum Enum { EV }; struct POD { Enum e; int i; float f; NonPOD* p; }; +struct Empty {}; +typedef Empty EmptyAr[10]; typedef int Int; typedef Int IntAr[10]; class Statics { static int priv; static NonPOD np; }; +union EmptyUnion {}; +union Union { int i; float f; }; +struct HasFunc { void f (); }; +struct HasOp { void operator *(); }; +struct HasConv { operator int(); }; +struct HasAssign { void operator =(int); }; // Not PODs struct Derives : POD {}; +struct DerivesEmpty : Empty {}; struct HasCons { HasCons(int); }; -struct HasAssign { HasAssign operator =(const HasAssign&); }; +struct HasCopyAssign { HasCopyAssign operator =(const HasCopyAssign&); }; struct HasDest { ~HasDest(); }; class HasPriv { int priv; }; class HasProt { protected: int prot; }; @@ -23,6 +32,7 @@ struct HasNonPOD { NonPOD np; }; struct HasVirt { virtual void Virt() {}; }; typedef Derives NonPODAr[10]; typedef HasVirt VirtAr[10]; +union NonPODUnion { int i; Derives n; }; void is_pod() { @@ -32,10 +42,17 @@ void is_pod() int t04[T(__is_pod(Int))]; int t05[T(__is_pod(IntAr))]; int t06[T(__is_pod(Statics))]; + int t07[T(__is_pod(Empty))]; + int t08[T(__is_pod(EmptyUnion))]; + int t09[T(__is_pod(Union))]; + int t10[T(__is_pod(HasFunc))]; + int t11[T(__is_pod(HasOp))]; + int t12[T(__is_pod(HasConv))]; + int t13[T(__is_pod(HasAssign))]; int t21[F(__is_pod(Derives))]; int t22[F(__is_pod(HasCons))]; - int t23[F(__is_pod(HasAssign))]; + int t23[F(__is_pod(HasCopyAssign))]; int t24[F(__is_pod(HasDest))]; int t25[F(__is_pod(HasPriv))]; int t26[F(__is_pod(HasProt))]; @@ -43,9 +60,40 @@ void is_pod() int t28[F(__is_pod(HasNonPOD))]; int t29[F(__is_pod(HasVirt))]; int t30[F(__is_pod(NonPODAr))]; + int t31[F(__is_pod(DerivesEmpty))]; + // int t32[F(__is_pod(NonPODUnion))]; +} + +typedef Empty EmptyAr[10]; +struct Bit0 { int : 0; }; +struct Bit0Cons { int : 0; Bit0Cons(); }; +struct BitOnly { int x : 3; }; +//struct DerivesVirt : virtual POD {}; + +void is_empty() +{ + int t01[T(__is_empty(Empty))]; + int t02[T(__is_empty(DerivesEmpty))]; + int t03[T(__is_empty(HasCons))]; + int t04[T(__is_empty(HasCopyAssign))]; + int t05[T(__is_empty(HasDest))]; + int t06[T(__is_empty(HasFunc))]; + int t07[T(__is_empty(HasOp))]; + int t08[T(__is_empty(HasConv))]; + int t09[T(__is_empty(HasAssign))]; + int t10[T(__is_empty(Bit0))]; + int t11[T(__is_empty(Bit0Cons))]; + + int t21[F(__is_empty(Int))]; + int t22[F(__is_empty(POD))]; + int t23[F(__is_empty(EmptyUnion))]; + int t24[F(__is_empty(EmptyAr))]; + int t25[F(__is_empty(HasRef))]; + int t26[F(__is_empty(HasVirt))]; + int t27[F(__is_empty(BitOnly))]; +// int t27[F(__is_empty(DerivesVirt))]; } -union Union { int i; float f; }; typedef Derives ClassType; void is_class() @@ -93,7 +141,7 @@ void is_enum() int t17[F(__is_enum(ClassType))]; } -struct Polymorph { virtual void f(); }; +typedef HasVirt Polymorph; struct InheritPolymorph : Polymorph {}; void is_polymorphic() @@ -134,7 +182,7 @@ void has_trivial_default_constructor() { int t12[F(__has_trivial_constructor(HasRef))]; int t13[F(__has_trivial_constructor(HasCopy))]; int t14[F(__has_trivial_constructor(IntRef))]; - int t15[T(__has_trivial_constructor(HasAssign))]; + int t15[T(__has_trivial_constructor(HasCopyAssign))]; int t16[T(__has_trivial_constructor(const Int))]; int t17[T(__has_trivial_constructor(NonPODAr))]; int t18[F(__has_trivial_constructor(VirtAr))]; @@ -155,7 +203,7 @@ void has_trivial_copy_constructor() { int t12[T(__has_trivial_copy(HasRef))]; int t13[F(__has_trivial_copy(HasCopy))]; int t14[T(__has_trivial_copy(IntRef))]; - int t15[T(__has_trivial_copy(HasAssign))]; + int t15[T(__has_trivial_copy(HasCopyAssign))]; int t16[T(__has_trivial_copy(const Int))]; int t17[F(__has_trivial_copy(NonPODAr))]; int t18[F(__has_trivial_copy(VirtAr))]; @@ -176,7 +224,7 @@ void has_trivial_copy_assignment() { int t12[T(__has_trivial_assign(HasRef))]; int t13[T(__has_trivial_assign(HasCopy))]; int t14[F(__has_trivial_assign(IntRef))]; - int t15[F(__has_trivial_assign(HasAssign))]; + int t15[F(__has_trivial_assign(HasCopyAssign))]; int t16[F(__has_trivial_assign(const Int))]; int t17[F(__has_trivial_assign(NonPODAr))]; int t18[F(__has_trivial_assign(VirtAr))]; @@ -197,7 +245,7 @@ void has_trivial_destructor() { int t12[T(__has_trivial_destructor(HasRef))]; int t13[T(__has_trivial_destructor(HasCopy))]; int t14[T(__has_trivial_destructor(IntRef))]; - int t15[T(__has_trivial_destructor(HasAssign))]; + int t15[T(__has_trivial_destructor(HasCopyAssign))]; int t16[T(__has_trivial_destructor(const Int))]; int t17[T(__has_trivial_destructor(NonPODAr))]; int t18[T(__has_trivial_destructor(VirtAr))]; |