Search code examples
c++language-lawyerone-definition-rule

How does odr-use apply to a variable identified by a qualified-id?


Sample code:

struct S
{
    static const int a = 0;
};
int const *b = &S::a;

My understanding of the intent of the ODR is that S::a should be odr-used here, because its address is taken.

My question is: Where and how does the Standard specify that S::a is odr-used in this code?


My research so far: The only relevant part of the C++14 standard seems to be [basic.def.odr]/3:

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.

However I don't see how S::a fits into this. The definition of name ([basic]/4) excludes qualified-ids, so x can't refer to S::a here. I don't see any other text in the standard supporting the use of name to mean anything other than the definition from [basic]/4.

Maybe x means a; however a never appears as an expression, let alone a potentially-evaluated one: the a in S::a is an identifier, not an expression. (A qualified-id is a nested-name-specifier followed by an identifier, or some other things not relevant here).

I also don't understand why two different placeholders x and ex are used in this sentence. Saying "A appears as B" says to me that A and B are lexically identical but seeing A in the context of B has some extra meaning. At first I thought this might mean x is a more abstract way of talking about a variable (e.g. meaning the variable that is identified by S::a) and ex is an expression denoting that variable. However the quote goes on to say "Applying the lvalue-to-rvalue conversion to x", therefore x is actually an expression after all; so I don't see what the difference is between x and ex.

Further, I am not sure what "an expression e" refers to exactly. I guess it is an existential taken over all expressions in the program such that ex is a subexpression of e.


Solution

  • This sloppy drafting seems to have been fixed in the C++23 draft by P1787R6.

    [basic.def.odr]/5:

    A variable is named by an expression if the expression is an id-expression that denotes it. A variable x that is named by a potentially-evaluated expression E is odr-used by E unless [...]

    S::a is an id-expression and it names the variable in question.