1use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
2use rustc_session::errors::feature_err;
3use rustc_span::edition::Edition::Edition2024;
4
5use super::prelude::*;
6use crate::attributes::AttributeSafety;
7use crate::session_diagnostics::{
8 NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector,
9 ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
10};
11use crate::target_checking::Policy::AllowSilent;
12
13pub(crate) struct OptimizeParser;
14
15impl SingleAttributeParser for OptimizeParser {
16 const PATH: &[Symbol] = &[sym::optimize];
17 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
18 Allow(Target::Fn),
19 Allow(Target::Closure),
20 Allow(Target::Method(MethodKind::Trait { body: true })),
21 Allow(Target::Method(MethodKind::TraitImpl)),
22 Allow(Target::Method(MethodKind::Inherent)),
23 ]);
24 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["size", "speed", "none"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["size", "speed", "none"]);
25
26 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
27 let single = cx.expect_single_element_list(args, cx.attr_span)?;
28
29 let res = match single.meta_item().and_then(|i| i.path().word().map(|i| i.name)) {
30 Some(sym::size) => OptimizeAttr::Size,
31 Some(sym::speed) => OptimizeAttr::Speed,
32 Some(sym::none) => OptimizeAttr::DoNotOptimize,
33 _ => {
34 cx.adcx()
35 .expected_specific_argument(single.span(), &[sym::size, sym::speed, sym::none]);
36 OptimizeAttr::Default
37 }
38 };
39
40 Some(AttributeKind::Optimize(res, cx.attr_span))
41 }
42}
43
44pub(crate) struct ColdParser;
45
46impl NoArgsAttributeParser for ColdParser {
47 const PATH: &[Symbol] = &[sym::cold];
48 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
49 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
50 Allow(Target::Fn),
51 Allow(Target::Method(MethodKind::Trait { body: true })),
52 Allow(Target::Method(MethodKind::TraitImpl)),
53 Allow(Target::Method(MethodKind::Inherent)),
54 Allow(Target::ForeignFn),
55 Allow(Target::Closure),
56 ]);
57 const CREATE: fn(Span) -> AttributeKind = AttributeKind::Cold;
58}
59
60pub(crate) struct CoverageParser;
61
62impl SingleAttributeParser for CoverageParser {
63 const PATH: &[Symbol] = &[sym::coverage];
64 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
65 Allow(Target::Fn),
66 Allow(Target::Closure),
67 Allow(Target::Method(MethodKind::Trait { body: true })),
68 Allow(Target::Method(MethodKind::TraitImpl)),
69 Allow(Target::Method(MethodKind::Inherent)),
70 Allow(Target::Impl { of_trait: true }),
71 Allow(Target::Impl { of_trait: false }),
72 Allow(Target::Mod),
73 Allow(Target::Crate),
74 ]);
75 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[sym::off, sym::on],
name_value_str: None,
docs: None,
}template!(OneOf: &[sym::off, sym::on]);
76
77 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
78 let arg = cx.expect_single_element_list(args, cx.attr_span)?;
79
80 let mut fail_incorrect_argument =
81 |span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]);
82
83 let Some(arg) = arg.meta_item() else {
84 fail_incorrect_argument(arg.span());
85 return None;
86 };
87
88 let kind = match arg.path().word_sym() {
89 Some(sym::off) => CoverageAttrKind::Off,
90 Some(sym::on) => CoverageAttrKind::On,
91 None | Some(_) => {
92 fail_incorrect_argument(arg.span());
93 return None;
94 }
95 };
96
97 Some(AttributeKind::Coverage(cx.attr_span, kind))
98 }
99}
100
101pub(crate) struct ExportNameParser;
102
103impl SingleAttributeParser for ExportNameParser {
104 const PATH: &[rustc_span::Symbol] = &[sym::export_name];
105 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
106 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
107 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
108 Allow(Target::Static),
109 Allow(Target::Fn),
110 Allow(Target::Method(MethodKind::Inherent)),
111 Allow(Target::Method(MethodKind::Trait { body: true })),
112 Allow(Target::Method(MethodKind::TraitImpl)),
113 Warn(Target::Field),
114 Warn(Target::Arm),
115 Warn(Target::MacroDef),
116 Warn(Target::MacroCall),
117 ]);
118 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["name"]),
docs: None,
}template!(NameValueStr: "name");
119
120 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
121 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
122 let Some(name) = nv.value_as_str() else {
123 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));
124 return None;
125 };
126 if name.as_str().contains('\0') {
127 cx.emit_err(NullOnExport { span: cx.attr_span });
130 return None;
131 }
132 Some(AttributeKind::ExportName { name, span: cx.attr_span })
133 }
134}
135
136pub(crate) struct RustcObjcClassParser;
137
138impl SingleAttributeParser for RustcObjcClassParser {
139 const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class];
140 const ALLOWED_TARGETS: AllowedTargets =
141 AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
142 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["ClassName"]),
docs: None,
}template!(NameValueStr: "ClassName");
143
144 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
145 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
146 let Some(classname) = nv.value_as_str() else {
147 cx.emit_err(ObjcClassExpectedStringLiteral { span: nv.value_span });
151 return None;
152 };
153 if classname.as_str().contains('\0') {
154 cx.emit_err(NullOnObjcClass { span: nv.value_span });
157 return None;
158 }
159 Some(AttributeKind::RustcObjcClass { classname, span: cx.attr_span })
160 }
161}
162
163pub(crate) struct RustcObjcSelectorParser;
164
165impl SingleAttributeParser for RustcObjcSelectorParser {
166 const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector];
167 const ALLOWED_TARGETS: AllowedTargets =
168 AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
169 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["methodName"]),
docs: None,
}template!(NameValueStr: "methodName");
170
171 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
172 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
173 let Some(methname) = nv.value_as_str() else {
174 cx.emit_err(ObjcSelectorExpectedStringLiteral { span: nv.value_span });
178 return None;
179 };
180 if methname.as_str().contains('\0') {
181 cx.emit_err(NullOnObjcSelector { span: nv.value_span });
184 return None;
185 }
186 Some(AttributeKind::RustcObjcSelector { methname, span: cx.attr_span })
187 }
188}
189
190#[derive(#[automatically_derived]
impl ::core::default::Default for NakedParser {
#[inline]
fn default() -> NakedParser {
NakedParser { span: ::core::default::Default::default() }
}
}Default)]
191pub(crate) struct NakedParser {
192 span: Option<Span>,
193}
194
195impl AttributeParser for NakedParser {
196 const ATTRIBUTES: AcceptMapping<Self> =
197 &[(&[sym::naked], ::rustc_feature::AttributeTemplate {
word: true,
list: None,
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word), |this, cx, args| {
198 let Some(()) = cx.expect_no_args(args) else {
199 return;
200 };
201
202 if let Some(earlier) = this.span {
203 let span = cx.attr_span;
204 cx.warn_unused_duplicate(earlier, span);
205 } else {
206 this.span = Some(cx.attr_span);
207 }
208 })];
209 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
210 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
211 Allow(Target::Fn),
212 Allow(Target::Method(MethodKind::Inherent)),
213 Allow(Target::Method(MethodKind::Trait { body: true })),
214 Allow(Target::Method(MethodKind::TraitImpl)),
215 Warn(Target::MacroCall),
216 ]);
217
218 fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
219 const ALLOW_LIST: &[rustc_span::Symbol] = &[
232 sym::cfg_trace,
234 sym::cfg_attr_trace,
235 sym::test,
237 sym::ignore,
238 sym::should_panic,
239 sym::bench,
240 sym::allow,
242 sym::warn,
243 sym::deny,
244 sym::forbid,
245 sym::deprecated,
246 sym::must_use,
247 sym::cold,
249 sym::export_name,
250 sym::link_section,
251 sym::linkage,
252 sym::no_mangle,
253 sym::instruction_set,
254 sym::repr,
255 sym::rustc_std_internal_symbol,
256 sym::rustc_align,
258 sym::rustc_align_static,
259 sym::naked,
261 sym::doc,
263 ];
264
265 let span = self.span?;
266
267 'outer: for other_attr in cx.all_attrs {
269 for allowed_attr in ALLOW_LIST {
270 if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
271 continue 'outer;
274 }
275 if other_attr.word_is(*allowed_attr) {
276 continue 'outer;
279 }
280
281 if other_attr.word_is(sym::target_feature) {
282 if !cx.features().naked_functions_target_feature() {
283 feature_err(
284 &cx.sess(),
285 sym::naked_functions_target_feature,
286 other_attr.span(),
287 "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions",
288 ).emit();
289 }
290
291 continue 'outer;
292 }
293 }
294
295 cx.emit_err(NakedFunctionIncompatibleAttribute {
296 span: other_attr.span(),
297 naked_span: span,
298 attr: other_attr.get_attribute_path().to_string(),
299 });
300 }
301
302 Some(AttributeKind::Naked(span))
303 }
304}
305
306pub(crate) struct TrackCallerParser;
307impl NoArgsAttributeParser for TrackCallerParser {
308 const PATH: &[Symbol] = &[sym::track_caller];
309 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
310 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
311 Allow(Target::Fn),
312 Allow(Target::Method(MethodKind::Inherent)),
313 Allow(Target::Method(MethodKind::Trait { body: true })),
314 Allow(Target::Method(MethodKind::TraitImpl)),
315 Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::ForeignFn),
317 Allow(Target::Closure),
318 Warn(Target::MacroDef),
319 Warn(Target::Arm),
320 Warn(Target::Field),
321 Warn(Target::MacroCall),
322 ]);
323 const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
324}
325
326pub(crate) struct NoMangleParser;
327impl NoArgsAttributeParser for NoMangleParser {
328 const PATH: &[Symbol] = &[sym::no_mangle];
329 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
330 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
331 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
332 Allow(Target::Fn),
333 Allow(Target::Static),
334 Allow(Target::Method(MethodKind::Inherent)),
335 Allow(Target::Method(MethodKind::TraitImpl)),
336 AllowSilent(Target::Const), Error(Target::Closure),
338 ]);
339 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
340}
341
342#[derive(#[automatically_derived]
impl ::core::default::Default for UsedParser {
#[inline]
fn default() -> UsedParser {
UsedParser {
first_compiler: ::core::default::Default::default(),
first_linker: ::core::default::Default::default(),
first_default: ::core::default::Default::default(),
}
}
}Default)]
343pub(crate) struct UsedParser {
344 first_compiler: Option<Span>,
345 first_linker: Option<Span>,
346 first_default: Option<Span>,
347}
348
349impl AttributeParser for UsedParser {
354 const ATTRIBUTES: AcceptMapping<Self> = &[(
355 &[sym::used],
356 ::rustc_feature::AttributeTemplate {
word: true,
list: Some(&["compiler", "linker"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["compiler", "linker"]),
357 |group: &mut Self, cx, args| {
358 let used_by = match args {
359 ArgParser::NoArgs => UsedBy::Default,
360 ArgParser::List(list) => {
361 let Some(l) = cx.expect_single(list) else {
362 return;
363 };
364
365 match l.meta_item().and_then(|i| i.path().word_sym()) {
366 Some(sym::compiler) => {
367 if !cx.features().used_with_arg() {
368 feature_err(
369 &cx.sess(),
370 sym::used_with_arg,
371 cx.attr_span,
372 "`#[used(compiler)]` is currently unstable",
373 )
374 .emit();
375 }
376 UsedBy::Compiler
377 }
378 Some(sym::linker) => {
379 if !cx.features().used_with_arg() {
380 feature_err(
381 &cx.sess(),
382 sym::used_with_arg,
383 cx.attr_span,
384 "`#[used(linker)]` is currently unstable",
385 )
386 .emit();
387 }
388 UsedBy::Linker
389 }
390 _ => {
391 cx.adcx().expected_specific_argument(
392 l.span(),
393 &[sym::compiler, sym::linker],
394 );
395 return;
396 }
397 }
398 }
399 ArgParser::NameValue(_) => return,
400 };
401
402 let attr_span = cx.attr_span;
403
404 let target = match used_by {
408 UsedBy::Compiler => &mut group.first_compiler,
409 UsedBy::Linker => {
410 if let Some(prev) = group.first_default {
411 cx.warn_unused_duplicate(prev, attr_span);
412 return;
413 }
414 &mut group.first_linker
415 }
416 UsedBy::Default => {
417 if let Some(prev) = group.first_linker {
418 cx.warn_unused_duplicate(prev, attr_span);
419 return;
420 }
421 &mut group.first_default
422 }
423 };
424
425 if let Some(prev) = *target {
426 cx.warn_unused_duplicate(prev, attr_span);
427 } else {
428 *target = Some(attr_span);
429 }
430 },
431 )];
432 const ALLOWED_TARGETS: AllowedTargets =
433 AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]);
434
435 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
436 Some(match (self.first_compiler, self.first_linker, self.first_default) {
439 (_, Some(span), _) => AttributeKind::Used { used_by: UsedBy::Linker, span },
440 (Some(span), _, _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
441 (_, _, Some(span)) => AttributeKind::Used { used_by: UsedBy::Default, span },
442 (None, None, None) => return None,
443 })
444 }
445}
446
447fn parse_tf_attribute(
448 cx: &mut AcceptContext<'_, '_>,
449 args: &ArgParser,
450) -> impl IntoIterator<Item = (Symbol, Span)> {
451 let mut features = Vec::new();
452 let Some(list) = cx.expect_list(args, cx.attr_span) else {
453 return features;
454 };
455 if list.is_empty() {
456 let attr_span = cx.attr_span;
457 cx.adcx().warn_empty_attribute(attr_span);
458 return features;
459 }
460 for item in list.mixed() {
461 let Some((ident, value)) = cx.expect_name_value(item, item.span(), Some(sym::enable))
462 else {
463 return features;
464 };
465
466 if ident.name != sym::enable {
468 cx.adcx().expected_specific_argument(ident.span, &[sym::enable]);
469 return features;
470 }
471
472 let Some(value_str) = value.value_as_str() else {
474 cx.adcx().expected_string_literal(value.value_span, Some(value.value_as_lit()));
475 return features;
476 };
477 for feature in value_str.as_str().split(",") {
478 features.push((Symbol::intern(feature), item.span()));
479 }
480 }
481 features
482}
483
484pub(crate) struct TargetFeatureParser;
485
486impl CombineAttributeParser for TargetFeatureParser {
487 type Item = (Symbol, Span);
488 const PATH: &[Symbol] = &[sym::target_feature];
489 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
490 features: items,
491 attr_span: span,
492 was_forced: false,
493 };
494 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["enable = \"feat1, feat2\""]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["enable = \"feat1, feat2\""]);
495
496 fn extend(
497 cx: &mut AcceptContext<'_, '_>,
498 args: &ArgParser,
499 ) -> impl IntoIterator<Item = Self::Item> {
500 parse_tf_attribute(cx, args)
501 }
502
503 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
504 Allow(Target::Fn),
505 Allow(Target::Method(MethodKind::Inherent)),
506 Allow(Target::Method(MethodKind::Trait { body: true })),
507 Allow(Target::Method(MethodKind::TraitImpl)),
508 Warn(Target::Statement),
509 Warn(Target::Field),
510 Warn(Target::Arm),
511 Warn(Target::MacroDef),
512 Warn(Target::MacroCall),
513 ]);
514}
515
516pub(crate) struct ForceTargetFeatureParser;
517
518impl CombineAttributeParser for ForceTargetFeatureParser {
519 type Item = (Symbol, Span);
520 const PATH: &[Symbol] = &[sym::force_target_feature];
521 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
522 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
523 features: items,
524 attr_span: span,
525 was_forced: true,
526 };
527 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["enable = \"feat1, feat2\""]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["enable = \"feat1, feat2\""]);
528 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
529 Allow(Target::Fn),
530 Allow(Target::Method(MethodKind::Inherent)),
531 Allow(Target::Method(MethodKind::Trait { body: true })),
532 Allow(Target::Method(MethodKind::TraitImpl)),
533 ]);
534
535 fn extend(
536 cx: &mut AcceptContext<'_, '_>,
537 args: &ArgParser,
538 ) -> impl IntoIterator<Item = Self::Item> {
539 parse_tf_attribute(cx, args)
540 }
541}
542
543pub(crate) struct SanitizeParser;
544
545impl SingleAttributeParser for SanitizeParser {
546 const PATH: &[Symbol] = &[sym::sanitize];
547
548 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
550
551 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&[r#"address = "on|off""#, r#"kernel_address = "on|off""#,
r#"cfi = "on|off""#, r#"hwaddress = "on|off""#,
r#"kernel_hwaddress = "on|off""#, r#"kcfi = "on|off""#,
r#"memory = "on|off""#, r#"memtag = "on|off""#,
r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#,
r#"realtime = "nonblocking|blocking|caller""#]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &[
552 r#"address = "on|off""#,
553 r#"kernel_address = "on|off""#,
554 r#"cfi = "on|off""#,
555 r#"hwaddress = "on|off""#,
556 r#"kernel_hwaddress = "on|off""#,
557 r#"kcfi = "on|off""#,
558 r#"memory = "on|off""#,
559 r#"memtag = "on|off""#,
560 r#"shadow_call_stack = "on|off""#,
561 r#"thread = "on|off""#,
562 r#"realtime = "nonblocking|blocking|caller""#,
563 ]);
564
565 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
566 let list = cx.expect_list(args, cx.attr_span)?;
567
568 let mut on_set = SanitizerSet::empty();
569 let mut off_set = SanitizerSet::empty();
570 let mut rtsan = None;
571
572 for item in list.mixed() {
573 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
574 continue;
575 };
576
577 let mut apply = |s: SanitizerSet| {
578 let is_on = match value.value_as_str() {
579 Some(sym::on) => true,
580 Some(sym::off) => false,
581 Some(_) => {
582 cx.adcx().expected_specific_argument_strings(
583 value.value_span,
584 &[sym::on, sym::off],
585 );
586 return;
587 }
588 None => {
589 cx.adcx()
590 .expected_string_literal(value.value_span, Some(value.value_as_lit()));
591 return;
592 }
593 };
594
595 if is_on {
596 on_set |= s;
597 } else {
598 off_set |= s;
599 }
600 };
601
602 match ident.name {
603 sym::address | sym::kernel_address => {
604 apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
605 }
606 sym::cfi => apply(SanitizerSet::CFI),
607 sym::kcfi => apply(SanitizerSet::KCFI),
608 sym::memory => apply(SanitizerSet::MEMORY),
609 sym::memtag => apply(SanitizerSet::MEMTAG),
610 sym::shadow_call_stack => apply(SanitizerSet::SHADOWCALLSTACK),
611 sym::thread => apply(SanitizerSet::THREAD),
612 sym::hwaddress | sym::kernel_hwaddress => {
613 apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
614 }
615 sym::realtime => match value.value_as_str() {
616 Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
617 Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
618 Some(sym::caller) => rtsan = Some(RtsanSetting::Caller),
619 _ => {
620 cx.adcx().expected_specific_argument_strings(
621 value.value_span,
622 &[sym::nonblocking, sym::blocking, sym::caller],
623 );
624 }
625 },
626 _ => {
627 cx.adcx().expected_specific_argument_strings(
628 ident.span,
629 &[
630 sym::address,
631 sym::kernel_address,
632 sym::cfi,
633 sym::kcfi,
634 sym::memory,
635 sym::memtag,
636 sym::shadow_call_stack,
637 sym::thread,
638 sym::hwaddress,
639 sym::kernel_hwaddress,
640 sym::realtime,
641 ],
642 );
643 continue;
644 }
645 }
646 }
647
648 Some(AttributeKind::Sanitize { on_set, off_set, rtsan, span: cx.attr_span })
649 }
650}
651
652pub(crate) struct ThreadLocalParser;
653
654impl NoArgsAttributeParser for ThreadLocalParser {
655 const PATH: &[Symbol] = &[sym::thread_local];
656 const ALLOWED_TARGETS: AllowedTargets =
657 AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
658 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
659}
660
661pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
662
663impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser {
664 const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
665 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
666 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
667}
668
669pub(crate) struct RustcEiiForeignItemParser;
670
671impl NoArgsAttributeParser for RustcEiiForeignItemParser {
672 const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
673 const ALLOWED_TARGETS: AllowedTargets =
674 AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
675 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
676}
677
678pub(crate) struct PatchableFunctionEntryParser;
679
680impl SingleAttributeParser for PatchableFunctionEntryParser {
681 const PATH: &[Symbol] = &[sym::patchable_function_entry];
682 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
683 const TEMPLATE: AttributeTemplate = ::rustc_feature::AttributeTemplate {
word: false,
list: Some(&["prefix_nops = m, entry_nops = n"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["prefix_nops = m, entry_nops = n"]);
684
685 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
686 let meta_item_list = cx.expect_list(args, cx.attr_span)?;
687
688 let mut prefix = None;
689 let mut entry = None;
690
691 if meta_item_list.len() == 0 {
692 cx.adcx().expected_at_least_one_argument(meta_item_list.span);
693 return None;
694 }
695
696 let mut errored = false;
697
698 for item in meta_item_list.mixed() {
699 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
700 continue;
701 };
702
703 let attrib_to_write = match ident.name {
704 sym::prefix_nops => {
705 if prefix.is_some() {
707 errored = true;
708 cx.adcx().duplicate_key(ident.span, sym::prefix_nops);
709 continue;
710 }
711 &mut prefix
712 }
713 sym::entry_nops => {
714 if entry.is_some() {
716 errored = true;
717 cx.adcx().duplicate_key(ident.span, sym::entry_nops);
718 continue;
719 }
720 &mut entry
721 }
722 _ => {
723 errored = true;
724 cx.adcx().expected_specific_argument(
725 ident.span,
726 &[sym::prefix_nops, sym::entry_nops],
727 );
728 continue;
729 }
730 };
731
732 let rustc_ast::LitKind::Int(val, _) = value.value_as_lit().kind else {
733 errored = true;
734 cx.adcx().expected_integer_literal(value.value_span);
735 continue;
736 };
737
738 let Ok(val) = val.get().try_into() else {
739 errored = true;
740 cx.adcx().expected_integer_literal_in_range(
741 value.value_span,
742 u8::MIN as isize,
743 u8::MAX as isize,
744 );
745 continue;
746 };
747
748 *attrib_to_write = Some(val);
749 }
750
751 if errored {
752 None
753 } else {
754 Some(AttributeKind::PatchableFunctionEntry {
755 prefix: prefix.unwrap_or(0),
756 entry: entry.unwrap_or(0),
757 })
758 }
759 }
760}