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