diff --git a/gcc/calls.cc b/gcc/calls.cc index 4d7f6c3d291..0242d52cfb3 100644 --- a/gcc/calls.cc +++ b/gcc/calls.cc @@ -506,11 +506,11 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, tree fndecl ATTRIBUTE_UNU if (ecf_flags & ECF_NORETURN) add_reg_note (call_insn, REG_NORETURN, const0_rtx); - if (ecf_flags & ECF_RETURNS_TWICE) - { - add_reg_note (call_insn, REG_SETJMP, const0_rtx); - cfun->calls_setjmp = 1; - } + if (ecf_flags & ECF_RETURNS_TWICE + /* We rely on GIMPLE setting this flag and here use it to + catch formerly indirect and not control-altering calls. */ + && cfun->calls_setjmp) + add_reg_note (call_insn, REG_SETJMP, const0_rtx); SIBLING_CALL_P (call_insn) = ((ecf_flags & ECF_SIBCALL) != 0); diff --git a/gcc/cfgexpand.cc b/gcc/cfgexpand.cc index 25b1558dcb9..ab143a6d2d3 100644 --- a/gcc/cfgexpand.cc +++ b/gcc/cfgexpand.cc @@ -2808,6 +2808,11 @@ expand_call_stmt (gcall *stmt) /* Must come after copying location. */ copy_warning (exp, stmt); + /* For calls that do not alter control flow avoid REG_SETJMP notes. */ + bool saved_calls_setjmp = cfun->calls_setjmp; + if (!gimple_call_ctrl_altering_p (stmt)) + cfun->calls_setjmp = false; + /* Ensure RTL is created for debug args. */ if (decl && DECL_HAS_DEBUG_ARGS_P (decl)) { @@ -2846,6 +2851,8 @@ expand_call_stmt (gcall *stmt) } mark_transaction_restart_calls (stmt); + + cfun->calls_setjmp = saved_calls_setjmp; } diff --git a/gcc/testsuite/gcc.dg/pr108691.c b/gcc/testsuite/gcc.dg/pr108691.c new file mode 100644 index 00000000000..e412df10f22 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr108691.c @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern int __attribute__((returns_twice)) setjmp(void*); + +void bbb(void) { + int (*fnptr)(void*) = setjmp; + fnptr(0); +} diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc index a9fcc7fd050..e23293e5cd1 100644 --- a/gcc/tree-cfg.cc +++ b/gcc/tree-cfg.cc @@ -2280,7 +2280,9 @@ notice_special_calls (gcall *call) if (flags & ECF_MAY_BE_ALLOCA) cfun->calls_alloca = true; - if (flags & ECF_RETURNS_TWICE) + if (flags & ECF_RETURNS_TWICE + && (!(cfun->curr_properties & PROP_cfg) + || gimple_call_ctrl_altering_p (call))) cfun->calls_setjmp = true; }