Jason Merrill <ja...@redhat.com> writes: > On 8/2/24 4:36 PM, Arsen Arsenović wrote: >> I'm not 100% clear on what the semantics of the matching here are meant >> to be - AFAICT, an operator new/delete pair matches (after falling >> through the other cases) if all their components (besides the actual >> operator name, of course) match, and the pair of actual operator names >> matches if one is a singleton new and the other a singleton delete, or, >> similarly, if one is an array new and the other an array delete. We >> also appear to ignore their argument types (or so it seems by >> experimentation - I was not able to quite discern what path those take). > > Ignoring argument types is correct, placement delete is only called for > exception handling.
ACK - good to know. >> Stripping operator template arguments from either side of the pair >> should have no impact on this logic, I think. > > Agreed. > >> Tested on x86_64-pc-linux-gnu, no regressions. >> OK for trunk? >> TIA, have a lovely evening. >> ---------- >8 ---------- >> Template parameters on a member operator new cannot affect its member >> status nor whether it is a singleton or array operator new, hence, we >> can ignore it for purposes of matching. Similar logic applies to the >> placement operator delete. >> In the PR (and a lot of idiomatic coroutine code generally), operator >> new is templated in order to be able to inspect (some of) the arguments >> passed to the coroutine, to make allocation-related decisions. However, >> the coroutine implementation will not call a placement delete form, so >> it cannot get templated. As a result, when demangling, we have an extra >> template DEMANGLE_COMPONENT_TEMPLATE around the actual operator new, but >> not operator delete. This terminates new_delete_mismatch_p early. >> PR middle-end/109224 - Wmismatched-new-delete false positive with a templated >> operator new (common with coroutines) >> gcc/ChangeLog: >> PR middle-end/109224 >> * gimple-ssa-warn-access.cc (new_delete_mismatch_p): Strip >> DEMANGLE_COMPONENT_TEMPLATE from the operator new and operator >> after demangling. >> gcc/testsuite/ChangeLog: >> PR middle-end/109224 >> * g++.dg/warn/Wmismatched-new-delete-9.C: New test. >> --- >> gcc/gimple-ssa-warn-access.cc | 18 ++++++- >> .../g++.dg/warn/Wmismatched-new-delete-9.C | 47 +++++++++++++++++++ >> gcc/testsuite/g++.dg/warn/pr109224.C | 25 ++++++++++ >> 3 files changed, 89 insertions(+), 1 deletion(-) >> create mode 100644 gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C >> create mode 100644 gcc/testsuite/g++.dg/warn/pr109224.C >> diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc >> index 61f9f0f3d310..e3fec5fb8e77 100644 >> --- a/gcc/gimple-ssa-warn-access.cc >> +++ b/gcc/gimple-ssa-warn-access.cc >> @@ -1762,7 +1762,23 @@ new_delete_mismatch_p (tree new_decl, tree >> delete_decl) >> void *np = NULL, *dp = NULL; >> demangle_component *ndc = cplus_demangle_v3_components (new_str, 0, &np); >> demangle_component *ddc = cplus_demangle_v3_components (del_str, 0, &dp); >> - bool mismatch = ndc && ddc && new_delete_mismatch_p (*ndc, *ddc); >> + >> + /* Sometimes, notably quite often with coroutines, 'operator new' is >> + templated. However, template arguments can't change whether a given >> + new/delete is a singleton or array one, nor what it is a member of, so >> + the template arguments can be safely ignored for the purposes of >> checking >> + for mismatches. */ >> + >> + auto strip_dc_template = [] (demangle_component* dc) >> + { >> + if (dc->type == DEMANGLE_COMPONENT_TEMPLATE) >> + dc = dc->u.s_binary.left; >> + return dc; >> + }; >> + >> + bool mismatch = ndc && ddc >> + && new_delete_mismatch_p (*strip_dc_template (ndc), >> + *strip_dc_template (ddc)); > > The && should not be left of the =; if the initializer needs to span multiple > lines, it's usually best to wrap it in (). Okay - done. >> free (np); >> free (dp); >> return mismatch; >> diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C >> b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C >> new file mode 100644 >> index 000000000000..fa511bbfdb4b >> --- /dev/null >> +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C >> @@ -0,0 +1,47 @@ >> +/* { dg-do compile { target c++11 } } */ >> +/* { dg-additional-options "-Wmismatched-new-delete" } */ >> +/* PR middle-end/109224 */ >> +/* Verify that we consider templated operator new matching with its operator >> + delete. */ >> + >> +#include <new> >> + >> +struct foo >> +{ >> + template<typename... Args> >> + void* operator new (std::size_t sz, Args&&...); >> + template<typename... Args> >> + void* operator new[] (std::size_t sz, Args&&...); >> + >> + void operator delete (void* x); >> + void operator delete[] (void* x); >> + >> + template<typename... Args> >> + void operator delete (void* x, Args&&...); >> + template<typename... Args> >> + void operator delete[] (void* x, Args&&...); >> +}; >> + >> +void >> +f () >> +{ >> + delete (new (123, true) foo); >> + delete[] (new (123, true) foo[123]); >> + >> + delete (new (123, true) foo[123]); >> + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } >> + // { dg-note "returned from" "" { target *-*-* } {.-2} } >> + delete[] (new (123, true) foo); >> + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } >> + // { dg-note "returned from" "" { target *-*-* } {.-2} } >> + >> + foo::operator delete (new (123, true) foo, 123, true); >> + foo::operator delete[] (new (123, true) foo[123], 123, true); > > Instead of passing the result of a new-expression directly to operator delete, > you should also call operator new directly. > >> + foo::operator delete (new (123, true) foo[123], 123, true); >> + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } >> + // { dg-note "returned from" "" { target *-*-* } {.-2} } >> + foo::operator delete[] (new (123, true) foo, 123, true); > > Likewise. Ah, good point - adjusted. Here are the changes to v1 I've made as well as the full patch below them. Does this look OK? --8<---------------cut here---------------start------------->8--- modified gcc/gimple-ssa-warn-access.cc @@ -1776,9 +1776,9 @@ new_delete_mismatch_p (tree new_decl, tree delete_decl) return dc; }; - bool mismatch = ndc && ddc - && new_delete_mismatch_p (*strip_dc_template (ndc), - *strip_dc_template (ddc)); + bool mismatch = (ndc && ddc + && new_delete_mismatch_p (*strip_dc_template (ndc), + *strip_dc_template (ddc))); free (np); free (dp); return mismatch; modified gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C @@ -35,13 +35,13 @@ f () // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } // { dg-note "returned from" "" { target *-*-* } {.-2} } - foo::operator delete (new (123, true) foo, 123, true); - foo::operator delete[] (new (123, true) foo[123], 123, true); + foo::operator delete (foo::operator new (1, 123, true), 123, true); + foo::operator delete[] (foo::operator new[] (123, 123, true), 123, true); - foo::operator delete (new (123, true) foo[123], 123, true); + foo::operator delete (foo::operator new[] (123, 123, true), 123, true); // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } // { dg-note "returned from" "" { target *-*-* } {.-2} } - foo::operator delete[] (new (123, true) foo, 123, true); + foo::operator delete[] (foo::operator new (1, 123, true), 123, true); // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } // { dg-note "returned from" "" { target *-*-* } {.-2} } } --8<---------------cut here---------------end--------------->8--- ---------- >8 ---------- Template parameters on a member operator new cannot affect its member status nor whether it is a singleton or array operator new, hence, we can ignore it for purposes of matching. Similar logic applies to the placement operator delete. In the PR (and a lot of idiomatic coroutine code generally), operator new is templated in order to be able to inspect (some of) the arguments passed to the coroutine, to make allocation-related decisions. However, the coroutine implementation will not call a placement delete form, so it cannot get templated. As a result, when demangling, we have an extra template DEMANGLE_COMPONENT_TEMPLATE around the actual operator new, but not operator delete. This terminates new_delete_mismatch_p early. PR middle-end/109224 - Wmismatched-new-delete false positive with a templated operator new (common with coroutines) gcc/ChangeLog: * gimple-ssa-warn-access.cc (new_delete_mismatch_p): Strip DEMANGLE_COMPONENT_TEMPLATE from the operator new and operator after demangling. gcc/testsuite/ChangeLog: * g++.dg/warn/Wmismatched-new-delete-9.C: New test. --- gcc/gimple-ssa-warn-access.cc | 18 ++++++- .../g++.dg/warn/Wmismatched-new-delete-9.C | 47 +++++++++++++++++++ gcc/testsuite/g++.dg/warn/pr109224.C | 25 ++++++++++ 3 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C create mode 100644 gcc/testsuite/g++.dg/warn/pr109224.C diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 61f9f0f3d310..fcce63ee332d 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -1762,7 +1762,23 @@ new_delete_mismatch_p (tree new_decl, tree delete_decl) void *np = NULL, *dp = NULL; demangle_component *ndc = cplus_demangle_v3_components (new_str, 0, &np); demangle_component *ddc = cplus_demangle_v3_components (del_str, 0, &dp); - bool mismatch = ndc && ddc && new_delete_mismatch_p (*ndc, *ddc); + + /* Sometimes, notably quite often with coroutines, 'operator new' is + templated. However, template arguments can't change whether a given + new/delete is a singleton or array one, nor what it is a member of, so + the template arguments can be safely ignored for the purposes of checking + for mismatches. */ + + auto strip_dc_template = [] (demangle_component* dc) + { + if (dc->type == DEMANGLE_COMPONENT_TEMPLATE) + dc = dc->u.s_binary.left; + return dc; + }; + + bool mismatch = (ndc && ddc + && new_delete_mismatch_p (*strip_dc_template (ndc), + *strip_dc_template (ddc))); free (np); free (dp); return mismatch; diff --git a/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C new file mode 100644 index 000000000000..d431f4049e87 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C @@ -0,0 +1,47 @@ +/* { dg-do compile { target c++11 } } */ +/* { dg-additional-options "-Wmismatched-new-delete" } */ +/* PR middle-end/109224 */ +/* Verify that we consider templated operator new matching with its operator + delete. */ + +#include <new> + +struct foo +{ + template<typename... Args> + void* operator new (std::size_t sz, Args&&...); + template<typename... Args> + void* operator new[] (std::size_t sz, Args&&...); + + void operator delete (void* x); + void operator delete[] (void* x); + + template<typename... Args> + void operator delete (void* x, Args&&...); + template<typename... Args> + void operator delete[] (void* x, Args&&...); +}; + +void +f () +{ + delete (new (123, true) foo); + delete[] (new (123, true) foo[123]); + + delete (new (123, true) foo[123]); + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } + // { dg-note "returned from" "" { target *-*-* } {.-2} } + delete[] (new (123, true) foo); + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } + // { dg-note "returned from" "" { target *-*-* } {.-2} } + + foo::operator delete (foo::operator new (1, 123, true), 123, true); + foo::operator delete[] (foo::operator new[] (123, 123, true), 123, true); + + foo::operator delete (foo::operator new[] (123, 123, true), 123, true); + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } + // { dg-note "returned from" "" { target *-*-* } {.-2} } + foo::operator delete[] (foo::operator new (1, 123, true), 123, true); + // { dg-warning "Wmismatched-new-delete" "" { target *-*-* } {.-1} } + // { dg-note "returned from" "" { target *-*-* } {.-2} } +} diff --git a/gcc/testsuite/g++.dg/warn/pr109224.C b/gcc/testsuite/g++.dg/warn/pr109224.C new file mode 100644 index 000000000000..4b6102226ffc --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/pr109224.C @@ -0,0 +1,25 @@ +// { dg-do compile { target c++20 } } +#include <coroutine> + +struct Task { + struct promise_type { + std::suspend_never initial_suspend() { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + void unhandled_exception() { throw; } + Task get_return_object() { return {}; } + void return_void() {} + + template<class I> + void* operator new(std::size_t sz, I); + + void operator delete(void* ptr, std::size_t); + }; +}; + +Task f(int) { + co_return; +} + +int main() { + f(42); +} -- 2.46.0
signature.asc
Description: PGP signature