From caf2523d6d984c1c46b1c5056b835448f4fc02a9 Mon Sep 17 00:00:00 2001 From: Richard Henderson Date: Fri, 18 Jun 2004 15:51:57 -0700 Subject: [PATCH] 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 --- gcc/ChangeLog | 6 ++ gcc/c-gimplify.c | 22 ------ gcc/cp/ChangeLog | 11 +++ gcc/cp/semantics.c | 121 ++++++++++++++----------------- gcc/testsuite/g++.dg/eh/scope1.C | 71 ++++++++++++++++++ 5 files changed, 142 insertions(+), 89 deletions(-) create mode 100644 gcc/testsuite/g++.dg/eh/scope1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2b764ee9ece..9ac5634c027 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2004-06-18 Richard Henderson + + * c-gimplify.c (gimplify_condition): Remove. + (gimplify_c_loop, gimplify_if_stmt, gimplify_switch_stmt): Don't + call it. + 2004-06-18 Richard Henderson * tree-eh.c (decide_copy_try_finally): Fix scaling of copy and diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c index 933b24faf31..7334621106a 100644 --- a/gcc/c-gimplify.c +++ b/gcc/c-gimplify.c @@ -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 (); diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0107506ed5e..d830e20ccd7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,14 @@ +2004-06-18 Richard Henderson + + 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 PR c++/16015 diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index ec5ef7a3c41..74a513a9cd6 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -346,68 +346,60 @@ 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) -{ - 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 (); - } - else - stmt = build_tree_list (stmt, cond); +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) +{ + if (processing_template_decl) + { + tree cond = pop_stmt_list (*cond_p); + if (TREE_CODE (cond) == DECL_STMT) + expr = cond; } - else - stmt = cond; - *stmt_p = stmt; + *cond_p = expr; } /* If *COND_P specifies a conditional with a declaration, transform the loop such that - while (A x = 42) { } - for (; A x = 42;) { } + while (A x = 42) { } + for (; A x = 42;) { } 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. */ - + while (true) { A x = 42; if (!x) break; } + for (;;) { A x = 42; if (!x) break; } + 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; - *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); - finish_if_stmt_cond (cond, if_stmt); - finish_break_stmt (); - finish_then_clause (if_stmt); - finish_if_stmt (if_stmt); - } -} + if (!TREE_SIDE_EFFECTS (body)) + return; + 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. */ @@ -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 (); } diff --git a/gcc/testsuite/g++.dg/eh/scope1.C b/gcc/testsuite/g++.dg/eh/scope1.C new file mode 100644 index 00000000000..276e0d6e588 --- /dev/null +++ b/gcc/testsuite/g++.dg/eh/scope1.C @@ -0,0 +1,71 @@ +// 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; +} -- 2.30.2