Change:
else { return; }; <ins> // Also, let's skip processing any bodies with errors, since there's no guarantee // the MIR body will be constructed well. </ins> let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; if coroutine_ty.references_error() { return; } <del> let ty::Coroutine(_, args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; let coroutine_kind = args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(); </del> <ins> let ty::Coroutine(_, coroutine_args) = *coroutine_ty.kind() else { bug!("{body:#?}") }; // We don't need to generate a by-move coroutine if the kind of the coroutine is // already `FnOnce` -- that means that any upvars that the closure consumes have // already been taken by-value. let coroutine_kind = coroutine_args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(); </ins> if coroutine_kind == ty::ClosureKind::FnOnce { return; } <ins> let parent_def_id = tcx.local_parent(coroutine_def_id); let ty::CoroutineClosure(_, parent_args) = *tcx.type_of(parent_def_id).instantiate_identity().kind() else { bug!(); }; let parent_closure_args = parent_args.as_coroutine_closure(); let num_args = parent_closure_args .coroutine_closure_sig() .skip_binder() .tupled_inputs_ty .tuple_fields() .len(); </ins> let mut by_ref_fields = UnordSet::default(); <del> let by_move_upvars = Ty::new_tup_from_iter( tcx, tcx.closure_captures(coroutine_def_id).iter().enumerate().map(|(idx, capture)| { if capture.is_by_ref() { by_ref_fields.insert(FieldIdx::from_usize(idx)); } capture.place.ty() }), ); let by_move_coroutine_ty = Ty::new_coroutine( tcx, coroutine_def_id.to_def_id(), ty::CoroutineArgs::new( </del> <ins> for (idx, (coroutine_capture, parent_capture)) in tcx .closure_captures(coroutine_def_id) .iter() // By construction we capture all the args first. .skip(num_args) .zip_eq(tcx.closure_captures(parent_def_id)) .enumerate() { // This upvar is captured by-move from the parent closure, but by-ref // from the inner async block. That means that it's being borrowed from // the outer closure body -- we need to change the coroutine to take the // upvar by value. if coroutine_capture.is_by_ref() && !parent_capture.is_by_ref() { by_ref_fields.insert(FieldIdx::from_usize(num_args + idx)); } // Make sure we're actually talking about the same capture. // FIXME(async_closures): We could look at the `hir::Upvar` instead? assert_eq!(coroutine_capture.place.ty(), parent_capture.place.ty()); } let by_move_coroutine_ty = tcx .instantiate_bound_regions_with_erased(parent_closure_args.coroutine_closure_sig()) .to_coroutine_given_kind_and_upvars( </ins> tcx, <del> ty::CoroutineArgsParts { parent_args: args.as_coroutine().parent_args(), kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnOnce), resume_ty: args.as_coroutine().resume_ty(), yield_ty: args.as_coroutine().yield_ty(), return_ty: args.as_coroutine().return_ty(), witness: args.as_coroutine().witness(), tupled_upvars_ty: by_move_upvars, }, ) .args, ); </del> <ins> parent_closure_args.parent_args(), coroutine_def_id.to_def_id(), ty::ClosureKind::FnOnce, tcx.lifetimes.re_erased, parent_closure_args.tupled_upvars_ty(), parent_closure_args.coroutine_captures_by_ref_ty(), ); </ins> let mut by_move_body = body.clone(); MakeByMoveBody { tcx, by_ref_fields, by_move_coroutine_ty }.visit_body(&mut by_move_body);

Discussion:
Something is still wrong w/ async call shims. I think I'm not doing the transform correctly or something. Putting this up so I don't forget about it, but I'll fix it.
ohhhhh lol it's drop glue. Huh.
Oh hell yes this is actually totally wrong wtf: