@@ -36,6 +36,7 @@ use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
36
36
use dataflow:: { EverInitializedLvals , MovingOutStatements } ;
37
37
use dataflow:: { Borrows , BorrowData , ReserveOrActivateIndex } ;
38
38
use dataflow:: { ActiveBorrows , Reservations } ;
39
+ use dataflow:: indexes:: { BorrowIndex } ;
39
40
use dataflow:: move_paths:: { IllegalMoveOriginKind , MoveError } ;
40
41
use dataflow:: move_paths:: { HasMoveData , LookupResult , MoveData , MovePathIndex } ;
41
42
use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
@@ -222,6 +223,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
222
223
} ,
223
224
storage_dead_or_drop_error_reported_l : FxHashSet ( ) ,
224
225
storage_dead_or_drop_error_reported_s : FxHashSet ( ) ,
226
+ reservation_error_reported : FxHashSet ( ) ,
225
227
} ;
226
228
227
229
let borrows = Borrows :: new ( tcx, mir, opt_regioncx, def_id, body_id) ;
@@ -287,6 +289,14 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
287
289
storage_dead_or_drop_error_reported_l : FxHashSet < Local > ,
288
290
/// Same as the above, but for statics (thread-locals)
289
291
storage_dead_or_drop_error_reported_s : FxHashSet < DefId > ,
292
+ /// This field keeps track of when borrow conflict errors are reported
293
+ /// for reservations, so that we don't report seemingly duplicate
294
+ /// errors for corresponding activations
295
+ ///
296
+ /// FIXME: Ideally this would be a set of BorrowIndex, not Places,
297
+ /// but it is currently inconvenient to track down the BorrowIndex
298
+ /// at the time we detect and report a reservation error.
299
+ reservation_error_reported : FxHashSet < Place < ' tcx > > ,
290
300
}
291
301
292
302
// Check that:
@@ -318,6 +328,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
318
328
flow_state
319
329
) ;
320
330
let span = stmt. source_info . span ;
331
+
332
+ self . check_activations ( location, span, flow_state) ;
333
+
321
334
match stmt. kind {
322
335
StatementKind :: Assign ( ref lhs, ref rhs) => {
323
336
// NOTE: NLL RFC calls for *shallow* write; using Deep
@@ -424,6 +437,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
424
437
flow_state
425
438
) ;
426
439
let span = term. source_info . span ;
440
+
441
+ self . check_activations ( location, span, flow_state) ;
442
+
427
443
match term. kind {
428
444
TerminatorKind :: SwitchInt {
429
445
ref discr,
@@ -557,7 +573,7 @@ enum Control {
557
573
}
558
574
559
575
use self :: ShallowOrDeep :: { Deep , Shallow } ;
560
- use self :: ReadOrWrite :: { Read , Write } ;
576
+ use self :: ReadOrWrite :: { Activation , Read , Reservation , Write } ;
561
577
562
578
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
563
579
enum ArtificialField {
@@ -592,6 +608,12 @@ enum ReadOrWrite {
592
608
/// new values or otherwise invalidated (for example, it could be
593
609
/// de-initialized, as in a move operation).
594
610
Write ( WriteKind ) ,
611
+
612
+ /// For two-phase borrows, we distinguish a reservation (which is treated
613
+ /// like a Read) from an activation (which is treated like a write), and
614
+ /// each of those is furthermore distinguished from Reads/Writes above.
615
+ Reservation ( WriteKind ) ,
616
+ Activation ( WriteKind , BorrowIndex ) ,
595
617
}
596
618
597
619
/// Kind of read access to a value
@@ -680,6 +702,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
680
702
) -> AccessErrorsReported {
681
703
let ( sd, rw) = kind;
682
704
705
+ if let Activation ( _, borrow_index) = rw {
706
+ if self . reservation_error_reported . contains ( & place_span. 0 ) {
707
+ debug ! ( "skipping access_place for activation of invalid reservation \
708
+ place: {:?} borrow_index: {:?}", place_span. 0 , borrow_index) ;
709
+ return AccessErrorsReported { mutability_error : false , conflict_error : false } ;
710
+ }
711
+ }
712
+
683
713
let mutability_error =
684
714
self . check_access_permissions ( place_span, rw, is_local_mutation_allowed) ;
685
715
let conflict_error =
@@ -702,9 +732,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
702
732
( sd, place_span. 0 ) ,
703
733
flow_state,
704
734
|this, index, borrow| match ( rw, borrow. kind ) {
705
- ( Read ( _) , BorrowKind :: Shared ) => Control :: Continue ,
735
+ // Obviously an activation is compatible with its own reservation;
736
+ // so don't check if they interfere.
737
+ ( Activation ( _, activating) , _) if index. is_reservation ( ) &&
738
+ activating == index. borrow_index ( ) => Control :: Continue ,
706
739
707
- ( Read ( kind) , BorrowKind :: Unique ) | ( Read ( kind) , BorrowKind :: Mut ) => {
740
+ ( Read ( _) , BorrowKind :: Shared ) |
741
+ ( Reservation ( ..) , BorrowKind :: Shared ) => Control :: Continue ,
742
+
743
+ ( Read ( kind) , BorrowKind :: Unique ) |
744
+ ( Read ( kind) , BorrowKind :: Mut ) => {
708
745
// Reading from mere reservations of mutable-borrows is OK.
709
746
if this. tcx . sess . opts . debugging_opts . two_phase_borrows &&
710
747
index. is_reservation ( )
@@ -734,13 +771,32 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
734
771
}
735
772
Control :: Break
736
773
}
774
+
775
+ ( Reservation ( kind) , BorrowKind :: Unique ) |
776
+ ( Reservation ( kind) , BorrowKind :: Mut ) |
777
+ ( Activation ( kind, _) , _) |
737
778
( Write ( kind) , _) => {
779
+
780
+ match rw {
781
+ Reservation ( _) => {
782
+ debug ! ( "recording invalid reservation of \
783
+ place: {:?}", place_span. 0 ) ;
784
+ this. reservation_error_reported . insert ( place_span. 0 . clone ( ) ) ;
785
+ }
786
+ Activation ( _, activating) => {
787
+ debug ! ( "observing check_place for activation of \
788
+ borrow_index: {:?}", activating) ;
789
+ }
790
+ Read ( ..) | Write ( ..) => { }
791
+ }
792
+
738
793
match kind {
739
794
WriteKind :: MutableBorrow ( bk) => {
740
795
let end_issued_loan_span = flow_state
741
796
. borrows
742
797
. operator ( )
743
798
. opt_region_end_span ( & borrow. region ) ;
799
+
744
800
error_reported = true ;
745
801
this. report_conflicting_borrow (
746
802
context,
@@ -827,16 +883,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
827
883
let access_kind = match bk {
828
884
BorrowKind :: Shared => ( Deep , Read ( ReadKind :: Borrow ( bk) ) ) ,
829
885
BorrowKind :: Unique | BorrowKind :: Mut => {
830
- ( Deep , Write ( WriteKind :: MutableBorrow ( bk) ) )
886
+ let wk = WriteKind :: MutableBorrow ( bk) ;
887
+ if self . tcx . sess . opts . debugging_opts . two_phase_borrows {
888
+ ( Deep , Reservation ( wk) )
889
+ } else {
890
+ ( Deep , Write ( wk) )
891
+ }
831
892
}
832
893
} ;
894
+
833
895
self . access_place (
834
896
context,
835
897
( place, span) ,
836
898
access_kind,
837
899
LocalMutationIsAllowed :: No ,
838
900
flow_state,
839
901
) ;
902
+
840
903
self . check_if_path_is_moved (
841
904
context,
842
905
InitializationRequiringAction :: Borrow ,
@@ -1007,6 +1070,49 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1007
1070
)
1008
1071
}
1009
1072
}
1073
+
1074
+ fn check_activations ( & mut self ,
1075
+ location : Location ,
1076
+ span : Span ,
1077
+ flow_state : & Flows < ' cx , ' gcx , ' tcx > )
1078
+ {
1079
+ if !self . tcx . sess . opts . debugging_opts . two_phase_borrows {
1080
+ return ;
1081
+ }
1082
+
1083
+ // Two-phase borrow support: For each activation that is newly
1084
+ // generated at this statement, check if it interferes with
1085
+ // another borrow.
1086
+ let domain = flow_state. borrows . operator ( ) ;
1087
+ let data = domain. borrows ( ) ;
1088
+ flow_state. borrows . each_gen_bit ( |gen| {
1089
+ if gen. is_activation ( ) && // must be activation,
1090
+ !flow_state. borrows . contains ( & gen) // and newly generated.
1091
+ {
1092
+ let borrow_index = gen. borrow_index ( ) ;
1093
+ let borrow = & data[ borrow_index] ;
1094
+ // currently the flow analysis registers
1095
+ // activations for both mutable and immutable
1096
+ // borrows. So make sure we are talking about a
1097
+ // mutable borrow before we check it.
1098
+ match borrow. kind {
1099
+ BorrowKind :: Shared => return ,
1100
+ BorrowKind :: Unique |
1101
+ BorrowKind :: Mut => { }
1102
+ }
1103
+
1104
+ self . access_place ( ContextKind :: Activation . new ( location) ,
1105
+ ( & borrow. borrowed_place , span) ,
1106
+ ( Deep , Activation ( WriteKind :: MutableBorrow ( borrow. kind ) ,
1107
+ borrow_index) ) ,
1108
+ LocalMutationIsAllowed :: No ,
1109
+ flow_state) ;
1110
+ // We do not need to call `check_if_path_is_moved`
1111
+ // again, as we already called it when we made the
1112
+ // initial reservation.
1113
+ }
1114
+ } ) ;
1115
+ }
1010
1116
}
1011
1117
1012
1118
impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
@@ -1250,11 +1356,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1250
1356
) ;
1251
1357
let mut error_reported = false ;
1252
1358
match kind {
1359
+ Reservation ( WriteKind :: MutableBorrow ( BorrowKind :: Unique ) ) |
1253
1360
Write ( WriteKind :: MutableBorrow ( BorrowKind :: Unique ) ) => {
1254
1361
if let Err ( _place_err) = self . is_mutable ( place, LocalMutationIsAllowed :: Yes ) {
1255
1362
span_bug ! ( span, "&unique borrow for {:?} should not fail" , place) ;
1256
1363
}
1257
1364
}
1365
+ Reservation ( WriteKind :: MutableBorrow ( BorrowKind :: Mut ) ) |
1258
1366
Write ( WriteKind :: MutableBorrow ( BorrowKind :: Mut ) ) => if let Err ( place_err) =
1259
1367
self . is_mutable ( place, is_local_mutation_allowed)
1260
1368
{
@@ -1277,6 +1385,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1277
1385
1278
1386
err. emit ( ) ;
1279
1387
} ,
1388
+ Reservation ( WriteKind :: Mutate ) |
1280
1389
Write ( WriteKind :: Mutate ) => {
1281
1390
if let Err ( place_err) = self . is_mutable ( place, is_local_mutation_allowed) {
1282
1391
error_reported = true ;
@@ -1298,6 +1407,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1298
1407
err. emit ( ) ;
1299
1408
}
1300
1409
}
1410
+ Reservation ( WriteKind :: Move ) |
1411
+ Reservation ( WriteKind :: StorageDeadOrDrop ) |
1412
+ Reservation ( WriteKind :: MutableBorrow ( BorrowKind :: Shared ) ) |
1301
1413
Write ( WriteKind :: Move ) |
1302
1414
Write ( WriteKind :: StorageDeadOrDrop ) |
1303
1415
Write ( WriteKind :: MutableBorrow ( BorrowKind :: Shared ) ) => {
@@ -1312,6 +1424,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1312
1424
) ;
1313
1425
}
1314
1426
}
1427
+
1428
+ Activation ( ..) => { } // permission checks are done at Reservation point.
1429
+
1315
1430
Read ( ReadKind :: Borrow ( BorrowKind :: Unique ) ) |
1316
1431
Read ( ReadKind :: Borrow ( BorrowKind :: Mut ) ) |
1317
1432
Read ( ReadKind :: Borrow ( BorrowKind :: Shared ) ) |
@@ -1892,6 +2007,7 @@ struct Context {
1892
2007
1893
2008
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
1894
2009
enum ContextKind {
2010
+ Activation ,
1895
2011
AssignLhs ,
1896
2012
AssignRhs ,
1897
2013
SetDiscrim ,
0 commit comments