@@ -42,6 +42,9 @@ pub enum Permission {
42
42
SharedReadWrite ,
43
43
/// Greants shared read-only access.
44
44
SharedReadOnly ,
45
+ /// Grants no access, but separates two groups of SharedReadWrite so they are not
46
+ /// all considered mutually compatible.
47
+ Disabled ,
45
48
}
46
49
47
50
/// An item in the per-location borrow stack.
@@ -199,8 +202,8 @@ impl Default for Tag {
199
202
impl Permission {
200
203
/// This defines for a given permission, whether it permits the given kind of access.
201
204
fn grants ( self , access : AccessKind ) -> bool {
202
- // All items grant read access, and except for SharedReadOnly they grant write access.
203
- access == AccessKind :: Read || self != Permission :: SharedReadOnly
205
+ // Disabled grants nother. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access.
206
+ self != Permission :: Disabled && ( access == AccessKind :: Read || self != Permission :: SharedReadOnly )
204
207
}
205
208
}
206
209
@@ -224,12 +227,14 @@ impl<'tcx> Stack {
224
227
}
225
228
226
229
/// Find the first write-incompatible item above the given one --
227
- /// i.e, find the heigh to which the stack will be truncated when writing to `granting`.
230
+ /// i.e, find the height to which the stack will be truncated when writing to `granting`.
228
231
fn find_first_write_incompaible ( & self , granting : usize ) -> usize {
229
232
let perm = self . borrows [ granting] . perm ;
230
233
match perm {
231
234
Permission :: SharedReadOnly =>
232
235
bug ! ( "Cannot use SharedReadOnly for writing" ) ,
236
+ Permission :: Disabled =>
237
+ bug ! ( "Cannot use Disabled for anything" ) ,
233
238
Permission :: Unique =>
234
239
// On a write, everything above us is incompatible.
235
240
granting+1 ,
@@ -250,10 +255,8 @@ impl<'tcx> Stack {
250
255
}
251
256
}
252
257
253
- /// Remove the given item, enforcing barriers.
254
- /// `tag` is just used for the error message.
255
- fn remove ( & mut self , idx : usize , tag : Option < Tag > , global : & GlobalState ) -> EvalResult < ' tcx > {
256
- let item = self . borrows . remove ( idx) ;
258
+ /// Check if the given item is protected.
259
+ fn check_protector ( item : & Item , tag : Option < Tag > , global : & GlobalState ) -> EvalResult < ' tcx > {
257
260
if let Some ( call) = item. protector {
258
261
if global. is_active ( call) {
259
262
if let Some ( tag) = tag {
@@ -268,7 +271,6 @@ impl<'tcx> Stack {
268
271
}
269
272
}
270
273
}
271
- trace ! ( "access: removing item {}" , item) ;
272
274
Ok ( ( ) )
273
275
}
274
276
@@ -295,20 +297,26 @@ impl<'tcx> Stack {
295
297
// Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique
296
298
// pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses).
297
299
let first_incompatible_idx = self . find_first_write_incompaible ( granting_idx) ;
298
- for idx in ( first_incompatible_idx..self . borrows . len ( ) ) . rev ( ) {
299
- self . remove ( idx, Some ( tag) , global) ?;
300
+ while self . borrows . len ( ) > first_incompatible_idx {
301
+ let item = self . borrows . pop ( ) . unwrap ( ) ;
302
+ trace ! ( "access: popping item {}" , item) ;
303
+ Stack :: check_protector ( & item, Some ( tag) , global) ?;
300
304
}
301
305
} else {
302
- // On a read, remove all `Unique` above the granting item. This ensures U2 for read accesses.
303
- // The reason this is not following the stack discipline is that in
304
- // `let raw = &mut *x as *mut _; let _val = *x;`, the second statement
306
+ // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses.
307
+ // The reason this is not following the stack discipline (by removing the first Unique and
308
+ // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement
305
309
// would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the
306
310
// `SharedReadWrite` for `raw`.
307
311
// This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared
308
312
// reference and use that.
313
+ // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs.
309
314
for idx in ( granting_idx+1 .. self . borrows . len ( ) ) . rev ( ) {
310
- if self . borrows [ idx] . perm == Permission :: Unique {
311
- self . remove ( idx, Some ( tag) , global) ?;
315
+ let item = & mut self . borrows [ idx] ;
316
+ if item. perm == Permission :: Unique {
317
+ trace ! ( "access: disabling item {}" , item) ;
318
+ Stack :: check_protector ( item, Some ( tag) , global) ?;
319
+ item. perm = Permission :: Disabled ;
312
320
}
313
321
}
314
322
}
@@ -332,8 +340,9 @@ impl<'tcx> Stack {
332
340
) ) ) ?;
333
341
334
342
// Step 2: Remove all items. Also checks for protectors.
335
- for idx in ( 0 ..self . borrows . len ( ) ) . rev ( ) {
336
- self . remove ( idx, None , global) ?;
343
+ while self . borrows . len ( ) > 0 {
344
+ let item = self . borrows . pop ( ) . unwrap ( ) ;
345
+ Stack :: check_protector ( & item, None , global) ?;
337
346
}
338
347
339
348
Ok ( ( ) )
0 commit comments