Safe Transmute: Enable handling references, including recursive types

This patch enables support for references in Safe Transmute, by generating
nested obligations during trait selection. Specifically, when we call
`confirm_transmutability_candidate(...)`, we now recursively traverse the
`rustc_transmute::Answer` tree and create obligations for all the `Answer`
variants, some of which include multiple nested `Answer`s.

Also, to handle recursive types, enable support for coinduction for the Safe
Transmute trait (`BikeshedIntrinsicFrom`) by adding the `#[rustc_coinduction]`
annotation.

Also fix some small logic issues when reducing the `or` and `and` combinations
in `rustc_transmute`, so that we don't end up with additional redundant
`Answer`s in the tree.

Co-authored-by: Jack Wrenn <jack@wrenn.fyi>
This commit is contained in:
Bryan Garza 2023-04-21 16:49:36 -07:00
parent 97d328012b
commit 8f1cec8d84
26 changed files with 460 additions and 103 deletions

View file

@ -23,7 +23,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defin
--> $DIR/should_require_well_defined_layout.rs:27:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `[String; 0]` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
@ -65,7 +65,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defin
--> $DIR/should_require_well_defined_layout.rs:33:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `[String; 1]` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
@ -107,7 +107,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defin
--> $DIR/should_require_well_defined_layout.rs:39:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `[String; 2]` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14

View file

@ -24,7 +24,7 @@ error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scop
--> $DIR/primitive_reprs_should_have_correct_length.rs:50:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0i8` is smaller than the size of `u16`
| ^^^^^^ At least one value of `V0i8` isn't a bit-valid value of `u16`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -68,7 +68,7 @@ error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scop
--> $DIR/primitive_reprs_should_have_correct_length.rs:58:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0u8` is smaller than the size of `u16`
| ^^^^^^ At least one value of `V0u8` isn't a bit-valid value of `u16`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -112,7 +112,7 @@ error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining sco
--> $DIR/primitive_reprs_should_have_correct_length.rs:74:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0i16` is smaller than the size of `u32`
| ^^^^^^ At least one value of `V0i16` isn't a bit-valid value of `u32`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -156,7 +156,7 @@ error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining sco
--> $DIR/primitive_reprs_should_have_correct_length.rs:82:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0u16` is smaller than the size of `u32`
| ^^^^^^ At least one value of `V0u16` isn't a bit-valid value of `u32`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -200,7 +200,7 @@ error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining sco
--> $DIR/primitive_reprs_should_have_correct_length.rs:98:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0i32` is smaller than the size of `u64`
| ^^^^^^ At least one value of `V0i32` isn't a bit-valid value of `u64`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -244,7 +244,7 @@ error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining sco
--> $DIR/primitive_reprs_should_have_correct_length.rs:106:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0u32` is smaller than the size of `u64`
| ^^^^^^ At least one value of `V0u32` isn't a bit-valid value of `u64`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -288,7 +288,7 @@ error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining sc
--> $DIR/primitive_reprs_should_have_correct_length.rs:122:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0i64` is smaller than the size of `u128`
| ^^^^^^ At least one value of `V0i64` isn't a bit-valid value of `u128`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -332,7 +332,7 @@ error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining sc
--> $DIR/primitive_reprs_should_have_correct_length.rs:130:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0u64` is smaller than the size of `u128`
| ^^^^^^ At least one value of `V0u64` isn't a bit-valid value of `u128`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -376,7 +376,7 @@ error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the def
--> $DIR/primitive_reprs_should_have_correct_length.rs:146:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0isize` is smaller than the size of `[usize; 2]`
| ^^^^^^ At least one value of `V0isize` isn't a bit-valid value of `[usize; 2]`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
@ -420,7 +420,7 @@ error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the def
--> $DIR/primitive_reprs_should_have_correct_length.rs:154:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ The size of `V0usize` is smaller than the size of `[usize; 2]`
| ^^^^^^ At least one value of `V0usize` isn't a bit-valid value of `[usize; 2]`
|
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14

View file

@ -24,7 +24,7 @@ error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the d
--> $DIR/should_require_well_defined_layout.rs:29:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `void::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
@ -68,7 +68,7 @@ error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in
--> $DIR/should_require_well_defined_layout.rs:35:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `singleton::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
@ -112,7 +112,7 @@ error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the
--> $DIR/should_require_well_defined_layout.rs:41:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `duplex::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14

View file

@ -2,7 +2,7 @@ error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope
--> $DIR/should_pad_variants.rs:44:36
|
LL | assert::is_transmutable::<Src, Dst, Context>();
| ^^^ The size of `Src` is smaller than the size of `Dst`
| ^^^ At least one value of `Src` isn't a bit-valid value of `Dst`
|
note: required by a bound in `is_transmutable`
--> $DIR/should_pad_variants.rs:13:14

View file

@ -0,0 +1,27 @@
// check-fail
#![feature(transmutability)]
mod assert {
use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, {
Assume {
alignment: true,
lifetimes: false,
safety: true,
validity: false,
}
}>
{}
}
fn main() {
#[repr(C)] struct A(bool, &'static A);
#[repr(C)] struct B(u8, &'static B);
// FIXME(bryangarza): Make 2 variants of this test, depending on mutability.
// Right now, we are being strict by default and checking A->B and B->A both.
assert::is_maybe_transmutable::<&'static A, &'static B>(); //~ ERROR `B` cannot be safely transmuted into `A`
}

View file

@ -0,0 +1,25 @@
error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`
--> $DIR/recursive-wrapper-types-bit-compatible.rs:26:49
|
LL | assert::is_maybe_transmutable::<&'static A, &'static B>();
| ^^^^^^^^^^ At least one value of `B` isn't a bit-valid value of `A`
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/recursive-wrapper-types-bit-compatible.rs:10:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this function
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
| ______________^
LL | | Assume {
LL | | alignment: true,
LL | | lifetimes: false,
... |
LL | | }
LL | | }>
| |__________^ required by this bound in `is_maybe_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,25 @@
// check-fail
#![feature(transmutability)]
mod assert {
use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, {
Assume {
alignment: true,
lifetimes: false,
safety: true,
validity: false,
}
}>
{}
}
fn main() {
#[repr(C)] struct A(bool, &'static A);
#[repr(C)] struct B(u8, &'static B);
assert::is_maybe_transmutable::<&'static B, &'static A>(); //~ ERROR `B` cannot be safely transmuted into `A`
}

View file

@ -0,0 +1,25 @@
error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`
--> $DIR/recursive-wrapper-types-bit-incompatible.rs:24:49
|
LL | assert::is_maybe_transmutable::<&'static B, &'static A>();
| ^^^^^^^^^^ At least one value of `B` isn't a bit-valid value of `A`
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/recursive-wrapper-types-bit-incompatible.rs:10:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this function
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, {
| ______________^
LL | | Assume {
LL | | alignment: true,
LL | | lifetimes: false,
... |
LL | | }
LL | | }>
| |__________^ required by this bound in `is_maybe_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View file

@ -0,0 +1,26 @@
// check-pass
#![feature(transmutability)]
mod assert {
use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, {
Assume {
alignment: true,
lifetimes: false,
safety: true,
validity: false,
}
}>
{}
}
fn main() {
#[repr(C)] struct A(&'static B);
#[repr(C)] struct B(&'static A);
assert::is_maybe_transmutable::<&'static A, &'static B>();
assert::is_maybe_transmutable::<&'static B, &'static A>();
}

View file

@ -1,11 +1,5 @@
// revisions: current next
//[next] compile-flags: -Ztrait-solver=next
//! Transmutations involving references are not yet supported.
#![crate_type = "lib"]
// check-fail
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::{Assume, BikeshedIntrinsicFrom};
@ -24,7 +18,7 @@ mod assert {
{}
}
fn not_yet_implemented() {
fn main() {
#[repr(C)] struct Unit;
assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<&'static u8, &'static Unit>(); //~ ERROR `Unit` cannot be safely transmuted into `u8`
}

View file

@ -1,11 +1,11 @@
error[E0277]: `&Unit` cannot be safely transmuted into `&Unit` in the defining scope of `assert::Context`
--> $DIR/references.rs:29:52
error[E0277]: `Unit` cannot be safely transmuted into `u8` in the defining scope of `assert::Context`
--> $DIR/u8-to-unit.rs:23:50
|
LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
| ^^^^^^^^^^^^^ `&Unit` does not have a well-specified layout
LL | assert::is_maybe_transmutable::<&'static u8, &'static Unit>();
| ^^^^^^^^^^^^^ The size of `Unit` is smaller than the size of `u8`
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/references.rs:16:14
--> $DIR/u8-to-unit.rs:10:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this function

View file

@ -0,0 +1,24 @@
// check-pass
#![feature(transmutability)]
mod assert {
use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, {
Assume {
alignment: true,
lifetimes: false,
safety: true,
validity: false,
}
}>
{}
}
fn main() {
#[repr(C)] struct Unit;
assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
}

View file

@ -0,0 +1,24 @@
// check-fail
#![feature(transmutability)]
mod assert {
use std::mem::{Assume, BikeshedIntrinsicFrom};
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, {
Assume {
alignment: true,
lifetimes: true,
safety: true,
validity: true,
}
}>
{}
}
fn main() {
#[repr(C)] struct Unit;
assert::is_maybe_transmutable::<&'static Unit, &'static u8>(); //~ ERROR `Unit` cannot be safely transmuted into `u8`
}

View file

@ -1,11 +1,11 @@
error[E0277]: `&Unit` cannot be safely transmuted into `&Unit` in the defining scope of `assert::Context`
--> $DIR/references.rs:29:52
error[E0277]: `Unit` cannot be safely transmuted into `u8` in the defining scope of `assert::Context`
--> $DIR/unit-to-u8.rs:23:52
|
LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
| ^^^^^^^^^^^^^ `&Unit` does not have a well-specified layout
LL | assert::is_maybe_transmutable::<&'static Unit, &'static u8>();
| ^^^^^^^^^^^ The size of `Unit` is smaller than the size of `u8`
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/references.rs:16:14
--> $DIR/unit-to-u8.rs:10:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this function

View file

@ -2,7 +2,7 @@ error[E0277]: `()` cannot be safely transmuted into `W<'_>` in the defining scop
--> $DIR/region-infer.rs:20:5
|
LL | test();
| ^^^^ `W<'_>` does not have a well-specified layout
| ^^^^ The size of `()` is smaller than the size of `W<'_>`
|
note: required by a bound in `test`
--> $DIR/region-infer.rs:11:12

View file

@ -24,7 +24,7 @@ error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::
--> $DIR/should_require_well_defined_layout.rs:29:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `should_reject_repr_rust::unit::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
@ -68,7 +68,7 @@ error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::
--> $DIR/should_require_well_defined_layout.rs:35:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `should_reject_repr_rust::tuple::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
@ -112,7 +112,7 @@ error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::
--> $DIR/should_require_well_defined_layout.rs:41:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `should_reject_repr_rust::braces::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
@ -156,7 +156,7 @@ error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in th
--> $DIR/should_require_well_defined_layout.rs:47:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `aligned::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
@ -200,7 +200,7 @@ error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the
--> $DIR/should_require_well_defined_layout.rs:53:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `packed::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
@ -244,7 +244,7 @@ error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the de
--> $DIR/should_require_well_defined_layout.rs:60:47
|
LL | assert::is_maybe_transmutable::<u128, repr_c>();
| ^^^^^^ `nested::repr_c` does not have a well-specified layout
| ^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14

View file

@ -24,7 +24,7 @@ error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::
--> $DIR/should_require_well_defined_layout.rs:31:43
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `should_reject_repr_rust::repr_rust` does not have a well-specified layout
| ^^^^^^^^^ `u128` does not have a well-specified layout
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14

View file

@ -2,7 +2,7 @@ error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope
--> $DIR/should_pad_variants.rs:44:36
|
LL | assert::is_transmutable::<Src, Dst, Context>();
| ^^^ The size of `Src` is smaller than the size of `Dst`
| ^^^ At least one value of `Src` isn't a bit-valid value of `Dst`
|
note: required by a bound in `is_transmutable`
--> $DIR/should_pad_variants.rs:13:14

View file

@ -2,7 +2,7 @@ error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of
--> $DIR/transmute-padding-ice.rs:27:40
|
LL | assert::is_maybe_transmutable::<B, A>();
| ^ The size of `B` is smaller than the size of `A`
| ^ At least one value of `B` isn't a bit-valid value of `A`
|
note: required by a bound in `is_maybe_transmutable`
--> $DIR/transmute-padding-ice.rs:11:14