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::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 ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
26 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
27 Allow(Target::ForeignFn),
28 Allow(Target::ForeignStatic),
29 ]);
30 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!(
31 NameValueStr: "name",
32 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"
33 );
34
35 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
36 let Some(nv) = args.name_value() else {
37 cx.expected_name_value(cx.attr_span, None);
38 return None;
39 };
40 let Some(name) = nv.value_as_str() else {
41 cx.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<S: Stage> CombineAttributeParser<S> 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<'_, '_, S>,
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.warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
75 return None;
76 }
77 _ => {
78 cx.expected_list(cx.attr_span, args);
79 return None;
80 }
81 };
82
83 let sess = cx.sess();
84 let features = cx.features();
85
86 let mut name = None;
87 let mut kind = None;
88 let mut modifiers = None;
89 let mut cfg = None;
90 let mut wasm_import_module = None;
91 let mut import_name_type = None;
92 for item in items.mixed() {
93 let Some(item) = item.meta_item() else {
94 cx.unexpected_literal(item.span());
95 continue;
96 };
97
98 let cont = match item.path().word().map(|ident| ident.name) {
99 Some(sym::name) => Self::parse_link_name(item, &mut name, cx),
100 Some(sym::kind) => Self::parse_link_kind(item, &mut kind, cx, sess, features),
101 Some(sym::modifiers) => Self::parse_link_modifiers(item, &mut modifiers, cx),
102 Some(sym::cfg) => Self::parse_link_cfg(item, &mut cfg, cx, sess, features),
103 Some(sym::wasm_import_module) => {
104 Self::parse_link_wasm_import_module(item, &mut wasm_import_module, cx)
105 }
106 Some(sym::import_name_type) => {
107 Self::parse_link_import_name_type(item, &mut import_name_type, cx)
108 }
109 _ => {
110 cx.expected_specific_argument_strings(
111 item.span(),
112 &[
113 sym::name,
114 sym::kind,
115 sym::modifiers,
116 sym::cfg,
117 sym::wasm_import_module,
118 sym::import_name_type,
119 ],
120 );
121 true
122 }
123 };
124 if !cont {
125 return None;
126 }
127 }
128
129 let mut verbatim = None;
131 if let Some((modifiers, span)) = modifiers {
132 for modifier in modifiers.as_str().split(',') {
133 let (modifier, value): (Symbol, bool) = match modifier.strip_prefix(&['+', '-']) {
134 Some(m) => (Symbol::intern(m), modifier.starts_with('+')),
135 None => {
136 cx.emit_err(InvalidLinkModifier { span });
137 continue;
138 }
139 };
140
141 macro report_unstable_modifier($feature: ident) {
142 if !features.$feature() {
143 feature_err(
144 sess,
145 sym::$feature,
146 span,
147 format!("linking modifier `{modifier}` is unstable"),
148 )
149 .emit();
150 }
151 }
152 let assign_modifier = |dst: &mut Option<bool>| {
153 if dst.is_some() {
154 cx.emit_err(MultipleModifiers { span, modifier });
155 } else {
156 *dst = Some(value);
157 }
158 };
159 match (modifier, &mut kind) {
160 (sym::bundle, Some(NativeLibKind::Static { bundle, .. })) => {
161 assign_modifier(bundle)
162 }
163 (sym::bundle, _) => {
164 cx.emit_err(BundleNeedsStatic { span });
165 }
166
167 (sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
168 assign_modifier(export_symbols)
169 }
170
171 (sym::export_symbols, _) => {
172 cx.emit_err(ExportSymbolsNeedsStatic { span });
173 }
174
175 (sym::verbatim, _) => assign_modifier(&mut verbatim),
176
177 (
178 sym::whole_dash_archive,
179 Some(NativeLibKind::Static { whole_archive, .. }),
180 ) => assign_modifier(whole_archive),
181 (sym::whole_dash_archive, _) => {
182 cx.emit_err(WholeArchiveNeedsStatic { span });
183 }
184
185 (sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed }))
186 | (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed }))
187 | (sym::as_dash_needed, Some(NativeLibKind::RawDylib { as_needed })) => {
188 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);
189 assign_modifier(as_needed)
190 }
191 (sym::as_dash_needed, _) => {
192 cx.emit_err(AsNeededCompatibility { span });
193 }
194
195 _ => {
196 cx.expected_specific_argument_strings(
197 span,
198 &[
199 sym::bundle,
200 sym::export_symbols,
201 sym::verbatim,
202 sym::whole_dash_archive,
203 sym::as_dash_needed,
204 ],
205 );
206 }
207 }
208 }
209 }
210
211 if let Some((_, span)) = wasm_import_module {
212 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
213 cx.emit_err(IncompatibleWasmLink { span });
214 }
215 }
216
217 if wasm_import_module.is_some() {
218 (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
219 }
220 let Some((name, name_span)) = name else {
221 cx.emit_err(LinkRequiresName { span: cx.attr_span });
222 return None;
223 };
224
225 if let Some((_, span)) = import_name_type {
227 if !#[allow(non_exhaustive_omitted_patterns)] match kind {
Some(NativeLibKind::RawDylib { .. }) => true,
_ => false,
}matches!(kind, Some(NativeLibKind::RawDylib { .. })) {
228 cx.emit_err(ImportNameTypeRaw { span });
229 }
230 }
231
232 if let Some(NativeLibKind::RawDylib { .. }) = kind
233 && name.as_str().contains('\0')
234 {
235 cx.emit_err(RawDylibNoNul { span: name_span });
236 }
237
238 Some(LinkEntry {
239 span: cx.attr_span,
240 kind: kind.unwrap_or(NativeLibKind::Unspecified),
241 name,
242 cfg,
243 verbatim,
244 import_name_type,
245 })
246 }
247}
248
249impl LinkParser {
250 fn parse_link_name<S: Stage>(
251 item: &MetaItemParser,
252 name: &mut Option<(Symbol, Span)>,
253 cx: &mut AcceptContext<'_, '_, S>,
254 ) -> bool {
255 if name.is_some() {
256 cx.duplicate_key(item.span(), sym::name);
257 return true;
258 }
259 let Some(nv) = item.args().name_value() else {
260 cx.expected_name_value(item.span(), Some(sym::name));
261 return false;
262 };
263 let Some(link_name) = nv.value_as_str() else {
264 cx.expected_name_value(item.span(), Some(sym::name));
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<S: Stage>(
276 item: &MetaItemParser,
277 kind: &mut Option<NativeLibKind>,
278 cx: &mut AcceptContext<'_, '_, S>,
279 sess: &Session,
280 features: &Features,
281 ) -> bool {
282 if kind.is_some() {
283 cx.duplicate_key(item.span(), sym::kind);
284 return true;
285 }
286 let Some(nv) = item.args().name_value() else {
287 cx.expected_name_value(item.span(), Some(sym::kind));
288 return true;
289 };
290 let Some(link_kind) = nv.value_as_str() else {
291 cx.expected_name_value(item.span(), Some(sym::kind));
292 return true;
293 };
294
295 let link_kind = match link_kind {
296 kw::Static => {
297 NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
298 }
299 sym::dylib => NativeLibKind::Dylib { as_needed: None },
300 sym::framework => {
301 if !sess.target.is_like_darwin {
302 cx.emit_err(LinkFrameworkApple { span: nv.value_span });
303 }
304 NativeLibKind::Framework { as_needed: None }
305 }
306 sym::raw_dash_dylib => {
307 if sess.target.is_like_windows {
308 } else if sess.target.binary_format == BinaryFormat::Elf && features.raw_dylib_elf()
310 {
311 } else if sess.target.binary_format == BinaryFormat::Elf && sess.is_nightly_build()
313 {
314 feature_err(
315 sess,
316 sym::raw_dylib_elf,
317 nv.value_span,
318 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"),
319 )
320 .emit();
321 } else {
322 cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
323 }
324
325 NativeLibKind::RawDylib { as_needed: None }
326 }
327 sym::link_dash_arg => {
328 if !features.link_arg_attribute() {
329 feature_err(
330 sess,
331 sym::link_arg_attribute,
332 nv.value_span,
333 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("link kind `link-arg` is unstable"))msg!("link kind `link-arg` is unstable"),
334 )
335 .emit();
336 }
337 NativeLibKind::LinkArg
338 }
339 _kind => {
340 cx.expected_specific_argument_strings(
341 nv.value_span,
342 &[
343 kw::Static,
344 sym::dylib,
345 sym::framework,
346 sym::raw_dash_dylib,
347 sym::link_dash_arg,
348 ],
349 );
350 return true;
351 }
352 };
353 *kind = Some(link_kind);
354 true
355 }
356
357 fn parse_link_modifiers<S: Stage>(
358 item: &MetaItemParser,
359 modifiers: &mut Option<(Symbol, Span)>,
360 cx: &mut AcceptContext<'_, '_, S>,
361 ) -> bool {
362 if modifiers.is_some() {
363 cx.duplicate_key(item.span(), sym::modifiers);
364 return true;
365 }
366 let Some(nv) = item.args().name_value() else {
367 cx.expected_name_value(item.span(), Some(sym::modifiers));
368 return true;
369 };
370 let Some(link_modifiers) = nv.value_as_str() else {
371 cx.expected_name_value(item.span(), Some(sym::modifiers));
372 return true;
373 };
374 *modifiers = Some((link_modifiers, nv.value_span));
375 true
376 }
377
378 fn parse_link_cfg<S: Stage>(
379 item: &MetaItemParser,
380 cfg: &mut Option<CfgEntry>,
381 cx: &mut AcceptContext<'_, '_, S>,
382 sess: &Session,
383 features: &Features,
384 ) -> bool {
385 if cfg.is_some() {
386 cx.duplicate_key(item.span(), sym::cfg);
387 return true;
388 }
389 let Some(link_cfg) = item.args().list() else {
390 cx.expected_list(item.span(), item.args());
391 return true;
392 };
393 let Some(link_cfg) = link_cfg.single() else {
394 cx.expected_single_argument(item.span());
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<S: Stage>(
405 item: &MetaItemParser,
406 wasm_import_module: &mut Option<(Symbol, Span)>,
407 cx: &mut AcceptContext<'_, '_, S>,
408 ) -> bool {
409 if wasm_import_module.is_some() {
410 cx.duplicate_key(item.span(), sym::wasm_import_module);
411 return true;
412 }
413 let Some(nv) = item.args().name_value() else {
414 cx.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.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<S: Stage>(
426 item: &MetaItemParser,
427 import_name_type: &mut Option<(PeImportNameType, Span)>,
428 cx: &mut AcceptContext<'_, '_, S>,
429 ) -> bool {
430 if import_name_type.is_some() {
431 cx.duplicate_key(item.span(), sym::import_name_type);
432 return true;
433 }
434 let Some(nv) = item.args().name_value() else {
435 cx.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.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.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
466impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
467 const PATH: &[Symbol] = &[sym::link_section];
468 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
469 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
470 Allow(Target::Static),
471 Allow(Target::Fn),
472 Allow(Target::Method(MethodKind::Inherent)),
473 Allow(Target::Method(MethodKind::Trait { body: true })),
474 Allow(Target::Method(MethodKind::TraitImpl)),
475 ]);
476 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!(
477 NameValueStr: "name",
478 "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
479 );
480
481 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
482 let Some(nv) = args.name_value() else {
483 cx.expected_name_value(cx.attr_span, None);
484 return None;
485 };
486 let Some(name) = nv.value_as_str() else {
487 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
488 return None;
489 };
490 if name.as_str().contains('\0') {
491 cx.emit_err(NullOnLinkSection { span: cx.attr_span });
494 return None;
495 }
496
497 Some(LinkSection { name, span: cx.attr_span })
498 }
499}
500
501pub(crate) struct ExportStableParser;
502impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
503 const PATH: &[Symbol] = &[sym::export_stable];
504 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
505 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
507}
508
509pub(crate) struct FfiConstParser;
510impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
511 const PATH: &[Symbol] = &[sym::ffi_const];
512 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
513 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
514 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
515}
516
517pub(crate) struct FfiPureParser;
518impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
519 const PATH: &[Symbol] = &[sym::ffi_pure];
520 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
521 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
522 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
523}
524
525pub(crate) struct RustcStdInternalSymbolParser;
526impl<S: Stage> NoArgsAttributeParser<S> for RustcStdInternalSymbolParser {
527 const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
528 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
529 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
530 Allow(Target::Fn),
531 Allow(Target::ForeignFn),
532 Allow(Target::Static),
533 Allow(Target::ForeignStatic),
534 ]);
535 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
536}
537
538pub(crate) struct LinkOrdinalParser;
539
540impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
541 const PATH: &[Symbol] = &[sym::link_ordinal];
542 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
543 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
544 Allow(Target::ForeignFn),
545 Allow(Target::ForeignStatic),
546 Warn(Target::MacroCall),
547 ]);
548 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!(
549 List: &["ordinal"],
550 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
551 );
552
553 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
554 let ordinal = parse_single_integer(cx, args)?;
555
556 let Ok(ordinal) = ordinal.try_into() else {
570 cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
571 return None;
572 };
573
574 Some(LinkOrdinal { ordinal, span: cx.attr_span })
575 }
576}
577
578pub(crate) struct LinkageParser;
579
580impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
581 const PATH: &[Symbol] = &[sym::linkage];
582
583 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
584 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
585 Allow(Target::Fn),
586 Allow(Target::Method(MethodKind::Inherent)),
587 Allow(Target::Method(MethodKind::Trait { body: true })),
588 Allow(Target::Method(MethodKind::TraitImpl)),
589 Allow(Target::Static),
590 Allow(Target::ForeignStatic),
591 Allow(Target::ForeignFn),
592 Warn(Target::Method(MethodKind::Trait { body: false })), ]);
594
595 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: [
596 "available_externally",
597 "common",
598 "extern_weak",
599 "external",
600 "internal",
601 "linkonce",
602 "linkonce_odr",
603 "weak",
604 "weak_odr",
605 ]);
606
607 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
608 let Some(name_value) = args.name_value() else {
609 cx.expected_name_value(cx.attr_span, Some(sym::linkage));
610 return None;
611 };
612
613 let Some(value) = name_value.value_as_str() else {
614 cx.expected_string_literal(name_value.value_span, Some(name_value.value_as_lit()));
615 return None;
616 };
617
618 let linkage = match value {
627 sym::available_externally => Linkage::AvailableExternally,
628 sym::common => Linkage::Common,
629 sym::extern_weak => Linkage::ExternalWeak,
630 sym::external => Linkage::External,
631 sym::internal => Linkage::Internal,
632 sym::linkonce => Linkage::LinkOnceAny,
633 sym::linkonce_odr => Linkage::LinkOnceODR,
634 sym::weak => Linkage::WeakAny,
635 sym::weak_odr => Linkage::WeakODR,
636
637 _ => {
638 cx.expected_specific_argument(
639 name_value.value_span,
640 &[
641 sym::available_externally,
642 sym::common,
643 sym::extern_weak,
644 sym::external,
645 sym::internal,
646 sym::linkonce,
647 sym::linkonce_odr,
648 sym::weak,
649 sym::weak_odr,
650 ],
651 );
652 return None;
653 }
654 };
655
656 Some(AttributeKind::Linkage(linkage, cx.attr_span))
657 }
658}
659
660pub(crate) struct NeedsAllocatorParser;
661
662impl<S: Stage> NoArgsAttributeParser<S> for NeedsAllocatorParser {
663 const PATH: &[Symbol] = &[sym::needs_allocator];
664 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
665 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
666 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
667}
668
669pub(crate) struct CompilerBuiltinsParser;
670
671impl<S: Stage> NoArgsAttributeParser<S> for CompilerBuiltinsParser {
672 const PATH: &[Symbol] = &[sym::compiler_builtins];
673 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
674 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
675 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
676}