1use rustc_feature::AttributeStability;
2use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy};
3use rustc_session::errors::feature_err;
4use rustc_span::edition::Edition::Edition2024;
5
6use super::prelude::*;
7use crate::attributes::AttributeSafety;
8use crate::session_diagnostics::{
9 EmptyExportName, NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass,
10 NullOnObjcSelector, ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral,
11 SanitizeInvalidStatic,
12};
13use crate::target_checking::Policy::AllowSilent;
14
15pub(crate) struct OptimizeParser;
16
17impl SingleAttributeParser for OptimizeParser {
18 const PATH: &[Symbol] = &[sym::optimize];
19 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
20 Allow(Target::Fn),
21 Allow(Target::Closure),
22 Allow(Target::Method(MethodKind::Trait { body: true })),
23 Allow(Target::Method(MethodKind::TraitImpl)),
24 Allow(Target::Method(MethodKind::Inherent)),
25 ]);
26 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: Some(&["size", "speed", "none"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["size", "speed", "none"]);
27 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::optimize_attribute,
gate_check: rustc_feature::Features::optimize_attribute,
notes: &[],
}unstable!(optimize_attribute);
28
29 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
30 let single = cx.expect_single_element_list(args, cx.attr_span)?;
31
32 let res = match single.meta_item_no_args().and_then(|i| i.path().word().map(|i| i.name)) {
33 Some(sym::size) => OptimizeAttr::Size,
34 Some(sym::speed) => OptimizeAttr::Speed,
35 Some(sym::none) => OptimizeAttr::DoNotOptimize,
36 _ => {
37 cx.adcx()
38 .expected_specific_argument(single.span(), &[sym::size, sym::speed, sym::none]);
39 OptimizeAttr::Default
40 }
41 };
42
43 Some(AttributeKind::Optimize(res, cx.attr_span))
44 }
45}
46
47pub(crate) struct ColdParser;
48
49impl NoArgsAttributeParser for ColdParser {
50 const PATH: &[Symbol] = &[sym::cold];
51 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
52 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
53 Allow(Target::Fn),
54 Allow(Target::Method(MethodKind::Trait { body: true })),
55 Allow(Target::Method(MethodKind::TraitImpl)),
56 Allow(Target::Method(MethodKind::Inherent)),
57 Allow(Target::ForeignFn),
58 Allow(Target::Closure),
59 ]);
60 const STABILITY: AttributeStability = AttributeStability::Stable;
61 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Cold;
62}
63
64pub(crate) struct CoverageParser;
65
66impl SingleAttributeParser for CoverageParser {
67 const PATH: &[Symbol] = &[sym::coverage];
68 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
69 Allow(Target::Fn),
70 Allow(Target::Closure),
71 Allow(Target::Method(MethodKind::Trait { body: true })),
72 Allow(Target::Method(MethodKind::TraitImpl)),
73 Allow(Target::Method(MethodKind::Inherent)),
74 Allow(Target::Impl { of_trait: true }),
75 Allow(Target::Impl { of_trait: false }),
76 Allow(Target::Mod),
77 Allow(Target::Crate),
78 ]);
79 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[sym::off, sym::on],
name_value_str: None,
docs: None,
}template!(OneOf: &[sym::off, sym::on]);
80 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::coverage_attribute,
gate_check: rustc_feature::Features::coverage_attribute,
notes: &[],
}unstable!(coverage_attribute);
81
82 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
83 let arg = cx.expect_single_element_list(args, cx.attr_span)?;
84
85 let mut fail_incorrect_argument =
86 |span| cx.adcx().expected_specific_argument(span, &[sym::on, sym::off]);
87
88 let Some(arg) = arg.meta_item_no_args() else {
89 fail_incorrect_argument(arg.span());
90 return None;
91 };
92
93 let kind = match arg.path().word_sym() {
94 Some(sym::off) => CoverageAttrKind::Off,
95 Some(sym::on) => CoverageAttrKind::On,
96 None | Some(_) => {
97 fail_incorrect_argument(arg.span());
98 return None;
99 }
100 };
101
102 Some(AttributeKind::Coverage(kind))
103 }
104}
105
106pub(crate) struct ExportNameParser;
107
108impl SingleAttributeParser for ExportNameParser {
109 const PATH: &[rustc_span::Symbol] = &[sym::export_name];
110 const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError;
111 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
112 note: "the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them",
113 unsafe_since: Some(Edition2024),
114 };
115 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
116 Allow(Target::Static),
117 Allow(Target::Fn),
118 Allow(Target::Method(MethodKind::Inherent)),
119 Allow(Target::Method(MethodKind::Trait { body: true })),
120 Allow(Target::Method(MethodKind::TraitImpl)),
121 Warn(Target::Field),
122 Warn(Target::Arm),
123 Warn(Target::MacroDef),
124 Warn(Target::MacroCall),
125 ]);
126 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["name"]),
docs: None,
}template!(NameValueStr: "name");
127 const STABILITY: AttributeStability = AttributeStability::Stable;
128
129 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
130 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
131 let name = cx.expect_string_literal(nv)?;
132 if name.as_str().contains('\0') {
133 cx.emit_err(NullOnExport { span: cx.attr_span });
136 return None;
137 }
138 if name.is_empty() {
139 cx.emit_err(EmptyExportName { span: cx.attr_span });
142 return None;
143 }
144 Some(AttributeKind::ExportName { name, span: cx.attr_span })
145 }
146}
147
148pub(crate) struct RustcObjcClassParser;
149
150impl SingleAttributeParser for RustcObjcClassParser {
151 const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class];
152 const ALLOWED_TARGETS: AllowedTargets =
153 AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
154 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["ClassName"]),
docs: None,
}template!(NameValueStr: "ClassName");
155 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
gate_check: rustc_feature::Features::rustc_attrs,
notes: &[],
}unstable!(rustc_attrs);
156
157 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
158 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
159 let Some(classname) = nv.value_as_str() else {
160 cx.emit_err(ObjcClassExpectedStringLiteral { span: nv.value_span });
164 return None;
165 };
166 if classname.as_str().contains('\0') {
167 cx.emit_err(NullOnObjcClass { span: nv.value_span });
170 return None;
171 }
172 Some(AttributeKind::RustcObjcClass { classname })
173 }
174}
175
176pub(crate) struct RustcObjcSelectorParser;
177
178impl SingleAttributeParser for RustcObjcSelectorParser {
179 const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector];
180 const ALLOWED_TARGETS: AllowedTargets =
181 AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]);
182 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["methodName"]),
docs: None,
}template!(NameValueStr: "methodName");
183 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
gate_check: rustc_feature::Features::rustc_attrs,
notes: &[],
}unstable!(rustc_attrs);
184
185 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
186 let nv = cx.expect_name_value(args, cx.attr_span, None)?;
187 let Some(methname) = nv.value_as_str() else {
188 cx.emit_err(ObjcSelectorExpectedStringLiteral { span: nv.value_span });
192 return None;
193 };
194 if methname.as_str().contains('\0') {
195 cx.emit_err(NullOnObjcSelector { span: nv.value_span });
198 return None;
199 }
200 Some(AttributeKind::RustcObjcSelector { methname })
201 }
202}
203
204#[derive(#[automatically_derived]
impl ::core::default::Default for NakedParser {
#[inline]
fn default() -> NakedParser {
NakedParser { span: ::core::default::Default::default() }
}
}Default)]
205pub(crate) struct NakedParser {
206 span: Option<Span>,
207}
208
209impl AttributeParser for NakedParser {
210 const ATTRIBUTES: AcceptMapping<Self> =
211 &[(&[sym::naked], crate::AttributeTemplate {
word: true,
list: None,
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word), AttributeStability::Stable, |this, cx, args| {
212 let Some(()) = cx.expect_no_args(args) else {
213 return;
214 };
215
216 if let Some(earlier) = this.span {
217 let span = cx.attr_span;
218 cx.warn_unused_duplicate(earlier, span);
219 } else {
220 this.span = Some(cx.attr_span);
221 }
222 })];
223 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
224 note: "the `#[naked]` attribute adds the safety obligation that the function's body must respect the function’s calling convention, uphold its signature, and either return or diverge (i.e., not fall through past the end of the assembly code).",
225 unsafe_since: None,
226 };
227 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
228 Allow(Target::Fn),
229 Allow(Target::Method(MethodKind::Inherent)),
230 Allow(Target::Method(MethodKind::Trait { body: true })),
231 Allow(Target::Method(MethodKind::TraitImpl)),
232 Warn(Target::MacroCall),
233 ]);
234
235 fn finalize(self, cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
236 const ALLOW_LIST: &[rustc_span::Symbol] = &[
249 sym::cfg_trace,
251 sym::cfg_attr_trace,
252 sym::test,
254 sym::ignore,
255 sym::should_panic,
256 sym::bench,
257 sym::allow,
259 sym::warn,
260 sym::deny,
261 sym::forbid,
262 sym::deprecated,
263 sym::must_use,
264 sym::cold,
266 sym::export_name,
267 sym::link_section,
268 sym::linkage,
269 sym::no_mangle,
270 sym::instruction_set,
271 sym::repr,
272 sym::rustc_std_internal_symbol,
273 sym::rustc_align,
275 sym::rustc_align_static,
276 sym::naked,
278 sym::doc,
280 ];
281
282 let span = self.span?;
283
284 let Some(tools) = cx.tools else {
285 {
::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");
286 };
287
288 'outer: for other_attr in cx.all_attrs {
290 for allowed_attr in ALLOW_LIST {
291 if other_attr
292 .segments()
293 .next()
294 .is_some_and(|i| tools.iter().any(|tool| tool.name == i.name))
295 {
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 NoArgsAttributeParser for TrackCallerParser {
333 const PATH: &[Symbol] = &[sym::track_caller];
334 const ON_DUPLICATE: OnDuplicate = 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 STABILITY: AttributeStability = AttributeStability::Stable;
349 const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
350}
351
352pub(crate) struct NoMangleParser;
353impl NoArgsAttributeParser for NoMangleParser {
354 const PATH: &[Symbol] = &[sym::no_mangle];
355 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
356 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
357 note: "the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them",
358 unsafe_since: Some(Edition2024),
359 };
360 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[
361 Allow(Target::Fn),
362 Allow(Target::Static),
363 Allow(Target::Method(MethodKind::Inherent)),
364 Allow(Target::Method(MethodKind::TraitImpl)),
365 AllowSilent(Target::Const), Error(Target::Closure),
367 ]);
368 const STABILITY: AttributeStability = AttributeStability::Stable;
369 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
370}
371
372#[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)]
373pub(crate) struct UsedParser {
374 first_compiler: Option<Span>,
375 first_linker: Option<Span>,
376 first_default: Option<Span>,
377}
378
379impl AttributeParser for UsedParser {
384 const ATTRIBUTES: AcceptMapping<Self> = &[(
385 &[sym::used],
386 crate::AttributeTemplate {
word: true,
list: Some(&["compiler", "linker"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["compiler", "linker"]),
387 AttributeStability::Stable,
388 |group: &mut Self, cx, args| {
389 let used_by = match args {
390 ArgParser::NoArgs => UsedBy::Default,
391 ArgParser::List(list) => {
392 let Some(l) = cx.expect_single(list) else {
393 return;
394 };
395
396 match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
397 Some(sym::compiler) => {
398 if !cx.features().used_with_arg() {
399 feature_err(
400 &cx.sess(),
401 sym::used_with_arg,
402 cx.attr_span,
403 "`#[used(compiler)]` is currently unstable",
404 )
405 .emit();
406 }
407 UsedBy::Compiler
408 }
409 Some(sym::linker) => {
410 if !cx.features().used_with_arg() {
411 feature_err(
412 &cx.sess(),
413 sym::used_with_arg,
414 cx.attr_span,
415 "`#[used(linker)]` is currently unstable",
416 )
417 .emit();
418 }
419 UsedBy::Linker
420 }
421 _ => {
422 cx.adcx().expected_specific_argument(
423 l.span(),
424 &[sym::compiler, sym::linker],
425 );
426 return;
427 }
428 }
429 }
430 ArgParser::NameValue(_) => return,
431 };
432
433 let attr_span = cx.attr_span;
434
435 let target = match used_by {
439 UsedBy::Compiler => &mut group.first_compiler,
440 UsedBy::Linker => {
441 if let Some(prev) = group.first_default {
442 cx.warn_unused_duplicate(prev, attr_span);
443 return;
444 }
445 &mut group.first_linker
446 }
447 UsedBy::Default => {
448 if let Some(prev) = group.first_linker {
449 cx.warn_unused_duplicate(prev, attr_span);
450 return;
451 }
452 &mut group.first_default
453 }
454 };
455
456 if let Some(prev) = *target {
457 cx.warn_unused_duplicate(prev, attr_span);
458 } else {
459 *target = Some(attr_span);
460 }
461 },
462 )];
463 const ALLOWED_TARGETS: AllowedTargets =
464 AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]);
465
466 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
467 Some(match (self.first_compiler, self.first_linker, self.first_default) {
470 (_, Some(_), _) => AttributeKind::Used { used_by: UsedBy::Linker },
471 (Some(_), _, _) => AttributeKind::Used { used_by: UsedBy::Compiler },
472 (_, _, Some(_)) => AttributeKind::Used { used_by: UsedBy::Default },
473 (None, None, None) => return None,
474 })
475 }
476}
477
478fn parse_tf_attribute(
479 cx: &mut AcceptContext<'_, '_>,
480 args: &ArgParser,
481) -> impl IntoIterator<Item = (Symbol, Span)> {
482 let mut features = Vec::new();
483 let Some(list) = cx.expect_list(args, cx.attr_span) else {
484 return features;
485 };
486 if list.is_empty() {
487 let attr_span = cx.attr_span;
488 cx.adcx().warn_empty_attribute(attr_span);
489 return features;
490 }
491 for item in list.mixed() {
492 let Some((ident, value)) = cx.expect_name_value(item, item.span(), Some(sym::enable))
493 else {
494 return features;
495 };
496
497 if ident.name != sym::enable {
499 cx.adcx().expected_specific_argument(ident.span, &[sym::enable]);
500 return features;
501 }
502
503 let Some(value_str) = cx.expect_string_literal(value) else {
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 CombineAttributeParser 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 = crate::AttributeTemplate {
word: false,
list: Some(&["enable = \"feat1, feat2\""]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["enable = \"feat1, feat2\""]);
525 const STABILITY: AttributeStability = AttributeStability::Stable;
526
527 fn extend(
528 cx: &mut AcceptContext<'_, '_>,
529 args: &ArgParser,
530 ) -> impl IntoIterator<Item = Self::Item> {
531 parse_tf_attribute(cx, args)
532 }
533
534 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
535 Allow(Target::Fn),
536 Allow(Target::Method(MethodKind::Inherent)),
537 Allow(Target::Method(MethodKind::Trait { body: true })),
538 Allow(Target::Method(MethodKind::TraitImpl)),
539 Warn(Target::Statement),
540 Warn(Target::Field),
541 Warn(Target::Arm),
542 Warn(Target::MacroDef),
543 Warn(Target::MacroCall),
544 ]);
545}
546
547pub(crate) struct ForceTargetFeatureParser;
548
549impl CombineAttributeParser for ForceTargetFeatureParser {
550 type Item = (Symbol, Span);
551 const PATH: &[Symbol] = &[sym::force_target_feature];
552 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
553 note: "a function with the signature of the function the attribute is applied to must only be callable if the force-enabled features are guaranteed to be present",
554 unsafe_since: None,
555 };
556 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
557 features: items,
558 attr_span: span,
559 was_forced: true,
560 };
561 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: Some(&["enable = \"feat1, feat2\""]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["enable = \"feat1, feat2\""]);
562 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
563 Allow(Target::Fn),
564 Allow(Target::Method(MethodKind::Inherent)),
565 Allow(Target::Method(MethodKind::Trait { body: true })),
566 Allow(Target::Method(MethodKind::TraitImpl)),
567 ]);
568 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::effective_target_features,
gate_check: rustc_feature::Features::effective_target_features,
notes: &[],
}unstable!(effective_target_features);
569
570 fn extend(
571 cx: &mut AcceptContext<'_, '_>,
572 args: &ArgParser,
573 ) -> impl IntoIterator<Item = Self::Item> {
574 parse_tf_attribute(cx, args)
575 }
576}
577
578pub(crate) struct SanitizeParser;
579
580impl SingleAttributeParser for SanitizeParser {
581 const PATH: &[Symbol] = &[sym::sanitize];
582 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[
583 Allow(Target::Fn),
584 Allow(Target::Closure),
585 Allow(Target::Method(MethodKind::Inherent)),
586 Allow(Target::Method(MethodKind::Trait { body: true })),
587 Allow(Target::Method(MethodKind::TraitImpl)),
588 Allow(Target::Impl { of_trait: false }),
589 Allow(Target::Impl { of_trait: true }),
590 Allow(Target::Mod),
591 Allow(Target::Crate),
592 Allow(Target::Static),
593 ]);
594 const TEMPLATE: AttributeTemplate = crate::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: &[
595 r#"address = "on|off""#,
596 r#"kernel_address = "on|off""#,
597 r#"cfi = "on|off""#,
598 r#"hwaddress = "on|off""#,
599 r#"kernel_hwaddress = "on|off""#,
600 r#"kcfi = "on|off""#,
601 r#"memory = "on|off""#,
602 r#"memtag = "on|off""#,
603 r#"shadow_call_stack = "on|off""#,
604 r#"thread = "on|off""#,
605 r#"realtime = "nonblocking|blocking|caller""#,
606 ]);
607 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::sanitize,
gate_check: rustc_feature::Features::sanitize,
notes: &[],
}unstable!(sanitize);
608
609 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
610 let list = cx.expect_list(args, cx.attr_span)?;
611
612 let mut on_set = SanitizerSet::empty();
613 let mut off_set = SanitizerSet::empty();
614 let mut rtsan = None;
615
616 for item in list.mixed() {
617 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
618 continue;
619 };
620
621 let mut apply = |s: SanitizerSet| {
622 let is_on = match value.value_as_str() {
623 Some(sym::on) => true,
624 Some(sym::off) => false,
625 Some(_) => {
626 cx.adcx().expected_specific_argument_strings(
627 value.value_span,
628 &[sym::on, sym::off],
629 );
630 return;
631 }
632 None => {
633 cx.adcx().expected_specific_argument_strings(
634 value.value_span,
635 &[sym::on, sym::off],
636 );
637 return;
638 }
639 };
640
641 if is_on {
642 on_set |= s;
643 } else {
644 off_set |= s;
645 }
646 };
647
648 match ident.name {
649 sym::address | sym::kernel_address => {
650 apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
651 }
652 sym::cfi => apply(SanitizerSet::CFI),
653 sym::kcfi => apply(SanitizerSet::KCFI),
654 sym::memory => apply(SanitizerSet::MEMORY),
655 sym::memtag => apply(SanitizerSet::MEMTAG),
656 sym::shadow_call_stack => apply(SanitizerSet::SHADOWCALLSTACK),
657 sym::thread => apply(SanitizerSet::THREAD),
658 sym::hwaddress | sym::kernel_hwaddress => {
659 apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
660 }
661 sym::realtime => match value.value_as_str() {
662 Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
663 Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
664 Some(sym::caller) => rtsan = Some(RtsanSetting::Caller),
665 _ => {
666 cx.adcx().expected_specific_argument_strings(
667 value.value_span,
668 &[sym::nonblocking, sym::blocking, sym::caller],
669 );
670 }
671 },
672 _ => {
673 cx.adcx().expected_specific_argument_strings(
674 ident.span,
675 &[
676 sym::address,
677 sym::kernel_address,
678 sym::cfi,
679 sym::kcfi,
680 sym::memory,
681 sym::memtag,
682 sym::shadow_call_stack,
683 sym::thread,
684 sym::hwaddress,
685 sym::kernel_hwaddress,
686 sym::realtime,
687 ],
688 );
689 continue;
690 }
691 }
692 }
693
694 let all_set_except_address =
696 (on_set | off_set) & !(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS);
697 if cx.target == Target::Static
698 && let Some(set) = all_set_except_address.iter().next()
699 {
700 cx.emit_err(SanitizeInvalidStatic {
701 span: cx.attr_span,
702 field: set.as_str().expect("Since this `SanitizerSet` is returned from an iterator, exactly one field is set")
703 });
704 }
705
706 Some(AttributeKind::Sanitize { on_set, off_set, rtsan, span: cx.attr_span })
707 }
708}
709
710pub(crate) struct ThreadLocalParser;
711
712impl NoArgsAttributeParser for ThreadLocalParser {
713 const PATH: &[Symbol] = &[sym::thread_local];
714 const ALLOWED_TARGETS: AllowedTargets =
715 AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
716 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::thread_local,
gate_check: rustc_feature::Features::thread_local,
notes: &[],
}unstable!(thread_local);
717 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
718}
719
720pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
721
722impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser {
723 const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
724 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
725 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
gate_check: rustc_feature::Features::rustc_attrs,
notes: &[],
}unstable!(rustc_attrs);
726 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
727}
728
729pub(crate) struct RustcEiiForeignItemParser;
730
731impl NoArgsAttributeParser for RustcEiiForeignItemParser {
732 const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
733 const ALLOWED_TARGETS: AllowedTargets =
734 AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
735 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::eii_internals,
gate_check: rustc_feature::Features::eii_internals,
notes: &[],
}unstable!(eii_internals);
736 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
737}
738
739pub(crate) struct PatchableFunctionEntryParser;
740
741impl SingleAttributeParser for PatchableFunctionEntryParser {
742 const PATH: &[Symbol] = &[sym::patchable_function_entry];
743 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
744 const TEMPLATE: AttributeTemplate = crate::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"]);
745 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::patchable_function_entry,
gate_check: rustc_feature::Features::patchable_function_entry,
notes: &[],
}unstable!(patchable_function_entry);
746
747 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
748 let meta_item_list = cx.expect_list(args, cx.attr_span)?;
749
750 let mut prefix = None;
751 let mut entry = None;
752
753 if meta_item_list.len() == 0 {
754 cx.adcx().expected_at_least_one_argument(meta_item_list.span);
755 return None;
756 }
757
758 let mut errored = false;
759
760 for item in meta_item_list.mixed() {
761 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
762 continue;
763 };
764
765 let attrib_to_write = match ident.name {
766 sym::prefix_nops => {
767 if prefix.is_some() {
769 errored = true;
770 cx.adcx().duplicate_key(ident.span, sym::prefix_nops);
771 continue;
772 }
773 &mut prefix
774 }
775 sym::entry_nops => {
776 if entry.is_some() {
778 errored = true;
779 cx.adcx().duplicate_key(ident.span, sym::entry_nops);
780 continue;
781 }
782 &mut entry
783 }
784 _ => {
785 errored = true;
786 cx.adcx().expected_specific_argument(
787 ident.span,
788 &[sym::prefix_nops, sym::entry_nops],
789 );
790 continue;
791 }
792 };
793
794 let rustc_ast::LitKind::Int(val, _) = value.value_as_lit().kind else {
795 errored = true;
796 cx.adcx().expected_integer_literal(value.value_span);
797 continue;
798 };
799
800 let Ok(val) = val.get().try_into() else {
801 errored = true;
802 cx.adcx().expected_integer_literal_in_range(
803 value.value_span,
804 u8::MIN as isize,
805 u8::MAX as isize,
806 );
807 continue;
808 };
809
810 *attrib_to_write = Some(val);
811 }
812
813 if errored {
814 None
815 } else {
816 Some(AttributeKind::PatchableFunctionEntry {
817 prefix: prefix.unwrap_or(0),
818 entry: entry.unwrap_or(0),
819 })
820 }
821 }
822}