From 2b4cffe7faed0a23e9d0c4c0596dfe7155a85ab1 Mon Sep 17 00:00:00 2001
From: rth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Date: Fri, 18 Jun 2004 22:51:57 +0000
Subject: [PATCH]         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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@83368 138bc75d-0d04-0410-961f-82ee72b054a4
---
 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 2b764ee9ece6..9ac5634c0272 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+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
diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c
index 933b24faf312..7334621106aa 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 0107506ed5e6..d830e20ccd72 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 ec5ef7a3c414..74a513a9cd67 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 000000000000..276e0d6e588e
--- /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;
+}
-- 
GitLab