Auto merge of #117712 - lcnr:expand-coroutine, r=jackh726
generator layout: ignore fake borrows
fixes #117059
We emit fake shallow borrows in case the scrutinee place uses a `Deref` and there is a match guard. This is necessary to prevent the match guard from mutating the scrutinee: fab1054e17/compiler/rustc_mir_build/src/build/matches/mod.rs (L1250-L1265)
These fake borrows end up impacting the generator witness computation in `mir_generator_witnesses`, which causes the issue in #117059. This PR now completely ignores fake borrows during this computation. This is sound as thse are always removed after analysis and the actual computation of the generator layout happens afterwards.
Only the second commit impacts behavior, and could be backported by itself.
r? types
This commit is contained in:
commit
b7583d38b7
40 changed files with 140 additions and 91 deletions
|
@ -4,13 +4,13 @@
|
|||
//!
|
||||
//! - [`AscribeUserType`]
|
||||
//! - [`FakeRead`]
|
||||
//! - [`Assign`] statements with a [`Shallow`] borrow
|
||||
//! - [`Assign`] statements with a [`Fake`] borrow
|
||||
//!
|
||||
//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
|
||||
//! [`Assign`]: rustc_middle::mir::StatementKind::Assign
|
||||
//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
|
||||
//! [`Nop`]: rustc_middle::mir::StatementKind::Nop
|
||||
//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
|
||||
//! [`Fake`]: rustc_middle::mir::BorrowKind::Fake
|
||||
|
||||
use crate::MirPass;
|
||||
use rustc_middle::mir::{Body, BorrowKind, Rvalue, StatementKind, TerminatorKind};
|
||||
|
@ -24,7 +24,7 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
|
|||
for statement in basic_block.statements.iter_mut() {
|
||||
match statement.kind {
|
||||
StatementKind::AscribeUserType(..)
|
||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
|
||||
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Fake, _)))
|
||||
| StatementKind::FakeRead(..) => statement.make_nop(),
|
||||
_ => (),
|
||||
}
|
||||
|
|
|
@ -668,7 +668,7 @@ impl<'tcx> Visitor<'tcx> for CanConstProp {
|
|||
// These can't ever be propagated under any scheme, as we can't reason about indirect
|
||||
// mutation.
|
||||
| NonMutatingUse(NonMutatingUseContext::SharedBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::FakeBorrow)
|
||||
| NonMutatingUse(NonMutatingUseContext::AddressOf)
|
||||
| MutatingUse(MutatingUseContext::Borrow)
|
||||
| MutatingUse(MutatingUseContext::AddressOf) => {
|
||||
|
|
|
@ -131,7 +131,7 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
|
|||
let observes_address = match ctxt {
|
||||
PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow
|
||||
| NonMutatingUseContext::ShallowBorrow
|
||||
| NonMutatingUseContext::FakeBorrow
|
||||
| NonMutatingUseContext::AddressOf,
|
||||
) => true,
|
||||
// For debuginfo, merging locals is ok.
|
||||
|
|
|
@ -637,6 +637,14 @@ struct LivenessInfo {
|
|||
storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
|
||||
}
|
||||
|
||||
/// Computes which locals have to be stored in the state-machine for the
|
||||
/// given coroutine.
|
||||
///
|
||||
/// The basic idea is as follows:
|
||||
/// - a local is live until we encounter a `StorageDead` statement. In
|
||||
/// case none exist, the local is considered to be always live.
|
||||
/// - a local has to be stored if it is either directly used after the
|
||||
/// the suspend point, or if it is live and has been previously borrowed.
|
||||
fn locals_live_across_suspend_points<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
|
@ -1449,16 +1457,15 @@ pub(crate) fn mir_coroutine_witnesses<'tcx>(
|
|||
// The first argument is the coroutine type passed by value
|
||||
let coroutine_ty = body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty;
|
||||
|
||||
// Get the interior types and args which typeck computed
|
||||
let movable = match *coroutine_ty.kind() {
|
||||
ty::Coroutine(_, _, movability) => movability == hir::Movability::Movable,
|
||||
ty::Error(_) => return None,
|
||||
_ => span_bug!(body.span, "unexpected coroutine type {}", coroutine_ty),
|
||||
};
|
||||
|
||||
// When first entering the coroutine, move the resume argument into its new local.
|
||||
let always_live_locals = always_storage_live_locals(&body);
|
||||
// The witness simply contains all locals live across suspend points.
|
||||
|
||||
let always_live_locals = always_storage_live_locals(&body);
|
||||
let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
|
||||
|
||||
// Extract locals which are live across suspension point into `layout`
|
||||
|
|
|
@ -234,7 +234,7 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
|
|||
// so we have to remove them too.
|
||||
PlaceContext::NonMutatingUse(
|
||||
NonMutatingUseContext::SharedBorrow
|
||||
| NonMutatingUseContext::ShallowBorrow
|
||||
| NonMutatingUseContext::FakeBorrow
|
||||
| NonMutatingUseContext::AddressOf,
|
||||
)
|
||||
| PlaceContext::MutatingUse(_) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue