]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ast/src/attr/mod.rs
x.py setup: Avoid infinite loop if stdin is /dev/null
[rust.git] / compiler / rustc_ast / src / attr / mod.rs
1 //! Functions dealing with attributes and meta items.
2
3 use crate::ast;
4 use crate::ast::{AttrId, AttrItem, AttrKind, AttrStyle, AttrVec, Attribute};
5 use crate::ast::{Expr, GenericParam, Item, Lit, LitKind, Local, Stmt, StmtKind};
6 use crate::ast::{MacArgs, MacDelimiter, MetaItem, MetaItemKind, NestedMetaItem};
7 use crate::ast::{Path, PathSegment};
8 use crate::mut_visit::visit_clobber;
9 use crate::ptr::P;
10 use crate::token::{self, CommentKind, Token};
11 use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing};
12
13 use rustc_index::bit_set::GrowableBitSet;
14 use rustc_span::source_map::{BytePos, Spanned};
15 use rustc_span::symbol::{sym, Ident, Symbol};
16 use rustc_span::Span;
17
18 use std::iter;
19
20 pub struct MarkedAttrs(GrowableBitSet<AttrId>);
21
22 impl MarkedAttrs {
23     // We have no idea how many attributes there will be, so just
24     // initiate the vectors with 0 bits. We'll grow them as necessary.
25     pub fn new() -> Self {
26         MarkedAttrs(GrowableBitSet::new_empty())
27     }
28
29     pub fn mark(&mut self, attr: &Attribute) {
30         self.0.insert(attr.id);
31     }
32
33     pub fn is_marked(&self, attr: &Attribute) -> bool {
34         self.0.contains(attr.id)
35     }
36 }
37
38 pub fn is_known_lint_tool(m_item: Ident) -> bool {
39     [sym::clippy, sym::rustc].contains(&m_item.name)
40 }
41
42 impl NestedMetaItem {
43     /// Returns the `MetaItem` if `self` is a `NestedMetaItem::MetaItem`.
44     pub fn meta_item(&self) -> Option<&MetaItem> {
45         match *self {
46             NestedMetaItem::MetaItem(ref item) => Some(item),
47             _ => None,
48         }
49     }
50
51     /// Returns the `Lit` if `self` is a `NestedMetaItem::Literal`s.
52     pub fn literal(&self) -> Option<&Lit> {
53         match *self {
54             NestedMetaItem::Literal(ref lit) => Some(lit),
55             _ => None,
56         }
57     }
58
59     /// Returns `true` if this list item is a MetaItem with a name of `name`.
60     pub fn has_name(&self, name: Symbol) -> bool {
61         self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
62     }
63
64     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
65     pub fn ident(&self) -> Option<Ident> {
66         self.meta_item().and_then(|meta_item| meta_item.ident())
67     }
68     pub fn name_or_empty(&self) -> Symbol {
69         self.ident().unwrap_or(Ident::invalid()).name
70     }
71
72     /// Gets the string value if `self` is a `MetaItem` and the `MetaItem` is a
73     /// `MetaItemKind::NameValue` variant containing a string, otherwise `None`.
74     pub fn value_str(&self) -> Option<Symbol> {
75         self.meta_item().and_then(|meta_item| meta_item.value_str())
76     }
77
78     /// Returns a name and single literal value tuple of the `MetaItem`.
79     pub fn name_value_literal(&self) -> Option<(Symbol, &Lit)> {
80         self.meta_item().and_then(|meta_item| {
81             meta_item.meta_item_list().and_then(|meta_item_list| {
82                 if meta_item_list.len() == 1 {
83                     if let Some(ident) = meta_item.ident() {
84                         if let Some(lit) = meta_item_list[0].literal() {
85                             return Some((ident.name, lit));
86                         }
87                     }
88                 }
89                 None
90             })
91         })
92     }
93
94     /// Gets a list of inner meta items from a list `MetaItem` type.
95     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
96         self.meta_item().and_then(|meta_item| meta_item.meta_item_list())
97     }
98
99     /// Returns `true` if the variant is `MetaItem`.
100     pub fn is_meta_item(&self) -> bool {
101         self.meta_item().is_some()
102     }
103
104     /// Returns `true` if the variant is `Literal`.
105     pub fn is_literal(&self) -> bool {
106         self.literal().is_some()
107     }
108
109     /// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
110     pub fn is_word(&self) -> bool {
111         self.meta_item().map_or(false, |meta_item| meta_item.is_word())
112     }
113
114     /// Returns `true` if `self` is a `MetaItem` and the meta item is a `ValueString`.
115     pub fn is_value_str(&self) -> bool {
116         self.value_str().is_some()
117     }
118
119     /// Returns `true` if `self` is a `MetaItem` and the meta item is a list.
120     pub fn is_meta_item_list(&self) -> bool {
121         self.meta_item_list().is_some()
122     }
123 }
124
125 impl Attribute {
126     pub fn has_name(&self, name: Symbol) -> bool {
127         match self.kind {
128             AttrKind::Normal(ref item) => item.path == name,
129             AttrKind::DocComment(..) => false,
130         }
131     }
132
133     /// For a single-segment attribute, returns its name; otherwise, returns `None`.
134     pub fn ident(&self) -> Option<Ident> {
135         match self.kind {
136             AttrKind::Normal(ref item) => {
137                 if item.path.segments.len() == 1 {
138                     Some(item.path.segments[0].ident)
139                 } else {
140                     None
141                 }
142             }
143             AttrKind::DocComment(..) => None,
144         }
145     }
146     pub fn name_or_empty(&self) -> Symbol {
147         self.ident().unwrap_or(Ident::invalid()).name
148     }
149
150     pub fn value_str(&self) -> Option<Symbol> {
151         match self.kind {
152             AttrKind::Normal(ref item) => item.meta(self.span).and_then(|meta| meta.value_str()),
153             AttrKind::DocComment(..) => None,
154         }
155     }
156
157     pub fn meta_item_list(&self) -> Option<Vec<NestedMetaItem>> {
158         match self.kind {
159             AttrKind::Normal(ref item) => match item.meta(self.span) {
160                 Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
161                 _ => None,
162             },
163             AttrKind::DocComment(..) => None,
164         }
165     }
166
167     pub fn is_word(&self) -> bool {
168         if let AttrKind::Normal(item) = &self.kind {
169             matches!(item.args, MacArgs::Empty)
170         } else {
171             false
172         }
173     }
174
175     pub fn is_meta_item_list(&self) -> bool {
176         self.meta_item_list().is_some()
177     }
178
179     /// Indicates if the attribute is a `ValueString`.
180     pub fn is_value_str(&self) -> bool {
181         self.value_str().is_some()
182     }
183 }
184
185 impl MetaItem {
186     /// For a single-segment meta item, returns its name; otherwise, returns `None`.
187     pub fn ident(&self) -> Option<Ident> {
188         if self.path.segments.len() == 1 { Some(self.path.segments[0].ident) } else { None }
189     }
190     pub fn name_or_empty(&self) -> Symbol {
191         self.ident().unwrap_or(Ident::invalid()).name
192     }
193
194     // Example:
195     //     #[attribute(name = "value")]
196     //                 ^^^^^^^^^^^^^^
197     pub fn name_value_literal(&self) -> Option<&Lit> {
198         match &self.kind {
199             MetaItemKind::NameValue(v) => Some(v),
200             _ => None,
201         }
202     }
203
204     pub fn value_str(&self) -> Option<Symbol> {
205         match self.kind {
206             MetaItemKind::NameValue(ref v) => match v.kind {
207                 LitKind::Str(ref s, _) => Some(*s),
208                 _ => None,
209             },
210             _ => None,
211         }
212     }
213
214     pub fn meta_item_list(&self) -> Option<&[NestedMetaItem]> {
215         match self.kind {
216             MetaItemKind::List(ref l) => Some(&l[..]),
217             _ => None,
218         }
219     }
220
221     pub fn is_word(&self) -> bool {
222         match self.kind {
223             MetaItemKind::Word => true,
224             _ => false,
225         }
226     }
227
228     pub fn has_name(&self, name: Symbol) -> bool {
229         self.path == name
230     }
231
232     pub fn is_value_str(&self) -> bool {
233         self.value_str().is_some()
234     }
235
236     pub fn is_meta_item_list(&self) -> bool {
237         self.meta_item_list().is_some()
238     }
239 }
240
241 impl AttrItem {
242     pub fn span(&self) -> Span {
243         self.args.span().map_or(self.path.span, |args_span| self.path.span.to(args_span))
244     }
245
246     pub fn meta(&self, span: Span) -> Option<MetaItem> {
247         Some(MetaItem {
248             path: self.path.clone(),
249             kind: MetaItemKind::from_mac_args(&self.args)?,
250             span,
251         })
252     }
253 }
254
255 impl Attribute {
256     pub fn is_doc_comment(&self) -> bool {
257         match self.kind {
258             AttrKind::Normal(_) => false,
259             AttrKind::DocComment(..) => true,
260         }
261     }
262
263     pub fn doc_str(&self) -> Option<Symbol> {
264         match self.kind {
265             AttrKind::DocComment(.., data) => Some(data),
266             AttrKind::Normal(ref item) if item.path == sym::doc => {
267                 item.meta(self.span).and_then(|meta| meta.value_str())
268             }
269             _ => None,
270         }
271     }
272
273     pub fn get_normal_item(&self) -> &AttrItem {
274         match self.kind {
275             AttrKind::Normal(ref item) => item,
276             AttrKind::DocComment(..) => panic!("unexpected doc comment"),
277         }
278     }
279
280     pub fn unwrap_normal_item(self) -> AttrItem {
281         match self.kind {
282             AttrKind::Normal(item) => item,
283             AttrKind::DocComment(..) => panic!("unexpected doc comment"),
284         }
285     }
286
287     /// Extracts the MetaItem from inside this Attribute.
288     pub fn meta(&self) -> Option<MetaItem> {
289         match self.kind {
290             AttrKind::Normal(ref item) => item.meta(self.span),
291             AttrKind::DocComment(..) => None,
292         }
293     }
294 }
295
296 /* Constructors */
297
298 pub fn mk_name_value_item_str(ident: Ident, str: Symbol, str_span: Span) -> MetaItem {
299     let lit_kind = LitKind::Str(str, ast::StrStyle::Cooked);
300     mk_name_value_item(ident, lit_kind, str_span)
301 }
302
303 pub fn mk_name_value_item(ident: Ident, lit_kind: LitKind, lit_span: Span) -> MetaItem {
304     let lit = Lit::from_lit_kind(lit_kind, lit_span);
305     let span = ident.span.to(lit_span);
306     MetaItem { path: Path::from_ident(ident), span, kind: MetaItemKind::NameValue(lit) }
307 }
308
309 pub fn mk_list_item(ident: Ident, items: Vec<NestedMetaItem>) -> MetaItem {
310     MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::List(items) }
311 }
312
313 pub fn mk_word_item(ident: Ident) -> MetaItem {
314     MetaItem { path: Path::from_ident(ident), span: ident.span, kind: MetaItemKind::Word }
315 }
316
317 pub fn mk_nested_word_item(ident: Ident) -> NestedMetaItem {
318     NestedMetaItem::MetaItem(mk_word_item(ident))
319 }
320
321 crate fn mk_attr_id() -> AttrId {
322     use std::sync::atomic::AtomicU32;
323     use std::sync::atomic::Ordering;
324
325     static NEXT_ATTR_ID: AtomicU32 = AtomicU32::new(0);
326
327     let id = NEXT_ATTR_ID.fetch_add(1, Ordering::SeqCst);
328     assert!(id != u32::MAX);
329     AttrId::from_u32(id)
330 }
331
332 pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute {
333     mk_attr_from_item(style, AttrItem { path, args, tokens: None }, span)
334 }
335
336 pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute {
337     Attribute { kind: AttrKind::Normal(item), id: mk_attr_id(), style, span }
338 }
339
340 /// Returns an inner attribute with the given value and span.
341 pub fn mk_attr_inner(item: MetaItem) -> Attribute {
342     mk_attr(AttrStyle::Inner, item.path, item.kind.mac_args(item.span), item.span)
343 }
344
345 /// Returns an outer attribute with the given value and span.
346 pub fn mk_attr_outer(item: MetaItem) -> Attribute {
347     mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
348 }
349
350 pub fn mk_doc_comment(
351     comment_kind: CommentKind,
352     style: AttrStyle,
353     data: Symbol,
354     span: Span,
355 ) -> Attribute {
356     Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span }
357 }
358
359 pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
360     items.iter().any(|item| item.has_name(name))
361 }
362
363 impl MetaItem {
364     fn token_trees_and_spacings(&self) -> Vec<TreeAndSpacing> {
365         let mut idents = vec![];
366         let mut last_pos = BytePos(0 as u32);
367         for (i, segment) in self.path.segments.iter().enumerate() {
368             let is_first = i == 0;
369             if !is_first {
370                 let mod_sep_span =
371                     Span::new(last_pos, segment.ident.span.lo(), segment.ident.span.ctxt());
372                 idents.push(TokenTree::token(token::ModSep, mod_sep_span).into());
373             }
374             idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into());
375             last_pos = segment.ident.span.hi();
376         }
377         idents.extend(self.kind.token_trees_and_spacings(self.span));
378         idents
379     }
380
381     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<MetaItem>
382     where
383         I: Iterator<Item = TokenTree>,
384     {
385         // FIXME: Share code with `parse_path`.
386         let path = match tokens.next().map(TokenTree::uninterpolate) {
387             Some(TokenTree::Token(Token {
388                 kind: kind @ (token::Ident(..) | token::ModSep),
389                 span,
390             })) => 'arm: {
391                 let mut segments = if let token::Ident(name, _) = kind {
392                     if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek()
393                     {
394                         tokens.next();
395                         vec![PathSegment::from_ident(Ident::new(name, span))]
396                     } else {
397                         break 'arm Path::from_ident(Ident::new(name, span));
398                     }
399                 } else {
400                     vec![PathSegment::path_root(span)]
401                 };
402                 loop {
403                     if let Some(TokenTree::Token(Token { kind: token::Ident(name, _), span })) =
404                         tokens.next().map(TokenTree::uninterpolate)
405                     {
406                         segments.push(PathSegment::from_ident(Ident::new(name, span)));
407                     } else {
408                         return None;
409                     }
410                     if let Some(TokenTree::Token(Token { kind: token::ModSep, .. })) = tokens.peek()
411                     {
412                         tokens.next();
413                     } else {
414                         break;
415                     }
416                 }
417                 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
418                 Path { span, segments, tokens: None }
419             }
420             Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt {
421                 token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span),
422                 token::Nonterminal::NtPath(ref path) => path.clone(),
423                 _ => return None,
424             },
425             _ => return None,
426         };
427         let list_closing_paren_pos = tokens.peek().map(|tt| tt.span().hi());
428         let kind = MetaItemKind::from_tokens(tokens)?;
429         let hi = match kind {
430             MetaItemKind::NameValue(ref lit) => lit.span.hi(),
431             MetaItemKind::List(..) => list_closing_paren_pos.unwrap_or(path.span.hi()),
432             _ => path.span.hi(),
433         };
434         let span = path.span.with_hi(hi);
435         Some(MetaItem { path, kind, span })
436     }
437 }
438
439 impl MetaItemKind {
440     pub fn mac_args(&self, span: Span) -> MacArgs {
441         match self {
442             MetaItemKind::Word => MacArgs::Empty,
443             MetaItemKind::NameValue(lit) => MacArgs::Eq(span, lit.token_tree().into()),
444             MetaItemKind::List(list) => {
445                 let mut tts = Vec::new();
446                 for (i, item) in list.iter().enumerate() {
447                     if i > 0 {
448                         tts.push(TokenTree::token(token::Comma, span).into());
449                     }
450                     tts.extend(item.token_trees_and_spacings())
451                 }
452                 MacArgs::Delimited(
453                     DelimSpan::from_single(span),
454                     MacDelimiter::Parenthesis,
455                     TokenStream::new(tts),
456                 )
457             }
458         }
459     }
460
461     fn token_trees_and_spacings(&self, span: Span) -> Vec<TreeAndSpacing> {
462         match *self {
463             MetaItemKind::Word => vec![],
464             MetaItemKind::NameValue(ref lit) => {
465                 vec![TokenTree::token(token::Eq, span).into(), lit.token_tree().into()]
466             }
467             MetaItemKind::List(ref list) => {
468                 let mut tokens = Vec::new();
469                 for (i, item) in list.iter().enumerate() {
470                     if i > 0 {
471                         tokens.push(TokenTree::token(token::Comma, span).into());
472                     }
473                     tokens.extend(item.token_trees_and_spacings())
474                 }
475                 vec![
476                     TokenTree::Delimited(
477                         DelimSpan::from_single(span),
478                         token::Paren,
479                         TokenStream::new(tokens),
480                     )
481                     .into(),
482                 ]
483             }
484         }
485     }
486
487     fn list_from_tokens(tokens: TokenStream) -> Option<MetaItemKind> {
488         let mut tokens = tokens.into_trees().peekable();
489         let mut result = Vec::new();
490         while let Some(..) = tokens.peek() {
491             let item = NestedMetaItem::from_tokens(&mut tokens)?;
492             result.push(item);
493             match tokens.next() {
494                 None | Some(TokenTree::Token(Token { kind: token::Comma, .. })) => {}
495                 _ => return None,
496             }
497         }
498         Some(MetaItemKind::List(result))
499     }
500
501     fn name_value_from_tokens(
502         tokens: &mut impl Iterator<Item = TokenTree>,
503     ) -> Option<MetaItemKind> {
504         match tokens.next() {
505             Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
506                 MetaItemKind::name_value_from_tokens(&mut inner_tokens.trees())
507             }
508             Some(TokenTree::Token(token)) => {
509                 Lit::from_token(&token).ok().map(MetaItemKind::NameValue)
510             }
511             _ => None,
512         }
513     }
514
515     fn from_mac_args(args: &MacArgs) -> Option<MetaItemKind> {
516         match args {
517             MacArgs::Delimited(_, MacDelimiter::Parenthesis, tokens) => {
518                 MetaItemKind::list_from_tokens(tokens.clone())
519             }
520             MacArgs::Delimited(..) => None,
521             MacArgs::Eq(_, tokens) => {
522                 assert!(tokens.len() == 1);
523                 MetaItemKind::name_value_from_tokens(&mut tokens.trees())
524             }
525             MacArgs::Empty => Some(MetaItemKind::Word),
526         }
527     }
528
529     fn from_tokens(
530         tokens: &mut iter::Peekable<impl Iterator<Item = TokenTree>>,
531     ) -> Option<MetaItemKind> {
532         match tokens.peek() {
533             Some(TokenTree::Delimited(_, token::Paren, inner_tokens)) => {
534                 let inner_tokens = inner_tokens.clone();
535                 tokens.next();
536                 MetaItemKind::list_from_tokens(inner_tokens)
537             }
538             Some(TokenTree::Delimited(..)) => None,
539             Some(TokenTree::Token(Token { kind: token::Eq, .. })) => {
540                 tokens.next();
541                 MetaItemKind::name_value_from_tokens(tokens)
542             }
543             _ => Some(MetaItemKind::Word),
544         }
545     }
546 }
547
548 impl NestedMetaItem {
549     pub fn span(&self) -> Span {
550         match *self {
551             NestedMetaItem::MetaItem(ref item) => item.span,
552             NestedMetaItem::Literal(ref lit) => lit.span,
553         }
554     }
555
556     fn token_trees_and_spacings(&self) -> Vec<TreeAndSpacing> {
557         match *self {
558             NestedMetaItem::MetaItem(ref item) => item.token_trees_and_spacings(),
559             NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()],
560         }
561     }
562
563     fn from_tokens<I>(tokens: &mut iter::Peekable<I>) -> Option<NestedMetaItem>
564     where
565         I: Iterator<Item = TokenTree>,
566     {
567         match tokens.peek() {
568             Some(TokenTree::Token(token)) => {
569                 if let Ok(lit) = Lit::from_token(token) {
570                     tokens.next();
571                     return Some(NestedMetaItem::Literal(lit));
572                 }
573             }
574             Some(TokenTree::Delimited(_, token::NoDelim, inner_tokens)) => {
575                 let inner_tokens = inner_tokens.clone();
576                 tokens.next();
577                 return NestedMetaItem::from_tokens(&mut inner_tokens.into_trees().peekable());
578             }
579             _ => {}
580         }
581         MetaItem::from_tokens(tokens).map(NestedMetaItem::MetaItem)
582     }
583 }
584
585 pub trait HasAttrs: Sized {
586     fn attrs(&self) -> &[Attribute];
587     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>));
588 }
589
590 impl<T: HasAttrs> HasAttrs for Spanned<T> {
591     fn attrs(&self) -> &[Attribute] {
592         self.node.attrs()
593     }
594     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
595         self.node.visit_attrs(f);
596     }
597 }
598
599 impl HasAttrs for Vec<Attribute> {
600     fn attrs(&self) -> &[Attribute] {
601         self
602     }
603     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
604         f(self)
605     }
606 }
607
608 impl HasAttrs for AttrVec {
609     fn attrs(&self) -> &[Attribute] {
610         self
611     }
612     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
613         visit_clobber(self, |this| {
614             let mut vec = this.into();
615             f(&mut vec);
616             vec.into()
617         });
618     }
619 }
620
621 impl<T: HasAttrs + 'static> HasAttrs for P<T> {
622     fn attrs(&self) -> &[Attribute] {
623         (**self).attrs()
624     }
625     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
626         (**self).visit_attrs(f);
627     }
628 }
629
630 impl HasAttrs for StmtKind {
631     fn attrs(&self) -> &[Attribute] {
632         match *self {
633             StmtKind::Local(ref local) => local.attrs(),
634             StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(),
635             StmtKind::Empty | StmtKind::Item(..) => &[],
636             StmtKind::MacCall(ref mac) => mac.attrs.attrs(),
637         }
638     }
639
640     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
641         match self {
642             StmtKind::Local(local) => local.visit_attrs(f),
643             StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f),
644             StmtKind::Empty | StmtKind::Item(..) => {}
645             StmtKind::MacCall(mac) => {
646                 mac.attrs.visit_attrs(f);
647             }
648         }
649     }
650 }
651
652 impl HasAttrs for Stmt {
653     fn attrs(&self) -> &[ast::Attribute] {
654         self.kind.attrs()
655     }
656
657     fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
658         self.kind.visit_attrs(f);
659     }
660 }
661
662 macro_rules! derive_has_attrs {
663     ($($ty:path),*) => { $(
664         impl HasAttrs for $ty {
665             fn attrs(&self) -> &[Attribute] {
666                 &self.attrs
667             }
668
669             fn visit_attrs(&mut self, f: impl FnOnce(&mut Vec<Attribute>)) {
670                 self.attrs.visit_attrs(f);
671             }
672         }
673     )* }
674 }
675
676 derive_has_attrs! {
677     Item, Expr, Local, ast::AssocItem, ast::ForeignItem, ast::StructField, ast::Arm,
678     ast::Field, ast::FieldPat, ast::Variant, ast::Param, GenericParam
679 }