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
This commit is contained in:
Jakub Jelinek 2019-01-23 15:41:16 +01:00 committed by Jakub Jelinek
parent d0f2db2316
commit 372e6e6bac
6 changed files with 197 additions and 5 deletions

View 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

View 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.

View 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)

View 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,

View 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.

View File

@ -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;
}