From ad0fcac72b4fbd5a6558fa1d440882156eafae33 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 5 Apr 2024 17:34:57 -0400 Subject: [PATCH] Account for an additional reborrow inserted by UniqueImmBorrow and MutBorrow --- .../src/coroutine/by_move_body.rs | 11 +++++--- .../async-closures/mut-ref-reborrow.rs | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 tests/ui/async-await/async-closures/mut-ref-reborrow.rs diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index d94441b1413..320d8fd3977 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -289,10 +289,15 @@ impl<'tcx> MutVisitor<'tcx> for MakeByMoveBody<'tcx> { // generating, we also are taking that field by value. Peel off a deref, // since a layer of reffing has now become redundant. let final_deref = if needs_deref { - let [mir::ProjectionElem::Deref] = projection else { - bug!("There should only be a single deref for an upvar local initialization"); + let Some((mir::ProjectionElem::Deref, projection)) = projection.split_first() + else { + bug!( + "There should be at least a single deref for an upvar local initialization, found {projection:#?}" + ); }; - &[] + // There may be more derefs, since we may also implicitly reborrow + // a captured mut pointer. + projection } else { projection }; diff --git a/tests/ui/async-await/async-closures/mut-ref-reborrow.rs b/tests/ui/async-await/async-closures/mut-ref-reborrow.rs new file mode 100644 index 00000000000..9f2cbd7ce1c --- /dev/null +++ b/tests/ui/async-await/async-closures/mut-ref-reborrow.rs @@ -0,0 +1,27 @@ +//@ aux-build:block-on.rs +//@ run-pass +//@ check-run-results +//@ revisions: e2021 e2018 +//@[e2018] edition:2018 +//@[e2021] edition:2021 + +#![feature(async_closure)] + +extern crate block_on; + +async fn call_once(f: impl async FnOnce()) { f().await; } + +pub async fn async_closure(x: &mut i32) { + let c = async move || { + *x += 1; + }; + call_once(c).await; +} + +fn main() { + block_on::block_on(async { + let mut x = 0; + async_closure(&mut x).await; + assert_eq!(x, 1); + }); +}