summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/c-gimplify.c22
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/semantics.c121
-rw-r--r--gcc/testsuite/g++.dg/eh/scope1.C71
5 files changed, 142 insertions, 89 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2b764ee9ece..9ac5634c027 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,11 @@
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.
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 <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
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;
+}