Skip to content

Commit 1232148

Browse files
committed
Auto merge of #107728 - RalfJung:miri-dyn-star, r=RalfJung,oli-obk
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
2 parents ef95b20 + 9df7fc3 commit 1232148

File tree

6 files changed

+126
-5
lines changed

6 files changed

+126
-5
lines changed

src/helpers.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
478478
} else if matches!(v.layout.fields, FieldsShape::Union(..)) {
479479
// A (non-frozen) union. We fall back to whatever the type says.
480480
(self.unsafe_cell_action)(v)
481+
} else if matches!(v.layout.ty.kind(), ty::Dynamic(_, _, ty::DynStar)) {
482+
// This needs to read the vtable pointer to proceed type-driven, but we don't
483+
// want to reentrantly read from memory here.
484+
(self.unsafe_cell_action)(v)
481485
} else {
482486
// We want to not actually read from memory for this visit. So, before
483487
// walking this value, we have to make sure it is not a

tests/fail/branchless-select-i128-pointer.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address $HEX is unallocated)
1+
error: Undefined Behavior: constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
22
--> $DIR/branchless-select-i128-pointer.rs:LL:CC
33
|
44
LL | / transmute::<_, &str>(
55
LL | |
66
LL | | !mask & transmute::<_, TwoPtrs>("false !")
77
LL | | | mask & transmute::<_, TwoPtrs>("true !"),
88
LL | | )
9-
| |_____________^ constructing invalid value: encountered a dangling reference (address $HEX is unallocated)
9+
| |_____________^ constructing invalid value: encountered a dangling reference ($HEX[noalloc] has no provenance)
1010
|
1111
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
1212
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

tests/fail/validity/dangling_ref1.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@
33
use std::mem;
44

55
fn main() {
6-
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated)
6+
let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference
77
}

tests/fail/validity/dangling_ref1.stderr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address 0x10 is unallocated)
1+
error: Undefined Behavior: constructing invalid value: encountered a dangling reference (0x10[noalloc] has no provenance)
22
--> $DIR/dangling_ref1.rs:LL:CC
33
|
44
LL | let _x: &i32 = unsafe { mem::transmute(16usize) };
5-
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x10 is unallocated)
5+
| ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x10[noalloc] has no provenance)
66
|
77
= help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
88
= help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information

tests/pass/dyn-star.rs

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#![feature(dyn_star)]
2+
#![allow(incomplete_features)]
3+
4+
use std::fmt::{Debug, Display};
5+
6+
fn main() {
7+
make_dyn_star();
8+
method();
9+
box_();
10+
dispatch_on_pin_mut();
11+
dyn_star_to_dyn();
12+
dyn_to_dyn_star();
13+
}
14+
15+
fn dyn_star_to_dyn() {
16+
let x: dyn* Debug = &42;
17+
let x = Box::new(x) as Box<dyn Debug>;
18+
assert_eq!("42", format!("{x:?}"));
19+
}
20+
21+
fn dyn_to_dyn_star() {
22+
let x: Box<dyn Debug> = Box::new(42);
23+
let x = &x as dyn* Debug;
24+
assert_eq!("42", format!("{x:?}"));
25+
}
26+
27+
fn make_dyn_star() {
28+
fn make_dyn_star_coercion(i: usize) {
29+
let _dyn_i: dyn* Debug = i;
30+
}
31+
32+
fn make_dyn_star_explicit(i: usize) {
33+
let _dyn_i: dyn* Debug = i as dyn* Debug;
34+
}
35+
36+
make_dyn_star_coercion(42);
37+
make_dyn_star_explicit(42);
38+
}
39+
40+
fn method() {
41+
trait Foo {
42+
fn get(&self) -> usize;
43+
}
44+
45+
impl Foo for usize {
46+
fn get(&self) -> usize {
47+
*self
48+
}
49+
}
50+
51+
fn invoke_dyn_star(i: dyn* Foo) -> usize {
52+
i.get()
53+
}
54+
55+
fn make_and_invoke_dyn_star(i: usize) -> usize {
56+
let dyn_i: dyn* Foo = i;
57+
invoke_dyn_star(dyn_i)
58+
}
59+
60+
assert_eq!(make_and_invoke_dyn_star(42), 42);
61+
}
62+
63+
fn box_() {
64+
fn make_dyn_star() -> dyn* Display {
65+
Box::new(42) as dyn* Display
66+
}
67+
68+
let x = make_dyn_star();
69+
assert_eq!(format!("{x}"), "42");
70+
}
71+
72+
fn dispatch_on_pin_mut() {
73+
use std::future::Future;
74+
75+
async fn foo(f: dyn* Future<Output = i32>) {
76+
println!("dispatch_on_pin_mut: value: {}", f.await);
77+
}
78+
79+
async fn async_main() {
80+
foo(Box::pin(async { 1 })).await
81+
}
82+
83+
// ------------------------------------------------------------------------- //
84+
// Implementation Details Below...
85+
86+
use std::pin::Pin;
87+
use std::task::*;
88+
89+
pub fn noop_waker() -> Waker {
90+
let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
91+
92+
// SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
93+
unsafe { Waker::from_raw(raw) }
94+
}
95+
96+
const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
97+
98+
unsafe fn noop_clone(_p: *const ()) -> RawWaker {
99+
RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
100+
}
101+
102+
unsafe fn noop(_p: *const ()) {}
103+
104+
let mut fut = async_main();
105+
106+
// Poll loop, just to test the future...
107+
let waker = noop_waker();
108+
let ctx = &mut Context::from_waker(&waker);
109+
110+
loop {
111+
match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
112+
Poll::Pending => {}
113+
Poll::Ready(()) => break,
114+
}
115+
}
116+
}

tests/pass/dyn-star.stdout

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dispatch_on_pin_mut: value: 1

0 commit comments

Comments
 (0)