1use std::path::PathBuf;23use rustc_ast::{LitIntType, LitKind, MetaItemLit};4use rustc_feature::AttributeStability;5use rustc_hir::LangItem;6use rustc_hir::attrs::{7 BorrowckGraphvizFormatKind, CguFields, CguKind, DivergingBlockBehavior,8 DivergingFallbackBehavior, RustcCleanAttribute, RustcCleanQueries, RustcMirKind,9};10use rustc_span::Symbol;1112use super::prelude::*;13use super::util::parse_single_integer;14use crate::diagnostics;15use crate::session_diagnostics::{16 AttributeRequiresOpt, CguFieldsMissing, RustcScalableVectorCountOutOfRange, UnknownLangItem,17};1819pub(crate) struct RustcMainParser;2021impl NoArgsAttributeParser for RustcMainParser {22 const PATH: &[Symbol] = &[sym::rustc_main];23 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);24 const STABILITY: AttributeStability = unstable!(25 rustc_attrs,26 "the `#[rustc_main]` attribute is used internally to specify test entry point function"27 );28 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcMain;29}3031pub(crate) struct RustcMustImplementOneOfParser;3233impl SingleAttributeParser for RustcMustImplementOneOfParser {34 const PATH: &[Symbol] = &[sym::rustc_must_implement_one_of];35 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);36 const STABILITY: AttributeStability = unstable!(37 rustc_attrs,38 "the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete definition of a trait. Its syntax and semantics are highly experimental and will be subject to change before stabilization"39 );40 const TEMPLATE: AttributeTemplate = template!(List: &["function1, function2, ..."]);41 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {42 let list = cx.expect_list(args, cx.attr_span)?;4344 let mut fn_names = ThinVec::new();4546 let inputs: Vec<_> = list.mixed().collect();4748 if inputs.len() < 2 {49 cx.adcx().expected_list_with_num_args_or_more(2, list.span);50 return None;51 }5253 let mut errored = false;54 for argument in inputs {55 let Some(meta) = argument.meta_item_no_args() else {56 cx.adcx().expected_identifier(argument.span());57 return None;58 };5960 let Some(ident) = meta.ident() else {61 cx.dcx()62 .emit_err(diagnostics::MustBeNameOfAssociatedFunction { span: meta.span() });63 errored = true;64 continue;65 };6667 fn_names.push(ident);68 }69 if errored {70 return None;71 }7273 Some(AttributeKind::RustcMustImplementOneOf { attr_span: cx.attr_span, fn_names })74 }75}7677pub(crate) struct RustcNeverReturnsNullPtrParser;7879impl NoArgsAttributeParser for RustcNeverReturnsNullPtrParser {80 const PATH: &[Symbol] = &[sym::rustc_never_returns_null_ptr];81 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[82 Allow(Target::Fn),83 Allow(Target::Method(MethodKind::Inherent)),84 Allow(Target::Method(MethodKind::Trait { body: false })),85 Allow(Target::Method(MethodKind::Trait { body: true })),86 Allow(Target::Method(MethodKind::TraitImpl)),87 ]);88 const STABILITY: AttributeStability = unstable!(rustc_attrs);8990 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNeverReturnsNullPtr;91}92pub(crate) struct RustcNoImplicitAutorefsParser;9394impl NoArgsAttributeParser for RustcNoImplicitAutorefsParser {95 const PATH: &[Symbol] = &[sym::rustc_no_implicit_autorefs];96 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[97 Allow(Target::Fn),98 Allow(Target::Method(MethodKind::Inherent)),99 Allow(Target::Method(MethodKind::Trait { body: false })),100 Allow(Target::Method(MethodKind::Trait { body: true })),101 Allow(Target::Method(MethodKind::TraitImpl)),102 ]);103 const STABILITY: AttributeStability = unstable!(rustc_attrs);104105 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoImplicitAutorefs;106}107108pub(crate) struct RustcLegacyConstGenericsParser;109110impl SingleAttributeParser for RustcLegacyConstGenericsParser {111 const PATH: &[Symbol] = &[sym::rustc_legacy_const_generics];112 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);113 const TEMPLATE: AttributeTemplate = template!(List: &["N"]);114 const STABILITY: AttributeStability = unstable!(rustc_attrs);115116 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {117 let meta_items = cx.expect_list(args, cx.attr_span)?;118119 let mut parsed_indexes = ThinVec::new();120 let mut errored = false;121122 for possible_index in meta_items.mixed() {123 if let MetaItemOrLitParser::Lit(MetaItemLit {124 kind: LitKind::Int(index, LitIntType::Unsuffixed),125 ..126 }) = possible_index127 {128 parsed_indexes.push((index.0 as usize, possible_index.span()));129 } else {130 cx.adcx().expected_integer_literal(possible_index.span());131 errored = true;132 }133 }134 if errored {135 return None;136 } else if parsed_indexes.is_empty() {137 cx.adcx().expected_at_least_one_argument(args.span()?);138 return None;139 }140141 Some(AttributeKind::RustcLegacyConstGenerics {142 fn_indexes: parsed_indexes,143 attr_span: cx.attr_span,144 })145 }146}147148pub(crate) struct RustcInheritOverflowChecksParser;149150impl NoArgsAttributeParser for RustcInheritOverflowChecksParser {151 const PATH: &[Symbol] = &[sym::rustc_inherit_overflow_checks];152 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[153 Allow(Target::Fn),154 Allow(Target::Method(MethodKind::Inherent)),155 Allow(Target::Method(MethodKind::TraitImpl)),156 Allow(Target::Closure),157 ]);158 const STABILITY: AttributeStability = unstable!(rustc_attrs);159 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInheritOverflowChecks;160}161162pub(crate) struct RustcLintOptDenyFieldAccessParser;163164impl SingleAttributeParser for RustcLintOptDenyFieldAccessParser {165 const PATH: &[Symbol] = &[sym::rustc_lint_opt_deny_field_access];166 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Field)]);167 const TEMPLATE: AttributeTemplate = template!(Word);168 const STABILITY: AttributeStability = unstable!(rustc_attrs);169 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {170 let arg = cx.expect_single_element_list(args, cx.attr_span)?;171 let lint_message = cx.expect_string_literal(arg)?;172173 Some(AttributeKind::RustcLintOptDenyFieldAccess { lint_message })174 }175}176177pub(crate) struct RustcLintOptTyParser;178179impl NoArgsAttributeParser for RustcLintOptTyParser {180 const PATH: &[Symbol] = &[sym::rustc_lint_opt_ty];181 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);182 const STABILITY: AttributeStability = unstable!(rustc_attrs);183 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintOptTy;184}185186fn parse_cgu_fields(187 cx: &mut AcceptContext<'_, '_>,188 args: &ArgParser,189 accepts_kind: bool,190) -> Option<(Symbol, Symbol, Option<CguKind>)> {191 let args = cx.expect_list(args, cx.attr_span)?;192193 let mut cfg = None::<(Symbol, Span)>;194 let mut module = None::<(Symbol, Span)>;195 let mut kind = None::<(Symbol, Span)>;196197 for arg in args.mixed() {198 let Some((ident, arg)) = cx.expect_name_value(arg, arg.span(), None) else {199 continue;200 };201202 let res = match ident.name {203 sym::cfg => &mut cfg,204 sym::module => &mut module,205 sym::kind if accepts_kind => &mut kind,206 _ => {207 cx.adcx().expected_specific_argument(208 ident.span,209 if accepts_kind {210 &[sym::cfg, sym::module, sym::kind]211 } else {212 &[sym::cfg, sym::module]213 },214 );215 continue;216 }217 };218219 let str = cx.expect_string_literal(arg)?;220221 if res.is_some() {222 cx.adcx().duplicate_key(ident.span.to(arg.args_span()), ident.name);223 continue;224 }225226 *res = Some((str, arg.value_span));227 }228229 let Some((cfg, _)) = cfg else {230 cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::cfg });231 return None;232 };233 let Some((module, _)) = module else {234 cx.emit_err(CguFieldsMissing { span: args.span, name: &cx.attr_path, field: sym::module });235 return None;236 };237 let kind = if let Some((kind, span)) = kind {238 Some(match kind {239 sym::no => CguKind::No,240 sym::pre_dash_lto => CguKind::PreDashLto,241 sym::post_dash_lto => CguKind::PostDashLto,242 sym::any => CguKind::Any,243 _ => {244 cx.adcx().expected_specific_argument_strings(245 span,246 &[sym::no, sym::pre_dash_lto, sym::post_dash_lto, sym::any],247 );248 return None;249 }250 })251 } else {252 // return None so that an unwrap for the attributes that need it is ok.253 if accepts_kind {254 cx.emit_err(CguFieldsMissing {255 span: args.span,256 name: &cx.attr_path,257 field: sym::kind,258 });259 return None;260 };261262 None263 };264265 Some((cfg, module, kind))266}267268#[derive(Default)]269pub(crate) struct RustcCguTestAttributeParser {270 items: ThinVec<(Span, CguFields)>,271}272273impl AttributeParser for RustcCguTestAttributeParser {274 const ATTRIBUTES: AcceptMapping<Self> = &[275 (276 &[sym::rustc_partition_reused],277 template!(List: &[r#"cfg = "...", module = "...""#]),278 unstable!(rustc_attrs),279 |this, cx, args| {280 this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {281 (cx.attr_span, CguFields::PartitionReused { cfg, module })282 }));283 },284 ),285 (286 &[sym::rustc_partition_codegened],287 template!(List: &[r#"cfg = "...", module = "...""#]),288 unstable!(rustc_attrs),289 |this, cx, args| {290 this.items.extend(parse_cgu_fields(cx, args, false).map(|(cfg, module, _)| {291 (cx.attr_span, CguFields::PartitionCodegened { cfg, module })292 }));293 },294 ),295 (296 &[sym::rustc_expected_cgu_reuse],297 template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]),298 unstable!(rustc_attrs),299 |this, cx, args| {300 this.items.extend(parse_cgu_fields(cx, args, true).map(|(cfg, module, kind)| {301 // unwrap ok because if not given, we return None in `parse_cgu_fields`.302 (cx.attr_span, CguFields::ExpectedCguReuse { cfg, module, kind: kind.unwrap() })303 }));304 },305 ),306 ];307308 const ALLOWED_TARGETS: AllowedTargets =309 AllowedTargets::AllowList(&[Allow(Target::Mod), Allow(Target::Crate)]);310311 fn finalize(self, _cx: &FinalizeContext<'_, '_>) -> Option<AttributeKind> {312 Some(AttributeKind::RustcCguTestAttr(self.items))313 }314}315316pub(crate) struct RustcDeprecatedSafe2024Parser;317318impl SingleAttributeParser for RustcDeprecatedSafe2024Parser {319 const PATH: &[Symbol] = &[sym::rustc_deprecated_safe_2024];320 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[321 Allow(Target::Fn),322 Allow(Target::Method(MethodKind::Inherent)),323 Allow(Target::Method(MethodKind::Trait { body: false })),324 Allow(Target::Method(MethodKind::Trait { body: true })),325 Allow(Target::Method(MethodKind::TraitImpl)),326 ]);327 const TEMPLATE: AttributeTemplate = template!(List: &[r#"audit_that = "...""#]);328 const STABILITY: AttributeStability = unstable!(rustc_attrs);329330 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {331 let single = cx.expect_single_element_list(args, cx.attr_span)?;332333 let (path, arg) = cx.expect_name_value(single, cx.attr_span, None)?;334335 if path.name != sym::audit_that {336 cx.adcx().expected_specific_argument(path.span, &[sym::audit_that]);337 return None;338 };339340 let suggestion = cx.expect_string_literal(arg)?;341342 Some(AttributeKind::RustcDeprecatedSafe2024 { suggestion })343 }344}345346pub(crate) struct RustcConversionSuggestionParser;347348impl NoArgsAttributeParser for RustcConversionSuggestionParser {349 const PATH: &[Symbol] = &[sym::rustc_conversion_suggestion];350 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[351 Allow(Target::Fn),352 Allow(Target::Method(MethodKind::Inherent)),353 Allow(Target::Method(MethodKind::Trait { body: false })),354 Allow(Target::Method(MethodKind::Trait { body: true })),355 Allow(Target::Method(MethodKind::TraitImpl)),356 ]);357 const STABILITY: AttributeStability = unstable!(rustc_attrs);358 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcConversionSuggestion;359}360361pub(crate) struct RustcCaptureAnalysisParser;362363impl NoArgsAttributeParser for RustcCaptureAnalysisParser {364 const PATH: &[Symbol] = &[sym::rustc_capture_analysis];365 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Closure)]);366 const STABILITY: AttributeStability = unstable!(rustc_attrs);367 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcCaptureAnalysis;368}369370pub(crate) struct RustcNeverTypeOptionsParser;371372impl SingleAttributeParser for RustcNeverTypeOptionsParser {373 const PATH: &[Symbol] = &[sym::rustc_never_type_options];374 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]);375 const TEMPLATE: AttributeTemplate = template!(List: &[376 r#"fallback = "unit", "never", "no""#,377 r#"diverging_block_default = "unit", "never""#,378 ]);379 const STABILITY: AttributeStability = unstable!(380 rustc_attrs,381 "`rustc_never_type_options` is used to experiment with never type fallback and work on never type stabilization"382 );383384 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {385 let list = cx.expect_list(args, cx.attr_span)?;386387 let mut fallback = None::<Ident>;388 let mut diverging_block_default = None::<Ident>;389390 for arg in list.mixed() {391 let Some((ident, arg)) = cx.expect_name_value(arg, arg.span(), None) else {392 continue;393 };394395 let res = match ident.name {396 sym::fallback => &mut fallback,397 sym::diverging_block_default => &mut diverging_block_default,398 _ => {399 cx.adcx().expected_specific_argument(400 ident.span,401 &[sym::fallback, sym::diverging_block_default],402 );403 continue;404 }405 };406407 let field = cx.expect_string_literal(arg)?;408409 if res.is_some() {410 cx.adcx().duplicate_key(ident.span, ident.name);411 continue;412 }413414 *res = Some(Ident { name: field, span: arg.value_span });415 }416417 let fallback = match fallback {418 None => None,419 Some(Ident { name: sym::unit, .. }) => Some(DivergingFallbackBehavior::ToUnit),420 Some(Ident { name: sym::never, .. }) => Some(DivergingFallbackBehavior::ToNever),421 Some(Ident { name: sym::no, .. }) => Some(DivergingFallbackBehavior::NoFallback),422 Some(Ident { span, .. }) => {423 cx.adcx()424 .expected_specific_argument_strings(span, &[sym::unit, sym::never, sym::no]);425 return None;426 }427 };428429 let diverging_block_default = match diverging_block_default {430 None => None,431 Some(Ident { name: sym::unit, .. }) => Some(DivergingBlockBehavior::Unit),432 Some(Ident { name: sym::never, .. }) => Some(DivergingBlockBehavior::Never),433 Some(Ident { span, .. }) => {434 cx.adcx().expected_specific_argument_strings(span, &[sym::unit, sym::no]);435 return None;436 }437 };438439 Some(AttributeKind::RustcNeverTypeOptions { fallback, diverging_block_default })440 }441}442443pub(crate) struct RustcTrivialFieldReadsParser;444445impl NoArgsAttributeParser for RustcTrivialFieldReadsParser {446 const PATH: &[Symbol] = &[sym::rustc_trivial_field_reads];447 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Trait)]);448 const STABILITY: AttributeStability = unstable!(rustc_attrs);449 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcTrivialFieldReads;450}451452pub(crate) struct RustcNoMirInlineParser;453454impl NoArgsAttributeParser for RustcNoMirInlineParser {455 const PATH: &[Symbol] = &[sym::rustc_no_mir_inline];456 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[457 Allow(Target::Fn),458 Allow(Target::Method(MethodKind::Inherent)),459 Allow(Target::Method(MethodKind::Trait { body: false })),460 Allow(Target::Method(MethodKind::Trait { body: true })),461 Allow(Target::Method(MethodKind::TraitImpl)),462 ]);463 const STABILITY: AttributeStability = unstable!(rustc_attrs);464 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoMirInline;465}466467pub(crate) struct RustcNoWritableParser;468469impl NoArgsAttributeParser for RustcNoWritableParser {470 const PATH: &[Symbol] = &[sym::rustc_no_writable];471 const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error;472 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[473 Allow(Target::Fn),474 Allow(Target::Closure),475 Allow(Target::Method(MethodKind::Inherent)),476 Allow(Target::Method(MethodKind::TraitImpl)),477 Allow(Target::Method(MethodKind::Trait { body: true })),478 ]);479 const STABILITY: AttributeStability = unstable!(rustc_attrs);480 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNoWritable;481}482483pub(crate) struct RustcLintQueryInstabilityParser;484485impl NoArgsAttributeParser for RustcLintQueryInstabilityParser {486 const PATH: &[Symbol] = &[sym::rustc_lint_query_instability];487 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[488 Allow(Target::Fn),489 Allow(Target::Method(MethodKind::Inherent)),490 Allow(Target::Method(MethodKind::Trait { body: false })),491 Allow(Target::Method(MethodKind::Trait { body: true })),492 Allow(Target::Method(MethodKind::TraitImpl)),493 ]);494 const STABILITY: AttributeStability = unstable!(rustc_attrs);495 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintQueryInstability;496}497498pub(crate) struct RustcRegionsParser;499500impl NoArgsAttributeParser for RustcRegionsParser {501 const PATH: &[Symbol] = &[sym::rustc_regions];502 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[503 Allow(Target::Fn),504 Allow(Target::Method(MethodKind::Inherent)),505 Allow(Target::Method(MethodKind::Trait { body: false })),506 Allow(Target::Method(MethodKind::Trait { body: true })),507 Allow(Target::Method(MethodKind::TraitImpl)),508 ]);509 const STABILITY: AttributeStability = unstable!(rustc_attrs);510 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcRegions;511}512513pub(crate) struct RustcLintUntrackedQueryInformationParser;514515impl NoArgsAttributeParser for RustcLintUntrackedQueryInformationParser {516 const PATH: &[Symbol] = &[sym::rustc_lint_untracked_query_information];517 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[518 Allow(Target::Fn),519 Allow(Target::Method(MethodKind::Inherent)),520 Allow(Target::Method(MethodKind::Trait { body: false })),521 Allow(Target::Method(MethodKind::Trait { body: true })),522 Allow(Target::Method(MethodKind::TraitImpl)),523 ]);524 const STABILITY: AttributeStability = unstable!(rustc_attrs);525 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcLintUntrackedQueryInformation;526}527528pub(crate) struct RustcSimdMonomorphizeLaneLimitParser;529530impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser {531 const PATH: &[Symbol] = &[sym::rustc_simd_monomorphize_lane_limit];532 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);533 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N");534 const STABILITY: AttributeStability = unstable!(rustc_attrs);535536 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {537 let nv = cx.expect_name_value(args, cx.attr_span, None)?;538 Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?))539 }540}541542pub(crate) struct RustcScalableVectorParser;543544impl SingleAttributeParser for RustcScalableVectorParser {545 const PATH: &[Symbol] = &[sym::rustc_scalable_vector];546 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);547 const TEMPLATE: AttributeTemplate = template!(Word, List: &["count"]);548 const STABILITY: AttributeStability = unstable!(rustc_attrs);549550 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {551 if args.as_no_args().is_ok() {552 return Some(AttributeKind::RustcScalableVector { element_count: None });553 }554555 let n = parse_single_integer(cx, args)?;556 let Ok(n) = n.try_into() else {557 cx.emit_err(RustcScalableVectorCountOutOfRange { span: cx.attr_span, n });558 return None;559 };560 Some(AttributeKind::RustcScalableVector { element_count: Some(n) })561 }562}563564pub(crate) struct LangParser;565566impl SingleAttributeParser for LangParser {567 const PATH: &[Symbol] = &[sym::lang];568 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`569 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");570 const STABILITY: AttributeStability = unstable!(lang_items);571572 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {573 let nv = cx.expect_name_value(args, cx.attr_span, None)?;574 let name = cx.expect_string_literal(nv)?;575 let Some(lang_item) = LangItem::from_name(name) else {576 cx.emit_err(UnknownLangItem { span: cx.attr_span, name });577 return None;578 };579 Some(AttributeKind::Lang(lang_item))580 }581}582583pub(crate) struct RustcHasIncoherentInherentImplsParser;584585impl NoArgsAttributeParser for RustcHasIncoherentInherentImplsParser {586 const PATH: &[Symbol] = &[sym::rustc_has_incoherent_inherent_impls];587 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[588 Allow(Target::Trait),589 Allow(Target::Struct),590 Allow(Target::Enum),591 Allow(Target::Union),592 Allow(Target::ForeignTy),593 ]);594 const STABILITY: AttributeStability = unstable!(rustc_attrs);595 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcHasIncoherentInherentImpls;596}597598pub(crate) struct PanicHandlerParser;599600impl NoArgsAttributeParser for PanicHandlerParser {601 const PATH: &[Symbol] = &[sym::panic_handler];602 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(ALL_TARGETS); // Targets are checked per lang item in `rustc_passes`603 const STABILITY: AttributeStability = AttributeStability::Stable;604 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::Lang(LangItem::PanicImpl);605}606607pub(crate) struct RustcNounwindParser;608609impl NoArgsAttributeParser for RustcNounwindParser {610 const PATH: &[Symbol] = &[sym::rustc_nounwind];611 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[612 Allow(Target::Fn),613 Allow(Target::ForeignFn),614 Allow(Target::Method(MethodKind::Inherent)),615 Allow(Target::Method(MethodKind::TraitImpl)),616 Allow(Target::Method(MethodKind::Trait { body: true })),617 ]);618 const STABILITY: AttributeStability = unstable!(rustc_attrs);619 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNounwind;620}621622pub(crate) struct RustcOffloadKernelParser;623624impl NoArgsAttributeParser for RustcOffloadKernelParser {625 const PATH: &[Symbol] = &[sym::rustc_offload_kernel];626 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);627 const STABILITY: AttributeStability = unstable!(rustc_attrs);628 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcOffloadKernel;629}630631pub(crate) struct RustcMirParser;632633impl CombineAttributeParser for RustcMirParser {634 const PATH: &[Symbol] = &[sym::rustc_mir];635636 type Item = RustcMirKind;637638 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcMir(items);639 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[640 Allow(Target::Fn),641 Allow(Target::Method(MethodKind::Inherent)),642 Allow(Target::Method(MethodKind::TraitImpl)),643 Allow(Target::Method(MethodKind::Trait { body: false })),644 Allow(Target::Method(MethodKind::Trait { body: true })),645 ]);646 const TEMPLATE: AttributeTemplate = template!(List: &["arg1, arg2, ..."]);647 const STABILITY: AttributeStability = unstable!(rustc_attrs);648649 fn extend(650 cx: &mut AcceptContext<'_, '_>,651 args: &ArgParser,652 ) -> impl IntoIterator<Item = Self::Item> {653 let Some(list) = cx.expect_list(args, cx.attr_span) else {654 return ThinVec::new();655 };656657 list.mixed()658 .filter_map(|arg| arg.meta_item())659 .filter_map(|mi| {660 if let Some(ident) = mi.ident() {661 match ident.name {662 sym::rustc_peek_maybe_init => Some(RustcMirKind::PeekMaybeInit),663 sym::rustc_peek_maybe_uninit => Some(RustcMirKind::PeekMaybeUninit),664 sym::rustc_peek_liveness => Some(RustcMirKind::PeekLiveness),665 sym::stop_after_dataflow => Some(RustcMirKind::StopAfterDataflow),666 sym::borrowck_graphviz_postflow => {667 let nv = cx.expect_name_value(668 mi.args(),669 mi.span(),670 Some(sym::borrowck_graphviz_postflow),671 )?;672 let path = cx.expect_string_literal(nv)?;673 let path = PathBuf::from(path.to_string());674 if path.file_name().is_some() {675 Some(RustcMirKind::BorrowckGraphvizPostflow { path })676 } else {677 cx.adcx().expected_filename_literal(nv.value_span);678 None679 }680 }681 sym::borrowck_graphviz_format => {682 let nv = cx.expect_name_value(683 mi.args(),684 mi.span(),685 Some(sym::borrowck_graphviz_format),686 )?;687 let Some(format) = nv.value_as_ident() else {688 cx.adcx().expected_identifier(nv.value_span);689 return None;690 };691 match format.name {692 sym::two_phase => Some(RustcMirKind::BorrowckGraphvizFormat {693 format: BorrowckGraphvizFormatKind::TwoPhase,694 }),695 _ => {696 cx.adcx()697 .expected_specific_argument(format.span, &[sym::two_phase]);698 None699 }700 }701 }702 _ => None,703 }704 } else {705 None706 }707 })708 .collect()709 }710}711pub(crate) struct RustcNonConstTraitMethodParser;712713impl NoArgsAttributeParser for RustcNonConstTraitMethodParser {714 const PATH: &[Symbol] = &[sym::rustc_non_const_trait_method];715 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[716 Allow(Target::Method(MethodKind::Trait { body: true })),717 Allow(Target::Method(MethodKind::Trait { body: false })),718 ]);719 const STABILITY: AttributeStability = unstable!(720 rustc_attrs,721 "`#[rustc_non_const_trait_method]` should only used by the standard library to mark trait methods as non-const to allow large traits an easier transition to const"722 );723 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonConstTraitMethod;724}725726pub(crate) struct RustcCleanParser;727728impl CombineAttributeParser for RustcCleanParser {729 const PATH: &[Symbol] = &[sym::rustc_clean];730731 type Item = RustcCleanAttribute;732733 const CONVERT: ConvertFn<Self::Item> = |items, _| AttributeKind::RustcClean(items);734 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[735 // tidy-alphabetical-start736 Allow(Target::AssocConst),737 Allow(Target::AssocTy),738 Allow(Target::Const),739 Allow(Target::Enum),740 Allow(Target::Expression),741 Allow(Target::Field),742 Allow(Target::Fn),743 Allow(Target::ForeignMod),744 Allow(Target::Impl { of_trait: false }),745 Allow(Target::Impl { of_trait: true }),746 Allow(Target::Method(MethodKind::Inherent)),747 Allow(Target::Method(MethodKind::Trait { body: false })),748 Allow(Target::Method(MethodKind::Trait { body: true })),749 Allow(Target::Method(MethodKind::TraitImpl)),750 Allow(Target::Mod),751 Allow(Target::Static),752 Allow(Target::Struct),753 Allow(Target::Trait),754 Allow(Target::TyAlias),755 Allow(Target::Union),756 // tidy-alphabetical-end757 ]);758 const STABILITY: AttributeStability = unstable!(rustc_attrs);759 const TEMPLATE: AttributeTemplate =760 template!(List: &[r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#]);761762 fn extend(763 cx: &mut AcceptContext<'_, '_>,764 args: &ArgParser,765 ) -> impl IntoIterator<Item = Self::Item> {766 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {767 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });768 }769 let list = cx.expect_list(args, cx.attr_span)?;770771 let mut except = None;772 let mut loaded_from_disk = None;773 let mut cfg = None;774775 for item in list.mixed() {776 let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else {777 continue;778 };779 let value_span = value.value_span;780 let Some(value) = cx.expect_string_literal(value) else {781 continue;782 };783 match ident.name {784 sym::cfg if cfg.is_some() => {785 cx.adcx().duplicate_key(item.span(), sym::cfg);786 }787 sym::cfg => {788 cfg = Some(value);789 }790 sym::except if except.is_some() => {791 cx.adcx().duplicate_key(item.span(), sym::except);792 }793 sym::except => {794 let entries =795 value.as_str().split(',').map(|s| Symbol::intern(s.trim())).collect();796 except = Some(RustcCleanQueries { entries, span: value_span });797 }798 sym::loaded_from_disk if loaded_from_disk.is_some() => {799 cx.adcx().duplicate_key(item.span(), sym::loaded_from_disk);800 }801 sym::loaded_from_disk => {802 let entries =803 value.as_str().split(',').map(|s| Symbol::intern(s.trim())).collect();804 loaded_from_disk = Some(RustcCleanQueries { entries, span: value_span });805 }806 _ => {807 cx.adcx().expected_specific_argument(808 ident.span,809 &[sym::cfg, sym::except, sym::loaded_from_disk],810 );811 }812 }813 }814 let Some(cfg) = cfg else {815 cx.adcx().expected_specific_argument(list.span, &[sym::cfg]);816 return None;817 };818819 Some(RustcCleanAttribute { span: cx.attr_span, cfg, except, loaded_from_disk })820 }821}822823pub(crate) struct RustcIfThisChangedParser;824825impl SingleAttributeParser for RustcIfThisChangedParser {826 const PATH: &[Symbol] = &[sym::rustc_if_this_changed];827 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[828 // tidy-alphabetical-start829 Allow(Target::AssocConst),830 Allow(Target::AssocTy),831 Allow(Target::Const),832 Allow(Target::Enum),833 Allow(Target::Expression),834 Allow(Target::Field),835 Allow(Target::Fn),836 Allow(Target::ForeignMod),837 Allow(Target::Impl { of_trait: false }),838 Allow(Target::Impl { of_trait: true }),839 Allow(Target::Method(MethodKind::Inherent)),840 Allow(Target::Method(MethodKind::Trait { body: false })),841 Allow(Target::Method(MethodKind::Trait { body: true })),842 Allow(Target::Method(MethodKind::TraitImpl)),843 Allow(Target::Mod),844 Allow(Target::Static),845 Allow(Target::Struct),846 Allow(Target::Trait),847 Allow(Target::TyAlias),848 Allow(Target::Union),849 // tidy-alphabetical-end850 ]);851 const TEMPLATE: AttributeTemplate = template!(Word, List: &["DepNode"]);852 const STABILITY: AttributeStability = unstable!(rustc_attrs);853854 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {855 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {856 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });857 }858 match args {859 ArgParser::NoArgs => Some(AttributeKind::RustcIfThisChanged(cx.attr_span, None)),860 ArgParser::List(list) => {861 let item = cx.expect_single(list)?;862 let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else {863 cx.adcx().expected_identifier(item.span());864 return None;865 };866 Some(AttributeKind::RustcIfThisChanged(cx.attr_span, Some(ident.name)))867 }868 ArgParser::NameValue(_) => {869 let inner_span = cx.inner_span;870 cx.adcx().expected_list_or_no_args(inner_span);871 None872 }873 }874 }875}876877pub(crate) struct RustcThenThisWouldNeedParser;878879impl CombineAttributeParser for RustcThenThisWouldNeedParser {880 const PATH: &[Symbol] = &[sym::rustc_then_this_would_need];881 type Item = Ident;882883 const CONVERT: ConvertFn<Self::Item> =884 |items, _span| AttributeKind::RustcThenThisWouldNeed(items);885 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[886 // tidy-alphabetical-start887 Allow(Target::AssocConst),888 Allow(Target::AssocTy),889 Allow(Target::Const),890 Allow(Target::Enum),891 Allow(Target::Expression),892 Allow(Target::Field),893 Allow(Target::Fn),894 Allow(Target::ForeignMod),895 Allow(Target::Impl { of_trait: false }),896 Allow(Target::Impl { of_trait: true }),897 Allow(Target::Method(MethodKind::Inherent)),898 Allow(Target::Method(MethodKind::Trait { body: false })),899 Allow(Target::Method(MethodKind::Trait { body: true })),900 Allow(Target::Method(MethodKind::TraitImpl)),901 Allow(Target::Mod),902 Allow(Target::Static),903 Allow(Target::Struct),904 Allow(Target::Trait),905 Allow(Target::TyAlias),906 Allow(Target::Union),907 // tidy-alphabetical-end908 ]);909 const TEMPLATE: AttributeTemplate = template!(List: &["DepNode"]);910 const STABILITY: AttributeStability = unstable!(rustc_attrs);911912 fn extend(913 cx: &mut AcceptContext<'_, '_>,914 args: &ArgParser,915 ) -> impl IntoIterator<Item = Self::Item> {916 if !cx.cx.sess.opts.unstable_opts.query_dep_graph {917 cx.emit_err(AttributeRequiresOpt { span: cx.attr_span, opt: "-Z query-dep-graph" });918 }919 let item = cx.expect_single_element_list(args, cx.attr_span)?;920 let Some(ident) = item.meta_item_no_args().and_then(|item| item.ident()) else {921 cx.adcx().expected_identifier(item.span());922 return None;923 };924 Some(ident)925 }926}927928pub(crate) struct RustcInsignificantDtorParser;929930impl NoArgsAttributeParser for RustcInsignificantDtorParser {931 const PATH: &[Symbol] = &[sym::rustc_insignificant_dtor];932 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[933 Allow(Target::Enum),934 Allow(Target::Struct),935 Allow(Target::ForeignTy),936 ]);937 const STABILITY: AttributeStability = unstable!(rustc_attrs);938 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcInsignificantDtor;939}940941pub(crate) struct RustcEffectiveVisibilityParser;942943impl NoArgsAttributeParser for RustcEffectiveVisibilityParser {944 const PATH: &[Symbol] = &[sym::rustc_effective_visibility];945 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[946 Allow(Target::Use),947 Allow(Target::Static),948 Allow(Target::Const),949 Allow(Target::Fn),950 Allow(Target::Closure),951 Allow(Target::Mod),952 Allow(Target::ForeignMod),953 Allow(Target::TyAlias),954 Allow(Target::Enum),955 Allow(Target::Variant),956 Allow(Target::Struct),957 Allow(Target::Field),958 Allow(Target::Union),959 Allow(Target::Trait),960 Allow(Target::TraitAlias),961 Allow(Target::Impl { of_trait: false }),962 Allow(Target::Impl { of_trait: true }),963 Allow(Target::AssocConst),964 Allow(Target::Method(MethodKind::Inherent)),965 Allow(Target::Method(MethodKind::Trait { body: false })),966 Allow(Target::Method(MethodKind::Trait { body: true })),967 Allow(Target::Method(MethodKind::TraitImpl)),968 Allow(Target::AssocTy),969 Allow(Target::ForeignFn),970 Allow(Target::ForeignStatic),971 Allow(Target::ForeignTy),972 Allow(Target::MacroDef),973 Allow(Target::PatField),974 Allow(Target::Crate),975 ]);976 const STABILITY: AttributeStability = unstable!(rustc_attrs);977 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcEffectiveVisibility;978}979980pub(crate) struct RustcDiagnosticItemParser;981982impl SingleAttributeParser for RustcDiagnosticItemParser {983 const PATH: &[Symbol] = &[sym::rustc_diagnostic_item];984 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[985 Allow(Target::Trait),986 Allow(Target::Struct),987 Allow(Target::Enum),988 Allow(Target::MacroDef),989 Allow(Target::TyAlias),990 Allow(Target::AssocTy),991 Allow(Target::AssocConst),992 Allow(Target::Fn),993 Allow(Target::Const),994 Allow(Target::Mod),995 Allow(Target::Impl { of_trait: false }),996 Allow(Target::Method(MethodKind::Inherent)),997 Allow(Target::Method(MethodKind::Trait { body: false })),998 Allow(Target::Method(MethodKind::Trait { body: true })),999 Allow(Target::Method(MethodKind::TraitImpl)),1000 Allow(Target::Crate),1001 ]);1002 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name");1003 const STABILITY: AttributeStability = unstable!(1004 rustc_attrs,1005 "the `#[rustc_diagnostic_item]` attribute allows the compiler to reference types from the standard library for diagnostic purposes"1006 );10071008 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {1009 let nv = cx.expect_name_value(args, cx.attr_span, None)?;1010 let value = cx.expect_string_literal(nv)?;1011 Some(AttributeKind::RustcDiagnosticItem(value))1012 }1013}10141015pub(crate) struct RustcDoNotConstCheckParser;10161017impl NoArgsAttributeParser for RustcDoNotConstCheckParser {1018 const PATH: &[Symbol] = &[sym::rustc_do_not_const_check];1019 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[1020 Allow(Target::Fn),1021 Allow(Target::Method(MethodKind::Inherent)),1022 Allow(Target::Method(MethodKind::TraitImpl)),1023 Allow(Target::Method(MethodKind::Trait { body: false })),1024 Allow(Target::Method(MethodKind::Trait { body: true })),1025 ]);1026 const STABILITY: AttributeStability = unstable!(1027 rustc_attrs,1028 "`#[rustc_do_not_const_check]` skips const-check for this function's body"1029 );1030 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcDoNotConstCheck;1031}10321033pub(crate) struct RustcNonnullOptimizationGuaranteedParser;10341035impl NoArgsAttributeParser for RustcNonnullOptimizationGuaranteedParser {1036 const PATH: &[Symbol] = &[sym::rustc_nonnull_optimization_guaranteed];1037 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Struct)]);1038 const STABILITY: AttributeStability = unstable!(1039 rustc_attrs,1040 "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document guaranteed niche optimizations in the standard library",1041 "the compiler does not even check whether the type indeed is being non-null-optimized; it is your responsibility to ensure that the attribute is only used on types that are optimized"1042 );1043 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcNonnullOptimizationGuaranteed;1044}10451046pub(crate) struct RustcStrictCoherenceParser;10471048impl NoArgsAttributeParser for RustcStrictCoherenceParser {1049 const PATH: &[Symbol] = &[sym::rustc_strict_coherence];1050 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[1051 Allow(Target::Trait),1052 Allow(Target::Struct),1053 Allow(Target::Enum),1054 Allow(Target::Union),1055 Allow(Target::ForeignTy),1056 ]);1057 const STABILITY: AttributeStability = unstable!(rustc_attrs);1058 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcStrictCoherence;1059}10601061pub(crate) struct RustcReservationImplParser;10621063impl SingleAttributeParser for RustcReservationImplParser {1064 const PATH: &[Symbol] = &[sym::rustc_reservation_impl];1065 const ALLOWED_TARGETS: AllowedTargets =1066 AllowedTargets::AllowList(&[Allow(Target::Impl { of_trait: true })]);1067 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "reservation message");1068 const STABILITY: AttributeStability = unstable!(rustc_attrs);10691070 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {1071 let nv = cx.expect_name_value(args, cx.attr_span, None)?;1072 let value_str = cx.expect_string_literal(nv)?;10731074 Some(AttributeKind::RustcReservationImpl(value_str))1075 }1076}10771078pub(crate) struct PreludeImportParser;10791080impl NoArgsAttributeParser for PreludeImportParser {1081 const PATH: &[Symbol] = &[sym::prelude_import];1082 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Use)]);1083 const STABILITY: AttributeStability = unstable!(prelude_import);1084 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::PreludeImport;1085}10861087pub(crate) struct RustcDocPrimitiveParser;10881089impl SingleAttributeParser for RustcDocPrimitiveParser {1090 const PATH: &[Symbol] = &[sym::rustc_doc_primitive];1091 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Mod)]);1092 const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name");1093 const STABILITY: AttributeStability = unstable!(1094 rustc_attrs,1095 "the `#[rustc_doc_primitive]` attribute is used by the standard library to provide a way to generate documentation for primitive types"1096 );10971098 fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> {1099 let nv = cx.expect_name_value(args, cx.attr_span, None)?;1100 let value_str = cx.expect_string_literal(nv)?;11011102 Some(AttributeKind::RustcDocPrimitive(cx.attr_span, value_str))1103 }1104}11051106pub(crate) struct RustcIntrinsicParser;11071108impl NoArgsAttributeParser for RustcIntrinsicParser {1109 const PATH: &[Symbol] = &[sym::rustc_intrinsic];1110 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);1111 const STABILITY: AttributeStability = unstable!(intrinsics);1112 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsic;1113}11141115pub(crate) struct RustcIntrinsicConstStableIndirectParser;11161117impl NoArgsAttributeParser for RustcIntrinsicConstStableIndirectParser {1118 const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];1119 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Fn)]);1120 const STABILITY: AttributeStability = unstable!(rustc_attrs);1121 const CREATE: fn(Span) -> AttributeKind = |_| AttributeKind::RustcIntrinsicConstStableIndirect;1122}11231124pub(crate) struct RustcExhaustiveParser;11251126impl NoArgsAttributeParser for RustcExhaustiveParser {1127 const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];1128 const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Enum)]);1129 const STABILITY: AttributeStability = unstable!(rustc_attrs);1130 const CREATE: fn(Span) -> AttributeKind = AttributeKind::RustcMustMatchExhaustively;1131}
Findings
✓ No findings reported for this file.