mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Port #[link_section] to the new attribute parsing infrastructure
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 },
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user