Rollup merge of #146552 - cjgillot:resume-noremap, r=jackh726

StateTransform: Do not renumber resume local.

MIR parameters are not explicitly assigned-to when entering the MIR body. If we want to save their values inside the coroutine state, we need to do so explicitly.

This was done by renaming the `_2` local, and introducing an explicit assignment pre-transform. This particular trick confuses me.

This version makes explicit that we are assigning parameters to saved locals.

r? ``@dingxiangfei2009``
This commit is contained in:
Stuart Cook 2025-09-17 14:56:47 +10:00 committed by GitHub
commit 577f18ffe2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 639 additions and 225 deletions

View file

@ -471,7 +471,7 @@ impl<'tcx> Body<'tcx> {
/// Returns an iterator over all function arguments.
#[inline]
pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator {
pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator + use<> {
(1..self.arg_count + 1).map(Local::new)
}

View file

@ -17,7 +17,7 @@ use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty};
rustc_index::newtype_index! {
#[derive(HashStable)]
#[encodable]
#[debug_format = "_{}"]
#[debug_format = "_s{}"]
pub struct CoroutineSavedLocal {}
}

View file

@ -1340,14 +1340,13 @@ fn create_cases<'tcx>(
}
}
if operation == Operation::Resume {
if operation == Operation::Resume && point.resume_arg != CTX_ARG.into() {
// Move the resume argument to the destination place of the `Yield` terminator
let resume_arg = CTX_ARG;
statements.push(Statement::new(
source_info,
StatementKind::Assign(Box::new((
point.resume_arg,
Rvalue::Use(Operand::Move(resume_arg.into())),
Rvalue::Use(Operand::Move(CTX_ARG.into())),
))),
));
}
@ -1439,7 +1438,10 @@ fn check_field_tys_sized<'tcx>(
}
impl<'tcx> crate::MirPass<'tcx> for StateTransform {
#[instrument(level = "debug", skip(self, tcx, body), ret)]
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!(def_id = ?body.source.def_id());
let Some(old_yield_ty) = body.yield_ty() else {
// This only applies to coroutines
return;
@ -1518,31 +1520,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
cleanup_async_drops(body);
}
// We also replace the resume argument and insert an `Assign`.
// This is needed because the resume argument `_2` might be live across a `yield`, in which
// case there is no `Assign` to it that the transform can turn into a store to the coroutine
// state. After the yield the slot in the coroutine state would then be uninitialized.
let resume_local = CTX_ARG;
let resume_ty = body.local_decls[resume_local].ty;
let old_resume_local = replace_local(resume_local, resume_ty, body, tcx);
// When first entering the coroutine, move the resume argument into its old local
// (which is now a generator interior).
let source_info = SourceInfo::outermost(body.span);
let stmts = &mut body.basic_blocks_mut()[START_BLOCK].statements;
stmts.insert(
0,
Statement::new(
source_info,
StatementKind::Assign(Box::new((
old_resume_local.into(),
Rvalue::Use(Operand::Move(resume_local.into())),
))),
),
);
let always_live_locals = always_storage_live_locals(body);
let movable = coroutine_kind.movability() == hir::Movability::Movable;
let liveness_info =
locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
@ -1583,6 +1561,21 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform {
};
transform.visit_body(body);
// MIR parameters are not explicitly assigned-to when entering the MIR body.
// If we want to save their values inside the coroutine state, we need to do so explicitly.
let source_info = SourceInfo::outermost(body.span);
let args_iter = body.args_iter();
body.basic_blocks.as_mut()[START_BLOCK].statements.splice(
0..0,
args_iter.filter_map(|local| {
let (ty, variant_index, idx) = transform.remap[local]?;
let lhs = transform.make_field(variant_index, idx, ty);
let rhs = Rvalue::Use(Operand::Move(local.into()));
let assign = StatementKind::Assign(Box::new((lhs, rhs)));
Some(Statement::new(source_info, assign))
}),
);
// Update our MIR struct to reflect the changes we've made
body.arg_count = 2; // self, resume arg
body.spread_arg = None;

View file

@ -1,7 +1,7 @@
// MIR for `a::{closure#0}` 0 coroutine_drop_async
fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) -> Poll<()> {
debug _task_context => _19;
debug _task_context => _2;
debug x => ((*(_1.0: &mut {async fn body of a<T>()})).0: T);
let mut _0: std::task::Poll<()>;
let _3: T;
@ -20,15 +20,14 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>)
let mut _16: &mut impl std::future::Future<Output = ()>;
let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
let mut _18: isize;
let mut _19: &mut std::task::Context<'_>;
let mut _20: u32;
let mut _19: u32;
scope 1 {
debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T);
}
bb0: {
_20 = discriminant((*(_1.0: &mut {async fn body of a<T>()})));
switchInt(move _20) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14];
_19 = discriminant((*(_1.0: &mut {async fn body of a<T>()})));
switchInt(move _19) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14];
}
bb1: {

View file

@ -1,7 +1,7 @@
// MIR for `a::{closure#0}` 0 coroutine_drop_async
fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) -> Poll<()> {
debug _task_context => _19;
debug _task_context => _2;
debug x => ((*(_1.0: &mut {async fn body of a<T>()})).0: T);
let mut _0: std::task::Poll<()>;
let _3: T;
@ -20,15 +20,14 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>)
let mut _16: &mut impl std::future::Future<Output = ()>;
let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>;
let mut _18: isize;
let mut _19: &mut std::task::Context<'_>;
let mut _20: u32;
let mut _19: u32;
scope 1 {
debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T);
}
bb0: {
_20 = discriminant((*(_1.0: &mut {async fn body of a<T>()})));
switchInt(move _20) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19];
_19 = discriminant((*(_1.0: &mut {async fn body of a<T>()})));
switchInt(move _19) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19];
}
bb1: {

View file

@ -10,19 +10,17 @@
} */
fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> {
debug _task_context => _4;
debug _task_context => _2;
let mut _0: std::task::Poll<()>;
let mut _3: ();
let mut _4: &mut std::task::Context<'_>;
let mut _5: u32;
let mut _4: u32;
bb0: {
_5 = discriminant((*(_1.0: &mut {async fn body of a()})));
switchInt(move _5) -> [0: bb1, 1: bb4, otherwise: bb5];
_4 = discriminant((*(_1.0: &mut {async fn body of a()})));
switchInt(move _4) -> [0: bb1, 1: bb4, otherwise: bb5];
}
bb1: {
_4 = move _2;
_3 = const ();
goto -> bb3;
}

View file

@ -1,7 +1,7 @@
// MIR for `b::{closure#0}` 0 coroutine_resume
/* coroutine_layout = CoroutineLayout {
field_tys: {
_0: CoroutineSavedTy {
_s0: CoroutineSavedTy {
ty: Coroutine(
DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
[
@ -18,7 +18,7 @@
},
ignore_for_traits: false,
},
_1: CoroutineSavedTy {
_s1: CoroutineSavedTy {
ty: Coroutine(
DefId(0:5 ~ async_await[ccf8]::a::{closure#0}),
[
@ -40,17 +40,17 @@
Unresumed(0): [],
Returned (1): [],
Panicked (2): [],
Suspend0 (3): [_0],
Suspend1 (4): [_1],
Suspend0 (3): [_s0],
Suspend1 (4): [_s1],
},
storage_conflicts: BitMatrix(2x2) {
(_0, _0),
(_1, _1),
(_s0, _s0),
(_s1, _s1),
},
} */
fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> Poll<()> {
debug _task_context => _38;
debug _task_context => _2;
let mut _0: std::task::Poll<()>;
let _3: ();
let mut _4: {async fn body of a()};
@ -85,8 +85,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
let mut _35: &mut std::task::Context<'_>;
let mut _36: ();
let mut _37: ();
let mut _38: &mut std::task::Context<'_>;
let mut _39: u32;
let mut _38: u32;
scope 1 {
debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()});
let _17: ();
@ -103,12 +102,11 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
}
bb0: {
_39 = discriminant((*(_1.0: &mut {async fn body of b()})));
switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8];
_38 = discriminant((*(_1.0: &mut {async fn body of b()})));
switchInt(move _38) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8];
}
bb1: {
_38 = move _2;
StorageLive(_3);
StorageLive(_4);
StorageLive(_5);
@ -143,7 +141,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
StorageLive(_13);
StorageLive(_14);
StorageLive(_15);
_15 = copy _38;
_15 = copy _2;
_14 = move _15;
goto -> bb6;
}
@ -198,7 +196,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
bb11: {
StorageDead(_20);
_38 = move _19;
_2 = move _19;
StorageDead(_19);
_7 = const ();
goto -> bb4;
@ -245,7 +243,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
StorageLive(_29);
StorageLive(_30);
StorageLive(_31);
_31 = copy _38;
_31 = copy _2;
_30 = move _31;
goto -> bb18;
}
@ -295,7 +293,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) ->
bb22: {
StorageDead(_36);
_38 = move _35;
_2 = move _35;
StorageDead(_35);
_7 = const ();
goto -> bb16;

View file

@ -0,0 +1,207 @@
// MIR for `main::{closure#0}` after StateTransform
/* coroutine_layout = CoroutineLayout {
field_tys: {
_s0: CoroutineSavedTy {
ty: std::string::String,
source_info: SourceInfo {
span: $DIR/coroutine.rs:18:6: 18:9 (#0),
scope: scope[0],
},
ignore_for_traits: false,
},
},
variant_fields: {
Unresumed(0): [],
Returned (1): [],
Panicked (2): [],
Suspend0 (3): [_s0],
Suspend1 (4): [_s0],
},
storage_conflicts: BitMatrix(1x1) {
(_s0, _s0),
},
} */
fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2: String) -> CoroutineState<(&str, String, &Location<'_>), ()> {
debug arg => (((*(_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18})) as variant#4).0: std::string::String);
let mut _0: std::ops::CoroutineState<(&str, std::string::String, &std::panic::Location<'_>), ()>;
let _3: std::string::String;
let mut _4: (&str, std::string::String, &std::panic::Location<'_>);
let mut _5: std::string::String;
let mut _6: &std::string::String;
let mut _7: &std::panic::Location<'_>;
let _8: std::string::String;
let mut _9: (&str, std::string::String, &std::panic::Location<'_>);
let mut _10: &str;
let _11: &str;
let mut _12: std::string::String;
let mut _13: &std::string::String;
let mut _14: &std::panic::Location<'_>;
let _15: &std::panic::Location<'_>;
let mut _16: ();
let mut _17: u32;
let mut _18: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
let mut _19: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
let mut _20: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
let mut _21: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
let mut _22: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
let mut _23: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
let mut _24: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
let mut _25: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18};
bb0: {
_18 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
_17 = discriminant((*_18));
switchInt(move _17) -> [0: bb1, 1: bb19, 3: bb17, 4: bb18, otherwise: bb20];
}
bb1: {
_19 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
(((*_19) as variant#4).0: std::string::String) = move _2;
StorageLive(_3);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
_20 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
_6 = &(((*_20) as variant#4).0: std::string::String);
_5 = <String as Clone>::clone(move _6) -> [return: bb2, unwind unreachable];
}
bb2: {
StorageDead(_6);
StorageLive(_7);
_7 = Location::<'_>::caller() -> [return: bb3, unwind unreachable];
}
bb3: {
_4 = (const "first", move _5, move _7);
StorageDead(_7);
goto -> bb4;
}
bb4: {
StorageDead(_5);
_0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _4);
StorageDead(_3);
StorageDead(_4);
_21 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
discriminant((*_21)) = 3;
return;
}
bb5: {
goto -> bb6;
}
bb6: {
StorageDead(_4);
drop(_3) -> [return: bb7, unwind unreachable];
}
bb7: {
StorageDead(_3);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
StorageLive(_11);
_11 = const "second";
_10 = &(*_11);
StorageLive(_12);
StorageLive(_13);
_22 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
_13 = &(((*_22) as variant#4).0: std::string::String);
_12 = <String as Clone>::clone(move _13) -> [return: bb8, unwind unreachable];
}
bb8: {
StorageDead(_13);
StorageLive(_14);
StorageLive(_15);
_15 = Location::<'_>::caller() -> [return: bb9, unwind unreachable];
}
bb9: {
_14 = &(*_15);
_9 = (move _10, move _12, move _14);
StorageDead(_14);
goto -> bb10;
}
bb10: {
StorageDead(_12);
StorageDead(_10);
_0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _9);
StorageDead(_8);
StorageDead(_9);
StorageDead(_11);
StorageDead(_15);
_23 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
discriminant((*_23)) = 4;
return;
}
bb11: {
goto -> bb12;
}
bb12: {
StorageDead(_9);
drop(_8) -> [return: bb13, unwind unreachable];
}
bb13: {
StorageDead(_15);
StorageDead(_11);
StorageDead(_8);
_16 = const ();
_24 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
drop((((*_24) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable];
}
bb14: {
goto -> bb16;
}
bb15: {
_0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Complete(move _16);
_25 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18});
discriminant((*_25)) = 1;
return;
}
bb16: {
goto -> bb15;
}
bb17: {
StorageLive(_3);
StorageLive(_4);
_3 = move _2;
goto -> bb5;
}
bb18: {
StorageLive(_8);
StorageLive(_9);
StorageLive(_11);
StorageLive(_15);
_8 = move _2;
goto -> bb11;
}
bb19: {
assert(const false, "coroutine resumed after completion") -> [success: bb19, unwind unreachable];
}
bb20: {
unreachable;
}
}
ALLOC0 (size: 6, align: 1) {
73 65 63 6f 6e 64 second
}
ALLOC1 (size: 5, align: 1) {
66 69 72 73 74 first
}

View file

@ -0,0 +1,207 @@
// MIR for `main::{closure#1}` after StateTransform
/* coroutine_layout = CoroutineLayout {
field_tys: {
_s0: CoroutineSavedTy {
ty: std::string::String,
source_info: SourceInfo {
span: $DIR/coroutine.rs:25:6: 25:9 (#0),
scope: scope[0],
},
ignore_for_traits: false,
},
},
variant_fields: {
Unresumed(0): [],
Returned (1): [],
Panicked (2): [],
Suspend0 (3): [_s0],
Suspend1 (4): [_s0],
},
storage_conflicts: BitMatrix(1x1) {
(_s0, _s0),
},
} */
fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2: String) -> CoroutineState<(&str, String, &Location<'_>), ()> {
debug arg => (((*(_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18})) as variant#4).0: std::string::String);
let mut _0: std::ops::CoroutineState<(&str, std::string::String, &std::panic::Location<'_>), ()>;
let _3: std::string::String;
let mut _4: (&str, std::string::String, &std::panic::Location<'_>);
let mut _5: std::string::String;
let mut _6: &std::string::String;
let mut _7: &std::panic::Location<'_>;
let _8: std::string::String;
let mut _9: (&str, std::string::String, &std::panic::Location<'_>);
let mut _10: &str;
let _11: &str;
let mut _12: std::string::String;
let mut _13: &std::string::String;
let mut _14: &std::panic::Location<'_>;
let _15: &std::panic::Location<'_>;
let mut _16: ();
let mut _17: u32;
let mut _18: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
let mut _19: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
let mut _20: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
let mut _21: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
let mut _22: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
let mut _23: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
let mut _24: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
let mut _25: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18};
bb0: {
_18 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
_17 = discriminant((*_18));
switchInt(move _17) -> [0: bb1, 1: bb19, 3: bb17, 4: bb18, otherwise: bb20];
}
bb1: {
_19 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
(((*_19) as variant#4).0: std::string::String) = move _2;
StorageLive(_3);
StorageLive(_4);
StorageLive(_5);
StorageLive(_6);
_20 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
_6 = &(((*_20) as variant#4).0: std::string::String);
_5 = <String as Clone>::clone(move _6) -> [return: bb2, unwind unreachable];
}
bb2: {
StorageDead(_6);
StorageLive(_7);
_7 = Location::<'_>::caller() -> [return: bb3, unwind unreachable];
}
bb3: {
_4 = (const "first", move _5, move _7);
StorageDead(_7);
goto -> bb4;
}
bb4: {
StorageDead(_5);
_0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _4);
StorageDead(_3);
StorageDead(_4);
_21 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
discriminant((*_21)) = 3;
return;
}
bb5: {
goto -> bb6;
}
bb6: {
StorageDead(_4);
drop(_3) -> [return: bb7, unwind unreachable];
}
bb7: {
StorageDead(_3);
StorageLive(_8);
StorageLive(_9);
StorageLive(_10);
StorageLive(_11);
_11 = const "second";
_10 = &(*_11);
StorageLive(_12);
StorageLive(_13);
_22 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
_13 = &(((*_22) as variant#4).0: std::string::String);
_12 = <String as Clone>::clone(move _13) -> [return: bb8, unwind unreachable];
}
bb8: {
StorageDead(_13);
StorageLive(_14);
StorageLive(_15);
_15 = Location::<'_>::caller() -> [return: bb9, unwind unreachable];
}
bb9: {
_14 = &(*_15);
_9 = (move _10, move _12, move _14);
StorageDead(_14);
goto -> bb10;
}
bb10: {
StorageDead(_12);
StorageDead(_10);
_0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _9);
StorageDead(_8);
StorageDead(_9);
StorageDead(_11);
StorageDead(_15);
_23 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
discriminant((*_23)) = 4;
return;
}
bb11: {
goto -> bb12;
}
bb12: {
StorageDead(_9);
drop(_8) -> [return: bb13, unwind unreachable];
}
bb13: {
StorageDead(_15);
StorageDead(_11);
StorageDead(_8);
_16 = const ();
_24 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
drop((((*_24) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable];
}
bb14: {
goto -> bb16;
}
bb15: {
_0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Complete(move _16);
_25 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18});
discriminant((*_25)) = 1;
return;
}
bb16: {
goto -> bb15;
}
bb17: {
StorageLive(_3);
StorageLive(_4);
_3 = move _2;
goto -> bb5;
}
bb18: {
StorageLive(_8);
StorageLive(_9);
StorageLive(_11);
StorageLive(_15);
_8 = move _2;
goto -> bb11;
}
bb19: {
assert(const false, "coroutine resumed after completion") -> [success: bb19, unwind unreachable];
}
bb20: {
unreachable;
}
}
ALLOC0 (size: 6, align: 1) {
73 65 63 6f 6e 64 second
}
ALLOC1 (size: 5, align: 1) {
66 69 72 73 74 first
}

View file

@ -0,0 +1,29 @@
// skip-filecheck
//@ edition:2024
//@ compile-flags: -Zmir-opt-level=0 -C panic=abort
#![feature(stmt_expr_attributes)]
#![feature(closure_track_caller)]
#![feature(coroutine_trait)]
#![feature(coroutines)]
use std::ops::{Coroutine, CoroutineState};
use std::panic::Location;
use std::pin::Pin;
// EMIT_MIR coroutine.main-{closure#0}.StateTransform.after.mir
// EMIT_MIR coroutine.main-{closure#1}.StateTransform.after.mir
fn main() {
let simple = #[coroutine]
|arg: String| {
yield ("first", arg.clone(), Location::caller());
yield ("second", arg.clone(), Location::caller());
};
let track_caller = #[track_caller]
#[coroutine]
|arg: String| {
yield ("first", arg.clone(), Location::caller());
yield ("second", arg.clone(), Location::caller());
};
}

View file

@ -7,15 +7,14 @@ fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12
let _4: ();
let mut _5: ();
let mut _6: ();
let mut _7: ();
let mut _8: u32;
let mut _7: u32;
scope 1 {
debug _s => (((*_1) as variant#3).0: std::string::String);
}
bb0: {
_8 = discriminant((*_1));
switchInt(move _8) -> [0: bb5, 3: bb8, otherwise: bb9];
_7 = discriminant((*_1));
switchInt(move _7) -> [0: bb5, 3: bb8, otherwise: bb9];
}
bb1: {

View file

@ -7,15 +7,14 @@ fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12
let _4: ();
let mut _5: ();
let mut _6: ();
let mut _7: ();
let mut _8: u32;
let mut _7: u32;
scope 1 {
debug _s => (((*_1) as variant#3).0: std::string::String);
}
bb0: {
_8 = discriminant((*_1));
switchInt(move _8) -> [0: bb7, 3: bb10, otherwise: bb11];
_7 = discriminant((*_1));
switchInt(move _7) -> [0: bb7, 3: bb10, otherwise: bb11];
}
bb1: {

View file

@ -1,7 +1,7 @@
// MIR for `main::{closure#0}` 0 coroutine_resume
/* coroutine_layout = CoroutineLayout {
field_tys: {
_0: CoroutineSavedTy {
_s0: CoroutineSavedTy {
ty: HasDrop,
source_info: SourceInfo {
span: $DIR/coroutine_tiny.rs:22:13: 22:15 (#0),
@ -14,15 +14,15 @@
Unresumed(0): [],
Returned (1): [],
Panicked (2): [],
Suspend0 (3): [_0],
Suspend0 (3): [_s0],
},
storage_conflicts: BitMatrix(1x1) {
(_0, _0),
(_s0, _s0),
},
} */
fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}>, _2: u8) -> CoroutineState<(), ()> {
debug _x => _10;
debug _x => _2;
let mut _0: std::ops::CoroutineState<(), ()>;
let _3: HasDrop;
let mut _4: !;
@ -31,19 +31,17 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}
let mut _7: ();
let _8: ();
let mut _9: ();
let _10: u8;
let mut _11: u32;
let mut _10: u32;
scope 1 {
debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop);
}
bb0: {
_11 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})));
switchInt(move _11) -> [0: bb1, 3: bb5, otherwise: bb6];
_10 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})));
switchInt(move _10) -> [0: bb1, 3: bb5, otherwise: bb6];
}
bb1: {
_10 = move _2;
nop;
(((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop) = HasDrop;
StorageLive(_4);

View file

@ -39,8 +39,8 @@
+ let mut _28: &mut std::task::Context<'_>;
+ let mut _29: ();
+ let mut _30: ();
+ let mut _31: &mut std::task::Context<'_>;
+ let mut _32: u32;
+ let mut _31: u32;
+ let mut _32: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _34: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _35: &mut {async fn body of ActionPermit<'_, T>::perform()};
@ -48,7 +48,6 @@
+ let mut _37: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _38: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ scope 7 {
+ let mut _15: std::future::Ready<()>;
+ scope 8 {
@ -58,14 +57,14 @@
+ scope 12 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ }
+ scope 13 (inlined <std::future::Ready<()> as Future>::poll) {
+ let mut _42: ();
+ let mut _43: std::option::Option<()>;
+ let mut _44: &mut std::option::Option<()>;
+ let mut _45: &mut std::future::Ready<()>;
+ let mut _46: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ let mut _41: ();
+ let mut _42: std::option::Option<()>;
+ let mut _43: &mut std::option::Option<()>;
+ let mut _44: &mut std::future::Ready<()>;
+ let mut _45: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
+ let mut _47: &mut &mut std::future::Ready<()>;
+ let mut _46: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ }
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
@ -75,22 +74,22 @@
+ }
+ }
+ scope 19 (inlined Option::<()>::take) {
+ let mut _48: std::option::Option<()>;
+ let mut _47: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _49: isize;
+ let mut _50: !;
+ let mut _48: isize;
+ let mut _49: !;
+ scope 23 {
+ }
+ }
+ }
+ }
+ scope 10 (inlined ready::<()>) {
+ let mut _41: std::option::Option<()>;
+ let mut _40: std::option::Option<()>;
+ }
+ scope 11 (inlined <std::future::Ready<()> as IntoFuture>::into_future) {
+ }
@ -145,10 +144,9 @@
+ StorageLive(_37);
+ StorageLive(_38);
+ StorageLive(_39);
+ StorageLive(_40);
+ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _32 = discriminant((*_33));
+ switchInt(move _32) -> [0: bb3, 1: bb10, 3: bb9, otherwise: bb5];
+ _32 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _31 = discriminant((*_32));
+ switchInt(move _31) -> [0: bb3, 1: bb10, 3: bb9, otherwise: bb5];
}
- bb3: {
@ -158,7 +156,6 @@
+ }
+
+ bb2: {
+ StorageDead(_40);
+ StorageDead(_39);
+ StorageDead(_38);
+ StorageDead(_37);
@ -186,23 +183,22 @@
}
+ bb3: {
+ _31 = move _9;
+ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _34 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>);
+ (((*_33) as variant#3).0: ActionPermit<'_, T>) = move ((*_34).0: ActionPermit<'_, T>);
+ StorageLive(_12);
+ StorageLive(_13);
+ StorageLive(_14);
+ _14 = ();
+ StorageLive(_41);
+ _41 = Option::<()>::Some(copy _14);
+ _13 = std::future::Ready::<()>(move _41);
+ StorageDead(_41);
+ StorageLive(_40);
+ _40 = Option::<()>::Some(copy _14);
+ _13 = std::future::Ready::<()>(move _40);
+ StorageDead(_40);
+ StorageDead(_14);
+ _12 = move _13;
+ StorageDead(_13);
+ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ (((*_36) as variant#3).1: std::future::Ready<()>) = move _12;
+ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ (((*_35) as variant#3).1: std::future::Ready<()>) = move _12;
+ goto -> bb4;
+ }
+
@ -214,39 +210,39 @@
+ StorageLive(_19);
+ StorageLive(_20);
+ StorageLive(_21);
+ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>);
+ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _21 = &mut (((*_36) as variant#3).1: std::future::Ready<()>);
+ _20 = &mut (*_21);
+ _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 };
+ StorageDead(_20);
+ StorageLive(_22);
+ StorageLive(_23);
+ StorageLive(_24);
+ _24 = copy _31;
+ _24 = copy _9;
+ _23 = move _24;
+ _22 = &mut (*_23);
+ StorageDead(_24);
+ StorageLive(_44);
+ StorageLive(_45);
+ StorageLive(_46);
+ StorageLive(_50);
+ StorageLive(_49);
+ StorageLive(_41);
+ StorageLive(_42);
+ StorageLive(_43);
+ StorageLive(_44);
+ _46 = &mut _19;
+ _45 = &mut _19;
+ StorageLive(_46);
+ _46 = &mut (_19.0: &mut std::future::Ready<()>);
+ _44 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_46);
+ _43 = &mut ((*_44).0: std::option::Option<()>);
+ StorageLive(_47);
+ _47 = &mut (_19.0: &mut std::future::Ready<()>);
+ _45 = copy (_19.0: &mut std::future::Ready<()>);
+ _47 = Option::<()>::None;
+ _42 = copy ((*_44).0: std::option::Option<()>);
+ ((*_44).0: std::option::Option<()>) = copy _47;
+ StorageDead(_47);
+ _44 = &mut ((*_45).0: std::option::Option<()>);
+ StorageDead(_43);
+ StorageLive(_48);
+ _48 = Option::<()>::None;
+ _43 = copy ((*_45).0: std::option::Option<()>);
+ ((*_45).0: std::option::Option<()>) = copy _48;
+ StorageDead(_48);
+ StorageDead(_44);
+ StorageLive(_49);
+ _49 = discriminant(_43);
+ switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5];
+ _48 = discriminant(_42);
+ switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5];
}
+
+ bb5: {
@ -266,8 +262,8 @@
+ StorageDead(_12);
+ StorageDead(_28);
+ StorageDead(_29);
+ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_38)) = 3;
+ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_37)) = 3;
+ goto -> bb2;
+ }
+
@ -281,14 +277,14 @@
+ StorageDead(_18);
+ StorageDead(_17);
+ StorageDead(_12);
+ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb8, unwind unreachable];
+ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ drop((((*_38) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb8, unwind unreachable];
+ }
+
+ bb8: {
+ _7 = Poll::<()>::Ready(move _30);
+ _40 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_40)) = 1;
+ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_39)) = 1;
+ goto -> bb2;
+ }
+
@ -298,7 +294,7 @@
+ StorageLive(_29);
+ _28 = move _9;
+ StorageDead(_29);
+ _31 = move _28;
+ _9 = move _28;
+ StorageDead(_28);
+ _16 = const ();
+ goto -> bb4;
@ -309,18 +305,18 @@
+ }
+
+ bb11: {
+ _50 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ _49 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable;
+ }
+
+ bb12: {
+ _42 = move ((_43 as Some).0: ());
+ StorageDead(_49);
+ StorageDead(_43);
+ _18 = Poll::<()>::Ready(move _42);
+ _41 = move ((_42 as Some).0: ());
+ StorageDead(_48);
+ StorageDead(_42);
+ StorageDead(_50);
+ StorageDead(_46);
+ _18 = Poll::<()>::Ready(move _41);
+ StorageDead(_41);
+ StorageDead(_49);
+ StorageDead(_45);
+ StorageDead(_44);
+ StorageDead(_22);
+ StorageDead(_19);
+ _25 = discriminant(_18);

View file

@ -39,8 +39,8 @@
+ let mut _28: &mut std::task::Context<'_>;
+ let mut _29: ();
+ let mut _30: ();
+ let mut _31: &mut std::task::Context<'_>;
+ let mut _32: u32;
+ let mut _31: u32;
+ let mut _32: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _34: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _35: &mut {async fn body of ActionPermit<'_, T>::perform()};
@ -50,7 +50,6 @@
+ let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _41: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ let mut _42: &mut {async fn body of ActionPermit<'_, T>::perform()};
+ scope 7 {
+ let mut _15: std::future::Ready<()>;
+ scope 8 {
@ -60,14 +59,14 @@
+ scope 12 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ }
+ scope 13 (inlined <std::future::Ready<()> as Future>::poll) {
+ let mut _44: ();
+ let mut _45: std::option::Option<()>;
+ let mut _46: &mut std::option::Option<()>;
+ let mut _47: &mut std::future::Ready<()>;
+ let mut _48: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ let mut _43: ();
+ let mut _44: std::option::Option<()>;
+ let mut _45: &mut std::option::Option<()>;
+ let mut _46: &mut std::future::Ready<()>;
+ let mut _47: &mut std::pin::Pin<&mut std::future::Ready<()>>;
+ scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) {
+ scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) {
+ let mut _49: &mut &mut std::future::Ready<()>;
+ let mut _48: &mut &mut std::future::Ready<()>;
+ scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) {
+ }
+ scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) {
@ -77,22 +76,22 @@
+ }
+ }
+ scope 19 (inlined Option::<()>::take) {
+ let mut _50: std::option::Option<()>;
+ let mut _49: std::option::Option<()>;
+ scope 20 (inlined std::mem::replace::<Option<()>>) {
+ scope 21 {
+ }
+ }
+ }
+ scope 22 (inlined #[track_caller] Option::<()>::expect) {
+ let mut _51: isize;
+ let mut _52: !;
+ let mut _50: isize;
+ let mut _51: !;
+ scope 23 {
+ }
+ }
+ }
+ }
+ scope 10 (inlined ready::<()>) {
+ let mut _43: std::option::Option<()>;
+ let mut _42: std::option::Option<()>;
+ }
+ scope 11 (inlined <std::future::Ready<()> as IntoFuture>::into_future) {
+ }
@ -149,10 +148,9 @@
+ StorageLive(_39);
+ StorageLive(_40);
+ StorageLive(_41);
+ StorageLive(_42);
+ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _32 = discriminant((*_33));
+ switchInt(move _32) -> [0: bb5, 1: bb15, 2: bb14, 3: bb13, otherwise: bb7];
+ _32 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _31 = discriminant((*_32));
+ switchInt(move _31) -> [0: bb5, 1: bb15, 2: bb14, 3: bb13, otherwise: bb7];
}
- bb3: {
@ -170,7 +168,6 @@
+ }
+
+ bb4: {
+ StorageDead(_42);
+ StorageDead(_41);
+ StorageDead(_40);
+ StorageDead(_39);
@ -203,23 +200,22 @@
- StorageDead(_2);
- return;
+ bb5: {
+ _31 = move _9;
+ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _34 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>);
+ (((*_33) as variant#3).0: ActionPermit<'_, T>) = move ((*_34).0: ActionPermit<'_, T>);
+ StorageLive(_12);
+ StorageLive(_13);
+ StorageLive(_14);
+ _14 = ();
+ StorageLive(_43);
+ _43 = Option::<()>::Some(copy _14);
+ _13 = std::future::Ready::<()>(move _43);
+ StorageDead(_43);
+ StorageLive(_42);
+ _42 = Option::<()>::Some(copy _14);
+ _13 = std::future::Ready::<()>(move _42);
+ StorageDead(_42);
+ StorageDead(_14);
+ _12 = move _13;
+ StorageDead(_13);
+ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ (((*_36) as variant#3).1: std::future::Ready<()>) = move _12;
+ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ (((*_35) as variant#3).1: std::future::Ready<()>) = move _12;
+ goto -> bb6;
}
@ -231,39 +227,39 @@
+ StorageLive(_19);
+ StorageLive(_20);
+ StorageLive(_21);
+ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>);
+ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ _21 = &mut (((*_36) as variant#3).1: std::future::Ready<()>);
+ _20 = &mut (*_21);
+ _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 };
+ StorageDead(_20);
+ StorageLive(_22);
+ StorageLive(_23);
+ StorageLive(_24);
+ _24 = copy _31;
+ _24 = copy _9;
+ _23 = move _24;
+ _22 = &mut (*_23);
+ StorageDead(_24);
+ StorageLive(_46);
+ StorageLive(_47);
+ StorageLive(_48);
+ StorageLive(_52);
+ StorageLive(_51);
+ StorageLive(_43);
+ StorageLive(_44);
+ StorageLive(_45);
+ StorageLive(_46);
+ _48 = &mut _19;
+ _47 = &mut _19;
+ StorageLive(_48);
+ _48 = &mut (_19.0: &mut std::future::Ready<()>);
+ _46 = copy (_19.0: &mut std::future::Ready<()>);
+ StorageDead(_48);
+ _45 = &mut ((*_46).0: std::option::Option<()>);
+ StorageLive(_49);
+ _49 = &mut (_19.0: &mut std::future::Ready<()>);
+ _47 = copy (_19.0: &mut std::future::Ready<()>);
+ _49 = Option::<()>::None;
+ _44 = copy ((*_46).0: std::option::Option<()>);
+ ((*_46).0: std::option::Option<()>) = copy _49;
+ StorageDead(_49);
+ _46 = &mut ((*_47).0: std::option::Option<()>);
+ StorageDead(_45);
+ StorageLive(_50);
+ _50 = Option::<()>::None;
+ _45 = copy ((*_47).0: std::option::Option<()>);
+ ((*_47).0: std::option::Option<()>) = copy _50;
+ StorageDead(_50);
+ StorageDead(_46);
+ StorageLive(_51);
+ _51 = discriminant(_45);
+ switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7];
+ _50 = discriminant(_44);
+ switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7];
}
- bb6 (cleanup): {
@ -285,8 +281,8 @@
+ StorageDead(_12);
+ StorageDead(_28);
+ StorageDead(_29);
+ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_38)) = 3;
+ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_37)) = 3;
+ goto -> bb4;
+ }
+
@ -300,14 +296,14 @@
+ StorageDead(_18);
+ StorageDead(_17);
+ StorageDead(_12);
+ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb10, unwind: bb12];
+ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ drop((((*_38) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb10, unwind: bb12];
+ }
+
+ bb10: {
+ _7 = Poll::<()>::Ready(move _30);
+ _40 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_40)) = 1;
+ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_39)) = 1;
+ goto -> bb4;
+ }
+
@ -319,13 +315,13 @@
+ StorageDead(_18);
+ StorageDead(_17);
+ StorageDead(_12);
+ _41 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ drop((((*_41) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb12, unwind terminate(cleanup)];
+ _40 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ drop((((*_40) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb12, unwind terminate(cleanup)];
+ }
+
+ bb12 (cleanup): {
+ _42 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_42)) = 2;
+ _41 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()});
+ discriminant((*_41)) = 2;
+ goto -> bb2;
+ }
+
@ -335,7 +331,7 @@
+ StorageLive(_29);
+ _28 = move _9;
+ StorageDead(_29);
+ _31 = move _28;
+ _9 = move _28;
+ StorageDead(_28);
+ _16 = const ();
+ goto -> bb6;
@ -350,18 +346,18 @@
+ }
+
+ bb16: {
+ _52 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ _51 = option::expect_failed(const "`Ready` polled after completion") -> bb11;
+ }
+
+ bb17: {
+ _44 = move ((_45 as Some).0: ());
+ StorageDead(_51);
+ StorageDead(_45);
+ _18 = Poll::<()>::Ready(move _44);
+ _43 = move ((_44 as Some).0: ());
+ StorageDead(_50);
+ StorageDead(_44);
+ StorageDead(_52);
+ StorageDead(_48);
+ _18 = Poll::<()>::Ready(move _43);
+ StorageDead(_43);
+ StorageDead(_51);
+ StorageDead(_47);
+ StorageDead(_46);
+ StorageDead(_22);
+ StorageDead(_19);
+ _25 = discriminant(_18);

View file

@ -1,6 +1,6 @@
//@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort -Zmir-opt-level=0
//@ check-pass
//@ only-x86_64
//@ only-64bit
//@ edition: 2024
//@ needs-unwind unwind edges are different with panic=abort

View file

@ -40,30 +40,28 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo
let _3: i32;
let mut _4: &i32;
let mut _5: ();
let mut _6: &mut Context<'_>;
let mut _7: u32;
let mut _6: u32;
let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
debug _task_context => _6;
debug _task_context => _2;
debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32));
debug y => _3;
bb0: {
_8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_7 = discriminant((*_8));
switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3];
_7 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_6 = discriminant((*_7));
switchInt(move _6) -> [0: bb1, 1: bb2, otherwise: bb3];
}
bb1: {
_6 = move _2;
StorageLive(_3);
_9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_4 = CopyForDeref(((*_9).0: &i32));
_8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_4 = CopyForDeref(((*_8).0: &i32));
_3 = (*_4);
_5 = ();
StorageDead(_3);
_0 = std::task::Poll::Ready(move _5);
_10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
discriminant((*_10)) = 1;
_9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
discriminant((*_9)) = 1;
return;
}
bb2: {
@ -78,30 +76,28 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c
let _3: i32;
let mut _4: &i32;
let mut _5: ();
let mut _6: &mut Context<'_>;
let mut _7: u32;
let mut _6: u32;
let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6};
debug _task_context => _6;
debug _task_context => _2;
debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32));
debug y => _3;
bb0: {
_8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_7 = discriminant((*_8));
switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3];
_7 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_6 = discriminant((*_7));
switchInt(move _6) -> [0: bb1, 1: bb2, otherwise: bb3];
}
bb1: {
_6 = move _2;
StorageLive(_3);
_9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_4 = CopyForDeref(((*_9).0: &i32));
_8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
_4 = CopyForDeref(((*_8).0: &i32));
_3 = (*_4);
_5 = ();
StorageDead(_3);
_0 = std::task::Poll::Ready(move _5);
_10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
discriminant((*_10)) = 1;
_9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}));
discriminant((*_9)) = 1;
return;
}
bb2: {