rustc_passes/
check_attr.rs

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