Port #[link_section] to the new attribute parsing infrastructure

This commit is contained in:
Anne Stijns
2025-06-29 15:37:54 +02:00
parent 5ca574e85b
commit 54cec0cf5a
14 changed files with 101 additions and 26 deletions
@@ -256,6 +256,9 @@ pub enum AttributeKind {
/// Represents `#[link_name]`.
LinkName { name: Symbol, span: Span },
/// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
LinkSection { name: Symbol, span: Span },
/// Represents `#[loop_match]`.
LoopMatch(Span),
@@ -24,6 +24,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate {
DocComment { .. } => Yes,
ExportName { .. } => Yes,
Inline(..) => No,
LinkSection { .. } => No,
MacroTransparency(..) => Yes,
Repr(..) => No,
Stability { .. } => Yes,
+2
View File
@@ -99,6 +99,8 @@ attr_parsing_non_ident_feature =
attr_parsing_null_on_export = `export_name` may not contain null characters
attr_parsing_null_on_link_section = `link_section` may not contain null characters
attr_parsing_repr_ident =
meta item in `repr` must be an identifier
@@ -1,11 +1,12 @@
use rustc_attr_data_structures::AttributeKind;
use rustc_attr_data_structures::AttributeKind::LinkName;
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkSection};
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;
use crate::session_diagnostics::NullOnLinkSection;
pub(crate) struct LinkNameParser;
@@ -28,3 +29,31 @@ fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<At
Some(LinkName { name, span: cx.attr_span })
}
}
pub(crate) struct LinkSectionParser;
impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
const PATH: &[Symbol] = &[sym::link_section];
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;
};
if name.as_str().contains('\0') {
// `#[link_section = ...]` will be converted to a null-terminated string,
// so it may not contain any null characters.
cx.emit_err(NullOnLinkSection { span: cx.attr_span });
return None;
}
Some(LinkSection { name, span: cx.attr_span })
}
}
+2 -1
View File
@@ -22,7 +22,7 @@
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::link_attrs::{LinkNameParser, LinkSectionParser};
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
use crate::attributes::must_use::MustUseParser;
@@ -123,6 +123,7 @@ mod late {
Single<ExportNameParser>,
Single<InlineParser>,
Single<LinkNameParser>,
Single<LinkSectionParser>,
Single<LoopMatchParser>,
Single<MayDangleParser>,
Single<MustUseParser>,
@@ -452,6 +452,13 @@ pub(crate) struct NullOnExport {
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_null_on_link_section, code = E0648)]
pub(crate) struct NullOnLinkSection {
#[primary_span]
pub span: Span,
}
#[derive(Diagnostic)]
#[diag(attr_parsing_stability_outside_std, code = E0734)]
pub(crate) struct StabilityOutsideStd {
@@ -124,6 +124,9 @@ 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::LinkSection { name, .. } => {
codegen_fn_attrs.link_section = Some(*name)
}
AttributeKind::NoMangle(attr_span) => {
if tcx.opt_item_name(did.to_def_id()).is_some() {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
@@ -253,16 +256,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
}
}
}
sym::link_section => {
if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) {
let msg = format!("illegal null byte in link_section value: `{val}`");
tcx.dcx().span_err(attr.span(), msg);
} else {
codegen_fn_attrs.link_section = Some(val);
}
}
}
sym::link_ordinal => {
link_ordinal_span = Some(attr.span());
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
+6 -4
View File
@@ -177,6 +177,9 @@ fn check_attributes(
Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
self.check_align(span, target, *align, *repr_span)
}
Attribute::Parsed(AttributeKind::LinkSection { span: attr_span, .. }) => {
self.check_link_section(hir_id, *attr_span, span, target)
}
Attribute::Parsed(AttributeKind::Naked(attr_span)) => {
self.check_naked(hir_id, *attr_span, span, target)
}
@@ -286,7 +289,6 @@ fn check_attributes(
[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_section, ..] => self.check_link_section(hir_id, attr, span, target),
[sym::macro_use, ..] | [sym::macro_escape, ..] => {
self.check_macro_use(hir_id, attr, target)
}
@@ -1831,7 +1833,7 @@ fn check_must_be_applied_to_trait(&self, attr_span: Span, defn_span: Span, targe
}
/// Checks if `#[link_section]` is applied to a function or static.
fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
fn check_link_section(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
match target {
Target::Static | Target::Fn | Target::Method(..) => {}
// FIXME(#80564): We permit struct fields, match arms and macro defs to have an
@@ -1839,7 +1841,7 @@ fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target
// 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_section");
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "link_section");
}
_ => {
// FIXME: #[link_section] was previously allowed on non-functions/statics and some
@@ -1847,7 +1849,7 @@ fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: Span, target
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span(),
attr_span,
errors::LinkSection { span },
);
}
+4 -1
View File
@@ -753,9 +753,12 @@ fn attributes_without_repr(&self, tcx: TyCtxt<'_>, is_json: bool) -> Vec<String>
.other_attrs
.iter()
.filter_map(|attr| {
if let hir::Attribute::Parsed(AttributeKind::LinkSection { name, .. }) = attr {
Some(format!("#[link_section = \"{name}\"]"))
}
// NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing.
// It is also used by cargo-semver-checks.
if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
else if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
Some("#[no_mangle]".to_string())
} else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
{
@@ -0,0 +1,6 @@
//@ edition: 2021
#![no_std]
//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]'
#[link_section = ".text"]
pub extern "C" fn example() {}
@@ -0,0 +1,9 @@
//@ edition: 2024
#![no_std]
// Since the 2024 edition the link_section attribute must use the unsafe qualification.
// However, the unsafe qualification is not shown by rustdoc.
//@ is "$.index[?(@.name=='example')].attrs" '["#[link_section = \".text\"]"]'
#[unsafe(link_section = ".text")]
pub extern "C" fn example() {}
@@ -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 function or static
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1
|
LL | #![link_section = "1800"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a 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 definition
--> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1
|
@@ -411,6 +403,14 @@ LL | #![link_name = "1900"]
|
= 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
|
LL | #![link_section = "1800"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ not a 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
|
@@ -102,4 +102,10 @@ pub fn no_mangle_test() {}
#[used] //~ ERROR unused attribute
static FOO: u32 = 0;
#[link_section = ".text"]
//~^ ERROR unused attribute
//~| WARN this was previously accepted
#[link_section = ".bss"]
pub extern "C" fn example() {}
fn main() {}
@@ -289,5 +289,18 @@ note: attribute also specified here
LL | #[used]
| ^^^^^^^
error: aborting due to 23 previous errors
error: unused attribute
--> $DIR/unused-attr-duplicate.rs:105:1
|
LL | #[link_section = ".text"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
|
note: attribute also specified here
--> $DIR/unused-attr-duplicate.rs:108:1
|
LL | #[link_section = ".bss"]
| ^^^^^^^^^^^^^^^^^^^^^^^^
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
error: aborting due to 24 previous errors