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;
--- /dev/null
+/* { 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} }
+}
--- /dev/null
+// { 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);
+}