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