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