calls: Fix error recovery after sorry differently [PR104989]
On Mon, Feb 28, 2022 at 07:52:56AM -0000, Roger Sayle wrote: > This patch resolves PR c++/84964 which is an ICE in the middle-end after > emitting a "sorry, unimplemented" message, and is a regression from > earlier releases of GCC. This issue is that after encountering a > function call requiring an unreasonable amount of stack space, the > code continues and falls foul of an assert checking that stack pointer > has been correctly updated. The fix is to (locally) consider aborted > function calls as "no return", which skips this downstream sanity check. As can be seen on PR104989, just setting ECF_NORETURN after sorry is quite risky and leads to other ICEs. The problem is that ECF_NORETURN calls better should be at the end of basic blocks that don't have any fallthru successor edges, otherwise we can ICE later. This patch instead sets sibcall_failure if in pass == 0 (sibcall_failure means that the tail call sequence is not useful/not desirable and throws it away) and otherwise sets a new bool variable that will let us pass the assertion and also throws away the whole call sequence, I think that is best for error recovery. 2022-03-22 Jakub Jelinek <jakub@redhat.com> PR rtl-optimization/104989 * calls.cc (expand_call): Don't set ECF_NORETURN in flags after sorry for passing too large argument, instead set sibcall_failure for pass == 0, or a new normal_failure flag otherwise. If normal_failure is set, don't assert all stack has been deallocated at the end and throw away the whole insn sequence. * g++.dg/other/pr104989.C: New test.
This commit is contained in:
parent
c6bc483565
commit
6adbb51eaa
@ -3068,6 +3068,7 @@ expand_call (tree exp, rtx target, int ignore)
|
|||||||
for (pass = try_tail_call ? 0 : 1; pass < 2; pass++)
|
for (pass = try_tail_call ? 0 : 1; pass < 2; pass++)
|
||||||
{
|
{
|
||||||
int sibcall_failure = 0;
|
int sibcall_failure = 0;
|
||||||
|
bool normal_failure = false;
|
||||||
/* We want to emit any pending stack adjustments before the tail
|
/* We want to emit any pending stack adjustments before the tail
|
||||||
recursion "call". That way we know any adjustment after the tail
|
recursion "call". That way we know any adjustment after the tail
|
||||||
recursion call can be ignored if we indeed use the tail
|
recursion call can be ignored if we indeed use the tail
|
||||||
@ -3448,7 +3449,10 @@ expand_call (tree exp, rtx target, int ignore)
|
|||||||
{
|
{
|
||||||
sorry ("passing too large argument on stack");
|
sorry ("passing too large argument on stack");
|
||||||
/* Don't worry about stack clean-up. */
|
/* Don't worry about stack clean-up. */
|
||||||
flags |= ECF_NORETURN;
|
if (pass == 0)
|
||||||
|
sibcall_failure = 1;
|
||||||
|
else
|
||||||
|
normal_failure = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3905,9 +3909,12 @@ expand_call (tree exp, rtx target, int ignore)
|
|||||||
|
|
||||||
/* Verify that we've deallocated all the stack we used. */
|
/* Verify that we've deallocated all the stack we used. */
|
||||||
gcc_assert ((flags & ECF_NORETURN)
|
gcc_assert ((flags & ECF_NORETURN)
|
||||||
|
|| normal_failure
|
||||||
|| known_eq (old_stack_allocated,
|
|| known_eq (old_stack_allocated,
|
||||||
stack_pointer_delta
|
stack_pointer_delta
|
||||||
- pending_stack_adjust));
|
- pending_stack_adjust));
|
||||||
|
if (normal_failure)
|
||||||
|
normal_call_insns = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If something prevents making this a sibling call,
|
/* If something prevents making this a sibling call,
|
||||||
|
9
gcc/testsuite/g++.dg/other/pr104989.C
Normal file
9
gcc/testsuite/g++.dg/other/pr104989.C
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// PR rtl-optimization/104989
|
||||||
|
// { dg-do compile }
|
||||||
|
// { dg-options "-fnon-call-exceptions" }
|
||||||
|
|
||||||
|
struct a {
|
||||||
|
short b : -1ULL;
|
||||||
|
};
|
||||||
|
void c(...) { c(a()); }
|
||||||
|
// { dg-excess-errors "" }
|
Loading…
x
Reference in New Issue
Block a user