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, NullOnLinkSection, RawDylibNoNul, 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 Some(name) = nv.value_as_str() else {
41 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
42 return None;
43 };
44
45 Some(LinkName { name, span: cx.attr_span })
46 }
47}
48
49pub(crate) struct LinkParser;
50
51impl CombineAttributeParser for LinkParser {
52 type Item = LinkEntry;
53 const PATH: &[Symbol] = &[sym::link];
54 const CONVERT: ConvertFn<Self::Item> = AttributeKind::Link;
55 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: &[
56 r#"name = "...""#,
57 r#"name = "...", kind = "dylib|static|...""#,
58 r#"name = "...", wasm_import_module = "...""#,
59 r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
60 r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
61 ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute");
62 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); fn extend(
65 cx: &mut AcceptContext<'_, '_>,
66 args: &ArgParser,
67 ) -> impl IntoIterator<Item = Self::Item> {
68 let items = match args {
69 ArgParser::List(list) => list,
70 ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => {
74 cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
75 return None;
76 }
77 _ => {
78 let attr_span = cx.attr_span;
79 cx.adcx().expected_list(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.adcx().expected_not_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.adcx().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.adcx().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(
252 item: &MetaItemParser,
253 name: &mut Option<(Symbol, Span)>,
254 cx: &mut AcceptContext<'_, '_>,
255 ) -> bool {
256 if name.is_some() {
257 cx.adcx().duplicate_key(item.span(), sym::name);
258 return true;
259 }
260 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::name)) else {
261 return false;
262 };
263 let Some(link_name) = nv.value_as_str() else {
264 cx.adcx().expected_string_literal(nv.args_span(), Some(nv.value_as_lit()));
265 return false;
266 };
267
268 if link_name.is_empty() {
269 cx.emit_err(EmptyLinkName { span: nv.value_span });
270 }
271 *name = Some((link_name, nv.value_span));
272 true
273 }
274
275 fn parse_link_kind(
276 item: &MetaItemParser,
277 kind: &mut Option<NativeLibKind>,
278 cx: &mut AcceptContext<'_, '_>,
279 sess: &Session,
280 features: &Features,
281 ) -> bool {
282 if kind.is_some() {
283 cx.adcx().duplicate_key(item.span(), sym::kind);
284 return true;
285 }
286 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::kind)) else {
287 return true;
288 };
289 let Some(link_kind) = nv.value_as_str() else {
290 cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit()));
291 return true;
292 };
293
294 let link_kind = match link_kind {
295 kw::Static => {
296 NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
297 }
298 sym::dylib => NativeLibKind::Dylib { as_needed: None },
299 sym::framework => {
300 if !sess.target.is_like_darwin {
301 cx.emit_err(LinkFrameworkApple { span: nv.value_span });
302 }
303 NativeLibKind::Framework { as_needed: None }
304 }
305 sym::raw_dash_dylib => {
306 if sess.target.is_like_windows {
307 } else if sess.target.binary_format == BinaryFormat::Elf && features.raw_dylib_elf()
309 {
310 } else if sess.target.binary_format == BinaryFormat::Elf && sess.is_nightly_build()
312 {
313 feature_err(
314 sess,
315 sym::raw_dylib_elf,
316 nv.value_span,
317 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"),
318 )
319 .emit();
320 } else {
321 cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
322 }
323
324 NativeLibKind::RawDylib { as_needed: None }
325 }
326 sym::link_dash_arg => {
327 if !features.link_arg_attribute() {
328 feature_err(
329 sess,
330 sym::link_arg_attribute,
331 nv.value_span,
332 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("link kind `link-arg` is unstable"))msg!("link kind `link-arg` is unstable"),
333 )
334 .emit();
335 }
336 NativeLibKind::LinkArg
337 }
338 _kind => {
339 cx.adcx().expected_specific_argument_strings(
340 nv.value_span,
341 &[
342 kw::Static,
343 sym::dylib,
344 sym::framework,
345 sym::raw_dash_dylib,
346 sym::link_dash_arg,
347 ],
348 );
349 return true;
350 }
351 };
352 *kind = Some(link_kind);
353 true
354 }
355
356 fn parse_link_modifiers(
357 item: &MetaItemParser,
358 modifiers: &mut Option<(Symbol, Span)>,
359 cx: &mut AcceptContext<'_, '_>,
360 ) -> bool {
361 if modifiers.is_some() {
362 cx.adcx().duplicate_key(item.span(), sym::modifiers);
363 return true;
364 }
365 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::modifiers)) else {
366 return true;
367 };
368 let Some(link_modifiers) = nv.value_as_str() else {
369 cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit()));
370 return true;
371 };
372 *modifiers = Some((link_modifiers, nv.value_span));
373 true
374 }
375
376 fn parse_link_cfg(
377 item: &MetaItemParser,
378 cfg: &mut Option<CfgEntry>,
379 cx: &mut AcceptContext<'_, '_>,
380 sess: &Session,
381 features: &Features,
382 ) -> bool {
383 if cfg.is_some() {
384 cx.adcx().duplicate_key(item.span(), sym::cfg);
385 return true;
386 }
387 let Some(link_cfg) = cx.expect_single_element_list(item.args(), item.span()) else {
388 return true;
389 };
390 if !features.link_cfg() {
391 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();
392 }
393 *cfg = parse_cfg_entry(cx, link_cfg).ok();
394 true
395 }
396
397 fn parse_link_wasm_import_module(
398 item: &MetaItemParser,
399 wasm_import_module: &mut Option<(Symbol, Span)>,
400 cx: &mut AcceptContext<'_, '_>,
401 ) -> bool {
402 if wasm_import_module.is_some() {
403 cx.adcx().duplicate_key(item.span(), sym::wasm_import_module);
404 return true;
405 }
406 let Some(nv) =
407 cx.expect_name_value(item.args(), item.span(), Some(sym::wasm_import_module))
408 else {
409 return true;
410 };
411 let Some(link_wasm_import_module) = nv.value_as_str() else {
412 cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit()));
413 return true;
414 };
415 *wasm_import_module = Some((link_wasm_import_module, item.span()));
416 true
417 }
418
419 fn parse_link_import_name_type(
420 item: &MetaItemParser,
421 import_name_type: &mut Option<(PeImportNameType, Span)>,
422 cx: &mut AcceptContext<'_, '_>,
423 ) -> bool {
424 if import_name_type.is_some() {
425 cx.adcx().duplicate_key(item.span(), sym::import_name_type);
426 return true;
427 }
428 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::import_name_type))
429 else {
430 return true;
431 };
432 let Some(link_import_name_type) = nv.value_as_str() else {
433 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
434 return true;
435 };
436 if cx.sess().target.arch != Arch::X86 {
437 cx.emit_err(ImportNameTypeX86 { span: item.span() });
438 return true;
439 }
440
441 let link_import_name_type = match link_import_name_type {
442 sym::decorated => PeImportNameType::Decorated,
443 sym::noprefix => PeImportNameType::NoPrefix,
444 sym::undecorated => PeImportNameType::Undecorated,
445 _ => {
446 cx.adcx().expected_specific_argument_strings(
447 item.span(),
448 &[sym::decorated, sym::noprefix, sym::undecorated],
449 );
450 return true;
451 }
452 };
453 *import_name_type = Some((link_import_name_type, item.span()));
454 true
455 }
456}
457
458pub(crate) struct LinkSectionParser;
459
460fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> {
461 let mut parts = name.as_str().split(',').map(|s| s.trim());
462
463 let _segment = parts.next();
465
466 let section = match parts.next() {
468 None | Some("") => return Err(InvalidMachoSectionReason::MissingSection),
469 Some(section) => section,
470 };
471
472 if section.len() > 16 {
473 return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() });
474 }
475
476 Ok(())
481}
482
483impl SingleAttributeParser for LinkSectionParser {
484 const PATH: &[Symbol] = &[sym::link_section];
485 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
486 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
487 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
488 Allow(Target::Static),
489 Allow(Target::Fn),
490 Allow(Target::Method(MethodKind::Inherent)),
491 Allow(Target::Method(MethodKind::Trait { body: true })),
492 Allow(Target::Method(MethodKind::TraitImpl)),
493 ]);
494 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!(
495 NameValueStr: "name",
496 "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
497 );
498
499 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
500 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
501 let Some(name) = nv.value_as_str() else {
502 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
503 return None;
504 };
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) = name_value.value_as_str() else {
634 cx.adcx()
635 .expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
636 return None;
637 };
638
639 let linkage = match value {
648 sym::available_externally => Linkage::AvailableExternally,
649 sym::common => Linkage::Common,
650 sym::extern_weak => Linkage::ExternalWeak,
651 sym::external => Linkage::External,
652 sym::internal => Linkage::Internal,
653 sym::linkonce => Linkage::LinkOnceAny,
654 sym::linkonce_odr => Linkage::LinkOnceODR,
655 sym::weak => Linkage::WeakAny,
656 sym::weak_odr => Linkage::WeakODR,
657
658 _ => {
659 cx.adcx().expected_specific_argument(
660 name_value.value_span,
661 &[
662 sym::available_externally,
663 sym::common,
664 sym::extern_weak,
665 sym::external,
666 sym::internal,
667 sym::linkonce,
668 sym::linkonce_odr,
669 sym::weak,
670 sym::weak_odr,
671 ],
672 );
673 return None;
674 }
675 };
676
677 Some(AttributeKind::Linkage(linkage, cx.attr_span))
678 }
679}
680
681pub(crate) struct NeedsAllocatorParser;
682
683impl NoArgsAttributeParser for NeedsAllocatorParser {
684 const PATH: &[Symbol] = &[sym::needs_allocator];
685 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
686 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
687}
688
689pub(crate) struct CompilerBuiltinsParser;
690
691impl NoArgsAttributeParser for CompilerBuiltinsParser {
692 const PATH: &[Symbol] = &[sym::compiler_builtins];
693 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
694 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
695}