Skip to content

Commit a87fe92

Browse files
Auto merge of #143217 - Periodic1911:link-ordinal, r=<try>
Port #[link_ordinal] to the new attribute parsing infrastructure Ports link_ordinal to the new attribute parsing infrastructure for #131229 (comment) try-job: x86_64-msvc-1 try-job: x86_64-msvc-2
2 parents a2d45f7 + d92419f commit a87fe92

File tree

20 files changed

+156
-149
lines changed

20 files changed

+156
-149
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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ attr_parsing_invalid_repr_hint_no_value =
7878
attr_parsing_invalid_since =
7979
'since' must be a Rust version number, such as "1.31.0"
8080
81+
attr_parsing_link_ordinal_out_of_range = ordinal value in `link_ordinal` is too large: `{$ordinal}`
82+
.note = the value may not exceed `u16::MAX`
83+
8184
attr_parsing_missing_feature =
8285
missing 'feature'
8386

compiler/rustc_attr_parsing/src/attributes/link_attrs.rs

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use rustc_attr_data_structures::AttributeKind;
2-
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkSection};
2+
use rustc_attr_data_structures::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
33
use rustc_feature::{AttributeTemplate, template};
44
use rustc_span::{Symbol, sym};
55

66
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
7-
use crate::context::{AcceptContext, Stage};
7+
use crate::context::{AcceptContext, Stage, parse_single_integer};
88
use crate::parser::ArgParser;
9-
use crate::session_diagnostics::NullOnLinkSection;
9+
use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection};
1010

1111
pub(crate) struct LinkNameParser;
1212

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

compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use rustc_ast::LitKind;
21
use rustc_attr_data_structures::AttributeKind;
32
use rustc_feature::{AttributeTemplate, template};
43
use rustc_span::{Symbol, sym};
54

65
use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
7-
use crate::context::{AcceptContext, Stage};
6+
use crate::context::{AcceptContext, Stage, parse_single_integer};
87
use crate::parser::ArgParser;
98

109
pub(crate) struct RustcLayoutScalarValidRangeStart;
@@ -16,8 +15,8 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeStart {
1615
const TEMPLATE: AttributeTemplate = template!(List: "start");
1716

1817
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
19-
parse_rustc_layout_scalar_valid_range(cx, args)
20-
.map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(n, cx.attr_span))
18+
parse_single_integer(cx, args)
19+
.map(|n| AttributeKind::RustcLayoutScalarValidRangeStart(Box::new(n), cx.attr_span))
2120
}
2221
}
2322

@@ -30,34 +29,11 @@ impl<S: Stage> SingleAttributeParser<S> for RustcLayoutScalarValidRangeEnd {
3029
const TEMPLATE: AttributeTemplate = template!(List: "end");
3130

3231
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
33-
parse_rustc_layout_scalar_valid_range(cx, args)
34-
.map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(n, cx.attr_span))
32+
parse_single_integer(cx, args)
33+
.map(|n| AttributeKind::RustcLayoutScalarValidRangeEnd(Box::new(n), cx.attr_span))
3534
}
3635
}
3736

38-
fn parse_rustc_layout_scalar_valid_range<S: Stage>(
39-
cx: &mut AcceptContext<'_, '_, S>,
40-
args: &ArgParser<'_>,
41-
) -> Option<Box<u128>> {
42-
let Some(list) = args.list() else {
43-
cx.expected_list(cx.attr_span);
44-
return None;
45-
};
46-
let Some(single) = list.single() else {
47-
cx.expected_single_argument(list.span);
48-
return None;
49-
};
50-
let Some(lit) = single.lit() else {
51-
cx.expected_integer_literal(single.span());
52-
return None;
53-
};
54-
let LitKind::Int(num, _ty) = lit.kind else {
55-
cx.expected_integer_literal(single.span());
56-
return None;
57-
};
58-
Some(Box::new(num.0))
59-
}
60-
6137
pub(crate) struct RustcObjectLifetimeDefaultParser;
6238

6339
impl<S: Stage> SingleAttributeParser<S> for RustcObjectLifetimeDefaultParser {

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::ops::{Deref, DerefMut};
55
use std::sync::LazyLock;
66

77
use private::Sealed;
8-
use rustc_ast::{self as ast, MetaItemLit, NodeId};
8+
use rustc_ast::{self as ast, LitKind, MetaItemLit, NodeId};
99
use rustc_attr_data_structures::AttributeKind;
1010
use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
1111
use rustc_errors::{DiagCtxtHandle, Diagnostic};
@@ -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, LinkSectionParser};
25+
use crate::attributes::link_attrs::{LinkNameParser, LinkOrdinalParser, LinkSectionParser};
2626
use crate::attributes::lint_helpers::{AsPtrParser, PassByValueParser, PubTransparentParser};
2727
use crate::attributes::loop_match::{ConstContinueParser, LoopMatchParser};
2828
use crate::attributes::must_use::MustUseParser;
@@ -131,6 +131,7 @@ attribute_parsers!(
131131
Single<IgnoreParser>,
132132
Single<InlineParser>,
133133
Single<LinkNameParser>,
134+
Single<LinkOrdinalParser>,
134135
Single<LinkSectionParser>,
135136
Single<MustUseParser>,
136137
Single<OptimizeParser>,
@@ -741,3 +742,32 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
741742
}
742743
}
743744
}
745+
746+
/// Parse a single integer.
747+
///
748+
/// Used by attributes that take a single integer as argument, such as
749+
/// `#[link_ordinal]` and `#[rustc_layout_scalar_valid_range_start]`.
750+
/// `cx` is the context given to the attribute.
751+
/// `args` is the parser for the attribute arguments.
752+
pub(crate) fn parse_single_integer<S: Stage>(
753+
cx: &mut AcceptContext<'_, '_, S>,
754+
args: &ArgParser<'_>,
755+
) -> Option<u128> {
756+
let Some(list) = args.list() else {
757+
cx.expected_list(cx.attr_span);
758+
return None;
759+
};
760+
let Some(single) = list.single() else {
761+
cx.expected_single_argument(list.span);
762+
return None;
763+
};
764+
let Some(lit) = single.lit() else {
765+
cx.expected_integer_literal(single.span());
766+
return None;
767+
};
768+
let LitKind::Int(num, _ty) = lit.kind else {
769+
cx.expected_integer_literal(single.span());
770+
return None;
771+
};
772+
Some(num.0)
773+
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

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

517+
#[derive(Diagnostic)]
518+
#[diag(attr_parsing_link_ordinal_out_of_range)]
519+
#[note]
520+
pub(crate) struct LinkOrdinalOutOfRange {
521+
#[primary_span]
522+
pub span: Span,
523+
pub ordinal: u128,
524+
}
525+
517526
pub(crate) enum AttributeParseErrorReason {
518527
ExpectedNoArgs,
519528
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
@@ -116,6 +116,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
116116
AttributeKind::Naked(_) => codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED,
117117
AttributeKind::Align { align, .. } => codegen_fn_attrs.alignment = Some(*align),
118118
AttributeKind::LinkName { name, .. } => codegen_fn_attrs.link_name = Some(*name),
119+
AttributeKind::LinkOrdinal { ordinal, span } => {
120+
codegen_fn_attrs.link_ordinal = Some(*ordinal);
121+
link_ordinal_span = Some(*span);
122+
}
119123
AttributeKind::LinkSection { name, .. } => {
120124
codegen_fn_attrs.link_section = Some(*name)
121125
}
@@ -248,12 +252,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
248252
}
249253
}
250254
}
251-
sym::link_ordinal => {
252-
link_ordinal_span = Some(attr.span());
253-
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
254-
codegen_fn_attrs.link_ordinal = ordinal;
255-
}
256-
}
257255
sym::no_sanitize => {
258256
no_sanitize_span = Some(attr.span());
259257
if let Some(list) = attr.meta_item_list() {
@@ -566,45 +564,6 @@ fn inherited_align<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Align> {
566564
tcx.codegen_fn_attrs(opt_trait_item(tcx, def_id)?).alignment
567565
}
568566

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

1111-
#[derive(Diagnostic)]
1112-
#[diag(codegen_ssa_invalid_link_ordinal_nargs)]
1113-
#[note]
1114-
pub(crate) struct InvalidLinkOrdinalNargs {
1115-
#[primary_span]
1116-
pub span: Span,
1117-
}
1118-
1119-
#[derive(Diagnostic)]
1120-
#[diag(codegen_ssa_illegal_link_ordinal_format)]
1121-
#[note]
1122-
pub(crate) struct InvalidLinkOrdinalFormat {
1123-
#[primary_span]
1124-
pub span: Span,
1125-
}
1126-
11271111
#[derive(Diagnostic)]
11281112
#[diag(codegen_ssa_target_feature_safe_trait)]
11291113
pub(crate) struct TargetFeatureSafeTrait {

0 commit comments

Comments
 (0)