diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index 1017ccffb0b2a..89f022fbc6474 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -672,6 +672,11 @@ rustc_queries! { desc { "promoting constants in MIR for `{}`", tcx.def_path_str(key) } } + query mir_post_borrowck_cleanup(key: LocalDefId) -> &'tcx Steal> { + no_hash + desc { "post borrowck cleanup of MIR for `{}`", tcx.def_path_str(key) } + } + query closure_typeinfo(key: LocalDefId) -> ty::ClosureTypeInfo<'tcx> { desc { "finding symbols for captures of closure `{}`", diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 652fd00d54d02..49cd161d31db2 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1392,7 +1392,7 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, ) -> Option> { - let (body, _) = tcx.mir_promoted(def_id); + let body = tcx.mir_post_borrowck_cleanup(def_id); let body = body.borrow(); let body = &*body; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 9273c2103d442..180cec519a0eb 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -171,6 +171,7 @@ declare_passes! { mod promote_consts : PromoteTemps; mod ref_prop : ReferencePropagation; mod remove_noop_landing_pads : RemoveNoopLandingPads; + mod remove_dead_drops : RemoveDeadDrops; mod remove_place_mention : RemovePlaceMention; mod remove_storage_markers : RemoveStorageMarkers; mod remove_uninit_drops : RemoveUninitDrops; @@ -221,6 +222,7 @@ pub fn provide(providers: &mut Providers) { mir_built, mir_const_qualif, mir_promoted, + mir_post_borrowck_cleanup, mir_drops_elaborated_and_const_checked, mir_for_ctfe, mir_coroutine_witnesses: coroutine::mir_coroutine_witnesses, @@ -485,6 +487,19 @@ fn mir_promoted( (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted)) } +fn mir_post_borrowck_cleanup(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { + let (body, _) = tcx.mir_promoted(def); + let mut body = body.borrow().clone(); + pm::run_passes( + tcx, + &mut body, + &[&remove_dead_drops::RemoveDeadDrops], + None, + pm::Optimizations::Allowed, + ); + tcx.alloc_steal_mir(body) +} + /// Compute the MIR that is used during CTFE (and thus has no optimizations run on it) fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> { debug_assert!(!tcx.is_trivial_const(def_id), "Tried to get mir_for_ctfe of a trivial const"); @@ -543,7 +558,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & tcx.ensure_done().check_liveness(def); - let (body, _) = tcx.mir_promoted(def); + let body = tcx.mir_post_borrowck_cleanup(def); let mut body = body.steal(); if let Some(error_reported) = tainted_by_errors { diff --git a/compiler/rustc_mir_transform/src/remove_dead_drops.rs b/compiler/rustc_mir_transform/src/remove_dead_drops.rs new file mode 100644 index 0000000000000..abf2f717ed3dd --- /dev/null +++ b/compiler/rustc_mir_transform/src/remove_dead_drops.rs @@ -0,0 +1,62 @@ +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_mir_dataflow::impls::MaybeInitializedPlaces; +use rustc_mir_dataflow::move_paths::{LookupResult, MoveData}; +use rustc_mir_dataflow::{Analysis, MaybeReachable}; + +use super::simplify::simplify_cfg; + +pub(crate) struct RemoveDeadDrops; + +impl<'tcx> crate::MirPass<'tcx> for RemoveDeadDrops { + fn is_required(&self) -> bool { + true + } + + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + if body.coroutine.is_none() { + return; + } + + let move_data = MoveData::gather_moves(body, tcx, |_| true); + + let mut maybe_init_cursor = MaybeInitializedPlaces::new(tcx, body, &move_data) + .iterate_to_fixpoint(tcx, body, None) + .into_results_cursor(body); + + let mut dead_drops = Vec::new(); + + for (block, data) in body.basic_blocks.iter_enumerated() { + if let Some(terminator) = &data.terminator + && let TerminatorKind::Drop { place, target, .. } = &terminator.kind + { + let LookupResult::Exact(path) = move_data.rev_lookup.find(place.as_ref()) else { + continue; + }; + + let term_location = Location { block, statement_index: data.statements.len() }; + maybe_init_cursor.seek_before_primary_effect(term_location); + + let is_dead = match maybe_init_cursor.get() { + MaybeReachable::Unreachable => true, + MaybeReachable::Reachable(maybe_init) => !maybe_init.contains(path), + }; + + if is_dead { + dead_drops.push((block, *target)); + } + } + } + + if !dead_drops.is_empty() { + for (block, target) in dead_drops { + if let Some(terminator) = &mut body.basic_blocks.as_mut()[block].terminator { + terminator.kind = TerminatorKind::Goto { target }; + } + } + + // Removing drop terminators may simplify the CFG, so run cleanup. + simplify_cfg(tcx, body); + } + } +} 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 96ee37185db16..8da6495dfd87c 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 @@ -105,7 +105,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> bb0: { _39 = copy (_1.0: &mut {async fn body of b()}); _38 = discriminant((*_39)); - switchInt(move _38) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8]; + switchInt(move _38) -> [0: bb1, 1: bb27, 3: bb25, 4: bb26, otherwise: bb8]; } bb1: { @@ -206,30 +206,26 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> bb12: { nop; - goto -> bb13; - } - - bb13: { StorageDead(_4); StorageDead(_3); StorageLive(_21); StorageLive(_22); - _22 = a() -> [return: bb14, unwind unreachable]; + _22 = a() -> [return: bb13, unwind unreachable]; } - bb14: { - _21 = <{async fn body of a()} as IntoFuture>::into_future(move _22) -> [return: bb15, unwind unreachable]; + bb13: { + _21 = <{async fn body of a()} as IntoFuture>::into_future(move _22) -> [return: bb14, unwind unreachable]; } - bb15: { + bb14: { StorageDead(_22); PlaceMention(_21); nop; (((*_39) as variant#4).0: {async fn body of a()}) = move _21; - goto -> bb16; + goto -> bb15; } - bb16: { + bb15: { StorageLive(_24); StorageLive(_25); StorageLive(_26); @@ -237,34 +233,34 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> StorageLive(_28); _28 = &mut (((*_39) as variant#4).0: {async fn body of a()}); _27 = &mut (*_28); - _26 = Pin::<&mut {async fn body of a()}>::new_unchecked(move _27) -> [return: bb17, unwind unreachable]; + _26 = Pin::<&mut {async fn body of a()}>::new_unchecked(move _27) -> [return: bb16, unwind unreachable]; } - bb17: { + bb16: { StorageDead(_27); StorageLive(_29); StorageLive(_30); StorageLive(_31); _31 = copy _2; _30 = move _31; - goto -> bb18; + goto -> bb17; } - bb18: { + bb17: { _29 = &mut (*_30); StorageDead(_31); - _25 = <{async fn body of a()} as Future>::poll(move _26, move _29) -> [return: bb19, unwind unreachable]; + _25 = <{async fn body of a()} as Future>::poll(move _26, move _29) -> [return: bb18, unwind unreachable]; } - bb19: { + bb18: { StorageDead(_29); StorageDead(_26); PlaceMention(_25); _32 = discriminant(_25); - switchInt(move _32) -> [0: bb21, 1: bb20, otherwise: bb8]; + switchInt(move _32) -> [0: bb20, 1: bb19, otherwise: bb8]; } - bb20: { + bb19: { _24 = const (); StorageDead(_30); StorageDead(_28); @@ -281,7 +277,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> return; } - bb21: { + bb20: { StorageLive(_33); _33 = copy ((_25 as Ready).0: ()); _37 = copy _33; @@ -290,38 +286,34 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> StorageDead(_28); StorageDead(_25); StorageDead(_24); - drop((((*_39) as variant#4).0: {async fn body of a()})) -> [return: bb23, unwind unreachable]; + drop((((*_39) as variant#4).0: {async fn body of a()})) -> [return: bb22, unwind unreachable]; } - bb22: { + bb21: { StorageDead(_36); _2 = move _35; StorageDead(_35); _7 = const (); - goto -> bb16; + goto -> bb15; } - bb23: { + bb22: { nop; - goto -> bb24; - } - - bb24: { StorageDead(_21); - goto -> bb26; + goto -> bb24; } - bb25: { + bb23: { _0 = Poll::<()>::Ready(move _37); discriminant((*_39)) = 1; return; } - bb26: { - goto -> bb25; + bb24: { + goto -> bb23; } - bb27: { + bb25: { StorageLive(_3); StorageLive(_4); StorageLive(_19); @@ -330,15 +322,15 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> goto -> bb11; } - bb28: { + bb26: { StorageLive(_21); StorageLive(_35); StorageLive(_36); _35 = move _2; - goto -> bb22; + goto -> bb21; } - bb29: { - assert(const false, "`async fn` resumed after completion") -> [success: bb29, unwind unreachable]; + bb27: { + assert(const false, "`async fn` resumed after completion") -> [success: bb27, unwind unreachable]; } } 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 index b61215dc28cb4..428d29fc518ad 100644 --- a/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir +++ b/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir @@ -45,7 +45,7 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2 bb0: { _18 = 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]; + switchInt(move _17) -> [0: bb1, 1: bb15, 3: bb13, 4: bb14, otherwise: bb16]; } bb1: { @@ -67,10 +67,6 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2 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); @@ -79,16 +75,12 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2 return; } - bb5: { - goto -> bb6; - } - - bb6: { + bb4: { StorageDead(_4); - drop(_3) -> [return: bb7, unwind unreachable]; + drop(_3) -> [return: bb5, unwind unreachable]; } - bb7: { + bb5: { StorageDead(_3); StorageLive(_8); StorageLive(_9); @@ -99,24 +91,20 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2 StorageLive(_12); StorageLive(_13); _13 = &(((*_18) as variant#4).0: std::string::String); - _12 = ::clone(move _13) -> [return: bb8, unwind unreachable]; + _12 = ::clone(move _13) -> [return: bb6, unwind unreachable]; } - bb8: { + bb6: { StorageDead(_13); StorageLive(_14); StorageLive(_15); - _15 = Location::<'_>::caller() -> [return: bb9, unwind unreachable]; + _15 = Location::<'_>::caller() -> [return: bb7, unwind unreachable]; } - bb9: { + bb7: { _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); @@ -128,58 +116,54 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2 return; } - bb11: { - goto -> bb12; - } - - bb12: { + bb8: { StorageDead(_9); - drop(_8) -> [return: bb13, unwind unreachable]; + drop(_8) -> [return: bb9, unwind unreachable]; } - bb13: { + bb9: { StorageDead(_15); StorageDead(_11); StorageDead(_8); _16 = const (); - drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable]; + drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb10, unwind unreachable]; } - bb14: { - goto -> bb16; + bb10: { + goto -> bb12; } - bb15: { + bb11: { _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Complete(move _16); discriminant((*_18)) = 1; return; } - bb16: { - goto -> bb15; + bb12: { + goto -> bb11; } - bb17: { + bb13: { StorageLive(_3); StorageLive(_4); _3 = move _2; - goto -> bb5; + goto -> bb4; } - bb18: { + bb14: { StorageLive(_8); StorageLive(_9); StorageLive(_11); StorageLive(_15); _8 = move _2; - goto -> bb11; + goto -> bb8; } - bb19: { - assert(const false, "coroutine resumed after completion") -> [success: bb19, unwind unreachable]; + bb15: { + assert(const false, "coroutine resumed after completion") -> [success: bb15, unwind unreachable]; } - bb20: { + bb16: { unreachable; } } 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 index aac028a9e6c0e..23d0afa337deb 100644 --- a/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir +++ b/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir @@ -45,7 +45,7 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2 bb0: { _18 = 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]; + switchInt(move _17) -> [0: bb1, 1: bb15, 3: bb13, 4: bb14, otherwise: bb16]; } bb1: { @@ -67,10 +67,6 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2 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); @@ -79,16 +75,12 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2 return; } - bb5: { - goto -> bb6; - } - - bb6: { + bb4: { StorageDead(_4); - drop(_3) -> [return: bb7, unwind unreachable]; + drop(_3) -> [return: bb5, unwind unreachable]; } - bb7: { + bb5: { StorageDead(_3); StorageLive(_8); StorageLive(_9); @@ -99,24 +91,20 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2 StorageLive(_12); StorageLive(_13); _13 = &(((*_18) as variant#4).0: std::string::String); - _12 = ::clone(move _13) -> [return: bb8, unwind unreachable]; + _12 = ::clone(move _13) -> [return: bb6, unwind unreachable]; } - bb8: { + bb6: { StorageDead(_13); StorageLive(_14); StorageLive(_15); - _15 = Location::<'_>::caller() -> [return: bb9, unwind unreachable]; + _15 = Location::<'_>::caller() -> [return: bb7, unwind unreachable]; } - bb9: { + bb7: { _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); @@ -128,58 +116,54 @@ fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2 return; } - bb11: { - goto -> bb12; - } - - bb12: { + bb8: { StorageDead(_9); - drop(_8) -> [return: bb13, unwind unreachable]; + drop(_8) -> [return: bb9, unwind unreachable]; } - bb13: { + bb9: { StorageDead(_15); StorageDead(_11); StorageDead(_8); _16 = const (); - drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable]; + drop((((*_18) as variant#4).0: std::string::String)) -> [return: bb10, unwind unreachable]; } - bb14: { - goto -> bb16; + bb10: { + goto -> bb12; } - bb15: { + bb11: { _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Complete(move _16); discriminant((*_18)) = 1; return; } - bb16: { - goto -> bb15; + bb12: { + goto -> bb11; } - bb17: { + bb13: { StorageLive(_3); StorageLive(_4); _3 = move _2; - goto -> bb5; + goto -> bb4; } - bb18: { + bb14: { StorageLive(_8); StorageLive(_9); StorageLive(_11); StorageLive(_15); _8 = move _2; - goto -> bb11; + goto -> bb8; } - bb19: { - assert(const false, "coroutine resumed after completion") -> [success: bb19, unwind unreachable]; + bb15: { + assert(const false, "coroutine resumed after completion") -> [success: bb15, unwind unreachable]; } - bb20: { + bb16: { unreachable; } } diff --git a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir index 4731aed335d9f..6500af9310616 100644 --- a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir +++ b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-abort.mir @@ -27,7 +27,7 @@ yields () StorageLive(_5); StorageLive(_6); _6 = (); - _5 = yield(move _6) -> [resume: bb1, drop: bb6]; + _5 = yield(move _6) -> [resume: bb1, drop: bb5]; } bb1: { @@ -53,31 +53,27 @@ yields () StorageDead(_9); _0 = const (); StorageDead(_4); - goto -> bb4; - } - - bb4: { StorageDead(_3); - drop(_1) -> [return: bb5, unwind unreachable]; + drop(_1) -> [return: bb4, unwind unreachable]; } - bb5: { + bb4: { return; } - bb6: { + bb5: { StorageDead(_6); StorageDead(_5); StorageDead(_4); - drop(_3) -> [return: bb7, unwind unreachable]; + drop(_3) -> [return: bb6, unwind unreachable]; } - bb7: { + bb6: { StorageDead(_3); - drop(_1) -> [return: bb8, unwind unreachable]; + drop(_1) -> [return: bb7, unwind unreachable]; } - bb8: { + bb7: { coroutine_drop; } } diff --git a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir index 14e1782b86016..2347cea599112 100644 --- a/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir +++ b/tests/mir-opt/coroutine_storage_dead_unwind.main-{closure#0}.StateTransform.before.panic-unwind.mir @@ -27,7 +27,7 @@ yields () StorageLive(_5); StorageLive(_6); _6 = (); - _5 = yield(move _6) -> [resume: bb1, drop: bb6]; + _5 = yield(move _6) -> [resume: bb1, drop: bb5]; } bb1: { @@ -36,7 +36,7 @@ yields () StorageLive(_7); StorageLive(_8); _8 = move _3; - _7 = take::(move _8) -> [return: bb2, unwind: bb10]; + _7 = take::(move _8) -> [return: bb2, unwind: bb9]; } bb2: { @@ -45,7 +45,7 @@ yields () StorageLive(_9); StorageLive(_10); _10 = move _4; - _9 = take::(move _10) -> [return: bb3, unwind: bb9]; + _9 = take::(move _10) -> [return: bb3, unwind: bb8]; } bb3: { @@ -53,66 +53,54 @@ yields () StorageDead(_9); _0 = const (); StorageDead(_4); - goto -> bb4; - } - - bb4: { StorageDead(_3); - drop(_1) -> [return: bb5, unwind: bb14]; + drop(_1) -> [return: bb4, unwind: bb11]; } - bb5: { + bb4: { return; } - bb6: { + bb5: { StorageDead(_6); StorageDead(_5); StorageDead(_4); - drop(_3) -> [return: bb7, unwind: bb15]; + drop(_3) -> [return: bb6, unwind: bb12]; } - bb7: { + bb6: { StorageDead(_3); - drop(_1) -> [return: bb8, unwind: bb14]; + drop(_1) -> [return: bb7, unwind: bb11]; } - bb8: { + bb7: { coroutine_drop; } - bb9 (cleanup): { + bb8 (cleanup): { StorageDead(_10); StorageDead(_9); - goto -> bb12; + goto -> bb10; } - bb10 (cleanup): { - goto -> bb11; - } - - bb11 (cleanup): { + bb9 (cleanup): { StorageDead(_8); StorageDead(_7); - goto -> bb12; + goto -> bb10; } - bb12 (cleanup): { + bb10 (cleanup): { StorageDead(_4); - goto -> bb13; - } - - bb13 (cleanup): { StorageDead(_3); - drop(_1) -> [return: bb14, unwind terminate(cleanup)]; + drop(_1) -> [return: bb11, unwind terminate(cleanup)]; } - bb14 (cleanup): { + bb11 (cleanup): { resume; } - bb15 (cleanup): { + bb12 (cleanup): { StorageDead(_3); - drop(_1) -> [return: bb14, unwind terminate(cleanup)]; + drop(_1) -> [return: bb11, unwind terminate(cleanup)]; } } diff --git a/tests/ui/coroutine/minimal_reproducer.rs b/tests/ui/coroutine/minimal_reproducer.rs new file mode 100644 index 0000000000000..895cd3e748335 --- /dev/null +++ b/tests/ui/coroutine/minimal_reproducer.rs @@ -0,0 +1,31 @@ +//@ check-pass +#![feature(coroutines, coroutine_trait, stmt_expr_attributes, negative_impls)] + +use std::ops::Coroutine; + +struct Guard; +impl !Send for Guard {} +impl Drop for Guard { + fn drop(&mut self) {} +} + +fn lock() -> Guard { + Guard +} + +fn bar() -> impl Coroutine { + #[coroutine] + static || { + let mut guard = lock(); + loop { + drop(guard); + yield; + guard = lock(); + } + } +} + +fn main() { + fn require_send(_: T) {} + require_send(bar()); +} diff --git a/tests/ui/coroutine/mutex_guard_await.rs b/tests/ui/coroutine/mutex_guard_await.rs new file mode 100644 index 0000000000000..46c1daa0ff1ca --- /dev/null +++ b/tests/ui/coroutine/mutex_guard_await.rs @@ -0,0 +1,26 @@ +//@ check-pass +//@ edition: 2024 + +use std::sync::Mutex; + +struct Fut; +impl std::future::Future for Fut { + type Output = (); + fn poll(self: std::pin::Pin<&mut Self>, _cx: &mut std::task::Context<'_>) -> std::task::Poll<()> { + std::task::Poll::Ready(()) + } +} + +async fn bar(mutex: &Mutex<()>) { + let mut guard = mutex.lock(); + loop { + drop(guard); + Fut.await; + guard = mutex.lock(); + } +} + +fn main() { + fn require_send(_: T) {} + require_send(bar(&Mutex::new(()))); +}