Don't insert panic when generator can not return
This commit is contained in:
parent
823ff8cf13
commit
425e7e5596
@ -991,12 +991,30 @@ fn insert_panic_block<'tcx>(
|
|||||||
assert_block
|
assert_block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
|
||||||
|
// Returning from a function with an uninhabited return type is undefined behavior.
|
||||||
|
if body.return_ty().conservative_is_privately_uninhabited(tcx) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's no return terminator the function also won't return.
|
||||||
|
for block in body.basic_blocks() {
|
||||||
|
if let TerminatorKind::Return = block.terminator().kind {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise we assume that the function may return.
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
fn create_generator_resume_function<'tcx>(
|
fn create_generator_resume_function<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
transform: TransformVisitor<'tcx>,
|
transform: TransformVisitor<'tcx>,
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
source: MirSource<'tcx>,
|
source: MirSource<'tcx>,
|
||||||
body: &mut BodyAndCache<'tcx>,
|
body: &mut BodyAndCache<'tcx>,
|
||||||
|
can_return: bool,
|
||||||
) {
|
) {
|
||||||
// Poison the generator when it unwinds
|
// Poison the generator when it unwinds
|
||||||
for block in body.basic_blocks_mut() {
|
for block in body.basic_blocks_mut() {
|
||||||
@ -1015,7 +1033,14 @@ fn create_generator_resume_function<'tcx>(
|
|||||||
|
|
||||||
// Panic when resumed on the returned or poisoned state
|
// Panic when resumed on the returned or poisoned state
|
||||||
let generator_kind = body.generator_kind.unwrap();
|
let generator_kind = body.generator_kind.unwrap();
|
||||||
cases.insert(1, (RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(generator_kind))));
|
|
||||||
|
if can_return {
|
||||||
|
cases.insert(
|
||||||
|
1,
|
||||||
|
(RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(generator_kind))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
cases.insert(2, (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind))));
|
cases.insert(2, (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind))));
|
||||||
|
|
||||||
insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
|
insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
|
||||||
@ -1200,6 +1225,8 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||||||
let (remap, layout, storage_liveness) =
|
let (remap, layout, storage_liveness) =
|
||||||
compute_layout(tcx, source, &upvars, interior, movable, body);
|
compute_layout(tcx, source, &upvars, interior, movable, body);
|
||||||
|
|
||||||
|
let can_return = can_return(tcx, body);
|
||||||
|
|
||||||
// Run the transformation which converts Places from Local to generator struct
|
// Run the transformation which converts Places from Local to generator struct
|
||||||
// accesses for locals in `remap`.
|
// accesses for locals in `remap`.
|
||||||
// It also rewrites `return x` and `yield y` as writing a new generator state and returning
|
// It also rewrites `return x` and `yield y` as writing a new generator state and returning
|
||||||
@ -1243,6 +1270,6 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||||||
body.generator_drop = Some(box drop_shim);
|
body.generator_drop = Some(box drop_shim);
|
||||||
|
|
||||||
// Create the Generator::resume function
|
// Create the Generator::resume function
|
||||||
create_generator_resume_function(tcx, transform, def_id, source, body);
|
create_generator_resume_function(tcx, transform, def_id, source, body, can_return);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user