]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_passes/src/check_attr.rs
Rollup merge of #93400 - ChayimFriedman2:dont-suggest-using-const-with-bounds-unused...
[rust.git] / compiler / rustc_passes / src / check_attr.rs
1 //! This module implements some validity checks for attributes.
2 //! In particular it verifies that `#[inline]` and `#[repr]` attributes are
3 //! attached to items that actually support them and if there are
4 //! conflicts between multiple such attributes attached to the same
5 //! item.
6
7 use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
8 use rustc_data_structures::fx::FxHashMap;
9 use rustc_errors::{pluralize, struct_span_err, Applicability};
10 use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
11 use rustc_hir as hir;
12 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
13 use rustc_hir::intravisit::{self, Visitor};
14 use rustc_hir::{self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID};
15 use rustc_hir::{MethodKind, Target};
16 use rustc_middle::hir::nested_filter;
17 use rustc_middle::ty::query::Providers;
18 use rustc_middle::ty::TyCtxt;
19 use rustc_session::lint::builtin::{
20     CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, UNUSED_ATTRIBUTES,
21 };
22 use rustc_session::parse::feature_err;
23 use rustc_span::symbol::{sym, Symbol};
24 use rustc_span::{MultiSpan, Span, DUMMY_SP};
25 use std::collections::hash_map::Entry;
26
27 pub(crate) fn target_from_impl_item<'tcx>(
28     tcx: TyCtxt<'tcx>,
29     impl_item: &hir::ImplItem<'_>,
30 ) -> Target {
31     match impl_item.kind {
32         hir::ImplItemKind::Const(..) => Target::AssocConst,
33         hir::ImplItemKind::Fn(..) => {
34             let parent_hir_id = tcx.hir().get_parent_item(impl_item.hir_id());
35             let containing_item = tcx.hir().expect_item(parent_hir_id);
36             let containing_impl_is_for_trait = match &containing_item.kind {
37                 hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
38                 _ => bug!("parent of an ImplItem must be an Impl"),
39             };
40             if containing_impl_is_for_trait {
41                 Target::Method(MethodKind::Trait { body: true })
42             } else {
43                 Target::Method(MethodKind::Inherent)
44             }
45         }
46         hir::ImplItemKind::TyAlias(..) => Target::AssocTy,
47     }
48 }
49
50 #[derive(Clone, Copy)]
51 enum ItemLike<'tcx> {
52     Item(&'tcx Item<'tcx>),
53     ForeignItem(&'tcx ForeignItem<'tcx>),
54 }
55
56 struct CheckAttrVisitor<'tcx> {
57     tcx: TyCtxt<'tcx>,
58 }
59
60 impl CheckAttrVisitor<'_> {
61     /// Checks any attribute.
62     fn check_attributes(
63         &self,
64         hir_id: HirId,
65         span: Span,
66         target: Target,
67         item: Option<ItemLike<'_>>,
68     ) {
69         let mut doc_aliases = FxHashMap::default();
70         let mut is_valid = true;
71         let mut specified_inline = None;
72         let mut seen = FxHashMap::default();
73         let attrs = self.tcx.hir().attrs(hir_id);
74         for attr in attrs {
75             let attr_is_valid = match attr.name_or_empty() {
76                 sym::inline => self.check_inline(hir_id, attr, span, target),
77                 sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
78                 sym::marker => self.check_marker(hir_id, attr, span, target),
79                 sym::rustc_must_implement_one_of => {
80                     self.check_rustc_must_implement_one_of(attr, span, target)
81                 }
82                 sym::target_feature => self.check_target_feature(hir_id, attr, span, target),
83                 sym::track_caller => {
84                     self.check_track_caller(hir_id, attr.span, attrs, span, target)
85                 }
86                 sym::doc => self.check_doc_attrs(
87                     attr,
88                     hir_id,
89                     target,
90                     &mut specified_inline,
91                     &mut doc_aliases,
92                 ),
93                 sym::no_link => self.check_no_link(hir_id, &attr, span, target),
94                 sym::export_name => self.check_export_name(hir_id, &attr, span, target),
95                 sym::rustc_layout_scalar_valid_range_start
96                 | sym::rustc_layout_scalar_valid_range_end => {
97                     self.check_rustc_layout_scalar_valid_range(&attr, span, target)
98                 }
99                 sym::allow_internal_unstable => {
100                     self.check_allow_internal_unstable(hir_id, &attr, span, target, &attrs)
101                 }
102                 sym::rustc_allow_const_fn_unstable => {
103                     self.check_rustc_allow_const_fn_unstable(hir_id, &attr, span, target)
104                 }
105                 sym::naked => self.check_naked(hir_id, attr, span, target),
106                 sym::rustc_legacy_const_generics => {
107                     self.check_rustc_legacy_const_generics(&attr, span, target, item)
108                 }
109                 sym::rustc_lint_query_instability => {
110                     self.check_rustc_lint_query_instability(&attr, span, target)
111                 }
112                 sym::rustc_clean
113                 | sym::rustc_dirty
114                 | sym::rustc_if_this_changed
115                 | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(&attr),
116                 sym::cmse_nonsecure_entry => self.check_cmse_nonsecure_entry(attr, span, target),
117                 sym::default_method_body_is_const => {
118                     self.check_default_method_body_is_const(attr, span, target)
119                 }
120                 sym::must_not_suspend => self.check_must_not_suspend(&attr, span, target),
121                 sym::must_use => self.check_must_use(hir_id, &attr, span, target),
122                 sym::rustc_pass_by_value => self.check_pass_by_value(&attr, span, target),
123                 sym::rustc_const_unstable
124                 | sym::rustc_const_stable
125                 | sym::unstable
126                 | sym::stable
127                 | sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
128                 _ => true,
129             };
130             is_valid &= attr_is_valid;
131
132             // lint-only checks
133             match attr.name_or_empty() {
134                 sym::cold => self.check_cold(hir_id, attr, span, target),
135                 sym::link => self.check_link(hir_id, attr, span, target),
136                 sym::link_name => self.check_link_name(hir_id, attr, span, target),
137                 sym::link_section => self.check_link_section(hir_id, attr, span, target),
138                 sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
139                 sym::deprecated | sym::rustc_deprecated => {
140                     self.check_deprecated(hir_id, attr, span, target)
141                 }
142                 sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
143                 sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
144                 sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
145                 sym::macro_export => self.check_macro_export(hir_id, attr, target),
146                 sym::ignore | sym::should_panic | sym::proc_macro_derive => {
147                     self.check_generic_attr(hir_id, attr, target, &[Target::Fn])
148                 }
149                 sym::automatically_derived => {
150                     self.check_generic_attr(hir_id, attr, target, &[Target::Impl])
151                 }
152                 sym::no_implicit_prelude => {
153                     self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
154                 }
155                 _ => {}
156             }
157
158             let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
159
160             if hir_id != CRATE_HIR_ID {
161                 if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
162                     attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
163                 {
164                     self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
165                         let msg = match attr.style {
166                             ast::AttrStyle::Outer => {
167                                 "crate-level attribute should be an inner attribute: add an exclamation \
168                                  mark: `#![foo]`"
169                             }
170                             ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
171                         };
172                         lint.build(msg).emit()
173                     });
174                 }
175             }
176
177             if let Some(BuiltinAttribute { duplicates, .. }) = builtin {
178                 check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
179             }
180
181             // Warn on useless empty attributes.
182             if matches!(
183                 attr.name_or_empty(),
184                 sym::macro_use
185                     | sym::allow
186                     | sym::warn
187                     | sym::deny
188                     | sym::forbid
189                     | sym::feature
190                     | sym::repr
191                     | sym::target_feature
192             ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
193             {
194                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
195                     lint.build("unused attribute")
196                         .span_suggestion(
197                             attr.span,
198                             "remove this attribute",
199                             String::new(),
200                             Applicability::MachineApplicable,
201                         )
202                         .note(&format!(
203                             "attribute `{}` with an empty list has no effect",
204                             attr.name_or_empty()
205                         ))
206                         .emit();
207                 });
208             }
209         }
210
211         if !is_valid {
212             return;
213         }
214
215         if matches!(target, Target::Closure | Target::Fn | Target::Method(_) | Target::ForeignFn) {
216             self.tcx.ensure().codegen_fn_attrs(self.tcx.hir().local_def_id(hir_id));
217         }
218
219         self.check_repr(attrs, span, target, item, hir_id);
220         self.check_used(attrs, target);
221     }
222
223     fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
224         self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
225             lint.build(&format!(
226                 "`#[{}]` is ignored on struct fields, match arms and macro defs",
227                 sym,
228             ))
229             .warn(
230                 "this was previously accepted by the compiler but is \
231                  being phased out; it will become a hard error in \
232                  a future release!",
233             )
234             .note(
235                 "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
236                  for more information",
237             )
238             .emit();
239         });
240     }
241
242     fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
243         self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
244             lint.build(&format!("`#[{}]` is ignored on struct fields and match arms", sym))
245                 .warn(
246                     "this was previously accepted by the compiler but is \
247                  being phased out; it will become a hard error in \
248                  a future release!",
249                 )
250                 .note(
251                     "see issue #80564 <https://github.com/rust-lang/rust/issues/80564> \
252                  for more information",
253                 )
254                 .emit();
255         });
256     }
257
258     /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
259     fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
260         match target {
261             Target::Fn
262             | Target::Closure
263             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
264             Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
265                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
266                     lint.build("`#[inline]` is ignored on function prototypes").emit()
267                 });
268                 true
269             }
270             // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
271             // just a lint, because we previously erroneously allowed it and some crates used it
272             // accidentally, to to be compatible with crates depending on them, we can't throw an
273             // error here.
274             Target::AssocConst => {
275                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
276                     lint.build("`#[inline]` is ignored on constants")
277                         .warn(
278                             "this was previously accepted by the compiler but is \
279                              being phased out; it will become a hard error in \
280                              a future release!",
281                         )
282                         .note(
283                             "see issue #65833 <https://github.com/rust-lang/rust/issues/65833> \
284                              for more information",
285                         )
286                         .emit();
287                 });
288                 true
289             }
290             // FIXME(#80564): Same for fields, arms, and macro defs
291             Target::Field | Target::Arm | Target::MacroDef => {
292                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline");
293                 true
294             }
295             _ => {
296                 struct_span_err!(
297                     self.tcx.sess,
298                     attr.span,
299                     E0518,
300                     "attribute should be applied to function or closure",
301                 )
302                 .span_label(span, "not a function or closure")
303                 .emit();
304                 false
305             }
306         }
307     }
308
309     fn check_generic_attr(
310         &self,
311         hir_id: HirId,
312         attr: &Attribute,
313         target: Target,
314         allowed_targets: &[Target],
315     ) {
316         if !allowed_targets.iter().any(|t| t == &target) {
317             let name = attr.name_or_empty();
318             let mut i = allowed_targets.iter();
319             // Pluralize
320             let b = i.next().map_or_else(String::new, |t| t.to_string() + "s");
321             let supported_names = i.enumerate().fold(b, |mut b, (i, allowed_target)| {
322                 if allowed_targets.len() > 2 && i == allowed_targets.len() - 2 {
323                     b.push_str(", and ");
324                 } else if allowed_targets.len() == 2 && i == allowed_targets.len() - 2 {
325                     b.push_str(" and ");
326                 } else {
327                     b.push_str(", ");
328                 }
329                 // Pluralize
330                 b.push_str(&(allowed_target.to_string() + "s"));
331                 b
332             });
333             self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
334                 lint.build(&format!("`#[{name}]` only has an effect on {}", supported_names))
335                     .emit();
336             });
337         }
338     }
339
340     /// Checks if `#[naked]` is applied to a function definition.
341     fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
342         match target {
343             Target::Fn
344             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
345             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
346             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
347             // erroneously allowed it and some crates used it accidentally, to to be compatible
348             // with crates depending on them, we can't throw an error here.
349             Target::Field | Target::Arm | Target::MacroDef => {
350                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked");
351                 true
352             }
353             _ => {
354                 self.tcx
355                     .sess
356                     .struct_span_err(
357                         attr.span,
358                         "attribute should be applied to a function definition",
359                     )
360                     .span_label(span, "not a function definition")
361                     .emit();
362                 false
363             }
364         }
365     }
366
367     /// Checks if `#[cmse_nonsecure_entry]` is applied to a function definition.
368     fn check_cmse_nonsecure_entry(&self, attr: &Attribute, span: Span, target: Target) -> bool {
369         match target {
370             Target::Fn
371             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
372             _ => {
373                 self.tcx
374                     .sess
375                     .struct_span_err(
376                         attr.span,
377                         "attribute should be applied to a function definition",
378                     )
379                     .span_label(span, "not a function definition")
380                     .emit();
381                 false
382             }
383         }
384     }
385
386     /// Checks if a `#[track_caller]` is applied to a non-naked function. Returns `true` if valid.
387     fn check_track_caller(
388         &self,
389         hir_id: HirId,
390         attr_span: Span,
391         attrs: &[Attribute],
392         span: Span,
393         target: Target,
394     ) -> bool {
395         match target {
396             _ if attrs.iter().any(|attr| attr.has_name(sym::naked)) => {
397                 struct_span_err!(
398                     self.tcx.sess,
399                     attr_span,
400                     E0736,
401                     "cannot use `#[track_caller]` with `#[naked]`",
402                 )
403                 .emit();
404                 false
405             }
406             Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true,
407             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
408             // `#[track_caller]` attribute with just a lint, because we previously
409             // erroneously allowed it and some crates used it accidentally, to to be compatible
410             // with crates depending on them, we can't throw an error here.
411             Target::Field | Target::Arm | Target::MacroDef => {
412                 for attr in attrs {
413                     self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
414                 }
415                 true
416             }
417             _ => {
418                 struct_span_err!(
419                     self.tcx.sess,
420                     attr_span,
421                     E0739,
422                     "attribute should be applied to function"
423                 )
424                 .span_label(span, "not a function")
425                 .emit();
426                 false
427             }
428         }
429     }
430
431     /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid. Returns `true` if valid.
432     fn check_non_exhaustive(
433         &self,
434         hir_id: HirId,
435         attr: &Attribute,
436         span: Span,
437         target: Target,
438     ) -> bool {
439         match target {
440             Target::Struct | Target::Enum | Target::Variant => true,
441             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
442             // `#[non_exhaustive]` attribute with just a lint, because we previously
443             // erroneously allowed it and some crates used it accidentally, to to be compatible
444             // with crates depending on them, we can't throw an error here.
445             Target::Field | Target::Arm | Target::MacroDef => {
446                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
447                 true
448             }
449             _ => {
450                 struct_span_err!(
451                     self.tcx.sess,
452                     attr.span,
453                     E0701,
454                     "attribute can only be applied to a struct or enum"
455                 )
456                 .span_label(span, "not a struct or enum")
457                 .emit();
458                 false
459             }
460         }
461     }
462
463     /// Checks if the `#[marker]` attribute on an `item` is valid. Returns `true` if valid.
464     fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
465         match target {
466             Target::Trait => true,
467             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
468             // `#[marker]` attribute with just a lint, because we previously
469             // erroneously allowed it and some crates used it accidentally, to to be compatible
470             // with crates depending on them, we can't throw an error here.
471             Target::Field | Target::Arm | Target::MacroDef => {
472                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
473                 true
474             }
475             _ => {
476                 self.tcx
477                     .sess
478                     .struct_span_err(attr.span, "attribute can only be applied to a trait")
479                     .span_label(span, "not a trait")
480                     .emit();
481                 false
482             }
483         }
484     }
485
486     /// Checks if the `#[rustc_must_implement_one_of]` attribute on a `target` is valid. Returns `true` if valid.
487     fn check_rustc_must_implement_one_of(
488         &self,
489         attr: &Attribute,
490         span: Span,
491         target: Target,
492     ) -> bool {
493         match target {
494             Target::Trait => true,
495             _ => {
496                 self.tcx
497                     .sess
498                     .struct_span_err(attr.span, "attribute can only be applied to a trait")
499                     .span_label(span, "not a trait")
500                     .emit();
501                 false
502             }
503         }
504     }
505
506     /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid.
507     fn check_target_feature(
508         &self,
509         hir_id: HirId,
510         attr: &Attribute,
511         span: Span,
512         target: Target,
513     ) -> bool {
514         match target {
515             Target::Fn
516             | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true,
517             // FIXME: #[target_feature] was previously erroneously allowed on statements and some
518             // crates used this, so only emit a warning.
519             Target::Statement => {
520                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
521                     lint.build("attribute should be applied to a function")
522                         .warn(
523                             "this was previously accepted by the compiler but is \
524                              being phased out; it will become a hard error in \
525                              a future release!",
526                         )
527                         .span_label(span, "not a function")
528                         .emit();
529                 });
530                 true
531             }
532             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
533             // `#[target_feature]` attribute with just a lint, because we previously
534             // erroneously allowed it and some crates used it accidentally, to to be compatible
535             // with crates depending on them, we can't throw an error here.
536             Target::Field | Target::Arm | Target::MacroDef => {
537                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
538                 true
539             }
540             _ => {
541                 self.tcx
542                     .sess
543                     .struct_span_err(attr.span, "attribute should be applied to a function")
544                     .span_label(span, "not a function")
545                     .emit();
546                 false
547             }
548         }
549     }
550
551     fn doc_attr_str_error(&self, meta: &NestedMetaItem, attr_name: &str) {
552         self.tcx
553             .sess
554             .struct_span_err(
555                 meta.span(),
556                 &format!("doc {0} attribute expects a string: #[doc({0} = \"a\")]", attr_name),
557             )
558             .emit();
559     }
560
561     fn check_doc_alias_value(
562         &self,
563         meta: &NestedMetaItem,
564         doc_alias: &str,
565         hir_id: HirId,
566         target: Target,
567         is_list: bool,
568         aliases: &mut FxHashMap<String, Span>,
569     ) -> bool {
570         let tcx = self.tcx;
571         let err_fn = move |span: Span, msg: &str| {
572             tcx.sess.span_err(
573                 span,
574                 &format!(
575                     "`#[doc(alias{})]` {}",
576                     if is_list { "(\"...\")" } else { " = \"...\"" },
577                     msg,
578                 ),
579             );
580             false
581         };
582         if doc_alias.is_empty() {
583             return err_fn(
584                 meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
585                 "attribute cannot have empty value",
586             );
587         }
588         if let Some(c) =
589             doc_alias.chars().find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
590         {
591             self.tcx.sess.span_err(
592                 meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
593                 &format!(
594                     "{:?} character isn't allowed in `#[doc(alias{})]`",
595                     c,
596                     if is_list { "(\"...\")" } else { " = \"...\"" },
597                 ),
598             );
599             return false;
600         }
601         if doc_alias.starts_with(' ') || doc_alias.ends_with(' ') {
602             return err_fn(
603                 meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
604                 "cannot start or end with ' '",
605             );
606         }
607         if let Some(err) = match target {
608             Target::Impl => Some("implementation block"),
609             Target::ForeignMod => Some("extern block"),
610             Target::AssocTy => {
611                 let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
612                 let containing_item = self.tcx.hir().expect_item(parent_hir_id);
613                 if Target::from_item(containing_item) == Target::Impl {
614                     Some("type alias in implementation block")
615                 } else {
616                     None
617                 }
618             }
619             Target::AssocConst => {
620                 let parent_hir_id = self.tcx.hir().get_parent_item(hir_id);
621                 let containing_item = self.tcx.hir().expect_item(parent_hir_id);
622                 // We can't link to trait impl's consts.
623                 let err = "associated constant in trait implementation block";
624                 match containing_item.kind {
625                     ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => Some(err),
626                     _ => None,
627                 }
628             }
629             // we check the validity of params elsewhere
630             Target::Param => return false,
631             _ => None,
632         } {
633             return err_fn(meta.span(), &format!("isn't allowed on {}", err));
634         }
635         let item_name = self.tcx.hir().name(hir_id);
636         if item_name.as_str() == doc_alias {
637             return err_fn(meta.span(), "is the same as the item's name");
638         }
639         let span = meta.span();
640         if let Err(entry) = aliases.try_insert(doc_alias.to_owned(), span) {
641             self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, span, |lint| {
642                 lint.build("doc alias is duplicated")
643                     .span_label(*entry.entry.get(), "first defined here")
644                     .emit();
645             });
646         }
647         true
648     }
649
650     fn check_doc_alias(
651         &self,
652         meta: &NestedMetaItem,
653         hir_id: HirId,
654         target: Target,
655         aliases: &mut FxHashMap<String, Span>,
656     ) -> bool {
657         if let Some(values) = meta.meta_item_list() {
658             let mut errors = 0;
659             for v in values {
660                 match v.literal() {
661                     Some(l) => match l.kind {
662                         LitKind::Str(s, _) => {
663                             if !self.check_doc_alias_value(
664                                 v,
665                                 s.as_str(),
666                                 hir_id,
667                                 target,
668                                 true,
669                                 aliases,
670                             ) {
671                                 errors += 1;
672                             }
673                         }
674                         _ => {
675                             self.tcx
676                                 .sess
677                                 .struct_span_err(
678                                     v.span(),
679                                     "`#[doc(alias(\"a\"))]` expects string literals",
680                                 )
681                                 .emit();
682                             errors += 1;
683                         }
684                     },
685                     None => {
686                         self.tcx
687                             .sess
688                             .struct_span_err(
689                                 v.span(),
690                                 "`#[doc(alias(\"a\"))]` expects string literals",
691                             )
692                             .emit();
693                         errors += 1;
694                     }
695                 }
696             }
697             errors == 0
698         } else if let Some(doc_alias) = meta.value_str().map(|s| s.to_string()) {
699             self.check_doc_alias_value(meta, &doc_alias, hir_id, target, false, aliases)
700         } else {
701             self.tcx
702                 .sess
703                 .struct_span_err(
704                     meta.span(),
705                     "doc alias attribute expects a string `#[doc(alias = \"a\")]` or a list of \
706                      strings `#[doc(alias(\"a\", \"b\"))]`",
707                 )
708                 .emit();
709             false
710         }
711     }
712
713     fn check_doc_keyword(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
714         let doc_keyword = meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new);
715         if doc_keyword.is_empty() {
716             self.doc_attr_str_error(meta, "keyword");
717             return false;
718         }
719         match self.tcx.hir().find(hir_id).and_then(|node| match node {
720             hir::Node::Item(item) => Some(&item.kind),
721             _ => None,
722         }) {
723             Some(ItemKind::Mod(ref module)) => {
724                 if !module.item_ids.is_empty() {
725                     self.tcx
726                         .sess
727                         .struct_span_err(
728                             meta.span(),
729                             "`#[doc(keyword = \"...\")]` can only be used on empty modules",
730                         )
731                         .emit();
732                     return false;
733                 }
734             }
735             _ => {
736                 self.tcx
737                     .sess
738                     .struct_span_err(
739                         meta.span(),
740                         "`#[doc(keyword = \"...\")]` can only be used on modules",
741                     )
742                     .emit();
743                 return false;
744             }
745         }
746         if !rustc_lexer::is_ident(&doc_keyword) {
747             self.tcx
748                 .sess
749                 .struct_span_err(
750                     meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
751                     &format!("`{}` is not a valid identifier", doc_keyword),
752                 )
753                 .emit();
754             return false;
755         }
756         true
757     }
758
759     /// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes. Returns `true` if valid.
760     ///
761     /// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
762     /// if there are conflicting attributes for one item.
763     ///
764     /// `specified_inline` is used to keep track of whether we have
765     /// already seen an inlining attribute for this item.
766     /// If so, `specified_inline` holds the value and the span of
767     /// the first `inline`/`no_inline` attribute.
768     fn check_doc_inline(
769         &self,
770         attr: &Attribute,
771         meta: &NestedMetaItem,
772         hir_id: HirId,
773         target: Target,
774         specified_inline: &mut Option<(bool, Span)>,
775     ) -> bool {
776         if target == Target::Use || target == Target::ExternCrate {
777             let do_inline = meta.name_or_empty() == sym::inline;
778             if let Some((prev_inline, prev_span)) = *specified_inline {
779                 if do_inline != prev_inline {
780                     let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
781                     spans.push_span_label(prev_span, String::from("this attribute..."));
782                     spans.push_span_label(
783                         meta.span(),
784                         String::from("...conflicts with this attribute"),
785                     );
786                     self.tcx
787                         .sess
788                         .struct_span_err(spans, "conflicting doc inlining attributes")
789                         .help("remove one of the conflicting attributes")
790                         .emit();
791                     return false;
792                 }
793                 true
794             } else {
795                 *specified_inline = Some((do_inline, meta.span()));
796                 true
797             }
798         } else {
799             self.tcx.struct_span_lint_hir(
800                 INVALID_DOC_ATTRIBUTES,
801                 hir_id,
802                 meta.span(),
803                 |lint| {
804                     let mut err = lint.build(
805                         "this attribute can only be applied to a `use` item",
806                     );
807                     err.span_label(meta.span(), "only applicable on `use` items");
808                     if attr.style == AttrStyle::Outer {
809                         err.span_label(
810                             self.tcx.hir().span(hir_id),
811                             "not a `use` item",
812                         );
813                     }
814                     err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline for more information")
815                         .emit();
816                 },
817             );
818             false
819         }
820     }
821
822     /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
823     fn check_attr_not_crate_level(
824         &self,
825         meta: &NestedMetaItem,
826         hir_id: HirId,
827         attr_name: &str,
828     ) -> bool {
829         if CRATE_HIR_ID == hir_id {
830             self.tcx
831                 .sess
832                 .struct_span_err(
833                     meta.span(),
834                     &format!(
835                         "`#![doc({} = \"...\")]` isn't allowed as a crate-level attribute",
836                         attr_name,
837                     ),
838                 )
839                 .emit();
840             return false;
841         }
842         true
843     }
844
845     /// Checks that an attribute is used at the crate level. Returns `true` if valid.
846     fn check_attr_crate_level(
847         &self,
848         attr: &Attribute,
849         meta: &NestedMetaItem,
850         hir_id: HirId,
851     ) -> bool {
852         if hir_id != CRATE_HIR_ID {
853             self.tcx.struct_span_lint_hir(
854                 INVALID_DOC_ATTRIBUTES,
855                 hir_id,
856                 meta.span(),
857                 |lint| {
858                     let mut err = lint.build(
859                         "this attribute can only be applied at the crate level",
860                     );
861                     if attr.style == AttrStyle::Outer && self.tcx.hir().get_parent_item(hir_id) == CRATE_DEF_ID {
862                         if let Ok(mut src) =
863                             self.tcx.sess.source_map().span_to_snippet(attr.span)
864                         {
865                             src.insert(1, '!');
866                             err.span_suggestion_verbose(
867                                 attr.span,
868                                 "to apply to the crate, use an inner attribute",
869                                 src,
870                                 Applicability::MaybeIncorrect,
871                             );
872                         } else {
873                             err.span_help(
874                                 attr.span,
875                                 "to apply to the crate, use an inner attribute",
876                             );
877                         }
878                     }
879                     err.note("read https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level for more information")
880                         .emit();
881                 },
882             );
883             return false;
884         }
885         true
886     }
887
888     /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if
889     /// valid.
890     fn check_test_attr(&self, meta: &NestedMetaItem, hir_id: HirId) -> bool {
891         let mut is_valid = true;
892         if let Some(metas) = meta.meta_item_list() {
893             for i_meta in metas {
894                 match i_meta.name_or_empty() {
895                     sym::attr | sym::no_crate_inject => {}
896                     _ => {
897                         self.tcx.struct_span_lint_hir(
898                             INVALID_DOC_ATTRIBUTES,
899                             hir_id,
900                             i_meta.span(),
901                             |lint| {
902                                 lint.build(&format!(
903                                     "unknown `doc(test)` attribute `{}`",
904                                     rustc_ast_pretty::pprust::path_to_string(
905                                         &i_meta.meta_item().unwrap().path
906                                     ),
907                                 ))
908                                 .emit();
909                             },
910                         );
911                         is_valid = false;
912                     }
913                 }
914             }
915         } else {
916             self.tcx.struct_span_lint_hir(INVALID_DOC_ATTRIBUTES, hir_id, meta.span(), |lint| {
917                 lint.build("`#[doc(test(...)]` takes a list of attributes").emit();
918             });
919             is_valid = false;
920         }
921         is_valid
922     }
923
924     /// Runs various checks on `#[doc]` attributes. Returns `true` if valid.
925     ///
926     /// `specified_inline` should be initialized to `None` and kept for the scope
927     /// of one item. Read the documentation of [`check_doc_inline`] for more information.
928     ///
929     /// [`check_doc_inline`]: Self::check_doc_inline
930     fn check_doc_attrs(
931         &self,
932         attr: &Attribute,
933         hir_id: HirId,
934         target: Target,
935         specified_inline: &mut Option<(bool, Span)>,
936         aliases: &mut FxHashMap<String, Span>,
937     ) -> bool {
938         let mut is_valid = true;
939
940         if let Some(list) = attr.meta().and_then(|mi| mi.meta_item_list().map(|l| l.to_vec())) {
941             for meta in &list {
942                 if let Some(i_meta) = meta.meta_item() {
943                     match i_meta.name_or_empty() {
944                         sym::alias
945                             if !self.check_attr_not_crate_level(&meta, hir_id, "alias")
946                                 || !self.check_doc_alias(&meta, hir_id, target, aliases) =>
947                         {
948                             is_valid = false
949                         }
950
951                         sym::keyword
952                             if !self.check_attr_not_crate_level(&meta, hir_id, "keyword")
953                                 || !self.check_doc_keyword(&meta, hir_id) =>
954                         {
955                             is_valid = false
956                         }
957
958                         sym::html_favicon_url
959                         | sym::html_logo_url
960                         | sym::html_playground_url
961                         | sym::issue_tracker_base_url
962                         | sym::html_root_url
963                         | sym::html_no_source
964                         | sym::test
965                             if !self.check_attr_crate_level(&attr, &meta, hir_id) =>
966                         {
967                             is_valid = false;
968                         }
969
970                         sym::inline | sym::no_inline
971                             if !self.check_doc_inline(
972                                 &attr,
973                                 &meta,
974                                 hir_id,
975                                 target,
976                                 specified_inline,
977                             ) =>
978                         {
979                             is_valid = false;
980                         }
981
982                         // no_default_passes: deprecated
983                         // passes: deprecated
984                         // plugins: removed, but rustdoc warns about it itself
985                         sym::alias
986                         | sym::cfg
987                         | sym::cfg_hide
988                         | sym::hidden
989                         | sym::html_favicon_url
990                         | sym::html_logo_url
991                         | sym::html_no_source
992                         | sym::html_playground_url
993                         | sym::html_root_url
994                         | sym::inline
995                         | sym::issue_tracker_base_url
996                         | sym::keyword
997                         | sym::masked
998                         | sym::no_default_passes
999                         | sym::no_inline
1000                         | sym::notable_trait
1001                         | sym::passes
1002                         | sym::plugins => {}
1003
1004                         sym::test => {
1005                             if !self.check_test_attr(&meta, hir_id) {
1006                                 is_valid = false;
1007                             }
1008                         }
1009
1010                         sym::primitive => {
1011                             if !self.tcx.features().rustdoc_internals {
1012                                 self.tcx.struct_span_lint_hir(
1013                                     INVALID_DOC_ATTRIBUTES,
1014                                     hir_id,
1015                                     i_meta.span,
1016                                     |lint| {
1017                                         let mut diag = lint.build(
1018                                             "`doc(primitive)` should never have been stable",
1019                                         );
1020                                         diag.emit();
1021                                     },
1022                                 );
1023                             }
1024                         }
1025
1026                         _ => {
1027                             self.tcx.struct_span_lint_hir(
1028                                 INVALID_DOC_ATTRIBUTES,
1029                                 hir_id,
1030                                 i_meta.span,
1031                                 |lint| {
1032                                     let mut diag = lint.build(&format!(
1033                                         "unknown `doc` attribute `{}`",
1034                                         rustc_ast_pretty::pprust::path_to_string(&i_meta.path),
1035                                     ));
1036                                     if i_meta.has_name(sym::spotlight) {
1037                                         diag.note(
1038                                             "`doc(spotlight)` was renamed to `doc(notable_trait)`",
1039                                         );
1040                                         diag.span_suggestion_short(
1041                                             i_meta.span,
1042                                             "use `notable_trait` instead",
1043                                             String::from("notable_trait"),
1044                                             Applicability::MachineApplicable,
1045                                         );
1046                                         diag.note("`doc(spotlight)` is now a no-op");
1047                                     }
1048                                     if i_meta.has_name(sym::include) {
1049                                         if let Some(value) = i_meta.value_str() {
1050                                             // if there are multiple attributes, the suggestion would suggest deleting all of them, which is incorrect
1051                                             let applicability = if list.len() == 1 {
1052                                                 Applicability::MachineApplicable
1053                                             } else {
1054                                                 Applicability::MaybeIncorrect
1055                                             };
1056                                             let inner = if attr.style == AttrStyle::Inner {
1057                                                 "!"
1058                                             } else {
1059                                                 ""
1060                                             };
1061                                             diag.span_suggestion(
1062                                                 attr.meta().unwrap().span,
1063                                                 "use `doc = include_str!` instead",
1064                                                 format!(
1065                                                     "#{}[doc = include_str!(\"{}\")]",
1066                                                     inner, value
1067                                                 ),
1068                                                 applicability,
1069                                             );
1070                                         }
1071                                     }
1072                                     diag.emit();
1073                                 },
1074                             );
1075                             is_valid = false;
1076                         }
1077                     }
1078                 } else {
1079                     self.tcx.struct_span_lint_hir(
1080                         INVALID_DOC_ATTRIBUTES,
1081                         hir_id,
1082                         meta.span(),
1083                         |lint| {
1084                             lint.build(&"invalid `doc` attribute").emit();
1085                         },
1086                     );
1087                     is_valid = false;
1088                 }
1089             }
1090         }
1091
1092         is_valid
1093     }
1094
1095     /// Warns against some misuses of `#[pass_by_value]`
1096     fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) -> bool {
1097         match target {
1098             Target::Struct | Target::Enum | Target::TyAlias => true,
1099             _ => {
1100                 self.tcx
1101                     .sess
1102                     .struct_span_err(
1103                         attr.span,
1104                         "`pass_by_value` attribute should be applied to a struct, enum or type alias.",
1105                     )
1106                     .span_label(span, "is not a struct, enum or type alias")
1107                     .emit();
1108                 false
1109             }
1110         }
1111     }
1112
1113     /// Warns against some misuses of `#[must_use]`
1114     fn check_must_use(&self, hir_id: HirId, attr: &Attribute, span: Span, _target: Target) -> bool {
1115         let node = self.tcx.hir().get(hir_id);
1116         if let Some(fn_node) = node.fn_kind() {
1117             if let rustc_hir::IsAsync::Async = fn_node.asyncness() {
1118                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1119                     lint.build(
1120                         "`must_use` attribute on `async` functions \
1121                               applies to the anonymous `Future` returned by the \
1122                               function, not the value within",
1123                     )
1124                     .span_label(
1125                         span,
1126                         "this attribute does nothing, the `Future`s \
1127                                 returned by async functions are already `must_use`",
1128                     )
1129                     .emit();
1130                 });
1131             }
1132         }
1133
1134         // For now, its always valid
1135         true
1136     }
1137
1138     /// Checks if `#[must_not_suspend]` is applied to a function. Returns `true` if valid.
1139     fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) -> bool {
1140         match target {
1141             Target::Struct | Target::Enum | Target::Union | Target::Trait => true,
1142             _ => {
1143                 self.tcx
1144                     .sess
1145                     .struct_span_err(attr.span, "`must_not_suspend` attribute should be applied to a struct, enum, or trait")
1146                         .span_label(span, "is not a struct, enum, or trait")
1147                         .emit();
1148                 false
1149             }
1150         }
1151     }
1152
1153     /// Checks if `#[cold]` is applied to a non-function. Returns `true` if valid.
1154     fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1155         match target {
1156             Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
1157             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1158             // `#[cold]` attribute with just a lint, because we previously
1159             // erroneously allowed it and some crates used it accidentally, to to be compatible
1160             // with crates depending on them, we can't throw an error here.
1161             Target::Field | Target::Arm | Target::MacroDef => {
1162                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "cold");
1163             }
1164             _ => {
1165                 // FIXME: #[cold] was previously allowed on non-functions and some crates used
1166                 // this, so only emit a warning.
1167                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1168                     lint.build("attribute should be applied to a function")
1169                         .warn(
1170                             "this was previously accepted by the compiler but is \
1171                              being phased out; it will become a hard error in \
1172                              a future release!",
1173                         )
1174                         .span_label(span, "not a function")
1175                         .emit();
1176                 });
1177             }
1178         }
1179     }
1180
1181     /// Checks if `#[link]` is applied to an item other than a foreign module.
1182     fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1183         match target {
1184             Target::ForeignMod => {}
1185             _ => {
1186                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1187                     let mut diag = lint.build("attribute should be applied to an `extern` block");
1188                     diag.warn(
1189                         "this was previously accepted by the compiler but is \
1190                          being phased out; it will become a hard error in \
1191                          a future release!",
1192                     );
1193
1194                     diag.span_label(span, "not an `extern` block");
1195                     diag.emit();
1196                 });
1197             }
1198         }
1199     }
1200
1201     /// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
1202     fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1203         match target {
1204             Target::ForeignFn | Target::ForeignStatic => {}
1205             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1206             // `#[link_name]` attribute with just a lint, because we previously
1207             // erroneously allowed it and some crates used it accidentally, to to be compatible
1208             // with crates depending on them, we can't throw an error here.
1209             Target::Field | Target::Arm | Target::MacroDef => {
1210                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
1211             }
1212             _ => {
1213                 // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
1214                 // used this, so only emit a warning.
1215                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1216                     let mut diag =
1217                         lint.build("attribute should be applied to a foreign function or static");
1218                     diag.warn(
1219                         "this was previously accepted by the compiler but is \
1220                          being phased out; it will become a hard error in \
1221                          a future release!",
1222                     );
1223
1224                     // See issue #47725
1225                     if let Target::ForeignMod = target {
1226                         if let Some(value) = attr.value_str() {
1227                             diag.span_help(
1228                                 attr.span,
1229                                 &format!(r#"try `#[link(name = "{}")]` instead"#, value),
1230                             );
1231                         } else {
1232                             diag.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#);
1233                         }
1234                     }
1235
1236                     diag.span_label(span, "not a foreign function or static");
1237                     diag.emit();
1238                 });
1239             }
1240         }
1241     }
1242
1243     /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid.
1244     fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) -> bool {
1245         match target {
1246             Target::ExternCrate => true,
1247             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1248             // `#[no_link]` attribute with just a lint, because we previously
1249             // erroneously allowed it and some crates used it accidentally, to to be compatible
1250             // with crates depending on them, we can't throw an error here.
1251             Target::Field | Target::Arm | Target::MacroDef => {
1252                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
1253                 true
1254             }
1255             _ => {
1256                 self.tcx
1257                     .sess
1258                     .struct_span_err(
1259                         attr.span,
1260                         "attribute should be applied to an `extern crate` item",
1261                     )
1262                     .span_label(span, "not an `extern crate` item")
1263                     .emit();
1264                 false
1265             }
1266         }
1267     }
1268
1269     fn is_impl_item(&self, hir_id: HirId) -> bool {
1270         matches!(self.tcx.hir().get(hir_id), hir::Node::ImplItem(..))
1271     }
1272
1273     /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid.
1274     fn check_export_name(
1275         &self,
1276         hir_id: HirId,
1277         attr: &Attribute,
1278         span: Span,
1279         target: Target,
1280     ) -> bool {
1281         match target {
1282             Target::Static | Target::Fn => true,
1283             Target::Method(..) if self.is_impl_item(hir_id) => true,
1284             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1285             // `#[export_name]` attribute with just a lint, because we previously
1286             // erroneously allowed it and some crates used it accidentally, to to be compatible
1287             // with crates depending on them, we can't throw an error here.
1288             Target::Field | Target::Arm | Target::MacroDef => {
1289                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
1290                 true
1291             }
1292             _ => {
1293                 self.tcx
1294                     .sess
1295                     .struct_span_err(
1296                         attr.span,
1297                         "attribute should be applied to a free function, impl method or static",
1298                     )
1299                     .span_label(span, "not a free function, impl method or static")
1300                     .emit();
1301                 false
1302             }
1303         }
1304     }
1305
1306     fn check_rustc_layout_scalar_valid_range(
1307         &self,
1308         attr: &Attribute,
1309         span: Span,
1310         target: Target,
1311     ) -> bool {
1312         if target != Target::Struct {
1313             self.tcx
1314                 .sess
1315                 .struct_span_err(attr.span, "attribute should be applied to a struct")
1316                 .span_label(span, "not a struct")
1317                 .emit();
1318             return false;
1319         }
1320
1321         let Some(list) = attr.meta_item_list() else {
1322             return false;
1323         };
1324
1325         if matches!(&list[..], &[NestedMetaItem::Literal(Lit { kind: LitKind::Int(..), .. })]) {
1326             true
1327         } else {
1328             self.tcx
1329                 .sess
1330                 .struct_span_err(attr.span, "expected exactly one integer literal argument")
1331                 .emit();
1332             false
1333         }
1334     }
1335
1336     /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument.
1337     fn check_rustc_legacy_const_generics(
1338         &self,
1339         attr: &Attribute,
1340         span: Span,
1341         target: Target,
1342         item: Option<ItemLike<'_>>,
1343     ) -> bool {
1344         let is_function = matches!(target, Target::Fn | Target::Method(..));
1345         if !is_function {
1346             self.tcx
1347                 .sess
1348                 .struct_span_err(attr.span, "attribute should be applied to a function")
1349                 .span_label(span, "not a function")
1350                 .emit();
1351             return false;
1352         }
1353
1354         let Some(list) = attr.meta_item_list() else {
1355             // The attribute form is validated on AST.
1356             return false;
1357         };
1358
1359         let Some(ItemLike::Item(Item {
1360             kind: ItemKind::Fn(FnSig { decl, .. }, generics, _),
1361             ..
1362         }))  = item else {
1363             bug!("should be a function item");
1364         };
1365
1366         for param in generics.params {
1367             match param.kind {
1368                 hir::GenericParamKind::Const { .. } => {}
1369                 _ => {
1370                     self.tcx
1371                         .sess
1372                         .struct_span_err(
1373                             attr.span,
1374                             "#[rustc_legacy_const_generics] functions must \
1375                              only have const generics",
1376                         )
1377                         .span_label(param.span, "non-const generic parameter")
1378                         .emit();
1379                     return false;
1380                 }
1381             }
1382         }
1383
1384         if list.len() != generics.params.len() {
1385             self.tcx
1386                 .sess
1387                 .struct_span_err(
1388                     attr.span,
1389                     "#[rustc_legacy_const_generics] must have one index for each generic parameter",
1390                 )
1391                 .span_label(generics.span, "generic parameters")
1392                 .emit();
1393             return false;
1394         }
1395
1396         let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128;
1397         let mut invalid_args = vec![];
1398         for meta in list {
1399             if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) {
1400                 if *val >= arg_count {
1401                     let span = meta.span();
1402                     self.tcx
1403                         .sess
1404                         .struct_span_err(span, "index exceeds number of arguments")
1405                         .span_label(
1406                             span,
1407                             format!(
1408                                 "there {} only {} argument{}",
1409                                 if arg_count != 1 { "are" } else { "is" },
1410                                 arg_count,
1411                                 pluralize!(arg_count)
1412                             ),
1413                         )
1414                         .emit();
1415                     return false;
1416                 }
1417             } else {
1418                 invalid_args.push(meta.span());
1419             }
1420         }
1421
1422         if !invalid_args.is_empty() {
1423             self.tcx
1424                 .sess
1425                 .struct_span_err(invalid_args, "arguments should be non-negative integers")
1426                 .emit();
1427             false
1428         } else {
1429             true
1430         }
1431     }
1432
1433     fn check_rustc_lint_query_instability(
1434         &self,
1435         attr: &Attribute,
1436         span: Span,
1437         target: Target,
1438     ) -> bool {
1439         let is_function = matches!(target, Target::Fn | Target::Method(..));
1440         if !is_function {
1441             self.tcx
1442                 .sess
1443                 .struct_span_err(attr.span, "attribute should be applied to a function")
1444                 .span_label(span, "not a function")
1445                 .emit();
1446             false
1447         } else {
1448             true
1449         }
1450     }
1451
1452     /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
1453     /// option is passed to the compiler.
1454     fn check_rustc_dirty_clean(&self, attr: &Attribute) -> bool {
1455         if self.tcx.sess.opts.debugging_opts.query_dep_graph {
1456             true
1457         } else {
1458             self.tcx
1459                 .sess
1460                 .struct_span_err(attr.span, "attribute requires -Z query-dep-graph to be enabled")
1461                 .emit();
1462             false
1463         }
1464     }
1465
1466     /// Checks if `#[link_section]` is applied to a function or static.
1467     fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1468         match target {
1469             Target::Static | Target::Fn | Target::Method(..) => {}
1470             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1471             // `#[link_section]` attribute with just a lint, because we previously
1472             // erroneously allowed it and some crates used it accidentally, to to be compatible
1473             // with crates depending on them, we can't throw an error here.
1474             Target::Field | Target::Arm | Target::MacroDef => {
1475                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
1476             }
1477             _ => {
1478                 // FIXME: #[link_section] was previously allowed on non-functions/statics and some
1479                 // crates used this, so only emit a warning.
1480                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1481                     lint.build("attribute should be applied to a function or static")
1482                         .warn(
1483                             "this was previously accepted by the compiler but is \
1484                              being phased out; it will become a hard error in \
1485                              a future release!",
1486                         )
1487                         .span_label(span, "not a function or static")
1488                         .emit();
1489                 });
1490             }
1491         }
1492     }
1493
1494     /// Checks if `#[no_mangle]` is applied to a function or static.
1495     fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1496         match target {
1497             Target::Static | Target::Fn => {}
1498             Target::Method(..) if self.is_impl_item(hir_id) => {}
1499             // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1500             // `#[no_mangle]` attribute with just a lint, because we previously
1501             // erroneously allowed it and some crates used it accidentally, to to be compatible
1502             // with crates depending on them, we can't throw an error here.
1503             Target::Field | Target::Arm | Target::MacroDef => {
1504                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
1505             }
1506             // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error
1507             // The error should specify that the item that is wrong is specifically a *foreign* fn/static
1508             // otherwise the error seems odd
1509             Target::ForeignFn | Target::ForeignStatic => {
1510                 let foreign_item_kind = match target {
1511                     Target::ForeignFn => "function",
1512                     Target::ForeignStatic => "static",
1513                     _ => unreachable!(),
1514                 };
1515                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1516                     lint.build(&format!(
1517                         "`#[no_mangle]` has no effect on a foreign {}",
1518                         foreign_item_kind
1519                     ))
1520                     .warn(
1521                         "this was previously accepted by the compiler but is \
1522                             being phased out; it will become a hard error in \
1523                             a future release!",
1524                     )
1525                     .span_label(span, format!("foreign {}", foreign_item_kind))
1526                     .note("symbol names in extern blocks are not mangled")
1527                     .span_suggestion(
1528                         attr.span,
1529                         "remove this attribute",
1530                         String::new(),
1531                         Applicability::MachineApplicable,
1532                     )
1533                     .emit();
1534                 });
1535             }
1536             _ => {
1537                 // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
1538                 // crates used this, so only emit a warning.
1539                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1540                     lint.build(
1541                         "attribute should be applied to a free function, impl method or static",
1542                     )
1543                     .warn(
1544                         "this was previously accepted by the compiler but is \
1545                          being phased out; it will become a hard error in \
1546                          a future release!",
1547                     )
1548                     .span_label(span, "not a free function, impl method or static")
1549                     .emit();
1550                 });
1551             }
1552         }
1553     }
1554
1555     /// Checks if the `#[repr]` attributes on `item` are valid.
1556     fn check_repr(
1557         &self,
1558         attrs: &[Attribute],
1559         span: Span,
1560         target: Target,
1561         item: Option<ItemLike<'_>>,
1562         hir_id: HirId,
1563     ) {
1564         // Extract the names of all repr hints, e.g., [foo, bar, align] for:
1565         // ```
1566         // #[repr(foo)]
1567         // #[repr(bar, align(8))]
1568         // ```
1569         let hints: Vec<_> = attrs
1570             .iter()
1571             .filter(|attr| attr.has_name(sym::repr))
1572             .filter_map(|attr| attr.meta_item_list())
1573             .flatten()
1574             .collect();
1575
1576         let mut int_reprs = 0;
1577         let mut is_c = false;
1578         let mut is_simd = false;
1579         let mut is_transparent = false;
1580
1581         for hint in &hints {
1582             if !hint.is_meta_item() {
1583                 struct_span_err!(
1584                     self.tcx.sess,
1585                     hint.span(),
1586                     E0565,
1587                     "meta item in `repr` must be an identifier"
1588                 )
1589                 .emit();
1590                 continue;
1591             }
1592
1593             let (article, allowed_targets) = match hint.name_or_empty() {
1594                 sym::C => {
1595                     is_c = true;
1596                     match target {
1597                         Target::Struct | Target::Union | Target::Enum => continue,
1598                         _ => ("a", "struct, enum, or union"),
1599                     }
1600                 }
1601                 sym::align => {
1602                     if let (Target::Fn, true) = (target, !self.tcx.features().fn_align) {
1603                         feature_err(
1604                             &self.tcx.sess.parse_sess,
1605                             sym::fn_align,
1606                             hint.span(),
1607                             "`repr(align)` attributes on functions are unstable",
1608                         )
1609                         .emit();
1610                     }
1611
1612                     match target {
1613                         Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
1614                         _ => ("a", "struct, enum, function, or union"),
1615                     }
1616                 }
1617                 sym::packed => {
1618                     if target != Target::Struct && target != Target::Union {
1619                         ("a", "struct or union")
1620                     } else {
1621                         continue;
1622                     }
1623                 }
1624                 sym::simd => {
1625                     is_simd = true;
1626                     if target != Target::Struct {
1627                         ("a", "struct")
1628                     } else {
1629                         continue;
1630                     }
1631                 }
1632                 sym::transparent => {
1633                     is_transparent = true;
1634                     match target {
1635                         Target::Struct | Target::Union | Target::Enum => continue,
1636                         _ => ("a", "struct, enum, or union"),
1637                     }
1638                 }
1639                 sym::no_niche => {
1640                     if !self.tcx.features().enabled(sym::no_niche) {
1641                         feature_err(
1642                             &self.tcx.sess.parse_sess,
1643                             sym::no_niche,
1644                             hint.span(),
1645                             "the attribute `repr(no_niche)` is currently unstable",
1646                         )
1647                         .emit();
1648                     }
1649                     match target {
1650                         Target::Struct | Target::Enum => continue,
1651                         _ => ("a", "struct or enum"),
1652                     }
1653                 }
1654                 sym::i8
1655                 | sym::u8
1656                 | sym::i16
1657                 | sym::u16
1658                 | sym::i32
1659                 | sym::u32
1660                 | sym::i64
1661                 | sym::u64
1662                 | sym::i128
1663                 | sym::u128
1664                 | sym::isize
1665                 | sym::usize => {
1666                     int_reprs += 1;
1667                     if target != Target::Enum {
1668                         ("an", "enum")
1669                     } else {
1670                         continue;
1671                     }
1672                 }
1673                 _ => {
1674                     struct_span_err!(
1675                         self.tcx.sess,
1676                         hint.span(),
1677                         E0552,
1678                         "unrecognized representation hint"
1679                     )
1680                     .emit();
1681
1682                     continue;
1683                 }
1684             };
1685
1686             struct_span_err!(
1687                 self.tcx.sess,
1688                 hint.span(),
1689                 E0517,
1690                 "{}",
1691                 &format!("attribute should be applied to {} {}", article, allowed_targets)
1692             )
1693             .span_label(span, &format!("not {} {}", article, allowed_targets))
1694             .emit();
1695         }
1696
1697         // Just point at all repr hints if there are any incompatibilities.
1698         // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
1699         let hint_spans = hints.iter().map(|hint| hint.span());
1700
1701         // Error on repr(transparent, <anything else apart from no_niche>).
1702         let non_no_niche = |hint: &&NestedMetaItem| hint.name_or_empty() != sym::no_niche;
1703         let non_no_niche_count = hints.iter().filter(non_no_niche).count();
1704         if is_transparent && non_no_niche_count > 1 {
1705             let hint_spans: Vec<_> = hint_spans.clone().collect();
1706             struct_span_err!(
1707                 self.tcx.sess,
1708                 hint_spans,
1709                 E0692,
1710                 "transparent {} cannot have other repr hints",
1711                 target
1712             )
1713             .emit();
1714         }
1715         // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
1716         if (int_reprs > 1)
1717             || (is_simd && is_c)
1718             || (int_reprs == 1
1719                 && is_c
1720                 && item.map_or(false, |item| {
1721                     if let ItemLike::Item(item) = item {
1722                         return is_c_like_enum(item);
1723                     }
1724                     return false;
1725                 }))
1726         {
1727             self.tcx.struct_span_lint_hir(
1728                 CONFLICTING_REPR_HINTS,
1729                 hir_id,
1730                 hint_spans.collect::<Vec<Span>>(),
1731                 |lint| {
1732                     lint.build("conflicting representation hints")
1733                         .code(rustc_errors::error_code!(E0566))
1734                         .emit();
1735                 },
1736             );
1737         }
1738     }
1739
1740     fn check_used(&self, attrs: &[Attribute], target: Target) {
1741         let mut used_linker_span = None;
1742         let mut used_compiler_span = None;
1743         for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
1744             if target != Target::Static {
1745                 self.tcx
1746                     .sess
1747                     .span_err(attr.span, "attribute must be applied to a `static` variable");
1748             }
1749             let inner = attr.meta_item_list();
1750             match inner.as_deref() {
1751                 Some([item]) if item.has_name(sym::linker) => {
1752                     if used_linker_span.is_none() {
1753                         used_linker_span = Some(attr.span);
1754                     }
1755                 }
1756                 Some([item]) if item.has_name(sym::compiler) => {
1757                     if used_compiler_span.is_none() {
1758                         used_compiler_span = Some(attr.span);
1759                     }
1760                 }
1761                 Some(_) => {
1762                     // This error case is handled in rustc_typeck::collect.
1763                 }
1764                 None => {
1765                     // Default case (compiler) when arg isn't defined.
1766                     if used_compiler_span.is_none() {
1767                         used_compiler_span = Some(attr.span);
1768                     }
1769                 }
1770             }
1771         }
1772         if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
1773             let spans = vec![linker_span, compiler_span];
1774             self.tcx
1775                 .sess
1776                 .struct_span_err(
1777                     spans,
1778                     "`used(compiler)` and `used(linker)` can't be used together",
1779                 )
1780                 .emit();
1781         }
1782     }
1783
1784     /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
1785     /// (Allows proc_macro functions)
1786     fn check_allow_internal_unstable(
1787         &self,
1788         hir_id: HirId,
1789         attr: &Attribute,
1790         span: Span,
1791         target: Target,
1792         attrs: &[Attribute],
1793     ) -> bool {
1794         debug!("Checking target: {:?}", target);
1795         match target {
1796             Target::Fn => {
1797                 for attr in attrs {
1798                     if self.tcx.sess.is_proc_macro_attr(attr) {
1799                         debug!("Is proc macro attr");
1800                         return true;
1801                     }
1802                 }
1803                 debug!("Is not proc macro attr");
1804                 false
1805             }
1806             Target::MacroDef => true,
1807             // FIXME(#80564): We permit struct fields and match arms to have an
1808             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
1809             // erroneously allowed it and some crates used it accidentally, to to be compatible
1810             // with crates depending on them, we can't throw an error here.
1811             Target::Field | Target::Arm => {
1812                 self.inline_attr_str_error_without_macro_def(
1813                     hir_id,
1814                     attr,
1815                     "allow_internal_unstable",
1816                 );
1817                 true
1818             }
1819             _ => {
1820                 self.tcx
1821                     .sess
1822                     .struct_span_err(attr.span, "attribute should be applied to a macro")
1823                     .span_label(span, "not a macro")
1824                     .emit();
1825                 false
1826             }
1827         }
1828     }
1829
1830     /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
1831     /// (Allows proc_macro functions)
1832     fn check_rustc_allow_const_fn_unstable(
1833         &self,
1834         hir_id: HirId,
1835         attr: &Attribute,
1836         span: Span,
1837         target: Target,
1838     ) -> bool {
1839         match target {
1840             Target::Fn | Target::Method(_)
1841                 if self.tcx.is_const_fn_raw(self.tcx.hir().local_def_id(hir_id)) =>
1842             {
1843                 true
1844             }
1845             // FIXME(#80564): We permit struct fields and match arms to have an
1846             // `#[allow_internal_unstable]` attribute with just a lint, because we previously
1847             // erroneously allowed it and some crates used it accidentally, to to be compatible
1848             // with crates depending on them, we can't throw an error here.
1849             Target::Field | Target::Arm | Target::MacroDef => {
1850                 self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable");
1851                 true
1852             }
1853             _ => {
1854                 self.tcx
1855                     .sess
1856                     .struct_span_err(attr.span, "attribute should be applied to `const fn`")
1857                     .span_label(span, "not a `const fn`")
1858                     .emit();
1859                 false
1860             }
1861         }
1862     }
1863
1864     /// default_method_body_is_const should only be applied to trait methods with default bodies.
1865     fn check_default_method_body_is_const(
1866         &self,
1867         attr: &Attribute,
1868         span: Span,
1869         target: Target,
1870     ) -> bool {
1871         match target {
1872             Target::Method(MethodKind::Trait { body: true }) => true,
1873             _ => {
1874                 self.tcx
1875                     .sess
1876                     .struct_span_err(
1877                         attr.span,
1878                         "attribute should be applied to a trait method with body",
1879                     )
1880                     .span_label(span, "not a trait method or missing a body")
1881                     .emit();
1882                 false
1883             }
1884         }
1885     }
1886
1887     fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
1888         match target {
1889             Target::Expression => {
1890                 self.tcx
1891                     .sess
1892                     .struct_span_err(attr.span, "attribute cannot be applied to an expression")
1893                     .emit();
1894                 false
1895             }
1896             _ => true,
1897         }
1898     }
1899
1900     fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
1901         match target {
1902             Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
1903                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1904                     lint.build("attribute is ignored here").emit();
1905                 });
1906             }
1907             _ => {}
1908         }
1909     }
1910
1911     fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
1912         let name = attr.name_or_empty();
1913         match target {
1914             Target::ExternCrate | Target::Mod => {}
1915             _ => {
1916                 self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1917                     lint.build(&format!(
1918                         "`#[{name}]` only has an effect on `extern crate` and modules"
1919                     ))
1920                     .emit();
1921                 });
1922             }
1923         }
1924     }
1925
1926     fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
1927         if target != Target::MacroDef {
1928             self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1929                 lint.build("`#[macro_export]` only has an effect on macro definitions").emit();
1930             });
1931         }
1932     }
1933
1934     fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) {
1935         if target != Target::Fn {
1936             self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
1937                 lint.build("`#[plugin_registrar]` only has an effect on functions").emit();
1938             });
1939         }
1940     }
1941 }
1942
1943 impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
1944     type NestedFilter = nested_filter::OnlyBodies;
1945
1946     fn nested_visit_map(&mut self) -> Self::Map {
1947         self.tcx.hir()
1948     }
1949
1950     fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
1951         // Historically we've run more checks on non-exported than exported macros,
1952         // so this lets us continue to run them while maintaining backwards compatibility.
1953         // In the long run, the checks should be harmonized.
1954         if let ItemKind::Macro(ref macro_def, _) = item.kind {
1955             let def_id = item.def_id.to_def_id();
1956             if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
1957                 check_non_exported_macro_for_invalid_attrs(self.tcx, item);
1958             }
1959         }
1960
1961         let target = Target::from_item(item);
1962         self.check_attributes(item.hir_id(), item.span, target, Some(ItemLike::Item(item)));
1963         intravisit::walk_item(self, item)
1964     }
1965
1966     fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
1967         let target = Target::from_generic_param(generic_param);
1968         self.check_attributes(generic_param.hir_id, generic_param.span, target, None);
1969         intravisit::walk_generic_param(self, generic_param)
1970     }
1971
1972     fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
1973         let target = Target::from_trait_item(trait_item);
1974         self.check_attributes(trait_item.hir_id(), trait_item.span, target, None);
1975         intravisit::walk_trait_item(self, trait_item)
1976     }
1977
1978     fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) {
1979         self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None);
1980         intravisit::walk_field_def(self, struct_field);
1981     }
1982
1983     fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
1984         self.check_attributes(arm.hir_id, arm.span, Target::Arm, None);
1985         intravisit::walk_arm(self, arm);
1986     }
1987
1988     fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
1989         let target = Target::from_foreign_item(f_item);
1990         self.check_attributes(
1991             f_item.hir_id(),
1992             f_item.span,
1993             target,
1994             Some(ItemLike::ForeignItem(f_item)),
1995         );
1996         intravisit::walk_foreign_item(self, f_item)
1997     }
1998
1999     fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
2000         let target = target_from_impl_item(self.tcx, impl_item);
2001         self.check_attributes(impl_item.hir_id(), impl_item.span, target, None);
2002         intravisit::walk_impl_item(self, impl_item)
2003     }
2004
2005     fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
2006         // When checking statements ignore expressions, they will be checked later.
2007         if let hir::StmtKind::Local(ref l) = stmt.kind {
2008             self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
2009         }
2010         intravisit::walk_stmt(self, stmt)
2011     }
2012
2013     fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
2014         let target = match expr.kind {
2015             hir::ExprKind::Closure(..) => Target::Closure,
2016             _ => Target::Expression,
2017         };
2018
2019         self.check_attributes(expr.hir_id, expr.span, target, None);
2020         intravisit::walk_expr(self, expr)
2021     }
2022
2023     fn visit_variant(
2024         &mut self,
2025         variant: &'tcx hir::Variant<'tcx>,
2026         generics: &'tcx hir::Generics<'tcx>,
2027         item_id: HirId,
2028     ) {
2029         self.check_attributes(variant.id, variant.span, Target::Variant, None);
2030         intravisit::walk_variant(self, variant, generics, item_id)
2031     }
2032
2033     fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
2034         self.check_attributes(param.hir_id, param.span, Target::Param, None);
2035
2036         intravisit::walk_param(self, param);
2037     }
2038 }
2039
2040 fn is_c_like_enum(item: &Item<'_>) -> bool {
2041     if let ItemKind::Enum(ref def, _) = item.kind {
2042         for variant in def.variants {
2043             match variant.data {
2044                 hir::VariantData::Unit(..) => { /* continue */ }
2045                 _ => return false,
2046             }
2047         }
2048         true
2049     } else {
2050         false
2051     }
2052 }
2053
2054 // FIXME: Fix "Cannot determine resolution" error and remove built-in macros
2055 // from this check.
2056 fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
2057     // Check for builtin attributes at the crate level
2058     // which were unsuccessfully resolved due to cannot determine
2059     // resolution for the attribute macro error.
2060     const ATTRS_TO_CHECK: &[Symbol] = &[
2061         sym::macro_export,
2062         sym::repr,
2063         sym::path,
2064         sym::automatically_derived,
2065         sym::start,
2066         sym::rustc_main,
2067         sym::derive,
2068         sym::test,
2069         sym::test_case,
2070         sym::global_allocator,
2071         sym::bench,
2072     ];
2073
2074     for attr in attrs {
2075         // This function should only be called with crate attributes
2076         // which are inner attributes always but lets check to make sure
2077         if attr.style == AttrStyle::Inner {
2078             for attr_to_check in ATTRS_TO_CHECK {
2079                 if attr.has_name(*attr_to_check) {
2080                     let mut err = tcx.sess.struct_span_err(
2081                         attr.span,
2082                         &format!(
2083                             "`{}` attribute cannot be used at crate level",
2084                             attr_to_check.to_ident_string()
2085                         ),
2086                     );
2087                     // Only emit an error with a suggestion if we can create a
2088                     // string out of the attribute span
2089                     if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) {
2090                         let replacement = src.replace("#!", "#");
2091                         err.span_suggestion_verbose(
2092                             attr.span,
2093                             "perhaps you meant to use an outer attribute",
2094                             replacement,
2095                             rustc_errors::Applicability::MachineApplicable,
2096                         );
2097                     }
2098                     err.emit();
2099                 }
2100             }
2101         }
2102     }
2103 }
2104
2105 fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
2106     let attrs = tcx.hir().attrs(item.hir_id());
2107
2108     for attr in attrs {
2109         if attr.has_name(sym::inline) {
2110             struct_span_err!(
2111                 tcx.sess,
2112                 attr.span,
2113                 E0518,
2114                 "attribute should be applied to function or closure",
2115             )
2116             .span_label(attr.span, "not a function or closure")
2117             .emit();
2118         }
2119     }
2120 }
2121
2122 fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
2123     let check_attr_visitor = &mut CheckAttrVisitor { tcx };
2124     tcx.hir().visit_item_likes_in_module(module_def_id, &mut check_attr_visitor.as_deep_visitor());
2125     if module_def_id.is_top_level_module() {
2126         check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
2127         check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
2128     }
2129 }
2130
2131 pub(crate) fn provide(providers: &mut Providers) {
2132     *providers = Providers { check_mod_attrs, ..*providers };
2133 }
2134
2135 fn check_duplicates(
2136     tcx: TyCtxt<'_>,
2137     attr: &Attribute,
2138     hir_id: HirId,
2139     duplicates: AttributeDuplicates,
2140     seen: &mut FxHashMap<Symbol, Span>,
2141 ) {
2142     use AttributeDuplicates::*;
2143     if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
2144         return;
2145     }
2146     match duplicates {
2147         DuplicatesOk => {}
2148         WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
2149             match seen.entry(attr.name_or_empty()) {
2150                 Entry::Occupied(mut entry) => {
2151                     let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
2152                         let to_remove = entry.insert(attr.span);
2153                         (to_remove, attr.span)
2154                     } else {
2155                         (attr.span, *entry.get())
2156                     };
2157                     tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, this, |lint| {
2158                         let mut db = lint.build("unused attribute");
2159                         db.span_note(other, "attribute also specified here").span_suggestion(
2160                             this,
2161                             "remove this attribute",
2162                             String::new(),
2163                             Applicability::MachineApplicable,
2164                         );
2165                         if matches!(duplicates, FutureWarnFollowing | FutureWarnPreceding) {
2166                             db.warn(
2167                                 "this was previously accepted by the compiler but is \
2168                                  being phased out; it will become a hard error in \
2169                                  a future release!",
2170                             );
2171                         }
2172                         db.emit();
2173                     });
2174                 }
2175                 Entry::Vacant(entry) => {
2176                     entry.insert(attr.span);
2177                 }
2178             }
2179         }
2180         ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) {
2181             Entry::Occupied(mut entry) => {
2182                 let (this, other) = if matches!(duplicates, ErrorPreceding) {
2183                     let to_remove = entry.insert(attr.span);
2184                     (to_remove, attr.span)
2185                 } else {
2186                     (attr.span, *entry.get())
2187                 };
2188                 tcx.sess
2189                     .struct_span_err(
2190                         this,
2191                         &format!("multiple `{}` attributes", attr.name_or_empty()),
2192                     )
2193                     .span_note(other, "attribute also specified here")
2194                     .span_suggestion(
2195                         this,
2196                         "remove this attribute",
2197                         String::new(),
2198                         Applicability::MachineApplicable,
2199                     )
2200                     .emit();
2201             }
2202             Entry::Vacant(entry) => {
2203                 entry.insert(attr.span);
2204             }
2205         },
2206     }
2207 }