rust-lang/rust · #162683
Use attribute parser for `#[inline()]` attribute check
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 |