16
16
use crate :: ast:: { AttrStyle , StmtKind } ;
17
17
use crate :: ast_traits:: { HasAttrs , HasTokens } ;
18
18
use crate :: token:: { self , Delimiter , Nonterminal , Token , TokenKind } ;
19
- use crate :: AttrVec ;
19
+ use crate :: { AttrVec , Attribute } ;
20
20
21
21
use rustc_data_structures:: stable_hasher:: { HashStable , StableHasher } ;
22
22
use rustc_data_structures:: sync:: { self , Lrc } ;
@@ -179,11 +179,10 @@ impl AttrTokenStream {
179
179
AttrTokenStream ( Lrc :: new ( tokens) )
180
180
}
181
181
182
- /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`.
183
- /// During conversion, `AttrTokenTree::AttrsTarget` get 'flattened'
184
- /// back to a `TokenStream` of the form `outer_attr attr_target`.
185
- /// If there are inner attributes, they are inserted into the proper
186
- /// place in the attribute target tokens.
182
+ /// Converts this `AttrTokenStream` to a plain `Vec<TokenTree>`. During
183
+ /// conversion, any `AttrTokenTree::AttrsTarget` gets "flattened" back to a
184
+ /// `TokenStream`, as described in the comment on
185
+ /// `attrs_and_tokens_to_token_trees`.
187
186
pub fn to_token_trees ( & self ) -> Vec < TokenTree > {
188
187
let mut res = Vec :: with_capacity ( self . 0 . len ( ) ) ;
189
188
for tree in self . 0 . iter ( ) {
@@ -200,67 +199,84 @@ impl AttrTokenStream {
200
199
) )
201
200
}
202
201
AttrTokenTree :: AttrsTarget ( target) => {
203
- let idx = target
204
- . attrs
205
- . partition_point ( |attr| matches ! ( attr. style, crate :: AttrStyle :: Outer ) ) ;
206
- let ( outer_attrs, inner_attrs) = target. attrs . split_at ( idx) ;
207
-
208
- let mut target_tokens = target. tokens . to_attr_token_stream ( ) . to_token_trees ( ) ;
209
- if !inner_attrs. is_empty ( ) {
210
- let mut found = false ;
211
- // Check the last two trees (to account for a trailing semi)
212
- for tree in target_tokens. iter_mut ( ) . rev ( ) . take ( 2 ) {
213
- if let TokenTree :: Delimited ( span, spacing, delim, delim_tokens) = tree {
214
- // Inner attributes are only supported on extern blocks, functions,
215
- // impls, and modules. All of these have their inner attributes
216
- // placed at the beginning of the rightmost outermost braced group:
217
- // e.g. fn foo() { #![my_attr] }
218
- //
219
- // Therefore, we can insert them back into the right location
220
- // without needing to do any extra position tracking.
221
- //
222
- // Note: Outline modules are an exception - they can
223
- // have attributes like `#![my_attr]` at the start of a file.
224
- // Support for custom attributes in this position is not
225
- // properly implemented - we always synthesize fake tokens,
226
- // so we never reach this code.
227
-
228
- let mut stream = TokenStream :: default ( ) ;
229
- for inner_attr in inner_attrs {
230
- stream. push_stream ( inner_attr. get_tokens ( ) ) ;
231
- }
232
- stream. push_stream ( delim_tokens. clone ( ) ) ;
233
- * tree = TokenTree :: Delimited ( * span, * spacing, * delim, stream) ;
234
- found = true ;
235
- break ;
236
- }
237
- }
238
-
239
- assert ! (
240
- found,
241
- "Failed to find trailing delimited group in: {target_tokens:?}"
242
- ) ;
243
- }
244
- for attr in outer_attrs {
245
- res. extend ( attr. get_tokens ( ) . 0 . iter ( ) . cloned ( ) ) ;
246
- }
247
- res. extend ( target_tokens) ;
202
+ attrs_and_tokens_to_token_trees ( & target. attrs , & target. tokens , & mut res) ;
248
203
}
249
204
}
250
205
}
251
206
res
252
207
}
253
208
}
254
209
210
+ // Converts multiple attributes and the tokens for a target AST node into token trees, and appends
211
+ // them to `res`.
212
+ //
213
+ // Example: if the AST node is "fn f() { blah(); }", then:
214
+ // - Simple if no attributes are present, e.g. "fn f() { blah(); }"
215
+ // - Simple if only outer attribute are present, e.g. "#[outer1] #[outer2] fn f() { blah(); }"
216
+ // - Trickier if inner attributes are present, because they must be moved within the AST node's
217
+ // tokens, e.g. "#[outer] fn f() { #![inner] blah() }"
218
+ fn attrs_and_tokens_to_token_trees (
219
+ attrs : & [ Attribute ] ,
220
+ target_tokens : & LazyAttrTokenStream ,
221
+ res : & mut Vec < TokenTree > ,
222
+ ) {
223
+ let idx = attrs. partition_point ( |attr| matches ! ( attr. style, crate :: AttrStyle :: Outer ) ) ;
224
+ let ( outer_attrs, inner_attrs) = attrs. split_at ( idx) ;
225
+
226
+ // Add outer attribute tokens.
227
+ for attr in outer_attrs {
228
+ res. extend ( attr. token_trees ( ) ) ;
229
+ }
230
+
231
+ // Add target AST node tokens.
232
+ res. extend ( target_tokens. to_attr_token_stream ( ) . to_token_trees ( ) ) ;
233
+
234
+ // Insert inner attribute tokens.
235
+ if !inner_attrs. is_empty ( ) {
236
+ let mut found = false ;
237
+ // Check the last two trees (to account for a trailing semi)
238
+ for tree in res. iter_mut ( ) . rev ( ) . take ( 2 ) {
239
+ if let TokenTree :: Delimited ( span, spacing, delim, delim_tokens) = tree {
240
+ // Inner attributes are only supported on extern blocks, functions,
241
+ // impls, and modules. All of these have their inner attributes
242
+ // placed at the beginning of the rightmost outermost braced group:
243
+ // e.g. fn foo() { #![my_attr] }
244
+ //
245
+ // Therefore, we can insert them back into the right location
246
+ // without needing to do any extra position tracking.
247
+ //
248
+ // Note: Outline modules are an exception - they can
249
+ // have attributes like `#![my_attr]` at the start of a file.
250
+ // Support for custom attributes in this position is not
251
+ // properly implemented - we always synthesize fake tokens,
252
+ // so we never reach this code.
253
+ let mut tts = vec ! [ ] ;
254
+ for inner_attr in inner_attrs {
255
+ tts. extend ( inner_attr. token_trees ( ) ) ;
256
+ }
257
+ tts. extend ( delim_tokens. 0 . iter ( ) . cloned ( ) ) ;
258
+ let stream = TokenStream :: new ( tts) ;
259
+ * tree = TokenTree :: Delimited ( * span, * spacing, * delim, stream) ;
260
+ found = true ;
261
+ break ;
262
+ }
263
+ }
264
+ assert ! ( found, "Failed to find trailing delimited group in: {res:?}" ) ;
265
+ }
266
+ }
267
+
255
268
/// Stores the tokens for an attribute target, along
256
269
/// with its attributes.
257
270
///
258
271
/// This is constructed during parsing when we need to capture
259
- /// tokens.
272
+ /// tokens, for `cfg` and `cfg_attr` attributes .
260
273
///
261
274
/// For example, `#[cfg(FALSE)] struct Foo {}` would
262
275
/// have an `attrs` field containing the `#[cfg(FALSE)]` attr,
263
276
/// and a `tokens` field storing the (unparsed) tokens `struct Foo {}`
277
+ ///
278
+ /// The `cfg`/`cfg_attr` processing occurs in
279
+ /// `StripUnconfigured::configure_tokens`.
264
280
#[ derive( Clone , Debug , Encodable , Decodable ) ]
265
281
pub struct AttrsTarget {
266
282
/// Attributes, both outer and inner.
@@ -437,18 +453,10 @@ impl TokenStream {
437
453
}
438
454
439
455
pub fn from_ast ( node : & ( impl HasAttrs + HasTokens + fmt:: Debug ) ) -> TokenStream {
440
- let Some ( tokens) = node. tokens ( ) else {
441
- panic ! ( "missing tokens for node: {:?}" , node) ;
442
- } ;
443
- let attrs = node. attrs ( ) ;
444
- let attr_stream = if attrs. is_empty ( ) {
445
- tokens. to_attr_token_stream ( )
446
- } else {
447
- let target =
448
- AttrsTarget { attrs : attrs. iter ( ) . cloned ( ) . collect ( ) , tokens : tokens. clone ( ) } ;
449
- AttrTokenStream :: new ( vec ! [ AttrTokenTree :: AttrsTarget ( target) ] )
450
- } ;
451
- TokenStream :: new ( attr_stream. to_token_trees ( ) )
456
+ let tokens = node. tokens ( ) . unwrap_or_else ( || panic ! ( "missing tokens for node: {:?}" , node) ) ;
457
+ let mut tts = vec ! [ ] ;
458
+ attrs_and_tokens_to_token_trees ( node. attrs ( ) , tokens, & mut tts) ;
459
+ TokenStream :: new ( tts)
452
460
}
453
461
454
462
pub fn from_nonterminal_ast ( nt : & Nonterminal ) -> TokenStream {
0 commit comments