@@ -60,10 +60,6 @@ impl AttrWrapper {
60
60
pub fn is_empty ( & self ) -> bool {
61
61
self . attrs . is_empty ( )
62
62
}
63
-
64
- pub fn is_complete ( & self ) -> bool {
65
- crate :: parser:: attr:: is_complete ( & self . attrs )
66
- }
67
63
}
68
64
69
65
/// Returns `true` if `attrs` contains a `cfg` or `cfg_attr` attribute
@@ -114,17 +110,15 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
114
110
replace_ranges. sort_by_key ( |( range, _) | range. start ) ;
115
111
116
112
#[ cfg( debug_assertions) ]
117
- {
118
- for [ ( range, tokens) , ( next_range, next_tokens) ] in replace_ranges. array_windows ( ) {
119
- assert ! (
120
- range. end <= next_range. start || range. end >= next_range. end,
121
- "Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})" ,
122
- range,
123
- tokens,
124
- next_range,
125
- next_tokens,
126
- ) ;
127
- }
113
+ for [ ( range, tokens) , ( next_range, next_tokens) ] in replace_ranges. array_windows ( ) {
114
+ assert ! (
115
+ range. end <= next_range. start || range. end >= next_range. end,
116
+ "Replace ranges should either be disjoint or nested: ({:?}, {:?}) ({:?}, {:?})" ,
117
+ range,
118
+ tokens,
119
+ next_range,
120
+ next_tokens,
121
+ ) ;
128
122
}
129
123
130
124
// Process the replace ranges, starting from the highest start
@@ -137,9 +131,9 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
137
131
// `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }`
138
132
//
139
133
// By starting processing from the replace range with the greatest
140
- // start position, we ensure that any replace range which encloses
141
- // another replace range will capture the *replaced* tokens for the inner
142
- // range, not the original tokens .
134
+ // start position, we ensure that any (outer) replace range which
135
+ // encloses another (inner) replace range will fully overwrite the
136
+ // inner range's replacement .
143
137
for ( range, target) in replace_ranges. into_iter ( ) . rev ( ) {
144
138
assert ! ( !range. is_empty( ) , "Cannot replace an empty range: {range:?}" ) ;
145
139
@@ -199,20 +193,20 @@ impl<'a> Parser<'a> {
199
193
force_collect : ForceCollect ,
200
194
f : impl FnOnce ( & mut Self , ast:: AttrVec ) -> PResult < ' a , ( R , bool ) > ,
201
195
) -> PResult < ' a , R > {
202
- // Skip collection when nothing could observe the collected tokens, i.e.
203
- // all of the following conditions hold.
204
- // - We are not force collecting tokens (because force collection
205
- // requires tokens by definition).
206
- if matches ! ( force_collect, ForceCollect :: No )
207
- // - None of our outer attributes require tokens.
208
- && attrs. is_complete ( )
209
- // - Our target doesn't support custom inner attributes (custom
196
+ // We must collect if anything could observe the collected tokens, i.e.
197
+ // if any of the following conditions hold.
198
+ // - We are force collecting tokens (because force collection requires
199
+ // tokens by definition).
200
+ let needs_collection = matches ! ( force_collect, ForceCollect :: Yes )
201
+ // - Any of our outer attributes require tokens.
202
+ || needs_tokens ( & attrs. attrs )
203
+ // - Our target supports custom inner attributes (custom
210
204
// inner attribute invocation might require token capturing).
211
- && ! R :: SUPPORTS_CUSTOM_INNER_ATTRS
212
- // - We are not in `capture_cfg` mode (which requires tokens if
205
+ || R :: SUPPORTS_CUSTOM_INNER_ATTRS
206
+ // - We are in `capture_cfg` mode (which requires tokens if
213
207
// the parsed node has `#[cfg]` or `#[cfg_attr]` attributes).
214
- && ! self . capture_cfg
215
- {
208
+ || self . capture_cfg ;
209
+ if !needs_collection {
216
210
return Ok ( f ( self , attrs. attrs ) ?. 0 ) ;
217
211
}
218
212
@@ -250,28 +244,28 @@ impl<'a> Parser<'a> {
250
244
return Ok ( ret) ;
251
245
}
252
246
253
- // This is similar to the "skip collection" check at the start of this
254
- // function, but now that we've parsed an AST node we have more
247
+ // This is similar to the `needs_collection` check at the start of this
248
+ // function, but now that we've parsed an AST node we have complete
255
249
// information available. (If we return early here that means the
256
250
// setup, such as cloning the token cursor, was unnecessary. That's
257
251
// hard to avoid.)
258
252
//
259
- // Skip collection when nothing could observe the collected tokens, i.e.
260
- // all of the following conditions hold.
261
- // - We are not force collecting tokens.
262
- if matches ! ( force_collect, ForceCollect :: No )
263
- // - None of our outer *or* inner attributes require tokens.
264
- // (`attrs` was just outer attributes, but `ret.attrs()` is outer
265
- // and inner attributes. That makes this check more precise than
266
- // `attrs.is_complete()` at the start of the function , and we can
267
- // skip the subsequent check on `R::SUPPORTS_CUSTOM_INNER_ATTRS`.
268
- && crate :: parser :: attr :: is_complete ( ret. attrs ( ) )
269
- // - We are not in `capture_cfg` mode, or we are but there are no
270
- // `#[cfg]` or `#[ cfg_attr]` attributes. (During normal
271
- // non-`capture_cfg` parsing, we don't need any special capturing
272
- // for those attributes, because they're builtin.)
273
- && ( ! self . capture_cfg || ! has_cfg_or_cfg_attr ( ret. attrs ( ) ) )
274
- {
253
+ // We must collect if anything could observe the collected tokens, i.e.
254
+ // if any of the following conditions hold.
255
+ // - We are force collecting tokens.
256
+ let needs_collection = matches ! ( force_collect, ForceCollect :: Yes )
257
+ // - Any of our outer *or* inner attributes require tokens.
258
+ // (`attr. attrs` was just outer attributes, but `ret.attrs()` is
259
+ // outer and inner attributes. So this check is more precise than
260
+ // the earlier `needs_tokens` check , and we don't need to
261
+ // check `R::SUPPORTS_CUSTOM_INNER_ATTRS`.)
262
+ || needs_tokens ( ret. attrs ( ) )
263
+ // - We are in `capture_cfg` mode and there are `#[cfg]` or
264
+ // `#[cfg_attr]` attributes. (During normal non-`capture_cfg`
265
+ // parsing, we don't need any special capturing for those
266
+ // attributes, because they're builtin.)
267
+ || ( self . capture_cfg && has_cfg_or_cfg_attr ( ret. attrs ( ) ) ) ;
268
+ if !needs_collection {
275
269
return Ok ( ret) ;
276
270
}
277
271
@@ -297,11 +291,13 @@ impl<'a> Parser<'a> {
297
291
// with `None`, which means the relevant tokens will be removed. (More
298
292
// details below.)
299
293
let mut inner_attr_replace_ranges = Vec :: new ( ) ;
300
- for inner_attr in ret. attrs ( ) . iter ( ) . filter ( |a| a. style == ast:: AttrStyle :: Inner ) {
301
- if let Some ( attr_range) = self . capture_state . inner_attr_ranges . remove ( & inner_attr. id ) {
302
- inner_attr_replace_ranges. push ( ( attr_range, None ) ) ;
303
- } else {
304
- self . dcx ( ) . span_delayed_bug ( inner_attr. span , "Missing token range for attribute" ) ;
294
+ for attr in ret. attrs ( ) {
295
+ if attr. style == ast:: AttrStyle :: Inner {
296
+ if let Some ( attr_range) = self . capture_state . inner_attr_ranges . remove ( & attr. id ) {
297
+ inner_attr_replace_ranges. push ( ( attr_range, None ) ) ;
298
+ } else {
299
+ self . dcx ( ) . span_delayed_bug ( attr. span , "Missing token range for attribute" ) ;
300
+ }
305
301
}
306
302
}
307
303
@@ -337,8 +333,7 @@ impl<'a> Parser<'a> {
337
333
// When parsing `m`:
338
334
// - `start_pos..end_pos` is `0..34` (`mod m`, excluding the `#[cfg_eval]` attribute).
339
335
// - `inner_attr_replace_ranges` is empty.
340
- // - `replace_range_start..replace_ranges_end` has two entries.
341
- // - One to delete the inner attribute (`17..27`), obtained when parsing `g` (see above).
336
+ // - `replace_range_start..replace_ranges_end` has one entry.
342
337
// - One `AttrsTarget` (added below when parsing `g`) to replace all of `g` (`3..33`,
343
338
// including its outer attribute), with:
344
339
// - `attrs`: includes the outer and the inner attr.
@@ -369,12 +364,10 @@ impl<'a> Parser<'a> {
369
364
370
365
// What is the status here when parsing the example code at the top of this method?
371
366
//
372
- // When parsing `g`, we add two entries :
367
+ // When parsing `g`, we add one entry :
373
368
// - The `start_pos..end_pos` (`3..33`) entry has a new `AttrsTarget` with:
374
369
// - `attrs`: includes the outer and the inner attr.
375
370
// - `tokens`: lazy tokens for `g` (with its inner attr deleted).
376
- // - `inner_attr_replace_ranges` contains the one entry to delete the inner attr's
377
- // tokens (`17..27`).
378
371
//
379
372
// When parsing `m`, we do nothing here.
380
373
@@ -384,7 +377,6 @@ impl<'a> Parser<'a> {
384
377
let start_pos = if has_outer_attrs { attrs. start_pos } else { start_pos } ;
385
378
let target = AttrsTarget { attrs : ret. attrs ( ) . iter ( ) . cloned ( ) . collect ( ) , tokens } ;
386
379
self . capture_state . replace_ranges . push ( ( start_pos..end_pos, Some ( target) ) ) ;
387
- self . capture_state . replace_ranges . extend ( inner_attr_replace_ranges) ;
388
380
} else if matches ! ( self . capture_state. capturing, Capturing :: No ) {
389
381
// Only clear the ranges once we've finished capturing entirely, i.e. we've finished
390
382
// the outermost call to this method.
@@ -461,6 +453,19 @@ fn make_attr_token_stream(
461
453
AttrTokenStream :: new ( stack_top. inner )
462
454
}
463
455
456
+ /// Tokens are needed if:
457
+ /// - any non-single-segment attributes (other than doc comments) are present; or
458
+ /// - any `cfg_attr` attributes are present;
459
+ /// - any single-segment, non-builtin attributes are present.
460
+ fn needs_tokens ( attrs : & [ ast:: Attribute ] ) -> bool {
461
+ attrs. iter ( ) . any ( |attr| match attr. ident ( ) {
462
+ None => !attr. is_doc_comment ( ) ,
463
+ Some ( ident) => {
464
+ ident. name == sym:: cfg_attr || !rustc_feature:: is_builtin_attr_name ( ident. name )
465
+ }
466
+ } )
467
+ }
468
+
464
469
// Some types are used a lot. Make sure they don't unintentionally get bigger.
465
470
#[ cfg( target_pointer_width = "64" ) ]
466
471
mod size_asserts {
0 commit comments