diff options
author | Anders Carlsson <andersca@mac.com> | 2009-04-17 02:34:54 +0000 |
---|---|---|
committer | Anders Carlsson <andersca@mac.com> | 2009-04-17 02:34:54 +0000 |
commit | 072abefcddea5fb65e435cea60921b3c21c1279d (patch) | |
tree | ccbbe619641b2fb59dd63d8bf4667eee5b349308 | |
parent | 27ae53665f8b00fe4ba21da0fa79a4ce6e0b6cd5 (diff) |
Add support for the __has_trivial_destructor type trait.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69345 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/AST/DeclCXX.h | 13 | ||||
-rw-r--r-- | lib/AST/DeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 6 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 18 | ||||
-rw-r--r-- | test/SemaCXX/trivial-constructor.cpp | 4 | ||||
-rw-r--r-- | test/SemaCXX/trivial-destructor.cpp | 38 |
8 files changed, 81 insertions, 7 deletions
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h index 328ec8701e..26f8f1a75f 100644 --- a/include/clang/AST/DeclCXX.h +++ b/include/clang/AST/DeclCXX.h @@ -228,6 +228,9 @@ class CXXRecordDecl : public RecordDecl { /// HasTrivialConstructor - True when this class has a trivial constructor bool HasTrivialConstructor : 1; + /// HasTrivialDestructor - True when this class has a trivial destructor + bool HasTrivialDestructor : 1; + /// Bases - Base classes of this class. /// FIXME: This is wasted space for a union. CXXBaseSpecifier *Bases; @@ -327,7 +330,7 @@ public: /// setUserDeclaredDestructor - Set whether this class has a /// user-declared destructor. If not set by the time the class is /// fully defined, a destructor will be implicitly declared. - void setUserDeclaredDestructor(bool UCD = true) { + void setUserDeclaredDestructor(bool UCD) { UserDeclaredDestructor = UCD; } @@ -386,6 +389,14 @@ public: // (C++ [class.ctor]p5) void setHasTrivialConstructor(bool TC) { HasTrivialConstructor = TC; } + // hasTrivialDestructor - Whether this class has a trivial destructor + // (C++ [class.dtor]p3) + bool hasTrivialDestructor() const { return HasTrivialDestructor; } + + // setHasTrivialDestructor - Set whether this class has a trivial destructor + // (C++ [class.dtor]p3) + void setHasTrivialDestructor(bool TC) { HasTrivialDestructor = TC; } + /// \brief If this record is an instantiation of a member class, /// retrieves the member class from which it was instantiated. /// diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp index 78ed3fcf4d..a5d133c643 100644 --- a/lib/AST/DeclCXX.cpp +++ b/lib/AST/DeclCXX.cpp @@ -29,7 +29,7 @@ CXXRecordDecl::CXXRecordDecl(Kind K, TagKind TK, DeclContext *DC, UserDeclaredConstructor(false), UserDeclaredCopyConstructor(false), UserDeclaredCopyAssignment(false), UserDeclaredDestructor(false), Aggregate(true), PlainOldData(true), Polymorphic(false), Abstract(false), - HasTrivialConstructor(true), + HasTrivialConstructor(true), HasTrivialDestructor(true), Bases(0), NumBases(0), Conversions(DC, DeclarationName()), TemplateOrInstantiation() { } diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 3634c20356..d73ea370cf 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -173,7 +173,11 @@ bool UnaryTypeTraitExpr::EvaluateTrait() const { case UTT_HasTrivialConstructor: if (const RecordType *RT = QueriedType->getAsRecordType()) return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialConstructor(); - return false; + return false; + case UTT_HasTrivialDestructor: + if (const RecordType *RT = QueriedType->getAsRecordType()) + return cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor(); + return false; } } diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 3280730564..47e364e361 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -493,7 +493,7 @@ Parser::ParseRHSOfBinaryExpression(OwningExprResult LHS, unsigned MinPrec) { /// '__has_trivial_assign' [TODO] /// '__has_trivial_copy' [TODO] /// '__has_trivial_constructor' -/// '__has_trivial_destructor' [TODO] +/// '__has_trivial_destructor' /// '__has_virtual_destructor' [TODO] /// '__is_abstract' [TODO] /// '__is_class' @@ -783,6 +783,7 @@ 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_destructor: return ParseUnaryTypeTrait(); case tok::at: { diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a2b565beb6..3b6ce6bd73 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2251,6 +2251,10 @@ bool Sema::CheckFunctionDeclaration(FunctionDecl *NewFD, NamedDecl *&PrevDecl, // C++ [class]p4: A POD-struct is an aggregate class that has [...] no // user-defined destructor. Record->setPOD(false); + + // C++ [class.dtor]p3: A destructor is trivial if it is an implicitly- + // declared destructor. + Record->setHasTrivialDestructor(false); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD)) ActOnConversionDeclarator(Conversion); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e3195a9b28..9fd62269f2 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -380,6 +380,12 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, Class->setHasTrivialConstructor(cast<CXXRecordDecl>(BaseDecl)-> hasTrivialConstructor()); } + + // C++ [class.ctor]p3: + // A destructor is trivial if all the direct base classes of its class + // have trivial destructors. + Class->setHasTrivialDestructor(cast<CXXRecordDecl>(BaseDecl)-> + hasTrivialDestructor()); // Create the base specifier. // FIXME: Allocate via ASTContext? @@ -952,7 +958,7 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, if (RD->isAbstract()) AbstractClassUsageDiagnoser(*this, RD); - if (RD->hasTrivialConstructor()) { + if (RD->hasTrivialConstructor() || RD->hasTrivialDestructor()) { for (RecordDecl::field_iterator i = RD->field_begin(Context), e = RD->field_end(Context); i != e; ++i) { // All the nonstatic data members must have trivial constructors. @@ -962,10 +968,16 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, if (const RecordType *RT = FTy->getAsRecordType()) { CXXRecordDecl *FieldRD = cast<CXXRecordDecl>(RT->getDecl()); - if (!FieldRD->hasTrivialConstructor()) { + + if (!FieldRD->hasTrivialConstructor()) RD->setHasTrivialConstructor(false); + if (!FieldRD->hasTrivialDestructor()) + RD->setHasTrivialDestructor(false); + + // If RD has neither a trivial constructor nor a trivial destructor + // we don't need to continue checking. + if (!RD->hasTrivialConstructor() && !RD->hasTrivialDestructor()) break; - } } } } diff --git a/test/SemaCXX/trivial-constructor.cpp b/test/SemaCXX/trivial-constructor.cpp index 0c4231ef19..8fc14d9c82 100644 --- a/test/SemaCXX/trivial-constructor.cpp +++ b/test/SemaCXX/trivial-constructor.cpp @@ -32,3 +32,7 @@ struct T7 { T4 t4; }; static_assert(!__has_trivial_constructor(T7), "t4 does not have a trivial constructor!"); + +struct T8 : T2 { +}; +static_assert(!__has_trivial_constructor(T8), "The base class T2 does not have a trivial constructor!"); diff --git a/test/SemaCXX/trivial-destructor.cpp b/test/SemaCXX/trivial-destructor.cpp new file mode 100644 index 0000000000..9e7f3a16dd --- /dev/null +++ b/test/SemaCXX/trivial-destructor.cpp @@ -0,0 +1,38 @@ +// RUN: clang-cc -fsyntax-only -verify %s -std=c++0x +struct T1 { +}; +static_assert(__has_trivial_destructor(T1), "T1 has trivial destructor!"); + +struct T2 { + ~T2(); +}; +static_assert(!__has_trivial_destructor(T2), "T2 has a user-declared destructor!"); + +struct T3 { + virtual void f(); +}; +static_assert(__has_trivial_destructor(T3), "T3 has a virtual function (but still a trivial destructor)!"); + +struct T4 : virtual T3 { +}; +static_assert(__has_trivial_destructor(T4), "T4 has a virtual base class! (but still a trivial destructor)!"); + +struct T5 : T1 { +}; +static_assert(__has_trivial_destructor(T5), "All the direct base classes of T5 have trivial destructors!"); + +struct T6 { + T5 t5; + T1 t1[2][2]; + static T2 t2; +}; +static_assert(__has_trivial_destructor(T6), "All nonstatic data members of T6 have trivial destructors!"); + +struct T7 { + T2 t2; +}; +static_assert(!__has_trivial_destructor(T7), "t2 does not have a trivial destructor!"); + +struct T8 : T2 { +}; +static_assert(!__has_trivial_destructor(T8), "The base class T2 does not have a trivial destructor!"); |