From 4790bae26305d0c9af7e49c6021e91f2a87b5c29 Mon Sep 17 00:00:00 2001 From: hizyyo Date: Sat, 5 Sep 2026 21:33:26 +0500 Subject: [PATCH] Move the foreign module #[link] ABI check to attribute parsing --- compiler/rustc_ast_lowering/src/expr.rs | 2 +- compiler/rustc_ast_lowering/src/item.rs | 9 ++++ compiler/rustc_ast_lowering/src/lib.rs | 15 +++++-- .../src/attributes/allow_unstable.rs | 2 +- .../src/attributes/codegen_attrs.rs | 4 +- .../src/attributes/inline.rs | 2 +- .../src/attributes/link_attrs.rs | 13 ++++-- .../src/attributes/lint_helpers.rs | 2 +- .../src/attributes/macro_attrs.rs | 2 +- .../rustc_attr_parsing/src/attributes/mod.rs | 8 ++-- compiler/rustc_attr_parsing/src/context.rs | 5 ++- .../rustc_attr_parsing/src/diagnostics.rs | 7 +++ compiler/rustc_attr_parsing/src/interface.rs | 6 ++- compiler/rustc_passes/src/check_attr.rs | 19 +------- compiler/rustc_passes/src/diagnostics.rs | 7 --- compiler/rustc_resolve/src/def_collector.rs | 1 + tests/ui/attributes/link-foreign-mod-abi.rs | 45 +++++++++++++++++++ tests/ui/attributes/link-invalid-abi.rs | 13 ++++++ tests/ui/attributes/link-invalid-abi.stderr | 24 ++++++++++ ...issue-43106-gating-of-builtin-attrs.stderr | 16 +++---- 20 files changed, 150 insertions(+), 52 deletions(-) create mode 100644 tests/ui/attributes/link-foreign-mod-abi.rs create mode 100644 tests/ui/attributes/link-invalid-abi.rs create mode 100644 tests/ui/attributes/link-invalid-abi.stderr diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 0a4a2ae7145e3..27ad70958db3e 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -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); diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b5e28d21a2613..18f25d491572c 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -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, ); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ef6995d9c11d6..f60bf24a175c4 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -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}; @@ -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( @@ -1183,13 +1184,19 @@ impl<'hir> LoweringContext<'_, 'hir> { attrs: &[Attribute], target_span: Span, target: Target, + foreign_mod_abi: Option, 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); @@ -1216,12 +1223,14 @@ impl<'hir> LoweringContext<'_, 'hir> { target_span: Span, target_hir_id: HirId, target: Target, + foreign_mod_abi: Option, ) -> Vec { 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 { diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 743d3c9b5e76e..42e5f0ca2add4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -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); } } diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index bff7d7ad81cb9..2553829f8c5ce 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -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 { diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index f3e305ea266a1..78a989fdfdba6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -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; diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs index a00e5af00c2eb..95aa7a846ac2c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -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; @@ -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, }; @@ -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 { @@ -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 }); diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs index 4ead90af8d630..10e42ced30705 100644 --- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs +++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs @@ -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, diff --git a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs index c9625521aec44..85aaeffec00d5 100644 --- a/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/macro_attrs.rs @@ -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); } } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 242b4a73b06a6..8e47414f6c72a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -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(PhantomData); @@ -311,7 +311,7 @@ impl SingleAttributeParser for WithoutArgs { 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`]. diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index cf99311cc0cfc..21ac4f7f6f1cc 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -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}; @@ -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 { @@ -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, + /// A list of all attribute on this syntax node. /// /// Useful for compatibility checks with other attributes. diff --git a/compiler/rustc_attr_parsing/src/diagnostics.rs b/compiler/rustc_attr_parsing/src/diagnostics.rs index 663915e39dccd..352a51f647c57 100644 --- a/compiler/rustc_attr_parsing/src/diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/diagnostics.rs @@ -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 { diff --git a/compiler/rustc_attr_parsing/src/interface.rs b/compiler/rustc_attr_parsing/src/interface.rs index 240f437828259..6e5d31f8011fd 100644 --- a/compiler/rustc_attr_parsing/src/interface.rs +++ b/compiler/rustc_attr_parsing/src/interface.rs @@ -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}; @@ -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) @@ -315,6 +317,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], target_span: Span, target: Target, + foreign_mod_abi: Option, lower_span: impl Copy + Fn(Span) -> Span, mut emit_lint: impl FnMut(LintId, MultiSpan, EmitAttribute), ) -> Vec { @@ -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, @@ -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, }, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index cd7f422fb72f3..c349f7253e0c6 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -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; @@ -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) } @@ -274,6 +272,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::InstructionSet(..) => (), AttributeKind::InstrumentFn(..) => (), AttributeKind::Lang(..) => (), + AttributeKind::Link(..) => (), AttributeKind::LinkName { .. } => (), AttributeKind::LinkOrdinal { .. } => (), AttributeKind::LinkSection { .. } => (), @@ -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, diff --git a/compiler/rustc_passes/src/diagnostics.rs b/compiler/rustc_passes/src/diagnostics.rs index 5f99c4b133597..486aad577ef91 100644 --- a/compiler/rustc_passes/src/diagnostics.rs +++ b/compiler/rustc_passes/src/diagnostics.rs @@ -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 { diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 4c8000c28f065..1fab7a37a9941 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -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 diff --git a/tests/ui/attributes/link-foreign-mod-abi.rs b/tests/ui/attributes/link-foreign-mod-abi.rs new file mode 100644 index 0000000000000..83d0a2dd47f0b --- /dev/null +++ b/tests/ui/attributes/link-foreign-mod-abi.rs @@ -0,0 +1,45 @@ +//@ check-pass +//@ compile-flags: --crate-type=lib + +#![no_core] +#![feature(no_core, rust_cold_cc, rust_preserve_none_cc, rust_tail_cc, unboxed_closures)] +#![allow(missing_abi)] +#![deny(unfulfilled_lint_expectations, unused_attributes)] + +#[link(name = "omitted")] +extern {} + +#[link(name = "c")] +extern "C" {} + +#[link(name = "rust-call")] +extern "rust-call" {} + +#[link(name = "rust-cold")] +extern "rust-cold" {} + +#[link(name = "rust-preserve-none")] +extern "rust-preserve-none" {} + +#[link(name = "tail")] +extern "tail" {} + +#[cfg_attr(any(), link(name = "disabled"))] +extern "Rust" {} + +#[expect(unused_attributes)] +#[cfg_attr(all(), link(name = "enabled"))] +extern "Rust" {} + +#[allow(unused_attributes)] +#[link(name = "allowed")] +extern "Rust" {} + +#[expect(unused_attributes)] +#[link(name = "expected")] +extern "Rust" {} + +#[expect(unused_attributes)] +#[link(name = "first")] +#[link(name = "second")] +extern "Rust" {} diff --git a/tests/ui/attributes/link-invalid-abi.rs b/tests/ui/attributes/link-invalid-abi.rs new file mode 100644 index 0000000000000..49f91236c1a2b --- /dev/null +++ b/tests/ui/attributes/link-invalid-abi.rs @@ -0,0 +1,13 @@ +//@ check-fail +//@ compile-flags: --crate-type=lib + +#![no_core] +#![feature(no_core)] +#![warn(unused_attributes)] + +#[link(name = "first")] +//~^ WARN +//~| WARN +#[link(name = "second")] +extern "invalid" {} +//~^ ERROR diff --git a/tests/ui/attributes/link-invalid-abi.stderr b/tests/ui/attributes/link-invalid-abi.stderr new file mode 100644 index 0000000000000..add2ebcb7c186 --- /dev/null +++ b/tests/ui/attributes/link-invalid-abi.stderr @@ -0,0 +1,24 @@ +error[E0703]: invalid ABI: found `invalid` + --> $DIR/link-invalid-abi.rs:12:8 + | +LL | extern "invalid" {} + | ^^^^^^^^^ invalid ABI + | + = note: invoke `rustc --print=calling-conventions` for a full list of supported calling conventions + +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/link-invalid-abi.rs:8:1 + | +LL | #[link(name = "first")] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +note: the lint level is defined here + --> $DIR/link-invalid-abi.rs:6:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0703`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr index a677339551153..2d3b7658f9aae 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs.stderr @@ -207,14 +207,6 @@ note: the lint level is defined here LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^^^^^ -warning: attribute should be applied to an `extern` block with non-Rust ABI - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 - | -LL | #[link(name = "x")] extern "Rust" {} - | ^^^^^^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - warning: the `macro_use` attribute cannot be used on crates --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:4 | @@ -978,6 +970,14 @@ LL | #[link(name = "x")] impl S { } = help: the `link` attribute can only be applied to foreign modules = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +warning: attribute should be applied to an `extern` block with non-Rust ABI + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:5 + | +LL | #[link(name = "x")] extern "Rust" {} + | ^^^^^^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: the `must_use` attribute cannot be used on modules --> $DIR/issue-43106-gating-of-builtin-attrs.rs:749:3 |