1use rustc_feature::Features;
2use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
3use rustc_hir::attrs::*;
4use rustc_session::Session;
5use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
6use rustc_session::parse::feature_err;
7use rustc_span::kw;
8use rustc_target::spec::{Arch, BinaryFormat};
9
10use super::prelude::*;
11use super::util::parse_single_integer;
12use crate::attributes::cfg::parse_cfg_entry;
13use crate::fluent_generated;
14use crate::session_diagnostics::{
15 AsNeededCompatibility, BundleNeedsStatic, EmptyLinkName, ImportNameTypeRaw, ImportNameTypeX86,
16 IncompatibleWasmLink, InvalidLinkModifier, LinkFrameworkApple, LinkOrdinalOutOfRange,
17 LinkRequiresName, MultipleModifiers, NullOnLinkSection, RawDylibNoNul, RawDylibOnlyWindows,
18 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::verbatim, _) => assign_modifier(&mut verbatim),
169
170 (
171 sym::whole_dash_archive,
172 Some(NativeLibKind::Static { whole_archive, .. }),
173 ) => assign_modifier(whole_archive),
174 (sym::whole_dash_archive, _) => {
175 cx.emit_err(WholeArchiveNeedsStatic { span });
176 }
177
178 (sym::as_dash_needed, Some(NativeLibKind::Dylib { as_needed }))
179 | (sym::as_dash_needed, Some(NativeLibKind::Framework { as_needed }))
180 | (sym::as_dash_needed, Some(NativeLibKind::RawDylib { as_needed })) => {
181 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);
182 assign_modifier(as_needed)
183 }
184 (sym::as_dash_needed, _) => {
185 cx.emit_err(AsNeededCompatibility { span });
186 }
187
188 _ => {
189 cx.expected_specific_argument_strings(
190 span,
191 &[
192 sym::bundle,
193 sym::verbatim,
194 sym::whole_dash_archive,
195 sym::as_dash_needed,
196 ],
197 );
198 }
199 }
200 }
201 }
202
203 if let Some((_, span)) = wasm_import_module {
204 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
205 cx.emit_err(IncompatibleWasmLink { span });
206 }
207 }
208
209 if wasm_import_module.is_some() {
210 (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
211 }
212 let Some((name, name_span)) = name else {
213 cx.emit_err(LinkRequiresName { span: cx.attr_span });
214 return None;
215 };
216
217 if let Some((_, span)) = import_name_type {
219 if !#[allow(non_exhaustive_omitted_patterns)] match kind {
Some(NativeLibKind::RawDylib { .. }) => true,
_ => false,
}matches!(kind, Some(NativeLibKind::RawDylib { .. })) {
220 cx.emit_err(ImportNameTypeRaw { span });
221 }
222 }
223
224 if let Some(NativeLibKind::RawDylib { .. }) = kind
225 && name.as_str().contains('\0')
226 {
227 cx.emit_err(RawDylibNoNul { span: name_span });
228 }
229
230 Some(LinkEntry {
231 span: cx.attr_span,
232 kind: kind.unwrap_or(NativeLibKind::Unspecified),
233 name,
234 cfg,
235 verbatim,
236 import_name_type,
237 })
238 }
239}
240
241impl LinkParser {
242 fn parse_link_name<S: Stage>(
243 item: &MetaItemParser,
244 name: &mut Option<(Symbol, Span)>,
245 cx: &mut AcceptContext<'_, '_, S>,
246 ) -> bool {
247 if name.is_some() {
248 cx.duplicate_key(item.span(), sym::name);
249 return true;
250 }
251 let Some(nv) = item.args().name_value() else {
252 cx.expected_name_value(item.span(), Some(sym::name));
253 return false;
254 };
255 let Some(link_name) = nv.value_as_str() else {
256 cx.expected_name_value(item.span(), Some(sym::name));
257 return false;
258 };
259
260 if link_name.is_empty() {
261 cx.emit_err(EmptyLinkName { span: nv.value_span });
262 }
263 *name = Some((link_name, nv.value_span));
264 true
265 }
266
267 fn parse_link_kind<S: Stage>(
268 item: &MetaItemParser,
269 kind: &mut Option<NativeLibKind>,
270 cx: &mut AcceptContext<'_, '_, S>,
271 sess: &Session,
272 features: &Features,
273 ) -> bool {
274 if kind.is_some() {
275 cx.duplicate_key(item.span(), sym::kind);
276 return true;
277 }
278 let Some(nv) = item.args().name_value() else {
279 cx.expected_name_value(item.span(), Some(sym::kind));
280 return true;
281 };
282 let Some(link_kind) = nv.value_as_str() else {
283 cx.expected_name_value(item.span(), Some(sym::kind));
284 return true;
285 };
286
287 let link_kind = match link_kind {
288 kw::Static => NativeLibKind::Static { bundle: None, whole_archive: None },
289 sym::dylib => NativeLibKind::Dylib { as_needed: None },
290 sym::framework => {
291 if !sess.target.is_like_darwin {
292 cx.emit_err(LinkFrameworkApple { span: nv.value_span });
293 }
294 NativeLibKind::Framework { as_needed: None }
295 }
296 sym::raw_dash_dylib => {
297 if sess.target.is_like_windows {
298 } else if sess.target.binary_format == BinaryFormat::Elf && features.raw_dylib_elf()
300 {
301 } else if sess.target.binary_format == BinaryFormat::Elf && sess.is_nightly_build()
303 {
304 feature_err(
305 sess,
306 sym::raw_dylib_elf,
307 nv.value_span,
308 fluent_generated::attr_parsing_raw_dylib_elf_unstable,
309 )
310 .emit();
311 } else {
312 cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
313 }
314
315 NativeLibKind::RawDylib { as_needed: None }
316 }
317 sym::link_dash_arg => {
318 if !features.link_arg_attribute() {
319 feature_err(
320 sess,
321 sym::link_arg_attribute,
322 nv.value_span,
323 fluent_generated::attr_parsing_link_arg_unstable,
324 )
325 .emit();
326 }
327 NativeLibKind::LinkArg
328 }
329 _kind => {
330 cx.expected_specific_argument_strings(
331 nv.value_span,
332 &[
333 kw::Static,
334 sym::dylib,
335 sym::framework,
336 sym::raw_dash_dylib,
337 sym::link_dash_arg,
338 ],
339 );
340 return true;
341 }
342 };
343 *kind = Some(link_kind);
344 true
345 }
346
347 fn parse_link_modifiers<S: Stage>(
348 item: &MetaItemParser,
349 modifiers: &mut Option<(Symbol, Span)>,
350 cx: &mut AcceptContext<'_, '_, S>,
351 ) -> bool {
352 if modifiers.is_some() {
353 cx.duplicate_key(item.span(), sym::modifiers);
354 return true;
355 }
356 let Some(nv) = item.args().name_value() else {
357 cx.expected_name_value(item.span(), Some(sym::modifiers));
358 return true;
359 };
360 let Some(link_modifiers) = nv.value_as_str() else {
361 cx.expected_name_value(item.span(), Some(sym::modifiers));
362 return true;
363 };
364 *modifiers = Some((link_modifiers, nv.value_span));
365 true
366 }
367
368 fn parse_link_cfg<S: Stage>(
369 item: &MetaItemParser,
370 cfg: &mut Option<CfgEntry>,
371 cx: &mut AcceptContext<'_, '_, S>,
372 sess: &Session,
373 features: &Features,
374 ) -> bool {
375 if cfg.is_some() {
376 cx.duplicate_key(item.span(), sym::cfg);
377 return true;
378 }
379 let Some(link_cfg) = item.args().list() else {
380 cx.expected_list(item.span(), item.args());
381 return true;
382 };
383 let Some(link_cfg) = link_cfg.single() else {
384 cx.expected_single_argument(item.span());
385 return true;
386 };
387 if !features.link_cfg() {
388 feature_err(
389 sess,
390 sym::link_cfg,
391 item.span(),
392 fluent_generated::attr_parsing_link_cfg_unstable,
393 )
394 .emit();
395 }
396 *cfg = parse_cfg_entry(cx, link_cfg).ok();
397 true
398 }
399
400 fn parse_link_wasm_import_module<S: Stage>(
401 item: &MetaItemParser,
402 wasm_import_module: &mut Option<(Symbol, Span)>,
403 cx: &mut AcceptContext<'_, '_, S>,
404 ) -> bool {
405 if wasm_import_module.is_some() {
406 cx.duplicate_key(item.span(), sym::wasm_import_module);
407 return true;
408 }
409 let Some(nv) = item.args().name_value() else {
410 cx.expected_name_value(item.span(), Some(sym::wasm_import_module));
411 return true;
412 };
413 let Some(link_wasm_import_module) = nv.value_as_str() else {
414 cx.expected_name_value(item.span(), Some(sym::wasm_import_module));
415 return true;
416 };
417 *wasm_import_module = Some((link_wasm_import_module, item.span()));
418 true
419 }
420
421 fn parse_link_import_name_type<S: Stage>(
422 item: &MetaItemParser,
423 import_name_type: &mut Option<(PeImportNameType, Span)>,
424 cx: &mut AcceptContext<'_, '_, S>,
425 ) -> bool {
426 if import_name_type.is_some() {
427 cx.duplicate_key(item.span(), sym::import_name_type);
428 return true;
429 }
430 let Some(nv) = item.args().name_value() else {
431 cx.expected_name_value(item.span(), Some(sym::import_name_type));
432 return true;
433 };
434 let Some(link_import_name_type) = nv.value_as_str() else {
435 cx.expected_name_value(item.span(), Some(sym::import_name_type));
436 return true;
437 };
438 if cx.sess().target.arch != Arch::X86 {
439 cx.emit_err(ImportNameTypeX86 { span: item.span() });
440 return true;
441 }
442
443 let link_import_name_type = match link_import_name_type {
444 sym::decorated => PeImportNameType::Decorated,
445 sym::noprefix => PeImportNameType::NoPrefix,
446 sym::undecorated => PeImportNameType::Undecorated,
447 _ => {
448 cx.expected_specific_argument_strings(
449 item.span(),
450 &[sym::decorated, sym::noprefix, sym::undecorated],
451 );
452 return true;
453 }
454 };
455 *import_name_type = Some((link_import_name_type, item.span()));
456 true
457 }
458}
459
460pub(crate) struct LinkSectionParser;
461
462impl<S: Stage> SingleAttributeParser<S> for LinkSectionParser {
463 const PATH: &[Symbol] = &[sym::link_section];
464 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost;
465 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::WarnButFutureError;
466 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
467 Allow(Target::Static),
468 Allow(Target::Fn),
469 Allow(Target::Method(MethodKind::Inherent)),
470 Allow(Target::Method(MethodKind::Trait { body: true })),
471 Allow(Target::Method(MethodKind::TraitImpl)),
472 ]);
473 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!(
474 NameValueStr: "name",
475 "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
476 );
477
478 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
479 let Some(nv) = args.name_value() else {
480 cx.expected_name_value(cx.attr_span, None);
481 return None;
482 };
483 let Some(name) = nv.value_as_str() else {
484 cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
485 return None;
486 };
487 if name.as_str().contains('\0') {
488 cx.emit_err(NullOnLinkSection { span: cx.attr_span });
491 return None;
492 }
493
494 Some(LinkSection { name, span: cx.attr_span })
495 }
496}
497
498pub(crate) struct ExportStableParser;
499impl<S: Stage> NoArgsAttributeParser<S> for ExportStableParser {
500 const PATH: &[Symbol] = &[sym::export_stable];
501 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
502 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
504}
505
506pub(crate) struct FfiConstParser;
507impl<S: Stage> NoArgsAttributeParser<S> for FfiConstParser {
508 const PATH: &[Symbol] = &[sym::ffi_const];
509 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
510 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
511 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiConst;
512}
513
514pub(crate) struct FfiPureParser;
515impl<S: Stage> NoArgsAttributeParser<S> for FfiPureParser {
516 const PATH: &[Symbol] = &[sym::ffi_pure];
517 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Warn;
518 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
519 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
520}
521
522pub(crate) struct StdInternalSymbolParser;
523impl<S: Stage> NoArgsAttributeParser<S> for StdInternalSymbolParser {
524 const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
525 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
526 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
527 Allow(Target::Fn),
528 Allow(Target::ForeignFn),
529 Allow(Target::Static),
530 Allow(Target::ForeignStatic),
531 ]);
532 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStdInternalSymbol;
533}
534
535pub(crate) struct LinkOrdinalParser;
536
537impl<S: Stage> SingleAttributeParser<S> for LinkOrdinalParser {
538 const PATH: &[Symbol] = &[sym::link_ordinal];
539 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
540 const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
541 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
542 Allow(Target::ForeignFn),
543 Allow(Target::ForeignStatic),
544 Warn(Target::MacroCall),
545 ]);
546 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!(
547 List: &["ordinal"],
548 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
549 );
550
551 fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option<AttributeKind> {
552 let ordinal = parse_single_integer(cx, args)?;
553
554 let Ok(ordinal) = ordinal.try_into() else {
568 cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
569 return None;
570 };
571
572 Some(LinkOrdinal { ordinal, span: cx.attr_span })
573 }
574}
575
576pub(crate) struct LinkageParser;
577
578impl<S: Stage> SingleAttributeParser<S> for LinkageParser {
579 const PATH: &[Symbol] = &[sym::linkage];
580
581 const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepOutermost;
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}