Skip to content

Commit fae4d2e

Browse files
committed
Compute mutability of closure captures
- Store this in `ty::CapturedPlace` - Use `ty::CapturedPlace::mutability` to in mir_build and borrow_check
1 parent 2bdc568 commit fae4d2e

File tree

4 files changed

+61
-23
lines changed

4 files changed

+61
-23
lines changed

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,7 @@ pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
805805
pub struct CapturedPlace<'tcx> {
806806
pub place: HirPlace<'tcx>,
807807
pub info: CaptureInfo<'tcx>,
808+
pub mutability: hir::Mutability,
808809
}
809810

810811
/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)

compiler/rustc_mir/src/borrow_check/mod.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -168,17 +168,12 @@ fn do_mir_borrowck<'a, 'tcx>(
168168
ty::UpvarCapture::ByValue(_) => false,
169169
ty::UpvarCapture::ByRef(..) => true,
170170
};
171-
let mut upvar = Upvar {
171+
Upvar {
172172
name: tcx.hir().name(var_hir_id),
173173
var_hir_id,
174174
by_ref,
175-
mutability: Mutability::Not,
176-
};
177-
let bm = *tables.pat_binding_modes().get(var_hir_id).expect("missing binding mode");
178-
if bm == ty::BindByValue(hir::Mutability::Mut) {
179-
upvar.mutability = Mutability::Mut;
175+
mutability: captured_place.mutability,
180176
}
181-
upvar
182177
})
183178
.collect();
184179

compiler/rustc_mir_build/src/build/mod.rs

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -851,22 +851,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
851851
_ => bug!("Expected an upvar")
852852
};
853853

854-
let mut mutability = Mutability::Not;
854+
let mutability = captured_place.mutability;
855855

856856
// FIXME(project-rfc-2229#8): Store more precise information
857857
let mut name = kw::Invalid;
858858
if let Some(Node::Binding(pat)) = tcx_hir.find(var_id) {
859859
if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
860860
name = ident.name;
861-
match hir_typeck_results
862-
.extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
863-
{
864-
Some(ty::BindByValue(hir::Mutability::Mut)) => {
865-
mutability = Mutability::Mut;
866-
}
867-
Some(_) => mutability = Mutability::Not,
868-
_ => {}
869-
}
870861
}
871862
}
872863

compiler/rustc_typeck/src/check/upvar.rs

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts};
4444
use rustc_span::sym;
4545
use rustc_span::{Span, Symbol};
4646

47+
use std::env;
48+
4749
/// Describe the relationship between the paths of two places
4850
/// eg:
4951
/// - `foo` is ancestor of `foo.bar.baz`
@@ -123,10 +125,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
123125
};
124126

125127
let local_def_id = closure_def_id.expect_local();
126-
127128
let mut capture_information: FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>> =
128129
Default::default();
129-
if !self.tcx.features().capture_disjoint_fields {
130+
131+
if !self.tcx.features().capture_disjoint_fields && env::var("SG_NEW").is_err() {
130132
if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) {
131133
for (&var_hir_id, _) in upvars.iter() {
132134
let place = self.place_for_root_variable(local_def_id, var_hir_id);
@@ -238,8 +240,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
238240
let capture = captured_place.info.capture_kind;
239241

240242
debug!(
241-
"place={:?} upvar_ty={:?} capture={:?}",
242-
captured_place.place, upvar_ty, capture
243+
"final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability={:?}",
244+
captured_place.place,
245+
upvar_ty,
246+
capture,
247+
self.determine_mutability(&captured_place.place),
243248
);
244249

245250
match capture {
@@ -391,7 +396,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
391396

392397
let min_cap_list = match root_var_min_capture_list.get_mut(&var_hir_id) {
393398
None => {
394-
let min_cap_list = vec![ty::CapturedPlace { place: place, info: capture_info }];
399+
let mutability = self.determine_mutability(&place);
400+
let min_cap_list =
401+
vec![ty::CapturedPlace { place, info: capture_info, mutability }];
395402
root_var_min_capture_list.insert(var_hir_id, min_cap_list);
396403
continue;
397404
}
@@ -445,8 +452,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
445452

446453
// Only need to insert when we don't have an ancestor in the existing min capture list
447454
if !ancestor_found {
455+
let mutability = self.determine_mutability(&place);
448456
let captured_place =
449-
ty::CapturedPlace { place: place.clone(), info: updated_capture_info };
457+
ty::CapturedPlace { place, info: updated_capture_info, mutability };
450458
min_cap_list.push(captured_place);
451459
}
452460
}
@@ -542,6 +550,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
542550
}
543551
}
544552
}
553+
554+
/// A place is mutable if
555+
/// 1. Projections don't include a Deref of an immut-borrow, **and**
556+
/// 2. PlaceBase is mut or projections include a Deref of a mut-borrow.
557+
fn determine_mutability(&self, place: &Place<'tcx>) -> hir::Mutability {
558+
if place.deref_tys().any(ty::TyS::is_unsafe_ptr) {
559+
// Raw pointers don't inherit mutability.
560+
return hir::Mutability::Not;
561+
}
562+
563+
let var_hir_id = match place.base {
564+
PlaceBase::Upvar(upvar_id) => upvar_id.var_path.hir_id,
565+
_ => unreachable!(),
566+
};
567+
568+
let bm = *self
569+
.typeck_results
570+
.borrow()
571+
.pat_binding_modes()
572+
.get(var_hir_id)
573+
.expect("missing binding mode");
574+
575+
let mut is_mutbl = match bm {
576+
ty::BindByValue(mutability) => mutability,
577+
ty::BindByReference(_) => hir::Mutability::Not,
578+
};
579+
580+
for pointer_ty in place.deref_tys() {
581+
match pointer_ty.kind() {
582+
// Raw pointers don't inherit mutability.
583+
ty::RawPtr(_) => return hir::Mutability::Not,
584+
// assignment to deref of an `&mut`
585+
// borrowed pointer implies that the
586+
// pointer itself must be unique, but not
587+
// necessarily *mutable*
588+
ty::Ref(.., hir::Mutability::Mut) => is_mutbl = hir::Mutability::Mut,
589+
ty::Ref(.., hir::Mutability::Not) => return hir::Mutability::Not,
590+
_ => (),
591+
}
592+
}
593+
594+
is_mutbl
595+
}
545596
}
546597

547598
struct InferBorrowKind<'a, 'tcx> {

0 commit comments

Comments
 (0)