Diagnose uses of deleted destructors and inaccessible defaulted destructors.
We had two separate issues here: firstly, varions functions were assuming that
they did not need to perform semantic checks on trivial destructors (this is
not true in C++11, where a trivial destructor can nonetheless be private or
deleted), and a bunch of DiagnoseUseOfDecl calls were missing for uses of
destructors.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150866 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/AST/DeclCXX.h b/include/clang/AST/DeclCXX.h
index c371c08..5db16ed 100644
--- a/include/clang/AST/DeclCXX.h
+++ b/include/clang/AST/DeclCXX.h
@@ -1122,6 +1122,13 @@
// (C++ [class.dtor]p3)
bool hasTrivialDestructor() const { return data().HasTrivialDestructor; }
+ // hasIrrelevantDestructor - Whether this class has a destructor which has no
+ // semantic effect. Any such destructor will be trivial, public, defaulted
+ // and not deleted.
+ bool hasIrrelevantDestructor() const {
+ return hasTrivialDestructor() && !hasUserDeclaredDestructor();
+ }
+
// hasNonLiteralTypeFieldsOrBases - Whether this class has a non-literal or
// volatile type non-static data member or base class.
bool hasNonLiteralTypeFieldsOrBases() const {
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index 5a9b7a7..d271921 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -3282,7 +3282,7 @@
CXXRecordDecl *FieldClassDecl = cast<CXXRecordDecl>(RT->getDecl());
if (FieldClassDecl->isInvalidDecl())
continue;
- if (FieldClassDecl->hasTrivialDestructor())
+ if (FieldClassDecl->hasIrrelevantDestructor())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(FieldClassDecl);
@@ -3293,6 +3293,7 @@
<< FieldType);
MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ DiagnoseUseOfDecl(Dtor, Location);
}
llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases;
@@ -3311,8 +3312,7 @@
// If our base class is invalid, we probably can't get its dtor anyway.
if (BaseClassDecl->isInvalidDecl())
continue;
- // Ignore trivial destructors.
- if (BaseClassDecl->hasTrivialDestructor())
+ if (BaseClassDecl->hasIrrelevantDestructor())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
@@ -3325,6 +3325,7 @@
<< Base->getSourceRange());
MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ DiagnoseUseOfDecl(Dtor, Location);
}
// Virtual bases.
@@ -3342,8 +3343,7 @@
// If our base class is invalid, we probably can't get its dtor anyway.
if (BaseClassDecl->isInvalidDecl())
continue;
- // Ignore trivial destructors.
- if (BaseClassDecl->hasTrivialDestructor())
+ if (BaseClassDecl->hasIrrelevantDestructor())
continue;
CXXDestructorDecl *Dtor = LookupDestructor(BaseClassDecl);
@@ -3353,6 +3353,7 @@
<< VBase->getType());
MarkFunctionReferenced(Location, const_cast<CXXDestructorDecl*>(Dtor));
+ DiagnoseUseOfDecl(Dtor, Location);
}
}
@@ -8918,7 +8919,7 @@
CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl());
if (ClassDecl->isInvalidDecl()) return;
- if (ClassDecl->hasTrivialDestructor()) return;
+ if (ClassDecl->hasIrrelevantDestructor()) return;
if (ClassDecl->isDependentContext()) return;
CXXDestructorDecl *Destructor = LookupDestructor(ClassDecl);
@@ -8927,6 +8928,7 @@
PDiag(diag::err_access_dtor_var)
<< VD->getDeclName()
<< VD->getType());
+ DiagnoseUseOfDecl(Destructor, VD->getLocation());
if (!VD->hasGlobalStorage()) return;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index ca84119..74bac67 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -637,8 +637,8 @@
if (isPointer)
return Owned(E);
- // If the class has a non-trivial destructor, we must be able to call it.
- if (RD->hasTrivialDestructor())
+ // If the class has a destructor, we must be able to call it.
+ if (RD->hasIrrelevantDestructor())
return Owned(E);
CXXDestructorDecl *Destructor
@@ -649,6 +649,7 @@
MarkFunctionReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_exception) << Ty);
+ DiagnoseUseOfDecl(Destructor, E->getExprLoc());
return Owned(E);
}
@@ -1318,6 +1319,7 @@
CheckDestructorAccess(StartLoc, dtor,
PDiag(diag::err_access_dtor)
<< Context.getBaseElementType(AllocType));
+ DiagnoseUseOfDecl(dtor, StartLoc);
}
}
@@ -2064,7 +2066,7 @@
UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2);
}
- if (!PointeeRD->hasTrivialDestructor())
+ if (!PointeeRD->hasIrrelevantDestructor())
if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) {
MarkFunctionReferenced(StartLoc,
const_cast<CXXDestructorDecl*>(Dtor));
@@ -4309,23 +4311,28 @@
}
// That should be enough to guarantee that this type is complete.
- // If it has a trivial destructor, we can avoid the extra copy.
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
- if (RD->isInvalidDecl() || RD->hasTrivialDestructor())
+ if (RD->isInvalidDecl() || RD->isDependentContext())
return Owned(E);
-
CXXDestructorDecl *Destructor = LookupDestructor(RD);
- CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
if (Destructor) {
MarkFunctionReferenced(E->getExprLoc(), Destructor);
CheckDestructorAccess(E->getExprLoc(), Destructor,
PDiag(diag::err_access_dtor_temp)
<< E->getType());
+ DiagnoseUseOfDecl(Destructor, E->getExprLoc());
+ }
+ // If destructor is trivial, we can avoid the extra copy.
+ if (Destructor->isTrivial())
+ return Owned(E);
+
+ if (Destructor)
// We need a cleanup, but we don't need to remember the temporary.
ExprNeedsCleanups = true;
- }
+
+ CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
return Owned(CXXBindTemporaryExpr::Create(Context, Temp, E));
}
diff --git a/test/SemaCXX/defaulted-private-dtor.cpp b/test/SemaCXX/defaulted-private-dtor.cpp
new file mode 100644
index 0000000..a15bdde
--- /dev/null
+++ b/test/SemaCXX/defaulted-private-dtor.cpp
@@ -0,0 +1,47 @@
+// RUN: %clang_cc1 -verify -std=c++11 %s -fcxx-exceptions
+
+class BadDtor {
+ // A private, but nonetheless trivial, destructor.
+ ~BadDtor() = default; // expected-note 9{{here}}
+ friend class K;
+};
+void f() {
+ BadDtor *p = new BadDtor[3]; // expected-error {{private destructor}}
+ delete [] p; // expected-error {{private destructor}}
+ const BadDtor &dd2 = BadDtor(); // expected-error {{private destructor}}
+ BadDtor dd; // expected-error {{private destructor}}
+ throw dd; // expected-error {{private destructor}}
+}
+struct X : BadDtor { // expected-error {{private destructor}}
+ ~X() {}
+};
+struct Y {
+ BadDtor dd; // expected-error {{private destructor}}
+ ~Y() {}
+};
+struct Z : virtual BadDtor { // expected-error {{private destructor}}
+ ~Z() {}
+};
+BadDtor dd; // expected-error {{private destructor}}
+
+class K : BadDtor {
+ void f() {
+ BadDtor *p = new BadDtor[3];
+ delete [] p;
+ const BadDtor &dd2 = BadDtor();
+ BadDtor dd;
+ throw dd;
+
+ {
+ BadDtor x;
+ goto dont_call_dtor;
+ }
+dont_call_dtor:
+ ;
+ }
+ struct Z : virtual BadDtor {
+ ~Z() {}
+ };
+ BadDtor dd;
+ ~K();
+};
diff --git a/test/SemaCXX/deleted-function.cpp b/test/SemaCXX/deleted-function.cpp
index 4620a19..d13fd0e 100644
--- a/test/SemaCXX/deleted-function.cpp
+++ b/test/SemaCXX/deleted-function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 -fcxx-exceptions %s
int i = delete; // expected-error {{only functions can have deleted definitions}}
@@ -33,3 +33,25 @@
d->fn(); // expected-error {{attempt to use a deleted function}}
int i = *d; // expected-error {{invokes a deleted function}}
}
+
+struct DelDtor {
+ ~DelDtor() = delete; // expected-note 9{{here}}
+};
+void f() {
+ DelDtor *p = new DelDtor[3]; // expected-error {{attempt to use a deleted function}}
+ delete [] p; // expected-error {{attempt to use a deleted function}}
+ const DelDtor &dd2 = DelDtor(); // expected-error {{attempt to use a deleted function}}
+ DelDtor dd; // expected-error {{attempt to use a deleted function}}
+ throw dd; // expected-error {{attempt to use a deleted function}}
+}
+struct X : DelDtor {
+ ~X() {} // expected-error {{attempt to use a deleted function}}
+};
+struct Y {
+ DelDtor dd;
+ ~Y() {} // expected-error {{attempt to use a deleted function}}
+};
+struct Z : virtual DelDtor {
+ ~Z() {} // expected-error {{attempt to use a deleted function}}
+};
+DelDtor dd; // expected-error {{attempt to use a deleted function}}