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