]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Fix crash during NRV optimization with invalid input [PR117099, PR117129]
authorSimon Martin <simon@nasilyan.com>
Tue, 5 Nov 2024 09:44:34 +0000 (10:44 +0100)
committerSimon Martin <simon@nasilyan.com>
Tue, 5 Nov 2024 09:44:34 +0000 (10:44 +0100)
PR117099 and PR117129 are ICEs upon invalid code that happen when NRVO
is activated, and both due to the fact that we don't consistently set
current_function_return_value to error_mark_node upon error in
finish_return_expr.

This patch fixes this inconsistency which fixes both cases since we skip
calling finalize_nrv when current_function_return_value is
error_mark_node.

PR c++/117099
PR c++/117129

gcc/cp/ChangeLog:

* typeck.cc (check_return_expr): Upon error, set
current_function_return_value to error_mark_node.

gcc/testsuite/ChangeLog:

* g++.dg/parse/crash78.C: New test.
* g++.dg/parse/crash78a.C: New test.
* g++.dg/parse/crash79.C: New test.

gcc/cp/typeck.cc
gcc/testsuite/g++.dg/parse/crash78.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/crash78a.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/crash79.C [new file with mode: 0644]

index 439681216bed8e0220543057ac53f2d189bf06cf..4c15e26f692afe62500dbecf62cfbd3f8821b99a 100644 (file)
@@ -11239,6 +11239,8 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
                   "function returning %qT", valtype);
       /* Remember that this function did return.  */
       current_function_returns_value = 1;
+      /* But suppress NRV  .*/
+      current_function_return_value = error_mark_node;
       /* And signal caller that TREE_NO_WARNING should be set on the
         RETURN_EXPR to avoid control reaches end of non-void function
         warnings in tree-cfg.cc.  */
@@ -11449,7 +11451,11 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
 
       /* If the conversion failed, treat this just like `return;'.  */
       if (retval == error_mark_node)
-       return retval;
+       {
+         /* And suppress NRV.  */
+         current_function_return_value = error_mark_node;
+         return retval;
+       }
       /* We can't initialize a register from a AGGR_INIT_EXPR.  */
       else if (! cfun->returns_struct
               && TREE_CODE (retval) == TARGET_EXPR
diff --git a/gcc/testsuite/g++.dg/parse/crash78.C b/gcc/testsuite/g++.dg/parse/crash78.C
new file mode 100644 (file)
index 0000000..f30fe08
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/117099
+// { dg-do "compile" }
+
+struct X {
+  ~X();
+};
+
+X test(bool b) {
+  {
+    X x;
+    return x;
+  }
+  return X();
+  if (!(b)) return; // { dg-error "return-statement with no value" }
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash78a.C b/gcc/testsuite/g++.dg/parse/crash78a.C
new file mode 100644 (file)
index 0000000..241a5e3
--- /dev/null
@@ -0,0 +1,22 @@
+// PR c++/117099
+// With -fpermissive, make sure we don't do NRV in this case, but keep
+// executing fine. Note that the return at line 16 is undefined behaviour.
+// { dg-do "run" }
+// { dg-options "-fpermissive" }
+
+struct X {
+  ~X() {}
+};
+
+X test(bool b) {
+  X x;
+  if (b)
+    return x;
+  else
+    return; // { dg-warning "return-statement with no value" }
+}
+
+int main(int, char*[]) {
+  (void) test (false);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash79.C b/gcc/testsuite/g++.dg/parse/crash79.C
new file mode 100644 (file)
index 0000000..08d62af
--- /dev/null
@@ -0,0 +1,15 @@
+// PR c++/117129
+// { dg-do "compile" { target c++11 } }
+
+struct Noncopyable {
+  Noncopyable();
+  Noncopyable(const Noncopyable &) = delete; // { dg-note "declared here" }
+  virtual ~Noncopyable();
+};
+Noncopyable nrvo() { 
+  {
+    Noncopyable A;
+    return A; // { dg-error "use of deleted function" }
+             // { dg-note "display considered" "" { target *-*-* } .-1 }
+  }
+}