Title
Evaluation context of manifestly constant-evaluated expressions
Status
open
Section
7.7 [expr.const]
Submitter
Dan Katz

Created on 2026-02-13.00:00:00 last changed 2 days ago

Messages

Date: 2026-03-06.19:51:35

Suggested resolution:

This also resolves issue 3127.

Change in 7.7 [expr.const] paragraph 30 as follows:

During an evaluation V (6.10.1 [intro.execution]) of an expression, conversion, or initialization E as a core constant expression, the point of evaluation of E during V is the program point P determined as follows:
  • If E is a potentially-evaluated subexpression of a default member initializer I, and V is the evaluation of E in the evaluation of I as an immediate subexpression of a (possibly aggregate) initialization, then P is the point of evaluation of that initialization.
  • Otherwise, if E is a potentially-evaluated subexpression of a default argument A (9.3.4.7 [dcl.fct.default]), and V is the evaluation of E in the evaluation of A as an immediate subexpression of a function call (7.6.1.3 [expr.call]), then P is the point of evaluation of that function call.
  • Otherwise, P is the point at which E appears.
The evaluation context evaluation context is a set of program points that determines the behavior of certain functions used for reflection (21.4 [meta.reflection]). During the evaluation V of an expression E as a core constant expression, the evaluation context evaluation context of an evaluation X (6.10.1 [intro.execution]) consists of the following points during V is the set C of program points determined as follows:
  • The program point EVAL-PT(L), where L is the point at which E appears, and where EVAL-PT(P), for a point P, is a point R determined as follows:
    • If a potentially-evaluated subexpression (6.10.1 [intro.execution]) of a default member initializer I appears at P , and a (possibly aggregate) initialization during V is using I, then R is EVAL-PT(Q) where Q is the point at which that initialization appears.
    • Otherwise, if a potentially-evaluated subexpression of a default argument (9.3.4.7 [dcl.fct.default]) appears at P, and an invocation of a function (7.6.1.3 [expr.call]) during V is using that default argument, then R is EVAL-PT(Q) where Q is the point at which that invocation appears.
    • Otherwise, R is P.
  • If the execution of X occurs during the evaluation Y of a manifestly constant-evaluated expression, then C is the evaluation context of X during Y.
  • Otherwise, C contains
    • the point of evaluation of E during V and each synthesized point in the instantiation context thereof and
    • Each each synthesized point corresponding to an injected declaration produced by any evaluation executed during V that is sequenced before X (6.10.1 [intro.execution]).
Date: 2026-02-13.00:00:00

(From submission #848.)

Consider:

  struct S;
  consteval size_t f() {
    constexpr bool b = is_complete_type(^^S);
    return b ? 1 : 2;
  }

  struct T;
  consteval {
    define_aggregate(^^S, {});
    define_aggregate(^^T, {
      data_member_spec(^^int, {.name="m", .bit_width=f()}),
   });
  }

  int main() {
    return bit_size_of(^^T::m);
  }

The Working Draft arguably says that this program should exit with status 1: During the evaluation of the expression corresponding to the consteval-block, the evaluation of is_complete_type(^^S) contains the synthesized point associated with the injected declaration of S; therefore, the type is complete.

But this was never the intention of P2996; the intention was to evaluate manifestly constant-evaluated expressions at the point where they appear. The problem is that we didn't consider manifestly constant-evaluated expressions that might be executed (formally, per the abstract machine) during the evaluation of other manifestly constant-evaluated expressions.

History
Date User Action Args
2026-03-05 08:23:53adminsetmessages: + msg8497
2026-02-13 00:00:00admincreate