aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2008-01-21 23:53:33 -0500
committerJason Merrill <jason@gcc.gnu.org>2008-01-21 23:53:33 -0500
commit33b45227e0826ce8ddfe659c42f2c35cc0814065 (patch)
tree1cf758304e987f9c212d745d72e58a7eefe2e85f
parent9444edce910401a6aaf7fb7a535d52f6c2780be4 (diff)
downloadgcc-33b45227e0826ce8ddfe659c42f2c35cc0814065.zip
gcc-33b45227e0826ce8ddfe659c42f2c35cc0814065.tar.gz
gcc-33b45227e0826ce8ddfe659c42f2c35cc0814065.tar.bz2
re PR c++/34196 (uninitialized variable warning in dead exception region)
PR c++/34196 * 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. From-SVN: r131710
-rw-r--r--gcc/ChangeLog7
-rw-r--r--gcc/cp/ChangeLog5
-rw-r--r--gcc/cp/decl.c18
-rw-r--r--gcc/testsuite/g++.dg/eh/init-temp2.C31
-rw-r--r--gcc/tree-eh.c17
-rw-r--r--gcc/tree.h9
6 files changed, 84 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 873cdd4..d65e496 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 768efc5..fa48f7c 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 4b2a55f..338e1ed 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -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
index 0000000..6a58dda
--- /dev/null
+++ b/gcc/testsuite/g++.dg/eh/init-temp2.C
@@ -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()));
+}
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 71d3d94..44d5a6d 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -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. */
diff --git a/gcc/tree.h b/gcc/tree.h
index 52cb973..de0b11d 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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) \