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
This commit is contained in:
parent
e1cb14c91a
commit
b84702c057
|
@ -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>
|
2017-02-13 Nathan Sidwell <nathan@acm.org>
|
||||||
|
|
||||||
PR c++/79296 - ICE mangling localized template instantiation
|
PR c++/79296 - ICE mangling localized template instantiation
|
||||||
|
|
|
@ -7571,16 +7571,26 @@ tree
|
||||||
cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
|
cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
|
||||||
tree rhs, tsubst_flags_t complain)
|
tree rhs, tsubst_flags_t complain)
|
||||||
{
|
{
|
||||||
tree result;
|
tree result = NULL_TREE;
|
||||||
tree newrhs = rhs;
|
tree newrhs = rhs;
|
||||||
tree lhstype = TREE_TYPE (lhs);
|
tree lhstype = TREE_TYPE (lhs);
|
||||||
|
tree olhs = lhs;
|
||||||
tree olhstype = lhstype;
|
tree olhstype = lhstype;
|
||||||
bool plain_assign = (modifycode == NOP_EXPR);
|
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. */
|
/* Avoid duplicate error messages from operands that had errors. */
|
||||||
if (error_operand_p (lhs) || error_operand_p (rhs))
|
if (error_operand_p (lhs) || error_operand_p (rhs))
|
||||||
return error_mark_node;
|
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
|
/* Handle control structure constructs used as "lvalues". Note that we
|
||||||
leave COMPOUND_EXPR on the LHS because it is sequenced after the RHS. */
|
leave COMPOUND_EXPR on the LHS because it is sequenced after the RHS. */
|
||||||
switch (TREE_CODE (lhs))
|
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++. */
|
/* Handle --foo = 5; as these are valid constructs in C++. */
|
||||||
case PREDECREMENT_EXPR:
|
case PREDECREMENT_EXPR:
|
||||||
case PREINCREMENT_EXPR:
|
case PREINCREMENT_EXPR:
|
||||||
|
if (compound_side_effects_p)
|
||||||
|
newrhs = rhs = stabilize_expr (rhs, &preeval);
|
||||||
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
|
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
|
||||||
lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
|
lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
|
||||||
cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
|
cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
|
||||||
TREE_OPERAND (lhs, 1));
|
TREE_OPERAND (lhs, 1));
|
||||||
lhs = build2 (COMPOUND_EXPR, lhstype, lhs, TREE_OPERAND (lhs, 0));
|
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;
|
break;
|
||||||
|
|
||||||
case MODIFY_EXPR:
|
case MODIFY_EXPR:
|
||||||
|
if (compound_side_effects_p)
|
||||||
|
newrhs = rhs = stabilize_expr (rhs, &preeval);
|
||||||
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
|
if (TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0)))
|
||||||
lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
|
lhs = build2 (TREE_CODE (lhs), TREE_TYPE (lhs),
|
||||||
cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
|
cp_stabilize_reference (TREE_OPERAND (lhs, 0)),
|
||||||
TREE_OPERAND (lhs, 1));
|
TREE_OPERAND (lhs, 1));
|
||||||
lhs = build2 (COMPOUND_EXPR, lhstype, lhs, TREE_OPERAND (lhs, 0));
|
lhs = build2 (COMPOUND_EXPR, lhstype, lhs, TREE_OPERAND (lhs, 0));
|
||||||
break;
|
goto maybe_add_compound;
|
||||||
|
|
||||||
case MIN_EXPR:
|
case MIN_EXPR:
|
||||||
case MAX_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
|
except that the RHS goes through a save-expr
|
||||||
so the code to compute it is only emitted once. */
|
so the code to compute it is only emitted once. */
|
||||||
tree cond;
|
tree cond;
|
||||||
tree preeval = NULL_TREE;
|
|
||||||
|
|
||||||
if (VOID_TYPE_P (TREE_TYPE (rhs)))
|
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)
|
if (cond == error_mark_node)
|
||||||
return cond;
|
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
|
/* Make sure the code to compute the rhs comes out
|
||||||
before the split. */
|
before the split. */
|
||||||
if (preeval)
|
result = cond;
|
||||||
cond = build2 (COMPOUND_EXPR, TREE_TYPE (lhs), preeval, cond);
|
goto ret;
|
||||||
return cond;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
lhs = olhs;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7678,7 +7725,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
|
||||||
rhs = convert (lhstype, rhs);
|
rhs = convert (lhstype, rhs);
|
||||||
result = build2 (INIT_EXPR, lhstype, lhs, rhs);
|
result = build2 (INIT_EXPR, lhstype, lhs, rhs);
|
||||||
TREE_SIDE_EFFECTS (result) = 1;
|
TREE_SIDE_EFFECTS (result) = 1;
|
||||||
return result;
|
goto ret;
|
||||||
}
|
}
|
||||||
else if (! MAYBE_CLASS_TYPE_P (lhstype))
|
else if (! MAYBE_CLASS_TYPE_P (lhstype))
|
||||||
/* Do the default thing. */;
|
/* 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);
|
release_tree_vector (rhs_vec);
|
||||||
if (result == NULL_TREE)
|
if (result == NULL_TREE)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
return result;
|
goto ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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);
|
result = objc_maybe_build_modify_expr (lhs, rhs);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
goto ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* `operator=' is not an inheritable operator. */
|
/* `operator=' is not an inheritable operator. */
|
||||||
|
@ -7720,7 +7767,7 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
|
||||||
complain);
|
complain);
|
||||||
if (result == NULL_TREE)
|
if (result == NULL_TREE)
|
||||||
return error_mark_node;
|
return error_mark_node;
|
||||||
return result;
|
goto ret;
|
||||||
}
|
}
|
||||||
lhstype = olhstype;
|
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);
|
result = objc_maybe_build_modify_expr (lhs, newrhs);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
goto ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gcc_assert (TREE_CODE (lhstype) != REFERENCE_TYPE);
|
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
|
from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
|
||||||
? 1 + (modifycode != INIT_EXPR): 0;
|
? 1 + (modifycode != INIT_EXPR): 0;
|
||||||
return build_vec_init (lhs, NULL_TREE, newrhs,
|
result = build_vec_init (lhs, NULL_TREE, newrhs,
|
||||||
/*explicit_value_init_p=*/false,
|
/*explicit_value_init_p=*/false,
|
||||||
from_array, complain);
|
from_array, complain);
|
||||||
|
goto ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modifycode == INIT_EXPR)
|
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);
|
result = objc_generate_write_barrier (lhs, modifycode, newrhs);
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
goto ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = build2 (modifycode == NOP_EXPR ? MODIFY_EXPR : INIT_EXPR,
|
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)
|
if (!plain_assign)
|
||||||
TREE_NO_WARNING (result) = 1;
|
TREE_NO_WARNING (result) = 1;
|
||||||
|
|
||||||
|
ret:
|
||||||
|
if (preeval)
|
||||||
|
result = build2 (COMPOUND_EXPR, TREE_TYPE (result), preeval, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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>
|
2017-02-13 Nathan Sidwell <nathan@acm.org>
|
||||||
|
|
||||||
PR c++/79296
|
PR c++/79296
|
||||||
|
|
|
@ -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 ();
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
Loading…
Reference in New Issue