Skip to content

Commit 655d92d

Browse files
committed
Port #[link_ordinal] to the new attribute parsing infrastructure
1 parent de031bb commit 655d92d

File tree

15 files changed

+121
-98
lines changed

15 files changed

+121
-98
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,9 @@ pub enum AttributeKind {
261261
/// Represents `#[link_name]`.
262262
LinkName { name: Symbol, span: Span },
263263

264+
/// Represents `#[link_ordinal]`.
265+
LinkOrdinal { ordinal: u16, span: Span },
266+
264267
/// Represents [`#[link_section]`](https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute)
265268
LinkSection { name: Symbol, span: Span },
266269

compiler/rustc_attr_data_structures/src/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ impl AttributeKind {
2929
Ignore { .. } => No,
3030
Inline(..) => No,
3131
LinkName { .. } => Yes,
32+
LinkOrdinal { .. } => Yes,
3233
LinkSection { .. } => No,
3334
LoopMatch(..) => No,
3435
MacroTransparency(..) => Yes,

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ attr_parsing_ill_formed_attribute_input = {$num_suggestions ->
3232
*[other] valid forms for the attribute are {$suggestions}
3333
}
3434
35+
attr_parsing_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
36+
.note = an unsuffixed integer value, e.g., `1`, is expected
37+
3538
attr_parsing_incorrect_repr_format_align_one_arg =
3639
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
3740
@@ -78,6 +81,9 @@ attr_parsing_invalid_repr_hint_no_value =
7881
attr_parsing_invalid_since =
7982
'since' must be a Rust version number, such as "1.31.0"
8083
84+
attr_parsing_link_ordinal_out_of_range = ordinal value in `link_ordinal` is too large: `{$ordinal}`
85+
.note = the value may not exceed `u16::MAX`
86+
8187
attr_parsing_missing_feature =
8288
missing 'feature'
8389

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1+
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
12
use rustc_attr_data_structures::AttributeKind;
2-
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkSection};
3+
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
34
use rustc_feature::{AttributeTemplate, template};
45
use rustc_span::{Symbol, sym};
56

67
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
78
use crate::context::{AcceptContext, Stage};
89
use crate::parser::ArgParser;
10+
use crate::session_diagnostics::{InvalidLinkOrdinalFormat, LinkOrdinalOutOfRange};
911
use crate::session_diagnostics::NullOnLinkSection;
1012

1113
pub(crate) struct LinkNameParser;
@@ -57,3 +59,51 @@ impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
5759
Some(LinkSection { name, span: cx.attr_span })
5860
}
5961
}
62+
63+
pub(crate) struct LinkOrdinalParser;
64+
65+
impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
66+
const PATH: &[Symbol] = &[sym::link_ordinal];
67+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
68+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
69+
const TEMPLATE: AttributeTemplate = template!(List: "ordinal");
70+
71+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
72+
let Some(arg_list) = args.list() else {
73+
cx.expected_list(cx.attr_span);
74+
return None;
75+
};
76+
77+
let Some(single_arg) = arg_list.single() else {
78+
cx.expected_single_argument(cx.attr_span);
79+
return None;
80+
};
81+
82+
let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
83+
single_arg.lit()
84+
else {
85+
cx.emit_err(InvalidLinkOrdinalFormat { span: cx.attr_span });
86+
return None;
87+
};
88+
89+
// According to the table at
90+
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the
91+
// ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
92+
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import
93+
// information to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
94+
//
95+
// FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for
96+
// this: both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that
97+
// specifies a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import
98+
// library for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an
99+
// import library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I
100+
// don't know yet if the resulting EXE runs, as I haven't yet built the necessary DLL --
101+
// see earlier comment about LINK.EXE failing.)
102+
let Ok(ordinal) = ordinal.get().try_into() else {
103+
cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal: ordinal.get() });
104+
return None;
105+
};
106+
107+
Some(LinkOrdinal { ordinal, span: cx.attr_span })
108+
}
109+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use crate::attributes::codegen_attrs::{
2222
use crate::attributes::confusables::ConfusablesParser;
2323
use crate::attributes::deprecation::DeprecationParser;
2424
use crate::attributes::inline::{InlineParser, RustcForceInlineParser};
25-
use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser};
26-
use crate::attributes::lint_helpers::{AsPtrParser, PassByValueParser, PubTransparentParser};
25+
use crate::attributes::link_attrs::{LinkNameParser, LinkSectionParser, LinkOrdinalParser};
26+
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
2727
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
2828
use crate::attributes::must_use::MustUseParser;
2929
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
@@ -130,6 +130,7 @@ attribute_parsers!(
130130
Single<IgnoreParser>,
131131
Single<InlineParser>,
132132
Single<LinkNameParser>,
133+
Single<LinkOrdinalParser>,
133134
Single<LinkSectionParser>,
134135
Single<MustUseParser>,
135136
Single<OptimizeParser>,

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,23 @@ pub(crate) struct NakedFunctionIncompatibleAttribute {
514514
pub attr: String,
515515
}
516516

517+
#[derive(Diagnostic)]
518+
#[diag(attr_parsing_illegal_link_ordinal_format)]
519+
#[note]
520+
pub(crate) struct InvalidLinkOrdinalFormat {
521+
#[primary_span]
522+
pub span: Span,
523+
}
524+
525+
#[derive(Diagnostic)]
526+
#[diag(attr_parsing_link_ordinal_out_of_range)]
527+
#[note]
528+
pub(crate) struct LinkOrdinalOutOfRange {
529+
#[primary_span]
530+
pub span: Span,
531+
pub ordinal: u128,
532+
}
533+
517534
pub(crate) enum AttributeParseErrorReason {
518535
ExpectedNoArgs,
519536
ExpectedStringLiteral { byte_string: Option<Span> },

compiler/rustc_codegen_ssa/messages.ftl

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,6 @@ codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extensio
8080
8181
codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
8282
83-
codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
84-
.note = an unsuffixed integer value, e.g., `1`, is expected
85-
8683
codegen_ssa_incorrect_cgu_reuse_type =
8784
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
8885
[one] {"at least "}
@@ -93,9 +90,6 @@ codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and i
9390
9491
codegen_ssa_invalid_instruction_set = invalid instruction set specified
9592
96-
codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
97-
.note = the attribute requires exactly one argument
98-
9993
codegen_ssa_invalid_literal_value = invalid literal value
10094
.label = value must be an integer between `0` and `255`
10195

compiler/rustc_codegen_ssa/src/codegen_attrs.rs

Lines changed: 4 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
124124
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
125125
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
126126
AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
127+
AttributeKind::LinkOrdinal { ordinal, span } => {
128+
codegen_fn_attrs.link_ordinal = Some(*ordinal);
129+
link_ordinal_span = Some(*span);
130+
}
127131
AttributeKind::LinkSection { name, .. } => {
128132
codegen_fn_attrs.link_section = Some(*name)
129133
}
@@ -256,12 +260,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
256260
}
257261
}
258262
}
259-
sym::link_ordinal => {
260-
link_ordinal_span = Some(attr.span());
261-
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
262-
codegen_fn_attrs.link_ordinal = ordinal;
263-
}
264-
}
265263
sym::no_sanitize => {
266264
no_sanitize_span = Some(attr.span());
267265
if let Some(list) = attr.meta_item_list() {
@@ -574,45 +572,6 @@ fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> {
574572
tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment
575573
}
576574

577-
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &hir::Attribute) -> Option<u16> {
578-
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
579-
let meta_item_list = attr.meta_item_list()?;
580-
let [sole_meta_list] = &meta_item_list[..] else {
581-
tcx.dcx().emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span() });
582-
return None;
583-
};
584-
if let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
585-
sole_meta_list.lit()
586-
{
587-
// According to the table at
588-
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the
589-
// ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
590-
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import
591-
// information to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
592-
//
593-
// FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for
594-
// this: both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that
595-
// specifies a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import
596-
// library for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an
597-
// import library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I
598-
// don't know yet if the resulting EXE runs, as I haven't yet built the necessary DLL --
599-
// see earlier comment about LINK.EXE failing.)
600-
if *ordinal <= u16::MAX as u128 {
601-
Some(ordinal.get() as u16)
602-
} else {
603-
let msg = format!("ordinal value in `link_ordinal` is too large: `{ordinal}`");
604-
tcx.dcx()
605-
.struct_span_err(attr.span(), msg)
606-
.with_note("the value may not exceed `u16::MAX`")
607-
.emit();
608-
None
609-
}
610-
} else {
611-
tcx.dcx().emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span() });
612-
None
613-
}
614-
}
615-
616575
fn check_link_name_xor_ordinal(
617576
tcx: TyCtxt<'_>,
618577
codegen_fn_attrs: &CodegenFnAttrs,

compiler/rustc_codegen_ssa/src/errors.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1101,22 +1101,6 @@ pub(crate) struct InvalidNoSanitize {
11011101
pub span: Span,
11021102
}
11031103

1104-
#[derive(Diagnostic)]
1105-
#[diag(codegen_ssa_invalid_link_ordinal_nargs)]
1106-
#[note]
1107-
pub(crate) struct InvalidLinkOrdinalNargs {
1108-
#[primary_span]
1109-
pub span: Span,
1110-
}
1111-
1112-
#[derive(Diagnostic)]
1113-
#[diag(codegen_ssa_illegal_link_ordinal_format)]
1114-
#[note]
1115-
pub(crate) struct InvalidLinkOrdinalFormat {
1116-
#[primary_span]
1117-
pub span: Span,
1118-
}
1119-
11201104
#[derive(Diagnostic)]
11211105
#[diag(codegen_ssa_target_feature_safe_trait)]
11221106
pub(crate) struct TargetFeatureSafeTrait {

compiler/rustc_metadata/src/native_libs.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
33

44
use rustc_abi::ExternAbi;
55
use rustc_ast::CRATE_NODE_ID;
6+
use rustc_attr_data_structures::{AttributeKind, find_attr};
67
use rustc_attr_parsing as attr;
78
use rustc_data_structures::fx::FxHashSet;
89
use rustc_middle::query::LocalCrate;
@@ -496,14 +497,9 @@ impl<'tcx> Collector<'tcx> {
496497
}
497498
_ => {
498499
for &child_item in foreign_items {
499-
if self.tcx.def_kind(child_item).has_codegen_attrs()
500-
&& self.tcx.codegen_fn_attrs(child_item).link_ordinal.is_some()
500+
if let Some(span) = find_attr!(self.tcx.get_all_attrs(child_item), AttributeKind::LinkOrdinal {span, ..} => *span)
501501
{
502-
let link_ordinal_attr =
503-
self.tcx.get_attr(child_item, sym::link_ordinal).unwrap();
504-
sess.dcx().emit_err(errors::LinkOrdinalRawDylib {
505-
span: link_ordinal_attr.span(),
506-
});
502+
sess.dcx().emit_err(errors::LinkOrdinalRawDylib { span });
507503
}
508504
}
509505

0 commit comments

Comments
 (0)