Correct behaviour of trivial statements involving expressions with volatile variables?

c++, language-lawyer, standards, volatile

Solution

The G++ warning about the "implicit dereference" comes from code in `gcc/cp/cvt.c` which intentionally does not load the value through a reference:

    /* Don't load the value if this is an implicit dereference, or if
       the type needs to be handled by ctors/dtors.  */
    else if (is_volatile && is_reference)

G++ does that intentionally, because as stated in the manual (When is a Volatile C++ Object Accessed?) the standard is not clear about what constitutes an access of a volatile-qualified object. As stated there you need to force lvalue-to-rvalue conversion to force a load from a volatile.

Clang gives warnings in C++03 mode that indicate a similar interpretation:

a.cc:4:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
  a;   // statement A
  ^
a.cc:6:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
  *b;  // statement B
  ^~
a.cc:8:3: warning: expression result unused; assign into a variable to force a volatile load [-Wunused-volatile-lvalue]
  c;   // statement C
  ^
3 warnings generated.

The G++ behaviour and the GCC manual seem to be correct for C++03, but there is a difference in C++11 relative to C++03, introduced by DR 1054 (which also explains why Clang behaves differently in C++)3 and C++11 modes). 5 [expr] p10 defines a discarded-value-expression and says that for volatiles the lvalue-to-rvalue conversion is applied to an id-expression such as your statements A and C. The spec for lvalue-to-rvalue conversion (4.1 [conv.lval]) says that the result is the value of the glvalue, which constitutes an access of the volatile. According to 5p10 all three of your statements should be accesses, so G++'s handling of statement C needs to be updated to conform to C++11. I've reported it as http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59314

Problem

Consider the following statements ``` volatile int a = 7; a; // statement A volatile int* b = &a; *b; // statement B volatile int& c = a; c; // statement C ``` Now, I've been trying to find a point in the standard that tells me how a compiler is to behave when coming across these statements. All I could find is that A (and possibly C) gives me an lvalue, and so does B: "§ 5.1.1.8 Primary expressions - General" says An identifier is an id-expression provided it has been suitably declared (Clause 7). [..] [..] The result is the entity denoted by the identifier. The result is an lvalue if the entity is a function, variable, or data member and a prvalue otherwise. [..] "§ 5.3.1 Unary operators" says The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points. clang and gcc I tried this with clang++ 3.2-11 and g++ 4.7.3, and the first produced three reads in C++11 mode and zero reads in C++03 mode (outputting three warnings) while g++ only produced the first two, explicitly warning me that the third would not be generated. Question It is clear which type of value comes out of the expression, from the quoted line in the standard, but: which of the statements (A,B,C) should produce a read from the volatile entity according to the C++ standard?

Original source