rustc_attr_parsing/attributes/
link_attrs.rs1use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
2use rustc_hir::attrs::Linkage;
3
4use super::prelude::*;
5use super::util::parse_single_integer;
6use crate::session_diagnostics::{LinkOrdinalOutOfRange, NullOnLinkSection};
7
8pub(crate) struct LinkNameParser;
9
10impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
11 const PATH: &[Symbol] = &[sym::link_name];
12 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
13 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
14 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
15 Allow(Target::ForeignFn),
16 Allow(Target::ForeignStatic),
17 ]);
18 const TEMPLATE: AttributeTemplate = template!(
19 NameValueStr: "name",
20 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
21 );
22
23 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
24 let Some(nv) = args.name_value() else {
25 cx.expected_name_value(cx.attr_span, None);
26 return None;
27 };
28 let Some(name) = nv.value_as_str() else {
29 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
30 return None;
31 };
32
33 Some(LinkName { name, span: cx.attr_span })
34 }
35}
36
37pub(crate) struct LinkSectionParser;
38
39impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
40 const PATH: &[Symbol] = &[sym::link_section];
41 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
42 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
43 const ALLOWED_TARGETS: AllowedTargets =
44 AllowedTargets::AllowListWarnRest(&[Allow(Target::Static), Allow(Target::Fn)]);
45 const TEMPLATE: AttributeTemplate = template!(
46 NameValueStr: "name",
47 "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
48 );
49
50 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
51 let Some(nv) = args.name_value() else {
52 cx.expected_name_value(cx.attr_span, None);
53 return None;
54 };
55 let Some(name) = nv.value_as_str() else {
56 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
57 return None;
58 };
59 if name.as_str().contains('\0') {
60 cx.emit_err(NullOnLinkSection { span: cx.attr_span });
63 return None;
64 }
65
66 Some(LinkSection { name, span: cx.attr_span })
67 }
68}
69
70pub(crate) struct ExportStableParser;
71impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
72 const PATH: &[Symbol] = &[sym::export_stable];
73 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
74 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
76}
77
78pub(crate) struct FfiConstParser;
79impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
80 const PATH: &[Symbol] = &[sym::ffi_const];
81 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
82 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
83 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
84}
85
86pub(crate) struct FfiPureParser;
87impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
88 const PATH: &[Symbol] = &[sym::ffi_pure];
89 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
90 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
91 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
92}
93
94pub(crate) struct StdInternalSymbolParser;
95impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
96 const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
97 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
98 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
99 Allow(Target::Fn),
100 Allow(Target::ForeignFn),
101 Allow(Target::Static),
102 Allow(Target::ForeignStatic),
103 ]);
104 const CREATE: fn(Span) -> AttributeKind = AttributeKind::StdInternalSymbol;
105}
106
107pub(crate) struct LinkOrdinalParser;
108
109impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
110 const PATH: &[Symbol] = &[sym::link_ordinal];
111 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
112 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
113 const ALLOWED_TARGETS: AllowedTargets =
114 AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
115 const TEMPLATE: AttributeTemplate = template!(
116 List: &["ordinal"],
117 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
118 );
119
120 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
121 let ordinal = parse_single_integer(cx, args)?;
122
123 let Ok(ordinal) = ordinal.try_into() else {
137 cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
138 return None;
139 };
140
141 Some(LinkOrdinal { ordinal, span: cx.attr_span })
142 }
143}
144
145pub(crate) struct LinkageParser;
146
147impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
148 const PATH: &[Symbol] = &[sym::linkage];
149
150 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
151
152 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
153 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
154 Allow(Target::Fn),
155 Allow(Target::Method(MethodKind::Inherent)),
156 Allow(Target::Method(MethodKind::Trait { body: false })),
157 Allow(Target::Method(MethodKind::Trait { body: true })),
158 Allow(Target::Method(MethodKind::TraitImpl)),
159 Allow(Target::Static),
160 Allow(Target::ForeignStatic),
161 Allow(Target::ForeignFn),
162 ]);
163
164 const TEMPLATE: AttributeTemplate = template!(NameValueStr: [
165 "available_externally",
166 "common",
167 "extern_weak",
168 "external",
169 "internal",
170 "linkonce",
171 "linkonce_odr",
172 "weak",
173 "weak_odr",
174 ]);
175
176 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
177 let Some(name_value) = args.name_value() else {
178 cx.expected_name_value(cx.attr_span, Some(sym::linkage));
179 return None;
180 };
181
182 let Some(value) = name_value.value_as_str() else {
183 cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
184 return None;
185 };
186
187 let linkage = match value {
196 sym::available_externally => Linkage::AvailableExternally,
197 sym::common => Linkage::Common,
198 sym::extern_weak => Linkage::ExternalWeak,
199 sym::external => Linkage::External,
200 sym::internal => Linkage::Internal,
201 sym::linkonce => Linkage::LinkOnceAny,
202 sym::linkonce_odr => Linkage::LinkOnceODR,
203 sym::weak => Linkage::WeakAny,
204 sym::weak_odr => Linkage::WeakODR,
205
206 _ => {
207 cx.expected_specific_argument(
208 name_value.value_span,
209 &[
210 sym::available_externally,
211 sym::common,
212 sym::extern_weak,
213 sym::external,
214 sym::internal,
215 sym::linkonce,
216 sym::linkonce_odr,
217 sym::weak,
218 sym::weak_odr,
219 ],
220 );
221 return None;
222 }
223 };
224
225 Some(AttributeKind::Linkage(linkage, cx.attr_span))
226 }
227}