Skip to main content

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::slice;
10
11use rustc_attr_ir::diagnostic::Directive;
12use rustc_attr_ir::lang_items::LangItem;
13use rustc_attr_ir::lint::LintCheck;
14use rustc_attr_ir::target::{AssocCtxt, MethodKind, Target};
15use rustc_attr_ir::{
16    Attribute, AttributeKind, DocAttribute, EiiDecl, EiiImpl, EiiImplResolution, InlineAttr,
17    OptimizeAttr, ReprAttr, RustcAssertVarianceKind, find_attr,
18};
19use rustc_attr_parsing::AttributeParser;
20use rustc_data_structures::thin_vec::ThinVec;
21use rustc_errors::{DiagCtxtHandle, IntoDiagArg};
22use rustc_feature::BUILTIN_ATTRIBUTE_SET;
23use rustc_hir::def::DefKind;
24use rustc_hir::def_id::LocalModId;
25use rustc_hir::intravisit::{self, Visitor};
26use rustc_hir::{
27    self as hir, CRATE_HIR_ID, Constness, ForeignItem, GenericParam, GenericParamKind, HirId, Item,
28    ItemKind, Mod, Node, ParamName, TraitItem,
29};
30use rustc_lint_defs::builtin::{
31    CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, MALFORMED_DIAGNOSTIC_ATTRIBUTES,
32    MALFORMED_DIAGNOSTIC_FORMAT_LITERALS, MISPLACED_DIAGNOSTIC_ATTRIBUTES, REPEATED_REPRS,
33    UNUSED_ATTRIBUTES,
34};
35use rustc_macros::Diagnostic;
36use rustc_middle::hir::nested_filter;
37use rustc_middle::query::Providers;
38use rustc_middle::traits::ObligationCause;
39use rustc_middle::ty::error::{ExpectedFound, TypeError};
40use rustc_middle::ty::{self, TyCtxt, TypingMode, Unnormalized, Variance};
41use rustc_span::edition::Edition;
42use rustc_span::{DUMMY_SP, Ident, Span, Symbol, bug, span_bug, sym};
43use rustc_structures::CrateType;
44use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
45use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
46use rustc_trait_selection::traits::{ObligationCtxt, TraitErrors};
47
48use crate::diagnostics;
49
50#[derive(const _: () =
    {
        impl<'_sess> rustc_errors::Diagnostic<'_sess> for
            DiagnosticOnConstOnlyForNonConstTraitImpls {
            #[track_caller]
            fn into_diag(self, dcx: rustc_errors::DiagCtxtHandle<'_sess>,
                level: rustc_errors::Level) -> rustc_errors::Diag<'_sess> {
                match self {
                    DiagnosticOnConstOnlyForNonConstTraitImpls {
                        item_span: __binding_0 } => {
                        let mut diag =
                            rustc_errors::Diag::new(dcx, level,
                                rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("the `diagnostic::on_const` attribute can only be applied to non-const trait implementations")));
                        ;
                        diag.span_label(__binding_0,
                            rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("this is a const trait implementation")));
                        diag
                    }
                }
            }
        }
    };Diagnostic)]
51#[diag(
52    "the `diagnostic::on_const` attribute can only be applied to non-const trait implementations"
53)]
54struct DiagnosticOnConstOnlyForNonConstTraitImpls {
55    #[label("this is a const trait implementation")]
56    item_span: Span,
57}
58
59fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
60    match impl_item.kind {
61        hir::ImplItemKind::Const(..) => {
62            let parent_def_id = tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
63            let containing_item = tcx.hir_expect_item(parent_def_id);
64            let of_trait = match &containing_item.kind {
65                hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
66                _ => ::rustc_span::macros::bug_impl(None,
    format_args!("parent of an ImplItem must be an Impl"), Location::caller())bug!("parent of an ImplItem must be an Impl"),
67            };
68            Target::AssocConst(AssocCtxt::Impl { of_trait })
69        }
70        hir::ImplItemKind::Fn(..) => {
71            let parent_def_id = tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
72            let containing_item = tcx.hir_expect_item(parent_def_id);
73            let containing_impl_is_for_trait = match &containing_item.kind {
74                hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
75                _ => ::rustc_span::macros::bug_impl(None,
    format_args!("parent of an ImplItem must be an Impl"), Location::caller())bug!("parent of an ImplItem must be an Impl"),
76            };
77            if containing_impl_is_for_trait {
78                Target::Method(MethodKind::TraitImpl)
79            } else {
80                Target::Method(MethodKind::Inherent)
81            }
82        }
83        hir::ImplItemKind::Type(..) => {
84            let parent_def_id = tcx.hir_get_parent_item(impl_item.hir_id()).def_id;
85            let containing_item = tcx.hir_expect_item(parent_def_id);
86            let of_trait = match &containing_item.kind {
87                hir::ItemKind::Impl(impl_) => impl_.of_trait.is_some(),
88                _ => ::rustc_span::macros::bug_impl(None,
    format_args!("parent of an ImplItem must be an Impl"), Location::caller())bug!("parent of an ImplItem must be an Impl"),
89            };
90            Target::AssocTy(AssocCtxt::Impl { of_trait })
91        }
92    }
93}
94
95#[derive(#[automatically_derived]impl ::core::marker::Copy for ProcMacroKind { }Copy, #[automatically_derived]#[doc(hidden)]unsafe impl ::core::clone::TrivialClone
    for ProcMacroKind {
}
#[automatically_derived]impl ::core::clone::Clone for ProcMacroKind {
    #[inline]
    fn clone(&self) -> Self { *self }
}Clone)]
96pub(crate) enum ProcMacroKind {
97    FunctionLike,
98    Derive,
99    Attribute,
100}
101
102impl IntoDiagArg for ProcMacroKind {
103    fn into_diag_arg(self, _: &mut Option<std::path::PathBuf>) -> rustc_errors::DiagArgValue {
104        match self {
105            ProcMacroKind::Attribute => "attribute proc macro",
106            ProcMacroKind::Derive => "derive proc macro",
107            ProcMacroKind::FunctionLike => "function-like proc macro",
108        }
109        .into_diag_arg(&mut None)
110    }
111}
112
113struct CheckAttrVisitor<'tcx> {
114    tcx: TyCtxt<'tcx>,
115
116    // Whether or not this visitor should abort after finding errors
117    abort: Cell<bool>,
118}
119
120impl<'tcx> CheckAttrVisitor<'tcx> {
121    fn dcx(&self) -> DiagCtxtHandle<'tcx> {
122        self.tcx.dcx()
123    }
124
125    /// Checks any attribute.
126    fn check_attributes(
127        &self,
128        hir_id: HirId,
129        span: Span,
130        target: Target,
131        item: Option<&'tcx Item<'tcx>>,
132    ) {
133        let attrs = self.tcx.hir_attrs(hir_id);
134        for attr in attrs {
135            match attr {
136                Attribute::Parsed(attr_kind) => {
137                    self.check_one_parsed_attribute(hir_id, span, target, item, attr_kind);
138                }
139                Attribute::Tool(u) | Attribute::DeriveHelper(u) => {
140                    match &*u.path.segments {
141                        [name, rest @ ..] => {
142                            if BUILTIN_ATTRIBUTE_SET.contains(name) {
143                                if rest.len() > 0
144                                    && AttributeParser::is_parsed_attribute(slice::from_ref(name))
145                                {
146                                    // Check if we tried to use a builtin attribute as an attribute
147                                    // namespace, like `#[must_use::skip]`. This check is here to
148                                    // solve <https://github.com/rust-lang/rust/issues/137590>.
149                                    // An error is already produced for this case elsewhere.
150                                    return;
151                                }
152
153                                ::rustc_span::macros::bug_impl(Some(u.span),
    format_args!("builtin attribute {0:?} not handled by `CheckAttrVisitor`",
        name), Location::caller())span_bug!(
154                                    u.span,
155                                    "builtin attribute {name:?} not handled by `CheckAttrVisitor`"
156                                )
157                            }
158                        }
159
160                        [] => ::core::panicking::unreachable_default_msg()unreachable!(),
161                    }
162                }
163            }
164        }
165
166        self.check_repr(attrs, span, target, item, hir_id);
167        self.check_rustc_force_inline(hir_id, attrs, target);
168        self.check_mix_no_mangle_export(hir_id, attrs);
169        self.check_optimize_and_inline(attrs);
170    }
171
172    /// Called by [`Self::check_attributes()`] to check a single attribute which is
173    /// [`Attribute::Parsed`].
174    ///
175    /// This is a separate function to help with comprehensibility and rustfmt-ability.
176    fn check_one_parsed_attribute(
177        &self,
178        hir_id: HirId,
179        span: Span,
180        target: Target,
181        item: Option<&'tcx Item<'tcx>>,
182        attr: &AttributeKind,
183    ) {
184        match attr {
185            AttributeKind::ProcMacro => {
186                self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
187            }
188            AttributeKind::ProcMacroAttribute => {
189                self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
190            }
191            AttributeKind::ProcMacroDerive { .. } => {
192                self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
193            }
194            AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span),
195            AttributeKind::Doc(attr) => self.check_doc_attrs(attr, hir_id, target),
196            AttributeKind::EiiImpl(eii_impl) => self.check_eii_impl(eii_impl),
197            AttributeKind::RustcMustImplementOneOf { attr_span, fn_names } => {
198                self.check_rustc_must_implement_one_of(*attr_span, fn_names, hir_id, target)
199            }
200            AttributeKind::OnUnimplemented { directive } => {
201                self.check_diagnostic_on_unimplemented(hir_id, directive.as_deref())
202            }
203            AttributeKind::OnConst { span, directive } => {
204                self.check_diagnostic_on_const(*span, hir_id, target, item, directive.as_deref())
205            }
206            AttributeKind::OnMove { directive } => {
207                self.check_diagnostic_on_move(hir_id, directive.as_deref())
208            }
209            AttributeKind::OnTypeError { directive, .. } => {
210                self.check_diagnostic_on_type_error(hir_id, directive.as_deref())
211            }
212            AttributeKind::Linkage(_linkage, span) => {
213                self.check_linkage(*span, hir_id, target, item)
214            }
215            AttributeKind::RustcAssertVariance { span: attr_span, kind } => {
216                self.check_rustc_assert_variance(span, *attr_span, hir_id, target, *kind);
217            }
218            AttributeKind::LintCheck(lints) => self.check_lint_check(hir_id, lints),
219
220            // All of the following attributes have no specific checks.
221            // tidy-alphabetical-start
222            AttributeKind::AllowInternalUnsafe(..) => (),
223            AttributeKind::AllowInternalUnstable(..) => (),
224            AttributeKind::AlwaysGca => (),
225            AttributeKind::AutomaticallyDerived => (),
226            AttributeKind::CfgAttrTrace(..) => (),
227            AttributeKind::CfgTrace(..) => (),
228            AttributeKind::CfiEncoding { .. } => (),
229            AttributeKind::Cold => (),
230            AttributeKind::CollapseDebugInfo(..) => (),
231            AttributeKind::CompilerBuiltins => (),
232            AttributeKind::ConstContinue(..) => {}
233            AttributeKind::Coroutine => (),
234            AttributeKind::Coverage(..) => (),
235            AttributeKind::CrateName { .. } => (),
236            AttributeKind::CrateType(..) => (),
237            AttributeKind::CustomMir(..) => (),
238            AttributeKind::DebuggerVisualizer(..) => (),
239            AttributeKind::DefaultLibAllocator => (),
240            AttributeKind::Deprecated { .. } => (),
241            AttributeKind::DoNotRecommend => (),
242            // `#[doc]` is actually a lot more than just doc comments, so is checked below
243            AttributeKind::DocComment { .. } => (),
244            AttributeKind::EiiDeclaration { .. } => (),
245            AttributeKind::ExportName { .. } => (),
246            AttributeKind::ExportStable => (),
247            AttributeKind::Feature(..) => (),
248            AttributeKind::FfiConst => (),
249            AttributeKind::FfiPure(..) => (),
250            AttributeKind::Fundamental => (),
251            AttributeKind::Ignore { .. } => (),
252            AttributeKind::Inline(..) => (),
253            AttributeKind::InstructionSet(..) => (),
254            AttributeKind::InstrumentFn(..) => (),
255            AttributeKind::Lang(..) => (),
256            AttributeKind::Link(..) => (),
257            AttributeKind::LinkName { .. } => (),
258            AttributeKind::LinkOrdinal { .. } => (),
259            AttributeKind::LinkSection { .. } => (),
260            AttributeKind::LoopMatch(..) => (),
261            AttributeKind::MacroEscape => (),
262            AttributeKind::MacroExport { .. } => (),
263            AttributeKind::MacroUse { .. } => (),
264            AttributeKind::Marker => (),
265            AttributeKind::MoveSizeLimit { .. } => (),
266            AttributeKind::MustNotSupend { .. } => (),
267            AttributeKind::MustUse { .. } => (),
268            AttributeKind::Naked(..) => (),
269            AttributeKind::NeedsAllocator => (),
270            AttributeKind::NeedsPanicRuntime => (),
271            AttributeKind::NoBuiltins => (),
272            AttributeKind::NoCore { .. } => (),
273            AttributeKind::NoImplicitPrelude => (),
274            AttributeKind::NoLink => (),
275            AttributeKind::NoMain => (),
276            AttributeKind::NoMangle(..) => (),
277            AttributeKind::NoStd { .. } => (),
278            AttributeKind::NonExhaustive(_) => (),
279            AttributeKind::OnUnknown { .. } => (),
280            AttributeKind::OnUnmatchedArgs { .. } => (),
281            AttributeKind::Opaque => (),
282            AttributeKind::Optimize(..) => (),
283            AttributeKind::PanicRuntime => (),
284            AttributeKind::PatchableFunctionEntry { .. } => (),
285            AttributeKind::Path(_, span) => self.check_path(*span, hir_id),
286            AttributeKind::PatternComplexityLimit { .. } => (),
287            AttributeKind::PinV2(..) => (),
288            AttributeKind::PreludeImport => (),
289            AttributeKind::ProfilerRuntime => (),
290            AttributeKind::RecursionLimit { .. } => (),
291            AttributeKind::ReexportTestHarnessMain(..) => (),
292            AttributeKind::RegisterTool { .. } => (),
293            // handled below this loop and elsewhere
294            AttributeKind::Repr { .. } => (),
295            AttributeKind::RustcAbi { .. } => (),
296            AttributeKind::RustcAlign { .. } => {}
297            AttributeKind::RustcAllocator => (),
298            AttributeKind::RustcAllocatorZeroed => (),
299            AttributeKind::RustcAllocatorZeroedVariant { .. } => (),
300            AttributeKind::RustcAllowConstFnUnstable(..) => (),
301            AttributeKind::RustcAllowIncoherentImpl(..) => (),
302            AttributeKind::RustcAllowLifetimeDependentSpecialization => (),
303            AttributeKind::RustcAsPtr => (),
304            AttributeKind::RustcAutodiff(..) => (),
305            AttributeKind::RustcBodyStability { .. } => (),
306            AttributeKind::RustcBuiltinMacro { .. } => (),
307            AttributeKind::RustcCanonicalSymbol => (),
308            AttributeKind::RustcCaptureAnalysis => (),
309            AttributeKind::RustcCguTestAttr(..) => (),
310            AttributeKind::RustcClean(..) => (),
311            AttributeKind::RustcCoherenceIsCore => (),
312            AttributeKind::RustcCoinductive => (),
313            AttributeKind::RustcComptime(_) => (),
314            AttributeKind::RustcConfusables { .. } => (),
315            AttributeKind::RustcConstStability { .. } => (),
316            AttributeKind::RustcConstStableIndirect => (),
317            AttributeKind::RustcConversionSuggestion => (),
318            AttributeKind::RustcDeallocator => (),
319            AttributeKind::RustcDelayedBugFromInsideQuery => (),
320            AttributeKind::RustcDenyExplicitImpl => (),
321            AttributeKind::RustcDeprecatedSafe2024 { .. } => (),
322            AttributeKind::RustcDiagnosticItem(..) => (),
323            AttributeKind::RustcDoNotConstCheck => (),
324            AttributeKind::RustcDocPrimitive(..) => (),
325            AttributeKind::RustcDummy => (),
326            AttributeKind::RustcDumpClauses => (),
327            AttributeKind::RustcDumpDefParents => (),
328            AttributeKind::RustcDumpDefPath(..) => (),
329            AttributeKind::RustcDumpGenerics => (),
330            AttributeKind::RustcDumpHiddenTypeOfOpaques => (),
331            AttributeKind::RustcDumpInferredOutlives => (),
332            AttributeKind::RustcDumpItemBounds => (),
333            AttributeKind::RustcDumpLayout(..) => (),
334            AttributeKind::RustcDumpObjectLifetimeDefaults => (),
335            AttributeKind::RustcDumpSymbolName(..) => (),
336            AttributeKind::RustcDumpUserArgs => (),
337            AttributeKind::RustcDumpVariances => (),
338            AttributeKind::RustcDumpVariancesOfOpaques => (),
339            AttributeKind::RustcDumpVtable(..) => (),
340            AttributeKind::RustcDynIncompatibleTrait(..) => (),
341            AttributeKind::RustcEffectiveVisibility => (),
342            AttributeKind::RustcEiiForeignItem => (),
343            AttributeKind::RustcEvaluateWhereClauses => (),
344            AttributeKind::RustcHasIncoherentInherentImpls => (),
345            AttributeKind::RustcIfThisChanged(..) => (),
346            AttributeKind::RustcInheritOverflowChecks => (),
347            AttributeKind::RustcInsignificantDtor => (),
348            AttributeKind::RustcIntrinsic => (),
349            AttributeKind::RustcIntrinsicConstStableIndirect => (),
350            AttributeKind::RustcLegacyConstGenerics { .. } => (),
351            AttributeKind::RustcLintOptDenyFieldAccess { .. } => (),
352            AttributeKind::RustcLintOptTy => (),
353            AttributeKind::RustcLintQueryInstability => (),
354            AttributeKind::RustcLintUntrackedQueryInformation => (),
355            AttributeKind::RustcMacroTransparency(_) => (),
356            AttributeKind::RustcMain => (),
357            AttributeKind::RustcMir(_) => (),
358            AttributeKind::RustcMustMatchExhaustively(..) => (),
359            AttributeKind::RustcNeverReturnsNullPtr => (),
360            AttributeKind::RustcNoImplicitAutorefs => (),
361            AttributeKind::RustcNoImplicitBounds => (),
362            AttributeKind::RustcNoMirInline => (),
363            AttributeKind::RustcNoWritable => (),
364            AttributeKind::RustcNonConstTraitMethod => (),
365            AttributeKind::RustcNonnullOptimizationGuaranteed => (),
366            AttributeKind::RustcNounwind => (),
367            AttributeKind::RustcObjcClass { .. } => (),
368            AttributeKind::RustcObjcSelector { .. } => (),
369            AttributeKind::RustcOffloadKernel => (),
370            AttributeKind::RustcPanicsWhenZero => (),
371            AttributeKind::RustcParenSugar => (),
372            AttributeKind::RustcPassByValue => (),
373            AttributeKind::RustcPassIndirectlyInNonRusticAbis(..) => (),
374            AttributeKind::RustcPreserveUbChecks => (),
375            AttributeKind::RustcProcMacroDecls => (),
376            AttributeKind::RustcPubTransparent(..) => (),
377            AttributeKind::RustcReallocator => (),
378            AttributeKind::RustcRegions => (),
379            AttributeKind::RustcScalableVector { .. } => (),
380            AttributeKind::RustcShouldNotBeCalledOnConstItems => (),
381            AttributeKind::RustcShowSpans(_) => (),
382            AttributeKind::RustcSimdMonomorphizeLaneLimit(..) => (),
383            AttributeKind::RustcSkipDuringMethodDispatch { .. } => (),
384            AttributeKind::RustcSpecializationTrait => (),
385            AttributeKind::RustcStdInternalSymbol => (),
386            AttributeKind::RustcStrictCoherence(..) => (),
387            AttributeKind::RustcTestMarker(..) => (),
388            AttributeKind::RustcThenThisWouldNeed(..) => (),
389            AttributeKind::RustcTrivialFieldReads => (),
390            AttributeKind::Sanitize { .. } => {}
391            AttributeKind::ShouldPanic { .. } => (),
392            AttributeKind::Splat(..) => (),
393            AttributeKind::Stability { .. } => (),
394            AttributeKind::TargetFeature { .. } => {}
395            AttributeKind::TestRunner(..) => (),
396            AttributeKind::ThreadLocal => (),
397            AttributeKind::TrackCaller(_) => (),
398            AttributeKind::TypeLengthLimit { .. } => (),
399            AttributeKind::UncheckedTypeAlias => (),
400            AttributeKind::Unroll(..) => (),
401            AttributeKind::UnstableFeatureBound(..) => (),
402            AttributeKind::UnstableRemoved(..) => (),
403            AttributeKind::Used { .. } => (),
404            AttributeKind::WindowsSubsystem(..) => (),
405            // tidy-alphabetical-end
406        }
407    }
408
409    fn check_path(&self, span: Span, hir_id: HirId) {
410        let Node::Item(item) = self.tcx.hir_node(hir_id) else {
411            return;
412        };
413
414        let ItemKind::Mod(_, module) = &item.kind else {
415            return;
416        };
417
418        if item.span == module.spans.inner_span || !item.span.contains(module.spans.inner_span) {
419            return;
420        }
421
422        // Do not warn when a nested module uses `#[path]` or is out-of-line,
423        // because the attribute may affect nested module path resolution.
424        if self.has_nested_module_path_dependency(module) {
425            return;
426        }
427
428        self.tcx.emit_node_span_lint(
429            UNUSED_ATTRIBUTES,
430            hir_id,
431            span,
432            diagnostics::Unused {
433                attr_span: span,
434                note: diagnostics::UnusedNote::PathOnInlineModule,
435            },
436        );
437    }
438
439    fn has_nested_module_path_dependency(&self, module: &Mod<'tcx>) -> bool {
440        module.item_ids.iter().any(|item_id| {
441            let child = self.tcx.hir_item(*item_id);
442
443            let ItemKind::Mod(_, child_module) = &child.kind else {
444                return false;
445            };
446
447            let is_out_of_line = child.span == child_module.spans.inner_span
448                || !child.span.contains(child_module.spans.inner_span);
449
450            let has_path_attr = {
        {
            'done:
                {
                for i in
                    ::rustc_attr_ir::HasAttrs::get_attrs(child.hir_id(),
                        &self.tcx) {
                    #[allow(unused_imports)]
                    use ::rustc_attr_ir::AttributeKind::*;
                    let i: &::rustc_attr_ir::Attribute = i;
                    match i {
                        ::rustc_attr_ir::Attribute::Parsed(Path(..)) => {
                            break 'done Some(());
                        }
                        ::rustc_attr_ir::Attribute::Tool(..) |
                            ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(self.tcx, child.hir_id(), Path(..));
451
452            is_out_of_line || has_path_attr || self.has_nested_module_path_dependency(child_module)
453        })
454    }
455
456    fn check_rustc_must_implement_one_of(
457        &self,
458        attr_span: Span,
459        list: &ThinVec<Ident>,
460        hir_id: HirId,
461        target: Target,
462    ) {
463        // Ignoring invalid targets because TyCtxt::associated_items emits bug if the target isn't valid
464        // the parser has already produced an error for the target being invalid
465        if !#[allow(non_exhaustive_omitted_patterns)] match target {
    Target::Trait => true,
    _ => false,
}matches!(target, Target::Trait) {
466            return;
467        }
468
469        let def_id = hir_id.owner.def_id;
470
471        let items = self.tcx.associated_items(def_id);
472        // Check that all arguments of `#[rustc_must_implement_one_of]` reference
473        // functions in the trait with default implementations
474        for ident in list {
475            let item = items
476                .filter_by_name_unhygienic(ident.name)
477                .find(|item| item.ident(self.tcx) == *ident);
478
479            match item {
480                Some(item) if #[allow(non_exhaustive_omitted_patterns)] match item.kind {
    ty::AssocKind::Fn { .. } => true,
    _ => false,
}matches!(item.kind, ty::AssocKind::Fn { .. }) => {
481                    if !item.defaultness(self.tcx).has_value() {
482                        self.tcx.dcx().emit_err(
483                            diagnostics::FunctionNotHaveDefaultImplementation {
484                                span: self.tcx.def_span(item.def_id),
485                                note_span: attr_span,
486                            },
487                        );
488                    }
489                }
490                Some(item) => {
491                    self.dcx().emit_err(diagnostics::MustImplementNotFunction {
492                        span: self.tcx.def_span(item.def_id),
493                        span_note: diagnostics::MustImplementNotFunctionSpanNote {
494                            span: attr_span,
495                        },
496                        note: diagnostics::MustImplementNotFunctionNote {},
497                    });
498                }
499                None => {
500                    self.dcx().emit_err(diagnostics::FunctionNotFoundInTrait { span: ident.span });
501                }
502            }
503        }
504    }
505
506    /// Checks that each externally implementable item (EII) implementation uses `unsafe`
507    /// exactly when its declaration requires it.
508    fn check_eii_impl(&self, eii_impl: &EiiImpl) {
509        let EiiImpl { span, inner_span, resolution, impl_unsafe_span, is_default: _ } = eii_impl;
510        let impl_unsafe = match resolution {
511            EiiImplResolution::Macro(eii_macro) => {
    {
        'done:
            {
            for i in
                ::rustc_attr_ir::HasAttrs::get_attrs(*eii_macro, &self.tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(EiiDeclaration(EiiDecl {
                        impl_unsafe, .. })) => {
                        break 'done Some(*impl_unsafe);
                    }
                    ::rustc_attr_ir::Attribute::Tool(..) |
                        ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(
512                self.tcx,
513                *eii_macro,
514                EiiDeclaration(EiiDecl { impl_unsafe, .. }) => *impl_unsafe
515            ),
516            EiiImplResolution::Known(foreign_item_did) => self
517                .tcx
518                .externally_implementable_items(foreign_item_did.krate)
519                .get(foreign_item_did)
520                .map(|(decl, _)| decl.impl_unsafe),
521            EiiImplResolution::Error(_) => None,
522        };
523        let Some(needs_unsafe) = impl_unsafe else {
524            return;
525        };
526
527        let name = match resolution {
528            EiiImplResolution::Macro(eii_macro) => self.tcx.item_name(*eii_macro),
529            EiiImplResolution::Known(def_id) => self.tcx.item_name(*def_id),
530            EiiImplResolution::Error(_) => ::core::panicking::unreachable_default_msg()unreachable!(),
531        };
532
533        match (needs_unsafe, *impl_unsafe_span) {
534            (true, None) => {
535                self.dcx().emit_err(diagnostics::EiiImplRequiresUnsafe {
536                    span: *span,
537                    name,
538                    suggestion: diagnostics::EiiImplRequiresUnsafeSuggestion {
539                        left: inner_span.shrink_to_lo(),
540                        right: inner_span.shrink_to_hi(),
541                    },
542                });
543            }
544            (false, Some(unsafe_span)) => {
545                self.dcx().emit_err(diagnostics::EiiImplCannotBeUnsafe {
546                    impl_span: *span,
547                    unsafe_span,
548                    name,
549                });
550            }
551            _ => {}
552        }
553    }
554
555    /// Checks use of generic formatting parameters in `#[diagnostic::on_unimplemented]`
556    fn check_diagnostic_on_unimplemented(&self, hir_id: HirId, directive: Option<&Directive>) {
557        if let Some(directive) = directive {
558            if let Node::Item(Item {
559                kind: ItemKind::Trait { ident: trait_name, generics, .. },
560                ..
561            }) = self.tcx.hir_node(hir_id)
562            {
563                directive.visit_params(&mut |argument_name, span| {
564                    let has_generic = generics.params.iter().any(|p| {
565                        if !#[allow(non_exhaustive_omitted_patterns)] match p.kind {
    GenericParamKind::Lifetime { .. } => true,
    _ => false,
}matches!(p.kind, GenericParamKind::Lifetime { .. })
566                            && let ParamName::Plain(name) = p.name
567                            && name.name == argument_name
568                        {
569                            true
570                        } else {
571                            false
572                        }
573                    });
574                    if !has_generic {
575                        self.tcx.emit_node_span_lint(
576                            MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
577                            hir_id,
578                            span,
579                            diagnostics::UnknownFormatParameterForOnUnimplementedAttr {
580                                argument_name,
581                                trait_name: *trait_name,
582                                help: !directive.is_rustc_attr,
583                            },
584                        )
585                    }
586                })
587            }
588        }
589    }
590
591    /// Checks if `#[diagnostic::on_const]` is applied to a on-const trait impl
592    fn check_diagnostic_on_const(
593        &self,
594        attr_path_span: Span,
595        hir_id: HirId,
596        target: Target,
597        item: Option<&'tcx Item<'tcx>>,
598        directive: Option<&Directive>,
599    ) {
600        // We only check the non-constness here. A diagnostic for use
601        // on not-trait impl items is issued during attribute parsing.
602        if target == (Target::Impl { of_trait: true }) {
603            if let Some(directive) = directive
604                && let Node::Item(Item { kind: ItemKind::Impl(hir::Impl { generics, .. }), .. }) =
605                    self.tcx.hir_node(hir_id)
606            {
607                directive.visit_params(&mut |argument_name, span| {
608                    let has_generic = generics.params.iter().any(|p| {
609                        if !#[allow(non_exhaustive_omitted_patterns)] match p.kind {
    GenericParamKind::Lifetime { .. } => true,
    _ => false,
}matches!(p.kind, GenericParamKind::Lifetime { .. })
610                            && let ParamName::Plain(name) = p.name
611                            && name.name == argument_name
612                        {
613                            true
614                        } else {
615                            false
616                        }
617                    });
618                    if !has_generic {
619                        self.tcx.emit_node_span_lint(
620                            MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
621                            hir_id,
622                            span,
623                            diagnostics::OnConstMalformedFormatLiterals { name: argument_name },
624                        )
625                    }
626                });
627            }
628            match item.unwrap().expect_impl().constness {
629                Constness::Const { .. } => {
630                    let item_span = self.tcx.hir_span(hir_id);
631                    self.tcx.emit_node_span_lint(
632                        MISPLACED_DIAGNOSTIC_ATTRIBUTES,
633                        hir_id,
634                        attr_path_span,
635                        DiagnosticOnConstOnlyForNonConstTraitImpls { item_span },
636                    );
637                    return;
638                }
639                Constness::NotConst => return,
640            }
641        }
642    }
643
644    /// Checks use of generic formatting parameters in `#[diagnostic::on_move]`
645    fn check_diagnostic_on_move(&self, hir_id: HirId, directive: Option<&Directive>) {
646        if let Some(directive) = directive {
647            if let Node::Item(Item {
648                kind:
649                    ItemKind::Struct(_, generics, _)
650                    | ItemKind::Enum(_, generics, _)
651                    | ItemKind::Union(_, generics, _),
652                ..
653            }) = self.tcx.hir_node(hir_id)
654            {
655                directive.visit_params(&mut |argument_name, span| {
656                    let has_generic = generics.params.iter().any(|p| {
657                        if !#[allow(non_exhaustive_omitted_patterns)] match p.kind {
    GenericParamKind::Lifetime { .. } => true,
    _ => false,
}matches!(p.kind, GenericParamKind::Lifetime { .. })
658                            && let ParamName::Plain(name) = p.name
659                            && name.name == argument_name
660                        {
661                            true
662                        } else {
663                            false
664                        }
665                    });
666                    if !has_generic {
667                        self.tcx.emit_node_span_lint(
668                            MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
669                            hir_id,
670                            span,
671                            diagnostics::OnMoveMalformedFormatLiterals { name: argument_name },
672                        )
673                    }
674                });
675            }
676        }
677    }
678
679    fn check_diagnostic_on_type_error(&self, hir_id: HirId, directive: Option<&Directive>) {
680        if let Some(directive) = directive {
681            if let Node::Item(Item {
682                kind:
683                    ItemKind::Struct(_, generics, _)
684                    | ItemKind::Enum(_, generics, _)
685                    | ItemKind::Union(_, generics, _),
686                ..
687            }) = self.tcx.hir_node(hir_id)
688            {
689                let generic_count = generics
690                    .params
691                    .iter()
692                    .filter(|p| !#[allow(non_exhaustive_omitted_patterns)] match p.kind {
    GenericParamKind::Lifetime { .. } => true,
    _ => false,
}matches!(p.kind, GenericParamKind::Lifetime { .. }))
693                    .count();
694
695                // Enforce: at most one generic
696                if generic_count != 1 {
697                    self.tcx.emit_node_span_lint(
698                        MALFORMED_DIAGNOSTIC_ATTRIBUTES,
699                        hir_id,
700                        generics.span,
701                        diagnostics::OnTypeErrorNotExactlyOneGeneric { count: generic_count },
702                    );
703                }
704
705                directive.visit_params(&mut |argument_name, span| {
706                    let has_generic = generics.params.iter().any(|p| {
707                        if !#[allow(non_exhaustive_omitted_patterns)] match p.kind {
    GenericParamKind::Lifetime { .. } => true,
    _ => false,
}matches!(p.kind, GenericParamKind::Lifetime { .. })
708                            && let ParamName::Plain(name) = p.name
709                            && name.name == argument_name
710                        {
711                            true
712                        } else {
713                            false
714                        }
715                    });
716
717                    let is_allowed = argument_name == sym::expected || argument_name == sym::found;
718                    if !(has_generic | is_allowed) {
719                        self.tcx.emit_node_span_lint(
720                            MALFORMED_DIAGNOSTIC_FORMAT_LITERALS,
721                            hir_id,
722                            span,
723                            diagnostics::OnTypeErrorMalformedFormatLiterals { name: argument_name },
724                        )
725                    }
726                });
727            }
728        }
729    }
730
731    fn check_doc_alias_value(&self, span: Span, hir_id: HirId, target: Target, alias: Symbol) {
732        if let Some(location) = match target {
733            Target::AssocTy(_) => {
734                if let DefKind::Impl { .. } =
735                    self.tcx.def_kind(self.tcx.local_parent(hir_id.owner.def_id))
736                {
737                    Some("type alias in implementation block")
738                } else {
739                    None
740                }
741            }
742            Target::AssocConst(_) => {
743                let parent_def_id = self.tcx.hir_get_parent_item(hir_id).def_id;
744                let containing_item = self.tcx.hir_expect_item(parent_def_id);
745                // We can't link to trait impl's consts.
746                let err = "associated constant in trait implementation block";
747                match containing_item.kind {
748                    ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => Some(err),
749                    _ => None,
750                }
751            }
752            // we check the validity of params elsewhere
753            Target::Param => return,
754            Target::Expression
755            | Target::Statement
756            | Target::Arm
757            | Target::ForeignMod
758            | Target::Closure
759            | Target::Impl { .. }
760            | Target::WherePredicate => Some(target.name()),
761            Target::ExternCrate
762            | Target::Use
763            | Target::Static
764            | Target::Const
765            | Target::Fn
766            | Target::Mod
767            | Target::GlobalAsm
768            | Target::TyAlias
769            | Target::Enum
770            | Target::Variant
771            | Target::Struct
772            | Target::Field
773            | Target::Union
774            | Target::Trait
775            | Target::TraitAlias
776            | Target::Method(..)
777            | Target::ForeignFn
778            | Target::ForeignStatic
779            | Target::ForeignTy
780            | Target::TypeParam
781            | Target::LifetimeParam
782            | Target::ConstParam
783            | Target::MacroDef
784            | Target::PatField
785            | Target::ExprField
786            | Target::Crate
787            | Target::MacroCall
788            | Target::Delegation { .. }
789            | Target::Loop
790            | Target::ForLoop
791            | Target::While
792            | Target::Break => None,
793        } {
794            self.tcx.dcx().emit_err(diagnostics::DocAliasBadLocation { span, location });
795            return;
796        }
797        if self.tcx.hir_opt_name(hir_id) == Some(alias) {
798            self.tcx.dcx().emit_err(diagnostics::DocAliasNotAnAlias { span, attr_str: alias });
799            return;
800        }
801    }
802
803    fn check_doc_fake_variadic(&self, span: Span, hir_id: HirId) {
804        let item_kind = match self.tcx.hir_node(hir_id) {
805            hir::Node::Item(item) => Some(&item.kind),
806            _ => None,
807        };
808        match item_kind {
809            Some(ItemKind::Impl(i)) => {
810                let is_valid = doc_fake_variadic_is_allowed_self_ty(i.self_ty)
811                    || if let Some(&[hir::GenericArg::Type(ty)]) = i
812                        .of_trait
813                        .and_then(|of_trait| of_trait.trait_ref.path.segments.last())
814                        .map(|last_segment| last_segment.args().args)
815                    {
816                        #[allow(non_exhaustive_omitted_patterns)] match &ty.kind {
    hir::TyKind::Tup([_]) => true,
    _ => false,
}matches!(&ty.kind, hir::TyKind::Tup([_]))
817                    } else {
818                        false
819                    };
820                if !is_valid {
821                    self.dcx().emit_err(diagnostics::DocFakeVariadicNotValid { span });
822                }
823            }
824            _ => {
825                self.dcx().emit_err(diagnostics::DocKeywordOnlyImpl { span });
826            }
827        }
828    }
829
830    fn check_doc_search_unbox(&self, span: Span, hir_id: HirId) {
831        let hir::Node::Item(item) = self.tcx.hir_node(hir_id) else {
832            self.dcx().emit_err(diagnostics::DocSearchUnboxInvalid { span });
833            return;
834        };
835        match item.kind {
836            ItemKind::Enum(_, generics, _) | ItemKind::Struct(_, generics, _)
837                if generics.params.len() != 0 => {}
838            ItemKind::Trait { generics, items, .. }
839                if generics.params.len() != 0
840                    || items.iter().any(|item| {
841                        #[allow(non_exhaustive_omitted_patterns)] match self.tcx.def_kind(item.owner_id)
    {
    DefKind::AssocTy => true,
    _ => false,
}matches!(self.tcx.def_kind(item.owner_id), DefKind::AssocTy)
842                    }) => {}
843            ItemKind::TyAlias(_, generics, _) if generics.params.len() != 0 => {}
844            _ => {
845                self.dcx().emit_err(diagnostics::DocSearchUnboxInvalid { span });
846            }
847        }
848    }
849
850    fn check_doc_masked(&self, span: Span, hir_id: HirId, target: Target) {
851        if target != Target::ExternCrate {
852            self.tcx.emit_node_span_lint(
853                INVALID_DOC_ATTRIBUTES,
854                hir_id,
855                span,
856                diagnostics::DocMaskedOnlyExternCrate {
857                    attr_span: span,
858                    item_span: self.tcx.hir_span(hir_id),
859                },
860            );
861            return;
862        }
863
864        if self.tcx.extern_mod_stmt_cnum(hir_id.owner.def_id).is_none() {
865            self.tcx.emit_node_span_lint(
866                INVALID_DOC_ATTRIBUTES,
867                hir_id,
868                span,
869                diagnostics::DocMaskedNotExternCrateSelf {
870                    attr_span: span,
871                    item_span: self.tcx.hir_span(hir_id),
872                },
873            );
874        }
875    }
876
877    /// Runs various checks on `#[doc]` attributes.
878    fn check_doc_attrs(&self, attr: &DocAttribute, hir_id: HirId, target: Target) {
879        let DocAttribute {
880            first_span: _,
881            aliases,
882            // valid pretty much anywhere, not checked here?
883            // FIXME: should we?
884            hidden: _,
885            // already checked in attr_parsing
886            inline: _,
887            // FIXME: currently unchecked
888            cfg: _,
889            // already checked in attr_parsing
890            auto_cfg: _,
891            // already checked in attr_parsing
892            auto_cfg_change: _,
893            fake_variadic,
894            // already checked in attr_parsing
895            keyword: _,
896            masked,
897            // FIXME: currently unchecked
898            notable_trait: _,
899            search_unbox,
900            // already checked in attr_parsing
901            html_favicon_url: _,
902            // already checked in attr_parsing
903            html_logo_url: _,
904            // already checked in attr_parsing
905            html_playground_url: _,
906            // already checked in attr_parsing
907            html_root_url: _,
908            // already checked in attr_parsing
909            html_no_source: _,
910            // already checked in attr_parsing
911            issue_tracker_base_url: _,
912            // already checked in attr_parsing
913            rust_logo: _,
914            // allowed anywhere
915            test_attrs: _,
916            // already checked in attr_parsing
917            no_crate_inject: _,
918            // already checked in attr_parsing
919            attribute: _,
920        } = attr;
921
922        for (alias, span) in aliases {
923            self.check_doc_alias_value(*span, hir_id, target, *alias);
924        }
925
926        if let Some(span) = fake_variadic {
927            self.check_doc_fake_variadic(*span, hir_id);
928        }
929
930        if let Some(span) = search_unbox {
931            self.check_doc_search_unbox(*span, hir_id);
932        }
933
934        if let Some(span) = masked {
935            self.check_doc_masked(*span, hir_id, target);
936        }
937    }
938
939    /// Checks if `#[may_dangle]` is applied to a lifetime or type generic parameter in `Drop` impl.
940    fn check_may_dangle(&self, hir_id: HirId, attr_span: Span) {
941        let hir::Node::GenericParam(
942            param @ GenericParam {
943                kind: hir::GenericParamKind::Lifetime { .. } | hir::GenericParamKind::Type { .. },
944                ..
945            },
946        ) = self.tcx.hir_node(hir_id)
947        else {
948            self.dcx().delayed_bug("Checked in attr parser");
949            return;
950        };
951
952        if #[allow(non_exhaustive_omitted_patterns)] match param.source {
    hir::GenericParamSource::Generics => true,
    _ => false,
}matches!(param.source, hir::GenericParamSource::Generics)
953            && let parent_hir_id = self.tcx.parent_hir_id(hir_id)
954            && let hir::Node::Item(item) = self.tcx.hir_node(parent_hir_id)
955            && let hir::ItemKind::Impl(impl_) = item.kind
956            && let Some(of_trait) = impl_.of_trait
957            && let Some(def_id) = of_trait.trait_ref.trait_def_id()
958            && self.tcx.is_lang_item(def_id, LangItem::Drop)
959        {
960            return;
961        }
962
963        self.dcx().emit_err(diagnostics::InvalidMayDangle { attr_span });
964    }
965
966    /// Checks if the `#[repr]` attributes on `item` are valid.
967    fn check_repr(
968        &self,
969        attrs: &[Attribute],
970        span: Span,
971        target: Target,
972        item: Option<&'tcx Item<'tcx>>,
973        hir_id: HirId,
974    ) {
975        // Extract the names of all repr hints, e.g., [foo, bar, align] for:
976        // ```
977        // #[repr(foo)]
978        // #[repr(bar, align(8))]
979        // ```
980        let (reprs, _first_attr_span) =
981            {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(Repr { reprs, first_span })
                    => {
                    break 'done Some((reprs.as_slice(), Some(*first_span)));
                }
                ::rustc_attr_ir::Attribute::Tool(..) |
                    ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, Repr { reprs, first_span } => (reprs.as_slice(), Some(*first_span)))
982                .unwrap_or((&[], None));
983
984        let mut int_reprs = 0;
985        let mut is_explicit_rust = false;
986        let mut is_c = false;
987        let mut is_simd = false;
988        let mut is_transparent = false;
989
990        for (repr, _repr_span) in reprs {
991            match repr {
992                ReprAttr::ReprRust => {
993                    is_explicit_rust = true;
994                }
995                ReprAttr::ReprC => {
996                    is_c = true;
997                }
998                ReprAttr::ReprAlign(..) => (),
999                ReprAttr::ReprPacked(..) => (),
1000                ReprAttr::ReprSimd => {
1001                    is_simd = true;
1002                }
1003                ReprAttr::ReprTransparent => {
1004                    is_transparent = true;
1005                }
1006                ReprAttr::ReprInt(..) => {
1007                    int_reprs += 1;
1008                }
1009            };
1010        }
1011
1012        if !reprs.is_empty() {
1013            let sorted_reprs = {
1014                let mut to_sort = reprs.to_owned();
1015                to_sort.sort_unstable_by_key(|(attr, span)| (*attr, span.lo_hi()));
1016                to_sort
1017            };
1018
1019            // To collect all duplicates, get subslices where all of the elements of the subslice
1020            // are equal, then filter out all those whose length is not 1. We could return warnings
1021            // for each of them, but that's annoyingly excessive. So we instead collect all spans in
1022            // one big Vec.
1023            let spans: Vec<Span> = sorted_reprs
1024                .chunk_by(|(a, _), (b, _)| a == b)
1025                .map(ToOwned::to_owned)
1026                .filter(|slice| slice.len() != 1)
1027                .flatten()
1028                .map(|(_, span)| span)
1029                .collect();
1030
1031            if !spans.is_empty() {
1032                self.tcx.emit_node_span_lint(
1033                    REPEATED_REPRS,
1034                    hir_id,
1035                    spans,
1036                    diagnostics::RepeatedRepr,
1037                );
1038            }
1039        }
1040
1041        // Just point at all repr hints if there are any incompatibilities.
1042        // This is not ideal, but tracking precisely which ones are at fault is a huge hassle.
1043        let hint_spans = reprs.iter().map(|(_, span)| *span);
1044
1045        // Error on repr(transparent, <anything else>).
1046        if is_transparent && reprs.len() > 1 {
1047            let hint_spans = hint_spans.clone().collect();
1048            self.dcx().emit_err(diagnostics::TransparentIncompatible {
1049                hint_spans,
1050                target: target.to_string(),
1051            });
1052        }
1053        // Error on `#[repr(transparent)]` in combination with
1054        // `#[rustc_pass_indirectly_in_non_rustic_abis]`
1055        if is_transparent
1056            && let Some(&pass_indirectly_span) =
1057                {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(RustcPassIndirectlyInNonRusticAbis(span))
                    => {
                    break 'done Some(span);
                }
                ::rustc_attr_ir::Attribute::Tool(..) |
                    ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, RustcPassIndirectlyInNonRusticAbis(span) => span)
1058        {
1059            self.dcx().emit_err(diagnostics::TransparentIncompatible {
1060                hint_spans: ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [span, pass_indirectly_span]))vec![span, pass_indirectly_span],
1061                target: target.to_string(),
1062            });
1063        }
1064        if is_explicit_rust && (int_reprs > 0 || is_c || is_simd) {
1065            let hint_spans = hint_spans.clone().collect();
1066            self.dcx().emit_err(diagnostics::ReprConflicting { hint_spans });
1067        }
1068        // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8)
1069        if (int_reprs > 1)
1070            || (is_simd && is_c)
1071            || (int_reprs == 1 && is_c && item.is_some_and(is_c_like_enum))
1072        {
1073            self.tcx.emit_node_span_lint(
1074                CONFLICTING_REPR_HINTS,
1075                hir_id,
1076                hint_spans.collect::<Vec<Span>>(),
1077                diagnostics::ReprConflictingLint,
1078            );
1079        }
1080    }
1081
1082    /// A best effort attempt to create an error for a mismatching proc macro signature.
1083    ///
1084    /// If this best effort goes wrong, it will just emit a worse error later (see #102923)
1085    fn check_proc_macro(&self, hir_id: HirId, target: Target, kind: ProcMacroKind) {
1086        if target != Target::Fn {
1087            return;
1088        }
1089
1090        let tcx = self.tcx;
1091        let Some(token_stream_def_id) = tcx.get_diagnostic_item(sym::TokenStream) else {
1092            return;
1093        };
1094        let Some(token_stream) = tcx.type_of(token_stream_def_id).no_bound_vars() else {
1095            return;
1096        };
1097
1098        let def_id = hir_id.expect_owner().def_id;
1099        let param_env = ty::ParamEnv::empty();
1100
1101        let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis());
1102        let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
1103
1104        let span = tcx.def_span(def_id);
1105        let fresh_args = infcx.fresh_args_for_item(span, def_id.to_def_id());
1106        let sig = tcx.liberate_late_bound_regions(
1107            def_id.to_def_id(),
1108            tcx.fn_sig(def_id).instantiate(tcx, fresh_args).skip_norm_wip(),
1109        );
1110
1111        let mut cause = ObligationCause::misc(span, def_id);
1112        let sig = ocx.normalize(&cause, param_env, Unnormalized::new_wip(sig));
1113
1114        // proc macro is not WF.
1115        let errors = ocx.try_evaluate_obligations();
1116        if !errors.no_errors() {
1117            return;
1118        }
1119
1120        let expected_sig = tcx.mk_fn_sig_safe_rust_abi(
1121            std::iter::repeat_n(
1122                token_stream,
1123                match kind {
1124                    ProcMacroKind::Attribute => 2,
1125                    ProcMacroKind::Derive | ProcMacroKind::FunctionLike => 1,
1126                },
1127            ),
1128            token_stream,
1129        );
1130
1131        if let Err(terr) = ocx.eq(&cause, param_env, expected_sig, sig) {
1132            let mut diag = tcx.dcx().create_err(diagnostics::ProcMacroBadSig { span, kind });
1133
1134            let hir_sig = tcx.hir_fn_sig_by_hir_id(hir_id);
1135            if let Some(hir_sig) = hir_sig {
1136                match terr {
1137                    TypeError::ArgumentMutability(idx) | TypeError::ArgumentSorts(_, idx) => {
1138                        if let Some(ty) = hir_sig.decl.inputs.get(idx) {
1139                            diag.span(ty.span);
1140                            cause.span = ty.span;
1141                        } else if idx == hir_sig.decl.inputs.len() {
1142                            let span = hir_sig.decl.output.span();
1143                            diag.span(span);
1144                            cause.span = span;
1145                        }
1146                    }
1147                    TypeError::ArgCount => {
1148                        if let Some(ty) = hir_sig.decl.inputs.get(expected_sig.inputs().len()) {
1149                            diag.span(ty.span);
1150                            cause.span = ty.span;
1151                        }
1152                    }
1153                    TypeError::SafetyMismatch(_) => {
1154                        // FIXME: Would be nice if we had a span here..
1155                    }
1156                    TypeError::AbiMismatch(_) => {
1157                        // FIXME: Would be nice if we had a span here..
1158                    }
1159                    TypeError::VariadicMismatch(_) => {
1160                        // FIXME: Would be nice if we had a span here..
1161                    }
1162                    _ => {}
1163                }
1164            }
1165
1166            infcx.err_ctxt().note_type_err(
1167                &mut diag,
1168                &cause,
1169                None,
1170                Some(param_env.and(ValuePairs::PolySigs(ExpectedFound {
1171                    expected: ty::Binder::dummy(expected_sig),
1172                    found: ty::Binder::dummy(sig),
1173                }))),
1174                terr,
1175                false,
1176                None,
1177            );
1178            diag.emit();
1179            self.abort.set(true);
1180        }
1181
1182        let errors = ocx.evaluate_obligations_error_on_ambiguity();
1183        if let TraitErrors::HasErrors(errors) = errors {
1184            infcx.err_ctxt().report_fulfillment_errors(errors);
1185            self.abort.set(true);
1186        }
1187    }
1188
1189    fn check_rustc_force_inline(&self, hir_id: HirId, attrs: &[Attribute], target: Target) {
1190        if let (Target::Closure, None) = (
1191            target,
1192            {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(Inline(InlineAttr::Force {
                    attr_span, .. }, _)) => {
                    break 'done Some(*attr_span);
                }
                ::rustc_attr_ir::Attribute::Tool(..) |
                    ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span),
1193        ) {
1194            let is_coro = #[allow(non_exhaustive_omitted_patterns)] match self.tcx.hir_expect_expr(hir_id).kind
    {
    hir::ExprKind::Closure(hir::Closure {
        kind: hir::ClosureKind::Coroutine(..) |
            hir::ClosureKind::CoroutineClosure(..), .. }) => true,
    _ => false,
}matches!(
1195                self.tcx.hir_expect_expr(hir_id).kind,
1196                hir::ExprKind::Closure(hir::Closure {
1197                    kind: hir::ClosureKind::Coroutine(..) | hir::ClosureKind::CoroutineClosure(..),
1198                    ..
1199                })
1200            );
1201            let parent_did = self.tcx.hir_get_parent_item(hir_id).to_def_id();
1202            let parent_span = self.tcx.def_span(parent_did);
1203
1204            if let Some(attr_span) = {
    {
        'done:
            {
            for i in
                ::rustc_attr_ir::HasAttrs::get_attrs(parent_did, &self.tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(Inline(InlineAttr::Force {
                        attr_span, .. }, _)) => {
                        break 'done Some(*attr_span);
                    }
                    ::rustc_attr_ir::Attribute::Tool(..) |
                        ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(
1205                self.tcx, parent_did,
1206                Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span
1207            ) && is_coro
1208            {
1209                self.dcx()
1210                    .emit_err(diagnostics::RustcForceInlineCoro { attr_span, span: parent_span });
1211            }
1212        }
1213    }
1214
1215    fn check_mix_no_mangle_export(&self, hir_id: HirId, attrs: &[Attribute]) {
1216        if let Some(export_name_span) =
1217            {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(ExportName {
                    span: export_name_span, .. }) => {
                    break 'done Some(*export_name_span);
                }
                ::rustc_attr_ir::Attribute::Tool(..) |
                    ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, ExportName { span: export_name_span, .. } => *export_name_span)
1218            && let Some(no_mangle_span) =
1219                {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(NoMangle(no_mangle_span))
                    => {
                    break 'done Some(*no_mangle_span);
                }
                ::rustc_attr_ir::Attribute::Tool(..) |
                    ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, NoMangle(no_mangle_span) => *no_mangle_span)
1220        {
1221            let no_mangle_attr = if no_mangle_span.edition() >= Edition::Edition2024 {
1222                "#[unsafe(no_mangle)]"
1223            } else {
1224                "#[no_mangle]"
1225            };
1226            let export_name_attr = if export_name_span.edition() >= Edition::Edition2024 {
1227                "#[unsafe(export_name)]"
1228            } else {
1229                "#[export_name]"
1230            };
1231
1232            self.tcx.emit_node_span_lint(
1233                UNUSED_ATTRIBUTES,
1234                hir_id,
1235                no_mangle_span,
1236                diagnostics::MixedExportNameAndNoMangle {
1237                    no_mangle_span,
1238                    export_name_span,
1239                    no_mangle_attr,
1240                    export_name_attr,
1241                },
1242            );
1243        }
1244    }
1245
1246    fn check_optimize_and_inline(&self, attrs: &[Attribute]) {
1247        if let Some(optimize_span) =
1248            {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(Optimize(OptimizeAttr::DoNotOptimize,
                    span)) => {
                    break 'done Some(*span);
                }
                ::rustc_attr_ir::Attribute::Tool(..) |
                    ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, Optimize(OptimizeAttr::DoNotOptimize, span) => *span)
1249            && let Some((inline_attr, inline_span)) =
1250                {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(Inline(inline_attr, span))
                    => {
                    break 'done Some((inline_attr, *span));
                }
                ::rustc_attr_ir::Attribute::Tool(..) |
                    ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, Inline(inline_attr, span) => (inline_attr, *span))
1251            && inline_attr != &InlineAttr::Never
1252        {
1253            self.dcx()
1254                .emit_err(diagnostics::BothOptimizeNoneAndInline { optimize_span, inline_span });
1255        }
1256    }
1257
1258    fn check_linkage(
1259        &self,
1260        span: Span,
1261        hir_id: HirId,
1262        target: Target,
1263        item: Option<&'tcx Item<'tcx>>,
1264    ) {
1265        // FIXME(eii) Once eii is no longer so experimental, suggest doing
1266        // linkage stuff with externally implementable items instead
1267        match target {
1268            Target::ForeignStatic
1269                if self.tcx.is_mutable_static(hir_id.expect_owner().def_id.into()) =>
1270            {
1271                self.tcx.dcx().emit_err(diagnostics::StaticMutLinkage { span });
1272            }
1273            Target::Fn
1274                if let Item { kind: ItemKind::Fn { sig, .. }, .. } = item.unwrap()
1275                    && #[allow(non_exhaustive_omitted_patterns)] match sig.header.constness {
    Constness::Const { .. } => true,
    _ => false,
}matches!(sig.header.constness, Constness::Const { .. }) =>
1276            {
1277                self.tcx.dcx().emit_err(diagnostics::ConstFnLinkage { span });
1278            }
1279            _ => {}
1280        }
1281    }
1282
1283    fn check_rustc_assert_variance(
1284        &self,
1285        span: Span,
1286        attr_span: Span,
1287        hir_id: HirId,
1288        target: Target,
1289        kind: RustcAssertVarianceKind,
1290    ) {
1291        // If the target is invalid the parser has already emitted an error
1292        if !#[allow(non_exhaustive_omitted_patterns)] match target {
    Target::TypeParam | Target::LifetimeParam | Target::ConstParam => true,
    _ => false,
}matches!(target, Target::TypeParam | Target::LifetimeParam | Target::ConstParam) {
1293            return;
1294        }
1295
1296        let Node::GenericParam(param) = self.tcx.hir_node(hir_id) else { return };
1297        let owner = hir_id.owner.to_def_id();
1298        let variances = self.tcx.variances_of(owner);
1299        let generics = self.tcx.generics_of(owner);
1300
1301        let variance = generics
1302            .own_params
1303            .iter()
1304            .zip(variances.iter())
1305            .filter(|(other_param, _)| other_param.def_id == param.def_id.to_def_id())
1306            .map(|(_, variance)| variance)
1307            .nth(0)
1308            .expect("generic parameter should have variance");
1309
1310        match (kind, variance) {
1311            (RustcAssertVarianceKind::Covariant, Variance::Covariant) => {}
1312            (RustcAssertVarianceKind::Invariant, Variance::Invariant) => {}
1313            (RustcAssertVarianceKind::Contravariant, Variance::Contravariant) => {}
1314            (RustcAssertVarianceKind::Bivariant, Variance::Bivariant) => {}
1315            (asserted, actual) => {
1316                let expected_variance = match asserted {
1317                    RustcAssertVarianceKind::Covariant => sym::covariant,
1318                    RustcAssertVarianceKind::Invariant => sym::invariant,
1319                    RustcAssertVarianceKind::Contravariant => sym::contravariant,
1320                    RustcAssertVarianceKind::Bivariant => sym::bivariant,
1321                };
1322
1323                let actual_variance = match actual {
1324                    Variance::Covariant => sym::covariant,
1325                    Variance::Invariant => sym::invariant,
1326                    Variance::Contravariant => sym::contravariant,
1327                    Variance::Bivariant => sym::bivariant,
1328                };
1329
1330                let item_ident = self.tcx.item_ident(owner);
1331
1332                let note = diagnostics::RustcAssertVarianceFailedNote { span: attr_span };
1333                self.tcx.dcx().emit_err(diagnostics::RustcAssertVarianceFailed {
1334                    item_span: self.tcx.def_span(owner),
1335                    note,
1336                    param_ident: param.name.ident(),
1337                    param_span: span,
1338                    item_ident,
1339                    expected_variance,
1340                    actual_variance,
1341                });
1342            }
1343        }
1344    }
1345
1346    fn check_lint_check(&self, hir_id: HirId, lints: &[LintCheck]) {
1347        for LintCheck { lint_name, lint_span, .. } in lints {
1348            if lint_name.is(sym::dead_code_pub_in_binary) {
1349                if !self.tcx.crate_types().contains(&CrateType::Executable) {
1350                    self.tcx.emit_node_span_lint(
1351                        UNUSED_ATTRIBUTES,
1352                        hir_id,
1353                        *lint_span,
1354                        diagnostics::Unused {
1355                            attr_span: *lint_span,
1356                            note: diagnostics::UnusedNote::NoEffectDeadCodePubInBinary,
1357                        },
1358                    );
1359                }
1360            }
1361
1362            if lint_name.is(sym::linker_messages) | lint_name.is(sym::linker_info) {
1363                if hir_id == CRATE_HIR_ID
1364                    && self
1365                        .tcx
1366                        .crate_types()
1367                        .iter()
1368                        .all(|kind| #[allow(non_exhaustive_omitted_patterns)] match kind {
    CrateType::Rlib | CrateType::StaticLib => true,
    _ => false,
}matches!(kind, CrateType::Rlib | CrateType::StaticLib))
1369                {
1370                    self.tcx.emit_node_span_lint(
1371                        UNUSED_ATTRIBUTES,
1372                        hir_id,
1373                        *lint_span,
1374                        diagnostics::Unused {
1375                            attr_span: *lint_span,
1376                            note: diagnostics::UnusedNote::LinkerMessagesBinaryCrateOnly,
1377                        },
1378                    );
1379                }
1380            }
1381        }
1382    }
1383}
1384
1385impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> {
1386    type NestedFilter = nested_filter::OnlyBodies;
1387
1388    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
1389        self.tcx
1390    }
1391
1392    fn visit_item(&mut self, item: &'tcx Item<'tcx>) {
1393        // Historically we've run more checks on non-exported than exported macros,
1394        // so this lets us continue to run them while maintaining backwards compatibility.
1395        // In the long run, the checks should be harmonized.
1396        if let ItemKind::Macro(_, macro_def, _) = item.kind {
1397            let def_id = item.owner_id.to_def_id();
1398            if macro_def.macro_rules && !{
        {
            'done:
                {
                for i in
                    ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &self.tcx) {
                    #[allow(unused_imports)]
                    use ::rustc_attr_ir::AttributeKind::*;
                    let i: &::rustc_attr_ir::Attribute = i;
                    match i {
                        ::rustc_attr_ir::Attribute::Parsed(MacroExport { .. }) => {
                            break 'done Some(());
                        }
                        ::rustc_attr_ir::Attribute::Tool(..) |
                            ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(self.tcx, def_id, MacroExport { .. }) {
1399                check_non_exported_macro_for_invalid_attrs(self.tcx, item);
1400            }
1401        }
1402
1403        let target = Target::from(item);
1404        self.check_attributes(item.hir_id(), item.span, target, Some(item));
1405        intravisit::walk_item(self, item)
1406    }
1407
1408    fn visit_where_predicate(&mut self, where_predicate: &'tcx hir::WherePredicate<'tcx>) {
1409        self.check_attributes(
1410            where_predicate.hir_id,
1411            where_predicate.span,
1412            Target::WherePredicate,
1413            None,
1414        );
1415        intravisit::walk_where_predicate(self, where_predicate)
1416    }
1417
1418    fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
1419        let target = Target::from(generic_param);
1420        self.check_attributes(generic_param.hir_id, generic_param.span, target, None);
1421        intravisit::walk_generic_param(self, generic_param)
1422    }
1423
1424    fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
1425        let target = Target::from(trait_item);
1426        self.check_attributes(trait_item.hir_id(), trait_item.span, target, None);
1427        intravisit::walk_trait_item(self, trait_item)
1428    }
1429
1430    fn visit_field_def(&mut self, struct_field: &'tcx hir::FieldDef<'tcx>) {
1431        self.check_attributes(struct_field.hir_id, struct_field.span, Target::Field, None);
1432        intravisit::walk_field_def(self, struct_field);
1433    }
1434
1435    fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) {
1436        self.check_attributes(arm.hir_id, arm.span, Target::Arm, None);
1437        intravisit::walk_arm(self, arm);
1438    }
1439
1440    fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) {
1441        let target = Target::from(f_item);
1442        self.check_attributes(f_item.hir_id(), f_item.span, target, None);
1443        intravisit::walk_foreign_item(self, f_item)
1444    }
1445
1446    fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem<'tcx>) {
1447        let target = target_from_impl_item(self.tcx, impl_item);
1448        self.check_attributes(impl_item.hir_id(), impl_item.span, target, None);
1449        intravisit::walk_impl_item(self, impl_item)
1450    }
1451
1452    fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt<'tcx>) {
1453        // When checking statements ignore expressions, they will be checked later.
1454        if let hir::StmtKind::Let(l) = stmt.kind {
1455            self.check_attributes(l.hir_id, stmt.span, Target::Statement, None);
1456        }
1457        intravisit::walk_stmt(self, stmt)
1458    }
1459
1460    fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) {
1461        let target = match expr.kind {
1462            hir::ExprKind::Closure { .. } => Target::Closure,
1463            _ => Target::Expression,
1464        };
1465
1466        self.check_attributes(expr.hir_id, expr.span, target, None);
1467        intravisit::walk_expr(self, expr)
1468    }
1469
1470    fn visit_expr_field(&mut self, field: &'tcx hir::ExprField<'tcx>) {
1471        self.check_attributes(field.hir_id, field.span, Target::ExprField, None);
1472        intravisit::walk_expr_field(self, field)
1473    }
1474
1475    fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) {
1476        self.check_attributes(variant.hir_id, variant.span, Target::Variant, None);
1477        intravisit::walk_variant(self, variant)
1478    }
1479
1480    fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) {
1481        self.check_attributes(param.hir_id, param.span, Target::Param, None);
1482
1483        intravisit::walk_param(self, param);
1484    }
1485
1486    fn visit_pat_field(&mut self, field: &'tcx hir::PatField<'tcx>) {
1487        self.check_attributes(field.hir_id, field.span, Target::PatField, None);
1488        intravisit::walk_pat_field(self, field);
1489    }
1490}
1491
1492fn is_c_like_enum(item: &Item<'_>) -> bool {
1493    if let ItemKind::Enum(_, _, ref def) = item.kind {
1494        for variant in def.variants {
1495            match variant.data {
1496                hir::VariantData::Unit(..) => { /* continue */ }
1497                _ => return false,
1498            }
1499        }
1500        true
1501    } else {
1502        false
1503    }
1504}
1505
1506fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) {
1507    let attrs = tcx.hir_attrs(item.hir_id());
1508
1509    if let Some(attr_span) =
1510        {
    'done:
        {
        for i in attrs {
            #[allow(unused_imports)]
            use ::rustc_attr_ir::AttributeKind::*;
            let i: &::rustc_attr_ir::Attribute = i;
            match i {
                ::rustc_attr_ir::Attribute::Parsed(Inline(i, span)) if
                    !#[allow(non_exhaustive_omitted_patterns)] match i {
                            InlineAttr::Force { .. } => true,
                            _ => false,
                        } => {
                    break 'done Some(*span);
                }
                ::rustc_attr_ir::Attribute::Tool(..) |
                    ::rustc_attr_ir::Attribute::DeriveHelper(..) =>
                    {}
                    #[deny(unreachable_patterns)]
                    _ => {}
            }
        }
        None
    }
}find_attr!(attrs, Inline(i, span) if !matches!(i, InlineAttr::Force{..}) => *span)
1511    {
1512        tcx.dcx().emit_err(diagnostics::NonExportedMacroInvalidAttrs { attr_span });
1513    }
1514}
1515
1516fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalModId) {
1517    let check_attr_visitor = &mut CheckAttrVisitor { tcx, abort: Cell::new(false) };
1518    tcx.hir_visit_item_likes_in_module(module_def_id, check_attr_visitor);
1519    if module_def_id.to_local_def_id().is_top_level_module() {
1520        check_attr_visitor.check_attributes(CRATE_HIR_ID, DUMMY_SP, Target::Mod, None);
1521    }
1522    if check_attr_visitor.abort.get() {
1523        tcx.dcx().abort_if_errors()
1524    }
1525}
1526
1527pub(crate) fn provide(providers: &mut Providers) {
1528    *providers = Providers { check_mod_attrs, ..*providers };
1529}
1530
1531fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
1532    #[allow(non_exhaustive_omitted_patterns)] match &self_ty.kind {
    hir::TyKind::Tup([_]) => true,
    _ => false,
}matches!(&self_ty.kind, hir::TyKind::Tup([_]))
1533        || if let hir::TyKind::FnPtr(fn_ptr_ty) = &self_ty.kind {
1534            fn_ptr_ty.decl.inputs.len() == 1
1535        } else {
1536            false
1537        }
1538        || (if let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = &self_ty.kind
1539            && let Some(&[hir::GenericArg::Type(ty)]) =
1540                path.segments.last().map(|last| last.args().args)
1541        {
1542            doc_fake_variadic_is_allowed_self_ty(ty.as_unambig_ty())
1543        } else {
1544            false
1545        })
1546}