From: Douglas Gregor Date: Thu, 23 Jul 2009 23:49:00 +0000 (+0000) Subject: This patch fixes the implementations of the __has_trivial_destructor X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5e03f9ea8174ae588c5e69ec6b5ef4c68f8fd766;p=clang This patch fixes the implementations of the __has_trivial_destructor and __has_trivial_constructor builtin pseudo-functions and additionally implements __has_trivial_copy and __has_trivial_assign, from John McCall! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76916 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/AST/ASTContext.h b/include/clang/AST/ASTContext.h index 67fcff0db4..6af58288bb 100644 --- a/include/clang/AST/ASTContext.h +++ b/include/clang/AST/ASTContext.h @@ -708,6 +708,10 @@ public: /// getBaseElementType - Returns the innermost element type of a variable /// length array type. For example, will return "int" for int[m][n] QualType getBaseElementType(const VariableArrayType *VAT); + + /// getBaseElementType - Returns the innermost element type of a type + /// (which needn't actually be an array type). + QualType getBaseElementType(QualType QT); /// getArrayDecayedType - Return the properly qualified result of decaying the /// specified array type to a pointer. This operation is non-trivial when diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 1767866017..460067d50b 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -913,7 +913,7 @@ public: QualType getQueriedType() const { return QueriedType; } - bool EvaluateTrait() const; + bool EvaluateTrait(ASTContext&) const; static bool classof(const Stmt *T) { return T->getStmtClass() == UnaryTypeTraitExprClass; diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 8500676d78..28f1c9d9d0 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -564,6 +564,39 @@ public: }; +/// QualifierSet - This class is used to collect qualifiers. +class QualifierSet { +public: + QualifierSet() : + CVRMask(0), AddressSpace(0), GCAttrType(QualType::GCNone) { + } + + /// Collect any qualifiers on the given type and return an + /// unqualified type. + const Type *strip(QualType QT) { + CVRMask |= QT.getCVRQualifiers(); + return strip(QT.getTypePtr()); + } + + /// Collect any qualifiers on the given type and return an + /// unqualified type. + const Type *strip(const Type* T); + + /// Apply the collected qualifiers to the given type. + QualType apply(QualType QT, ASTContext& C); + + /// Apply the collected qualifiers to the given type. + QualType apply(const Type* T, ASTContext& C) { + return apply(QualType(T, 0), C); + } + +private: + unsigned CVRMask; + unsigned AddressSpace; + QualType::GCAttrTypes GCAttrType; +}; + + /// BuiltinType - This class is used for builtin types like 'int'. Builtin /// types are always canonical and have a literal name field. class BuiltinType : public Type { diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index 727dc4ee3d..5572b7a3a0 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -2107,6 +2107,18 @@ QualType ASTContext::getArrayDecayedType(QualType Ty) { return PtrTy.getQualifiedType(PrettyArrayType->getIndexTypeQualifier()); } +QualType ASTContext::getBaseElementType(QualType QT) { + QualifierSet qualifiers; + while (true) { + const Type *UT = qualifiers.strip(QT); + if (const ArrayType *AT = getAsArrayType(QualType(UT,0))) { + QT = AT->getElementType(); + }else { + return qualifiers.apply(QT, *this); + } + } +} + QualType ASTContext::getBaseElementType(const VariableArrayType *VAT) { QualType ElemTy = VAT->getElementType(); diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 7b5a29028c..4d861be9fd 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -537,14 +537,11 @@ CXXDestructorDecl::computeBaseOrMembersToDestroy(ASTContext &C) { // non-static data members. for (CXXRecordDecl::field_iterator Field = ClassDecl->field_begin(), E = ClassDecl->field_end(); Field != E; ++Field) { - QualType FieldType = C.getCanonicalType((*Field)->getType()); - while (const ArrayType *AT = C.getAsArrayType(FieldType)) - FieldType = AT->getElementType(); + QualType FieldType = C.getBaseElementType((*Field)->getType()); - if (FieldType->getAsRecordType()) { + if (const RecordType* RT = FieldType->getAsRecordType()) { // Skip over virtual bases which have trivial destructors. - CXXRecordDecl *BaseClassDecl - = cast(FieldType->getAsRecordType()->getDecl()); + CXXRecordDecl *BaseClassDecl = cast(RT->getDecl()); if (BaseClassDecl->hasTrivialDestructor()) continue; uintptr_t Member = reinterpret_cast(*Field); @@ -640,16 +637,12 @@ CXXConstructorDecl::setBaseOrMemberInitializers( AllToInit.push_back(AllBaseFields[Key]); continue; } - QualType FieldType = C.getCanonicalType((*Field)->getType()); - while (const ArrayType *AT = C.getAsArrayType(FieldType)) - FieldType = AT->getElementType(); - - if (FieldType->getAsRecordType()) { - CXXConstructorDecl *Ctor = 0; - if (CXXRecordDecl *FieldClassDecl = - dyn_cast(FieldType->getAsRecordType()->getDecl())) - Ctor = FieldClassDecl->getDefaultConstructor(C); - if (!Ctor && !FieldType->isDependentType()) + + QualType FT = C.getBaseElementType((*Field)->getType()); + if (const RecordType* RT = FT->getAsRecordType()) { + CXXConstructorDecl *Ctor = + cast(RT->getDecl())->getDefaultConstructor(C); + if (!Ctor && !FT->isDependentType()) Fields.push_back(*Field); CXXBaseOrMemberInitializer *Member = new (C) CXXBaseOrMemberInitializer((*Field), 0, 0, diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 399c30255a..fbefcd1ee8 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -213,7 +213,7 @@ Stmt::child_iterator TemplateIdRefExpr::child_end() { return Stmt::child_iterator(); } -bool UnaryTypeTraitExpr::EvaluateTrait() const { +bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const { switch(UTT) { default: assert(false && "Unknown type trait or not implemented"); case UTT_IsPOD: return QueriedType->isPODType(); @@ -236,11 +236,58 @@ bool UnaryTypeTraitExpr::EvaluateTrait() const { return cast(RT->getDecl())->isAbstract(); return false; case UTT_HasTrivialConstructor: - if (const RecordType *RT = QueriedType->getAsRecordType()) + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true then the trait is true, else if type is + // a cv class or union type (or array thereof) with a trivial default + // constructor ([class.ctor]) then the trait is true, else it is false. + if (QueriedType->isPODType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(QueriedType)->getAsRecordType()) return cast(RT->getDecl())->hasTrivialConstructor(); return false; - case UTT_HasTrivialDestructor: + case UTT_HasTrivialCopy: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type then + // the trait is true, else if type is a cv class or union type + // with a trivial copy constructor ([class.copy]) then the trait + // is true, else it is false. + if (QueriedType->isPODType() || QueriedType->isReferenceType()) + return true; + if (const RecordType *RT = QueriedType->getAsRecordType()) + return cast(RT->getDecl())->hasTrivialCopyConstructor(); + return false; + case UTT_HasTrivialAssign: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If type is const qualified or is a reference type then the + // trait is false. Otherwise if __is_pod (type) is true then the + // trait is true, else if type is a cv class or union type with + // a trivial copy assignment ([class.copy]) then the trait is + // true, else it is false. + // Note: the const and reference restrictions are interesting, + // given that const and reference members don't prevent a class + // from having a trivial copy assignment operator (but do cause + // errors if the copy assignment operator is actually used, q.v. + // [class.copy]p12). + + if (C.getBaseElementType(QueriedType).isConstQualified()) + return false; + if (QueriedType->isPODType()) + return true; if (const RecordType *RT = QueriedType->getAsRecordType()) + return cast(RT->getDecl())->hasTrivialCopyAssignment(); + return false; + case UTT_HasTrivialDestructor: + // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html: + // If __is_pod (type) is true or type is a reference type + // then the trait is true, else if type is a cv class or union + // type (or array thereof) with a trivial destructor + // ([class.dtor]) then the trait is true, else it is + // false. + if (QueriedType->isPODType() || QueriedType->isReferenceType()) + return true; + if (const RecordType *RT = + C.getBaseElementType(QueriedType)->getAsRecordType()) return cast(RT->getDecl())->hasTrivialDestructor(); return false; } diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c3d0402152..0291f6af15 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -735,7 +735,7 @@ public: } bool VisitUnaryTypeTraitExpr(const UnaryTypeTraitExpr *E) { - return Success(E->EvaluateTrait(), E); + return Success(E->EvaluateTrait(Info.Ctx), E); } bool VisitChooseExpr(const ChooseExpr *E) { diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp index 1df8b63e2e..c3bb29b8d5 100644 --- a/lib/AST/Type.cpp +++ b/lib/AST/Type.cpp @@ -1072,6 +1072,30 @@ TemplateSpecializationType::Profile(llvm::FoldingSetNodeID &ID, Args[Idx].Profile(ID); } +const Type *QualifierSet::strip(const Type* T) { + QualType DT = T->getDesugaredType(); + CVRMask |= DT.getCVRQualifiers(); + + if (const ExtQualType* EQT = dyn_cast(DT)) { + if (EQT->getAddressSpace()) + AddressSpace = EQT->getAddressSpace(); + if (EQT->getObjCGCAttr()) + GCAttrType = EQT->getObjCGCAttr(); + return EQT->getBaseType(); + }else { + // Use the sugared type unless desugaring found extra qualifiers. + return (DT.getCVRQualifiers() ? DT.getTypePtr() : T); + } +} + +QualType QualifierSet::apply(QualType QT, ASTContext& C) { + QT = QT.getWithAdditionalQualifiers(CVRMask); + if (GCAttrType) QT = C.getObjCGCQualType(QT, GCAttrType); + if (AddressSpace) QT = C.getAddrSpaceQualType(QT, AddressSpace); + return QT; +} + + //===----------------------------------------------------------------------===// // Type Printing //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index c2086b9e1a..4720bcb572 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -815,6 +815,8 @@ Parser::OwningExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___is_polymorphic: case tok::kw___is_abstract: case tok::kw___has_trivial_constructor: + case tok::kw___has_trivial_copy: + case tok::kw___has_trivial_assign: case tok::kw___has_trivial_destructor: return ParseUnaryTypeTrait(); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 0211470c76..2ecefde538 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -4244,9 +4244,7 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, } if (getLangOptions().CPlusPlus) { - QualType EltTy = T; - while (const ArrayType *AT = Context.getAsArrayType(EltTy)) - EltTy = AT->getElementType(); + QualType EltTy = Context.getBaseElementType(T); if (const RecordType *RT = EltTy->getAsRecordType()) { CXXRecordDecl* RDecl = cast(RT->getDecl()); @@ -4430,10 +4428,7 @@ void Sema::DiagnoseNontrivial(const RecordType* T, CXXSpecialMember member) { typedef RecordDecl::field_iterator field_iter; for (field_iter fi = RD->field_begin(), fe = RD->field_end(); fi != fe; ++fi) { - QualType EltTy = (*fi)->getType(); - while (const ArrayType *AT = Context.getAsArrayType(EltTy)) - EltTy = AT->getElementType(); - + QualType EltTy = Context.getBaseElementType((*fi)->getType()); if (const RecordType *EltRT = EltTy->getAsRecordType()) { CXXRecordDecl* EltRD = cast(EltRT->getDecl()); diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp index 1a2e329b2a..758dfe71e5 100644 --- a/test/SemaCXX/type-traits.cpp +++ b/test/SemaCXX/type-traits.cpp @@ -22,6 +22,7 @@ struct HasRef { int i; int& ref; HasRef() : i(0), ref(i) {} }; struct HasNonPOD { NonPOD np; }; struct HasVirt { virtual void Virt() {}; }; typedef Derives NonPODAr[10]; +typedef HasVirt VirtAr[10]; void is_pod() { @@ -109,3 +110,95 @@ void is_polymorphic() int t17[F(__is_polymorphic(ClassType))]; int t18[F(__is_polymorphic(Enum))]; } + +typedef Int& IntRef; +typedef const IntAr ConstIntAr; +typedef ConstIntAr ConstIntArAr[4]; + +struct HasCopy { + HasCopy(HasCopy& cp); +}; + +void has_trivial_default_constructor() { + int t01[T(__has_trivial_constructor(Int))]; + int t02[T(__has_trivial_constructor(IntAr))]; + int t03[T(__has_trivial_constructor(Union))]; + int t04[T(__has_trivial_constructor(UnionAr))]; + int t05[T(__has_trivial_constructor(POD))]; + int t06[T(__has_trivial_constructor(Derives))]; + int t07[T(__has_trivial_constructor(ConstIntAr))]; + int t08[T(__has_trivial_constructor(ConstIntArAr))]; + int t09[T(__has_trivial_constructor(HasDest))]; + int t10[T(__has_trivial_constructor(HasPriv))]; + int t11[F(__has_trivial_constructor(HasCons))]; + 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 t16[T(__has_trivial_constructor(const Int))]; + int t17[T(__has_trivial_constructor(NonPODAr))]; + int t18[F(__has_trivial_constructor(VirtAr))]; +} + +void has_trivial_copy_constructor() { + int t01[T(__has_trivial_copy(Int))]; + int t02[T(__has_trivial_copy(IntAr))]; + int t03[T(__has_trivial_copy(Union))]; + int t04[T(__has_trivial_copy(UnionAr))]; + int t05[T(__has_trivial_copy(POD))]; + int t06[T(__has_trivial_copy(Derives))]; + int t07[T(__has_trivial_copy(ConstIntAr))]; + int t08[T(__has_trivial_copy(ConstIntArAr))]; + int t09[T(__has_trivial_copy(HasDest))]; + int t10[T(__has_trivial_copy(HasPriv))]; + int t11[T(__has_trivial_copy(HasCons))]; + 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 t16[T(__has_trivial_copy(const Int))]; + int t17[F(__has_trivial_copy(NonPODAr))]; + int t18[F(__has_trivial_copy(VirtAr))]; +} + +void has_trivial_copy_assignment() { + int t01[T(__has_trivial_assign(Int))]; + int t02[T(__has_trivial_assign(IntAr))]; + int t03[T(__has_trivial_assign(Union))]; + int t04[T(__has_trivial_assign(UnionAr))]; + int t05[T(__has_trivial_assign(POD))]; + int t06[T(__has_trivial_assign(Derives))]; + int t07[F(__has_trivial_assign(ConstIntAr))]; + int t08[F(__has_trivial_assign(ConstIntArAr))]; + int t09[T(__has_trivial_assign(HasDest))]; + int t10[T(__has_trivial_assign(HasPriv))]; + int t11[T(__has_trivial_assign(HasCons))]; + 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 t16[F(__has_trivial_assign(const Int))]; + int t17[F(__has_trivial_assign(NonPODAr))]; + int t18[F(__has_trivial_assign(VirtAr))]; +} + +void has_trivial_destructor() { + int t01[T(__has_trivial_destructor(Int))]; + int t02[T(__has_trivial_destructor(IntAr))]; + int t03[T(__has_trivial_destructor(Union))]; + int t04[T(__has_trivial_destructor(UnionAr))]; + int t05[T(__has_trivial_destructor(POD))]; + int t06[T(__has_trivial_destructor(Derives))]; + int t07[T(__has_trivial_destructor(ConstIntAr))]; + int t08[T(__has_trivial_destructor(ConstIntArAr))]; + int t09[F(__has_trivial_destructor(HasDest))]; + int t10[T(__has_trivial_destructor(HasPriv))]; + int t11[T(__has_trivial_destructor(HasCons))]; + 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 t16[T(__has_trivial_destructor(const Int))]; + int t17[T(__has_trivial_destructor(NonPODAr))]; + int t18[T(__has_trivial_destructor(VirtAr))]; +}