mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-14 02:49:40 +00:00
Some tweaks and comments
This commit is contained in:
parent
ffcd32cfe6
commit
bbe15522d5
@ -412,12 +412,13 @@ pub struct LocalDecl<'tcx> {
|
|||||||
pub is_user_variable: bool,
|
pub is_user_variable: bool,
|
||||||
|
|
||||||
/// True if this is an internal local.
|
/// True if this is an internal local.
|
||||||
/// Such locals are not checked against the legal types in a generator.
|
/// These locals are not based on types in the source code and are only used
|
||||||
///
|
/// for drop flags at the moment.
|
||||||
/// Scalar state variables created by optimizations (e.g. nonzeroing drop
|
/// The generator transformation will sanity check the locals which are live across
|
||||||
/// flags) should not be included in generator OIBIT computations.
|
/// a suspension point against the type components of the generator which
|
||||||
/// Therefore, we mark them as `internal` so we can ignore them when
|
/// type checking knows are live across a suspension point.
|
||||||
/// sanity-checking the OIBIT list.
|
/// We need to flag drop flags to avoid triggering this check as they are introduced
|
||||||
|
/// after typeck.
|
||||||
pub internal: bool,
|
pub internal: bool,
|
||||||
|
|
||||||
/// Type of this local.
|
/// Type of this local.
|
||||||
|
@ -26,7 +26,6 @@ use std::collections::HashMap;
|
|||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use syntax::ast::NodeId;
|
|
||||||
use transform::simplify;
|
use transform::simplify;
|
||||||
|
|
||||||
pub struct StateTransform;
|
pub struct StateTransform;
|
||||||
@ -67,20 +66,35 @@ struct TransformVisitor<'a, 'tcx: 'a> {
|
|||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
state_adt_ref: &'tcx AdtDef,
|
state_adt_ref: &'tcx AdtDef,
|
||||||
state_substs: &'tcx Substs<'tcx>,
|
state_substs: &'tcx Substs<'tcx>,
|
||||||
remap: HashMap<Local, (Ty<'tcx>, usize)>,
|
|
||||||
bb_target_count: u32,
|
// The index of the generator state in the generator struct
|
||||||
bb_targets: HashMap<(BasicBlock, Option<BasicBlock>), u32>,
|
|
||||||
new_ret_local: Local,
|
|
||||||
return_block: BasicBlock,
|
|
||||||
state_field: usize,
|
state_field: usize,
|
||||||
|
|
||||||
|
// Mapping from Local to (type of local, generator struct index)
|
||||||
|
remap: HashMap<Local, (Ty<'tcx>, usize)>,
|
||||||
|
|
||||||
|
// The number of generator states. 0 is unresumed, 1 is poisoned. So this is initialized to 2
|
||||||
|
bb_target_count: u32,
|
||||||
|
|
||||||
|
// Map from a (which block to resume execution at, which block to use to drop the generator) to a
|
||||||
|
// genrator state
|
||||||
|
bb_targets: HashMap<(BasicBlock, Option<BasicBlock>), u32>,
|
||||||
|
|
||||||
|
// The original RETURN_POINTER local
|
||||||
|
new_ret_local: Local,
|
||||||
|
|
||||||
|
// The block to resume execution when for Return
|
||||||
|
return_block: BasicBlock,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
||||||
|
// Make a GeneratorState rvalue
|
||||||
fn make_state(&self, idx: usize, val: Operand<'tcx>) -> Rvalue<'tcx> {
|
fn make_state(&self, idx: usize, val: Operand<'tcx>) -> Rvalue<'tcx> {
|
||||||
let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None);
|
let adt = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None);
|
||||||
Rvalue::Aggregate(box adt, vec![val])
|
Rvalue::Aggregate(box adt, vec![val])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a Lvalue referencing a generator struct field
|
||||||
fn make_field(&self, idx: usize, ty: Ty<'tcx>) -> Lvalue<'tcx> {
|
fn make_field(&self, idx: usize, ty: Ty<'tcx>) -> Lvalue<'tcx> {
|
||||||
let base = Lvalue::Local(Local::new(1));
|
let base = Lvalue::Local(Local::new(1));
|
||||||
let field = Projection {
|
let field = Projection {
|
||||||
@ -90,6 +104,7 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
|||||||
Lvalue::Projection(Box::new(field))
|
Lvalue::Projection(Box::new(field))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a statement which changes the generator state
|
||||||
fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'tcx> {
|
fn set_state(&self, state_disc: u32, source_info: SourceInfo) -> Statement<'tcx> {
|
||||||
let state = self.make_field(self.state_field, self.tcx.types.u32);
|
let state = self.make_field(self.state_field, self.tcx.types.u32);
|
||||||
let val = Operand::Constant(box Constant {
|
let val = Operand::Constant(box Constant {
|
||||||
@ -112,6 +127,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
|||||||
context: LvalueContext<'tcx>,
|
context: LvalueContext<'tcx>,
|
||||||
location: Location) {
|
location: Location) {
|
||||||
if let Lvalue::Local(l) = *lvalue {
|
if let Lvalue::Local(l) = *lvalue {
|
||||||
|
// Replace an Local in the remap with a generator struct access
|
||||||
if let Some(&(ty, idx)) = self.remap.get(&l) {
|
if let Some(&(ty, idx)) = self.remap.get(&l) {
|
||||||
*lvalue = self.make_field(idx, ty);
|
*lvalue = self.make_field(idx, ty);
|
||||||
}
|
}
|
||||||
@ -135,6 +151,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
|||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Remove StorageLive and StorageDead statements for remapped locals
|
||||||
data.retain_statements(|s| {
|
data.retain_statements(|s| {
|
||||||
match s.kind {
|
match s.kind {
|
||||||
StatementKind::StorageLive(ref l) | StatementKind::StorageDead(ref l) => {
|
StatementKind::StorageLive(ref l) | StatementKind::StorageDead(ref l) => {
|
||||||
@ -172,16 +189,6 @@ impl<'a, 'tcx> MutVisitor<'tcx> for TransformVisitor<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_generator_state_argument<'a, 'tcx>(
|
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|
||||||
node_id: NodeId,
|
|
||||||
def_id: DefId,
|
|
||||||
mir: &mut Mir<'tcx>) -> (Ty<'tcx>, GeneratorInterior<'tcx>) {
|
|
||||||
let interior = *tcx.typeck_tables_of(def_id).generator_interiors.get(&node_id).unwrap();
|
|
||||||
let gen_ty = mir.local_decls.raw[1].ty;
|
|
||||||
(gen_ty, interior)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn make_generator_state_argument_indirect<'a, 'tcx>(
|
fn make_generator_state_argument_indirect<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
@ -259,14 +266,21 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||||||
mir: &mut Mir<'tcx>)
|
mir: &mut Mir<'tcx>)
|
||||||
-> (HashMap<Local, (Ty<'tcx>, usize)>, GeneratorLayout<'tcx>)
|
-> (HashMap<Local, (Ty<'tcx>, usize)>, GeneratorLayout<'tcx>)
|
||||||
{
|
{
|
||||||
|
// Use a liveness analysis to compute locals which are live across a suspension point
|
||||||
let live_locals = locals_live_across_suspend_points(tcx, mir, source);
|
let live_locals = locals_live_across_suspend_points(tcx, mir, source);
|
||||||
|
|
||||||
|
// Erase regions from the types passed in from typeck so we can compare them with
|
||||||
|
// MIR types
|
||||||
let allowed = tcx.erase_regions(&interior.as_slice());
|
let allowed = tcx.erase_regions(&interior.as_slice());
|
||||||
|
|
||||||
for (local, decl) in mir.local_decls.iter_enumerated() {
|
for (local, decl) in mir.local_decls.iter_enumerated() {
|
||||||
|
// Ignore locals which are internal or not live
|
||||||
if !live_locals.contains(&local) || decl.internal {
|
if !live_locals.contains(&local) || decl.internal {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanity check that typeck knows about the type of locals which are
|
||||||
|
// live across a suspension point
|
||||||
if !allowed.contains(&decl.ty) {
|
if !allowed.contains(&decl.ty) {
|
||||||
span_bug!(mir.span,
|
span_bug!(mir.span,
|
||||||
"Broken MIR: generator contains type {} in MIR, \
|
"Broken MIR: generator contains type {} in MIR, \
|
||||||
@ -278,10 +292,17 @@ fn compute_layout<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||||||
|
|
||||||
let upvar_len = mir.upvar_decls.len();
|
let upvar_len = mir.upvar_decls.len();
|
||||||
let dummy_local = LocalDecl::new_internal(tcx.mk_nil(), mir.span);
|
let dummy_local = LocalDecl::new_internal(tcx.mk_nil(), mir.span);
|
||||||
|
|
||||||
|
// Gather live locals and their indices replacing values in mir.local_decls with a dummy
|
||||||
|
// to avoid changing local indices
|
||||||
let live_decls = live_locals.iter().map(|local| {
|
let live_decls = live_locals.iter().map(|local| {
|
||||||
let var = mem::replace(&mut mir.local_decls[local], dummy_local.clone());
|
let var = mem::replace(&mut mir.local_decls[local], dummy_local.clone());
|
||||||
(local, var)
|
(local, var)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Create a map from local indices to generator struct indices.
|
||||||
|
// These are offset by (upvar_len + 1) because of fields which comes before locals.
|
||||||
|
// We also create a vector of the LocalDecls of these locals.
|
||||||
let (remap, vars) = live_decls.enumerate().map(|(idx, (local, var))| {
|
let (remap, vars) = live_decls.enumerate().map(|(idx, (local, var))| {
|
||||||
((local, (var.ty, upvar_len + 1 + idx)), var)
|
((local, (var.ty, upvar_len + 1 + idx)), var)
|
||||||
}).unzip();
|
}).unzip();
|
||||||
@ -353,14 +374,16 @@ fn elaborate_generator_drops<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_drop<'a, 'tcx>(
|
fn create_generator_drop_shim<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
transform: &TransformVisitor<'a, 'tcx>,
|
transform: &TransformVisitor<'a, 'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
source: MirSource,
|
source: MirSource,
|
||||||
gen_ty: Ty<'tcx>,
|
gen_ty: Ty<'tcx>,
|
||||||
mir: &mut Mir<'tcx>,
|
mir: &Mir<'tcx>,
|
||||||
drop_clean: BasicBlock) {
|
drop_clean: BasicBlock) -> Mir<'tcx> {
|
||||||
|
let mut mir = mir.clone();
|
||||||
|
|
||||||
let source_info = SourceInfo {
|
let source_info = SourceInfo {
|
||||||
span: mir.span,
|
span: mir.span,
|
||||||
scope: ARGUMENT_VISIBILITY_SCOPE,
|
scope: ARGUMENT_VISIBILITY_SCOPE,
|
||||||
@ -393,7 +416,7 @@ fn generate_drop<'a, 'tcx>(
|
|||||||
targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
|
targets: cases.iter().map(|&(_, d)| d).chain(once(return_block)).collect(),
|
||||||
};
|
};
|
||||||
|
|
||||||
insert_entry_point(mir, BasicBlockData {
|
insert_entry_point(&mut mir, BasicBlockData {
|
||||||
statements: Vec::new(),
|
statements: Vec::new(),
|
||||||
terminator: Some(Terminator {
|
terminator: Some(Terminator {
|
||||||
source_info,
|
source_info,
|
||||||
@ -425,7 +448,7 @@ fn generate_drop<'a, 'tcx>(
|
|||||||
is_user_variable: false,
|
is_user_variable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
make_generator_state_argument_indirect(tcx, def_id, mir);
|
make_generator_state_argument_indirect(tcx, def_id, &mut mir);
|
||||||
|
|
||||||
// Change the generator argument from &mut to *mut
|
// Change the generator argument from &mut to *mut
|
||||||
mir.local_decls[Local::new(1)] = LocalDecl {
|
mir.local_decls[Local::new(1)] = LocalDecl {
|
||||||
@ -442,12 +465,14 @@ fn generate_drop<'a, 'tcx>(
|
|||||||
|
|
||||||
// Make sure we remove dead blocks to remove
|
// Make sure we remove dead blocks to remove
|
||||||
// unrelated code from the resume part of the function
|
// unrelated code from the resume part of the function
|
||||||
simplify::remove_dead_blocks(mir);
|
simplify::remove_dead_blocks(&mut mir);
|
||||||
|
|
||||||
dump_mir(tcx, None, "generator_drop", &0, source, mir);
|
dump_mir(tcx, None, "generator_drop", &0, source, &mut mir);
|
||||||
|
|
||||||
|
mir
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn insert_panic_on_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
mir: &mut Mir<'tcx>) {
|
mir: &mut Mir<'tcx>) {
|
||||||
let assert_block = BasicBlock::new(mir.basic_blocks().len());
|
let assert_block = BasicBlock::new(mir.basic_blocks().len());
|
||||||
let term = TerminatorKind::Assert {
|
let term = TerminatorKind::Assert {
|
||||||
@ -479,12 +504,12 @@ fn insert_resume_after_return<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_entry_point<'a, 'tcx>(
|
fn creator_generator_resume_function<'a, 'tcx>(
|
||||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
mut transform: TransformVisitor<'a, 'tcx>,
|
mut transform: TransformVisitor<'a, 'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
source: MirSource,
|
source: MirSource,
|
||||||
mir: &mut Mir<'tcx>) {
|
mir: &mut Mir<'tcx>) {
|
||||||
// Poison the generator when it unwinds
|
// Poison the generator when it unwinds
|
||||||
for block in mir.basic_blocks_mut() {
|
for block in mir.basic_blocks_mut() {
|
||||||
let source_info = block.terminator().source_info;
|
let source_info = block.terminator().source_info;
|
||||||
@ -555,7 +580,7 @@ fn generate_entry_point<'a, 'tcx>(
|
|||||||
dump_mir(tcx, None, "generator_resume", &0, source, mir);
|
dump_mir(tcx, None, "generator_resume", &0, source, mir);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> (BasicBlock, BasicBlock) {
|
fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> BasicBlock {
|
||||||
let source_info = SourceInfo {
|
let source_info = SourceInfo {
|
||||||
span: mir.span,
|
span: mir.span,
|
||||||
scope: ARGUMENT_VISIBILITY_SCOPE,
|
scope: ARGUMENT_VISIBILITY_SCOPE,
|
||||||
@ -587,7 +612,7 @@ fn insert_clean_drop<'a, 'tcx>(mir: &mut Mir<'tcx>) -> (BasicBlock, BasicBlock)
|
|||||||
is_cleanup: false,
|
is_cleanup: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
(return_block, drop_clean)
|
drop_clean
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirPass for StateTransform {
|
impl MirPass for StateTransform {
|
||||||
@ -607,25 +632,39 @@ impl MirPass for StateTransform {
|
|||||||
let node_id = source.item_id();
|
let node_id = source.item_id();
|
||||||
let def_id = tcx.hir.local_def_id(source.item_id());
|
let def_id = tcx.hir.local_def_id(source.item_id());
|
||||||
|
|
||||||
let (gen_ty, interior) = ensure_generator_state_argument(tcx, node_id, def_id, mir);
|
// Get the interior types which typeck computed
|
||||||
|
let interior = *tcx.typeck_tables_of(def_id).generator_interiors.get(&node_id).unwrap();
|
||||||
|
|
||||||
|
// The first argument is the generator type passed by value
|
||||||
|
let gen_ty = mir.local_decls.raw[1].ty;
|
||||||
|
|
||||||
|
// Compute GeneratorState<yield_ty, return_ty>
|
||||||
let state_did = tcx.lang_items.gen_state().unwrap();
|
let state_did = tcx.lang_items.gen_state().unwrap();
|
||||||
let state_adt_ref = tcx.adt_def(state_did);
|
let state_adt_ref = tcx.adt_def(state_did);
|
||||||
let state_substs = tcx.mk_substs([Kind::from(yield_ty),
|
let state_substs = tcx.mk_substs([Kind::from(yield_ty),
|
||||||
Kind::from(mir.return_ty)].iter());
|
Kind::from(mir.return_ty)].iter());
|
||||||
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
|
let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
|
||||||
|
|
||||||
|
// We rename RETURN_POINTER which has type mir.return_ty to new_ret_local
|
||||||
|
// RETURN_POINTER then is a fresh unused local with type ret_ty.
|
||||||
let new_ret_local = replace_result_variable(ret_ty, mir);
|
let new_ret_local = replace_result_variable(ret_ty, mir);
|
||||||
|
|
||||||
|
// Extract locals which are live across suspension point into `layout`
|
||||||
|
// `remap` gives a mapping from local indices onto generator struct indices
|
||||||
let (remap, layout) = compute_layout(tcx, source, interior, mir);
|
let (remap, layout) = compute_layout(tcx, source, interior, mir);
|
||||||
|
|
||||||
let tail_block = BasicBlock::new(mir.basic_blocks().len());
|
|
||||||
|
|
||||||
let state_field = mir.upvar_decls.len();
|
let state_field = mir.upvar_decls.len();
|
||||||
|
|
||||||
let mut bb_targets = HashMap::new();
|
let mut bb_targets = HashMap::new();
|
||||||
|
|
||||||
|
// If we jump to the entry point, we should go to the initial 0 generator state.
|
||||||
|
// FIXME: Could this result in the need for destruction for state 0?
|
||||||
bb_targets.insert((BasicBlock::new(0), None), 0);
|
bb_targets.insert((BasicBlock::new(0), None), 0);
|
||||||
|
|
||||||
|
// Run the transformation which converts Lvalues from Local to generator struct
|
||||||
|
// accesses for locals in `remap`.
|
||||||
|
// It also rewrites `return x` and `yield y` as writing a new generator state and returning
|
||||||
|
// GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
|
||||||
let mut transform = TransformVisitor {
|
let mut transform = TransformVisitor {
|
||||||
tcx,
|
tcx,
|
||||||
state_adt_ref,
|
state_adt_ref,
|
||||||
@ -634,39 +673,50 @@ impl MirPass for StateTransform {
|
|||||||
bb_target_count: 2,
|
bb_target_count: 2,
|
||||||
bb_targets,
|
bb_targets,
|
||||||
new_ret_local,
|
new_ret_local,
|
||||||
return_block: tail_block,
|
|
||||||
state_field,
|
state_field,
|
||||||
|
|
||||||
|
// For returns we will resume execution at the next added basic block.
|
||||||
|
// This happens in `insert_panic_on_resume_after_return`
|
||||||
|
return_block: BasicBlock::new(mir.basic_blocks().len()),
|
||||||
};
|
};
|
||||||
transform.visit_mir(mir);
|
transform.visit_mir(mir);
|
||||||
|
|
||||||
|
// Update our MIR struct to reflect the changed we've made
|
||||||
mir.return_ty = ret_ty;
|
mir.return_ty = ret_ty;
|
||||||
mir.yield_ty = None;
|
mir.yield_ty = None;
|
||||||
mir.arg_count = 1;
|
mir.arg_count = 1;
|
||||||
mir.spread_arg = None;
|
mir.spread_arg = None;
|
||||||
mir.generator_layout = Some(layout);
|
mir.generator_layout = Some(layout);
|
||||||
|
|
||||||
insert_resume_after_return(tcx, mir);
|
// Panic if we resumed after returning
|
||||||
|
insert_panic_on_resume_after_return(tcx, mir);
|
||||||
|
|
||||||
let (_return_block, drop_clean) = insert_clean_drop(mir);
|
// Insert `drop(generator_struct)` which is used to drop upvars for generators in
|
||||||
|
// the unresumed (0) state.
|
||||||
|
// This is expanded to a drop ladder in `elaborate_generator_drops`.
|
||||||
|
let drop_clean = insert_clean_drop(mir);
|
||||||
|
|
||||||
dump_mir(tcx, None, "generator_pre-elab", &0, source, mir);
|
dump_mir(tcx, None, "generator_pre-elab", &0, source, mir);
|
||||||
|
|
||||||
|
// Expand `drop(generator_struct)` to a drop ladder which destroys upvars.
|
||||||
|
// If any upvars are moved out of, drop elaboration will handle upvar destruction.
|
||||||
|
// However we need to also elaborate the code generated by `insert_clean_drop`.
|
||||||
elaborate_generator_drops(tcx, def_id, mir);
|
elaborate_generator_drops(tcx, def_id, mir);
|
||||||
|
|
||||||
dump_mir(tcx, None, "generator_post-transform", &0, source, mir);
|
dump_mir(tcx, None, "generator_post-transform", &0, source, mir);
|
||||||
|
|
||||||
let mut drop_impl = mir.clone();
|
// Create a copy of our MIR and use it to create the drop shim for the generator
|
||||||
|
let drop_shim = create_generator_drop_shim(tcx,
|
||||||
|
&transform,
|
||||||
|
def_id,
|
||||||
|
source,
|
||||||
|
gen_ty,
|
||||||
|
&mir,
|
||||||
|
drop_clean);
|
||||||
|
|
||||||
generate_drop(tcx,
|
mir.generator_drop = Some(box drop_shim);
|
||||||
&transform,
|
|
||||||
def_id,
|
|
||||||
source,
|
|
||||||
gen_ty,
|
|
||||||
&mut drop_impl,
|
|
||||||
drop_clean);
|
|
||||||
|
|
||||||
mir.generator_drop = Some(box drop_impl);
|
// Create the Genreator::resume function
|
||||||
|
creator_generator_resume_function(tcx, transform, def_id, source, mir);
|
||||||
generate_entry_point(tcx, transform, def_id, source, mir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user