compiler/rustc_hir_analysis/src/check/check.rs RUST 2,309 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 2,309.
1use std::cell::LazyCell;2use std::ops::ControlFlow;34use rustc_abi::{ExternAbi, FieldIdx, ScalableElt};5use rustc_data_structures::unord::{UnordMap, UnordSet};6use rustc_errors::codes::*;7use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, MultiSpan};8use rustc_hir as hir;9use rustc_hir::attrs::ReprAttr::ReprPacked;10use rustc_hir::def::{CtorKind, DefKind};11use rustc_hir::{LangItem, Node, find_attr, intravisit};12use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};13use rustc_infer::traits::{Obligation, ObligationCauseCode, WellFormedLoc};14use rustc_lint_defs::builtin::{REPR_TRANSPARENT_NON_ZST_FIELDS, UNSUPPORTED_CALLING_CONVENTIONS};15use rustc_macros::Diagnostic;16use rustc_middle::hir::nested_filter;17use rustc_middle::middle::resolve_bound_vars::ResolvedArg;18use rustc_middle::middle::stability::EvalResult;19use rustc_middle::ty::error::TypeErrorToStringExt;20use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};21use rustc_middle::ty::util::Discr;22use rustc_middle::ty::{23    AdtDef, BottomUpFolder, FnSig, GenericArgKind, RegionKind, TypeFoldable, TypeSuperVisitable,24    TypeVisitable, TypeVisitableExt, Unnormalized, fold_regions,25};26use rustc_session::lint::builtin::UNINHABITED_STATIC;27use rustc_target::spec::{AbiMap, AbiMapping};28use rustc_trait_selection::error_reporting::InferCtxtErrorExt;29use rustc_trait_selection::traits;30use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;31use tracing::{debug, instrument};32use ty::TypingMode;3334use super::compare_impl_item::check_type_bounds;35use super::*;36use crate::check::wfcheck::{37    check_associated_item, check_trait_item, check_variances_for_type_defn, check_where_clauses,38    enter_wf_checking_ctxt,39};4041fn add_abi_diag_help<T: EmissionGuarantee>(abi: ExternAbi, diag: &mut Diag<'_, T>) {42    if let ExternAbi::Cdecl { unwind } = abi {43        let c_abi = ExternAbi::C { unwind };44        diag.help(format!("use `extern {c_abi}` instead",));45    } else if let ExternAbi::Stdcall { unwind } = abi {46        let c_abi = ExternAbi::C { unwind };47        let system_abi = ExternAbi::System { unwind };48        diag.help(format!(49            "if you need `extern {abi}` on win32 and `extern {c_abi}` everywhere else, \50                use `extern {system_abi}`"51        ));52    }53}5455pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: ExternAbi) {56    struct UnsupportedCallingConventions {57        abi: ExternAbi,58    }5960    impl<'a> Diagnostic<'a, ()> for UnsupportedCallingConventions {61        fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {62            let Self { abi } = self;63            let mut lint = Diag::new(64                dcx,65                level,66                format!("{abi} is not a supported ABI for the current target"),67            );68            add_abi_diag_help(abi, &mut lint);69            lint70        }71    }72    // FIXME: This should be checked earlier, e.g. in `rustc_ast_lowering`, as this73    // currently only guards function imports, function definitions, and function pointer types.74    // Functions in trait declarations can still use "deprecated" ABIs without any warning.7576    match AbiMap::from_target(&tcx.sess.target).canonize_abi(abi, false) {77        AbiMapping::Direct(..) => (),78        // already erred in rustc_ast_lowering79        AbiMapping::Invalid => {80            tcx.dcx().span_delayed_bug(span, format!("{abi} should be rejected in ast_lowering"));81        }82        AbiMapping::Deprecated(..) => {83            tcx.emit_node_span_lint(84                UNSUPPORTED_CALLING_CONVENTIONS,85                hir_id,86                span,87                UnsupportedCallingConventions { abi },88            );89        }90    }91}9293pub fn check_custom_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, fn_sig: FnSig<'_>, fn_sig_span: Span) {94    if fn_sig.abi() == ExternAbi::Custom {95        // Function definitions that use `extern "custom"` must be naked functions.96        if !find_attr!(tcx, def_id, Naked(_)) {97            tcx.dcx().emit_err(crate::errors::AbiCustomClothedFunction {98                span: fn_sig_span,99                naked_span: tcx.def_span(def_id).shrink_to_lo(),100            });101        }102    }103}104105fn check_struct(tcx: TyCtxt<'_>, def_id: LocalDefId) {106    let def = tcx.adt_def(def_id);107    let span = tcx.def_span(def_id);108    def.destructor(tcx); // force the destructor to be evaluated109110    if let Some(scalable) = def.repr().scalable {111        check_scalable_vector(tcx, span, def_id, scalable);112    } else if def.repr().simd() {113        check_simd(tcx, span, def_id);114    }115116    check_transparent(tcx, def);117    check_packed(tcx, span, def);118}119120fn check_union(tcx: TyCtxt<'_>, def_id: LocalDefId) {121    let def = tcx.adt_def(def_id);122    let span = tcx.def_span(def_id);123    def.destructor(tcx); // force the destructor to be evaluated124    check_transparent(tcx, def);125    check_union_fields(tcx, span, def_id);126    check_packed(tcx, span, def);127}128129fn allowed_union_or_unsafe_field<'tcx>(130    tcx: TyCtxt<'tcx>,131    ty: Ty<'tcx>,132    typing_env: ty::TypingEnv<'tcx>,133    span: Span,134) -> bool {135    // HACK (not that bad of a hack don't worry): Some codegen tests don't even define proper136    // impls for `Copy`. Let's short-circuit here for this validity check, since a lot of them137    // use unions. We should eventually fix all the tests to define that lang item or use138    // minicore stubs.139    if ty.is_trivially_pure_clone_copy() {140        return true;141    }142    // If `BikeshedGuaranteedNoDrop` is not defined in a `#[no_core]` test, fall back to `Copy`.143    // This is an underapproximation of `BikeshedGuaranteedNoDrop`,144    let def_id = tcx145        .lang_items()146        .get(LangItem::BikeshedGuaranteedNoDrop)147        .unwrap_or_else(|| tcx.require_lang_item(LangItem::Copy, span));148    let Ok(ty) = tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)) else {149        tcx.dcx().span_delayed_bug(span, "could not normalize field type");150        return true;151    };152    let (infcx, param_env) = tcx.infer_ctxt().build_with_typing_env(typing_env);153    infcx.predicate_must_hold_modulo_regions(&Obligation::new(154        tcx,155        ObligationCause::dummy_with_span(span),156        param_env,157        ty::TraitRef::new(tcx, def_id, [ty]),158    ))159}160161/// Check that the fields of the `union` do not need dropping.162fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool {163    let def = tcx.adt_def(item_def_id);164    assert!(def.is_union());165166    let typing_env = ty::TypingEnv::non_body_analysis(tcx, item_def_id);167    let args = ty::GenericArgs::identity_for_item(tcx, item_def_id);168169    for field in &def.non_enum_variant().fields {170        if !allowed_union_or_unsafe_field(tcx, field.ty(tcx, args), typing_env, span) {171            let (field_span, ty_span) = match tcx.hir_get_if_local(field.did) {172                // We are currently checking the type this field came from, so it must be local.173                Some(Node::Field(field)) => (field.span, field.ty.span),174                _ => unreachable!("mir field has to correspond to hir field"),175            };176            tcx.dcx().emit_err(errors::InvalidUnionField {177                field_span,178                sugg: errors::InvalidUnionFieldSuggestion {179                    lo: ty_span.shrink_to_lo(),180                    hi: ty_span.shrink_to_hi(),181                },182                note: (),183            });184            return false;185        }186    }187188    true189}190191/// Check that a `static` is inhabited.192fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {193    #[derive(Diagnostic)]194    #[diag("static of uninhabited type")]195    #[note("uninhabited statics cannot be initialized, and any access would be an immediate error")]196    struct StaticOfUninhabitedType;197198    // Make sure statics are inhabited.199    // Other parts of the compiler assume that there are no uninhabited places. In principle it200    // would be enough to check this for `extern` statics, as statics with an initializer will201    // have UB during initialization if they are uninhabited, but there also seems to be no good202    // reason to allow any statics to be uninhabited.203    let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();204    let span = tcx.def_span(def_id);205    let layout = match tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(ty)) {206        Ok(l) => l,207        // Foreign statics that overflow their allowed size should emit an error208        Err(LayoutError::SizeOverflow(_))209            if matches!(tcx.def_kind(def_id), DefKind::Static{ .. }210                if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>211        {212            tcx.dcx().emit_err(errors::TooLargeStatic { span });213            return;214        }215        // SIMD types with invalid layout (e.g., zero-length) should emit an error216        Err(e @ LayoutError::InvalidSimd { .. }) => {217            let ty_span = tcx.ty_span(def_id);218            tcx.dcx().span_err(ty_span, e.to_string());219            return;220        }221        // Generic statics are rejected, but we still reach this case.222        Err(e) => {223            tcx.dcx().span_delayed_bug(span, format!("{e:?}"));224            return;225        }226    };227    if layout.is_uninhabited() {228        tcx.emit_node_span_lint(229            UNINHABITED_STATIC,230            tcx.local_def_id_to_hir_id(def_id),231            span,232            StaticOfUninhabitedType,233        );234    }235}236237/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo`238/// projections that would result in "inheriting lifetimes".239fn check_opaque(tcx: TyCtxt<'_>, def_id: LocalDefId) {240    let hir::OpaqueTy { origin, .. } = *tcx.hir_expect_opaque_ty(def_id);241242    // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting243    // `async-std` (and `pub async fn` in general).244    // Since rustdoc doesn't care about the hidden type behind `impl Trait`, just don't look at it!245    // See https://github.com/rust-lang/rust/issues/75100246    if tcx.sess.opts.actually_rustdoc {247        return;248    }249250    if tcx.type_of(def_id).instantiate_identity().skip_norm_wip().references_error() {251        return;252    }253    if check_opaque_for_cycles(tcx, def_id).is_err() {254        return;255    }256257    let _ = check_opaque_meets_bounds(tcx, def_id, origin);258}259260/// Checks that an opaque type does not contain cycles.261pub(super) fn check_opaque_for_cycles<'tcx>(262    tcx: TyCtxt<'tcx>,263    def_id: LocalDefId,264) -> Result<(), ErrorGuaranteed> {265    let args = GenericArgs::identity_for_item(tcx, def_id);266267    // First, try to look at any opaque expansion cycles, considering coroutine fields268    // (even though these aren't necessarily true errors).269    if tcx.try_expand_impl_trait_type(def_id.to_def_id(), args).is_err() {270        let reported = opaque_type_cycle_error(tcx, def_id);271        return Err(reported);272    }273274    Ok(())275}276277/// Check that the hidden type behind `impl Trait` actually implements `Trait`.278///279/// This is mostly checked at the places that specify the opaque type, but we280/// check those cases in the `param_env` of that function, which may have281/// bounds not on this opaque type:282///283/// ```ignore (illustrative)284/// type X<T> = impl Clone;285/// fn f<T: Clone>(t: T) -> X<T> {286///     t287/// }288/// ```289///290/// Without this check the above code is incorrectly accepted: we would ICE if291/// some tried, for example, to clone an `Option<X<&mut ()>>`.292#[instrument(level = "debug", skip(tcx))]293fn check_opaque_meets_bounds<'tcx>(294    tcx: TyCtxt<'tcx>,295    def_id: LocalDefId,296    origin: hir::OpaqueTyOrigin<LocalDefId>,297) -> Result<(), ErrorGuaranteed> {298    let (span, definition_def_id) =299        if let Some((span, def_id)) = best_definition_site_of_opaque(tcx, def_id, origin) {300            (span, Some(def_id))301        } else {302            (tcx.def_span(def_id), None)303        };304305    let defining_use_anchor = match origin {306        hir::OpaqueTyOrigin::FnReturn { parent, .. }307        | hir::OpaqueTyOrigin::AsyncFn { parent, .. }308        | hir::OpaqueTyOrigin::TyAlias { parent, .. } => parent,309    };310    let param_env = tcx.param_env(defining_use_anchor);311312    // FIXME(#132279): Once `PostBorrowckAnalysis` is supported in the old solver, this branch should be removed.313    let infcx = tcx.infer_ctxt().build(if tcx.next_trait_solver_globally() {314        TypingMode::post_borrowck_analysis(tcx, defining_use_anchor)315    } else {316        TypingMode::analysis_in_body(tcx, defining_use_anchor)317    });318    let ocx = ObligationCtxt::new_with_diagnostics(&infcx);319320    let args = match origin {321        hir::OpaqueTyOrigin::FnReturn { parent, .. }322        | hir::OpaqueTyOrigin::AsyncFn { parent, .. }323        | hir::OpaqueTyOrigin::TyAlias { parent, .. } => GenericArgs::identity_for_item(324            tcx, parent,325        )326        .extend_to(tcx, def_id.to_def_id(), |param, _| {327            tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local()).into()328        }),329    };330331    let opaque_ty = Ty::new_opaque(tcx, def_id.to_def_id(), args);332333    // `ReErased` regions appear in the "parent_args" of closures/coroutines.334    // We're ignoring them here and replacing them with fresh region variables.335    // See tests in ui/type-alias-impl-trait/closure_{parent_args,wf_outlives}.rs.336    //337    // FIXME: Consider wrapping the hidden type in an existential `Binder` and instantiating it338    // here rather than using ReErased.339    let hidden_ty = tcx.type_of(def_id.to_def_id()).instantiate(tcx, args).skip_norm_wip();340    let hidden_ty = fold_regions(tcx, hidden_ty, |re, _dbi| match re.kind() {341        ty::ReErased => infcx.next_region_var(RegionVariableOrigin::Misc(span)),342        _ => re,343    });344345    // HACK: We eagerly instantiate some bounds to report better errors for them...346    // This isn't necessary for correctness, since we register these bounds when347    // equating the opaque below, but we should clean this up in the new solver.348    for (predicate, pred_span) in tcx349        .explicit_item_bounds(def_id)350        .iter_instantiated_copied(tcx, args)351        .map(Unnormalized::skip_norm_wip)352    {353        let predicate = predicate.fold_with(&mut BottomUpFolder {354            tcx,355            ty_op: |ty| if ty == opaque_ty { hidden_ty } else { ty },356            lt_op: |lt| lt,357            ct_op: |ct| ct,358        });359360        ocx.register_obligation(Obligation::new(361            tcx,362            ObligationCause::new(363                span,364                def_id,365                ObligationCauseCode::OpaqueTypeBound(pred_span, definition_def_id),366            ),367            param_env,368            predicate,369        ));370    }371372    let misc_cause = ObligationCause::misc(span, def_id);373    // FIXME: We should just register the item bounds here, rather than equating.374    // FIXME(const_trait_impl): When we do that, please make sure to also register375    // the `[const]` bounds.376    match ocx.eq(&misc_cause, param_env, opaque_ty, hidden_ty) {377        Ok(()) => {}378        Err(ty_err) => {379            // Some types may be left "stranded" if they can't be reached380            // from a lowered rustc_middle bound but they're mentioned in the HIR.381            // This will happen, e.g., when a nested opaque is inside of a non-382            // existent associated type, like `impl Trait<Missing = impl Trait>`.383            // See <tests/ui/impl-trait/stranded-opaque.rs>.384            let ty_err = ty_err.to_string(tcx);385            let guar = tcx.dcx().span_delayed_bug(386                span,387                format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),388            );389            return Err(guar);390        }391    }392393    // Additionally require the hidden type to be well-formed with only the generics of the opaque type.394    // Defining use functions may have more bounds than the opaque type, which is ok, as long as the395    // hidden type is well formed even without those bounds.396    let predicate =397        ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(hidden_ty.into())));398    ocx.register_obligation(Obligation::new(tcx, misc_cause.clone(), param_env, predicate));399400    // Check that all obligations are satisfied by the implementation's401    // version.402    let errors = ocx.evaluate_obligations_error_on_ambiguity();403    if !errors.is_empty() {404        let guar = infcx.err_ctxt().report_fulfillment_errors(errors);405        return Err(guar);406    }407408    let wf_tys = ocx.assumed_wf_types_and_report_errors(param_env, defining_use_anchor)?;409    ocx.resolve_regions_and_report_errors(defining_use_anchor, param_env, wf_tys)?;410411    if infcx.next_trait_solver() {412        Ok(())413    } else if let hir::OpaqueTyOrigin::FnReturn { .. } | hir::OpaqueTyOrigin::AsyncFn { .. } =414        origin415    {416        // HACK: this should also fall through to the hidden type check below, but the original417        // implementation had a bug where equivalent lifetimes are not identical. This caused us418        // to reject existing stable code that is otherwise completely fine. The real fix is to419        // compare the hidden types via our type equivalence/relation infra instead of doing an420        // identity check.421        let _ = infcx.take_opaque_types();422        Ok(())423    } else {424        // Check that any hidden types found during wf checking match the hidden types that `type_of` sees.425        for (mut key, mut ty) in infcx.take_opaque_types() {426            ty.ty = infcx.resolve_vars_if_possible(ty.ty);427            key = infcx.resolve_vars_if_possible(key);428            sanity_check_found_hidden_type(tcx, key, ty)?;429        }430        Ok(())431    }432}433434fn best_definition_site_of_opaque<'tcx>(435    tcx: TyCtxt<'tcx>,436    opaque_def_id: LocalDefId,437    origin: hir::OpaqueTyOrigin<LocalDefId>,438) -> Option<(Span, LocalDefId)> {439    struct TaitConstraintLocator<'tcx> {440        opaque_def_id: LocalDefId,441        tcx: TyCtxt<'tcx>,442    }443    impl<'tcx> TaitConstraintLocator<'tcx> {444        fn check(&self, item_def_id: LocalDefId) -> ControlFlow<(Span, LocalDefId)> {445            if !self.tcx.has_typeck_results(item_def_id) {446                return ControlFlow::Continue(());447            }448449            let opaque_types_defined_by = self.tcx.opaque_types_defined_by(item_def_id);450            // Don't try to check items that cannot possibly constrain the type.451            if !opaque_types_defined_by.contains(&self.opaque_def_id) {452                return ControlFlow::Continue(());453            }454455            if let Some(hidden_ty) = self456                .tcx457                .mir_borrowck(item_def_id)458                .ok()459                .and_then(|opaque_types| opaque_types.get(&self.opaque_def_id))460            {461                ControlFlow::Break((hidden_ty.span, item_def_id))462            } else {463                ControlFlow::Continue(())464            }465        }466    }467    impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {468        type NestedFilter = nested_filter::All;469        type Result = ControlFlow<(Span, LocalDefId)>;470        fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {471            self.tcx472        }473        fn visit_expr(&mut self, ex: &'tcx hir::Expr<'tcx>) -> Self::Result {474            intravisit::walk_expr(self, ex)475        }476        fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) -> Self::Result {477            self.check(it.owner_id.def_id)?;478            intravisit::walk_item(self, it)479        }480        fn visit_impl_item(&mut self, it: &'tcx hir::ImplItem<'tcx>) -> Self::Result {481            self.check(it.owner_id.def_id)?;482            intravisit::walk_impl_item(self, it)483        }484        fn visit_trait_item(&mut self, it: &'tcx hir::TraitItem<'tcx>) -> Self::Result {485            self.check(it.owner_id.def_id)?;486            intravisit::walk_trait_item(self, it)487        }488        fn visit_foreign_item(&mut self, it: &'tcx hir::ForeignItem<'tcx>) -> Self::Result {489            intravisit::walk_foreign_item(self, it)490        }491    }492493    let mut locator = TaitConstraintLocator { tcx, opaque_def_id };494    match origin {495        hir::OpaqueTyOrigin::FnReturn { parent, .. }496        | hir::OpaqueTyOrigin::AsyncFn { parent, .. } => locator.check(parent).break_value(),497        hir::OpaqueTyOrigin::TyAlias { parent, in_assoc_ty: true } => {498            let impl_def_id = tcx.local_parent(parent);499            for assoc in tcx.associated_items(impl_def_id).in_definition_order() {500                match assoc.kind {501                    ty::AssocKind::Const { .. } | ty::AssocKind::Fn { .. } => {502                        if let ControlFlow::Break(span) = locator.check(assoc.def_id.expect_local())503                        {504                            return Some(span);505                        }506                    }507                    ty::AssocKind::Type { .. } => {}508                }509            }510511            None512        }513        hir::OpaqueTyOrigin::TyAlias { in_assoc_ty: false, .. } => {514            tcx.hir_walk_toplevel_module(&mut locator).break_value()515        }516    }517}518519fn sanity_check_found_hidden_type<'tcx>(520    tcx: TyCtxt<'tcx>,521    key: ty::OpaqueTypeKey<'tcx>,522    mut ty: ty::ProvisionalHiddenType<'tcx>,523) -> Result<(), ErrorGuaranteed> {524    if ty.ty.is_ty_var() {525        // Nothing was actually constrained.526        return Ok(());527    }528    if let &ty::Alias(ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) = ty.ty.kind() {529        if def_id == key.def_id.to_def_id() && args == key.args {530            // Nothing was actually constrained, this is an opaque usage that was531            // only discovered to be opaque after inference vars resolved.532            return Ok(());533        }534    }535    let erase_re_vars = |ty: Ty<'tcx>| {536        fold_regions(tcx, ty, |r, _| match r.kind() {537            RegionKind::ReVar(_) => tcx.lifetimes.re_erased,538            _ => r,539        })540    };541    // Closures frequently end up containing erased lifetimes in their final representation.542    // These correspond to lifetime variables that never got resolved, so we patch this up here.543    ty.ty = erase_re_vars(ty.ty);544    // Get the hidden type.545    let hidden_ty = tcx.type_of(key.def_id).instantiate(tcx, key.args).skip_norm_wip();546    let hidden_ty = erase_re_vars(hidden_ty);547548    // If the hidden types differ, emit a type mismatch diagnostic.549    if hidden_ty == ty.ty {550        Ok(())551    } else {552        let span = tcx.def_span(key.def_id);553        let other = ty::ProvisionalHiddenType { ty: hidden_ty, span };554        Err(ty.build_mismatch_error(&other, tcx)?.emit())555    }556}557558/// Check that the opaque's precise captures list is valid (if present).559/// We check this for regular `impl Trait`s and also RPITITs, even though the latter560/// are technically GATs.561///562/// This function is responsible for:563/// 1. Checking that all type/const params are mention in the captures list.564/// 2. Checking that all lifetimes that are implicitly captured are mentioned.565/// 3. Asserting that all parameters mentioned in the captures list are invariant.566fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {567    let hir::OpaqueTy { bounds, .. } = *tcx.hir_node_by_def_id(opaque_def_id).expect_opaque_ty();568    let Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {569        hir::GenericBound::Use(bounds, ..) => Some(bounds),570        _ => None,571    }) else {572        // No precise capturing args; nothing to validate573        return;574    };575576    let mut expected_captures = UnordSet::default();577    let mut shadowed_captures = UnordSet::default();578    let mut seen_params = UnordMap::default();579    let mut prev_non_lifetime_param = None;580    for arg in precise_capturing_args {581        let (hir_id, ident) = match *arg {582            hir::PreciseCapturingArg::Param(hir::PreciseCapturingNonLifetimeArg {583                hir_id,584                ident,585                ..586            }) => {587                if prev_non_lifetime_param.is_none() {588                    prev_non_lifetime_param = Some(ident);589                }590                (hir_id, ident)591            }592            hir::PreciseCapturingArg::Lifetime(&hir::Lifetime { hir_id, ident, .. }) => {593                if let Some(prev_non_lifetime_param) = prev_non_lifetime_param {594                    tcx.dcx().emit_err(errors::LifetimesMustBeFirst {595                        lifetime_span: ident.span,596                        name: ident.name,597                        other_span: prev_non_lifetime_param.span,598                    });599                }600                (hir_id, ident)601            }602        };603604        let ident = ident.normalize_to_macros_2_0();605        if let Some(span) = seen_params.insert(ident, ident.span) {606            tcx.dcx().emit_err(errors::DuplicatePreciseCapture {607                name: ident.name,608                first_span: span,609                second_span: ident.span,610            });611        }612613        match tcx.named_bound_var(hir_id) {614            Some(ResolvedArg::EarlyBound(def_id)) => {615                expected_captures.insert(def_id.to_def_id());616617                // Make sure we allow capturing these lifetimes through `Self` and618                // `T::Assoc` projection syntax, too. These will occur when we only619                // see lifetimes are captured after hir-lowering -- this aligns with620                // the cases that were stabilized with the `impl_trait_projection`621                // feature -- see <https://github.com/rust-lang/rust/pull/115659>.622                if let DefKind::LifetimeParam = tcx.def_kind(def_id)623                    && let Some(def_id) = tcx624                        .map_opaque_lifetime_to_parent_lifetime(def_id)625                        .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))626                {627                    shadowed_captures.insert(def_id);628                }629            }630            _ => {631                tcx.dcx()632                    .span_delayed_bug(tcx.hir_span(hir_id), "parameter should have been resolved");633            }634        }635    }636637    let variances = tcx.variances_of(opaque_def_id);638    let mut def_id = Some(opaque_def_id.to_def_id());639    while let Some(generics) = def_id {640        let generics = tcx.generics_of(generics);641        def_id = generics.parent;642643        for param in &generics.own_params {644            if expected_captures.contains(&param.def_id) {645                assert_eq!(646                    variances[param.index as usize],647                    ty::Invariant,648                    "precise captured param should be invariant"649                );650                continue;651            }652            // If a param is shadowed by a early-bound (duplicated) lifetime, then653            // it may or may not be captured as invariant, depending on if it shows654            // up through `Self` or `T::Assoc` syntax.655            if shadowed_captures.contains(&param.def_id) {656                continue;657            }658659            match param.kind {660                ty::GenericParamDefKind::Lifetime => {661                    let use_span = tcx.def_span(param.def_id);662                    let opaque_span = tcx.def_span(opaque_def_id);663                    // Check if the lifetime param was captured but isn't named in the precise captures list.664                    if variances[param.index as usize] == ty::Invariant {665                        if let DefKind::OpaqueTy = tcx.def_kind(tcx.parent(param.def_id))666                            && let Some(def_id) = tcx667                                .map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local())668                                .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id()))669                        {670                            tcx.dcx().emit_err(errors::LifetimeNotCaptured {671                                opaque_span,672                                use_span,673                                param_span: tcx.def_span(def_id),674                            });675                        } else {676                            if tcx.def_kind(tcx.parent(param.def_id)) == DefKind::Trait {677                                tcx.dcx().emit_err(errors::LifetimeImplicitlyCaptured {678                                    opaque_span,679                                    param_span: tcx.def_span(param.def_id),680                                });681                            } else {682                                // If the `use_span` is actually just the param itself, then we must683                                // have not duplicated the lifetime but captured the original.684                                // The "effective" `use_span` will be the span of the opaque itself,685                                // and the param span will be the def span of the param.686                                tcx.dcx().emit_err(errors::LifetimeNotCaptured {687                                    opaque_span,688                                    use_span: opaque_span,689                                    param_span: use_span,690                                });691                            }692                        }693                        continue;694                    }695                }696                ty::GenericParamDefKind::Type { .. } => {697                    if matches!(tcx.def_kind(param.def_id), DefKind::Trait | DefKind::TraitAlias) {698                        // FIXME(precise_capturing): Structured suggestion for this would be useful699                        tcx.dcx().emit_err(errors::SelfTyNotCaptured {700                            trait_span: tcx.def_span(param.def_id),701                            opaque_span: tcx.def_span(opaque_def_id),702                        });703                    } else {704                        // FIXME(precise_capturing): Structured suggestion for this would be useful705                        tcx.dcx().emit_err(errors::ParamNotCaptured {706                            param_span: tcx.def_span(param.def_id),707                            opaque_span: tcx.def_span(opaque_def_id),708                            kind: "type",709                        });710                    }711                }712                ty::GenericParamDefKind::Const { .. } => {713                    // FIXME(precise_capturing): Structured suggestion for this would be useful714                    tcx.dcx().emit_err(errors::ParamNotCaptured {715                        param_span: tcx.def_span(param.def_id),716                        opaque_span: tcx.def_span(opaque_def_id),717                        kind: "const",718                    });719                }720            }721        }722    }723}724725fn is_enum_of_nonnullable_ptr<'tcx>(726    tcx: TyCtxt<'tcx>,727    adt_def: AdtDef<'tcx>,728    args: GenericArgsRef<'tcx>,729) -> bool {730    if adt_def.repr().inhibit_enum_layout_opt() {731        return false;732    }733734    let [var_one, var_two] = &adt_def.variants().raw[..] else {735        return false;736    };737    let (([], [field]) | ([field], [])) = (&var_one.fields.raw[..], &var_two.fields.raw[..]) else {738        return false;739    };740    matches!(field.ty(tcx, args).kind(), ty::FnPtr(..) | ty::Ref(..))741}742743fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) {744    if tcx.codegen_fn_attrs(def_id).import_linkage.is_some() {745        if match tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind() {746            ty::RawPtr(_, _) => false,747            ty::Adt(adt_def, args) => !is_enum_of_nonnullable_ptr(tcx, *adt_def, *args),748            _ => true,749        } {750            tcx.dcx().emit_err(errors::LinkageType { span: tcx.def_span(def_id) });751        }752    }753}754755pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {756    let mut res = Ok(());757    let generics = tcx.generics_of(def_id);758759    for param in &generics.own_params {760        match param.kind {761            ty::GenericParamDefKind::Lifetime { .. } => {}762            ty::GenericParamDefKind::Type { has_default, .. } => {763                if has_default {764                    tcx.ensure_ok().type_of(param.def_id);765                }766            }767            ty::GenericParamDefKind::Const { has_default, .. } => {768                tcx.ensure_ok().type_of(param.def_id);769                if has_default {770                    // need to store default and type of default771                    let ct = tcx.const_param_default(param.def_id).skip_binder();772                    if let ty::ConstKind::Unevaluated(uv) = ct.kind() {773                        tcx.ensure_ok().type_of(uv.def);774                    }775                }776            }777        }778    }779780    match tcx.def_kind(def_id) {781        DefKind::Static { .. } => {782            tcx.ensure_ok().generics_of(def_id);783            tcx.ensure_ok().type_of(def_id);784            tcx.ensure_ok().predicates_of(def_id);785786            check_static_inhabited(tcx, def_id);787            check_static_linkage(tcx, def_id);788            let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();789            res = res.and(wfcheck::check_static_item(790                tcx, def_id, ty, /* should_check_for_sync */ true,791            ));792793            // Only `Node::Item` and `Node::ForeignItem` still have HIR based794            // checks. Returning early here does not miss any checks and795            // avoids this query from having a direct dependency edge on the HIR796            return res;797        }798        DefKind::Enum => {799            tcx.ensure_ok().generics_of(def_id);800            tcx.ensure_ok().type_of(def_id);801            tcx.ensure_ok().predicates_of(def_id);802            crate::collect::lower_enum_variant_types(tcx, def_id);803            check_enum(tcx, def_id);804            check_variances_for_type_defn(tcx, def_id);805        }806        DefKind::Fn => {807            tcx.ensure_ok().generics_of(def_id);808            tcx.ensure_ok().type_of(def_id);809            tcx.ensure_ok().predicates_of(def_id);810            tcx.ensure_ok().fn_sig(def_id);811            tcx.ensure_ok().codegen_fn_attrs(def_id);812            if let Some(i) = tcx.intrinsic(def_id) {813                intrinsic::check_intrinsic_type(814                    tcx,815                    def_id,816                    tcx.def_ident_span(def_id).unwrap(),817                    i.name,818                )819            }820        }821        DefKind::Impl { of_trait } => {822            tcx.ensure_ok().generics_of(def_id);823            tcx.ensure_ok().type_of(def_id);824            tcx.ensure_ok().predicates_of(def_id);825            tcx.ensure_ok().associated_items(def_id);826            if of_trait {827                let impl_trait_header = tcx.impl_trait_header(def_id);828                res = res.and(tcx.ensure_result().coherent_trait(829                    impl_trait_header.trait_ref.instantiate_identity().skip_norm_wip().def_id,830                ));831832                if res.is_ok() {833                    // Checking this only makes sense if the all trait impls satisfy basic834                    // requirements (see `coherent_trait` query), otherwise835                    // we run into infinite recursions a lot.836                    check_impl_items_against_trait(tcx, def_id, impl_trait_header);837                }838            }839        }840        DefKind::Trait => {841            tcx.ensure_ok().generics_of(def_id);842            tcx.ensure_ok().trait_def(def_id);843            tcx.ensure_ok().explicit_super_predicates_of(def_id);844            tcx.ensure_ok().predicates_of(def_id);845            tcx.ensure_ok().associated_items(def_id);846            let assoc_items = tcx.associated_items(def_id);847848            for &assoc_item in assoc_items.in_definition_order() {849                match assoc_item.kind {850                    ty::AssocKind::Type { .. } if assoc_item.defaultness(tcx).has_value() => {851                        let trait_args = GenericArgs::identity_for_item(tcx, def_id);852                        let _: Result<_, rustc_errors::ErrorGuaranteed> = check_type_bounds(853                            tcx,854                            assoc_item,855                            assoc_item,856                            ty::TraitRef::new_from_args(tcx, def_id.to_def_id(), trait_args),857                        );858                    }859                    _ => {}860                }861            }862        }863        DefKind::TraitAlias => {864            tcx.ensure_ok().generics_of(def_id);865            tcx.ensure_ok().explicit_implied_predicates_of(def_id);866            tcx.ensure_ok().explicit_super_predicates_of(def_id);867            tcx.ensure_ok().predicates_of(def_id);868        }869        def_kind @ (DefKind::Struct | DefKind::Union) => {870            tcx.ensure_ok().generics_of(def_id);871            tcx.ensure_ok().type_of(def_id);872            tcx.ensure_ok().predicates_of(def_id);873874            let adt = tcx.adt_def(def_id).non_enum_variant();875            for f in adt.fields.iter() {876                tcx.ensure_ok().generics_of(f.did);877                tcx.ensure_ok().type_of(f.did);878                tcx.ensure_ok().predicates_of(f.did);879            }880881            if let Some((_, ctor_def_id)) = adt.ctor {882                crate::collect::lower_variant_ctor(tcx, ctor_def_id.expect_local());883            }884            match def_kind {885                DefKind::Struct => check_struct(tcx, def_id),886                DefKind::Union => check_union(tcx, def_id),887                _ => unreachable!(),888            }889            check_variances_for_type_defn(tcx, def_id);890        }891        DefKind::OpaqueTy => {892            check_opaque_precise_captures(tcx, def_id);893894            let origin = tcx.local_opaque_ty_origin(def_id);895            if let hir::OpaqueTyOrigin::FnReturn { parent: fn_def_id, .. }896            | hir::OpaqueTyOrigin::AsyncFn { parent: fn_def_id, .. } = origin897                && let hir::Node::TraitItem(trait_item) = tcx.hir_node_by_def_id(fn_def_id)898                && let (_, hir::TraitFn::Required(..)) = trait_item.expect_fn()899            {900                // Skip opaques from RPIT in traits with no default body.901            } else {902                check_opaque(tcx, def_id);903            }904905            tcx.ensure_ok().predicates_of(def_id);906            tcx.ensure_ok().explicit_item_bounds(def_id);907            tcx.ensure_ok().explicit_item_self_bounds(def_id);908            if tcx.is_conditionally_const(def_id) {909                tcx.ensure_ok().explicit_implied_const_bounds(def_id);910                tcx.ensure_ok().const_conditions(def_id);911            }912913            // Only `Node::Item` and `Node::ForeignItem` still have HIR based914            // checks. Returning early here does not miss any checks and915            // avoids this query from having a direct dependency edge on the HIR916            return res;917        }918        DefKind::Const { .. } => {919            tcx.ensure_ok().generics_of(def_id);920            tcx.ensure_ok().type_of(def_id);921            tcx.ensure_ok().predicates_of(def_id);922923            res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {924                let ty = tcx.type_of(def_id).instantiate_identity();925                let ty_span = tcx.ty_span(def_id);926                let ty = wfcx.deeply_normalize(ty_span, Some(WellFormedLoc::Ty(def_id)), ty);927                wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(def_id)), ty.into());928                wfcx.register_bound(929                    traits::ObligationCause::new(930                        ty_span,931                        def_id,932                        ObligationCauseCode::SizedConstOrStatic,933                    ),934                    tcx.param_env(def_id),935                    ty,936                    tcx.require_lang_item(LangItem::Sized, ty_span),937                );938                check_where_clauses(wfcx, def_id);939940                if tcx.is_type_const(def_id) {941                    wfcheck::check_type_const(wfcx, def_id, ty, true)?;942                }943                Ok(())944            }));945946            // Only `Node::Item` and `Node::ForeignItem` still have HIR based947            // checks. Returning early here does not miss any checks and948            // avoids this query from having a direct dependency edge on the HIR949            return res;950        }951        DefKind::TyAlias => {952            tcx.ensure_ok().generics_of(def_id);953            tcx.ensure_ok().type_of(def_id);954            tcx.ensure_ok().predicates_of(def_id);955            check_type_alias_type_params_are_used(tcx, def_id);956            let ty = tcx.type_of(def_id).instantiate_identity();957            let span = tcx.def_span(def_id);958            if tcx.type_alias_is_lazy(def_id) {959                res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {960                    let item_ty = wfcx.deeply_normalize(span, Some(WellFormedLoc::Ty(def_id)), ty);961                    wfcx.register_wf_obligation(962                        span,963                        Some(WellFormedLoc::Ty(def_id)),964                        item_ty.into(),965                    );966                    check_where_clauses(wfcx, def_id);967                    Ok(())968                }));969                check_variances_for_type_defn(tcx, def_id);970            } else {971                res = res.and(enter_wf_checking_ctxt(tcx, def_id, |wfcx| {972                    // HACK: We sometimes incidentally check that const arguments have the correct973                    // type as a side effect of the anon const desugaring. To make this "consistent"974                    // for users we explicitly check `ConstArgHasType` clauses so that const args975                    // that don't go through an anon const still have their types checked.976                    //977                    // We use the unnormalized type as this mirrors the behaviour that we previously978                    // would have had when all const arguments were anon consts.979                    //980                    // Changing this to normalized obligations is a breaking change:981                    // `type Bar = [(); panic!()];` would become an error982                    if let Some(unnormalized_obligations) = wfcx.unnormalized_obligations(span, ty.skip_norm_wip())983                    {984                        let filtered_obligations =985                            unnormalized_obligations.into_iter().filter(|o| {986                                matches!(o.predicate.kind().skip_binder(),987                                    ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _))988                                    if matches!(ct.kind(), ty::ConstKind::Param(..)))989                            });990                        wfcx.ocx.register_obligations(filtered_obligations)991                    }992                    Ok(())993                }));994            }995996            // Only `Node::Item` and `Node::ForeignItem` still have HIR based997            // checks. Returning early here does not miss any checks and998            // avoids this query from having a direct dependency edge on the HIR999            return res;1000        }1001        DefKind::ForeignMod => {1002            let it = tcx.hir_expect_item(def_id);1003            let hir::ItemKind::ForeignMod { abi, items } = it.kind else {1004                return Ok(());1005            };10061007            check_abi(tcx, it.hir_id(), it.span, abi);10081009            for &item in items {1010                let def_id = item.owner_id.def_id;10111012                let generics = tcx.generics_of(def_id);1013                let own_counts = generics.own_counts();1014                if generics.own_params.len() - own_counts.lifetimes != 0 {1015                    let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {1016                        (_, 0) => ("type", "types", Some("u32")),1017                        // We don't specify an example value, because we can't generate1018                        // a valid value for any type.1019                        (0, _) => ("const", "consts", None),1020                        _ => ("type or const", "types or consts", None),1021                    };1022                    let name = if find_attr!(tcx, def_id, RustcEiiForeignItem) {1023                        "externally implementable items"1024                    } else {1025                        "foreign items"1026                    };10271028                    let span = tcx.def_span(def_id);1029                    struct_span_code_err!(1030                        tcx.dcx(),1031                        span,1032                        E0044,1033                        "{name} may not have {kinds} parameters",1034                    )1035                    .with_span_label(span, format!("can't have {kinds} parameters"))1036                    .with_help(1037                        // FIXME: once we start storing spans for type arguments, turn this1038                        // into a suggestion.1039                        format!(1040                            "replace the {} parameters with concrete {}{}",1041                            kinds,1042                            kinds_pl,1043                            egs.map(|egs| format!(" like `{egs}`")).unwrap_or_default(),1044                        ),1045                    )1046                    .emit();1047                }10481049                tcx.ensure_ok().generics_of(def_id);1050                tcx.ensure_ok().type_of(def_id);1051                tcx.ensure_ok().predicates_of(def_id);1052                if tcx.is_conditionally_const(def_id) {1053                    tcx.ensure_ok().explicit_implied_const_bounds(def_id);1054                    tcx.ensure_ok().const_conditions(def_id);1055                }1056                match tcx.def_kind(def_id) {1057                    DefKind::Fn => {1058                        tcx.ensure_ok().codegen_fn_attrs(def_id);1059                        tcx.ensure_ok().fn_sig(def_id);1060                        let item = tcx.hir_foreign_item(item);1061                        let hir::ForeignItemKind::Fn(sig, ..) = item.kind else { bug!() };1062                        check_c_variadic_abi(tcx, sig.decl, abi, item.span);1063                    }1064                    DefKind::Static { .. } => {1065                        tcx.ensure_ok().codegen_fn_attrs(def_id);1066                    }1067                    _ => (),1068                }1069            }1070        }1071        DefKind::Closure => {1072            // This is guaranteed to be called by metadata encoding,1073            // we still call it in wfcheck eagerly to ensure errors in codegen1074            // attrs prevent lints from spamming the output.1075            tcx.ensure_ok().codegen_fn_attrs(def_id);1076            // We do not call `type_of` for closures here as that1077            // depends on typecheck and would therefore hide1078            // any further errors in case one typeck fails.10791080            // Only `Node::Item` and `Node::ForeignItem` still have HIR based1081            // checks. Returning early here does not miss any checks and1082            // avoids this query from having a direct dependency edge on the HIR1083            return res;1084        }1085        DefKind::AssocFn => {1086            tcx.ensure_ok().codegen_fn_attrs(def_id);1087            tcx.ensure_ok().type_of(def_id);1088            tcx.ensure_ok().fn_sig(def_id);1089            tcx.ensure_ok().predicates_of(def_id);1090            res = res.and(check_associated_item(tcx, def_id));1091            let assoc_item = tcx.associated_item(def_id);1092            match assoc_item.container {1093                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {}1094                ty::AssocContainer::Trait => {1095                    res = res.and(check_trait_item(tcx, def_id));1096                }1097            }10981099            // Only `Node::Item` and `Node::ForeignItem` still have HIR based1100            // checks. Returning early here does not miss any checks and1101            // avoids this query from having a direct dependency edge on the HIR1102            return res;1103        }1104        DefKind::AssocConst { .. } => {1105            tcx.ensure_ok().type_of(def_id);1106            tcx.ensure_ok().predicates_of(def_id);1107            res = res.and(check_associated_item(tcx, def_id));1108            let assoc_item = tcx.associated_item(def_id);1109            match assoc_item.container {1110                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => {}1111                ty::AssocContainer::Trait => {1112                    res = res.and(check_trait_item(tcx, def_id));1113                }1114            }11151116            // Only `Node::Item` and `Node::ForeignItem` still have HIR based1117            // checks. Returning early here does not miss any checks and1118            // avoids this query from having a direct dependency edge on the HIR1119            return res;1120        }1121        DefKind::AssocTy => {1122            tcx.ensure_ok().predicates_of(def_id);1123            res = res.and(check_associated_item(tcx, def_id));11241125            let assoc_item = tcx.associated_item(def_id);1126            let has_type = match assoc_item.container {1127                ty::AssocContainer::InherentImpl | ty::AssocContainer::TraitImpl(_) => true,1128                ty::AssocContainer::Trait => {1129                    tcx.ensure_ok().explicit_item_bounds(def_id);1130                    tcx.ensure_ok().explicit_item_self_bounds(def_id);1131                    if tcx.is_conditionally_const(def_id) {1132                        tcx.ensure_ok().explicit_implied_const_bounds(def_id);1133                        tcx.ensure_ok().const_conditions(def_id);1134                    }1135                    res = res.and(check_trait_item(tcx, def_id));1136                    assoc_item.defaultness(tcx).has_value()1137                }1138            };1139            if has_type {1140                tcx.ensure_ok().type_of(def_id);1141            }11421143            // Only `Node::Item` and `Node::ForeignItem` still have HIR based1144            // checks. Returning early here does not miss any checks and1145            // avoids this query from having a direct dependency edge on the HIR1146            return res;1147        }11481149        // Only `Node::Item` and `Node::ForeignItem` still have HIR based1150        // checks. Returning early here does not miss any checks and1151        // avoids this query from having a direct dependency edge on the HIR1152        DefKind::AnonConst | DefKind::InlineConst => return res,1153        _ => {}1154    }1155    let node = tcx.hir_node_by_def_id(def_id);1156    res.and(match node {1157        hir::Node::Crate(_) => bug!("check_well_formed cannot be applied to the crate root"),1158        hir::Node::Item(item) => wfcheck::check_item(tcx, item),1159        hir::Node::ForeignItem(item) => wfcheck::check_foreign_item(tcx, item),1160        _ => unreachable!("{node:?}"),1161    })1162}11631164pub(super) fn check_specialization_validity<'tcx>(1165    tcx: TyCtxt<'tcx>,1166    trait_def: &ty::TraitDef,1167    trait_item: ty::AssocItem,1168    impl_id: DefId,1169    impl_item: DefId,1170) {1171    let Ok(ancestors) = trait_def.ancestors(tcx, impl_id) else { return };1172    let mut ancestor_impls = ancestors.skip(1).filter_map(|parent| {1173        if parent.is_from_trait() {1174            None1175        } else {1176            Some((parent, parent.item(tcx, trait_item.def_id)))1177        }1178    });11791180    let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| {1181        match parent_item {1182            // Parent impl exists, and contains the parent item we're trying to specialize, but1183            // doesn't mark it `default`.1184            Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => {1185                Some(Err(parent_impl.def_id()))1186            }11871188            // Parent impl contains item and makes it specializable.1189            Some(_) => Some(Ok(())),11901191            // Parent impl doesn't mention the item. This means it's inherited from the1192            // grandparent. In that case, if parent is a `default impl`, inherited items use the1193            // "defaultness" from the grandparent, else they are final.1194            None => {1195                if tcx.defaultness(parent_impl.def_id()).is_default() {1196                    None1197                } else {1198                    Some(Err(parent_impl.def_id()))1199                }1200            }1201        }1202    });12031204    // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the1205    // item. This is allowed, the item isn't actually getting specialized here.1206    let result = opt_result.unwrap_or(Ok(()));12071208    if let Err(parent_impl) = result {1209        if !tcx.is_impl_trait_in_trait(impl_item) {1210            let span = tcx.def_span(impl_item);1211            let ident = tcx.item_ident(impl_item);12121213            let err = match tcx.span_of_impl(parent_impl) {1214                Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },1215                Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },1216            };12171218            tcx.dcx().emit_err(err);1219        } else {1220            tcx.dcx().delayed_bug(format!("parent item: {parent_impl:?} not marked as default"));1221        }1222    }1223}12241225fn check_overriding_final_trait_item<'tcx>(1226    tcx: TyCtxt<'tcx>,1227    trait_item: ty::AssocItem,1228    impl_item: ty::AssocItem,1229) {1230    if trait_item.defaultness(tcx).is_final() {1231        tcx.dcx().emit_err(errors::OverridingFinalTraitFunction {1232            impl_span: tcx.def_span(impl_item.def_id),1233            trait_span: tcx.def_span(trait_item.def_id),1234            ident: tcx.item_ident(impl_item.def_id),1235        });1236    }1237}12381239fn check_impl_items_against_trait<'tcx>(1240    tcx: TyCtxt<'tcx>,1241    impl_id: LocalDefId,1242    impl_trait_header: ty::ImplTraitHeader<'tcx>,1243) {1244    let trait_ref = impl_trait_header.trait_ref.instantiate_identity().skip_norm_wip();1245    // If the trait reference itself is erroneous (so the compilation is going1246    // to fail), skip checking the items here -- the `impl_item` table in `tcx`1247    // isn't populated for such impls.1248    if trait_ref.references_error() {1249        return;1250    }12511252    let impl_item_refs = tcx.associated_item_def_ids(impl_id);12531254    // Negative impls are not expected to have any items1255    match impl_trait_header.polarity {1256        ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {}1257        ty::ImplPolarity::Negative => {1258            if let [first_item_ref, ..] = *impl_item_refs {1259                let first_item_span = tcx.def_span(first_item_ref);1260                struct_span_code_err!(1261                    tcx.dcx(),1262                    first_item_span,1263                    E0749,1264                    "negative impls cannot have any items"1265                )1266                .emit();1267            }1268            return;1269        }1270    }12711272    let trait_def = tcx.trait_def(trait_ref.def_id);12731274    let self_is_guaranteed_unsize_self = tcx.impl_self_is_guaranteed_unsized(impl_id);12751276    for &impl_item in impl_item_refs {1277        let ty_impl_item = tcx.associated_item(impl_item);1278        let ty_trait_item = match ty_impl_item.expect_trait_impl() {1279            Ok(trait_item_id) => tcx.associated_item(trait_item_id),1280            Err(ErrorGuaranteed { .. }) => continue,1281        };12821283        let res = tcx.ensure_result().compare_impl_item(impl_item.expect_local());1284        if res.is_ok() {1285            match ty_impl_item.kind {1286                ty::AssocKind::Fn { .. } => {1287                    compare_impl_item::refine::check_refining_return_position_impl_trait_in_trait(1288                        tcx,1289                        ty_impl_item,1290                        ty_trait_item,1291                        tcx.impl_trait_ref(ty_impl_item.container_id(tcx))1292                            .instantiate_identity()1293                            .skip_norm_wip(),1294                    );1295                }1296                ty::AssocKind::Const { .. } => {}1297                ty::AssocKind::Type { .. } => {}1298            }1299        }13001301        if self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(ty_trait_item.def_id) {1302            tcx.emit_node_span_lint(1303                rustc_lint_defs::builtin::DEAD_CODE,1304                tcx.local_def_id_to_hir_id(ty_impl_item.def_id.expect_local()),1305                tcx.def_span(ty_impl_item.def_id),1306                errors::UselessImplItem,1307            )1308        }13091310        check_specialization_validity(1311            tcx,1312            trait_def,1313            ty_trait_item,1314            impl_id.to_def_id(),1315            impl_item,1316        );13171318        check_overriding_final_trait_item(tcx, ty_trait_item, ty_impl_item);1319    }13201321    if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) {1322        // Check for missing items from trait1323        let mut missing_items = Vec::new();13241325        let mut must_implement_one_of: Option<&[Ident]> =1326            trait_def.must_implement_one_of.as_deref();13271328        for &trait_item_id in tcx.associated_item_def_ids(trait_ref.def_id) {1329            let leaf_def = ancestors.leaf_def(tcx, trait_item_id);13301331            let is_implemented = leaf_def1332                .as_ref()1333                .is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());13341335            if !is_implemented1336                && tcx.defaultness(impl_id).is_final()1337                // unsized types don't need to implement methods that have `Self: Sized` bounds.1338                && !(self_is_guaranteed_unsize_self && tcx.generics_require_sized_self(trait_item_id))1339            {1340                missing_items.push(tcx.associated_item(trait_item_id));1341            }13421343            // true if this item is specifically implemented in this impl1344            let is_implemented_here =1345                leaf_def.as_ref().is_some_and(|node_item| !node_item.defining_node.is_from_trait());13461347            if !is_implemented_here {1348                let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id));1349                match tcx.eval_default_body_stability(trait_item_id, full_impl_span) {1350                    EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable(1351                        tcx,1352                        full_impl_span,1353                        trait_item_id,1354                        feature,1355                        reason,1356                        issue,1357                    ),13581359                    // Unmarked default bodies are considered stable (at least for now).1360                    EvalResult::Allow | EvalResult::Unmarked => {}1361                }1362            }13631364            if let Some(required_items) = &must_implement_one_of {1365                if is_implemented_here {1366                    let trait_item = tcx.associated_item(trait_item_id);1367                    if required_items.contains(&trait_item.ident(tcx)) {1368                        must_implement_one_of = None;1369                    }1370                }1371            }13721373            if let Some(leaf_def) = &leaf_def1374                && !leaf_def.is_final()1375                && let def_id = leaf_def.item.def_id1376                && tcx.impl_method_has_trait_impl_trait_tys(def_id)1377            {1378                let def_kind = tcx.def_kind(def_id);1379                let descr = tcx.def_kind_descr(def_kind, def_id);1380                let (msg, feature) = if tcx.asyncness(def_id).is_async() {1381                    (1382                        format!("async {descr} in trait cannot be specialized"),1383                        "async functions in traits",1384                    )1385                } else {1386                    (1387                        format!(1388                            "{descr} with return-position `impl Trait` in trait cannot be specialized"1389                        ),1390                        "return position `impl Trait` in traits",1391                    )1392                };1393                tcx.dcx()1394                    .struct_span_err(tcx.def_span(def_id), msg)1395                    .with_note(format!(1396                        "specialization behaves in inconsistent and surprising ways with \1397                        {feature}, and for now is disallowed"1398                    ))1399                    .emit();1400            }1401        }14021403        if !missing_items.is_empty() {1404            let full_impl_span = tcx.hir_span_with_body(tcx.local_def_id_to_hir_id(impl_id));1405            missing_items_err(tcx, impl_id, &missing_items, full_impl_span);1406        }14071408        if let Some(missing_items) = must_implement_one_of {1409            let attr_span = find_attr!(tcx, trait_ref.def_id, RustcMustImplementOneOf {attr_span, ..} => *attr_span);14101411            missing_items_must_implement_one_of_err(1412                tcx,1413                tcx.def_span(impl_id),1414                missing_items,1415                attr_span,1416            );1417        }1418    }1419}14201421fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) {1422    let t = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();1423    if let ty::Adt(def, args) = t.kind()1424        && def.is_struct()1425    {1426        let fields = &def.non_enum_variant().fields;1427        if fields.is_empty() {1428            struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();1429            return;1430        }14311432        let array_field = &fields[FieldIdx::ZERO];1433        let array_ty = array_field.ty(tcx, args);1434        let ty::Array(element_ty, len_const) = array_ty.kind() else {1435            struct_span_code_err!(1436                tcx.dcx(),1437                sp,1438                E0076,1439                "SIMD vector's only field must be an array"1440            )1441            .with_span_label(tcx.def_span(array_field.did), "not an array")1442            .emit();1443            return;1444        };14451446        if let Some(second_field) = fields.get(FieldIdx::ONE) {1447            struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot have multiple fields")1448                .with_span_label(tcx.def_span(second_field.did), "excess field")1449                .emit();1450            return;1451        }14521453        // FIXME(repr_simd): This check is nice, but perhaps unnecessary due to the fact1454        // we do not expect users to implement their own `repr(simd)` types. If they could,1455        // this check is easily side-steppable by hiding the const behind normalization.1456        // The consequence is that the error is, in general, only observable post-mono.1457        if let Some(len) = len_const.try_to_target_usize(tcx) {1458            if len == 0 {1459                struct_span_code_err!(tcx.dcx(), sp, E0075, "SIMD vector cannot be empty").emit();1460                return;1461            } else if len > MAX_SIMD_LANES {1462                struct_span_code_err!(1463                    tcx.dcx(),1464                    sp,1465                    E0075,1466                    "SIMD vector cannot have more than {MAX_SIMD_LANES} elements",1467                )1468                .emit();1469                return;1470            }1471        }14721473        // Check that we use types valid for use in the lanes of a SIMD "vector register"1474        // These are scalar types which directly match a "machine" type1475        // Yes: Integers, floats, "thin" pointers1476        // No: char, "wide" pointers, compound types1477        match element_ty.kind() {1478            ty::Param(_) => (), // pass struct<T>([T; 4]) through, let monomorphization catch errors1479            ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::RawPtr(_, _) => (), // struct([u8; 4]) is ok1480            _ => {1481                struct_span_code_err!(1482                    tcx.dcx(),1483                    sp,1484                    E0077,1485                    "SIMD vector element type should be a \1486                        primitive scalar (integer/float/pointer) type"1487                )1488                .emit();1489                return;1490            }1491        }1492    }1493}14941495#[tracing::instrument(skip(tcx), level = "debug")]1496fn check_scalable_vector(tcx: TyCtxt<'_>, span: Span, def_id: LocalDefId, scalable: ScalableElt) {1497    let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip();1498    let ty::Adt(def, args) = ty.kind() else { return };1499    if !def.is_struct() {1500        tcx.dcx().delayed_bug("`rustc_scalable_vector` applied to non-struct");1501        return;1502    }15031504    let fields = &def.non_enum_variant().fields;1505    match scalable {1506        ScalableElt::ElementCount(..) if fields.is_empty() => {1507            let mut err =1508                tcx.dcx().struct_span_err(span, "scalable vectors must have a single field");1509            err.help("scalable vector types' only field must be a primitive scalar type");1510            err.emit();1511            return;1512        }1513        ScalableElt::ElementCount(..) if fields.len() >= 2 => {1514            tcx.dcx().struct_span_err(span, "scalable vectors cannot have multiple fields").emit();1515            return;1516        }1517        ScalableElt::Container if fields.is_empty() => {1518            let mut err = tcx1519                .dcx()1520                .struct_span_err(span, "scalable vector tuples must have at least one field");1521            err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type");1522            err.emit();1523            return;1524        }1525        ScalableElt::Container if fields.len() > 8 => {1526            let mut err = tcx1527                .dcx()1528                .struct_span_err(span, "scalable vector tuples can have at most eight fields");1529            err.help("tuples of scalable vectors can only contain multiple of the same scalable vector type");1530            err.emit();1531            return;1532        }1533        _ => {}1534    }15351536    match scalable {1537        ScalableElt::ElementCount(..) => {1538            let element_ty = &fields[FieldIdx::ZERO].ty(tcx, args);15391540            // Check that `element_ty` only uses types valid in the lanes of a scalable vector1541            // register: scalar types which directly match a "machine" type - integers, floats and1542            // bools1543            match element_ty.kind() {1544                ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Bool => (),1545                _ => {1546                    let mut err = tcx.dcx().struct_span_err(1547                        span,1548                        "element type of a scalable vector must be a primitive scalar",1549                    );1550                    err.help("only `u*`, `i*`, `f*` and `bool` types are accepted");1551                    err.emit();1552                }1553            }1554        }1555        ScalableElt::Container => {1556            let mut prev_field_ty = None;1557            for field in fields.iter() {1558                let element_ty = field.ty(tcx, args);1559                if let ty::Adt(def, _) = element_ty.kind()1560                    && def.repr().scalable()1561                {1562                    match def1563                        .repr()1564                        .scalable1565                        .expect("`repr().scalable.is_some()` != `repr().scalable()`")1566                    {1567                        ScalableElt::ElementCount(_) => { /* expected field */ }1568                        ScalableElt::Container => {1569                            tcx.dcx().span_err(1570                                tcx.def_span(field.did),1571                                "scalable vector structs cannot contain other scalable vector structs",1572                            );1573                            break;1574                        }1575                    }1576                } else {1577                    tcx.dcx().span_err(1578                        tcx.def_span(field.did),1579                        "scalable vector structs can only have scalable vector fields",1580                    );1581                    break;1582                }15831584                if let Some(prev_ty) = prev_field_ty.replace(element_ty)1585                    && prev_ty != element_ty1586                {1587                    tcx.dcx().span_err(1588                        tcx.def_span(field.did),1589                        "all fields in a scalable vector struct must be the same type",1590                    );1591                    break;1592                }1593            }1594        }1595    }1596}15971598pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {1599    let repr = def.repr();1600    if repr.packed() {1601        if let Some(reprs) = find_attr!(tcx, def.did(), Repr { reprs, .. } => reprs) {1602            for (r, _) in reprs {1603                if let ReprPacked(pack) = r1604                    && let Some(repr_pack) = repr.pack1605                    && pack != &repr_pack1606                {1607                    struct_span_code_err!(1608                        tcx.dcx(),1609                        sp,1610                        E0634,1611                        "type has conflicting packed representation hints"1612                    )1613                    .emit();1614                }1615            }1616        }1617        if repr.align.is_some() {1618            struct_span_code_err!(1619                tcx.dcx(),1620                sp,1621                E0587,1622                "type has conflicting packed and align representation hints"1623            )1624            .emit();1625        } else if let Some(def_spans) = check_packed_inner(tcx, def.did(), &mut vec![]) {1626            let mut err = struct_span_code_err!(1627                tcx.dcx(),1628                sp,1629                E0588,1630                "packed type cannot transitively contain a `#[repr(align)]` type"1631            );16321633            err.span_note(1634                tcx.def_span(def_spans[0].0),1635                format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)),1636            );16371638            if def_spans.len() > 2 {1639                let mut first = true;1640                for (adt_def, span) in def_spans.iter().skip(1).rev() {1641                    let ident = tcx.item_name(*adt_def);1642                    err.span_note(1643                        *span,1644                        if first {1645                            format!(1646                                "`{}` contains a field of type `{}`",1647                                tcx.type_of(def.did()).instantiate_identity().skip_norm_wip(),1648                                ident1649                            )1650                        } else {1651                            format!("...which contains a field of type `{ident}`")1652                        },1653                    );1654                    first = false;1655                }1656            }16571658            err.emit();1659        }1660    }1661}16621663pub(super) fn check_packed_inner(1664    tcx: TyCtxt<'_>,1665    def_id: DefId,1666    stack: &mut Vec<DefId>,1667) -> Option<Vec<(DefId, Span)>> {1668    if let ty::Adt(def, args) = tcx.type_of(def_id).instantiate_identity().skip_norm_wip().kind() {1669        if def.is_struct() || def.is_union() {1670            if def.repr().align.is_some() {1671                return Some(vec![(def.did(), DUMMY_SP)]);1672            }16731674            stack.push(def_id);1675            for field in &def.non_enum_variant().fields {1676                if let ty::Adt(def, _) = field.ty(tcx, args).kind()1677                    && !stack.contains(&def.did())1678                    && let Some(mut defs) = check_packed_inner(tcx, def.did(), stack)1679                {1680                    defs.push((def.did(), field.ident(tcx).span));1681                    return Some(defs);1682                }1683            }1684            stack.pop();1685        }1686    }16871688    None1689}16901691pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {1692    struct ZeroSizedFieldReprTransparentIncompatibility<'tcx> {1693        unsuited: UnsuitedInfo<'tcx>,1694    }16951696    impl<'a, 'tcx> Diagnostic<'a, ()> for ZeroSizedFieldReprTransparentIncompatibility<'tcx> {1697        fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {1698            let Self { unsuited } = self;1699            let (title, note) = match unsuited.reason {1700                UnsuitedReason::NonExhaustive => (1701                    "external non-exhaustive types",1702                    "is marked with `#[non_exhaustive]`, so it could become non-zero-sized in the future.",1703                ),1704                UnsuitedReason::PrivateField => (1705                    "external types with private fields",1706                    "contains private fields, so it could become non-zero-sized in the future.",1707                ),1708                UnsuitedReason::ReprC => (1709                    "`repr(C)` types",1710                    "is a `#[repr(C)]` type, so it is not guaranteed to be zero-sized on all targets.",1711                ),1712            };1713            Diag::new(1714                dcx,1715                level,1716                format!("zero-sized fields in `repr(transparent)` cannot contain {title}"),1717            )1718            .with_note(format!(1719                "this field contains `{field_ty}`, which {note}",1720                field_ty = unsuited.ty,1721            ))1722        }1723    }17241725    if !adt.repr().transparent() {1726        return;1727    }17281729    if adt.is_union() && !tcx.features().transparent_unions() {1730        feature_err(1731            &tcx.sess,1732            sym::transparent_unions,1733            tcx.def_span(adt.did()),1734            "transparent unions are unstable",1735        )1736        .emit();1737    }17381739    if adt.variants().len() != 1 {1740        bad_variant_count(tcx, adt, tcx.def_span(adt.did()), adt.did());1741        // Don't bother checking the fields.1742        return;1743    }17441745    let typing_env = ty::TypingEnv::non_body_analysis(tcx, adt.did());1746    // For each field, figure out if it has "trivial" layout (i.e., is a 1-ZST).1747    struct FieldInfo<'tcx> {1748        span: Span,1749        trivial: bool,1750        ty: Ty<'tcx>,1751    }17521753    let field_infos = adt.all_fields().map(|field| {1754        let ty = field.ty(tcx, GenericArgs::identity_for_item(tcx, field.did));1755        let layout = tcx.layout_of(typing_env.as_query_input(ty));1756        // We are currently checking the type this field came from, so it must be local1757        let span = tcx.hir_span_if_local(field.did).unwrap();1758        let trivial = layout.is_ok_and(|layout| layout.is_1zst());1759        FieldInfo { span, trivial, ty }1760    });17611762    let non_trivial_fields = field_infos1763        .clone()1764        .filter_map(|field| if !field.trivial { Some(field.span) } else { None });1765    let non_trivial_count = non_trivial_fields.clone().count();1766    if non_trivial_count >= 2 {1767        bad_non_zero_sized_fields(1768            tcx,1769            adt,1770            non_trivial_count,1771            non_trivial_fields,1772            tcx.def_span(adt.did()),1773        );1774        return;1775    }17761777    // Even some 1-ZST fields are not allowed though, if they have `non_exhaustive` or private1778    // fields or `repr(C)`. We call those fields "unsuited".1779    struct UnsuitedInfo<'tcx> {1780        /// The source of the problem, a type that is found somewhere within the field type.1781        ty: Ty<'tcx>,1782        reason: UnsuitedReason,1783    }1784    enum UnsuitedReason {1785        NonExhaustive,1786        PrivateField,1787        ReprC,1788    }17891790    fn check_unsuited<'tcx>(1791        tcx: TyCtxt<'tcx>,1792        typing_env: ty::TypingEnv<'tcx>,1793        ty: Ty<'tcx>,1794    ) -> ControlFlow<UnsuitedInfo<'tcx>> {1795        // We can encounter projections during traversal, so ensure the type is normalized.1796        let ty =1797            tcx.try_normalize_erasing_regions(typing_env, Unnormalized::new_wip(ty)).unwrap_or(ty);1798        match ty.kind() {1799            ty::Tuple(list) => list.iter().try_for_each(|t| check_unsuited(tcx, typing_env, t)),1800            ty::Array(ty, _) => check_unsuited(tcx, typing_env, *ty),1801            ty::Adt(def, args) => {1802                if !def.did().is_local() && !find_attr!(tcx, def.did(), RustcPubTransparent(_)) {1803                    let non_exhaustive = def.is_variant_list_non_exhaustive()1804                        || def.variants().iter().any(ty::VariantDef::is_field_list_non_exhaustive);1805                    let has_priv = def.all_fields().any(|f| !f.vis.is_public());1806                    if non_exhaustive || has_priv {1807                        return ControlFlow::Break(UnsuitedInfo {1808                            ty,1809                            reason: if non_exhaustive {1810                                UnsuitedReason::NonExhaustive1811                            } else {1812                                UnsuitedReason::PrivateField1813                            },1814                        });1815                    }1816                }1817                if def.repr().c() {1818                    return ControlFlow::Break(UnsuitedInfo { ty, reason: UnsuitedReason::ReprC });1819                }1820                def.all_fields()1821                    .map(|field| field.ty(tcx, args))1822                    .try_for_each(|t| check_unsuited(tcx, typing_env, t))1823            }1824            _ => ControlFlow::Continue(()),1825        }1826    }18271828    let mut prev_unsuited_1zst = false;1829    for field in field_infos {1830        if field.trivial1831            && let Some(unsuited) = check_unsuited(tcx, typing_env, field.ty).break_value()1832        {1833            // If there are any non-trivial fields, then there can be no non-exhaustive 1-zsts.1834            // Otherwise, it's only an issue if there's >1 non-exhaustive 1-zst.1835            if non_trivial_count > 0 || prev_unsuited_1zst {1836                tcx.emit_node_span_lint(1837                    REPR_TRANSPARENT_NON_ZST_FIELDS,1838                    tcx.local_def_id_to_hir_id(adt.did().expect_local()),1839                    field.span,1840                    ZeroSizedFieldReprTransparentIncompatibility { unsuited },1841                );1842            } else {1843                prev_unsuited_1zst = true;1844            }1845        }1846    }1847}18481849#[allow(trivial_numeric_casts)]1850fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) {1851    let def = tcx.adt_def(def_id);1852    def.destructor(tcx); // force the destructor to be evaluated18531854    if def.variants().is_empty() {1855        find_attr!(tcx, def_id, Repr { reprs, first_span } => {1856            struct_span_code_err!(1857                tcx.dcx(),1858                reprs.first().map(|repr| repr.1).unwrap_or(*first_span),1859                E0084,1860                "unsupported representation for zero-variant enum"1861            )1862            .with_span_label(tcx.def_span(def_id), "zero-variant enum")1863            .emit();1864        });1865    }18661867    for v in def.variants() {1868        if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr {1869            tcx.ensure_ok().typeck(discr_def_id.expect_local());1870        }1871    }18721873    if def.repr().int.is_none() {1874        let is_unit = |var: &ty::VariantDef| matches!(var.ctor_kind(), Some(CtorKind::Const));1875        let get_disr = |var: &ty::VariantDef| match var.discr {1876            ty::VariantDiscr::Explicit(disr) => Some(disr),1877            ty::VariantDiscr::Relative(_) => None,1878        };18791880        let non_unit = def.variants().iter().find(|var| !is_unit(var));1881        let disr_unit =1882            def.variants().iter().filter(|var| is_unit(var)).find_map(|var| get_disr(var));1883        let disr_non_unit =1884            def.variants().iter().filter(|var| !is_unit(var)).find_map(|var| get_disr(var));18851886        if disr_non_unit.is_some() || (disr_unit.is_some() && non_unit.is_some()) {1887            let mut err = struct_span_code_err!(1888                tcx.dcx(),1889                tcx.def_span(def_id),1890                E0732,1891                "`#[repr(inttype)]` must be specified for enums with explicit discriminants and non-unit variants"1892            );1893            if let Some(disr_non_unit) = disr_non_unit {1894                err.span_label(1895                    tcx.def_span(disr_non_unit),1896                    "explicit discriminant on non-unit variant specified here",1897                );1898            } else {1899                err.span_label(1900                    tcx.def_span(disr_unit.unwrap()),1901                    "explicit discriminant specified here",1902                );1903                err.span_label(1904                    tcx.def_span(non_unit.unwrap().def_id),1905                    "non-unit discriminant declared here",1906                );1907            }1908            err.emit();1909        }1910    }19111912    detect_discriminant_duplicate(tcx, def);1913    check_transparent(tcx, def);1914}19151916/// Part of enum check. Given the discriminants of an enum, errors if two or more discriminants are equal1917fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) {1918    // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate.1919    // Here `idx` refers to the order of which the discriminant appears, and its index in `vs`1920    let report = |dis: Discr<'tcx>, idx, err: &mut Diag<'_>| {1921        let var = adt.variant(idx); // HIR for the duplicate discriminant1922        let (span, display_discr) = match var.discr {1923            ty::VariantDiscr::Explicit(discr_def_id) => {1924                // In the case the discriminant is both a duplicate and overflowed, let the user know1925                if let hir::Node::AnonConst(expr) =1926                    tcx.hir_node_by_def_id(discr_def_id.expect_local())1927                    && let hir::ExprKind::Lit(lit) = &tcx.hir_body(expr.body).value.kind1928                    && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node1929                    && *lit_value != dis.val1930                {1931                    (tcx.def_span(discr_def_id), format!("`{dis}` (overflowed from `{lit_value}`)"))1932                } else {1933                    // Otherwise, format the value as-is1934                    (tcx.def_span(discr_def_id), format!("`{dis}`"))1935                }1936            }1937            // This should not happen.1938            ty::VariantDiscr::Relative(0) => (tcx.def_span(var.def_id), format!("`{dis}`")),1939            ty::VariantDiscr::Relative(distance_to_explicit) => {1940                // At this point we know this discriminant is a duplicate, and was not explicitly1941                // assigned by the user. Here we iterate backwards to fetch the HIR for the last1942                // explicitly assigned discriminant, and letting the user know that this was the1943                // increment startpoint, and how many steps from there leading to the duplicate1944                if let Some(explicit_idx) =1945                    idx.as_u32().checked_sub(distance_to_explicit).map(VariantIdx::from_u32)1946                {1947                    let explicit_variant = adt.variant(explicit_idx);1948                    let ve_ident = var.name;1949                    let ex_ident = explicit_variant.name;1950                    let sp = if distance_to_explicit > 1 { "variants" } else { "variant" };19511952                    err.span_label(1953                        tcx.def_span(explicit_variant.def_id),1954                        format!(1955                            "discriminant for `{ve_ident}` incremented from this startpoint \1956                            (`{ex_ident}` + {distance_to_explicit} {sp} later \1957                             => `{ve_ident}` = {dis})"1958                        ),1959                    );1960                }19611962                (tcx.def_span(var.def_id), format!("`{dis}`"))1963            }1964        };19651966        err.span_label(span, format!("{display_discr} assigned here"));1967    };19681969    let mut discrs = adt.discriminants(tcx).collect::<Vec<_>>();19701971    // Here we loop through the discriminants, comparing each discriminant to another.1972    // When a duplicate is detected, we instantiate an error and point to both1973    // initial and duplicate value. The duplicate discriminant is then discarded by swapping1974    // it with the last element and decrementing the `vec.len` (which is why we have to evaluate1975    // `discrs.len()` anew every iteration, and why this could be tricky to do in a functional1976    // style as we are mutating `discrs` on the fly).1977    let mut i = 0;1978    while i < discrs.len() {1979        let var_i_idx = discrs[i].0;1980        let mut error: Option<Diag<'_, _>> = None;19811982        let mut o = i + 1;1983        while o < discrs.len() {1984            let var_o_idx = discrs[o].0;19851986            if discrs[i].1.val == discrs[o].1.val {1987                let err = error.get_or_insert_with(|| {1988                    let mut ret = struct_span_code_err!(1989                        tcx.dcx(),1990                        tcx.def_span(adt.did()),1991                        E0081,1992                        "discriminant value `{}` assigned more than once",1993                        discrs[i].1,1994                    );19951996                    report(discrs[i].1, var_i_idx, &mut ret);19971998                    ret1999                });

Code quality findings 51

Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning correctness discarded-result
let _ = check_opaque_meets_bounds(tcx, def_id, origin);
Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning correctness discarded-result
let _ = infcx.take_opaque_types();
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
variances[param.index as usize],
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
if variances[param.index as usize] == ty::Invariant {
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
let [var_one, var_two] = &adt_def.variants().raw[..] else {
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
let (([], [field]) | ([field], [])) = (&var_one.fields.raw[..], &var_two.fields.raw[..]) else {
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
tcx.def_ident_span(def_id).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
if let [first_item_ref, ..] = *impl_item_refs {
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
let array_field = &fields[FieldIdx::ZERO];
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
let element_ty = &fields[FieldIdx::ZERO].ty(tcx, args);
Warning: '.expect()' will panic with a custom message on None/Err. While better than unwrap() for debugging, prefer non-panicking error handling in production code (match, if let, ?).
warning correctness expect-usage
.expect("`repr().scalable.is_some()` != `repr().scalable()`")
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
tcx.def_span(def_spans[0].0),
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
format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)),
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
let span = tcx.hir_span_if_local(field.did).unwrap();
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
tcx.def_span(disr_unit.unwrap()),
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
tcx.def_span(non_unit.unwrap().def_id),
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
let var_i_idx = discrs[i].0;
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
let var_o_idx = discrs[o].0;
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
if discrs[i].1.val == discrs[o].1.val {
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
discrs[i].1,
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
report(discrs[i].1, var_i_idx, &mut ret);
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
report(discrs[o].1, var_o_idx, err);
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
discrs[o] = *discrs.last().unwrap();
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
discrs[o] = *discrs.last().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
err.span_label(spans[0], "this returned value is of `!` type");
Warning: Ignoring a Result or Option using 'let _ =' can hide errors or unexpected None values. Ensure the value is handled appropriately (match, if let, ?, expect) unless intentionally discarded with justification.
warning correctness discarded-result
let _ = infcx.take_opaque_types();
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 rustc_errors::codes::*;
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::*;
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 (field_span, ty_span) = match tcx.hir_get_if_local(field.did) {
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 hidden_ty = fold_regions(tcx, hidden_ty, |re, _dbi| match re.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
fold_regions(tcx, ty, |r, _| match r.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 Some(precise_capturing_args) = bounds.iter().find_map(|bound| match *bound {
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
if match tcx.type_of(def_id).instantiate_identity().skip_norm_wip().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
match assoc_item.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
match def_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 (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) {
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
res.and(match node {
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
// These are scalar types which directly match a "machine" type
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 element_ty.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
match scalable {
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
// register: scalar types which directly match a "machine" type - integers, floats and
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 element_ty.kind() {
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
stack.push(def_id);
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
defs.push((def.did(), field.ident(tcx).span));
Info: Usage of `#[allow(...)]` suppresses compiler lints. Ensure the allowance is justified, well-scoped, and ideally temporary. Overuse can hide potential issues.
info maintainability allow-lint
#[allow(trivial_numeric_casts)]
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 bounded_ty = match predicate.kind().skip_binder() {
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
let mut multispan: MultiSpan = spans.clone().into();
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 *t.kind() {
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
self.closures.push(def_id);
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, *predicate));
Performance Info: Frequent cloning, especially of Strings, Vecs, or other heap-allocated types inside loops, can be expensive. Consider using references/borrowing where possible.
info performance clone-in-loop
ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));

Get this view in your editor

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