aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/DeclCXX.cpp3
-rw-r--r--lib/AST/ExprCXX.cpp10
-rw-r--r--lib/Parse/ParseExpr.cpp3
-rw-r--r--test/SemaCXX/type-traits.cpp29
4 files changed, 43 insertions, 2 deletions
diff --git a/lib/AST/DeclCXX.cpp b/lib/AST/DeclCXX.cpp
index f404155350..f2f0694826 100644
--- a/lib/AST/DeclCXX.cpp
+++ b/lib/AST/DeclCXX.cpp
@@ -609,7 +609,8 @@ CXXDestructorDecl *CXXRecordDecl::getDestructor() const {
DeclContext::lookup_const_iterator I, E;
llvm::tie(I, E) = lookup(Name);
- assert(I != E && "Did not find a destructor!");
+ if (I == E)
+ return 0;
CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(*I);
assert(++I == E && "Found more than one destructor!");
diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp
index ae57f4cd67..0a101300d8 100644
--- a/lib/AST/ExprCXX.cpp
+++ b/lib/AST/ExprCXX.cpp
@@ -488,6 +488,16 @@ bool UnaryTypeTraitExpr::EvaluateTrait(ASTContext& C) const {
}
}
return false;
+ case UTT_HasVirtualDestructor:
+ // http://gcc.gnu.org/onlinedocs/gcc/Type-Traits.html:
+ // If type is a class type with a virtual destructor ([class.dtor])
+ // then the trait is true, else it is false.
+ if (const RecordType *Record = QueriedType->getAs<RecordType>()) {
+ CXXRecordDecl *RD = cast<CXXRecordDecl>(Record->getDecl());
+ if (CXXDestructorDecl *Destructor = RD->getDestructor())
+ return Destructor->isVirtual();
+ }
+ return false;
}
}
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index f1abd59421..c4beab191d 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -533,7 +533,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
/// '__has_trivial_copy' [TODO]
/// '__has_trivial_constructor'
/// '__has_trivial_destructor'
-/// '__has_virtual_destructor' [TODO]
+/// '__has_virtual_destructor'
/// '__is_abstract' [TODO]
/// '__is_class'
/// '__is_empty' [TODO]
@@ -903,6 +903,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
case tok::kw___has_nothrow_assign:
case tok::kw___has_nothrow_copy:
case tok::kw___has_nothrow_constructor:
+ case tok::kw___has_virtual_destructor:
return ParseUnaryTypeTrait();
case tok::at: {
diff --git a/test/SemaCXX/type-traits.cpp b/test/SemaCXX/type-traits.cpp
index b561206143..b05dd07ec2 100644
--- a/test/SemaCXX/type-traits.cpp
+++ b/test/SemaCXX/type-traits.cpp
@@ -61,6 +61,10 @@ struct HasMultipleNoThrowCopy {
HasMultipleNoThrowCopy(volatile HasMultipleNoThrowCopy&) throw();
};
+struct HasVirtDest { virtual ~HasVirtDest(); };
+struct DerivedVirtDest : HasVirtDest {};
+typedef HasVirtDest VirtDestAr[1];
+
void is_pod()
{
int t01[T(__is_pod(int))];
@@ -359,3 +363,28 @@ void has_nothrow_constructor() {
int t19[T(__has_nothrow_constructor(HasNoThrowConstructor))];
int t20[F(__has_nothrow_constructor(HasNoThrowConstructorWithArgs))];
}
+
+void has_virtual_destructor() {
+ int t01[F(__has_virtual_destructor(Int))];
+ int t02[F(__has_virtual_destructor(IntAr))];
+ int t03[F(__has_virtual_destructor(Union))];
+ int t04[F(__has_virtual_destructor(UnionAr))];
+ int t05[F(__has_virtual_destructor(POD))];
+ int t06[F(__has_virtual_destructor(Derives))];
+ int t07[F(__has_virtual_destructor(ConstIntAr))];
+ int t08[F(__has_virtual_destructor(ConstIntArAr))];
+ int t09[F(__has_virtual_destructor(HasDest))];
+ int t10[F(__has_virtual_destructor(HasPriv))];
+ int t11[F(__has_virtual_destructor(HasCons))];
+ int t12[F(__has_virtual_destructor(HasRef))];
+ int t13[F(__has_virtual_destructor(HasCopy))];
+ int t14[F(__has_virtual_destructor(IntRef))];
+ int t15[F(__has_virtual_destructor(HasCopyAssign))];
+ int t16[F(__has_virtual_destructor(const Int))];
+ int t17[F(__has_virtual_destructor(NonPODAr))];
+ int t18[F(__has_virtual_destructor(VirtAr))];
+
+ int t19[T(__has_virtual_destructor(HasVirtDest))];
+ int t20[T(__has_virtual_destructor(DerivedVirtDest))];
+ int t21[F(__has_virtual_destructor(VirtDestAr))];
+}