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