1use rustc_errors::msg;
2use rustc_feature::{AttributeStability, Features};
3use rustc_hir::attrs::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
4use rustc_hir::attrs::*;
5use rustc_session::Session;
6use rustc_session::diagnostics::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, BothFfiConstAndPure, BundleNeedsStatic, EmptyLinkName,
18 ExportSymbolsNeedsStatic, ImportNameTypeRaw, ImportNameTypeX86, IncompatibleWasmLink,
19 InvalidLinkModifier, InvalidMachoSection, InvalidMachoSectionReason, LinkFrameworkApple,
20 LinkOrdinalOutOfRange, LinkRequiresName, MultipleModifiers, NullOnLinkName, NullOnLinkSection,
21 RawDylibOnlyWindows, 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 = crate::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 const STABILITY: AttributeStability = AttributeStability::Stable;
38
39 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
40 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
41 let name = cx.expect_string_literal(nv)?;
42
43 if name.as_str().contains('\0') {
44 cx.emit_err(NullOnLinkName { span: nv.value_span });
47 return None;
48 }
49 if name.is_empty() {
50 cx.emit_err(EmptyLinkName { span: nv.value_span });
53 return None;
54 }
55
56 Some(LinkName { name, span: cx.attr_span })
57 }
58}
59
60pub(crate) struct LinkParser;
61
62impl CombineAttributeParser for LinkParser {
63 type Item = LinkEntry;
64 const PATH: &[Symbol] = &[sym::link];
65 const CONVERT: ConvertFn<Self::Item> = AttributeKind::Link;
66 const TEMPLATE: AttributeTemplate = crate::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: &[
67 r#"name = "...""#,
68 r#"name = "...", kind = "dylib|static|...""#,
69 r#"name = "...", wasm_import_module = "...""#,
70 r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
71 r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
72 ], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute");
73 const ALLOWED_TARGETS: AllowedTargets<'_> =
74 AllowedTargets::AllowListWarnRest(&[Allow(Target::ForeignMod)]);
75 const STABILITY: AttributeStability = AttributeStability::Stable;
76
77 fn extend(
78 cx: &mut AcceptContext<'_, '_>,
79 args: &ArgParser,
80 ) -> impl IntoIterator<Item = Self::Item> {
81 let items = match args {
82 ArgParser::List(list) => list,
83 ArgParser::NameValue(nv) if nv.value_as_str().is_some_and(|v| v == sym::dl) => {
87 cx.adcx().warn_ill_formed_attribute_input(ILL_FORMED_ATTRIBUTE_INPUT);
88 return None;
89 }
90 _ => {
91 let attr_span = cx.attr_span;
92 cx.adcx().expected_list(attr_span, args);
93 return None;
94 }
95 };
96
97 let sess = cx.sess();
98 let features = cx.features();
99
100 let mut name = None;
101 let mut kind = None;
102 let mut modifiers = None;
103 let mut cfg = None;
104 let mut wasm_import_module = None;
105 let mut import_name_type = None;
106 for item in items.mixed() {
107 let Some(item) = item.meta_item() else {
108 cx.adcx().expected_not_literal(item.span());
109 continue;
110 };
111
112 let cont = match item.path().word().map(|ident| ident.name) {
113 Some(sym::name) => Self::parse_link_name(item, &mut name, cx),
114 Some(sym::kind) => Self::parse_link_kind(item, &mut kind, cx, sess, features),
115 Some(sym::modifiers) => Self::parse_link_modifiers(item, &mut modifiers, cx),
116 Some(sym::cfg) => Self::parse_link_cfg(item, &mut cfg, cx, sess, features),
117 Some(sym::wasm_import_module) => {
118 Self::parse_link_wasm_import_module(item, &mut wasm_import_module, cx)
119 }
120 Some(sym::import_name_type) => {
121 Self::parse_link_import_name_type(item, &mut import_name_type, cx)
122 }
123 _ => {
124 cx.adcx().expected_specific_argument_strings(
125 item.span(),
126 &[
127 sym::name,
128 sym::kind,
129 sym::modifiers,
130 sym::cfg,
131 sym::wasm_import_module,
132 sym::import_name_type,
133 ],
134 );
135 true
136 }
137 };
138 if !cont {
139 return None;
140 }
141 }
142
143 let mut verbatim = None;
145 if let Some((modifiers, span)) = modifiers {
146 for modifier in modifiers.as_str().split(',') {
147 let (modifier, value): (Symbol, bool) =
148 if let Some(m) = modifier.strip_prefix(['+', '-']) {
149 (Symbol::intern(m), modifier.starts_with('+'))
150 } else {
151 cx.emit_err(InvalidLinkModifier { span });
152 continue;
153 };
154
155 macro report_unstable_modifier($feature: ident) {
156 if !features.$feature() {
157 feature_err(
158 sess,
159 sym::$feature,
160 span,
161 format!("linking modifier `{modifier}` is unstable"),
162 )
163 .emit();
164 }
165 }
166 let assign_modifier = |dst: &mut Option<bool>| {
167 if dst.is_some() {
168 cx.emit_err(MultipleModifiers { span, modifier });
169 } else {
170 *dst = Some(value);
171 }
172 };
173 match (modifier, &mut kind) {
174 (sym::bundle, Some(NativeLibKind::Static { bundle, .. })) => {
175 assign_modifier(bundle)
176 }
177 (sym::bundle, _) => {
178 cx.emit_err(BundleNeedsStatic { span });
179 }
180
181 (sym::export_symbols, Some(NativeLibKind::Static { export_symbols, .. })) => {
182 assign_modifier(export_symbols)
183 }
184
185 (sym::export_symbols, _) => {
186 cx.emit_err(ExportSymbolsNeedsStatic { span });
187 }
188
189 (sym::verbatim, _) => assign_modifier(&mut verbatim),
190
191 (
192 sym::whole_dash_archive,
193 Some(NativeLibKind::Static { whole_archive, .. }),
194 ) => assign_modifier(whole_archive),
195 (sym::whole_dash_archive, _) => {
196 cx.emit_err(WholeArchiveNeedsStatic { span });
197 }
198
199 (
200 sym::as_dash_needed,
201 Some(
202 NativeLibKind::Dylib { as_needed }
203 | NativeLibKind::Framework { as_needed }
204 | NativeLibKind::RawDylib { as_needed },
205 ),
206 ) => {
207 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);
208 assign_modifier(as_needed)
209 }
210 (sym::as_dash_needed, _) => {
211 cx.emit_err(AsNeededCompatibility { span });
212 }
213
214 _ => {
215 cx.adcx().expected_specific_argument_strings(
216 span,
217 &[
218 sym::bundle,
219 sym::export_symbols,
220 sym::verbatim,
221 sym::whole_dash_archive,
222 sym::as_dash_needed,
223 ],
224 );
225 }
226 }
227 }
228 }
229
230 if let Some((_, span)) = wasm_import_module {
231 if name.is_some() || kind.is_some() || modifiers.is_some() || cfg.is_some() {
232 cx.emit_err(IncompatibleWasmLink { span });
233 }
234 }
235
236 if wasm_import_module.is_some() {
237 (name, kind) = (wasm_import_module, Some(NativeLibKind::WasmImportModule));
238 }
239 let Some((name, _name_span)) = name else {
240 cx.emit_err(LinkRequiresName { span: cx.attr_span });
241 return None;
242 };
243
244 if let Some((_, span)) = import_name_type {
246 if !#[allow(non_exhaustive_omitted_patterns)] match kind {
Some(NativeLibKind::RawDylib { .. }) => true,
_ => false,
}matches!(kind, Some(NativeLibKind::RawDylib { .. })) {
247 cx.emit_err(ImportNameTypeRaw { span });
248 }
249 }
250
251 Some(LinkEntry {
252 span: cx.attr_span,
253 kind: kind.unwrap_or(NativeLibKind::Unspecified),
254 name,
255 cfg,
256 verbatim,
257 import_name_type,
258 })
259 }
260}
261
262impl LinkParser {
263 fn parse_link_name(
264 item: &MetaItemParser,
265 name: &mut Option<(Symbol, Span)>,
266 cx: &mut AcceptContext<'_, '_>,
267 ) -> bool {
268 if name.is_some() {
269 cx.adcx().duplicate_key(item.span(), sym::name);
270 return true;
271 }
272 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::name)) else {
273 return false;
274 };
275 let Some(link_name) = cx.expect_string_literal(nv) else {
276 return false;
277 };
278
279 if link_name.as_str().contains('\0') {
280 cx.emit_err(NullOnLinkName { span: nv.value_span });
281 }
282 if link_name.is_empty() {
283 cx.emit_err(EmptyLinkName { span: nv.value_span });
284 }
285
286 *name = Some((link_name, nv.value_span));
287 true
288 }
289
290 fn parse_link_kind(
291 item: &MetaItemParser,
292 kind: &mut Option<NativeLibKind>,
293 cx: &mut AcceptContext<'_, '_>,
294 sess: &Session,
295 features: &Features,
296 ) -> bool {
297 if kind.is_some() {
298 cx.adcx().duplicate_key(item.span(), sym::kind);
299 return true;
300 }
301 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::kind)) else {
302 return true;
303 };
304 let Some(link_kind) = cx.expect_string_literal(nv) else {
305 return true;
306 };
307
308 let link_kind = match link_kind {
309 kw::Static => {
310 NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
311 }
312 sym::dylib => NativeLibKind::Dylib { as_needed: None },
313 sym::framework => {
314 if !sess.target.is_like_darwin {
315 cx.emit_err(LinkFrameworkApple { span: nv.value_span });
316 }
317 NativeLibKind::Framework { as_needed: None }
318 }
319 sym::raw_dash_dylib => {
320 if sess.target.is_like_windows {
321 } else if sess.target.binary_format == BinaryFormat::Elf && features.raw_dylib_elf()
323 {
324 } else if sess.target.binary_format == BinaryFormat::Elf && sess.is_nightly_build()
326 {
327 feature_err(
328 sess,
329 sym::raw_dylib_elf,
330 nv.value_span,
331 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"),
332 )
333 .emit();
334 } else {
335 cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
336 }
337
338 NativeLibKind::RawDylib { as_needed: None }
339 }
340 sym::link_dash_arg => {
341 if !features.link_arg_attribute() {
342 feature_err(
343 sess,
344 sym::link_arg_attribute,
345 nv.value_span,
346 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("link kind `link-arg` is unstable"))msg!("link kind `link-arg` is unstable"),
347 )
348 .emit();
349 }
350 NativeLibKind::LinkArg
351 }
352 _kind => {
353 cx.adcx().expected_specific_argument_strings(
354 nv.value_span,
355 &[
356 kw::Static,
357 sym::dylib,
358 sym::framework,
359 sym::raw_dash_dylib,
360 sym::link_dash_arg,
361 ],
362 );
363 return true;
364 }
365 };
366 *kind = Some(link_kind);
367 true
368 }
369
370 fn parse_link_modifiers(
371 item: &MetaItemParser,
372 modifiers: &mut Option<(Symbol, Span)>,
373 cx: &mut AcceptContext<'_, '_>,
374 ) -> bool {
375 if modifiers.is_some() {
376 cx.adcx().duplicate_key(item.span(), sym::modifiers);
377 return true;
378 }
379 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::modifiers)) else {
380 return true;
381 };
382 let Some(link_modifiers) = cx.expect_string_literal(nv) else {
383 return true;
384 };
385 *modifiers = Some((link_modifiers, nv.value_span));
386 true
387 }
388
389 fn parse_link_cfg(
390 item: &MetaItemParser,
391 cfg: &mut Option<CfgEntry>,
392 cx: &mut AcceptContext<'_, '_>,
393 sess: &Session,
394 features: &Features,
395 ) -> bool {
396 if cfg.is_some() {
397 cx.adcx().duplicate_key(item.span(), sym::cfg);
398 return true;
399 }
400 let Some(link_cfg) = cx.expect_single_element_list(item.args(), item.span()) else {
401 return true;
402 };
403 if !features.link_cfg() {
404 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();
405 }
406 *cfg = parse_cfg_entry(cx, link_cfg).ok();
407 true
408 }
409
410 fn parse_link_wasm_import_module(
411 item: &MetaItemParser,
412 wasm_import_module: &mut Option<(Symbol, Span)>,
413 cx: &mut AcceptContext<'_, '_>,
414 ) -> bool {
415 if wasm_import_module.is_some() {
416 cx.adcx().duplicate_key(item.span(), sym::wasm_import_module);
417 return true;
418 }
419 let Some(nv) =
420 cx.expect_name_value(item.args(), item.span(), Some(sym::wasm_import_module))
421 else {
422 return true;
423 };
424 let Some(link_wasm_import_module) = cx.expect_string_literal(nv) else {
425 return true;
426 };
427 *wasm_import_module = Some((link_wasm_import_module, item.span()));
428 true
429 }
430
431 fn parse_link_import_name_type(
432 item: &MetaItemParser,
433 import_name_type: &mut Option<(PeImportNameType, Span)>,
434 cx: &mut AcceptContext<'_, '_>,
435 ) -> bool {
436 if import_name_type.is_some() {
437 cx.adcx().duplicate_key(item.span(), sym::import_name_type);
438 return true;
439 }
440 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::import_name_type))
441 else {
442 return true;
443 };
444 let Some(link_import_name_type) = cx.expect_string_literal(nv) else {
445 return true;
446 };
447 if cx.sess().target.arch != Arch::X86 {
448 cx.emit_err(ImportNameTypeX86 { span: item.span() });
449 return true;
450 }
451
452 let link_import_name_type = match link_import_name_type {
453 sym::decorated => PeImportNameType::Decorated,
454 sym::noprefix => PeImportNameType::NoPrefix,
455 sym::undecorated => PeImportNameType::Undecorated,
456 _ => {
457 cx.adcx().expected_specific_argument_strings(
458 item.span(),
459 &[sym::decorated, sym::noprefix, sym::undecorated],
460 );
461 return true;
462 }
463 };
464 *import_name_type = Some((link_import_name_type, item.span()));
465 true
466 }
467}
468
469pub(crate) struct LinkSectionParser;
470
471fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> {
472 let mut parts = name.as_str().split(',').map(|s| s.trim());
473
474 let _segment = parts.next();
476
477 let section = match parts.next() {
479 None | Some("") => return Err(InvalidMachoSectionReason::MissingSection),
480 Some(section) => section,
481 };
482
483 if section.len() > 16 {
484 return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() });
485 }
486
487 Ok(())
492}
493
494impl SingleAttributeParser for LinkSectionParser {
495 const PATH: &[Symbol] = &[sym::link_section];
496 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
497 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
498 note: "the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them",
499 unsafe_since: Some(Edition2024),
500 };
501 const STABILITY: AttributeStability = AttributeStability::Stable;
502 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[
503 Allow(Target::Static),
504 Allow(Target::Fn),
505 Allow(Target::Method(MethodKind::Inherent)),
506 Allow(Target::Method(MethodKind::Trait { body: true })),
507 Allow(Target::Method(MethodKind::TraitImpl)),
508 ]);
509 const TEMPLATE: AttributeTemplate = crate::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!(
510 NameValueStr: "name",
511 "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
512 );
513
514 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
515 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
516 let name = cx.expect_string_literal(nv)?;
517 if name.as_str().contains('\0') {
518 cx.emit_err(NullOnLinkSection { span: cx.attr_span });
521 return None;
522 }
523
524 match cx.sess.target.binary_format {
526 BinaryFormat::MachO => match check_link_section_macho(name) {
527 Ok(()) => {}
528 Err(reason) => {
529 cx.emit_err(InvalidMachoSection { name_span: nv.value_span, reason });
530 return None;
531 }
532 },
533 BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Wasm | BinaryFormat::Xcoff => {}
534 }
535
536 Some(LinkSection { name })
537 }
538}
539
540pub(crate) struct ExportStableParser;
541impl NoArgsAttributeParser for ExportStableParser {
542 const PATH: &[Symbol] = &[sym::export_stable];
543 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
544 Allow(Target::Fn),
545 Allow(Target::Method(MethodKind::Inherent)),
546 Allow(Target::Struct),
547 Allow(Target::Enum),
548 Allow(Target::Union),
549 Allow(Target::TyAlias),
550 Allow(Target::AssocTy),
551 Allow(Target::Use),
552 Allow(Target::Mod),
553 Allow(Target::Impl { of_trait: false }),
554 ]);
555 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::export_stable,
gate_check: rustc_feature::Features::export_stable,
notes: &[],
}unstable!(export_stable);
556 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
557}
558
559pub(crate) struct FfiConstParser;
560impl NoArgsAttributeParser for FfiConstParser {
561 const PATH: &[Symbol] = &[sym::ffi_const];
562 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
563 note: "`#[ffi_const]` functions shall have no effects except for its return value, which can only depend on the values of the function parameters, and is not affected by changes to the observable state of the program.",
564 unsafe_since: None,
565 };
566 const ALLOWED_TARGETS: AllowedTargets<'_> =
567 AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
568 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::ffi_const,
gate_check: rustc_feature::Features::ffi_const,
notes: &[],
}unstable!(ffi_const);
569 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::FfiConst;
570}
571
572pub(crate) struct FfiPureParser;
573impl NoArgsAttributeParser for FfiPureParser {
574 const PATH: &[Symbol] = &[sym::ffi_pure];
575 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
576 note: "`#[ffi_pure]` functions shall have no effects except for its return value, which shall not change across two consecutive function calls with the same parameters.",
577 unsafe_since: None,
578 };
579 const ALLOWED_TARGETS: AllowedTargets<'_> =
580 AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
581 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::ffi_pure,
gate_check: rustc_feature::Features::ffi_pure,
notes: &[],
}unstable!(ffi_pure);
582 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
583
584 fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
585 if cx.all_attrs.iter().any(|a| a.word_is(sym::ffi_const)) {
587 cx.emit_err(BothFfiConstAndPure { attr_span });
588 }
589 }
590}
591
592pub(crate) struct RustcStdInternalSymbolParser;
593impl NoArgsAttributeParser for RustcStdInternalSymbolParser {
594 const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
595 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
596 Allow(Target::Fn),
597 Allow(Target::ForeignFn),
598 Allow(Target::Static),
599 Allow(Target::ForeignStatic),
600 ]);
601 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
gate_check: rustc_feature::Features::rustc_attrs,
notes: &[],
}unstable!(rustc_attrs);
602 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcStdInternalSymbol;
603}
604
605pub(crate) struct LinkOrdinalParser;
606
607impl SingleAttributeParser for LinkOrdinalParser {
608 const PATH: &[Symbol] = &[sym::link_ordinal];
609 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
610 Allow(Target::ForeignFn),
611 Allow(Target::ForeignStatic),
612 Warn(Target::MacroCall),
613 ]);
614 const TEMPLATE: AttributeTemplate = crate::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!(
615 List: &["ordinal"],
616 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
617 );
618 const STABILITY: AttributeStability = AttributeStability::Stable;
619
620 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
621 let ordinal = parse_single_integer(cx, args)?;
622
623 let Ok(ordinal) = ordinal.try_into() else {
637 cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
638 return None;
639 };
640
641 Some(LinkOrdinal { ordinal, span: cx.attr_span })
642 }
643}
644
645pub(crate) struct LinkageParser;
646
647impl SingleAttributeParser for LinkageParser {
648 const PATH: &[Symbol] = &[sym::linkage];
649 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
650 Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)),
652 Allow(Target::Method(MethodKind::Trait { body: true })),
653 Allow(Target::Method(MethodKind::TraitImpl)),
654 Allow(Target::Static),
655 Allow(Target::ForeignStatic), Allow(Target::ForeignFn),
657 ]);
658 const TEMPLATE: AttributeTemplate = crate::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: [
659 "available_externally",
660 "common",
661 "extern_weak",
662 "external",
663 "internal",
664 "linkonce",
665 "linkonce_odr",
666 "weak",
667 "weak_odr",
668 ]);
669 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::linkage,
gate_check: rustc_feature::Features::linkage,
notes: &[],
}unstable!(linkage);
670
671 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
672 let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::linkage))?;
673
674 let value = cx.expect_string_literal(name_value)?;
675
676 let linkage = match value {
685 sym::available_externally => Linkage::AvailableExternally,
686 sym::common => Linkage::Common,
687 sym::extern_weak => Linkage::ExternalWeak,
688 sym::external => Linkage::External,
689 sym::internal => Linkage::Internal,
690 sym::linkonce => Linkage::LinkOnceAny,
691 sym::linkonce_odr => Linkage::LinkOnceODR,
692 sym::weak => Linkage::WeakAny,
693 sym::weak_odr => Linkage::WeakODR,
694
695 _ => {
696 cx.adcx().expected_specific_argument(
697 name_value.value_span,
698 &[
699 sym::available_externally,
700 sym::common,
701 sym::extern_weak,
702 sym::external,
703 sym::internal,
704 sym::linkonce,
705 sym::linkonce_odr,
706 sym::weak,
707 sym::weak_odr,
708 ],
709 );
710 return None;
711 }
712 };
713
714 Some(AttributeKind::Linkage(linkage, cx.attr_span))
715 }
716}
717
718pub(crate) struct NeedsAllocatorParser;
719
720impl NoArgsAttributeParser for NeedsAllocatorParser {
721 const PATH: &[Symbol] = &[sym::needs_allocator];
722 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
723 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::allocator_internals,
gate_check: rustc_feature::Features::allocator_internals,
notes: &[],
}unstable!(allocator_internals);
724 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
725}
726
727pub(crate) struct CompilerBuiltinsParser;
728
729impl NoArgsAttributeParser for CompilerBuiltinsParser {
730 const PATH: &[Symbol] = &[sym::compiler_builtins];
731 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
732 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::compiler_builtins,
gate_check: rustc_feature::Features::compiler_builtins,
notes: &[],
}unstable!(compiler_builtins);
733 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
734}