diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index da2245b12d2c2..28142382b130b 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -471,7 +471,7 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all function arguments. #[inline] - pub fn args_iter(&self) -> impl Iterator + ExactSizeIterator { + pub fn args_iter(&self) -> impl Iterator + ExactSizeIterator + use<> { (1..self.arg_count + 1).map(Local::new) } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 466b9c7a3c23a..a509c40c89cd6 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -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 {} } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 029586a9c554c..b79b67c5927b0 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1359,6 +1359,7 @@ impl<'tcx> Ty<'tcx> { /// 2229 drop reorder migration analysis. #[inline] pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + assert!(!self.has_non_region_infer()); // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1371,14 +1372,6 @@ impl<'tcx> Ty<'tcx> { _ => self, }; - // FIXME(#86868): We should be canonicalizing, or else moving this to a method of inference - // context, or *something* like that, but for now just avoid passing inference - // variables to queries that can't cope with them. Instead, conservatively - // return "true" (may change drop order). - if query_ty.has_infer() { - return true; - } - // This doesn't depend on regions, so try to minimize distinct // query keys used. let erased = tcx.normalize_erasing_regions(typing_env, query_ty); diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 4603c695dedd5..08316aaed3b42 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -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; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 3525c7c1d1a99..5fcd0386170cb 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -751,7 +751,8 @@ impl Session { // ELF x86-64 abi, but it can be disabled for some compilation units. // // Typically when we're compiling with `-C panic=abort` we don't need - // `uwtable` because we can't generate any exceptions! + // `uwtable` because we can't generate any exceptions! But note that + // some targets require unwind tables to generate backtraces. // Unwind tables are needed when compiling with `-C panic=unwind`, but // LLVM won't omit unwind tables unless the function is also marked as // `nounwind`, so users are allowed to disable `uwtable` emission. diff --git a/compiler/rustc_target/src/spec/base/android.rs b/compiler/rustc_target/src/spec/base/android.rs index 0426ea44c6a21..df2757aaabf65 100644 --- a/compiler/rustc_target/src/spec/base/android.rs +++ b/compiler/rustc_target/src/spec/base/android.rs @@ -8,10 +8,6 @@ pub(crate) fn opts() -> TargetOptions { base.tls_model = TlsModel::Emulated; base.has_thread_local = false; base.supported_sanitizers = SanitizerSet::ADDRESS; - // This is for backward compatibility, see https://github.com/rust-lang/rust/issues/49867 - // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution - // was to always emit `uwtable`). - base.default_uwtable = true; base.crt_static_respected = true; base } diff --git a/compiler/rustc_target/src/spec/base/linux.rs b/compiler/rustc_target/src/spec/base/linux.rs index 9982c254eca52..26e4590cf5e69 100644 --- a/compiler/rustc_target/src/spec/base/linux.rs +++ b/compiler/rustc_target/src/spec/base/linux.rs @@ -12,6 +12,9 @@ pub(crate) fn opts() -> TargetOptions { relro_level: RelroLevel::Full, has_thread_local: true, crt_static_respected: true, + // We want backtraces to work by default and they rely on unwind tables + // (regardless of `-C panic` strategy). + default_uwtable: true, supported_split_debuginfo: Cow::Borrowed(&[ SplitDebuginfo::Packed, SplitDebuginfo::Unpacked, diff --git a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir index 347e4119cd0e0..050aac7c3ff05 100644 --- a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir +++ b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir @@ -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()}>, _2: &mut Context<'_>) -> Poll<()> { - debug _task_context => _19; + debug _task_context => _2; debug x => ((*(_1.0: &mut {async fn body of a()})).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()}>, _2: &mut Context<'_>) let mut _16: &mut impl std::future::Future; let mut _17: std::pin::Pin<&mut impl std::future::Future>; 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()})) as variant#4).0: T); } bb0: { - _20 = discriminant((*(_1.0: &mut {async fn body of a()}))); - switchInt(move _20) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14]; + _19 = discriminant((*(_1.0: &mut {async fn body of a()}))); + switchInt(move _19) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14]; } bb1: { diff --git a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir index b1cf5373f9191..796e95ff3d825 100644 --- a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir +++ b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir @@ -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()}>, _2: &mut Context<'_>) -> Poll<()> { - debug _task_context => _19; + debug _task_context => _2; debug x => ((*(_1.0: &mut {async fn body of a()})).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()}>, _2: &mut Context<'_>) let mut _16: &mut impl std::future::Future; let mut _17: std::pin::Pin<&mut impl std::future::Future>; 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()})) as variant#4).0: T); } bb0: { - _20 = discriminant((*(_1.0: &mut {async fn body of a()}))); - switchInt(move _20) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19]; + _19 = discriminant((*(_1.0: &mut {async fn body of a()}))); + switchInt(move _19) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19]; } bb1: { diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir index 7480324b17791..2e2876cb3fcf2 100644 --- a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir @@ -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; } diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 9bff257e06392..20fc4112ef288 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -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; diff --git a/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir b/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir new file mode 100644 index 0000000000000..d8fdb446135b3 --- /dev/null +++ b/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir @@ -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 = ::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 = ::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 +} diff --git a/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir b/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir new file mode 100644 index 0000000000000..dd17afad656b8 --- /dev/null +++ b/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir @@ -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 = ::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 = ::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 +} diff --git a/tests/mir-opt/building/coroutine.rs b/tests/mir-opt/building/coroutine.rs new file mode 100644 index 0000000000000..6d50c4d90b1a4 --- /dev/null +++ b/tests/mir-opt/building/coroutine.rs @@ -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()); + }; +} diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir index 7e033916fd348..33fbca7f77ed1 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir @@ -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: { diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir index 613ef2909b5e4..69e7219af9ff8 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir @@ -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: { diff --git a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir index f8b3f68d21e63..9905cc3e00f99 100644 --- a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir @@ -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); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 22e6ea722ddaf..2ae86e2eb8bbd 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -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 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 > 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::>) { + 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 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); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 8b027e988b8e8..d7ae931aaae58 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -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 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 > 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::>) { + 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 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); diff --git a/tests/run-make/musl-default-linking/rmake.rs b/tests/run-make/musl-default-linking/rmake.rs index 7bb54e2739c9d..1b30c538b5e30 100644 --- a/tests/run-make/musl-default-linking/rmake.rs +++ b/tests/run-make/musl-default-linking/rmake.rs @@ -4,7 +4,7 @@ use run_make_support::{rustc, serde_json}; // Per https://github.com/rust-lang/compiler-team/issues/422, // we should be trying to move these targets to dynamically link // musl libc by default. -//@ needs-llvm-components: aarch64 arm mips powerpc riscv systemz x86 +//@ needs-llvm-components: aarch64 arm mips powerpc x86 static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[ "aarch64-unknown-linux-musl", "arm-unknown-linux-musleabi", @@ -14,16 +14,8 @@ static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[ "armv7-unknown-linux-musleabihf", "i586-unknown-linux-musl", "i686-unknown-linux-musl", - "mips64-unknown-linux-musl", - "mips64-unknown-linux-muslabi64", "mips64el-unknown-linux-muslabi64", - "powerpc-unknown-linux-musl", - "powerpc-unknown-linux-muslspe", - "powerpc64-unknown-linux-musl", "powerpc64le-unknown-linux-musl", - "riscv32gc-unknown-linux-musl", - "s390x-unknown-linux-musl", - "thumbv7neon-unknown-linux-musleabihf", "x86_64-unknown-linux-musl", ]; diff --git a/tests/run-make/panic-abort-eh_frame/rmake.rs b/tests/run-make/panic-abort-eh_frame/rmake.rs index 23d95dc577491..2eccde627955c 100644 --- a/tests/run-make/panic-abort-eh_frame/rmake.rs +++ b/tests/run-make/panic-abort-eh_frame/rmake.rs @@ -1,9 +1,11 @@ // An `.eh_frame` section in an object file is a symptom of an UnwindAction::Terminate // being inserted, useful for determining whether or not unwinding is necessary. -// This is useless when panics would NEVER unwind due to -C panic=abort. This section should -// therefore never appear in the emit file of a -C panic=abort compilation, and this test -// checks that this is respected. -// See https://github.com/rust-lang/rust/pull/112403 +// This is useless when panics would NEVER unwind due to -C panic=abort and when we don't need +// being able to generate backtraces (which depend on unwind tables on linux). This section should +// therefore never appear in the emit file of a -C panic=abort compilation +// with -C force-unwind-tables=no, and this test checks that this is respected. +// See https://github.com/rust-lang/rust/pull/112403 and +// https://github.com/rust-lang/rust/pull/143613. //@ only-linux // FIXME(Oneirical): the DW_CFA symbol appears on Windows-gnu, because uwtable @@ -19,6 +21,7 @@ fn main() { .panic("abort") .edition("2021") .arg("-Zvalidate-mir") + .arg("-Cforce-unwind-tables=no") .run(); llvm_objdump().arg("--dwarf=frames").input("foo.o").run().assert_stdout_not_contains("DW_CFA"); } diff --git a/tests/ui/panics/panic-abort-backtrace.rs b/tests/ui/panics/panic-abort-backtrace.rs new file mode 100644 index 0000000000000..1424b305ca0e0 --- /dev/null +++ b/tests/ui/panics/panic-abort-backtrace.rs @@ -0,0 +1,50 @@ +//! Test that with `-C panic=abort` the backtrace is not cut off by default +//! (i.e. without using `-C force-unwind-tables=yes`) by ensuring that our own +//! functions are in the backtrace. If we just check one function it might be +//! the last function, so make sure the backtrace can continue by checking for +//! two functions. Regression test for +//! . + +//@ run-pass +//@ needs-subprocess +//@ compile-flags: -C panic=abort -C opt-level=0 +//@ no-prefer-dynamic + +static FN_1: &str = "this_function_must_be_in_the_backtrace"; +fn this_function_must_be_in_the_backtrace() { + and_this_function_too(); +} + +static FN_2: &str = "and_this_function_too"; +fn and_this_function_too() { + panic!("generate panic backtrace"); +} + +fn run_test() { + let output = std::process::Command::new(std::env::current_exe().unwrap()) + .arg("whatever") + .env("RUST_BACKTRACE", "full") + .output() + .unwrap(); + let backtrace = std::str::from_utf8(&output.stderr).unwrap(); + + fn assert(function_name: &str, backtrace: &str) { + assert!( + backtrace.contains(function_name), + "ERROR: no `{}` in stderr! actual stderr: {}", + function_name, + backtrace + ); + } + assert(FN_1, backtrace); + assert(FN_2, backtrace); +} + +fn main() { + let args: Vec = std::env::args().collect(); + if args.len() == 1 { + run_test(); + } else { + this_function_must_be_in_the_backtrace(); + } +} diff --git a/tests/ui/type-inference/has_sigdrop.rs b/tests/ui/type-inference/has_sigdrop.rs new file mode 100644 index 0000000000000..c3d835cfe16f8 --- /dev/null +++ b/tests/ui/type-inference/has_sigdrop.rs @@ -0,0 +1,18 @@ +//@ run-pass +// Inference, canonicalization, and significant drops should work nicely together. +// Related issue: #86868 + +#[clippy::has_significant_drop] +struct DropGuy {} + +fn creator() -> DropGuy { + DropGuy {} +} + +fn dropper() { + let _ = creator(); +} + +fn main() { + dropper(); +}