From: Eli Friedman Date: Tue, 26 Jul 2011 22:50:18 +0000 (+0000) Subject: Diagnose trying to delete a pointer to an abstract class with a non-virtual destructo... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=e33f643230738400f0bf5503a87d886e9bc635de;p=clang Diagnose trying to delete a pointer to an abstract class with a non-virtual destructor. PR10504. I'm not completely sure the standard allows us to reject this, but if it doesn't, it should. :) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@136172 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 20332dc286..264f7a9d10 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -3406,6 +3406,8 @@ def warn_non_virtual_dtor : Warning< def warn_delete_non_virtual_dtor : Warning< "delete called on %0 that has virtual functions but non-virtual destructor">, InGroup, DefaultIgnore; +def err_delete_abstract_non_virtual_dtor : Error< + "cannot delete %0, which is abstract and does not have a virtual destructor">; def warn_overloaded_virtual : Warning< "%q0 hides overloaded virtual %select{function|functions}1">, InGroup, DefaultIgnore; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index a3e3c11c6a..86a4ecc1fc 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1913,6 +1913,18 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, DiagnoseUseOfDecl(Dtor, StartLoc); } + // Deleting an abstract class with a non-virtual destructor is always + // undefined per [expr.delete]p3, and leads to strange-looking + // linker errors. + if (PointeeRD->isAbstract()) { + CXXDestructorDecl *dtor = PointeeRD->getDestructor(); + if (dtor && !dtor->isVirtual()) { + Diag(StartLoc, diag::err_delete_abstract_non_virtual_dtor) + << PointeeElem; + return ExprError(); + } + } + // C++ [expr.delete]p3: // In the first alternative (delete object), if the static type of the // object to be deleted is different from its dynamic type, the static @@ -1924,7 +1936,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, if (!ArrayForm && PointeeRD->isPolymorphic() && !PointeeRD->hasAttr()) { CXXDestructorDecl *dtor = PointeeRD->getDestructor(); - if (!dtor || !dtor->isVirtual()) + if (dtor && !dtor->isVirtual()) Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; } diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp index 850229c320..7545b7c136 100644 --- a/test/SemaCXX/new-delete.cpp +++ b/test/SemaCXX/new-delete.cpp @@ -409,3 +409,10 @@ namespace DeleteIncompleteClassPointerError { void f(A *x) { 1+delete x; } // expected-warning {{deleting pointer to incomplete type}} \ // expected-error {{invalid operands to binary expression}} } + +namespace PR10504 { + struct A { + virtual void foo() = 0; + }; + void f(A *x) { delete x; } // expected-error {{cannot delete 'PR10504::A', which is abstract and does not have a virtual destructor}} +}