Commit 33b45227 by Jason Merrill Committed by Jason Merrill

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
parent 9444edce
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> 2008-01-21 DJ Delorie <dj@redhat.com>
* doc/tm.texi (HARD_REGNO_NREGS): Note that this macro must not * 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> 2008-01-21 Richard Guenther <rguenther@suse.de>
PR c++/34850 PR c++/34850
......
...@@ -5165,7 +5165,10 @@ wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data) ...@@ -5165,7 +5165,10 @@ wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data)
tree tcleanup = TARGET_EXPR_CLEANUP (*stmt_p); tree tcleanup = TARGET_EXPR_CLEANUP (*stmt_p);
tcleanup = build2 (TRY_CATCH_EXPR, void_type_node, tcleanup, guard); 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; TARGET_EXPR_CLEANUP (*stmt_p) = tcleanup;
} }
...@@ -5175,7 +5178,18 @@ wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data) ...@@ -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 /* 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 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 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 static void
wrap_temporary_cleanups (tree init, tree guard) wrap_temporary_cleanups (tree init, tree guard)
......
// 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()));
}
...@@ -840,6 +840,23 @@ honor_protect_cleanup_actions (struct leh_state *outer_state, ...@@ -840,6 +840,23 @@ honor_protect_cleanup_actions (struct leh_state *outer_state,
if (this_state) if (this_state)
finally = lower_try_finally_dup_block (finally, outer_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 /* Resume execution after the exception. Adding this now lets
lower_eh_filter not add unnecessary gotos, as it is clear that lower_eh_filter not add unnecessary gotos, as it is clear that
we never fallthru from this copy of the finally block. */ we never fallthru from this copy of the finally block. */
......
...@@ -447,6 +447,8 @@ struct gimple_stmt GTY(()) ...@@ -447,6 +447,8 @@ struct gimple_stmt GTY(())
IDENTIFIER_NODE IDENTIFIER_NODE
CLEANUP_EH_ONLY in CLEANUP_EH_ONLY in
TARGET_EXPR, WITH_CLEANUP_EXPR TARGET_EXPR, WITH_CLEANUP_EXPR
TRY_CATCH_IS_CLEANUP in
TRY_CATCH_EXPR
ASM_INPUT_P in ASM_INPUT_P in
ASM_EXPR ASM_EXPR
EH_FILTER_MUST_NOT_THROW in EH_FILTER_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, ...@@ -1166,11 +1168,16 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
should be cleaned up some day. */ should be cleaned up some day. */
#define TREE_STATIC(NODE) ((NODE)->base.static_flag) #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 should only be executed if an exception is thrown, not on normal exit
of its scope. */ of its scope. */
#define CLEANUP_EH_ONLY(NODE) ((NODE)->base.static_flag) #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 /* Used as a temporary field on a CASE_LABEL_EXPR to indicate that the
CASE_HIGH operand has been processed. */ CASE_HIGH operand has been processed. */
#define CASE_HIGH_SEEN(NODE) \ #define CASE_HIGH_SEEN(NODE) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment