@@ -34,6 +34,7 @@ use dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
34
34
use dataflow:: { EverInitializedLvals , MovingOutStatements } ;
35
35
use dataflow:: { Borrows , BorrowData , ResActIndex } ;
36
36
use dataflow:: { ActiveBorrows , Reservations } ;
37
+ use dataflow:: indexes:: { BorrowIndex } ;
37
38
use dataflow:: move_paths:: { IllegalMoveOriginKind , MoveError } ;
38
39
use dataflow:: move_paths:: { HasMoveData , LookupResult , MoveData , MoveOutIndex , MovePathIndex } ;
39
40
use util:: borrowck_errors:: { BorrowckErrors , Origin } ;
@@ -195,6 +196,7 @@ fn do_mir_borrowck<'a, 'gcx, 'tcx>(
195
196
move_data : & mdpe. move_data ,
196
197
param_env : param_env,
197
198
storage_dead_or_drop_error_reported : FxHashSet ( ) ,
199
+ reservation_error_reported : FxHashSet ( ) ,
198
200
} ;
199
201
200
202
let borrows = Borrows :: new ( tcx, mir, opt_regioncx) ;
@@ -249,6 +251,14 @@ pub struct MirBorrowckCtxt<'cx, 'gcx: 'tcx, 'tcx: 'cx> {
249
251
/// in order to stop duplicate error reporting and identify the conditions required
250
252
/// for a "temporary value dropped here while still borrowed" error. See #45360.
251
253
storage_dead_or_drop_error_reported : FxHashSet < Local > ,
254
+ /// This field keeps track of when borrow conflict errors are reported
255
+ /// for reservations, so that we don't report seemingly duplicate
256
+ /// errors for corresponding activations
257
+ ///
258
+ /// FIXME: Ideally this would be a set of BorrowIndex, not Places,
259
+ /// but it is currently inconvenient to track down the BorrowIndex
260
+ /// at the time we detect and report a reservation error.
261
+ reservation_error_reported : FxHashSet < Place < ' tcx > > ,
252
262
}
253
263
254
264
// (forced to be `pub` due to its use as an associated type below.)
@@ -347,6 +357,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
347
357
summary
348
358
) ;
349
359
let span = stmt. source_info . span ;
360
+
361
+ self . check_activations ( location, span, flow_state) ;
362
+
350
363
match stmt. kind {
351
364
StatementKind :: Assign ( ref lhs, ref rhs) => {
352
365
// NOTE: NLL RFC calls for *shallow* write; using Deep
@@ -454,6 +467,9 @@ impl<'cx, 'gcx, 'tcx> DataflowResultsConsumer<'cx, 'tcx> for MirBorrowckCtxt<'cx
454
467
summary
455
468
) ;
456
469
let span = term. source_info . span ;
470
+
471
+ self . check_activations ( location, span, flow_state) ;
472
+
457
473
match term. kind {
458
474
TerminatorKind :: SwitchInt {
459
475
ref discr,
@@ -600,7 +616,7 @@ enum Control {
600
616
}
601
617
602
618
use self :: ShallowOrDeep :: { Deep , Shallow } ;
603
- use self :: ReadOrWrite :: { Read , Write } ;
619
+ use self :: ReadOrWrite :: { Activation , Read , Reservation , Write } ;
604
620
605
621
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
606
622
enum ArtificialField {
@@ -635,6 +651,12 @@ enum ReadOrWrite {
635
651
/// new values or otherwise invalidated (for example, it could be
636
652
/// de-initialized, as in a move operation).
637
653
Write ( WriteKind ) ,
654
+
655
+ /// For two-phase borrows, we distinguish a reservation (which is treated
656
+ /// like a Read) from an activation (which is treated like a write), and
657
+ /// each of those is furthermore distinguished from Reads/Writes above.
658
+ Reservation ( WriteKind ) ,
659
+ Activation ( WriteKind , BorrowIndex ) ,
638
660
}
639
661
640
662
/// Kind of read access to a value
@@ -726,6 +748,14 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
726
748
}
727
749
}
728
750
751
+ if let Activation ( _, borrow_index) = rw {
752
+ if self . reservation_error_reported . contains ( & place_span. 0 ) {
753
+ debug ! ( "skipping check_place for activation of invalid reservation \
754
+ place: {:?} borrow_index: {:?}", place_span. 0 , borrow_index) ;
755
+ return ;
756
+ }
757
+ }
758
+
729
759
// Check permissions
730
760
let mut error_reported =
731
761
self . check_access_permissions ( place_span, rw, is_local_mutation_allowed) ;
@@ -735,9 +765,17 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
735
765
( sd, place_span. 0 ) ,
736
766
flow_state,
737
767
|this, index, borrow, common_prefix| match ( rw, borrow. kind ) {
738
- ( Read ( _) , BorrowKind :: Shared ) => Control :: Continue ,
739
768
740
- ( Read ( kind) , BorrowKind :: Unique ) | ( Read ( kind) , BorrowKind :: Mut ) => {
769
+ // Obviously an activation is compatible with its own reservation;
770
+ // so don't check if they interfere.
771
+ ( Activation ( _, activating) , _) if index. is_reservation ( ) &&
772
+ activating == index. borrow_index ( ) => Control :: Continue ,
773
+
774
+ ( Read ( _) , BorrowKind :: Shared ) |
775
+ ( Reservation ( ..) , BorrowKind :: Shared ) => Control :: Continue ,
776
+
777
+ ( Read ( kind) , BorrowKind :: Unique ) |
778
+ ( Read ( kind) , BorrowKind :: Mut ) => {
741
779
// Reading from mere reservations of mutable-borrows is OK.
742
780
if this. tcx . sess . opts . debugging_opts . two_phase_borrows &&
743
781
index. is_reservation ( )
@@ -769,14 +807,33 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
769
807
}
770
808
Control :: Break
771
809
}
810
+
811
+ ( Reservation ( kind) , BorrowKind :: Unique ) |
812
+ ( Reservation ( kind) , BorrowKind :: Mut ) |
813
+ ( Activation ( kind, _) , _) |
772
814
( Write ( kind) , _) => {
815
+
816
+ match rw {
817
+ Reservation ( _) => {
818
+ debug ! ( "recording invalid reservation of \
819
+ place: {:?}", place_span. 0 ) ;
820
+ this. reservation_error_reported . insert ( place_span. 0 . clone ( ) ) ;
821
+ }
822
+ Activation ( _, activating) => {
823
+ debug ! ( "observing check_place for activation of \
824
+ borrow_index: {:?}", activating) ;
825
+ }
826
+ Read ( ..) | Write ( ..) => { }
827
+ }
828
+
773
829
match kind {
774
830
WriteKind :: MutableBorrow ( bk) => {
775
831
let end_issued_loan_span = flow_state
776
832
. borrows
777
833
. base_results
778
834
. operator ( )
779
835
. opt_region_end_span ( & borrow. region ) ;
836
+
780
837
error_reported = true ;
781
838
this. report_conflicting_borrow (
782
839
context,
@@ -868,16 +925,23 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
868
925
let access_kind = match bk {
869
926
BorrowKind :: Shared => ( Deep , Read ( ReadKind :: Borrow ( bk) ) ) ,
870
927
BorrowKind :: Unique | BorrowKind :: Mut => {
871
- ( Deep , Write ( WriteKind :: MutableBorrow ( bk) ) )
928
+ let wk = WriteKind :: MutableBorrow ( bk) ;
929
+ if self . tcx . sess . opts . debugging_opts . two_phase_borrows {
930
+ ( Deep , Reservation ( wk) )
931
+ } else {
932
+ ( Deep , Write ( wk) )
933
+ }
872
934
}
873
935
} ;
936
+
874
937
self . access_place (
875
938
context,
876
939
( place, span) ,
877
940
access_kind,
878
941
LocalMutationIsAllowed :: No ,
879
942
flow_state,
880
943
) ;
944
+
881
945
self . check_if_path_is_moved (
882
946
context,
883
947
InitializationRequiringAction :: Borrow ,
@@ -1031,6 +1095,50 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1031
1095
self . prefixes ( place, prefix_set)
1032
1096
. any ( |prefix| prefix == root_place)
1033
1097
}
1098
+
1099
+ fn check_activations ( & mut self ,
1100
+ location : Location ,
1101
+ span : Span ,
1102
+ flow_state : & InProgress < ' cx , ' gcx , ' tcx > )
1103
+ {
1104
+ if !self . tcx . sess . opts . debugging_opts . two_phase_borrows {
1105
+ return ;
1106
+ }
1107
+
1108
+ // Two-phase borrow support: For each activation that is newly
1109
+ // generated at this statement, check if it interferes with
1110
+ // another borrow.
1111
+ let domain = flow_state. borrows . base_results . operator ( ) ;
1112
+ let data = domain. borrows ( ) ;
1113
+ let sets = & flow_state. borrows . sets ;
1114
+ for gen in sets. gen_set . iter ( ) {
1115
+ if gen. is_activation ( ) && // must be activation,
1116
+ !sets. on_entry . contains ( & gen) // and newly generated.
1117
+ {
1118
+ let borrow_index = gen. borrow_index ( ) ;
1119
+ let borrow = & data[ borrow_index] ;
1120
+ // currently the flow analysis registers
1121
+ // activations for both mutable and immutable
1122
+ // borrows. So make sure we are talking about a
1123
+ // mutable borrow before we check it.
1124
+ match borrow. kind {
1125
+ BorrowKind :: Shared => continue ,
1126
+ BorrowKind :: Unique |
1127
+ BorrowKind :: Mut => { }
1128
+ }
1129
+
1130
+ self . access_place ( ContextKind :: Activation . new ( location) ,
1131
+ ( & borrow. borrowed_place , span) ,
1132
+ ( Deep , Activation ( WriteKind :: MutableBorrow ( borrow. kind ) ,
1133
+ borrow_index) ) ,
1134
+ LocalMutationIsAllowed :: No ,
1135
+ flow_state) ;
1136
+ // We do not need to call `check_if_path_is_moved`
1137
+ // again, as we already called it when we made the
1138
+ // initial reservation.
1139
+ }
1140
+ }
1141
+ }
1034
1142
}
1035
1143
1036
1144
impl < ' cx , ' gcx , ' tcx > MirBorrowckCtxt < ' cx , ' gcx , ' tcx > {
@@ -1293,11 +1401,13 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1293
1401
) ;
1294
1402
let mut error_reported = false ;
1295
1403
match kind {
1404
+ Reservation ( WriteKind :: MutableBorrow ( BorrowKind :: Unique ) ) |
1296
1405
Write ( WriteKind :: MutableBorrow ( BorrowKind :: Unique ) ) => {
1297
1406
if let Err ( _place_err) = self . is_unique ( place) {
1298
1407
span_bug ! ( span, "&unique borrow for {:?} should not fail" , place) ;
1299
1408
}
1300
1409
}
1410
+ Reservation ( WriteKind :: MutableBorrow ( BorrowKind :: Mut ) ) |
1301
1411
Write ( WriteKind :: MutableBorrow ( BorrowKind :: Mut ) ) => if let Err ( place_err) =
1302
1412
self . is_mutable ( place, is_local_mutation_allowed)
1303
1413
{
@@ -1320,6 +1430,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1320
1430
1321
1431
err. emit ( ) ;
1322
1432
} ,
1433
+ Reservation ( WriteKind :: Mutate ) |
1323
1434
Write ( WriteKind :: Mutate ) => {
1324
1435
if let Err ( place_err) = self . is_mutable ( place, is_local_mutation_allowed) {
1325
1436
error_reported = true ;
@@ -1341,6 +1452,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1341
1452
err. emit ( ) ;
1342
1453
}
1343
1454
}
1455
+ Reservation ( WriteKind :: Move ) |
1456
+ Reservation ( WriteKind :: StorageDeadOrDrop ) |
1457
+ Reservation ( WriteKind :: MutableBorrow ( BorrowKind :: Shared ) ) |
1344
1458
Write ( WriteKind :: Move ) |
1345
1459
Write ( WriteKind :: StorageDeadOrDrop ) |
1346
1460
Write ( WriteKind :: MutableBorrow ( BorrowKind :: Shared ) ) => {
@@ -1355,6 +1469,9 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1355
1469
) ;
1356
1470
}
1357
1471
}
1472
+
1473
+ Activation ( ..) => { } // permission checks are done at Reservation point.
1474
+
1358
1475
Read ( ReadKind :: Borrow ( BorrowKind :: Unique ) ) |
1359
1476
Read ( ReadKind :: Borrow ( BorrowKind :: Mut ) ) |
1360
1477
Read ( ReadKind :: Borrow ( BorrowKind :: Shared ) ) |
@@ -1892,6 +2009,12 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
1892
2009
use rustc:: hir:: ExprClosure ;
1893
2010
use rustc:: mir:: AggregateKind ;
1894
2011
2012
+ if location. statement_index == self . mir [ location. block ] . statements . len ( ) {
2013
+ // Code below hasn't been written in a manner to deal with
2014
+ // a terminator location.
2015
+ return None ;
2016
+ }
2017
+
1895
2018
let local = if let StatementKind :: Assign ( Place :: Local ( local) , _) =
1896
2019
self . mir [ location. block ] . statements [ location. statement_index ] . kind
1897
2020
{
@@ -2355,6 +2478,7 @@ struct Context {
2355
2478
2356
2479
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
2357
2480
enum ContextKind {
2481
+ Activation ,
2358
2482
AssignLhs ,
2359
2483
AssignRhs ,
2360
2484
SetDiscrim ,
0 commit comments