rustc_passes/
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
7use std::cell::Cell;
8use std::collections::hash_map::Entry;
9
10use rustc_abi::{ExternAbi, Size};
11use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast};
12use rustc_data_structures::fx::FxHashMap;
13use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey};
14use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
15use rustc_hir::def_id::LocalModDefId;
16use rustc_hir::intravisit::{self, Visitor};
17use rustc_hir::{
18    self as hir, self, AssocItemKind, AttrKind, Attribute, CRATE_HIR_ID, CRATE_OWNER_ID, FnSig,
19    ForeignItem, HirId, Item, ItemKind, MethodKind, Safety, Target, TraitItem,
20};
21use rustc_macros::LintDiagnostic;
22use rustc_middle::hir::nested_filter;
23use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
24use rustc_middle::query::Providers;
25use rustc_middle::traits::ObligationCause;
26use rustc_middle::ty::error::{ExpectedFound, TypeError};
27use rustc_middle::ty::{self, TyCtxt, TypingMode};
28use rustc_middle::{bug, span_bug};
29use rustc_session::config::CrateType;
30use rustc_session::lint::builtin::{
31    CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
32    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES,
33};
34use rustc_session::parse::feature_err;
35use rustc_span::{BytePos, DUMMY_SP, Span, Symbol, kw, sym};
36use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
37use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
38use rustc_trait_selection::traits::ObligationCtxt;
39use tracing::debug;
40
41use crate::{errors, fluent_generated as fluent};
42
43#[derive(LintDiagnostic)]
44#[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)]
45struct DiagnosticOnUnimplementedOnlyForTraits;
46
47fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
48    match impl_item.kind {
49        hir::ImplItemKind::Const(..) => Target::AssocConst,
50        hir::ImplItemKind::Fn(..) => {
51            let parent_def_id = tcx.hir().get_parent_item(impl_item.hir_id()).def_id;
52            let containing_item = tcx.hir().expect_item(parent_def_id);
53            let containing_impl_is_for_trait = match &containing_item.kind {
54                hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
55                _ => bug!("parent of an ImplItem must be an Impl"),
56            };
57            if containing_impl_is_for_trait {
58                Target::Method(MethodKind::Trait { body: true })
59            } else {
60                Target::Method(MethodKind::Inherent)
61            }
62        }
63        hir::ImplItemKind::Type(..) => Target::AssocTy,
64    }
65}
66
67#[derive(Clone, Copy)]
68enum ItemLike<'tcx> {
69    Item(&'tcx Item<'tcx>),
70    ForeignItem,
71}
72
73#[derive(Copy, Clone)]
74pub(crate) enum ProcMacroKind {
75    FunctionLike,
76    Derive,
77    Attribute,
78}
79
80impl IntoDiagArg for ProcMacroKind {
81    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
82        match self {
83            ProcMacroKind::Attribute => "attribute proc macro",
84            ProcMacroKind::Derive => "derive proc macro",
85            ProcMacroKind::FunctionLike => "function-like proc macro",
86        }
87        .into_diag_arg()
88    }
89}
90
91struct CheckAttrVisitor<'tcx> {
92    tcx: TyCtxt<'tcx>,
93
94    // Whether or not this visitor should abort after finding errors
95    abort: Cell<bool>,
96}
97
98impl<'tcx> CheckAttrVisitor<'tcx> {
99    fn dcx(&self) -> DiagCtxtHandle<'tcx> {
100        self.tcx.dcx()
101    }
102
103    /// Checks any attribute.
104    fn check_attributes(
105        &self,
106        hir_id: HirId,
107        span: Span,
108        target: Target,
109        item: Option<ItemLike<'_>>,
110    ) {
111        let mut doc_aliases = FxHashMap::default();
112        let mut specified_inline = None;
113        let mut seen = FxHashMap::default();
114        let attrs = self.tcx.hir().attrs(hir_id);
115        for attr in attrs {
116            match attr.path().as_slice() {
117                [sym::diagnostic, sym::do_not_recommend, ..] => {
118                    self.check_do_not_recommend(attr.span, hir_id, target, attr, item)
119                }
120                [sym::diagnostic, sym::on_unimplemented, ..] => {
121                    self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
122                }
123                [sym::inline, ..] => self.check_inline(hir_id, attr, span, target),
124                [sym::coverage, ..] => self.check_coverage(attr, span, target),
125                [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target),
126                [sym::no_sanitize, ..] => self.check_no_sanitize(attr, span, target),
127                [sym::non_exhaustive, ..] => self.check_non_exhaustive(hir_id, attr, span, target, item),
128                [sym::marker, ..] => self.check_marker(hir_id, attr, span, target),
129                [sym::target_feature, ..] => {
130                    self.check_target_feature(hir_id, attr, span, target, attrs)
131                }
132                [sym::thread_local, ..] => self.check_thread_local(attr, span, target),
133                [sym::track_caller, ..] => {
134                    self.check_track_caller(hir_id, attr.span, attrs, span, target)
135                }
136                [sym::doc, ..] => self.check_doc_attrs(
137                    attr,
138                    hir_id,
139                    target,
140                    &mut specified_inline,
141                    &mut doc_aliases,
142                ),
143                [sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
144                [sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target),
145                [sym::rustc_layout_scalar_valid_range_start, ..]
146                | [sym::rustc_layout_scalar_valid_range_end, ..] => {
147                    self.check_rustc_layout_scalar_valid_range(attr, span, target)
148                }
149                [sym::allow_internal_unstable, ..] => {
150                    self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
151                }
152                [sym::debugger_visualizer, ..] => self.check_debugger_visualizer(attr, target),
153                [sym::rustc_allow_const_fn_unstable, ..] => {
154                    self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
155                }
156                [sym::rustc_std_internal_symbol, ..] => {
157                    self.check_rustc_std_internal_symbol(attr, span, target)
158                }
159                [sym::naked, ..] => self.check_naked(hir_id, attr, span, target, attrs),
160                [sym::rustc_as_ptr, ..] => {
161                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
162                }
163                [sym::rustc_never_returns_null_ptr, ..] => {
164                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
165                }
166                [sym::rustc_legacy_const_generics, ..] => {
167                    self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
168                }
169                [sym::rustc_lint_query_instability, ..] => {
170                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
171                }
172                [sym::rustc_lint_untracked_query_information, ..] => {
173                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
174                }
175                [sym::rustc_lint_diagnostics, ..] => {
176                    self.check_applied_to_fn_or_method(hir_id, attr, span, target)
177                }
178                [sym::rustc_lint_opt_ty, ..] => self.check_rustc_lint_opt_ty(attr, span, target),
179                [sym::rustc_lint_opt_deny_field_access, ..] => {
180                    self.check_rustc_lint_opt_deny_field_access(attr, span, target)
181                }
182                [sym::rustc_clean, ..]
183                | [sym::rustc_dirty, ..]
184                | [sym::rustc_if_this_changed, ..]
185                | [sym::rustc_then_this_would_need, ..] => self.check_rustc_dirty_clean(attr),
186                [sym::rustc_coinductive, ..]
187                | [sym::rustc_must_implement_one_of, ..]
188                | [sym::rustc_deny_explicit_impl, ..]
189                | [sym::rustc_do_not_implement_via_object, ..]
190                | [sym::const_trait, ..] => self.check_must_be_applied_to_trait(attr, span, target),
191                [sym::collapse_debuginfo, ..] => self.check_collapse_debuginfo(attr, span, target),
192                [sym::must_not_suspend, ..] => self.check_must_not_suspend(attr, span, target),
193                [sym::must_use, ..] => self.check_must_use(hir_id, attr, target),
194                [sym::may_dangle, ..] => self.check_may_dangle(hir_id, attr),
195                [sym::rustc_pass_by_value, ..] => self.check_pass_by_value(attr, span, target),
196                [sym::rustc_allow_incoherent_impl, ..] => {
197                    self.check_allow_incoherent_impl(attr, span, target)
198                }
199                [sym::rustc_has_incoherent_inherent_impls, ..] => {
200                    self.check_has_incoherent_inherent_impls(attr, span, target)
201                }
202                [sym::ffi_pure, ..] => self.check_ffi_pure(attr.span, attrs, target),
203                [sym::ffi_const, ..] => self.check_ffi_const(attr.span, target),
204                [sym::rustc_const_unstable, ..]
205                | [sym::rustc_const_stable, ..]
206                | [sym::unstable, ..]
207                | [sym::stable, ..]
208                | [sym::rustc_allowed_through_unstable_modules, ..]
209                | [sym::rustc_promotable, ..] => self.check_stability_promotable(attr, target),
210                [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target),
211                [sym::rustc_confusables, ..] => self.check_confusables(attr, target),
212                [sym::cold, ..] => self.check_cold(hir_id, attr, span, target),
213                [sym::link, ..] => self.check_link(hir_id, attr, span, target),
214                [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target),
215                [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
216                [sym::no_mangle, ..] => self.check_no_mangle(hir_id, attr, span, target),
217                [sym::deprecated, ..] => self.check_deprecated(hir_id, attr, span, target),
218                [sym::macro_use, ..] | [sym::macro_escape, ..] => {
219                    self.check_macro_use(hir_id, attr, target)
220                }
221                [sym::path, ..] => self.check_generic_attr(hir_id, attr, target, Target::Mod),
222                [sym::macro_export, ..] => self.check_macro_export(hir_id, attr, target),
223                [sym::ignore, ..] | [sym::should_panic, ..] => {
224                    self.check_generic_attr(hir_id, attr, target, Target::Fn)
225                }
226                [sym::automatically_derived, ..] => {
227                    self.check_generic_attr(hir_id, attr, target, Target::Impl)
228                }
229                [sym::no_implicit_prelude, ..] => {
230                    self.check_generic_attr(hir_id, attr, target, Target::Mod)
231                }
232                [sym::rustc_object_lifetime_default, ..] => self.check_object_lifetime_default(hir_id),
233                [sym::proc_macro, ..] => {
234                    self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
235                }
236                [sym::proc_macro_attribute, ..] => {
237                    self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
238                }
239                [sym::proc_macro_derive, ..] => {
240                    self.check_generic_attr(hir_id, attr, target, Target::Fn);
241                    self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
242                }
243                [sym::autodiff, ..] => {
244                    self.check_autodiff(hir_id, attr, span, target)
245                }
246                [sym::coroutine, ..] => {
247                    self.check_coroutine(attr, target);
248                }
249                [sym::linkage, ..] => self.check_linkage(attr, span, target),
250                [sym::rustc_pub_transparent, ..] => self.check_rustc_pub_transparent(attr.span, span, attrs),
251                [
252                    // ok
253                    sym::allow
254                    | sym::expect
255                    | sym::warn
256                    | sym::deny
257                    | sym::forbid
258                    | sym::cfg
259                    | sym::cfg_attr
260                    // need to be fixed
261                    | sym::cfi_encoding // FIXME(cfi_encoding)
262                    | sym::pointee // FIXME(derive_coerce_pointee)
263                    | sym::omit_gdb_pretty_printer_section // FIXME(omit_gdb_pretty_printer_section)
264                    | sym::used // handled elsewhere to restrict to static items
265                    | sym::repr // handled elsewhere to restrict to type decls items
266                    | sym::instruction_set // broken on stable!!!
267                    | sym::windows_subsystem // broken on stable!!!
268                    | sym::patchable_function_entry // FIXME(patchable_function_entry)
269                    | sym::deprecated_safe // FIXME(deprecated_safe)
270                    // internal
271                    | sym::prelude_import
272                    | sym::panic_handler
273                    | sym::allow_internal_unsafe
274                    | sym::fundamental
275                    | sym::lang
276                    | sym::needs_allocator
277                    | sym::default_lib_allocator
278                    | sym::custom_mir,
279                    ..
280                ] => {}
281                [name, ..] => {
282                    match BUILTIN_ATTRIBUTE_MAP.get(name) {
283                        // checked below
284                        Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) => {}
285                        Some(_) => {
286                            // FIXME: differentiate between unstable and internal attributes just
287                            // like we do with features instead of just accepting `rustc_`
288                            // attributes by name. That should allow trimming the above list, too.
289                            if !name.as_str().starts_with("rustc_") {
290                                span_bug!(
291                                    attr.span,
292                                    "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
293                                )
294                            }
295                        }
296                        None => (),
297                    }
298                }
299                [] => unreachable!(),
300            }
301
302            let builtin = attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name));
303
304            if hir_id != CRATE_HIR_ID {
305                if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
306                    attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
307                {
308                    match attr.style {
309                        ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
310                            UNUSED_ATTRIBUTES,
311                            hir_id,
312                            attr.span,
313                            errors::OuterCrateLevelAttr,
314                        ),
315                        ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
316                            UNUSED_ATTRIBUTES,
317                            hir_id,
318                            attr.span,
319                            errors::InnerCrateLevelAttr,
320                        ),
321                    }
322                }
323            }
324
325            if let Some(BuiltinAttribute { duplicates, .. }) = builtin {
326                check_duplicates(self.tcx, attr, hir_id, *duplicates, &mut seen);
327            }
328
329            self.check_unused_attribute(hir_id, attr)
330        }
331
332        self.check_repr(attrs, span, target, item, hir_id);
333        self.check_used(attrs, target, span);
334        self.check_rustc_force_inline(hir_id, attrs, span, target);
335    }
336
337    fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
338        self.tcx.emit_node_span_lint(
339            UNUSED_ATTRIBUTES,
340            hir_id,
341            attr.span,
342            errors::IgnoredAttrWithMacro { sym },
343        );
344    }
345
346    fn inline_attr_str_error_without_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) {
347        self.tcx.emit_node_span_lint(
348            UNUSED_ATTRIBUTES,
349            hir_id,
350            attr.span,
351            errors::IgnoredAttr { sym },
352        );
353    }
354
355    /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl.
356    fn check_do_not_recommend(
357        &self,
358        attr_span: Span,
359        hir_id: HirId,
360        target: Target,
361        attr: &Attribute,
362        item: Option<ItemLike<'_>>,
363    ) {
364        if !matches!(target, Target::Impl)
365            || matches!(
366                item,
367                Some(ItemLike::Item(hir::Item {  kind: hir::ItemKind::Impl(_impl),.. }))
368                    if _impl.of_trait.is_none()
369            )
370        {
371            self.tcx.emit_node_span_lint(
372                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
373                hir_id,
374                attr_span,
375                errors::IncorrectDoNotRecommendLocation,
376            );
377        }
378        if !attr.is_word() {
379            self.tcx.emit_node_span_lint(
380                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
381                hir_id,
382                attr_span,
383                errors::DoNotRecommendDoesNotExpectArgs,
384            );
385        }
386    }
387
388    /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
389    fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
390        if !matches!(target, Target::Trait) {
391            self.tcx.emit_node_span_lint(
392                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
393                hir_id,
394                attr_span,
395                DiagnosticOnUnimplementedOnlyForTraits,
396            );
397        }
398    }
399
400    /// Checks if an `#[inline]` is applied to a function or a closure.
401    fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
402        match target {
403            Target::Fn
404            | Target::Closure
405            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {}
406            Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
407                self.tcx.emit_node_span_lint(
408                    UNUSED_ATTRIBUTES,
409                    hir_id,
410                    attr.span,
411                    errors::IgnoredInlineAttrFnProto,
412                )
413            }
414            // FIXME(#65833): We permit associated consts to have an `#[inline]` attribute with
415            // just a lint, because we previously erroneously allowed it and some crates used it
416            // accidentally, to be compatible with crates depending on them, we can't throw an
417            // error here.
418            Target::AssocConst => self.tcx.emit_node_span_lint(
419                UNUSED_ATTRIBUTES,
420                hir_id,
421                attr.span,
422                errors::IgnoredInlineAttrConstants,
423            ),
424            // FIXME(#80564): Same for fields, arms, and macro defs
425            Target::Field | Target::Arm | Target::MacroDef => {
426                self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline")
427            }
428            _ => {
429                self.dcx().emit_err(errors::InlineNotFnOrClosure {
430                    attr_span: attr.span,
431                    defn_span: span,
432                });
433            }
434        }
435    }
436
437    /// Checks that `#[coverage(..)]` is applied to a function/closure/method,
438    /// or to an impl block or module.
439    fn check_coverage(&self, attr: &Attribute, target_span: Span, target: Target) {
440        let mut not_fn_impl_mod = None;
441        let mut no_body = None;
442
443        match target {
444            Target::Fn
445            | Target::Closure
446            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
447            | Target::Impl
448            | Target::Mod => return,
449
450            // These are "functions", but they aren't allowed because they don't
451            // have a body, so the usual explanation would be confusing.
452            Target::Method(MethodKind::Trait { body: false }) | Target::ForeignFn => {
453                no_body = Some(target_span);
454            }
455
456            _ => {
457                not_fn_impl_mod = Some(target_span);
458            }
459        }
460
461        self.dcx().emit_err(errors::CoverageAttributeNotAllowed {
462            attr_span: attr.span,
463            not_fn_impl_mod,
464            no_body,
465            help: (),
466        });
467    }
468
469    /// Checks that `#[optimize(..)]` is applied to a function/closure/method,
470    /// or to an impl block or module.
471    fn check_optimize(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
472        let is_valid = matches!(
473            target,
474            Target::Fn
475                | Target::Closure
476                | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
477        );
478        if !is_valid {
479            self.dcx().emit_err(errors::OptimizeInvalidTarget {
480                attr_span: attr.span,
481                defn_span: span,
482                on_crate: hir_id == CRATE_HIR_ID,
483            });
484        }
485    }
486
487    fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
488        if let Some(list) = attr.meta_item_list() {
489            for item in list.iter() {
490                let sym = item.name_or_empty();
491                match sym {
492                    sym::address | sym::hwaddress => {
493                        let is_valid =
494                            matches!(target, Target::Fn | Target::Method(..) | Target::Static);
495                        if !is_valid {
496                            self.dcx().emit_err(errors::NoSanitize {
497                                attr_span: item.span(),
498                                defn_span: span,
499                                accepted_kind: "a function or static",
500                                attr_str: sym.as_str(),
501                            });
502                        }
503                    }
504                    _ => {
505                        let is_valid = matches!(target, Target::Fn | Target::Method(..));
506                        if !is_valid {
507                            self.dcx().emit_err(errors::NoSanitize {
508                                attr_span: item.span(),
509                                defn_span: span,
510                                accepted_kind: "a function",
511                                attr_str: sym.as_str(),
512                            });
513                        }
514                    }
515                }
516            }
517        }
518    }
519
520    fn check_generic_attr(
521        &self,
522        hir_id: HirId,
523        attr: &Attribute,
524        target: Target,
525        allowed_target: Target,
526    ) {
527        if target != allowed_target {
528            self.tcx.emit_node_span_lint(
529                UNUSED_ATTRIBUTES,
530                hir_id,
531                attr.span,
532                errors::OnlyHasEffectOn {
533                    attr_name: attr.name_or_empty(),
534                    target_name: allowed_target.name().replace(' ', "_"),
535                },
536            );
537        }
538    }
539
540    /// Checks if `#[naked]` is applied to a function definition.
541    fn check_naked(
542        &self,
543        hir_id: HirId,
544        attr: &Attribute,
545        span: Span,
546        target: Target,
547        attrs: &[Attribute],
548    ) {
549        // many attributes don't make sense in combination with #[naked].
550        // Notable attributes that are incompatible with `#[naked]` are:
551        //
552        // * `#[inline]`
553        // * `#[track_caller]`
554        // * `#[test]`, `#[ignore]`, `#[should_panic]`
555        //
556        // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate
557        const ALLOW_LIST: &[rustc_span::Symbol] = &[
558            // conditional compilation
559            sym::cfg,
560            sym::cfg_attr,
561            // testing (allowed here so better errors can be generated in `rustc_builtin_macros::test`)
562            sym::test,
563            sym::ignore,
564            sym::should_panic,
565            sym::bench,
566            // diagnostics
567            sym::allow,
568            sym::warn,
569            sym::deny,
570            sym::forbid,
571            sym::deprecated,
572            sym::must_use,
573            // abi, linking and FFI
574            sym::export_name,
575            sym::link_section,
576            sym::linkage,
577            sym::no_mangle,
578            sym::naked,
579            sym::instruction_set,
580            sym::repr,
581            // code generation
582            sym::cold,
583            sym::target_feature,
584            // documentation
585            sym::doc,
586        ];
587
588        match target {
589            Target::Fn
590            | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => {
591                for other_attr in attrs {
592                    // this covers "sugared doc comments" of the form `/// ...`
593                    // it does not cover `#[doc = "..."]`, which is handled below
594                    if other_attr.is_doc_comment() {
595                        continue;
596                    }
597
598                    if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) {
599                        self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute {
600                            span: other_attr.span,
601                            naked_span: attr.span,
602                            attr: other_attr.name_or_empty(),
603                        });
604
605                        return;
606                    }
607                }
608            }
609            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
610            // `#[naked]` attribute with just a lint, because we previously
611            // erroneously allowed it and some crates used it accidentally, to be compatible
612            // with crates depending on them, we can't throw an error here.
613            Target::Field | Target::Arm | Target::MacroDef => {
614                self.inline_attr_str_error_with_macro_def(hir_id, attr, "naked")
615            }
616            _ => {
617                self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
618                    attr_span: attr.span,
619                    defn_span: span,
620                    on_crate: hir_id == CRATE_HIR_ID,
621                });
622            }
623        }
624    }
625
626    /// Debugging aid for `object_lifetime_default` query.
627    fn check_object_lifetime_default(&self, hir_id: HirId) {
628        let tcx = self.tcx;
629        if let Some(owner_id) = hir_id.as_owner()
630            && let Some(generics) = tcx.hir().get_generics(owner_id.def_id)
631        {
632            for p in generics.params {
633                let hir::GenericParamKind::Type { .. } = p.kind else { continue };
634                let default = tcx.object_lifetime_default(p.def_id);
635                let repr = match default {
636                    ObjectLifetimeDefault::Empty => "BaseDefault".to_owned(),
637                    ObjectLifetimeDefault::Static => "'static".to_owned(),
638                    ObjectLifetimeDefault::Param(def_id) => tcx.item_name(def_id).to_string(),
639                    ObjectLifetimeDefault::Ambiguous => "Ambiguous".to_owned(),
640                };
641                tcx.dcx().emit_err(errors::ObjectLifetimeErr { span: p.span, repr });
642            }
643        }
644    }
645
646    /// Checks if `#[collapse_debuginfo]` is applied to a macro.
647    fn check_collapse_debuginfo(&self, attr: &Attribute, span: Span, target: Target) {
648        match target {
649            Target::MacroDef => {}
650            _ => {
651                self.tcx
652                    .dcx()
653                    .emit_err(errors::CollapseDebuginfo { attr_span: attr.span, defn_span: span });
654            }
655        }
656    }
657
658    /// Checks if a `#[track_caller]` is applied to a function.
659    fn check_track_caller(
660        &self,
661        hir_id: HirId,
662        attr_span: Span,
663        attrs: &[Attribute],
664        span: Span,
665        target: Target,
666    ) {
667        match target {
668            Target::Fn => {
669                // `#[track_caller]` is not valid on weak lang items because they are called via
670                // `extern` declarations and `#[track_caller]` would alter their ABI.
671                if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
672                    && let Some(item) = hir::LangItem::from_name(lang_item)
673                    && item.is_weak()
674                {
675                    let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
676
677                    self.dcx().emit_err(errors::LangItemWithTrackCaller {
678                        attr_span,
679                        name: lang_item,
680                        sig_span: sig.span,
681                    });
682                }
683            }
684            Target::Method(..) | Target::ForeignFn | Target::Closure => {}
685            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
686            // `#[track_caller]` attribute with just a lint, because we previously
687            // erroneously allowed it and some crates used it accidentally, to be compatible
688            // with crates depending on them, we can't throw an error here.
689            Target::Field | Target::Arm | Target::MacroDef => {
690                for attr in attrs {
691                    self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller");
692                }
693            }
694            _ => {
695                self.dcx().emit_err(errors::TrackedCallerWrongLocation {
696                    attr_span,
697                    defn_span: span,
698                    on_crate: hir_id == CRATE_HIR_ID,
699                });
700            }
701        }
702    }
703
704    /// Checks if the `#[non_exhaustive]` attribute on an `item` is valid.
705    fn check_non_exhaustive(
706        &self,
707        hir_id: HirId,
708        attr: &Attribute,
709        span: Span,
710        target: Target,
711        item: Option<ItemLike<'_>>,
712    ) {
713        match target {
714            Target::Struct => {
715                if let Some(ItemLike::Item(hir::Item {
716                    kind: hir::ItemKind::Struct(hir::VariantData::Struct { fields, .. }, _),
717                    ..
718                })) = item
719                    && !fields.is_empty()
720                    && fields.iter().any(|f| f.default.is_some())
721                {
722                    self.dcx().emit_err(errors::NonExhaustiveWithDefaultFieldValues {
723                        attr_span: attr.span,
724                        defn_span: span,
725                    });
726                }
727            }
728            Target::Enum | Target::Variant => {}
729            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
730            // `#[non_exhaustive]` attribute with just a lint, because we previously
731            // erroneously allowed it and some crates used it accidentally, to be compatible
732            // with crates depending on them, we can't throw an error here.
733            Target::Field | Target::Arm | Target::MacroDef => {
734                self.inline_attr_str_error_with_macro_def(hir_id, attr, "non_exhaustive");
735            }
736            _ => {
737                self.dcx().emit_err(errors::NonExhaustiveWrongLocation {
738                    attr_span: attr.span,
739                    defn_span: span,
740                });
741            }
742        }
743    }
744
745    /// Checks if the `#[marker]` attribute on an `item` is valid.
746    fn check_marker(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
747        match target {
748            Target::Trait => {}
749            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
750            // `#[marker]` attribute with just a lint, because we previously
751            // erroneously allowed it and some crates used it accidentally, to be compatible
752            // with crates depending on them, we can't throw an error here.
753            Target::Field | Target::Arm | Target::MacroDef => {
754                self.inline_attr_str_error_with_macro_def(hir_id, attr, "marker");
755            }
756            _ => {
757                self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
758                    attr_span: attr.span,
759                    defn_span: span,
760                });
761            }
762        }
763    }
764
765    /// Checks if the `#[target_feature]` attribute on `item` is valid.
766    fn check_target_feature(
767        &self,
768        hir_id: HirId,
769        attr: &Attribute,
770        span: Span,
771        target: Target,
772        attrs: &[Attribute],
773    ) {
774        match target {
775            Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent)
776            | Target::Fn => {
777                // `#[target_feature]` is not allowed in lang items.
778                if let Some((lang_item, _)) = hir::lang_items::extract(attrs)
779                    // Calling functions with `#[target_feature]` is
780                    // not unsafe on WASM, see #84988
781                    && !self.tcx.sess.target.is_like_wasm
782                    && !self.tcx.sess.opts.actually_rustdoc
783                {
784                    let sig = self.tcx.hir_node(hir_id).fn_sig().unwrap();
785
786                    self.dcx().emit_err(errors::LangItemWithTargetFeature {
787                        attr_span: attr.span,
788                        name: lang_item,
789                        sig_span: sig.span,
790                    });
791                }
792            }
793            // FIXME: #[target_feature] was previously erroneously allowed on statements and some
794            // crates used this, so only emit a warning.
795            Target::Statement => {
796                self.tcx.emit_node_span_lint(
797                    UNUSED_ATTRIBUTES,
798                    hir_id,
799                    attr.span,
800                    errors::TargetFeatureOnStatement,
801                );
802            }
803            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
804            // `#[target_feature]` attribute with just a lint, because we previously
805            // erroneously allowed it and some crates used it accidentally, to be compatible
806            // with crates depending on them, we can't throw an error here.
807            Target::Field | Target::Arm | Target::MacroDef => {
808                self.inline_attr_str_error_with_macro_def(hir_id, attr, "target_feature");
809            }
810            _ => {
811                self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
812                    attr_span: attr.span,
813                    defn_span: span,
814                    on_crate: hir_id == CRATE_HIR_ID,
815                });
816            }
817        }
818    }
819
820    /// Checks if the `#[thread_local]` attribute on `item` is valid.
821    fn check_thread_local(&self, attr: &Attribute, span: Span, target: Target) {
822        match target {
823            Target::ForeignStatic | Target::Static => {}
824            _ => {
825                self.dcx().emit_err(errors::AttrShouldBeAppliedToStatic {
826                    attr_span: attr.span,
827                    defn_span: span,
828                });
829            }
830        }
831    }
832
833    fn doc_attr_str_error(&self, meta: &MetaItemInner, attr_name: &str) {
834        self.dcx().emit_err(errors::DocExpectStr { attr_span: meta.span(), attr_name });
835    }
836
837    fn check_doc_alias_value(
838        &self,
839        meta: &MetaItemInner,
840        doc_alias: Symbol,
841        hir_id: HirId,
842        target: Target,
843        is_list: bool,
844        aliases: &mut FxHashMap<String, Span>,
845    ) {
846        let tcx = self.tcx;
847        let span = meta.name_value_literal_span().unwrap_or_else(|| meta.span());
848        let attr_str =
849            &format!("`#[doc(alias{})]`", if is_list { "(\"...\")" } else { " = \"...\"" });
850        if doc_alias == kw::Empty {
851            tcx.dcx().emit_err(errors::DocAliasEmpty { span, attr_str });
852            return;
853        }
854
855        let doc_alias_str = doc_alias.as_str();
856        if let Some(c) = doc_alias_str
857            .chars()
858            .find(|&c| c == '"' || c == '\'' || (c.is_whitespace() && c != ' '))
859        {
860            tcx.dcx().emit_err(errors::DocAliasBadChar { span, attr_str, char_: c });
861            return;
862        }
863        if doc_alias_str.starts_with(' ') || doc_alias_str.ends_with(' ') {
864            tcx.dcx().emit_err(errors::DocAliasStartEnd { span, attr_str });
865            return;
866        }
867
868        let span = meta.span();
869        if let Some(location) = match target {
870            Target::AssocTy => {
871                let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id;
872                let containing_item = self.tcx.hir().expect_item(parent_def_id);
873                if Target::from_item(containing_item) == Target::Impl {
874                    Some("type alias in implementation block")
875                } else {
876                    None
877                }
878            }
879            Target::AssocConst => {
880                let parent_def_id = self.tcx.hir().get_parent_item(hir_id).def_id;
881                let containing_item = self.tcx.hir().expect_item(parent_def_id);
882                // We can't link to trait impl's consts.
883                let err = "associated constant in trait implementation block";
884                match containing_item.kind {
885                    ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => Some(err),
886                    _ => None,
887                }
888            }
889            // we check the validity of params elsewhere
890            Target::Param => return,
891            Target::Expression
892            | Target::Statement
893            | Target::Arm
894            | Target::ForeignMod
895            | Target::Closure
896            | Target::Impl => Some(target.name()),
897            Target::ExternCrate
898            | Target::Use
899            | Target::Static
900            | Target::Const
901            | Target::Fn
902            | Target::Mod
903            | Target::GlobalAsm
904            | Target::TyAlias
905            | Target::Enum
906            | Target::Variant
907            | Target::Struct
908            | Target::Field
909            | Target::Union
910            | Target::Trait
911            | Target::TraitAlias
912            | Target::Method(..)
913            | Target::ForeignFn
914            | Target::ForeignStatic
915            | Target::ForeignTy
916            | Target::GenericParam(..)
917            | Target::MacroDef
918            | Target::PatField
919            | Target::ExprField => None,
920        } {
921            tcx.dcx().emit_err(errors::DocAliasBadLocation { span, attr_str, location });
922            return;
923        }
924        let item_name = self.tcx.hir().name(hir_id);
925        if item_name == doc_alias {
926            tcx.dcx().emit_err(errors::DocAliasNotAnAlias { span, attr_str });
927            return;
928        }
929        if let Err(entry) = aliases.try_insert(doc_alias_str.to_owned(), span) {
930            self.tcx.emit_node_span_lint(
931                UNUSED_ATTRIBUTES,
932                hir_id,
933                span,
934                errors::DocAliasDuplicated { first_defn: *entry.entry.get() },
935            );
936        }
937    }
938
939    fn check_doc_alias(
940        &self,
941        meta: &MetaItemInner,
942        hir_id: HirId,
943        target: Target,
944        aliases: &mut FxHashMap<String, Span>,
945    ) {
946        if let Some(values) = meta.meta_item_list() {
947            for v in values {
948                match v.lit() {
949                    Some(l) => match l.kind {
950                        LitKind::Str(s, _) => {
951                            self.check_doc_alias_value(v, s, hir_id, target, true, aliases);
952                        }
953                        _ => {
954                            self.tcx
955                                .dcx()
956                                .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
957                        }
958                    },
959                    None => {
960                        self.tcx
961                            .dcx()
962                            .emit_err(errors::DocAliasNotStringLiteral { span: v.span() });
963                    }
964                }
965            }
966        } else if let Some(doc_alias) = meta.value_str() {
967            self.check_doc_alias_value(meta, doc_alias, hir_id, target, false, aliases)
968        } else {
969            self.dcx().emit_err(errors::DocAliasMalformed { span: meta.span() });
970        }
971    }
972
973    fn check_doc_keyword(&self, meta: &MetaItemInner, hir_id: HirId) {
974        fn is_doc_keyword(s: Symbol) -> bool {
975            // FIXME: Once rustdoc can handle URL conflicts on case insensitive file systems, we
976            // can remove the `SelfTy` case here, remove `sym::SelfTy`, and update the
977            // `#[doc(keyword = "SelfTy")` attribute in `library/std/src/keyword_docs.rs`.
978            s <= kw::Union || s == sym::SelfTy
979        }
980
981        let doc_keyword = meta.value_str().unwrap_or(kw::Empty);
982        if doc_keyword == kw::Empty {
983            self.doc_attr_str_error(meta, "keyword");
984            return;
985        }
986        let item_kind = match self.tcx.hir_node(hir_id) {
987            hir::Node::Item(item) => Some(&item.kind),
988            _ => None,
989        };
990        match item_kind {
991            Some(ItemKind::Mod(module)) => {
992                if !module.item_ids.is_empty() {
993                    self.dcx().emit_err(errors::DocKeywordEmptyMod { span: meta.span() });
994                    return;
995                }
996            }
997            _ => {
998                self.dcx().emit_err(errors::DocKeywordNotMod { span: meta.span() });
999                return;
1000            }
1001        }
1002        if !is_doc_keyword(doc_keyword) {
1003            self.dcx().emit_err(errors::DocKeywordNotKeyword {
1004                span: meta.name_value_literal_span().unwrap_or_else(|| meta.span()),
1005                keyword: doc_keyword,
1006            });
1007        }
1008    }
1009
1010    fn check_doc_fake_variadic(&self, meta: &MetaItemInner, hir_id: HirId) {
1011        let item_kind = match self.tcx.hir_node(hir_id) {
1012            hir::Node::Item(item) => Some(&item.kind),
1013            _ => None,
1014        };
1015        match item_kind {
1016            Some(ItemKind::Impl(i)) => {
1017                let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty)
1018                    || if let Some(&[hir::GenericArg::Type(ty)]) = i
1019                        .of_trait
1020                        .as_ref()
1021                        .and_then(|trait_ref| trait_ref.path.segments.last())
1022                        .map(|last_segment| last_segment.args().args)
1023                    {
1024                        matches!(&ty.kind, hir::TyKind::Tup([_]))
1025                    } else {
1026                        false
1027                    };
1028                if !is_valid {
1029                    self.dcx().emit_err(errors::DocFakeVariadicNotValid { span: meta.span() });
1030                }
1031            }
1032            _ => {
1033                self.dcx().emit_err(errors::DocKeywordOnlyImpl { span: meta.span() });
1034            }
1035        }
1036    }
1037
1038    fn check_doc_search_unbox(&self, meta: &MetaItemInner, hir_id: HirId) {
1039        let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else {
1040            self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
1041            return;
1042        };
1043        match item.kind {
1044            ItemKind::Enum(_, generics) | ItemKind::Struct(_, generics)
1045                if generics.params.len() != 0 => {}
1046            ItemKind::Trait(_, _, generics, _, items)
1047                if generics.params.len() != 0
1048                    || items.iter().any(|item| matches!(item.kind, AssocItemKind::Type)) => {}
1049            _ => {
1050                self.dcx().emit_err(errors::DocSearchUnboxInvalid { span: meta.span() });
1051            }
1052        }
1053    }
1054
1055    /// Checks `#[doc(inline)]`/`#[doc(no_inline)]` attributes.
1056    ///
1057    /// A doc inlining attribute is invalid if it is applied to a non-`use` item, or
1058    /// if there are conflicting attributes for one item.
1059    ///
1060    /// `specified_inline` is used to keep track of whether we have
1061    /// already seen an inlining attribute for this item.
1062    /// If so, `specified_inline` holds the value and the span of
1063    /// the first `inline`/`no_inline` attribute.
1064    fn check_doc_inline(
1065        &self,
1066        attr: &Attribute,
1067        meta: &MetaItemInner,
1068        hir_id: HirId,
1069        target: Target,
1070        specified_inline: &mut Option<(bool, Span)>,
1071    ) {
1072        match target {
1073            Target::Use | Target::ExternCrate => {
1074                let do_inline = meta.name_or_empty() == sym::inline;
1075                if let Some((prev_inline, prev_span)) = *specified_inline {
1076                    if do_inline != prev_inline {
1077                        let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
1078                        spans.push_span_label(prev_span, fluent::passes_doc_inline_conflict_first);
1079                        spans.push_span_label(
1080                            meta.span(),
1081                            fluent::passes_doc_inline_conflict_second,
1082                        );
1083                        self.dcx().emit_err(errors::DocKeywordConflict { spans });
1084                    }
1085                } else {
1086                    *specified_inline = Some((do_inline, meta.span()));
1087                }
1088            }
1089            _ => {
1090                self.tcx.emit_node_span_lint(
1091                    INVALID_DOC_ATTRIBUTES,
1092                    hir_id,
1093                    meta.span(),
1094                    errors::DocInlineOnlyUse {
1095                        attr_span: meta.span(),
1096                        item_span: (attr.style == AttrStyle::Outer)
1097                            .then(|| self.tcx.hir().span(hir_id)),
1098                    },
1099                );
1100            }
1101        }
1102    }
1103
1104    fn check_doc_masked(
1105        &self,
1106        attr: &Attribute,
1107        meta: &MetaItemInner,
1108        hir_id: HirId,
1109        target: Target,
1110    ) {
1111        if target != Target::ExternCrate {
1112            self.tcx.emit_node_span_lint(
1113                INVALID_DOC_ATTRIBUTES,
1114                hir_id,
1115                meta.span(),
1116                errors::DocMaskedOnlyExternCrate {
1117                    attr_span: meta.span(),
1118                    item_span: (attr.style == AttrStyle::Outer)
1119                        .then(|| self.tcx.hir().span(hir_id)),
1120                },
1121            );
1122            return;
1123        }
1124
1125        if self.tcx.extern_mod_stmt_cnum(hir_id.owner).is_none() {
1126            self.tcx.emit_node_span_lint(
1127                INVALID_DOC_ATTRIBUTES,
1128                hir_id,
1129                meta.span(),
1130                errors::DocMaskedNotExternCrateSelf {
1131                    attr_span: meta.span(),
1132                    item_span: (attr.style == AttrStyle::Outer)
1133                        .then(|| self.tcx.hir().span(hir_id)),
1134                },
1135            );
1136        }
1137    }
1138
1139    /// Checks that an attribute is *not* used at the crate level. Returns `true` if valid.
1140    fn check_attr_not_crate_level(
1141        &self,
1142        meta: &MetaItemInner,
1143        hir_id: HirId,
1144        attr_name: &str,
1145    ) -> bool {
1146        if CRATE_HIR_ID == hir_id {
1147            self.dcx().emit_err(errors::DocAttrNotCrateLevel { span: meta.span(), attr_name });
1148            return false;
1149        }
1150        true
1151    }
1152
1153    /// Checks that an attribute is used at the crate level. Returns `true` if valid.
1154    fn check_attr_crate_level(
1155        &self,
1156        attr: &Attribute,
1157        meta: &MetaItemInner,
1158        hir_id: HirId,
1159    ) -> bool {
1160        if hir_id != CRATE_HIR_ID {
1161            // insert a bang between `#` and `[...`
1162            let bang_span = attr.span.lo() + BytePos(1);
1163            let sugg = (attr.style == AttrStyle::Outer
1164                && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID)
1165                .then_some(errors::AttrCrateLevelOnlySugg {
1166                    attr: attr.span.with_lo(bang_span).with_hi(bang_span),
1167                });
1168            self.tcx.emit_node_span_lint(
1169                INVALID_DOC_ATTRIBUTES,
1170                hir_id,
1171                meta.span(),
1172                errors::AttrCrateLevelOnly { sugg },
1173            );
1174            return false;
1175        }
1176        true
1177    }
1178
1179    /// Checks that `doc(test(...))` attribute contains only valid attributes. Returns `true` if
1180    /// valid.
1181    fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) {
1182        if let Some(metas) = meta.meta_item_list() {
1183            for i_meta in metas {
1184                match (i_meta.name_or_empty(), i_meta.meta_item()) {
1185                    (sym::attr | sym::no_crate_inject, _) => {}
1186                    (_, Some(m)) => {
1187                        self.tcx.emit_node_span_lint(
1188                            INVALID_DOC_ATTRIBUTES,
1189                            hir_id,
1190                            i_meta.span(),
1191                            errors::DocTestUnknown {
1192                                path: rustc_ast_pretty::pprust::path_to_string(&m.path),
1193                            },
1194                        );
1195                    }
1196                    (_, None) => {
1197                        self.tcx.emit_node_span_lint(
1198                            INVALID_DOC_ATTRIBUTES,
1199                            hir_id,
1200                            i_meta.span(),
1201                            errors::DocTestLiteral,
1202                        );
1203                    }
1204                }
1205            }
1206        } else {
1207            self.tcx.emit_node_span_lint(
1208                INVALID_DOC_ATTRIBUTES,
1209                hir_id,
1210                meta.span(),
1211                errors::DocTestTakesList,
1212            );
1213        }
1214    }
1215
1216    /// Check that the `#![doc(cfg_hide(...))]` attribute only contains a list of attributes.
1217    ///
1218    fn check_doc_cfg_hide(&self, meta: &MetaItemInner, hir_id: HirId) {
1219        if meta.meta_item_list().is_none() {
1220            self.tcx.emit_node_span_lint(
1221                INVALID_DOC_ATTRIBUTES,
1222                hir_id,
1223                meta.span(),
1224                errors::DocCfgHideTakesList,
1225            );
1226        }
1227    }
1228
1229    /// Runs various checks on `#[doc]` attributes.
1230    ///
1231    /// `specified_inline` should be initialized to `None` and kept for the scope
1232    /// of one item. Read the documentation of [`check_doc_inline`] for more information.
1233    ///
1234    /// [`check_doc_inline`]: Self::check_doc_inline
1235    fn check_doc_attrs(
1236        &self,
1237        attr: &Attribute,
1238        hir_id: HirId,
1239        target: Target,
1240        specified_inline: &mut Option<(bool, Span)>,
1241        aliases: &mut FxHashMap<String, Span>,
1242    ) {
1243        if let Some(list) = attr.meta_item_list() {
1244            for meta in &list {
1245                if let Some(i_meta) = meta.meta_item() {
1246                    match i_meta.name_or_empty() {
1247                        sym::alias => {
1248                            if self.check_attr_not_crate_level(meta, hir_id, "alias") {
1249                                self.check_doc_alias(meta, hir_id, target, aliases);
1250                            }
1251                        }
1252
1253                        sym::keyword => {
1254                            if self.check_attr_not_crate_level(meta, hir_id, "keyword") {
1255                                self.check_doc_keyword(meta, hir_id);
1256                            }
1257                        }
1258
1259                        sym::fake_variadic => {
1260                            if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
1261                                self.check_doc_fake_variadic(meta, hir_id);
1262                            }
1263                        }
1264
1265                        sym::search_unbox => {
1266                            if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
1267                                self.check_doc_search_unbox(meta, hir_id);
1268                            }
1269                        }
1270
1271                        sym::test => {
1272                            if self.check_attr_crate_level(attr, meta, hir_id) {
1273                                self.check_test_attr(meta, hir_id);
1274                            }
1275                        }
1276
1277                        sym::html_favicon_url
1278                        | sym::html_logo_url
1279                        | sym::html_playground_url
1280                        | sym::issue_tracker_base_url
1281                        | sym::html_root_url
1282                        | sym::html_no_source => {
1283                            self.check_attr_crate_level(attr, meta, hir_id);
1284                        }
1285
1286                        sym::cfg_hide => {
1287                            if self.check_attr_crate_level(attr, meta, hir_id) {
1288                                self.check_doc_cfg_hide(meta, hir_id);
1289                            }
1290                        }
1291
1292                        sym::inline | sym::no_inline => {
1293                            self.check_doc_inline(attr, meta, hir_id, target, specified_inline)
1294                        }
1295
1296                        sym::masked => self.check_doc_masked(attr, meta, hir_id, target),
1297
1298                        sym::cfg | sym::hidden | sym::notable_trait => {}
1299
1300                        sym::rust_logo => {
1301                            if self.check_attr_crate_level(attr, meta, hir_id)
1302                                && !self.tcx.features().rustdoc_internals()
1303                            {
1304                                feature_err(
1305                                    &self.tcx.sess,
1306                                    sym::rustdoc_internals,
1307                                    meta.span(),
1308                                    fluent::passes_doc_rust_logo,
1309                                )
1310                                .emit();
1311                            }
1312                        }
1313
1314                        _ => {
1315                            let path = rustc_ast_pretty::pprust::path_to_string(&i_meta.path);
1316                            if i_meta.has_name(sym::spotlight) {
1317                                self.tcx.emit_node_span_lint(
1318                                    INVALID_DOC_ATTRIBUTES,
1319                                    hir_id,
1320                                    i_meta.span,
1321                                    errors::DocTestUnknownSpotlight { path, span: i_meta.span },
1322                                );
1323                            } else if i_meta.has_name(sym::include)
1324                                && let Some(value) = i_meta.value_str()
1325                            {
1326                                let applicability = if list.len() == 1 {
1327                                    Applicability::MachineApplicable
1328                                } else {
1329                                    Applicability::MaybeIncorrect
1330                                };
1331                                // If there are multiple attributes, the suggestion would suggest
1332                                // deleting all of them, which is incorrect.
1333                                self.tcx.emit_node_span_lint(
1334                                    INVALID_DOC_ATTRIBUTES,
1335                                    hir_id,
1336                                    i_meta.span,
1337                                    errors::DocTestUnknownInclude {
1338                                        path,
1339                                        value: value.to_string(),
1340                                        inner: match attr.style {
1341                                            AttrStyle::Inner => "!",
1342                                            AttrStyle::Outer => "",
1343                                        },
1344                                        sugg: (attr.span, applicability),
1345                                    },
1346                                );
1347                            } else if i_meta.has_name(sym::passes)
1348                                || i_meta.has_name(sym::no_default_passes)
1349                            {
1350                                self.tcx.emit_node_span_lint(
1351                                    INVALID_DOC_ATTRIBUTES,
1352                                    hir_id,
1353                                    i_meta.span,
1354                                    errors::DocTestUnknownPasses { path, span: i_meta.span },
1355                                );
1356                            } else if i_meta.has_name(sym::plugins) {
1357                                self.tcx.emit_node_span_lint(
1358                                    INVALID_DOC_ATTRIBUTES,
1359                                    hir_id,
1360                                    i_meta.span,
1361                                    errors::DocTestUnknownPlugins { path, span: i_meta.span },
1362                                );
1363                            } else {
1364                                self.tcx.emit_node_span_lint(
1365                                    INVALID_DOC_ATTRIBUTES,
1366                                    hir_id,
1367                                    i_meta.span,
1368                                    errors::DocTestUnknownAny { path },
1369                                );
1370                            }
1371                        }
1372                    }
1373                } else {
1374                    self.tcx.emit_node_span_lint(
1375                        INVALID_DOC_ATTRIBUTES,
1376                        hir_id,
1377                        meta.span(),
1378                        errors::DocInvalid,
1379                    );
1380                }
1381            }
1382        }
1383    }
1384
1385    /// Warns against some misuses of `#[pass_by_value]`
1386    fn check_pass_by_value(&self, attr: &Attribute, span: Span, target: Target) {
1387        match target {
1388            Target::Struct | Target::Enum | Target::TyAlias => {}
1389            _ => {
1390                self.dcx().emit_err(errors::PassByValue { attr_span: attr.span, span });
1391            }
1392        }
1393    }
1394
1395    fn check_allow_incoherent_impl(&self, attr: &Attribute, span: Span, target: Target) {
1396        match target {
1397            Target::Method(MethodKind::Inherent) => {}
1398            _ => {
1399                self.dcx().emit_err(errors::AllowIncoherentImpl { attr_span: attr.span, span });
1400            }
1401        }
1402    }
1403
1404    fn check_has_incoherent_inherent_impls(&self, attr: &Attribute, span: Span, target: Target) {
1405        match target {
1406            Target::Trait | Target::Struct | Target::Enum | Target::Union | Target::ForeignTy => {}
1407            _ => {
1408                self.tcx
1409                    .dcx()
1410                    .emit_err(errors::HasIncoherentInherentImpl { attr_span: attr.span, span });
1411            }
1412        }
1413    }
1414
1415    fn check_ffi_pure(&self, attr_span: Span, attrs: &[Attribute], target: Target) {
1416        if target != Target::ForeignFn {
1417            self.dcx().emit_err(errors::FfiPureInvalidTarget { attr_span });
1418            return;
1419        }
1420        if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
1421            // `#[ffi_const]` functions cannot be `#[ffi_pure]`
1422            self.dcx().emit_err(errors::BothFfiConstAndPure { attr_span });
1423        }
1424    }
1425
1426    fn check_ffi_const(&self, attr_span: Span, target: Target) {
1427        if target != Target::ForeignFn {
1428            self.dcx().emit_err(errors::FfiConstInvalidTarget { attr_span });
1429        }
1430    }
1431
1432    /// Warns against some misuses of `#[must_use]`
1433    fn check_must_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
1434        if !matches!(
1435            target,
1436            Target::Fn
1437                | Target::Enum
1438                | Target::Struct
1439                | Target::Union
1440                | Target::Method(_)
1441                | Target::ForeignFn
1442                // `impl Trait` in return position can trip
1443                // `unused_must_use` if `Trait` is marked as
1444                // `#[must_use]`
1445                | Target::Trait
1446        ) {
1447            let article = match target {
1448                Target::ExternCrate
1449                | Target::Enum
1450                | Target::Impl
1451                | Target::Expression
1452                | Target::Arm
1453                | Target::AssocConst
1454                | Target::AssocTy => "an",
1455                _ => "a",
1456            };
1457
1458            self.tcx.emit_node_span_lint(
1459                UNUSED_ATTRIBUTES,
1460                hir_id,
1461                attr.span,
1462                errors::MustUseNoEffect { article, target },
1463            );
1464        }
1465    }
1466
1467    /// Checks if `#[must_not_suspend]` is applied to a struct, enum, union, or trait.
1468    fn check_must_not_suspend(&self, attr: &Attribute, span: Span, target: Target) {
1469        match target {
1470            Target::Struct | Target::Enum | Target::Union | Target::Trait => {}
1471            _ => {
1472                self.dcx().emit_err(errors::MustNotSuspend { attr_span: attr.span, span });
1473            }
1474        }
1475    }
1476
1477    /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl.
1478    fn check_may_dangle(&self, hir_id: HirId, attr: &Attribute) {
1479        if let hir::Node::GenericParam(param) = self.tcx.hir_node(hir_id)
1480            && matches!(
1481                param.kind,
1482                hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. }
1483            )
1484            && matches!(param.source, hir::GenericParamSource::Generics)
1485            && let parent_hir_id = self.tcx.parent_hir_id(hir_id)
1486            && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
1487            && let hir::ItemKind::Impl(impl_) = item.kind
1488            && let Some(trait_) = impl_.of_trait
1489            && let Some(def_id) = trait_.trait_def_id()
1490            && self.tcx.is_lang_item(def_id, hir::LangItem::Drop)
1491        {
1492            return;
1493        }
1494
1495        self.dcx().emit_err(errors::InvalidMayDangle { attr_span: attr.span });
1496    }
1497
1498    /// Checks if `#[cold]` is applied to a non-function.
1499    fn check_cold(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1500        match target {
1501            Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {}
1502            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1503            // `#[cold]` attribute with just a lint, because we previously
1504            // erroneously allowed it and some crates used it accidentally, 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, "cold");
1508            }
1509            _ => {
1510                // FIXME: #[cold] was previously allowed on non-functions and some crates used
1511                // this, so only emit a warning.
1512                self.tcx.emit_node_span_lint(
1513                    UNUSED_ATTRIBUTES,
1514                    hir_id,
1515                    attr.span,
1516                    errors::Cold { span, on_crate: hir_id == CRATE_HIR_ID },
1517                );
1518            }
1519        }
1520    }
1521
1522    /// Checks if `#[link]` is applied to an item other than a foreign module.
1523    fn check_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1524        if target == Target::ForeignMod
1525            && let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
1526            && let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
1527            && !matches!(abi, ExternAbi::Rust | ExternAbi::RustIntrinsic)
1528        {
1529            return;
1530        }
1531
1532        self.tcx.emit_node_span_lint(
1533            UNUSED_ATTRIBUTES,
1534            hir_id,
1535            attr.span,
1536            errors::Link { span: (target != Target::ForeignMod).then_some(span) },
1537        );
1538    }
1539
1540    /// Checks if `#[link_name]` is applied to an item other than a foreign function or static.
1541    fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1542        match target {
1543            Target::ForeignFn | Target::ForeignStatic => {}
1544            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1545            // `#[link_name]` attribute with just a lint, because we previously
1546            // erroneously allowed it and some crates used it accidentally, to be compatible
1547            // with crates depending on them, we can't throw an error here.
1548            Target::Field | Target::Arm | Target::MacroDef => {
1549                self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_name");
1550            }
1551            _ => {
1552                // FIXME: #[cold] was previously allowed on non-functions/statics and some crates
1553                // used this, so only emit a warning.
1554                let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span);
1555                if let Some(s) = attr.value_str() {
1556                    self.tcx.emit_node_span_lint(
1557                        UNUSED_ATTRIBUTES,
1558                        hir_id,
1559                        attr.span,
1560                        errors::LinkName { span, attr_span, value: s.as_str() },
1561                    );
1562                } else {
1563                    self.tcx.emit_node_span_lint(
1564                        UNUSED_ATTRIBUTES,
1565                        hir_id,
1566                        attr.span,
1567                        errors::LinkName { span, attr_span, value: "..." },
1568                    );
1569                };
1570            }
1571        }
1572    }
1573
1574    /// Checks if `#[no_link]` is applied to an `extern crate`.
1575    fn check_no_link(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1576        match target {
1577            Target::ExternCrate => {}
1578            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1579            // `#[no_link]` attribute with just a lint, because we previously
1580            // erroneously allowed it and some crates used it accidentally, to be compatible
1581            // with crates depending on them, we can't throw an error here.
1582            Target::Field | Target::Arm | Target::MacroDef => {
1583                self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_link");
1584            }
1585            _ => {
1586                self.dcx().emit_err(errors::NoLink { attr_span: attr.span, span });
1587            }
1588        }
1589    }
1590
1591    fn is_impl_item(&self, hir_id: HirId) -> bool {
1592        matches!(self.tcx.hir_node(hir_id), hir::Node::ImplItem(..))
1593    }
1594
1595    /// Checks if `#[export_name]` is applied to a function or static.
1596    fn check_export_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1597        match target {
1598            Target::Static | Target::Fn => {}
1599            Target::Method(..) if self.is_impl_item(hir_id) => {}
1600            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1601            // `#[export_name]` attribute with just a lint, because we previously
1602            // erroneously allowed it and some crates used it accidentally, to be compatible
1603            // with crates depending on them, we can't throw an error here.
1604            Target::Field | Target::Arm | Target::MacroDef => {
1605                self.inline_attr_str_error_with_macro_def(hir_id, attr, "export_name");
1606            }
1607            _ => {
1608                self.dcx().emit_err(errors::ExportName { attr_span: attr.span, span });
1609            }
1610        }
1611    }
1612
1613    fn check_rustc_layout_scalar_valid_range(&self, attr: &Attribute, span: Span, target: Target) {
1614        if target != Target::Struct {
1615            self.dcx().emit_err(errors::RustcLayoutScalarValidRangeNotStruct {
1616                attr_span: attr.span,
1617                span,
1618            });
1619            return;
1620        }
1621
1622        let Some(list) = attr.meta_item_list() else {
1623            return;
1624        };
1625
1626        if !matches!(&list[..], &[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Int(..), .. })]) {
1627            self.tcx
1628                .dcx()
1629                .emit_err(errors::RustcLayoutScalarValidRangeArg { attr_span: attr.span });
1630        }
1631    }
1632
1633    /// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument.
1634    fn check_rustc_legacy_const_generics(
1635        &self,
1636        hir_id: HirId,
1637        attr: &Attribute,
1638        span: Span,
1639        target: Target,
1640        item: Option<ItemLike<'_>>,
1641    ) {
1642        let is_function = matches!(target, Target::Fn);
1643        if !is_function {
1644            self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
1645                attr_span: attr.span,
1646                defn_span: span,
1647                on_crate: hir_id == CRATE_HIR_ID,
1648            });
1649            return;
1650        }
1651
1652        let Some(list) = attr.meta_item_list() else {
1653            // The attribute form is validated on AST.
1654            return;
1655        };
1656
1657        let Some(ItemLike::Item(Item {
1658            kind: ItemKind::Fn { sig: FnSig { decl, .. }, generics, .. },
1659            ..
1660        })) = item
1661        else {
1662            bug!("should be a function item");
1663        };
1664
1665        for param in generics.params {
1666            match param.kind {
1667                hir::GenericParamKind::Const { .. } => {}
1668                _ => {
1669                    self.dcx().emit_err(errors::RustcLegacyConstGenericsOnly {
1670                        attr_span: attr.span,
1671                        param_span: param.span,
1672                    });
1673                    return;
1674                }
1675            }
1676        }
1677
1678        if list.len() != generics.params.len() {
1679            self.dcx().emit_err(errors::RustcLegacyConstGenericsIndex {
1680                attr_span: attr.span,
1681                generics_span: generics.span,
1682            });
1683            return;
1684        }
1685
1686        let arg_count = decl.inputs.len() as u128 + generics.params.len() as u128;
1687        let mut invalid_args = vec![];
1688        for meta in list {
1689            if let Some(LitKind::Int(val, _)) = meta.lit().map(|lit| &lit.kind) {
1690                if *val >= arg_count {
1691                    let span = meta.span();
1692                    self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexExceed {
1693                        span,
1694                        arg_count: arg_count as usize,
1695                    });
1696                    return;
1697                }
1698            } else {
1699                invalid_args.push(meta.span());
1700            }
1701        }
1702
1703        if !invalid_args.is_empty() {
1704            self.dcx().emit_err(errors::RustcLegacyConstGenericsIndexNegative { invalid_args });
1705        }
1706    }
1707
1708    /// Helper function for checking that the provided attribute is only applied to a function or
1709    /// method.
1710    fn check_applied_to_fn_or_method(
1711        &self,
1712        hir_id: HirId,
1713        attr: &Attribute,
1714        span: Span,
1715        target: Target,
1716    ) {
1717        let is_function = matches!(target, Target::Fn | Target::Method(..));
1718        if !is_function {
1719            self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
1720                attr_span: attr.span,
1721                defn_span: span,
1722                on_crate: hir_id == CRATE_HIR_ID,
1723            });
1724        }
1725    }
1726
1727    /// Checks that the `#[rustc_lint_opt_ty]` attribute is only applied to a struct.
1728    fn check_rustc_lint_opt_ty(&self, attr: &Attribute, span: Span, target: Target) {
1729        match target {
1730            Target::Struct => {}
1731            _ => {
1732                self.dcx().emit_err(errors::RustcLintOptTy { attr_span: attr.span, span });
1733            }
1734        }
1735    }
1736
1737    /// Checks that the `#[rustc_lint_opt_deny_field_access]` attribute is only applied to a field.
1738    fn check_rustc_lint_opt_deny_field_access(&self, attr: &Attribute, span: Span, target: Target) {
1739        match target {
1740            Target::Field => {}
1741            _ => {
1742                self.tcx
1743                    .dcx()
1744                    .emit_err(errors::RustcLintOptDenyFieldAccess { attr_span: attr.span, span });
1745            }
1746        }
1747    }
1748
1749    /// Checks that the dep-graph debugging attributes are only present when the query-dep-graph
1750    /// option is passed to the compiler.
1751    fn check_rustc_dirty_clean(&self, attr: &Attribute) {
1752        if !self.tcx.sess.opts.unstable_opts.query_dep_graph {
1753            self.dcx().emit_err(errors::RustcDirtyClean { span: attr.span });
1754        }
1755    }
1756
1757    /// Checks if the attribute is applied to a trait.
1758    fn check_must_be_applied_to_trait(&self, attr: &Attribute, span: Span, target: Target) {
1759        match target {
1760            Target::Trait => {}
1761            _ => {
1762                self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait {
1763                    attr_span: attr.span,
1764                    defn_span: span,
1765                });
1766            }
1767        }
1768    }
1769
1770    /// Checks if `#[link_section]` is applied to a function or static.
1771    fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1772        match target {
1773            Target::Static | Target::Fn | Target::Method(..) => {}
1774            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1775            // `#[link_section]` attribute with just a lint, because we previously
1776            // erroneously allowed it and some crates used it accidentally, to be compatible
1777            // with crates depending on them, we can't throw an error here.
1778            Target::Field | Target::Arm | Target::MacroDef => {
1779                self.inline_attr_str_error_with_macro_def(hir_id, attr, "link_section");
1780            }
1781            _ => {
1782                // FIXME: #[link_section] was previously allowed on non-functions/statics and some
1783                // crates used this, so only emit a warning.
1784                self.tcx.emit_node_span_lint(
1785                    UNUSED_ATTRIBUTES,
1786                    hir_id,
1787                    attr.span,
1788                    errors::LinkSection { span },
1789                );
1790            }
1791        }
1792    }
1793
1794    /// Checks if `#[no_mangle]` is applied to a function or static.
1795    fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1796        match target {
1797            Target::Static | Target::Fn => {}
1798            Target::Method(..) if self.is_impl_item(hir_id) => {}
1799            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
1800            // `#[no_mangle]` attribute with just a lint, because we previously
1801            // erroneously allowed it and some crates used it accidentally, to be compatible
1802            // with crates depending on them, we can't throw an error here.
1803            Target::Field | Target::Arm | Target::MacroDef => {
1804                self.inline_attr_str_error_with_macro_def(hir_id, attr, "no_mangle");
1805            }
1806            // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error
1807            // The error should specify that the item that is wrong is specifically a *foreign* fn/static
1808            // otherwise the error seems odd
1809            Target::ForeignFn | Target::ForeignStatic => {
1810                let foreign_item_kind = match target {
1811                    Target::ForeignFn => "function",
1812                    Target::ForeignStatic => "static",
1813                    _ => unreachable!(),
1814                };
1815                self.tcx.emit_node_span_lint(
1816                    UNUSED_ATTRIBUTES,
1817                    hir_id,
1818                    attr.span,
1819                    errors::NoMangleForeign { span, attr_span: attr.span, foreign_item_kind },
1820                );
1821            }
1822            _ => {
1823                // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some
1824                // crates used this, so only emit a warning.
1825                self.tcx.emit_node_span_lint(
1826                    UNUSED_ATTRIBUTES,
1827                    hir_id,
1828                    attr.span,
1829                    errors::NoMangle { span },
1830                );
1831            }
1832        }
1833    }
1834
1835    /// Checks if the `#[repr]` attributes on `item` are valid.
1836    fn check_repr(
1837        &self,
1838        attrs: &[Attribute],
1839        span: Span,
1840        target: Target,
1841        item: Option<ItemLike<'_>>,
1842        hir_id: HirId,
1843    ) {
1844        // Extract the names of all repr hints, e.g., [foo, bar, align] for:
1845        // ```
1846        // #[repr(foo)]
1847        // #[repr(bar, align(8))]
1848        // ```
1849        let hints: Vec<_> = attrs
1850            .iter()
1851            .filter(|attr| attr.has_name(sym::repr))
1852            .filter_map(|attr| attr.meta_item_list())
1853            .flatten()
1854            .collect();
1855
1856        let mut int_reprs = 0;
1857        let mut is_explicit_rust = false;
1858        let mut is_c = false;
1859        let mut is_simd = false;
1860        let mut is_transparent = false;
1861
1862        // catch `repr()` with no arguments, applied to an item (i.e. not `#![repr()]`)
1863        if hints.is_empty() && item.is_some() {
1864            for attr in attrs.iter().filter(|attr| attr.has_name(sym::repr)) {
1865                match target {
1866                    Target::Struct | Target::Union | Target::Enum => {}
1867                    Target::Fn | Target::Method(_) => {
1868                        feature_err(
1869                            &self.tcx.sess,
1870                            sym::fn_align,
1871                            attr.span,
1872                            fluent::passes_repr_align_function,
1873                        )
1874                        .emit();
1875                    }
1876                    _ => {
1877                        self.dcx().emit_err(
1878                            errors::AttrApplication::StructEnumFunctionMethodUnion {
1879                                hint_span: attr.span,
1880                                span,
1881                            },
1882                        );
1883                    }
1884                }
1885            }
1886
1887            return;
1888        }
1889
1890        for hint in &hints {
1891            if !hint.is_meta_item() {
1892                self.dcx().emit_err(errors::ReprIdent { span: hint.span() });
1893                continue;
1894            }
1895
1896            match hint.name_or_empty() {
1897                sym::Rust => {
1898                    is_explicit_rust = true;
1899                    match target {
1900                        Target::Struct | Target::Union | Target::Enum => continue,
1901                        _ => {
1902                            self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1903                                hint_span: hint.span(),
1904                                span,
1905                            });
1906                        }
1907                    }
1908                }
1909                sym::C => {
1910                    is_c = true;
1911                    match target {
1912                        Target::Struct | Target::Union | Target::Enum => continue,
1913                        _ => {
1914                            self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1915                                hint_span: hint.span(),
1916                                span,
1917                            });
1918                        }
1919                    }
1920                }
1921                sym::align => {
1922                    match target {
1923                        Target::Struct | Target::Union | Target::Enum => {}
1924                        Target::Fn | Target::Method(_) => {
1925                            if !self.tcx.features().fn_align() {
1926                                feature_err(
1927                                    &self.tcx.sess,
1928                                    sym::fn_align,
1929                                    hint.span(),
1930                                    fluent::passes_repr_align_function,
1931                                )
1932                                .emit();
1933                            }
1934                        }
1935                        _ => {
1936                            self.dcx().emit_err(
1937                                errors::AttrApplication::StructEnumFunctionMethodUnion {
1938                                    hint_span: hint.span(),
1939                                    span,
1940                                },
1941                            );
1942                        }
1943                    }
1944
1945                    self.check_align_value(hint);
1946                }
1947                sym::packed => {
1948                    if target != Target::Struct && target != Target::Union {
1949                        self.dcx().emit_err(errors::AttrApplication::StructUnion {
1950                            hint_span: hint.span(),
1951                            span,
1952                        });
1953                    } else {
1954                        continue;
1955                    }
1956                }
1957                sym::simd => {
1958                    is_simd = true;
1959                    if target != Target::Struct {
1960                        self.dcx().emit_err(errors::AttrApplication::Struct {
1961                            hint_span: hint.span(),
1962                            span,
1963                        });
1964                    } else {
1965                        continue;
1966                    }
1967                }
1968                sym::transparent => {
1969                    is_transparent = true;
1970                    match target {
1971                        Target::Struct | Target::Union | Target::Enum => continue,
1972                        _ => {
1973                            self.dcx().emit_err(errors::AttrApplication::StructEnumUnion {
1974                                hint_span: hint.span(),
1975                                span,
1976                            });
1977                        }
1978                    }
1979                }
1980                sym::i8
1981                | sym::u8
1982                | sym::i16
1983                | sym::u16
1984                | sym::i32
1985                | sym::u32
1986                | sym::i64
1987                | sym::u64
1988                | sym::i128
1989                | sym::u128
1990                | sym::isize
1991                | sym::usize => {
1992                    int_reprs += 1;
1993                    if target != Target::Enum {
1994                        self.dcx().emit_err(errors::AttrApplication::Enum {
1995                            hint_span: hint.span(),
1996                            span,
1997                        });
1998                    } else {
1999                        continue;
2000                    }
2001                }
2002                _ => {
2003                    self.dcx().emit_err(errors::UnrecognizedReprHint { span: hint.span() });
2004                    continue;
2005                }
2006            };
2007        }
2008
2009        // Just point at all repr hints if there are any incompatibilities.
2010        // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
2011        let hint_spans = hints.iter().map(|hint| hint.span());
2012
2013        // Error on repr(transparent, <anything else>).
2014        if is_transparent && hints.len() > 1 {
2015            let hint_spans = hint_spans.clone().collect();
2016            self.dcx().emit_err(errors::TransparentIncompatible {
2017                hint_spans,
2018                target: target.to_string(),
2019            });
2020        }
2021        if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
2022            let hint_spans = hint_spans.clone().collect();
2023            self.dcx().emit_err(errors::ReprConflicting { hint_spans });
2024        }
2025        // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
2026        if (int_reprs > 1)
2027            || (is_simd && is_c)
2028            || (int_reprs == 1
2029                && is_c
2030                && item.is_some_and(|item| {
2031                    if let ItemLike::Item(item) = item { is_c_like_enum(item) } else { false }
2032                }))
2033        {
2034            self.tcx.emit_node_span_lint(
2035                CONFLICTING_REPR_HINTS,
2036                hir_id,
2037                hint_spans.collect::<Vec<Span>>(),
2038                errors::ReprConflictingLint,
2039            );
2040        }
2041    }
2042
2043    fn check_align_value(&self, item: &MetaItemInner) {
2044        match item.singleton_lit_list() {
2045            Some((
2046                _,
2047                MetaItemLit {
2048                    kind: ast::LitKind::Int(literal, ast::LitIntType::Unsuffixed), ..
2049                },
2050            )) => {
2051                let val = literal.get() as u64;
2052                if val > 2_u64.pow(29) {
2053                    // for values greater than 2^29, a different error will be emitted, make sure that happens
2054                    self.dcx().span_delayed_bug(
2055                        item.span(),
2056                        "alignment greater than 2^29 should be errored on elsewhere",
2057                    );
2058                } else {
2059                    // only do this check when <= 2^29 to prevent duplicate errors:
2060                    // alignment greater than 2^29 not supported
2061                    // alignment is too large for the current target
2062
2063                    let max =
2064                        Size::from_bits(self.tcx.sess.target.pointer_width).signed_int_max() as u64;
2065                    if val > max {
2066                        self.dcx().emit_err(errors::InvalidReprAlignForTarget {
2067                            span: item.span(),
2068                            size: max,
2069                        });
2070                    }
2071                }
2072            }
2073
2074            // if the attribute is malformed, singleton_lit_list may not be of the expected type or may be None
2075            // but an error will have already been emitted, so this code should just skip such attributes
2076            Some((_, _)) | None => {
2077                self.dcx().span_delayed_bug(item.span(), "malformed repr(align(N))");
2078            }
2079        }
2080    }
2081
2082    fn check_used(&self, attrs: &[Attribute], target: Target, target_span: Span) {
2083        let mut used_linker_span = None;
2084        let mut used_compiler_span = None;
2085        for attr in attrs.iter().filter(|attr| attr.has_name(sym::used)) {
2086            if target != Target::Static {
2087                self.dcx().emit_err(errors::UsedStatic {
2088                    attr_span: attr.span,
2089                    span: target_span,
2090                    target: target.name(),
2091                });
2092            }
2093            let inner = attr.meta_item_list();
2094            match inner.as_deref() {
2095                Some([item]) if item.has_name(sym::linker) => {
2096                    if used_linker_span.is_none() {
2097                        used_linker_span = Some(attr.span);
2098                    }
2099                }
2100                Some([item]) if item.has_name(sym::compiler) => {
2101                    if used_compiler_span.is_none() {
2102                        used_compiler_span = Some(attr.span);
2103                    }
2104                }
2105                Some(_) => {
2106                    // This error case is handled in rustc_hir_analysis::collect.
2107                }
2108                None => {
2109                    // Default case (compiler) when arg isn't defined.
2110                    if used_compiler_span.is_none() {
2111                        used_compiler_span = Some(attr.span);
2112                    }
2113                }
2114            }
2115        }
2116        if let (Some(linker_span), Some(compiler_span)) = (used_linker_span, used_compiler_span) {
2117            self.tcx
2118                .dcx()
2119                .emit_err(errors::UsedCompilerLinker { spans: vec![linker_span, compiler_span] });
2120        }
2121    }
2122
2123    /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
2124    /// (Allows proc_macro functions)
2125    fn check_allow_internal_unstable(
2126        &self,
2127        hir_id: HirId,
2128        attr: &Attribute,
2129        span: Span,
2130        target: Target,
2131        attrs: &[Attribute],
2132    ) {
2133        debug!("Checking target: {:?}", target);
2134        match target {
2135            Target::Fn => {
2136                for attr in attrs {
2137                    if attr.is_proc_macro_attr() {
2138                        debug!("Is proc macro attr");
2139                        return;
2140                    }
2141                }
2142                debug!("Is not proc macro attr");
2143            }
2144            Target::MacroDef => {}
2145            // FIXME(#80564): We permit struct fields and match arms to have an
2146            // `#[allow_internal_unstable]` attribute with just a lint, because we previously
2147            // erroneously allowed it and some crates used it accidentally, to be compatible
2148            // with crates depending on them, we can't throw an error here.
2149            Target::Field | Target::Arm => self.inline_attr_str_error_without_macro_def(
2150                hir_id,
2151                attr,
2152                "allow_internal_unstable",
2153            ),
2154            _ => {
2155                self.tcx
2156                    .dcx()
2157                    .emit_err(errors::AllowInternalUnstable { attr_span: attr.span, span });
2158            }
2159        }
2160    }
2161
2162    /// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
2163    fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) {
2164        // Here we only check that the #[debugger_visualizer] attribute is attached
2165        // to nothing other than a module. All other checks are done in the
2166        // `debugger_visualizer` query where they need to be done for decoding
2167        // anyway.
2168        match target {
2169            Target::Mod => {}
2170            _ => {
2171                self.dcx().emit_err(errors::DebugVisualizerPlacement { span: attr.span });
2172            }
2173        }
2174    }
2175
2176    /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
2177    /// (Allows proc_macro functions)
2178    fn check_rustc_allow_const_fn_unstable(
2179        &self,
2180        hir_id: HirId,
2181        attr: &Attribute,
2182        span: Span,
2183        target: Target,
2184    ) {
2185        match target {
2186            Target::Fn | Target::Method(_)
2187                if self.tcx.is_const_fn(hir_id.expect_owner().to_def_id()) => {}
2188            // FIXME(#80564): We permit struct fields and match arms to have an
2189            // `#[allow_internal_unstable]` attribute with just a lint, because we previously
2190            // erroneously allowed it and some crates used it accidentally, to be compatible
2191            // with crates depending on them, we can't throw an error here.
2192            Target::Field | Target::Arm | Target::MacroDef => {
2193                self.inline_attr_str_error_with_macro_def(hir_id, attr, "allow_internal_unstable")
2194            }
2195            _ => {
2196                self.tcx
2197                    .dcx()
2198                    .emit_err(errors::RustcAllowConstFnUnstable { attr_span: attr.span, span });
2199            }
2200        }
2201    }
2202
2203    fn check_rustc_std_internal_symbol(&self, attr: &Attribute, span: Span, target: Target) {
2204        match target {
2205            Target::Fn | Target::Static => {}
2206            _ => {
2207                self.tcx
2208                    .dcx()
2209                    .emit_err(errors::RustcStdInternalSymbol { attr_span: attr.span, span });
2210            }
2211        }
2212    }
2213
2214    fn check_stability_promotable(&self, attr: &Attribute, target: Target) {
2215        match target {
2216            Target::Expression => {
2217                self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span });
2218            }
2219            _ => {}
2220        }
2221    }
2222
2223    fn check_link_ordinal(&self, attr: &Attribute, _span: Span, target: Target) {
2224        match target {
2225            Target::ForeignFn | Target::ForeignStatic => {}
2226            _ => {
2227                self.dcx().emit_err(errors::LinkOrdinal { attr_span: attr.span });
2228            }
2229        }
2230    }
2231
2232    fn check_confusables(&self, attr: &Attribute, target: Target) {
2233        match target {
2234            Target::Method(MethodKind::Inherent) => {
2235                let Some(metas) = attr.meta_item_list() else {
2236                    return;
2237                };
2238
2239                let mut candidates = Vec::new();
2240
2241                for meta in metas {
2242                    let MetaItemInner::Lit(meta_lit) = meta else {
2243                        self.dcx().emit_err(errors::IncorrectMetaItem {
2244                            span: meta.span(),
2245                            suggestion: errors::IncorrectMetaItemSuggestion {
2246                                lo: meta.span().shrink_to_lo(),
2247                                hi: meta.span().shrink_to_hi(),
2248                            },
2249                        });
2250                        return;
2251                    };
2252                    candidates.push(meta_lit.symbol);
2253                }
2254
2255                if candidates.is_empty() {
2256                    self.dcx().emit_err(errors::EmptyConfusables { span: attr.span });
2257                }
2258            }
2259            _ => {
2260                self.dcx().emit_err(errors::Confusables { attr_span: attr.span });
2261            }
2262        }
2263    }
2264
2265    fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: Span, target: Target) {
2266        match target {
2267            Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
2268                self.tcx.emit_node_span_lint(
2269                    UNUSED_ATTRIBUTES,
2270                    hir_id,
2271                    attr.span,
2272                    errors::Deprecated,
2273                );
2274            }
2275            _ => {}
2276        }
2277    }
2278
2279    fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
2280        let name = attr.name_or_empty();
2281        match target {
2282            Target::ExternCrate | Target::Mod => {}
2283            _ => {
2284                self.tcx.emit_node_span_lint(
2285                    UNUSED_ATTRIBUTES,
2286                    hir_id,
2287                    attr.span,
2288                    errors::MacroUse { name },
2289                );
2290            }
2291        }
2292    }
2293
2294    fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
2295        if target != Target::MacroDef {
2296            self.tcx.emit_node_span_lint(
2297                UNUSED_ATTRIBUTES,
2298                hir_id,
2299                attr.span,
2300                errors::MacroExport::Normal,
2301            );
2302        } else if let Some(meta_item_list) = attr.meta_item_list()
2303            && !meta_item_list.is_empty()
2304        {
2305            if meta_item_list.len() > 1 {
2306                self.tcx.emit_node_span_lint(
2307                    INVALID_MACRO_EXPORT_ARGUMENTS,
2308                    hir_id,
2309                    attr.span,
2310                    errors::MacroExport::TooManyItems,
2311                );
2312            } else if meta_item_list[0].name_or_empty() != sym::local_inner_macros {
2313                self.tcx.emit_node_span_lint(
2314                    INVALID_MACRO_EXPORT_ARGUMENTS,
2315                    hir_id,
2316                    meta_item_list[0].span(),
2317                    errors::MacroExport::UnknownItem { name: meta_item_list[0].name_or_empty() },
2318                );
2319            }
2320        } else {
2321            // special case when `#[macro_export]` is applied to a macro 2.0
2322            let (macro_definition, _) = self.tcx.hir_node(hir_id).expect_item().expect_macro();
2323            let is_decl_macro = !macro_definition.macro_rules;
2324
2325            if is_decl_macro {
2326                self.tcx.emit_node_span_lint(
2327                    UNUSED_ATTRIBUTES,
2328                    hir_id,
2329                    attr.span,
2330                    errors::MacroExport::OnDeclMacro,
2331                );
2332            }
2333        }
2334    }
2335
2336    fn check_unused_attribute(&self, hir_id: HirId, attr: &Attribute) {
2337        // Warn on useless empty attributes.
2338        let note = if matches!(
2339            attr.name_or_empty(),
2340            sym::macro_use
2341                | sym::allow
2342                | sym::expect
2343                | sym::warn
2344                | sym::deny
2345                | sym::forbid
2346                | sym::feature
2347                | sym::repr
2348                | sym::target_feature
2349        ) && attr.meta_item_list().is_some_and(|list| list.is_empty())
2350        {
2351            errors::UnusedNote::EmptyList { name: attr.name_or_empty() }
2352        } else if matches!(
2353            attr.name_or_empty(),
2354            sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
2355        ) && let Some(meta) = attr.meta_item_list()
2356            && let [meta] = meta.as_slice()
2357            && let Some(item) = meta.meta_item()
2358            && let MetaItemKind::NameValue(_) = &item.kind
2359            && item.path == sym::reason
2360        {
2361            errors::UnusedNote::NoLints { name: attr.name_or_empty() }
2362        } else if matches!(
2363            attr.name_or_empty(),
2364            sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
2365        ) && let Some(meta) = attr.meta_item_list()
2366            && meta.iter().any(|meta| {
2367                meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
2368            })
2369        {
2370            if hir_id != CRATE_HIR_ID {
2371                match attr.style {
2372                    ast::AttrStyle::Outer => self.tcx.emit_node_span_lint(
2373                        UNUSED_ATTRIBUTES,
2374                        hir_id,
2375                        attr.span,
2376                        errors::OuterCrateLevelAttr,
2377                    ),
2378                    ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
2379                        UNUSED_ATTRIBUTES,
2380                        hir_id,
2381                        attr.span,
2382                        errors::InnerCrateLevelAttr,
2383                    ),
2384                };
2385                return;
2386            } else {
2387                let never_needs_link = self
2388                    .tcx
2389                    .crate_types()
2390                    .iter()
2391                    .all(|kind| matches!(kind, CrateType::Rlib | CrateType::Staticlib));
2392                if never_needs_link {
2393                    errors::UnusedNote::LinkerWarningsBinaryCrateOnly
2394                } else {
2395                    return;
2396                }
2397            }
2398        } else if attr.name_or_empty() == sym::default_method_body_is_const {
2399            errors::UnusedNote::DefaultMethodBodyConst
2400        } else {
2401            return;
2402        };
2403
2404        self.tcx.emit_node_span_lint(
2405            UNUSED_ATTRIBUTES,
2406            hir_id,
2407            attr.span,
2408            errors::Unused { attr_span: attr.span, note },
2409        );
2410    }
2411
2412    /// A best effort attempt to create an error for a mismatching proc macro signature.
2413    ///
2414    /// If this best effort goes wrong, it will just emit a worse error later (see #102923)
2415    fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
2416        if target != Target::Fn {
2417            return;
2418        }
2419
2420        let tcx = self.tcx;
2421        let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else {
2422            return;
2423        };
2424        let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else {
2425            return;
2426        };
2427
2428        let def_id = hir_id.expect_owner().def_id;
2429        let param_env = ty::ParamEnv::empty();
2430
2431        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
2432        let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
2433
2434        let span = tcx.def_span(def_id);
2435        let fresh_args = infcx.fresh_args_for_item(span, def_id.to_def_id());
2436        let sig = tcx.liberate_late_bound_regions(
2437            def_id.to_def_id(),
2438            tcx.fn_sig(def_id).instantiate(tcx, fresh_args),
2439        );
2440
2441        let mut cause = ObligationCause::misc(span, def_id);
2442        let sig = ocx.normalize(&cause, param_env, sig);
2443
2444        // proc macro is not WF.
2445        let errors = ocx.select_where_possible();
2446        if !errors.is_empty() {
2447            return;
2448        }
2449
2450        let expected_sig = tcx.mk_fn_sig(
2451            std::iter::repeat(token_stream).take(match kind {
2452                ProcMacroKind::Attribute => 2,
2453                ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
2454            }),
2455            token_stream,
2456            false,
2457            Safety::Safe,
2458            ExternAbi::Rust,
2459        );
2460
2461        if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
2462            let mut diag = tcx.dcx().create_err(errors::ProcMacroBadSig { span, kind });
2463
2464            let hir_sig = tcx.hir().fn_sig_by_hir_id(hir_id);
2465            if let Some(hir_sig) = hir_sig {
2466                #[allow(rustc::diagnostic_outside_of_impl)] // FIXME
2467                match terr {
2468                    TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
2469                        if let Some(ty) = hir_sig.decl.inputs.get(idx) {
2470                            diag.span(ty.span);
2471                            cause.span = ty.span;
2472                        } else if idx == hir_sig.decl.inputs.len() {
2473                            let span = hir_sig.decl.output.span();
2474                            diag.span(span);
2475                            cause.span = span;
2476                        }
2477                    }
2478                    TypeError::ArgCount => {
2479                        if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) {
2480                            diag.span(ty.span);
2481                            cause.span = ty.span;
2482                        }
2483                    }
2484                    TypeError::SafetyMismatch(_) => {
2485                        // FIXME: Would be nice if we had a span here..
2486                    }
2487                    TypeError::AbiMismatch(_) => {
2488                        // FIXME: Would be nice if we had a span here..
2489                    }
2490                    TypeError::VariadicMismatch(_) => {
2491                        // FIXME: Would be nice if we had a span here..
2492                    }
2493                    _ => {}
2494                }
2495            }
2496
2497            infcx.err_ctxt().note_type_err(
2498                &mut diag,
2499                &cause,
2500                None,
2501                Some(param_env.and(ValuePairs::PolySigs(ExpectedFound {
2502                    expected: ty::Binder::dummy(expected_sig),
2503                    found: ty::Binder::dummy(sig),
2504                }))),
2505                terr,
2506                false,
2507                None,
2508            );
2509            diag.emit();
2510            self.abort.set(true);
2511        }
2512
2513        let errors = ocx.select_all_or_error();
2514        if !errors.is_empty() {
2515            infcx.err_ctxt().report_fulfillment_errors(errors);
2516            self.abort.set(true);
2517        }
2518    }
2519
2520    fn check_coroutine(&self, attr: &Attribute, target: Target) {
2521        match target {
2522            Target::Closure => return,
2523            _ => {
2524                self.dcx().emit_err(errors::CoroutineOnNonClosure { span: attr.span });
2525            }
2526        }
2527    }
2528
2529    fn check_linkage(&self, attr: &Attribute, span: Span, target: Target) {
2530        match target {
2531            Target::Fn
2532            | Target::Method(..)
2533            | Target::Static
2534            | Target::ForeignStatic
2535            | Target::ForeignFn => {}
2536            _ => {
2537                self.dcx().emit_err(errors::Linkage { attr_span: attr.span, span });
2538            }
2539        }
2540    }
2541
2542    fn check_rustc_pub_transparent(&self, attr_span: Span, span: Span, attrs: &[Attribute]) {
2543        if !attrs
2544            .iter()
2545            .filter(|attr| attr.has_name(sym::repr))
2546            .filter_map(|attr| attr.meta_item_list())
2547            .flatten()
2548            .any(|nmi| nmi.has_name(sym::transparent))
2549        {
2550            self.dcx().emit_err(errors::RustcPubTransparent { span, attr_span });
2551        }
2552    }
2553
2554    fn check_rustc_force_inline(
2555        &self,
2556        hir_id: HirId,
2557        attrs: &[Attribute],
2558        span: Span,
2559        target: Target,
2560    ) {
2561        let force_inline_attr = attrs.iter().find(|attr| attr.has_name(sym::rustc_force_inline));
2562        match (target, force_inline_attr) {
2563            (Target::Closure, None) => {
2564                let is_coro = matches!(
2565                    self.tcx.hir().expect_expr(hir_id).kind,
2566                    hir::ExprKind::Closure(hir::Closure {
2567                        kind: hir::ClosureKind::Coroutine(..)
2568                            | hir::ClosureKind::CoroutineClosure(..),
2569                        ..
2570                    })
2571                );
2572                let parent_did = self.tcx.hir().get_parent_item(hir_id).to_def_id();
2573                let parent_span = self.tcx.def_span(parent_did);
2574                let parent_force_inline_attr =
2575                    self.tcx.get_attr(parent_did, sym::rustc_force_inline);
2576                if let Some(attr) = parent_force_inline_attr
2577                    && is_coro
2578                {
2579                    self.dcx().emit_err(errors::RustcForceInlineCoro {
2580                        attr_span: attr.span,
2581                        span: parent_span,
2582                    });
2583                }
2584            }
2585            (Target::Fn, _) => (),
2586            (_, Some(attr)) => {
2587                self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span, span });
2588            }
2589            (_, None) => (),
2590        }
2591    }
2592
2593    /// Checks if `#[autodiff]` is applied to an item other than a function item.
2594    fn check_autodiff(&self, _hir_id: HirId, _attr: &Attribute, span: Span, target: Target) {
2595        debug!("check_autodiff");
2596        match target {
2597            Target::Fn => {}
2598            _ => {
2599                self.dcx().emit_err(errors::AutoDiffAttr { attr_span: span });
2600                self.abort.set(true);
2601            }
2602        }
2603    }
2604}
2605
2606impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
2607    type NestedFilter = nested_filter::OnlyBodies;
2608
2609    fn nested_visit_map(&mut self) -> Self::Map {
2610        self.tcx.hir()
2611    }
2612
2613    fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
2614        // Historically we've run more checks on non-exported than exported macros,
2615        // so this lets us continue to run them while maintaining backwards compatibility.
2616        // In the long run, the checks should be harmonized.
2617        if let ItemKind::Macro(macro_def, _) = item.kind {
2618            let def_id = item.owner_id.to_def_id();
2619            if macro_def.macro_rules && !self.tcx.has_attr(def_id, sym::macro_export) {
2620                check_non_exported_macro_for_invalid_attrs(self.tcx, item);
2621            }
2622        }
2623
2624        let target = Target::from_item(item);
2625        self.check_attributes(item.hir_id(), item.span, target, Some(ItemLike::Item(item)));
2626        intravisit::walk_item(self, item)
2627    }
2628
2629    fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
2630        let target = Target::from_generic_param(generic_param);
2631        self.check_attributes(generic_param.hir_id, generic_param.span, target, None);
2632        intravisit::walk_generic_param(self, generic_param)
2633    }
2634
2635    fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
2636        let target = Target::from_trait_item(trait_item);
2637        self.check_attributes(trait_item.hir_id(), trait_item.span, target, None);
2638        intravisit::walk_trait_item(self, trait_item)
2639    }
2640
2641    fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) {
2642        self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None);
2643        intravisit::walk_field_def(self, struct_field);
2644    }
2645
2646    fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
2647        self.check_attributes(arm.hir_id, arm.span, Target::Arm, None);
2648        intravisit::walk_arm(self, arm);
2649    }
2650
2651    fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
2652        let target = Target::from_foreign_item(f_item);
2653        self.check_attributes(f_item.hir_id(), f_item.span, target, Some(ItemLike::ForeignItem));
2654        intravisit::walk_foreign_item(self, f_item)
2655    }
2656
2657    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
2658        let target = target_from_impl_item(self.tcx, impl_item);
2659        self.check_attributes(impl_item.hir_id(), impl_item.span, target, None);
2660        intravisit::walk_impl_item(self, impl_item)
2661    }
2662
2663    fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
2664        // When checking statements ignore expressions, they will be checked later.
2665        if let hir::StmtKind::Let(l) = stmt.kind {
2666            self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
2667        }
2668        intravisit::walk_stmt(self, stmt)
2669    }
2670
2671    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
2672        let target = match expr.kind {
2673            hir::ExprKind::Closure { .. } => Target::Closure,
2674            _ => Target::Expression,
2675        };
2676
2677        self.check_attributes(expr.hir_id, expr.span, target, None);
2678        intravisit::walk_expr(self, expr)
2679    }
2680
2681    fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
2682        self.check_attributes(field.hir_id, field.span, Target::ExprField, None);
2683        intravisit::walk_expr_field(self, field)
2684    }
2685
2686    fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) {
2687        self.check_attributes(variant.hir_id, variant.span, Target::Variant, None);
2688        intravisit::walk_variant(self, variant)
2689    }
2690
2691    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
2692        self.check_attributes(param.hir_id, param.span, Target::Param, None);
2693
2694        intravisit::walk_param(self, param);
2695    }
2696
2697    fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) {
2698        self.check_attributes(field.hir_id, field.span, Target::PatField, None);
2699        intravisit::walk_pat_field(self, field);
2700    }
2701}
2702
2703fn is_c_like_enum(item: &Item<'_>) -> bool {
2704    if let ItemKind::Enum(ref def, _) = item.kind {
2705        for variant in def.variants {
2706            match variant.data {
2707                hir::VariantData::Unit(..) => { /* continue */ }
2708                _ => return false,
2709            }
2710        }
2711        true
2712    } else {
2713        false
2714    }
2715}
2716
2717// FIXME: Fix "Cannot determine resolution" error and remove built-in macros
2718// from this check.
2719fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
2720    // Check for builtin attributes at the crate level
2721    // which were unsuccessfully resolved due to cannot determine
2722    // resolution for the attribute macro error.
2723    const ATTRS_TO_CHECK: &[Symbol] = &[
2724        sym::macro_export,
2725        sym::repr,
2726        sym::path,
2727        sym::automatically_derived,
2728        sym::rustc_main,
2729        sym::derive,
2730        sym::test,
2731        sym::test_case,
2732        sym::global_allocator,
2733        sym::bench,
2734    ];
2735
2736    for attr in attrs {
2737        // This function should only be called with crate attributes
2738        // which are inner attributes always but lets check to make sure
2739        if attr.style == AttrStyle::Inner {
2740            for attr_to_check in ATTRS_TO_CHECK {
2741                if attr.has_name(*attr_to_check) {
2742                    let item = tcx
2743                        .hir()
2744                        .items()
2745                        .map(|id| tcx.hir().item(id))
2746                        .find(|item| !item.span.is_dummy()) // Skip prelude `use`s
2747                        .map(|item| errors::ItemFollowingInnerAttr {
2748                            span: item.ident.span,
2749                            kind: item.kind.descr(),
2750                        });
2751                    let err = tcx.dcx().create_err(errors::InvalidAttrAtCrateLevel {
2752                        span: attr.span,
2753                        sugg_span: tcx
2754                            .sess
2755                            .source_map()
2756                            .span_to_snippet(attr.span)
2757                            .ok()
2758                            .filter(|src| src.starts_with("#!["))
2759                            .map(|_| {
2760                                attr.span
2761                                    .with_lo(attr.span.lo() + BytePos(1))
2762                                    .with_hi(attr.span.lo() + BytePos(2))
2763                            }),
2764                        name: *attr_to_check,
2765                        item,
2766                    });
2767
2768                    if let AttrKind::Normal(ref p) = attr.kind {
2769                        tcx.dcx().try_steal_replace_and_emit_err(
2770                            p.path.span,
2771                            StashKey::UndeterminedMacroResolution,
2772                            err,
2773                        );
2774                    } else {
2775                        err.emit();
2776                    }
2777                }
2778            }
2779        }
2780    }
2781}
2782
2783fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
2784    let attrs = tcx.hir().attrs(item.hir_id());
2785
2786    for attr in attrs {
2787        if attr.has_name(sym::inline) {
2788            tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span });
2789        }
2790    }
2791}
2792
2793fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModDefId) {
2794    let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
2795    tcx.hir().visit_item_likes_in_module(module_def_id, check_attr_visitor);
2796    if module_def_id.to_local_def_id().is_top_level_module() {
2797        check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
2798        check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
2799    }
2800    if check_attr_visitor.abort.get() {
2801        tcx.dcx().abort_if_errors()
2802    }
2803}
2804
2805pub(crate) fn provide(providers: &mut Providers) {
2806    *providers = Providers { check_mod_attrs, ..*providers };
2807}
2808
2809fn check_duplicates(
2810    tcx: TyCtxt<'_>,
2811    attr: &Attribute,
2812    hir_id: HirId,
2813    duplicates: AttributeDuplicates,
2814    seen: &mut FxHashMap<Symbol, Span>,
2815) {
2816    use AttributeDuplicates::*;
2817    if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
2818        return;
2819    }
2820    match duplicates {
2821        DuplicatesOk => {}
2822        WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
2823            match seen.entry(attr.name_or_empty()) {
2824                Entry::Occupied(mut entry) => {
2825                    let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
2826                        let to_remove = entry.insert(attr.span);
2827                        (to_remove, attr.span)
2828                    } else {
2829                        (attr.span, *entry.get())
2830                    };
2831                    tcx.emit_node_span_lint(
2832                        UNUSED_ATTRIBUTES,
2833                        hir_id,
2834                        this,
2835                        errors::UnusedDuplicate {
2836                            this,
2837                            other,
2838                            warning: matches!(
2839                                duplicates,
2840                                FutureWarnFollowing | FutureWarnPreceding
2841                            ),
2842                        },
2843                    );
2844                }
2845                Entry::Vacant(entry) => {
2846                    entry.insert(attr.span);
2847                }
2848            }
2849        }
2850        ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) {
2851            Entry::Occupied(mut entry) => {
2852                let (this, other) = if matches!(duplicates, ErrorPreceding) {
2853                    let to_remove = entry.insert(attr.span);
2854                    (to_remove, attr.span)
2855                } else {
2856                    (attr.span, *entry.get())
2857                };
2858                tcx.dcx().emit_err(errors::UnusedMultiple {
2859                    this,
2860                    other,
2861                    name: attr.name_or_empty(),
2862                });
2863            }
2864            Entry::Vacant(entry) => {
2865                entry.insert(attr.span);
2866            }
2867        },
2868    }
2869}
2870
2871fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
2872    matches!(&self_ty.kind, hir::TyKind::Tup([_]))
2873        || if let hir::TyKind::BareFn(bare_fn_ty) = &self_ty.kind {
2874            bare_fn_ty.decl.inputs.len() == 1
2875        } else {
2876            false
2877        }
2878        || (if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &self_ty.kind
2879            && let Some(&[hir::GenericArg::Type(ty)]) =
2880                path.segments.last().map(|last| last.args().args)
2881        {
2882            doc_fake_variadic_is_allowed_self_ty(ty.as_unambig_ty())
2883        } else {
2884            false
2885        })
2886}