Message ID | 20160422115033.GX28445@redhat.com |
---|---|
State | New |
Headers | show |
On 04/22/2016 07:50 AM, Marek Polacek wrote: > 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. Your change will turn the expression into an rvalue, so that isn't enough. We need to turn the expression into some sort of _REF before passing it to stabilize_reference, perhaps by factoring out the cast-to-reference code from force_paren_expr. This should probably be part of a cp_stabilize_reference function that replaces all uses of stabilize_reference in the front end. Jason
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: