1use std::path::PathBuf;23use rustc_ast::{LitIntType, LitKind, MetaItemLit};4use rustc_hir::LangItem;5use rustc_hir::attrs::{6 BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,7 DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcMirKind,8};9use rustc_span::Symbol;1011use super::prelude::*;12use super::util::parse_single_integer;13use crate::errors;14use crate::session_diagnostics::{15 AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange, UnknownLangItem,16};1718pub(crate) struct RustcMainParser;1920impl NoArgsAttributeParser for RustcMainParser {21 const PATH: &[Symbol] = &[sym::rustc_main];22 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);23 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;24}2526pub(crate) struct RustcMustImplementOneOfParser;2728impl SingleAttributeParser for RustcMustImplementOneOfParser {29 const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];30 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);31 const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);32 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {33 let list = cx.expect_list(args, cx.attr_span)?;3435 let mut fn_names = ThinVec::new();3637 let inputs: Vec<_> = list.mixed().collect();3839 if inputs.len() < 2 {40 cx.adcx().expected_list_with_num_args_or_more(2, list.span);41 return None;42 }4344 let mut errored = false;45 for argument in inputs {46 let Some(meta) = argument.meta_item() else {47 cx.adcx().expected_identifier(argument.span());48 return None;49 };5051 let Some(ident) = meta.ident() else {52 cx.dcx().emit_err(errors::MustBeNameOfAssociatedFunction { span: meta.span() });53 errored = true;54 continue;55 };5657 fn_names.push(ident);58 }59 if errored {60 return None;61 }6263 Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })64 }65}6667pub(crate) struct RustcNeverReturnsNullPtrParser;6869impl NoArgsAttributeParser for RustcNeverReturnsNullPtrParser {70 const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];71 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[72 Allow(Target::Fn),73 Allow(Target::Method(MethodKind::Inherent)),74 Allow(Target::Method(MethodKind::Trait { body: false })),75 Allow(Target::Method(MethodKind::Trait { body: true })),76 Allow(Target::Method(MethodKind::TraitImpl)),77 ]);78 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPtr;79}80pub(crate) struct RustcNoImplicitAutorefsParser;8182impl NoArgsAttributeParser for RustcNoImplicitAutorefsParser {83 const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];84 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[85 Allow(Target::Fn),86 Allow(Target::Method(MethodKind::Inherent)),87 Allow(Target::Method(MethodKind::Trait { body: false })),88 Allow(Target::Method(MethodKind::Trait { body: true })),89 Allow(Target::Method(MethodKind::TraitImpl)),90 ]);9192 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;93}9495pub(crate) struct RustcLegacyConstGenericsParser;9697impl SingleAttributeParser for RustcLegacyConstGenericsParser {98 const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];99 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);100 const TEMPLATE: AttributeTemplate = template!(List: &["N"]);101102 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {103 let meta_items = cx.expect_list(args, cx.attr_span)?;104105 let mut parsed_indexes = ThinVec::new();106 let mut errored = false;107108 for possible_index in meta_items.mixed() {109 if let MetaItemOrLitParser::Lit(MetaItemLit {110 kind: LitKind::Int(index, LitIntType::Unsuffixed),111 ..112 }) = possible_index113 {114 parsed_indexes.push((index.0 as usize, possible_index.span()));115 } else {116 cx.adcx().expected_integer_literal(possible_index.span());117 errored = true;118 }119 }120 if errored {121 return None;122 } else if parsed_indexes.is_empty() {123 cx.adcx().expected_at_least_one_argument(args.span()?);124 return None;125 }126127 Some(AttributeKind::RustcLegacyConstGenerics {128 fn_indexes: parsed_indexes,129 attr_span: cx.attr_span,130 })131 }132}133134pub(crate) struct RustcInheritOverflowChecksParser;135136impl NoArgsAttributeParser for RustcInheritOverflowChecksParser {137 const PATH: &[Symbol] = &[sym::rustc_inherit_overflow_checks];138 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[139 Allow(Target::Fn),140 Allow(Target::Method(MethodKind::Inherent)),141 Allow(Target::Method(MethodKind::TraitImpl)),142 Allow(Target::Closure),143 ]);144 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInheritOverflowChecks;145}146147pub(crate) struct RustcLintOptDenyFieldAccessParser;148149impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser {150 const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];151 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);152 const TEMPLATE: AttributeTemplate = template!(Word);153 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {154 let arg = cx.expect_single_element_list(args, cx.attr_span)?;155156 let MetaItemOrLitParser::Lit(MetaItemLit { kind: LitKind::Str(lint_message, _), .. }) = arg157 else {158 cx.adcx().expected_string_literal(arg.span(), arg.lit());159 return None;160 };161162 Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message: *lint_message })163 }164}165166pub(crate) struct RustcLintOptTyParser;167168impl NoArgsAttributeParser for RustcLintOptTyParser {169 const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];170 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);171 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;172}173174fn parse_cgu_fields(175 cx: &mut AcceptContext<'_, '_>,176 args: &ArgParser,177 accepts_kind: bool,178) -> Option<(Symbol, Symbol, Option<CguKind>)> {179 let args = cx.expect_list(args, cx.attr_span)?;180181 let mut cfg = None::<(Symbol, Span)>;182 let mut module = None::<(Symbol, Span)>;183 let mut kind = None::<(Symbol, Span)>;184185 for arg in args.mixed() {186 let Some((ident, arg)) = cx.expect_name_value(arg, arg.span(), None) else {187 continue;188 };189190 let res = match ident.name {191 sym::cfg => &mut cfg,192 sym::module => &mut module,193 sym::kind if accepts_kind => &mut kind,194 _ => {195 cx.adcx().expected_specific_argument(196 ident.span,197 if accepts_kind {198 &[sym::cfg, sym::module, sym::kind]199 } else {200 &[sym::cfg, sym::module]201 },202 );203 continue;204 }205 };206207 let Some(str) = arg.value_as_str() else {208 cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit()));209 continue;210 };211212 if res.is_some() {213 cx.adcx().duplicate_key(ident.span.to(arg.args_span()), ident.name);214 continue;215 }216217 *res = Some((str, arg.value_span));218 }219220 let Some((cfg, _)) = cfg else {221 cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::cfg });222 return None;223 };224 let Some((module, _)) = module else {225 cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::module });226 return None;227 };228 let kind = if let Some((kind, span)) = kind {229 Some(match kind {230 sym::no => CguKind::No,231 sym::pre_dash_lto => CguKind::PreDashLto,232 sym::post_dash_lto => CguKind::PostDashLto,233 sym::any => CguKind::Any,234 _ => {235 cx.adcx().expected_specific_argument_strings(236 span,237 &[sym::no, sym::pre_dash_lto, sym::post_dash_lto, sym::any],238 );239 return None;240 }241 })242 } else {243 // return None so that an unwrap for the attributes that need it is ok.244 if accepts_kind {245 cx.emit_err(CguFieldsMissing {246 span: args.span,247 name: &cx.attr_path,248 field: sym::kind,249 });250 return None;251 };252253 None254 };255256 Some((cfg, module, kind))257}258259#[derive(Default)]260pub(crate) struct RustcCguTestAttributeParser {261 items: ThinVec<(Span, CguFields)>,262}263264impl AttributeParser for RustcCguTestAttributeParser {265 const ATTRIBUTES: AcceptMapping<Self> = &[266 (267 &[sym::rustc_partition_reused],268 template!(List: &[r#"cfg = "...", module = "...""#]),269 |this, cx, args| {270 this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {271 (cx.attr_span, CguFields::PartitionReused { cfg, module })272 }));273 },274 ),275 (276 &[sym::rustc_partition_codegened],277 template!(List: &[r#"cfg = "...", module = "...""#]),278 |this, cx, args| {279 this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {280 (cx.attr_span, CguFields::PartitionCodegened { cfg, module })281 }));282 },283 ),284 (285 &[sym::rustc_expected_cgu_reuse],286 template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]),287 |this, cx, args| {288 this.items.extend(parse_cgu_fields(cx, args, true).map(|(cfg, module, kind)| {289 // unwrap ok because if not given, we return None in `parse_cgu_fields`.290 (cx.attr_span, CguFields::ExpectedCguReuse { cfg, module, kind: kind.unwrap() })291 }));292 },293 ),294 ];295296 const ALLOWED_TARGETS: AllowedTargets =297 AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);298299 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {300 Some(AttributeKind::RustcCguTestAttr(self.items))301 }302}303304pub(crate) struct RustcDeprecatedSafe2024Parser;305306impl SingleAttributeParser for RustcDeprecatedSafe2024Parser {307 const PATH: &[Symbol] = &[sym::rustc_deprecated_safe_2024];308 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[309 Allow(Target::Fn),310 Allow(Target::Method(MethodKind::Inherent)),311 Allow(Target::Method(MethodKind::Trait { body: false })),312 Allow(Target::Method(MethodKind::Trait { body: true })),313 Allow(Target::Method(MethodKind::TraitImpl)),314 ]);315 const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]);316317 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {318 let single = cx.expect_single_element_list(args, cx.attr_span)?;319320 let (path, arg) = cx.expect_name_value(single, cx.attr_span, None)?;321322 if path.name != sym::audit_that {323 cx.adcx().expected_specific_argument(path.span, &[sym::audit_that]);324 return None;325 };326327 let Some(suggestion) = arg.value_as_str() else {328 cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit()));329 return None;330 };331332 Some(AttributeKind::RustcDeprecatedSafe2024 { suggestion })333 }334}335336pub(crate) struct RustcConversionSuggestionParser;337338impl NoArgsAttributeParser for RustcConversionSuggestionParser {339 const PATH: &[Symbol] = &[sym::rustc_conversion_suggestion];340 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[341 Allow(Target::Fn),342 Allow(Target::Method(MethodKind::Inherent)),343 Allow(Target::Method(MethodKind::Trait { body: false })),344 Allow(Target::Method(MethodKind::Trait { body: true })),345 Allow(Target::Method(MethodKind::TraitImpl)),346 ]);347 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConversionSuggestion;348}349350pub(crate) struct RustcCaptureAnalysisParser;351352impl NoArgsAttributeParser for RustcCaptureAnalysisParser {353 const PATH: &[Symbol] = &[sym::rustc_capture_analysis];354 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);355 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis;356}357358pub(crate) struct RustcNeverTypeOptionsParser;359360impl SingleAttributeParser for RustcNeverTypeOptionsParser {361 const PATH: &[Symbol] = &[sym::rustc_never_type_options];362 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);363 const TEMPLATE: AttributeTemplate = template!(List: &[364 r#"fallback = "unit", "never", "no""#,365 r#"diverging_block_default = "unit", "never""#,366 ]);367368 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {369 let list = cx.expect_list(args, cx.attr_span)?;370371 let mut fallback = None::<Ident>;372 let mut diverging_block_default = None::<Ident>;373374 for arg in list.mixed() {375 let Some((ident, arg)) = cx.expect_name_value(arg, arg.span(), None) else {376 continue;377 };378379 let res = match ident.name {380 sym::fallback => &mut fallback,381 sym::diverging_block_default => &mut diverging_block_default,382 _ => {383 cx.adcx().expected_specific_argument(384 ident.span,385 &[sym::fallback, sym::diverging_block_default],386 );387 continue;388 }389 };390391 let Some(field) = arg.value_as_str() else {392 cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit()));393 continue;394 };395396 if res.is_some() {397 cx.adcx().duplicate_key(ident.span, ident.name);398 continue;399 }400401 *res = Some(Ident { name: field, span: arg.value_span });402 }403404 let fallback = match fallback {405 None => None,406 Some(Ident { name: sym::unit, .. }) => Some(DivergingFallbackBehavior::ToUnit),407 Some(Ident { name: sym::never, .. }) => Some(DivergingFallbackBehavior::ToNever),408 Some(Ident { name: sym::no, .. }) => Some(DivergingFallbackBehavior::NoFallback),409 Some(Ident { span, .. }) => {410 cx.adcx()411 .expected_specific_argument_strings(span, &[sym::unit, sym::never, sym::no]);412 return None;413 }414 };415416 let diverging_block_default = match diverging_block_default {417 None => None,418 Some(Ident { name: sym::unit, .. }) => Some(DivergingBlockBehavior::Unit),419 Some(Ident { name: sym::never, .. }) => Some(DivergingBlockBehavior::Never),420 Some(Ident { span, .. }) => {421 cx.adcx().expected_specific_argument_strings(span, &[sym::unit, sym::no]);422 return None;423 }424 };425426 Some(AttributeKind::RustcNeverTypeOptions { fallback, diverging_block_default })427 }428}429430pub(crate) struct RustcTrivialFieldReadsParser;431432impl NoArgsAttributeParser for RustcTrivialFieldReadsParser {433 const PATH: &[Symbol] = &[sym::rustc_trivial_field_reads];434 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);435 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTrivialFieldReads;436}437438pub(crate) struct RustcNoMirInlineParser;439440impl NoArgsAttributeParser for RustcNoMirInlineParser {441 const PATH: &[Symbol] = &[sym::rustc_no_mir_inline];442 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[443 Allow(Target::Fn),444 Allow(Target::Method(MethodKind::Inherent)),445 Allow(Target::Method(MethodKind::Trait { body: false })),446 Allow(Target::Method(MethodKind::Trait { body: true })),447 Allow(Target::Method(MethodKind::TraitImpl)),448 ]);449 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoMirInline;450}451452pub(crate) struct RustcNoWritableParser;453454impl NoArgsAttributeParser for RustcNoWritableParser {455 const PATH: &[Symbol] = &[sym::rustc_no_writable];456 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;457 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[458 Allow(Target::Fn),459 Allow(Target::Closure),460 Allow(Target::Method(MethodKind::Inherent)),461 Allow(Target::Method(MethodKind::TraitImpl)),462 Allow(Target::Method(MethodKind::Trait { body: true })),463 ]);464 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoWritable;465}466467pub(crate) struct RustcLintQueryInstabilityParser;468469impl NoArgsAttributeParser for RustcLintQueryInstabilityParser {470 const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];471 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[472 Allow(Target::Fn),473 Allow(Target::Method(MethodKind::Inherent)),474 Allow(Target::Method(MethodKind::Trait { body: false })),475 Allow(Target::Method(MethodKind::Trait { body: true })),476 Allow(Target::Method(MethodKind::TraitImpl)),477 ]);478 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintQueryInstability;479}480481pub(crate) struct RustcRegionsParser;482483impl NoArgsAttributeParser for RustcRegionsParser {484 const PATH: &[Symbol] = &[sym::rustc_regions];485 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[486 Allow(Target::Fn),487 Allow(Target::Method(MethodKind::Inherent)),488 Allow(Target::Method(MethodKind::Trait { body: false })),489 Allow(Target::Method(MethodKind::Trait { body: true })),490 Allow(Target::Method(MethodKind::TraitImpl)),491 ]);492493 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcRegions;494}495496pub(crate) struct RustcLintUntrackedQueryInformationParser;497498impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationParser {499 const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information];500 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[501 Allow(Target::Fn),502 Allow(Target::Method(MethodKind::Inherent)),503 Allow(Target::Method(MethodKind::Trait { body: false })),504 Allow(Target::Method(MethodKind::Trait { body: true })),505 Allow(Target::Method(MethodKind::TraitImpl)),506 ]);507508 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintUntrackedQueryInformation;509}510511pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;512513impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser {514 const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];515 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);516 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");517518 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {519 let nv = cx.expect_name_value(args, cx.attr_span, None)?;520 Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))521 }522}523524pub(crate) struct RustcScalableVectorParser;525526impl SingleAttributeParser for RustcScalableVectorParser {527 const PATH: &[Symbol] = &[sym::rustc_scalable_vector];528 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);529 const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);530531 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {532 if args.as_no_args().is_ok() {533 return Some(AttributeKind::RustcScalableVector { element_count: None });534 }535536 let n = parse_single_integer(cx, args)?;537 let Ok(n) = n.try_into() else {538 cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });539 return None;540 };541 Some(AttributeKind::RustcScalableVector { element_count: Some(n) })542 }543}544545pub(crate) struct LangParser;546547impl SingleAttributeParser for LangParser {548 const PATH: &[Symbol] = &[sym::lang];549 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`550 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");551552 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {553 let nv = cx.expect_name_value(args, cx.attr_span, None)?;554 let Some(name) = nv.value_as_str() else {555 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));556 return None;557 };558 let Some(lang_item) = LangItem::from_name(name) else {559 cx.emit_err(UnknownLangItem { span: cx.attr_span, name });560 return None;561 };562 Some(AttributeKind::Lang(lang_item))563 }564}565566pub(crate) struct RustcHasIncoherentInherentImplsParser;567568impl NoArgsAttributeParser for RustcHasIncoherentInherentImplsParser {569 const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];570 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[571 Allow(Target::Trait),572 Allow(Target::Struct),573 Allow(Target::Enum),574 Allow(Target::Union),575 Allow(Target::ForeignTy),576 ]);577 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;578}579580pub(crate) struct PanicHandlerParser;581582impl NoArgsAttributeParser for PanicHandlerParser {583 const PATH: &[Symbol] = &[sym::panic_handler];584 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`585 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Lang(LangItem::PanicImpl);586}587588pub(crate) struct RustcNounwindParser;589590impl NoArgsAttributeParser for RustcNounwindParser {591 const PATH: &[Symbol] = &[sym::rustc_nounwind];592 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[593 Allow(Target::Fn),594 Allow(Target::ForeignFn),595 Allow(Target::Method(MethodKind::Inherent)),596 Allow(Target::Method(MethodKind::TraitImpl)),597 Allow(Target::Method(MethodKind::Trait { body: true })),598 ]);599 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind;600}601602pub(crate) struct RustcOffloadKernelParser;603604impl NoArgsAttributeParser for RustcOffloadKernelParser {605 const PATH: &[Symbol] = &[sym::rustc_offload_kernel];606 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);607 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;608}609610pub(crate) struct RustcMirParser;611612impl CombineAttributeParser for RustcMirParser {613 const PATH: &[Symbol] = &[sym::rustc_mir];614615 type Item = RustcMirKind;616617 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcMir(items);618619 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[620 Allow(Target::Fn),621 Allow(Target::Method(MethodKind::Inherent)),622 Allow(Target::Method(MethodKind::TraitImpl)),623 Allow(Target::Method(MethodKind::Trait { body: false })),624 Allow(Target::Method(MethodKind::Trait { body: true })),625 ]);626627 const TEMPLATE: AttributeTemplate = template!(List: &["arg1, arg2, ..."]);628629 fn extend(630 cx: &mut AcceptContext<'_, '_>,631 args: &ArgParser,632 ) -> impl IntoIterator<Item = Self::Item> {633 let Some(list) = cx.expect_list(args, cx.attr_span) else {634 return ThinVec::new();635 };636637 list.mixed()638 .filter_map(|arg| arg.meta_item())639 .filter_map(|mi| {640 if let Some(ident) = mi.ident() {641 match ident.name {642 sym::rustc_peek_maybe_init => Some(RustcMirKind::PeekMaybeInit),643 sym::rustc_peek_maybe_uninit => Some(RustcMirKind::PeekMaybeUninit),644 sym::rustc_peek_liveness => Some(RustcMirKind::PeekLiveness),645 sym::stop_after_dataflow => Some(RustcMirKind::StopAfterDataflow),646 sym::borrowck_graphviz_postflow => {647 let nv = cx.expect_name_value(648 mi.args(),649 mi.span(),650 Some(sym::borrowck_graphviz_postflow),651 )?;652 let Some(path) = nv.value_as_str() else {653 cx.adcx().expected_string_literal(nv.value_span, None);654 return None;655 };656 let path = PathBuf::from(path.to_string());657 if path.file_name().is_some() {658 Some(RustcMirKind::BorrowckGraphvizPostflow { path })659 } else {660 cx.adcx().expected_filename_literal(nv.value_span);661 None662 }663 }664 sym::borrowck_graphviz_format => {665 let nv = cx.expect_name_value(666 mi.args(),667 mi.span(),668 Some(sym::borrowck_graphviz_format),669 )?;670 let Some(format) = nv.value_as_ident() else {671 cx.adcx().expected_identifier(nv.value_span);672 return None;673 };674 match format.name {675 sym::two_phase => Some(RustcMirKind::BorrowckGraphvizFormat {676 format: BorrowckGraphvizFormatKind::TwoPhase,677 }),678 _ => {679 cx.adcx()680 .expected_specific_argument(format.span, &[sym::two_phase]);681 None682 }683 }684 }685 _ => None,686 }687 } else {688 None689 }690 })691 .collect()692 }693}694pub(crate) struct RustcNonConstTraitMethodParser;695696impl NoArgsAttributeParser for RustcNonConstTraitMethodParser {697 const PATH: &[Symbol] = &[sym::rustc_non_const_trait_method];698 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[699 Allow(Target::Method(MethodKind::Trait { body: true })),700 Allow(Target::Method(MethodKind::Trait { body: false })),701 ]);702 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonConstTraitMethod;703}704705pub(crate) struct RustcCleanParser;706707impl CombineAttributeParser for RustcCleanParser {708 const PATH: &[Symbol] = &[sym::rustc_clean];709710 type Item = RustcCleanAttribute;711712 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcClean(items);713714 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[715 // tidy-alphabetical-start716 Allow(Target::AssocConst),717 Allow(Target::AssocTy),718 Allow(Target::Const),719 Allow(Target::Enum),720 Allow(Target::Expression),721 Allow(Target::Field),722 Allow(Target::Fn),723 Allow(Target::ForeignMod),724 Allow(Target::Impl { of_trait: false }),725 Allow(Target::Impl { of_trait: true }),726 Allow(Target::Method(MethodKind::Inherent)),727 Allow(Target::Method(MethodKind::Trait { body: false })),728 Allow(Target::Method(MethodKind::Trait { body: true })),729 Allow(Target::Method(MethodKind::TraitImpl)),730 Allow(Target::Mod),731 Allow(Target::Static),732 Allow(Target::Struct),733 Allow(Target::Trait),734 Allow(Target::TyAlias),735 Allow(Target::Union),736 // tidy-alphabetical-end737 ]);738739 const TEMPLATE: AttributeTemplate =740 template!(List: &[r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#]);741742 fn extend(743 cx: &mut AcceptContext<'_, '_>,744 args: &ArgParser,745 ) -> impl IntoIterator<Item = Self::Item> {746 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {747 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });748 }749 let list = cx.expect_list(args, cx.attr_span)?;750751 let mut except = None;752 let mut loaded_from_disk = None;753 let mut cfg = None;754755 for item in list.mixed() {756 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {757 continue;758 };759 let value_span = value.value_span;760 let Some(value) = value.value_as_str() else {761 cx.adcx().expected_string_literal(value_span, None);762 continue;763 };764 match ident.name {765 sym::cfg if cfg.is_some() => {766 cx.adcx().duplicate_key(item.span(), sym::cfg);767 }768 sym::cfg => {769 cfg = Some(value);770 }771 sym::except if except.is_some() => {772 cx.adcx().duplicate_key(item.span(), sym::except);773 }774 sym::except => {775 let entries =776 value.as_str().split(',').map(|s| Symbol::intern(s.trim())).collect();777 except = Some(RustcCleanQueries { entries, span: value_span });778 }779 sym::loaded_from_disk if loaded_from_disk.is_some() => {780 cx.adcx().duplicate_key(item.span(), sym::loaded_from_disk);781 }782 sym::loaded_from_disk => {783 let entries =784 value.as_str().split(',').map(|s| Symbol::intern(s.trim())).collect();785 loaded_from_disk = Some(RustcCleanQueries { entries, span: value_span });786 }787 _ => {788 cx.adcx().expected_specific_argument(789 ident.span,790 &[sym::cfg, sym::except, sym::loaded_from_disk],791 );792 }793 }794 }795 let Some(cfg) = cfg else {796 cx.adcx().expected_specific_argument(list.span, &[sym::cfg]);797 return None;798 };799800 Some(RustcCleanAttribute { span: cx.attr_span, cfg, except, loaded_from_disk })801 }802}803804pub(crate) struct RustcIfThisChangedParser;805806impl SingleAttributeParser for RustcIfThisChangedParser {807 const PATH: &[Symbol] = &[sym::rustc_if_this_changed];808809 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[810 // tidy-alphabetical-start811 Allow(Target::AssocConst),812 Allow(Target::AssocTy),813 Allow(Target::Const),814 Allow(Target::Enum),815 Allow(Target::Expression),816 Allow(Target::Field),817 Allow(Target::Fn),818 Allow(Target::ForeignMod),819 Allow(Target::Impl { of_trait: false }),820 Allow(Target::Impl { of_trait: true }),821 Allow(Target::Method(MethodKind::Inherent)),822 Allow(Target::Method(MethodKind::Trait { body: false })),823 Allow(Target::Method(MethodKind::Trait { body: true })),824 Allow(Target::Method(MethodKind::TraitImpl)),825 Allow(Target::Mod),826 Allow(Target::Static),827 Allow(Target::Struct),828 Allow(Target::Trait),829 Allow(Target::TyAlias),830 Allow(Target::Union),831 // tidy-alphabetical-end832 ]);833834 const TEMPLATE: AttributeTemplate = template!(Word, List: &["DepNode"]);835836 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {837 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {838 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });839 }840 match args {841 ArgParser::NoArgs => Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)),842 ArgParser::List(list) => {843 let item = cx.expect_single(list)?;844 let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {845 cx.adcx().expected_identifier(item.span());846 return None;847 };848 Some(AttributeKind::RustcIfThisChanged(cx.attr_span, Some(ident.name)))849 }850 ArgParser::NameValue(_) => {851 let inner_span = cx.inner_span;852 cx.adcx().expected_list_or_no_args(inner_span);853 None854 }855 }856 }857}858859pub(crate) struct RustcThenThisWouldNeedParser;860861impl CombineAttributeParser for RustcThenThisWouldNeedParser {862 const PATH: &[Symbol] = &[sym::rustc_then_this_would_need];863 type Item = Ident;864865 const CONVERT: ConvertFn<Self::Item> =866 |items, _span| AttributeKind::RustcThenThisWouldNeed(items);867 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[868 // tidy-alphabetical-start869 Allow(Target::AssocConst),870 Allow(Target::AssocTy),871 Allow(Target::Const),872 Allow(Target::Enum),873 Allow(Target::Expression),874 Allow(Target::Field),875 Allow(Target::Fn),876 Allow(Target::ForeignMod),877 Allow(Target::Impl { of_trait: false }),878 Allow(Target::Impl { of_trait: true }),879 Allow(Target::Method(MethodKind::Inherent)),880 Allow(Target::Method(MethodKind::Trait { body: false })),881 Allow(Target::Method(MethodKind::Trait { body: true })),882 Allow(Target::Method(MethodKind::TraitImpl)),883 Allow(Target::Mod),884 Allow(Target::Static),885 Allow(Target::Struct),886 Allow(Target::Trait),887 Allow(Target::TyAlias),888 Allow(Target::Union),889 // tidy-alphabetical-end890 ]);891892 const TEMPLATE: AttributeTemplate = template!(List: &["DepNode"]);893894 fn extend(895 cx: &mut AcceptContext<'_, '_>,896 args: &ArgParser,897 ) -> impl IntoIterator<Item = Self::Item> {898 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {899 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });900 }901 let item = cx.expect_single_element_list(args, cx.attr_span)?;902 let Some(ident) = item.meta_item().and_then(|item| item.ident()) else {903 cx.adcx().expected_identifier(item.span());904 return None;905 };906 Some(ident)907 }908}909910pub(crate) struct RustcInsignificantDtorParser;911912impl NoArgsAttributeParser for RustcInsignificantDtorParser {913 const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor];914 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[915 Allow(Target::Enum),916 Allow(Target::Struct),917 Allow(Target::ForeignTy),918 ]);919 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInsignificantDtor;920}921922pub(crate) struct RustcEffectiveVisibilityParser;923924impl NoArgsAttributeParser for RustcEffectiveVisibilityParser {925 const PATH: &[Symbol] = &[sym::rustc_effective_visibility];926 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[927 Allow(Target::Use),928 Allow(Target::Static),929 Allow(Target::Const),930 Allow(Target::Fn),931 Allow(Target::Closure),932 Allow(Target::Mod),933 Allow(Target::ForeignMod),934 Allow(Target::TyAlias),935 Allow(Target::Enum),936 Allow(Target::Variant),937 Allow(Target::Struct),938 Allow(Target::Field),939 Allow(Target::Union),940 Allow(Target::Trait),941 Allow(Target::TraitAlias),942 Allow(Target::Impl { of_trait: false }),943 Allow(Target::Impl { of_trait: true }),944 Allow(Target::AssocConst),945 Allow(Target::Method(MethodKind::Inherent)),946 Allow(Target::Method(MethodKind::Trait { body: false })),947 Allow(Target::Method(MethodKind::Trait { body: true })),948 Allow(Target::Method(MethodKind::TraitImpl)),949 Allow(Target::AssocTy),950 Allow(Target::ForeignFn),951 Allow(Target::ForeignStatic),952 Allow(Target::ForeignTy),953 Allow(Target::MacroDef),954 Allow(Target::PatField),955 Allow(Target::Crate),956 ]);957 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEffectiveVisibility;958}959960pub(crate) struct RustcDiagnosticItemParser;961962impl SingleAttributeParser for RustcDiagnosticItemParser {963 const PATH: &[Symbol] = &[sym::rustc_diagnostic_item];964 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[965 Allow(Target::Trait),966 Allow(Target::Struct),967 Allow(Target::Enum),968 Allow(Target::MacroDef),969 Allow(Target::TyAlias),970 Allow(Target::AssocTy),971 Allow(Target::AssocConst),972 Allow(Target::Fn),973 Allow(Target::Const),974 Allow(Target::Mod),975 Allow(Target::Impl { of_trait: false }),976 Allow(Target::Method(MethodKind::Inherent)),977 Allow(Target::Method(MethodKind::Trait { body: false })),978 Allow(Target::Method(MethodKind::Trait { body: true })),979 Allow(Target::Method(MethodKind::TraitImpl)),980 Allow(Target::Crate),981 ]);982 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");983984 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {985 let nv = cx.expect_name_value(args, cx.attr_span, None)?;986 let Some(value) = nv.value_as_str() else {987 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));988 return None;989 };990 Some(AttributeKind::RustcDiagnosticItem(value))991 }992}993994pub(crate) struct RustcDoNotConstCheckParser;995996impl NoArgsAttributeParser for RustcDoNotConstCheckParser {997 const PATH: &[Symbol] = &[sym::rustc_do_not_const_check];998 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[999 Allow(Target::Fn),1000 Allow(Target::Method(MethodKind::Inherent)),1001 Allow(Target::Method(MethodKind::TraitImpl)),1002 Allow(Target::Method(MethodKind::Trait { body: false })),1003 Allow(Target::Method(MethodKind::Trait { body: true })),1004 ]);1005 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDoNotConstCheck;1006}10071008pub(crate) struct RustcNonnullOptimizationGuaranteedParser;10091010impl NoArgsAttributeParser for RustcNonnullOptimizationGuaranteedParser {1011 const PATH: &[Symbol] = &[sym::rustc_nonnull_optimization_guaranteed];1012 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);1013 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonnullOptimizationGuaranteed;1014}10151016pub(crate) struct RustcStrictCoherenceParser;10171018impl NoArgsAttributeParser for RustcStrictCoherenceParser {1019 const PATH: &[Symbol] = &[sym::rustc_strict_coherence];1020 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[1021 Allow(Target::Trait),1022 Allow(Target::Struct),1023 Allow(Target::Enum),1024 Allow(Target::Union),1025 Allow(Target::ForeignTy),1026 ]);1027 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStrictCoherence;1028}10291030pub(crate) struct RustcReservationImplParser;10311032impl SingleAttributeParser for RustcReservationImplParser {1033 const PATH: &[Symbol] = &[sym::rustc_reservation_impl];1034 const ALLOWED_TARGETS: AllowedTargets =1035 AllowedTargets::AllowList(&[Allow(Target::Impl { of_trait: true })]);10361037 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "reservation message");10381039 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {1040 let nv = cx.expect_name_value(args, cx.attr_span, None)?;10411042 let Some(value_str) = nv.value_as_str() else {1043 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));1044 return None;1045 };10461047 Some(AttributeKind::RustcReservationImpl(value_str))1048 }1049}10501051pub(crate) struct PreludeImportParser;10521053impl NoArgsAttributeParser for PreludeImportParser {1054 const PATH: &[Symbol] = &[sym::prelude_import];1055 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Use)]);1056 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PreludeImport;1057}10581059pub(crate) struct RustcDocPrimitiveParser;10601061impl SingleAttributeParser for RustcDocPrimitiveParser {1062 const PATH: &[Symbol] = &[sym::rustc_doc_primitive];1063 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Mod)]);1064 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name");10651066 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {1067 let nv = cx.expect_name_value(args, cx.attr_span, None)?;10681069 let Some(value_str) = nv.value_as_str() else {1070 cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit()));1071 return None;1072 };10731074 Some(AttributeKind::RustcDocPrimitive(cx.attr_span, value_str))1075 }1076}10771078pub(crate) struct RustcIntrinsicParser;10791080impl NoArgsAttributeParser for RustcIntrinsicParser {1081 const PATH: &[Symbol] = &[sym::rustc_intrinsic];1082 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);1083 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic;1084}10851086pub(crate) struct RustcIntrinsicConstStableIndirectParser;10871088impl NoArgsAttributeParser for RustcIntrinsicConstStableIndirectParser {1089 const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];1090 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);1091 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;1092}10931094pub(crate) struct RustcExhaustiveParser;10951096impl NoArgsAttributeParser for RustcExhaustiveParser {1097 const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];1098 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Enum)]);1099 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;1100}