Open
Description
Consider this example:
pub fn testcase() -> *const dyn Bar {
let baz: &dyn Baz = &1;
// Unexpected coercion in the next line
let baz_fake = unsafe { std::mem::transmute::<_, *const dyn Bar>(baz) };
baz_fake
}
The initial MIR after MIR building is
bb0: {
StorageLive(_1);
StorageLive(_2);
StorageLive(_3);
StorageLive(_4);
StorageLive(_5);
_5 = const 1_i32;
_4 = &_5;
_3 = &(*_4);
_2 = move _3 as &dyn Baz (PointerCoercion(Unsize));
StorageDead(_3);
FakeRead(ForLet(None), _2);
AscribeUserType(_2, o, UserTypeProjection { base: UserType(1), projs: [] });
StorageDead(_4);
StorageLive(_6);
StorageLive(_7);
StorageLive(_8);
_8 = _2;
_7 = transmute::<&dyn Baz, *const dyn Bar>(move _8) -> [return: bb1, unwind: bb2];
}
bb1: {
StorageDead(_8);
_6 = move _7 as *const dyn Bar (PointerCoercion(Unsize));
StorageDead(_7);
FakeRead(ForLet(None), _6);
StorageLive(_9);
_9 = _6;
_1 = move _9 as *const dyn Bar (PointerCoercion(Unsize));
StorageDead(_9);
StorageDead(_6);
StorageDead(_5);
StorageDead(_2);
_0 = move _1 as *const dyn Bar (PointerCoercion(Unsize));
StorageDead(_1);
return;
}
Notice the no less than three coercions in bb1
, all of which coerce from *const dyn Bar
to *const dyn Bar
. I would have expected to see zero of them; the transmute
returns exactly the type we want so there's no reason to insert a coercion.
This came up because Miri actually considers such coercions to be a simple form of upcast that can introduce UB, so unexpected coercions can lead to unexpected UB. We can just change the MIR opsem to make identity coercions true NOPs, but we don't do this for any other kind of coercion so it's an odd special case.
Cc @rust-lang/types @rust-lang/opsem