aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2017-02-13 20:31:14 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2017-02-13 20:31:14 +0100
commitb84702c0572614a71e720e9f822d1c31c7cea5b7 (patch)
treedf43d3655d26975e5a4f7618be2d1f4f19b47b6b /gcc
parente1cb14c91a56a5ee7aad50e67361bcbec7441ca0 (diff)
downloadgcc-b84702c0572614a71e720e9f822d1c31c7cea5b7.zip
gcc-b84702c0572614a71e720e9f822d1c31c7cea5b7.tar.gz
gcc-b84702c0572614a71e720e9f822d1c31c7cea5b7.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog7
-rw-r--r--gcc/cp/typeck.c81
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/eval-order4.C80
-rw-r--r--gcc/testsuite/g++.dg/other/pr79232.C12
5 files changed, 171 insertions, 15 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 3008604..3fffb5b 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,10 @@
+2017-02-13 Jakub Jelinek <jakub@redhat.com>
+
+ 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 <nathan@acm.org>
PR c++/79296 - ICE mangling localized template instantiation
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index ef4dae4..87e7cc0 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 c7aad27..281aca0 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2017-02-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/79232
+ * g++.dg/cpp1z/eval-order4.C: New test.
+ * g++.dg/other/pr79232.C: New test.
+
2017-02-13 Nathan Sidwell <nathan@acm.org>
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 0000000..04da8cc
--- /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 0000000..1b5d18d
--- /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;
+}