Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
215 changes: 215 additions & 0 deletions compiler/rustc_attr_ir/src/encode_cross_crate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`].

@JonathanBrouwer JonathanBrouwer Sep 18, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I'm not a big fan that we are duplicating this logic here.
The effort done to ensure these stay in sync is good, but it would be better not do to this at all.
Can we re-implement instantiation_mode using this method instead, and then remove CodegenFnAttrs::contains_extern_indicator?

View changes since the review

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can do that, we can re-consider if we need to match exhaustively here. It might be nice to still do, but it's a lot less valuable then

///
/// [`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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down
27 changes: 23 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/inline.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 });
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
Expand Down
8 changes: 4 additions & 4 deletions compiler/rustc_attr_parsing/src/attributes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`].
Expand Down Expand Up @@ -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>);
Expand All @@ -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)
}
}
Expand Down Expand Up @@ -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`].
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_attr_parsing/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Loading
Loading