1use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
2use rustc_session::parse::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 if let Err(span) = args.no_args() {
199 cx.adcx().expected_no_args(span);
200 return;
201 }
202
203 if let Some(earlier) = this.span {
204 let span = cx.attr_span;
205 cx.warn_unused_duplicate(earlier, span);
206 } else {
207 this.span = Some(cx.attr_span);
208 }
209 })];
210 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
211 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
212 Allow(Target::Fn),
213 Allow(Target::Method(MethodKind::Inherent)),
214 Allow(Target::Method(MethodKind::Trait { body: true })),
215 Allow(Target::Method(MethodKind::TraitImpl)),
216 Warn(Target::MacroCall),
217 ]);
218
219 fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
220 const ALLOW_LIST: &[rustc_span::Symbol] = &[
233 sym::cfg_trace,
235 sym::cfg_attr_trace,
236 sym::test,
238 sym::ignore,
239 sym::should_panic,
240 sym::bench,
241 sym::allow,
243 sym::warn,
244 sym::deny,
245 sym::forbid,
246 sym::deprecated,
247 sym::must_use,
248 sym::cold,
250 sym::export_name,
251 sym::link_section,
252 sym::linkage,
253 sym::no_mangle,
254 sym::instruction_set,
255 sym::repr,
256 sym::rustc_std_internal_symbol,
257 sym::rustc_align,
259 sym::rustc_align_static,
260 sym::naked,
262 sym::doc,
264 ];
265
266 let span = self.span?;
267
268 'outer: for other_attr in cx.all_attrs {
270 for allowed_attr in ALLOW_LIST {
271 if other_attr.segments().next().is_some_and(|i| cx.tools.contains(&i.name)) {
272 continue 'outer;
275 }
276 if other_attr.word_is(*allowed_attr) {
277 continue 'outer;
280 }
281
282 if other_attr.word_is(sym::target_feature) {
283 if !cx.features().naked_functions_target_feature() {
284 feature_err(
285 &cx.sess(),
286 sym::naked_functions_target_feature,
287 other_attr.span(),
288 "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions",
289 ).emit();
290 }
291
292 continue 'outer;
293 }
294 }
295
296 cx.emit_err(NakedFunctionIncompatibleAttribute {
297 span: other_attr.span(),
298 naked_span: span,
299 attr: other_attr.get_attribute_path().to_string(),
300 });
301 }
302
303 Some(AttributeKind::Naked(span))
304 }
305}
306
307pub(crate) struct TrackCallerParser;
308impl NoArgsAttributeParser for TrackCallerParser {
309 const PATH: &[Symbol] = &[sym::track_caller];
310 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
311 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
312 Allow(Target::Fn),
313 Allow(Target::Method(MethodKind::Inherent)),
314 Allow(Target::Method(MethodKind::Trait { body: true })),
315 Allow(Target::Method(MethodKind::TraitImpl)),
316 Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::ForeignFn),
318 Allow(Target::Closure),
319 Warn(Target::MacroDef),
320 Warn(Target::Arm),
321 Warn(Target::Field),
322 Warn(Target::MacroCall),
323 ]);
324 const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
325}
326
327pub(crate) struct NoMangleParser;
328impl NoArgsAttributeParser for NoMangleParser {
329 const PATH: &[Symbol] = &[sym::no_mangle];
330 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
331 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: Some(Edition2024) };
332 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
333 Allow(Target::Fn),
334 Allow(Target::Static),
335 Allow(Target::Method(MethodKind::Inherent)),
336 Allow(Target::Method(MethodKind::TraitImpl)),
337 AllowSilent(Target::Const), Error(Target::Closure),
339 ]);
340 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
341}
342
343#[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)]
344pub(crate) struct UsedParser {
345 first_compiler: Option<Span>,
346 first_linker: Option<Span>,
347 first_default: Option<Span>,
348}
349
350impl AttributeParser for UsedParser {
355 const ATTRIBUTES: AcceptMapping<Self> = &[(
356 &[sym::used],
357 ::rustc_feature::AttributeTemplate {
word: true,
list: Some(&["compiler", "linker"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["compiler", "linker"]),
358 |group: &mut Self, cx, args| {
359 let used_by = match args {
360 ArgParser::NoArgs => UsedBy::Default,
361 ArgParser::List(list) => {
362 let Some(l) = cx.expect_single(list) else {
363 return;
364 };
365
366 match l.meta_item().and_then(|i| i.path().word_sym()) {
367 Some(sym::compiler) => {
368 if !cx.features().used_with_arg() {
369 feature_err(
370 &cx.sess(),
371 sym::used_with_arg,
372 cx.attr_span,
373 "`#[used(compiler)]` is currently unstable",
374 )
375 .emit();
376 }
377 UsedBy::Compiler
378 }
379 Some(sym::linker) => {
380 if !cx.features().used_with_arg() {
381 feature_err(
382 &cx.sess(),
383 sym::used_with_arg,
384 cx.attr_span,
385 "`#[used(linker)]` is currently unstable",
386 )
387 .emit();
388 }
389 UsedBy::Linker
390 }
391 _ => {
392 cx.adcx().expected_specific_argument(
393 l.span(),
394 &[sym::compiler, sym::linker],
395 );
396 return;
397 }
398 }
399 }
400 ArgParser::NameValue(_) => return,
401 };
402
403 let attr_span = cx.attr_span;
404
405 let target = match used_by {
409 UsedBy::Compiler => &mut group.first_compiler,
410 UsedBy::Linker => {
411 if let Some(prev) = group.first_default {
412 cx.warn_unused_duplicate(prev, attr_span);
413 return;
414 }
415 &mut group.first_linker
416 }
417 UsedBy::Default => {
418 if let Some(prev) = group.first_linker {
419 cx.warn_unused_duplicate(prev, attr_span);
420 return;
421 }
422 &mut group.first_default
423 }
424 };
425
426 if let Some(prev) = *target {
427 cx.warn_unused_duplicate(prev, attr_span);
428 } else {
429 *target = Some(attr_span);
430 }
431 },
432 )];
433 const ALLOWED_TARGETS: AllowedTargets =
434 AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]);
435
436 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
437 Some(match (self.first_compiler, self.first_linker, self.first_default) {
440 (_, Some(span), _) => AttributeKind::Used { used_by: UsedBy::Linker, span },
441 (Some(span), _, _) => AttributeKind::Used { used_by: UsedBy::Compiler, span },
442 (_, _, Some(span)) => AttributeKind::Used { used_by: UsedBy::Default, span },
443 (None, None, None) => return None,
444 })
445 }
446}
447
448fn parse_tf_attribute(
449 cx: &mut AcceptContext<'_, '_>,
450 args: &ArgParser,
451) -> impl IntoIterator<Item = (Symbol, Span)> {
452 let mut features = Vec::new();
453 let Some(list) = cx.expect_list(args, cx.attr_span) else {
454 return features;
455 };
456 if list.is_empty() {
457 let attr_span = cx.attr_span;
458 cx.adcx().warn_empty_attribute(attr_span);
459 return features;
460 }
461 for item in list.mixed() {
462 let Some((ident, value)) = cx.expect_name_value(item, item.span(), Some(sym::enable))
463 else {
464 return features;
465 };
466
467 if ident.name != sym::enable {
469 cx.adcx().expected_specific_argument(ident.span, &[sym::enable]);
470 return features;
471 }
472
473 let Some(value_str) = value.value_as_str() else {
475 cx.adcx().expected_string_literal(value.value_span, Some(value.value_as_lit()));
476 return features;
477 };
478 for feature in value_str.as_str().split(",") {
479 features.push((Symbol::intern(feature), item.span()));
480 }
481 }
482 features
483}
484
485pub(crate) struct TargetFeatureParser;
486
487impl CombineAttributeParser for TargetFeatureParser {
488 type Item = (Symbol, Span);
489 const PATH: &[Symbol] = &[sym::target_feature];
490 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
491 features: items,
492 attr_span: span,
493 was_forced: false,
494 };
495 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\""]);
496
497 fn extend(
498 cx: &mut AcceptContext<'_, '_>,
499 args: &ArgParser,
500 ) -> impl IntoIterator<Item = Self::Item> {
501 parse_tf_attribute(cx, args)
502 }
503
504 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
505 Allow(Target::Fn),
506 Allow(Target::Method(MethodKind::Inherent)),
507 Allow(Target::Method(MethodKind::Trait { body: true })),
508 Allow(Target::Method(MethodKind::TraitImpl)),
509 Warn(Target::Statement),
510 Warn(Target::Field),
511 Warn(Target::Arm),
512 Warn(Target::MacroDef),
513 Warn(Target::MacroCall),
514 ]);
515}
516
517pub(crate) struct ForceTargetFeatureParser;
518
519impl CombineAttributeParser for ForceTargetFeatureParser {
520 type Item = (Symbol, Span);
521 const PATH: &[Symbol] = &[sym::force_target_feature];
522 const SAFETY: AttributeSafety = AttributeSafety::Unsafe { unsafe_since: None };
523 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
524 features: items,
525 attr_span: span,
526 was_forced: true,
527 };
528 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\""]);
529 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
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
536 fn extend(
537 cx: &mut AcceptContext<'_, '_>,
538 args: &ArgParser,
539 ) -> impl IntoIterator<Item = Self::Item> {
540 parse_tf_attribute(cx, args)
541 }
542}
543
544pub(crate) struct SanitizeParser;
545
546impl SingleAttributeParser for SanitizeParser {
547 const PATH: &[Symbol] = &[sym::sanitize];
548
549 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS);
551
552 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: &[
553 r#"address = "on|off""#,
554 r#"kernel_address = "on|off""#,
555 r#"cfi = "on|off""#,
556 r#"hwaddress = "on|off""#,
557 r#"kernel_hwaddress = "on|off""#,
558 r#"kcfi = "on|off""#,
559 r#"memory = "on|off""#,
560 r#"memtag = "on|off""#,
561 r#"shadow_call_stack = "on|off""#,
562 r#"thread = "on|off""#,
563 r#"realtime = "nonblocking|blocking|caller""#,
564 ]);
565
566 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
567 let list = cx.expect_list(args, cx.attr_span)?;
568
569 let mut on_set = SanitizerSet::empty();
570 let mut off_set = SanitizerSet::empty();
571 let mut rtsan = None;
572
573 for item in list.mixed() {
574 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
575 continue;
576 };
577
578 let mut apply = |s: SanitizerSet| {
579 let is_on = match value.value_as_str() {
580 Some(sym::on) => true,
581 Some(sym::off) => false,
582 Some(_) => {
583 cx.adcx().expected_specific_argument_strings(
584 value.value_span,
585 &[sym::on, sym::off],
586 );
587 return;
588 }
589 None => {
590 cx.adcx()
591 .expected_string_literal(value.value_span, Some(value.value_as_lit()));
592 return;
593 }
594 };
595
596 if is_on {
597 on_set |= s;
598 } else {
599 off_set |= s;
600 }
601 };
602
603 match ident.name {
604 sym::address | sym::kernel_address => {
605 apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
606 }
607 sym::cfi => apply(SanitizerSet::CFI),
608 sym::kcfi => apply(SanitizerSet::KCFI),
609 sym::memory => apply(SanitizerSet::MEMORY),
610 sym::memtag => apply(SanitizerSet::MEMTAG),
611 sym::shadow_call_stack => apply(SanitizerSet::SHADOWCALLSTACK),
612 sym::thread => apply(SanitizerSet::THREAD),
613 sym::hwaddress | sym::kernel_hwaddress => {
614 apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
615 }
616 sym::realtime => match value.value_as_str() {
617 Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
618 Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
619 Some(sym::caller) => rtsan = Some(RtsanSetting::Caller),
620 _ => {
621 cx.adcx().expected_specific_argument_strings(
622 value.value_span,
623 &[sym::nonblocking, sym::blocking, sym::caller],
624 );
625 }
626 },
627 _ => {
628 cx.adcx().expected_specific_argument_strings(
629 ident.span,
630 &[
631 sym::address,
632 sym::kernel_address,
633 sym::cfi,
634 sym::kcfi,
635 sym::memory,
636 sym::memtag,
637 sym::shadow_call_stack,
638 sym::thread,
639 sym::hwaddress,
640 sym::kernel_hwaddress,
641 sym::realtime,
642 ],
643 );
644 continue;
645 }
646 }
647 }
648
649 Some(AttributeKind::Sanitize { on_set, off_set, rtsan, span: cx.attr_span })
650 }
651}
652
653pub(crate) struct ThreadLocalParser;
654
655impl NoArgsAttributeParser for ThreadLocalParser {
656 const PATH: &[Symbol] = &[sym::thread_local];
657 const ALLOWED_TARGETS: AllowedTargets =
658 AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
659 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
660}
661
662pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
663
664impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser {
665 const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
666 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
667 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
668}
669
670pub(crate) struct RustcEiiForeignItemParser;
671
672impl NoArgsAttributeParser for RustcEiiForeignItemParser {
673 const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
674 const ALLOWED_TARGETS: AllowedTargets =
675 AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
676 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
677}
678
679pub(crate) struct PatchableFunctionEntryParser;
680
681impl SingleAttributeParser for PatchableFunctionEntryParser {
682 const PATH: &[Symbol] = &[sym::patchable_function_entry];
683 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
684 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"]);
685
686 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
687 let meta_item_list = cx.expect_list(args, cx.attr_span)?;
688
689 let mut prefix = None;
690 let mut entry = None;
691
692 if meta_item_list.len() == 0 {
693 cx.adcx().expected_at_least_one_argument(meta_item_list.span);
694 return None;
695 }
696
697 let mut errored = false;
698
699 for item in meta_item_list.mixed() {
700 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
701 continue;
702 };
703
704 let attrib_to_write = match ident.name {
705 sym::prefix_nops => {
706 if prefix.is_some() {
708 errored = true;
709 cx.adcx().duplicate_key(ident.span, sym::prefix_nops);
710 continue;
711 }
712 &mut prefix
713 }
714 sym::entry_nops => {
715 if entry.is_some() {
717 errored = true;
718 cx.adcx().duplicate_key(ident.span, sym::entry_nops);
719 continue;
720 }
721 &mut entry
722 }
723 _ => {
724 errored = true;
725 cx.adcx().expected_specific_argument(
726 ident.span,
727 &[sym::prefix_nops, sym::entry_nops],
728 );
729 continue;
730 }
731 };
732
733 let rustc_ast::LitKind::Int(val, _) = value.value_as_lit().kind else {
734 errored = true;
735 cx.adcx().expected_integer_literal(value.value_span);
736 continue;
737 };
738
739 let Ok(val) = val.get().try_into() else {
740 errored = true;
741 cx.adcx().expected_integer_literal_in_range(
742 value.value_span,
743 u8::MIN as isize,
744 u8::MAX as isize,
745 );
746 continue;
747 };
748
749 *attrib_to_write = Some(val);
750 }
751
752 if errored {
753 None
754 } else {
755 Some(AttributeKind::PatchableFunctionEntry {
756 prefix: prefix.unwrap_or(0),
757 entry: entry.unwrap_or(0),
758 })
759 }
760 }
761}