compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs RUST 1,101 lines View on github.com → Search inside
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}

Code quality findings 9

Warning: '.unwrap()' will panic on None/Err variants. Prefer using pattern matching (match, if let), combinators (map, and_then), or the '?' operator for robust error handling.
warning correctness unwrap-usage
(cx.attr_span, CguFields::ExpectedCguReuse { cfg, module, kind: kind.unwrap() })
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
const PATH: &'static [Symbol] = &[sym::rustc_intrinsic_const_stable_indirect];
Warning: Direct indexing (e.g., `vec[i]`, `slice[i]`) panics on out-of-bounds access. Prefer using `.get(index)` or `.get_mut(index)` which return Option<&T>/Option<&mut T>.
warning correctness unchecked-indexing
const PATH: &'static [Symbol] = &[sym::rustc_must_match_exhaustively];
Info: Wildcard imports (`use some::path::*;`) can obscure the origin of names and lead to conflicts. Prefer importing specific items explicitly.
info maintainability wildcard-import
use super::prelude::*;
Performance Info: Calling .push() repeatedly inside a loop without prior capacity reservation can lead to multiple reallocations. Consider using `Vec::with_capacity(n)` or `vec.reserve(n)` if the approximate number of elements is known.
info performance push-without-reserve
parsed_indexes.push((index.0 as usize, possible_index.span()));
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let res = match ident.name {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
Some(match kind {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
let res = match ident.name {
Info: Ensure 'match' statements are exhaustive. If matching on enums, consider adding a wildcard arm `_ => {}` only if necessary and intentional, as it suppresses warnings about unhandled variants.
info correctness match-wildcard
match format.name {

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.