rust-lang/rust · #162683

Use attribute parser for `#[inline()]` attribute check

obeis · merged Sep 28, 202617 files · 272 + / 68 −
compiler/rustc_attr_ir/src/encode_cross_crate.rs215 + / 0 −
@@ -212,4 +212,219 @@ impl AttributeKind {             // tidy-alphabetical-end         }     }++    /// Whether this attribute is an extern indicator.+    ///+    /// Must stay in sync with [`CodegenFnAttrs::contains_extern_indicator`].+    ///+    /// [`CodegenFnAttrs::contains_extern_indicator`]: ../rustc_middle/middle/codegen_fn_attrs/struct.CodegenFnAttrs.html#method.contains_extern_indicator+    pub fn is_extern_indicator(&self) -> bool {+        use AttributeKind::*;++        match self {+            // tidy-alphabetical-start+            AllowInternalUnsafe(..) => false,+            AllowInternalUnstable(..) => false,+            AlwaysGca => false,+            AutomaticallyDerived => false,+            CfgAttrTrace(..) => false,+            CfgTrace(..) => false,+            CfiEncoding { .. } => false,+            Cold => false,+            CollapseDebugInfo(..) => false,+            CompilerBuiltins => false,+            ConstContinue(..) => false,+            Coroutine => false,+            Coverage(..) => false,+            CrateName { .. } => false,+            CrateType(_) => false,+            CustomMir(_, _) => false,+            DebuggerVisualizer(..) => false,+            DefaultLibAllocator => false,+            Deprecated { .. } => false,+            DoNotRecommend => false,+            Doc(_) => false,+            DocComment { .. } => false,+            EiiDeclaration(_) => false,+            EiiImpl(..) => true,+            ExportName { .. } => true,+            ExportStable => false,+            Feature(..) => false,+            FfiConst => false,+            FfiPure(..) => false,+            Fundamental { .. } => false,+            Ignore { .. } => false,+            Inline(..) => false,+            InstructionSet(..) => false,+            InstrumentFn(..) => false,+            Lang(item) => item.link_name().is_some(),+            Link(..) => false,+            LinkName { .. } => false,+            LinkOrdinal { .. } => false,+            LinkSection { .. } => false,+            Linkage(linkage, _) => match *linkage {+                crate::Linkage::Internal => false,+                crate::Linkage::AvailableExternally+                | crate::Linkage::Common+                | crate::Linkage::External+                | crate::Linkage::ExternalWeak+                | crate::Linkage::LinkOnceAny+                | crate::Linkage::LinkOnceODR+                | crate::Linkage::WeakAny+                | crate::Linkage::WeakODR => true,+            },+            LoopMatch(..) => false,+            MacroEscape => false,+            MacroExport { .. } => false,+            MacroUse { .. } => false,+            Marker => false,+            MayDangle(..) => false,+            MoveSizeLimit { .. } => false,+            MustNotSupend { .. } => false,+            MustUse { .. } => false,+            Naked(..) => false,+            NeedsAllocator => false,+            NeedsPanicRuntime => false,+            NoBuiltins => false,+            NoCore => false,+            NoImplicitPrelude => false,+            NoLink => false,+            NoMain => false,+            NoMangle(..) => true,+            NoStd => false,+            NonExhaustive(..) => false,+            OnConst { .. } => false,+            OnMove { .. } => false,+            OnTypeError { .. } => false,+            OnUnimplemented { .. } => false,+            OnUnknown { .. } => false,+            OnUnmatchedArgs { .. } => false,+            Opaque => false,+            Optimize(..) => false,+            PanicRuntime => false,+            PatchableFunctionEntry { .. } => false,+            Path(..) => false,+            PatternComplexityLimit { .. } => false,+            PinV2(..) => false,+            PreludeImport => false,+            ProcMacro => false,+            ProcMacroAttribute => false,+            ProcMacroDerive { .. } => false,+            ProfilerRuntime => false,+            RecursionLimit { .. } => false,+            ReexportTestHarnessMain(..) => false,+            RegisterTool { .. } => false,+            Repr { .. } => false,+            RustcAbi { .. } => false,+            RustcAlign { .. } => false,+            RustcAllocator => false,+            RustcAllocatorZeroed => false,+            RustcAllocatorZeroedVariant { .. } => false,+            RustcAllowConstFnUnstable(..) => false,+            RustcAllowIncoherentImpl(..) => false,+            RustcAllowLifetimeDependentSpecialization => false,+            RustcAsPtr => false,+            RustcAutodiff(..) => false,+            RustcBodyStability { .. } => false,+            RustcBuiltinMacro { .. } => false,+            RustcCanonicalSymbol => false,+            RustcCaptureAnalysis => false,+            RustcCguTestAttr { .. } => false,+            RustcClean { .. } => false,+            RustcCoherenceIsCore => false,+            RustcCoinductive => false,+            RustcComptime(..) => false,+            RustcConfusables { .. } => false,+            RustcConstStability { .. } => false,+            RustcConstStableIndirect => false,+            RustcConversionSuggestion => false,+            RustcDeallocator => false,+            RustcDelayedBugFromInsideQuery => false,+            RustcDenyExplicitImpl => false,+            RustcDeprecatedSafe2024 { .. } => false,+            RustcDiagnosticItem(..) => false,+            RustcDoNotConstCheck => false,+            RustcDocPrimitive(..) => false,+            RustcDummy => false,+            RustcDumpClauses => false,+            RustcDumpDefParents => false,+            RustcDumpDefPath(..) => false,+            RustcDumpGenerics => false,+            RustcDumpHiddenTypeOfOpaques => false,+            RustcDumpInferredOutlives => false,+            RustcDumpItemBounds => false,+            RustcDumpLayout(..) => false,+            RustcDumpObjectLifetimeDefaults => false,+            RustcDumpSymbolName(..) => false,+            RustcDumpUserArgs => false,+            RustcDumpVariances => false,+            RustcDumpVariancesOfOpaques => false,+            RustcDumpVtable(..) => false,+            RustcDynIncompatibleTrait(..) => false,+            RustcEffectiveVisibility => false,+            RustcEiiForeignItem => true,+            RustcEvaluateWhereClauses => false,+            RustcHasIncoherentInherentImpls => false,+            RustcIfThisChanged(..) => false,+            RustcInheritOverflowChecks => false,+            RustcInsignificantDtor => false,+            RustcIntrinsic => false,+            RustcIntrinsicConstStableIndirect => false,+            RustcLegacyConstGenerics { .. } => false,+            RustcLintOptDenyFieldAccess { .. } => false,+            RustcLintOptTy => false,+            RustcLintQueryInstability => false,+            RustcLintUntrackedQueryInformation => false,+            RustcMacroTransparency(..) => false,+            RustcMain => false,+            RustcMir(..) => false,+            RustcMustImplementOneOf { .. } => false,+            RustcMustMatchExhaustively(..) => false,+            RustcNeverReturnsNullPtr => false,+            RustcNoImplicitAutorefs => false,+            RustcNoImplicitBounds => false,+            RustcNoMirInline => false,+            RustcNoWritable => false,+            RustcNonConstTraitMethod => false,+            RustcNonnullOptimizationGuaranteed => false,+            RustcNounwind => false,+            RustcObjcClass { .. } => false,+            RustcObjcSelector { .. } => false,+            RustcOffloadKernel => true,+            RustcPanicsWhenZero => false,+            RustcParenSugar => false,+            RustcPassByValue => false,+            RustcPassIndirectlyInNonRusticAbis(..) => false,+            RustcPreserveUbChecks => false,+            RustcProcMacroDecls => false,+            RustcPubTransparent(..) => false,+            RustcReallocator => false,+            RustcRegions => false,+            RustcScalableVector { .. } => false,+            RustcShouldNotBeCalledOnConstItems => false,+            RustcSimdMonomorphizeLaneLimit(..) => false,+            RustcSkipDuringMethodDispatch { .. } => false,+            RustcSpecializationTrait => false,+            RustcStdInternalSymbol => true,+            RustcStrictCoherence(..) => false,+            RustcTestMarker(..) => false,+            RustcThenThisWouldNeed(..) => false,+            RustcTrivialFieldReads => false,+            Sanitize { .. } => false,+            ShouldPanic { .. } => false,+            Splat(..) => false,+            Stability { .. } => false,+            TargetFeature { .. } => false,+            TestRunner(..) => false,+            ThreadLocal => false,+            TrackCaller(..) => false,+            TypeLengthLimit { .. } => false,+            Unroll(..) => false,+            UnstableFeatureBound(..) => false,+            UnstableRemoved(..) => false,+            Used { .. } => false,+            WindowsSubsystem(..) => false,+            // tidy-alphabetical-end+        }+    } }
compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs1 + / 1 −
@@ -30,7 +30,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser {             .zip(iter::repeat(cx.attr_span))     } -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         check_macro_only(cx, attr_span);     } }
compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs2 + / 2 −
@@ -349,7 +349,7 @@ impl NoArgsAttributeParser for TrackCallerParser {     const STABILITY: AttributeStability = AttributeStability::Stable;     const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller; -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         match cx.target {             Target::Fn => {                 // `#[track_caller]` is not valid on weak lang items because they are called via@@ -571,7 +571,7 @@ impl CombineAttributeParser for TargetFeatureParser {         parse_tf_attribute(cx, args)     } -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         // `#[target_feature]` is incompatible with lang item functions,         // except on WASM where calling target-feature functions is safe (see #84988).         if !cx.sess().target.is_like_wasm && !cx.sess().opts.actually_rustdoc {
compiler/rustc_attr_parsing/src/attributes/inline.rs23 + / 4 −
@@ -1,9 +1,9 @@-use rustc_attr_ir::{AttributeKind, InlineAttr, find_attr};+use rustc_attr_ir::{Attribute, AttributeKind, InlineAttr, find_attr}; use rustc_feature::AttributeStability;-use rustc_lint_defs::builtin::ILL_FORMED_ATTRIBUTE_INPUT;+use rustc_lint_defs::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNUSED_ATTRIBUTES};  use super::prelude::*;-use crate::diagnostics::InlineForceInlineConflict;+use crate::diagnostics::{InlineForceInlineConflict, InlineIgnoredForExported};  pub(crate) struct InlineParser; @@ -59,6 +59,25 @@ impl SingleAttributeParser for InlineParser {             }         }     }++    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {+        let exported = cx.parsed_attrs.iter().any(|attr| {+            let Attribute::Parsed(kind) = attr else { return false };+            kind.is_extern_indicator()+        });+        if matches!(+            cx.target,+            Target::Fn+                | Target::Closure+                | Target::Method(+                    MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent,+                )+        ) && !find_attr!(cx.parsed_attrs, Inline(InlineAttr::Never, _))+            && exported+        {+            cx.emit_lint(UNUSED_ATTRIBUTES, InlineIgnoredForExported, attr_span);+        }+    } }  pub(crate) struct RustcForceInlineParser;@@ -94,7 +113,7 @@ impl SingleAttributeParser for RustcForceInlineParser {         ))     } -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         let Some(inline_span) = find_attr!(cx.parsed_attrs, Inline(attr, span) if !matches!(attr, InlineAttr::Force { .. }) => span)         else {             return;
compiler/rustc_attr_parsing/src/attributes/link_attrs.rs1 + / 1 −
@@ -584,7 +584,7 @@ impl NoArgsAttributeParser for FfiPureParser {     const STABILITY: AttributeStability = unstable!(ffi_pure);     const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure; -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         // `#[ffi_const]` functions cannot be `#[ffi_pure]`.         if cx.all_attrs.iter().any(|a| a.word_is(sym::ffi_const)) {             cx.emit_err(BothFfiConstAndPure { attr_span });
compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs1 + / 1 −
@@ -29,7 +29,7 @@ impl NoArgsAttributeParser for RustcPubTransparentParser {     const STABILITY: AttributeStability = unstable!(rustc_attrs);     const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPubTransparent; -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         // `#[rustc_pub_transparent]` may only be applied to `#[repr(transparent)]` types.         let is_transparent = find_attr!(             cx.parsed_attrs,
compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs1 + / 1 −
@@ -140,7 +140,7 @@ impl NoArgsAttributeParser for AllowInternalUnsafeParser {     const STABILITY: AttributeStability = unstable!(allow_internal_unsafe);     const CREATE: fn(Span) -> AttributeKind = |span| AttributeKind::AllowInternalUnsafe(span); -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         check_macro_only(cx, attr_span);     } }
compiler/rustc_attr_parsing/src/attributes/mod.rs4 + / 4 −
@@ -169,7 +169,7 @@ pub(crate) trait SingleAttributeParser: 'static {     /// combinations. `attr_span` is the span of this attribute.     ///     /// Defaults to a no-op.-    fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}+    fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {} }  /// Use in combination with [`SingleAttributeParser`].@@ -287,7 +287,7 @@ pub(crate) trait NoArgsAttributeParser: 'static {     /// `attr_span` is the span of this attribute.     ///     /// Defaults to a no-op.-    fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}+    fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {} }  pub(crate) struct WithoutArgs<T: NoArgsAttributeParser>(PhantomData<T>);@@ -311,7 +311,7 @@ impl<T: NoArgsAttributeParser> SingleAttributeParser for WithoutArgs<T> {         Some(T::CREATE(cx.attr_span))     } -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         T::finalize_check(cx, attr_span)     } }@@ -355,7 +355,7 @@ pub(crate) trait CombineAttributeParser: 'static {     /// `attr_span` is the span of the first attribute that was encountered.     ///     /// Defaults to a no-op.-    fn finalize_check(_cx: &FinalizeCheckContext<'_, '_>, _attr_span: Span) {}+    fn finalize_check(_cx: &mut FinalizeCheckContext<'_, '_>, _attr_span: Span) {} }  /// Use in combination with [`CombineAttributeParser`].
compiler/rustc_attr_parsing/src/attributes/non_exhaustive.rs1 + / 1 −
@@ -21,7 +21,7 @@ impl NoArgsAttributeParser for NonExhaustiveParser {     const STABILITY: AttributeStability = AttributeStability::Stable;     const CREATE: fn(Span) -> AttributeKind = AttributeKind::NonExhaustive; -    fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {+    fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {         if cx.target != Target::Struct {             return;         }
compiler/rustc_attr_parsing/src/context.rs1 + / 1 −
@@ -102,7 +102,7 @@ pub(crate) type FinalizeFn = fn(&mut FinalizeContext<'_, '_>) -> FinalizeOutput; /// finalized, so it can inspect the fully parsed attributes via /// [`FinalizeCheckContext::parsed_attrs`]. The [`Span`] is the span of the attribute the /// check is associated with, used for diagnostics.-pub(crate) type FinalizeCheckFn = fn(&FinalizeCheckContext<'_, '_>, Span);+pub(crate) type FinalizeCheckFn = fn(&mut FinalizeCheckContext<'_, '_>, Span);  /// The result of finalizing a single attribute parser. pub(crate) struct FinalizeOutput {
compiler/rustc_attr_parsing/src/diagnostics.rs7 + / 0 −
@@ -896,6 +896,13 @@ pub(crate) struct InlineForceInlineConflict {     pub inline_span: Span, } +#[derive(Diagnostic)]+#[diag("`#[inline]` is ignored on externally exported functions")]+#[help(+    "externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`"+)]+pub(crate) struct InlineIgnoredForExported;+ #[derive(Diagnostic)] #[diag("`#[ffi_const]` function cannot be `#[ffi_pure]`", code = E0757)] pub(crate) struct BothFfiConstAndPure {
compiler/rustc_attr_parsing/src/interface.rs1 + / 1 −
@@ -512,7 +512,7 @@ impl<'sess> AttributeParser<'sess> {         // inspect the fully parsed attributes via `FinalizeCheckContext::parsed_attrs`.         for (check, attr_span) in deferred_checks {             check(-                &FinalizeCheckContext {+                &mut FinalizeCheckContext {                     shared: SharedContext {                         cx: self,                         target_span,
compiler/rustc_middle/src/middle/codegen_fn_attrs.rs3 + / 1 −
@@ -270,7 +270,9 @@ impl CodegenFnAttrs {     /// * `#[export_name(...)]` is present     /// * `#[linkage]` is present     ///-    /// Keep this in sync with the logic for the unused_attributes for `#[inline]` lint.+    /// Keep this in sync with [`AttributeKind::is_extern_indicator`].+    ///+    /// [`AttributeKind::is_extern_indicator`]: rustc_attr_ir::AttributeKind::is_extern_indicator     pub fn contains_extern_indicator(&self) -> bool {         if self.flags.contains(CodegenFnAttrFlags::FOREIGN_ITEM) {             return false;
compiler/rustc_passes/src/check_attr.rs1 + / 33 −
@@ -199,10 +199,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {             AttributeKind::ProcMacroDerive { .. } => {                 self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)             }-            AttributeKind::Inline(InlineAttr::Force { .. }, ..) => {} // handled separately below-            AttributeKind::Inline(kind, attr_span) => {-                self.check_inline(hir_id, *attr_span, kind, target)-            }             AttributeKind::RustcAllowConstFnUnstable(_, first_span) => {                 self.check_rustc_allow_const_fn_unstable(hir_id, *first_span, span, target)             }@@ -268,6 +264,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {             AttributeKind::FfiPure(..) => (),             AttributeKind::Fundamental => (),             AttributeKind::Ignore { .. } => (),+            AttributeKind::Inline(..) => (),             AttributeKind::InstructionSet(..) => (),             AttributeKind::InstrumentFn(..) => (),             AttributeKind::Lang(..) => (),@@ -740,35 +737,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {         }     } -    /// Checks if an `#[inline]` is applied to a function or a closure.-    fn check_inline(&self, hir_id: HirId, attr_span: Span, kind: &InlineAttr, target: Target) {-        match target {-            Target::Fn-            | Target::Closure-            | Target::Method(-                MethodKind::Trait { body: true } | MethodKind::TraitImpl | MethodKind::Inherent,-            ) => {-                // `#[inline]` is ignored if the symbol must be codegened upstream because it's exported.-                if let Some(did) = hir_id.as_owner()-                    && self.tcx.def_kind(did).has_codegen_attrs()-                    && kind != &InlineAttr::Never-                {-                    let attrs = self.tcx.codegen_fn_attrs(did);-                    // Not checking naked as `#[inline]` is forbidden for naked functions anyways.-                    if attrs.contains_extern_indicator() {-                        self.tcx.emit_node_span_lint(-                            UNUSED_ATTRIBUTES,-                            hir_id,-                            attr_span,-                            diagnostics::InlineIgnoredForExported,-                        );-                    }-                }-            }-            _ => {}-        }-    }-     /// Checks if `#[naked]` is applied to a function definition.     fn check_naked(&self, hir_id: HirId, target: Target) {         match target {
compiler/rustc_passes/src/diagnostics.rs0 + / 7 −
@@ -562,13 +562,6 @@ pub(crate) struct UselessAssignment<'a> {     pub ty: Ty<'a>, } -#[derive(Diagnostic)]-#[diag("`#[inline]` is ignored on externally exported functions")]-#[help(-    "externally exported functions are functions with `#[no_mangle]`, `#[export_name]`, or `#[linkage]`"-)]-pub(crate) struct InlineIgnoredForExported;- #[derive(Diagnostic)] #[diag("transparent {$target} cannot have other repr hints", code = E0692)] pub(crate) struct TransparentIncompatible {
tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.runtime-optimized.after.panic-abort.mir2 + / 2 −
@@ -21,7 +21,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {             debug x => _34;         }         scope 18 (inlined <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next) {-            let mut _22: std::option::Option<std::convert::Infallible>;+            let mut _22: std::option::Option<!>;             let mut _27: std::option::Option<&T>;             let mut _30: (usize, bool);             let mut _31: (usize, &T);@@ -32,7 +32,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () {             }             scope 20 {                 scope 21 {-                    scope 27 (inlined <Option<(usize, &T)> as FromResidual<Option<Infallible>>>::from_residual) {+                    scope 27 (inlined <Option<(usize, &T)> as FromResidual<Option<!>>>::from_residual) {                         let mut _21: isize;                         let mut _23: bool;                     }
tests/ui/target-feature/invalid-attribute.stderr8 + / 8 −
@@ -160,14 +160,6 @@ LL |     #[target_feature(enable = "sse2")]    |    = help: the `target_feature` attribute can be applied to functions and methods -error: cannot use `#[inline(always)]` with `#[target_feature]`-  --> $DIR/invalid-attribute.rs:69:1-   |-LL | #[inline(always)]-   | ^^^^^^^^^^^^^^^^^-   |-   = note: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574- error: the feature named `foo` is not valid for this target   --> $DIR/invalid-attribute.rs:27:18    |@@ -176,6 +168,14 @@ LL | #[target_feature(enable = "foo")]    |    = help: valid names are: `fma`, `xop`, `adx`, `aes`, and `avx` and X more +error: cannot use `#[inline(always)]` with `#[target_feature]`+  --> $DIR/invalid-attribute.rs:69:1+   |+LL | #[inline(always)]+   | ^^^^^^^^^^^^^^^^^+   |+   = note: See this issue for full discussion: https://github.com/rust-lang/rust/issues/145574+ error[E0046]: not all trait items implemented, missing: `foo`   --> $DIR/invalid-attribute.rs:81:1    |