1use rustc_errors::inline_fluent;
2use rustc_feature::Features;
3use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
4use rustc_hir::attrs::*;
5use rustc_session::Session;
6use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
7use rustc_session::parse::feature_err;
8use rustc_span::kw;
9use rustc_target::spec::{Arch, BinaryFormat};
10
11use super::prelude::*;
12use super::util::parse_single_integer;
13use crate::attributes::cfg::parse_cfg_entry;
14use crate::session_diagnostics::{
15 AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ExportSymbolsNeedsStatic,
16 ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink, InvalidLinkModifier,
17 LinkFrameworkApple, LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers,
18 NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows, WholeArchiveNeedsStatic,
19};
20
21pub(crate) struct LinkNameParser;
22
23impl<S: Stage> SingleAttributeParser<S> for LinkNameParser {
24 const PATH: &[Symbol] = &[sym::link_name];
25 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
26 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
27 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
28 Allow(Target::ForeignFn),
29 Allow(Target::ForeignStatic),
30 ]);
31 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["name"]),
docs: Some("https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"),
}template!(
32 NameValueStr: "name",
33 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
34 );
35
36 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
37 let Some(nv) = args.name_value() else {
38 cx.expected_name_value(cx.attr_span, None);
39 return None;
40 };
41 let Some(name) = nv.value_as_str() else {
42 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
43 return None;
44 };
45
46 Some(LinkName { name, span: cx.attr_span })
47 }
48}
49
50pub(crate) struct LinkParser;
51
52impl<S: Stage> CombineAttributeParser<S> for LinkParser {
53 type Item = LinkEntry;
54 const PATH: &[Symbol] = &[sym::link];
55 const CONVERT: ConvertFn<Self::Item> = AttributeKind::Link;
56 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&[r#"name = "...""#,
r#"name = "...", kind = "dylib|static|...""#,
r#"name = "...", wasm_import_module = "...""#,
r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#]),
one_of: &[],
name_value_str: None,
docs: Some("https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"),
}template!(List: &[
57 r#"name = "...""#,
58 r#"name = "...", kind = "dylib|static|...""#,
59 r#"name = "...", wasm_import_module = "...""#,
60 r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
61 r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
62 ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute");
63 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); fn extend(
66 cx: &mut AcceptContext<'_, '_, S>,
67 args: &ArgParser,
68 ) -> impl IntoIterator<Item = Self::Item> {
69 let items = match args {
70 ArgParser::List(list) => list,
71 ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => {
75 cx.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
76 return None;
77 }
78 _ => {
79 cx.expected_list(cx.attr_span, args);
80 return None;
81 }
82 };
83
84 let sess = cx.sess();
85 let features = cx.features();
86
87 let mut name = None;
88 let mut kind = None;
89 let mut modifiers = None;
90 let mut cfg = None;
91 let mut wasm_import_module = None;
92 let mut import_name_type = None;
93 for item in items.mixed() {
94 let Some(item) = item.meta_item() else {
95 cx.unexpected_literal(item.span());
96 continue;
97 };
98
99 let cont = match item.path().word().map(|ident| ident.name) {
100 Some(sym::name) => Self::parse_link_name(item, &mut name, cx),
101 Some(sym::kind) => Self::parse_link_kind(item, &mut kind, cx, sess, features),
102 Some(sym::modifiers) => Self::parse_link_modifiers(item, &mut modifiers, cx),
103 Some(sym::cfg) => Self::parse_link_cfg(item, &mut cfg, cx, sess, features),
104 Some(sym::wasm_import_module) => {
105 Self::parse_link_wasm_import_module(item, &mut wasm_import_module, cx)
106 }
107 Some(sym::import_name_type) => {
108 Self::parse_link_import_name_type(item, &mut import_name_type, cx)
109 }
110 _ => {
111 cx.expected_specific_argument_strings(
112 item.span(),
113 &[
114 sym::name,
115 sym::kind,
116 sym::modifiers,
117 sym::cfg,
118 sym::wasm_import_module,
119 sym::import_name_type,
120 ],
121 );
122 true
123 }
124 };
125 if !cont {
126 return None;
127 }
128 }
129
130 let mut verbatim = None;
132 if let Some((modifiers, span)) = modifiers {
133 for modifier in modifiers.as_str().split(',') {
134 let (modifier, value): (Symbol, bool) = match modifier.strip_prefix(&['+', '-']) {
135 Some(m) => (Symbol::intern(m), modifier.starts_with('+')),
136 None => {
137 cx.emit_err(InvalidLinkModifier { span });
138 continue;
139 }
140 };
141
142 macro report_unstable_modifier($feature: ident) {
143 if !features.$feature() {
144 feature_err(
145 sess,
146 sym::$feature,
147 span,
148 format!("linking modifier `{modifier}` is unstable"),
149 )
150 .emit();
151 }
152 }
153 let assign_modifier = |dst: &mut Option<bool>| {
154 if dst.is_some() {
155 cx.emit_err(MultipleModifiers { span, modifier });
156 } else {
157 *dst = Some(value);
158 }
159 };
160 match (modifier, &mut kind) {
161 (sym::bundle, Some(NativeLibKind::Static { bundle, .. })) => {
162 assign_modifier(bundle)
163 }
164 (sym::bundle, _) => {
165 cx.emit_err(BundleNeedsStatic { span });
166 }
167
168 (sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
169 assign_modifier(export_symbols)
170 }
171
172 (sym::export_symbols, _) => {
173 cx.emit_err(ExportSymbolsNeedsStatic { span });
174 }
175
176 (sym::verbatim, _) => assign_modifier(&mut verbatim),
177
178 (
179 sym::whole_dash_archive,
180 Some(NativeLibKind::Static { whole_archive, .. }),
181 ) => assign_modifier(whole_archive),
182 (sym::whole_dash_archive, _) => {
183 cx.emit_err(WholeArchiveNeedsStatic { span });
184 }
185
186 (sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed }))
187 | (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed }))
188 | (sym::as_dash_needed, Some(NativeLibKind::RawDylib { as_needed })) => {
189 if !features.native_link_modifiers_as_needed() {
feature_err(sess, sym::native_link_modifiers_as_needed, span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("linking modifier `{0}` is unstable",
modifier))
})).emit();
};report_unstable_modifier!(native_link_modifiers_as_needed);
190 assign_modifier(as_needed)
191 }
192 (sym::as_dash_needed, _) => {
193 cx.emit_err(AsNeededCompatibility { span });
194 }
195
196 _ => {
197 cx.expected_specific_argument_strings(
198 span,
199 &[
200 sym::bundle,
201 sym::export_symbols,
202 sym::verbatim,
203 sym::whole_dash_archive,
204 sym::as_dash_needed,
205 ],
206 );
207 }
208 }
209 }
210 }
211
212 if let Some((_, span)) = wasm_import_module {
213 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
214 cx.emit_err(IncompatibleWasmLink { span });
215 }
216 }
217
218 if wasm_import_module.is_some() {
219 (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
220 }
221 let Some((name, name_span)) = name else {
222 cx.emit_err(LinkRequiresName { span: cx.attr_span });
223 return None;
224 };
225
226 if let Some((_, span)) = import_name_type {
228 if !#[allow(non_exhaustive_omitted_patterns)] match kind {
Some(NativeLibKind::RawDylib { .. }) => true,
_ => false,
}matches!(kind, Some(NativeLibKind::RawDylib { .. })) {
229 cx.emit_err(ImportNameTypeRaw { span });
230 }
231 }
232
233 if let Some(NativeLibKind::RawDylib { .. }) = kind
234 && name.as_str().contains('\0')
235 {
236 cx.emit_err(RawDylibNoNul { span: name_span });
237 }
238
239 Some(LinkEntry {
240 span: cx.attr_span,
241 kind: kind.unwrap_or(NativeLibKind::Unspecified),
242 name,
243 cfg,
244 verbatim,
245 import_name_type,
246 })
247 }
248}
249
250impl LinkParser {
251 fn parse_link_name<S: Stage>(
252 item: &MetaItemParser,
253 name: &mut Option<(Symbol, Span)>,
254 cx: &mut AcceptContext<'_, '_, S>,
255 ) -> bool {
256 if name.is_some() {
257 cx.duplicate_key(item.span(), sym::name);
258 return true;
259 }
260 let Some(nv) = item.args().name_value() else {
261 cx.expected_name_value(item.span(), Some(sym::name));
262 return false;
263 };
264 let Some(link_name) = nv.value_as_str() else {
265 cx.expected_name_value(item.span(), Some(sym::name));
266 return false;
267 };
268
269 if link_name.is_empty() {
270 cx.emit_err(EmptyLinkName { span: nv.value_span });
271 }
272 *name = Some((link_name, nv.value_span));
273 true
274 }
275
276 fn parse_link_kind<S: Stage>(
277 item: &MetaItemParser,
278 kind: &mut Option<NativeLibKind>,
279 cx: &mut AcceptContext<'_, '_, S>,
280 sess: &Session,
281 features: &Features,
282 ) -> bool {
283 if kind.is_some() {
284 cx.duplicate_key(item.span(), sym::kind);
285 return true;
286 }
287 let Some(nv) = item.args().name_value() else {
288 cx.expected_name_value(item.span(), Some(sym::kind));
289 return true;
290 };
291 let Some(link_kind) = nv.value_as_str() else {
292 cx.expected_name_value(item.span(), Some(sym::kind));
293 return true;
294 };
295
296 let link_kind = match link_kind {
297 kw::Static => {
298 NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
299 }
300 sym::dylib => NativeLibKind::Dylib { as_needed: None },
301 sym::framework => {
302 if !sess.target.is_like_darwin {
303 cx.emit_err(LinkFrameworkApple { span: nv.value_span });
304 }
305 NativeLibKind::Framework { as_needed: None }
306 }
307 sym::raw_dash_dylib => {
308 if sess.target.is_like_windows {
309 } else if sess.target.binary_format == BinaryFormat::Elf && features.raw_dylib_elf()
311 {
312 } else if sess.target.binary_format == BinaryFormat::Elf && sess.is_nightly_build()
314 {
315 feature_err(
316 sess,
317 sym::raw_dylib_elf,
318 nv.value_span,
319 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("link kind `raw-dylib` is unstable on ELF platforms"))inline_fluent!("link kind `raw-dylib` is unstable on ELF platforms"),
320 )
321 .emit();
322 } else {
323 cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
324 }
325
326 NativeLibKind::RawDylib { as_needed: None }
327 }
328 sym::link_dash_arg => {
329 if !features.link_arg_attribute() {
330 feature_err(
331 sess,
332 sym::link_arg_attribute,
333 nv.value_span,
334 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("link kind `link-arg` is unstable"))inline_fluent!("link kind `link-arg` is unstable"),
335 )
336 .emit();
337 }
338 NativeLibKind::LinkArg
339 }
340 _kind => {
341 cx.expected_specific_argument_strings(
342 nv.value_span,
343 &[
344 kw::Static,
345 sym::dylib,
346 sym::framework,
347 sym::raw_dash_dylib,
348 sym::link_dash_arg,
349 ],
350 );
351 return true;
352 }
353 };
354 *kind = Some(link_kind);
355 true
356 }
357
358 fn parse_link_modifiers<S: Stage>(
359 item: &MetaItemParser,
360 modifiers: &mut Option<(Symbol, Span)>,
361 cx: &mut AcceptContext<'_, '_, S>,
362 ) -> bool {
363 if modifiers.is_some() {
364 cx.duplicate_key(item.span(), sym::modifiers);
365 return true;
366 }
367 let Some(nv) = item.args().name_value() else {
368 cx.expected_name_value(item.span(), Some(sym::modifiers));
369 return true;
370 };
371 let Some(link_modifiers) = nv.value_as_str() else {
372 cx.expected_name_value(item.span(), Some(sym::modifiers));
373 return true;
374 };
375 *modifiers = Some((link_modifiers, nv.value_span));
376 true
377 }
378
379 fn parse_link_cfg<S: Stage>(
380 item: &MetaItemParser,
381 cfg: &mut Option<CfgEntry>,
382 cx: &mut AcceptContext<'_, '_, S>,
383 sess: &Session,
384 features: &Features,
385 ) -> bool {
386 if cfg.is_some() {
387 cx.duplicate_key(item.span(), sym::cfg);
388 return true;
389 }
390 let Some(link_cfg) = item.args().list() else {
391 cx.expected_list(item.span(), item.args());
392 return true;
393 };
394 let Some(link_cfg) = link_cfg.single() else {
395 cx.expected_single_argument(item.span());
396 return true;
397 };
398 if !features.link_cfg() {
399 feature_err(sess, sym::link_cfg, item.span(), rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("link cfg is unstable"))inline_fluent!("link cfg is unstable"))
400 .emit();
401 }
402 *cfg = parse_cfg_entry(cx, link_cfg).ok();
403 true
404 }
405
406 fn parse_link_wasm_import_module<S: Stage>(
407 item: &MetaItemParser,
408 wasm_import_module: &mut Option<(Symbol, Span)>,
409 cx: &mut AcceptContext<'_, '_, S>,
410 ) -> bool {
411 if wasm_import_module.is_some() {
412 cx.duplicate_key(item.span(), sym::wasm_import_module);
413 return true;
414 }
415 let Some(nv) = item.args().name_value() else {
416 cx.expected_name_value(item.span(), Some(sym::wasm_import_module));
417 return true;
418 };
419 let Some(link_wasm_import_module) = nv.value_as_str() else {
420 cx.expected_name_value(item.span(), Some(sym::wasm_import_module));
421 return true;
422 };
423 *wasm_import_module = Some((link_wasm_import_module, item.span()));
424 true
425 }
426
427 fn parse_link_import_name_type<S: Stage>(
428 item: &MetaItemParser,
429 import_name_type: &mut Option<(PeImportNameType, Span)>,
430 cx: &mut AcceptContext<'_, '_, S>,
431 ) -> bool {
432 if import_name_type.is_some() {
433 cx.duplicate_key(item.span(), sym::import_name_type);
434 return true;
435 }
436 let Some(nv) = item.args().name_value() else {
437 cx.expected_name_value(item.span(), Some(sym::import_name_type));
438 return true;
439 };
440 let Some(link_import_name_type) = nv.value_as_str() else {
441 cx.expected_name_value(item.span(), Some(sym::import_name_type));
442 return true;
443 };
444 if cx.sess().target.arch != Arch::X86 {
445 cx.emit_err(ImportNameTypeX86 { span: item.span() });
446 return true;
447 }
448
449 let link_import_name_type = match link_import_name_type {
450 sym::decorated => PeImportNameType::Decorated,
451 sym::noprefix => PeImportNameType::NoPrefix,
452 sym::undecorated => PeImportNameType::Undecorated,
453 _ => {
454 cx.expected_specific_argument_strings(
455 item.span(),
456 &[sym::decorated, sym::noprefix, sym::undecorated],
457 );
458 return true;
459 }
460 };
461 *import_name_type = Some((link_import_name_type, item.span()));
462 true
463 }
464}
465
466pub(crate) struct LinkSectionParser;
467
468impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
469 const PATH: &[Symbol] = &[sym::link_section];
470 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
471 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
472 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
473 Allow(Target::Static),
474 Allow(Target::Fn),
475 Allow(Target::Method(MethodKind::Inherent)),
476 Allow(Target::Method(MethodKind::Trait { body: true })),
477 Allow(Target::Method(MethodKind::TraitImpl)),
478 ]);
479 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["name"]),
docs: Some("https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"),
}template!(
480 NameValueStr: "name",
481 "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
482 );
483
484 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
485 let Some(nv) = args.name_value() else {
486 cx.expected_name_value(cx.attr_span, None);
487 return None;
488 };
489 let Some(name) = nv.value_as_str() else {
490 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
491 return None;
492 };
493 if name.as_str().contains('\0') {
494 cx.emit_err(NullOnLinkSection { span: cx.attr_span });
497 return None;
498 }
499
500 Some(LinkSection { name, span: cx.attr_span })
501 }
502}
503
504pub(crate) struct ExportStableParser;
505impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
506 const PATH: &[Symbol] = &[sym::export_stable];
507 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
508 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
510}
511
512pub(crate) struct FfiConstParser;
513impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
514 const PATH: &[Symbol] = &[sym::ffi_const];
515 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
516 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
517 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
518}
519
520pub(crate) struct FfiPureParser;
521impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
522 const PATH: &[Symbol] = &[sym::ffi_pure];
523 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
524 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
525 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
526}
527
528pub(crate) struct StdInternalSymbolParser;
529impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
530 const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
531 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
532 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
533 Allow(Target::Fn),
534 Allow(Target::ForeignFn),
535 Allow(Target::Static),
536 Allow(Target::ForeignStatic),
537 ]);
538 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
539}
540
541pub(crate) struct LinkOrdinalParser;
542
543impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
544 const PATH: &[Symbol] = &[sym::link_ordinal];
545 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
546 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
547 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
548 Allow(Target::ForeignFn),
549 Allow(Target::ForeignStatic),
550 Warn(Target::MacroCall),
551 ]);
552 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["ordinal"]),
one_of: &[],
name_value_str: None,
docs: Some("https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"),
}template!(
553 List: &["ordinal"],
554 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
555 );
556
557 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
558 let ordinal = parse_single_integer(cx, args)?;
559
560 let Ok(ordinal) = ordinal.try_into() else {
574 cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
575 return None;
576 };
577
578 Some(LinkOrdinal { ordinal, span: cx.attr_span })
579 }
580}
581
582pub(crate) struct LinkageParser;
583
584impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
585 const PATH: &[Symbol] = &[sym::linkage];
586
587 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
588
589 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
590 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
591 Allow(Target::Fn),
592 Allow(Target::Method(MethodKind::Inherent)),
593 Allow(Target::Method(MethodKind::Trait { body: true })),
594 Allow(Target::Method(MethodKind::TraitImpl)),
595 Allow(Target::Static),
596 Allow(Target::ForeignStatic),
597 Allow(Target::ForeignFn),
598 Warn(Target::Method(MethodKind::Trait { body: false })), ]);
600
601 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["available_externally", "common", "extern_weak",
"external", "internal", "linkonce", "linkonce_odr", "weak",
"weak_odr"]),
docs: None,
}template!(NameValueStr: [
602 "available_externally",
603 "common",
604 "extern_weak",
605 "external",
606 "internal",
607 "linkonce",
608 "linkonce_odr",
609 "weak",
610 "weak_odr",
611 ]);
612
613 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
614 let Some(name_value) = args.name_value() else {
615 cx.expected_name_value(cx.attr_span, Some(sym::linkage));
616 return None;
617 };
618
619 let Some(value) = name_value.value_as_str() else {
620 cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
621 return None;
622 };
623
624 let linkage = match value {
633 sym::available_externally => Linkage::AvailableExternally,
634 sym::common => Linkage::Common,
635 sym::extern_weak => Linkage::ExternalWeak,
636 sym::external => Linkage::External,
637 sym::internal => Linkage::Internal,
638 sym::linkonce => Linkage::LinkOnceAny,
639 sym::linkonce_odr => Linkage::LinkOnceODR,
640 sym::weak => Linkage::WeakAny,
641 sym::weak_odr => Linkage::WeakODR,
642
643 _ => {
644 cx.expected_specific_argument(
645 name_value.value_span,
646 &[
647 sym::available_externally,
648 sym::common,
649 sym::extern_weak,
650 sym::external,
651 sym::internal,
652 sym::linkonce,
653 sym::linkonce_odr,
654 sym::weak,
655 sym::weak_odr,
656 ],
657 );
658 return None;
659 }
660 };
661
662 Some(AttributeKind::Linkage(linkage, cx.attr_span))
663 }
664}
665
666pub(crate) struct NeedsAllocatorParser;
667
668impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
669 const PATH: &[Symbol] = &[sym::needs_allocator];
670 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
671 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
672 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
673}
674
675pub(crate) struct CompilerBuiltinsParser;
676
677impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
678 const PATH: &[Symbol] = &[sym::compiler_builtins];
679 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
680 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
681 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
682}