diff --git a/src/librustc_mir/transform/generator.rs b/src/librustc_mir/transform/generator.rs index 461b13c4f638..60c040c25f97 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/src/librustc_mir/transform/generator.rs @@ -669,6 +669,51 @@ fn compute_storage_conflicts( storage_conflicts } +/// Validates the typeck view of the generator against the actual set of types retained between +/// yield points. +fn sanitize_witness<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + did: DefId, + witness: Ty<'tcx>, + upvars: &Vec>, + retained: &BitSet, +) { + let allowed_upvars = tcx.erase_regions(upvars); + let allowed = match witness.kind { + ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), + _ => { + tcx.sess.delay_span_bug( + body.span, + &format!("unexpected generator witness type {:?}", witness.kind), + ); + return; + } + }; + + let param_env = tcx.param_env(did); + + for (local, decl) in body.local_decls.iter_enumerated() { + // Ignore locals which are internal or not retained between yields. + if !retained.contains(local) || decl.internal { + continue; + } + let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty); + + // Sanity check that typeck knows about the type of locals which are + // live across a suspension point + if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) { + span_bug!( + body.span, + "Broken MIR: generator contains type {} in MIR, \ + but typeck only knows about {}", + decl.ty, + witness, + ); + } + } +} + fn compute_layout<'tcx>( tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, @@ -690,35 +735,7 @@ fn compute_layout<'tcx>( storage_liveness, } = locals_live_across_suspend_points(tcx, body, source, always_live_locals, movable); - // Erase regions from the types passed in from typeck so we can compare them with - // MIR types - let allowed_upvars = tcx.erase_regions(upvars); - let allowed = match interior.kind { - ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(&s), - _ => bug!(), - }; - - let param_env = tcx.param_env(source.def_id()); - - for (local, decl) in body.local_decls.iter_enumerated() { - // Ignore locals which are internal or not live - if !live_locals.contains(local) || decl.internal { - continue; - } - let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty); - - // Sanity check that typeck knows about the type of locals which are - // live across a suspension point - if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) { - span_bug!( - body.span, - "Broken MIR: generator contains type {} in MIR, \ - but typeck only knows about {}", - decl.ty, - interior - ); - } - } + sanitize_witness(tcx, body, source.def_id(), interior, upvars, &live_locals); // Gather live local types and their indices. let mut locals = IndexVec::::new(); diff --git a/src/librustc_ty/needs_drop.rs b/src/librustc_ty/needs_drop.rs index c54704e7877f..439bec1702ea 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/src/librustc_ty/needs_drop.rs @@ -99,7 +99,7 @@ where } } - ty::Generator(_, substs, _) => { + ty::Generator(def_id, substs, _) => { let substs = substs.as_generator(); for upvar_ty in substs.upvar_tys() { queue_type(self, upvar_ty); @@ -108,7 +108,13 @@ where let witness = substs.witness(); let interior_tys = match &witness.kind { ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), - _ => bug!(), + _ => { + tcx.sess.delay_span_bug( + tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP), + &format!("unexpected generator witness type {:?}", witness), + ); + return Some(Err(AlwaysRequiresDrop)); + } }; for interior_ty in interior_tys {