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
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
let old_attrs =
self.curr_owner.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]);
let new_attrs = self
.lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e))
.lower_attrs_vec(&e.attrs, e.span, ex.hir_id, Target::from_expr(e), None)
.into_iter()
.chain(old_attrs.iter().cloned());
let new_attrs = &*self.arena.alloc_from_iter(new_attrs);
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,21 @@ impl<'hir> LoweringContext<'_, 'hir> {
let hir_id: HirId = owner_id.into();
let vis_span = self.lower_span(i.vis.span);

let foreign_mod_abi = if let ItemKind::ForeignMod(fm) = &i.kind {
Some(fm.abi.map_or(ExternAbi::FALLBACK, |abi| {
abi.symbol_unescaped.as_str().parse().unwrap_or(ExternAbi::Rust)
}))
} else {
None
};

let extra_hir_attributes = self.generate_extra_attrs_for_item_kind(i.id, &i.kind);
let attrs = self.lower_attrs_with_extra(
hir_id,
&i.attrs,
i.span,
Target::from_ast_item(i),
foreign_mod_abi,
&extra_hir_attributes,
);

Expand Down
15 changes: 12 additions & 3 deletions compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
use std::mem;
use std::sync::Arc;

use rustc_abi::ExternAbi;
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::node_id::NodeMap;
use rustc_ast::visit::{self, Visitor};
Expand Down Expand Up @@ -1174,7 +1175,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
target_span: Span,
target: Target,
) -> &'hir [hir::Attribute] {
self.lower_attrs_with_extra(id, attrs, target_span, target, &[])
self.lower_attrs_with_extra(id, attrs, target_span, target, None, &[])
}

fn lower_attrs_with_extra(
Expand All @@ -1183,13 +1184,19 @@ impl<'hir> LoweringContext<'_, 'hir> {
attrs: &[Attribute],
target_span: Span,
target: Target,
foreign_mod_abi: Option<ExternAbi>,

@JonathanBrouwer JonathanBrouwer Sep 6, 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.

I'm not sure how I like the approach of this approach of passing such specific information into this function. Specifically, I think that approach that this PR takes might also work for this attribute and this doesn't require that. It might make more sense to wait to see for what happens to that PR first

View changes since the review

extra_hir_attributes: &[hir::Attribute],
) -> &'hir [hir::Attribute] {
if attrs.is_empty() && extra_hir_attributes.is_empty() {
&[]
} else {
let mut lowered_attrs =
self.lower_attrs_vec(attrs, self.lower_span(target_span), id, target);
let mut lowered_attrs = self.lower_attrs_vec(
attrs,
self.lower_span(target_span),
id,
target,
foreign_mod_abi,
);
lowered_attrs.extend(extra_hir_attributes.iter().cloned());

assert_eq!(id.owner, self.curr_owner.owner_id);
Expand All @@ -1216,12 +1223,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
target_span: Span,
target_hir_id: HirId,
target: Target,
foreign_mod_abi: Option<ExternAbi>,
) -> Vec<hir::Attribute> {
let l = self.span_lowerer();
self.attribute_parser.parse_attribute_list(
attrs,
target_span,
target,
foreign_mod_abi,
|s| l.lower(s),
|lint_id, span, kind| {
self.curr_owner.delayed_lints.push(DelayedLint {
Expand Down
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
2 changes: 1 addition & 1 deletion compiler/rustc_attr_parsing/src/attributes/inline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,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
13 changes: 10 additions & 3 deletions compiler/rustc_attr_parsing/src/attributes/link_attrs.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use rustc_abi::ExternAbi;
use rustc_attr_ir::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
use rustc_attr_ir::*;
use rustc_errors::msg;
use rustc_feature::{AttributeStability, Features};
use rustc_lint_defs::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
use rustc_lint_defs::builtin::{ILL_FORMED_ATTRIBUTE_INPUT, UNUSED_ATTRIBUTES};
use rustc_session::Session;
use rustc_session::diagnostics::feature_err;
use rustc_span::edition::Edition::Edition2024;
Expand All @@ -17,7 +18,7 @@ use crate::attributes::cfg::parse_cfg_entry;
use crate::diagnostics::{
AsNeededCompatibility, BothFfiConstAndPure, BundleNeedsStatic, EmptyLinkName,
ExportSymbolsNeedsStatic, ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink,
InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple,
InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, Link, LinkFrameworkApple,
LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection,
RawDylibOnlyWindows, WholeArchiveNeedsStatic,
};
Expand Down Expand Up @@ -258,6 +259,12 @@ impl CombineAttributeParser for LinkParser {
import_name_type,
})
}

fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
if matches!(cx.foreign_mod_abi, Some(ExternAbi::Rust)) {
cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span);
}
}
}

impl LinkParser {
Expand Down Expand Up @@ -584,7 +591,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
5 changes: 4 additions & 1 deletion compiler/rustc_attr_parsing/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::sync::LazyLock;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicBool, Ordering};

use rustc_abi::ExternAbi;
use rustc_ast::{AttrStyle, MetaItemLit, Safety};
use rustc_attr_ir::target::Target;
use rustc_attr_ir::{AttrPath, Attribute, AttributeKind};
Expand Down Expand Up @@ -102,7 +103,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 Expand Up @@ -821,6 +822,8 @@ impl<'p, 'sess: 'p> DerefMut for FinalizeContext<'p, 'sess> {
pub(crate) struct FinalizeCheckContext<'p, 'sess> {
pub(crate) shared: SharedContext<'p, 'sess>,

pub(crate) foreign_mod_abi: Option<ExternAbi>,

/// A list of all attribute on this syntax node.
///
/// Useful for compatibility checks with other attributes.
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 @@ -1824,6 +1824,13 @@ pub(crate) struct EmptyLinkName {
pub span: Span,
}

#[derive(Diagnostic)]
#[diag("attribute should be applied to an `extern` block with non-Rust ABI")]
#[warning(
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
)]
pub(crate) struct Link;

#[derive(Diagnostic)]
#[diag("link kind `framework` is only supported on Apple targets", code = E0455)]
pub(crate) struct LinkFrameworkApple {
Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_attr_parsing/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::convert::identity;
#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicBool, Ordering};

use rustc_abi::ExternAbi;
use rustc_ast as ast;
use rustc_ast::token::DocFragmentKind;
use rustc_ast::{AttrStyle, CRATE_NODE_ID, NodeId, Safety};
Expand Down Expand Up @@ -161,6 +162,7 @@ impl<'sess> AttributeParser<'sess> {
attrs,
target_span,
target,
None,
std::convert::identity,
|lint_id, span, kind| {
sess.psess.dyn_buffer_lint_sess(lint_id.lint, span, target_node_id, kind.0)
Expand Down Expand Up @@ -315,6 +317,7 @@ impl<'sess> AttributeParser<'sess> {
attrs: &[ast::Attribute],
target_span: Span,
target: Target,
foreign_mod_abi: Option<ExternAbi>,
lower_span: impl Copy + Fn(Span) -> Span,
mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute),
) -> Vec<Attribute> {
Expand Down Expand Up @@ -510,7 +513,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 All @@ -519,6 +522,7 @@ impl<'sess> AttributeParser<'sess> {
#[cfg(debug_assertions)]
has_lint_been_emitted: AtomicBool::new(false),
},
foreign_mod_abi,
all_attrs: &attr_paths,
parsed_attrs: &attributes,
},
Expand Down
19 changes: 1 addition & 18 deletions compiler/rustc_passes/src/check_attr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use std::cell::Cell;
use std::slice;

use rustc_abi::ExternAbi;
use rustc_ast::{AttrStyle, MetaItemKind, ast};
use rustc_attr_parsing::AttributeParser;
use rustc_data_structures::thin_vec::ThinVec;
Expand Down Expand Up @@ -212,7 +211,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.check_non_exhaustive(*attr_span, span, target, item)
}
AttributeKind::MayDangle(attr_span) => self.check_may_dangle(hir_id, *attr_span),
AttributeKind::Link(_, attr_span) => self.check_link(hir_id, *attr_span, target),
AttributeKind::MacroExport { span, .. } => {
self.check_macro_export(hir_id, *span, target)
}
Expand Down Expand Up @@ -274,6 +272,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
AttributeKind::InstructionSet(..) => (),
AttributeKind::InstrumentFn(..) => (),
AttributeKind::Lang(..) => (),
AttributeKind::Link(..) => (),
AttributeKind::LinkName { .. } => (),
AttributeKind::LinkOrdinal { .. } => (),
AttributeKind::LinkSection { .. } => (),
Expand Down Expand Up @@ -1126,22 +1125,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
self.dcx().emit_err(diagnostics::InvalidMayDangle { attr_span });
}

/// Checks if `#[link]` is applied to an item other than a foreign module.
fn check_link(&self, hir_id: HirId, attr_span: Span, target: Target) {
if target != Target::ForeignMod {
return; // Checked by attribute parser
}

if let hir::Node::Item(item) = self.tcx.hir_node(hir_id)
&& let Item { kind: ItemKind::ForeignMod { abi, .. }, .. } = item
&& !matches!(abi, ExternAbi::Rust)
{
return;
}

self.tcx.emit_node_span_lint(UNUSED_ATTRIBUTES, hir_id, attr_span, diagnostics::Link);
}

/// Checks if `#[rustc_legacy_const_generics]` is applied to a function and has a valid argument.
fn check_rustc_legacy_const_generics(
&self,
Expand Down
7 changes: 0 additions & 7 deletions compiler/rustc_passes/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,13 +155,6 @@ pub(crate) struct BothOptimizeNoneAndInline {
pub inline_span: Span,
}

#[derive(Diagnostic)]
#[diag("attribute should be applied to an `extern` block with non-Rust ABI")]
#[warning(
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
)]
pub(crate) struct Link;

#[derive(Diagnostic)]
#[diag("#[rustc_legacy_const_generics] functions must only have const generics")]
pub(crate) struct RustcLegacyConstGenericsOnly {
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_resolve/src/def_collector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
&i.attrs,
i.span,
Target::MacroDef,
None,
std::convert::identity,
|_lint_id, _span, _kind| {
// FIXME(jdonszelmann): emit lints here properly
Expand Down
Loading
Loading