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