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