Is it correct to say that the compiler can replace the expression `a->i` below by its value 1 because…?

  • A+
Category:Languages

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 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 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 a core constant expression unless 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;
  • [...]

Comment

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: