aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2019-01-23 15:41:16 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2019-01-23 15:41:16 +0100
commit372e6e6bac4046d87e92894535b80f28409e9d3f (patch)
tree99fe79352a4af99969da0d773320d576ce4db3f6
parentd0f2db231639f73802c07f03cf4a77125a0daeb7 (diff)
downloadgcc-372e6e6bac4046d87e92894535b80f28409e9d3f.zip
gcc-372e6e6bac4046d87e92894535b80f28409e9d3f.tar.gz
gcc-372e6e6bac4046d87e92894535b80f28409e9d3f.tar.bz2
re PR c/44715 (Break in increment expression of "for" statement inconsistent with g++)
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
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/cp-gimplify.c9
-rw-r--r--gcc/doc/extend.texi9
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/c-c++-common/pr44715.c171
6 files changed, 197 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index bbbaceb..401b81d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 363dff1..a36fe31 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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.
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index e476b8f..33111bd 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -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)
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 2f3f10b..4044fba 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -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,
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index c6006e0..38fec83 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..f20a146
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr44715.c
@@ -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;
+}