Rollup merge of #143138 - JonathanBrouwer:link_name_parser, r=jdonszelmann

Port `#[link_name]` to the new attribute parsing infrastructure

Ports `link_name` to the new attribute parsing infrastructure for https://github.com/rust-lang/rust/issues/131229#issuecomment-2971353197

r? `@jdonszelmann`
This commit is contained in:
Matthias Krüger
2025-06-29 06:59:31 +02:00
committed by GitHub
14 changed files with 96 additions and 70 deletions

View File

@@ -253,6 +253,9 @@ pub enum AttributeKind {
/// Represents `#[inline]` and `#[rustc_force_inline]`. /// Represents `#[inline]` and `#[rustc_force_inline]`.
Inline(InlineAttr, Span), Inline(InlineAttr, Span),
/// Represents `#[link_name]`.
LinkName { name: Symbol, span: Span },
/// Represents `#[loop_match]`. /// Represents `#[loop_match]`.
LoopMatch(Span), LoopMatch(Span),

View File

@@ -29,6 +29,7 @@ impl AttributeKind {
Stability { .. } => Yes, Stability { .. } => Yes,
Cold(..) => No, Cold(..) => No,
ConstContinue(..) => No, ConstContinue(..) => No,
LinkName { .. } => Yes,
LoopMatch(..) => No, LoopMatch(..) => No,
MayDangle(..) => No, MayDangle(..) => No,
MustUse { .. } => Yes, MustUse { .. } => Yes,

View File

@@ -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<S: Stage> SingleAttributeParser<S> for LinkNameParser {
const PATH: &[Symbol] = &[sym::link_name];
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
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 })
}
}

View File

@@ -31,6 +31,7 @@ pub(crate) mod codegen_attrs;
pub(crate) mod confusables; pub(crate) mod confusables;
pub(crate) mod deprecation; pub(crate) mod deprecation;
pub(crate) mod inline; pub(crate) mod inline;
pub(crate) mod link_attrs;
pub(crate) mod lint_helpers; pub(crate) mod lint_helpers;
pub(crate) mod loop_match; pub(crate) mod loop_match;
pub(crate) mod must_use; pub(crate) mod must_use;

View File

@@ -22,6 +22,7 @@ use crate::attributes::codegen_attrs::{
use crate::attributes::confusables::ConfusablesParser; use crate::attributes::confusables::ConfusablesParser;
use crate::attributes::deprecation::DeprecationParser; use crate::attributes::deprecation::DeprecationParser;
use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
use crate::attributes::link_attrs::LinkNameParser;
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser}; use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser}; use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::must_use::MustUseParser; use crate::attributes::must_use::MustUseParser;
@@ -121,6 +122,7 @@ attribute_parsers!(
Single<DeprecationParser>, Single<DeprecationParser>,
Single<ExportNameParser>, Single<ExportNameParser>,
Single<InlineParser>, Single<InlineParser>,
Single<LinkNameParser>,
Single<LoopMatchParser>, Single<LoopMatchParser>,
Single<MayDangleParser>, Single<MayDangleParser>,
Single<MustUseParser>, Single<MustUseParser>,

View File

@@ -123,6 +123,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
} }
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED, AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align), AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
AttributeKind::NoMangle(attr_span) => { AttributeKind::NoMangle(attr_span) => {
if tcx.opt_item_name(did.to_def_id()).is_some() { if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; 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 => { sym::link_ordinal => {
link_ordinal_span = Some(attr.span()); link_ordinal_span = Some(attr.span());
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {

View File

@@ -1,4 +1,5 @@
use rustc_abi::FIRST_VARIANT; 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::stack::ensure_sufficient_stack;
use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir; use rustc_hir as hir;
@@ -6,7 +7,7 @@ use rustc_hir::def::DefKind;
use rustc_middle::query::Providers; use rustc_middle::query::Providers;
use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt}; use rustc_middle::ty::{self, AdtDef, Instance, Ty, TyCtxt};
use rustc_session::declare_lint; use rustc_session::declare_lint;
use rustc_span::{Span, Symbol, sym}; use rustc_span::{Span, Symbol};
use tracing::{debug, instrument}; use tracing::{debug, instrument};
use crate::lints::{BuiltinClashingExtern, BuiltinClashingExternSub}; 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 // 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 // where the attribute was defined. However, until this is found to be a
// bottleneck, this does just fine. // 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) SymbolName::Link(overridden_link_name, overridden_link_name_span)

View File

@@ -302,6 +302,7 @@ fn emit_malformed_attribute(
| sym::no_mangle | sym::no_mangle
| sym::must_use | sym::must_use
| sym::track_caller | sym::track_caller
| sym::link_name
) { ) {
return; return;
} }

View File

@@ -191,6 +191,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => { Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target) 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)) => { Attribute::Parsed(AttributeKind::MayDangle(attr_span)) => {
self.check_may_dangle(hir_id, *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::ffi_const, ..] => self.check_ffi_const(attr.span(), target),
[sym::link_ordinal, ..] => self.check_link_ordinal(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, ..] => 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::link_section, ..] => self.check_link_section(hir_id, attr, span, target),
[sym::macro_use, ..] | [sym::macro_escape, ..] => { [sym::macro_use, ..] | [sym::macro_escape, ..] => {
self.check_macro_use(hir_id, attr, target) 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. /// 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 { match target {
Target::ForeignFn | Target::ForeignStatic => {} Target::ForeignFn | Target::ForeignStatic => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an // 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 // erroneously allowed it and some crates used it accidentally, to be compatible
// with crates depending on them, we can't throw an error here. // with crates depending on them, we can't throw an error here.
Target::Field | Target::Arm | Target::MacroDef => { 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. // used this, so only emit a warning.
let attr_span = matches!(target, Target::ForeignMod).then_some(attr.span()); let help_span = matches!(target, Target::ForeignMod).then_some(attr_span);
if let Some(s) = attr.value_str() {
self.tcx.emit_node_span_lint( self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES, UNUSED_ATTRIBUTES,
hir_id, hir_id,
attr.span(), attr_span,
errors::LinkName { span, attr_span, value: s.as_str() }, errors::LinkName { span, help_span, value: name.as_str() },
); );
} else {
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
errors::LinkName { span, attr_span, value: "..." },
);
};
} }
} }
} }

View File

@@ -502,7 +502,7 @@ pub(crate) struct Link {
#[warning] #[warning]
pub(crate) struct LinkName<'a> { pub(crate) struct LinkName<'a> {
#[help] #[help]
pub attr_span: Option<Span>, pub help_span: Option<Span>,
#[label] #[label]
pub span: Span, pub span: Span,
pub value: &'a str, pub value: &'a str,

View File

@@ -17,12 +17,9 @@ extern "C" {
#[link_name] #[link_name]
//~^ ERROR malformed `link_name` attribute input //~^ ERROR malformed `link_name` attribute input
//~| HELP must be of the form //~| HELP must be of the form
//~| WARN attribute should be applied to a foreign function or static [unused_attributes] //~| NOTE expected this to be of the form `link_name = "..."
//~| 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
extern "C" { extern "C" {
fn bar() -> u32; fn bar() -> u32;
} }
//~^^^ NOTE not a foreign function or static
fn main() {} fn main() {}

View File

@@ -1,8 +1,11 @@
error: malformed `link_name` attribute input error[E0539]: malformed `link_name` attribute input
--> $DIR/issue-47725.rs:17:1 --> $DIR/issue-47725.rs:17:1
| |
LL | #[link_name] 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 warning: attribute should be applied to a foreign function or static
--> $DIR/issue-47725.rs:3:1 --> $DIR/issue-47725.rs:3:1
@@ -38,23 +41,6 @@ help: try `#[link(name = "foobar")]` instead
LL | #[link_name = "foobar"] LL | #[link_name = "foobar"]
| ^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^
warning: attribute should be applied to a foreign function or static error: aborting due to 1 previous error; 2 warnings emitted
--> $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
For more information about this error, try `rustc --explain E0539`.

View File

@@ -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: 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 warning: attribute should be applied to a function or static
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 --> $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: 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 warning: `#[must_use]` has no effect when applied to a module
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1 --> $DIR/issue-43106-gating-of-builtin-attrs.rs:72:1
| |

View File

@@ -89,19 +89,6 @@ note: attribute also specified here
LL | #[automatically_derived] 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 error: unused attribute
--> $DIR/unused-attr-duplicate.rs:14:1 --> $DIR/unused-attr-duplicate.rs:14:1
| |
@@ -252,6 +239,19 @@ note: attribute also specified here
LL | #[track_caller] 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 error: unused attribute
--> $DIR/unused-attr-duplicate.rs:92:1 --> $DIR/unused-attr-duplicate.rs:92:1
| |