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