This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/70744 (wrong-code with x ?: y extension)
- From: Marek Polacek <polacek at redhat dot com>
- To: GCC Patches <gcc-patches at gcc dot gnu dot org>, Jason Merrill <jason at redhat dot com>
- Date: Fri, 22 Apr 2016 13:50:33 +0200
- Subject: C++ PATCH for c++/70744 (wrong-code with x ?: y extension)
- Authentication-results: sourceware.org; auth=none
This PR shows that we generate wrong code with the x ?: y extension in case the
first operand contains either predecrement or preincrement. The problem is
that we don't emit SAVE_EXPR, thus the operand is evaluated twice, which it
should not be.
While ++i or --i can be lvalues in C++, i++ or i-- can not. The code in
build_conditional_expr_1 has:
4635 /* Make sure that lvalues remain lvalues. See g++.oliva/ext1.C. */
4636 if (real_lvalue_p (arg1))
4637 arg2 = arg1 = stabilize_reference (arg1);
4638 else
4639 arg2 = arg1 = save_expr (arg1);
so for ++i/--i we call stabilize_reference, but that doesn't know anything
about PREINCREMENT_EXPR or PREDECREMENT_EXPR and just returns the same
expression, so SAVE_EXPR isn't created.
I think one fix would be to teach stabilize_reference what to do with those,
similarly to how we handle COMPOUND_EXPR there.
Bootstrapped/regtested on x86_64-linux, ok for trunk?
2016-04-22 Marek Polacek <polacek@redhat.com>
PR c++/70744
* tree.c (stabilize_reference): Handle PREINCREMENT_EXPR and
PREDECREMENT_EXPR.
* g++.dg/ext/cond2.C: New test.
diff --git gcc/testsuite/g++.dg/ext/cond2.C gcc/testsuite/g++.dg/ext/cond2.C
index e69de29..d9f1d59 100644
--- gcc/testsuite/g++.dg/ext/cond2.C
+++ gcc/testsuite/g++.dg/ext/cond2.C
@@ -0,0 +1,28 @@
+// PR c++/70744
+// { dg-do run }
+// { dg-options "" }
+
+static void
+fn1 (void)
+{
+ int x = 2;
+ ++x ? : 42;
+ if (x != 3)
+ __builtin_abort ();
+ --x ? : 42;
+ if (x != 2)
+ __builtin_abort ();
+ x++ ? : 42;
+ if (x != 3)
+ __builtin_abort ();
+ x-- ? : 42;
+ if (x != 2)
+ __builtin_abort ();
+}
+
+int
+main ()
+{
+ fn1 ();
+ return 0;
+}
diff --git gcc/tree.c gcc/tree.c
index 6de46a8..8fd4e81 100644
--- gcc/tree.c
+++ gcc/tree.c
@@ -4255,6 +4255,13 @@ stabilize_reference (tree ref)
volatiles. */
return stabilize_reference_1 (ref);
+ case PREINCREMENT_EXPR:
+ case PREDECREMENT_EXPR:
+ /* While in C++ postincrement and postdecrement expressions are not
+ considered lvalues, preincrement and predecrement expressions can
+ be lvalues. */
+ return stabilize_reference_1 (ref);
+
/* If arg isn't a kind of lvalue we recognize, make no change.
Caller should recognize the error for an invalid lvalue. */
default:
Marek