Skip to content

Commit 612fce2

Browse files
Port #[export_name] to the new attribute parsing infrastructure
Signed-off-by: Jonathan Brouwer <[email protected]>
1 parent 3129d37 commit 612fce2

File tree

12 files changed

+85
-46
lines changed

12 files changed

+85
-46
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,14 @@ pub enum AttributeKind {
228228
/// Represents [`#[doc]`](https://doc.rust-lang.org/stable/rustdoc/write-documentation/the-doc-attribute.html).
229229
DocComment { style: AttrStyle, kind: CommentKind, span: Span, comment: Symbol },
230230

231+
/// Represents [`#[export_name]`](https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute).
232+
ExportName {
233+
/// The name to export this item with.
234+
/// It may not contain \0 bytes as it will be converted to a null-terminated string.
235+
name: Symbol,
236+
span: Span,
237+
},
238+
231239
/// Represents `#[inline]` and `#[rustc_force_inline]`.
232240
Inline(InlineAttr, Span),
233241

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,12 @@ attr_parsing_naked_functions_incompatible_attribute =
9393
attribute incompatible with `#[unsafe(naked)]`
9494
.label = the `{$attr}` attribute is incompatible with `#[unsafe(naked)]`
9595
.naked_attribute = function marked with `#[unsafe(naked)]` here
96+
9697
attr_parsing_non_ident_feature =
9798
'feature' is not an identifier
9899
100+
attr_parsing_null_on_export = `export_name` may not contain null characters
101+
99102
attr_parsing_repr_ident =
100103
meta item in `repr` must be an identifier
101104

compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_span::{Span, sym};
66
use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser};
77
use crate::context::{AcceptContext, FinalizeContext, Stage};
88
use crate::parser::ArgParser;
9-
use crate::session_diagnostics::NakedFunctionIncompatibleAttribute;
9+
use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport};
1010

1111
pub(crate) struct OptimizeParser;
1212

@@ -59,6 +59,33 @@ impl<S: Stage> SingleAttributeParser<S> for ColdParser {
5959
}
6060
}
6161

62+
pub(crate) struct ExportNameParser;
63+
64+
impl<S: Stage> SingleAttributeParser<S> for ExportNameParser {
65+
const PATH: &[rustc_span::Symbol] = &[sym::export_name];
66+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
67+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
68+
const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
69+
70+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
71+
let Some(nv) = args.name_value() else {
72+
cx.expected_name_value(cx.attr_span, None);
73+
return None;
74+
};
75+
let Some(name) = nv.value_as_str() else {
76+
cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
77+
return None;
78+
};
79+
if name.as_str().contains('\0') {
80+
// `#[export_name = ...]` will be converted to a null-terminated string,
81+
// so it may not contain any null characters.
82+
cx.emit_err(NullOnExport { span: cx.attr_span });
83+
return None;
84+
}
85+
Some(AttributeKind::ExportName { name, span: cx.attr_span })
86+
}
87+
}
88+
6289
#[derive(Default)]
6390
pub(crate) struct NakedParser {
6491
span: Option<Span>,

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use rustc_session::Session;
1515
use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym};
1616

1717
use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser};
18-
use crate::attributes::codegen_attrs::{ColdParser, NakedParser, NoMangleParser, OptimizeParser};
18+
use crate::attributes::codegen_attrs::{
19+
ColdParser, ExportNameParser, NakedParser, NoMangleParser, OptimizeParser,
20+
};
1921
use crate::attributes::confusables::ConfusablesParser;
2022
use crate::attributes::deprecation::DeprecationParser;
2123
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
@@ -113,6 +115,7 @@ attribute_parsers!(
113115
Single<ColdParser>,
114116
Single<ConstStabilityIndirectParser>,
115117
Single<DeprecationParser>,
118+
Single<ExportNameParser>,
116119
Single<InlineParser>,
117120
Single<MayDangleParser>,
118121
Single<MustUseParser>,

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,13 @@ pub(crate) struct MustUseIllFormedAttributeInput {
445445
pub suggestions: DiagArgValue,
446446
}
447447

448+
#[derive(Diagnostic)]
449+
#[diag(attr_parsing_null_on_export, code = E0648)]
450+
pub(crate) struct NullOnExport {
451+
#[primary_span]
452+
pub span: Span,
453+
}
454+
448455
#[derive(Diagnostic)]
449456
#[diag(attr_parsing_stability_outside_std, code = E0734)]
450457
pub(crate) struct StabilityOutsideStd {

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,6 @@ codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
230230
231231
codegen_ssa_no_saved_object_file = cached cgu {$cgu_name} should have an object file, but doesn't
232232
233-
codegen_ssa_null_on_export = `export_name` may not contain null characters
234-
235233
codegen_ssa_out_of_range_integer = integer value out of range
236234
.label = value must be between `0` and `255`
237235

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
121121
.max();
122122
}
123123
AttributeKind::Cold(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD,
124+
AttributeKind::ExportName { name, span: attr_span } => {
125+
codegen_fn_attrs.export_name = Some(*name);
126+
mixed_export_name_no_mangle_lint_state.track_export_name(*attr_span);
127+
}
124128
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
125129
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
126130
AttributeKind::NoMangle(attr_span) => {
@@ -225,17 +229,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
225229
}
226230
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER
227231
}
228-
sym::export_name => {
229-
if let Some(s) = attr.value_str() {
230-
if s.as_str().contains('\0') {
231-
// `#[export_name = ...]` will be converted to a null-terminated string,
232-
// so it may not contain any null characters.
233-
tcx.dcx().emit_err(errors::NullOnExport { span: attr.span() });
234-
}
235-
codegen_fn_attrs.export_name = Some(s);
236-
mixed_export_name_no_mangle_lint_state.track_export_name(attr.span());
237-
}
238-
}
239232
sym::target_feature => {
240233
let Some(sig) = tcx.hir_node_by_def_id(did).fn_sig() else {
241234
tcx.dcx().span_delayed_bug(attr.span(), "target_feature applied to non-fn");

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,6 @@ pub(crate) struct RequiresRustAbi {
140140
pub span: Span,
141141
}
142142

143-
#[derive(Diagnostic)]
144-
#[diag(codegen_ssa_null_on_export, code = E0648)]
145-
pub(crate) struct NullOnExport {
146-
#[primary_span]
147-
pub span: Span,
148-
}
149-
150143
#[derive(Diagnostic)]
151144
#[diag(codegen_ssa_unsupported_instruction_set, code = E0779)]
152145
pub(crate) struct UnsupportedInstructionSet {

compiler/rustc_lint/src/builtin.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -977,9 +977,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
977977
};
978978
match it.kind {
979979
hir::ItemKind::Fn { generics, .. } => {
980-
if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name)
981-
.map(|at| at.span())
982-
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
980+
if let Some(attr_span) =
981+
find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
982+
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
983983
{
984984
check_no_mangle_on_generic_fn(attr_span, None, generics, it.span);
985985
}
@@ -1010,9 +1010,11 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems {
10101010
for it in *items {
10111011
if let hir::AssocItemKind::Fn { .. } = it.kind {
10121012
let attrs = cx.tcx.hir_attrs(it.id.hir_id());
1013-
if let Some(attr_span) = attr::find_by_name(attrs, sym::export_name)
1014-
.map(|at| at.span())
1015-
.or_else(|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span))
1013+
if let Some(attr_span) =
1014+
find_attr!(attrs, AttributeKind::ExportName {span, ..} => *span)
1015+
.or_else(
1016+
|| find_attr!(attrs, AttributeKind::NoMangle(span) => *span),
1017+
)
10161018
{
10171019
check_no_mangle_on_generic_fn(
10181020
attr_span,

compiler/rustc_passes/src/check_attr.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
163163
Attribute::Parsed(AttributeKind::Cold(attr_span)) => {
164164
self.check_cold(hir_id, *attr_span, span, target)
165165
}
166+
Attribute::Parsed(AttributeKind::ExportName { span: attr_span, .. }) => {
167+
self.check_export_name(hir_id, *attr_span, span, target)
168+
}
166169
Attribute::Parsed(AttributeKind::Align { align, span: repr_span }) => {
167170
self.check_align(span, target, *align, *repr_span)
168171
}
@@ -217,7 +220,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
217220
&mut doc_aliases,
218221
),
219222
[sym::no_link, ..] => self.check_no_link(hir_id, attr, span, target),
220-
[sym::export_name, ..] => self.check_export_name(hir_id, attr, span, target),
221223
[sym::rustc_layout_scalar_valid_range_start, ..]
222224
| [sym::rustc_layout_scalar_valid_range_end, ..] => {
223225
self.check_rustc_layout_scalar_valid_range(attr, span, target)
@@ -1649,7 +1651,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
16491651
}
16501652

16511653
/// Checks if `#[export_name]` is applied to a function or static.
1652-
fn check_export_name(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) {
1654+
fn check_export_name(&self, hir_id: HirId, attr_span: Span, span: Span, target: Target) {
16531655
match target {
16541656
Target::Static | Target::Fn => {}
16551657
Target::Method(..) if self.is_impl_item(hir_id) => {}
@@ -1658,10 +1660,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
16581660
// erroneously allowed it and some crates used it accidentally, to be compatible
16591661
// with crates depending on them, we can't throw an error here.
16601662
Target::Field | Target::Arm | Target::MacroDef => {
1661-
self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name");
1663+
self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "export_name");
16621664
}
16631665
_ => {
1664-
self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span });
1666+
self.dcx().emit_err(errors::ExportName { attr_span, span });
16651667
}
16661668
}
16671669
}

src/librustdoc/clean/types.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -755,8 +755,11 @@ impl Item {
755755
.filter_map(|attr| {
756756
// NoMangle is special cased, as it appears in HTML output, and we want to show it in source form, not HIR printing.
757757
// It is also used by cargo-semver-checks.
758-
if matches!(attr, hir::Attribute::Parsed(AttributeKind::NoMangle(..))) {
758+
if let hir::Attribute::Parsed(AttributeKind::NoMangle(..)) = attr {
759759
Some("#[no_mangle]".to_string())
760+
} else if let hir::Attribute::Parsed(AttributeKind::ExportName { name, .. }) = attr
761+
{
762+
Some(format!("#[export_name = \"{name}\"]"))
760763
} else if is_json {
761764
match attr {
762765
// rustdoc-json stores this in `Item::deprecation`, so we

tests/ui/lint/unused/unused-attr-duplicate.stderr

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,6 @@ note: attribute also specified here
101101
LL | #[track_caller]
102102
| ^^^^^^^^^^^^^^^
103103

104-
error: unused attribute
105-
--> $DIR/unused-attr-duplicate.rs:92:1
106-
|
107-
LL | #[export_name = "exported_symbol_name"]
108-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
109-
|
110-
note: attribute also specified here
111-
--> $DIR/unused-attr-duplicate.rs:94:1
112-
|
113-
LL | #[export_name = "exported_symbol_name2"]
114-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
115-
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
116-
117104
error: unused attribute
118105
--> $DIR/unused-attr-duplicate.rs:102:1
119106
|
@@ -277,6 +264,19 @@ note: attribute also specified here
277264
LL | #[cold]
278265
| ^^^^^^^
279266

267+
error: unused attribute
268+
--> $DIR/unused-attr-duplicate.rs:92:1
269+
|
270+
LL | #[export_name = "exported_symbol_name"]
271+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove this attribute
272+
|
273+
note: attribute also specified here
274+
--> $DIR/unused-attr-duplicate.rs:94:1
275+
|
276+
LL | #[export_name = "exported_symbol_name2"]
277+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
278+
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
279+
280280
error: unused attribute
281281
--> $DIR/unused-attr-duplicate.rs:98:1
282282
|

0 commit comments

Comments
 (0)