From b84702c0572614a71e720e9f822d1c31c7cea5b7 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Mon, 13 Feb 2017 20:31:14 +0100 Subject: [PATCH] re PR c++/79232 (error: invalid rhs for gimple memory store) PR c++/79232 * typeck.c (cp_build_modify_expr): Handle properly COMPOUND_EXPRs on lhs that have {PRE{DEC,INC}REMENT,MODIFY,MIN,MAX,COND}_EXPR in the rightmost operand. * g++.dg/cpp1z/eval-order4.C: New test. * g++.dg/other/pr79232.C: New test. From-SVN: r245401 --- gcc/cp/ChangeLog | 7 ++ gcc/cp/typeck.c | 81 +++++++++++++++++++----- gcc/testsuite/ChangeLog | 6 ++ gcc/testsuite/g++.dg/cpp1z/eval-order4.C | 80 +++++++++++++++++++++++ gcc/testsuite/g++.dg/other/pr79232.C | 12 ++++ 5 files changed, 171 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp1z/eval-order4.C create mode 100644 gcc/testsuite/g++.dg/other/pr79232.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 300860416dd..3fffb5b04b6 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2017-02-13 Jakub Jelinek + + PR c++/79232 + * typeck.c (cp_build_modify_expr): Handle properly COMPOUND_EXPRs + on lhs that have {PRE{DEC,INC}REMENT,MODIFY,MIN,MAX,COND}_EXPR + in the rightmost operand. + 2017-02-13 Nathan Sidwell PR c++/79296 - ICE mangling localized template instantiation diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index ef4dae47133..87e7cc0b029 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -7571,16 +7571,26 @@ tree cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, tree rhs, tsubst_flags_t complain) { - tree result; + tree result = NULL_TREE; tree newrhs = rhs; tree lhstype = TREE_TYPE (lhs); + tree olhs = lhs; tree olhstype = lhstype; bool plain_assign = (modifycode == NOP_EXPR); + bool compound_side_effects_p = false; + tree preeval = NULL_TREE; /* Avoid duplicate error messages from operands that had errors. */ if (error_operand_p (lhs) || error_operand_p (rhs)) return error_mark_node; + while (TREE_CODE (lhs) == COMPOUND_EXPR) + { + if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))) + compound_side_effects_p = true; + lhs = TREE_OPERAND (lhs, 1); + } + /* Handle control structure constructs used as "lvalues". Note that we leave COMPOUND_EXPR on the LHS because it is sequenced after the RHS. */ switch (TREE_CODE (lhs)) @@ -7588,20 +7598,41 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, /* Handle --foo = 5; as these are valid constructs in C++. */ case PREDECREMENT_EXPR: case PREINCREMENT_EXPR: + if (compound_side_effects_p) + newrhs = rhs = stabilize_expr (rhs, &preeval); if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))) lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs), cp_stabilize_reference (TREE_OPERAND (lhs, 0)), TREE_OPERAND (lhs, 1)); lhs = build2 (COMPOUND_EXPR, lhstype, lhs, TREE_OPERAND (lhs, 0)); + maybe_add_compound: + /* If we had (bar, --foo) = 5; or (bar, (baz, --foo)) = 5; + and looked through the COMPOUND_EXPRs, readd them now around + the resulting lhs. */ + if (TREE_CODE (olhs) == COMPOUND_EXPR) + { + lhs = build2 (COMPOUND_EXPR, lhstype, TREE_OPERAND (olhs, 0), lhs); + tree *ptr = &TREE_OPERAND (lhs, 1); + for (olhs = TREE_OPERAND (olhs, 1); + TREE_CODE (olhs) == COMPOUND_EXPR; + olhs = TREE_OPERAND (olhs, 1)) + { + *ptr = build2 (COMPOUND_EXPR, lhstype, + TREE_OPERAND (olhs, 0), *ptr); + ptr = &TREE_OPERAND (*ptr, 1); + } + } break; case MODIFY_EXPR: + if (compound_side_effects_p) + newrhs = rhs = stabilize_expr (rhs, &preeval); if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))) lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs), cp_stabilize_reference (TREE_OPERAND (lhs, 0)), TREE_OPERAND (lhs, 1)); lhs = build2 (COMPOUND_EXPR, lhstype, lhs, TREE_OPERAND (lhs, 0)); - break; + goto maybe_add_compound; case MIN_EXPR: case MAX_EXPR: @@ -7629,7 +7660,6 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, except that the RHS goes through a save-expr so the code to compute it is only emitted once. */ tree cond; - tree preeval = NULL_TREE; if (VOID_TYPE_P (TREE_TYPE (rhs))) { @@ -7655,14 +7685,31 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, if (cond == error_mark_node) return cond; + /* If we had (e, (a ? b : c)) = d; or (e, (f, (a ? b : c))) = d; + and looked through the COMPOUND_EXPRs, readd them now around + the resulting cond before adding the preevaluated rhs. */ + if (TREE_CODE (olhs) == COMPOUND_EXPR) + { + cond = build2 (COMPOUND_EXPR, TREE_TYPE (cond), + TREE_OPERAND (olhs, 0), cond); + tree *ptr = &TREE_OPERAND (cond, 1); + for (olhs = TREE_OPERAND (olhs, 1); + TREE_CODE (olhs) == COMPOUND_EXPR; + olhs = TREE_OPERAND (olhs, 1)) + { + *ptr = build2 (COMPOUND_EXPR, TREE_TYPE (cond), + TREE_OPERAND (olhs, 0), *ptr); + ptr = &TREE_OPERAND (*ptr, 1); + } + } /* Make sure the code to compute the rhs comes out before the split. */ - if (preeval) - cond = build2 (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond); - return cond; + result = cond; + goto ret; } default: + lhs = olhs; break; } @@ -7678,7 +7725,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, rhs = convert (lhstype, rhs); result = build2 (INIT_EXPR, lhstype, lhs, rhs); TREE_SIDE_EFFECTS (result) = 1; - return result; + goto ret; } else if (! MAYBE_CLASS_TYPE_P (lhstype)) /* Do the default thing. */; @@ -7691,7 +7738,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, release_tree_vector (rhs_vec); if (result == NULL_TREE) return error_mark_node; - return result; + goto ret; } } else @@ -7706,7 +7753,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, { result = objc_maybe_build_modify_expr (lhs, rhs); if (result) - return result; + goto ret; } /* `operator=' is not an inheritable operator. */ @@ -7720,7 +7767,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, complain); if (result == NULL_TREE) return error_mark_node; - return result; + goto ret; } lhstype = olhstype; } @@ -7765,7 +7812,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, { result = objc_maybe_build_modify_expr (lhs, newrhs); if (result) - return result; + goto ret; } } gcc_assert (TREE_CODE (lhstype) != REFERENCE_TYPE); @@ -7861,9 +7908,10 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE ? 1 + (modifycode != INIT_EXPR): 0; - return build_vec_init (lhs, NULL_TREE, newrhs, - /*explicit_value_init_p=*/false, - from_array, complain); + result = build_vec_init (lhs, NULL_TREE, newrhs, + /*explicit_value_init_p=*/false, + from_array, complain); + goto ret; } if (modifycode == INIT_EXPR) @@ -7902,7 +7950,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, result = objc_generate_write_barrier (lhs, modifycode, newrhs); if (result) - return result; + goto ret; } result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR, @@ -7912,6 +7960,9 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode, if (!plain_assign) TREE_NO_WARNING (result) = 1; + ret: + if (preeval) + result = build2 (COMPOUND_EXPR, TREE_TYPE (result), preeval, result); return result; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c7aad270697..281aca05594 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2017-02-13 Jakub Jelinek + + PR c++/79232 + * g++.dg/cpp1z/eval-order4.C: New test. + * g++.dg/other/pr79232.C: New test. + 2017-02-13 Nathan Sidwell PR c++/79296 diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order4.C b/gcc/testsuite/g++.dg/cpp1z/eval-order4.C new file mode 100644 index 00000000000..04da8ccc478 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/eval-order4.C @@ -0,0 +1,80 @@ +// PR c++/79232 +// { dg-do run } +// { dg-options "-fstrong-eval-order" } + +int last = 0; + +int +foo (int i) +{ + if (i != last + 1) + __builtin_abort (); + last = i; + return i; +} + +char a, b; +int c; + +char & +bar (int i, int j) +{ + foo (i); + return j ? a : b; +} + +int +main () +{ + (foo (2) ? bar (3, 0) : bar (3, 1)) = foo (1); + if (last != 3) + __builtin_abort (); + last = 0; + (foo (2), foo (3) ? bar (4, 0) : bar (4, 1)) = foo (1); + if (last != 4) + __builtin_abort (); + last = 0; + (foo (2), (foo (3) ? bar (4, 0) : bar (4, 1))) = foo (1); + if (last != 4) + __builtin_abort (); + last = 0; + (foo (2), foo (3), foo (4) ? bar (5, 0) : bar (5, 1)) = foo (1); + if (last != 5) + __builtin_abort (); + last = 0; + (foo (2), (foo (3), (foo (4) ? bar (5, 0) : bar (5, 1)))) = foo (1); + if (last != 5) + __builtin_abort (); + last = 0; + --c = foo (1); + if (c != 1) + __builtin_abort (); + last = 0; + (foo (2), --c) = foo (1); + if (last != 2 || c != 1) + __builtin_abort (); + last = 0; + (foo (2), foo (3), --c) = foo (1); + if (last != 3 || c != 1) + __builtin_abort (); + last = 0; + (foo (2), (foo (3), --c)) = foo (1); + if (last != 3 || c != 1) + __builtin_abort (); + last = 0; + bar (2, 0) = foo (1); + if (last != 2) + __builtin_abort (); + last = 0; + (foo (2), bar (3, 0)) = foo (1); + if (last != 3) + __builtin_abort (); + last = 0; + (foo (2), foo (3), bar (4, 0)) = foo (1); + if (last != 4) + __builtin_abort (); + last = 0; + (foo (2), (foo (3), bar (4, 0))) = foo (1); + if (last != 4) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/other/pr79232.C b/gcc/testsuite/g++.dg/other/pr79232.C new file mode 100644 index 00000000000..1b5d18d9491 --- /dev/null +++ b/gcc/testsuite/g++.dg/other/pr79232.C @@ -0,0 +1,12 @@ +// PR c++/79232 +// { dg-do compile } + +extern char a[]; +int b; +char c, e; + +void +foo (long d) +{ + (0, b ? &c : a)[d] = e; +} -- 2.30.2