diff options
author | Arsen Arsenović <arsen@aarsen.me> | 2024-08-01 17:38:15 +0200 |
---|---|---|
committer | Arsen Arsenović <arsen@gcc.gnu.org> | 2024-12-21 20:52:13 +0100 |
commit | 7d83a32aacd6005c0c038c74562e35d70f6a77a8 (patch) | |
tree | 72742da9ae59a8b6eb189da4c08c38e26de01c50 | |
parent | d637e6d069ade775a4b61f51fff61fe4cce01c36 (diff) | |
download | gcc-7d83a32aacd6005c0c038c74562e35d70f6a77a8.zip gcc-7d83a32aacd6005c0c038c74562e35d70f6a77a8.tar.gz gcc-7d83a32aacd6005c0c038c74562e35d70f6a77a8.tar.bz2 |
warn-access: ignore template parameters when matching operator new/delete [PR109224]
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.
-rw-r--r-- | gcc/gimple-ssa-warn-access.cc | 18 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C | 47 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/warn/pr109224.C | 25 |
3 files changed, 89 insertions, 1 deletions
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc index 820f238..1eb9d2e 100644 --- a/gcc/gimple-ssa-warn-access.cc +++ b/gcc/gimple-ssa-warn-access.cc @@ -1765,7 +1765,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 0000000..d431f40 --- /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 0000000..4b610222 --- /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); +} |