New patch using CLASSTYPE_PURE_VIRTUALS, thanks for that. Bootstrapped and tested again on x86_64-linux, no regressions.
ChangeLogs as before, OK for trunk?
Index: c-family/c.opt =================================================================== --- c-family/c.opt (revision 174624) +++ c-family/c.opt (working copy) @@ -331,6 +331,10 @@ Wdeclaration-after-statement C ObjC Var(warn_declaration_after_statement) Warning Warn when a declaration is found after a statement +Wdelete-non-virtual-dtor +C++ ObjC++ Var(warn_delnonvdtor) Warning +Warn about deleting polymorphic objects with non-virtual destructors + Wdeprecated C C++ ObjC ObjC++ Var(warn_deprecated) Init(1) Warning Warn if a deprecated compiler feature, class, method, or field is used Index: c-family/c-opts.c =================================================================== --- c-family/c-opts.c (revision 174624) +++ c-family/c-opts.c (working copy) @@ -405,6 +405,7 @@ c_common_handle_option (size_t scode, co warn_sign_compare = value; warn_reorder = value; warn_cxx0x_compat = value; + warn_delnonvdtor = value; } cpp_opts->warn_trigraphs = value; Index: cp/init.c =================================================================== --- cp/init.c (revision 174624) +++ cp/init.c (working copy) @@ -3421,6 +3421,25 @@ build_delete (tree type, tree addr, spec } complete_p = false; } + else if (warn_delnonvdtor && MAYBE_CLASS_TYPE_P (type) + && !CLASSTYPE_FINAL (type) && TYPE_POLYMORPHIC_P (type)) + { + tree dtor; + dtor = CLASSTYPE_DESTRUCTORS (type); + if (!dtor || !DECL_VINDEX (dtor)) + { + if (CLASSTYPE_PURE_VIRTUALS (type)) + warning(OPT_Wdelete_non_virtual_dtor, + "deleting object of abstract class type %qT" + " which has non-virtual destructor" + " will cause undefined behaviour", type); + else + warning(OPT_Wdelete_non_virtual_dtor, + "deleting object of polymorphic class type %qT" + " which has non-virtual destructor" + " may cause undefined behaviour", type); + } + } } if (VOID_TYPE_P (type) || !complete_p || !MAYBE_CLASS_TYPE_P (type)) /* Call the builtin operator delete. */ Index: doc/invoke.texi =================================================================== --- doc/invoke.texi (revision 174624) +++ doc/invoke.texi (working copy) @@ -2331,6 +2331,15 @@ Warn when a class seems unusable because destructors in that class are private, and it has neither friends nor public static member functions. +@item -Wdelete-non-virtual-dtor @r{(C++ and Objective-C++ only)} +@opindex Wdelete-non-virtual-dtor +@opindex Wno-delete-non-virtual-dtor +Warn when @samp{delete} is used to destroy an instance of a class which +has virtual functions and non-virtual destructor. It is unsafe to delete +an instance of a derived class through a pointer to a base class if the +base class does not have a virtual destructor. This warning is enabled +by @option{-Wall}. + @item -Wnoexcept @r{(C++ and Objective-C++ only)} @opindex Wnoexcept @opindex Wno-noexcept Index: testsuite/g++.dg/warn/delete-non-virtual-dtor.C =================================================================== --- testsuite/g++.dg/warn/delete-non-virtual-dtor.C (revision 0) +++ testsuite/g++.dg/warn/delete-non-virtual-dtor.C (revision 0) @@ -0,0 +1,44 @@ +// { dg-options "-std=gnu++0x -Wdelete-non-virtual-dtor" } +// { dg-do compile } + +struct polyBase { virtual void f(); }; + +void f(polyBase* p, polyBase* arr) +{ + delete p; // { dg-warning "non-virtual destructor may" } + delete [] arr; +} + +struct polyDerived : polyBase { }; + +void f(polyDerived* p, polyDerived* arr) +{ + delete p; // { dg-warning "non-virtual destructor may" } + delete [] arr; +} + +struct absDerived : polyBase { virtual void g() = 0; }; + +void f(absDerived* p, absDerived* arr) +{ + delete p; // { dg-warning "non-virtual destructor will" } + delete [] arr; +} + +struct finalDerived final : polyBase { }; + +void f(finalDerived* p, finalDerived* arr) +{ + delete p; // no error for final classes + delete [] arr; +} + +struct safeBase { virtual ~safeBase(); }; +struct safeDerived : safeBase { virtual void f(); }; + +void f(safeDerived* p, safeDerived* arr) +{ + delete p; // no error because base has virtual dtor + delete [] arr; +} +