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

--- Comment #3 from Lukas Grätz <lukas.gra...@tu-darmstadt.de> ---
(In reply to Jakub Jelinek from comment #1)
> We completely intentionally don't emit tail calls to noreturn functions, so
> that e.g. in case of abort one doesn't need to virtually reconstruct
> backtrace.
> In your case, the interprocedural optimizations determine expr_main_original
> is noreturn and so calls it normally (and optimizes away anything after that
> call).

Thank you very much indeed! (Ah yes, this also explains why there is not
"ret".) And sorry for not realizing that this is duplicate. So the "call" is
intentionally emitted by gcc for a better debugging experience. I agree, this
makes perfectly sense in many cases.

However, the price of better debugging seems to be the danger of a stack
overflow. After I understood your "complete" intention, it took me about 20 min
to construct an example with bears a stack overflow following that intention.

---
void foo(int n) {
    if (n == 0)
        exit(0);
    int x[200];
    for (int i = 0; i < 200; i++)
        extern_function(x[i], x[200-i]);
    return foo(n-1);
}
---

After adding __attribute__((noreturn)), compiling with -O3 and passing 10000 to
foo(), I get a segmentation fault. There is still a warning "function declared
‘noreturn’ has a ‘return’ statement". But in our case, the noreturn attribute
is not wrong, because none of the recursive calls actually do return. This
might be something that interprocedure optimizations detect in the future. So
even without attribute noreturn, gcc could decide to produce no tail recursion
(because it is a noreturn function, regardless of the noreturn attribute).

Last remark, then I remain silent. I just learned that clang actually has the
attribute musttail which would help for my reported C file as well as in the
foo() example above to prevent the stack overflow. But I guess it is not
planned to add musttail to gcc?

Reply via email to