Commit caf2523d by Richard Henderson Committed by Richard Henderson

re PR c++/16034 (dtor called prematurely for while-loop scoped variable)

        PR c++/16034
        * c-gimplify.c (gimplify_condition): Remove.
        (gimplify_c_loop, gimplify_if_stmt, gimplify_switch_stmt): Don't
        call it.
cp/
        * semantics.c (begin_cond): New.
        (finish_cond): Rewrite to handle template DECL_STMTs specially.
        Assume that non-template decls go land before the conditional.
        (simplify_loop_decl_cond): Likewise.
        (begin_if_stmt, finish_if_stmt_cond, begin_while_stmt,
        finish_while_stmt_cond, finish_for_init_stmt, finish_for_cond,
        begin_switch_stmt, finish_switch_cond): Update to match.

From-SVN: r83368
parent 7465ed07
2004-06-18 Richard Henderson <rth@redhat.com> 2004-06-18 Richard Henderson <rth@redhat.com>
* c-gimplify.c (gimplify_condition): Remove.
(gimplify_c_loop, gimplify_if_stmt, gimplify_switch_stmt): Don't
call it.
2004-06-18 Richard Henderson <rth@redhat.com>
* tree-eh.c (decide_copy_try_finally): Fix scaling of copy and * tree-eh.c (decide_copy_try_finally): Fix scaling of copy and
switch estimates. switch estimates.
......
...@@ -86,7 +86,6 @@ static tree gimplify_c_loop (tree, tree, tree, bool); ...@@ -86,7 +86,6 @@ static tree gimplify_c_loop (tree, tree, tree, bool);
static void push_context (void); static void push_context (void);
static void pop_context (void); static void pop_context (void);
static void add_block_to_enclosing (tree); static void add_block_to_enclosing (tree);
static void gimplify_condition (tree *);
enum bc_t { bc_break = 0, bc_continue = 1 }; enum bc_t { bc_break = 0, bc_continue = 1 };
static tree begin_bc_block (enum bc_t); static tree begin_bc_block (enum bc_t);
...@@ -417,23 +416,6 @@ gimplify_expr_stmt (tree *stmt_p) ...@@ -417,23 +416,6 @@ gimplify_expr_stmt (tree *stmt_p)
return GS_OK; return GS_OK;
} }
/* If the condition for a loop (or the like) is a decl, it will be a
TREE_LIST where the TREE_PURPOSE is a DECL_STMT and the TREE_VALUE is
a use of the decl. Turn such a thing into a COMPOUND_EXPR. */
static void
gimplify_condition (tree *cond_p)
{
tree cond = *cond_p;
if (cond && TREE_CODE (cond) == TREE_LIST)
{
tree decl = TREE_PURPOSE (cond);
tree value = TREE_VALUE (cond);
gimplify_stmt (&decl);
*cond_p = build (COMPOUND_EXPR, TREE_TYPE (value), decl, value);
}
}
/* Begin a scope which can be exited by a break or continue statement. BC /* Begin a scope which can be exited by a break or continue statement. BC
indicates which. indicates which.
...@@ -548,7 +530,6 @@ gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first) ...@@ -548,7 +530,6 @@ gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first)
exit = build_and_jump (&LABEL_EXPR_LABEL (top)); exit = build_and_jump (&LABEL_EXPR_LABEL (top));
if (cond) if (cond)
{ {
gimplify_condition (&cond);
t = build_bc_goto (bc_break); t = build_bc_goto (bc_break);
exit = build (COND_EXPR, void_type_node, cond, exit, t); exit = build (COND_EXPR, void_type_node, cond, exit, t);
exit = fold (exit); exit = fold (exit);
...@@ -647,7 +628,6 @@ gimplify_if_stmt (tree *stmt_p) ...@@ -647,7 +628,6 @@ gimplify_if_stmt (tree *stmt_p)
else_ = build_empty_stmt (); else_ = build_empty_stmt ();
stmt = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_); stmt = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_);
gimplify_condition (& TREE_OPERAND (stmt, 0));
*stmt_p = stmt; *stmt_p = stmt;
return GS_OK; return GS_OK;
...@@ -664,8 +644,6 @@ gimplify_switch_stmt (tree *stmt_p) ...@@ -664,8 +644,6 @@ gimplify_switch_stmt (tree *stmt_p)
break_block = begin_bc_block (bc_break); break_block = begin_bc_block (bc_break);
gimplify_condition (&SWITCH_COND (stmt));
body = SWITCH_BODY (stmt); body = SWITCH_BODY (stmt);
if (!body) if (!body)
body = build_empty_stmt (); body = build_empty_stmt ();
......
2004-06-18 Richard Henderson <rth@redhat.com>
PR c++/16034
* semantics.c (begin_cond): New.
(finish_cond): Rewrite to handle template DECL_STMTs specially.
Assume that non-template decls go land before the conditional.
(simplify_loop_decl_cond): Likewise.
(begin_if_stmt, finish_if_stmt_cond, begin_while_stmt,
finish_while_stmt_cond, finish_for_init_stmt, finish_for_cond,
begin_switch_stmt, finish_switch_cond): Update to match.
2004-06-17 Jason Merrill <jason@redhat.com> 2004-06-17 Jason Merrill <jason@redhat.com>
PR c++/16015 PR c++/16015
......
...@@ -346,68 +346,60 @@ do_pushlevel (scope_kind sk) ...@@ -346,68 +346,60 @@ do_pushlevel (scope_kind sk)
return ret; return ret;
} }
/* Finish processing a conditional. COND contains the raw expression; /* Begin a conditional that might contain a declaration. When generating
STMT_P is a stacked statement list that will contain any other stmts normal code, we want the declaration to appear before the statement
emitting during the processing of this conditional. Place the containing the conditional. When generating template code, we want the
resulting conditional back in STMT_P. */ conditional to be rendered as the raw DECL_STMT. */
static void static void
finish_cond (tree cond, tree *stmt_p) begin_cond (tree *cond_p)
{ {
tree stmt = *stmt_p; if (processing_template_decl)
stmt = pop_stmt_list (stmt); *cond_p = push_stmt_list ();
if (TREE_SIDE_EFFECTS (stmt)) }
{
/* If stmt is set, it will be a DECL_STMT. When processing a template, /* Finish such a conditional. */
using this is enough, because tsubst_expr considers the result of a
DECL_STMT to be the DECL. When generating real code, we build a static void
funny little TREE_LIST thingy that's handled by the gimplifier. */ finish_cond (tree *cond_p, tree expr)
/* ??? The object of this thingy is to get the DECL declared in the {
proper scope. Seems like this oughtn't be terribly hard with the if (processing_template_decl)
new explicit uses of BIND_EXPR and such. */ {
if (processing_template_decl) tree cond = pop_stmt_list (*cond_p);
{ if (TREE_CODE (cond) == DECL_STMT)
stmt = expr_only (stmt); expr = cond;
if (!stmt)
abort ();
}
else
stmt = build_tree_list (stmt, cond);
} }
else *cond_p = expr;
stmt = cond;
*stmt_p = stmt;
} }
/* If *COND_P specifies a conditional with a declaration, transform the /* If *COND_P specifies a conditional with a declaration, transform the
loop such that loop such that
while (A x = 42) { } while (A x = 42) { }
for (; A x = 42;) { } for (; A x = 42;) { }
becomes becomes
while (true) { A x = 42; if (!x) break; } while (true) { A x = 42; if (!x) break; }
for (;;) { A x = 42; if (!x) break; } for (;;) { A x = 42; if (!x) break; }
The statement list for the loop body should have been pushed. */ The statement list for BODY will be empty if the conditional did
not declare anything. */
static void static void
simplify_loop_decl_cond (tree *cond_p) simplify_loop_decl_cond (tree *cond_p, tree body)
{ {
tree cond = *cond_p; tree cond, if_stmt;
if (TREE_CODE (cond) == TREE_LIST)
{
tree if_stmt;
*cond_p = boolean_true_node; if (!TREE_SIDE_EFFECTS (body))
return;
if_stmt = begin_if_stmt ();
add_stmt (TREE_PURPOSE (cond));
cond = build_unary_op (TRUTH_NOT_EXPR, TREE_VALUE (cond), 0);
finish_if_stmt_cond (cond, if_stmt);
finish_break_stmt ();
finish_then_clause (if_stmt);
finish_if_stmt (if_stmt);
}
}
cond = *cond_p;
*cond_p = boolean_true_node;
if_stmt = begin_if_stmt ();
cond = build_unary_op (TRUTH_NOT_EXPR, cond, 0);
finish_if_stmt_cond (cond, if_stmt);
finish_break_stmt ();
finish_then_clause (if_stmt);
finish_if_stmt (if_stmt);
}
/* Finish a goto-statement. */ /* Finish a goto-statement. */
...@@ -494,8 +486,7 @@ begin_if_stmt (void) ...@@ -494,8 +486,7 @@ begin_if_stmt (void)
scope = do_pushlevel (sk_block); scope = do_pushlevel (sk_block);
r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE); r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
TREE_CHAIN (r) = scope; TREE_CHAIN (r) = scope;
add_stmt (r); begin_cond (&IF_COND (r));
IF_COND (r) = push_stmt_list ();
return r; return r;
} }
...@@ -505,8 +496,8 @@ begin_if_stmt (void) ...@@ -505,8 +496,8 @@ begin_if_stmt (void)
void void
finish_if_stmt_cond (tree cond, tree if_stmt) finish_if_stmt_cond (tree cond, tree if_stmt)
{ {
cond = maybe_convert_cond (cond); finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond));
finish_cond (cond, &IF_COND (if_stmt)); add_stmt (if_stmt);
THEN_CLAUSE (if_stmt) = push_stmt_list (); THEN_CLAUSE (if_stmt) = push_stmt_list ();
} }
...@@ -558,7 +549,7 @@ begin_while_stmt (void) ...@@ -558,7 +549,7 @@ begin_while_stmt (void)
r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE); r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
add_stmt (r); add_stmt (r);
WHILE_BODY (r) = do_pushlevel (sk_block); WHILE_BODY (r) = do_pushlevel (sk_block);
WHILE_COND (r) = push_stmt_list (); begin_cond (&WHILE_COND (r));
return r; return r;
} }
...@@ -568,9 +559,8 @@ begin_while_stmt (void) ...@@ -568,9 +559,8 @@ begin_while_stmt (void)
void void
finish_while_stmt_cond (tree cond, tree while_stmt) finish_while_stmt_cond (tree cond, tree while_stmt)
{ {
cond = maybe_convert_cond (cond); finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
finish_cond (cond, &WHILE_COND (while_stmt)); simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
simplify_loop_decl_cond (&WHILE_COND (while_stmt));
} }
/* Finish a while-statement, which may be given by WHILE_STMT. */ /* Finish a while-statement, which may be given by WHILE_STMT. */
...@@ -668,7 +658,7 @@ finish_for_init_stmt (tree for_stmt) ...@@ -668,7 +658,7 @@ finish_for_init_stmt (tree for_stmt)
FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt)); FOR_INIT_STMT (for_stmt) = pop_stmt_list (FOR_INIT_STMT (for_stmt));
add_stmt (for_stmt); add_stmt (for_stmt);
FOR_BODY (for_stmt) = do_pushlevel (sk_block); FOR_BODY (for_stmt) = do_pushlevel (sk_block);
FOR_COND (for_stmt) = push_stmt_list (); begin_cond (&FOR_COND (for_stmt));
} }
/* Finish the COND of a for-statement, which may be given by /* Finish the COND of a for-statement, which may be given by
...@@ -677,10 +667,8 @@ finish_for_init_stmt (tree for_stmt) ...@@ -677,10 +667,8 @@ finish_for_init_stmt (tree for_stmt)
void void
finish_for_cond (tree cond, tree for_stmt) finish_for_cond (tree cond, tree for_stmt)
{ {
cond = maybe_convert_cond (cond); finish_cond (&FOR_COND (for_stmt), maybe_convert_cond (cond));
finish_cond (cond, &FOR_COND (for_stmt)); simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
if (FOR_COND (for_stmt))
simplify_loop_decl_cond (&FOR_COND (for_stmt));
} }
/* Finish the increment-EXPRESSION in a for-statement, which may be /* Finish the increment-EXPRESSION in a for-statement, which may be
...@@ -747,9 +735,7 @@ begin_switch_stmt (void) ...@@ -747,9 +735,7 @@ begin_switch_stmt (void)
scope = do_pushlevel (sk_block); scope = do_pushlevel (sk_block);
TREE_CHAIN (r) = scope; TREE_CHAIN (r) = scope;
begin_cond (&SWITCH_COND (r));
add_stmt (r);
SWITCH_COND (r) = push_stmt_list ();
return r; return r;
} }
...@@ -793,8 +779,9 @@ finish_switch_cond (tree cond, tree switch_stmt) ...@@ -793,8 +779,9 @@ finish_switch_cond (tree cond, tree switch_stmt)
cond = index; cond = index;
} }
} }
finish_cond (cond, &SWITCH_COND (switch_stmt)); finish_cond (&SWITCH_COND (switch_stmt), cond);
SWITCH_TYPE (switch_stmt) = orig_type; SWITCH_TYPE (switch_stmt) = orig_type;
add_stmt (switch_stmt);
push_switch (switch_stmt); push_switch (switch_stmt);
SWITCH_BODY (switch_stmt) = push_stmt_list (); SWITCH_BODY (switch_stmt) = push_stmt_list ();
} }
......
// Test that we've scoped the destructor properly for variables declared
// in a conditional.
// { dg-do run }
extern "C" void abort ();
class C
{
bool live;
public:
C();
C(const C &);
~C ();
operator bool() const;
};
void f1 ()
{
while (C br = C()) abort ();
}
void f2 ()
{
for (; C br = C(); ) abort ();
}
void f3 ()
{
if (C br = C()) abort ();
}
void f4 ()
{
switch (C br = C())
{
default:
abort ();
case false:
break;
}
}
int main()
{
f1(); f2(); f3(); f4();
return 0;
}
C::C()
{
live = true;
}
C::C(const C &o)
{
if (!o.live)
abort ();
live = true;
}
C::~C()
{
live = false;
}
C::operator bool() const
{
if (!live)
abort ();
return false;
}
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