Hi Andrew, Would you pls take a look on my patch? I followed you comments on Bugzilla to fix it. Thanks a lot.
Best, Yifan yifan.dong <[email protected]> 于2026年3月4日周三 23:02写道: > Hi! > > I am trying to submit my first patch to gcc. I hope I made everything > right. > > This patch fixes two false positives related to C++20 destroying operator > delete in -Wmismatched-new-delete and -Wfree-nonheap-object. > > Tested on x86_64-pc-linux-gnu: > - make -k check > - bootstrapped > > 2026-03-04 Yifan Dong <[email protected]> > > ChangeLog: > * gimple-ssa-warn-access.cc: Handle destroying operator delete in matching > and offset-warning paths. > * testsuite/g++.dg/warn/pr100861.C: New test. > * testsuite/g++.dg/warn/pr121717.C: New test. > > > diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc > index c8f10cae32f..fce84f4b025 100644 > --- a/gcc/gimple-ssa-warn-access.cc > +++ b/gcc/gimple-ssa-warn-access.cc > @@ -1810,6 +1810,40 @@ new_delete_mismatch_p (tree new_decl, tree > delete_decl) > return mismatch; > } > > +/* Return true if TYPE is std::destroying_delete_t. */ > + > +static bool > +std_destroying_delete_t_p (tree type) > +{ > + if (!type) > + return false; > + > + type = TYPE_MAIN_VARIANT (type); > + return (TYPE_CONTEXT (type) > + && TREE_CODE (TYPE_CONTEXT (type)) == NAMESPACE_DECL > + && DECL_NAME (TYPE_CONTEXT (type)) > + && id_equal (DECL_NAME (TYPE_CONTEXT (type)), "std") > + && TYPE_IDENTIFIER (type) > + && id_equal (TYPE_IDENTIFIER (type), "destroying_delete_t")); > +} > + > +/* Return true if FNDECL is a destroying operator delete. > + Such a function has at least two parameters and its second one has > + type std::destroying_delete_t. */ > + > +static bool > +destroying_operator_delete_p (tree fndecl) > +{ > + if (!DECL_IS_OPERATOR_DELETE_P (fndecl)) > + return false; > + > + tree args = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); > + if (!args || !TREE_CHAIN (args)) > + return false; > + > + return std_destroying_delete_t_p (TREE_VALUE (TREE_CHAIN (args))); > +} > + > /* ALLOC_DECL and DEALLOC_DECL are pair of allocation and deallocation > functions. Return true if the latter is suitable to deallocate objects > allocated by calls to the former. */ > @@ -1825,9 +1859,16 @@ matching_alloc_calls_p (tree alloc_decl, tree > dealloc_decl) > if (DECL_IS_OPERATOR_NEW_P (alloc_decl)) > { > if (DECL_IS_OPERATOR_DELETE_P (dealloc_decl)) > - /* Return true iff both functions are of the same array or > - singleton form and false otherwise. */ > - return !new_delete_mismatch_p (alloc_decl, dealloc_decl); > + { > + /* Return true iff both functions are of the same array or > + singleton form and false otherwise. Destroying delete has no > + matching operator new counterpart and so should never mismatch > + with one. */ > + if (destroying_operator_delete_p (dealloc_decl)) > + return true; > + > + return !new_delete_mismatch_p (alloc_decl, dealloc_decl); > + } > > /* Return false for deallocation functions that are known not > to match. */ > @@ -2052,6 +2093,11 @@ warn_dealloc_offset (location_t loc, gimple *call, > const access_ref &aref) > if (!dealloc_decl) > return false; > > + /* A destroying operator delete can legitimately be invoked with an > + adjusted base-subobject pointer. */ > + if (destroying_operator_delete_p (dealloc_decl)) > + return false; > + > if (DECL_IS_OPERATOR_DELETE_P (dealloc_decl) > && !DECL_IS_REPLACEABLE_OPERATOR (dealloc_decl)) > { > diff --git a/gcc/testsuite/g++.dg/warn/pr100861.C > b/gcc/testsuite/g++.dg/warn/pr100861.C > new file mode 100644 > index 00000000000..37ea5129c56 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/pr100861.C > @@ -0,0 +1,31 @@ > +/* PR c++/100861 */ > +/* { dg-do compile { target c++20 } } */ > +/* { dg-additional-options "-Wmismatched-new-delete" } */ > + > +typedef __SIZE_TYPE__ size_t; > + > +namespace std { > +struct destroying_delete_t > +{ > + explicit destroying_delete_t () = default; > +}; > +} // namespace std > + > +void *operator new (size_t); > +void operator delete (void *) noexcept; > + > +struct Widget > +{ > + void operator delete (Widget *p, std::destroying_delete_t) > + { > + p->~Widget (); > + ::operator delete (p); > + } > +}; > + > +void > +f () > +{ > + Widget *p = new Widget; > + delete p; // { dg-bogus "Wmismatched-new-delete" } > +} > diff --git a/gcc/testsuite/g++.dg/warn/pr121717.C > b/gcc/testsuite/g++.dg/warn/pr121717.C > new file mode 100644 > index 00000000000..86a0362b8c2 > --- /dev/null > +++ b/gcc/testsuite/g++.dg/warn/pr121717.C > @@ -0,0 +1,30 @@ > +/* PR middle-end/121717 */ > +/* { dg-do compile { target c++20 } } */ > +/* { dg-options "-O2 -Wfree-nonheap-object" } */ > + > +typedef __SIZE_TYPE__ size_t; > + > +namespace std { > +struct destroying_delete_t > +{ > + explicit destroying_delete_t () = default; > +}; > +} // namespace std > + > +struct A > +{ > + virtual ~A (); > + void operator delete (A *, std::destroying_delete_t, size_t) noexcept; > +}; > + > +struct B > +{ > + virtual void b () = 0; > +}; > + > +class X : private B, public A > +{ > + ~X () override; > +}; > + > +X::~X () {} // { dg-bogus "-Wfree-nonheap-object" } > > > Best, > Yifan >
