This is an unofficial snapshot of the ISO/IEC JTC1 SC22 WG21 Core Issues List revision 119c. See http://www.open-std.org/jtc1/sc22/wg21/ for the official list.
2026-03-06
(From submission #836.)
A class type is consteval-only depending on its member types. However, a class type may be incomplete, and thus the question cannot be answered where needed.
For example,
struct S;
void f(S*); // #1
struct S { // #2
std::meta::info x;
};
Does the class definition at #2 make the function declaration #1 retroactively ill-formed? What if #1 and #2 are not mutually reachable?
Suggested resolution (February, 2026):
Change in 6.9.1 [basic.types.general] paragraph 12 and split into separate paragraphs as follows:
A type is consteval-only if it is
- std::meta::info,
- cv T, pointer to T, reference to T, or array of T, where T is a consteval-only type,
- a pointer or reference to a consteval-only type,
- an array of consteval-only type,
- a function type having a return type or any parameter type that is consteval-only,
- a class type with
anya non-static data memberhavingof consteval-only type, or- a type “pointer to member of class C of type T”, where at least one of C or T is
aconsteval-onlytype.
A type is observably consteval-only from a program point P if it is
- std::meta::info,
- cv T, pointer to T, reference to T, or an array of T, where T is observably consteval-only from P,
- a function type having return type or any parameter type that is observably consteval-only from P,
- a class type that is complete from P with a non-static data member whose type is observably consteval-only from P, or
- a type "pointer to member of class C of type T", where at least one of C or T is 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, and U are all consteval-only types, even though neither T nor U is observably consteval-only from any point in the program. -- end example]
Every object of consteval-only type shall beEvery function of consteval-only type shall be an immediate function (7.7 [expr.const]).
- the object associated with a constexpr variable or a subobject thereof,
- a template parameter object (13.2 [temp.param]) or a subobject thereof, or
- an object whose lifetime begins and ends during the evaluation of a core constant expression.
Each declaration D of a variable or structured binding with consteval-only type T shall be eithera diagnostic is required only if D is reachable from a program point from which T is observably consteval-only.
- constexpr or
- introduced by the declaration of an object or reference whose lifetime begins and ends within a manifestly constant-evaluated expression;
Each declaration D of a function of consteval-only type T shall be either
- consteval or
- a declaration of an immediate-escalating function (7.7 [expr.const]);
a diagnostic is required only if D is reachable from a program point from which T is observably consteval-only.
[Note: Immediate-escalating functions of consteval-only type are immediate functions (7.7 [expr.const]). --end note]
Each potentially-evaluated expression or conversion E of consteval-only type T shall be in an immediate function context; a diagnostic is required only if the innermost declaration that contains E is reachable from a program point where T is observably consteval-only.
[Note: An expression is immediate-escalating if its type is observably consteval-only from the program point following the expression (7.7 [expr.const]). --end note]
Change 7.7 [expr.const] paragraph 21 as follows:
A constant expression is either
- a glvalue core constant expression E for which
[Example 11: ... —end example] or
- E refers to a non-immediate function,
- E designates an object o, and if the complete object of o is of observably consteval-only type from the program point immediately following E then so is E,
- a prvalue core constant expression E whose result object (7.2.1 [basic.lval]) satisfies the following constraints:
- each constituent reference refers to an object or a non-immediate function,
- no constituent value of scalar type is an indeterminate or erroneous value (6.8.5 [basic.indet]),
- no constituent value of pointer type is a pointer to an immediate function or an invalid pointer value (6.9.4 [basic.compound]),
- no constituent value pointer-to-member type designates an immediate function, and
- unless the value is of consteval-only type,
- 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,- 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
- no constituent reference refers to an object whose complete object is of observably consteval-only type from the program point immediately following E.
Change in 7.7 [expr.const] paragraph 24 as follows:
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
- it is an id-expression or splice-expression that designates an immediate function,
- it is an immediate invocation that is not a constant expression, or
- it is of observably consteval-only type from the program point immediately following E (6.9.1 [basic.types.general]).
Change in 7.7 [expr.const] paragraph 26 as follows:
An immediate function is a function that is[Note 11: Default member initializers used to initialize a base or member subobject (11.9.3 [class.base.init]) are considered to be part of the function body (9.6.1 [dcl.fct.def.general]). —end note]
- declared with the consteval specifier,
- an immediate-escalating function whose type is observably consteval-only from the program point immediately following its definition (6.9.1 [basic.types.general]), or
- an immediate-escalating function F whose function body contains either
whose innermost enclosing non-block scope is F's function parameter scope.
- an immediate-escalating expression or
- a definition of a non-constexpr variable
withwhose type is observably consteval-onlytypefrom the program point immediately following the expression
Change in 11.7.3 [class.virtual] paragraph 18 as follows:
A class with a constevalAn immediate virtual function that overrides a virtual function that is notconstevalimmediate shallhave consteval-only typebe a member of a class C that is observably consteval-only from the program point immediate following the definition of C (6.9.1 [basic.types.general]).A constevalAn immediate virtual function shall not be overridden by a virtual function that is notconstevalan immediate function.
Change the condition for is_consteval_only in 21.3.6.4 [meta.unary.prop] as follows:
T is observably consteval-only (6.9.1 [basic.types.general]) from a program point in the instantiation context
CWG 2026-03-06
Drop the last change, which is covered by LWG4534. The approach above would cause excessive template instantiations:
template<class T> struct S { };
void f(S<int>*); // now instantiates S to determine whether S is consteval-only, because the completeness of S<int> affects the semantics of the program
The current phrasing with "reachable" requires checking module contents without naming the respective entity in source code at the point where the check is supposed to occur. This is not in harmony with the design of modules.
Proposed resolution (March 2026; work in progress):
Change in 6.9.1 [basic.types.general] paragraph 12 and split into separate paragraphs as follows:
A type is consteval-only if it is
- std::meta::info,
- cv T, pointer to T, reference to T, or array of T, where T is a consteval-only type,
- a pointer or reference to a consteval-only type,
- an array of consteval-only type,
- a function type having a return type or any parameter type that is consteval-only,
- a class type with
anya non-static data memberhavingof consteval-only type, or- a type “pointer to member of class C of type T”, where at least one of C or T is
aconsteval-onlytype.
A type is observably consteval-only from a program point P if it is
- std::meta::info,
- cv T, pointer to T, reference to T, or an array of T, where T is observably consteval-only from P,
- a function type having return type or any parameter type that is observably consteval-only from P,
- a class type that is complete from P with a non-static data member whose type is observably consteval-only from P, or
- a type "pointer to member of class C of type T", where at least one of C or T is 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, and U are all consteval-only types, even though neither T nor U is observably consteval-only from any point in the program. -- end example]
Every object of consteval-only type shall beEvery function of consteval-only type shall be an immediate function (7.7 [expr.const]).
- the object associated with a constexpr variable or a subobject thereof,
- a template parameter object (13.2 [temp.param]) or a subobject thereof, or
- an object whose lifetime begins and ends during the evaluation of a core constant expression.
Each declaration D of a variable or structured binding with consteval-only type T shall be eithera diagnostic is required only if D is reachable from a program point from which T is observably consteval-only.
- constexpr or
- introduced by the declaration of an object or reference whose lifetime begins and ends within a manifestly constant-evaluated expression;
Each declaration D of a function of consteval-only type T shall be either
- consteval or
- a declaration of an immediate-escalating function (7.7 [expr.const]);
a diagnostic is required only if D is reachable from a program point from which T is observably consteval-only.
[Note: Immediate-escalating functions of consteval-only type are immediate functions (7.7 [expr.const]). --end note]
Each potentially-evaluated expression or conversion E of consteval-only type T shall be in an immediate function context; a diagnostic is required only if the innermost declaration that contains E is reachable from a program point where T is observably consteval-only.
[Note: An expression is immediate-escalating if its type is observably consteval-only from the program point following the expression (7.7 [expr.const]). --end note]
Change 7.7 [expr.const] paragraph 21 as follows:
A constant expression is either
- a glvalue core constant expression E for which
[Example 11: ... —end example] or
- E refers to a non-immediate function,
- E designates an object o, and if the complete object of o is of observably consteval-only type from the program point immediately following E then so is E,
- a prvalue core constant expression E whose result object (7.2.1 [basic.lval]) satisfies the following constraints:
- each constituent reference refers to an object or a non-immediate function,
- no constituent value of scalar type is an indeterminate or erroneous value (6.8.5 [basic.indet]),
- no constituent value of pointer type is a pointer to an immediate function or an invalid pointer value (6.9.4 [basic.compound]),
- no constituent value pointer-to-member type designates an immediate function, and
- unless the value is of consteval-only type,
- 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,- 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
- no constituent reference refers to an object whose complete object is of observably consteval-only type from the program point immediately following E.
Change in 7.7 [expr.const] paragraph 24 as follows:
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
- it is an id-expression or splice-expression that designates an immediate function,
- it is an immediate invocation that is not a constant expression, or
- it is of observably consteval-only type from the program point immediately following E (6.9.1 [basic.types.general]).
Change in 7.7 [expr.const] paragraph 26 as follows:
An immediate function is a function that is[Note 11: Default member initializers used to initialize a base or member subobject (11.9.3 [class.base.init]) are considered to be part of the function body (9.6.1 [dcl.fct.def.general]). —end note]
- declared with the consteval specifier,
- an immediate-escalating function whose type is observably consteval-only from the program point immediately following its definition (6.9.1 [basic.types.general]), or
- an immediate-escalating function F whose function body contains either
whose innermost enclosing non-block scope is F's function parameter scope.
- an immediate-escalating expression or
- a definition of a non-constexpr variable
withwhose type is observably consteval-onlytypefrom the program point immediately following the definition
Change in 11.7.3 [class.virtual] paragraph 18 as follows:
A class with a constevalAn immediate virtual function that overrides a virtual function that is notconstevalimmediate shallhave consteval-only typebe a member of a class C that is observably consteval-only from the program point immediate following the definition of C (6.9.1 [basic.types.general]).A constevalAn immediate virtual function shall not be overridden by a virtual function that is notconstevalan immediate function.