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