Skip to content

Commit 38ee95d

Browse files
committed
Port #[link_ordinal] to the new attribute parsing infrastructure
1 parent 5ca574e commit 38ee95d

File tree

15 files changed

+120
-97
lines changed

15 files changed

+120
-97
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

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

259+
/// Represents `#[link_ordinal]`.
260+
LinkOrdinal { ordinal: u16, span: Span },
261+
259262
/// Represents `#[loop_match]`.
260263
LoopMatch(Span),
261264

compiler/rustc_attr_data_structures/src/encode_cross_crate.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ impl AttributeKind {
3030
Cold(..) => No,
3131
ConstContinue(..) => No,
3232
LinkName { .. } => Yes,
33+
LinkOrdinal { .. } => Yes,
3334
LoopMatch(..) => No,
3435
MayDangle(..) => No,
3536
MustUse { .. } => Yes,

compiler/rustc_attr_parsing/messages.ftl

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ attr_parsing_ill_formed_attribute_input = {$num_suggestions ->
2828
*[other] valid forms for the attribute are {$suggestions}
2929
}
3030
31+
attr_parsing_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
32+
.note = an unsuffixed integer value, e.g., `1`, is expected
33+
3134
attr_parsing_incorrect_repr_format_align_one_arg =
3235
incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
3336
@@ -74,6 +77,9 @@ attr_parsing_invalid_repr_hint_no_value =
7477
attr_parsing_invalid_since =
7578
'since' must be a Rust version number, such as "1.31.0"
7679
80+
attr_parsing_link_ordinal_out_of_range = ordinal value in `link_ordinal` is too large: `{$ordinal}`
81+
.note = the value may not exceed `u16::MAX`
82+
7783
attr_parsing_missing_feature =
7884
missing 'feature'
7985

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;
3+
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkOrdinal};
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

1012
pub(crate) struct LinkNameParser;
1113

@@ -28,3 +30,51 @@ impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
2830
Some(LinkName { name, span: cx.attr_span })
2931
}
3032
}
33+
34+
pub(crate) struct LinkOrdinalParser;
35+
36+
impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
37+
const PATH: &[Symbol] = &[sym::link_ordinal];
38+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
39+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
40+
const TEMPLATE: AttributeTemplate = template!(List: "ordinal");
41+
42+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
43+
let Some(arg_list) = args.list() else {
44+
cx.expected_list(cx.attr_span);
45+
return None;
46+
};
47+
48+
let Some(single_arg) = arg_list.single() else {
49+
cx.expected_single_argument(cx.attr_span);
50+
return None;
51+
};
52+
53+
let Some(MetaItemLit { kind: LitKind::Int(ordinal, LitIntType::Unsuffixed), .. }) =
54+
single_arg.lit()
55+
else {
56+
cx.emit_err(InvalidLinkOrdinalFormat { span: cx.attr_span });
57+
return None;
58+
};
59+
60+
// According to the table at
61+
// https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the
62+
// ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
63+
// in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import
64+
// information to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
65+
//
66+
// FIXME: should we allow an ordinal of 0? The MSVC toolchain has inconsistent support for
67+
// this: both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that
68+
// specifies a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import
69+
// library for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an
70+
// import library produced by LLVM with an ordinal of 0, and it generates an .EXE. (I
71+
// don't know yet if the resulting EXE runs, as I haven't yet built the necessary DLL --
72+
// see earlier comment about LINK.EXE failing.)
73+
let Ok(ordinal) = ordinal.get().try_into() else {
74+
cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal: ordinal.get() });
75+
return None;
76+
};
77+
78+
Some(LinkOrdinal { ordinal, span: cx.attr_span })
79+
}
80+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ 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;
25+
use crate::attributes::link_attrs::{LinkNameParser, LinkOrdinalParser};
2626
use crate::attributes::lint_helpers::{AsPtrParser, PubTransparentParser};
2727
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
2828
use crate::attributes::must_use::MustUseParser;
@@ -123,6 +123,7 @@ attribute_parsers!(
123123
Single<ExportNameParser>,
124124
Single<InlineParser>,
125125
Single<LinkNameParser>,
126+
Single<LinkOrdinalParser>,
126127
Single<LoopMatchParser>,
127128
Single<MayDangleParser>,
128129
Single<MustUseParser>,

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,23 @@ pub(crate) struct NakedFunctionIncompatibleAttribute {
500500
pub attr: String,
501501
}
502502

503+
#[derive(Diagnostic)]
504+
#[diag(attr_parsing_illegal_link_ordinal_format)]
505+
#[note]
506+
pub(crate) struct InvalidLinkOrdinalFormat {
507+
#[primary_span]
508+
pub span: Span,
509+
}
510+
511+
#[derive(Diagnostic)]
512+
#[diag(attr_parsing_link_ordinal_out_of_range)]
513+
#[note]
514+
pub(crate) struct LinkOrdinalOutOfRange {
515+
#[primary_span]
516+
pub span: Span,
517+
pub ordinal: u128,
518+
}
519+
503520
pub(crate) enum AttributeParseErrorReason {
504521
ExpectedNoArgs,
505522
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
@@ -76,9 +76,6 @@ codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extensio
7676
7777
codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
7878
79-
codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
80-
.note = an unsuffixed integer value, e.g., `1`, is expected
81-
8279
codegen_ssa_incorrect_cgu_reuse_type =
8380
CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
8481
[one] {"at least "}
@@ -89,9 +86,6 @@ codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and i
8986
9087
codegen_ssa_invalid_instruction_set = invalid instruction set specified
9188
92-
codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
93-
.note = the attribute requires exactly one argument
94-
9589
codegen_ssa_invalid_literal_value = invalid literal value
9690
.label = value must be an integer between `0` and `255`
9791

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::NoMangle(attr_span) => {
128132
if tcx.opt_item_name(did.to_def_id()).is_some() {
129133
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
@@ -263,12 +267,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
263267
}
264268
}
265269
}
266-
sym::link_ordinal => {
267-
link_ordinal_span = Some(attr.span());
268-
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
269-
codegen_fn_attrs.link_ordinal = ordinal;
270-
}
271-
}
272270
sym::no_sanitize => {
273271
no_sanitize_span = Some(attr.span());
274272
if let Some(list) = attr.meta_item_list() {
@@ -569,45 +567,6 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
569567
false
570568
}
571569

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