[PATCH] tree: Handle ::operator {new,delete} function templates as uncertain matches [PR123513]
Jason Merrill
jason@redhat.com
Thu Jan 15 04:56:58 GMT 2026
On 1/13/26 4:54 PM, Jakub Jelinek wrote:
> Hi!
>
> We have for some reason two different ways to check for matching
> ::operator new vs. ::operator delete kind. One is a dumb one in
> tree.cc (valid_new_delete_pair_p) and another one is in
> gimple-ssa-warn-access.cc (new_delete_mismatch_p).
> The former is used both in the latter and in optimizations,
> the latter only for warnings.
> The former just handles the easy cases, global operator new and
> the latter can handle everything as it uses the demangler.
> The former has essentially a tri-state return even when it has just bool
> return type, it has another bool * optional argument, so can return
> true for this is definitely ok, false with false with this might be
> not matching and false with true for this definitely doesn't match.
> false with false is returned e.g. for the class scope operator new/delete,
> where we definitely need the demangler to figure stuff out.
> false with true is returned for mismatches which are guaranteed, e.g.
> when one mangled name starts with _Znw and the other with _Zda,
> one is ::operator new and the other is ::operator delete[].
> valid_new_delete_pair_p expects that after the _Znw/_Zna/_Zdl/_Zda
> prefix (or two _ at the start instead of one) it sees [jmy] for
> the size_t argument resp. Pv for void* for delete, for delete
> then optionally the same [jmy] for sized deallocation and
> optionally RKSt9nothrow_t after it for nothrow versions or
> also something with St11align_val_t. If it has some extra arguments
> after it, it also returns false/false.
Preexisting issue, but I'm not sure why this function is trying so hard;
why do we need to do more than check that the _Zn? and _Zd? match?
There doesn't seem to be a definition of what a "valid" pair is.
> The following testcase shows another case where I'm afraid we need
> to return the maybe mismatch - when the global operators are function
> templates.
> _ZnwILm1024EEPvmR13BumpAllocatorIXT_EE
> _ZdlILm1024EEvPvR13BumpAllocatorIXT_EE
> where the Ilm1024EE here mean <1024ul> and Pv after it means function
> return type void *. As valid_new_delete_pair_p needs to find the m
> after it, it would need to know everything about what can appear
> in between I and E for the template arguments (which is a lot) and
> also be able to skip over mangling of arbitrary function return types
> (though perhaps it could hardcode those Pv vs. v cases for those).
>
> So, the following patch just returns false/false instead of false/true
> if known _Z{nw,na,dl,da} is followed by I, i.e. if it is a function
> template. For optimizations it makes no difference, those care just
> about the return value and not on *pcertain, and for the warning it
> means it will use the demangler which will figure stuff hopefully right.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2026-01-13 Jakub Jelinek <jakub@redhat.com>
>
> PR tree-optimization/123513
> * tree.cc (valid_new_delete_pair_p): Change nonnull to false in
> function comment. If new_name[3] or delete_name[3] is 'I', return
> false with *pcertain set to false rather than true.
>
> * g++.dg/warn/Wmismatched-new-delete-10.C: New test.
>
> --- gcc/tree.cc.jj 2026-01-12 09:58:18.748429069 +0100
> +++ gcc/tree.cc 2026-01-12 19:21:33.465016103 +0100
> @@ -15269,7 +15269,7 @@ verify_type_context (location_t loc, typ
>
> /* Return true if NEW_ASM and DELETE_ASM name a valid pair of new and
> delete operators. Return false if they may or may not name such
> - a pair and, when nonnull, set *PCERTAIN to true if they certainly
> + a pair and, when false, set *PCERTAIN to true if they certainly
This change seems wrong; if pcertain is null we change a local variable
instead of anything from the function argument.
> do not. */
>
> bool
> @@ -15318,6 +15318,13 @@ valid_new_delete_pair_p (tree new_asm, t
> if ((new_name[2] != 'w' || delete_name[2] != 'l')
> && (new_name[2] != 'a' || delete_name[2] != 'a'))
> return false;
> + if (new_name[3] == 'I' || delete_name[3] == 'I')
> + {
> + /* When ::operator new or ::operator delete are function templates,
> + return uncertain mismatch, we need demangler in that case. */
> + *pcertain = false;
> + return false;
> + }
> /* 'j', 'm' and 'y' correspond to size_t. */
> if (new_name[3] != 'j' && new_name[3] != 'm' && new_name[3] != 'y')
> return false;
> --- gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-10.C.jj 2026-01-12 19:29:55.725562439 +0100
> +++ gcc/testsuite/g++.dg/warn/Wmismatched-new-delete-10.C 2026-01-12 19:29:17.085212804 +0100
> @@ -0,0 +1,25 @@
> +// PR tree-optimization/123513
> +// { dg-do compile }
> +// { dg-options "-Wmismatched-new-delete" }
> +
> +typedef __SIZE_TYPE__ size_t;
> +
> +template <size_t N>
> +class A {};
> +struct B { B (); };
> +
> +template <size_t N>
> +void *operator new (size_t, A <N> &);
> +
> +template <size_t N>
> +void operator delete (void *, A <N> &);
> +
> +void
> +foo (B *, A <1024> &);
> +
> +void
> +bar ()
> +{
> + A <1024> a;
> + foo (new (a) B (), a); // { dg-bogus "called on pointer returned from a mismatched allocation function" }
> +}
>
> Jakub
>
More information about the Gcc-patches
mailing list