aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorArsen Arsenović <arsen@aarsen.me>2024-08-01 17:38:15 +0200
committerArsen Arsenović <arsen@gcc.gnu.org>2024-12-21 20:52:13 +0100
commit7d83a32aacd6005c0c038c74562e35d70f6a77a8 (patch)
tree72742da9ae59a8b6eb189da4c08c38e26de01c50 /gcc
parentd637e6d069ade775a4b61f51fff61fe4cce01c36 (diff)
downloadgcc-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.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/gimple-ssa-warn-access.cc18
-rw-r--r--gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-9.C47
-rw-r--r--gcc/testsuite/g++.dg/warn/pr109224.C25
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);
+}