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