rustc_attr_parsing/attributes/
link_attrs.rs

1use rustc_feature::{AttributeTemplate, template};
2use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
3use rustc_hir::attrs::{AttributeKind, Linkage};
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!(
20        NameValueStr: "name",
21        "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
22    );
23
24    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
25        let Some(nv) = args.name_value() else {
26            cx.expected_name_value(cx.attr_span, None);
27            return None;
28        };
29        let Some(name) = nv.value_as_str() else {
30            cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
31            return None;
32        };
33
34        Some(LinkName { name, span: cx.attr_span })
35    }
36}
37
38pub(crate) struct LinkSectionParser;
39
40impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
41    const PATH: &[Symbol] = &[sym::link_section];
42    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
43    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
44    const TEMPLATE: AttributeTemplate = template!(
45        NameValueStr: "name",
46        "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
47    );
48
49    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
50        let Some(nv) = args.name_value() else {
51            cx.expected_name_value(cx.attr_span, None);
52            return None;
53        };
54        let Some(name) = nv.value_as_str() else {
55            cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
56            return None;
57        };
58        if name.as_str().contains('\0') {
59            // `#[link_section = ...]` will be converted to a null-terminated string,
60            // so it may not contain any null characters.
61            cx.emit_err(NullOnLinkSection { span: cx.attr_span });
62            return None;
63        }
64
65        Some(LinkSection { name, span: cx.attr_span })
66    }
67}
68
69pub(crate) struct ExportStableParser;
70impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
71    const PATH: &[Symbol] = &[sym::export_stable];
72    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
73    const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
74}
75
76pub(crate) struct FfiConstParser;
77impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
78    const PATH: &[Symbol] = &[sym::ffi_const];
79    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
80    const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
81}
82
83pub(crate) struct FfiPureParser;
84impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
85    const PATH: &[Symbol] = &[sym::ffi_pure];
86    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
87    const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
88}
89
90pub(crate) struct StdInternalSymbolParser;
91impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
92    const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
93    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
94    const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
95}
96
97pub(crate) struct LinkOrdinalParser;
98
99impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
100    const PATH: &[Symbol] = &[sym::link_ordinal];
101    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
102    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
103    const TEMPLATE: AttributeTemplate = template!(
104        List: &["ordinal"],
105        "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
106    );
107
108    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
109        let ordinal = parse_single_integer(cx, args)?;
110
111        // According to the table at
112        // https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-header, the
113        // ordinal must fit into 16 bits. Similarly, the Ordinal field in COFFShortExport (defined
114        // in llvm/include/llvm/Object/COFFImportFile.h), which we use to communicate import
115        // information to LLVM for `#[link(kind = "raw-dylib"_])`, is also defined to be uint16_t.
116        //
117        // FIXME: should we allow an ordinal of 0?  The MSVC toolchain has inconsistent support for
118        // this: both LINK.EXE and LIB.EXE signal errors and abort when given a .DEF file that
119        // specifies a zero ordinal. However, llvm-dlltool is perfectly happy to generate an import
120        // library for such a .DEF file, and MSVC's LINK.EXE is also perfectly happy to consume an
121        // import library produced by LLVM with an ordinal of 0, and it generates an .EXE.  (I
122        // don't know yet if the resulting EXE runs, as I haven't yet built the necessary DLL --
123        // see earlier comment about LINK.EXE failing.)
124        let Ok(ordinal) = ordinal.try_into() else {
125            cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
126            return None;
127        };
128
129        Some(LinkOrdinal { ordinal, span: cx.attr_span })
130    }
131}
132
133pub(crate) struct LinkageParser;
134
135impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
136    const PATH: &[Symbol] = &[sym::linkage];
137
138    const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
139
140    const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
141
142    const TEMPLATE: AttributeTemplate = template!(NameValueStr: [
143        "available_externally",
144        "common",
145        "extern_weak",
146        "external",
147        "internal",
148        "linkonce",
149        "linkonce_odr",
150        "weak",
151        "weak_odr",
152    ]);
153
154    fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
155        let Some(name_value) = args.name_value() else {
156            cx.expected_name_value(cx.attr_span, Some(sym::linkage));
157            return None;
158        };
159
160        let Some(value) = name_value.value_as_str() else {
161            cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
162            return None;
163        };
164
165        // Use the names from src/llvm/docs/LangRef.rst here. Most types are only
166        // applicable to variable declarations and may not really make sense for
167        // Rust code in the first place but allow them anyway and trust that the
168        // user knows what they're doing. Who knows, unanticipated use cases may pop
169        // up in the future.
170        //
171        // ghost, dllimport, dllexport and linkonce_odr_autohide are not supported
172        // and don't have to be, LLVM treats them as no-ops.
173        let linkage = match value {
174            sym::available_externally => Linkage::AvailableExternally,
175            sym::common => Linkage::Common,
176            sym::extern_weak => Linkage::ExternalWeak,
177            sym::external => Linkage::External,
178            sym::internal => Linkage::Internal,
179            sym::linkonce => Linkage::LinkOnceAny,
180            sym::linkonce_odr => Linkage::LinkOnceODR,
181            sym::weak => Linkage::WeakAny,
182            sym::weak_odr => Linkage::WeakODR,
183
184            _ => {
185                cx.expected_specific_argument(
186                    name_value.value_span,
187                    vec![
188                        "available_externally",
189                        "common",
190                        "extern_weak",
191                        "external",
192                        "internal",
193                        "linkonce",
194                        "linkonce_odr",
195                        "weak",
196                        "weak_odr",
197                    ],
198                );
199                return None;
200            }
201        };
202
203        Some(AttributeKind::Linkage(linkage, cx.attr_span))
204    }
205}