|
1 | 1 | use rustc_hir as hir;
|
2 | 2 | use rustc_hir::def_id::DefId;
|
3 | 3 | use rustc_hir::lang_items::LangItem;
|
| 4 | +use rustc_index::{Idx, IndexVec}; |
4 | 5 | use rustc_middle::mir::*;
|
5 | 6 | use rustc_middle::query::Providers;
|
6 | 7 | use rustc_middle::ty::GenericArgs;
|
7 | 8 | use rustc_middle::ty::{self, CoroutineArgs, CoroutineArgsExt, EarlyBinder, Ty, TyCtxt};
|
8 | 9 | use rustc_middle::{bug, span_bug};
|
9 |
| -use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; |
10 |
| - |
11 |
| -use rustc_index::{Idx, IndexVec}; |
12 |
| - |
13 | 10 | use rustc_span::{source_map::Spanned, Span, DUMMY_SP};
|
| 11 | +use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; |
14 | 12 | use rustc_target::spec::abi::Abi;
|
15 | 13 |
|
| 14 | +use std::assert_matches::assert_matches; |
16 | 15 | use std::fmt;
|
17 | 16 | use std::iter;
|
18 | 17 |
|
@@ -1020,21 +1019,19 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
|
1020 | 1019 | receiver_by_ref: bool,
|
1021 | 1020 | ) -> Body<'tcx> {
|
1022 | 1021 | let mut self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
|
| 1022 | + let mut self_local: Place<'tcx> = Local::from_usize(1).into(); |
1023 | 1023 | let ty::CoroutineClosure(_, args) = *self_ty.kind() else {
|
1024 | 1024 | bug!();
|
1025 | 1025 | };
|
1026 | 1026 |
|
1027 |
| - // We use `&mut Self` here because we only need to emit an ABI-compatible shim body, |
1028 |
| - // rather than match the signature exactly (which might take `&self` instead). |
| 1027 | + // We use `&Self` here because we only need to emit an ABI-compatible shim body, |
| 1028 | + // rather than match the signature exactly (which might take `&mut self` instead). |
1029 | 1029 | //
|
1030 |
| - // The self type here is a coroutine-closure, not a coroutine, and we never read from |
1031 |
| - // it because it never has any captures, because this is only true in the Fn/FnMut |
1032 |
| - // implementation, not the AsyncFn/AsyncFnMut implementation, which is implemented only |
1033 |
| - // if the coroutine-closure has no captures. |
| 1030 | + // We adjust the `self_local` to be a deref since we want to copy fields out of |
| 1031 | + // a reference to the closure. |
1034 | 1032 | if receiver_by_ref {
|
1035 |
| - // Triple-check that there's no captures here. |
1036 |
| - assert_eq!(args.as_coroutine_closure().tupled_upvars_ty(), tcx.types.unit); |
1037 |
| - self_ty = Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, self_ty); |
| 1033 | + self_local = tcx.mk_place_deref(self_local); |
| 1034 | + self_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_erased, self_ty); |
1038 | 1035 | }
|
1039 | 1036 |
|
1040 | 1037 | let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
|
@@ -1067,11 +1064,27 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
|
1067 | 1064 | fields.push(Operand::Move(Local::from_usize(idx + 1).into()));
|
1068 | 1065 | }
|
1069 | 1066 | for (idx, ty) in args.as_coroutine_closure().upvar_tys().iter().enumerate() {
|
1070 |
| - fields.push(Operand::Move(tcx.mk_place_field( |
1071 |
| - Local::from_usize(1).into(), |
1072 |
| - FieldIdx::from_usize(idx), |
1073 |
| - ty, |
1074 |
| - ))); |
| 1067 | + if receiver_by_ref { |
| 1068 | + // The only situation where it's possible is when we capture immuatable references, |
| 1069 | + // since those don't need to be reborrowed with the closure's env lifetime. Since |
| 1070 | + // references are always `Copy`, just emit a copy. |
| 1071 | + assert_matches!( |
| 1072 | + ty.kind(), |
| 1073 | + ty::Ref(_, _, hir::Mutability::Not), |
| 1074 | + "field should be captured by immutable ref if we have an `Fn` instance" |
| 1075 | + ); |
| 1076 | + fields.push(Operand::Copy(tcx.mk_place_field( |
| 1077 | + self_local, |
| 1078 | + FieldIdx::from_usize(idx), |
| 1079 | + ty, |
| 1080 | + ))); |
| 1081 | + } else { |
| 1082 | + fields.push(Operand::Move(tcx.mk_place_field( |
| 1083 | + self_local, |
| 1084 | + FieldIdx::from_usize(idx), |
| 1085 | + ty, |
| 1086 | + ))); |
| 1087 | + } |
1075 | 1088 | }
|
1076 | 1089 |
|
1077 | 1090 | let source_info = SourceInfo::outermost(span);
|
|
0 commit comments