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