re PR c/44715 (Break in increment expression of "for" statement inconsistent with...
authorJakub Jelinek <jakub@redhat.com>
Wed, 23 Jan 2019 14:41:16 +0000 (15:41 +0100)
committerJakub Jelinek <jakub@gcc.gnu.org>
Wed, 23 Jan 2019 14:41:16 +0000 (15:41 +0100)
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.

From-SVN: r268188

gcc/ChangeLog
gcc/cp/ChangeLog
gcc/cp/cp-gimplify.c
gcc/doc/extend.texi
gcc/testsuite/ChangeLog
gcc/testsuite/c-c++-common/pr44715.c [new file with mode: 0644]

index bbbacebf4cbed90d345126e73caa837ba8e4317a..401b81d75c7a86fc1e8915b4a154a88be2b4ce29 100644 (file)
@@ -1,3 +1,9 @@
+2019-01-23  Jakub Jelinek  <jakub@redhat.com>
+
+       PR c/44715
+       * doc/extend.texi: Document break and continue behavior in
+       statement expressions.
+
 2019-01-23  Richard Biener  <rguenther@suse.de>
 
        PR tree-optimization/89008
index 363dff135cfbda4ac7e846a94e7f6227950a4423..a36fe31ca23d56a19024b9f70e09ddb1c5f3c0a9 100644 (file)
@@ -1,5 +1,9 @@
 2019-01-23  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c/44715
+       * cp-gimplify.c (genericize_cp_loop): Call begin_bc_block only
+       after genericizing cond and incr expressions.
+
        PR c++/88984
        * cp-gimplify.c (genericize_switch_stmt): Move cond genericization
        before the begin_bc_block call.
index e476b8f53ec1aaf1581e19fe2a7598cc1bdf7051..33111bd14bffc20d03a824f867b869c7625a68b7 100644 (file)
@@ -242,14 +242,15 @@ genericize_cp_loop (tree *stmt_p, location_t start_locus, tree cond, tree body,
   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)
index 2f3f10b911ecab10031ea628898192e442735772..4044fba753e3cce0d8a8fbe6884b9cd04eda1d54 100644 (file)
@@ -213,7 +213,14 @@ statement expression is part of a larger expression then it is
 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,
 
index c6006e0655b1a9f678100afd09ea2a1350220c9a..38fec831cb88020afe1defd90528b3859e753d32 100644 (file)
@@ -1,5 +1,8 @@
 2019-01-23  Jakub Jelinek  <jakub@redhat.com>
 
+       PR c/44715
+       * c-c++-common/pr44715.c: New test.
+
        PR c++/88984
        * c-c++-common/pr88984.c: New test.
 
diff --git a/gcc/testsuite/c-c++-common/pr44715.c b/gcc/testsuite/c-c++-common/pr44715.c
new file mode 100644 (file)
index 0000000..f20a146
--- /dev/null
@@ -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;
+}