This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 115e. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.

2024-11-11


2545. Transparently replacing objects in constant expressions

Section: 7.7  [expr.const]     Status: open     Submitter: Richard Smith     Date: 2022-03-05

7.7 [expr.const] paragraph 6 specifies that std::construct_at can be used during constant evaluation:

Similarly, the evaluation of a call to std::construct_at or std::ranges::construct_at does not disqualify E from being a core constant expression unless the first argument, of type T*, does not point to storage allocated with std::allocator<T> or to an object whose lifetime began within the evaluation of E, or the evaluation of the underlying constructor call disqualifies E from being a core constant expression.

Apparently, implementations are required to track whether an object is transparently replaceable (6.7.3 [basic.life] paragraph 8) during constant evaluation to satisfy 7.7 [expr.const] bullet 5.8, which requires that undefined behavior be detected and rejected during constant evaluation:

For example,

  struct A {
    int x, y;
  };
  struct B {
    float a;
    int b;
  };
  union C {
    A a;
    B b;
  };
  constexpr int f() {
   C c = {};
   std::construct_at(&c.b.b, 5);
   // Does this return 5 if c.a.y and c.b.b are laid out at the same address?
   return c.a.y;
  }
  static_assert(f());  // not a constant-expression

No known implementation diagnoses the violation of the rules for transparently replaceable in the following example, but there is implementation divergence for the results of f():

  #include <memory>

  struct A {
    virtual constexpr char f() { return 'A'; }
  };
  struct B : A {
    constexpr char f() override { return 'B'; }
  };

  constexpr char f() {
    B b;
    A *p = &b;
    std::construct_at(p);
    return p->f();     // #1; alternative: return b.f()
  }
  static_assert(f() == 'A');   // error: #1 accesses out-of-lifetime object

See also issue 2866 for concerns about observing the effects of an attribute if the potentially-overlapping subobject was introduced via [[no_unique_address]].