PR c++/34196
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 22 Jan 2008 04:53:33 +0000 (04:53 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 22 Jan 2008 04:53:33 +0000 (04:53 +0000)
        * tree.h (TRY_CATCH_IS_CLEANUP): New macro.
        * cp/decl.c (wrap_cleanups_r): Set TRY_CATCH_IS_CLEANUP.
        * tree-eh.c (honor_protect_cleanup_actions): Strip TRY_CATCH_EXPR
        if it is set.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@131710 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/testsuite/g++.dg/eh/init-temp2.C [new file with mode: 0644]
gcc/tree-eh.c
gcc/tree.h

index 873cdd4..d65e496 100644 (file)
@@ -1,3 +1,10 @@
+2008-01-21  Jason Merrill  <jason@redhat.com>
+
+       PR c++/34196
+       * tree.h (TRY_CATCH_IS_CLEANUP): New macro.
+       * tree-eh.c (honor_protect_cleanup_actions): Strip TRY_CATCH_EXPR
+       if it is set.
+
 2008-01-21  DJ Delorie  <dj@redhat.com>
 
        * doc/tm.texi (HARD_REGNO_NREGS): Note that this macro must not
index 768efc5..fa48f7c 100644 (file)
@@ -1,3 +1,8 @@
+2008-01-21  Jason Merrill  <jason@redhat.com>
+
+       PR c++/34196
+       * decl.c (wrap_cleanups_r): Set TRY_CATCH_IS_CLEANUP.
+
 2008-01-21  Richard Guenther  <rguenther@suse.de>
 
        PR c++/34850
index 4b2a55f..338e1ed 100644 (file)
@@ -5165,7 +5165,10 @@ wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data)
       tree tcleanup = TARGET_EXPR_CLEANUP (*stmt_p);
 
       tcleanup = build2 (TRY_CATCH_EXPR, void_type_node, tcleanup, guard);
-
+      /* Tell honor_protect_cleanup_actions to handle this as a separate
+        cleanup.  */
+      TRY_CATCH_IS_CLEANUP (tcleanup) = 1;
       TARGET_EXPR_CLEANUP (*stmt_p) = tcleanup;
     }
 
@@ -5175,7 +5178,18 @@ wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data)
 /* We're initializing a local variable which has a cleanup GUARD.  If there
    are any temporaries used in the initializer INIT of this variable, we
    need to wrap their cleanups with TRY_CATCH_EXPR (, GUARD) so that the
-   variable will be cleaned up properly if one of them throws.  */
+   variable will be cleaned up properly if one of them throws.
+
+   Unfortunately, there's no way to express this properly in terms of
+   nesting, as the regions for the temporaries overlap the region for the
+   variable itself; if there are two temporaries, the variable needs to be
+   the first thing destroyed if either of them throws.  However, we only
+   want to run the variable's cleanup if it actually got constructed.  So
+   we need to guard the temporary cleanups with the variable's cleanup if
+   they are run on the normal path, but not if they are run on the
+   exceptional path.  We implement this by telling
+   honor_protect_cleanup_actions to strip the variable cleanup from the
+   exceptional path.  */
 
 static void
 wrap_temporary_cleanups (tree init, tree guard)
diff --git a/gcc/testsuite/g++.dg/eh/init-temp2.C b/gcc/testsuite/g++.dg/eh/init-temp2.C
new file mode 100644 (file)
index 0000000..6a58dda
--- /dev/null
@@ -0,0 +1,31 @@
+// PR c++/34196
+// { dg-options "-O -Wuninitialized" }
+
+template <class _Tp> class AutoPtr
+{
+  _Tp* _M_ptr;
+
+public:
+  explicit AutoPtr(_Tp* __p = 0)  : _M_ptr(__p) {}
+
+  ~AutoPtr() { delete _M_ptr; }
+};
+
+struct A
+{
+  A() { }
+  ~A() { throw 1.0; }
+};
+
+struct B
+{
+  virtual ~B();
+};
+
+B* f (const A &s) { throw 1; }
+
+int
+main()
+{
+  AutoPtr<B> wt(f(A()));
+}
index 71d3d94..44d5a6d 100644 (file)
@@ -840,6 +840,23 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
   if (this_state)
     finally = lower_try_finally_dup_block (finally, outer_state);
 
+  /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP
+     set, the handler of the TRY_CATCH_EXPR is another cleanup which ought
+     to be in an enclosing scope, but needs to be implemented at this level
+     to avoid a nesting violation (see wrap_temporary_cleanups in
+     cp/decl.c).  Since it's logically at an outer level, we should call
+     terminate before we get to it, so strip it away before adding the
+     MUST_NOT_THROW filter.  */
+  i = tsi_start (finally);
+  x = tsi_stmt (i);
+  if (protect_cleanup_actions
+      && TREE_CODE (x) == TRY_CATCH_EXPR
+      && TRY_CATCH_IS_CLEANUP (x))
+    {
+      tsi_link_before (&i, TREE_OPERAND (x, 0), TSI_SAME_STMT);
+      tsi_delink (&i);
+    }
+
   /* Resume execution after the exception.  Adding this now lets
      lower_eh_filter not add unnecessary gotos, as it is clear that
      we never fallthru from this copy of the finally block.  */
index 52cb973..de0b11d 100644 (file)
@@ -447,6 +447,8 @@ struct gimple_stmt GTY(())
            IDENTIFIER_NODE
        CLEANUP_EH_ONLY in
            TARGET_EXPR, WITH_CLEANUP_EXPR
+       TRY_CATCH_IS_CLEANUP in
+           TRY_CATCH_EXPR
        ASM_INPUT_P in
            ASM_EXPR
        EH_FILTER_MUST_NOT_THROW in EH_FILTER_EXPR
@@ -1166,11 +1168,16 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
    should be cleaned up some day.  */
 #define TREE_STATIC(NODE) ((NODE)->base.static_flag)
 
-/* In a TARGET_EXPR, WITH_CLEANUP_EXPR, means that the pertinent cleanup
+/* In a TARGET_EXPR or WITH_CLEANUP_EXPR, means that the pertinent cleanup
    should only be executed if an exception is thrown, not on normal exit
    of its scope.  */
 #define CLEANUP_EH_ONLY(NODE) ((NODE)->base.static_flag)
 
+/* In a TRY_CATCH_EXPR, means that the handler should be considered a
+   separate cleanup in honor_protect_cleanup_actions.  */
+#define TRY_CATCH_IS_CLEANUP(NODE) \
+  (TRY_CATCH_EXPR_CHECK (NODE)->base.static_flag)
+
 /* Used as a temporary field on a CASE_LABEL_EXPR to indicate that the
    CASE_HIGH operand has been processed.  */
 #define CASE_HIGH_SEEN(NODE) \