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