re PR c++/9993 (destructor not called for local object created within and returned...
authorJason Merrill <jason@redhat.com>
Mon, 17 Mar 2003 15:45:29 +0000 (10:45 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 17 Mar 2003 15:45:29 +0000 (10:45 -0500)
        PR c++/9993
        * decl.c (finish_function): Only allow the NRVO to use variables
        declared at function scope.

From-SVN: r64488

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/g++.dg/opt/nrv6.C [new file with mode: 0644]

index c0a968f33d06292c4743f0989608d4d32ead4e47..2439eddb630589530016f3b8a251aaf084ceb258 100644 (file)
@@ -1,3 +1,9 @@
+2003-03-16  Jason Merrill  <jason@redhat.com>
+
+       PR c++/9993
+       * decl.c (finish_function): Only allow the NRVO to use variables
+       declared at function scope.
+
 2003-03-17  Andreas Jaeger  <aj@suse.de>
 
        * Make-lang.in (cp/TAGS): Remove.
index 6d68251063069e37c2c61788834b4c48372f40fe..e00a5f32e38b59e57629bfb78584053b814bc8a4 100644 (file)
@@ -14092,11 +14092,21 @@ finish_function (int flags)
   if (current_function_return_value)
     {
       tree r = current_function_return_value;
-      /* This is only worth doing for fns that return in memory--and
-        simpler, since we don't have to worry about promoted modes.  */
+      tree outer;
+
       if (r != error_mark_node
-         && aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl))))
+         /* This is only worth doing for fns that return in memory--and
+            simpler, since we don't have to worry about promoted modes.  */
+         && aggregate_value_p (TREE_TYPE (TREE_TYPE (fndecl)))
+         /* Only allow this for variables declared in the outer scope of
+            the function so we know that their lifetime always ends with a
+            return; see g++.dg/opt/nrv6.C.  We could be more flexible if
+            we were to do this optimization in tree-ssa.  */
+         /* Skip the artificial function body block.  */
+         && (outer = BLOCK_SUBBLOCKS (BLOCK_SUBBLOCKS (DECL_INITIAL (fndecl))),
+             chain_member (r, BLOCK_VARS (outer))))
        {
+         
          DECL_ALIGN (r) = DECL_ALIGN (DECL_RESULT (fndecl));
          walk_tree_without_duplicates (&DECL_SAVED_TREE (fndecl),
                                        nullify_returns_r, r);
diff --git a/gcc/testsuite/g++.dg/opt/nrv6.C b/gcc/testsuite/g++.dg/opt/nrv6.C
new file mode 100644 (file)
index 0000000..57ff12e
--- /dev/null
@@ -0,0 +1,26 @@
+// PR c++/9993
+// Bug: We were failing to destroy b.
+
+// { dg-do run }
+
+int c, d;
+
+struct Object {
+  Object()                      { ++c; }
+  Object(const Object&)         { ++c; }
+  ~Object()                     { ++d; }
+};
+
+Object function() {
+  int i = 0;
+  do {
+    Object b;
+    if (i++ == 2)
+      return b;
+  } while (1);
+}
+
+int main() {
+  function();
+  return c != d;
+}