aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/tree.c4
-rw-r--r--gcc/cp/typeck.c22
-rw-r--r--gcc/testsuite/ChangeLog9
-rw-r--r--gcc/testsuite/g++.dg/opt/pr7503-1.C148
-rw-r--r--gcc/testsuite/g++.dg/opt/pr7503-2.C79
-rw-r--r--gcc/testsuite/g++.dg/opt/pr7503-3.C26
-rw-r--r--gcc/testsuite/g++.dg/opt/pr7503-4.C81
-rw-r--r--gcc/testsuite/g++.dg/opt/pr7503-5.C81
9 files changed, 461 insertions, 0 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index f436ad9..e9e6d42 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -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
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 28bb512..fc3516d 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -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),
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 990352d..164f7a3 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -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:
{
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index e64aafb..c52f7ba 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
diff --git a/gcc/testsuite/g++.dg/opt/pr7503-1.C b/gcc/testsuite/g++.dg/opt/pr7503-1.C
new file mode 100644
index 0000000..d366a61
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr7503-1.C
@@ -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;
+}
+
diff --git a/gcc/testsuite/g++.dg/opt/pr7503-2.C b/gcc/testsuite/g++.dg/opt/pr7503-2.C
new file mode 100644
index 0000000..68bb143
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr7503-2.C
@@ -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;
+}
+
diff --git a/gcc/testsuite/g++.dg/opt/pr7503-3.C b/gcc/testsuite/g++.dg/opt/pr7503-3.C
new file mode 100644
index 0000000..ed223f4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr7503-3.C
@@ -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" }
+}
+
diff --git a/gcc/testsuite/g++.dg/opt/pr7503-4.C b/gcc/testsuite/g++.dg/opt/pr7503-4.C
new file mode 100644
index 0000000..06ac901
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr7503-4.C
@@ -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;
+}
+
diff --git a/gcc/testsuite/g++.dg/opt/pr7503-5.C b/gcc/testsuite/g++.dg/opt/pr7503-5.C
new file mode 100644
index 0000000..9e1e719
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr7503-5.C
@@ -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;
+}
+