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>
* 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
switch estimates.
......
......@@ -86,7 +86,6 @@ static tree gimplify_c_loop (tree, tree, tree, bool);
static void push_context (void);
static void pop_context (void);
static void add_block_to_enclosing (tree);
static void gimplify_condition (tree *);
enum bc_t { bc_break = 0, bc_continue = 1 };
static tree begin_bc_block (enum bc_t);
......@@ -417,23 +416,6 @@ gimplify_expr_stmt (tree *stmt_p)
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
indicates which.
......@@ -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));
if (cond)
{
gimplify_condition (&cond);
t = build_bc_goto (bc_break);
exit = build (COND_EXPR, void_type_node, cond, exit, t);
exit = fold (exit);
......@@ -647,7 +628,6 @@ gimplify_if_stmt (tree *stmt_p)
else_ = build_empty_stmt ();
stmt = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_);
gimplify_condition (& TREE_OPERAND (stmt, 0));
*stmt_p = stmt;
return GS_OK;
......@@ -664,8 +644,6 @@ gimplify_switch_stmt (tree *stmt_p)
break_block = begin_bc_block (bc_break);
gimplify_condition (&SWITCH_COND (stmt));
body = SWITCH_BODY (stmt);
if (!body)
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>
PR c++/16015
......
......@@ -346,37 +346,30 @@ do_pushlevel (scope_kind sk)
return ret;
}
/* Finish processing a conditional. COND contains the raw expression;
STMT_P is a stacked statement list that will contain any other stmts
emitting during the processing of this conditional. Place the
resulting conditional back in STMT_P. */
/* Begin a conditional that might contain a declaration. When generating
normal code, we want the declaration to appear before the statement
containing the conditional. When generating template code, we want the
conditional to be rendered as the raw DECL_STMT. */
static void
finish_cond (tree cond, tree *stmt_p)
begin_cond (tree *cond_p)
{
if (processing_template_decl)
*cond_p = push_stmt_list ();
}
/* Finish such a conditional. */
static void
finish_cond (tree *cond_p, tree expr)
{
tree stmt = *stmt_p;
stmt = pop_stmt_list (stmt);
if (TREE_SIDE_EFFECTS (stmt))
{
/* If stmt is set, it will be a DECL_STMT. When processing a template,
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
funny little TREE_LIST thingy that's handled by the gimplifier. */
/* ??? 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
new explicit uses of BIND_EXPR and such. */
if (processing_template_decl)
{
stmt = expr_only (stmt);
if (!stmt)
abort ();
tree cond = pop_stmt_list (*cond_p);
if (TREE_CODE (cond) == DECL_STMT)
expr = cond;
}
else
stmt = build_tree_list (stmt, cond);
}
else
stmt = cond;
*stmt_p = stmt;
*cond_p = expr;
}
/* If *COND_P specifies a conditional with a declaration, transform the
......@@ -386,29 +379,28 @@ finish_cond (tree cond, tree *stmt_p)
becomes
while (true) { 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
simplify_loop_decl_cond (tree *cond_p)
simplify_loop_decl_cond (tree *cond_p, tree body)
{
tree cond = *cond_p;
if (TREE_CODE (cond) == TREE_LIST)
{
tree if_stmt;
tree cond, if_stmt;
if (!TREE_SIDE_EFFECTS (body))
return;
cond = *cond_p;
*cond_p = boolean_true_node;
if_stmt = begin_if_stmt ();
add_stmt (TREE_PURPOSE (cond));
cond = build_unary_op (TRUTH_NOT_EXPR, TREE_VALUE (cond), 0);
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. */
tree
......@@ -494,8 +486,7 @@ begin_if_stmt (void)
scope = do_pushlevel (sk_block);
r = build_stmt (IF_STMT, NULL_TREE, NULL_TREE, NULL_TREE);
TREE_CHAIN (r) = scope;
add_stmt (r);
IF_COND (r) = push_stmt_list ();
begin_cond (&IF_COND (r));
return r;
}
......@@ -505,8 +496,8 @@ begin_if_stmt (void)
void
finish_if_stmt_cond (tree cond, tree if_stmt)
{
cond = maybe_convert_cond (cond);
finish_cond (cond, &IF_COND (if_stmt));
finish_cond (&IF_COND (if_stmt), maybe_convert_cond (cond));
add_stmt (if_stmt);
THEN_CLAUSE (if_stmt) = push_stmt_list ();
}
......@@ -558,7 +549,7 @@ begin_while_stmt (void)
r = build_stmt (WHILE_STMT, NULL_TREE, NULL_TREE);
add_stmt (r);
WHILE_BODY (r) = do_pushlevel (sk_block);
WHILE_COND (r) = push_stmt_list ();
begin_cond (&WHILE_COND (r));
return r;
}
......@@ -568,9 +559,8 @@ begin_while_stmt (void)
void
finish_while_stmt_cond (tree cond, tree while_stmt)
{
cond = maybe_convert_cond (cond);
finish_cond (cond, &WHILE_COND (while_stmt));
simplify_loop_decl_cond (&WHILE_COND (while_stmt));
finish_cond (&WHILE_COND (while_stmt), maybe_convert_cond (cond));
simplify_loop_decl_cond (&WHILE_COND (while_stmt), WHILE_BODY (while_stmt));
}
/* Finish a while-statement, which may be given by WHILE_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));
add_stmt (for_stmt);
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
......@@ -677,10 +667,8 @@ finish_for_init_stmt (tree for_stmt)
void
finish_for_cond (tree cond, tree for_stmt)
{
cond = maybe_convert_cond (cond);
finish_cond (cond, &FOR_COND (for_stmt));
if (FOR_COND (for_stmt))
simplify_loop_decl_cond (&FOR_COND (for_stmt));
finish_cond (&FOR_COND (for_stmt), maybe_convert_cond (cond));
simplify_loop_decl_cond (&FOR_COND (for_stmt), FOR_BODY (for_stmt));
}
/* Finish the increment-EXPRESSION in a for-statement, which may be
......@@ -747,9 +735,7 @@ begin_switch_stmt (void)
scope = do_pushlevel (sk_block);
TREE_CHAIN (r) = scope;
add_stmt (r);
SWITCH_COND (r) = push_stmt_list ();
begin_cond (&SWITCH_COND (r));
return r;
}
......@@ -793,8 +779,9 @@ finish_switch_cond (tree cond, tree switch_stmt)
cond = index;
}
}
finish_cond (cond, &SWITCH_COND (switch_stmt));
finish_cond (&SWITCH_COND (switch_stmt), cond);
SWITCH_TYPE (switch_stmt) = orig_type;
add_stmt (switch_stmt);
push_switch (switch_stmt);
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