Clearly the comment in the snippet was wrong as the variable S::x
is odr-used by the expression &S::x
.
And then that expression is dropped on the bit floor. &S::x;
is not ODR-used. Once variant of [basic.def.odr]
paragraph 3 reads (bold emphasis mine):
A variable x
whose name appears as a potentially-evaluated expression ex
is odr-used by ex
unless applying the lvalue-to-rvalue conversion to x
yields a constant expression that does not invoke any non-trivial functions and, if x
is an object, ex
is an element of the set of potential results of an expression e
, where either the lvalue-to-rvalue conversion is applied to e
, or e
is a discarded-value expression.
The section[expr]
paragraph 11 covers the concept of a discarded-value expression:
In some contexts, an expression only appears for its side effects. Such an expression is called a discarded-value expression. The expression is evaluated and its value is discarded. The array-to-pointer and function- to-pointer standard conversions are not applied. The lvalue-to-rvalue conversion is applied if and only if the expression is a glvalue of volatile-qualified type and it is one of the following:
- ( expression ), where expression is one of these expressions,
- id-expression,
- subscripting,
- class member access,
- indirection,
- pointer-to-member operation,
- conditional expression where both the second and the third operands are one of these expressions, or
- comma expression where the right operand is one of these expressions.
The statement &S::x;
is a discarded-value expression that does not require lvalue-to-rvalue conversion, so there's nothing to convert. The statement might as well not exist, and hence doesn't exist as far as ODR-usage is concerned.
This metric can be changed by qualifying S::x
as volatile
rather than as const
, and by trying to drop S::x
on the bit floor:
struct S { static volatile int x; };
void f() { S::x; } // This discarded-value expression does odr-use S::x
int main(){
f();
}
The above compiles (but with a warning about a discarded expression) with GNU's C++ compiler/linker using --std=c++03
but fails to compile/link using --std=c++11
or higher. C++11 added quite a bit regarding the workings of the C++ abstract machine. Even though S::x;
remains a discarded value expression, that S::x
is now volatile requires the compiler to apply lvalue-to-rvalue conversion prior to dropping the result on the bit floor.
Change the S::x
in the above to &S::x
and the program once again compiles (but once again with a warning about a discarded expression). Even though S::x
is volatile, it's address is not.