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