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