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 = AllowedTargets::AllowList(&[
114 Allow(Target::ForeignFn),
115 Allow(Target::ForeignStatic),
116 Warn(Target::MacroCall),
117 ]);
118 const TEMPLATE: AttributeTemplate = template!(
119 List: &["ordinal"],
120 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
121 );
122
123 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
124 let ordinal = parse_single_integer(cx, args)?;
125
126 let Ok(ordinal) = ordinal.try_into() else {
140 cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
141 return None;
142 };
143
144 Some(LinkOrdinal { ordinal, span: cx.attr_span })
145 }
146}
147
148pub(crate) struct LinkageParser;
149
150impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
151 const PATH: &[Symbol] = &[sym::linkage];
152
153 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
154
155 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
156 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
157 Allow(Target::Fn),
158 Allow(Target::Method(MethodKind::Inherent)),
159 Allow(Target::Method(MethodKind::Trait { body: false })),
160 Allow(Target::Method(MethodKind::Trait { body: true })),
161 Allow(Target::Method(MethodKind::TraitImpl)),
162 Allow(Target::Static),
163 Allow(Target::ForeignStatic),
164 Allow(Target::ForeignFn),
165 ]);
166
167 const TEMPLATE: AttributeTemplate = template!(NameValueStr: [
168 "available_externally",
169 "common",
170 "extern_weak",
171 "external",
172 "internal",
173 "linkonce",
174 "linkonce_odr",
175 "weak",
176 "weak_odr",
177 ]);
178
179 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
180 let Some(name_value) = args.name_value() else {
181 cx.expected_name_value(cx.attr_span, Some(sym::linkage));
182 return None;
183 };
184
185 let Some(value) = name_value.value_as_str() else {
186 cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
187 return None;
188 };
189
190 let linkage = match value {
199 sym::available_externally => Linkage::AvailableExternally,
200 sym::common => Linkage::Common,
201 sym::extern_weak => Linkage::ExternalWeak,
202 sym::external => Linkage::External,
203 sym::internal => Linkage::Internal,
204 sym::linkonce => Linkage::LinkOnceAny,
205 sym::linkonce_odr => Linkage::LinkOnceODR,
206 sym::weak => Linkage::WeakAny,
207 sym::weak_odr => Linkage::WeakODR,
208
209 _ => {
210 cx.expected_specific_argument(
211 name_value.value_span,
212 &[
213 sym::available_externally,
214 sym::common,
215 sym::extern_weak,
216 sym::external,
217 sym::internal,
218 sym::linkonce,
219 sym::linkonce_odr,
220 sym::weak,
221 sym::weak_odr,
222 ],
223 );
224 return None;
225 }
226 };
227
228 Some(AttributeKind::Linkage(linkage, cx.attr_span))
229 }
230}