Skip to content

Commit deb9bfd

Browse files
committed
Auto merge of #1952 - RalfJung:self-referential, r=RalfJung
exclude mutable references to !Unpin types from uniqueness guarantees This basically works around rust-lang/unsafe-code-guidelines#148 by not requiring uniqueness any more for mutable references to self-referential generators. That corresponds to [the same work-around that was applied in rustc itself](https://github.com/rust-lang/rust/blob/b81553267437627af63c79c1a20c73af865a842a/compiler/rustc_middle/src/ty/layout.rs#L2482). I am not entirely sure if this is a good idea since it might hide too many errors in case types are "accidentally" `!Unpin`. OTOH, our test suite still passes, and to my knowledge the vast majority of types is `Unpin`. (`place.layout.ty` is monomorphic, we should always exactly know which type this is.)
2 parents c8b3cf0 + 77cec81 commit deb9bfd

File tree

2 files changed

+49
-3
lines changed

2 files changed

+49
-3
lines changed

src/stacked_borrows.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ use std::num::NonZeroU64;
99
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
1010
use rustc_hir::Mutability;
1111
use rustc_middle::mir::RetagKind;
12-
use rustc_middle::ty::{self, layout::LayoutOf};
12+
use rustc_middle::ty::{
13+
self,
14+
layout::{HasParamEnv, LayoutOf},
15+
};
16+
use rustc_span::DUMMY_SP;
1317
use rustc_target::abi::Size;
1418

1519
use crate::*;
@@ -657,8 +661,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
657661
// Make sure that raw pointers and mutable shared references are reborrowed "weak":
658662
// There could be existing unique pointers reborrowed from them that should remain valid!
659663
let perm = match kind {
660-
RefKind::Unique { two_phase: false } => Permission::Unique,
661-
RefKind::Unique { two_phase: true } => Permission::SharedReadWrite,
664+
RefKind::Unique { two_phase: false }
665+
if place.layout.ty.is_unpin(this.tcx.at(DUMMY_SP), this.param_env()) =>
666+
{
667+
// Only if the type is unpin do we actually enforce uniqueness
668+
Permission::Unique
669+
}
670+
RefKind::Unique { .. } => {
671+
// Two-phase references and !Unpin references are treated as SharedReadWrite
672+
Permission::SharedReadWrite
673+
}
662674
RefKind::Raw { mutable: true } => Permission::SharedReadWrite,
663675
RefKind::Shared | RefKind::Raw { mutable: false } => {
664676
// Shared references and *const are a whole different kind of game, the
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// See https://github.com/rust-lang/unsafe-code-guidelines/issues/148:
2+
// this fails when Stacked Borrows is strictly applied even to `!Unpin` types.
3+
#![feature(generators, generator_trait)]
4+
5+
use std::{
6+
ops::{Generator, GeneratorState},
7+
pin::Pin,
8+
};
9+
10+
fn firstn() -> impl Generator<Yield = u64, Return = ()> {
11+
static move || {
12+
let mut num = 0;
13+
let num = &mut num;
14+
15+
yield *num;
16+
*num += 1; //~ ERROR: borrow stack
17+
18+
yield *num;
19+
*num += 1;
20+
21+
yield *num;
22+
*num += 1;
23+
}
24+
}
25+
26+
fn main() {
27+
let mut generator_iterator = firstn();
28+
let mut pin = unsafe { Pin::new_unchecked(&mut generator_iterator) };
29+
let mut sum = 0;
30+
while let GeneratorState::Yielded(x) = pin.as_mut().resume(()) {
31+
sum += x;
32+
}
33+
assert_eq!(sum, 3);
34+
}

0 commit comments

Comments
 (0)