11use super :: ptr:: P ;
2- use super :: tokenstream:: LazyTokenStream ;
2+ use super :: tokenstream:: { LazyTokenStream , Spacing , AttributesData , PreexpTokenTree , PreexpTokenStream } ;
33use super :: { Arm , Field , FieldPat , GenericParam , Param , StructField , Variant } ;
4- use super :: { AssocItem , Expr , ForeignItem , Item , Local } ;
4+ use super :: { AssocItem , Expr , ForeignItem , Item , Local , MacCallStmt } ;
55use super :: { AttrItem , AttrKind , Block , Pat , Path , Ty , Visibility } ;
66use super :: { AttrVec , Attribute , Stmt , StmtKind } ;
7+ use rustc_span:: sym;
78
89/// An `AstLike` represents an AST node (or some wrapper around
910/// and AST node) which stores some combination of attributes
1011/// and tokens.
1112pub trait AstLike : Sized {
13+ const SUPPORTS_INNER_ATTRS : bool ;
1214 fn attrs ( & self ) -> & [ Attribute ] ;
1315 fn visit_attrs ( & mut self , f : impl FnOnce ( & mut Vec < Attribute > ) ) ;
1416 /// Called by `Parser::collect_tokens` to store the collected
1517 /// tokens inside an AST node
16- fn finalize_tokens ( & mut self , _tokens : LazyTokenStream ) {
18+ fn finalize_tokens ( & mut self , _tokens : LazyTokenStream ) -> Option < AttributesData > {
1719 // This default impl makes this trait easier to implement
1820 // in tools like `rust-analyzer`
1921 panic ! ( "`finalize_tokens` is not supported!" )
2022 }
23+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) ;
2124}
2225
2326impl < T : AstLike + ' static > AstLike for P < T > {
27+ const SUPPORTS_INNER_ATTRS : bool = T :: SUPPORTS_INNER_ATTRS ;
2428 fn attrs ( & self ) -> & [ Attribute ] {
2529 ( * * self ) . attrs ( )
2630 }
2731 fn visit_attrs ( & mut self , f : impl FnOnce ( & mut Vec < Attribute > ) ) {
2832 ( * * self ) . visit_attrs ( f) ;
2933 }
30- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
34+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
3135 ( * * self ) . finalize_tokens ( tokens)
3236 }
37+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
38+ ( * * self ) . visit_tokens ( f) ;
39+ }
3340}
3441
3542fn visit_attrvec ( attrs : & mut AttrVec , f : impl FnOnce ( & mut Vec < Attribute > ) ) {
@@ -41,6 +48,10 @@ fn visit_attrvec(attrs: &mut AttrVec, f: impl FnOnce(&mut Vec<Attribute>)) {
4148}
4249
4350impl AstLike for StmtKind {
51+ // This might be an `StmtKind::Item`, which contains
52+ // an item that supports inner attrs
53+ const SUPPORTS_INNER_ATTRS : bool = true ;
54+
4455 fn attrs ( & self ) -> & [ Attribute ] {
4556 match * self {
4657 StmtKind :: Local ( ref local) => local. attrs ( ) ,
@@ -60,53 +71,85 @@ impl AstLike for StmtKind {
6071 StmtKind :: MacCall ( mac) => visit_attrvec ( & mut mac. attrs , f) ,
6172 }
6273 }
63- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
64- let stmt_tokens = match self {
65- StmtKind :: Local ( ref mut local) => & mut local. tokens ,
66- StmtKind :: Item ( ref mut item) => & mut item. tokens ,
67- StmtKind :: Expr ( ref mut expr) | StmtKind :: Semi ( ref mut expr) => & mut expr. tokens ,
68- StmtKind :: Empty => return ,
69- StmtKind :: MacCall ( ref mut mac) => & mut mac. tokens ,
74+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
75+ match self {
76+ StmtKind :: Local ( ref mut local) => local. finalize_tokens ( tokens) ,
77+ StmtKind :: MacCall ( ref mut mac) => mac. finalize_tokens ( tokens) ,
78+ StmtKind :: Expr ( ref mut expr) | StmtKind :: Semi ( ref mut expr) => {
79+ expr. finalize_tokens ( tokens)
80+ }
81+ StmtKind :: Item ( ref mut item) => item. finalize_tokens ( tokens) ,
82+ StmtKind :: Empty => None ,
83+ }
84+ }
85+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
86+ let tokens = match self {
87+ StmtKind :: Local ( ref mut local) => Some ( & mut local. tokens ) ,
88+ StmtKind :: Item ( ref mut item) => Some ( & mut item. tokens ) ,
89+ StmtKind :: Expr ( ref mut expr) | StmtKind :: Semi ( ref mut expr) => Some ( & mut expr. tokens ) ,
90+ StmtKind :: Empty => None ,
91+ StmtKind :: MacCall ( ref mut mac) => Some ( & mut mac. tokens ) ,
7092 } ;
71- if stmt_tokens . is_none ( ) {
72- * stmt_tokens = Some ( tokens) ;
93+ if let Some ( tokens ) = tokens {
94+ f ( tokens) ;
7395 }
7496 }
7597}
7698
7799impl AstLike for Stmt {
100+ const SUPPORTS_INNER_ATTRS : bool = StmtKind :: SUPPORTS_INNER_ATTRS ;
101+
78102 fn attrs ( & self ) -> & [ Attribute ] {
79103 self . kind . attrs ( )
80104 }
81105
82106 fn visit_attrs ( & mut self , f : impl FnOnce ( & mut Vec < Attribute > ) ) {
83107 self . kind . visit_attrs ( f) ;
84108 }
85- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
109+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
86110 self . kind . finalize_tokens ( tokens)
87111 }
112+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
113+ self . kind . visit_tokens ( f)
114+ }
88115}
89116
90117impl AstLike for Attribute {
118+ const SUPPORTS_INNER_ATTRS : bool = false ;
119+
91120 fn attrs ( & self ) -> & [ Attribute ] {
92121 & [ ]
93122 }
94123 fn visit_attrs ( & mut self , _f : impl FnOnce ( & mut Vec < Attribute > ) ) { }
95- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
124+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
96125 match & mut self . kind {
97126 AttrKind :: Normal ( _, attr_tokens) => {
98127 if attr_tokens. is_none ( ) {
99128 * attr_tokens = Some ( tokens) ;
100129 }
130+ None
101131 }
102132 AttrKind :: DocComment ( ..) => {
103133 panic ! ( "Called finalize_tokens on doc comment attr {:?}" , self )
104134 }
105135 }
106136 }
137+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
138+ match & mut self . kind {
139+ AttrKind :: Normal ( _, attr_tokens) => {
140+ f ( attr_tokens) ;
141+ }
142+ AttrKind :: DocComment ( ..) => {
143+ panic ! ( "Called visit_tokens on doc comment attr {:?}" , self )
144+ }
145+ }
146+
147+ }
107148}
108149
109150impl < T : AstLike > AstLike for Option < T > {
151+ const SUPPORTS_INNER_ATTRS : bool = T :: SUPPORTS_INNER_ATTRS ;
152+
110153 fn attrs ( & self ) -> & [ Attribute ] {
111154 self . as_ref ( ) . map ( |inner| inner. attrs ( ) ) . unwrap_or ( & [ ] )
112155 }
@@ -115,13 +158,26 @@ impl<T: AstLike> AstLike for Option<T> {
115158 inner. visit_attrs ( f) ;
116159 }
117160 }
118- fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) {
161+ fn finalize_tokens ( & mut self , tokens : LazyTokenStream ) -> Option < AttributesData > {
162+ self . as_mut ( ) . and_then ( |inner| inner. finalize_tokens ( tokens) )
163+ }
164+ fn visit_tokens ( & mut self , f : impl FnOnce ( & mut Option < LazyTokenStream > ) ) {
119165 if let Some ( inner) = self {
120- inner. finalize_tokens ( tokens ) ;
166+ inner. visit_tokens ( f ) ;
121167 }
122168 }
123169}
124170
171+ // NOTE: Builtin attributes like `cfg` and `cfg_attr` cannot be renamed via imports.
172+ // Therefore, the absence of a literal `cfg` or `cfg_attr` guarantees that
173+ // we don't need to do any eager expansion.
174+ pub fn has_cfg_or_cfg_any ( attrs : & [ Attribute ] ) -> bool {
175+ attrs. iter ( ) . any ( |attr| {
176+ attr. ident ( ) . map_or ( false , |ident| ident. name == sym:: cfg || ident. name == sym:: cfg_attr)
177+ } )
178+ }
179+
180+
125181/// Helper trait for the macros below. Abstracts over
126182/// the two types of attribute fields that AST nodes
127183/// may have (`Vec<Attribute>` or `AttrVec`)
@@ -142,8 +198,13 @@ impl VecOrAttrVec for AttrVec {
142198}
143199
144200macro_rules! derive_has_tokens_and_attrs {
145- ( $( $ty: path) ,* ) => { $(
201+ (
202+ const SUPPORTS_INNER_ATTRS : bool = $inner_attrs: literal;
203+ $( $ty: path) ,*
204+ ) => { $(
146205 impl AstLike for $ty {
206+ const SUPPORTS_INNER_ATTRS : bool = $inner_attrs;
207+
147208 fn attrs( & self ) -> & [ Attribute ] {
148209 & self . attrs
149210 }
@@ -152,19 +213,31 @@ macro_rules! derive_has_tokens_and_attrs {
152213 VecOrAttrVec :: visit( & mut self . attrs, f)
153214 }
154215
155- fn finalize_tokens( & mut self , tokens: LazyTokenStream ) {
216+ fn finalize_tokens( & mut self , tokens: LazyTokenStream ) -> Option < AttributesData > {
156217 if self . tokens. is_none( ) {
157218 self . tokens = Some ( tokens) ;
158219 }
159220
221+ if has_cfg_or_cfg_any( & self . attrs) {
222+ Some ( AttributesData { attrs: self . attrs. clone( ) . into( ) , tokens: self . tokens. clone( ) . unwrap( ) } )
223+ } else {
224+ None
225+ }
226+ }
227+
228+ fn visit_tokens( & mut self , f: impl FnOnce ( & mut Option <LazyTokenStream >) ) {
229+ f( & mut self . tokens)
160230 }
231+
161232 }
162233 ) * }
163234}
164235
165236macro_rules! derive_has_attrs_no_tokens {
166237 ( $( $ty: path) ,* ) => { $(
167238 impl AstLike for $ty {
239+ const SUPPORTS_INNER_ATTRS : bool = false ;
240+
168241 fn attrs( & self ) -> & [ Attribute ] {
169242 & self . attrs
170243 }
@@ -173,35 +246,61 @@ macro_rules! derive_has_attrs_no_tokens {
173246 VecOrAttrVec :: visit( & mut self . attrs, f)
174247 }
175248
176- fn finalize_tokens( & mut self , _tokens: LazyTokenStream ) { }
249+ fn finalize_tokens( & mut self , tokens: LazyTokenStream ) -> Option <AttributesData > {
250+ if has_cfg_or_cfg_any( & self . attrs) {
251+ Some ( AttributesData { attrs: self . attrs. clone( ) . into( ) , tokens } )
252+ } else {
253+ None
254+ }
255+ }
256+ fn visit_tokens( & mut self , _f: impl FnOnce ( & mut Option <LazyTokenStream >) ) { }
257+
177258 }
178259 ) * }
179260}
180261
181262macro_rules! derive_has_tokens_no_attrs {
182263 ( $( $ty: path) ,* ) => { $(
183264 impl AstLike for $ty {
265+ const SUPPORTS_INNER_ATTRS : bool = false ;
266+
184267 fn attrs( & self ) -> & [ Attribute ] {
185268 & [ ]
186269 }
187270
188271 fn visit_attrs( & mut self , _f: impl FnOnce ( & mut Vec <Attribute >) ) {
189272 }
190273
191- fn finalize_tokens( & mut self , tokens: LazyTokenStream ) {
274+ fn finalize_tokens( & mut self , tokens: LazyTokenStream ) -> Option <AttributesData > {
275+ // FIXME - stoer them directly?
192276 if self . tokens. is_none( ) {
193- self . tokens = Some ( tokens) ;
277+ self . tokens = Some ( LazyTokenStream :: new( PreexpTokenStream :: new( vec![
278+ ( PreexpTokenTree :: Attributes ( AttributesData {
279+ attrs: Default :: default ( ) ,
280+ tokens,
281+ } ) , Spacing :: Alone ) ] ) ) ) ;
194282 }
195-
283+ None
284+ }
285+ fn visit_tokens( & mut self , f: impl FnOnce ( & mut Option <LazyTokenStream >) ) {
286+ f( & mut self . tokens)
196287 }
197288 }
198289 ) * }
199290}
200291
201- // These AST nodes support both inert and active
202- // attributes, so they also have tokens.
292+ // These ast nodes support both active and inert attributes,
293+ // so they have tokens collected to pass to proc macros
294+ derive_has_tokens_and_attrs ! {
295+ // Both `Item` and `AssocItem` can have bodies, which
296+ // can contain inner attributes
297+ const SUPPORTS_INNER_ATTRS : bool = true ;
298+ Item , AssocItem
299+ }
300+
203301derive_has_tokens_and_attrs ! {
204- Item , Expr , Local , AssocItem , ForeignItem
302+ const SUPPORTS_INNER_ATTRS : bool = false ;
303+ ForeignItem , Expr , Local , MacCallStmt
205304}
206305
207306// These ast nodes only support inert attributes, so they don't
0 commit comments