re PR c++/7503 ((x < Y ? X : Y) used for assignment causes wrong code)

PR c++/7503
	* tree.c (lvalue_p_1):  Disallow MIN_EXPR and MAX_EXPR as lvalues
	if either operand has side-effects.
	* typeck.c (rationalize_conditional_expr): Assert that neither
	operand of MIN_EXPR or MAX_EXPR has side-effects.
	(build_modify_expr):  Add support for MIN_EXPR and MAX_EXPR.
	Check that the "lhs" is a valid lvalue, i.e. that neither operand
	of a MIN_EXPR or MAX_EXPR has a side-effect.

	* g++.dg/opt/pr7503-1.C: New testcase for COND_EXPR lvalues.
	* g++.dg/opt/pr7503-2.C: New testcase for <? and >? lvalues.
	* g++.dg/opt/pr7503-3.C: New testcase for invalid <? lvalue errors.
	* g++.dg/opt/pr7503-4.C: New testcase for <?= and >?= assignments.
	* g++.dg/opt/pr7503-5.C: New testcase for side-effects with <?=.

From-SVN: r87810
This commit is contained in:
Roger Sayle 2004-09-21 16:20:12 +00:00 committed by Roger Sayle
parent f0c721ad7c
commit d211a298ce
9 changed files with 461 additions and 0 deletions

View File

@ -1,3 +1,14 @@
2004-09-21 Roger Sayle <roger@eyesopen.com>
PR c++/7503
* tree.c (lvalue_p_1): Disallow MIN_EXPR and MAX_EXPR as lvalues
if either operand has side-effects.
* typeck.c (rationalize_conditional_expr): Assert that neither
operand of MIN_EXPR or MAX_EXPR has side-effects.
(build_modify_expr): Add support for MIN_EXPR and MAX_EXPR.
Check that the "lhs" is a valid lvalue, i.e. that neither operand
of a MIN_EXPR or MAX_EXPR has a side-effect.
2004-09-21 Nathan Sidwell <nathan@codesourcery.com>
* cp-tree.h (struct lang_type_header): Remove

View File

@ -129,6 +129,10 @@ lvalue_p_1 (tree ref,
gcc_unreachable ();
case MAX_EXPR:
case MIN_EXPR:
/* Disallow <? and >? as lvalues if either argument side-effects. */
if (TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 0))
|| TREE_SIDE_EFFECTS (TREE_OPERAND (ref, 1)))
return clk_none;
op1_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 0),
treat_class_rvalues_as_lvalues);
op2_lvalue_kind = lvalue_p_1 (TREE_OPERAND (ref, 1),

View File

@ -1524,6 +1524,9 @@ rationalize_conditional_expr (enum tree_code code, tree t)
are equal, so we know what conditional expression this used to be. */
if (TREE_CODE (t) == MIN_EXPR || TREE_CODE (t) == MAX_EXPR)
{
/* The following code is incorrect if either operand side-effects. */
gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (t, 0))
&& !TREE_SIDE_EFFECTS (TREE_OPERAND (t, 1)));
return
build_conditional_expr (build_x_binary_op ((TREE_CODE (t) == MIN_EXPR
? LE_EXPR : GE_EXPR),
@ -5038,6 +5041,25 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
return error_mark_node;
return build2 (COMPOUND_EXPR, lhstype, lhs, newrhs);
case MIN_EXPR:
case MAX_EXPR:
/* MIN_EXPR and MAX_EXPR are currently only permitted as lvalues,
when neither operand has side-effects. */
if (!lvalue_or_else (lhs, "assignment"))
return error_mark_node;
gcc_assert (!TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 0))
&& !TREE_SIDE_EFFECTS (TREE_OPERAND (lhs, 1)));
lhs = build3 (COND_EXPR, TREE_TYPE (lhs),
build2 (TREE_CODE (lhs) == MIN_EXPR ? LE_EXPR : GE_EXPR,
boolean_type_node,
TREE_OPERAND (lhs, 0),
TREE_OPERAND (lhs, 1)),
TREE_OPERAND (lhs, 0),
TREE_OPERAND (lhs, 1));
/* Fall through. */
/* Handle (a ? b : c) used as an "lvalue". */
case COND_EXPR:
{

View File

@ -1,3 +1,12 @@
2004-09-21 Roger Sayle <roger@eyesopen.com>
PR c++/7503
* g++.dg/opt/pr7503-1.C: New testcase for COND_EXPR lvalues.
* g++.dg/opt/pr7503-2.C: New testcase for <? and >? lvalues.
* g++.dg/opt/pr7503-3.C: New testcase for invalid <? lvalue errors.
* g++.dg/opt/pr7503-4.C: New testcase for <?= and >?= assignments.
* g++.dg/opt/pr7503-5.C: New testcase for side-effects with <?=.
2004-09-21 Bud Davis <bdavis9659@comcast.net>
PR fortran/17286

View File

@ -0,0 +1,148 @@
// PR c++/7503
// { dg-do run }
// { dg-options "-O2" }
extern "C" void abort();
void test1a()
{
int A = 4;
int B = 4;
(A > B ? A : B) = 1;
if (A != 4 || B != 1)
abort ();
}
void test1b()
{
int A = 3;
int B = 5;
(A > B ? A : B) = 1;
if (A != 3 || B != 1)
abort ();
}
void test1c()
{
int A = 5;
int B = 3;
(A > B ? A : B) = 1;
if (A != 1 || B != 3)
abort ();
}
void test2a()
{
int A = 4;
int B = 4;
(A >= B ? A : B) = 1;
if (A != 1 || B != 4)
abort ();
}
void test2b()
{
int A = 3;
int B = 5;
(A >= B ? A : B) = 1;
if (A != 3 || B != 1)
abort ();
}
void test2c()
{
int A = 5;
int B = 3;
(A >= B ? A : B) = 1;
if (A != 1 || B != 3)
abort ();
}
void test3a()
{
int A = 4;
int B = 4;
(A < B ? A : B) = 1;
if (A != 4 || B != 1)
abort ();
}
void test3b()
{
int A = 3;
int B = 5;
(A < B ? A : B) = 1;
if (A != 1 || B != 5)
abort ();
}
void test3c()
{
int A = 5;
int B = 3;
(A < B ? A : B) = 1;
if (A != 5 || B != 1)
abort ();
}
void test4a()
{
int A = 4;
int B = 4;
(A <= B ? A : B) = 1;
if (A != 1 || B != 4)
abort ();
}
void test4b()
{
int A = 3;
int B = 5;
(A <= B ? A : B) = 1;
if (A != 1 || B != 5)
abort ();
}
void test4c()
{
int A = 5;
int B = 3;
(A <= B ? A : B) = 1;
if (A != 5 || B != 1)
abort ();
}
int main()
{
test1a();
test1b();
test1c();
test2a();
test2b();
test2c();
test3a();
test3b();
test3c();
test4a();
test4b();
test4c();
return 0;
}

View File

@ -0,0 +1,79 @@
// PR c++/7503
// { dg-do run }
// { dg-options "-O2" }
extern "C" void abort();
void test1a()
{
int A = 4;
int B = 4;
(A >? B) = 1;
if (A != 1 || B != 4)
abort ();
}
void test1b()
{
int A = 3;
int B = 5;
(A >? B) = 1;
if (A != 3 || B != 1)
abort ();
}
void test1c()
{
int A = 5;
int B = 3;
(A >? B) = 1;
if (A != 1 || B != 3)
abort ();
}
void test2a()
{
int A = 4;
int B = 4;
(A <? B) = 1;
if (A != 1 || B != 4)
abort ();
}
void test2b()
{
int A = 3;
int B = 5;
(A <? B) = 1;
if (A != 1 || B != 5)
abort ();
}
void test2c()
{
int A = 5;
int B = 3;
(A <? B) = 1;
if (A != 5 || B != 1)
abort ();
}
int main()
{
test1a();
test1b();
test1c();
test2a();
test2b();
test2c();
return 0;
}

View File

@ -0,0 +1,26 @@
// PR c++/7503
// { dg-do compile }
// { dg-options "-O2" }
extern int A, B;
void test1()
{
(A++ <? B) = 0; // { dg-error "non-lvalue in assignment" }
}
void test2()
{
(A <? B++) = 0; // { dg-error "non-lvalue in assignment" }
}
void test3()
{
(A++ >? B) = 0; // { dg-error "non-lvalue in assignment" }
}
void test4()
{
(A >? B++) = 0; // { dg-error "non-lvalue in assignment" }
}

View File

@ -0,0 +1,81 @@
// PR c++/7503
// { dg-do run }
// { dg-options "-O2" }
extern "C" void abort();
void test1a()
{
int A = 4;
int B = 4;
A >?= B;
if (A != 4 || B != 4)
abort ();
}
void test1b()
{
int A = 3;
int B = 5;
A >?= B;
if (A != 5 || B != 5)
abort ();
}
void test1c()
{
int A = 5;
int B = 3;
A >?= B;
if (A != 5 || B != 3)
abort ();
}
void test2a()
{
int A = 4;
int B = 4;
A <?= B;
if (A != 4 || B != 4)
abort ();
}
void test2b()
{
int A = 3;
int B = 5;
A <?= B;
if (A != 3 || B != 5)
abort ();
}
void test2c()
{
int A = 5;
int B = 3;
A <?= B;
if (A != 3 || B != 3)
abort ();
}
int main()
{
test1a();
test1b();
test1c();
test2a();
test2b();
test2c();
return 0;
}

View File

@ -0,0 +1,81 @@
// PR c++/7503
// { dg-do run }
// { dg-options "-O2" }
extern "C" void abort();
void test1a()
{
int A = 4;
int B = 4;
A >?= B++;
if (A != 4 || B != 5)
abort ();
}
void test1b()
{
int A = 3;
int B = 5;
A >?= B++;
if (A != 5 || B != 6)
abort ();
}
void test1c()
{
int A = 5;
int B = 3;
A >?= B++;
if (A != 5 || B != 4)
abort ();
}
void test2a()
{
int A = 4;
int B = 4;
A <?= B++;
if (A != 4 || B != 5)
abort ();
}
void test2b()
{
int A = 3;
int B = 5;
A <?= B++;
if (A != 3 || B != 6)
abort ();
}
void test2c()
{
int A = 5;
int B = 3;
A <?= B++;
if (A != 3 || B != 4)
abort ();
}
int main()
{
test1a();
test1b();
test1c();
test2a();
test2b();
test2c();
return 0;
}