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::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
7use rustc_session::parse::feature_err;
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 Some(nv) = args.name_value() else {
40 let attr_span = cx.attr_span;
41 cx.adcx().expected_name_value(attr_span, None);
42 return None;
43 };
44 let Some(name) = nv.value_as_str() else {
45 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
46 return None;
47 };
48
49 Some(LinkName { name, span: cx.attr_span })
50 }
51}
52
53pub(crate) struct LinkParser;
54
55impl CombineAttributeParser for LinkParser {
56 type Item = LinkEntry;
57 const PATH: &[Symbol] = &[sym::link];
58 const CONVERT: ConvertFn<Self::Item> = AttributeKind::Link;
59 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: &[
60 r#"name = "...""#,
61 r#"name = "...", kind = "dylib|static|...""#,
62 r#"name = "...", wasm_import_module = "...""#,
63 r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
64 r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
65 ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute");
66 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); fn extend(
69 cx: &mut AcceptContext<'_, '_>,
70 args: &ArgParser,
71 ) -> impl IntoIterator<Item = Self::Item> {
72 let items = match args {
73 ArgParser::List(list) => list,
74 ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => {
78 cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
79 return None;
80 }
81 _ => {
82 let attr_span = cx.attr_span;
83 cx.adcx().expected_list(attr_span, args);
84 return None;
85 }
86 };
87
88 let sess = cx.sess();
89 let features = cx.features();
90
91 let mut name = None;
92 let mut kind = None;
93 let mut modifiers = None;
94 let mut cfg = None;
95 let mut wasm_import_module = None;
96 let mut import_name_type = None;
97 for item in items.mixed() {
98 let Some(item) = item.meta_item() else {
99 cx.adcx().expected_not_literal(item.span());
100 continue;
101 };
102
103 let cont = match item.path().word().map(|ident| ident.name) {
104 Some(sym::name) => Self::parse_link_name(item, &mut name, cx),
105 Some(sym::kind) => Self::parse_link_kind(item, &mut kind, cx, sess, features),
106 Some(sym::modifiers) => Self::parse_link_modifiers(item, &mut modifiers, cx),
107 Some(sym::cfg) => Self::parse_link_cfg(item, &mut cfg, cx, sess, features),
108 Some(sym::wasm_import_module) => {
109 Self::parse_link_wasm_import_module(item, &mut wasm_import_module, cx)
110 }
111 Some(sym::import_name_type) => {
112 Self::parse_link_import_name_type(item, &mut import_name_type, cx)
113 }
114 _ => {
115 cx.adcx().expected_specific_argument_strings(
116 item.span(),
117 &[
118 sym::name,
119 sym::kind,
120 sym::modifiers,
121 sym::cfg,
122 sym::wasm_import_module,
123 sym::import_name_type,
124 ],
125 );
126 true
127 }
128 };
129 if !cont {
130 return None;
131 }
132 }
133
134 let mut verbatim = None;
136 if let Some((modifiers, span)) = modifiers {
137 for modifier in modifiers.as_str().split(',') {
138 let (modifier, value): (Symbol, bool) = match modifier.strip_prefix(&['+', '-']) {
139 Some(m) => (Symbol::intern(m), modifier.starts_with('+')),
140 None => {
141 cx.emit_err(InvalidLinkModifier { span });
142 continue;
143 }
144 };
145
146 macro report_unstable_modifier($feature: ident) {
147 if !features.$feature() {
148 feature_err(
149 sess,
150 sym::$feature,
151 span,
152 format!("linking modifier `{modifier}` is unstable"),
153 )
154 .emit();
155 }
156 }
157 let assign_modifier = |dst: &mut Option<bool>| {
158 if dst.is_some() {
159 cx.emit_err(MultipleModifiers { span, modifier });
160 } else {
161 *dst = Some(value);
162 }
163 };
164 match (modifier, &mut kind) {
165 (sym::bundle, Some(NativeLibKind::Static { bundle, .. })) => {
166 assign_modifier(bundle)
167 }
168 (sym::bundle, _) => {
169 cx.emit_err(BundleNeedsStatic { span });
170 }
171
172 (sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
173 assign_modifier(export_symbols)
174 }
175
176 (sym::export_symbols, _) => {
177 cx.emit_err(ExportSymbolsNeedsStatic { span });
178 }
179
180 (sym::verbatim, _) => assign_modifier(&mut verbatim),
181
182 (
183 sym::whole_dash_archive,
184 Some(NativeLibKind::Static { whole_archive, .. }),
185 ) => assign_modifier(whole_archive),
186 (sym::whole_dash_archive, _) => {
187 cx.emit_err(WholeArchiveNeedsStatic { span });
188 }
189
190 (sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed }))
191 | (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed }))
192 | (sym::as_dash_needed, Some(NativeLibKind::RawDylib { as_needed })) => {
193 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);
194 assign_modifier(as_needed)
195 }
196 (sym::as_dash_needed, _) => {
197 cx.emit_err(AsNeededCompatibility { span });
198 }
199
200 _ => {
201 cx.adcx().expected_specific_argument_strings(
202 span,
203 &[
204 sym::bundle,
205 sym::export_symbols,
206 sym::verbatim,
207 sym::whole_dash_archive,
208 sym::as_dash_needed,
209 ],
210 );
211 }
212 }
213 }
214 }
215
216 if let Some((_, span)) = wasm_import_module {
217 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
218 cx.emit_err(IncompatibleWasmLink { span });
219 }
220 }
221
222 if wasm_import_module.is_some() {
223 (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
224 }
225 let Some((name, name_span)) = name else {
226 cx.emit_err(LinkRequiresName { span: cx.attr_span });
227 return None;
228 };
229
230 if let Some((_, span)) = import_name_type {
232 if !#[allow(non_exhaustive_omitted_patterns)] match kind {
Some(NativeLibKind::RawDylib { .. }) => true,
_ => false,
}matches!(kind, Some(NativeLibKind::RawDylib { .. })) {
233 cx.emit_err(ImportNameTypeRaw { span });
234 }
235 }
236
237 if let Some(NativeLibKind::RawDylib { .. }) = kind
238 && name.as_str().contains('\0')
239 {
240 cx.emit_err(RawDylibNoNul { span: name_span });
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) = item.args().name_value() else {
265 cx.adcx().expected_name_value(item.span(), Some(sym::name));
266 return false;
267 };
268 let Some(link_name) = nv.value_as_str() else {
269 cx.adcx().expected_name_value(item.span(), Some(sym::name));
270 return false;
271 };
272
273 if link_name.is_empty() {
274 cx.emit_err(EmptyLinkName { span: nv.value_span });
275 }
276 *name = Some((link_name, nv.value_span));
277 true
278 }
279
280 fn parse_link_kind(
281 item: &MetaItemParser,
282 kind: &mut Option<NativeLibKind>,
283 cx: &mut AcceptContext<'_, '_>,
284 sess: &Session,
285 features: &Features,
286 ) -> bool {
287 if kind.is_some() {
288 cx.adcx().duplicate_key(item.span(), sym::kind);
289 return true;
290 }
291 let Some(nv) = item.args().name_value() else {
292 cx.adcx().expected_name_value(item.span(), Some(sym::kind));
293 return true;
294 };
295 let Some(link_kind) = nv.value_as_str() else {
296 cx.adcx().expected_name_value(item.span(), Some(sym::kind));
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) = item.args().name_value() else {
372 cx.adcx().expected_name_value(item.span(), Some(sym::modifiers));
373 return true;
374 };
375 let Some(link_modifiers) = nv.value_as_str() else {
376 cx.adcx().expected_name_value(item.span(), Some(sym::modifiers));
377 return true;
378 };
379 *modifiers = Some((link_modifiers, nv.value_span));
380 true
381 }
382
383 fn parse_link_cfg(
384 item: &MetaItemParser,
385 cfg: &mut Option<CfgEntry>,
386 cx: &mut AcceptContext<'_, '_>,
387 sess: &Session,
388 features: &Features,
389 ) -> bool {
390 if cfg.is_some() {
391 cx.adcx().duplicate_key(item.span(), sym::cfg);
392 return true;
393 }
394 let Some(link_cfg) = cx.expect_single_element_list(item.args(), item.span()) else {
395 return true;
396 };
397 if !features.link_cfg() {
398 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();
399 }
400 *cfg = parse_cfg_entry(cx, link_cfg).ok();
401 true
402 }
403
404 fn parse_link_wasm_import_module(
405 item: &MetaItemParser,
406 wasm_import_module: &mut Option<(Symbol, Span)>,
407 cx: &mut AcceptContext<'_, '_>,
408 ) -> bool {
409 if wasm_import_module.is_some() {
410 cx.adcx().duplicate_key(item.span(), sym::wasm_import_module);
411 return true;
412 }
413 let Some(nv) = item.args().name_value() else {
414 cx.adcx().expected_name_value(item.span(), Some(sym::wasm_import_module));
415 return true;
416 };
417 let Some(link_wasm_import_module) = nv.value_as_str() else {
418 cx.adcx().expected_name_value(item.span(), Some(sym::wasm_import_module));
419 return true;
420 };
421 *wasm_import_module = Some((link_wasm_import_module, item.span()));
422 true
423 }
424
425 fn parse_link_import_name_type(
426 item: &MetaItemParser,
427 import_name_type: &mut Option<(PeImportNameType, Span)>,
428 cx: &mut AcceptContext<'_, '_>,
429 ) -> bool {
430 if import_name_type.is_some() {
431 cx.adcx().duplicate_key(item.span(), sym::import_name_type);
432 return true;
433 }
434 let Some(nv) = item.args().name_value() else {
435 cx.adcx().expected_name_value(item.span(), Some(sym::import_name_type));
436 return true;
437 };
438 let Some(link_import_name_type) = nv.value_as_str() else {
439 cx.adcx().expected_name_value(item.span(), Some(sym::import_name_type));
440 return true;
441 };
442 if cx.sess().target.arch != Arch::X86 {
443 cx.emit_err(ImportNameTypeX86 { span: item.span() });
444 return true;
445 }
446
447 let link_import_name_type = match link_import_name_type {
448 sym::decorated => PeImportNameType::Decorated,
449 sym::noprefix => PeImportNameType::NoPrefix,
450 sym::undecorated => PeImportNameType::Undecorated,
451 _ => {
452 cx.adcx().expected_specific_argument_strings(
453 item.span(),
454 &[sym::decorated, sym::noprefix, sym::undecorated],
455 );
456 return true;
457 }
458 };
459 *import_name_type = Some((link_import_name_type, item.span()));
460 true
461 }
462}
463
464pub(crate) struct LinkSectionParser;
465
466fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> {
467 let mut parts = name.as_str().split(',').map(|s| s.trim());
468
469 let _segment = parts.next();
471
472 let section = match parts.next() {
474 None | Some("") => return Err(InvalidMachoSectionReason::MissingSection),
475 Some(section) => section,
476 };
477
478 if section.len() > 16 {
479 return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() });
480 }
481
482 Ok(())
487}
488
489impl SingleAttributeParser for LinkSectionParser {
490 const PATH: &[Symbol] = &[sym::link_section];
491 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
492 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
493 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
494 Allow(Target::Static),
495 Allow(Target::Fn),
496 Allow(Target::Method(MethodKind::Inherent)),
497 Allow(Target::Method(MethodKind::Trait { body: true })),
498 Allow(Target::Method(MethodKind::TraitImpl)),
499 ]);
500 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!(
501 NameValueStr: "name",
502 "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
503 );
504
505 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
506 let Some(nv) = args.name_value() else {
507 let attr_span = cx.attr_span;
508 cx.adcx().expected_name_value(attr_span, None);
509 return None;
510 };
511 let Some(name) = nv.value_as_str() else {
512 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
513 return None;
514 };
515 if name.as_str().contains('\0') {
516 cx.emit_err(NullOnLinkSection { span: cx.attr_span });
519 return None;
520 }
521
522 match cx.sess.target.binary_format {
524 BinaryFormat::MachO => match check_link_section_macho(name) {
525 Ok(()) => {}
526 Err(reason) => {
527 cx.emit_err(InvalidMachoSection { name_span: nv.value_span, reason });
528 return None;
529 }
530 },
531 BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Wasm | BinaryFormat::Xcoff => {}
532 }
533
534 Some(LinkSection { name, span: cx.attr_span })
535 }
536}
537
538pub(crate) struct ExportStableParser;
539impl NoArgsAttributeParser for ExportStableParser {
540 const PATH: &[Symbol] = &[sym::export_stable];
541 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
543}
544
545pub(crate) struct FfiConstParser;
546impl NoArgsAttributeParser for FfiConstParser {
547 const PATH: &[Symbol] = &[sym::ffi_const];
548 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
549 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
550 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
551}
552
553pub(crate) struct FfiPureParser;
554impl NoArgsAttributeParser for FfiPureParser {
555 const PATH: &[Symbol] = &[sym::ffi_pure];
556 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
557 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
558 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
559}
560
561pub(crate) struct RustcStdInternalSymbolParser;
562impl NoArgsAttributeParser for RustcStdInternalSymbolParser {
563 const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
564 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
565 Allow(Target::Fn),
566 Allow(Target::ForeignFn),
567 Allow(Target::Static),
568 Allow(Target::ForeignStatic),
569 ]);
570 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
571}
572
573pub(crate) struct LinkOrdinalParser;
574
575impl SingleAttributeParser for LinkOrdinalParser {
576 const PATH: &[Symbol] = &[sym::link_ordinal];
577 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
578 Allow(Target::ForeignFn),
579 Allow(Target::ForeignStatic),
580 Warn(Target::MacroCall),
581 ]);
582 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!(
583 List: &["ordinal"],
584 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
585 );
586
587 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
588 let ordinal = parse_single_integer(cx, args)?;
589
590 let Ok(ordinal) = ordinal.try_into() else {
604 cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
605 return None;
606 };
607
608 Some(LinkOrdinal { ordinal, span: cx.attr_span })
609 }
610}
611
612pub(crate) struct LinkageParser;
613
614impl SingleAttributeParser for LinkageParser {
615 const PATH: &[Symbol] = &[sym::linkage];
616
617 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
618 Allow(Target::Fn),
619 Allow(Target::Method(MethodKind::Inherent)),
620 Allow(Target::Method(MethodKind::Trait { body: true })),
621 Allow(Target::Method(MethodKind::TraitImpl)),
622 Allow(Target::Static),
623 Allow(Target::ForeignStatic),
624 Allow(Target::ForeignFn),
625 Warn(Target::Method(MethodKind::Trait { body: false })), ]);
627
628 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: [
629 "available_externally",
630 "common",
631 "extern_weak",
632 "external",
633 "internal",
634 "linkonce",
635 "linkonce_odr",
636 "weak",
637 "weak_odr",
638 ]);
639
640 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
641 let Some(name_value) = args.name_value() else {
642 let attr_span = cx.attr_span;
643 cx.adcx().expected_name_value(attr_span, Some(sym::linkage));
644 return None;
645 };
646
647 let Some(value) = name_value.value_as_str() else {
648 cx.adcx()
649 .expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
650 return None;
651 };
652
653 let linkage = match value {
662 sym::available_externally => Linkage::AvailableExternally,
663 sym::common => Linkage::Common,
664 sym::extern_weak => Linkage::ExternalWeak,
665 sym::external => Linkage::External,
666 sym::internal => Linkage::Internal,
667 sym::linkonce => Linkage::LinkOnceAny,
668 sym::linkonce_odr => Linkage::LinkOnceODR,
669 sym::weak => Linkage::WeakAny,
670 sym::weak_odr => Linkage::WeakODR,
671
672 _ => {
673 cx.adcx().expected_specific_argument(
674 name_value.value_span,
675 &[
676 sym::available_externally,
677 sym::common,
678 sym::extern_weak,
679 sym::external,
680 sym::internal,
681 sym::linkonce,
682 sym::linkonce_odr,
683 sym::weak,
684 sym::weak_odr,
685 ],
686 );
687 return None;
688 }
689 };
690
691 Some(AttributeKind::Linkage(linkage, cx.attr_span))
692 }
693}
694
695pub(crate) struct NeedsAllocatorParser;
696
697impl NoArgsAttributeParser for NeedsAllocatorParser {
698 const PATH: &[Symbol] = &[sym::needs_allocator];
699 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
700 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
701}
702
703pub(crate) struct CompilerBuiltinsParser;
704
705impl NoArgsAttributeParser for CompilerBuiltinsParser {
706 const PATH: &[Symbol] = &[sym::compiler_builtins];
707 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
708 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
709}