- A+

The code below compiles in GCC, clang and VS2017 and the expression `a->i`

in the `return`

statement is replaced by its constant value 1. Is it correct to say that this is valid because `a`

is **not** odr-used in the expression `a->i`

?.

`struct A { static const int i = 1; }; int f() { A *a = nullptr; return a->i; } `

PS: I believe `a`

is **not** odr-used in the expression `a->i`

because it satisfies the "unless" condition in [basic.def.odr]/4, as follows:

A variable

`x`

whose name appears as a potentially-evaluated expression`ex`

is odr-used by`ex`

unlessapplying the lvalue-to-rvalue conversion (7.1) to`x`

yields a constant expression (8.6) 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 (7.1) is applied to`e`

, or`e`

is a discarded-value expression (8.2).

In particular, the expression `ex == a`

is an element of the set of potential results of the expression `e == a->i`

, according to [basic.def.odr]/2 (2.3), containing the expression `ex`

, where the lvalue-to-rvalue conversion is applied to `e`

.

`a`

is odr-used because you fail the first part of the "unless":

applying the lvalue-to-rvalue conversion (7.1) to

`x`

yields a constant expression (8.6) that does not invoke any non-trivial functions

Applying the lvalue-to-rvalue conversion to `a`

does not yield a constant expression.

The rest is core issues 315 and 232.

Your analysis is broken in two additional ways:

- The "object expression" is defined using the
`.`

form of class member access, so you need to rewrite`a->i`

to dot form, i.e.,`(*a).i`

, before applying [basic.def.odr]/2.3.`a`

is not a member of the set of potential results of that expression. - That bullet itself is defective because it was written with non-static data members in mind. For static data members, the set of potential results should be in fact the named static data member - see core issue 2353, so
`a`

is doubly not a member of the set of potential results of that expression.

[expr.const]/2.7:

An expression

`e`

is acore constant expressionunless the evaluation of`e`

, following the rules of the abstract machine, would evaluate one of the following expressions:

- [...]
- an lvalue-to-rvalue conversion unless it is applied to

- a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
- a non-volatile glvalue that refers to a subobject of a string literal, or
- a non-volatile glvalue that refers to a non-volatile object defined with
`constexpr`

, or that refers to a non-mutable subobject of such an object, or- a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of
`e`

;- [...]