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