Hi!

This patch adjusts genericize_cp_loop similarly to the
PR88984 change in genericize_switch_stmt, so that the following testcase now
behaves the same in both C and C++, plus adds the testcase and
documentation.

Bootstrapped/regtested on {x86_64,i686,powerpc64{,le}}-linux, ok for trunk?

2019-01-22  Jakub Jelinek  <ja...@redhat.com>

        PR c/44715
        * cp-gimplify.c (genericize_cp_loop): Call begin_bc_block only
        after genericizing cond and incr expressions.
        * doc/extend.texi: Document break and continue behavior in
        statement expressions.

        * c-c++-common/pr44715.c: New test.

--- gcc/cp/cp-gimplify.c.jj     2019-01-22 19:18:38.009931152 +0100
+++ gcc/cp/cp-gimplify.c        2019-01-22 19:47:59.799151375 +0100
@@ -242,14 +242,15 @@ genericize_cp_loop (tree *stmt_p, locati
   tree exit = NULL;
   tree stmt_list = NULL;
 
-  blab = begin_bc_block (bc_break, start_locus);
-  clab = begin_bc_block (bc_continue, start_locus);
-
   protected_set_expr_location (incr, start_locus);
 
   cp_walk_tree (&cond, cp_genericize_r, data, NULL);
-  cp_walk_tree (&body, cp_genericize_r, data, NULL);
   cp_walk_tree (&incr, cp_genericize_r, data, NULL);
+
+  blab = begin_bc_block (bc_break, start_locus);
+  clab = begin_bc_block (bc_continue, start_locus);
+
+  cp_walk_tree (&body, cp_genericize_r, data, NULL);
   *walk_subtrees = 0;
 
   if (cond && TREE_CODE (cond) != INTEGER_CST)
--- gcc/doc/extend.texi.jj      2019-01-18 10:13:23.171110816 +0100
+++ gcc/doc/extend.texi 2019-01-22 20:27:32.147492406 +0100
@@ -213,7 +213,14 @@ statement expression is part of a larger
 unspecified which other subexpressions of that expression have been
 evaluated except where the language definition requires certain
 subexpressions to be evaluated before or after the statement
-expression.  In any case, as with a function call, the evaluation of a
+expression.  A @code{break} or @code{continue} statement inside of
+a statement expression used in @code{while}, @code{do} or @code{for}
+loop or @code{switch} statement condition
+or @code{for} statement init or increment expressions jumps to an
+outer loop or @code{switch} statement if any (otherwise it is an error),
+rather than to the loop or @code{switch} statement in whose condition
+or init or increment expression it appears.
+In any case, as with a function call, the evaluation of a
 statement expression is not interleaved with the evaluation of other
 parts of the containing expression.  For example,
 
--- gcc/testsuite/c-c++-common/pr44715.c.jj     2019-01-22 20:13:32.871149496 
+0100
+++ gcc/testsuite/c-c++-common/pr44715.c        2019-01-22 20:17:30.837273821 
+0100
@@ -0,0 +1,171 @@
+/* PR c/44715 */
+/* { dg-do run } */
+/* { dg-options "" } */
+
+void
+foo (int x, int y)
+{
+  int z;
+  switch (x)
+    {
+    case 0:
+      while (({ if (y) break; 0; }))
+       ;
+      __builtin_abort ();
+      break;
+    case 1:
+      do
+       ;
+      while (({ if (y) break; 0; }));
+      __builtin_abort ();
+      break;
+    case 2:
+      for (z = ({ if (y) break; 0; }); z < 5; z++)
+       ;
+      __builtin_abort ();
+      break;
+    case 3:
+      for (z = 0; z < ({ if (y) break; 5; }); z++)
+       ;
+      __builtin_abort ();
+      break;
+    case 4:
+      for (z = 0; z < 5; z += ({ if (y) break; 1; }))
+       ;
+      __builtin_abort ();
+      break;
+    case 5:
+      switch (({ if (y) break; 1; }))
+       {
+       default: break;
+       }
+      __builtin_abort ();
+      break;
+    default:
+      __builtin_abort ();
+      break;
+    }
+}
+
+void
+bar (int x, int y)
+{
+  int z;
+  while (x >= 0)
+    {
+      if (x == 0)
+       {
+         while (({ if (y) break; 0; }))
+           ;
+         __builtin_abort ();
+       }
+      if (x == 1)
+       {
+         do
+           ;
+         while (({ if (y) break; 0; }));
+         __builtin_abort ();
+       }
+      if (x == 2)
+       {
+         for (z = ({ if (y) break; 0; }); z < 5; z++)
+           ;
+         __builtin_abort ();
+       }
+      if (x == 3)
+       {
+         for (z = 0; z < ({ if (y) break; 5; }); z++)
+           ;
+         __builtin_abort ();
+       }
+      if (x == 4)
+       {
+         for (z = 0; z < 5; z += ({ if (y) break; 1; }))
+           ;
+         __builtin_abort ();
+       }
+      if (x == 5)
+       {
+         switch (({ if (y) break; 1; }))
+           {
+           default: break;
+           }
+         __builtin_abort ();
+       }
+    }
+}
+
+void
+baz (int x, int y)
+{
+  int z;
+  while (x >= 0)
+    {
+      if (++y == 2)
+       return;
+      if (x == 0)
+       {
+         while (({ if (y) continue; 0; }))
+           ;
+         __builtin_abort ();
+       }
+      if (x == 1)
+       {
+         do
+           ;
+         while (({ if (y) continue; 0; }));
+         __builtin_abort ();
+       }
+      if (x == 2)
+       {
+         for (z = ({ if (y) continue; 0; }); z < 5; z++)
+           ;
+         __builtin_abort ();
+       }
+      if (x == 3)
+       {
+         for (z = 0; z < ({ if (y) continue; 5; }); z++)
+           ;
+         __builtin_abort ();
+       }
+      if (x == 4)
+       {
+         for (z = 0; z < 5; z += ({ if (y) continue; 1; }))
+           ;
+         __builtin_abort ();
+       }
+      if (x == 5)
+       {
+         switch (({ if (y) continue; 1; }))
+           {
+           default: break;
+           }
+         __builtin_abort ();
+       }
+    }
+  __builtin_abort ();
+}
+
+int
+main ()
+{
+  foo (0, 1);
+  foo (1, 1);
+  foo (2, 1);
+  foo (3, 1);
+  foo (4, 1);
+  foo (5, 1);
+  bar (0, 1);
+  bar (1, 1);
+  bar (2, 1);
+  bar (3, 1);
+  bar (4, 1);
+  bar (5, 1);
+  baz (0, 0);
+  baz (1, 0);
+  baz (2, 0);
+  baz (3, 0);
+  baz (4, 0);
+  baz (5, 0);
+  return 0;
+}

        Jakub

Reply via email to