@@ -60,10 +60,6 @@ impl AttrWrapper {
6060 pub fn is_empty ( & self ) -> bool {
6161 self . attrs . is_empty ( )
6262 }
63-
64- pub fn is_complete ( & self ) -> bool {
65- crate :: parser:: attr:: is_complete ( & self . attrs )
66- }
6763}
6864
6965/// Returns `true` if `attrs` contains a `cfg` or `cfg_attr` attribute
@@ -114,17 +110,15 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
114110 replace_ranges. sort_by_key ( |( range, _) | range. start ) ;
115111
116112 #[ 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+ ) ;
128122 }
129123
130124 // Process the replace ranges, starting from the highest start
@@ -137,9 +131,9 @@ impl ToAttrTokenStream for LazyAttrTokenStreamImpl {
137131 // `#[cfg(FALSE)] struct Foo { #[cfg(FALSE)] field: bool }`
138132 //
139133 // 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 .
143137 for ( range, target) in replace_ranges. into_iter ( ) . rev ( ) {
144138 assert ! ( !range. is_empty( ) , "Cannot replace an empty range: {range:?}" ) ;
145139
@@ -199,20 +193,20 @@ impl<'a> Parser<'a> {
199193 force_collect : ForceCollect ,
200194 f : impl FnOnce ( & mut Self , ast:: AttrVec ) -> PResult < ' a , ( R , bool ) > ,
201195 ) -> 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
210204 // 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
213207 // the parsed node has `#[cfg]` or `#[cfg_attr]` attributes).
214- && ! self . capture_cfg
215- {
208+ || self . capture_cfg ;
209+ if !needs_collection {
216210 return Ok ( f ( self , attrs. attrs ) ?. 0 ) ;
217211 }
218212
@@ -250,28 +244,28 @@ impl<'a> Parser<'a> {
250244 return Ok ( ret) ;
251245 }
252246
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
255249 // information available. (If we return early here that means the
256250 // setup, such as cloning the token cursor, was unnecessary. That's
257251 // hard to avoid.)
258252 //
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 {
275269 return Ok ( ret) ;
276270 }
277271
@@ -297,11 +291,13 @@ impl<'a> Parser<'a> {
297291 // with `None`, which means the relevant tokens will be removed. (More
298292 // details below.)
299293 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+ }
305301 }
306302 }
307303
@@ -337,8 +333,7 @@ impl<'a> Parser<'a> {
337333 // When parsing `m`:
338334 // - `start_pos..end_pos` is `0..34` (`mod m`, excluding the `#[cfg_eval]` attribute).
339335 // - `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.
342337 // - One `AttrsTarget` (added below when parsing `g`) to replace all of `g` (`3..33`,
343338 // including its outer attribute), with:
344339 // - `attrs`: includes the outer and the inner attr.
@@ -369,12 +364,10 @@ impl<'a> Parser<'a> {
369364
370365 // What is the status here when parsing the example code at the top of this method?
371366 //
372- // When parsing `g`, we add two entries :
367+ // When parsing `g`, we add one entry :
373368 // - The `start_pos..end_pos` (`3..33`) entry has a new `AttrsTarget` with:
374369 // - `attrs`: includes the outer and the inner attr.
375370 // - `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`).
378371 //
379372 // When parsing `m`, we do nothing here.
380373
@@ -384,7 +377,6 @@ impl<'a> Parser<'a> {
384377 let start_pos = if has_outer_attrs { attrs. start_pos } else { start_pos } ;
385378 let target = AttrsTarget { attrs : ret. attrs ( ) . iter ( ) . cloned ( ) . collect ( ) , tokens } ;
386379 self . capture_state . replace_ranges . push ( ( start_pos..end_pos, Some ( target) ) ) ;
387- self . capture_state . replace_ranges . extend ( inner_attr_replace_ranges) ;
388380 } else if matches ! ( self . capture_state. capturing, Capturing :: No ) {
389381 // Only clear the ranges once we've finished capturing entirely, i.e. we've finished
390382 // the outermost call to this method.
@@ -461,6 +453,19 @@ fn make_attr_token_stream(
461453 AttrTokenStream :: new ( stack_top. inner )
462454}
463455
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+
464469// Some types are used a lot. Make sure they don't unintentionally get bigger.
465470#[ cfg( target_pointer_width = "64" ) ]
466471mod size_asserts {
0 commit comments