aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td5
-rw-r--r--lib/Sema/SemaExprCXX.cpp29
-rw-r--r--test/SemaCXX/new-delete.cpp2
3 files changed, 17 insertions, 19 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 41aaebaa60..7ee93568e3 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3421,8 +3421,9 @@ 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<DeleteNonVirtualDtor>, DefaultIgnore;
-def err_delete_abstract_non_virtual_dtor : Error<
- "cannot delete %0, which is abstract and does not have a virtual destructor">;
+def warn_delete_abstract_non_virtual_dtor : Warning<
+ "delete called on %0 that is abstract but has non-virtual destructor">,
+ InGroup<DeleteNonVirtualDtor>;
def warn_overloaded_virtual : Warning<
"%q0 hides overloaded virtual %select{function|functions}1">,
InGroup<OverloadedVirtual>, DefaultIgnore;
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 86a4ecc1fc..94a5bafa7c 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -1913,18 +1913,6 @@ 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
@@ -1933,11 +1921,20 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
// behavior is undefined.
//
// Note: a final class cannot be derived from, no issue there
- if (!ArrayForm && PointeeRD->isPolymorphic() &&
- !PointeeRD->hasAttr<FinalAttr>()) {
+ if (PointeeRD->isPolymorphic() && !PointeeRD->hasAttr<FinalAttr>()) {
CXXDestructorDecl *dtor = PointeeRD->getDestructor();
- if (dtor && !dtor->isVirtual())
- Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
+ if (dtor && !dtor->isVirtual()) {
+ if (PointeeRD->isAbstract()) {
+ // If the class is abstract, we warn by default, because we're
+ // sure the code has undefined behavior.
+ Diag(StartLoc, diag::warn_delete_abstract_non_virtual_dtor)
+ << PointeeElem;
+ } else if (!ArrayForm) {
+ // Otherwise, if this is not an array delete, it's a bit suspect,
+ // but not necessarily wrong.
+ Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
+ }
+ }
}
} else if (getLangOptions().ObjCAutoRefCount &&
diff --git a/test/SemaCXX/new-delete.cpp b/test/SemaCXX/new-delete.cpp
index 7545b7c136..748ce77700 100644
--- a/test/SemaCXX/new-delete.cpp
+++ b/test/SemaCXX/new-delete.cpp
@@ -414,5 +414,5 @@ 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}}
+ void f(A *x) { delete x; } // expected-warning {{delete called on 'PR10504::A' that is abstract but has non-virtual destructor}}
}