aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnders Carlsson <andersca@mac.com>2009-04-17 02:34:54 +0000
committerAnders Carlsson <andersca@mac.com>2009-04-17 02:34:54 +0000
commit072abefcddea5fb65e435cea60921b3c21c1279d (patch)
treeccbbe619641b2fb59dd63d8bf4667eee5b349308
parent27ae53665f8b00fe4ba21da0fa79a4ce6e0b6cd5 (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.h13
-rw-r--r--lib/AST/DeclCXX.cpp2
-rw-r--r--lib/AST/ExprCXX.cpp6
-rw-r--r--lib/Parse/ParseExpr.cpp3
-rw-r--r--lib/Sema/SemaDecl.cpp4
-rw-r--r--lib/Sema/SemaDeclCXX.cpp18
-rw-r--r--test/SemaCXX/trivial-constructor.cpp4
-rw-r--r--test/SemaCXX/trivial-destructor.cpp38
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!");