diff --git a/source/basic.tex b/source/basic.tex index 5b3e9e0362..1f052f1bc7 100644 --- a/source/basic.tex +++ b/source/basic.tex @@ -5590,6 +5590,7 @@ \item a structured binding\iref{dcl.struct.bind}, \item a function\iref{dcl.fct}, \item an enumerator\iref{dcl.enum}, +\item an annotation\iref{dcl.attr.grammar}, \item a type alias\iref{dcl.typedef}, \item a type\iref{basic.types}, \item a class member\iref{class.mem}, diff --git a/source/declarations.tex b/source/declarations.tex index 96092fc9ec..7681fc6790 100644 --- a/source/declarations.tex +++ b/source/declarations.tex @@ -9360,7 +9360,7 @@ \pnum \indextext{attribute!syntax and semantics}% -Attributes specify additional information for various source constructs +Attributes and annotations specify additional information for various source constructs such as types, variables, names, contract assertions, blocks, or translation units. \begin{bnf} @@ -9371,6 +9371,7 @@ \begin{bnf} \nontermdef{attribute-specifier}\br \terminal{[} \terminal{[} \opt{attribute-using-prefix} attribute-list \terminal{]} \terminal{]}\br + \terminal{[} \terminal{[} annotation-list \terminal{]} \terminal{]}\br alignment-specifier \end{bnf} @@ -9393,11 +9394,22 @@ attribute-list \terminal{,} attribute \terminal{...} \end{bnf} +\begin{bnf} +\nontermdef{annotation-list}\br + annotation \opt{\terminal{...}}\br + annotation-list \terminal{,} annotation \opt{\terminal{...}} +\end{bnf} + \begin{bnf} \nontermdef{attribute}\br attribute-token \opt{attribute-argument-clause} \end{bnf} +\begin{bnf} +\nontermdef{annotation}\br + \terminal{=} constant-expression +\end{bnf} + \begin{bnf} \nontermdef{attribute-token}\br identifier\br @@ -9470,10 +9482,11 @@ 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} and no \grammarterm{alignment-specifier} -has no -effect. The order in which the \grammarterm{attribute-token}{s} appear in an +An \grammarterm{attribute-specifier} that contains +an \grammarterm{attribute-list} with 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} or an alternative token\iref{lex.digraph} that satisfies the syntactic requirements @@ -9484,6 +9497,10 @@ \grammarterm{attribute-token}. The \grammarterm{attribute-token} determines additional requirements on the \grammarterm{attribute-argument-clause} (if any). +\pnum +An \grammarterm{annotation} followed by an ellipsis +is a pack expansion\iref{temp.variadic}. + \pnum Each \grammarterm{attribute-specifier-seq} is said to \defn{appertain} to some entity or statement, identified by the syntactic context @@ -10181,5 +10198,56 @@ if their respective types are all empty. \end{example} +\rSec2[dcl.attr.annotation]{Annotations}% +\indextext{attribute!annotations} + +\pnum +An annotation may be applied to any declaration of a +type, +type alias, +variable, +function, +namespace, +enumerator, +\grammarterm{base-specifier}, or +non-static data member. + +\pnum +Let $E$ be the expression +\tcode{std::meta::reflect_constant(\grammarterm{constant-expression})}. +$E$ shall be a constant expression; +the result of $E$ is the \defnadj{underlying}{constant} of the annotation. + +\pnum +Each \grammarterm{annotation} produces a unique annotation. + +\pnum +Substituting into an \grammarterm{annotation} +is not in the immediate context. +\begin{example} +\begin{codeblock} +[[=1]] void f(); +[[=2, =3, =2]] void g(); +void g [[=4, =2]] (); +\end{codeblock} +\tcode{f} has one annotation +and \tcode{g} has five annotations. +These can be queried with metafunctions +such as \tcode{std::\brk{}meta::\brk{}anno\-tations_of}\iref{meta.reflection.annotation}. +\end{example} +\begin{example} +\begin{codeblock} +template + [[=T::type()]] void f(T t); + +void f(int); + +void g() { + f(0); // OK + f('0'); // error, substituting into the annotation results in an invalid expression +} +\end{codeblock} +\end{example} + \indextext{attribute|)}% \indextext{declaration|)} diff --git a/source/expressions.tex b/source/expressions.tex index e89b27303c..d3670fa297 100644 --- a/source/expressions.tex +++ b/source/expressions.tex @@ -7608,6 +7608,7 @@ \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 annotation\iref{dcl.attr.annotation}, \item represent the same direct base class relationship, or \item represent equal data member descriptions\iref{class.mem.general}, \end{itemize} diff --git a/source/meta.tex b/source/meta.tex index 392ad9937e..fe90847f6d 100644 --- a/source/meta.tex +++ b/source/meta.tex @@ -2625,6 +2625,7 @@ consteval bool is_bit_field(info r); consteval bool is_enumerator(info r); + consteval bool is_annotation(info r); consteval bool is_const(info r); consteval bool is_volatile(info r); @@ -2912,6 +2913,10 @@ consteval info variant_alternative(size_t index, info type); consteval strong_ordering type_order(info type_a, info type_b); + + // \ref{meta.reflection.annotation}, annotation reflection + consteval vector annotations_of(info item); + consteval vector annotations_of_with_type(info item, info type); } \end{codeblock} @@ -3243,6 +3248,7 @@ \returns \tcode{true} if \tcode{r} represents a value, +annotation, object, variable, function whose type does not contain an undeduced placeholder type @@ -3277,6 +3283,9 @@ 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 annotation, + then \tcode{type_of(constant_of(r))}. \item Otherwise, if \tcode{r} represents an enumerator $N$ of an enumeration $E$, then: @@ -3358,19 +3367,26 @@ \begin{itemdescr} \pnum -Let \tcode{\placeholder{R}} be a constant expression of type \tcode{info} -such that \tcode{\placeholder{R} == r} is \tcode{true}. +Let $R$ be a constant expression of type \tcode{info} +such that \tcode{$R$ == r} is \tcode{true}. +If \tcode{r} represents an annotation, +then let $C$ be its underlying constant. \pnum \constantwhen -\tcode{[: \placeholder{R} :]} is a valid +Either \tcode{r} represents an annotation or +\tcode{[: $R$ :]} is a valid \grammarterm{splice-expression}\iref{expr.prim.splice}. \pnum \effects Equivalent to: \begin{codeblock} -return reflect_constant([: @\placeholder{R}@ :]); +if constexpr (is_annotation(@$R$@)) { + return @$C$@; +} else { + return reflect_constant([: @$R$@ :]); +} \end{codeblock} \begin{example} \begin{codeblock} @@ -3552,14 +3568,16 @@ \end{itemdescr} \indexlibraryglobal{is_enumerator}% +\indexlibraryglobal{is_annotation}% \begin{itemdecl} consteval bool is_enumerator(info r); +consteval bool is_annotation(info r); \end{itemdecl} \begin{itemdescr} \pnum \returns -\tcode{true} if \tcode{r} represents an enumerator. +\tcode{true} if \tcode{r} represents an enumerator or annotation, respectively. Otherwise, \tcode{false}. \end{itemdescr} @@ -5946,6 +5964,115 @@ represented by \tcode{dealias(t1)} and \tcode{dealias(t2)}, respectively. \end{itemdescr} +\rSec2[meta.reflection.annotation]{Annotation reflection} + +\indexlibraryglobal{annotations_of}% +\begin{itemdecl} +consteval vector annotations_of(info item); +\end{itemdecl} + +\begin{itemdescr} +\pnum +\constantwhen +\tcode{item} represents a +type, +type alias, +variable, +function, +namespace, +enumerator, +direct base class relationship, or +non-static data member. + +%FIXME: it is highly unusual for this subclause to put Let paragraphs after Constant When +\pnum +Let $E$ be +\begin{itemize} +\item + the corresponding \grammarterm{base-specifier} + if \tcode{item} represents a direct base class relationship, +\item + otherwise, the entity represented by \tcode{item}. +\end{itemize} + +\pnum +\returns +A \tcode{vector} containing all of the reflections $R$ +representing each annotation applying to each declaration of $E$ that precedes either +some point in the evaluation context\iref{expr.const} or +a point immediately following the \grammarterm{class-specifier} +of the outermost class for which such a point is in a complete-class context. +For any two reflections $R_1$ and $R_2$ in the returned \tcode{vector}, +if the annotation represented by $R_1$ precedes the annotation represented by $R_2$, +then $R_1$ appears before $R_2$. +If $R_1$ and $R_2$ represent annotations from the same translation unit $T$, +any element in the returned \tcode{vector} between $R_1$ and $R_2$ +represents an annotation from $T$. +\begin{note} +The order in which two annotations appear is otherwise unspecified. +\end{note} +\begin{example} +\begin{codeblock} +[[=1]] void f(); +[[=2, =3]] void g(); +void g [[=4]] (); + +static_assert(annotations_of(^^f).size() == 1); +static_assert(annotations_of(^^g).size() == 3); +static_assert([: constant_of(annotations_of(^^g)[0]) :] == 2); +static_assert(extract(annotations_of(^^g)[1]) == 3); +static_assert(extract(annotations_of(^^g)[2]) == 4); + +struct Option { bool value; }; + +struct C { + [[=Option{true}]] int a; + [[=Option{false}]] int b; +}; + +static_assert(extract