1+ use  std:: borrow:: Cow ; 
12use  std:: { iter,  mem} ; 
23
34use  rustc_ast:: token:: { Delimiter ,  Token ,  TokenKind } ; 
@@ -6,6 +7,7 @@ use rustc_ast::tokenstream::{
67    Spacing ,  ToAttrTokenStream , 
78} ; 
89use  rustc_ast:: { self  as  ast,  AttrVec ,  Attribute ,  HasAttrs ,  HasTokens } ; 
10+ use  rustc_data_structures:: fx:: FxHashSet ; 
911use  rustc_errors:: PResult ; 
1012use  rustc_session:: parse:: ParseSess ; 
1113use  rustc_span:: { sym,  Span ,  DUMMY_SP } ; 
@@ -256,35 +258,48 @@ impl<'a> Parser<'a> {
256258            res?
257259        } ; 
258260
261+         // - `None`: Our target doesn't support tokens at all (e.g. `NtIdent`). 
262+         // - `Some(None)`: Our target supports tokens and has none. 
263+         // - `Some(Some(_))`: Our target already has tokens set (e.g. we've 
264+         //   parsed something like `#[my_attr] $item`). 
265+         let  ret_can_hold_tokens = matches ! ( ret. tokens_mut( ) ,  Some ( None ) ) ; 
266+ 
259267        // Ignore any attributes we've previously processed. This happens when 
260268        // an inner call to `collect_tokens` returns an AST node and then an 
261269        // outer call ends up with the same AST node without any additional 
262270        // 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 ( ) ; 
271+         let  mut  seen_indices = FxHashSet :: default ( ) ; 
272+         for  ( i,  attr)  in  ret. attrs ( ) . iter ( ) . enumerate ( )  { 
273+             let  is_unseen = self . capture_state . seen_attrs . insert ( attr. id ) ; 
274+             if  !is_unseen { 
275+                 seen_indices. insert ( i) ; 
276+             } 
277+         } 
278+         let  ret_attrs:  Cow < ' _ ,  [ Attribute ] >  =
279+             if  seen_indices. is_empty ( )  { 
280+                 Cow :: Borrowed ( ret. attrs ( ) ) 
281+             }  else  { 
282+                 let  ret_attrs =
283+                     ret. attrs ( ) 
284+                         . iter ( ) 
285+                         . enumerate ( ) 
286+                         . filter_map ( |( i,  attr) | { 
287+                             if  seen_indices. contains ( & i)  {  None  }  else  {  Some ( attr. clone ( ) )  } 
288+                         } ) 
289+                         . collect ( ) ; 
290+                 Cow :: Owned ( ret_attrs) 
291+             } ; 
272292
273293        // When we're not in "definite capture mode", then skip collecting and 
274-         // return early if either of the following conditions hold. 
275-         // - `None`: Our target doesn't support tokens at all (e.g. `NtIdent`). 
276-         // - `Some(Some(_))`: Our target already has tokens set (e.g. we've 
277-         //   parsed something like `#[my_attr] $item`). The actual parsing code 
278-         //   takes care of prepending any attributes to the nonterminal, so we 
279-         //   don't need to modify the already captured tokens. 
294+         // return early if `ret` doesn't support tokens or already has some. 
280295        // 
281296        // Note that this check is independent of `force_collect`. There's no 
282297        // need to collect tokens when we don't support tokens or already have 
283298        // tokens. 
284299        let  definite_capture_mode = self . capture_cfg 
285300            && matches ! ( self . capture_state. capturing,  Capturing :: Yes ) 
286301            && has_cfg_or_cfg_attr ( & ret_attrs) ; 
287-         if  !definite_capture_mode && matches ! ( ret . tokens_mut ( ) ,   None  |  Some ( Some ( _ ) ) )  { 
302+         if  !definite_capture_mode && !ret_can_hold_tokens  { 
288303            return  Ok ( ret) ; 
289304        } 
290305
@@ -406,12 +421,6 @@ impl<'a> Parser<'a> {
406421        } ) ; 
407422        let  mut  tokens_used = false ; 
408423
409-         // If we support tokens and don't already have them, store the newly captured tokens. 
410-         if  let  Some ( target_tokens @ None )  = ret. tokens_mut ( )  { 
411-             tokens_used = true ; 
412-             * target_tokens = Some ( tokens. clone ( ) ) ; 
413-         } 
414- 
415424        // If in "definite capture mode" we need to register a replace range 
416425        // for the `#[cfg]` and/or `#[cfg_attr]` attrs. This allows us to run 
417426        // eager cfg-expansion on the captured token stream. 
@@ -432,7 +441,8 @@ impl<'a> Parser<'a> {
432441            // cfg-expand this AST node. 
433442            let  start_pos =
434443                if  has_outer_attrs {  attrs. start_pos . unwrap ( )  }  else  {  collect_pos. start_pos  } ; 
435-             let  target = AttrsTarget  {  attrs :  ret_attrs,  tokens } ; 
444+             let  target =
445+                 AttrsTarget  {  attrs :  ret_attrs. iter ( ) . cloned ( ) . collect ( ) ,  tokens :  tokens. clone ( )  } ; 
436446            tokens_used = true ; 
437447            self . capture_state 
438448                . parser_replacements 
@@ -444,6 +454,13 @@ impl<'a> Parser<'a> {
444454            self . capture_state . inner_attr_parser_ranges . clear ( ) ; 
445455            self . capture_state . seen_attrs . clear ( ) ; 
446456        } 
457+ 
458+         // If we support tokens and don't already have them, store the newly captured tokens. 
459+         if  let  Some ( target_tokens @ None )  = ret. tokens_mut ( )  { 
460+             tokens_used = true ; 
461+             * target_tokens = Some ( tokens) ; 
462+         } 
463+ 
447464        assert ! ( tokens_used) ;  // check we didn't create `tokens` unnecessarily 
448465        Ok ( ret) 
449466    } 
0 commit comments