rustc_attr_parsing/attributes/
link_attrs.rs

1use rustc_attr_data_structures::AttributeKind;
2use rustc_attr_data_structures::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
3use rustc_feature::{AttributeTemplate, template};
4use rustc_span::{Span, Symbol, sym};
5
6use crate::attributes::{
7    AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
8};
9use crate::context::{AcceptContext, Stage, parse_single_integer};
10use crate::parser::ArgParser;
11use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection};
12
13pub(crate) struct LinkNameParser;
14
15impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
16    const PATH: &[Symbol] = &[sym::link_name];
17    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
18    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
19    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
20
21    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
22        let Some(nv) = args.name_value() else {
23            cx.expected_name_value(cx.attr_span, None);
24            return None;
25        };
26        let Some(name) = nv.value_as_str() else {
27            cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
28            return None;
29        };
30
31        Some(LinkName { name, span: cx.attr_span })
32    }
33}
34
35pub(crate) struct LinkSectionParser;
36
37impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
38    const PATH: &[Symbol] = &[sym::link_section];
39    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
40    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
41    const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");
42
43    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
44        let Some(nv) = args.name_value() else {
45            cx.expected_name_value(cx.attr_span, None);
46            return None;
47        };
48        let Some(name) = nv.value_as_str() else {
49            cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
50            return None;
51        };
52        if name.as_str().contains('\0') {
53            // `#[link_section = ...]` will be converted to a null-terminated string,
54            // so it may not contain any null characters.
55            cx.emit_err(NullOnLinkSection { span: cx.attr_span });
56            return None;
57        }
58
59        Some(LinkSection { name, span: cx.attr_span })
60    }
61}
62
63pub(crate) struct ExportStableParser;
64impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
65    const PATH: &[Symbol] = &[sym::export_stable];
66    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
67    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
68}
69
70pub(crate) struct FfiConstParser;
71impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
72    const PATH: &[Symbol] = &[sym::ffi_const];
73    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
74    const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
75}
76
77pub(crate) struct FfiPureParser;
78impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
79    const PATH: &[Symbol] = &[sym::ffi_pure];
80    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
81    const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
82}
83
84pub(crate) struct StdInternalSymbolParser;
85impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
86    const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
87    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
88    const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
89}
90
91pub(crate) struct LinkOrdinalParser;
92
93impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
94    const PATH: &[Symbol] = &[sym::link_ordinal];
95    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
96    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
97    const TEMPLATE: AttributeTemplate = template!(List: "ordinal");
98
99    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
100        let ordinal = parse_single_integer(cx, args)?;
101
102        // According to the table at
103        // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the
104        // ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
105        // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import
106        // information to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
107        //
108        // FIXME: should we allow an ordinal of 0?  The MSVC toolchain has inconsistent support for
109        // this: both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that
110        // specifies a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import
111        // library for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an
112        // import library produced by LLVM with an ordinal of 0, and it generates an .EXE.  (I
113        // don't know yet if the resulting EXE runs, as I haven't yet built the necessary DLL --
114        // see earlier comment about LINK.EXE failing.)
115        let Ok(ordinal) = ordinal.try_into() else {
116            cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
117            return None;
118        };
119
120        Some(LinkOrdinal { ordinal, span: cx.attr_span })
121    }
122}