Skip to content

Commit c9f136b

Browse files
committed
also do not add noalias on not-Unpin Box
1 parent 8e1bc87 commit c9f136b

File tree

2 files changed

+71
-16
lines changed

2 files changed

+71
-16
lines changed

src/borrow_tracker/stacked_borrows/mod.rs

+27-6
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,32 @@ impl NewPermission {
135135
}
136136
}
137137

138+
fn from_box_ty<'tcx>(
139+
ty: Ty<'tcx>,
140+
kind: RetagKind,
141+
cx: &crate::MiriInterpCx<'_, 'tcx>,
142+
) -> Self {
143+
// `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
144+
let pointee = ty.builtin_deref(true).unwrap().ty;
145+
if pointee.is_unpin(*cx.tcx, cx.param_env()) {
146+
// A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
147+
// a weak protector).
148+
NewPermission::Uniform {
149+
perm: Permission::Unique,
150+
access: Some(AccessKind::Write),
151+
protector: (kind == RetagKind::FnEntry)
152+
.then_some(ProtectorKind::WeakProtector),
153+
}
154+
} else {
155+
// `!Unpin` boxes do not get `noalias` nor `dereferenceable`.
156+
NewPermission::Uniform {
157+
perm: Permission::SharedReadWrite,
158+
access: None,
159+
protector: None,
160+
}
161+
}
162+
}
163+
138164
fn protector(&self) -> Option<ProtectorKind> {
139165
match self {
140166
NewPermission::Uniform { protector, .. } => *protector,
@@ -914,12 +940,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
914940

915941
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
916942
// Boxes get a weak protectors, since they may be deallocated.
917-
let new_perm = NewPermission::Uniform {
918-
perm: Permission::Unique,
919-
access: Some(AccessKind::Write),
920-
protector: (self.kind == RetagKind::FnEntry)
921-
.then_some(ProtectorKind::WeakProtector),
922-
};
943+
let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
923944
self.retag_ptr_inplace(place, new_perm, self.retag_cause)
924945
}
925946

tests/pass/stacked-borrows/future-self-referential.rs

+44-10
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ impl Future for Delay {
2626
}
2727
}
2828

29+
fn mk_waker() -> Waker {
30+
use std::sync::Arc;
31+
32+
struct MyWaker;
33+
impl Wake for MyWaker {
34+
fn wake(self: Arc<Self>) {
35+
unimplemented!()
36+
}
37+
}
38+
39+
Waker::from(Arc::new(MyWaker))
40+
}
41+
2942
async fn do_stuff() {
3043
(&mut Delay::new(1)).await;
3144
}
@@ -73,16 +86,7 @@ impl Future for DoStuff {
7386
}
7487

7588
fn run_fut<T>(fut: impl Future<Output = T>) -> T {
76-
use std::sync::Arc;
77-
78-
struct MyWaker;
79-
impl Wake for MyWaker {
80-
fn wake(self: Arc<Self>) {
81-
unimplemented!()
82-
}
83-
}
84-
85-
let waker = Waker::from(Arc::new(MyWaker));
89+
let waker = mk_waker();
8690
let mut context = Context::from_waker(&waker);
8791

8892
let mut pinned = pin!(fut);
@@ -94,7 +98,37 @@ fn run_fut<T>(fut: impl Future<Output = T>) -> T {
9498
}
9599
}
96100

101+
fn self_referential_box() {
102+
let waker = mk_waker();
103+
let cx = &mut Context::from_waker(&waker);
104+
105+
async fn my_fut() -> i32 {
106+
let val = 10;
107+
let val_ref = &val;
108+
109+
let _ = Delay::new(1).await;
110+
111+
*val_ref
112+
}
113+
114+
fn box_poll<F: Future>(
115+
mut f: Pin<Box<F>>,
116+
cx: &mut Context<'_>,
117+
) -> (Pin<Box<F>>, Poll<F::Output>) {
118+
let p = f.as_mut().poll(cx);
119+
(f, p)
120+
}
121+
122+
let my_fut = Box::pin(my_fut());
123+
let (my_fut, p1) = box_poll(my_fut, cx);
124+
assert!(p1.is_pending());
125+
let (my_fut, p2) = box_poll(my_fut, cx);
126+
assert!(p2.is_ready());
127+
drop(my_fut);
128+
}
129+
97130
fn main() {
98131
run_fut(do_stuff());
99132
run_fut(DoStuff::new());
133+
self_referential_box();
100134
}

0 commit comments

Comments
 (0)