diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 18b2bc218710..c41e19dbe4f8 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6417,12 +6417,12 @@ def warn_non_virtual_dtor : Warning< def warn_delete_non_virtual_dtor : Warning< "%select{delete|destructor}0 called on non-final %1 that has " "virtual functions but non-virtual destructor">, - InGroup, DefaultIgnore; + InGroup, DefaultIgnore, ShowInSystemHeader; def note_delete_non_virtual : Note< "qualify call to silence this warning">; def warn_delete_abstract_non_virtual_dtor : Warning< "%select{delete|destructor}0 called on %1 that is abstract but has " - "non-virtual destructor">, InGroup; + "non-virtual destructor">, InGroup, ShowInSystemHeader; def warn_overloaded_virtual : Warning< "%q0 hides overloaded virtual %select{function|functions}1">, InGroup, DefaultIgnore; diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 456aff2fe00e..8de3d33d085e 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -3284,7 +3284,7 @@ void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, bool IsDelete, bool CallCanBeVirtual, bool WarnOnNonAbstractTypes, SourceLocation DtorLoc) { - if (!dtor || dtor->isVirtual() || !CallCanBeVirtual) + if (!dtor || dtor->isVirtual() || !CallCanBeVirtual || isUnevaluatedContext()) return; // C++ [expr.delete]p3: diff --git a/clang/test/SemaCXX/destructor.cpp b/clang/test/SemaCXX/destructor.cpp index 49cdc50f3c13..31ee60a718ad 100644 --- a/clang/test/SemaCXX/destructor.cpp +++ b/clang/test/SemaCXX/destructor.cpp @@ -1,5 +1,31 @@ // RUN: %clang_cc1 -std=c++11 -triple %itanium_abi_triple -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -fcxx-exceptions -verify %s // RUN: %clang_cc1 -std=c++11 -triple %ms_abi_triple -DMSABI -fsyntax-only -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -verify %s + +#if defined(BE_THE_HEADER) + +// Wdelete-non-virtual-dtor should warn about the delete from smart pointer +// classes in system headers (std::unique_ptr...) too. + +#pragma clang system_header +namespace dnvd { +template +class simple_ptr { +public: + simple_ptr(T* t): _ptr(t) {} + ~simple_ptr() { delete _ptr; } // \ + // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} \ + // expected-warning {{delete called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}} + T& operator*() const { return *_ptr; } +private: + T* _ptr; +}; +} + +#else + +#define BE_THE_HEADER +#include __FILE__ + class A { public: ~A(); @@ -212,18 +238,6 @@ struct VD: VB {}; struct VF final: VB {}; -template -class simple_ptr { -public: - simple_ptr(T* t): _ptr(t) {} - ~simple_ptr() { delete _ptr; } // \ - // expected-warning {{delete called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} \ - // expected-warning {{delete called on non-final 'dnvd::D' that has virtual functions but non-virtual destructor}} - T& operator*() const { return *_ptr; } -private: - T* _ptr; -}; - template class simple_ptr2 { public: @@ -335,10 +349,28 @@ void warn0() { } } +// Taken from libc++, slightly simplified. +template +struct __is_destructible_apply { typedef int type; }; +struct __two {char __lx[2];}; +template +struct __is_destructor_wellformed { + template + static char __test(typename __is_destructible_apply< + decltype(_Tp1().~_Tp1())>::type); + template + static __two __test (...); + + static const bool value = sizeof(__test<_Tp>(12)) == sizeof(char); +}; + void warn0_explicit_dtor(B* b, B& br, D* d) { b->~B(); // expected-warning {{destructor called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}} b->B::~B(); // No warning when the call isn't virtual. + // No warning in unevaluated contexts. + (void)__is_destructor_wellformed::value; + br.~B(); // expected-warning {{destructor called on non-final 'dnvd::B' that has virtual functions but non-virtual destructor}} expected-note{{qualify call to silence this warning}} br.B::~B(); @@ -451,3 +483,4 @@ void foo1() { x.foo1(); } } +#endif // BE_THE_HEADER diff --git a/clang/test/SemaCXX/implicit-exception-spec.cpp b/clang/test/SemaCXX/implicit-exception-spec.cpp index f400c222de83..c21f773e94c6 100644 --- a/clang/test/SemaCXX/implicit-exception-spec.cpp +++ b/clang/test/SemaCXX/implicit-exception-spec.cpp @@ -121,7 +121,7 @@ namespace PotentiallyConstructed { T &a = *p; static_assert(noexcept(a = a) == D, ""); static_assert(noexcept(a = static_cast(a)) == E, ""); - static_assert(noexcept(delete &a) == F, ""); // expected-warning 2{{abstract}} + static_assert(noexcept(delete &a) == F, ""); // These are last because the first failure here causes instantiation to bail out. static_assert(noexcept(new (nothrow) T()) == A, ""); // expected-error 2{{abstract}}