Skip to content

Commit

Permalink
Auto merge of #107728 - RalfJung:miri-dyn-star, r=RalfJung,oli-obk
Browse files Browse the repository at this point in the history
Miri: basic dyn* support

As usual I am very unsure about the dynamic dispatch stuff, but it passes even the `Pin<&mut dyn* Trait>` test so that is something.

TBH I think it was a mistake to make `dyn Trait` and `dyn* Trait` part of the same `TyKind` variant. Almost everywhere in Miri this lead to the wrong default behavior, resulting in strange ICEs instead of nice "unimplemented" messages. The two types describe pretty different runtime data layout after all.

Strangely I did not need to do the equivalent of [this diff](rust-lang/rust#106532 (comment)) in Miri. Maybe that is because the unsizing logic matches on `ty::Dynamic(.., ty::Dyn)` already? In `unsized_info` I don't think the `target_dyn_kind` can be `DynStar`, since then it wouldn't be unsized!

r? `@oli-obk` Cc `@eholk` (dyn-star) rust-lang/rust#102425
  • Loading branch information
bors committed Feb 21, 2023
2 parents ef95b20 + 9df7fc3 commit 1232148
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 5 deletions.
4 changes: 4 additions & 0 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
} else if matches!(v.layout.fields, FieldsShape::Union(..)) {
// A (non-frozen) union. We fall back to whatever the type says.
(self.unsafe_cell_action)(v)
} else if matches!(v.layout.ty.kind(), ty::Dynamic(_, _, ty::DynStar)) {
// This needs to read the vtable pointer to proceed type-driven, but we don't
// want to reentrantly read from memory here.
(self.unsafe_cell_action)(v)
} else {
// We want to not actually read from memory for this visit. So, before
// walking this value, we have to make sure it is not a
Expand Down
4 changes: 2 additions & 2 deletions tests/fail/branchless-select-i128-pointer.stderr
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address $HEX is unallocated)
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
--> $DIR/branchless-select-i128-pointer.rs:LL:CC
|
LL | / transmute::<_, &str>(
LL | |
LL | | !mask & transmute::<_, TwoPtrs>("false !")
LL | | | mask & transmute::<_, TwoPtrs>("true !"),
LL | | )
| |_____________^ constructing invalid value: encountered a dangling reference (address $HEX is unallocated)
| |_____________^ constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
Expand Down
2 changes: 1 addition & 1 deletion tests/fail/validity/dangling_ref1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
use std::mem;

fn main() {
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated)
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference
}
4 changes: 2 additions & 2 deletions tests/fail/validity/dangling_ref1.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address 0x10 is unallocated)
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (0x10[noalloc] has no provenance)
--> $DIR/dangling_ref1.rs:LL:CC
|
LL | let _x: &i32 = unsafe { mem::transmute(16usize) };
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x10 is unallocated)
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x10[noalloc] has no provenance)
|
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
Expand Down
116 changes: 116 additions & 0 deletions tests/pass/dyn-star.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#![feature(dyn_star)]
#![allow(incomplete_features)]

use std::fmt::{Debug, Display};

fn main() {
make_dyn_star();
method();
box_();
dispatch_on_pin_mut();
dyn_star_to_dyn();
dyn_to_dyn_star();
}

fn dyn_star_to_dyn() {
let x: dyn* Debug = &42;
let x = Box::new(x) as Box<dyn Debug>;
assert_eq!("42", format!("{x:?}"));
}

fn dyn_to_dyn_star() {
let x: Box<dyn Debug> = Box::new(42);
let x = &x as dyn* Debug;
assert_eq!("42", format!("{x:?}"));
}

fn make_dyn_star() {
fn make_dyn_star_coercion(i: usize) {
let _dyn_i: dyn* Debug = i;
}

fn make_dyn_star_explicit(i: usize) {
let _dyn_i: dyn* Debug = i as dyn* Debug;
}

make_dyn_star_coercion(42);
make_dyn_star_explicit(42);
}

fn method() {
trait Foo {
fn get(&self) -> usize;
}

impl Foo for usize {
fn get(&self) -> usize {
*self
}
}

fn invoke_dyn_star(i: dyn* Foo) -> usize {
i.get()
}

fn make_and_invoke_dyn_star(i: usize) -> usize {
let dyn_i: dyn* Foo = i;
invoke_dyn_star(dyn_i)
}

assert_eq!(make_and_invoke_dyn_star(42), 42);
}

fn box_() {
fn make_dyn_star() -> dyn* Display {
Box::new(42) as dyn* Display
}

let x = make_dyn_star();
assert_eq!(format!("{x}"), "42");
}

fn dispatch_on_pin_mut() {
use std::future::Future;

async fn foo(f: dyn* Future<Output = i32>) {
println!("dispatch_on_pin_mut: value: {}", f.await);
}

async fn async_main() {
foo(Box::pin(async { 1 })).await
}

// ------------------------------------------------------------------------- //
// Implementation Details Below...

use std::pin::Pin;
use std::task::*;

pub fn noop_waker() -> Waker {
let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);

// SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
unsafe { Waker::from_raw(raw) }
}

const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);

unsafe fn noop_clone(_p: *const ()) -> RawWaker {
RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
}

unsafe fn noop(_p: *const ()) {}

let mut fut = async_main();

// Poll loop, just to test the future...
let waker = noop_waker();
let ctx = &mut Context::from_waker(&waker);

loop {
match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
Poll::Pending => {}
Poll::Ready(()) => break,
}
}
}
1 change: 1 addition & 0 deletions tests/pass/dyn-star.stdout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dispatch_on_pin_mut: value: 1

0 comments on commit 1232148

Please sign in to comment.