1use rustc_feature::AttributeStability;
2use rustc_hir::attrs::{
3 CoverageAttrKind, InstrumentFnAttr, OptimizeAttr, RtsanSetting, SanitizerSet, UsedBy,
4};
5use rustc_session::diagnostics::feature_err;
6use rustc_span::edition::Edition::Edition2024;
7
8use super::prelude::*;
9use crate::attributes::AttributeSafety;
10use crate::session_diagnostics::{
11 EmptyExportName, EmptySection, NakedFunctionIncompatibleAttribute, NullOnExport,
12 NullOnObjcClass, NullOnObjcSelector, NullOnSection, ObjcClassExpectedStringLiteral,
13 ObjcSelectorExpectedStringLiteral, SanitizeInvalidStatic, TargetFeatureOnLangItem,
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::test,
253 sym::ignore,
254 sym::should_panic,
255 sym::bench,
256 sym::allow,
258 sym::warn,
259 sym::deny,
260 sym::forbid,
261 sym::deprecated,
262 sym::must_use,
263 sym::cold,
265 sym::export_name,
266 sym::link_section,
267 sym::linkage,
268 sym::no_mangle,
269 sym::instruction_set,
270 sym::repr,
271 sym::rustc_std_internal_symbol,
272 sym::rustc_align,
274 sym::rustc_align_static,
275 sym::naked,
277 sym::doc,
279 ];
280
281 let span = self.span?;
282
283 let Some(tools) = cx.tools else {
284 {
::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");
285 };
286
287 'outer: for other_attr in cx.all_attrs {
289 for allowed_attr in ALLOW_LIST {
290 if other_attr
291 .segments()
292 .next()
293 .is_some_and(|i| tools.iter().any(|tool| tool.name == i.name))
294 {
295 continue 'outer;
298 }
299 if other_attr.word_is(*allowed_attr) {
300 continue 'outer;
303 }
304
305 if other_attr.word_is(sym::target_feature) {
306 if !cx.features().naked_functions_target_feature() {
307 feature_err(
308 &cx.sess(),
309 sym::naked_functions_target_feature,
310 other_attr.span(),
311 "`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions",
312 ).emit();
313 }
314
315 continue 'outer;
316 }
317 }
318
319 cx.emit_err(NakedFunctionIncompatibleAttribute {
320 span: other_attr.span(),
321 naked_span: span,
322 attr: other_attr.get_attribute_path().to_string(),
323 });
324 }
325
326 Some(AttributeKind::Naked(span))
327 }
328}
329
330pub(crate) struct TrackCallerParser;
331impl NoArgsAttributeParser for TrackCallerParser {
332 const PATH: &[Symbol] = &[sym::track_caller];
333 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
334 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
335 Allow(Target::Fn),
336 Allow(Target::Method(MethodKind::Inherent)),
337 Allow(Target::Method(MethodKind::Trait { body: true })),
338 Allow(Target::Method(MethodKind::TraitImpl)),
339 Allow(Target::Method(MethodKind::Trait { body: false })), Allow(Target::ForeignFn),
341 Allow(Target::Closure),
342 Warn(Target::MacroDef),
343 Warn(Target::Arm),
344 Warn(Target::Field),
345 Warn(Target::MacroCall),
346 ]);
347 const STABILITY: AttributeStability = AttributeStability::Stable;
348 const CREATE: fn(Span) -> AttributeKind = AttributeKind::TrackCaller;
349}
350
351pub(crate) struct NoMangleParser;
352impl NoArgsAttributeParser for NoMangleParser {
353 const PATH: &[Symbol] = &[sym::no_mangle];
354 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
355 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
356 note: "the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them",
357 unsafe_since: Some(Edition2024),
358 };
359 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[
360 Allow(Target::Fn),
361 Allow(Target::Static),
362 Allow(Target::Method(MethodKind::Inherent)),
363 Allow(Target::Method(MethodKind::TraitImpl)),
364 AllowSilent(Target::Const), Error(Target::Closure),
366 ]);
367 const STABILITY: AttributeStability = AttributeStability::Stable;
368 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
369}
370
371#[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)]
372pub(crate) struct UsedParser {
373 first_compiler: Option<Span>,
374 first_linker: Option<Span>,
375 first_default: Option<Span>,
376}
377
378impl AttributeParser for UsedParser {
383 const ATTRIBUTES: AcceptMapping<Self> = &[(
384 &[sym::used],
385 crate::AttributeTemplate {
word: true,
list: Some(&["compiler", "linker"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["compiler", "linker"]),
386 AttributeStability::Stable,
387 |group: &mut Self, cx, args| {
388 let used_by = match args {
389 ArgParser::NoArgs => UsedBy::Default,
390 ArgParser::List(list) => {
391 let Some(l) = cx.expect_single(list) else {
392 return;
393 };
394
395 match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
396 Some(sym::compiler) => {
397 if !cx.features().used_with_arg() {
398 feature_err(
399 &cx.sess(),
400 sym::used_with_arg,
401 cx.attr_span,
402 "`#[used(compiler)]` is currently unstable",
403 )
404 .emit();
405 }
406 UsedBy::Compiler
407 }
408 Some(sym::linker) => {
409 if !cx.features().used_with_arg() {
410 feature_err(
411 &cx.sess(),
412 sym::used_with_arg,
413 cx.attr_span,
414 "`#[used(linker)]` is currently unstable",
415 )
416 .emit();
417 }
418 UsedBy::Linker
419 }
420 _ => {
421 cx.adcx().expected_specific_argument(
422 l.span(),
423 &[sym::compiler, sym::linker],
424 );
425 return;
426 }
427 }
428 }
429 ArgParser::NameValue(_) => return,
430 };
431
432 let attr_span = cx.attr_span;
433
434 let target = match used_by {
438 UsedBy::Compiler => &mut group.first_compiler,
439 UsedBy::Linker => {
440 if let Some(prev) = group.first_default {
441 cx.warn_unused_duplicate(prev, attr_span);
442 return;
443 }
444 &mut group.first_linker
445 }
446 UsedBy::Default => {
447 if let Some(prev) = group.first_linker {
448 cx.warn_unused_duplicate(prev, attr_span);
449 return;
450 }
451 &mut group.first_default
452 }
453 };
454
455 if let Some(prev) = *target {
456 cx.warn_unused_duplicate(prev, attr_span);
457 } else {
458 *target = Some(attr_span);
459 }
460 },
461 )];
462 const ALLOWED_TARGETS: AllowedTargets<'_> =
463 AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]);
464
465 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
466 Some(match (self.first_compiler, self.first_linker, self.first_default) {
469 (_, Some(_), _) => AttributeKind::Used { used_by: UsedBy::Linker },
470 (Some(_), _, _) => AttributeKind::Used { used_by: UsedBy::Compiler },
471 (_, _, Some(_)) => AttributeKind::Used { used_by: UsedBy::Default },
472 (None, None, None) => return None,
473 })
474 }
475}
476
477fn parse_tf_attribute(
478 cx: &mut AcceptContext<'_, '_>,
479 args: &ArgParser,
480) -> impl IntoIterator<Item = (Symbol, Span)> {
481 let mut features = Vec::new();
482 let Some(list) = cx.expect_list(args, cx.attr_span) else {
483 return features;
484 };
485 if list.is_empty() {
486 let attr_span = cx.attr_span;
487 cx.adcx().warn_empty_attribute(attr_span);
488 return features;
489 }
490 for item in list.mixed() {
491 let Some((ident, value)) = cx.expect_name_value(item, item.span(), Some(sym::enable))
492 else {
493 return features;
494 };
495
496 if ident.name != sym::enable {
498 cx.adcx().expected_specific_argument(ident.span, &[sym::enable]);
499 return features;
500 }
501
502 let Some(value_str) = cx.expect_string_literal(value) else {
504 return features;
505 };
506 for feature in value_str.as_str().split(",") {
507 features.push((Symbol::intern(feature), item.span()));
508 }
509 }
510 features
511}
512
513pub(crate) struct TargetFeatureParser;
514
515impl CombineAttributeParser for TargetFeatureParser {
516 type Item = (Symbol, Span);
517 const PATH: &[Symbol] = &[sym::target_feature];
518 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
519 features: items,
520 attr_span: span,
521 was_forced: false,
522 };
523 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\""]);
524 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
525 Allow(Target::Fn),
526 Allow(Target::Method(MethodKind::Inherent)),
527 Allow(Target::Method(MethodKind::Trait { body: true })),
528 Allow(Target::Method(MethodKind::TraitImpl)),
529 Warn(Target::Statement),
530 Warn(Target::Field),
531 Warn(Target::Arm),
532 Warn(Target::MacroDef),
533 Warn(Target::MacroCall),
534 ]);
535 const STABILITY: AttributeStability = AttributeStability::Stable;
536
537 fn extend(
538 cx: &mut AcceptContext<'_, '_>,
539 args: &ArgParser,
540 ) -> impl IntoIterator<Item = Self::Item> {
541 parse_tf_attribute(cx, args)
542 }
543
544 fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
545 if !cx.sess().target.is_like_wasm && !cx.sess().opts.actually_rustdoc {
548 let lang_kind = cx
550 .all_attrs
551 .iter()
552 .find_map(|a| [sym::panic_handler, sym::lang].into_iter().find(|&s| a.word_is(s)));
553 if let Some(kind) = lang_kind {
554 cx.emit_err(TargetFeatureOnLangItem { attr_span, kind, item_span: cx.target_span });
555 }
556 }
557 }
558}
559
560pub(crate) struct ForceTargetFeatureParser;
561
562impl CombineAttributeParser for ForceTargetFeatureParser {
563 type Item = (Symbol, Span);
564 const PATH: &[Symbol] = &[sym::force_target_feature];
565 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
566 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",
567 unsafe_since: None,
568 };
569 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
570 features: items,
571 attr_span: span,
572 was_forced: true,
573 };
574 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\""]);
575 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
576 Allow(Target::Fn),
577 Allow(Target::Method(MethodKind::Inherent)),
578 Allow(Target::Method(MethodKind::Trait { body: true })),
579 Allow(Target::Method(MethodKind::TraitImpl)),
580 ]);
581 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);
582
583 fn extend(
584 cx: &mut AcceptContext<'_, '_>,
585 args: &ArgParser,
586 ) -> impl IntoIterator<Item = Self::Item> {
587 parse_tf_attribute(cx, args)
588 }
589}
590
591pub(crate) struct InstrumentFnParser;
592
593impl SingleAttributeParser for InstrumentFnParser {
594 const PATH: &[Symbol] = &[sym::instrument_fn];
595 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
596 Allow(Target::Fn),
597 Allow(Target::Method(MethodKind::Inherent)),
598 Allow(Target::Method(MethodKind::Trait { body: true })),
599 Allow(Target::Method(MethodKind::TraitImpl)),
600 ]);
601 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["on|off"]),
docs: None,
}template!(NameValueStr: "on|off");
602 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::instrument_fn,
gate_check: rustc_feature::Features::instrument_fn,
notes: &[],
}unstable!(instrument_fn);
603
604 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
605 let instrument = match args {
606 ArgParser::NameValue(nv) => match nv.value_as_str() {
607 Some(sym::on) => Some(AttributeKind::InstrumentFn(InstrumentFnAttr::On)),
608 Some(sym::off) => Some(AttributeKind::InstrumentFn(InstrumentFnAttr::Off)),
609 _ => {
610 cx.adcx()
611 .expected_specific_argument_strings(nv.value_span, &[sym::on, sym::off]);
612 None
613 }
614 },
615 ArgParser::List(l) => {
616 cx.adcx().expected_single_argument(l.span, l.len());
617 None
618 }
619 ArgParser::NoArgs => {
620 let span = cx.attr_span;
621 cx.adcx().expected_specific_argument_strings(span, &[sym::on, sym::off]);
622 None
623 }
624 };
625 instrument
626 }
627}
628
629pub(crate) struct SanitizeParser;
630
631impl SingleAttributeParser for SanitizeParser {
632 const PATH: &[Symbol] = &[sym::sanitize];
633 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
634 Allow(Target::Fn),
635 Allow(Target::Closure),
636 Allow(Target::Method(MethodKind::Inherent)),
637 Allow(Target::Method(MethodKind::Trait { body: true })),
638 Allow(Target::Method(MethodKind::TraitImpl)),
639 Allow(Target::Impl { of_trait: false }),
640 Allow(Target::Impl { of_trait: true }),
641 Allow(Target::Mod),
642 Allow(Target::Crate),
643 Allow(Target::Static),
644 ]);
645 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: &[
646 r#"address = "on|off""#,
647 r#"kernel_address = "on|off""#,
648 r#"cfi = "on|off""#,
649 r#"hwaddress = "on|off""#,
650 r#"kernel_hwaddress = "on|off""#,
651 r#"kcfi = "on|off""#,
652 r#"memory = "on|off""#,
653 r#"memtag = "on|off""#,
654 r#"shadow_call_stack = "on|off""#,
655 r#"thread = "on|off""#,
656 r#"realtime = "nonblocking|blocking|caller""#,
657 ]);
658 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::sanitize,
gate_check: rustc_feature::Features::sanitize,
notes: &[],
}unstable!(sanitize);
659
660 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
661 let list = cx.expect_list(args, cx.attr_span)?;
662
663 let mut on_set = SanitizerSet::empty();
664 let mut off_set = SanitizerSet::empty();
665 let mut rtsan = None;
666
667 for item in list.mixed() {
668 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
669 continue;
670 };
671
672 let mut apply = |s: SanitizerSet| {
673 let is_on = match value.value_as_str() {
674 Some(sym::on) => true,
675 Some(sym::off) => false,
676 Some(_) => {
677 cx.adcx().expected_specific_argument_strings(
678 value.value_span,
679 &[sym::on, sym::off],
680 );
681 return;
682 }
683 None => {
684 cx.adcx().expected_specific_argument_strings(
685 value.value_span,
686 &[sym::on, sym::off],
687 );
688 return;
689 }
690 };
691
692 if is_on {
693 on_set |= s;
694 } else {
695 off_set |= s;
696 }
697 };
698
699 match ident.name {
700 sym::address | sym::kernel_address => {
701 apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
702 }
703 sym::cfi => apply(SanitizerSet::CFI),
704 sym::kcfi => apply(SanitizerSet::KCFI),
705 sym::memory => apply(SanitizerSet::MEMORY),
706 sym::memtag => apply(SanitizerSet::MEMTAG),
707 sym::shadow_call_stack => apply(SanitizerSet::SHADOWCALLSTACK),
708 sym::thread => apply(SanitizerSet::THREAD),
709 sym::hwaddress | sym::kernel_hwaddress => {
710 apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
711 }
712 sym::realtime => match value.value_as_str() {
713 Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
714 Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
715 Some(sym::caller) => rtsan = Some(RtsanSetting::Caller),
716 _ => {
717 cx.adcx().expected_specific_argument_strings(
718 value.value_span,
719 &[sym::nonblocking, sym::blocking, sym::caller],
720 );
721 }
722 },
723 _ => {
724 cx.adcx().expected_specific_argument_strings(
725 ident.span,
726 &[
727 sym::address,
728 sym::kernel_address,
729 sym::cfi,
730 sym::kcfi,
731 sym::memory,
732 sym::memtag,
733 sym::shadow_call_stack,
734 sym::thread,
735 sym::hwaddress,
736 sym::kernel_hwaddress,
737 sym::realtime,
738 ],
739 );
740 continue;
741 }
742 }
743 }
744
745 let all_set_except_address =
747 (on_set | off_set) & !(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS);
748 if cx.target == Target::Static
749 && let Some(set) = all_set_except_address.iter().next()
750 {
751 cx.emit_err(SanitizeInvalidStatic {
752 span: cx.attr_span,
753 field: set.as_str().expect("Since this `SanitizerSet` is returned from an iterator, exactly one field is set")
754 });
755 }
756
757 Some(AttributeKind::Sanitize { on_set, off_set, rtsan, span: cx.attr_span })
758 }
759}
760
761pub(crate) struct ThreadLocalParser;
762
763impl NoArgsAttributeParser for ThreadLocalParser {
764 const PATH: &[Symbol] = &[sym::thread_local];
765 const ALLOWED_TARGETS: AllowedTargets<'_> =
766 AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
767 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::thread_local,
gate_check: rustc_feature::Features::thread_local,
notes: &[],
}unstable!(thread_local);
768 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
769}
770
771pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
772
773impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser {
774 const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
775 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
776 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
gate_check: rustc_feature::Features::rustc_attrs,
notes: &[],
}unstable!(rustc_attrs);
777 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
778}
779
780pub(crate) struct RustcEiiForeignItemParser;
781
782impl NoArgsAttributeParser for RustcEiiForeignItemParser {
783 const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
784 const ALLOWED_TARGETS: AllowedTargets<'_> =
785 AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
786 const STABILITY: AttributeStability = AttributeStability::Unstable {
gate_name: rustc_span::sym::eii_internals,
gate_check: rustc_feature::Features::eii_internals,
notes: &[],
}unstable!(eii_internals);
787 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
788}
789
790pub(crate) struct PatchableFunctionEntryParser;
791
792impl SingleAttributeParser for PatchableFunctionEntryParser {
793 const PATH: &[Symbol] = &[sym::patchable_function_entry];
794 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
795 const TEMPLATE: AttributeTemplate =
796 crate::AttributeTemplate {
word: false,
list: Some(&["prefix_nops = m, entry_nops = n, section = \"section\""]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(List: &["prefix_nops = m, entry_nops = n, section = \"section\""]);
797 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);
798
799 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
800 let meta_item_list = cx.expect_list(args, cx.attr_span)?;
801
802 let mut prefix = None;
803 let mut entry = None;
804 let mut section = None;
805
806 if meta_item_list.len() == 0 {
807 cx.adcx().expected_at_least_one_argument(meta_item_list.span);
808 return None;
809 }
810
811 for item in meta_item_list.mixed() {
812 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
813 return None;
814 };
815
816 let attrib_to_write = match ident.name {
817 sym::prefix_nops => {
818 if prefix.is_some() {
820 cx.adcx().duplicate_key(ident.span, sym::prefix_nops);
821 return None;
822 }
823 &mut prefix
824 }
825 sym::entry_nops => {
826 if entry.is_some() {
828 cx.adcx().duplicate_key(ident.span, sym::entry_nops);
829 return None;
830 }
831 &mut entry
832 }
833 sym::section => {
834 if section.is_some() {
836 cx.adcx().duplicate_key(ident.span, sym::section);
837 return None;
838 }
839 let Some(value_str) = value.value_as_str() else {
841 cx.adcx().expect_string_literal(value);
842 return None;
843 };
844 if value_str.as_str().contains('\0') {
846 cx.emit_err(NullOnSection { span: value.value_span });
847 }
848 if value_str.is_empty() {
851 cx.emit_err(EmptySection { span: value.value_span });
852 }
853 section = Some(value_str);
854 continue;
856 }
857 _ => {
858 cx.adcx().expected_specific_argument(
859 ident.span,
860 &[sym::prefix_nops, sym::entry_nops],
861 );
862 return None;
863 }
864 };
865
866 let rustc_ast::LitKind::Int(val, _) = value.value_as_lit().kind else {
867 cx.adcx().expected_integer_literal(value.value_span);
868 return None;
869 };
870
871 let Ok(val) = val.get().try_into() else {
872 cx.adcx().expected_integer_literal_in_range(
873 value.value_span,
874 u8::MIN as isize,
875 u8::MAX as isize,
876 );
877 return None;
878 };
879
880 *attrib_to_write = Some(val);
881 }
882
883 Some(AttributeKind::PatchableFunctionEntry { prefix, entry, section })
884 }
885}