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