@@ -252,8 +252,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
252
252
let capture = captured_place. info . capture_kind ;
253
253
254
254
debug ! (
255
- "place={:?} upvar_ty={:?} capture={:?}" ,
256
- captured_place. place, upvar_ty, capture
255
+ "final_upvar_tys: place={:?} upvar_ty={:?} capture={:?}, mutability ={:?}" ,
256
+ captured_place. place, upvar_ty, capture, captured_place . mutability ,
257
257
) ;
258
258
259
259
match capture {
@@ -423,7 +423,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
423
423
424
424
let min_cap_list = match root_var_min_capture_list. get_mut ( & var_hir_id) {
425
425
None => {
426
- let min_cap_list = vec ! [ ty:: CapturedPlace { place, info: capture_info } ] ;
426
+ let mutability = self . determine_capture_mutability ( & place) ;
427
+ let min_cap_list =
428
+ vec ! [ ty:: CapturedPlace { place, info: capture_info, mutability } ] ;
427
429
root_var_min_capture_list. insert ( var_hir_id, min_cap_list) ;
428
430
continue ;
429
431
}
@@ -486,8 +488,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
486
488
487
489
// Only need to insert when we don't have an ancestor in the existing min capture list
488
490
if !ancestor_found {
491
+ let mutability = self . determine_capture_mutability ( & place) ;
489
492
let captured_place =
490
- ty:: CapturedPlace { place : place . clone ( ) , info : updated_capture_info } ;
493
+ ty:: CapturedPlace { place, info : updated_capture_info, mutability } ;
491
494
min_cap_list. push ( captured_place) ;
492
495
}
493
496
}
@@ -607,6 +610,49 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
607
610
}
608
611
}
609
612
}
613
+
614
+ /// A captured place is mutable if
615
+ /// 1. Projections don't include a Deref of an immut-borrow, **and**
616
+ /// 2. PlaceBase is mut or projections include a Deref of a mut-borrow.
617
+ fn determine_capture_mutability ( & self , place : & Place < ' tcx > ) -> hir:: Mutability {
618
+ let var_hir_id = match place. base {
619
+ PlaceBase :: Upvar ( upvar_id) => upvar_id. var_path . hir_id ,
620
+ _ => unreachable ! ( ) ,
621
+ } ;
622
+
623
+ let bm = * self
624
+ . typeck_results
625
+ . borrow ( )
626
+ . pat_binding_modes ( )
627
+ . get ( var_hir_id)
628
+ . expect ( "missing binding mode" ) ;
629
+
630
+ let mut is_mutbl = match bm {
631
+ ty:: BindByValue ( mutability) => mutability,
632
+ ty:: BindByReference ( _) => hir:: Mutability :: Not ,
633
+ } ;
634
+
635
+ for pointer_ty in place. deref_tys ( ) {
636
+ match pointer_ty. kind ( ) {
637
+ // We don't capture derefs of raw ptrs
638
+ ty:: RawPtr ( _) => unreachable ! ( ) ,
639
+
640
+ // Derefencing a mut-ref allows us to mut the Place if we don't deref
641
+ // an immut-ref after on top of this.
642
+ ty:: Ref ( .., hir:: Mutability :: Mut ) => is_mutbl = hir:: Mutability :: Mut ,
643
+
644
+ // The place isn't mutable once we dereference a immutable reference.
645
+ ty:: Ref ( .., hir:: Mutability :: Not ) => return hir:: Mutability :: Not ,
646
+
647
+ // Dereferencing a box doesn't change mutability
648
+ ty:: Adt ( def, ..) if def. is_box ( ) => { }
649
+
650
+ unexpected_ty => bug ! ( "deref of unexpected pointer type {:?}" , unexpected_ty) ,
651
+ }
652
+ }
653
+
654
+ is_mutbl
655
+ }
610
656
}
611
657
612
658
struct InferBorrowKind < ' a , ' tcx > {
0 commit comments