1use rustc_attr_ir::{
2 CoverageAttrKind, InstrumentFnAttr, OptimizeAttr, RtsanSetting, UsedBy, find_attr,
3};
4use rustc_feature::AttributeStability;
5use rustc_session::diagnostics::feature_err;
6use rustc_span::edition::Edition::Edition2024;
7use rustc_structures::SanitizerSet;
8
9use super::prelude::*;
10use crate::attributes::AttributeSafety;
11use crate::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 = {
_ = rustc_feature::Features::optimize_attribute;
AttributeStability::Unstable {
gate_name: rustc_span::sym::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 = {
_ = rustc_feature::Features::coverage_attribute;
AttributeStability::Unstable {
gate_name: rustc_span::sym::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 = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::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 = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::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_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)
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 Target::Closure if !cx.features().closure_track_caller() => {
368 feature_err(
369 cx.sess(),
370 sym::closure_track_caller,
371 attr_span,
372 "`#[track_caller]` on closures is currently unstable",
373 )
374 .emit();
375 }
376 _ => {}
377 }
378 }
379}
380
381pub(crate) struct NoMangleParser;
382impl NoArgsAttributeParser for NoMangleParser {
383 const PATH: &[Symbol] = &[sym::no_mangle];
384 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Warn;
385 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
386 note: "the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them",
387 unsafe_since: Some(Edition2024),
388 };
389 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowListWarnRest(&[
390 Allow(Target::Fn),
391 Allow(Target::Static),
392 Allow(Target::Method(MethodKind::Inherent)),
393 Allow(Target::Method(MethodKind::TraitImpl)),
394 AllowSilent(Target::Const), Error(Target::Closure),
396 ]);
397 const STABILITY: AttributeStability = AttributeStability::Stable;
398 const CREATE: fn(Span) -> AttributeKind = AttributeKind::NoMangle;
399}
400
401#[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)]
402pub(crate) struct UsedParser {
403 first_compiler: Option<Span>,
404 first_linker: Option<Span>,
405 first_default: Option<Span>,
406}
407
408impl AttributeParser for UsedParser {
413 const ATTRIBUTES: AcceptMapping<Self> = &[(
414 &[sym::used],
415 crate::AttributeTemplate {
word: true,
list: Some(&["compiler", "linker"]),
one_of: &[],
name_value_str: None,
docs: None,
}template!(Word, List: &["compiler", "linker"]),
416 AttributeStability::Stable,
417 |group: &mut Self, cx, args| {
418 let used_by = match args {
419 ArgParser::NoArgs => UsedBy::Default,
420 ArgParser::List(list) => {
421 let Some(l) = cx.expect_single(list) else {
422 return;
423 };
424
425 match l.meta_item_no_args().and_then(|i| i.path().word_sym()) {
426 Some(sym::compiler) => {
427 if !cx.features().used_with_arg() {
428 feature_err(
429 cx.sess(),
430 sym::used_with_arg,
431 cx.attr_span,
432 "`#[used(compiler)]` is currently unstable",
433 )
434 .emit();
435 }
436 UsedBy::Compiler
437 }
438 Some(sym::linker) => {
439 if !cx.features().used_with_arg() {
440 feature_err(
441 cx.sess(),
442 sym::used_with_arg,
443 cx.attr_span,
444 "`#[used(linker)]` is currently unstable",
445 )
446 .emit();
447 }
448 UsedBy::Linker
449 }
450 _ => {
451 cx.adcx().expected_specific_argument(
452 l.span(),
453 &[sym::compiler, sym::linker],
454 );
455 return;
456 }
457 }
458 }
459 ArgParser::NameValue(_) => return,
460 };
461
462 let attr_span = cx.attr_span;
463
464 let target = match used_by {
468 UsedBy::Compiler => &mut group.first_compiler,
469 UsedBy::Linker => {
470 if let Some(prev) = group.first_default {
471 cx.warn_unused_duplicate(prev, attr_span);
472 return;
473 }
474 &mut group.first_linker
475 }
476 UsedBy::Default => {
477 if let Some(prev) = group.first_linker {
478 cx.warn_unused_duplicate(prev, attr_span);
479 return;
480 }
481 &mut group.first_default
482 }
483 };
484
485 if let Some(prev) = *target {
486 cx.warn_unused_duplicate(prev, attr_span);
487 } else {
488 *target = Some(attr_span);
489 }
490 },
491 )];
492 const ALLOWED_TARGETS: AllowedTargets<'_> =
493 AllowedTargets::AllowList(&[Allow(Target::Static), Warn(Target::MacroCall)]);
494
495 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {
496 Some(match (self.first_compiler, self.first_linker, self.first_default) {
499 (_, Some(_), _) => AttributeKind::Used { used_by: UsedBy::Linker },
500 (Some(_), _, _) => AttributeKind::Used { used_by: UsedBy::Compiler },
501 (_, _, Some(_)) => AttributeKind::Used { used_by: UsedBy::Default },
502 (None, None, None) => return None,
503 })
504 }
505}
506
507fn parse_tf_attribute(
508 cx: &mut AcceptContext<'_, '_>,
509 args: &ArgParser,
510) -> impl IntoIterator<Item = (Symbol, Span)> {
511 let mut features = Vec::new();
512 let Some(list) = cx.expect_list(args, cx.attr_span) else {
513 return features;
514 };
515 if list.is_empty() {
516 let attr_span = cx.attr_span;
517 cx.adcx().warn_empty_attribute(attr_span);
518 return features;
519 }
520 for item in list.mixed() {
521 let Some((ident, value)) = cx.expect_name_value(item, item.span(), Some(sym::enable))
522 else {
523 return features;
524 };
525
526 if ident.name != sym::enable {
528 cx.adcx().expected_specific_argument(ident.span, &[sym::enable]);
529 return features;
530 }
531
532 let Some(value_str) = cx.expect_string_literal(value) else {
534 return features;
535 };
536 for feature in value_str.as_str().split(',') {
537 features.push((Symbol::intern(feature), item.span()));
538 }
539 }
540 features
541}
542
543pub(crate) struct TargetFeatureParser;
544
545impl CombineAttributeParser for TargetFeatureParser {
546 type Item = (Symbol, Span);
547 const PATH: &[Symbol] = &[sym::target_feature];
548 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
549 features: items,
550 attr_span: span,
551 was_forced: false,
552 };
553 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\""]);
554 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
555 Allow(Target::Fn),
556 Allow(Target::Method(MethodKind::Inherent)),
557 Allow(Target::Method(MethodKind::Trait { body: true })),
558 Allow(Target::Method(MethodKind::TraitImpl)),
559 Warn(Target::Statement),
560 Warn(Target::Field),
561 Warn(Target::Arm),
562 Warn(Target::MacroDef),
563 Warn(Target::MacroCall),
564 ]);
565 const STABILITY: AttributeStability = AttributeStability::Stable;
566
567 fn extend(
568 cx: &mut AcceptContext<'_, '_>,
569 args: &ArgParser,
570 ) -> impl IntoIterator<Item = Self::Item> {
571 parse_tf_attribute(cx, args)
572 }
573
574 fn finalize_check(cx: &FinalizeCheckContext<'_, '_>, attr_span: Span) {
575 if !cx.sess().target.is_like_wasm && !cx.sess().opts.actually_rustdoc {
578 let lang_kind = cx
580 .all_attrs
581 .iter()
582 .find_map(|a| [sym::panic_handler, sym::lang].into_iter().find(|&s| a.word_is(s)));
583 if let Some(kind) = lang_kind {
584 cx.emit_err(TargetFeatureOnLangItem { attr_span, kind, item_span: cx.target_span });
585 }
586 }
587 }
588}
589
590pub(crate) struct ForceTargetFeatureParser;
591
592impl CombineAttributeParser for ForceTargetFeatureParser {
593 type Item = (Symbol, Span);
594 const PATH: &[Symbol] = &[sym::force_target_feature];
595 const SAFETY: AttributeSafety = AttributeSafety::Unsafe {
596 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",
597 unsafe_since: None,
598 };
599 const CONVERT: ConvertFn<Self::Item> = |items, span| AttributeKind::TargetFeature {
600 features: items,
601 attr_span: span,
602 was_forced: true,
603 };
604 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\""]);
605 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
606 Allow(Target::Fn),
607 Allow(Target::Method(MethodKind::Inherent)),
608 Allow(Target::Method(MethodKind::Trait { body: true })),
609 Allow(Target::Method(MethodKind::TraitImpl)),
610 ]);
611 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::effective_target_features;
AttributeStability::Unstable {
gate_name: rustc_span::sym::effective_target_features,
notes: &[],
}
}unstable!(effective_target_features);
612
613 fn extend(
614 cx: &mut AcceptContext<'_, '_>,
615 args: &ArgParser,
616 ) -> impl IntoIterator<Item = Self::Item> {
617 parse_tf_attribute(cx, args)
618 }
619}
620
621pub(crate) struct InstrumentFnParser;
622
623impl SingleAttributeParser for InstrumentFnParser {
624 const PATH: &[Symbol] = &[sym::instrument_fn];
625 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
626 Allow(Target::Fn),
627 Allow(Target::Method(MethodKind::Inherent)),
628 Allow(Target::Method(MethodKind::Trait { body: true })),
629 Allow(Target::Method(MethodKind::TraitImpl)),
630 ]);
631 const TEMPLATE: AttributeTemplate = crate::AttributeTemplate {
word: false,
list: None,
one_of: &[],
name_value_str: Some(&["on|off"]),
docs: None,
}template!(NameValueStr: "on|off");
632 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::instrument_fn;
AttributeStability::Unstable {
gate_name: rustc_span::sym::instrument_fn,
notes: &[],
}
}unstable!(instrument_fn);
633
634 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
635 match args {
636 ArgParser::NameValue(nv) => match nv.value_as_str() {
637 Some(sym::on) => Some(AttributeKind::InstrumentFn(InstrumentFnAttr::On)),
638 Some(sym::off) => Some(AttributeKind::InstrumentFn(InstrumentFnAttr::Off)),
639 _ => {
640 cx.adcx()
641 .expected_specific_argument_strings(nv.value_span, &[sym::on, sym::off]);
642 None
643 }
644 },
645 ArgParser::List(l) => {
646 cx.adcx().expected_single_argument(l.span, l.len());
647 None
648 }
649 ArgParser::NoArgs => {
650 let span = cx.attr_span;
651 cx.adcx().expected_specific_argument_strings(span, &[sym::on, sym::off]);
652 None
653 }
654 }
655 }
656}
657
658pub(crate) struct SanitizeParser;
659
660impl SingleAttributeParser for SanitizeParser {
661 const PATH: &[Symbol] = &[sym::sanitize];
662 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[
663 Allow(Target::Fn),
664 Allow(Target::Closure),
665 Allow(Target::Method(MethodKind::Inherent)),
666 Allow(Target::Method(MethodKind::Trait { body: true })),
667 Allow(Target::Method(MethodKind::TraitImpl)),
668 Allow(Target::Impl { of_trait: false }),
669 Allow(Target::Impl { of_trait: true }),
670 Allow(Target::Mod),
671 Allow(Target::Crate),
672 Allow(Target::Static),
673 ]);
674 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#"safestack = "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: &[
675 r#"address = "on|off""#,
676 r#"kernel_address = "on|off""#,
677 r#"cfi = "on|off""#,
678 r#"hwaddress = "on|off""#,
679 r#"kernel_hwaddress = "on|off""#,
680 r#"kcfi = "on|off""#,
681 r#"memory = "on|off""#,
682 r#"memtag = "on|off""#,
683 r#"safestack = "on|off""#,
684 r#"shadow_call_stack = "on|off""#,
685 r#"thread = "on|off""#,
686 r#"realtime = "nonblocking|blocking|caller""#,
687 ]);
688 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::sanitize;
AttributeStability::Unstable {
gate_name: rustc_span::sym::sanitize,
notes: &[],
}
}unstable!(sanitize);
689
690 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
691 let list = cx.expect_list(args, cx.attr_span)?;
692
693 let mut on_set = SanitizerSet::empty();
694 let mut off_set = SanitizerSet::empty();
695 let mut rtsan = None;
696
697 for item in list.mixed() {
698 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {
699 continue;
700 };
701
702 let mut apply = |s: SanitizerSet| {
703 let is_on = match value.value_as_str() {
704 Some(sym::on) => true,
705 Some(sym::off) => false,
706 _ => {
707 cx.adcx().expected_specific_argument_strings(
708 value.value_span,
709 &[sym::on, sym::off],
710 );
711 return;
712 }
713 };
714
715 if is_on {
716 on_set |= s;
717 } else {
718 off_set |= s;
719 }
720 };
721
722 match ident.name {
723 sym::address | sym::kernel_address => {
724 apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS)
725 }
726 sym::cfi => apply(SanitizerSet::CFI),
727 sym::kcfi => apply(SanitizerSet::KCFI),
728 sym::memory => apply(SanitizerSet::MEMORY),
729 sym::memtag => apply(SanitizerSet::MEMTAG),
730 sym::safestack => apply(SanitizerSet::SAFESTACK),
731 sym::shadow_call_stack => apply(SanitizerSet::SHADOWCALLSTACK),
732 sym::thread => apply(SanitizerSet::THREAD),
733 sym::hwaddress | sym::kernel_hwaddress => {
734 apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS)
735 }
736 sym::realtime => match value.value_as_str() {
737 Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking),
738 Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking),
739 Some(sym::caller) => rtsan = Some(RtsanSetting::Caller),
740 _ => {
741 cx.adcx().expected_specific_argument_strings(
742 value.value_span,
743 &[sym::nonblocking, sym::blocking, sym::caller],
744 );
745 }
746 },
747 _ => {
748 cx.adcx().expected_specific_argument_strings(
749 ident.span,
750 &[
751 sym::address,
752 sym::kernel_address,
753 sym::cfi,
754 sym::kcfi,
755 sym::memory,
756 sym::memtag,
757 sym::safestack,
758 sym::shadow_call_stack,
759 sym::thread,
760 sym::hwaddress,
761 sym::kernel_hwaddress,
762 sym::realtime,
763 ],
764 );
765 }
766 }
767 }
768
769 let all_set_except_address =
771 (on_set | off_set) & !(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS);
772 if cx.target == Target::Static
773 && let Some(set) = all_set_except_address.iter().next()
774 {
775 cx.emit_err(SanitizeInvalidStatic {
776 span: cx.attr_span,
777 field: set.as_str().expect("Since this `SanitizerSet` is returned from an iterator, exactly one field is set")
778 });
779 }
780
781 Some(AttributeKind::Sanitize { on_set, off_set, rtsan, span: cx.attr_span })
782 }
783}
784
785pub(crate) struct ThreadLocalParser;
786
787impl NoArgsAttributeParser for ThreadLocalParser {
788 const PATH: &[Symbol] = &[sym::thread_local];
789 const ALLOWED_TARGETS: AllowedTargets<'_> =
790 AllowedTargets::AllowList(&[Allow(Target::Static), Allow(Target::ForeignStatic)]);
791 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::thread_local;
AttributeStability::Unstable {
gate_name: rustc_span::sym::thread_local,
notes: &[],
}
}unstable!(thread_local);
792 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::ThreadLocal;
793}
794
795pub(crate) struct RustcPassIndirectlyInNonRusticAbisParser;
796
797impl NoArgsAttributeParser for RustcPassIndirectlyInNonRusticAbisParser {
798 const PATH: &[Symbol] = &[sym::rustc_pass_indirectly_in_non_rustic_abis];
799 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Struct)]);
800 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::rustc_attrs;
AttributeStability::Unstable {
gate_name: rustc_span::sym::rustc_attrs,
notes: &[],
}
}unstable!(rustc_attrs);
801 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcPassIndirectlyInNonRusticAbis;
802}
803
804pub(crate) struct RustcEiiForeignItemParser;
805
806impl NoArgsAttributeParser for RustcEiiForeignItemParser {
807 const PATH: &[Symbol] = &[sym::rustc_eii_foreign_item];
808 const ALLOWED_TARGETS: AllowedTargets<'_> =
809 AllowedTargets::AllowList(&[Allow(Target::ForeignFn), Allow(Target::ForeignStatic)]);
810 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::eii_internals;
AttributeStability::Unstable {
gate_name: rustc_span::sym::eii_internals,
notes: &[],
}
}unstable!(eii_internals);
811 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEiiForeignItem;
812}
813
814pub(crate) struct PatchableFunctionEntryParser;
815
816impl SingleAttributeParser for PatchableFunctionEntryParser {
817 const PATH: &[Symbol] = &[sym::patchable_function_entry];
818 const ALLOWED_TARGETS: AllowedTargets<'_> = AllowedTargets::AllowList(&[Allow(Target::Fn)]);
819 const TEMPLATE: AttributeTemplate =
820 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\""]);
821 const STABILITY: AttributeStability = {
_ = rustc_feature::Features::patchable_function_entry;
AttributeStability::Unstable {
gate_name: rustc_span::sym::patchable_function_entry,
notes: &[],
}
}unstable!(patchable_function_entry);
822
823 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {
824 let meta_item_list = cx.expect_list(args, cx.attr_span)?;
825
826 let mut prefix = None;
827 let mut entry = None;
828 let mut section = None;
829
830 if meta_item_list.len() == 0 {
831 cx.adcx().expected_at_least_one_argument(meta_item_list.span);
832 return None;
833 }
834
835 for item in meta_item_list.mixed() {
836 let (ident, value) = cx.expect_name_value(item, item.span(), None)?;
837
838 let attrib_to_write = match ident.name {
839 sym::prefix_nops => {
840 if prefix.is_some() {
842 cx.adcx().duplicate_key(ident.span, sym::prefix_nops);
843 return None;
844 }
845 &mut prefix
846 }
847 sym::entry_nops => {
848 if entry.is_some() {
850 cx.adcx().duplicate_key(ident.span, sym::entry_nops);
851 return None;
852 }
853 &mut entry
854 }
855 sym::section => {
856 if section.is_some() {
858 cx.adcx().duplicate_key(ident.span, sym::section);
859 return None;
860 }
861 let Some(value_str) = value.value_as_str() else {
863 cx.adcx().expect_string_literal(value);
864 return None;
865 };
866 if value_str.as_str().contains('\0') {
868 cx.emit_err(NullOnSection { span: value.value_span });
869 }
870 if value_str.is_empty() {
873 cx.emit_err(EmptySection { span: value.value_span });
874 }
875 section = Some(value_str);
876 continue;
878 }
879 _ => {
880 cx.adcx().expected_specific_argument(
881 ident.span,
882 &[sym::prefix_nops, sym::entry_nops],
883 );
884 return None;
885 }
886 };
887
888 let rustc_ast::LitKind::Int(val, _) = value.value_as_lit().kind else {
889 cx.adcx().expected_integer_literal(value.value_span);
890 return None;
891 };
892
893 let Ok(val) = val.get().try_into() else {
894 cx.adcx().expected_integer_literal_in_range(
895 value.value_span,
896 u8::MIN as isize,
897 u8::MAX as isize,
898 );
899 return None;
900 };
901
902 *attrib_to_write = Some(val);
903 }
904
905 Some(AttributeKind::PatchableFunctionEntry { prefix, entry, section })
906 }
907}