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