Skip to content

[expr.const] Evaluating a reference in the initialization of itself during constant evaluation #846

@frederick-vs-ja

Description

@frederick-vs-ja

Full name of submitter (unless configured in github; will be published with the issue): Jiang An

Reference (section label): [expr.const], [dcl.ref]

Link to reflector thread (if any):

Issue description:

Currently, [dcl.ref] p6 states:

The behavior of an evaluation of a reference ([expr.prim.id], [expr.ref]) that does not happen after ([intro.races]) the initialization of the reference is undefined.

While [expr.const] p16 states:

During the evaluation of an expression E as a core constant expression, all id-expressions, splice-expressions, and uses of *this that refer to an object or reference whose lifetime did not begin with the evaluation of E are treated as referring to a specific instance of that object or reference whose lifetime and that of all subobjects (including all union members) includes the entire constant evaluation. For such an object that is not usable in constant expressions, the dynamic type of the object is constexpr-unknown. For such a reference that is not usable in constant expressions, the reference is treated as binding to an unspecified object of the referenced type whose lifetime and that of all subobjects includes the entire constant evaluation and whose dynamic type is constexpr-unknown.

Does [expr.const] p16 intend to mean that all references (to objects) are considered already initialized during constant evaluation, so the UB specified in [dcl.ref] p6 never causes constant evaluation failure?

Consider the following example (where there's implementation divergence, demo):

int n;

constexpr bool fun() {
  int& r3 = (r3, n); // runtime-only UB?
  return true;
}

int main() {
  int& r1 = (r1, n); // UB
  constexpr int& r2 = (r2, n); // OK?
  fun(); // UB
  static_assert(fun()); // OK?
}

Per currently rules, it seems that fun() essentially only causes runtime-undefined behavior.

P2280R4 talked about references that are

  • function parameters, and
  • only forward-declared at the point of constant evaluation,

and didn't talk about self-using in the initialization. Would it be better to slightly tighten the rule to reject "obvious" UB, by excluding the treatment in [expr.const] p16 for a reference that is being initialized?

Or alternatively, would it be better to make certain kinds evaluation of uninitialized reference well-defined, which would make the example UB-free?

Suggested resolution:

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions