C++ and volatile lvalue-to-rvalue

I want to put this gcc bug report to clang developer attention.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50364

The gcc developers believe that according to the standard

volatile int v;
x = v = 3;

does not imply necessarily a read from v.

clang instead add a lvalue-to-rvalue implicit cast outside v = 3
assignment (and there is general consensus that lvalue-to-rvalue *is*
the marker for memory read access).

If the beliefs of gcc developers are agreed by clang developers I think
that the cast kind should be changed in something else (and codegen
might handle this new kind differently).

Otherwise we should conclude that clang is right and gcc miscompile the
code above.

Note that the difference is not theoretic, just suppose that v is an
hardware register that when written is reset and when read return the
sensor state.

Of course the code above might be written as

v = 3;
x = v;

but this is pointless when trying to understand what is the right
semantic of C++ language as designed by the relevant standards.

C++11 5.17 [expr.ass]p1 says:
“The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand.”
So the result of (v = 3) is an lvalue referring to v, just as the expression (v) alone. Therefore the code is equivalent to the two separate statements:
v = 3;
x = v;

Clang is right, GCC is wrong.

Sebastian

To clarify: this is only C++. In C, the situation is different. C99 6.5.16p3 says:
“An assignment expression has the value of the left operand after the assignment, but is not an lvalue.”

So in C, GCC is right, and Clang is wrong.

It could be considered a defect of one of the two languages that they differ in such a subtle detail.

Sebastian

I definitely don't think that gcc developers would deny that v = 3 value
is an lvalue referring to v.

I'm inclined to believe that they think that there is a sort of "double
path" on exit from "v = 3": on the first path (lvalue) the result is an
lvalue referring v, on the second path (rvalue) the result is that of rhs.

This would be the reason why they write in texinfo doc the following
(emphasis is mine):

"Assignments are *also* expressions and have an rvalue. However when
assigning to a scalar volatile, the volatile object is not reread,
regardless of whether the assignment expression's rvalue is used or
not. If the assignment's rvalue is used, the value is that assigned
to the volatile object."

This would make a difference only with volatile and would give some
uniformity with C, but I really don't see how this perspective might be
matched with overloaded assign operators semantic... I'd guess that they
interpret that as an exception.

If you want to argue that this should both write to, and read from v, then I think you fall foul of lack of a sequence point, so the behaviour is undefined anyway.

Chris

We don't have a sequence point, but we have a partial ordering mandated
by the standard: the write should be done before the read (see 5.17p1).

Or you meant another source of undefined behaviour?

Note also that recent C++ standard no longer refers former "sequence
point" concept.

I want to put this gcc bug report to clang developer attention.

The gcc developers believe that according to the standard

volatile int v;
x = v = 3;

does not imply necessarily a read from v.

clang instead add a lvalue-to-rvalue implicit cast outside v = 3
assignment (and there is general consensus that lvalue-to-rvalue *is*
the marker for memory read access).

C++11 5.17 [expr.ass]p1 says:
“The assignment operator (=) and the compound assignment operators all group right-to-left. All require a modifiable lvalue as their left operand and return an lvalue referring to the left operand.”
So the result of (v = 3) is an lvalue referring to v, just as the expression (v) alone. Therefore the code is equivalent to the two separate statements:
v = 3;
x = v;

Clang is right, GCC is wrong.

To clarify: this is only C++. In C, the situation is different. C99 6.5.16p3 says:
“An assignment expression has the value of the left operand after the assignment, but is not an lvalue.”

So in C, GCC is right, and Clang is wrong.

Or rather, in C, Clang would be wrong if it emitted a volatile read here, which it does not. Clang implements different semantics in the two languages.

It could be considered a defect of one of the two languages that they differ in such a subtle detail.

Indeed, and the C++ committee has actually made some attempts to change this in C++11, but we haven’t implemented those changes yet, and we’re likely to only implement them in C++11 mode (i.e., treat C++11 as explicitly changing the semantics, rather than treating it as a true fix).

John.

It could be considered a defect of one of the two languages that they
differ in such a subtle detail.

I see this difference as a natural consequence of the different nature
of value of expression `a=b' in the two languages...

The differences are many and subtle in many different way and in many
areas (my preferred nasty one is that in gcc bitfield unsigned
arithmetic for bit widths larger than 32 bits use deliberately a
different modulo in C and C++)

Indeed, and the C++ committee has actually made some attempts to change
this in C++11, but we haven't implemented those changes yet, and we're
likely to only implement them in C++11 mode (i.e., treat C++11 as
explicitly changing the semantics, rather than treating it as a true fix).

Can you post a reference to that? I'm very interested to understand
where this leads.

Apparently I was mis-remembering; I was thinking of DR 1054, which
introduces lvalue-to-rvalue conversions in specific situations with certain
volatile l-value expressions. I know of no proposal to change assignment.

John.

Sebastian Redl <sebastian.redl@getdesigned.at>
writes:

It could be considered a defect of one of the two languages that they
differ in such a subtle detail.

Ugh...

To summarize: yet another reason to shun "volatile"...

-miles

Christopher Jefferson wrote:

I want to put this gcc bug report to clang developer attention.

http://gcc.gnu.org/bugzilla/show_bug.cgi?id=50364

The gcc developers believe that according to the standard

volatile int v;
x = v = 3;

does not imply necessarily a read from v.

If you want to argue that this should both write to, and read from v, then
I think you fall foul of lack of a sequence point, so the behaviour is
undefined anyway.

As clarified by Abramo, the assignment and the read from v are sequenced.
However the following would be undefined behavior:

    volatile int v = 0;
    int x = v + v;

Note how "v + v" does two side effects on v, and these side effects are not
sequenced.