@@ -134,30 +134,17 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
134
134
node_replacements. array_windows ( )
135
135
{
136
136
assert ! (
137
- node_range. 0 . end <= next_node_range. 0 . start
138
- || node_range. 0 . end >= next_node_range. 0 . end,
139
- "Node ranges should be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})" ,
137
+ node_range. 0 . end <= next_node_range. 0 . start,
138
+ "Node ranges should be disjoint: ({:?}, {:?}) ({:?}, {:?})" ,
140
139
node_range,
141
140
tokens,
142
141
next_node_range,
143
142
next_tokens,
144
143
) ;
145
144
}
146
145
147
- // Process the replace ranges, starting from the highest start
148
- // position and working our way back. If have tokens like:
149
- //
150
- // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }`
151
- //
152
- // Then we will generate replace ranges for both
153
- // the `#[cfg(FALSE)] field: bool` and the entire
154
- // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }`
155
- //
156
- // By starting processing from the replace range with the greatest
157
- // start position, we ensure that any (outer) replace range which
158
- // encloses another (inner) replace range will fully overwrite the
159
- // inner range's replacement.
160
- for ( node_range, target) in node_replacements. into_iter ( ) . rev ( ) {
146
+ // Process the replace ranges.
147
+ for ( node_range, target) in node_replacements. into_iter ( ) {
161
148
assert ! (
162
149
!node_range. 0 . is_empty( ) ,
163
150
"Cannot replace an empty node range: {:?}" ,
@@ -234,6 +221,8 @@ impl<'a> Parser<'a> {
234
221
force_collect : ForceCollect ,
235
222
f : impl FnOnce ( & mut Self , AttrVec ) -> PResult < ' a , ( R , Trailing , UsePreAttrPos ) > ,
236
223
) -> PResult < ' a , R > {
224
+ let possible_capture_mode = self . capture_cfg ;
225
+
237
226
// We must collect if anything could observe the collected tokens, i.e.
238
227
// if any of the following conditions hold.
239
228
// - We are force collecting tokens (because force collection requires
@@ -244,9 +233,9 @@ impl<'a> Parser<'a> {
244
233
// - Our target supports custom inner attributes (custom
245
234
// inner attribute invocation might require token capturing).
246
235
|| R :: SUPPORTS_CUSTOM_INNER_ATTRS
247
- // - We are in `capture_cfg` mode (which requires tokens if
236
+ // - We are in "possible capture mode" (which requires tokens if
248
237
// the parsed node has `#[cfg]` or `#[cfg_attr]` attributes).
249
- || self . capture_cfg ;
238
+ || possible_capture_mode ;
250
239
if !needs_collection {
251
240
return Ok ( f ( self , attrs. attrs ) ?. 0 ) ;
252
241
}
@@ -267,7 +256,21 @@ impl<'a> Parser<'a> {
267
256
res?
268
257
} ;
269
258
270
- // When we're not in `capture_cfg` mode, then skip collecting and
259
+ // Ignore any attributes we've previously processed. This happens when
260
+ // an inner call to `collect_tokens` returns an AST node and then an
261
+ // outer call ends up with the same AST node without any additional
262
+ // wrapping layer.
263
+ let ret_attrs: AttrVec = ret
264
+ . attrs ( )
265
+ . iter ( )
266
+ . cloned ( )
267
+ . filter ( |attr| {
268
+ let is_unseen = self . capture_state . seen_attrs . insert ( attr. id ) ;
269
+ is_unseen
270
+ } )
271
+ . collect ( ) ;
272
+
273
+ // When we're not in "definite capture mode", then skip collecting and
271
274
// return early if either of the following conditions hold.
272
275
// - `None`: Our target doesn't support tokens at all (e.g. `NtIdent`).
273
276
// - `Some(Some(_))`: Our target already has tokens set (e.g. we've
@@ -278,7 +281,10 @@ impl<'a> Parser<'a> {
278
281
// Note that this check is independent of `force_collect`. There's no
279
282
// need to collect tokens when we don't support tokens or already have
280
283
// tokens.
281
- if !self . capture_cfg && matches ! ( ret. tokens_mut( ) , None | Some ( Some ( _) ) ) {
284
+ let definite_capture_mode = self . capture_cfg
285
+ && matches ! ( self . capture_state. capturing, Capturing :: Yes )
286
+ && has_cfg_or_cfg_attr ( & ret_attrs) ;
287
+ if !definite_capture_mode && matches ! ( ret. tokens_mut( ) , None | Some ( Some ( _) ) ) {
282
288
return Ok ( ret) ;
283
289
}
284
290
@@ -297,12 +303,12 @@ impl<'a> Parser<'a> {
297
303
// outer and inner attributes. So this check is more precise than
298
304
// the earlier `needs_tokens` check, and we don't need to
299
305
// check `R::SUPPORTS_CUSTOM_INNER_ATTRS`.)
300
- || needs_tokens ( ret . attrs ( ) )
301
- // - We are in `capture_cfg` mode and there are `#[cfg]` or
302
- // `#[cfg_attr]` attributes. (During normal non-`capture_cfg`
303
- // parsing, we don't need any special capturing for those
304
- // attributes, because they're builtin.)
305
- || ( self . capture_cfg && has_cfg_or_cfg_attr ( ret . attrs ( ) ) ) ;
306
+ || needs_tokens ( & ret_attrs )
307
+ // - We are in "definite capture mode", which requires that there
308
+ // are `#[cfg]` or `#[ cfg_attr]` attributes. (During normal
309
+ // non-`capture_cfg` parsing, we don't need any special capturing
310
+ // for those attributes, because they're builtin.)
311
+ || definite_capture_mode ;
306
312
if !needs_collection {
307
313
return Ok ( ret) ;
308
314
}
@@ -336,7 +342,7 @@ impl<'a> Parser<'a> {
336
342
// `Parser::parse_inner_attributes`, and pair them in a `ParserReplacement` with `None`,
337
343
// which means the relevant tokens will be removed. (More details below.)
338
344
let mut inner_attr_parser_replacements = Vec :: new ( ) ;
339
- for attr in ret . attrs ( ) {
345
+ for attr in ret_attrs . iter ( ) {
340
346
if attr. style == ast:: AttrStyle :: Inner {
341
347
if let Some ( inner_attr_parser_range) =
342
348
self . capture_state . inner_attr_parser_ranges . remove ( & attr. id )
@@ -359,11 +365,10 @@ impl<'a> Parser<'a> {
359
365
// from `ParserRange` form to `NodeRange` form. We will perform the actual
360
366
// replacement only when we convert the `LazyAttrTokenStream` to an
361
367
// `AttrTokenStream`.
362
- self . capture_state . parser_replacements
363
- [ parser_replacements_start..parser_replacements_end]
364
- . iter ( )
365
- . cloned ( )
366
- . chain ( inner_attr_parser_replacements. iter ( ) . cloned ( ) )
368
+ self . capture_state
369
+ . parser_replacements
370
+ . drain ( parser_replacements_start..parser_replacements_end)
371
+ . chain ( inner_attr_parser_replacements. into_iter ( ) )
367
372
. map ( |( parser_range, data) | {
368
373
( NodeRange :: new ( parser_range, collect_pos. start_pos ) , data)
369
374
} )
@@ -399,20 +404,18 @@ impl<'a> Parser<'a> {
399
404
break_last_token : self . break_last_token ,
400
405
node_replacements,
401
406
} ) ;
407
+ let mut tokens_used = false ;
402
408
403
409
// If we support tokens and don't already have them, store the newly captured tokens.
404
410
if let Some ( target_tokens @ None ) = ret. tokens_mut ( ) {
411
+ tokens_used = true ;
405
412
* target_tokens = Some ( tokens. clone ( ) ) ;
406
413
}
407
414
408
- // If `capture_cfg` is set and we're inside a recursive call to
409
- // `collect_tokens`, then we need to register a replace range if we
410
- // have `#[cfg]` or `#[cfg_attr]`. This allows us to run eager
411
- // cfg-expansion on the captured token stream.
412
- if self . capture_cfg
413
- && matches ! ( self . capture_state. capturing, Capturing :: Yes )
414
- && has_cfg_or_cfg_attr ( ret. attrs ( ) )
415
- {
415
+ // If in "definite capture mode" we need to register a replace range
416
+ // for the `#[cfg]` and/or `#[cfg_attr]` attrs. This allows us to run
417
+ // eager cfg-expansion on the captured token stream.
418
+ if definite_capture_mode {
416
419
assert ! ( !self . break_last_token, "Should not have unglued last token with cfg attr" ) ;
417
420
418
421
// What is the status here when parsing the example code at the top of this method?
@@ -429,7 +432,8 @@ impl<'a> Parser<'a> {
429
432
// cfg-expand this AST node.
430
433
let start_pos =
431
434
if has_outer_attrs { attrs. start_pos . unwrap ( ) } else { collect_pos. start_pos } ;
432
- let target = AttrsTarget { attrs : ret. attrs ( ) . iter ( ) . cloned ( ) . collect ( ) , tokens } ;
435
+ let target = AttrsTarget { attrs : ret_attrs, tokens } ;
436
+ tokens_used = true ;
433
437
self . capture_state
434
438
. parser_replacements
435
439
. push ( ( ParserRange ( start_pos..end_pos) , Some ( target) ) ) ;
@@ -438,7 +442,9 @@ impl<'a> Parser<'a> {
438
442
// the outermost call to this method.
439
443
self . capture_state . parser_replacements . clear ( ) ;
440
444
self . capture_state . inner_attr_parser_ranges . clear ( ) ;
445
+ self . capture_state . seen_attrs . clear ( ) ;
441
446
}
447
+ assert ! ( tokens_used) ; // check we didn't create `tokens` unnecessarily
442
448
Ok ( ret)
443
449
}
444
450
}
@@ -510,9 +516,11 @@ fn make_attr_token_stream(
510
516
}
511
517
512
518
/// Tokens are needed if:
513
- /// - any non-single-segment attributes (other than doc comments) are present; or
514
- /// - any `cfg_attr` attributes are present;
515
- /// - any single-segment, non-builtin attributes are present.
519
+ /// - any non-single-segment attributes (other than doc comments) are present,
520
+ /// e.g. `rustfmt::skip`; or
521
+ /// - any `cfg_attr` attributes are present; or
522
+ /// - any single-segment, non-builtin attributes are present, e.g. `derive`,
523
+ /// `test`, `global_allocator`.
516
524
fn needs_tokens ( attrs : & [ ast:: Attribute ] ) -> bool {
517
525
attrs. iter ( ) . any ( |attr| match attr. ident ( ) {
518
526
None => !attr. is_doc_comment ( ) ,
0 commit comments