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);
/* 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))
{
}
mark_transaction_restart_calls (stmt);
+
+ cfun->calls_setjmp = saved_calls_setjmp;
}
--- /dev/null
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern int __attribute__((returns_twice)) setjmp(void*);
+
+void bbb(void) {
+ int (*fnptr)(void*) = setjmp;
+ fnptr(0);
+}
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;
}