https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107661
--- Comment #8 from Sergei Trofimovich <slyfox at gcc dot gnu.org> --- (In reply to Sergei Trofimovich from comment #7) > When debug reports unqualified `Aggregate replacements: 1[0]=callback_fn` > does it mean ipa-cp does not distinguish between: > * static void function_ref::callback_fn(void*) [with Callable = > seemingly_unused_foo(int)::L]/30. > * static void function_ref::callback_fn(void*) [with Callable = void()]/29. > ? > > I suspect it does not and that results in a wrong callback_fn inline. That was not it. Identical names is a printing artifact. I shrunk example a bit more to avoid any overloads and crashes. Now example just prints different things. // How to break: // $ ./gcc-13-snap/bin/gcc -O1 -fipa-cp -fipa-cp-clone a.cc -o a && ./a // GOOD // BAD // $ ./gcc-13-snap/bin/gcc -O1 -fipa-cp -fipa-cp-clone -DDISABLE_HACK a.cc -o a && ./a // GOOD // GOOD // #define DISABLE_HACK 1 #include <stdio.h> struct R {} RGood; struct L {} LBad; static void L_run(void) { fprintf(stderr, "BAD\n"); } static void callback_fn_L(void) { L_run(); } static void callback_fn_R(void) { fprintf(stderr, "GOOD\n"); } struct function_ref { void (*callback)(void) = nullptr; function_ref(L * pl) { callback = callback_fn_L; } function_ref(R * pr) { callback = callback_fn_R; } }; // allow one level of recursion to call callback twice static int is_recur(void) { static int n = 0; switch (n++) { case 0: return 1; default: return 0; } } static void do3(volatile int * punused, function_ref Expired) { Expired.callback(); if (is_recur()) do3(punused, Expired); } static void do1(function_ref Expired) { volatile int unused = 42; do3(&unused, Expired); } int main(void) { do1(&RGood); } #if defined(DISABLE_HACK) #else void seemingly_unused_foo(void) { do1(&LBad); } #endif