From 8b1803ad5db682b5e7d710a575bc5ba40d9baace Mon Sep 17 00:00:00 2001 From: asuto15 Date: Tue, 14 Jul 2026 06:19:32 +0900 Subject: [PATCH 1/2] Add suggestions for using `#[export_name]` instead of `#[link_name]` on statics --- .../src/session_diagnostics.rs | 12 +++++++++ .../rustc_attr_parsing/src/target_checking.rs | 14 ++++++++++- tests/ui/attributes/link-name-on-static.rs | 13 ++++++++++ .../ui/attributes/link-name-on-static.stderr | 17 +++++++++++++ .../attributes/unsafe-link-name-on-static.rs | 7 ++++++ .../unsafe-link-name-on-static.stderr | 25 +++++++++++++++++++ 6 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 tests/ui/attributes/link-name-on-static.rs create mode 100644 tests/ui/attributes/link-name-on-static.stderr create mode 100644 tests/ui/attributes/unsafe-link-name-on-static.rs create mode 100644 tests/ui/attributes/unsafe-link-name-on-static.stderr diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index fb984912b1936..b913518c191db 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -403,6 +403,18 @@ pub(crate) struct InvalidTarget { #[derive(Subdiagnostic)] pub(crate) enum InvalidTargetHelp { + #[multipart_suggestion( + "did you mean to use `#[export_name]`?", + applicability = "maybe-incorrect" + )] + UseExportName { + #[suggestion_part(code = "unsafe(")] + unsafe_open: Option, + #[suggestion_part(code = "export_name")] + name: Span, + #[suggestion_part(code = ")")] + unsafe_close: Option, + }, #[help("use `#[rustc_align(...)]` instead")] UseRustcAlign, #[help("use `#[rustc_align_static(...)]` instead")] diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index 461820626f2ad..f2d25d5a960ef 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; -use rustc_ast::AttrStyle; +use rustc_ast::{AttrStyle, Safety}; use rustc_errors::{DiagArgValue, MultiSpan, StashKey}; use rustc_feature::Features; use rustc_hir::attrs::AttributeKind; @@ -187,6 +187,18 @@ impl<'sess> AttributeParser<'sess> { cx: &AcceptContext<'_, '_>, ) -> Option { match &*cx.attr_path.segments { + [sym::link_name] + if cx.target == Target::Static + && matches!(cx.attr_safety, Safety::Default | Safety::Unsafe(_)) => + { + Some(InvalidTargetHelp::UseExportName { + unsafe_open: matches!(cx.attr_safety, Safety::Default) + .then(|| cx.inner_span.shrink_to_lo()), + name: cx.attr_path.span, + unsafe_close: matches!(cx.attr_safety, Safety::Default) + .then(|| cx.inner_span.shrink_to_hi()), + }) + } [sym::repr] if attribute_args == "(align(...))" => match cx.target { Target::Fn | Target::Method(..) if cx.features().fn_align() => { Some(InvalidTargetHelp::UseRustcAlign) diff --git a/tests/ui/attributes/link-name-on-static.rs b/tests/ui/attributes/link-name-on-static.rs new file mode 100644 index 0000000000000..be56852ad5fdf --- /dev/null +++ b/tests/ui/attributes/link-name-on-static.rs @@ -0,0 +1,13 @@ +//@ check-pass + +#[link_name = "VALUE"] +//~^ WARN `#[link_name]` attribute cannot be used on statics +//~| WARN this was previously accepted by the compiler but is being phased out +static VALUE_DEFINITION: u8 = 0; + +unsafe extern "C" { + #[link_name = "VALUE"] + static VALUE_DECLARATION: u8; +} + +fn main() {} diff --git a/tests/ui/attributes/link-name-on-static.stderr b/tests/ui/attributes/link-name-on-static.stderr new file mode 100644 index 0000000000000..c08b9ee23721b --- /dev/null +++ b/tests/ui/attributes/link-name-on-static.stderr @@ -0,0 +1,17 @@ +warning: `#[link_name]` attribute cannot be used on statics + --> $DIR/link-name-on-static.rs:3:1 + | +LL | #[link_name = "VALUE"] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link_name]` can be applied to foreign functions and foreign statics + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: requested on the command line with `-W unused-attributes` +help: did you mean to use `#[export_name]`? + | +LL - #[link_name = "VALUE"] +LL + #[unsafe(export_name = "VALUE")] + | + +warning: 1 warning emitted + diff --git a/tests/ui/attributes/unsafe-link-name-on-static.rs b/tests/ui/attributes/unsafe-link-name-on-static.rs new file mode 100644 index 0000000000000..1c88a89829485 --- /dev/null +++ b/tests/ui/attributes/unsafe-link-name-on-static.rs @@ -0,0 +1,7 @@ +#[unsafe(link_name = "VALUE")] +//~^ ERROR `link_name` is not an unsafe attribute +//~| WARN `#[link_name]` attribute cannot be used on statics +//~| WARN this was previously accepted by the compiler but is being phased out +static VALUE_DEFINITION: u8 = 0; + +fn main() {} diff --git a/tests/ui/attributes/unsafe-link-name-on-static.stderr b/tests/ui/attributes/unsafe-link-name-on-static.stderr new file mode 100644 index 0000000000000..5d987f7df390c --- /dev/null +++ b/tests/ui/attributes/unsafe-link-name-on-static.stderr @@ -0,0 +1,25 @@ +error: `link_name` is not an unsafe attribute + --> $DIR/unsafe-link-name-on-static.rs:1:3 + | +LL | #[unsafe(link_name = "VALUE")] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +warning: `#[link_name]` attribute cannot be used on statics + --> $DIR/unsafe-link-name-on-static.rs:1:1 + | +LL | #[unsafe(link_name = "VALUE")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: `#[link_name]` can be applied to foreign functions and foreign statics + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: requested on the command line with `-W unused-attributes` +help: did you mean to use `#[export_name]`? + | +LL - #[unsafe(link_name = "VALUE")] +LL + #[unsafe(export_name = "VALUE")] + | + +error: aborting due to 1 previous error; 1 warning emitted + From 5e5367ba4d58d8551aef91017f6ea95d3e8a95be Mon Sep 17 00:00:00 2001 From: asuto15 Date: Sun, 26 Jul 2026 20:30:27 +0900 Subject: [PATCH 2/2] Remove redundant suggestion filter and consolidate UI tests --- .../rustc_attr_parsing/src/target_checking.rs | 13 +++----- tests/ui/attributes/link-name-on-static.rs | 10 ++++-- .../ui/attributes/link-name-on-static.stderr | 32 ++++++++++++++++--- .../attributes/unsafe-link-name-on-static.rs | 7 ---- .../unsafe-link-name-on-static.stderr | 25 --------------- 5 files changed, 39 insertions(+), 48 deletions(-) delete mode 100644 tests/ui/attributes/unsafe-link-name-on-static.rs delete mode 100644 tests/ui/attributes/unsafe-link-name-on-static.stderr diff --git a/compiler/rustc_attr_parsing/src/target_checking.rs b/compiler/rustc_attr_parsing/src/target_checking.rs index f2d25d5a960ef..6b0d1b094ca0f 100644 --- a/compiler/rustc_attr_parsing/src/target_checking.rs +++ b/compiler/rustc_attr_parsing/src/target_checking.rs @@ -187,16 +187,13 @@ impl<'sess> AttributeParser<'sess> { cx: &AcceptContext<'_, '_>, ) -> Option { match &*cx.attr_path.segments { - [sym::link_name] - if cx.target == Target::Static - && matches!(cx.attr_safety, Safety::Default | Safety::Unsafe(_)) => - { + [sym::link_name] if cx.target == Target::Static => { + let needs_unsafe_wrapper = matches!(cx.attr_safety, Safety::Default); + Some(InvalidTargetHelp::UseExportName { - unsafe_open: matches!(cx.attr_safety, Safety::Default) - .then(|| cx.inner_span.shrink_to_lo()), + unsafe_open: needs_unsafe_wrapper.then(|| cx.inner_span.shrink_to_lo()), name: cx.attr_path.span, - unsafe_close: matches!(cx.attr_safety, Safety::Default) - .then(|| cx.inner_span.shrink_to_hi()), + unsafe_close: needs_unsafe_wrapper.then(|| cx.inner_span.shrink_to_hi()), }) } [sym::repr] if attribute_args == "(align(...))" => match cx.target { diff --git a/tests/ui/attributes/link-name-on-static.rs b/tests/ui/attributes/link-name-on-static.rs index be56852ad5fdf..85082d3a43fb4 100644 --- a/tests/ui/attributes/link-name-on-static.rs +++ b/tests/ui/attributes/link-name-on-static.rs @@ -1,10 +1,14 @@ -//@ check-pass - #[link_name = "VALUE"] -//~^ WARN `#[link_name]` attribute cannot be used on statics +//~^ WARN the `link_name` attribute cannot be used on statics //~| WARN this was previously accepted by the compiler but is being phased out static VALUE_DEFINITION: u8 = 0; +#[unsafe(link_name = "UNSAFE_VALUE")] +//~^ ERROR `link_name` is not an unsafe attribute +//~| WARN the `link_name` attribute cannot be used on statics +//~| WARN this was previously accepted by the compiler but is being phased out +static UNSAFE_VALUE_DEFINITION: u8 = 0; + unsafe extern "C" { #[link_name = "VALUE"] static VALUE_DECLARATION: u8; diff --git a/tests/ui/attributes/link-name-on-static.stderr b/tests/ui/attributes/link-name-on-static.stderr index c08b9ee23721b..2d768acd51bfb 100644 --- a/tests/ui/attributes/link-name-on-static.stderr +++ b/tests/ui/attributes/link-name-on-static.stderr @@ -1,10 +1,18 @@ -warning: `#[link_name]` attribute cannot be used on statics - --> $DIR/link-name-on-static.rs:3:1 +error: `link_name` is not an unsafe attribute + --> $DIR/link-name-on-static.rs:6:3 + | +LL | #[unsafe(link_name = "UNSAFE_VALUE")] + | ^^^^^^ this is not an unsafe attribute + | + = note: extraneous unsafe is not allowed in attributes + +warning: the `link_name` attribute cannot be used on statics + --> $DIR/link-name-on-static.rs:1:3 | LL | #[link_name = "VALUE"] - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ | - = help: `#[link_name]` can be applied to foreign functions and foreign statics + = help: the `link_name` attribute can be applied to foreign functions and foreign statics = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: requested on the command line with `-W unused-attributes` help: did you mean to use `#[export_name]`? @@ -13,5 +21,19 @@ LL - #[link_name = "VALUE"] LL + #[unsafe(export_name = "VALUE")] | -warning: 1 warning emitted +warning: the `link_name` attribute cannot be used on statics + --> $DIR/link-name-on-static.rs:6:10 + | +LL | #[unsafe(link_name = "UNSAFE_VALUE")] + | ^^^^^^^^^ + | + = help: the `link_name` attribute can be applied to foreign functions and foreign statics + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +help: did you mean to use `#[export_name]`? + | +LL - #[unsafe(link_name = "UNSAFE_VALUE")] +LL + #[unsafe(export_name = "UNSAFE_VALUE")] + | + +error: aborting due to 1 previous error; 2 warnings emitted diff --git a/tests/ui/attributes/unsafe-link-name-on-static.rs b/tests/ui/attributes/unsafe-link-name-on-static.rs deleted file mode 100644 index 1c88a89829485..0000000000000 --- a/tests/ui/attributes/unsafe-link-name-on-static.rs +++ /dev/null @@ -1,7 +0,0 @@ -#[unsafe(link_name = "VALUE")] -//~^ ERROR `link_name` is not an unsafe attribute -//~| WARN `#[link_name]` attribute cannot be used on statics -//~| WARN this was previously accepted by the compiler but is being phased out -static VALUE_DEFINITION: u8 = 0; - -fn main() {} diff --git a/tests/ui/attributes/unsafe-link-name-on-static.stderr b/tests/ui/attributes/unsafe-link-name-on-static.stderr deleted file mode 100644 index 5d987f7df390c..0000000000000 --- a/tests/ui/attributes/unsafe-link-name-on-static.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: `link_name` is not an unsafe attribute - --> $DIR/unsafe-link-name-on-static.rs:1:3 - | -LL | #[unsafe(link_name = "VALUE")] - | ^^^^^^ this is not an unsafe attribute - | - = note: extraneous unsafe is not allowed in attributes - -warning: `#[link_name]` attribute cannot be used on statics - --> $DIR/unsafe-link-name-on-static.rs:1:1 - | -LL | #[unsafe(link_name = "VALUE")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: `#[link_name]` can be applied to foreign functions and foreign statics - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: requested on the command line with `-W unused-attributes` -help: did you mean to use `#[export_name]`? - | -LL - #[unsafe(link_name = "VALUE")] -LL + #[unsafe(export_name = "VALUE")] - | - -error: aborting due to 1 previous error; 1 warning emitted -