Correct behavior of trivial operators associated with expressions with mutable variables?

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 was trying to find a point in the standard that tells me how the compiler should work when faced with these statements. All I could find was that A (and possibly C) gives me an lvalue, and B:

"ยง 5.1.1.8 Primary expressions - General" says

An identifier is an id expression if it has been declared appropriately (section 7). [..]
[..] The result is an object indicated by an identifier. The result is an lvalue if the object is a function, variable, or data item and prvalue otherwise.
[..]

"ยง 5.3.1 Unary operators" says

The unary * operator performs an indirect call: the expression to which it is applied must be a pointer to the type of the object or a pointer to the type of the function, and the result is an lvalue that refers to the object or function to which the expression refers.

clang and gcc

I tried this with clang ++ 3.2-11 and g ++ 4.7.3, and the first one created three reads in C ++ 11 mode, and zero reads in C ++ 03 mode (output of three warnings), and g ++ - only the first two, explicit way, I warn you that the third will not be generated.

Question

It is clear what type of value is derived from the expression from the quoted string in the standard, but:
which operator (A, B, C) should read from a mutable object in accordance with the C ++ standard?

+8
c ++ standards language-lawyer volatile
source share
2 answers

A g ++ warning about "implicit dereferencing" comes from code in gcc/cp/cvt.c , which intentionally does not load the value through a link:

  /* 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 this intentionally because, as indicated in the manual ( When is a VOLECTAL C ++ object available? the standard is not clear about what constitutes access to an object with mutable qualifications. As indicated there, you need to force lvalue-rvalue to be converted, to make the load unstable.

Clang gives warnings in C ++ 03 mode, which 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 ++ behavior and the GCC manual seem 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 an expression with a discarded value and says that for volatiles, the lvalue-to-rale conversion applies to the id, for example, your operators A and C. The specification for the lvalue-to-rvalue conversion (4.1) [conv.lval ]) says that the result is a value of glvalue, which represents access volatility. According to 5p10, all three of your statements must be accessible, so the processing of g ++ C instructions must be updated to comply with C ++ 11. I reported this as http://gcc.gnu.org/bugzilla/show_bug.cgi?id= 59314

+5
source share

This gcc 7.1 document When is the current VOLUME C ++ object available? I quote (my emphasis in the future):

The C ++ standard is different from the C standard when handling volatile objects. It cannot indicate what constitutes volatile access , except that C ++ should behave similarly to C with respect to volatile

The C and C ++ language specifications differ when accessing an object in the void context:

and provides this example:

 volatile int *src = somevalue; *src; 

and continues:

The C ++ standard states that such expressions do not undergo lvalue conversion to rvalue and that the type of the dereference object may be incomplete. The C ++ standard does not explicitly state that it is an lvalue for the rvalue transform, which is responsible for causing access.

which should keep in mind the draft standard section 5.3.1 Unary operators, paragraph 1, which states:

The unary operator * performs an indirect call: the expression to which it is applied must be a pointer to the type of the object or a pointer to the type of the function, and the result is an lvalue that refers to the object or functions to which the expression refers. [...]

and following the links:

When using the volatile reference, g ++ does not treat equivalent expressions as volatile references, but instead gives a warning that there is no volatile access. The rationale for this is that otherwise it becomes difficult to determine where volatile access occurs, and it is impossible to ignore the return value from functions that return volatile references. Again , if you want to force read, enter the rvalue link .

so it looks like this: gcc prefers to handle references to mutable in different ways and in order to make it read, which you need to pass to the r-value, for example:

 static_cast<volatile int>( c ) ; 

which generates a prvalue and therefore the conversion of lvalue to rvalue from section 5.2.9 Static cast:

The result of static_cast (v) is the result of converting v to type T. If T is a lvalue reference type or rvalue reference to a function type, the result is lvalue; if T is an rvalue reference to an object type, the result is an xvalue; Otherwise, the result will be prvalue.

Refresh

The C ++ 11 draft adds 5 expression 11, which states:

In some contexts, an expression appears only for its side effects. Such an expression is called a discarded value expression. The expression is evaluated and its value is discarded. Standard conversions using the pointer array (4.2) and the pointer function (4.3) do not apply. The lvalue-to-rvalue (4.1) transformation is applied if and only if the expression is an lvalue of a volatile-qualified type and is one of the following :

and includes:

- id expression (5.1.1),

This seems ambiguous to me, because with respect to a; and c; Section 5.1.1 p8 says that it is an lvalue , and it is not obvious to me that it covers this case, but since Jonathan found DR 1054 it says that it really covers this case.

+3
source share

All Articles