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