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.