+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
+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
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;
}
/* 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)
--- /dev/null
+// 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()));
+}
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. */
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
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) \