also do not add noalias on not-Unpin Box
This commit is contained in:
parent
ea541bc2ee
commit
1ef16874b5
6 changed files with 183 additions and 119 deletions
|
@ -1443,8 +1443,8 @@ pub enum PointerKind {
|
||||||
SharedRef { frozen: bool },
|
SharedRef { frozen: bool },
|
||||||
/// Mutable reference. `unpin` indicates the absence of any pinned data.
|
/// Mutable reference. `unpin` indicates the absence of any pinned data.
|
||||||
MutableRef { unpin: bool },
|
MutableRef { unpin: bool },
|
||||||
/// Box.
|
/// Box. `unpin` indicates the absence of any pinned data.
|
||||||
Box,
|
Box { unpin: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Note that this information is advisory only, and backends are free to ignore it.
|
/// Note that this information is advisory only, and backends are free to ignore it.
|
||||||
|
|
|
@ -818,8 +818,7 @@ where
|
||||||
let tcx = cx.tcx();
|
let tcx = cx.tcx();
|
||||||
let param_env = cx.param_env();
|
let param_env = cx.param_env();
|
||||||
|
|
||||||
let pointee_info =
|
let pointee_info = match *this.ty.kind() {
|
||||||
match *this.ty.kind() {
|
|
||||||
ty::RawPtr(mt) if offset.bytes() == 0 => {
|
ty::RawPtr(mt) if offset.bytes() == 0 => {
|
||||||
tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
|
tcx.layout_of(param_env.and(mt.ty)).ok().map(|layout| PointeeInfo {
|
||||||
size: layout.size,
|
size: layout.size,
|
||||||
|
@ -828,8 +827,10 @@ where
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
|
ty::FnPtr(fn_sig) if offset.bytes() == 0 => {
|
||||||
tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| {
|
tcx.layout_of(param_env.and(tcx.mk_fn_ptr(fn_sig))).ok().map(|layout| PointeeInfo {
|
||||||
PointeeInfo { size: layout.size, align: layout.align.abi, safe: None }
|
size: layout.size,
|
||||||
|
align: layout.align.abi,
|
||||||
|
safe: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
|
ty::Ref(_, ty, mt) if offset.bytes() == 0 => {
|
||||||
|
@ -914,7 +915,10 @@ where
|
||||||
if let Some(ref mut pointee) = result {
|
if let Some(ref mut pointee) = result {
|
||||||
if let ty::Adt(def, _) = this.ty.kind() {
|
if let ty::Adt(def, _) = this.ty.kind() {
|
||||||
if def.is_box() && offset.bytes() == 0 {
|
if def.is_box() && offset.bytes() == 0 {
|
||||||
pointee.safe = Some(PointerKind::Box);
|
let optimize = tcx.sess.opts.optimize != OptLevel::No;
|
||||||
|
pointee.safe = Some(PointerKind::Box {
|
||||||
|
unpin: optimize && this.ty.boxed_ty().is_unpin(tcx, cx.param_env()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,7 +261,7 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>). If LLVM had a way
|
// <https://github.com/rust-lang/unsafe-code-guidelines/issues/381>). If LLVM had a way
|
||||||
// to say "dereferenceable on entry" we could use it here.
|
// to say "dereferenceable on entry" we could use it here.
|
||||||
attrs.pointee_size = match kind {
|
attrs.pointee_size = match kind {
|
||||||
PointerKind::Box
|
PointerKind::Box { .. }
|
||||||
| PointerKind::SharedRef { frozen: false }
|
| PointerKind::SharedRef { frozen: false }
|
||||||
| PointerKind::MutableRef { unpin: false } => Size::ZERO,
|
| PointerKind::MutableRef { unpin: false } => Size::ZERO,
|
||||||
PointerKind::SharedRef { frozen: true }
|
PointerKind::SharedRef { frozen: true }
|
||||||
|
@ -278,17 +278,16 @@ fn adjust_for_rust_scalar<'tcx>(
|
||||||
// versions at all anymore. We still support turning it off using -Zmutable-noalias.
|
// versions at all anymore. We still support turning it off using -Zmutable-noalias.
|
||||||
let noalias_mut_ref = cx.tcx.sess.opts.unstable_opts.mutable_noalias;
|
let noalias_mut_ref = cx.tcx.sess.opts.unstable_opts.mutable_noalias;
|
||||||
|
|
||||||
// `&mut` pointer parameters never alias other parameters,
|
|
||||||
// or mutable global data
|
|
||||||
//
|
|
||||||
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
|
// `&T` where `T` contains no `UnsafeCell<U>` is immutable, and can be marked as both
|
||||||
// `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
|
// `readonly` and `noalias`, as LLVM's definition of `noalias` is based solely on memory
|
||||||
// dependencies rather than pointer equality. However this only applies to arguments,
|
// dependencies rather than pointer equality. However this only applies to arguments,
|
||||||
// not return values.
|
// not return values.
|
||||||
|
//
|
||||||
|
// `&mut T` and `Box<T>` where `T: Unpin` are unique and hence `noalias`.
|
||||||
let no_alias = match kind {
|
let no_alias = match kind {
|
||||||
PointerKind::SharedRef { frozen } => frozen,
|
PointerKind::SharedRef { frozen } => frozen,
|
||||||
PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
|
PointerKind::MutableRef { unpin } => unpin && noalias_mut_ref,
|
||||||
PointerKind::Box => noalias_for_box,
|
PointerKind::Box { unpin } => unpin && noalias_for_box,
|
||||||
};
|
};
|
||||||
// We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
|
// We can never add `noalias` in return position; that LLVM attribute has some very surprising semantics
|
||||||
// (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
|
// (see <https://github.com/rust-lang/unsafe-code-guidelines/issues/385#issuecomment-1368055745>).
|
||||||
|
|
|
@ -135,6 +135,32 @@ impl NewPermission {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn from_box_ty<'tcx>(
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
kind: RetagKind,
|
||||||
|
cx: &crate::MiriInterpCx<'_, 'tcx>,
|
||||||
|
) -> Self {
|
||||||
|
// `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
|
||||||
|
let pointee = ty.builtin_deref(true).unwrap().ty;
|
||||||
|
if pointee.is_unpin(*cx.tcx, cx.param_env()) {
|
||||||
|
// A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
|
||||||
|
// a weak protector).
|
||||||
|
NewPermission::Uniform {
|
||||||
|
perm: Permission::Unique,
|
||||||
|
access: Some(AccessKind::Write),
|
||||||
|
protector: (kind == RetagKind::FnEntry)
|
||||||
|
.then_some(ProtectorKind::WeakProtector),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// `!Unpin` boxes do not get `noalias` nor `dereferenceable`.
|
||||||
|
NewPermission::Uniform {
|
||||||
|
perm: Permission::SharedReadWrite,
|
||||||
|
access: None,
|
||||||
|
protector: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn protector(&self) -> Option<ProtectorKind> {
|
fn protector(&self) -> Option<ProtectorKind> {
|
||||||
match self {
|
match self {
|
||||||
NewPermission::Uniform { protector, .. } => *protector,
|
NewPermission::Uniform { protector, .. } => *protector,
|
||||||
|
@ -914,12 +940,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
||||||
|
|
||||||
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||||
// Boxes get a weak protectors, since they may be deallocated.
|
// Boxes get a weak protectors, since they may be deallocated.
|
||||||
let new_perm = NewPermission::Uniform {
|
let new_perm = NewPermission::from_box_ty(place.layout.ty, self.kind, self.ecx);
|
||||||
perm: Permission::Unique,
|
|
||||||
access: Some(AccessKind::Write),
|
|
||||||
protector: (self.kind == RetagKind::FnEntry)
|
|
||||||
.then_some(ProtectorKind::WeakProtector),
|
|
||||||
};
|
|
||||||
self.retag_ptr_inplace(place, new_perm, self.retag_cause)
|
self.retag_ptr_inplace(place, new_perm, self.retag_cause)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,19 @@ impl Future for Delay {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mk_waker() -> Waker {
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
struct MyWaker;
|
||||||
|
impl Wake for MyWaker {
|
||||||
|
fn wake(self: Arc<Self>) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Waker::from(Arc::new(MyWaker))
|
||||||
|
}
|
||||||
|
|
||||||
async fn do_stuff() {
|
async fn do_stuff() {
|
||||||
(&mut Delay::new(1)).await;
|
(&mut Delay::new(1)).await;
|
||||||
}
|
}
|
||||||
|
@ -73,16 +86,7 @@ impl Future for DoStuff {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_fut<T>(fut: impl Future<Output = T>) -> T {
|
fn run_fut<T>(fut: impl Future<Output = T>) -> T {
|
||||||
use std::sync::Arc;
|
let waker = mk_waker();
|
||||||
|
|
||||||
struct MyWaker;
|
|
||||||
impl Wake for MyWaker {
|
|
||||||
fn wake(self: Arc<Self>) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let waker = Waker::from(Arc::new(MyWaker));
|
|
||||||
let mut context = Context::from_waker(&waker);
|
let mut context = Context::from_waker(&waker);
|
||||||
|
|
||||||
let mut pinned = pin!(fut);
|
let mut pinned = pin!(fut);
|
||||||
|
@ -94,7 +98,37 @@ fn run_fut<T>(fut: impl Future<Output = T>) -> T {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn self_referential_box() {
|
||||||
|
let waker = mk_waker();
|
||||||
|
let cx = &mut Context::from_waker(&waker);
|
||||||
|
|
||||||
|
async fn my_fut() -> i32 {
|
||||||
|
let val = 10;
|
||||||
|
let val_ref = &val;
|
||||||
|
|
||||||
|
let _ = Delay::new(1).await;
|
||||||
|
|
||||||
|
*val_ref
|
||||||
|
}
|
||||||
|
|
||||||
|
fn box_poll<F: Future>(
|
||||||
|
mut f: Pin<Box<F>>,
|
||||||
|
cx: &mut Context<'_>,
|
||||||
|
) -> (Pin<Box<F>>, Poll<F::Output>) {
|
||||||
|
let p = f.as_mut().poll(cx);
|
||||||
|
(f, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
let my_fut = Box::pin(my_fut());
|
||||||
|
let (my_fut, p1) = box_poll(my_fut, cx);
|
||||||
|
assert!(p1.is_pending());
|
||||||
|
let (my_fut, p2) = box_poll(my_fut, cx);
|
||||||
|
assert!(p2.is_ready());
|
||||||
|
drop(my_fut);
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
run_fut(do_stuff());
|
run_fut(do_stuff());
|
||||||
run_fut(DoStuff::new());
|
run_fut(DoStuff::new());
|
||||||
|
self_referential_box();
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,6 +181,12 @@ pub fn _box(x: Box<i32>) -> Box<i32> {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: noundef nonnull align 4 {{i32\*|ptr}} @notunpin_box({{i32\*|ptr}} noundef nonnull align 4 %x)
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn notunpin_box(x: Box<NotUnpin>) -> Box<NotUnpin> {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
|
||||||
// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %0)?}})
|
// CHECK: @struct_return({{%S\*|ptr}} noalias nocapture noundef sret(%S) dereferenceable(32){{( %0)?}})
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn struct_return() -> S {
|
pub fn struct_return() -> S {
|
||||||
|
@ -247,12 +253,12 @@ pub fn trait_raw(_: *const dyn Drop) {
|
||||||
|
|
||||||
// CHECK: @trait_box({{\{\}\*|ptr}} noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
|
// CHECK: @trait_box({{\{\}\*|ptr}} noalias noundef nonnull align 1{{( %0)?}}, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}){{( %1)?}})
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn trait_box(_: Box<dyn Drop>) {
|
pub fn trait_box(_: Box<dyn Drop + Unpin>) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CHECK: { {{i8\*|ptr}}, {{i8\*|ptr}} } @trait_option({{i8\*|ptr}} noalias noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
|
// CHECK: { {{i8\*|ptr}}, {{i8\*|ptr}} } @trait_option({{i8\*|ptr}} noalias noundef align 1 %x.0, {{i8\*|ptr}} %x.1)
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn trait_option(x: Option<Box<dyn Drop>>) -> Option<Box<dyn Drop>> {
|
pub fn trait_option(x: Option<Box<dyn Drop + Unpin>>) -> Option<Box<dyn Drop + Unpin>> {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue