re PR c++/16034 (dtor called prematurely for while-loop scoped variable)
authorRichard Henderson <rth@redhat.com>
Fri, 18 Jun 2004 22:51:57 +0000 (15:51 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 18 Jun 2004 22:51:57 +0000 (15:51 -0700)
        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
gcc/c-gimplify.c
gcc/cp/ChangeLog
gcc/cp/semantics.c
gcc/testsuite/g++.dg/eh/scope1.C [new file with mode: 0644]

index 2b764ee9ece6aac689ae33bf2eb90b2e9b072400..9ac5634c0272db93c3251c619d134ab5b80b2314 100644 (file)
@@ -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
index 933b24faf312d1a0354c884e159972e22e61fac6..7334621106aaf7005566dde32231826fe150e130 100644 (file)
@@ -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 ();
index 0107506ed5e6f32f8300920d2b6eba68e6d82047..d830e20ccd72bde1c8e4f18f1cf303598f15f086 100644 (file)
@@ -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
index ec5ef7a3c4147aba4faf8d6fb86173348d26255d..74a513a9cd672b32b08c6836840b0c26f4308112 100644 (file)
@@ -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 (file)
index 0000000..276e0d6
--- /dev/null
@@ -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;
+}