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