On Thu, Mar 20, 2025 at 09:19:02AM -0700, Andi Kleen wrote: > The inlining was just one of the issue, there are some related to > different semantics of escaped locals. gcc always errors out while > LLVM declares it undefined. > > But maybe we can fix that one too.
I have 3 patches to be tested, the inline one, fnsplit one and ipa-icf one. For the escaped locals, I guess we need to decide if [[clang::musttail]] will be something different from [[gnu::musttail]] in GCC or not (and if yes, what __attribute__((musttail)) will be). The current difference in behavior is on int foo (void); void bar (int *); int baz (void) { int a; bar (&a); [[clang::musttail]] return foo (); } Clang makes the attribute not just a request to tail call it or fail, but also changes behavior and says if the code ever accesses a from the above during foo () (which without the attribute is completely valid), then it is UB. So, clang can compile this into a tail call, while GCC takes the safer approach and says it is invalid. Users can of course adjust their code to make it explicitly end lifetime before the tailcall, like with int qux (void) { { int a; bar (&a); } [[clang::musttail]] return foo (); } and then gcc should tail call it too. Strangely, it there is a var with non-trivial destructor which ends lifetime after the call, clang rejects it like gcc: struct S { S (); ~S (); int s; }; int corge (void) { S a; bar (&a.s); [[clang::musttail]] return foo (); } Jakub