| Document #: | P4132R0 [Latest] [Status] |
| Date: | 2026-03-23 |
| Project: | Programming Language C++ |
| Audience: |
EWG, CWG |
| Reply-to: |
Dan Katz <katzdm@gmail.com> Wyatt Childers <wchilders@nvidia.com> |
CWG3150 points out the difficulty of determining whether an incomplete class, or a pointer to such a class, is a consteval-only type. Discussion of the issue has surfaced two challenges:
std::meta::info *)
are themselves consteval-only, the implementation cannot know whether a
class whose data member has some S<int> *
type is consteval-only until S<int>
has been instantiated. As this can “affect the semantics of the
program”, this has the potential to require many instantiations that are
not required today, which would be expensive and would surely break
existing code.The wording changes proposed by this paper attempt to address these issues.
TODO: Flesh out if there’s time.
Modify [basic.types.general]/12 and split into separate paragraphs as follows:
12 A type is consteval-only if it is
- (12.1)
std::meta::info,- (12.2) cv
T, pointer toT, reference toT, or array ofT, whereTis a consteval-only type,a pointer or reference to a consteval-only type,an array of consteval-only type,- (12.3) a function type having a return type or any parameter type that is consteval-only,
- (12.4) a class type
Cfor whichwith any non-static data member having consteval-only type
- (12.4.1)
Cis complete from some point in the program,- (12.4.2)
Chas a non-static data member whose type is consteval-only, and- (12.4.3) if
Cis a specialization of a templated class, thenCis either an explicit specialization or is referenced in manner that requires the complete definition ofCfor a purpose other than determining whetherCis a consteval-only type, or- (12.5) a type “pointer to member of class
Cof typeT”, where at least one ofCorTisaconsteval-onlytype.A type is observably consteval-only from a program point P if it is
(12.5)
std::meta::info,(12.6) cv
T, pointer toT, reference toT, or array ofT, whereTis observably consteval-only from P,(12.7) a class type
Cfor which
- (12.7.1)
Cis complete from P,- (12.7.2)
Chas a non-static data member whose type is observably consteval-only from P, and- (12.7.3) if
Cis a specialization of a templated class for which no declared specialization is reachable from P, thenCis referenced at or prior to P in a context that requires the complete definition ofCfor a purpose other than determining whetherCis an observably consteval-only type, or(12.8) a type “pointer to member of class
Cof typeT”, where at least one ofCorTis observably consteval-only from P.[ Note: Every type which is observably consteval-only from some program point is also consteval-only. — end note ]
[ Example:// a.cpp struct S { std::meta::info m; }; struct T; struct U { T *m; }; // b.cpp struct S; struct T { S *m; };
S,T, andUare all consteval-only types, even though neitherTnorUis observably consteval-only from any point in the program. — end example ]Every object of consteval-only type shall be
- the object associated with a constexpr variable or a subobject thereof,
- a template parameter object ([temp.param]) or a subobject thereof, or
- an object whose lifetime begins and ends during the evaluation of a core constant expression.
Every function of consteval-only type shall be an immediate function ([expr.const]).
For each declaration D of a variable whose type
Tis consteval-only, one of the following shall hold:
- (12.9) D is
constexpr; or- (12.10) the lifetime of each object or reference introduced by the variable begins and ends within a manifestly constant-evaluated expression;
a diagnostic is required only if
Tis observably consteval-only from the end of the definition domain in which D appears.For each definition D of a non-consteval function whose type
Tis consteval-only,Tshall be observably consteval-only from the point following D; a diagnostic is only required ifTis observably consteval-only from the end of the definition domain in which D appears.Each potentially-evaluated expression or conversion E of consteval-only type
Tshall be in an immediate function context; a diagnostic is required only ifTis observably consteval-only from the end of the definition domain in which E appears.[ Note: An expression is immediate-escalating if its type is observably consteval-only from the program point following the expression ([expr.const]). — end note ]
For each manifestly constant-evaluated expression or conversion E whose result has a constituent value or a constituent reference that is, points to, or refers to an object whose complete object is of type
Tthat is consteval-only,Tshall be observably consteval-only from the point following where E appears; a diagnostic is only required ifTis observably consteval-only from the end of the definition domain in which E appears.
Modify [expr.const]/21 as follows:
21 A constant expression is either
(21.1) a glvalue core constant expression E for which
(21.1.1) E refers to a non-immediate function,
(21.1.2) E designates an object
o, and if the complete object ofois of observably consteval-only type from the program point immediately following E then so is E,[ Example: … — end example ]
or
(21.2) a prvalue core constant expression E whose result object ([basic.lval]) satisfies the following constraints:
- (21.2.1) each constituent reference refers to an object or a non-immediate function,
- (21.2.2) no constituent value of scalar type is an indeterminate or erroneous value ([basic.indet]),
- (21.2.3) no constituent value of pointer type is a pointer to an immediate function or an invalid pointer value ([basic.compound]),
- (21.2.4) no constituent value of pointer-to-member-type designates an immediate function, and
- (21.2.5) unless the value is of consteval-only type,
- (21.2.5.1) no constituent value of pointer-to-member type points to a direct member of a class that is observably consteval-only from the program point immediately following E
class type,- (21.2.5.2) no constituent value of pointer type points to or past an object whose complete object is of observably consteval-only type from the program point immediately following E, and
- (21.2.5.3) no constituent reference refers to an object whose complete object is of observably consteval-only type from the program point immediately following E.
Modify [expr.const]/24 as follows:
24 A potentially-evaluated expression or conversion E is immediate-escalating if it is neither initially in an immediate function context nor a subexpression of an immediate invocation, and
Modify [expr.const]/26 as follows:
26 An immediate function is a function that is either
(26.1) declared with the
constevalspecifier,or(26.2) an immediate-escalating function whose type is observably consteval-only ([basic.types.general]) from the program point immediately following that function’s definition, or
(26.3) an immediate-escalating function F whose function body contains either
- (26.3.1) an immediate-escalating expression or
- (26.3.2) a definition of a non-constexpr variable
withwhose type is observably consteval-only from the program point immediately following that definitionwhose innermost enclosing non-block scope is F’s function parameter scope.
[ Note: Default member initializers used to initialize a base or member subobject ([class.base.init]) are considered to be part of the function body ([dcl.fct.def.general]). — end note ]
Modify [class.virtual]/18 as follows:
18 A class
Cwith aconstevalvirtual function that overrides a virtual function that is notconstevalshallhavebe observably consteval-onlytypefrom the point following the definition ofC. Aconstevalvirtual function shall not be overriden by a virtual function that is not consteval.