From 1249c142326243ae9beb9fddd9eacfc66461998b Mon Sep 17 00:00:00 2001 From: Jonathan Brouwer Date: Sat, 28 Jun 2025 13:53:37 +0200 Subject: [PATCH] Port `#[link_name]` to the new attribute parsing infrastructure Co-authored-by: Anne Stijns Signed-off-by: Jonathan Brouwer --- .../src/attributes.rs | 3 ++ .../src/encode_cross_crate.rs | 1 + .../src/attributes/link_attrs.rs | 30 ++++++++++++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 2 + .../rustc_codegen_ssa/src/codegen_attrs.rs | 2 +- compiler/rustc_lint/src/foreign_modules.rs | 9 ++++- compiler/rustc_parse/src/validate_attr.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 40 +++++++++---------- compiler/rustc_passes/src/errors.rs | 2 +- tests/ui/extern/issue-47725.rs | 5 +-- tests/ui/extern/issue-47725.stderr | 28 ++++--------- ...issue-43106-gating-of-builtin-attrs.stderr | 16 ++++---- .../lint/unused/unused-attr-duplicate.stderr | 26 ++++++------ 14 files changed, 96 insertions(+), 70 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/link_attrs.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 60a4f28930691..5eb1931152d31 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -253,6 +253,9 @@ pub enum AttributeKind { /// Represents `#[inline]` and `#[rustc_force_inline]`. Inline(InlineAttr, Span), + /// Represents `#[link_name]`. + LinkName { name: Symbol, span: Span }, + /// Represents `#[loop_match]`. LoopMatch(Span), diff --git a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs index 64bcf1fe6cce7..0d6ee77c718d3 100644 --- a/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs +++ b/compiler/rustc_attr_data_structures/src/encode_cross_crate.rs @@ -29,6 +29,7 @@ impl AttributeKind { Stability { .. } => Yes, Cold(..) => No, ConstContinue(..) => No, + LinkName { .. } => Yes, LoopMatch(..) => No, MayDangle(..) => No, MustUse { .. } => Yes, diff --git a/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs new file mode 100644 index 0000000000000..740222178ed58 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/link_attrs.rs @@ -0,0 +1,30 @@ +use rustc_attr_data_structures::AttributeKind; +use rustc_attr_data_structures::AttributeKind::LinkName; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Symbol, sym}; + +use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::{AcceptContext, Stage}; +use crate::parser::ArgParser; + +pub(crate) struct LinkNameParser; + +impl SingleAttributeParser for LinkNameParser { + const PATH: &[Symbol] = &[sym::link_name]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(name) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + + Some(LinkName { name, span: cx.attr_span }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index d407669cb410c..584dadadcf7b3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -31,6 +31,7 @@ pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod deprecation; pub(crate) mod inline; +pub(crate) mod link_attrs; pub(crate) mod lint_helpers; pub(crate) mod loop_match; pub(crate) mod must_use; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 71bb86ca3d3b8..1ac41b9c7e8b5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -22,6 +22,7 @@ use crate::attributes::codegen_attrs::{ use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; +use crate::attributes::link_attrs::LinkNameParser; use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::must_use::MustUseParser; @@ -121,6 +122,7 @@ attribute_parsers!( Single, Single, Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index acdda32d58a3f..7680f8e107439 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -123,6 +123,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), + AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name), AttributeKind::NoMangle(attr_span) => { if tcx.opt_item_name(did.to_def_id()).is_some() { codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; @@ -262,7 +263,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { } } } - sym::link_name => codegen_fn_attrs.link_name = attr.value_str(), sym::link_ordinal => { link_ordinal_span = Some(attr.span()); if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs index d0668794198ac..d6c402d481f4e 100644 --- a/compiler/rustc_lint/src/foreign_modules.rs +++ b/compiler/rustc_lint/src/foreign_modules.rs @@ -1,4 +1,5 @@ use rustc_abi::FIRST_VARIANT; +use rustc_attr_data_structures::{AttributeKind, find_attr}; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir as hir; @@ -6,7 +7,7 @@ use rustc_hir::def::DefKind; use rustc_middle::query::Providers; use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_session::declare_lint; -use rustc_span::{Span, Symbol, sym}; +use rustc_span::{Span, Symbol}; use tracing::{debug, instrument}; use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub}; @@ -182,7 +183,11 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: hir::OwnerId) -> SymbolName { // information, we could have codegen_fn_attrs also give span information back for // where the attribute was defined. However, until this is found to be a // bottleneck, this does just fine. - (overridden_link_name, tcx.get_attr(fi, sym::link_name).unwrap().span()) + ( + overridden_link_name, + find_attr!(tcx.get_all_attrs(fi), AttributeKind::LinkName {span, ..} => *span) + .unwrap(), + ) }) { SymbolName::Link(overridden_link_name, overridden_link_name_span) diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 68d78af59431f..8b1d864c9957d 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -302,6 +302,7 @@ fn emit_malformed_attribute( | sym::no_mangle | sym::must_use | sym::track_caller + | sym::link_name ) { return; } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 877bb9be28961..ae486a58062bf 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -191,6 +191,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) } + Attribute::Parsed(AttributeKind::LinkName { span: attr_span, name }) => { + self.check_link_name(hir_id, *attr_span, *name, span, target) + } Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => { self.check_may_dangle(hir_id, *attr_span) } @@ -283,7 +286,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::ffi_const, ..] => self.check_ffi_const(attr.span(), target), [sym::link_ordinal, ..] => self.check_link_ordinal(attr, span, target), [sym::link, ..] => self.check_link(hir_id, attr, span, target), - [sym::link_name, ..] => self.check_link_name(hir_id, attr, span, target), [sym::link_section, ..] => self.check_link_section(hir_id, attr, span, target), [sym::macro_use, ..] | [sym::macro_escape, ..] => { self.check_macro_use(hir_id, attr, target) @@ -1604,7 +1606,14 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. - fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_link_name( + &self, + hir_id: HirId, + attr_span: Span, + name: Symbol, + span: Span, + target: Target, + ) { match target { Target::ForeignFn | Target::ForeignStatic => {} // FIXME(#80564): We permit struct fields, match arms and macro defs to have an @@ -1612,27 +1621,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // erroneously allowed it and some crates used it accidentally, to be compatible // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_name"); } _ => { - // FIXME: #[cold] was previously allowed on non-functions/statics and some crates + // FIXME: #[link_name] was previously allowed on non-functions/statics and some crates // used this, so only emit a warning. - let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span()); - if let Some(s) = attr.value_str() { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::LinkName { span, attr_span, value: s.as_str() }, - ); - } else { - self.tcx.emit_node_span_lint( - UNUSED_ATTRIBUTES, - hir_id, - attr.span(), - errors::LinkName { span, attr_span, value: "..." }, - ); - }; + let help_span = matches!(target, Target::ForeignMod).then_some(attr_span); + self.tcx.emit_node_span_lint( + UNUSED_ATTRIBUTES, + hir_id, + attr_span, + errors::LinkName { span, help_span, value: name.as_str() }, + ); } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index f89d925202c26..eaff1cc65de34 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -502,7 +502,7 @@ pub(crate) struct Link { #[warning] pub(crate) struct LinkName<'a> { #[help] - pub attr_span: Option, + pub help_span: Option, #[label] pub span: Span, pub value: &'a str, diff --git a/tests/ui/extern/issue-47725.rs b/tests/ui/extern/issue-47725.rs index 9ec55be58723c..012673b9159f1 100644 --- a/tests/ui/extern/issue-47725.rs +++ b/tests/ui/extern/issue-47725.rs @@ -17,12 +17,9 @@ extern "C" { #[link_name] //~^ ERROR malformed `link_name` attribute input //~| HELP must be of the form -//~| WARN attribute should be applied to a foreign function or static [unused_attributes] -//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -//~| HELP try `#[link(name = "...")]` instead +//~| NOTE expected this to be of the form `link_name = "..." extern "C" { fn bar() -> u32; } -//~^^^ NOTE not a foreign function or static fn main() {} diff --git a/tests/ui/extern/issue-47725.stderr b/tests/ui/extern/issue-47725.stderr index 0d3b77b46084c..53d6b4927f89f 100644 --- a/tests/ui/extern/issue-47725.stderr +++ b/tests/ui/extern/issue-47725.stderr @@ -1,8 +1,11 @@ -error: malformed `link_name` attribute input +error[E0539]: malformed `link_name` attribute input --> $DIR/issue-47725.rs:17:1 | LL | #[link_name] - | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` + | ^^^^^^^^^^^^ + | | + | expected this to be of the form `link_name = "..."` + | help: must be of the form: `#[link_name = "name"]` warning: attribute should be applied to a foreign function or static --> $DIR/issue-47725.rs:3:1 @@ -38,23 +41,6 @@ help: try `#[link(name = "foobar")]` instead LL | #[link_name = "foobar"] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: attribute should be applied to a foreign function or static - --> $DIR/issue-47725.rs:17:1 - | -LL | #[link_name] - | ^^^^^^^^^^^^ -... -LL | / extern "C" { -LL | | fn bar() -> u32; -LL | | } - | |_- not a foreign function or static - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! -help: try `#[link(name = "...")]` instead - --> $DIR/issue-47725.rs:17:1 - | -LL | #[link_name] - | ^^^^^^^^^^^^ - -error: aborting due to 1 previous error; 3 warnings emitted +error: aborting due to 1 previous error; 2 warnings emitted +For more information about this error, try `rustc --explain E0539`. 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 d2b1d71ab87c3..1243ed5d8f486 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 @@ -387,14 +387,6 @@ LL | #![link()] | = 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 a foreign function or static - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 - | -LL | #![link_name = "1900"] - | ^^^^^^^^^^^^^^^^^^^^^^ not a foreign function or static - | - = 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 a function or static --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 | @@ -411,6 +403,14 @@ LL | #![cold] | = 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 a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:66:1 + | +LL | #![link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^^ not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: `#[must_use]` has no effect when applied to a module --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 | diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index a18581192ea66..e8452465efc27 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -89,19 +89,6 @@ note: attribute also specified here LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:86:5 - | -LL | #[link_name = "this_does_not_exist"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:88:5 - | -LL | #[link_name = "rust_dbg_extern_identity_u32"] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - error: unused attribute --> $DIR/unused-attr-duplicate.rs:14:1 | @@ -252,6 +239,19 @@ note: attribute also specified here LL | #[track_caller] | ^^^^^^^^^^^^^^^ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:86:5 + | +LL | #[link_name = "this_does_not_exist"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:88:5 + | +LL | #[link_name = "rust_dbg_extern_identity_u32"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + error: unused attribute --> $DIR/unused-attr-duplicate.rs:92:1 |