Fix fn_sig_for_fn_abi and the coroutine transform for generators
There were three issues previously: * The self argument was pinned, despite Iterator::next taking an unpinned mutable reference. * A resume argument was passed, despite Iterator::next not having one. * The return value was CoroutineState<Item, ()> rather than Option<Item> While these things just so happened to work with the LLVM backend, cg_clif does much stricter checks when trying to assign a value to a place. In addition it can't handle the mismatch between the amount of arguments specified by the FnAbi and the FnSig.
This commit is contained in:
parent
237339fda1
commit
b7bc8d5cb7
7 changed files with 129 additions and 9 deletions
|
@ -617,6 +617,22 @@ fn replace_resume_ty_local<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
/// Transforms the `body` of the coroutine applying the following transform:
|
||||
///
|
||||
/// - Remove the `resume` argument.
|
||||
///
|
||||
/// Ideally the async lowering would not add the `resume` argument.
|
||||
///
|
||||
/// The async lowering step and the type / lifetime inference / checking are
|
||||
/// still using the `resume` argument for the time being. After this transform,
|
||||
/// the coroutine body doesn't have the `resume` argument.
|
||||
fn transform_gen_context<'tcx>(_tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
|
||||
// This leaves the local representing the `resume` argument in place,
|
||||
// but turns it into a regular local variable. This is cheaper than
|
||||
// adjusting all local references in the body after removing it.
|
||||
body.arg_count = 1;
|
||||
}
|
||||
|
||||
struct LivenessInfo {
|
||||
/// Which locals are live across any suspension point.
|
||||
saved_locals: CoroutineSavedLocals,
|
||||
|
@ -1337,7 +1353,15 @@ fn create_coroutine_resume_function<'tcx>(
|
|||
insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
|
||||
|
||||
make_coroutine_state_argument_indirect(tcx, body);
|
||||
make_coroutine_state_argument_pinned(tcx, body);
|
||||
|
||||
match coroutine_kind {
|
||||
// Iterator::next doesn't accept a pinned argument,
|
||||
// unlike for all other coroutine kinds.
|
||||
CoroutineKind::Gen(_) => {}
|
||||
_ => {
|
||||
make_coroutine_state_argument_pinned(tcx, body);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we remove dead blocks to remove
|
||||
// unrelated code from the drop part of the function
|
||||
|
@ -1504,6 +1528,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||
};
|
||||
|
||||
let is_async_kind = matches!(body.coroutine_kind(), Some(CoroutineKind::Async(_)));
|
||||
let is_gen_kind = matches!(body.coroutine_kind(), Some(CoroutineKind::Gen(_)));
|
||||
let (state_adt_ref, state_args) = match body.coroutine_kind().unwrap() {
|
||||
CoroutineKind::Async(_) => {
|
||||
// Compute Poll<return_ty>
|
||||
|
@ -1609,6 +1634,11 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
|
|||
body.arg_count = 2; // self, resume arg
|
||||
body.spread_arg = None;
|
||||
|
||||
// Remove the context argument within generator bodies.
|
||||
if is_gen_kind {
|
||||
transform_gen_context(tcx, body);
|
||||
}
|
||||
|
||||
// The original arguments to the function are no longer arguments, mark them as such.
|
||||
// Otherwise they'll conflict with our new arguments, which although they don't have
|
||||
// argument_index set, will get emitted as unnamed arguments.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue