Skip to content

Commit

Permalink
Check the base of the place too!
Browse files Browse the repository at this point in the history
  • Loading branch information
compiler-errors committed Apr 5, 2024
1 parent 0f13bd4 commit 49c4ebc
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 6 deletions.
26 changes: 20 additions & 6 deletions compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
use rustc_data_structures::unord::UnordMap;
use rustc_hir as hir;
use rustc_middle::hir::place::{Projection, ProjectionKind};
use rustc_middle::hir::place::{PlaceBase, Projection, ProjectionKind};
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::{self, dump_mir, MirPass};
use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, TypeVisitableExt};
Expand Down Expand Up @@ -149,17 +149,25 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
bug!("we ran out of parent captures!")
};

let PlaceBase::Upvar(parent_base) = parent_capture.place.base else {
bug!("expected capture to be an upvar");
};
let PlaceBase::Upvar(child_base) = child_capture.place.base else {
bug!("expected capture to be an upvar");
};

assert!(
child_capture.place.projections.len() >= parent_capture.place.projections.len()
);
// A parent matches a child they share the same prefix of projections.
// The child may have more, if it is capturing sub-fields out of
// something that is captured by-move in the parent closure.
if !std::iter::zip(
&child_capture.place.projections,
&parent_capture.place.projections,
)
.all(|(child, parent)| child.kind == parent.kind)
if parent_base.var_path.hir_id != child_base.var_path.hir_id
|| !std::iter::zip(
&child_capture.place.projections,
&parent_capture.place.projections,
)
.all(|(child, parent)| child.kind == parent.kind)
{
// Make sure the field was used at least once.
assert!(
Expand Down Expand Up @@ -217,6 +225,12 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
}
}

// Pop the last parent capture
if field_used_at_least_once {
let _ = parent_captures.next().unwrap();
}
assert_eq!(parent_captures.next(), None, "leftover parent captures?");

if coroutine_kind == ty::ClosureKind::FnOnce {
assert_eq!(field_remapping.len(), tcx.closure_captures(parent_def_id).len());
return;
Expand Down
27 changes: 27 additions & 0 deletions tests/ui/async-await/async-closures/overlapping-projs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//@ aux-build:block-on.rs
//@ edition:2021
//@ run-pass
//@ check-run-results

#![feature(async_closure)]

extern crate block_on;

async fn call_once(f: impl async FnOnce()) {
f().await;
}

async fn async_main() {
let x = &mut 0;
let y = &mut 0;
let c = async || {
*x = 1;
*y = 2;
};
call_once(c).await;
println!("{x} {y}");
}

fn main() {
block_on::block_on(async_main());
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
1 2

0 comments on commit 49c4ebc

Please sign in to comment.