calls: Fix error recovery after sorry differently [PR104989]
authorJakub Jelinek <jakub@redhat.com>
Tue, 22 Mar 2022 07:39:40 +0000 (08:39 +0100)
committerJakub Jelinek <jakub@redhat.com>
Tue, 22 Mar 2022 07:39:40 +0000 (08:39 +0100)
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.

gcc/calls.cc
gcc/testsuite/g++.dg/other/pr104989.C [new file with mode: 0644]

index 50fa7b8..e13469c 100644 (file)
@@ -3068,6 +3068,7 @@ expand_call (tree exp, rtx target, int ignore)
   for (pass = try_tail_call ? 0 : 1; pass < 2; pass++)
     {
       int sibcall_failure = 0;
+      bool normal_failure = false;
       /* We want to emit any pending stack adjustments before the tail
         recursion "call".  That way we know any adjustment after 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");
                  /* Don't worry about stack clean-up.  */
-                 flags |= ECF_NORETURN;
+                 if (pass == 0)
+                   sibcall_failure = 1;
+                 else
+                   normal_failure = true;
                  continue;
                }
 
@@ -3905,9 +3909,12 @@ expand_call (tree exp, rtx target, int ignore)
 
          /* Verify that we've deallocated all the stack we used.  */
          gcc_assert ((flags & ECF_NORETURN)
+                     || normal_failure
                      || known_eq (old_stack_allocated,
                                   stack_pointer_delta
                                   - pending_stack_adjust));
+         if (normal_failure)
+           normal_call_insns = NULL;
        }
 
       /* If something prevents making this a sibling call,
diff --git a/gcc/testsuite/g++.dg/other/pr104989.C b/gcc/testsuite/g++.dg/other/pr104989.C
new file mode 100644 (file)
index 0000000..8b1f79b
--- /dev/null
@@ -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 "" }