re PR c++/7503 ((x < Y ? X : Y) used for assignment causes wrong code)
authorRoger Sayle <roger@eyesopen.com>
Tue, 21 Sep 2004 16:20:12 +0000 (16:20 +0000)
committerRoger Sayle <sayle@gcc.gnu.org>
Tue, 21 Sep 2004 16:20:12 +0000 (16:20 +0000)
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

gcc/cp/ChangeLog
gcc/cp/tree.c
gcc/cp/typeck.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/opt/pr7503-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/opt/pr7503-2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/opt/pr7503-3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/opt/pr7503-4.C [new file with mode: 0644]
gcc/testsuite/g++.dg/opt/pr7503-5.C [new file with mode: 0644]

index f436ad9d077d6fcccb2c6488fae4a48fe550fc24..e9e6d4240df7ccfe2099eff4066e572ea10d346e 100644 (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
index 28bb512da75319ab52eec6b8503066ea0995d7e4..fc3516d8e8a8b8f823c54f378487d014811f316c 100644 (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),
index 990352d492d56e0dcf9e7f94505b1971cec59ab2..164f7a34a71aa0ad14d748ad42a1071ddc2f86cf 100644 (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:
       {
index e64aafb22f554f0dccfdaf40b001ffdaa5f3e0e5..c52f7ba68dde9de84c70cd3d7d01baa3225d5a89 100644 (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
diff --git a/gcc/testsuite/g++.dg/opt/pr7503-1.C b/gcc/testsuite/g++.dg/opt/pr7503-1.C
new file mode 100644 (file)
index 0000000..d366a61
--- /dev/null
@@ -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 (file)
index 0000000..68bb143
--- /dev/null
@@ -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 (file)
index 0000000..ed223f4
--- /dev/null
@@ -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 (file)
index 0000000..06ac901
--- /dev/null
@@ -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 (file)
index 0000000..9e1e719
--- /dev/null
@@ -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;
+}
+