Skip to content

Commit d7ff520

Browse files
authored
Merge 2025-06 CWG Motion 5
P3394R4 Annotations for Reflection
2 parents 29d39cd + 2f01c5c commit d7ff520

File tree

5 files changed

+211
-12
lines changed

5 files changed

+211
-12
lines changed

source/basic.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5590,6 +5590,7 @@
55905590
\item a structured binding\iref{dcl.struct.bind},
55915591
\item a function\iref{dcl.fct},
55925592
\item an enumerator\iref{dcl.enum},
5593+
\item an annotation\iref{dcl.attr.grammar},
55935594
\item a type alias\iref{dcl.typedef},
55945595
\item a type\iref{basic.types},
55955596
\item a class member\iref{class.mem},

source/declarations.tex

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9360,7 +9360,7 @@
93609360

93619361
\pnum
93629362
\indextext{attribute!syntax and semantics}%
9363-
Attributes specify additional information for various source constructs
9363+
Attributes and annotations specify additional information for various source constructs
93649364
such as types, variables, names, contract assertions, blocks, or translation units.
93659365

93669366
\begin{bnf}
@@ -9371,6 +9371,7 @@
93719371
\begin{bnf}
93729372
\nontermdef{attribute-specifier}\br
93739373
\terminal{[} \terminal{[} \opt{attribute-using-prefix} attribute-list \terminal{]} \terminal{]}\br
9374+
\terminal{[} \terminal{[} annotation-list \terminal{]} \terminal{]}\br
93749375
alignment-specifier
93759376
\end{bnf}
93769377

@@ -9393,11 +9394,22 @@
93939394
attribute-list \terminal{,} attribute \terminal{...}
93949395
\end{bnf}
93959396

9397+
\begin{bnf}
9398+
\nontermdef{annotation-list}\br
9399+
annotation \opt{\terminal{...}}\br
9400+
annotation-list \terminal{,} annotation \opt{\terminal{...}}
9401+
\end{bnf}
9402+
93969403
\begin{bnf}
93979404
\nontermdef{attribute}\br
93989405
attribute-token \opt{attribute-argument-clause}
93999406
\end{bnf}
94009407

9408+
\begin{bnf}
9409+
\nontermdef{annotation}\br
9410+
\terminal{=} constant-expression
9411+
\end{bnf}
9412+
94019413
\begin{bnf}
94029414
\nontermdef{attribute-token}\br
94039415
identifier\br
@@ -9470,10 +9482,11 @@
94709482
In an \grammarterm{attribute-list}, an ellipsis may appear only if that
94719483
\grammarterm{attribute}'s specification permits it. An \grammarterm{attribute} followed
94729484
by an ellipsis is a pack expansion\iref{temp.variadic}.
9473-
An \grammarterm{attribute-specifier}
9474-
that contains no \grammarterm{attribute}{s} and no \grammarterm{alignment-specifier}
9475-
has no
9476-
effect. The order in which the \grammarterm{attribute-token}{s} appear in an
9485+
An \grammarterm{attribute-specifier} that contains
9486+
an \grammarterm{attribute-list} with no \grammarterm{attribute}s
9487+
and no \grammarterm{alignment-specifier}
9488+
has no effect.
9489+
The order in which the \grammarterm{attribute-token}{s} appear in an
94779490
\grammarterm{attribute-list} is not significant. If a
94789491
keyword\iref{lex.key}
94799492
or an alternative token\iref{lex.digraph} that satisfies the syntactic requirements
@@ -9484,6 +9497,10 @@
94849497
\grammarterm{attribute-token}. The \grammarterm{attribute-token} determines additional
94859498
requirements on the \grammarterm{attribute-argument-clause} (if any).
94869499

9500+
\pnum
9501+
An \grammarterm{annotation} followed by an ellipsis
9502+
is a pack expansion\iref{temp.variadic}.
9503+
94879504
\pnum
94889505
Each \grammarterm{attribute-specifier-seq} is said to \defn{appertain} to some entity or
94899506
statement, identified by the syntactic context
@@ -10181,5 +10198,56 @@
1018110198
if their respective types are all empty.
1018210199
\end{example}
1018310200

10201+
\rSec2[dcl.attr.annotation]{Annotations}%
10202+
\indextext{attribute!annotations}
10203+
10204+
\pnum
10205+
An annotation may be applied to any declaration of a
10206+
type,
10207+
type alias,
10208+
variable,
10209+
function,
10210+
namespace,
10211+
enumerator,
10212+
\grammarterm{base-specifier}, or
10213+
non-static data member.
10214+
10215+
\pnum
10216+
Let $E$ be the expression
10217+
\tcode{std::meta::reflect_constant(\grammarterm{constant-expression})}.
10218+
$E$ shall be a constant expression;
10219+
the result of $E$ is the \defnadj{underlying}{constant} of the annotation.
10220+
10221+
\pnum
10222+
Each \grammarterm{annotation} produces a unique annotation.
10223+
10224+
\pnum
10225+
Substituting into an \grammarterm{annotation}
10226+
is not in the immediate context.
10227+
\begin{example}
10228+
\begin{codeblock}
10229+
[[=1]] void f();
10230+
[[=2, =3, =2]] void g();
10231+
void g [[=4, =2]] ();
10232+
\end{codeblock}
10233+
\tcode{f} has one annotation
10234+
and \tcode{g} has five annotations.
10235+
These can be queried with metafunctions
10236+
such as \tcode{std::\brk{}meta::\brk{}anno\-tations_of}\iref{meta.reflection.annotation}.
10237+
\end{example}
10238+
\begin{example}
10239+
\begin{codeblock}
10240+
template<class T>
10241+
[[=T::type()]] void f(T t);
10242+
10243+
void f(int);
10244+
10245+
void g() {
10246+
f(0); // OK
10247+
f('0'); // error, substituting into the annotation results in an invalid expression
10248+
}
10249+
\end{codeblock}
10250+
\end{example}
10251+
1018410252
\indextext{attribute|)}%
1018510253
\indextext{declaration|)}

source/expressions.tex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7608,6 +7608,7 @@
76087608
\item represent values that are template-argument-equivalent\iref{temp.type},
76097609
\item represent the same object,
76107610
\item represent the same entity,
7611+
\item represent the same annotation\iref{dcl.attr.annotation},
76117612
\item represent the same direct base class relationship, or
76127613
\item represent equal data member descriptions\iref{class.mem.general},
76137614
\end{itemize}

source/meta.tex

Lines changed: 132 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2625,6 +2625,7 @@
26252625

26262626
consteval bool is_bit_field(info r);
26272627
consteval bool is_enumerator(info r);
2628+
consteval bool is_annotation(info r);
26282629

26292630
consteval bool is_const(info r);
26302631
consteval bool is_volatile(info r);
@@ -2912,6 +2913,10 @@
29122913
consteval info variant_alternative(size_t index, info type);
29132914

29142915
consteval strong_ordering type_order(info type_a, info type_b);
2916+
2917+
// \ref{meta.reflection.annotation}, annotation reflection
2918+
consteval vector<info> annotations_of(info item);
2919+
consteval vector<info> annotations_of_with_type(info item, info type);
29152920
}
29162921
\end{codeblock}
29172922

@@ -3243,6 +3248,7 @@
32433248
\returns
32443249
\tcode{true} if \tcode{r} represents a
32453250
value,
3251+
annotation,
32463252
object,
32473253
variable,
32483254
function whose type does not contain an undeduced placeholder type
@@ -3277,6 +3283,9 @@
32773283
non-static data member, or
32783284
unnamed bit-field,
32793285
then the type of what is represented by \tcode{r}.
3286+
\item
3287+
Otherwise, if \tcode{r} represents an annotation,
3288+
then \tcode{type_of(constant_of(r))}.
32803289
\item
32813290
Otherwise, if \tcode{r} represents
32823291
an enumerator $N$ of an enumeration $E$, then:
@@ -3358,19 +3367,26 @@
33583367

33593368
\begin{itemdescr}
33603369
\pnum
3361-
Let \tcode{\placeholder{R}} be a constant expression of type \tcode{info}
3362-
such that \tcode{\placeholder{R} == r} is \tcode{true}.
3370+
Let $R$ be a constant expression of type \tcode{info}
3371+
such that \tcode{$R$ == r} is \tcode{true}.
3372+
If \tcode{r} represents an annotation,
3373+
then let $C$ be its underlying constant.
33633374

33643375
\pnum
33653376
\constantwhen
3366-
\tcode{[: \placeholder{R} :]} is a valid
3377+
Either \tcode{r} represents an annotation or
3378+
\tcode{[: $R$ :]} is a valid
33673379
\grammarterm{splice-expression}\iref{expr.prim.splice}.
33683380

33693381
\pnum
33703382
\effects
33713383
Equivalent to:
33723384
\begin{codeblock}
3373-
return reflect_constant([: @\placeholder{R}@ :]);
3385+
if constexpr (is_annotation(@$R$@)) {
3386+
return @$C$@;
3387+
} else {
3388+
return reflect_constant([: @$R$@ :]);
3389+
}
33743390
\end{codeblock}
33753391
\begin{example}
33763392
\begin{codeblock}
@@ -3552,14 +3568,16 @@
35523568
\end{itemdescr}
35533569

35543570
\indexlibraryglobal{is_enumerator}%
3571+
\indexlibraryglobal{is_annotation}%
35553572
\begin{itemdecl}
35563573
consteval bool is_enumerator(info r);
3574+
consteval bool is_annotation(info r);
35573575
\end{itemdecl}
35583576

35593577
\begin{itemdescr}
35603578
\pnum
35613579
\returns
3562-
\tcode{true} if \tcode{r} represents an enumerator.
3580+
\tcode{true} if \tcode{r} represents an enumerator or annotation, respectively.
35633581
Otherwise, \tcode{false}.
35643582
\end{itemdescr}
35653583

@@ -5946,6 +5964,115 @@
59465964
represented by \tcode{dealias(t1)} and \tcode{dealias(t2)}, respectively.
59475965
\end{itemdescr}
59485966

5967+
\rSec2[meta.reflection.annotation]{Annotation reflection}
5968+
5969+
\indexlibraryglobal{annotations_of}%
5970+
\begin{itemdecl}
5971+
consteval vector<info> annotations_of(info item);
5972+
\end{itemdecl}
5973+
5974+
\begin{itemdescr}
5975+
\pnum
5976+
\constantwhen
5977+
\tcode{item} represents a
5978+
type,
5979+
type alias,
5980+
variable,
5981+
function,
5982+
namespace,
5983+
enumerator,
5984+
direct base class relationship, or
5985+
non-static data member.
5986+
5987+
%FIXME: it is highly unusual for this subclause to put Let paragraphs after Constant When
5988+
\pnum
5989+
Let $E$ be
5990+
\begin{itemize}
5991+
\item
5992+
the corresponding \grammarterm{base-specifier}
5993+
if \tcode{item} represents a direct base class relationship,
5994+
\item
5995+
otherwise, the entity represented by \tcode{item}.
5996+
\end{itemize}
5997+
5998+
\pnum
5999+
\returns
6000+
A \tcode{vector} containing all of the reflections $R$
6001+
representing each annotation applying to each declaration of $E$ that precedes either
6002+
some point in the evaluation context\iref{expr.const} or
6003+
a point immediately following the \grammarterm{class-specifier}
6004+
of the outermost class for which such a point is in a complete-class context.
6005+
For any two reflections $R_1$ and $R_2$ in the returned \tcode{vector},
6006+
if the annotation represented by $R_1$ precedes the annotation represented by $R_2$,
6007+
then $R_1$ appears before $R_2$.
6008+
If $R_1$ and $R_2$ represent annotations from the same translation unit $T$,
6009+
any element in the returned \tcode{vector} between $R_1$ and $R_2$
6010+
represents an annotation from $T$.
6011+
\begin{note}
6012+
The order in which two annotations appear is otherwise unspecified.
6013+
\end{note}
6014+
\begin{example}
6015+
\begin{codeblock}
6016+
[[=1]] void f();
6017+
[[=2, =3]] void g();
6018+
void g [[=4]] ();
6019+
6020+
static_assert(annotations_of(^^f).size() == 1);
6021+
static_assert(annotations_of(^^g).size() == 3);
6022+
static_assert([: constant_of(annotations_of(^^g)[0]) :] == 2);
6023+
static_assert(extract<int>(annotations_of(^^g)[1]) == 3);
6024+
static_assert(extract<int>(annotations_of(^^g)[2]) == 4);
6025+
6026+
struct Option { bool value; };
6027+
6028+
struct C {
6029+
[[=Option{true}]] int a;
6030+
[[=Option{false}]] int b;
6031+
};
6032+
6033+
static_assert(extract<Option>(annotations_of(^^C::a)[0]).value);
6034+
static_assert(!extract<Option>(annotations_of(^^C::b)[0]).value);
6035+
6036+
template<class T>
6037+
struct [[=42]] D { };
6038+
6039+
constexpr std::meta::info a1 = annotations_of(^^D<int>)[0];
6040+
constexpr std::meta::info a2 = annotations_of(^^D<char>)[0];
6041+
static_assert(a1 != a2);
6042+
static_assert(constant_of(a1) == constant_of(a2));
6043+
6044+
[[=1]] int x, y;
6045+
static_assert(annotations_of(^^x)[0] == annotations_of(^^y)[0]);
6046+
\end{codeblock}
6047+
\end{example}
6048+
\end{itemdescr}
6049+
6050+
\indexlibraryglobal{annotations_of_with_type}%
6051+
\begin{itemdecl}
6052+
consteval vector<info> annotations_of_with_type(info item, info type);
6053+
\end{itemdecl}
6054+
6055+
\begin{itemdescr}
6056+
\pnum
6057+
\constantwhen
6058+
\begin{itemize}
6059+
\item
6060+
\tcode{annotations_of(item)} is a constant expression and
6061+
\item
6062+
\tcode{dealias(type)} represents a type that is complete
6063+
from some point in the evaluation context.
6064+
\end{itemize}
6065+
6066+
\pnum
6067+
\returns
6068+
A \tcode{vector} containing each element \tcode{e} of \tcode{annotations_of(item)}
6069+
where
6070+
\begin{codeblock}
6071+
remove_const(type_of(e)) == remove_const(type)
6072+
\end{codeblock}
6073+
is \tcode{true}, preserving their order.
6074+
\end{itemdescr}
6075+
59496076
\rSec1[ratio]{Compile-time rational arithmetic}
59506077

59516078
\rSec2[ratio.general]{General}

source/templates.tex

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,8 +3204,10 @@
32043204
\item In a \grammarterm{template-argument-list}\iref{temp.arg};
32053205
the pattern is a \grammarterm{template-argument}.
32063206

3207-
\item In an \grammarterm{attribute-list}\iref{dcl.attr.grammar}; the pattern is
3208-
an \grammarterm{attribute}.
3207+
\item In an \grammarterm{attribute-list}\iref{dcl.attr.grammar};
3208+
the pattern is an \grammarterm{attribute}.
3209+
In an \grammarterm{annotation-list};
3210+
the pattern is an \grammarterm{annotation}.
32093211

32103212
\item In an \grammarterm{alignment-specifier}\iref{dcl.align}; the pattern is
32113213
the \grammarterm{alignment-specifier} without the ellipsis.

0 commit comments

Comments
 (0)