diff --git a/source/basic.tex b/source/basic.tex index ba0d605817..64a4f2e3b6 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -114,17 +114,33 @@ A \defn{variable} is introduced by the declaration of a reference other than a non-static data member or of -an object. The variable's name, if any, denotes the reference or object. +an object. \pnum -An \defn{entity} is a value, object, reference, +An \defn{entity} is a +variable, structured binding, result binding, -function, enumerator, type, -class member, bit-field, template, template specialization, namespace, or -pack. An entity $E$ is denoted by the name (if any) -that is introduced by a declaration of $E$ or -by a \grammarterm{typedef-name} introduced by a declaration specifying $E$. +function, +enumerator, +type, +type alias, +non-static data member, +bit-field, +template, +namespace, +namespace alias, +template parameter, +function parameter, or +\grammarterm{init-capture}. +The \defnadj{underlying}{entity} of an entity is that entity +unless otherwise specified. +A name \defnx{denotes}{denote} the underlying entity of +the entity declared by each declaration that introduces the name. +\begin{note} +Type aliases and namespace aliases have underlying entities +that are distinct from themselves. +\end{note} \pnum A \defnadj{local}{entity} is a variable with @@ -153,7 +169,7 @@ unit. If so, the declaration specifies the interpretation and semantic properties of these names. -A declaration of an entity or \grammarterm{typedef-name} $X$ is +A declaration of an entity $X$ is a redeclaration of $X$ if another declaration of $X$ is reachable from it\iref{module.reach}; otherwise, it is a \defnadj{first}{declaration}. @@ -221,12 +237,15 @@ \item it is an \grammarterm{alias-declaration}\iref{dcl.typedef}, \item it is -a -\grammarterm{using-declaration}\iref{namespace.udecl}, +a \grammarterm{namespace-alias-definition}\iref{namespace.alias}, +\item it is +a \grammarterm{using-declaration}\iref{namespace.udecl}, \item it is a \grammarterm{deduction-guide}\iref{temp.deduct.guide}, \item it is a \grammarterm{static_assert-declaration}\iref{dcl.pre}, +\item it is +a \grammarterm{consteval-block-declaration}, \item it is an \grammarterm{attribute-declaration}\iref{dcl.pre}, @@ -264,7 +283,6 @@ int X::y = 1; // defines \tcode{X::y} enum { up, down }; // defines \tcode{up} and \tcode{down} namespace N { int d; } // defines \tcode{N} and \tcode{N::d} -namespace N1 = N; // defines \tcode{N1} X anX; // defines \tcode{anX} \end{codeblock} @@ -275,6 +293,7 @@ int f(int); // declares \tcode{f} struct S; // declares \tcode{S} typedef int Int; // declares \tcode{Int} +namespace N1 = N; // declares \tcode{N1} extern X anotherX; // declares \tcode{anotherX} using N::d; // declares \tcode{d} \end{codeblock} @@ -368,8 +387,9 @@ The set of \defn{potential results} of an expression $E$ is defined as follows: \begin{itemize} -\item If $E$ is an -\grammarterm{id-expression}\iref{expr.prim.id}, the set +\item If $E$ is +an \grammarterm{id-expression}\iref{expr.prim.id} or +a \grammarterm{splice-expression}\iref{expr.prim.splice}, the set contains only $E$. \item If $E$ is a subscripting operation\iref{expr.sub} with an array operand, the set contains the potential results of that operand. @@ -395,17 +415,21 @@ \item Otherwise, the set is empty. \end{itemize} \begin{note} -This set is a (possibly-empty) set of \grammarterm{id-expression}{s}, +This set is a (possibly-empty) set of +\grammarterm{id-expression}{s} and \grammarterm{splice-expression}s, each of which is either $E$ or a subexpression of $E$. \begin{example} In the following example, the set of potential results of the initializer of \tcode{n} contains the first \tcode{S::x} subexpression, but not the second \tcode{S::x} subexpression. +The set of potential results of the initializer of \tcode{o} contains +the subexpression \tcode{[:\caret\caret S::x:]}. \begin{codeblock} struct S { static const int x = 0; }; const int &f(const int &r); int n = b ? (1, S::x) // \tcode{S::x} is not odr-used here : f(S::x); // \tcode{S::x} is odr-used here, so a definition is required +int o = [:^^S::x:]; \end{codeblock} \end{example} \end{note} @@ -453,7 +477,9 @@ \pnum \label{term.odr.use}% A variable is named by an expression -if the expression is an \grammarterm{id-expression} that denotes it. +if the expression is an \grammarterm{id-expression} or +\grammarterm{splice-expression}\iref{expr.prim.splice} +that designates it. A variable \tcode{x} that is named by a potentially-evaluated expression $N$ that appears at a point $P$ @@ -510,7 +536,12 @@ \end{example} \pnum -A structured binding is odr-used if it appears as a potentially-evaluated expression. +A structured binding is named by an expression +if that expression is either an \grammarterm{id-expression} or +a \grammarterm{splice-expression} +that designates that structured binding. +A structured binding is odr-used +if it is named by a potentially-evaluated expression. \pnum \tcode{*\keyword{this}} is odr-used if \keyword{this} appears as a potentially-evaluated expression @@ -696,7 +727,16 @@ \end{note} \pnum -For any definable item \tcode{D} with definitions in multiple translation units, +If a definable item \tcode{D} is defined in a translation unit +by an injected declaration $X$\iref{expr.const} and +another translation unit contains a definition of \tcode{D}, +that definition shall be an injected declaration +having the same characteristic sequence as $X$; +a diagnostic is required only if \tcode{D} is attached to a named module and +a prior definition is reachable at the point where a later definition occurs. + +\pnum +For any other definable item \tcode{D} with definitions in multiple translation units, \begin{itemize} \item if \tcode{D} is a non-inline non-templated function or variable, or @@ -722,7 +762,7 @@ is considered to consist of the sequence of tokens of the corresponding \grammarterm{lambda-expression}. \item In each such definition, corresponding names, looked up -according to~\ref{basic.lookup}, shall refer to the same entity, after +according to~\ref{basic.lookup}, shall denote the same entity, after overload resolution\iref{over.match} and after matching of partial template specializations\iref{temp.spec.partial.match}, except that a name can refer to \begin{itemize} @@ -738,7 +778,7 @@ \item a reference with internal or no linkage initialized with a constant expression such that -the reference refers to the same entity in all definitions of \tcode{D}. +the reference refers to the same object or function in all definitions of \tcode{D}. \end{itemize} \item In each such definition, except within @@ -767,11 +807,17 @@ \item In each such definition, a default argument used by an (implicit or explicit) function call or a default template argument used by an (implicit or explicit) -\grammarterm{template-id} or \grammarterm{simple-template-id} +\grammarterm{template-id}, +\grammarterm{simple-template-id}, or +\grammarterm{splice-specialization-specifier} is treated as if its token sequence were present in the definition of \tcode{D}; that is, the default argument or default template argument is subject to the requirements described in this paragraph (recursively). + +\item In each such definition, +corresponding \grammarterm{reflect-expression}s\iref{expr.reflect} +compute equivalent values\iref{expr.eq}. \end{itemize} \pnum @@ -926,6 +972,9 @@ Any names (re)introduced by a declaration are \defnx{bound}{name!bound} to it in its target scope. \end{itemize} +The \defnadj{host}{scope} of a declaration is +the inhabited scope if that scope is a block scope and +the target scope otherwise. An entity \defnx{belongs}{entity!belong} to a scope $S$ if $S$ is the target scope of a declaration of the entity. \begin{note} @@ -1006,7 +1055,7 @@ \item either is a \grammarterm{using-declarator}, or \item -one declares a type (not a \grammarterm{typedef-name}) and the other declares a +one declares a type (not a type alias) and the other declares a variable, non-static data member other than of an anonymous union\iref{class.union.anon}, enumerator, @@ -1663,7 +1712,7 @@ In certain contexts, only certain kinds of declarations are included. After any such restriction, any declarations of classes or enumerations are discarded if any other declarations are found. \begin{note} -A type (but not a \grammarterm{typedef-name} or template) +A type (but not a type alias or template) is therefore hidden by any other entity in its scope. \end{note} \indextext{type-only!lookup|see{lookup, type-only}}% @@ -1671,8 +1720,8 @@ only declarations of types and templates whose specializations are types are considered; furthermore, if declarations -of a \grammarterm{typedef-name} and of the type to which it refers are found, -the declaration of the \grammarterm{typedef-name} is discarded +of a type alias and of its underlying entity are found, +the declaration of the type alias is discarded instead of the type declaration. \rSec2[class.member.lookup]{Member name lookup}% @@ -2136,7 +2185,16 @@ The set of entities is determined in the following way: \begin{itemize} -\item If \tcode{T} is a fundamental type, its associated set of +\item If \tcode{T} is \tcode{std::meta::info}\iref{meta.reflection.synop}, +its associated set of entities is the singleton containing +the enumeration type \tcode{std::meta::operators}\iref{meta.reflection.operators}. +\begin{note} +The \tcode{std::meta::info} type is a type alias, +so an explicit rule is needed to associate calls +whose arguments are reflections with the namespace \tcode{std::meta}. +\end{note} + +\item If \tcode{T} is any other fundamental type, its associated set of entities is empty. \item If \tcode{T} is a class type (including unions), @@ -2294,8 +2352,14 @@ followed by a \tcode{::} scope resolution operator considers only namespaces, types, and templates whose specializations are types. -If a name, \grammarterm{template-id}, or \grammarterm{computed-type-specifier} +If a +name, +\grammarterm{template-id}, +\grammarterm{splice-scope-specifier}, or +\grammarterm{computed-type-specifier} is followed by a \tcode{::}, +it shall either be +a dependent \grammarterm{splice-scope-specifier}\iref{temp.dep.splice} or it shall designate a namespace, class, enumeration, or dependent type, and the \tcode{::} is never interpreted as a complete \grammarterm{nested-name-specifier}. @@ -2344,6 +2408,7 @@ \item a \grammarterm{typename-specifier}, \item a \grammarterm{qualified-namespace-specifier}, or \item a \grammarterm{nested-name-specifier}, +\grammarterm{reflection-name}, \grammarterm{elaborated-type-specifier}, or \grammarterm{class-or-decltype} that has a \grammarterm{nested-name-specifier}\iref{expr.prim.id.qual}. @@ -2738,6 +2803,70 @@ only namespace names are considered.% \indextext{lookup!name|)}% +\rSec1[basic.splice]{Splice specifiers} +\indextext{splice|(}% + +\begin{bnf} +\nontermdef{splice-specifier}\br + \terminal{[:} constant-expression \terminal{:]} +\end{bnf} + +\begin{bnf} +\nontermdef{splice-specialization-specifier}\br + splice-specifier \terminal{<} \opt{template-argument-list} \terminal{>} +\end{bnf} + +\pnum +The \grammarterm{constant-expression} of a \grammarterm{splice-specifier} +shall be a converted constant expression of +type \tcode{std::meta::info}\iref{expr.const}. +A \grammarterm{splice-specifier} +whose converted \grammarterm{constant-expression} represents +a construct $X$ is said to \defn{designate} either +\begin{itemize} +\item the underlying entity of $X$ if $X$ is an entity\iref{basic.pre}, or +\item $X$ otherwise. +\end{itemize} +\begin{note} +A \grammarterm{splice-specifier} is dependent +if the converted \grammarterm{constant-expression} is +value-dependent\iref{temp.dep.splice}. +\end{note} + +\pnum +A non-dependent \grammarterm{splice-specifier} of +a \grammarterm{splice-specialization-specifier} shall designate a template. + +\pnum +\begin{note} +A \tcode{<} following a \grammarterm{splice-specifier} is interpreted as +the delimiter of a \grammarterm{template-argument-list} +when the \grammarterm{splice-specifier} is preceded by +the keyword \keyword{template} or the keyword \keyword{typename}, or +when it appears in a type-only context\iref{temp.names}. +\begin{example} +\begin{codeblock} +constexpr int v = 1; +template struct TCls { + static constexpr int s = V + 1; +}; + +using alias = [:^^TCls:]<([:^^v:])>; + // OK, a \grammarterm{splice-specialization-specifier} with a \grammarterm{splice-expression} as a template argument + +static_assert(alias::s == 2); + +auto o1 = [:^^TCls:]<([:^^v:])>(); // error: < means less than +auto o2 = typename [:^^TCls:]<([:^^v:])>(); // OK, o2 is an object of type TCls<1> + +consteval int bad_splice(std::meta::info v) { + return [:v:]; // error: v is not constant +} +\end{codeblock} +\end{example} +\end{note} +\indextext{splice|)} + \rSec1[basic.link]{Program and linkage}% \indextext{linkage|(} @@ -2909,6 +3038,8 @@ \item they appear in the same translation unit, or \item +they both declare type aliases or namespace aliases that have the same underlying entity, or +\item they both declare names with module linkage and are attached to the same module, or \item they both declare names with external linkage. @@ -3021,6 +3152,16 @@ \item $D$ contains a \grammarterm{lambda-expression} whose closure type is $E$, \item +$D$ contains +a \grammarterm{reflect-expression} or a \grammarterm{splice-specifier} +that, respectively, represents or designates $E$, +\item +$D$ is an injected declaration\iref{expr.const} +whose characteristic sequence contains a reflection +that represents +a data member description ($T$, $N$, $A$, $W$, $\mathit{NUA}$)\iref{class.mem.general} +for which $T$ is $E$, +\item $E$ is not a function or function template and $D$ contains an \grammarterm{id-expression}, \grammarterm{type-specifier}, @@ -3069,7 +3210,7 @@ An entity is \defnx{TU-local}{TU-local!entity} if it is \begin{itemize} \item -a type, function, variable, or template that +a type, type alias, namespace, namespace alias, function, variable, or template that \begin{itemize} \item has a name with internal linkage, or @@ -3101,14 +3242,28 @@ A value or object is \defnx{TU-local}{TU-local!value or object} if either \begin{itemize} \item +it is of TU-local type, +\item it is, or is a pointer to, -a TU-local function or the object associated with a TU-local variable, or +a TU-local function or the object associated with a TU-local variable, \item it is an object of class or array type and any of its subobjects or any of the objects or functions to which its non-static data members of reference type refer -is TU-local and is usable in constant expressions. +is TU-local and is usable in constant expressions, or +\item +it is a reflection value\iref{basic.fundamental} that represents +\begin{itemize} +\item +an entity, value, or object that is TU-local, +\item +a direct base class relationship (\tcode{D}, \tcode{B})\iref{class.derived.general} +for which either \tcode{D} or \tcode{B} is TU-local, or +\item +a data member description ($T$, $N$, $A$, $W$, $\mathit{NUA}$)\iref{class.mem.general} +for which $T$ is TU-local. +\end{itemize} \end{itemize} \pnum @@ -3158,6 +3313,16 @@ void adl(double); inline void h(auto x) { adl(x); } // OK, but certain specializations are exposures + +constexpr std::meta::info r1 = ^^g<0>; // OK +namespace N2 { + static constexpr std::meta::info r2 = ^^g<1>; // OK, \tcode{r2} is TU-local +} +constexpr std::meta::info r3 = ^^f; // error: \tcode{r3} is an exposure of \tcode{f} + +constexpr auto ctx = std::meta::access_context::current(); +constexpr std::meta::info r4 = + std::meta::members_of(^^N2, ctx)[0]; // error: \tcode{r4} is an exposure of \tcode{N2::r2} \end{codeblocktu} \begin{codeblocktu}{Translation unit \#2} module A; @@ -5021,7 +5186,7 @@ \label{term.scalar.type}% Arithmetic types\iref{basic.fundamental}, enumeration types, pointer types, pointer-to-member types\iref{basic.compound}, -\tcode{std::nullptr_t}, +\tcode{std::meta::\brk{}info}, \tcode{std::nullptr_t}, and cv-qualified\iref{basic.type.qualifier} versions of these types are collectively called @@ -5093,6 +5258,21 @@ layout-compatible enumerations\iref{dcl.enum}, or layout-compatible standard-layout class types\iref{class.mem}. +\pnum +A type is \defn{consteval-only} if it is either +\tcode{std::meta::info} or +a type compounded from a consteval-only type\iref{basic.compound}. +Every object of consteval-only type shall be +\begin{itemize} +\item +the object associated with a constexpr variable or a subobject thereof, +\item +a template parameter object\iref{temp.param} or a subobject thereof, or +\item +an object whose lifetime begins and ends +during the evaluation of a core constant expression. +\end{itemize} + \rSec2[basic.fundamental]{Fundamental types} \pnum @@ -5399,6 +5579,94 @@ pointer-to-member conversions\iref{conv.ptr,conv.mem}. \tcode{\keyword{sizeof}(std::nullptr_t)} shall be equal to \tcode{\keyword{sizeof}(\keyword{void}*)}. +\pnum +A value of type \tcode{std::meta::info} is called a \defn{reflection}. +There exists a unique \defnadj{null}{reflection}; +every other reflection is a representation of +\begin{itemize} +\item a value of scalar type\iref{temp.param}, +\item an object with static storage duration\iref{basic.stc}, +\item a variable\iref{basic.pre}, +\item a structured binding\iref{dcl.struct.bind}, +\item a function\iref{dcl.fct}, +\item an enumerator\iref{dcl.enum}, +\item a type alias\iref{dcl.typedef}, +\item a type\iref{basic.types}, +\item a class member\iref{class.mem}, +\item an unnamed bit-field\iref{class.bit}, +\item a class template\iref{temp.pre}, +\item a function template, +\item a variable template, +\item an alias template\iref{temp.alias}, +\item a concept\iref{temp.concept}, +\item a namespace alias\iref{namespace.alias}, +\item a namespace\iref{basic.namespace.general}, +\item a direct base class relationship\iref{class.derived.general}, or +\item a data member description\iref{class.mem.general}. +\end{itemize} +A reflection is said to \defn{represent} the corresponding construct. +\begin{note} +A reflection of a value can be produced by library functions such as +\tcode{std::meta::constant_of} and \tcode{std::meta::reflect_constant}. +\end{note} +\begin{example} +\begin{codeblock} +int arr[] = {1, 2, 3}; +auto [a1, a2, a3] = arr; +void fn(); +enum Enum { A }; +using Alias = int; +struct B {}; +struct S : B { + int mem; + int : 0; +}; +template struct TCls {}; +template void TFn(); +template int TVar; +template concept Concept = requires { true; }; +namespace NS {}; +namespace NSAlias = NS; + +constexpr auto ctx = std::meta::access_context::current(); + +constexpr auto r1 = std::meta::reflect_constant(42); // represents int value of 42 +constexpr auto r2 = std::meta::reflect_object(arr[1]); // represents int object +constexpr auto r3 = ^^arr; // represents a variable +constexpr auto r4 = ^^a3; // represents a structured binding +constexpr auto r5 = ^^fn; // represents a function +constexpr auto r6 = ^^Enum::A; // represents an enumerator +constexpr auto r7 = ^^Alias; // represents a type alias +constexpr auto r8 = ^^S; // represents a type +constexpr auto r9 = ^^S::mem; // represents a class member +constexpr auto r10 = std::meta::members_of(^^S, ctx)[1]; // represents an unnamed bit-field +constexpr auto r11 = ^^TCls; // represents a class template +constexpr auto r12 = ^^TFn; // represents a function template +constexpr auto r13 = ^^TVar; // represents a variable template +constexpr auto r14 = ^^Concept; // represents a concept +constexpr auto r15 = ^^NSAlias; // represents a namespace alias +constexpr auto r16 = ^^NS; // represents a namespace +constexpr auto r17 = std::meta::bases_of(^^S, ctx)[0]; // represents a direct base class relationship +constexpr auto r18 = + std::meta::data_member_spec(^^int, {.name="member"}); // represents a data member description +\end{codeblock} +\end{example} + +\pnum +\recommended +Implementations should not represent other constructs +specified in this document, such as +\grammarterm{using-declarator}s, +partial template specializations, +attributes, placeholder types, +statements, or +expressions, +as values of type \tcode{std::meta::info}. +\begin{note} +Future revisions of this document can specify semantics for reflections +representing any such constructs. +\end{note} + \pnum \indextext{type!fundamental}% The types described in this subclause @@ -6078,12 +6346,14 @@ \pnum \indextext{value computation|(}% -Reading an object designated by a \keyword{volatile} -glvalue\iref{basic.lval}, modifying an object, calling a library I/O -function, or calling a function that does any of those operations are -all -\defn{side effects}, which are changes in the state of the execution -environment. \defnx{Evaluation}{evaluation} of an expression (or a +Reading an object designated by a \keyword{volatile} glvalue\iref{basic.lval}, +modifying an object, +producing an injected declaration\iref{expr.const}, +calling a library I/O function, or +calling a function that does any of those operations +are all \defn{side effects}, +which are changes in the state of the execution or translation environment. +\defnx{Evaluation}{evaluation} of an expression (or a subexpression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and @@ -6256,6 +6526,14 @@ signal handler is usually unsequenced with respect to the rest of the program. \end{note} +\pnum +During the evaluation of an expression +as a core constant expression\iref{expr.const}, +evaluations of operands of individual operators and +of subexpressions of individual expressions +that are otherwise either unsequenced or indeterminately sequenced +are evaluated in lexical order. + \rSec2[intro.multithread]{Multi-threaded executions and data races} \rSec3[intro.multithread.general]{General} diff --git a/source/classes.tex b/source/classes.tex index a24602d91a..75ff18b5c5 100644 --- a/source/classes.tex +++ b/source/classes.tex @@ -555,6 +555,7 @@ using-declaration\br using-enum-declaration\br static_assert-declaration\br + consteval-block-declaration\br template-declaration\br explicit-specialization\br deduction-guide\br @@ -646,13 +647,14 @@ \end{note} \pnum -A \grammarterm{member-declaration} does not declare new members of the class +A \grammarterm{member-declaration} does not itself declare new members of the class if it is \begin{itemize} \item a friend declaration\iref{class.friend}, \item a \grammarterm{deduction-guide}\iref{temp.deduct.guide}, \item a \grammarterm{template-declaration} whose \grammarterm{declaration} is one of the above, \item a \grammarterm{static_assert-declaration}, +\item a \grammarterm{consteval-block-declaration}, \item a \grammarterm{using-declaration}\iref{namespace.udecl}, or \item an \grammarterm{empty-declaration}. \end{itemize} @@ -686,10 +688,21 @@ Any other data member or member function is a \defnadj{non-static}{member} (a \defnadj{non-static}{data member} or \defnadj{non-static}{member function}\iref{class.mfct.non.static}, respectively). -\begin{note} -A non-static data member of non-reference -type is a member subobject of a class object\iref{intro.object}. -\end{note} + +\pnum +Every object of class type has a unique member subobject +corresponding to each of its direct non-static data members. +If any non-static data member of a class \tcode{C} is of reference type, +then let \tcode{D} be an invented class +that is identical to \tcode{C} +except that each non-static member of \tcode{D} corresponding to +a member of \tcode{C} of type ``reference to \tcode{T}'' +instead has type ``pointer to \tcode{T}''. +Every member subobject of a complete object of type \tcode{C} +has the same size, alignment, and offset +as that of the corresponding subobject of a complete object of type \tcode{D}. +The size and alignment of \tcode{C} are the same as +the size and alignment of \tcode{D}. \pnum A member shall not be declared twice in the @@ -999,6 +1012,46 @@ pointer-interconvertible\iref{basic.compound,expr.static.cast}. \end{note} +\pnum +A \defnadj{data member}{description} is +a quintuple ($T$, $N$, $A$, $W$, $\mathit{NUA}$) +describing the potential declaration of a non-static data member where +\begin{itemize} +\item $T$ is a type, +\item $N$ is an identifier or $\bot$, +\item $A$ is an alignment or $\bot$, +\item $W$ is a bit-field width or $\bot$, and +\item $\mathit{NUA}$ is a boolean value. +\end{itemize} +Two data member descriptions are equal +if each of their respective components are the same entities, +are the same identifiers, have equal values, or are both $\bot$. +\begin{note} +The components of a data member description describe a data member such that +\begin{itemize} +\item +its type is specified using the type given by $T$, +\item +it is declared with the name given by $N$ +if $N$ is not $\bot$ and is otherwise unnamed, +\item +it is declared with the \grammarterm{alignment-specifier}\iref{dcl.align} +given by \tcode{alignas($A$)} +if $A$ is not $\bot$ and +is otherwise declared without an \grammarterm{alignment-specifier}, +\item +it is a bit-field\iref{class.bit} with the width given by $W$ +if W is not $\bot$ and is otherwise not a bit-field, and +\item +it is declared with +the attribute \tcode{[[no_unique_address]]}\iref{dcl.attr.nouniqueaddr} +if $\mathit{NUA}$ is true and is otherwise declared without that attribute. +\end{itemize} +Data member descriptions are represented by reflections\iref{basic.fundamental} +returned by \tcode{std::meta::data_member_spec}\iref{meta.reflection.define.aggregate} and +can be reified as data members of a class using \tcode{std::meta::define_aggregate}. +\end{note} + \rSec2[class.mfct]{Member functions}% \indextext{member function!class} @@ -3514,7 +3567,12 @@ The class denoted by the \grammarterm{class-or-decltype} of a \grammarterm{base-specifier} is called a \defnadj{direct}{base class} -for the class being defined. +for the class being defined; +for each such \grammarterm{base-specifier}, +the corresponding \defnadj{direct base class}{relationship} +is the ordered pair (\tcode{D}, \tcode{B}) +where \tcode{D} is the class being defined and +\tcode{B} is the direct base class. \indextext{base class}% \indextext{derivation|see{inheritance}}% The lookup for the component name of @@ -4345,9 +4403,10 @@ \end{codeblock} \end{example} \begin{note} -Because access control applies to the declarations named, if access control is applied to a -\grammarterm{typedef-name}, only the accessibility of the typedef or alias declaration itself is considered. -The accessibility of the entity referred to by the \grammarterm{typedef-name} is not considered. +Because access control applies to the declarations named, +if access control is applied to a type alias, +only the accessibility of the typedef or alias declaration itself is considered. +The accessibility of the underlying entity is not considered. \begin{example} \begin{codeblock} class A { @@ -4738,10 +4797,18 @@ to a pointer to a private or protected immediate base class of \tcode{X}. \end{note} -The access to a member is affected by the class in which the member is -named. -This naming class is -the class in whose scope name lookup performed a search that found the member. +An expression $E$ that designates a member \tcode{m} +has a \defnadj{designating}{class} +that affects the access to \tcode{m}. +This designating class is either +\begin{itemize} +\item +the innermost class of which \tcode{m} is directly a member +if $E$ is a \grammarterm{splice-expression} or +\item +the class in whose scope name lookup performed a search +that found \tcode{m} otherwise. +\end{itemize} \begin{note} This class can be explicit, e.g., when a \grammarterm{qualified-id} @@ -4753,7 +4820,7 @@ \grammarterm{qualified-id} are used to name the member (as in \tcode{p->T::m}), -the class naming the member is the class denoted by the +the class designating the member is the class designated by the \grammarterm{nested-name-specifier} of the \grammarterm{qualified-id} @@ -4764,11 +4831,13 @@ \tcode{m} is accessible at the point \placeholder{R} -when named in class +when designated in class \tcode{N} if \begin{itemize} \item +\tcode{m} is designated by a \grammarterm{splice-expression}, or +\item \tcode{m} as a member of \tcode{N} @@ -4810,7 +4879,7 @@ \tcode{m} is accessible at \placeholder{R} -when named in class +when designated in class \tcode{B}. \begin{example} \begin{codeblock} @@ -4836,10 +4905,10 @@ left operand (considered as a pointer in the ``\tcode{.}'' operator case) cannot be implicitly converted to a -pointer to the naming class of the right operand. +pointer to the designating class of the right operand. \begin{note} This requirement is in addition to the requirement that -the member be accessible as named. +the member be accessible as designated. \end{note} \rSec2[class.friend]{Friends}% diff --git a/source/compatibility.tex b/source/compatibility.tex index 8d1468e9cd..4904b17a86 100644 --- a/source/compatibility.tex +++ b/source/compatibility.tex @@ -13,6 +13,22 @@ \rSec2[diff.cpp23.lex]{\ref{lex}: Lexical conventions} +\diffref{lex.operators} +\change +New operator \tcode{\caret\caret}. +\rationale +Required for new features. +\effect +Valid \CppXXIII{} code that contains two consecutive \tcode{\caret} tokens +can be ill-formed in this revision of \Cpp{}. +\begin{example} +\begin{codeblock} +struct C { int operator^(int); }; +int operator^(int (C::*p)(int), C); +int i = &C::operator^^C{}; // ill-formed; previously well-formed +\end{codeblock} +\end{example} + \diffref{lex.key} \change New keywords. @@ -148,6 +164,22 @@ \end{codeblock} \end{example} +\diffref{dcl.attr.grammar} +\change +New token \tcode{:]}. +\rationale +Required for new features. +\effect +Valid \CppXXIII{} code that contained an \grammarterm{attribute-specifier} +with an \grammarterm{attribute-using-prefix} +but no attributes and no whitespace is ill-formed in this revision of \Cpp{}. +\begin{example} +\begin{codeblock} +struct [[using CC:]] C; // ill-formed; previously well-formed +struct [[using DD: ]] D; // OK +\end{codeblock} +\end{example} + \rSec2[diff.cpp23.temp]{\ref{temp}: templates} \diffref{temp.constr} @@ -221,6 +253,8 @@ \libheaderref{hive}, \libheaderrefx{inplace_vector}{inplace.vector.syn}, \libheaderref{linalg}, +%FIXME: \libheaderref{meta} after renaming to meta.syn +\libheaderrefx{meta}{meta.type.synop}, \libheaderref{rcu}, \libheaderref{simd}, \libheaderref{stdbit.h}, diff --git a/source/declarations.tex b/source/declarations.tex index 7c0c694c1d..96092fc9ec 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -53,6 +53,7 @@ using-enum-declaration\br using-directive\br static_assert-declaration\br + consteval-block-declaration\br alias-declaration\br opaque-enum-declaration \end{bnf} @@ -102,6 +103,11 @@ \keyword{static_assert} \terminal{(} constant-expression \terminal{,} static_assert-message \terminal{)} \terminal{;} \end{bnf} +\begin{bnf} +\nontermdef{consteval-block-declaration}\br + \keyword{consteval} compound-statement +\end{bnf} + \begin{bnf} \nontermdef{empty-declaration}\br \terminal{;} @@ -245,8 +251,7 @@ If the \grammarterm{decl-specifier-seq} contains the \keyword{typedef} specifier, the declaration is a \defnx{typedef declaration}{declaration!typedef} and each \grammarterm{declarator-id} -is declared to be a \grammarterm{typedef-name}, synonymous with its -associated type\iref{dcl.typedef}. +is declared to be a \grammarterm{typedef-name}\iref{dcl.typedef}. \begin{note} Such a \grammarterm{declarator-id} is an \grammarterm{identifier}\iref{class.conv.fct}. @@ -382,6 +387,35 @@ \end{codeblock} \end{example} +\pnum +For a \grammarterm{consteval-block-declaration} $D$, +the expression $E$ corresponding to $D$ is: +\begin{codeblock} + [] -> void static consteval @\grammarterm{compound-statement}@ () +\end{codeblock} +$E$ shall be a constant expression\iref{expr.const}. +\begin{note} +The evaluation of the expression +corresponding to a \grammarterm{consteval-block-declaration}\iref{lex.phases} +can produce injected declarations as side effects. +\end{note} +\begin{example} +\begin{codeblock} +struct S; +consteval { + std::meta::define_aggregate(^^S, {}); // OK + + template + struct X { }; // error: local templates are not allowed + + template + concept C = true; // error: local concepts are not allowed + + return; // OK +} +\end{codeblock} +\end{example} + \pnum An \grammarterm{empty-declaration} has no effect. @@ -708,9 +742,8 @@ \pnum Declarations containing the \grammarterm{decl-specifier} \keyword{typedef} -declare identifiers that can be used later for naming -fundamental\iref{basic.fundamental} or compound\iref{basic.compound} -types. The \keyword{typedef} specifier shall not be +declare \defnadjx{type}{aliases}{alias}. +The \keyword{typedef} specifier shall not be combined in a \grammarterm{decl-specifier-seq} with any other kind of specifier except a \grammarterm{defining-type-specifier}, and it shall not be used in the \grammarterm{decl-specifier-seq} of a @@ -728,14 +761,12 @@ A name declared with the \keyword{typedef} specifier becomes a \grammarterm{typedef-name}. -A \grammarterm{typedef-name} names +The underlying entity of the type alias is the type associated with the \grammarterm{identifier}\iref{dcl.decl} or \grammarterm{simple-template-id}\iref{temp.pre}; \indextext{declaration!typedef@\tcode{typedef} as type}% \indextext{equivalence!type}% -\indextext{synonym!type name as}% -a \grammarterm{typedef-name} is thus a synonym for another type. A -\grammarterm{typedef-name} does not introduce a new type the way a class +A \grammarterm{typedef-name} does not introduce a new type the way a class declaration\iref{class.name} or enum declaration\iref{dcl.enum} does. \begin{example} After @@ -752,14 +783,14 @@ \end{example} \pnum -A \grammarterm{typedef-name} can also be introduced by an +A type alias can also be declared by an \grammarterm{alias-declaration}. The \grammarterm{identifier} following the -\tcode{using} keyword is not looked up; it becomes a \grammarterm{typedef-name} +\tcode{using} keyword is not looked up; +it becomes the \grammarterm{typedef-name} of a type alias and the optional \grammarterm{attribute-specifier-seq} following the -\grammarterm{identifier} appertains to that \grammarterm{typedef-name}. -Such a \grammarterm{typedef-name} has the same -semantics as if it were introduced by the \keyword{typedef} specifier. In -particular, it does not define a new type. +\grammarterm{identifier} appertains to that type alias. +Such a type alias has the same +semantics as if it were introduced by the \keyword{typedef} specifier. \begin{example} \begin{codeblock} using handler_t = void (*)(int); @@ -1377,7 +1408,8 @@ \begin{bnf} \nontermdef{computed-type-specifier}\br decltype-specifier\br - pack-index-specifier + pack-index-specifier\br + splice-type-specifier \end{bnf} \pnum @@ -1412,12 +1444,21 @@ is a placeholder for a type to be deduced\iref{dcl.spec.auto}. \indextext{deduction!class template arguments}% -A \grammarterm{type-specifier} of the form -\opt{\keyword{typename}} \opt{\grammarterm{nested-name-specifier}} \grammarterm{template-name} -is a placeholder for -a deduced class type\iref{dcl.type.class.deduct}. -The \grammarterm{nested-name-specifier}, if any, shall be non-dependent and -the \grammarterm{template-name} shall name a deducible template. +A \grammarterm{type-specifier} is a placeholder for +a deduced class type\iref{dcl.type.class.deduct} if either +\begin{itemize} +\item +it is of the form +\opt{\keyword{typename}} \opt{\grammarterm{nested-name-specifier}} \grammarterm{template-name} or +\item +it is of the form \opt{\keyword{typename}} \grammarterm{splice-specifier} and +the \grammarterm{splice-specifier} designates +a class template or alias template. +\end{itemize} +The \grammarterm{nested-name-specifier} or \grammarterm{splice-specifier}, +if any, shall be non-dependent and +the \grammarterm{template-name} or \grammarterm{splice-specifier} +shall designate a deducible template. A \defnadj{deducible}{template} is either a class template or is an alias template whose \grammarterm{defining-type-id} is of the form @@ -1455,6 +1496,7 @@ \grammarterm{placeholder-type-specifier} & the type as defined in~\ref{dcl.spec.auto}\\ \grammarterm{template-name} & the type as defined in~\ref{dcl.type.class.deduct}\\ +\grammarterm{splice-type-specifier} & the type as defined in~\ref{dcl.type.splice}\\ \tcode{char} & ``\tcode{char}'' \\ \tcode{unsigned char} & ``\tcode{unsigned char}'' \\ \tcode{signed char} & ``\tcode{signed char}'' \\ @@ -1683,6 +1725,10 @@ type of the entity named by $E$. If there is no such entity, the program is ill-formed; +\item otherwise, if $E$ is an unparenthesized \grammarterm{splice-expression}, +\tcode{decltype($E$)} is the type of the entity, object, or value +designated by the \grammarterm{splice-specifier} of $E$; + \item otherwise, if $E$ is an xvalue, \tcode{decltype($E$)} is \tcode{T\&\&}, where \tcode{T} is the type of $E$; @@ -1706,11 +1752,13 @@ decltype(i) x2; // type is \tcode{int} decltype(a->x) x3; // type is \tcode{double} decltype((a->x)) x4 = x3; // type is \tcode{const double\&} +decltype([:^^x1:]) x5 = 18; // type is \tcode{const int\&\&} +decltype(([:^^x1:])) x6 = 19; // type is \tcode{const int\&} void f() { [](auto ...pack) { - decltype(pack...[0]) x5; // type is \tcode{int} - decltype((pack...[0])) x6; // type is \tcode{int\&} + decltype(pack...[0]) x7; // type is \tcode{int} + decltype((pack...[0])) x8; // type is \tcode{int\&} }(0); } \end{codeblock} @@ -2266,6 +2314,59 @@ container e{5, 6}; // error: \tcode{int} is not an iterator \end{codeblock} \end{example} + +\rSec3[dcl.type.splice]{Type splicing} + +\begin{bnf} +\nontermdef{splice-type-specifier}\br + \opt{\keyword{typename}} splice-specifier\br + \opt{\keyword{typename}} splice-specialization-specifier +\end{bnf} + +\pnum +A \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +immediately followed by \tcode{::} +is never interpreted as part of a \grammarterm{splice-type-specifier}. +A \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +not preceded by \keyword{typename} +is only interpreted as a \grammarterm{splice-type-specifier} +within a type-only context\iref{temp.res.general}. +\begin{example} +\begin{codeblock} +template void tfn() { + typename [:R:]::type m; // OK, \keyword{typename} applies to the qualified name +} + +struct S { using type = int; }; +void fn() { + [:^^S::type:] *var; // error: \tcode{[:\caret\caret S::type:]} is an expression + typename [:^^S::type:] *var; // OK, declares variable with type \tcode{int*} +} + +using alias = [:^^S::type:]; // OK, type-only context +\end{codeblock} +\end{example} + +\pnum +For a \grammarterm{splice-type-specifier} of the form +\opt{\keyword{typename}} \grammarterm{splice-specifier}, +the \grammarterm{splice-specifier} shall designate +a type, a class template, or an alias template. +The \grammarterm{splice-type-specifier} designates +the same entity as the \grammarterm{splice-specifier}. + +\pnum +For a \grammarterm{splice-type-specifier} of the form +\opt{\keyword{typename}} \grammarterm{splice-specialization-specifier}, +the \grammarterm{splice-specifier} of +the \grammarterm{splice-specialization-specifier} +shall designate a template \tcode{T} +that is either a class template or an alias template. +The \grammarterm{splice-type-specifier} designates +the specialization of \tcode{T} corresponding to +the template argument list of the \grammarterm{splice-specialization-specifier}. \indextext{specifier|)}% \rSec1[dcl.decl]{Declarators}% @@ -3276,7 +3377,7 @@ \end{ncsimplebnf} and the \grammarterm{nested-name-specifier} -denotes a class, +designates a class, and the type of the contained \grammarterm{declarator-id} in the declaration \tcode{T} \tcode{D1} @@ -3289,6 +3390,7 @@ \tcode{T}''. The optional \grammarterm{attribute-specifier-seq}\iref{dcl.attr.grammar} appertains to the pointer-to-member. +The \grammarterm{nested-name-specifier} shall not designate an anonymous union. \pnum \begin{example} @@ -3469,8 +3571,10 @@ and the type of the array is ``array of \tcode{N} \tcode{U}''. \pnum -Furthermore, if there is a reachable declaration of the entity that inhabits the same -scope in which the bound was specified, an omitted array bound is taken to +Furthermore, if there is a reachable declaration of the entity +that specifies a bound and +has the same host scope\iref{basic.scope.scope}, +an omitted array bound is taken to be the same as in that earlier declaration, and similarly for the definition of a static data member of a class. \begin{example} @@ -3487,6 +3591,9 @@ extern int x[]; int i = sizeof(x); // error: incomplete object type } + +namespace A { extern int z[3]; } +int A::z[] = {}; // OK, defines an array of 3 elements \end{codeblock} \end{example} @@ -3839,7 +3946,7 @@ \pnum A function type with a \grammarterm{cv-qualifier-seq} or a -\grammarterm{ref-qualifier} (including a type named by +\grammarterm{ref-qualifier} (including a type denoted by \grammarterm{typedef-name}\iref{dcl.typedef,temp.param}) shall appear only as: \begin{itemize} @@ -3855,15 +3962,18 @@ \item the \grammarterm{type-id} of a \grammarterm{template-argument} for a \grammarterm{type-parameter}\iref{temp.arg.type}. + +\item the operand of a \grammarterm{reflect-expression}\iref{expr.reflect}. \end{itemize} \begin{example} \begin{codeblock} typedef int FIC(int) const; -FIC f; // error: does not declare a member function +FIC f; // error: does not declare a member function struct S { - FIC f; // OK + FIC f; // OK }; -FIC S::*pm = &S::f; // OK +FIC S::*pm = &S::f; // OK +constexpr std::meta::info yeti = ^^void(int) const &; // OK \end{codeblock} \end{example} @@ -4220,9 +4330,9 @@ \pnum For non-template functions, default arguments can be added in later declarations of a -function that inhabit the same scope. -Declarations that inhabit different -scopes have completely distinct sets of default arguments. +function that have the same host scope. +Declarations that have different +host scopes have completely distinct sets of default arguments. That is, declarations in inner scopes do not acquire default arguments from declarations in outer scopes, and vice versa. @@ -4393,9 +4503,19 @@ int h(int a, int b = sizeof(a)); // OK, unevaluated operand\iref{term.unevaluated.operand} \end{codeblock} \end{example} -A non-static member shall not appear in a default argument unless it appears as -the \grammarterm{id-expression} of a class member access expression\iref{expr.ref} or -unless it is used to form a pointer to member\iref{expr.unary.op}. +A non-static member shall not be designated in a default argument unless +\begin{itemize} +\item +it is designated by +the \grammarterm{id-expression} or \grammarterm{splice-expression} +of a class member access expression\iref{expr.ref}, +\item +it is designated by an expression +used to form a pointer to member\iref{expr.unary.op}, or +\item +it appears as the operand of +a \grammarterm{reflect-expression}\iref{expr.reflect}. +\end{itemize} \begin{example} The declaration of \tcode{X::mem1()} @@ -4407,8 +4527,10 @@ int b; class X { int a; - int mem1(int i = a); // error: non-static member \tcode{a} used as default argument - int mem2(int i = b); // OK; use \tcode{X::b} + int mem1(int i = a); // error: non-static member \tcode{a} used as default argument + int mem2(int i = b); // OK, use \tcode{X::b} + consteval void mem3(std::meta::info r = ^^a) {} // OK + int mem4(int i = [:^^a:]); // error: non-static member a designated in default argument static int b; }; \end{codeblock} @@ -4433,10 +4555,13 @@ int (*p2)() = &f; // error: type mismatch \end{codeblock} \end{example} +\begin{note} When an overload set contains a declaration of a function -that inhabits a scope $S$, -any default argument associated with any reachable declaration that inhabits $S$ -is available to the call. +whose host scope is $S$, +any default argument associated with any reachable declaration +whose host scope is $S$ +is available to the call\iref{over.match.viable}. +\end{note} \begin{note} The candidate might have been found through a \grammarterm{using-declarator} from which the declaration that provides the default argument is not reachable. @@ -4895,20 +5020,16 @@ \indextext{initialization!default}% \indextext{variable!indeterminate uninitialized}% \indextext{initialization!zero-initialization}% -To -\defnx{zero-initialize}{zero-initialization} -an object or reference of type -\tcode{T} -means: +To \defnx{zero-initialize}{zero-initialization} +an object or reference of type \tcode{T} means: \begin{itemize} \item -if -\tcode{T} -is a scalar type\iref{term.scalar.type}, the -object -is initialized to the value obtained by converting the integer literal \tcode{0} -(zero) to -\tcode{T}; +if \tcode{T} is \tcode{std::meta::info}, +the object is initialized to a null reflection value; +\item +if \tcode{T} is any other scalar type\iref{term.scalar.type}, +the object is initialized to the value +obtained by converting the integer literal \tcode{0} (zero) to \tcode{T}; \begin{footnote} As specified in~\ref{conv.ptr}, converting an integer literal whose value is @@ -4974,6 +5095,9 @@ shall be met and each element is default-initialized. +\item +If \tcode{T} is \tcode{std::meta::info}, the object is zero-initialized. + \item Otherwise, no initialization is performed. @@ -5002,8 +5126,9 @@ \end{itemize} If a program calls for the default-initialization of an object of a -const-qualified type \tcode{T}, -\tcode{T} shall be a const-default-constructible class type or array thereof. +const-qualified type \tcode{T}, \tcode{T} shall be +\tcode{std::meta::\linebreak info} or a const-default-constructible class type or +array thereof. \pnum To @@ -7003,8 +7128,10 @@ deleted definition or a function that is implicitly defined as deleted. \pnum -A program that refers to a deleted function implicitly or explicitly, other -than to declare it, is ill-formed. +A construct that designates a deleted function implicitly or explicitly, +other than to declare it or to appear as the operand of +a \grammarterm{reflect-expression}\iref{expr.reflect}, +is ill-formed. \recommended The resulting diagnostic message should include @@ -7993,11 +8120,15 @@ \begin{bnf} \nontermdef{using-enum-declarator}\br \opt{nested-name-specifier} identifier\br - \opt{nested-name-specifier} simple-template-id + \opt{nested-name-specifier} simple-template-id\br + splice-type-specifier \end{bnf} \pnum -A \grammarterm{using-enum-declarator} +A \grammarterm{using-enum-declarator} of +the form \grammarterm{splice-type-specifier} +designates the same type designated by the \grammarterm{splice-type-specifier}. +Any other \grammarterm{using-enum-declarator} names the set of declarations found by type-only lookup\iref{basic.lookup.general} for the \grammarterm{using-enum-declarator}\iref{basic.lookup.unqual,basic.lookup.qual}. @@ -8261,7 +8392,7 @@ \grammarterm{unnamed-namespace-definition} and all occurrences of \exposid{unique} in a translation unit are replaced by the same identifier, and this identifier differs from all other -identifiers in the translation unit. +identifiers in the program. The optional \grammarterm{attribute-specifier-seq} in the \grammarterm{unnamed-namespace-definition} appertains to \exposid{unique}. @@ -8293,8 +8424,8 @@ \indextext{synonym} \pnum -A \grammarterm{namespace-alias-definition} declares an alternate name for a -namespace according to the following grammar: +A \grammarterm{namespace-alias-definition} declares a \defnadj{namespace}{alias} +according to the following grammar: \begin{bnf} \nontermdef{namespace-alias}\br @@ -8303,7 +8434,8 @@ \begin{bnf} \nontermdef{namespace-alias-definition}\br - \keyword{namespace} identifier \terminal{=} qualified-namespace-specifier \terminal{;} + \keyword{namespace} identifier \terminal{=} qualified-namespace-specifier \terminal{;}\br + \keyword{namespace} identifier \terminal{=} splice-specifier \terminal{;}\br \end{bnf} \begin{bnf} @@ -8311,10 +8443,19 @@ \opt{nested-name-specifier} namespace-name \end{bnf} +\pnum +The \grammarterm{splice-specifier} (if any) +shall designate a namespace that is not the global namespace. + \pnum The \grammarterm{identifier} in a \grammarterm{namespace-alias-definition} -becomes a \grammarterm{namespace-alias} and denotes the namespace denoted by the -\grammarterm{qualified-namespace-specifier}. +becomes a \grammarterm{namespace-alias}. + +\pnum +The underlying entity\iref{basic.pre} of the namespace alias is +the namespace either +denoted by the \grammarterm{qualified-namespace-specifier} or +designated by the \grammarterm{splice-specifier}. \begin{note} When looking up a \grammarterm{namespace-name} in a \grammarterm{namespace-alias-definition}, only namespace names are @@ -8326,9 +8467,18 @@ \begin{bnf} \nontermdef{using-directive}\br - \opt{attribute-specifier-seq} \keyword{using} \keyword{namespace} \opt{nested-name-specifier} namespace-name \terminal{;} + \opt{attribute-specifier-seq} \keyword{using} \keyword{namespace} \opt{nested-name-specifier} namespace-name \terminal{;}\br + \opt{attribute-specifier-seq} \keyword{using} \keyword{namespace} splice-specifier \terminal{;} \end{bnf} +\pnum +The \grammarterm{splice-specifier} (if any) shall designate a namespace +that is not the global namespace. +The \grammarterm{nested-name-specifier}, +\grammarterm{namespace-name}, and +\grammarterm{splice-specifier} +shall not be dependent. + \pnum A \grammarterm{using-directive} shall not appear in class scope, but may appear in namespace scope or in block scope. @@ -8341,13 +8491,13 @@ \pnum \begin{note} -A \grammarterm{using-directive} makes the names in the nominated +A \grammarterm{using-directive} makes the names in the designated namespace usable in the scope in which the \grammarterm{using-directive} appears after the \grammarterm{using-directive}\iref{basic.lookup.unqual,namespace.qual}. During unqualified name lookup, the names appear as if they were declared in the nearest enclosing namespace which -contains both the \grammarterm{using-directive} and the nominated +contains both the \grammarterm{using-directive} and the designated namespace. \end{note} @@ -8388,8 +8538,8 @@ \pnum \begin{note} A \grammarterm{using-directive} is transitive: if a scope contains a -\grammarterm{using-directive} that nominates a namespace that itself -contains \grammarterm{using-directive}{s}, the namespaces nominated by those +\grammarterm{using-directive} that designates a namespace that itself +contains \grammarterm{using-directive}{s}, the namespaces designated by those \grammarterm{using-directive}{s} are also eligible to be considered. \end{note} \begin{example} @@ -9280,7 +9430,8 @@ \terminal{(} \opt{balanced-token-seq} \terminal{)}\br \terminal{[} \opt{balanced-token-seq} \terminal{]}\br \terminal{\{} \opt{balanced-token-seq} \terminal{\}}\br - \textnormal{any \grammarterm{token} other than a parenthesis, a bracket, or a brace} + \terminal{[:} \opt{balanced-token-seq} \terminal{:]}\br + \textnormal{any \grammarterm{token} other than \terminal{(}, \terminal{)}, \terminal{[}, \terminal{]}, \terminal{\{}, \terminal{\}}, \terminal{[:}, or \terminal{:]}} \end{bnf} \pnum @@ -9319,7 +9470,9 @@ In an \grammarterm{attribute-list}, an ellipsis may appear only if that \grammarterm{attribute}'s specification permits it. An \grammarterm{attribute} followed by an ellipsis is a pack expansion\iref{temp.variadic}. -An \grammarterm{attribute-specifier} that contains no \grammarterm{attribute}{s} has no +An \grammarterm{attribute-specifier} +that contains no \grammarterm{attribute}{s} and no \grammarterm{alignment-specifier} +has no effect. The order in which the \grammarterm{attribute-token}{s} appear in an \grammarterm{attribute-list} is not significant. If a keyword\iref{lex.key} @@ -9575,7 +9728,7 @@ \pnum The attribute may be applied to the declaration of a class, -a \grammarterm{typedef-name}, +a type alias, a variable, a non-static data member, a function, @@ -9793,7 +9946,7 @@ \pnum The attribute may be applied to the declaration of a class, -\grammarterm{typedef-name}, +type alias, variable (including a structured binding declaration), structured binding, result binding\iref{dcl.contract.res}, diff --git a/source/expressions.tex b/source/expressions.tex index a885859f4c..95164d79be 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -147,7 +147,7 @@ \end{importgraphic} \begin{itemize} -\item A \defn{glvalue} is an expression whose evaluation determines the identity of an object or function. +\item A \defn{glvalue} is an expression whose evaluation determines the identity of an object, function, or non-static data member. \item A \defn{prvalue} is an expression whose evaluation initializes an object or computes the value of an operand of an operator, as specified by the context in which it appears, @@ -186,7 +186,8 @@ \begin{note} An expression is an xvalue if it is: \begin{itemize} -\item a move-eligible \grammarterm{id-expression}\iref{expr.prim.id.unqual}, +\item a move-eligible \grammarterm{id-expression}\iref{expr.prim.id.unqual} +or \grammarterm{splice-expression}\iref{expr.prim.splice}, \item the result of calling a function, whether implicitly or explicitly, whose return type is an rvalue reference to object type\iref{expr.call}, @@ -442,6 +443,7 @@ expr.typeid, expr.sizeof, expr.unary.noexcept, +expr.reflect, dcl.type.decltype, temp.pre, temp.concept}. @@ -467,6 +469,7 @@ \item \tcode{(} \grammarterm{expression} \tcode{)}, where \grammarterm{expression} is one of these expressions, \item \grammarterm{id-expression}\iref{expr.prim.id}, +\item \grammarterm{splice-expression}\iref{expr.prim.splice}, \item subscripting\iref{expr.sub}, \item class member access\iref{expr.ref}, \item indirection\iref{expr.unary.op}, @@ -1243,7 +1246,8 @@ id-expression\br lambda-expression\br fold-expression\br - requires-expression + requires-expression\br + splice-expression \end{bnf} \rSec2[expr.prim.literal]{Literals} @@ -1389,6 +1393,9 @@ $E$ is not the \grammarterm{id-expression} of a class member access expression\iref{expr.ref}, and \item +$E$ is not the \grammarterm{id-expression} of +a \grammarterm{reflect-expression}\iref{expr.reflect}, and +\item if $E$ is a \grammarterm{qualified-id}, $E$ is not the un-parenthesized operand of the unary \tcode{\&} operator\iref{expr.unary.op}, @@ -1446,7 +1453,8 @@ \end{itemize} \pnum -An \grammarterm{id-expression} that denotes a non-static data member or +An \grammarterm{id-expression} or \grammarterm{splice-expression} +that designates a non-static data member or implicit object member function of a class can only be used: \begin{itemize} \item as part of a class member access @@ -1459,7 +1467,8 @@ \item to form a pointer to member\iref{expr.unary.op}, or -\item if that \grammarterm{id-expression} denotes a non-static data member +\item if that \grammarterm{id-expression} or \grammarterm{splice-expression} +designates a non-static data member and it appears in an unevaluated operand. \begin{example} \begin{codeblock} @@ -1468,6 +1477,7 @@ }; int i = sizeof(S::m); // OK int j = sizeof(S::m + 42); // OK +int S::*k = &[:^^S::m:]; // OK \end{codeblock} \end{example} \end{itemize} @@ -1775,10 +1785,12 @@ a variable with automatic storage duration that is either a non-volatile object or an rvalue reference to a non-volatile object type. -An \grammarterm{id-expression} is \defn{move-eligible} if +An \grammarterm{id-expression} or +\grammarterm{splice-expression}\iref{expr.prim.splice} +is \defn{move-eligible} if \begin{itemize} \item -it names an implicitly movable entity, +it designates an implicitly movable entity, \item it is the (possibly parenthesized) operand of a \tcode{return}\iref{stmt.return} or @@ -1787,7 +1799,7 @@ \item each intervening scope between the declaration of the entity and -the innermost enclosing scope of the \grammarterm{id-expression} +the innermost enclosing scope of the expression is a block scope and, for a \grammarterm{throw-expression}, is not the block scope of @@ -1813,9 +1825,15 @@ type-name \terminal{::}\br namespace-name \terminal{::}\br computed-type-specifier \terminal{::}\br + splice-scope-specifier \terminal{::}\br nested-name-specifier identifier \terminal{::}\br nested-name-specifier \opt{\keyword{template}} simple-template-id \terminal{::} \end{bnf} +\begin{bnf} +\nontermdef{splice-scope-specifier}\br + splice-specifier\br + \opt{\keyword{template}} splice-specialization-specifier +\end{bnf} \pnum \indextext{component name}% @@ -1828,6 +1846,33 @@ \grammarterm{simple-template-id}, and/or \grammarterm{nested-name-specifier}. +\pnum +A \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +that is not followed by \tcode{::} +is never interpreted as part of a \grammarterm{splice-scope-specifier}. +The keyword \keyword{template} may only be omitted +from the form +\tcode{\opt{\keyword{template}} \grammarterm{splice-specialization-specifier} ::} +when the \grammarterm{splice-specialization-specifier} +is preceded by \keyword{typename}. +\begin{example} +\begin{codeblock} +template +struct TCls { + static constexpr int s = V; + using type = int; +}; + +int v1 = [:^^TCls<1>:]::s; +int v2 = template [:^^TCls:]<2>::s; // OK, \keyword{template} binds to \grammarterm{splice-scope-specifier} +typename [:^^TCls:]<3>::type v3 = 3; // OK, \keyword{typename} binds to the qualified name +template [:^^TCls:]<3>::type v4 = 4; // OK, \keyword{template} binds to the \grammarterm{splice-scope-specifier} +typename template [:^^TCls:]<3>::type v5 = 5; // OK, same as \tcode{v3} +[:^^TCls:]<3>::type v6 = 6; // error: unexpected \tcode{<} +\end{codeblock} +\end{example} + \pnum A \grammarterm{nested-name-specifier} is \defn{declarative} if it is part of \begin{itemize} @@ -1842,17 +1887,44 @@ a declarative \grammarterm{nested-name-specifier}. \end{itemize} A declarative \grammarterm{nested-name-specifier} -shall not have a \grammarterm{computed-type-specifier}. +shall not have a \grammarterm{computed-type-specifier} or +a \grammarterm{splice-scope-specifier}. A declaration that uses a declarative \grammarterm{nested-name-specifier} shall be a friend declaration or inhabit a scope that contains the entity being redeclared or specialized. \pnum -The \grammarterm{nested-name-specifier} \tcode{::} nominates +The entity designated by a \grammarterm{nested-name-specifier} +is determined as follows: +\begin{itemize} +\item +The \grammarterm{nested-name-specifier} \tcode{::} designates the global namespace. +\item A \grammarterm{nested-name-specifier} with a \grammarterm{computed-type-specifier} -nominates the type denoted by the \grammarterm{computed-type-specifier}, +designates the same type designated by the \grammarterm{computed-type-specifier}, which shall be a class or enumeration type. +\item +For a \grammarterm{nested-name-specifier} of +the form \tcode{\grammarterm{splice-specifier} ::}, +the \grammarterm{splice-specifier} shall designate +a class or enumeration type or a namespace. +The \grammarterm{nested-name-specifier} designates the same entity +as the \grammarterm{splice-specifier}. +\item +For a \grammarterm{nested-name-specifier} of +the form +\tcode{\opt{\keyword{template}} \grammarterm{splice-specialization-specifier} ::}, +the \grammarterm{splice-specifier} of +the \grammarterm{splice-specialization-specifier} shall designate +a class template or an alias template $T$. +Letting $S$ be the specialization of $T$ +corresponding to the template argument list of +the \grammarterm{splice-specialization-specifier}, +$S$ shall either be a class template specialization or +an alias template specialization that denotes a class or enumeration type. +The \grammarterm{nested-name-specifier} designates the underlying entity of $S$. +\item If a \grammarterm{nested-name-specifier} $N$ is declarative and has a \grammarterm{simple-template-id} with a template argument list $A$ @@ -1863,22 +1935,24 @@ \item If $A$ is the template argument list\iref{temp.arg} of the corresponding \grammarterm{template-head} $H$\iref{temp.mem}, -$N$ nominates the primary template of $T$; +$N$ designates the primary template of $T$; $H$ shall be equivalent to the \grammarterm{template-head} of $T$\iref{temp.over.link}. \item -Otherwise, $N$ nominates the partial specialization\iref{temp.spec.partial} of $T$ +Otherwise, $N$ designates the partial specialization\iref{temp.spec.partial} of $T$ whose template argument list is equivalent to $A$\iref{temp.over.link}; the program is ill-formed if no such partial specialization exists. \end{itemize} -Any other \grammarterm{nested-name-specifier} nominates -the entity denoted by its +\item +Any other \grammarterm{nested-name-specifier} designates +the entity denotes by its \grammarterm{type-name}, \grammarterm{namespace-name}, \grammarterm{identifier}, or \grammarterm{simple-template-id}. If the \grammarterm{nested-name-specifier} is not declarative, the entity shall not be a template. +\end{itemize} \pnum A \grammarterm{qualified-id} shall not be of the form @@ -2133,6 +2207,10 @@ called the \defn{closure type}, whose properties are described below. +\pnum +The closure type is not complete +until the end of its corresponding \grammarterm{compound-statement}. + \pnum The closure type is declared in the smallest block scope, class scope, or namespace scope that contains the corresponding @@ -2172,6 +2250,8 @@ respectively, and whose \grammarterm{template-parameter-list} consists of the specified \grammarterm{template-parameter-list}, if any. +The function call operator or the function call operator template are +direct members of the closure type. The \grammarterm{requires-clause} of the function call operator template is the \grammarterm{requires-clause} immediately following \tcode{<}~\grammarterm{template-parameter-list}{}~\tcode{>}, if any. @@ -2524,7 +2604,9 @@ }; \end{codeblock} \end{example} -Further, a variable \mname{func} is implicitly defined at the beginning of +Unless the \grammarterm{compound-statement} is +that of a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, +a variable \mname{func} is implicitly defined at the beginning of the \grammarterm{compound-statement} of the \grammarterm{lambda-expression}, with semantics as described in~\ref{dcl.fct.def.general}. @@ -3271,13 +3353,16 @@ \begin{bnf} \nontermdef{type-requirement}\br - \keyword{typename} \opt{nested-name-specifier} type-name \terminal{;} + \keyword{typename} \opt{nested-name-specifier} type-name \terminal{;}\br + \keyword{typename} splice-specifier\br + \keyword{typename} splice-specialization-specifier \end{bnf} \pnum A \grammarterm{type-requirement} asserts the validity of a type. The component names of a \grammarterm{type-requirement} are those of its -\grammarterm{nested-name-specifier} (if any) and \grammarterm{type-name}. +\grammarterm{nested-name-specifier} (if any) and +\grammarterm{type-name} (if any). \begin{note} The enclosing \grammarterm{requires-expression} will evaluate to \keyword{false} if substitution of template arguments fails. @@ -3288,10 +3373,12 @@ template using Ref = T&; template concept C = requires { - typename T::inner; // required nested member name - typename S; // required valid\iref{temp.names} \grammarterm{template-id}; - // fails if \tcode{T::type} does not exist as a type to which \tcode{0} can be implicitly converted - typename Ref; // required alias template substitution, fails if \tcode{T} is void + typename T::inner; // required nested member name + typename S; // required valid\iref{temp.names} \grammarterm{template-id}; fails if \tcode{T::type} does not exist as a type + // to which \tcode{0} can be implicitly converted + typename Ref; // required alias template substitution, fails if \tcode{T} is void + typename [:T::r1:]; // fails if \tcode{T::r1} is not a reflection of a type + typename [:T::r2:]; // fails if \tcode{T::r2} is not a reflection of a template \tcode{Z} for which \tcode{Z} is a type }; \end{codeblock} \end{example} @@ -3426,6 +3513,150 @@ \indextext{expression!requires|)} \indextext{expression!primary|)} +\rSec2[expr.prim.splice]{Expression splicing} + +\begin{bnf} +\nontermdef{splice-expression}\br + splice-specifier\br + \keyword{template} splice-specifier\br + \keyword{template} splice-specialization-specifier +\end{bnf} + +\pnum +A +\grammarterm{splice-specifier} or \grammarterm{splice-specialization-specifier} +immediately followed by \tcode{::} or preceded by \keyword{typename} +is never interpreted as part of a \grammarterm{splice-expression}. +\begin{example} +\begin{codeblock} +struct S { static constexpr int a = 1; }; +template struct TCls { static constexpr int b = 2; }; + +constexpr int c = [:^^S:]::a; // OK, \tcode{[:\caret\caret S:]} is not an expression +constexpr int d = template [:^^TCls:]::b; // OK, \tcode{template [:\caret\caret TCls:]} is not an expression +template constexpr int e = [:V:]; // OK +constexpr int f = template [:^^e:]<^^S::a>; // OK + +constexpr auto g = typename [:^^int:](42); // OK, \tcode{typename [:\caret\caret int:]} is a \grammarterm{splice-type-specifier} + +constexpr auto h = ^^g; +constexpr auto i = e<[:^^h:]>; // error: unparenthesized \grammarterm{splice-expression} used as template argument +constexpr auto j = e<([:^^h:])>; // OK +\end{codeblock} +\end{example} + +\pnum +For a \grammarterm{splice-expression} of the form \grammarterm{splice-specifier}, +let $S$ be the construct designated by \grammarterm{splice-specifier}. +\begin{itemize} +\item +The expression is ill-formed if $S$ is +\begin{itemize} +\item +a constructor, +\item +a destructor, +\item +an unnamed bit-field, or +\item +a local entity\iref{basic.pre} such that +\begin{itemize} +\item +there is a lambda scope that intervenes +between the expression and the point at which $S$ was introduced and +\item +the expression would be potentially evaluated +if the effect of any enclosing \keyword{typeid} expressions\iref{expr.typeid} +were ignored. +\end{itemize} +\end{itemize} +\item +Otherwise, if $S$ is a function $F$, +the expression denotes an overload set containing all declarations of $F$ +that precede either the expression or +the point immediately following the \grammarterm{class-specifier} of +the outermost class for which the expression is in a complete-class context; +overload resolution is performed\iref{over.match,over.over}. +\item +Otherwise, if $S$ is an object or a non-static data member, +the expression is an lvalue designating $S$. +The expression has the same type as that of $S$, and +is a bit-field if and only if $S$ is a bit-field. +\begin{note} +The implicit transformation +whereby an \grammarterm{id-expression} denoting a non-static member +becomes a class member access\iref{expr.prim.id} +does not apply to a \grammarterm{splice-expression}. +\end{note} +\item +Otherwise, if $S$ is a variable or a structured binding, +$S$ shall either have static or thread storage duration or +shall inhabit a scope enclosing the expression. +The expression is an lvalue referring to the object or function $X$ +associated with or referenced by $S$, +has the same type as that of $S$, and +is a bit-field if and only if $X$ is a bit-field. +\begin{note} +The type of a \grammarterm{splice-expression} +designating a variable or structured binding of reference type +will be adjusted to a non-reference type\iref{expr.type}. +\end{note} +\item +Otherwise, if $S$ is a value or an enumerator, +the expression is a prvalue that computes $S$ and +whose type is the same as that of $S$. +\item +Otherwise, the expression is ill-formed. +\end{itemize} + +\pnum +For a \grammarterm{splice-expression} of +the form \tcode{\keyword{template} \grammarterm{splice-specifier}}, +the \grammarterm{splice-specifier} shall designate a function template $T$ +that is not a constructor template. +The expression denotes an overload set containing all declarations of $T$ +that precede either the expression or +the point immediately following the \grammarterm{class-specifier} of +the outermost class for which the expression is in a complete-class context; +overload resolution is performed. +\begin{note} +During overload resolution, +candidate function templates undergo template argument deduction and +the resulting specializations are considered as candidate functions. +\end{note} + +\pnum +For a \grammarterm{splice-expression} of +the form \tcode{template \grammarterm{splice-specialization-specifier}}, +the \grammarterm{splice-specifier} of +the \grammarterm{splice-specialization-specifier} +shall designate a template $T$. +\begin{itemize} +\item +If $T$ is a function template, +the expression denotes an overload set containing all declarations of $T$ +that precede either the expression or +the point immediately following the \grammarterm{class-specifier} of +the outermost class for which the expression is in a complete-class context; +overload resolution is performed\iref{over.match,over.over}. +\item +Otherwise, if $T$ is a variable template, +let $S$ be the specialization of $T$ corresponding to +the template argument list of the \grammarterm{splice-specialization-specifier}. +The expression is an lvalue referring to +the object associated with $S$ and has the same type as that of $S$. +\item +Otherwise, the expression is ill-formed. +\end{itemize} +\begin{note} +Class members are accessible from any point +when designated by \grammarterm{splice-expression}s\iref{class.access.base}. +A class member access expression\iref{expr.ref} +whose right operand is a \grammarterm{splice-expression} is ill-formed +if the left operand (considered as a pointer) cannot be implicitly converted +to a pointer to the designating class of the right operand. +\end{note} + \rSec1[expr.compound]{Compound expressions} \rSec2[expr.post]{Postfix expressions}% @@ -3446,7 +3677,9 @@ simple-type-specifier braced-init-list\br typename-specifier braced-init-list\br postfix-expression \terminal{.} \opt{\keyword{template}} id-expression\br + postfix-expression \terminal{.} splice-expression\br postfix-expression \terminal{->} \opt{\keyword{template}} id-expression\br + postfix-expression \terminal{->} splice-expression\br postfix-expression \terminal{++}\br postfix-expression \terminal{--}\br \keyword{dynamic_cast} \terminal{<} type-id \terminal{>} \terminal{(} expression \terminal{)}\br @@ -3915,10 +4148,12 @@ A postfix expression followed by a dot \tcode{.} or an arrow \tcode{->}, optionally followed by the keyword \keyword{template}, and then followed by an -\grammarterm{id-expression}, is a postfix expression. +\grammarterm{id-expression} or a \grammarterm{splice-expression}, +is a postfix expression. \begin{note} -If the keyword \keyword{template} is used, -the following unqualified name +If the keyword \keyword{template} is used and +followed by an \grammarterm{id-expression}, +the unqualified name is considered to refer to a template\iref{temp.names}. If a \grammarterm{simple-template-id} results and is followed by a \tcode{::}, the \grammarterm{id-expression} is a \grammarterm{qualified-id}. @@ -3926,16 +4161,16 @@ \pnum \indextext{type!incomplete}% -For the first option (dot), -if the \grammarterm{id-expression} names a static member or an enumerator, +For a dot that is followed by an expression +that designates a static member or an enumerator, the first expression is a discarded-value expression\iref{expr.context}; -if the \grammarterm{id-expression} names a non-static data member, +if the expression after the dot designates a non-static data member, the first expression shall be a glvalue. -For the second option (arrow), the first expression +A postfix expression that is followed by an arrow shall be a prvalue having pointer type. The expression \tcode{E1->E2} is converted to the equivalent form \tcode{(*(E1)).E2}; the remainder of -\ref{expr.ref}~will address only the first option (dot). +\ref{expr.ref}~will address only the form using a dot. \begin{footnote} Note that \tcode{(*(E1))} is an lvalue. @@ -3951,12 +4186,14 @@ \grammarterm{id-expression} denotes a static member. \end{footnote} the result of that evaluation, -together with the \grammarterm{id-expression}, +together with +the \grammarterm{id-expression} or \grammarterm{splice-expression}, determines the result of the entire postfix expression. \pnum Abbreviating -\grammarterm{postfix-expression}\tcode{.}\grammarterm{id-expression} +\grammarterm{postfix-expression}\tcode{.}\grammarterm{id-expression} or +\grammarterm{postfix-expression}\tcode{.}\grammarterm{splice-expression} as \tcode{E1.E2}, \tcode{E1} is called the \defn{object expression}. If the object expression is of scalar type, \tcode{E2} shall name the pseudo-destructor @@ -3981,7 +4218,11 @@ \end{note} \pnum -If \tcode{E2} is a bit-field, \tcode{E1.E2} is a bit-field. The +If \tcode{E2} is a \grammarterm{splice-expression}, +then \tcode{E2} shall designate a member of the type of \tcode{E1}. + +\pnum +If \tcode{E2} designates a bit-field, \tcode{E1.E2} is a bit-field. The type and value category of \tcode{E1.E2} are determined as follows. In the remainder of~\ref{expr.ref}, \cvqual{cq} represents either \keyword{const} or the absence of \keyword{const} and \cvqual{vq} represents @@ -3990,9 +4231,10 @@ in~\ref{basic.type.qualifier}. \pnum -If \tcode{E2} is declared to have type ``reference to \tcode{T}'', then +If \tcode{E2} designates an entity +that is declared to have type ``reference to \tcode{T}'', then \tcode{E1.E2} is an lvalue of type \tcode{T}. -If \tcode{E2} is a static data member, +In that case, if \tcode{E2} designates a static data member, \tcode{E1.E2} designates the object or function to which the reference is bound, otherwise \tcode{E1.E2} designates the object or function to which @@ -4000,11 +4242,11 @@ Otherwise, one of the following rules applies. \begin{itemize} -\item If \tcode{E2} is a static data member and the type of \tcode{E2} +\item If \tcode{E2} designates a static data member and the type of \tcode{E2} is \tcode{T}, then \tcode{E1.E2} is an lvalue; the expression designates the named member of the class. The type of \tcode{E1.E2} is \tcode{T}. -\item If \tcode{E2} is a non-static data member and the type of +\item Otherwise, if \tcode{E2} designates a non-static data member and the type of \tcode{E1} is ``\cvqual{cq1 vq1} \tcode{X}'', and the type of \tcode{E2} is ``\cvqual{cq2 vq2} \tcode{T}'', the expression designates the corresponding member subobject of the object designated by the first expression. If \tcode{E1} @@ -4015,13 +4257,15 @@ is \tcode{volatile}, then \cvqual{vq12} is \keyword{volatile}. Similarly, let the notation \cvqual{cq12} stand for the ``union'' of \cvqual{cq1} and \cvqual{cq2}; that is, if \cvqual{cq1} or \cvqual{cq2} is -\keyword{const}, then \cvqual{cq12} is \keyword{const}. If \tcode{E2} is -declared to be a \keyword{mutable} member, then the type of \tcode{E1.E2} -is ``\cvqual{vq12} \tcode{T}''. If \tcode{E2} is not declared to be a -\keyword{mutable} member, then the type of \tcode{E1.E2} is -``\cvqual{cq12} \cvqual{vq12} \tcode{T}''. - -\item If \tcode{E2} is an overload set, +\keyword{const}, then \cvqual{cq12} is \keyword{const}. +If the entity designated by \tcode{E2} +is declared to be a \keyword{mutable} member, +then the type of \tcode{E1.E2} is ``\cvqual{vq12} \tcode{T}''. +If the entity designated by \tcode{E2} +is not declared to be a \keyword{mutable} member, +then the type of \tcode{E1.E2} is ``\cvqual{cq12} \cvqual{vq12} \tcode{T}''. + +\item If \tcode{E2} denotes an overload set, the expression shall be the (possibly-parenthesized) left-hand operand of a member function call\iref{expr.call}, and function overload resolution\iref{over.match} @@ -4041,26 +4285,30 @@ \end{note} \end{itemize} -\item If \tcode{E2} is a nested type, the expression \tcode{E1.E2} is +\item If \tcode{E2} designates a nested type, the expression \tcode{E1.E2} is ill-formed. -\item If \tcode{E2} is a member enumerator and the type of \tcode{E2} +\item If \tcode{E2} designates a member enumerator and the type of \tcode{E2} is \tcode{T}, the expression \tcode{E1.E2} is a prvalue of type \tcode{T} whose value is the value of the enumerator. + +\item Otherwise, the program is ill-formed. \end{itemize} \pnum -If \tcode{E2} is a non-static member, -the program is ill-formed if the class of which \tcode{E2} is -directly a member is an ambiguous base\iref{class.member.lookup} of -the naming class\iref{class.access.base} of \tcode{E2}. +If \tcode{E2} designates a non-static member +(possibly after overload resolution), +the program is ill-formed if the class of which \tcode{E2} designates +a direct member is an ambiguous base\iref{class.member.lookup} of +the designating class\iref{class.access.base} of \tcode{E2}. \begin{note} The program is also ill-formed if the naming class is an ambiguous base of the class type of the object expression; see~\ref{class.access.base}. \end{note} \pnum -If \tcode{E2} is a non-static member and +If \tcode{E2} designates a non-static member +(possibly after overload resolution) and the result of \tcode{E1} is an object whose type is not similar\iref{conv.qual} to the type of \tcode{E1}, the behavior is undefined. @@ -4907,7 +5155,8 @@ \keyword{alignof} \terminal{(} type-id \terminal{)}\br noexcept-expression\br new-expression\br - delete-expression + delete-expression\br + reflect-expression \end{bnf} \indextext{operator!indirection}% @@ -4963,14 +5212,25 @@ shall be an lvalue of some type \tcode{T}. \begin{itemize} \item -If the operand is a \grammarterm{qualified-id} naming a non-static or variant member \tcode{m} -of some class \tcode{C}, other than an explicit object member function, the result has type ``pointer to member -of class \tcode{C} of type \tcode{T}'' and designates \tcode{C::m}. +If the operand is a \grammarterm{qualified-id} or \grammarterm{splice-expression} +designating a non-static member \tcode{m}, +other than an explicit object member function, +\tcode{m} shall be a direct member of some class \tcode{C} +that is not an anonymous union. +The result has type ``pointer to member of class \tcode{C} of type \tcode{T}'' +and designates \tcode{C::m}. +\begin{note} +A \grammarterm{qualified-id} +that names a member of a namespace-scope anonymous union +is considered to be a class member access expression\iref{expr.prim.id.general} +and cannot be used to form a pointer to member. +\end{note} \item Otherwise, the result has type ``pointer to \tcode{T}'' and points to the designated object\iref{intro.memory} or function\iref{basic.compound}. -If the operand names an explicit object member function\iref{dcl.fct}, -the operand shall be a \grammarterm{qualified-id}. +If the operand designates an explicit object member function\iref{dcl.fct}, +the operand shall be +a \grammarterm{qualified-id} or a \grammarterm{splice-expression}. \begin{note} In particular, taking the address of a variable of type ``\cv{}~\tcode{T}'' yields a pointer of type ``pointer to \cv{}~\tcode{T}''. @@ -4995,8 +5255,9 @@ \pnum A pointer to member is only formed when an explicit \tcode{\&} is used -and its operand is a \grammarterm{qualified-id} not enclosed in -parentheses. +and its operand is +a \grammarterm{qualified-id} or \grammarterm{splice-expression} +not enclosed in parentheses. \begin{note} That is, the expression \tcode{\&(qualified-id)}, where the \grammarterm{qualified-id} is enclosed in parentheses, does not form an @@ -6327,6 +6588,232 @@ the behavior is undefined\iref{new.delete.single,new.delete.array}. \end{note} +\rSec3[expr.reflect]{The reflection operator} + +\begin{bnf} +\nontermdef{reflect-expression}\br + \terminal{\caret\caret} \terminal{::}\br + \terminal{\caret\caret} reflection-name\br + \terminal{\caret\caret} type-id\br + \terminal{\caret\caret} id-expression +\end{bnf} + +\begin{bnf} +\nontermdef{reflection-name}\br + \opt{nested-name-specifier} identifier\br + nested-name-specifier \keyword{template} identifier +\end{bnf} + +\pnum +The unary \tcode{\caret\caret} operator, +called the \defnadj{reflection}{operator}, +yields a prvalue of type \tcode{std::meta::info}\iref{basic.fundamental}. +\begin{note} +This document places no restriction on representing, by reflections, +constructs not described by this document or +using the names of such constructs +as operands of \grammarterm{reflect-expression}s. +\end{note} + +\pnum +The component names of a \grammarterm{reflection-name} +are those of its \grammarterm{nested-name-specifier} (if any) and +its \grammarterm{identifier}. +The terminal name of a \grammarterm{reflection-name} of the form +\grammarterm{nested-name-specifier} \keyword{template} \grammarterm{identifier} +shall denote a template. + +\pnum +A \grammarterm{reflect-expression} is parsed as +the longest possible sequence of tokens +that could syntactically form a \grammarterm{reflect-expression}. +An unparenthesized \grammarterm{reflect-expression} +that represents a template shall not be followed by \tcode{<}. +\begin{example} +\begin{codeblock} +static_assert(std::meta::is_type(^^int())); // \tcode{\caret\caret} applies to the type-id \tcode{int()} + +templatestruct X {}; +consteval bool operator<(std::meta::info, X) { return false; } +consteval void g(std::meta::info r, X xv) { + r == ^^int && true; // error: \tcode{\caret\caret} applies to the \grammarterm{type-id} \tcode{int\&\&} + r == ^^int & true; // error: \tcode{\caret\caret} applies to the type-id \tcode{int\&} + r == (^^int) && true; // OK + r == ^^int &&&& true; // error: \tcode{int \&\&\&\&} is not a valid \grammarterm{type-id} + ^^X < xv; // error: \grammarterm{reflect-expression} that represents a template is followed by \tcode{<} + (^^X) < xv; // OK + ^^X < xv; // OK +} +\end{codeblock} +\end{example} + +\pnum +A \grammarterm{reflect-expression} of the form \tcode{\caret\caret ::} +represents the global namespace. + +\pnum +If a \grammarterm{reflect-expression} $R$ matches +the form \tcode{\caret\caret \grammarterm{reflection-name}}, +it is interpreted as such; +the identifier is looked up and +the representation of $R$ is determined as follows: +\begin{itemize} +\item +If lookup finds a declaration +that replaced a \grammarterm{using-declarator} +during a single search\iref{basic.lookup.general,namespace.udecl}, +$R$ is ill-formed. +\begin{example} +\begin{codeblock} +struct A { struct S {}; }; +struct B : A { using A::S; }; +constexpr std::meta::info r1 = ^^B::S; // error: \tcode{A::S} found through \grammarterm{using-declarator} + +struct C : virtual B { struct S {}; }; +struct D : virtual B, C {}; +D::S s; // OK, names \tcode{C::S} per \ref{class.member.lookup} +constexpr std::meta::info r2 = ^^D::S; // OK, result \tcode{C::S} not found through \grammarterm{using-declarator} +\end{codeblock} +\end{example} +\item +Otherwise, if lookup finds a namespace alias\iref{namespace.alias}, +$R$ represents that namespace alias. +For any other \grammarterm{namespace-name}, +$R$ represents the denoted namespace. +\item +Otherwise, if lookup finds a namespace\iref{namespace.alias}, +$R$ represents that namespace. +\item +Otherwise, if lookup finds a concept\iref{temp.concept}, +$R$ represents the denoted concept. +\item +Otherwise, if lookup finds a template\iref{temp.names}, +the representation of $R$ is determined as follows: +\begin{itemize} +\item +If lookup finds an injected-class-name\iref{class.pre}, then: +\begin{itemize} +\item +If the \grammarterm{reflection-name} is of the form +\tcode{\grammarterm{nested-name-specifier} \keyword{template} \grammarterm{identifier}}, +then $R$ represents the class template named by the injected-class-name. +\item +Otherwise, the injected-class-name shall be unambiguous +when considered as a \grammarterm{type-name} and +$R$ represents the class template specialization so named. +\end{itemize} +\item +Otherwise, if lookup finds an overload set, +that overload set shall contain only +declarations of a unique function template F; +$R$ represents F. +\item +Otherwise, if lookup finds +a class template, variable template, or alias template, +$R$ represents that template. +\begin{note} +Lookup never finds a partial or explicit specialization. +\end{note} +\end{itemize} +\item +Otherwise, if lookup finds a type alias $A$, +$R$ represents the underlying entity of $A$ +if $A$ was introduced by the declaration of a template parameter; +otherwise, $R$ represents $A$. +\item +Otherwise, if lookup finds a class or an enumeration, +$R$ represents the denoted type. +\item +Otherwise, if lookup finds a class member of an anonymous union\iref{class.union.anon}, $R$ represents that class member. +\item +Otherwise, +the \grammarterm{reflection-name} shall be an \grammarterm{id-expression} \tcode{I} +and $R$ is \tcode{\caret\caret I} (see below). +\end{itemize} + +\pnum +A \grammarterm{reflect-expression} $R$ of the form +\tcode{\caret\caret \grammarterm{type-id}} +represents an entity determined as follows: +\begin{itemize} +\item +If the \grammarterm{type-id} designates +a placeholder type\iref{dcl.spec.auto.general}, +$R$ is ill-formed. +\item +Otherwise, if the \grammarterm{type-id} names a type alias +that is a specialization of an alias template\iref{temp.alias}, +$R$ represents that type alias. +\item +Otherwise, $R$ represents the type denoted by the \grammarterm{type-id}. +\end{itemize} + +\pnum +A \grammarterm{reflect-expression} $R$ of the form +\tcode{\caret\caret \grammarterm{id-expression}} +represents an entity determined as follows: +\begin{itemize} +\item +If the \grammarterm{id-expression} denotes +\begin{itemize} +\item +a variable declared by +an \grammarterm{init-capture}\iref{expr.prim.lambda.capture}, +\item +a function-local predefined variable\iref{dcl.fct.def.general}, +\item +a local parameter introduced by +a \grammarterm{requires-expression}\iref{expr.prim.req}, or +\item +a local entity $E$\iref{basic.pre} for which a lambda scope intervenes +between the point at which $E$ was introduced and $R$, +then $R$ is ill-formed. +\end{itemize} +\item +Otherwise, if the \grammarterm{id-expression} denotes an overload set $S$, +overload resolution for the expression \tcode{\&S} with no target +shall select a unique function\iref{over.over}; +$R$ represents that function. +\item +Otherwise, if the \grammarterm{id-expression} denotes +a variable, structured binding, enumerator, or non-static data member, +$R$ represents that entity. +\item +Otherwise, $R$ is ill-formed. +\begin{note} +This includes \grammarterm{unqualified-id}s +that name a constant template parameter and +\grammarterm{pack-index-expression}s. +\end{note} +\end{itemize} +The \grammarterm{id-expression} of +a \grammarterm{reflect-expression} is an unevaluated operand\iref{expr.context}. +\begin{example} +\begin{codeblock} +template void fn() requires (^^T != ^^int); +template void fn() requires (^^T == ^^int); +template void fn() requires (sizeof(T) == sizeof(int)); + +constexpr std::meta::info a = ^^fn; // OK +constexpr std::meta::info b = ^^fn; // error: ambiguous + +constexpr std::meta::info c = ^^std::vector; // OK + +template +struct S { + static constexpr std::meta::info r = ^^T; + using type = T; +}; +static_assert(S::r == ^^int); +static_assert(^^S::type != ^^int); + +typedef struct X {} Y; +typedef struct Z {} Z; +constexpr std::meta::info e = ^^Y; // OK, represents the type alias \tcode{Y} +constexpr std::meta::info f = ^^Z; // OK, represents the type alias \tcode{Z}, not the type\iref{basic.lookup.general} +\end{codeblock} +\end{example} + \rSec2[expr.cast]{Explicit type conversion (cast notation)}% \indextext{expression!cast|(} @@ -7113,6 +7600,19 @@ Two operands of type \tcode{std::nullptr_t} or one operand of type \tcode{std::nullptr_t} and the other a null pointer constant compare equal. +\pnum +If both operands are of type \tcode{std::meta::info}, +they compare equal if both operands +\begin{itemize} +\item are null reflection values, +\item represent values that are template-argument-equivalent\iref{temp.type}, +\item represent the same object, +\item represent the same entity, +\item represent the same direct base class relationship, or +\item represent equal data member descriptions\iref{class.mem.general}, +\end{itemize} +and they compare unequal otherwise. + \pnum If two operands compare equal, the result is \keyword{true} for the \tcode{==} operator and \keyword{false} for the \tcode{!=} operator. If two operands @@ -8158,6 +8658,11 @@ that would throw an exception where no definition of the exception type is reachable; +\item +an expression that would produce an injected declaration (see below), +unless $E$ is the corresponding expression of +a \grammarterm{consteval-block-declaration}\iref{dcl.pre}; + \item an \grammarterm{asm-declaration}\iref{dcl.asm}; @@ -8295,7 +8800,8 @@ \pnum During the evaluation of an expression $E$ as a core constant expression, -all \grammarterm{id-expression}s and uses of \tcode{*\keyword{this}} +all \grammarterm{id-expression}s, \grammarterm{splice-expression}s, and +uses of \tcode{*\keyword{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 @@ -8448,8 +8954,30 @@ \pnum A \defnadj{constant}{expression} is either -a glvalue core constant expression that refers to -an object or a non-immediate function, or +\begin{itemize} +\item +a glvalue core constant expression $E$ for which +\begin{itemize} +\item +$E$ refers to a non-immediate function +\item +$E$ designates an object \tcode{o}, and +if the complete object of \tcode{o} is of consteval-only type then so is $E$, +\begin{example} +\begin{codeblock} +struct Base { }; +struct Derived : Base { std::meta::info r; }; + +consteval const Base& fn(const Derived& derived) { return derived; } + +constexpr Derived obj{.r=^^::}; // OK +constexpr const Derived& d = obj; // OK +constexpr const Base& b = fn(obj); // error: not a constant expression because \tcode{Derived} is a consteval-only type but \tcode{Base} is not. +\end{codeblock} +\end{example} +\end{itemize} +or +\item a prvalue core constant expression whose result object\iref{basic.lval} satisfies the following constraints: \begin{itemize} @@ -8461,7 +8989,21 @@ no constituent value of pointer type is a pointer to an immediate function or an invalid pointer value\iref{basic.compound}, and \item -no constituent value of pointer-to-member type designates an immediate function. +no constituent value of pointer-to-member type designates an immediate function, and +\item +unless the value is of consteval-only type, +\begin{itemize} +\item +no constituent value of pointer-to-member type points to +a direct member of a consteval-only class type +\item +no constituent value of pointer type points to or past an object +whose complete object is of consteval-only type, and +\item +no constituent reference refers to an object +whose complete object is of consteval-only type. +\end{itemize} +\end{itemize} \end{itemize} \begin{note} A glvalue core constant expression @@ -8537,17 +9079,17 @@ \indexdefn{conversion!immediate-escalating}% \indexdefn{immediate-escalating!expression|see{expression, immediate-escalating}}% \indexdefn{immediate-escalating!conversion|see{conversion, immediate-escalating}}% -An expression or conversion is \defn{immediate-escalating} -if it is not initially in an immediate function context -and it is either +A potentially-evaluated expression or conversion is \defn{immediate-escalating} +if it is neither initially in an immediate function context +nor a subexpression of an immediate invocation, and \begin{itemize} \item -a potentially-evaluated \grammarterm{id-expression} -that denotes an immediate function -that is not a subexpression of an immediate invocation, or +it is an \grammarterm{id-expression} or \grammarterm{splice-expression} +that designates an immediate function, \item -an immediate invocation that is not a constant expression -and is not a subexpression of an immediate invocation. +it is an immediate invocation that is not a constant expression, or +\item +it is of consteval-only type\iref{basic.types.general}. \end{itemize} \pnum @@ -8568,14 +9110,18 @@ in an immediate-escalating function. \pnum -An \defnadj{immediate}{function} is a function or constructor that is +An \defnadj{immediate}{function} is a function or constructor that is either \begin{itemize} \item declared with the \keyword{consteval} specifier, or \item an immediate-escalating function \tcode{\placeholder{F}} -whose function body contains an immediate-escalating expression \tcode{\placeholder{E}} -such that \tcode{\placeholder{E}}'s innermost enclosing non-block scope +whose function body contains either +\begin{itemize} +\item an immediate-escalating expression or +\item a definition of a non-constexpr variable with consteval-only type +\end{itemize} +whose innermost enclosing non-block scope is \tcode{\placeholder{F}}'s function parameter scope. \begin{tailnote} Default member initializers used to initialize @@ -8649,7 +9195,6 @@ \end{codeblock} \end{example} - \pnum An expression or conversion is \defn{manifestly constant-evaluated} if it is: @@ -8697,6 +9242,143 @@ is evaluated even in an unevaluated operand\iref{term.unevaluated.operand}. \end{note} +\pnum +The evaluation of an expression can introduce +one or more \defnadjx{injected}{declarations}{declaration}. +The evaluation is said to \defn{produce} the declarations. +\begin{note} +An invocation of +the library function template \tcode{std::meta::define_aggregate} +produces an injected declaration\iref{meta.reflection.define.aggregate}. +\end{note} +Each such declaration has +\begin{itemize} +\item +an associated \defnadj{synthesized}{point}, +which follows the last non-synthesized program point +in the translation unit containing that declaration, and +\item +an associated \defnadj{characteristic}{sequence} of values. +\end{itemize} +\begin{note} +Special rules concerning reachability +apply to synthesized points\iref{module.reach}. +\end{note} +\begin{note} +The program is ill-formed +if injected declarations with different characteristic sequences +define the same entity in different translation units\iref{basic.def.odr}. +\end{note} + +\pnum +A member of an entity defined by an injected declaration +shall not have a name reserved to the implementation\iref{lex.name}; +no diagnostic is required. + +\pnum +Let $C$ be a \grammarterm{consteval-block-declaration}, +the evaluation of whose corresponding expression +produces an injected declaration for an entity $E$. +The program is ill-formed if either +\begin{itemize} +\item +$C$ is enclosed by a scope associated with $E$ or +\item +letting $P$ be a point whose immediate scope is that to which $E$ belongs, +there is a function parameter scope or class scope +that encloses exactly one of $C$ or $P$. +\end{itemize} +\begin{example} +\begin{codeblock} +struct S0 { + consteval { + std::meta::define_aggregate(^^S0, {}); // error: scope associated with S0 encloses the consteval block + } +}; + +struct S1; +consteval { std::meta::define_aggregate(^^S1, {}); } // OK + +template consteval void tfn1() { + std::meta::define_aggregate(R, {}); +} + +struct S2; +consteval { tfn1<^^S2>(); } // OK + +template consteval void tfn2() { + consteval { std::meta::define_aggregate(R, {}); } +} + +struct S3; +consteval { tfn2<^^S3>(); } + // error: function parameter scope of \tcode{tfn2<\caret\caret S3>} intervenes between the declaration of \tcode{S3} + // and the consteval block that produces the injected declaration + +template struct TCls { + struct S4; + static void sfn() requires ([] { + consteval { std::meta::define_aggregate(^^S4, {}); } + return true; + }()) { } +}; + +consteval { TCls::sfn(); } // error: \tcode{TCls::S4} is not enclosed by \grammarterm{requires-clause} lambda + +struct S5; +struct Cls { + consteval { std::meta::define_aggregate(^^S5, {}); } // error: \tcode{S5} is not enclosed by class \tcode{Cls} +}; + +struct S6; +consteval { // \#1 + struct S7; // local class + std::meta::define_aggregate(^^S7, {}); + // error: consteval block \#1 does not enclose itself, but encloses \tcode{S7} + consteval { // \#2 + std::meta::define_aggregate(^^S6, {}); + // error: consteval block \#1 encloses consteval block \#2 but not \tcode{S6} + std::meta::define_aggregate(^^S7, {}); // OK, consteval block \#1 encloses both \#2 and \tcode{S7} + } +} +\end{codeblock} +\end{example} + +\pnum +The \defn{evaluation context} is a set of program points +that determines the behavior of certain functions +used for reflection\iref{meta.reflection}. +During the evaluation $V$ of an expression $E$ as a core constant expression, +the evaluation context of an evaluation $X$\iref{intro.execution} +consists of the following points: +\begin{itemize} +\item +The program point $\textit{EVAL-PT}(L)$, +where $L$ is the point at which $E$ appears, and +where $\textit{EVAL-PT}(P)$, for a point $P$, +is a point $R$ determined as follows: +\begin{itemize} +\item +If a potentially-evaluated subexpression\iref{intro.execution} of +a default member initializer $I$ appears at $P$, and +a (possibly aggregate) initialization during $V$ is using $I$, +then $R$ is $\textit{EVAL-PT}(Q)$ +where $Q$ is the point at which that initialization appears. +\item +Otherwise, if a potentially-evaluated subexpression of +a default argument\iref{dcl.fct.default} appears at $P$, and +an invocation of a function\iref{expr.call} during $V$ +is using that default argument, +then $R$ is $\textit{EVAL-PT}(Q)$ +where $Q$ is the point at which that invocation appears. +\item +Otherwise, $R$ is $P$. +\end{itemize} +\item +Each synthesized point corresponding to an injected declaration produced by +any evaluation sequenced before $X$\iref{intro.execution}. +\end{itemize} + \pnum \indextext{expression!potentially constant evaluated}% An expression or conversion is \defn{potentially constant evaluated} diff --git a/source/lex.tex b/source/lex.tex index eb4f060959..4cc651a14d 100644 --- a/source/lex.tex +++ b/source/lex.tex @@ -210,43 +210,84 @@ only, and does not specify any particular implementation. \end{note} -\item Translated translation units and instantiation units are combined -as follows: -\begin{note} -Some or all of these can be supplied from a -library. -\end{note} -Each translated translation unit is examined to -produce a list of required instantiations. +While the tokens constituting translation units +are being analyzed and translated, +required instantiations are performed. \begin{note} This can include instantiations which have been explicitly requested\iref{temp.explicit}. \end{note} -The definitions of the -required templates are located. It is \impldef{whether source of translation units must -be available to locate template definitions} whether the -source of the translation units containing these definitions is required -to be available. -\begin{note} -An implementation can choose to encode sufficient -information into the translated translation unit so as to ensure the -source is not required here. -\end{note} -All the required instantiations -are performed to produce -\defn{instantiation units}. + +The contexts from which instantiations may be performed +are determined by their respective points of instantiation\iref{temp.point}. + \begin{note} -These are similar -to translated translation units, but contain no references to -uninstantiated templates and no template definitions. +Other requirements in this document can further constrain +the context from which an instantiation can be performed. +For example, a constexpr function template specialization +might have a point of instantation at the end of a translation unit, +but its use in certain constant expressions could require +that it be instantiated at an earlier point\iref{temp.inst}. \end{note} -The -program is ill-formed if any instantiation fails. + +Each instantiation results in new program constructs. +The program is ill-formed if any instantiation fails. + +During the analysis and translation of tokens, +certain expressions are evaluated\iref{expr.const}. +Constructs appearing at a program point $P$ are analyzed +in a context where each side effect of evaluating an expression $E$ +as a full-expression is complete if and only if +\begin{itemize} +\item +$E$ is the expression corresponding to +a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, and +\item +either that \grammarterm{consteval-block-declaration} or +the template definition from which it is instantiated +is reachable from\iref{module.reach} +\begin{itemize} +\item +$P$, or +\item +the point immediately following +the \grammarterm{class-specifier} of the outermost class +for which $P$ is in a complete-class context\iref{class.mem.general}. +\end{itemize} +\end{itemize} +\begin{example} +\begin{codeblock} +class S { + class Incomplete; + + class Inner { + void fn() { + /* P1 */ Incomplete i; // OK + } + }; /* P2 */ + + consteval { + define_aggregate(^^Incomplete, {}); + } +}; /* P3 */ +\end{codeblock} +Constructs at P1 are analyzed in a context +where the side effect of the call to \tcode{define_aggregate} is evaluated +because +\begin{itemize} +\item +$E$ is the expression corresponding to a consteval block, and +\item +P1 is in a complete-class context of \tcode{S} and +the consteval block is reachable from P3. +\end{itemize} +\end{example} \item \indextext{linking}% -All external entity references are resolved. Library +Translated translation units are combined, and +all external entity references are resolved. Library components are linked to satisfy external references to entities not defined in the current translation. All such translator output is collected into a program image which contains information @@ -584,6 +625,16 @@ is neither \tcode{:} nor \tcode{>}, the \tcode{<} is treated as a preprocessing token by itself and not as the first character of the alternative token \tcode{<:}. +\item +Otherwise, if the next three characters are \tcode{[::} and +the subsequent character is not \tcode{:}, or +if the next three characters are \tcode{[:>}, +the \tcode{[} is treated as a preprocessing token by itself and +not as the first character of the preprocessing token \tcode{[:}. +\begin{note} +The tokens \tcode{[:} and \tcode{:]} cannot be composed from digraphs. +\end{note} + \item Otherwise, the next preprocessing token is the longest sequence of characters that could constitute a preprocessing token, even if that @@ -750,9 +801,9 @@ \begin{bnf} \microtypesetup{protrusion=false} \nontermdef{operator-or-punctuator} \textnormal{one of}\br - \terminal{\{ \ \ \ \ \ \ \ \} \ \ \ \ \ \ \ [ \ \ \ \ \ \ \ ] \ \ \ \ \ \ \ ( \ \ \ \ \ \ \ )}\br + \terminal{\{ \ \ \ \ \ \ \ \} \ \ \ \ \ \ \ [ \ \ \ \ \ \ \ ] \ \ \ \ \ \ \ ( \ \ \ \ \ \ \ ) \ \ \ \ \ \ \ [: \ \ \ \ \ \ :]}\br \terminal{<\% \ \ \ \ \ \ \%> \ \ \ \ \ \ <: \ \ \ \ \ \ :> \ \ \ \ \ \ ; \ \ \ \ \ \ \ : \ \ \ \ \ \ \ ...}\br - \terminal{? \ \ \ \ \ \ \ :: \ \ \ \ \ \ . \ \ \ \ \ \ \ .* \ \ \ \ \ \ -> \ \ \ \ \ \ ->* \ \ \ \ \ \~}\br + \terminal{? \ \ \ \ \ \ \ :: \ \ \ \ \ \ . \ \ \ \ \ \ \ .* \ \ \ \ \ \ -> \ \ \ \ \ \ ->* \ \ \ \ \ \caret{}\caret{} \ \ \ \ \ \ \~}\br \terminal{! \ \ \ \ \ \ \ + \ \ \ \ \ \ \ - \ \ \ \ \ \ \ * \ \ \ \ \ \ \ / \ \ \ \ \ \ \ \% \ \ \ \ \ \ \ \caret{} \ \ \ \ \ \ \ \& \ \ \ \ \ \ \ |}\br \terminal{= \ \ \ \ \ \ \ += \ \ \ \ \ \ -= \ \ \ \ \ \ *= \ \ \ \ \ \ /= \ \ \ \ \ \ \%= \ \ \ \ \ \ \caret{}= \ \ \ \ \ \ \&= \ \ \ \ \ \ |=}\br \terminal{== \ \ \ \ \ \ != \ \ \ \ \ \ < \ \ \ \ \ \ \ > \ \ \ \ \ \ \ <= \ \ \ \ \ \ >= \ \ \ \ \ \ <=> \ \ \ \ \ \&\& \ \ \ \ \ \ ||}\br diff --git a/source/lib-intro.tex b/source/lib-intro.tex index ea7a21b782..4816083dd2 100644 --- a/source/lib-intro.tex +++ b/source/lib-intro.tex @@ -368,6 +368,11 @@ and also define the function as deleted. \end{example} +\item +\constantwhen +the conditions that are required for a call to the function +to be a constant subexpression\iref{defns.const.subexpr}. + \item \expects conditions that the function assumes to hold whenever it is called; @@ -454,6 +459,7 @@ Next, the semantics of the code sequence are determined by the \Fundescx{Constraints}, \Fundescx{Mandates}, +\Fundescx{Constant When}, \Fundescx{Preconditions}, \Fundescx{Hardened preconditions}, \Fundescx{Effects}, @@ -1223,8 +1229,8 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\tcode{} \\ \columnbreak +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1248,8 +1254,9 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ -\tcode{} \\ \columnbreak +\tcode{} \\ +\tcode{} \\ \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -1271,9 +1278,9 @@ \tcode{} \\ \tcode{} \\ \tcode{} \\ +\columnbreak \tcode{} \\ \tcode{} \\ -\columnbreak \tcode{} \\ \tcode{} \\ \tcode{} \\ @@ -3082,6 +3089,26 @@ either a standard library non-static member function\iref{member.functions} or an instantiation of a standard library member function template. +\pnum +Let \tcode{\placeholder{F}} denote +a standard library function or function template. +Unless \tcode{\placeholder{F}} is designated an addressable function, +it is unspecified if or how +a reflection value designating the associated entity can be formed. +%FIXME: Why is this not an example, but a note that begins with "For example"? +\begin{note} +For example, it is possible that \tcode{std::meta::members_of} +will not return reflections of standard library functions +that an implementation handles through an extra-linguistic mechanism. +\end{note} + +\pnum +Let \tcode{\placeholder{F}} denote +a standard library class or class template specialization. +It is unspecified if or how +a reflection value can be formed to any private member of \tcode{\placeholder{F}}, +or what the names of such members may be. + \pnum A translation unit shall not declare namespace \tcode{std} to be an inline namespace\iref{namespace.def}. diff --git a/source/macros.tex b/source/macros.tex index ec88684fcd..918bfdf3a5 100644 --- a/source/macros.tex +++ b/source/macros.tex @@ -363,6 +363,7 @@ \newcommand{\required}{\Fundesc{Required behavior}} \newcommand{\constraints}{\Fundesc{Constraints}} \newcommand{\mandates}{\Fundesc{Mandates}} +\newcommand{\constantwhen}{\Fundesc{Constant When}} \newcommand{\expects}{\Fundesc{Preconditions}} \newcommand{\hardexpects}{\Fundesc{Hardened preconditions}} \newcommand{\effects}{\Fundesc{Effects}} @@ -465,6 +466,10 @@ \newcommand{\unspecuniqtype}{\UNSP{unspecified unique type}} \newcommand{\unspecalloctype}{\UNSP{unspecified allocator type}} +%% Convenience macro for double carets in expressions, +%% particularly within \tcode. +\newcommand{\reflexpr}[1]{\caret\caret#1} + %% Manual insertion of italic corrections, for aligning in the presence %% of the above annotations. \newlength{\itcorrwidth} diff --git a/source/meta.tex b/source/meta.tex index cb8e6e7ade..06ea697150 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -179,6 +179,7 @@ template struct is_union; template struct is_class; template struct is_function; + template struct is_reflection; // \ref{meta.unary.comp}, composite type categories template struct is_reference; @@ -201,6 +202,7 @@ template struct is_abstract; template struct is_final; template struct is_aggregate; + template struct is_consteval_only; template struct is_signed; template struct is_unsigned; @@ -410,6 +412,8 @@ constexpr bool @\libglobal{is_class_v}@ = is_class::value; template constexpr bool @\libglobal{is_function_v}@ = is_function::value; + template + constexpr bool @\libglobal{is_reflection_v}@ = is_reflection::value; // \ref{meta.unary.comp}, composite type categories template @@ -448,6 +452,8 @@ constexpr bool @\libglobal{is_final_v}@ = is_final::value; template constexpr bool @\libglobal{is_aggregate_v}@ = is_aggregate::value; +template + constexpr bool @\libglobal{is_consteval_only_v}@ = is_consteval_only::value; template constexpr bool @\libglobal{is_signed_v}@ = is_signed::value; template @@ -723,7 +729,11 @@ \indexlibraryglobal{is_function}% \tcode{template}\br \tcode{struct is_function;} & -\tcode{T} is a function type\iref{basic.compound} & \\ +\tcode{T} is a function type\iref{basic.compound} & \\ \rowsep +\indexlibraryglobal{is_reflection}% +\tcode{template}\br + \tcode{struct is_reflection;} & +\tcode{T} is \tcode{std::meta::info} & \\ \end{libreqtab3e} \rSec3[meta.unary.comp]{Composite type traits} @@ -905,6 +915,12 @@ \tcode{T} is an aggregate type\iref{dcl.init.aggr} & \tcode{T} shall be an array type, a complete type, or \cv~\keyword{void}. \\ \rowsep +\indexlibraryglobal{is_consteval_only}% +\tcode{template}\br + \tcode{struct is_consteval_only;} & + \tcode{T} is consteval-only\iref{basic.types.general} & + \tcode{remove_all_extents_t} shall be a complete type or \cv~\keyword{void}. \\ \rowsep + \indexlibrary{\idxcode{is_signed}!class}% \tcode{template}\br \tcode{struct is_signed;} & @@ -2554,6 +2570,3461 @@ \end{example} \end{itemdescr} +%FIXME: The paper doesn't actually specify that this subclause should exist, +%but I read between the lines and took editorial liberty to create it. +\rSec1[meta.reflection]{Reflection} + +%FIXME: Jens said this should be [meta.syn] +\rSec2[meta.reflection.synop]{General} +\indexheader{meta}% + +\begin{codeblock} +%FIXME: I see the same in with a // see \ref{initializer.list.syn} comment +#include + +namespace std::meta { + using info = decltype(^^::); + + // \ref{meta.reflection.operators}, operator representations + enum class operators { + @\seebelow@; + }; + using enum operators; + consteval operators operator_of(info r); + consteval string_view symbol_of(operators op); + consteval u8string_view u8symbol_of(operators op); + + // \ref{meta.reflection.names}, reflection names and locations + consteval bool has_identifier(info r); + + consteval string_view identifier_of(info r); + consteval u8string_view u8identifier_of(info r); + + consteval string_view display_string_of(info r); + consteval u8string_view u8display_string_of(info r); + + consteval source_location source_location_of(info r); + + // \ref{meta.reflection.queries}, reflection queries + consteval info type_of(info r); + consteval info object_of(info r); + consteval info constant_of(info r); + + consteval bool is_public(info r); + consteval bool is_protected(info r); + consteval bool is_private(info r); + + consteval bool is_virtual(info r); + consteval bool is_pure_virtual(info r); + consteval bool is_override(info r); + consteval bool is_final(info r); + + consteval bool is_deleted(info r); + consteval bool is_defaulted(info r); + consteval bool is_user_provided(info r); + consteval bool is_user_declared(info r); + consteval bool is_explicit(info r); + consteval bool is_noexcept(info r); + + consteval bool is_bit_field(info r); + consteval bool is_enumerator(info r); + + consteval bool is_const(info r); + consteval bool is_volatile(info r); + consteval bool is_mutable_member(info r); + consteval bool is_lvalue_reference_qualified(info r); + consteval bool is_rvalue_reference_qualified(info r); + + consteval bool has_static_storage_duration(info r); + consteval bool has_thread_storage_duration(info r); + consteval bool has_automatic_storage_duration(info r); + + consteval bool has_internal_linkage(info r); + consteval bool has_module_linkage(info r); + consteval bool has_external_linkage(info r); + consteval bool has_c_language_linkage(info r); + consteval bool has_linkage(info r); + + consteval bool is_complete_type(info r); + consteval bool is_enumerable_type(info r); + + consteval bool is_variable(info r); + consteval bool is_type(info r); + consteval bool is_namespace(info r); + consteval bool is_type_alias(info r); + consteval bool is_namespace_alias(info r); + + consteval bool is_function(info r); + consteval bool is_conversion_function(info r); + consteval bool is_operator_function(info r); + consteval bool is_literal_operator(info r); + consteval bool is_special_member_function(info r); + consteval bool is_constructor(info r); + consteval bool is_default_constructor(info r); + consteval bool is_copy_constructor(info r); + consteval bool is_move_constructor(info r); + consteval bool is_assignment(info r); + consteval bool is_copy_assignment(info r); + consteval bool is_move_assignment(info r); + consteval bool is_destructor(info r); + + consteval bool is_template(info r); + consteval bool is_function_template(info r); + consteval bool is_variable_template(info r); + consteval bool is_class_template(info r); + consteval bool is_alias_template(info r); + consteval bool is_conversion_function_template(info r); + consteval bool is_operator_function_template(info r); + consteval bool is_literal_operator_template(info r); + consteval bool is_constructor_template(info r); + consteval bool is_concept(info r); + + consteval bool is_value(info r); + consteval bool is_object(info r); + + consteval bool is_structured_binding(info r); + + consteval bool is_class_member(info r); + consteval bool is_namespace_member(info r); + consteval bool is_nonstatic_data_member(info r); + consteval bool is_static_member(info r); + consteval bool is_base(info r); + + consteval bool has_default_member_initializer(info r); + + consteval bool has_parent(info r); + consteval info parent_of(info r); + + consteval info dealias(info r); + + consteval bool has_template_arguments(info r); + consteval info template_of(info r); + consteval vector template_arguments_of(info r); + + // \ref{meta.reflection.access.context}, access control context + struct access_context; + + // \ref{meta.reflection.access.queries}, member accessessibility queries + consteval bool is_accessible(info r, access_context ctx); + consteval bool has_inaccessible_nonstatic_data_members(info r, access_context ctx); + consteval bool has_inaccessible_bases(info r, access_context ctx); + + // \ref{meta.reflection.member.queries}, reflection member queries + consteval vector members_of(info r, access_context ctx); + consteval vector bases_of(info type, access_context ctx); + consteval vector static_data_members_of(info type, access_context ctx); + consteval vector nonstatic_data_members_of(info type, access_context ctx); + consteval vector enumerators_of(info type_enum); + + // \ref{meta.reflection.layout}, reflection layout queries + struct member_offset; + consteval member_offset offset_of(info r); + consteval size_t size_of(info r); + consteval size_t alignment_of(info r); + consteval size_t bit_size_of(info r); + + // \ref{meta.reflection.extract}, value extraction + template + consteval T extract(info); + + // \ref{meta.reflection.substitute}, reflection substitution + template + concept reflection_range = @\seebelow@; + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool can_substitute(info templ, R&& arguments); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info substitute(info templ, R&& arguments); + + // \ref{meta.reflection.result}, expression result reflection + template + consteval info reflect_constant(const T& value); + template + consteval info reflect_object(T& object); + template + consteval info reflect_function(T& fn); + + // \ref{meta.reflection.define.aggregate}, class definition generation + struct data_member_options; + consteval info data_member_spec(info type, data_member_options options); + consteval bool is_data_member_spec(info r); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info define_aggregate(info type_class, R&&); + + // associated with \ref{meta.unary.cat}, primary type categories + consteval bool is_void_type(info type); + consteval bool is_null_pointer_type(info type); + consteval bool is_integral_type(info type); + consteval bool is_floating_point_type(info type); + consteval bool is_array_type(info type); + consteval bool is_pointer_type(info type); + consteval bool is_lvalue_reference_type(info type); + consteval bool is_rvalue_reference_type(info type); + consteval bool is_member_object_pointer_type(info type); + consteval bool is_member_function_pointer_type(info type); + consteval bool is_enum_type(info type); + consteval bool is_union_type(info type); + consteval bool is_class_type(info type); + consteval bool is_function_type(info type); + consteval bool is_reflection_type(info type); + + // associated with \ref{meta.unary.comp}, composite type categories + consteval bool is_reference_type(info type); + consteval bool is_arithmetic_type(info type); + consteval bool is_fundamental_type(info type); + consteval bool is_object_type(info type); + consteval bool is_scalar_type(info type); + consteval bool is_compound_type(info type); + consteval bool is_member_pointer_type(info type); + + // associated with \ref{meta.unary.prop}, type properties + consteval bool is_const_type(info type); + consteval bool is_volatile_type(info type); + consteval bool is_trivially_copyable_type(info type); + consteval bool is_trivially_relocatable_type(info type); + consteval bool is_replaceable_type(info type); + consteval bool is_standard_layout_type(info type); + consteval bool is_empty_type(info type); + consteval bool is_polymorphic_type(info type); + consteval bool is_abstract_type(info type); + consteval bool is_final_type(info type); + consteval bool is_aggregate_type(info type); + consteval bool is_consteval_only_type(info type); + consteval bool is_signed_type(info type); + consteval bool is_unsigned_type(info type); + consteval bool is_bounded_array_type(info type); + consteval bool is_unbounded_array_type(info type); + consteval bool is_scoped_enum_type(info type); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_constructible_type(info type, R&& type_args); + consteval bool is_default_constructible_type(info type); + consteval bool is_copy_constructible_type(info type); + consteval bool is_move_constructible_type(info type); + + consteval bool is_assignable_type(info type_dst, info type_src); + consteval bool is_copy_assignable_type(info type); + consteval bool is_move_assignable_type(info type); + + consteval bool is_swappable_with_type(info type_dst, info type_src); + consteval bool is_swappable_type(info type); + + consteval bool is_destructible_type(info type); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_trivially_constructible_type(info type, R&& type_args); + consteval bool is_trivially_default_constructible_type(info type); + consteval bool is_trivially_copy_constructible_type(info type); + consteval bool is_trivially_move_constructible_type(info type); + + consteval bool is_trivially_assignable_type(info type_dst, info type_src); + consteval bool is_trivially_copy_assignable_type(info type); + consteval bool is_trivially_move_assignable_type(info type); + consteval bool is_trivially_destructible_type(info type); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_nothrow_constructible_type(info type, R&& type_args); + consteval bool is_nothrow_default_constructible_type(info type); + consteval bool is_nothrow_copy_constructible_type(info type); + consteval bool is_nothrow_move_constructible_type(info type); + + consteval bool is_nothrow_assignable_type(info type_dst, info type_src); + consteval bool is_nothrow_copy_assignable_type(info type); + consteval bool is_nothrow_move_assignable_type(info type); + + consteval bool is_nothrow_swappable_with_type(info type_dst, info type_src); + consteval bool is_nothrow_swappable_type(info type); + + consteval bool is_nothrow_destructible_type(info type); + consteval bool is_nothrow_relocatable_type(info type); + + consteval bool is_implicit_lifetime_type(info type); + + consteval bool has_virtual_destructor(info type); + + consteval bool has_unique_object_representations(info type); + + consteval bool reference_constructs_from_temporary(info type_dst, info type_src); + consteval bool reference_converts_from_temporary(info type_dst, info type_src); + + // associated with \ref{meta.unary.prop.query}, type property queries + consteval size_t rank(info type); + consteval size_t extent(info type, unsigned i = 0); + + // associated with \ref{meta.rel}, type relations + consteval bool is_same_type(info type1, info type2); + consteval bool is_base_of_type(info type_base, info type_derived); + consteval bool is_virtual_base_of_type(info type_base, info type_derived); + consteval bool is_convertible_type(info type_src, info type_dst); + consteval bool is_nothrow_convertible_type(info type_src, info type_dst); + consteval bool is_layout_compatible_type(info type1, info type2); + consteval bool is_pointer_interconvertible_base_of_type(info type_base, info type_derived); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_invocable_type(info type, R&& type_args); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_invocable_r_type(info type_result, info type, R&& type_args); + + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_nothrow_invocable_type(info type, R&& type_args); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool is_nothrow_invocable_r_type(info type_result, info type, R&& type_args); + + // associated with \ref{meta.trans.cv}, const-volatile modifications + consteval info remove_const(info type); + consteval info remove_volatile(info type); + consteval info remove_cv(info type); + consteval info add_const(info type); + consteval info add_volatile(info type); + consteval info add_cv(info type); + + // associated with \ref{meta.trans.ref}, reference modifications + consteval info remove_reference(info type); + consteval info add_lvalue_reference(info type); + consteval info add_rvalue_reference(info type); + + // associated with \ref{meta.trans.sign}, sign modifications + consteval info make_signed(info type); + consteval info make_unsigned(info type); + + // associated with \ref{meta.trans.arr}, array modifications + consteval info remove_extent(info type); + consteval info remove_all_extents(info type); + + // associated with \ref{meta.trans.ptr}, pointer modifications + consteval info remove_pointer(info type); + consteval info add_pointer(info type); + + // associated with \ref{meta.trans.other}, other transformations + consteval info remove_cvref(info type); + consteval info decay(info type); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info common_type(R&& type_args); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info common_reference(R&& type_args); + consteval info type_underlying_type(info type); + template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info invoke_result(info type, R&& type_args); + consteval info unwrap_reference(info type); + consteval info unwrap_ref_decay(info type); + + consteval size_t tuple_size(info type); + consteval info tuple_element(size_t index, info type); + + consteval size_t variant_size(info type); + consteval info variant_alternative(size_t index, info type); + + consteval strong_ordering type_order(info type_a, info type_b); +} +\end{codeblock} + +\pnum +Unless otherwise specified, +each function, and each specialization of any function template, +specified in this header +is a designated addressable function\iref{namespace.std}. + +\pnum +The behavior of any function specified in namespace \tcode{std::meta} is +\impldef{behavior of any function in \tcode{std::meta} +for implementation-specific constructs} +when a reflection of a construct not otherwise specified by this document +is provided as an argument. +\begin{note} +Values of type \tcode{std::meta::info} +can represent implementation-specific constructs\iref{basic.fundamental}. +\end{note} +\begin{note} +The behavior of many of the functions specified in namespace \tcode{std::meta} +have semantics that can be affected by +the completeness of class types represented by reflection values. +For such functions, +for any reflection \tcode{r} such that \tcode{dealias(r)} +represents a specialization of a templated class with a reachable definition, +the specialization is implicitly instantiated\iref{temp.inst}. +\begin{example} +\begin{codeblock} +template +struct X { + T mem; +}; + +static_assert(size_of(^^X) == sizeof(int)); // instantiates \tcode{X} +\end{codeblock} +\end{example} +\end{note} + +\pnum +Any function in namespace \tcode{std::meta} +whose return type is \tcode{string_view} or \tcode{u8string_view} +returns an object \exposid{V} such that +\tcode{\exposid{V}.data()[\exposid{V}.size()]} equals \tcode{'\textbackslash 0'}. +\begin{example} +\begin{codeblock} +struct C { }; + +constexpr string_view sv = identifier_of(^^C); +static_assert(sv == "C"); +static_assert(sv.data()[0] == 'C'); +%TODO: investigate if this is how we usually do backslashes in code blocks +static_assert(sv.data()[1] == '@\textbackslash@ 0'); +\end{codeblock} +\end{example} + +\rSec2[meta.reflection.operators]{Operator representations} + +%FIXME: I find it stylistically dubious that we don't say that +%this is std::meta::operators; +%we do repeat ranges:: in the itemdecls for ranges stuff. +%Is this actually okay? +%BIG fix needed in lots of places if not. +\begin{itemdecl} +enum class @\libglobal{operators}@ { + @\seebelow@; +}; +using enum operators; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The enumeration type \tcode{operators} specifies +constants used to identify operators that can be overloaded, +with the meanings listed in~\tref{meta.reflection.operators}. +The values of the constants are distinct. +\end{itemdescr} + +%TODO: double-check if this is the right table environment for the job +%TODO: What is the best way to index these enum members? +\begin{floattable}{Enum class\tcode{operators}}{meta.reflection.operators} +{lcc} +\topline +\chdr{Constant} & +\chdr{Corresponding \grammarterm{operator-function-id}} & +\chdr{Operator symbol name} \\ \capsep +\tcode{op_new} & \tcode{operator new} & \tcode{new} \\ \rowsep +\tcode{op_delete} & \tcode{operator delete} & \tcode{delete} \\ \rowsep +\tcode{op_array_new} & \tcode{operator new[]} & \tcode{new[]} \\ \rowsep +\tcode{op_array_delete} & \tcode{operator delete[]} & \tcode{delete[]} \\ \rowsep +\tcode{op_co_await} & \tcode{operator co_await} & \tcode{co_await} \\ \rowsep +\tcode{op_parentheses} & \tcode{operator()} & \tcode{()} \\ \rowsep +\tcode{op_square_brackets} & \tcode{operator[]} & \tcode{[]} \\ \rowsep +\tcode{op_arrow} & \tcode{operator->} & \tcode{->} \\ \rowsep +\tcode{op_arrow_star} & \tcode{operator->*} & \tcode{->*} \\ \rowsep +\tcode{op_tilde} & \tcode{operator~} & \tcode{~} \\ \rowsep +\tcode{op_exclamation} & \tcode{operator!} & \tcode{!} \\ \rowsep +\tcode{op_plus} & \tcode{operator+} & \tcode{+} \\ \rowsep +\tcode{op_minus} & \tcode{operator-} & \tcode{-} \\ \rowsep +\tcode{op_star} & \tcode{operator*} & \tcode{*} \\ \rowsep +\tcode{op_slash} & \tcode{operator/} & \tcode{/} \\ \rowsep +\tcode{op_percent} & \tcode{operator\%} & \tcode{\%} \\ \rowsep +\tcode{op_caret} & \tcode{operator\caret} & \tcode{\caret} \\ \rowsep +\tcode{op_ampersand} & \tcode{operator\&} & \tcode{\&} \\ \rowsep +\tcode{op_equals} & \tcode{operator=} & \tcode{=} \\ \rowsep +\tcode{op_pipe} & \tcode{operator|} & \tcode{|} \\ \rowsep +\tcode{op_plus_equals} & \tcode{operator+=} & \tcode{+} \\ \rowsep +\tcode{op_minus_equals} & \tcode{operator-=} & \tcode{-} \\ \rowsep +\tcode{op_star_equals} & \tcode{operator*=} & \tcode{*} \\ \rowsep +\tcode{op_slash_equals} & \tcode{operator/=} & \tcode{/} \\ \rowsep +\tcode{op_percent_equals} & \tcode{operator\%=} & \tcode{\%} \\ \rowsep +\tcode{op_caret_equals} & \tcode{operator\caret=} & \tcode{\caret=} \\ \rowsep +\tcode{op_ampersand_equals} & \tcode{operator\&=} & \tcode{\&} \\ \rowsep +\tcode{op_pipe_equals} & \tcode{operator|=} & \tcode{|} \\ \rowsep +\tcode{op_equals_equals} & \tcode{operator==} & \tcode{==} \\ \rowsep +\tcode{op_exclamation_equals} & \tcode{operator!=} & \tcode{!=} \\ \rowsep +\tcode{op_less} & \tcode{operator<} & \tcode{<} \\ \rowsep +\tcode{op_greater} & \tcode{operator>} & \tcode{>} \\ \rowsep +\tcode{op_less_equals} & \tcode{operator<=} & \tcode{<=} \\ \rowsep +\tcode{op_greater_equals} & \tcode{operator>=} & \tcode{>=} \\ \rowsep +\tcode{op_spaceship} & \tcode{operator<=>} & \tcode{<=>} \\ \rowsep +\tcode{op_ampersand_ampersand} & \tcode{operator\&\&} & \tcode{\&\&} \\ \rowsep +\tcode{op_pipe_pipe} & \tcode{operator||} & \tcode{||} \\ \rowsep +\tcode{op_less_less} & \tcode{operator<<} & \tcode{<<} \\ \rowsep +\tcode{op_greater_greater} & \tcode{operator>>} & \tcode{>>} \\ \rowsep +\tcode{op_less_less_equals} & \tcode{operator<<=} & \tcode{<<=} \\ \rowsep +\tcode{op_greater_greater_equals} & \tcode{operator>>=} & \tcode{>>=} \\ \rowsep +\tcode{op_plus_plus} & \tcode{operator++} & \tcode{++} \\ \rowsep +\tcode{op_minus_minus} & \tcode{operator--} & \tcode{--} \\ \rowsep +\tcode{op_comma} & \tcode{operator,} & \tcode{,} \\ +\end{floattable} + +\indexlibraryglobal{operator_of}% +\begin{itemdecl} +consteval operators operator_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{r} represents an operator function or operator function template. + +\pnum +\returns +The value of the enumerator from the \tcode{operators} +whose corresponding \grammarterm{operator-function-id} +is the unqualified name of the entity represented by \tcode{r}. +\end{itemdescr} + +\indexlibraryglobal{symbol_of}% +\indexlibraryglobal{u8symbol_of}% +\begin{itemdecl} +consteval string_view symbol_of(operators op); +consteval u8string_view u8symbol_of(operators op); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +The value of \tcode{op} corresponds to one of the enumerators in \tcode{operators}. + +\pnum +\returns +A \tcode{string_view} or \tcode{u8string_view} +containing the characters of the operator symbol name corresponding to \tcode{op}, +respectively encoded with the ordinary literal encoding or with UTF-8. +\end{itemdescr} + +\rSec2[meta.reflection.names]{Reflection names and locations} + +\indexlibraryglobal{has_identifier}% +\begin{itemdecl} +consteval bool has_identifier(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents an entity + that has a typedef name for linkage purposes\iref{dcl.typedef}, + then \tcode{true}. +\item + Otherwise, if \tcode{r} represents an unnamed entity, + then \tcode{false}. +\item + Otherwise, if \tcode{r} represents a class type, + then \tcode{!has_template_arguments(r)}. +\item + Otherwise, if \tcode{r} represents a function, + then \tcode{true} if \tcode{has_template_arguments(r)} is \tcode{false} + and the function is not a + constructor, + destructor, + operator function, or + conversion function. + Otherwise, \tcode{false}. +\item + Otherwise, if \tcode{r} represents a template, + then \tcode{true} if \tcode{r} does not represent a + constructor template, + operator function template, + or conversion function template. + Otherwise, \tcode{false}. +\item + Otherwise, if \tcode{r} represents a variable, + then \tcode{false} if the declaration of that variable + was instantiated from a function parameter pack. + Otherwise, \tcode{!has_template_arguments(r)}. +\item + Otherwise, if \tcode{r} represents a structured binding, + then \tcode{false} if the declaration of that structured binding + was instantiated from a structured binding pack. + Otherwise, \tcode{true}. +\item + Otherwise, if \tcode{r} represents a type alias, + then \tcode{!has_template_arguments(s)}. +\item + Otherwise, if \tcode{r} represents an + enumerator, + non-static-data member, + namespace, or + namespace alias, + then \tcode{true}. +\item + Otherwise, if \tcode{r} represents a direct base class relationship, + then \tcode{has_identifier(type_of(r))}. +\item + Otherwise, \tcode{r} represents a data member description + $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}; + \tcode{true} if $N$ is not $\perp$. + Otherwise, \tcode{false}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{identifier_of}% +\indexlibraryglobal{u8identifier_of}% +\begin{itemdecl} +consteval string_view identifier_of(info r); +consteval u8string_view u8identifier_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $E$ be UTF-8 for \tcode{u8identifier_of}, +and otherwise the ordinary literal encoding. + +\pnum +\constantwhen +\tcode{has_identifier(r)} is \tcode{true} +and the identifier that would be returned (see below) +is representable by $E$. + +\pnum +\returns +An \ntmbs{}, encoded with $E$, +determined as follows: +\begin{itemize} +\item + If \tcode{r} represents an entity with a typedef name for linkage purposes, + then that name. +\item + Otherwise, if \tcode{r} represents a literal operator or literal operator template, + then the \grammarterm{ud-suffix} of the operator or operator template. +\item + Otherwise, if \tcode{r} represents an entity, + then the identifier introduced by the declaration of that entity. +\item + Otherwise, if \tcode{r} represents a direct base class relationship, + then \tcode{identifier_of(type_of(r))} or \tcode{u8identifier_of(type_of(r))}, + respectively. +\item + Otherwise, \tcode{r} represents a data member description + $(T, N, A, W, NUA)$\iref{class.mem.general}; + a \tcode{string_view} or \tcode{u8string_view}, respectively, + containing the identifier \tcode{\placeholder{N}}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{display_string_of}% +\indexlibraryglobal{u8display_string_of}% +\begin{itemdecl} +consteval string_view display_string_of(info r); +consteval u8string_view u8display_string_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An +\impldef{the result of \tcode{display_string_of} and \tcode{u8display_string_of}} +\tcode{string_view} or \tcode{u8string_view}, respectively. + +\pnum +\recommended +Where possible, +implementations should return a string +suitable for identifying the represented construct. +\end{itemdescr} + +\indexlibraryglobal{source_location_of}% +\begin{itemdecl} +consteval source_location source_location_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +If \tcode{r} represents +a value, +a type other than a class type or an enumeration type, +the global namespace, or +a data member description, +then \tcode{source_location\{\}}. +Otherwise, an +\impldef{the value returned by \tcode{std::meta::source_location_of}} +\tcode{source_location} value. + +\pnum +\recommended +If \tcode{r} represents an entity with a definition +that is reachable from the evaluation context, +a value corresponding to a definition should be returned. +\end{itemdescr} + +\rSec2[meta.reflection.queries]{Reflection queries} + +\begin{itemdecl} +consteval bool @\exposid{has-type}@(info r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a +value, +object, +variable, +function whose type does not contain an undeduced placeholder type +and that is not a constructor or destructor, +enumerator, +non-static data member, +unnamed bit-field, +direct base class relationship, or +data member description. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{type_of}% +\begin{itemdecl} +consteval bool type_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{\exposid{has-type}(r)} is \tcode{true}. + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents a + value, + object, + variable, + function, + non-static data member, or + unnamed bit-field, + then the type of what is represented by \tcode{r}. +\item + Otherwise, if \tcode{r} represents + an enumerator $N$ of an enumeration $E$, then: + \begin{itemize} + \item + If $E$ is defined by a declaration $D$ + that precedes a point $P$ in the evaluation context + and $P$ does not occur within an \grammarterm{enum-specifier} of $D$, + then a reflection of $E$. + \item + Otherwise, a reflection of the type of $N$ + prior to the closing brace of the \grammarterm{enum-specifier} + as specified in~\ref{dcl.enum}. + \end{itemize} +\item + Otherwise, if \tcode{r} represents + a direct base class relationship $(D, B)$, + then a reflection of $B$. +\item + Otherwise, for a data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general}, + a reflection of the type $T$. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{object_of}% +\begin{itemdecl} +consteval info object_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{r} is a reflection representing either +\begin{itemize} +\item + an object with static storage duration\iref{basic.stc.general}, or +\item + a variable that either declares or refers to such an object, + and if that variable is a reference $R$, then either + \begin{itemize} + \item + $R$ is usable in constant expressions\iref{expr.const}, or + \item + the lifetime of $R$ began within the core constant expression + currently under evaluation. + \end{itemize} +\end{itemize} + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents an object, + then \tcode{r}. +\item + Otherwise, if \tcode{r} represents a reference, + then a reflection of the object referred to by that reference. +\item + Otherwise, \tcode{r} represents a variable; + a reflection of the object declared by that variable. +\end{itemize} +\begin{example} +\begin{codeblock} +int x; +int& y = x; + +static_assert(^^x != ^^y); // OK, \tcode{r} and \tcode{y} are different variables so their + // reflections compare different +static_assert(object_of((^^x) == object_of(^^y))); // OK, because \tcode{y} is a reference + // to \tcode{x}, their underlying objects are the same +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{constant_of}% +\begin{itemdecl} +consteval info constant_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\placeholder{R}} be a constant expression of type \tcode{info} +such that \tcode{\placeholder{R} == r} is \tcode{true}. + +\pnum +\constantwhen +\tcode{[: \placeholder{R} :]} is a valid +\grammarterm{splice-expression}\iref{expr.prim.splice}. + +\pnum +\effects +Equivalent to: +\begin{codeblock} +return reflect_constant([: \placeholder{R} :]); +\end{codeblock} +\begin{example} +\begin{codeblock} +constexpr int x = 0; +constexpr int y = 0; + +static_assert(^^x != ^^y); // OK, \tcode{x} and \tcode{y} are different variables so their + // reflections compare different +static_assert(constant_of(^^x) == constant_of(^^y)); // OK, both \tcode{constant_of(x)} and + // \tcode{constant_of(\reflexpr{y})} + // represent the value \tcode{0} +static_assert(constant_of(^^x) == reflect_constant(0)); // OK, likewise + +struct S { int m; }; +constexpr S s {42}; +static_assert(is_object(constant_of(^^s)) && + is_object(reflect_object(s))); +static_assert(constant_of(^^s) != reflect_object(s)); // OK, template parameter object that is + // template-argument-equivalent to \tcode{s} is + // a different object than \tcode{s} +static_assert(constant_of(^^s) == + constant_of(reflect_object(s))); // OK + +consteval info fn() { + constexpr int x = 42; + return ^^x; +} +constexpr info r = constant_of(fn()); // error: \tcode{x} is outside its lifetime +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{is_public}% +\indexlibraryglobal{is_protected}% +\indexlibraryglobal{is_private}% +\begin{itemdecl} +consteval bool is_public(info r); +consteval bool is_protected(info r); +consteval bool is_private(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents either +\begin{itemize} +\item + a class member or unnamed bit-field + that is public, protected, or private, respectively, or +\item + a direct base class relationship $(D, B)$ for which $B$ is, respectively, + a public, protected, or private base class of $D$. +\end{itemize} +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_virtual}% +\begin{itemdecl} +consteval bool is_virtual(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents either a virtual member function +or a direct base class relationship $(D, B)$ +for which $B$ is a virtual base class of $D$. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_pure_virtual}% +\indexlibraryglobal{is_override}% +\begin{itemdecl} +consteval bool is_pure_virtual(info r); +consteval bool is_override(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a member function that is pure virtual +or overrides another member function, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_final}% +\begin{itemdecl} +consteval bool is_final(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a final class or a final member function. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_deleted}% +\indexlibraryglobal{is_defaulted}% +\begin{itemdecl} +consteval bool is_deleted(info r); +consteval bool is_defaulted(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function that is +a deleted function\iref{dcl.fct.def.delete} +or defaulted function\iref{dcl.fct.def.default}, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_used_provided}% +\indexlibraryglobal{is_user_declared}% +\begin{itemdecl} +consteval bool is_user_provided(info r); +consteval bool is_user_declared(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function that is +user-provided or user-declared\iref{dcl.fct.def.default}, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_explicit}% +\begin{itemdecl} +consteval bool is_explicit(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +%FIXME: inconsistent font use for "explicit" between normative wording and note below. +\tcode{true} if \tcode{r} represents a member function that is declared explicit. +Otherwise, \tcode{false}. +\begin{note} +If \tcode{r} represents a member function template that is declared \tcode{explicit}, +\tcode{is_explicit(r)} is still \tcode{false} +because in general +%FIXME: comma +such queries for templates cannot be answered. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_noexcept}% +\begin{itemdecl} +consteval bool is_noexcept(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a \tcode{noexcept} function type +or a function with a non-throwing exception specification\iref{except.spec}. +Otherwise, \tcode{false}. +\begin{note} +If \tcode{r} represents a function template that is declared \tcode{noexcept}, +\tcode{is_noexcept(r)} is still \tcode{false} +because in general +%FIXME: comma +such queries for templates cannot be answered. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_bit_field}% +\begin{itemdecl} +consteval bool is_bit_field(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a bit-field, +or if \tcode{r} represents a data member description +$(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} +for which $W$ is not $\perp$. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_enumerator}% +\begin{itemdecl} +consteval bool is_enumerator(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents an enumerator. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_const}% +\indexlibraryglobal{is_volatile}% +\begin{itemdecl} +consteval bool is_const(info r); +consteval bool is_volatile(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a const or volatile type, respectively, +or a const- or volatile-qualified function type, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_mutable_member}% +\begin{itemdecl} +consteval bool is_mutable_member(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a \tcode{mutable} non-static data member. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_lvalue_reference_qualified}% +\indexlibraryglobal{is_rvalue_reference_qualified}% +\begin{itemdecl} +consteval bool is_lvalue_reference_qualified(info r); +consteval bool is_rvalue_reference_qualified(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $T$ be \tcode{type_of(r)} if \tcode{\exposid{has-type}(r)} is \tcode{true}. +Otherwise, let $T$ be \tcode{dealias(r)}. + +\pnum +\returns +\tcode{true} if $T$ represents a +%FIXME: "an", not "a" +lvalue- or rvalue-qualified function type, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{has_static_storage_duration}% +\indexlibraryglobal{has_thread_storage_duration}% +\indexlibraryglobal{has_automatic_storage_duration}% +\begin{itemdecl} +consteval bool has_static_storage_duration(info r); +consteval bool has_thread_storage_duration(info r); +consteval bool has_automatic_storage_duration(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents an object or variable that has +static, thread, or automatic storage duration, respectively\iref{basic.stc}. +Otherwise, \tcode{false}. +\begin{note} +It is not possible to have a reflection +representing an object or variable having dynamic storage duration. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{has_internal_linkage}% +\indexlibraryglobal{has_module_linkage}% +\indexlibraryglobal{has_external_linkage}% +\indexlibraryglobal{has_c_language_linkage}% +\indexlibraryglobal{has_linkage}% +\begin{itemdecl} +consteval bool has_internal_linkage(info r); +consteval bool has_module_linkage(info r); +consteval bool has_external_linkage(info r); +consteval bool has_c_language_linkage(info r); +consteval bool has_linkage(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a variable, function type, template, or namespace +whose name has +internal linkage, +module linkage, +C language linkage, or +any linkage, respectively\iref{basic.link}. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_copmlete_type}% +\begin{itemdecl} +consteval bool is_complete_type(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{is_type(r)} is \tcode{true} +and there is some point in the evaluation context +from which the type represented by \tcode{dealias(r)} +is not an incomplete type\iref{basic.types}. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_enumerable_type}% +\begin{itemdecl} +consteval bool is_enumerable_type(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +A type $T$ is \term{enumerable} from a point $P$ if either +\begin{itemize} +\item + $T$ is a class type complete at point $P$ or +\item + $T$ is an enumeration type defined by a declaration $D$ + such that $D$ is reachable from $P$ + but $P$ does not occur within an \grammarterm{enum-specifier} of $D$\iref{dcl.enum}. +\end{itemize} + +\pnum +\returns +\tcode{true} if \tcode{dealias(r)} represents a type that is enumerable +from some point in the evaluation context. +Otherwise, \tcode{false}. +\begin{example} +\begin{codeblock} +class S; +enum class E; +static_assert(!is_enumerable_type(^^S)); +static_assert(!is_enumerable_type(^^E)); + +class S { + void mfn() { + static_assert(is_enumerable_type(^^S)); + } + static_assert(!is_enumerable_type(^^S)); +}; +static_assert(is_enumerable_type(^^S)); + +enum class E { + A = is_enumerable_type(^^E) ? 1 : 2 +}; +static_assert(is_enumerable_type(^^E)); +static_assert(static_cast(E::A) == 2); +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{is_variable}% +\begin{itemdecl} +consteval bool is_variable(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a variable. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_type}% +\indexlibraryglobal{is_namespace}% +\begin{itemdecl} +consteval bool is_type(info r); +consteval bool is_namespace(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents an entity +whose underlying entity is a type or namespace, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_type_alias}% +\indexlibraryglobal{is_namespace_alias}% +\begin{itemdecl} +consteval bool is_type_alias(info r); +consteval bool is_namespace_alias(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a type alias or namespace alias, respectively +%FIXME: Very wonky note BEFORE the last sentence, inconsistent with the rest of this subclause. +\begin{note} +A specialization of an alias template is a type alias +%FIXME: missing period in note. +\end{note} +. %FIXME: period following note +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_function}% +\begin{itemdecl} +consteval bool is_function(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_conversion_function}% +\indexlibraryglobal{is_operator_function}% +\indexlibraryglobal{is_literal_operator}% +\begin{itemdecl} +consteval bool is_conversion_function(info r); +consteval bool is_operator_function(info r); +consteval bool is_literal_operator(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function that is a +conversion function\iref{class.conv.fct}, +operator function\iref{over.oper}, or +literal operator\iref{over.literal}, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_special_member_function}% +\indexlibraryglobal{is_constructor}% +\indexlibraryglobal{is_default_constructor}% +\indexlibraryglobal{is_copy_constructor}% +\indexlibraryglobal{is_move_constructor}% +\indexlibraryglobal{is_assignment}% +\indexlibraryglobal{is_copy_assignment}% +\indexlibraryglobal{is_move_assignment}% +\indexlibraryglobal{is_destructor}% +\begin{itemdecl} +consteval bool is_special_member_function(info r); +consteval bool is_constructor(info r); +consteval bool is_default_constructor(info r); +consteval bool is_copy_constructor(info r); +consteval bool is_move_constructor(info r); +consteval bool is_assignment(info r); +consteval bool is_copy_assignment(info r); +consteval bool is_move_assignment(info r); +consteval bool is_destructor(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a function that is a +special member function\iref{special}, +a constructor, +a default constructor, +a copy constructor, +a move constructor, +an assignment operator, +a copy assignment operator, +a move assignment operator, or +a destructor, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_template}% +\begin{itemdecl} +consteval bool is_template(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a +function template, +class template, +variable template, +alias template, or +concept. +Otherwise, \tcode{false}. + +%FIXME: Why does this not get its own paragraph? Inconsistent! +\pnum +\begin{note} +A template specialization is not a template. +%FIXME: begin example ? Maybe say "For example" at least? +\tcode{is_template(\brk{}\reflexpr{std::vector})} is \tcode{true} +but \tcode{is_template(\brk{}\reflexpr{std::vector})} is \tcode{false}. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_function_template}% +\indexlibraryglobal{is_variable_template}% +\indexlibraryglobal{is_class_template}% +\indexlibraryglobal{is_alias_template}% +\indexlibraryglobal{is_conversion_function_template}% +\indexlibraryglobal{is_operator_function_template}% +\indexlibraryglobal{is_literal_operator_template}% +\indexlibraryglobal{is_constructor_template}% +\indexlibraryglobal{is_concept}% +\begin{itemdecl} +consteval bool is_function_template(info r); +consteval bool is_variable_template(info r); +consteval bool is_class_template(info r); +consteval bool is_alias_template(info r); +consteval bool is_conversion_function_template(info r); +consteval bool is_operator_function_template(info r); +consteval bool is_literal_operator_template(info r); +consteval bool is_constructor_template(info r); +consteval bool is_concept(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a +function template, +variable template, +class template, +alias template, +conversion function template, +literal operator template, +constructor template, or +concept +%FIXME: comma +respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_value}% +\indexlibraryglobal{is_object}% +\begin{itemdecl} +consteval bool is_value(info r); +consteval bool is_object(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a value or object, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_structured_binding}% +\begin{itemdecl} +consteval bool is_structured_binding(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a structured binding. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{is_class_member}% +\indexlibraryglobal{is_namespace_member}% +\indexlibraryglobal{is_nonstatic_data_member}% +\indexlibraryglobal{is_static_member}% +\indexlibraryglobal{is_base}% +\begin{itemdecl} +consteval bool is_class_member(info r); +consteval bool is_namespace_member(info r); +consteval bool is_nonstatic_data_member(info r); +consteval bool is_static_member(info r); +consteval bool is_base(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a +class member, +namespace member, +non-static data member, +static member, or +direct base class relationship, respectively. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{has_default_member_initializer}% +\begin{itemdecl} +consteval bool has_default_member_initializer(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a non-static data member +that has a default member initializer. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{has_parent}% +\begin{itemdecl} +consteval bool has_parent(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents the global namespace, + then \tcode{false}. +\item + Otherwise, if \tcode{r} represents an entity that has C language linkage\iref{dcl.link}, + then \tcode{false}. +\item + Otherwise, if \tcode{r} represents an enitity that has a + language linkage other than \Cpp{} language linkage, + then an + \impldef{the result of \tcode{std::meta::has_parent} for entities + with neither C nor \Cpp{} language linkage} + value. +\item + Otherwise, if \tcode{r} represents a type that is neither a class nor enumeration type, + then \tcode{false}. +\item + Otherwise, if \tcode{r} represents an enity or direct base class relationship, + then \tcode{true}. +\item + Otherwise, \tcode{false}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{parent_of}% +\begin{itemdecl} +consteval info parent_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{has_parent(r)} is \tcode{true}. + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents a non-static data member + that is a direct member of an anonymous union, + or an unnamed bit-field declared + within the \grammarterm{member-specification} of such a union, + then a reflection representing the innermost enclosing anonymous union. +\item + Otherwise, if \tcode{r} represents an enumerator, + then a reflection representing the corresponding enumeration type. +\item + Otherwise, if \tcode{r} represents a direct base class relationship $(D, B)$, + then a reflection representing $D$. +\item + Otherwise, let $E$ be a class, function, or namespace + whose class scope, function parameter scope, or namespace scope, respectively, + is the innermost such scope that either is, or encloses, + the target scope of a declaration of what is represented by \tcode{r}. + \begin{itemize} + \item + If $E$ is the function call oeprator of a closure type + for a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, + then \tcode{parent_of(\brk{}parent_of(\reflexpr{$E$}))}. + \begin{note} + In this case, + the first \tcode{parent_of} will be the closure type, + so the second \tcode{parent_of} is necessary + to give the parent of that closure type. + \end{note} + \item + Otherwise, \tcode{\reflexpr{$E$}}. + \end{itemize} +\end{itemize} +\begin{example} +\begin{codeblock} +struct I { }; + +struct F : I { + union { + int o; + }; + + enum N { + A + }; +}; + +constexpr auto ctx = std::meta::access_context::current(); + +static_assert(parent_of(^^F) == ^^::); +static_assert(parent_of(bases_of(^^F, ctx)[0]) == ^^F); +static_assert(is_union_type(parent_of(^^F::o))); +static_assert(parent_of(^^F::N) == ^^F); +static_assert(parent_of(^^F::A) == ^^F::N); +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{delias}% +\begin{itemdecl} +consteval info dealias(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{r} represents an entity. + +\pnum +\returns +A reflection representing the underlying entity of what \tcode{r} represents. +\begin{example} +\begin{codeblock} +using X = int; +using Y = X; +static_assert(dealias(^^int) == ^^int); +static_assert(dealias(^^X) == ^^int); +static_assert(dealias(^^Y) == ^^int); +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{has_template_arguments}% +\begin{itemdecl} +consteval bool has_template_arguments(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a specialization of a +function template, +variable template, +class template, or +an alias template. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{template_of}% +\begin{itemdecl} +consteval info template_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{has_template_arguments(r)} is \tcode{true}. + +\pnum +\returns +A reflection of the template of the specialization represented by \tcode{r}. +\end{itemdescr} + +\indexlibraryglobal{template_arguments_of}% +\begin{itemdecl} +consteval vector template_arguments_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{has_template_arguments(r)} is \tcode{true}. + +\pnum +\returns +A \tcode{vector} containing reflections +of the template arguments +of the template specialization represented by \tcode{r}, +in the order they appear in the corresponding template argument list. +For a given template argument $A$, +its corresponding reflection $R$ is determined as follows: +\begin{itemize} +\item + If $A$ denotes a type or type alias, + then $R$ is a reflection representing the underlying entity of $A$. + \begin{note} + $R$ always represents a type, never a type alias. + \end{note} +\item + Otherwise, if $A$ denotes a + class template, + variable template, + concept, or + alias template, + then $R$ is a reflection representing $A$. +\item + Otherwise, $A$ is a constant template argument\iref{temp.arg.nontype}. + Let $P$ be the corresponding template parameter. + \begin{itemize} + \item + If $P$ has reference type, + then $R$ is a reflection + representing the object or function referred to by $A$. + \item + Otherwise, if $P$ has class type, + then $R$ represents the corresponding template parameter object. + \item + %FIXME: "computed by" feels weird and unusual, + %especially in a constant evaluation context. + %It seems fine to say "the value of $A$ without such quirks. + Otherwise, $R$ is a reflection representing the value computed by $A$. + \end{itemize} +\end{itemize} +\begin{example} +\begin{codeblock} +template struct Pair { }; +template struct Pair { }; +template using PairPtr = Pair; + +static_assert(template_of(^^Pair) == ^^Pair); +static_assert(template_of(^^Pair) == ^^Pair); +static_assert(template_arguments_of(^^Pair).size() == 2); +static_assert(template_arguments_of(^^Pair)[0] == ^^int); + +static_assert(template_of(^^PairPtr) == ^^PairPtr); +static_assert(template_arguments_of(^^PairPtr).size() == 1); + +struct S { }; +int i; +template class> + struct X { }; +constexpr auto T = ^^X<1, i, S{}, PairPtr>; +static_assert(is_value(template_arguments_of(T)[0])); +static_assert(is_object(template_arguments_of(T)[1])); +static_assert(is_object(template_arguments_of(T)[2])); +static_assert(template_arguments_of(T)[3] == ^^PairPtr); +\end{codeblock} +\end{example} +\end{itemdescr} + +\rSec2[meta.reflection.access.context]{Access control context} + +\pnum +The \tcode{access_context} class is a non-aggregate type +that represents a namespacee, class, or function +from which queries pertaining to access rules may be performed, +as well as the designating class\iref{class.access.base}, if any. + +\indexlibraryglobal{access_context}% +\pnum +An \tcode{access_context} has an associated scope and designating class. + +\begin{itemdecl} +struct access_context { + access_context() = delete; + + consteval info scope() const; + consteval info designating_class() const; + + static consteval access_context current() noexcept; + static consteval access_context unprivileged() noexcept; + static consteval access_context unchecked() noexcept; + consteval access_context via(info cls) const; +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\tcode{access_context} is a structural type. +Two values \tcode{ac1} and \tcode{ac2} of type \tcode{access_context} +are template-argument-equivalent\iref{temp.type} +if \tcode{a1.scope()} and \tcode{a2.scope()} +are template-argument-equivalent +and \tcode{ac1.desig\-nating_class()} and \tcode{ac2.desig\-nating_class()} +are template-argument-equivalent. +\end{itemdescr} + +\begin{itemdecl} +consteval info @\libmember{scope}{access_context}@() const; +consteval info @\libmember{designating_class}{access_context}@() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +The \tcode{access_context}'s associated scope +and designating class, respectively. +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{current}{access_context}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +%FIXME: why are we just dumping this into the wild instead of in \remarks? +\pnum +\tcode{current} is not an addressable function\iref{namespace.std}. + +\pnum +Given a program point $P$, +let \tcode{\exposid{eval-point}(P)} be the following program point: +\begin{itemize} +\item + If a potentially-evaluated subexpression\iref{intro.execution} + of a default member initializer $I$ + for a member of class $C$\iref{class.mem.general} + appears at $P$, + then a point determined as follows: + \begin{itemize} + \item + If an aggregate initialization is using $I$, + \tcode{\exposid{eval-point}($Q$)}, + where $Q$ is the point at which that aggregate initialization appears. + \item + Otherwise, if an initialization + by an inherited constructor\iref{class.inhctor.init} is using $I$, + a point whose immediate scope is the class scope corresponding to $C$. + \item + Otherwise, a point whose immediate scope + is the function parameter scope + corresponding to the constructor definition that is using $I$. + \end{itemize} + \item + Otherwise, if a potentially-evaluated subexpression + of a default argument\iref{dcl.fct.default} appears at $P$, + \tcode{\exposid{eval-point}($Q$)}, + where $Q$ is the point at which the invocation of the function\iref{expr.call} + using that default argument appears. + \item + Otherwise, if the immediate scope of $P$ + is a function parameter scope introduced by a declaration $D$, + and $P$ appears either before the locus of $D$ + or within the trailing \grammarterm{requires-clause} of $D$, + a point whose immediate scope is the innermost scope enclosing the locus of $D$ + that is not a template parameter scope. + \item + Otherwise, if the immediate scope of $P$ + is a function parameter scope + introduced by a \grammarterm{lambda-expression} $L$ + whose \grammarterm{lambda-introducer} appears at point $Q$, + and $P$ appears either within the \grammarterm{trailing-return-type} + or the trailing \grammarterm{requires-clause} of $L$, + \tcode{\exposid{eval-point}($Q$)}. + \item + Otherwise, if the innermost non-block scope enclosing $P$ + is the function parameter scope + introduced by a \grammarterm{consteval-block-declaration}\iref{dcl.pre}, + a point whose immediate scope is that inhabited + by the outermost \grammarterm{consteval-block-declaration} $D$ + containing $P$ such that each scope (if any) that intervenes between $P$ + and the function parameter scope introduced by $D$ is either + \begin{itemize} + \item + a block scope or + \item + a function parameter scope or lambda or lambda scope + introduced by a \grammarterm{consteval-block-declaration}. + \end{itemize} + \item + Otherwise, $P$. +\end{itemize} + +\pnum +Given a scope $S$, +let \tcode{\exposid{ctx-scope}($S$)} be the following scope: +\begin{itemize} +\item + If $S$ is a class scope or namespace scope, + $S$. +\item + Otherwise, if $S$ is a function parameter scope + introduced by the declaration of a function, + $S$. +\item + Otherwise, if $S$ is a lambda scope + introduced by a \grammarterm{lambda-expression} $L$, + the function parameter scope + corresponding to the call operator of the closure type of $L$. +\item + Otherwise, \tcode{\exposid{ctx-scope}($S'$)} + %FIXME: comma + where $S'$ is the parent scope of $S$. +\end{itemize} + +%FIXME: Why is this not \remarks? +\pnum +An invocation of \tcode{current} that appears at a program point $P$ +is value-dependent\iref{temp.dep.constexpr} +if \tcode{\exposid{eval-point}\brk{}(\brk{}$P$)} is enclosed by a scope +corresponding to a templated entity. + +\pnum +\returns +An \tcode{access_context} whose designating class is the null reflection +and whose scope represents the function, class, or namespace +whose corresponding function parameter scope, class scope, or namespace scope +%FIXME: respectively +is \tcode{\exposid{ctx-scope}($S$)}, +where $S$ is the immediate scope of \tcode{\exposid{eval-point}($P$)} +and $P$ is the point at which the invocation of \tcode{current} lexically appears. +\begin{example} +\begin{codeblock} +struct A { + int a = 0; + consteval A(int p) : a(p) {} +}; +struct B : A { + using A::A; + consteval B(int p, int q) : A(p * q) {} + info s = access_context::current().scope(); +}; +struct C : B { using B::B; }; + +struct Agg { + consteval bool eq(info rhs = access_context::current().scope()) { + return s == rhs; + } + info s = access_context::current().scope(); +}; + +namespace NS { + static_assert(Agg{}.s == access_context::current().scope()); // OK + static_assert(Agg{}.eq()); // OK + static_assert(B(1).s == ^^B); // OK + static_assert(is_constructor(B{1, 2}.s) && parent_of(B{1, 2}.s) == ^^B); // OK + static_assert(is_constructor(C{1, 2}.s) && parent_of(C{1, 2}.s) == ^^B); // OK + + auto fn() -> [:is_namespace(access_context::current().scope()) ? ^^int : ^^bool:]; + static_assert(type_of(^^fn) == ^^auto()->int); // OK + + template + struct TCls { + consteval bool fn() + requires (is_type(access_context::current().scope())) { + return true; // OK, scope is \tcode{TCls}. + } + }; + static_assert(TCls<0>{}.fn()); // OK +} +\end{codeblock} +\end{example} +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{unprivileged}{access_context}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An \tcode{access_context} whose designating class is the null reflection +and whose scope is the global namespace. +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{unchecked}{access_context}@() noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +An \tcode{access_context} whose designating class and scope +are both the null reflection. +\end{itemdescr} + +\begin{itemdecl} +static consteval access_context @\libmember{via}{access_context}@(info cls) noexcept; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{cls} is either the null reflection +or a reflection of a complete class type. + +\pnum +\returns +An \tcode{access_context} whose scope is \tcode{this->scope()} +and whose designating class is \tcode{cls}. +\end{itemdescr} + +\rSec2[meta.reflection.access.queries]{Member accessibility queries} + +\indexlibraryglobal{is_accessible}% +\begin{itemdecl} +consteval bool is_accessible(info r, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let \tcode{\exposid{PARENT-CLS}(r)} be: +\begin{itemize} +\item If \tcode{parent_of(r)} represents a class $C$, then $C$. +\item Otherwise, \tcode{\exposid{PARENT-CLS}(parent_of(r))}. +\end{itemize} + +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{r} does not represent a class member + for which \tcode{\exposid{PARENT-CLS}(r)} is an incomplete class and +\item + \tcode{r} does not represent a direct base class relationship $(D, B)$ + for which $D$ is incomplete. +\end{itemize} + +\pnum +Let \tcode{\exposid{DESIGNATING-CLS}(r, ctx)} be: +\begin{itemize} +\item If \tcode{ctx.designating_class()} represents a class $C$, then $C$. +\item Otherwise, \tcode{\exposid{PARENT-CLS}(r)}. +\end{itemize} + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents an unnamed bit-field $F$, + then \tcode{is_accessible($\tcode{r}_H$, ctx)} + %FIXME: comma + where $\tcode{r}_H$ represents a hypothetical non-static data member + of the class represented by \tcode{\exposid{PARENT-CLS}(r)} + with the same access as $F$. + \begin{note} + Unnamed bit-fields are treated as class members + for the purpose of \tcode{is_accessible}. + \end{note} +\item + Otherwise, if \tcode{r} does not represent a class member + or a direct base class relationship, + then \tcode{true}. +\item + Otherwise, if \tcode{r} represents + \begin{itemize} + \item + a class member that is not a (possibly indirect or variant) + member of \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)} or + \item + a direct base class relationship such that \tcode{parent_of(r)} + does not represent \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)} + or a (direct or indirect) base class thereof, + \end{itemize} + then \tcode{false}. +\item + Otherwise, if \tcode{ctx.scope()} is the null reflection, + then \tcode{true}. +\item + Otherwise, letting $P$ be a program point whose immediate scope is the + function parameter scope, class scope, or namespace scope + corresponding to the + function, class, or namespace + represented by \tcode{ctx.scope()}: + \begin{itemize} + \item + If \tcode{r} represents a direct base class relationship $(D, B)$, + then \tcode{true} if base class $B$ of \tcode{\exposid{DESIG\-NATING-CLS}(\brk{}r, ctx)} + is accessible at $P$\iref{class.access.base}; + otherwise \tcode{false}. + \item + Otherwise, \tcode{r} represents a class member $M$; + \tcode{true} if $M$ would be accessible at $P$ + with the designating class\iref{class.access.base} as \tcode{\exposid{DESIG\-NATING-CLS}(r, ctx)} + if the effect of any \grammarterm{using-declaration}s\iref{namespace.udecl} were ignored. + Otherwise, \tcode{false}. + \end{itemize} +\end{itemize} +\begin{note} +The definitions of when a class member or base class is accessible from a point $P$ +do not consider whether a declaration of that entity is reachable from $P$. +\end{note} +\begin{example} +\begin{codeblock} +consteval access_context fn() { + return access_context::current(); +} + +class Cls { + int mem; + friend consteval access_context fn(); +public: + static constexpr auto r = ^^mem; +}; + +static_assert(is_accessible(Cls::r, fn())); // OK +static_assert(!is_accessible(Cls::r, access_context::current())); // OK +static_assert(is_accessible(Cls::r, access_context::unchecked())); // OK +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{has_inaccessible_nonstatic_data_members}% +\begin{itemdecl} +consteval bool has_inaccessible_nonstatic_data_members(info r, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{nonstatic_data_members_of(\brk{}r, access_context::\brk{}unchecked())} + is a constant subexpression and +\item + \tcode{r} does not represent a closure type. +\end{itemize} + +\pnum +\returns +\tcode{true} if \tcode{is_accessible($R$, ctx)} is \tcode{false} +for any $R$ in \tcode{nonstatic_data_members_of(\brk{}r, access_context\brk{}::unchecked())}. +Otherwise, \tcode{false}. +\end{itemdescr} + +\begin{itemdecl} +consteval bool has_inaccessible_bases(info r, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{bases_of(r, access:context::unchecked())} +is a constant subexpression. + +\pnum +\returns +\tcode{true} if \tcode{is_accessible($R$, ctx)} is \tcode{false} +for any $R$ in \tcode{bases_of(\brk{}r, access_context\brk{}::unchecked())}. +Otherwise, \tcode{false}. +\end{itemdescr} + +\rSec2[meta.reflection.member.queries]{Reflection member queries} + +\indexlibraryglobal{members_of}% +\begin{itemdecl} +consteval vector members_of(info r, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(r)} is a reflection representing either +a class type that is complete from some point in the evaluation context +or a namespace. + +\pnum +A declaration $D$ \term{members-of-precedes} a point $P$ +if $D$ precedes either $P$ +or the point immediately following the \grammarterm{class-specifier} +of the outermost class for which $P$ is in a complete-class context. + +\pnum +A declaration $D$ of a member $M$ of a class or namespace $Q$ is +\term{$Q$-members-of-eligible} if +\begin{itemize} +\item + the host scope of $D$\iref{basic.scope.scope} + is the class scope or namespace scope associated with $Q$, +\item + $D$ is not a friend declaration, +\item + $M$ is not a closure type\iref{expr.prim.lambda.closure}, +\item + $M$ is not a specialization of a template\iref{temp.pre}, +\item + if $Q$ is a class that is not a closure type, + then $M$ is a direct member of $Q$\iref{class.mem.general} + that is not a variant member of a + nested anonymous union of $Q$\iref{class.union.anon}, and +\item + if $Q$ is a closure type, + then $M$ is a function call operator or function call operator template. +\end{itemize} +It is \impldef{whether declarations of some members of a closure type $Q$ +are $Q$-members-of-eliible} +whether declarations of other members of a closure type $Q$ +are $Q$-members-of-eligible. + +\pnum +A member $M$ of a class or namespace $Q$ is +\term{$Q$-members-of-representable} from a point $P$ +if a $Q$-members-of-eligible declaration of $M$ members-of-precedes $P$ +%FIXME: comma +and $M$ is +\begin{itemize} +\item + a class or enumeration type +\item + a type alias +\item + a class template, function template, + variable template, alias template, or concept, +\item + a variable or reference $V$ + for which the type of $V$ does not contain an undeduced placeholder type, +\item + a function $F$ for which + \begin{itemize} + \item + the type of $F$ does not contain an undeduced placeholder type, + \item + the constraints (if any) of $F$ are satisfied, and + \item + if $F$ is a prospective destructor, + $F$ is the selected destructor\iref{class.dtor}, + \end{itemize} +\item + a non-static data member, +\item + a namesapce, or +\item + a namespace alias. +\end{itemize} +\begin{note} +%FIXME: begin example? The entirety of the note is an example. +Examples of direct members that are not $Q$-members-of-representable +for any entity $Q$ include: +unscoped enumerators\iref{enum}, +partial specializations of templates\iref{temp.spec.partial}, and +closure types\iref{expr.prim.lambda.closure}. +\end{note} + +\pnum +\returns +A \tcode{vector} containing reflections of all members $M$ +of the entity $Q$ represented by \tcode{dealias(r)} for which +\begin{itemize} +\item + $M$ is $Q$-members-of-representable + from some point in the evaluation context and +\item + \tcode{is_accessible(\reflexpr{$M$}, ctx)} is \tcode{true}. +\end{itemize} +If \tcode{dealias(r)} represents a class $C$, +then the \tcode{vector} also contains reflections +representing all unnamed bit-fields $B$ +whose declarations inhabit the class scope corresponding to $C$ +for which \tcode{is_accessible(\reflexpr{$B$}, ctx)} is \tcode{true}. +Reflections of class members and unnamed bit-fields that are declared +appear in the order in which they are declared. +\begin{note} +Base classes are not members. +Implicitly-declared special members +appear after any user-declared members\iref{special}. +\end{note} +\begin{example} +\begin{codeblock} +// TU1 +export module M; +namespace NS { + export int m; + static int l; +} +static_assert(members_of(^^NS, access_context::current()).size() == 2); + +// TU2 +import M; + +static_assert( // \tcode{NS::l} does not precede + members_of(^^NS, access_context::current()).size() == 1); // the constant-expression\iref{basic.lookup} + +class B {}; + +struct S : B { +private: + class I; +public: + int m; +}; + +static_assert( // 6 special members, + members_of(^^S, access_context::current()).size() == 7); // 1 public member, + // does not include base + +static_assert( // all of the above, + members_of(^^S, access_context::unchecked()).size() == 8); // as well as a reflection + // representing \tcode{S::I} +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{bases_of}% +\begin{itemdecl} +consteval vector bases_of(info type, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(type)} represents a class type +that is complete from some point in the evaluation context. + +\pnum +\returns +Let $C$ be the class represented by \tcode{dealias(type)}. +A \tcode{vector} containing the reflections +of all the direct base class relationships of $B$, if any, +of $C$ such that \tcode{is_accessible(\brk{}\reflexpr{B}, txt)} is \tcode{true}. +The direct base class relationships appear in the order in which +the corresponding base classes appear in the \grammarterm{base-specifier-list} of $C$. +\end{itemdescr} + +\indexlibraryglobal{static_data_members_of}% +\begin{itemdecl} +consteval vector static_data_members_of(info type, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(type)} represents a class type +that is complete from some point in the evaluation context. + +\pnum +\returns +A \tcode{vector} containing each element \tcode{e} of \tcode{members_of(type, ctx)} +such that \tcode{is_variable(e)} is \tcode{true}, +preserving their order. +\end{itemdescr} + + +\indexlibraryglobal{nonstatic_data_members_of}% +\begin{itemdecl} +consteval vector nonstatic_data_members_of(info type, access_context ctx); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(type)} represents a class type +that is complete from some point in the evaluation context. + +\pnum +\returns +A \tcode{vector} containing each element \tcode{e} of \tcode{members_of(type, ctx)} +such that \tcode{is_nonstatic_data_members_of(e)} is \tcode{true}, +preserving their order. +\end{itemdescr} + +\indexlibraryglobal{enumerators_of}% +\begin{itemdecl} +consteval vector enumerators_of(info type_enum); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(type_enum)} represents an enumeration type +%FIXME: comma +and \tcode{is_enumerable_type(\brk{}type_enum)} is \tcode{true}. + +\pnum +\returns +A \tcode{vector} containing the reflections of each enumerator +of the enumeration represented by \tcode{dealias(type_enum)}, +in the order in which they are declared. +\end{itemdescr} + +\rSec2[meta.reflection.layout]{Reflection layout queries} + +\indexlibraryglobal{member_offset}% +\indexlibrarymember{member_offset}{total_bits}% +\begin{itemdecl} +struct member_offset { + ptrdiff_t bytes; + ptrdiff_t bits; + constexpr ptrdiff_t total_bits() const; + auto operator<=>(const member_offset&) const = default; +}; + +constexpr ptrdiff_t member_offset::total_bits() const; +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{bytes * CHAR_BIT + bits}. +\end{itemdescr} + +\indexlibraryglobal{offset_of}% +\begin{itemdecl} +consteval member_offset offset_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{r} represents a non-static data member, +unnamed bit-field, or +%FIXME: grammatically questionable; +%the relationship itself is not a virtual base class. +%but the base class $B$ in that relationship could be a virtual base class +%and the derived class $D$ could be an abstract class. +direct base class relationship $(D, B)$ +for which either $B$ is not a virtual base class +or $D$ is not an abstract class. + +\pnum +Let $V$ be the offset in bits from the beginning of a complete object +%FIXME: category error. +%parent_of(r) is not a type, it's an expression. +%Are we trying to say "the type represented by parent_of(r)"? +of type \tcode{parent_of(r)} +to the subobject associated with the entity represented by \tcode{r}. + +\pnum +\returns +\tcode{\{$V$ / CHAR_BIT, V \% CHAR_BIT\}}. +\end{itemdescr} + +\indexlibraryglobal{size_of}% +\begin{itemdecl} +consteval size_t size_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(r)} is a reflection of a +type, +object, +value, +variable of non-reference type, +non-static data member that is not a bit-field, +direct base class relationship, or +data member description $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} +where $W$ is not $\perp$. +If \tcode{dealias(r)} represents a type, +then \tcode{is_complete_type(r)} is \tcode{true}. + +\pnum +\returns +If \tcode{r} represents +\begin{itemize} +\item a non-static data member of type $T$, +\item a data member description $(T, N, A, W, \mathit{NUA})$, or +\item \tcode{dealias(r)} represents a type $T$, +\end{itemize} +then \tcode{sizeof($T$)} if $T$ is not a reference type +and \tcode{size_of(\brk{}add_pointer(\brk{}\reflexpr{$T$}))} otherwise. +Otherwise, \tcode{size_of(type_of(r))}. +\begin{note} +It is possible that while \tcode{sizeof(char)\brk{} == size_of(\reflexpr{char})} +%FIXME: "is true" +%FIXME: comma +that \tcode{sizeof(char\&)\brk{} != size_of(\brk{}\reflexpr{char}\&)}. +%FIXME: "is true" +If \tcode{b} represents a direct base class relationship of an empty base class, +then \tcode{size_of(b) > 0}. +%FIXME: "is true" +\end{note} +\end{itemdescr} + +\indexlibraryglobal{alignment_of}% +\begin{itemdecl} +consteval size_t alignment_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(r)} is a reflection of a +type, +object, +value, +variable of non-reference type, +non-static data member that is not a bit-field, +direct base class relationship, or +data member description. +If \tcode{dealias(r)} represents a type, +then \tcode{is_complete_type(r)} is \tcode{true}. + +\pnum +\returns +\begin{itemize} +\item + If \tcode{dealias(r)} represents a type $T$, + then the alignment requirement for the layout-associated type\iref{class.mem.general} + for a non-static data member of type $T$. +\item + Otherwise, if \tcode{dealias(r)} represents a variable or object, + then the alignment requirement of the variable or object. +\item + Otherwise, if \tcode{r} represents a direct base class relationship, + then \tcode{alignment_of(type_of(r))}. +\item + Otherwise, if \tcode{r} represents a non-static data member, + then the alignment requirement of the subobject + associated with the represented entity + within any object of type \tcode{parent_of(r)}. +\item + Otherwise, \tcode{r} represents a data member description + $(\mathit{TR}, N, A, W, \mathit{NUA})$\iref{class.mem.general}. + If $A$ is not $\perp$, + then the value of $A$. + Otherwise, \tcode{alignment_of(\reflexpr{$T$})}. +\end{itemize} +\end{itemdescr} + +\indexlibraryglobal{bit_size_of}% +\begin{itemdecl} +consteval size_t bit_size_of(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{dealias(r)} is a reflection of a +type, +object, +value, +variable of non-reference type, +non-static data member, +unnamed bit-field, +direct base class relationship, or +data member description. +If \tcode{dealias(r)} represents a type $T$, +there is a point within the evaluation context from which $T$ is not incomplete. + +\pnum +\returns +\begin{itemize} +\item + If \tcode{r} represents a non-static data member + that is a bit-field + %FIXME: comma. I believe non-static data members cannot be unnamed bit-fields, + %so the comma would prevent the sentence from suggesting that false reality. + or an unnamed bit-field with width $W$, + then $W$. +\item + Otherwise, if \tcode{r} represents a data member description + $(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} + and $W$ is not $\perp$, + then $W$. +\item + Otherwise, \tcode{CHAR_BIT * size_of(r)}. +\end{itemize} +\end{itemdescr} + +\rSec2[meta.reflection.extract]{Value extraction} + +\pnum +The \tcode{extract} function template may be used +to extract a value out of a reflection when its type is known. + +\pnum +The following are defined for exposition only +to aid in the specification of \tcode{extract}: +%FIXME: does ISO like paragraphs ending in a colon? + +\begin{itemdecl} +template + consteval T @\exposid{extract-ref}@(info r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\begin{note} +\tcode{T} is a reference type. +\end{note} + +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{r} represents a variable or object of type \tcode{U}, +\item + \tcode{is_convertible_v(*)[],\brk{} remove_reference_t<\brk{}T>(\brk{}*)[]>} + is \tcode{true},\newline and + \begin{note} + The intent is to allow only qualification conversion from \tcode{U} to \tcode{T}. + \end{note} +\item + If \tcode{r} represents a variable, + then either that variable is usable in constant expressions + or its lifetime began within the core constant expression currently under evaluation. +\end{itemize} + +\pnum +\returns +If \tcode{r} represents an object $O$, +then a reference ot $O$. +Otherwise, a reference to the object declared, or referred to, +by the variable represented by \tcode{r}. +\end{itemdescr} + +\begin{itemdecl} +template + consteval T @\exposid{extract-member-or-function}@(info r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{r} represents a non-static data member with type $X$, + that is not a bit-field, + that is a direct member of class \tcode{C}, + \tcode{T} and \tcode{C} are similar types\iref{conv.qual}, and + \tcode{T} is \tcode{is_convertible_v<\brk{}X C::*, T>} is \tcode{true}; +\item + \tcode{r} represents an implicit object member function + with type \tcode{F} or \tcode{F noexcept} + %FIXME: is this even valid C++? + %I don't think you can just slap noexcept after an identifier ... + that is a direct member of a class \tcode{C} + %FIXME: comma + and \tcode{T} is \tcode{F C::*}; or +\item + \tcode{r} represents a non-member function, + static member function, or + explicit object member function + of function type \tcode{F} or \tcode{F noexcept} + %FIXME: same malformedness issue as above. + %FIXME: comma. + and \tcode{T} is \tcode{F*}. +\end{itemize} + +\pnum +\returns +\begin{itemize} +\item + If \tcode{T} is a pointer type, + then a pointer value pointing to the function represented by \tcode{r}. +\item + Otherwise, a pointer-to-member value + designating the non-static data member or function represented by \tcode{r}. +\end{itemize} +\end{itemdescr} + +\begin{itemdecl} +template + consteval T @\exposid{extract-value}@(info r); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $U$ be the type of the value or object that \tcode{r} represents. + +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{U} is a pointer type, + \tcode{T} and \tcode{U} are similar types\iref{conv.qual}, and + \tcode{is_convertible_v<\brk{}U, T>} is \tcode{true}, +\item + \tcode{U} is not a pointer type + and the cv-unqualified types of \tcode{T} and \tcode{U} are the same, +\item + \tcode{U} is an array type, + \tcode{T} is a pointer type, and + the value \tcode{r} represents is convertible to \tcode{T}, or +\item + \tcode{U} is a closure type, + \tcode{T} is a function pointer type, and + the value that \tcode{r} represents is convertible to \tcode{T}. +\end{itemize} + +\pnum +\returns +\tcode{static_cast([:$R$:])}, +where $R$ is a constant expression of type \tcode{info} +such that \tcode{$R$ == r} is \tcode{true}. +\end{itemdescr} + +\indexlibraryglobal{extract}% +\begin{itemdecl} +template + consteval T extract(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +%FIXME: Why do we normally make a separate paragraph for Let, +%but here we cram it into effects? +Let \tcode{U} be \tcode{remove_cv_t}. +Equivalent to: +\begin{codeblock} +%FIXME: this is inconsistent with reflect_constant, +%which uses if constexpr, +%and presumably, we could do the same here, with the same semantics. +if (is_reference_type(^^T)) { + return @\exposid{extract-ref}@(r); +} else if (is_nonstatic_data_member(r) || is_function(r)) { + return @\exposid{extract-member-or-function}@(r); +} else { + return @\exposid{extract-value}@(constant_of(r)); +} +\end{codeblock} +\end{itemdescr} + +\rSec2[meta.reflection.substitute]{Reflection substitution} + +\begin{itemdecl} +template +concept @\deflibconcept{reflection_range}@ = + ranges::@\libconcept{input_range}@ && + @\libconcept{same_as}@, info> && + @\libconcept{same_as}@>, info>; + +template<@\libconcept{reflection_range}@ R = initializer_list> +consteval bool @\libglobal{can_substitute}@(info templ, R&& arguments); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{templ} represents a template +%FIXME: comma. We're not trying to say that temp represents a template and something else. +and every reflection in \tcode{arguments} represents a construct +usable as a template argument\iref{temp.arg}. + +\pnum +Let \tcode{Z} be the template represented by \tcode{templ} +and let \tcode{Args...} be a sequence of prvalue constant expressions +that compute the reflections held by the elements of \tcode{arguments}. + +\pnum +\returns +\tcode{true} if \tcode{Z<[:Args:]...>} is a valid \grammarterm{template-id}\iref{temp.names} +that does not name a function +whose type contains an undeduced placeholder type. +Otherwise, \tcode{false}. + +\pnum +\begin{note} +If forming \tcode{Z<[:Args:]...>} leads to a failure +outside of the immediate context, +the program is ill-formed. +\end{note} +\end{itemdescr} + +\indexlibraryglobal{substitute}% +\begin{itemdecl} +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info substitute(info templ, R&& arguments); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{can_substitute(templ, arguments)} is \tcode{true}. + +\pnum +Let \tcode{Z} be the template represented by \tcode{templ} +and let \tcode{Args...} be a sequence of prvalue constant expressions +that compute the reflections held by the elements of \tcode{arguments}. + +\pnum +\returns +\tcode{\reflexpr{Z<[:Args:]...>}}. + +\pnum +\begin{note} +If forming \tcode{Z<[:Args:]...>} leads to a failure outside of the immedaite context, +the program is ill-formed. +\end{note} + +\pnum +\begin{example} +\begin{codeblock} +template + auto fn1(); + +static_assert(!can_substitute(^^fn1, {^^int})); // OK +constexpr info r1 = substitute(^^fn1, {^^int}); // error: \tcode{fn} contains an undeduced + // placeholder type + +template + auto fn2() { + static_assert(^^T != ^^int); // static assertion failed during instantiation of \tcode{fn} + return 0; + } + +constexpr bool r2 = can_substitute(^^fn2, {^^int}); // error: instantiation of body of \tcode{fn} + // is needed to deduce return type +\end{codeblock} +\end{example} + +\pnum +\begin{example} +\begin{codeblock} +consteval info to_integral_constant(unsigned i) { + return substitute(^^integral_constant, {^^unsigned, reflect_constant(i)}); +} +constexpr info r = to_integral_constant(2); // OK, \tcode{r} represents the type + // \tcode{integral_constant} +\end{codeblock} +\end{example} +\end{itemdescr} + +\rSec2[meta.reflection.result]{Expression result reflection} + +\indexlibraryglobal{reflect_constant}% +\begin{itemdecl} +template + consteval info reflect_constant(T expr); // \expos +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{is_copy_constructible_v} is \tcode{true} +and \tcode{T} is a cv-unqualified structural type\iref{temp.param} +that is not a reference type. + +\pnum +Let $V$ be: +\begin{itemize} +\item + if \tcode{T} is a class type, + then an object that is template-argument-equivalent to the value of \tcode{expr}; +\item + otherwise, the value of \tcode{expr}. +\end{itemize} + +\pnum +\constantwhen +given the invented variable +\begin{codeblock} +template struct TCls; +\end{codeblock} +the \grammarterm{template-id} \tcode{TCls<$V$>} would be valid. + +\pnum +\returns +\tcode{template_arguments_of(\reflexpr{TCls<$V$>})[0]}. +\begin{note} +This is a reflection of an object for class types +%FIXME: comma. +and a reflection of a value otherwise. +\end{note} +\begin{example} +\begin{codeblock} +template + struct A { }; + +struct N { int x; }; +struct K { char const* p; }; + +constexpr info r1 = reflect_constant(42); +static_assert(is_value(r1)); +static_assert(r1 == template_arguments_of(^^A<42>)[0]); + +constexpr info r2 = reflect_constant(N{42}); +static_assert(is_object(r2)); +static_assert(r2 == template_arguments_of(^^A)[0]); + +constexpr info r3 = reflect_constant(K{nullptr}); // OK +constexpr info r4 = reflect_constant(K{"ebab"}); // error: constituent pointer points to string literal +\end{codeblock} +\end{example} +\end{itemdescr} + +\indexlibraryglobal{reflect_object}% +\begin{itemdecl} +template + consteval info reflect_object(T& expr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is an object type. + +\pnum +\constantwhen +\tcode{expr} is suitable for use as a constant template argument +for a constant template parameter of type \tcode{T\&}\iref{temp.arg.nontype}. + +\pnum +\returns +A reflection of the object designated by \tcode{expr}. +\end{itemdescr} + +\indexlibraryglobal{reflect_function}% +\begin{itemdecl} +template + consteval info reflect_function(T& expr); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\mandates +\tcode{T} is a function type. + +\pnum +\constantwhen +\tcode{expr} is suitable for use as a constant template argument +for a constant template parameter of type \tcode{T\&}\iref{temp.arg.nontype}. + +\pnum +\returns +A reflection of the function designated by \tcode{fn}. +\end{itemdescr} + +\rSec2[meta.reflection.define.aggregate]{Reflection class definition generation} + +\begin{itemdecl} +struct data_member_options { + struct @\exposid{name-type}@ { // \expos + template + requires @\libconcept{constructible_from}@ + consteval @\exposid{name-type}@(T&&); + + template + requires @\libconcept{constructible_from}@ + consteval @\exposid{name-type}@(T&&); + + private: + variant @\exposid{contents}@; // \expos + }; + + optional<@\exposid{name-type}@> name; + optional alignment; + optional bit_width; + bool no_unique_address = false; +}; +\end{itemdecl} + +\begin{itemdescr} +\pnum +The classes \tcode{data_member_options} +and \tcode{data_member_options::\brk{}\exposid{name-type}} +are consteval-only types\iref{basic.types.general}, +and are not structural types\iref{temp.param}. +\end{itemdescr} + +\begin{itemdecl} +template + requires @\libconcept{constructible_from}@ + consteval data_member_options::@\exposid{name-type}@(T&& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{contents} +with \tcode{u8string(std::forward(value))}. +\end{itemdescr} + +\begin{itemdecl} +template + requires @\libconcept{constructible_from}@ + consteval data_member_options::@\exposid{name-type}@(T&& value); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\effects +Initializes \exposid{contents} +with \tcode{string(std::forward(value))}. +\begin{note} +The class \exposid{name-type} allows +the function \tcode{data_member_spec} to accept +an ordinary string literal (or \tcode{string_view}, \tcode{string}, etc.) +or a UTF-8 string literal (or \tcode{u8string_view}, \tcode{u8string}, etc.) +equally well. +\begin{example} +\begin{codeblock} +consteval void fn() { + data_member_options o1 = {.name = "ordinary_literal_encoding"}; + data_member_options o2 = {.name = u8"utf8_encoding"}; +} +\end{codeblock} +\end{example} +\end{note} +\end{itemdescr} + +\indexlibraryglobal{data_member_spec}% +\begin{itemdecl} +consteval info data_member_spec(info type, data_member_options options); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\begin{itemize} +\item + \tcode{dealias(type)} represents eitehr an object type or a reference type; +\item + if \tcode{options.name} contains a value, then: + \begin{itemize} + \item + \tcode{holds_alternative(options.name->contents)} is \tcode{true} + and \tcode{get(\brk{}options.name->\brk{}contents)} + contains a valid identifier\iref{lex.name} + that is not a keyword\iref{lex.key} + when interpreted with UTF-8, or + \item + \tcode{holds_alternative(options.name->contents)} is \tcode{true} + and \tcode{get(\newline options.name->contents)} + contains a valid identifier\iref{lex.name} + that is not a keyword\iref{lex.key} + when interpreted with the ordinary literal encoding; + \end{itemize} + \begin{note} + The name corresponds to the spelling of an identifier~token + after phase~6 of translation\iref{lex.phases}. + Lexical constructs like + \grammarterm{universal-character-name}s\iref{lex.universal.char} are not processed + and will cause evaluation to fail. + %FIXME: what does it mean for evaluation to fail? Constant When violation? + For example, \tcode{R"(\textbackslash u03B1)"} is an invalid identifier + %FIXME: this shouldn't really be a mathematical alpha, + %but we'd need \textalpha or something from {textgreek} to make it work, I think ... + and is not interpreted as \tcode{"$\alpha$"}. + \end{note} +\item + if \tcode{options.name} does not contain a value, + then \tcode{options.bit_width} contains a value; +\item + if \tcode{options.bit_width} contains a value $V$, then + \begin{itemize} + \item + \tcode{is_integral_type(type) || is_enumeration_type(type)} is \tcode{true}, + \item + \tcode{options.alignment} does not contain a value, + \item + \tcode{options.no_unique_address} is \tcode{false}, and + \item + if $V$ equals \tcode{0} + %FIXME: comma + then \tcode{options.name} does not contain a value; and + \end{itemize} + \item + if \tcode{options.alignment} contains a value, + it is an alignment value\iref{basic.align} + not less than \tcode{alignment_of(type)}. +\end{itemize} + +\pnum +\returns +A reflection of a data member description +$(T, N, A, W, \mathit{NUA})$\iref{class.mem.general} where +\begin{itemize} +\item + $T$ is the type represented by \tcode{dealias(type)}, +\item + $N$ is either the identifier encoded by \tcode{options.name} + or $\perp$ if \tcode{options.name} does not contain a value, +\item + $A$ is either the alignment value held by \tcode{options.alignment} + or $\perp$ if \tcode{options.alignment} does not contain a value, +\item + $W$ is either the value held by \tcode{options.bit_width} + or $\perp$ if \tcode{options.bit_width} does not contain a value, and +\item + $\mathit{NUA}$ is the value held by \tcode{options.no_unique_address}. +\end{itemize} +\begin{note} +The returned reflection value is primarily useful +in conjunction with \tcode{define_aggregate}; +it can also be queried by certain other functions in \tcode{std::meta} +(e.g., \tcode{type_of}, \tcode{identifier_of}). +\end{note} +\end{itemdescr} + +\indexlibraryglobal{is_data_member_spec}% +\begin{itemdecl} +consteval bool is_data_member_spec(info r); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{true} if \tcode{r} represents a data member description. +Otherwise, \tcode{false}. +\end{itemdescr} + +\indexlibraryglobal{define_aggregate}% +\begin{itemdecl} +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info define_aggregate(info class_type, R&& mdescrs); +\end{itemdecl} + +\begin{itemdescr} +\pnum +Let $C$ be the class represented by \tcode{class_type} +and $r_K$ be the $K^\text{th}$ reflection value in \tcode{mdescrs}. +For every $r_K$ in \tcode{mdescrs}, +let $(T_K, N_K, A_K, W_K, \mathit{NUA}_K)$ be +the corresponding data member description represented by $r_K$. + +\pnum +\constantwhen +\begin{itemize} +\item + $C$ is incomplete from every point in the evaluation context; + \begin{note} + $C$ can be a class template specialization + for which there is a reachable definition of the class template. + In this case, + the injected declaration is an explicit specialization. + \end{note} +\item + \tcode{is_data_member_spec($r_K$)} is \tcode{true} for every $r_K$; +\item + \tcode{is_complete_type($T_K$)} is \tcode{true} for every $r_K$; and +\item + for every pair $(r_K, r_L)$ where $K < L$, + if $N_K$ is not $\perp$ and $N_L$ is not $\perp$, + then either: + \begin{itemize} + \item + \tcode{$N_K$ != $N_L$} is \tcode{true} or + \item + \tcode{$N_K$ != u8"_"} is \tcode{true}. + \begin{note} + $C$ can be a class template specialization + for which there is a reachable definition of the class template. + In this case, + the injected declaration is an explicit specialization. + \end{note} + \end{itemize} +\end{itemize} + +\pnum +\effects +Produces an injected declaration $C$\iref{expr.const} +that defines $C$ and has properties as follows: +\begin{itemize} +\item + The target scope of $D$ + is the scope to which $C$ belongs\iref{basic.scope.scope}. +\item + The locus of $D$ + follows immediately after the core constant expression + currently under evaluation. +\item + The characteristic sequence of $D$\iref{expr.const} + is the sequence of reflection values $r_K$. +\item + If $C$ is a specialization of a templated class $T$, + and $C$ is not a local class, + then $D$ is an explicit specialization of $T$. +\item + For each $r_K$, + there is a corresponding entity $M_K$ + belonging to the class cope of $D$ + with the following properties: + \begin{itemize} + \item + If $N_K$ is $\perp$, + $M_K$ is an unnamed bit-field. + Otherwise, $M_K$ is a non-static data member whose name is the identifier + determined by the character seqeunce encoed by $N_K$ in UTF-8. + \item + The type of $M_K$ is $T_K$. + \item + $M_K$ is declared with the attribute \tcode{[[no_unique_address]]} + if and only if $\mathit{NUA}_K$ is \tcode{true}. + \item + If $W_K$ is not $\perp$, + $M_K$ is a bit-field whose width is that value. + Otherwise, $M_K$ is not a bit-field. + \item + If $A_K$ is not $\perp$, + $M_K$ has the \grammarterm{alignment-specifier} \tcode{alignas($A_K$)}. + Otherwise, $M_K$ has no \grammarterm{alignment-specifier}. + \end{itemize} + \item + For every $r_L$ in \tcode{mdescrs} such that $K < L$, + the declaration corresponding to $r_K$ + precedes the declaration corresponding to $r_L$. +\end{itemize} + +\pnum +\returns +\tcode{class_type}. +\end{itemdescr} + +\rSec2[meta.reflection.traits]{Reflection type traits} + +%FIXME: There is no such defined thing as a "consteval function", +%but there is a \tcode{consteval} function! +\pnum +Subclause~\ref{meta.reflection.traits} specifies consteval functions to +query the properties of types\iref{meta.unary}, +query the relationships between types\iref{meta.rel}, or +transform types\iref{meta.trans} +%FIXME: better to say "during program translation". +%FIXME: comma woudl be good here because "at compile time" applies to ALL items. +at compile time. +%FIXME: \tcode{consteval} again. +Each consteval function declared in this class +has an associated class template declared elsewhere in this document. + +\pnum +Every function and function template declared in this subclause +has the following conditions +required for a call to that function or function template +to be a constant subexpression\iref{defns.const.subexpr}: +\begin{itemize} +\item + For every parameter \tcode{p} of type \tcode{info}, + \tcode{is_type(p)} is \tcode{true}. +\item + For every parameter \tcode{r} + whose type is constrained on \libconcept{reflection_range}, + \tcode{ranges::\brk{}all_of(\brk{}r, is_type)} is \tcode{true}. +\end{itemize} + +\begin{codeblock} +// associated with \ref{meta.unary.cat}, primary type categories +consteval bool @\libglobal{is_void_type}@(info type); +consteval bool @\libglobal{is_null_pointer_type}@(info type); +consteval bool @\libglobal{is_integral_type}@(info type); +consteval bool @\libglobal{is_floating_point_type}@(info type); +consteval bool @\libglobal{is_array_type}@(info type); +consteval bool @\libglobal{is_pointer_type}@(info type); +consteval bool @\libglobal{is_lvalue_reference_type}@(info type); +consteval bool @\libglobal{is_rvalue_reference_type}@(info type); +consteval bool @\libglobal{is_member_object_pointer_type}@(info type); +consteval bool @\libglobal{is_member_function_pointer_type}@(info type); +consteval bool @\libglobal{is_enum_type}@(info type); +consteval bool @\libglobal{is_union_type}@(info type); +consteval bool @\libglobal{is_class_type}@(info type); +consteval bool @\libglobal{is_function_type}@(info type); +consteval bool @\libglobal{is_reflection_type}@(info type); + +// associated with \ref{meta.unary.comp}, composite type categories +consteval bool @\libglobal{is_reference_type}@(info type); +consteval bool @\libglobal{is_arithmetic_type}@(info type); +consteval bool @\libglobal{is_fundamental_type}@(info type); +consteval bool @\libglobal{is_object_type}@(info type); +consteval bool @\libglobal{is_scalar_type}@(info type); +consteval bool @\libglobal{is_compound_type}@(info type); +consteval bool @\libglobal{is_member_pointer_type}@(info type); + +// associated with \ref{meta.unary.prop}, type properties +consteval bool @\libglobal{is_const_type}@(info type); +consteval bool @\libglobal{is_volatile_type}@(info type); +consteval bool @\libglobal{is_trivially_copyable_type}@(info type); +consteval bool @\libglobal{is_trivially_relocatable_type}@(info type); +consteval bool @\libglobal{is_replaceable_type}@(info type); +consteval bool @\libglobal{is_standard_layout_type}@(info type); +consteval bool @\libglobal{is_empty_type}@(info type); +consteval bool @\libglobal{is_polymorphic_type}@(info type); +consteval bool @\libglobal{is_abstract_type}@(info type); +consteval bool @\libglobal{is_final_type}@(info type); +consteval bool @\libglobal{is_aggregate_type}@(info type); +consteval bool @\libglobal{is_consteval_only_type}@(info type); +consteval bool @\libglobal{is_signed_type}@(info type); +consteval bool @\libglobal{is_unsigned_type}@(info type); +consteval bool @\libglobal{is_bounded_array_type}@(info type); +consteval bool @\libglobal{is_unbounded_array_type}@(info type); +consteval bool @\libglobal{is_scoped_enum_type}@(info type); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_constructible_type}@(info type, R&& type_args); +consteval bool @\libglobal{is_default_constructible_type}@(info type); +consteval bool @\libglobal{is_copy_constructible_type}@(info type); +consteval bool @\libglobal{is_move_constructible_type}@(info type); + +consteval bool @\libglobal{is_assignable_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_copy_assignable_type}@(info type); +consteval bool @\libglobal{is_move_assignable_type}@(info type); + +consteval bool @\libglobal{is_swappable_with_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_swappable_type}@(info type); + +consteval bool @\libglobal{is_destructible_type}@(info type); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_trivially_constructible_type}@(info type, R&& type_args); +consteval bool @\libglobal{is_trivially_default_constructible_type}@(info type); +consteval bool @\libglobal{is_trivially_copy_constructible_type}@(info type); +consteval bool @\libglobal{is_trivially_move_constructible_type}@(info type); + +consteval bool @\libglobal{is_trivially_assignable_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_trivially_copy_assignable_type}@(info type); +consteval bool @\libglobal{is_trivially_move_assignable_type}@(info type); +consteval bool @\libglobal{is_trivially_destructible_type}@(info type); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_nothrow_constructible_type}@(info type, R&& type_args); +consteval bool @\libglobal{is_nothrow_default_constructible_type}@(info type); +consteval bool @\libglobal{is_nothrow_copy_constructible_type}@(info type); +consteval bool @\libglobal{is_nothrow_move_constructible_type}@(info type); + +consteval bool @\libglobal{is_nothrow_assignable_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_nothrow_copy_assignable_type}@(info type); +consteval bool @\libglobal{is_nothrow_move_assignable_type}@(info type); + +consteval bool @\libglobal{is_nothrow_swappable_with_type}@(info type_dst, info type_src); +consteval bool @\libglobal{is_nothrow_swappable_type}@(info type); + +consteval bool @\libglobal{is_nothrow_destructible_type}@(info type); +consteval bool @\libglobal{is_nothrow_relocatable_type}@(info type); + +consteval bool @\libglobal{is_implicit_lifetime_type}@(info type); + +consteval bool @\libglobal{has_virtual_destructor}@(info type); + +consteval bool @\libglobal{has_unique_object_representations}@(info type); + +consteval bool @\libglobal{reference_constructs_from_temporary}@(info type_dst, info type_src); +consteval bool @\libglobal{reference_converts_from_temporary}@(info type_dst, info type_src); + +// associated with \ref{meta.rel}, type relations +consteval bool @\libglobal{is_same_type}@(info type1, info type2); +consteval bool @\libglobal{is_base_of_type}@(info type_base, info type_derived); +consteval bool @\libglobal{is_virtual_base_of_type}@(info type_base, info type_derived); +consteval bool @\libglobal{is_convertible_type}@(info type_src, info type_dst); +consteval bool @\libglobal{is_nothrow_convertible_type}@(info type_src, info type_dst); +consteval bool @\libglobal{is_layout_compatible_type}@(info type1, info type2); +consteval bool + @\libglobal{is_pointer_interconvertible_base_of_type}@(info type_base, info type_derived); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_invocable_type}@(info type, R&& type_args); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_invocable_r_type}@(info type_result, info type, R&& type_args); + +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool @\libglobal{is_nothrow_invocable_type}@(info type, R&& type_args); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval bool + @\libglobal{is_nothrow_invocable_r_type}@(info type_result, info type, R&& type_args); + +// associated with \ref{meta.trans.cv}, const-volatile modifications +consteval info @\libglobal{remove_const}@(info type); +consteval info @\libglobal{remove_volatile}@(info type); +consteval info @\libglobal{remove_cv}@(info type); +consteval info @\libglobal{add_const}@(info type); +consteval info @\libglobal{add_volatile}@(info type); +consteval info @\libglobal{add_cv}@(info type); + +// associated with \ref{meta.trans.ref}, reference modifications +consteval info @\libglobal{remove_reference}@(info type); +consteval info @\libglobal{add_lvalue_reference}@(info type); +consteval info @\libglobal{add_rvalue_reference}@(info type); + +// associated with \ref{meta.trans.sign}, sign modifications +consteval info @\libglobal{make_signed}@(info type); +consteval info @\libglobal{make_unsigned}@(info type); + +// associated with \ref{meta.trans.arr}, array modifications +consteval info @\libglobal{remove_extent}@(info type); +consteval info @\libglobal{remove_all_extents}@(info type); + +// associated with \ref{meta.trans.ptr}, pointer modifications +consteval info @\libglobal{remove_pointer}@(info type); +consteval info @\libglobal{add_pointer}@(info type); + +// associated with \ref{meta.trans.other}, other transformations +consteval info @\libglobal{remove_cvref}@(info type); +consteval info @\libglobal{decay}@(info type); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info @\libglobal{common_type}@(R&& type_args); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info @\libglobal{common_reference}@(R&& type_args); +consteval info @\libglobal{underlying_type}@(info type); +template<@\libconcept{reflection_range}@ R = initializer_list> + consteval info @\libglobal{invoke_result}@(info type, R&& type_args); +consteval info @\libglobal{unwrap_reference}@(info type); +consteval info @\libglobal{unwrap_ref_decay}@(info type); +\end{codeblock} + +\pnum +Ech function or function template declared above has the following behavior +based on the signature and return type of that function or function template. +\begin{note} +The associated class template need not be instantiated. +\end{note} + +%FIXME: This table looks terrible because the left column is too narrow +%to fit the declarations without wrapping. +\begin{libreqtab2a}{Reflection type traits}{meta.reflection.traits} +\\ \topline +\lhdr{Signature and Return Type} & \rhdr{\Fundescx{Returns}} \\ \capsep +\endfirsthead +\continuedcaption\\ +\topline +\lhdr{Signature and Return Type} & \rhdr{\Fundescx{Returns}} \\ \capsep +\endhead + +\indexlibraryglobal{remove_const}% +%FIXME: we have not been using meta:: in any of the item declarations FOR 3000 LINES of TeX +%but NOW we suddenly changed our minds? +%Maybe avoid meta:: for consistency, or use it everywhere above, +%like we do for ranges:: declarations ... +\tcode{bool meta::\placeholder{UNARY}(info type);\br +bool meta::\placeholder{UNARY}_type(info type);} & +%FIXME: Why are we suddenly using std:: in here? +%I don't think we usually do this for type traits ... +\tcode{std::\placeholder{UNARY}_v<$T$>}, +where $T$ is the type or type alias represented by \tcode{type} +\\ \rowsep + +\tcode{bool meta::\placeholder{BINARY}(info type);\br +bool meta::\placeholder{BINARY}_type(info type);} & +\tcode{std::\placeholder{BINARY}_v<$\mathit{T1}$, $\mathit{T2}$>}, +where $\mathit{T1}$ and $\mathit{T2}$ are the types or type aliases +represented by \tcode{t1} and \tcode{t2}, respectively +\\ \rowsep + +\tcode{template\br + bool meta::\placeholder{VARIADIC}_type(info type, R\&\& args);} & +\tcode{std::\placeholder{VARIADIC}_v<$T$, $U$...>} +%FIXME: commma +where $T$ is the type or type alias represented by \tcode{type} +and \tcode{U...} is the pack of types or type aliases +whose elements are represented by the corresponding elements of \tcode{args} +\\ \rowsep + +\tcode{template\br + bool meta::\placeholder{VARIADIC}_type(info t1, info t2, R\&\& args);} & +\tcode{std::\placeholder{VARIADIC}_v<$\mathit{T1}$, $\mathit{T2}$, $U$...>}, +where $\mathit{T1}$ and $\mathit{T2}$ are the types or type aliases +represented by \tcode{t1} and \tcode{t2}, respectively, +and \tcode{$U$...} is the pack of types or type aliases +whose elements are represented by the corresponding elements of \tcode{args} +\\ \rowsep + +\tcode{info meta::\placeholder{UNARY}(info type);\br +info meta::\placeholder{UNARY}(info type);} & +A reflection representing the type denoted by +\tcode{std::\placeholder{UNARY}_t<\brk{}$T$>}, +where $T$ is the type or type alias represented by \tcode{type} +\\ \rowsep + +\tcode{template\br + info meta::\placeholder{VARIADIC}(R\&\& args);} & +A reflection representing the type denoted by +\tcode{std::\placeholder{VARIADIC}_t<$T$...>} +%FIXME: commma +where \tcode{$T$...} is the pack of types or type aliases +whose elements are represented by the corresponding elements of \tcode{args} +\\ \rowsep + +\tcode{template\br + info meta::\placeholder{VARIADIC}(info type, R\&\& args);} & +A reflection representing the type denoted by +\tcode{std::\placeholder{VARIADIC}_t<$T$, $U$...>} +%FIXME: commma +where \tcode{$T$} is the type or type alias represented by \tcode{type} +and \tcode{$U$...} is the pack of types or type aliases +whose elements are represented by the corresponding elements of \tcode{args} +\\ +\end{libreqtab2a} + +\pnum +\begin{note} +For those functions or function templates which return a reflection, +that reflection always represents a type and never a type alias. +\end{note} + +\pnum +\begin{note} +%FIXME: this is obviously an example, not a note +If \tcode{t} is a reflection of the type \tcode{int} +and \tcode{u} is a reflection of an alias to the type \tcode{int}, +then \tcode{t == u} is \tcode{false} +but \tcode{is_same_type(t, u)} is \tcode{true}. +Also, \tcode{t == dealias(u)} is \tcode{true}. +\end{note} + +\indexlibraryglobal{rank}% +\begin{itemdecl} +consteval size_t rank(info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{rank_v}, +where \tcode{T} is the type represented by \tcode{dealias(type)}. +\end{itemdescr} + +\indexlibraryglobal{extent}% +\begin{itemdecl} +consteval size_t extent(info type, unsigned i = 0); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{extent_v}, +where \tcode{T} is the type represented by \tcode{dealias(type)} +and \tcode{I} is a constant equal to \tcode{i}. +\end{itemdescr} + +\indexlibraryglobal{tuple_size}% +\begin{itemdecl} +consteval size_t tuple_size(info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +%FIXME: why are we suddenly starting to use math symbols for T +%when the previous paragraph did not? +\tcode{tuple_size_v<$T$>} +%FIXME: comma. +where $T$ is the type represented by \tcode{dealias(type)}. +\end{itemdescr} + +\indexlibraryglobal{tuple_element}% +\begin{itemdecl} +consteval info tuple_element(size_t index, info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A reflection representing +the type denoted by \tcode{tuple_element_t<$I$, $T$>}, +where $T$ is th type represented by \tcode{dealias(type)} +%FIXME: comma. +and $I$ is a constant equal to \tcode{index}. +\end{itemdescr} + +\indexlibraryglobal{variant_size}% +\begin{itemdecl} +consteval size_t variant_size(info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{variant_size_v<$T$>} +%FIXME: comma +where $T$ is the type represented by dealias(type). +\end{itemdescr} + +\indexlibraryglobal{variant_alternative}% +\begin{itemdecl} +consteval info variant_alternative(size_t index, info type); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +A reflection representing the type denoted by +\tcode{variant_alternative_t<\brk{}$I$, $T$>} +%FIXME: comma +where $T$ is the type represented by \tcode{dealias(type)} +and $I$ is a consant equal to \tcode{index}. +\end{itemdescr} + +\indexlibraryglobal{type_order}% +\begin{itemdecl} +consteval strong_ordering type_order(info t1, info t2); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\returns +\tcode{type_order_v<$\mathit{T1}$, $\mathit{T2}$>}, +where $\mathit{T1}$ and $\mathit{T2}$ are the types +represented by \tcode{dealias(t1)} and \tcode{dealias(t2)}, respectively. +\end{itemdescr} + \rSec1[ratio]{Compile-time rational arithmetic} \rSec2[ratio.general]{General} diff --git a/source/modules.tex b/source/modules.tex index a0386b38ca..cfe20205b1 100644 --- a/source/modules.tex +++ b/source/modules.tex @@ -148,7 +148,9 @@ it is attached to the module to which the friend is attached\iref{basic.link}. \item Otherwise, if the declaration \begin{itemize} -\item is a \grammarterm{namespace-definition} with external linkage or +\item declares a namespace whose name has external linkage, +\item declares a type alias, +\item declares a namespace alias, or \item appears within a \grammarterm{linkage-specification}\iref{dcl.link} \end{itemize} it is attached to the global module. @@ -262,9 +264,10 @@ \pnum If an exported declaration is a \grammarterm{using-declaration}\iref{namespace.udecl} and is not within a header unit, -all entities to which all of the -\grammarterm{using-declarator}{s} ultimately refer (if any) -shall have been introduced with a name having external linkage. +all entities named by the +\grammarterm{using-declarator}{s} (if any) +shall either be a type alias or +have been introduced with a name having external linkage. \begin{example} \begin{codeblocktu}{Source file \tcode{"b.h"}} int f(); @@ -296,9 +299,8 @@ \end{codeblocktu} \end{example} \begin{note} -These constraints do not apply to -type names introduced by \keyword{typedef} declarations -and \grammarterm{alias-declaration}{s}. +The underlying entity of an exported type alias +need not have a name with external linkage. \begin{example} \begin{codeblock} export module M; @@ -312,13 +314,14 @@ A redeclaration of an entity $X$ is implicitly exported if $X$ was introduced by an exported declaration; -otherwise it shall not be exported unless it is a namespace. +otherwise it shall not be exported +unless it is a type alias, a namespace, or a namespace alias. \begin{example} \begin{codeblock} export module M; struct S { int n; }; typedef S S; -export typedef S S; // OK, does not redeclare an entity +export typedef S S; // OK export struct S; // error: exported declaration follows non-exported declaration namespace N { // external linkage, attached to global module, not exported void f(); @@ -698,12 +701,22 @@ that does not denote a dependent type is replaced by its denoted type prior to this determination, -and \item whether a non-value-dependent constant expression is replaced by the result of constant evaluation -prior to this determination. +prior to this determination, +and + +\item +whether +a \grammarterm{splice-expression}, +a \grammarterm{splice-type-specifier}, +a \grammarterm{splice-scope-specifier}, or +any \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +outside of the preceding is replaced in any non-dependent context +by the construct that it designates prior to this determination. \end{itemize} \pnum @@ -878,8 +891,9 @@ \pnum During the implicit definition of a defaulted function\iref{special,class.compare.default}, -the instantiation context is the union of +the instantiation context contains each point in the instantiation context from the definition of the class and +each point in the instantiation context of the program construct that resulted in the implicit definition of the defaulted function. @@ -887,7 +901,7 @@ During the implicit instantiation of a template whose point of instantiation is specified as that of an enclosing specialization\iref{temp.point}, -the instantiation context is the union of +the instantiation context contains each point in the instantiation context of the enclosing specialization and, if the template is defined in a module interface unit of a module $M$ and the point of instantiation is not in a module interface unit of $M$, @@ -900,18 +914,35 @@ During the implicit instantiation of a template that is implicitly instantiated because it is referenced from within the implicit definition of a defaulted function, -the instantiation context is the instantiation context of +the instantiation context contains each point in the instantiation context of the defaulted function. \pnum During the instantiation of any other template specialization, -the instantiation context comprises the point of instantiation +the instantiation context contains the point of instantiation of the template. +\pnum +During the implicit instantiation of any construct +that resulted from the evaluation of an expression +as a core constant expression, +the instantiation context contains +each point in the evaluation context\iref{expr.const}. +\begin{note} +Implicit instantiations can result +from invocations of library functions\iref{meta.reflection}. +The evaluation context can include synthesized points +associated with injected declarations +produced by \tcode{std::meta::define_aggregate}\iref{meta.reflection.define.aggregate}. +\end{note} + \pnum In any other case, the instantiation context at a point within the program -comprises that point. +contains that point. + +\pnum +The instantiation context contains only the points specified above. \pnum \begin{example} @@ -1008,13 +1039,42 @@ A declaration $D$ is \defnx{reachable from}{reachable from!declaration} a point $P$ if \begin{itemize} +\item +$P$ is a non-synthesized point and +\begin{itemize} \item $D$ appears prior to $P$ in the same translation unit, or \item $D$ is not discarded\iref{module.global.frag}, appears in a translation unit that is reachable from $P$, and -does not appear within a \grammarterm{private-module-fragment}. +does not appear within a \grammarterm{private-module-fragment}; or +\end{itemize} +\item +$D$ is the injected declaration +for which $P$ is the corresponding synthesized point. \end{itemize} +\begin{example} +\begin{codeblock} +class Incomplete; + +consteval { + int n = nonstatic_data_members_of( + define_aggregate(^^Incomplete, {data_member_spec(^^int, {.name="x"})}), + std::meta::access_context::current() + ).size(); + + Incomplete y; // error: type of \tcode{y} is incomplete +} +/* P */ +\end{codeblock} +The value of \tcode{n} is 1. +The member \tcode{Incomplete::x} +members-of-precedes\iref{meta.reflection.member.queries} +the synthesized point P associated with the injected declaration +produced by the call to \tcode{define_aggregate}. +\end{example} + +\pnum A declaration is \defnx{reachable}{reachable!declaration} if it is reachable from any point in the instantiation context\iref{module.context}. diff --git a/source/overloading.tex b/source/overloading.tex index 2bb867c346..2acf498fd3 100644 --- a/source/overloading.tex +++ b/source/overloading.tex @@ -16,13 +16,18 @@ \end{note} \pnum -When a function is named in a call, which function +When a function is designated in a call, which function declaration is being referenced and the validity of the call are determined by comparing the types of the arguments at the point of use with the types of the parameters in the declarations in the overload set. This function selection process is called \defn{overload resolution} and is defined in~\ref{over.match}. +\begin{note} +Overload sets are formed by \grammarterm{id-expression}s +naming functions and function templates and +by \grammarterm{splice-expression}s designating entities of the same kinds. +\end{note} \begin{example} \indextext{overloading!example of}% \begin{codeblock} @@ -380,13 +385,13 @@ overload set in other contexts is described in \ref{over.over}. \end{note} -\rSec4[over.call.func]{Call to named function} +\rSec4[over.call.func]{Call to designated function} \pnum -Of interest in~\ref{over.call.func} are only those function calls in -which the \grammarterm{postfix-expression} -ultimately contains an \grammarterm{id-expression} that -denotes one or more functions. +Of interest in~\ref{over.call.func} are only those function calls +in which the \grammarterm{postfix-expression} ultimately contains +an \grammarterm{id-expression} or \grammarterm{splice-expression} +that designates one or more functions. Such a \grammarterm{postfix-expression}, perhaps nested arbitrarily deep in @@ -395,8 +400,11 @@ \begin{ncbnf} postfix-expression:\br postfix-expression \terminal{.} id-expression\br + postfix-expression \terminal{.} splice-expression\br postfix-expression \terminal{->} id-expression\br - primary-expression + postfix-expression \terminal{->} splice-expression\br + id-expression\br + splice-expression \end{ncbnf} These represent two syntactic subcategories of function calls: @@ -404,7 +412,8 @@ \pnum In qualified function calls, -the function is named by an \grammarterm{id-expression} +the function is designated by +an \grammarterm{id-expression} or \grammarterm{splice-expression} $E$ preceded by an \tcode{->} or \tcode{.} operator. Since the construct @@ -433,8 +442,11 @@ resolution for both glvalue and class prvalue objects. \end{footnote} -The function declarations found by name lookup\iref{class.member.lookup} -constitute the set of candidate functions. +The set of candidate functions either +is the set found by name lookup\iref{class.member.lookup} +if $E$ is an \grammarterm{id-expression} or +is the set determined as specified in~\ref{expr.prim.splice} +if $E$ is a \grammarterm{splice-expression}. The argument list is the \grammarterm{expression-list} in the call augmented by the addition of the left operand of @@ -444,16 +456,20 @@ implied object argument\iref{over.match.funcs}. \pnum -In unqualified function calls, the function is named by a -\grammarterm{primary-expression}. -The function declarations found by name lookup\iref{basic.lookup} constitute the -set of candidate functions. -Because of the rules for name lookup, the set of candidate functions +In unqualified function calls, the function is designated by +an \grammarterm{id-expression} or a \grammarterm{splice-expression} $E$ +The set of candidate functions either +is the set found by name lookup\iref{basic.lookup} +if $E$ is an \grammarterm{id-expression} or +is the set determined as specified in~\ref{expr.prim.splice} +if $E$ is a \grammarterm{splice-expression}. +The set of candidate functions consists either entirely of non-member functions or entirely of member functions of some class \tcode{T}. In the former case or -if the \grammarterm{primary-expression} is the address of an overload set, +if $E$ is either a \grammarterm{splice-expression} or +the address of an overload set, the argument list is the same as the \grammarterm{expression-list} @@ -1210,7 +1226,8 @@ \pnum When resolving a placeholder for a deduced class type\iref{dcl.type.class.deduct} -where the \grammarterm{template-name} names a primary class template \tcode{C}, +where the \grammarterm{template-name} or \grammarterm{splice-type-specifier} +designates a primary class template \tcode{C}, a set of functions and function templates, called the guides of \tcode{C}, is formed comprising: \begin{itemize} @@ -1412,7 +1429,9 @@ \pnum When resolving a placeholder for a deduced class type\iref{dcl.type.simple} -where the \grammarterm{template-name} names an alias template \tcode{A}, +where +the \grammarterm{template-name} or \grammarterm{splice-type-specifier} +designates an alias template \tcode{A}, the \grammarterm{defining-type-id} of \tcode{A} must be of the form \begin{ncsimplebnf} \opt{\keyword{typename}} \opt{nested-name-specifier} \opt{\keyword{template}} simple-template-id @@ -1698,13 +1717,76 @@ any argument for which there is no corresponding parameter is considered to ``match the ellipsis''\iref{over.ics.ellipsis}. \item -A candidate function having more than $m$ parameters is viable -only if all parameters following the $m^\text{th}$ -have default arguments\iref{dcl.fct.default}. +A candidate function \tcode{C} having more than $m$ parameters is viable +only if the set of scopes $G$, as defined below, is not empty. +$G$ consists of every scope $X$ that satisfies all of the following: +\begin{itemize} +\item There is a declaration of \tcode{C}, whose host scope is $X$, +considered by the overload resolution. +\item For every $k^\textrm{th}$ parameter $P$ where $k$ > $m$, +there is a reachable declaration, whose host scope is $X$, +that specifies a default argument\iref{dcl.fct.default} for $P$. +\end{itemize} +If \tcode{C} is selected as the best viable function\iref{over.match.best}: +\begin{itemize} +\item +$G$ shall contain exactly one scope (call it $S$). +\item +If the candidates are denoted by a \grammarterm{splice-expression}, +then $S$ shall not be a block scope. +\item +The default arguments used in the call \tcode{C} are +the default arguments specified by +the reachable declarations whose host scope is $S$. +\end{itemize} For the purposes of overload resolution, the parameter list is truncated on the right, so that there are exactly $m$ parameters. \end{itemize} +\begin{example} +\begin{codeblock} +namespace A { + extern "C" void f(int, int = 5); + extern "C" void f(int = 6, int); +} +namespace B { + extern "C" void f(int, int = 7); +} + +void use() { + [:^^A::f:](3, 4); // OK, default argument was not used for viability + [:^^A::f:](3); // error: default argument provided by declarations from two scopes + [:^^A::f:](); // OK, default arguments provided by declarations in the scope of \tcode{A} + + using A::f; + using B::f; + f(3, 4); // OK, default argument was not used for viability + f(3); // error: default argument provided by declaration from two scopes + f(); // OK, default arguments provided by declarations in the scope of \tcode{A} + + void g(int = 8); + g(); // OK + [:^^g:](); // error: host scope is block scope +} + +void h(int = 7); +constexpr std::meta::info r = ^^h; +void poison() { + void h(int = 8); + h(); // OK, calls \tcode{h(8)} + [:^^h:](); // error: default argument provided by declarations from two scopes +} +void call_h() { + [:^^h:](); // error: default argument provided by declarations from two scopes + [:r:](); // error: default argument provided by declarations from two scopes +} + +template +int k(int = 3, Ts...); +int i = k(); // error: no default argument for the second parameter +int j = k<>(); // OK +\end{codeblock} +\end{example} \pnum Second, for a function to be viable, if it has associated constraints\iref{temp.constr.decl}, @@ -2006,29 +2088,10 @@ \end{example} \pnum -If the best viable function resolves to a function -for which multiple declarations were found, and -if any two of these declarations inhabit different scopes and -specify a default argument that made the function viable, -the program is ill-formed. -\begin{example} -\begin{codeblock} -namespace A { - extern "C" void f(int = 5); -} -namespace B { - extern "C" void f(int = 5); -} - -using A::f; -using B::f; - -void use() { - f(3); // OK, default argument was not used for viability - f(); // error: found default argument twice -} -\end{codeblock} -\end{example} +\begin{note} +If the best viable function was made viable by one or more default arguments, +additional requirements apply\iref{over.match.viable}. +\end{note} \rSec3[over.best.ics]{Implicit conversion sequences}% @@ -3100,8 +3163,8 @@ \indextext{overloaded function!address of} \pnum -An \grammarterm{id-expression} -whose terminal name refers to an overload set $S$ and +An expression +that designates an overload set $S$ and that appears without arguments is resolved to a function, @@ -3131,7 +3194,7 @@ If the target type contains a placeholder type, placeholder type deduction is performed\iref{dcl.type.auto.deduct}, and the remainder of this subclause uses the target type so deduced. -The \grammarterm{id-expression} can be preceded by the \tcode{\&} operator. +The expression can be preceded by the \tcode{\&} operator. \begin{note} Any redundant set of parentheses surrounding the function name is ignored\iref{expr.prim.paren}. @@ -3916,7 +3979,7 @@ \pnum For every \tcode{\placeholder{T}}, where \tcode{\placeholder{T}} -is a pointer-to-member type or \tcode{std::nullptr_t}, +is a pointer-to-member type, \tcode{std::meta::info}, or \tcode{std::nullptr_t}, there exist candidate operator functions of the form \begin{codeblock} bool operator==(@\placeholder{T}@, @\placeholder{T}@); diff --git a/source/preprocessor.tex b/source/preprocessor.tex index 3603cac280..c0cc2d363a 100644 --- a/source/preprocessor.tex +++ b/source/preprocessor.tex @@ -2348,6 +2348,7 @@ \defnxname{cpp_impl_coroutine} & \tcode{201902L} \\ \rowsep \defnxname{cpp_impl_destroying_delete} & \tcode{201806L} \\ \rowsep \defnxname{cpp_impl_three_way_comparison} & \tcode{201907L} \\ \rowsep +\defnxname{cpp_impl_reflection} & \tcode{202506L} \\ \rowsep \defnxname{cpp_implicit_move} & \tcode{202207L} \\ \rowsep \defnxname{cpp_inheriting_constructors} & \tcode{201511L} \\ \rowsep \defnxname{cpp_init_captures} & \tcode{201803L} \\ \rowsep diff --git a/source/templates.tex b/source/templates.tex index 016cabde0b..ff8644f1a9 100644 --- a/source/templates.tex +++ b/source/templates.tex @@ -331,6 +331,10 @@ concept template parameters are collectively referred to as \defnadj{template}{template parameters}. +\pnum +The \grammarterm{nested-name-specifier} of a \grammarterm{type-constraint}, +if any, shall not be dependent. + \pnum A concept template parameter shall not have associated constraints\iref{temp.constr.decl}. @@ -726,7 +730,16 @@ \pnum A \tcode{<} is interpreted as the delimiter of a \grammarterm{template-argument-list} -if it follows a name that is not a \grammarterm{conversion-function-id} and +if either +\begin{itemize} +\item +it follows a \grammarterm{splice-specifier} that either +\begin{itemize} +\item appears in a type-only context or +\item is preceded by \keyword{template} or \keyword{typename}, or +\end{itemize} +\item +it follows a name that is not a \grammarterm{conversion-function-id} and \begin{itemize} \item that follows the keyword \keyword{template} or a \tcode{\~} @@ -745,6 +758,7 @@ in a type-only context other than a \grammarterm{nested-name-specifier}\iref{temp.res}. \end{itemize} +\end{itemize} \begin{note} If the name is an \grammarterm{identifier}, it is then interpreted as a \grammarterm{template-name}. @@ -763,7 +777,11 @@ T* p2 = p->template alloc<200>(); // OK, \tcode{<} starts template argument list T::adjust<100>(); // error: \tcode{<} means less than T::template adjust<100>(); // OK, \tcode{<} starts template argument list -} + + static constexpr std::meta::info r = ^^T::adjust; + T* p3 = [:r:]<200>(); // error: \tcode{<} means less than + T* p4 = template [:r:]<200>(); // OK, \tcode{<} starts template argument list +}} \end{codeblock} \end{example} @@ -776,20 +794,21 @@ A \tcode{>} that encloses the \grammarterm{type-id} of a \keyword{dynamic_cast}, \keyword{static_cast}, \keyword{reinterpret_cast} or \keyword{const_cast}, or which encloses the \grammarterm{template-argument}{s} -of a subsequent \grammarterm{template-id}, is considered nested for the purpose -of this description. +of a subsequent \grammarterm{template-id} or +\grammarterm{splice-specialization-specifier}, +is considered nested for the purpose of this description. \end{footnote} is taken as the ending delimiter rather than a greater-than operator. Similarly, the first non-nested \tcode{>>} is treated as two consecutive but distinct \tcode{>} tokens, the first of which is taken as the end of the \grammarterm{template-argument-list} and completes -the \grammarterm{template-id}. +the \grammarterm{template-id} or \grammarterm{splice-specialization-specifier}. \begin{note} The second \tcode{>} token produced by this replacement rule can terminate an enclosing -\grammarterm{template-id} construct or it can be part of a different -construct (e.g., a cast). +\grammarterm{template-id} or \grammarterm{splice-specialization-specifier} +construct or it can be part of a different construct (e.g., a cast). \end{note} \begin{example} \begin{codeblock} @@ -809,6 +828,20 @@ The keyword \keyword{template} shall not appear immediately after a declarative \grammarterm{nested-name-specifier}\iref{expr.prim.id.qual}. +\pnum +The \grammarterm{constant-expression} of a \grammarterm{template-argument} +shall not be an unparenthesized \grammarterm{splice-expression}. +\begin{example} +\begin{codeblock} +template struct S { }; +constexpr int k = 5; +constexpr std::meta::info r = ^^k; +S<[:r:]> s1; // error: unparenthesized \grammarterm{splice-expression} used as template argument +S<([:r:])> s2; // OK +S<[:r:] + 1> s3; // OK +\end{codeblock} +\end{example} + \pnum A name prefixed by the keyword \keyword{template} @@ -854,7 +887,8 @@ \end{example} \pnum -A \grammarterm{template-id} is \defnx{valid}{\idxgram{template-id}!valid} if +A \grammarterm{template-id} or \grammarterm{splice-specialization-specifier} +is \defnx{valid}{\idxgram{template-id}!valid} if \begin{itemize} \item there are at most as many arguments as there are parameters @@ -873,11 +907,15 @@ template parameters (if any) succeeds, and \item - if the \grammarterm{template-id} is non-dependent, + if the \grammarterm{template-id} or + \grammarterm{splice-specialization-specifier} is non-dependent, the associated constraints are satisfied as specified in the next paragraph. \end{itemize} -A \grammarterm{simple-template-id} shall be valid unless it names a -function template specialization\iref{temp.deduct}. +A \grammarterm{simple-template-id} or +\grammarterm{splice-specialization-specifier} +shall be valid unless its respective +\grammarterm{template-name} or \grammarterm{splice-specifier} +names or designates a function template\iref{temp.deduct}. \begin{example} \begin{codeblock} template class X; @@ -894,13 +932,16 @@ \pnum When the \grammarterm{template-name} -of a \grammarterm{simple-template-id} -names a constrained non-function template +of a \grammarterm{simple-template-id} or +the \grammarterm{splice-specifier} +of a \grammarterm{splice-specialization-specifier} +designates a constrained non-function template or a constrained template template parameter, and all \grammarterm{template-argument}{s} -in the \grammarterm{simple-template-id} +in the \grammarterm{simple-template-id} or +\grammarterm{splice-specialization-specifier} are non-dependent\iref{temp.dep.temp}, the associated constraints\iref{temp.constr.decl} of the constrained template @@ -966,10 +1007,9 @@ \pnum \indextext{argument!template}% -The type and form of each -\grammarterm{template-argument} -specified in a -\grammarterm{template-id} +The type and form of each \grammarterm{template-argument} specified +in a \grammarterm{template-id} or +in a \grammarterm{splice-specialization-specifier} shall match the type and form specified for the corresponding parameter declared by the template in its \grammarterm{template-parameter-list}. @@ -1135,7 +1175,9 @@ \end{note} \pnum -When a \grammarterm{simple-template-id} does not name a function, +When a \grammarterm{simple-template-id} or +\grammarterm{splice-specialization-specifier} +does not designate a function, a default \grammarterm{template-argument} is implicitly instantiated\iref{temp.inst} when the value of that default argument is needed. @@ -2442,6 +2484,10 @@ \item they are of type \tcode{std::nullptr_t}, or +\item +they are of type \tcode{std::meta::info} and +their values compare equal\iref{expr.eq}, or + \item they are of enumeration type and their values are the same, \begin{footnote} @@ -2777,8 +2823,8 @@ \pnum Deduction guides are used -when a \grammarterm{template-name} appears -as a type specifier +when a \grammarterm{template-name} or \grammarterm{splice-type-specifier} +appears as a type specifier for a deduced class type\iref{dcl.type.class.deduct}. Deduction guides are not found by name lookup. Instead, when performing class template argument deduction\iref{over.match.class.deduct}, @@ -3005,7 +3051,7 @@ \begin{note} A specialization of a conversion function template -is referenced in +is named in the same way as a non-template conversion function that converts to the same type\iref{class.conv.fct}. \begin{example} @@ -3024,9 +3070,12 @@ } \end{codeblock} \end{example} -There is no syntax to form a \grammarterm{template-id}\iref{temp.names} -by providing an explicit template argument list\iref{temp.arg.explicit} -for a conversion function template. +An expression designating +a particular specialization of a conversion function template +can only be formed with a \grammarterm{splice-expression}. +There is no analogous syntax to form a \grammarterm{template-id}\iref{temp.names} +for such a function +by providing an explicit template argument list\iref{temp.arg.explicit}. \end{note} \rSec2[temp.variadic]{Variadic templates} @@ -4553,11 +4602,22 @@ types. The name of the alias template is a \grammarterm{template-name}. \pnum -When a \grammarterm{template-id} refers to the specialization of -an alias template, it is equivalent to the associated type obtained by +A +\begin{itemize} +\item +\grammarterm{template-id} +that is not the operand of a \grammarterm{reflect-expression} or +\item +\grammarterm{splice-specialization-specifier} +\end{itemize} +that designates the specialization of +an alias template is equivalent to the associated type obtained by substitution of its \grammarterm{template-argument}{s} for the \grammarterm{template-parameter}{s} in the \grammarterm{defining-type-id} of the alias template. +Any other \grammarterm{template-id} +that names a specialization of an alias template is +a \grammarterm{typedef-name} for a type alias. \begin{note} An alias template name is never deduced. \end{note} @@ -4831,7 +4891,9 @@ \grammarterm{type-requirement}, \grammarterm{nested-name-specifier}, \grammarterm{elaborated-type-specifier}, -\grammarterm{class-or-decltype}, or +\grammarterm{class-or-decltype}, +\grammarterm{using-enum-declarator}, +or \item a \grammarterm{simple-type-specifier} of a \grammarterm{friend-type-specifier}, or \item @@ -4869,17 +4931,26 @@ (which necessarily declares a constant template parameter). \end{itemize} \end{itemize} +A \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier}\iref{basic.splice} +is said to be in a type-only context +if a hypothetical qualified name appearing in the same position +would be in a type-only context. \begin{example} \begin{codeblock} template T::R f(); // OK, return type of a function declaration at global scope template void f(T::R); // ill-formed, no diagnostic required: attempt to declare // a \keyword{void} variable template +enum class Enum { A, B, C }; template struct S { using Ptr = PtrTraits::Ptr; // OK, in a \grammarterm{defining-type-id} + using Alias = [:^^int:]; // OK, in a \grammarterm{defining-type-id} T::R f(T::P p) { // OK, class scope return static_cast(p); // OK, \grammarterm{type-id} of a \keyword{static_cast} } auto g() -> S::Ptr; // OK, \grammarterm{trailing-return-type} + auto h() -> [:^^S:]; // OK, \grammarterm{trailing-return-type} + using enum [:^^Enum:]; // OK, \grammarterm{using-enum-declarator} }; template void f() { void (*pf)(T::X); // variable \tcode{pf} of type \tcode{\keyword{void}*} initialized with \tcode{T::X} @@ -5573,6 +5644,10 @@ \item a \grammarterm{pack-index-specifier}, or \item denoted by \tcode{decltype(}\grammarterm{expression}{}\tcode{)}, where \grammarterm{expression} is type-dependent\iref{temp.dep.expr}. +\item denoted by a \grammarterm{splice-type-specifier} in which either +the \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +is dependent\iref{temp.dep.splice}. \end{itemize} \pnum @@ -5702,7 +5777,8 @@ \opt{\terminal{::}} \keyword{delete} \terminal{[} \terminal{]} cast-expression\br \keyword{throw} \opt{assignment-expression}\br \keyword{noexcept} \terminal{(} expression \terminal{)}\br -requires-expression +requires-expression\br +reflect-expression \end{ncsimplebnf} \begin{note} @@ -5748,6 +5824,12 @@ A \grammarterm{pack-index-expression} is type-dependent if its \grammarterm{id-expression} is type-dependent. +\pnum +A \grammarterm{splice-expression} is type-dependent +if its \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +is dependent\iref{temp.dep.splice}. + \rSec3[temp.dep.constexpr]{Value-dependent expressions} \pnum @@ -5850,6 +5932,107 @@ the result of the evaluation refers to a templated entity that is an object with static or thread storage duration or a member function. +\pnum +A \grammarterm{reflect-expression} is value-dependent if +\begin{itemize} +\item +it is of the form \tcode{\caret\caret \grammarterm{reflection-name}} and +the \grammarterm{reflection-name} +\begin{itemize} +\item is a dependent qualified name, +\item is a dependent \grammarterm{namespace-name}, +\item is the name of a template parameter, or +\item names a dependent member of the current instantiation\iref{temp.dep.type}, +\end{itemize} +\item +it is of the form \tcode{\caret\caret \grammarterm{type-id}} and +the \grammarterm{type-id} denotes a dependent type, or +\item +it is of the form \tcode{\caret\caret \grammarterm{id-expression}} and +the \grammarterm{id-expression} is value-dependent. +\end{itemize} + +\pnum +A \grammarterm{splice-expression} is value-dependent +if its \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} +is dependent\iref{temp.dep.splice}. + +\rSec3[temp.dep.splice]{Dependent splice specifiers} + +\pnum +A \grammarterm{splice-specifier} is dependent +if its converted \grammarterm{constant-expression} is value-dependent. +A \grammarterm{splice-specialization-specifier} is dependent +if its \grammarterm{splice-specifier} is dependent or +if any of its template arguments are dependent. +A \grammarterm{splice-scope-specifier} is dependent +if its \grammarterm{splice-specifier} or +\grammarterm{splice-specialization-specifier} is dependent. + +\pnum +\begin{example} +\begin{codeblock} +template +void fn() { + using a = [:T:]<1>; // \tcode{[:T:]<1>} is dependent because \tcode{[:T:]} is dependent + static_assert([:NS:]::template TCls<1>::v == a::v); // \tcode{[:NS:]} is dependent +} + +namespace N { + template struct TCls { static constexpr int v = V; }; +} + +int main() { + fn<^^N::TCls, ^^N>(); +} +\end{codeblock} +\end{example} + +\pnum +\begin{example} +\begin{codeblock} +template class X> +struct S { + [:^^X:] m; +}; + +template struct V1 {}; +template struct V2 {}; + +S s1; // error: \tcode{V1} has too many template arguments +S s2; // OK +\end{codeblock} +\end{example} + +\rSec3[temp.dep.namespace]{Dependent namespaces} + +\pnum +A namespace alias is dependent +if it is introduced by a \grammarterm{namespace-alias-definition} +whose \grammarterm{qualified-namespace-specifier} (if any) is +a dependent qualified name or +whose \grammarterm{splice-specifier} (if any) is dependent. +A \grammarterm{namespace-name} is dependent +if it names a dependent namespace alias. + +\pnum +\begin{example} +\begin{codeblock} +template +int fn() { + namespace Alias = [:R:]; // \tcode{[:R:]} is dependent + return typename Alias::T{}; // \tcode{Alias} is dependent +} + +namespace NS { + using T = int; +} + +int a = fn<^^NS>(); +\end{codeblock} +\end{example} + \rSec3[temp.dep.temp]{Dependent template arguments} \pnum @@ -7134,11 +7317,10 @@ or to make it compile will be such a trial as to kindle its self-immolation. \pnum -A -\grammarterm{simple-template-id} -that names a class template explicit specialization that has been declared but -not defined can be used exactly like the names of other incompletely-defined -classes\iref{basic.types}. +\begin{note} +A class template explicit specialization that has been declared but +not defined can be used exactly like other +incompletely-defined classes\iref{basic.types}. \begin{example} \begin{codeblock} template class X; // \tcode{X} is a class template @@ -7148,6 +7330,7 @@ X x; // error: object of incomplete class \tcode{X} \end{codeblock} \end{example} +\end{note} \pnum \begin{note} @@ -7567,7 +7750,8 @@ \pnum When an explicit template argument list is specified, if the -given \grammarterm{template-id} is not valid\iref{temp.names}, +given \grammarterm{template-id} or +\grammarterm{splice-specialization-specifier} is not valid\iref{temp.names}, type deduction fails. Otherwise, the specified template argument values are substituted for the corresponding template parameters as specified below. @@ -8158,7 +8342,8 @@ is a class and \tcode{P} has the form -\grammarterm{simple-template-id}, +\grammarterm{simple-template-id} or +\opt{\keyword{typename}} \grammarterm{splice-specialization-specifier}, then the transformed \tcode{A} can be a derived class \tcode{D} of the @@ -8167,7 +8352,8 @@ Likewise, if \tcode{P} is a pointer to a class of the form -\grammarterm{simple-template-id}, +\grammarterm{simple-template-id} or +\opt{\keyword{typename}} \grammarterm{splice-specialization-specifier}, the transformed \tcode{A} can be a pointer to a derived class \tcode{D} pointed to by the deduced @@ -8704,6 +8890,8 @@ \item The \grammarterm{expression} of a \grammarterm{decltype-specifier}. \item +The \grammarterm{constant-expression} of a \grammarterm{splice-specifier}. +\item A constant template argument or an array bound in which a subexpression references a template parameter. \item @@ -9177,8 +9365,8 @@ If \tcode{P} has a form that contains \tcode{}, and if the type of \tcode{i} differs from the type of the corresponding template parameter -of the template named by the enclosing \grammarterm{simple-template-id}, -deduction fails. +of the template named by the enclosing \grammarterm{simple-template-id} or +\grammarterm{splice-specialization-specifier}, deduction fails. If \tcode{P} has a form that contains \tcode{[i]}, and if the type of \tcode{i} is not an integral type, deduction fails. \begin{footnote} diff --git a/source/utilities.tex b/source/utilities.tex index ced638f3f7..caae42247e 100644 --- a/source/utilities.tex +++ b/source/utilities.tex @@ -15145,6 +15145,22 @@ \item \tcode{is_trivially_copyable_v} is \tcode{true}. \end{itemize} +\pnum +\mandates +Neither \tcode{To} nor \tcode{From} are consteval-only types\iref{expr.const}. + +\pnum +\constantwhen +\tcode{To}, \tcode{From}, and the types of all subobjects +of \tcode{To} and \tcode{From} are types \tcode{T} such that: +\begin{itemize} +\item \tcode{is_union_v} is \tcode{false}; +\item \tcode{is_pointer_v} is \tcode{false}; +\item \tcode{is_member_pointer_v} is \tcode{false}; +\item \tcode{is_volatile_v} is \tcode{false}; and +\item \tcode{T} has no non-static data members of reference type. +\end{itemize} + \pnum \returns An object of type \tcode{To}. @@ -15179,19 +15195,6 @@ Otherwise, the behavior is erroneous, and the result is as specified above. \end{itemize} The result does not otherwise contain any indeterminate or erroneous values. - -\pnum -\remarks -This function is \keyword{constexpr} if and only if -\tcode{To}, \tcode{From}, and the types of all subobjects -of \tcode{To} and \tcode{From} are types \tcode{T} such that: -\begin{itemize} -\item \tcode{is_union_v} is \tcode{false}; -\item \tcode{is_pointer_v} is \tcode{false}; -\item \tcode{is_member_pointer_v} is \tcode{false}; -\item \tcode{is_volatile_v} is \tcode{false}; and -\item \tcode{T} has no non-static data members of reference type. -\end{itemize} \end{itemdescr} \rSec2[bit.byteswap]{\tcode{byteswap}} diff --git a/tools/check-source.sh b/tools/check-source.sh index b7be457455..0babcd2af8 100755 --- a/tools/check-source.sh +++ b/tools/check-source.sh @@ -97,7 +97,7 @@ grep -n 'unicode{[^}]*[^0-9a-f}][^}]*}' $texfiles | fail 'use lowercase hex digits inside \\unicode' || failed=1 # Use \iref instead of "(\ref", except for subclause ranges -grep -n '.(\\ref' $texfiles | grep -v -- "--" | +grep -n '.(\\ref{' $texfiles | grep -v -- "--" | fail 'use \\iref instead of (\\ref' || failed=1 # \iref cannot be at the start of a line @@ -259,7 +259,7 @@ done | fail 'subclause without siblings' || failed=1 for f in $texlibdesc; do sed -n '/begin{itemdescr}/,/end{itemdescr}/{=;p;}' < $f | sed '/^[0-9]\+$/{N;s/\n/:/;}' | sed "s/.*/$f:&/" | - awk -F: '$3 ~ /^\\pnum/ { seenpnum=1; next } $3 ~ /^\\index/ { next } $3 ~ /^\\(constraints|mandates|expects|effects|sync|ensures|returns|throws|complexity|remarks|errors|recommended)/ { if(seenpnum == 0) { print $0 } } { seenpnum=0 }' + awk -F: '$3 ~ /^\\pnum/ { seenpnum=1; next } $3 ~ /^\\index/ { next } $3 ~ /^\\(constraints|mandates|constantwhen|expects|hardexpects|effects|sync|ensures|returns|throws|complexity|remarks|errors|recommended)/ { if(seenpnum == 0) { print $0 } } { seenpnum=0 }' done | fail '\\pnum missing' || failed=1