| /* The goal here is to ensure that we never consider a call to a noreturn |
| function as a potential tail call. |
| |
| Right now GCC discovers potential tail calls by looking at the |
| predecessors of the exit block. A call to a non-return function |
| has no successors and thus can never match that first filter. |
| |
| But that could change one day and we want to catch it. The problem |
| is the compiler could potentially optimize a tail call to a nonreturn |
| function, even if the caller has a frame. That breaks the assumption |
| that calls probe *sp when saving the return address that some targets |
| depend on to elide stack probes. */ |
| |
| /* { dg-do compile } */ |
| /* { dg-options "-O2 -fstack-clash-protection -fdump-tree-tailc -fdump-tree-optimized" } */ |
| /* { dg-require-effective-target supports_stack_clash_protection } */ |
| |
| extern void foo (void) __attribute__ ((__noreturn__)); |
| |
| |
| void |
| test_direct_1 (void) |
| { |
| foo (); |
| } |
| |
| void |
| test_direct_2 (void) |
| { |
| return foo (); |
| } |
| |
| void (*indirect)(void)__attribute__ ((noreturn)); |
| |
| |
| void |
| test_indirect_1 () |
| { |
| (*indirect)(); |
| } |
| |
| void |
| test_indirect_2 (void) |
| { |
| return (*indirect)();; |
| } |
| |
| |
| typedef void (*pvfn)() __attribute__ ((noreturn)); |
| |
| void (*indirect_casted)(void); |
| |
| void |
| test_indirect_casted_1 () |
| { |
| (*(pvfn)indirect_casted)(); |
| } |
| |
| void |
| test_indirect_casted_2 (void) |
| { |
| return (*(pvfn)indirect_casted)(); |
| } |
| /* { dg-final { scan-tree-dump-not "tail call" "tailc" } } */ |
| /* { dg-final { scan-tree-dump-not "tail call" "optimized" } } */ |
| |