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