https://gcc.gnu.org/bugzilla/show_bug.cgi?id=123513

            Bug ID: 123513
           Summary: False positive -Wmismatched-new-delete with a
                    non-member template operator new
           Product: gcc
           Version: 16.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: middle-end
          Assignee: unassigned at gcc dot gnu.org
          Reporter: aaron.puchert at sap dot com
  Target Milestone: ---

Compile this with -Wall:

#include <cstddef>
#include <stdio.h>
#include <new>

template <size_t SlabSize>
class BumpAllocator {};

class C {};

template <size_t SlabSize>
void* operator new(size_t, BumpAllocator<SlabSize>&);

template <size_t SlabSize>
void operator delete(void*, BumpAllocator<SlabSize>&);

void test() {
    BumpAllocator<1024> alloc;
    new (alloc) C();
}

This warns:

<source>: In function 'void test()':
<source>:18:19: warning: 'void operator delete(void*, BumpAllocator<SlabSize>&)
[with long unsigned int SlabSize = 1024]' called on pointer returned from a
mismatched allocation function [-Wmismatched-new-delete]
   18 |     new (alloc) C();
      |                   ^
<source>:18:19: note: returned from 'void* operator new(size_t,
BumpAllocator<SlabSize>&) [with long unsigned int SlabSize = 1024]'
   18 |     new (alloc) C();
      |                   ^

This is reproducible with trunk, but I've debugged it with GCC 13. We're here:

valid_new_delete_pair_p (new_asm=new_asm@entry=0x7ffff6a74d00,
delete_asm=delete_asm@entry=0x7ffff6a74cc0,
pcertain=pcertain@entry=0x7fffffffd627)
    at ../../gcc/tree.cc:14816

Source:
https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/tree.cc;hb=releases/gcc-13.2.0#l14811.

(gdb) p new_name
$3 = 0x7ffff6a7c708 "_ZnwILm1024EEPvmR13BumpAllocatorIXT_EE"
(gdb) p delete_name
$4 = 0x7ffff6a4bca8 "_ZdlILm1024EEvPvR13BumpAllocatorIXT_EE"

We pass these lines:

14852   /* The following failures are certain mismatches.  */
14853   *pcertain = true;

Then exit here after consuming "_Znw":

14859   /* 'j', 'm' and 'y' correspond to size_t.  */
14860   if (new_name[3] != 'j' && new_name[3] != 'm' && new_name[3] != 'y')
14861     return false;

Before the desired "m" we have "ILm1024EEPv". "I[…]E" stands for a template
argument, "Lm1024E" stands for 1024, and "Pv" for the return type "void*".

It seems like the detection should skip template arguments (and if they exist,
the return type) before continuing with the parameters.

Reply via email to