1use rustc_abi::ExternAbi;
2use rustc_ast::ItemKind;
3use rustc_attr_ir::AttributeKind::{LinkName, LinkOrdinal, LinkSection};
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 if cx.target != Target::ForeignMod {
266 return;
267 }
268
269 let item = cx.target_item.expect("missing AST target item for Target::ForeignMod");
270 let ItemKind::ForeignMod(fm) = &item.kind else {
271 {
::core::panicking::panic_fmt(format_args!("expected foreign module AST target item for Target::ForeignMod"));
};panic!("expected foreign module AST target item for Target::ForeignMod");
272 };
273 let abi = fm.abi.map_or(ExternAbi::FALLBACK, |abi| {
274 abi.symbol_unescaped.as_str().parse().unwrap_or_else(|_| {
275 cx.dcx().span_delayed_bug(
276 abi.span,
277 "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",
278 );
279 ExternAbi::Rust
280 })
281 });
282 if #[allow(non_exhaustive_omitted_patterns)] match abi {
ExternAbi::Rust => true,
_ => false,
}matches!(abi, ExternAbi::Rust) {
283 cx.emit_lint(UNUSED_ATTRIBUTES, Link, attr_span);
284 }
285 }
286}
287
288impl LinkParser {
289 fn parse_link_name(
290 item: &MetaItemParser,
291 name: &mut Option<(Symbol, Span)>,
292 cx: &mut AcceptContext<'_, '_>,
293 ) -> bool {
294 if name.is_some() {
295 cx.adcx().duplicate_key(item.span(), sym::name);
296 return true;
297 }
298 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::name)) else {
299 return false;
300 };
301 let Some(link_name) = cx.expect_string_literal(nv) else {
302 return false;
303 };
304
305 if link_name.as_str().contains('\0') {
306 cx.emit_err(NullOnLinkName { span: nv.value_span });
307 }
308 if link_name.is_empty() {
309 cx.emit_err(EmptyLinkName { span: nv.value_span });
310 }
311
312 *name = Some((link_name, nv.value_span));
313 true
314 }
315
316 fn parse_link_kind(
317 item: &MetaItemParser,
318 kind: &mut Option<NativeLibKind>,
319 cx: &mut AcceptContext<'_, '_>,
320 sess: &Session,
321 features: &Features,
322 ) -> bool {
323 if kind.is_some() {
324 cx.adcx().duplicate_key(item.span(), sym::kind);
325 return true;
326 }
327 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::kind)) else {
328 return true;
329 };
330 let Some(link_kind) = cx.expect_string_literal(nv) else {
331 return true;
332 };
333
334 let link_kind = match link_kind {
335 kw::Static => {
336 NativeLibKind::Static { bundle: None, whole_archive: None, export_symbols: None }
337 }
338 sym::dylib => NativeLibKind::Dylib { as_needed: None },
339 sym::framework => {
340 if !sess.target.is_like_darwin {
341 cx.emit_err(LinkFrameworkApple { span: nv.value_span });
342 }
343 NativeLibKind::Framework { as_needed: None }
344 }
345 sym::raw_dash_dylib => {
346 if sess.target.is_like_windows {
347 } else if sess.target.binary_format == BinaryFormat::Elf && features.raw_dylib_elf()
349 {
350 } else if sess.target.binary_format == BinaryFormat::Elf && sess.is_nightly_build()
352 {
353 feature_err(
354 sess,
355 sym::raw_dylib_elf,
356 nv.value_span,
357 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"),
358 )
359 .emit();
360 } else {
361 cx.emit_err(RawDylibOnlyWindows { span: nv.value_span });
362 }
363
364 NativeLibKind::RawDylib { as_needed: None }
365 }
366 sym::link_dash_arg => {
367 if !features.link_arg_attribute() {
368 feature_err(
369 sess,
370 sym::link_arg_attribute,
371 nv.value_span,
372 rustc_errors::DiagMessage::Inline(std::borrow::Cow::Borrowed("link kind `link-arg` is unstable"))msg!("link kind `link-arg` is unstable"),
373 )
374 .emit();
375 }
376 NativeLibKind::LinkArg
377 }
378 _kind => {
379 cx.adcx().expected_specific_argument_strings(
380 nv.value_span,
381 &[
382 kw::Static,
383 sym::dylib,
384 sym::framework,
385 sym::raw_dash_dylib,
386 sym::link_dash_arg,
387 ],
388 );
389 return true;
390 }
391 };
392 *kind = Some(link_kind);
393 true
394 }
395
396 fn parse_link_modifiers(
397 item: &MetaItemParser,
398 modifiers: &mut Option<(Symbol, Span)>,
399 cx: &mut AcceptContext<'_, '_>,
400 ) -> bool {
401 if modifiers.is_some() {
402 cx.adcx().duplicate_key(item.span(), sym::modifiers);
403 return true;
404 }
405 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::modifiers)) else {
406 return true;
407 };
408 let Some(link_modifiers) = cx.expect_string_literal(nv) else {
409 return true;
410 };
411 *modifiers = Some((link_modifiers, nv.value_span));
412 true
413 }
414
415 fn parse_link_cfg(
416 item: &MetaItemParser,
417 cfg: &mut Option<CfgEntry>,
418 cx: &mut AcceptContext<'_, '_>,
419 sess: &Session,
420 features: &Features,
421 ) -> bool {
422 if cfg.is_some() {
423 cx.adcx().duplicate_key(item.span(), sym::cfg);
424 return true;
425 }
426 let Some(link_cfg) = cx.expect_single_element_list(item.args(), item.span()) else {
427 return true;
428 };
429 if !features.link_cfg() {
430 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();
431 }
432 *cfg = parse_cfg_entry(cx, link_cfg).ok();
433 true
434 }
435
436 fn parse_link_wasm_import_module(
437 item: &MetaItemParser,
438 wasm_import_module: &mut Option<(Symbol, Span)>,
439 cx: &mut AcceptContext<'_, '_>,
440 ) -> bool {
441 if wasm_import_module.is_some() {
442 cx.adcx().duplicate_key(item.span(), sym::wasm_import_module);
443 return true;
444 }
445 let Some(nv) =
446 cx.expect_name_value(item.args(), item.span(), Some(sym::wasm_import_module))
447 else {
448 return true;
449 };
450 let Some(link_wasm_import_module) = cx.expect_string_literal(nv) else {
451 return true;
452 };
453 *wasm_import_module = Some((link_wasm_import_module, item.span()));
454 true
455 }
456
457 fn parse_link_import_name_type(
458 item: &MetaItemParser,
459 import_name_type: &mut Option<(PeImportNameType, Span)>,
460 cx: &mut AcceptContext<'_, '_>,
461 ) -> bool {
462 if import_name_type.is_some() {
463 cx.adcx().duplicate_key(item.span(), sym::import_name_type);
464 return true;
465 }
466 let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::import_name_type))
467 else {
468 return true;
469 };
470 let Some(link_import_name_type) = cx.expect_string_literal(nv) else {
471 return true;
472 };
473 if cx.sess().target.arch != Arch::X86 {
474 cx.emit_err(ImportNameTypeX86 { span: item.span() });
475 return true;
476 }
477
478 let link_import_name_type = match link_import_name_type {
479 sym::decorated => PeImportNameType::Decorated,
480 sym::noprefix => PeImportNameType::NoPrefix,
481 sym::undecorated => PeImportNameType::Undecorated,
482 _ => {
483 cx.adcx().expected_specific_argument_strings(
484 item.span(),
485 &[sym::decorated, sym::noprefix, sym::undecorated],
486 );
487 return true;
488 }
489 };
490 *import_name_type = Some((link_import_name_type, item.span()));
491 true
492 }
493}
494
495pub(crate) struct LinkSectionParser;
496
497fn check_link_section_macho(name: Symbol) -> Result<(), InvalidMachoSectionReason> {
498 let mut parts = name.as_str().split(',').map(|s| s.trim());
499
500 let _segment = parts.next();
502
503 let section = match parts.next() {
505 None | Some("") => return Err(InvalidMachoSectionReason::MissingSection),
506 Some(section) => section,
507 };
508
509 if section.len() > 16 {
510 return Err(InvalidMachoSectionReason::SectionTooLong { section: section.to_string() });
511 }
512
513 Ok(())
518}
519
520impl SingleAttributeParser for LinkSectionParser {
521 const PATH: &[Symbol] = &[sym::link_section];
522 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
523 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
524 note: "the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them",
525 unsafe_since: Some(Edition2024),
526 };
527 const STABILITY: AttributeStability = AttributeStability::Stable;
528 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[
529 Allow(Target::Static),
530 Allow(Target::Fn),
531 Allow(Target::Method(MethodKind::Inherent)),
532 Allow(Target::Method(MethodKind::Trait { body: true })),
533 Allow(Target::Method(MethodKind::TraitImpl)),
534 ]);
535 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!(
536 NameValueStr: "name",
537 "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"
538 );
539
540 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
541 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
542 let name = cx.expect_string_literal(nv)?;
543 if name.as_str().contains('\0') {
544 cx.emit_err(NullOnLinkSection { span: cx.attr_span });
547 return None;
548 }
549
550 match cx.sess.target.binary_format {
552 BinaryFormat::MachO => match check_link_section_macho(name) {
553 Ok(()) => {}
554 Err(reason) => {
555 cx.emit_err(InvalidMachoSection { name_span: nv.value_span, reason });
556 return None;
557 }
558 },
559 BinaryFormat::Coff | BinaryFormat::Elf | BinaryFormat::Wasm | BinaryFormat::Xcoff => {}
560 }
561
562 Some(LinkSection { name })
563 }
564}
565
566pub(crate) struct ExportStableParser;
567impl NoArgsAttributeParser for ExportStableParser {
568 const PATH: &[Symbol] = &[sym::export_stable];
569 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
570 Allow(Target::Fn),
571 Allow(Target::Method(MethodKind::Inherent)),
572 Allow(Target::Struct),
573 Allow(Target::Enum),
574 Allow(Target::Union),
575 Allow(Target::TyAlias),
576 Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })),
577 Allow(Target::AssocTy(AssocCtxt::Trait)),
578 Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })),
579 Allow(Target::Use),
580 Allow(Target::Mod),
581 Allow(Target::Impl { of_trait: false }),
582 ]);
583 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::export_stable;
AttributeStability::Unstable {
gate_name: rustc_span::sym::export_stable,
notes: &[],
}
}unstable!(export_stable);
584 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ExportStable;
585}
586
587pub(crate) struct FfiConstParser;
588impl NoArgsAttributeParser for FfiConstParser {
589 const PATH: &[Symbol] = &[sym::ffi_const];
590 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
591 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.",
592 unsafe_since: None,
593 };
594 const ALLOWED_TARGETS: AllowedTargets<'_> =
595 AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
596 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::ffi_const;
AttributeStability::Unstable {
gate_name: rustc_span::sym::ffi_const,
notes: &[],
}
}unstable!(ffi_const);
597 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::FfiConst;
598}
599
600pub(crate) struct FfiPureParser;
601impl NoArgsAttributeParser for FfiPureParser {
602 const PATH: &[Symbol] = &[sym::ffi_pure];
603 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
604 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.",
605 unsafe_since: None,
606 };
607 const ALLOWED_TARGETS: AllowedTargets<'_> =
608 AllowedTargets::AllowList(&[Allow(Target::ForeignFn)]);
609 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::ffi_pure;
AttributeStability::Unstable {
gate_name: rustc_span::sym::ffi_pure,
notes: &[],
}
}unstable!(ffi_pure);
610 const CREATE: fn(Span) -> AttributeKind = AttributeKind::FfiPure;
611
612 fn finalize_check(cx: &mut FinalizeCheckContext<'_, '_>, attr_span: Span) {
613 if cx.all_attrs.iter().any(|a| a.word_is(sym::ffi_const)) {
615 cx.emit_err(BothFfiConstAndPure { attr_span });
616 }
617 }
618}
619
620pub(crate) struct RustcStdInternalSymbolParser;
621impl NoArgsAttributeParser for RustcStdInternalSymbolParser {
622 const PATH: &[Symbol] = &[sym::rustc_std_internal_symbol];
623 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
624 Allow(Target::Fn),
625 Allow(Target::ForeignFn),
626 Allow(Target::Static),
627 Allow(Target::ForeignStatic),
628 ]);
629 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
notes: &[],
}
}unstable!(rustc_attrs);
630 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcStdInternalSymbol;
631}
632
633pub(crate) struct LinkOrdinalParser;
634
635impl SingleAttributeParser for LinkOrdinalParser {
636 const PATH: &[Symbol] = &[sym::link_ordinal];
637 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
638 Allow(Target::ForeignFn),
639 Allow(Target::ForeignStatic),
640 Warn(Target::MacroCall),
641 ]);
642 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!(
643 List: &["ordinal"],
644 "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"
645 );
646 const STABILITY: AttributeStability = AttributeStability::Stable;
647
648 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
649 let ordinal = parse_single_integer(cx, args)?;
650
651 let Ok(ordinal) = ordinal.try_into() else {
665 cx.emit_err(LinkOrdinalOutOfRange { span: cx.attr_span, ordinal });
666 return None;
667 };
668
669 Some(LinkOrdinal { ordinal, span: cx.attr_span })
670 }
671}
672
673pub(crate) struct LinkageParser;
674
675impl SingleAttributeParser for LinkageParser {
676 const PATH: &[Symbol] = &[sym::linkage];
677 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
678 Allow(Target::Fn), Allow(Target::Method(MethodKind::Inherent)),
680 Allow(Target::Method(MethodKind::Trait { body: true })),
681 Allow(Target::Method(MethodKind::TraitImpl)),
682 Allow(Target::Static),
683 Allow(Target::ForeignStatic), Allow(Target::ForeignFn),
685 ]);
686 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: [
687 "available_externally",
688 "extern_weak",
689 "linkonce",
690 "linkonce_odr",
691 "weak",
692 "weak_odr",
693 ]);
694 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::linkage;
AttributeStability::Unstable {
gate_name: rustc_span::sym::linkage,
notes: &[],
}
}unstable!(linkage);
695
696 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
697 let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::linkage))?;
698
699 let value = cx.expect_string_literal(name_value)?;
700
701 let linkage = match value {
710 sym::available_externally => Linkage::AvailableExternally,
711 sym::extern_weak => Linkage::ExternalWeak,
712 sym::linkonce => Linkage::LinkOnceAny,
713 sym::linkonce_odr => Linkage::LinkOnceODR,
714 sym::weak => Linkage::WeakAny,
715 sym::weak_odr => Linkage::WeakODR,
716
717 _ => {
718 cx.adcx().expected_specific_argument(
719 name_value.value_span,
720 &[
721 sym::available_externally,
722 sym::extern_weak,
723 sym::linkonce,
724 sym::linkonce_odr,
725 sym::weak,
726 sym::weak_odr,
727 ],
728 );
729 return None;
730 }
731 };
732
733 Some(AttributeKind::Linkage(linkage, cx.attr_span))
734 }
735}
736
737pub(crate) struct NeedsAllocatorParser;
738
739impl NoArgsAttributeParser for NeedsAllocatorParser {
740 const PATH: &[Symbol] = &[sym::needs_allocator];
741 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
742 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::allocator_internals;
AttributeStability::Unstable {
gate_name: rustc_span::sym::allocator_internals,
notes: &[],
}
}unstable!(allocator_internals);
743 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::NeedsAllocator;
744}
745
746pub(crate) struct CompilerBuiltinsParser;
747
748impl NoArgsAttributeParser for CompilerBuiltinsParser {
749 const PATH: &[Symbol] = &[sym::compiler_builtins];
750 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Crate)]);
751 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::compiler_builtins;
AttributeStability::Unstable {
gate_name: rustc_span::sym::compiler_builtins,
notes: &[],
}
}unstable!(compiler_builtins);
752 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::CompilerBuiltins;
753}