Auto merge of #92268 - jswrenn:transmute, r=oli-obk

Initial implementation of transmutability trait.

*T'was the night before Christmas and all through the codebase, not a miri was stirring — no hint of `unsafe`!*

This PR provides an initial, **incomplete** implementation of *[MCP 411: Lang Item for Transmutability](https://github.com/rust-lang/compiler-team/issues/411)*. The `core::mem::BikeshedIntrinsicFrom` trait provided by this PR is implemented on-the-fly by the compiler for types `Src` and `Dst` when the bits of all possible values of type `Src` are safely reinterpretable as a value of type `Dst`.

What this PR provides is:
- [x] [support for transmutations involving primitives](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/primitives)
- [x] [support for transmutations involving arrays](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/arrays)
- [x] [support for transmutations involving structs](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/structs)
- [x] [support for transmutations involving enums](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/enums)
- [x] [support for transmutations involving unions](https://github.com/jswrenn/rust/tree/transmute/src/test/ui/transmutability/unions)
- [x] [support for weaker validity checks](https://github.com/jswrenn/rust/blob/transmute/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs) (i.e., `Assume::VALIDITY`)
- [x] visibility checking

What isn't yet implemented:
- [ ] transmutability options passed using the `Assume` struct
- [ ] [support for references](https://github.com/jswrenn/rust/blob/transmute/src/test/ui/transmutability/references.rs)
- [ ] smarter error messages

These features will be implemented in future PRs.
This commit is contained in:
bors 2022-08-02 21:17:31 +00:00
commit e4417cf020
96 changed files with 6026 additions and 2 deletions

View File

@ -4553,6 +4553,7 @@ dependencies = [
"rustc_session",
"rustc_span",
"rustc_target",
"rustc_transmute",
"smallvec",
"tracing",
]
@ -4577,6 +4578,20 @@ dependencies = [
"tracing",
]
[[package]]
name = "rustc_transmute"
version = "0.1.0"
dependencies = [
"itertools",
"rustc_data_structures",
"rustc_infer",
"rustc_macros",
"rustc_middle",
"rustc_span",
"rustc_target",
"tracing",
]
[[package]]
name = "rustc_ty_utils"
version = "0.0.0"

View File

@ -191,6 +191,9 @@ language_item_table! {
CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1);
DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1);
// language items relating to transmutability
TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(6);
Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1);
Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1);
Mul(Op), sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1);

View File

@ -109,6 +109,10 @@ pub enum SelectionCandidate<'tcx> {
/// `false` if there are no *further* obligations.
has_nested: bool,
},
/// Implementation of transmutability trait.
TransmutabilityCandidate,
ParamCandidate(ty::PolyTraitPredicate<'tcx>),
ImplCandidate(DefId),
AutoImplCandidate(DefId),

View File

@ -48,7 +48,7 @@ pub use subst::*;
pub use vtable::*;
use std::fmt::Debug;
use std::hash::Hash;
use std::hash::{Hash, Hasher};
use std::ops::ControlFlow;
use std::{fmt, str};
@ -1704,6 +1704,59 @@ impl VariantDef {
}
}
impl PartialEq for VariantDef {
#[inline]
fn eq(&self, other: &Self) -> bool {
// There should be only one `VariantDef` for each `def_id`, therefore
// it is fine to implement `PartialEq` only based on `def_id`.
//
// Below, we exhaustively destructure `self` and `other` so that if the
// definition of `VariantDef` changes, a compile-error will be produced,
// reminding us to revisit this assumption.
let Self {
def_id: lhs_def_id,
ctor_def_id: _,
name: _,
discr: _,
fields: _,
ctor_kind: _,
flags: _,
} = &self;
let Self {
def_id: rhs_def_id,
ctor_def_id: _,
name: _,
discr: _,
fields: _,
ctor_kind: _,
flags: _,
} = other;
lhs_def_id == rhs_def_id
}
}
impl Eq for VariantDef {}
impl Hash for VariantDef {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
// There should be only one `VariantDef` for each `def_id`, therefore
// it is fine to implement `Hash` only based on `def_id`.
//
// Below, we exhaustively destructure `self` so that if the definition
// of `VariantDef` changes, a compile-error will be produced, reminding
// us to revisit this assumption.
let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } =
&self;
def_id.hash(s)
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)]
pub enum VariantDiscr {
/// Explicit value for this variant, i.e., `X = 123`.
@ -1724,6 +1777,42 @@ pub struct FieldDef {
pub vis: Visibility,
}
impl PartialEq for FieldDef {
#[inline]
fn eq(&self, other: &Self) -> bool {
// There should be only one `FieldDef` for each `did`, therefore it is
// fine to implement `PartialEq` only based on `did`.
//
// Below, we exhaustively destructure `self` so that if the definition
// of `FieldDef` changes, a compile-error will be produced, reminding
// us to revisit this assumption.
let Self { did: lhs_did, name: _, vis: _ } = &self;
let Self { did: rhs_did, name: _, vis: _ } = other;
lhs_did == rhs_did
}
}
impl Eq for FieldDef {}
impl Hash for FieldDef {
#[inline]
fn hash<H: Hasher>(&self, s: &mut H) {
// There should be only one `FieldDef` for each `did`, therefore it is
// fine to implement `Hash` only based on `did`.
//
// Below, we exhaustively destructure `self` so that if the definition
// of `FieldDef` changes, a compile-error will be produced, reminding
// us to revisit this assumption.
let Self { did, name: _, vis: _ } = &self;
did.hash(s)
}
}
bitflags! {
#[derive(TyEncodable, TyDecodable, Default, HashStable)]
pub struct ReprFlags: u8 {

View File

@ -1464,6 +1464,7 @@ symbols! {
trait_alias,
trait_upcasting,
transmute,
transmute_trait,
transparent,
transparent_enums,
transparent_unions,

View File

@ -508,6 +508,7 @@ impl fmt::Debug for Align {
impl Align {
pub const ONE: Align = Align { pow2: 0 };
pub const MAX: Align = Align { pow2: 29 };
#[inline]
pub fn from_bits(bits: u64) -> Result<Align, String> {
@ -540,7 +541,7 @@ impl Align {
if bytes != 1 {
return Err(not_power_of_2(align));
}
if pow2 > 29 {
if pow2 > Self::MAX.pow2 {
return Err(too_large(align));
}

View File

@ -23,4 +23,5 @@ rustc_query_system = { path = "../rustc_query_system" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }

View File

@ -305,6 +305,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.assemble_candidates_for_unsizing(obligation, &mut candidates);
} else if lang_items.destruct_trait() == Some(def_id) {
self.assemble_const_destruct_candidates(obligation, &mut candidates);
} else if lang_items.transmute_trait() == Some(def_id) {
// User-defined transmutability impls are permitted.
self.assemble_candidates_from_impls(obligation, &mut candidates);
self.assemble_candidates_for_transmutability(obligation, &mut candidates);
} else {
if lang_items.clone_trait() == Some(def_id) {
// Same builtin conditions as `Copy`, i.e., every type which has builtin support
@ -873,6 +877,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};
}
#[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
fn assemble_candidates_for_transmutability(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
if obligation.has_param_types_or_consts() {
return;
}
if obligation.has_infer_types_or_consts() {
candidates.ambiguous = true;
return;
}
candidates.vec.push(TransmutabilityCandidate);
}
#[tracing::instrument(level = "debug", skip(self, obligation, candidates))]
fn assemble_candidates_for_trait_alias(
&mut self,

View File

@ -48,6 +48,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(data)
}
TransmutabilityCandidate => {
let data = self.confirm_transmutability_candidate(obligation)?;
ImplSource::Builtin(data)
}
ParamCandidate(param) => {
let obligations =
self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref));
@ -267,6 +272,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSourceBuiltinData { nested: obligations }
}
fn confirm_transmutability_candidate(
&mut self,
obligation: &TraitObligation<'tcx>,
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_transmutability_candidate");
let predicate = obligation.predicate;
let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
let bool_at = |i| {
predicate
.skip_binder()
.trait_ref
.substs
.const_at(i)
.try_eval_bool(self.tcx(), obligation.param_env)
.unwrap_or(true)
};
let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
src: p.trait_ref.substs.type_at(1),
dst: p.trait_ref.substs.type_at(0),
});
let scope = type_at(2).skip_binder();
let assume = rustc_transmute::Assume {
alignment: bool_at(3),
lifetimes: bool_at(4),
validity: bool_at(5),
visibility: bool_at(6),
};
let cause = obligation.cause.clone();
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
use rustc_transmute::Answer;
match maybe_transmutable {
Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
_ => Err(Unimplemented),
}
}
/// This handles the case where an `auto trait Foo` impl is being used.
/// The idea is that the impl applies to `X : Foo` if the following conditions are met:
///

View File

@ -1630,6 +1630,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);
}
// FIXME(@jswrenn): this should probably be more sophisticated
(TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false,
// (*)
(
BuiltinCandidate { has_nested: false }

View File

@ -0,0 +1,28 @@
[package]
name = "rustc_transmute"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
tracing = "0.1"
rustc_data_structures = { path = "../rustc_data_structures", optional = true}
rustc_infer = { path = "../rustc_infer", optional = true}
rustc_macros = { path = "../rustc_macros", optional = true}
rustc_middle = { path = "../rustc_middle", optional = true}
rustc_span = { path = "../rustc_span", optional = true}
rustc_target = { path = "../rustc_target", optional = true}
[features]
rustc = [
"rustc_middle",
"rustc_data_structures",
"rustc_infer",
"rustc_macros",
"rustc_span",
"rustc_target",
]
[dev-dependencies]
itertools = "0.10.1"

View File

@ -0,0 +1,184 @@
use super::{nfa, Byte, Nfa, Ref};
use crate::Map;
use std::fmt;
use std::sync::atomic::{AtomicU32, Ordering};
#[derive(PartialEq, Clone, Debug)]
pub(crate) struct Dfa<R>
where
R: Ref,
{
pub(crate) transitions: Map<State, Transitions<R>>,
pub(crate) start: State,
pub(crate) accepting: State,
}
#[derive(PartialEq, Clone, Debug)]
pub(crate) struct Transitions<R>
where
R: Ref,
{
byte_transitions: Map<Byte, State>,
ref_transitions: Map<R, State>,
}
impl<R> Default for Transitions<R>
where
R: Ref,
{
fn default() -> Self {
Self { byte_transitions: Map::default(), ref_transitions: Map::default() }
}
}
impl<R> Transitions<R>
where
R: Ref,
{
fn insert(&mut self, transition: Transition<R>, state: State) {
match transition {
Transition::Byte(b) => {
self.byte_transitions.insert(b, state);
}
Transition::Ref(r) => {
self.ref_transitions.insert(r, state);
}
}
}
}
/// The states in a `Nfa` represent byte offsets.
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
pub(crate) struct State(u32);
#[derive(Hash, Eq, PartialEq, Clone, Copy)]
pub(crate) enum Transition<R>
where
R: Ref,
{
Byte(Byte),
Ref(R),
}
impl fmt::Debug for State {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "S_{}", self.0)
}
}
impl<R> fmt::Debug for Transition<R>
where
R: Ref,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Self::Byte(b) => b.fmt(f),
Self::Ref(r) => r.fmt(f),
}
}
}
impl<R> Dfa<R>
where
R: Ref,
{
pub(crate) fn unit() -> Self {
let transitions: Map<State, Transitions<R>> = Map::default();
let start = State::new();
let accepting = start;
Self { transitions, start, accepting }
}
#[cfg(test)]
pub(crate) fn bool() -> Self {
let mut transitions: Map<State, Transitions<R>> = Map::default();
let start = State::new();
let accepting = State::new();
transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting);
transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting);
Self { transitions, start, accepting }
}
#[instrument(level = "debug")]
#[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
pub(crate) fn from_nfa(nfa: Nfa<R>) -> Self {
let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa;
let mut dfa_transitions: Map<State, Transitions<R>> = Map::default();
let mut nfa_to_dfa: Map<nfa::State, State> = Map::default();
let dfa_start = State::new();
nfa_to_dfa.insert(nfa_start, dfa_start);
let mut queue = vec![(nfa_start, dfa_start)];
while let Some((nfa_state, dfa_state)) = queue.pop() {
if nfa_state == nfa_accepting {
continue;
}
for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() {
let dfa_transitions =
dfa_transitions.entry(dfa_state).or_insert_with(Default::default);
let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied());
let next_dfa_state = match nfa_transition {
&nfa::Transition::Byte(b) => *dfa_transitions
.byte_transitions
.entry(b)
.or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
&nfa::Transition::Ref(r) => *dfa_transitions
.ref_transitions
.entry(r)
.or_insert_with(|| mapped_state.unwrap_or_else(State::new)),
};
for &next_nfa_state in next_nfa_states {
nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| {
queue.push((next_nfa_state, next_dfa_state));
next_dfa_state
});
}
}
}
let dfa_accepting = nfa_to_dfa[&nfa_accepting];
Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting }
}
pub(crate) fn bytes_from(&self, start: State) -> Option<&Map<Byte, State>> {
Some(&self.transitions.get(&start)?.byte_transitions)
}
pub(crate) fn byte_from(&self, start: State, byte: Byte) -> Option<State> {
self.transitions.get(&start)?.byte_transitions.get(&byte).copied()
}
pub(crate) fn refs_from(&self, start: State) -> Option<&Map<R, State>> {
Some(&self.transitions.get(&start)?.ref_transitions)
}
}
impl State {
pub(crate) fn new() -> Self {
static COUNTER: AtomicU32 = AtomicU32::new(0);
Self(COUNTER.fetch_add(1, Ordering::SeqCst))
}
}
impl<R> From<nfa::Transition<R>> for Transition<R>
where
R: Ref,
{
fn from(nfa_transition: nfa::Transition<R>) -> Self {
match nfa_transition {
nfa::Transition::Byte(byte) => Transition::Byte(byte),
nfa::Transition::Ref(r) => Transition::Ref(r),
}
}
}

View File

@ -0,0 +1,71 @@
use std::fmt::{self, Debug};
use std::hash::Hash;
pub(crate) mod tree;
pub(crate) use tree::Tree;
pub(crate) mod nfa;
pub(crate) use nfa::Nfa;
pub(crate) mod dfa;
pub(crate) use dfa::Dfa;
#[derive(Debug)]
pub(crate) struct Uninhabited;
/// An instance of a byte is either initialized to a particular value, or uninitialized.
#[derive(Hash, Eq, PartialEq, Clone, Copy)]
pub(crate) enum Byte {
Uninit,
Init(u8),
}
impl fmt::Debug for Byte {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Self::Uninit => f.write_str("??u8"),
Self::Init(b) => write!(f, "{:#04x}u8", b),
}
}
}
pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {}
pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {}
impl Def for ! {}
impl Ref for ! {}
#[cfg(feature = "rustc")]
pub(crate) mod rustc {
use rustc_middle::mir::Mutability;
use rustc_middle::ty;
use rustc_middle::ty::Region;
use rustc_middle::ty::Ty;
/// A reference in the layout.
#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
pub struct Ref<'tcx> {
lifetime: Region<'tcx>,
ty: Ty<'tcx>,
mutability: Mutability,
}
impl<'tcx> super::Ref for Ref<'tcx> {}
impl<'tcx> Ref<'tcx> {
pub fn min_align(&self) -> usize {
todo!()
}
}
/// A visibility node in the layout.
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
pub enum Def<'tcx> {
Adt(ty::AdtDef<'tcx>),
Variant(&'tcx ty::VariantDef),
Field(&'tcx ty::FieldDef),
Primitive,
}
impl<'tcx> super::Def for Def<'tcx> {}
}

View File

@ -0,0 +1,179 @@
use super::{Byte, Ref, Tree, Uninhabited};
use crate::{Map, Set};
use std::fmt;
use std::sync::atomic::{AtomicU32, Ordering};
/// A non-deterministic finite automaton (NFA) that represents the layout of a type.
/// The transmutability of two given types is computed by comparing their `Nfa`s.
#[derive(PartialEq, Debug)]
pub(crate) struct Nfa<R>
where
R: Ref,
{
pub(crate) transitions: Map<State, Map<Transition<R>, Set<State>>>,
pub(crate) start: State,
pub(crate) accepting: State,
}
/// The states in a `Nfa` represent byte offsets.
#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)]
pub(crate) struct State(u32);
/// The transitions between states in a `Nfa` reflect bit validity.
#[derive(Hash, Eq, PartialEq, Clone, Copy)]
pub(crate) enum Transition<R>
where
R: Ref,
{
Byte(Byte),
Ref(R),
}
impl fmt::Debug for State {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "S_{}", self.0)
}
}
impl<R> fmt::Debug for Transition<R>
where
R: Ref,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self {
Self::Byte(b) => b.fmt(f),
Self::Ref(r) => r.fmt(f),
}
}
}
impl<R> Nfa<R>
where
R: Ref,
{
pub(crate) fn unit() -> Self {
let transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
let start = State::new();
let accepting = start;
Nfa { transitions, start, accepting }
}
pub(crate) fn from_byte(byte: Byte) -> Self {
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
let start = State::new();
let accepting = State::new();
let source = transitions.entry(start).or_default();
let edge = source.entry(Transition::Byte(byte)).or_default();
edge.insert(accepting);
Nfa { transitions, start, accepting }
}
pub(crate) fn from_ref(r: R) -> Self {
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = Map::default();
let start = State::new();
let accepting = State::new();
let source = transitions.entry(start).or_default();
let edge = source.entry(Transition::Ref(r)).or_default();
edge.insert(accepting);
Nfa { transitions, start, accepting }
}
pub(crate) fn from_tree(tree: Tree<!, R>) -> Result<Self, Uninhabited> {
Ok(match tree {
Tree::Byte(b) => Self::from_byte(b),
Tree::Def(..) => unreachable!(),
Tree::Ref(r) => Self::from_ref(r),
Tree::Alt(alts) => {
let mut alts = alts.into_iter().map(Self::from_tree);
let mut nfa = alts.next().ok_or(Uninhabited)??;
for alt in alts {
nfa = nfa.union(alt?);
}
nfa
}
Tree::Seq(elts) => {
let mut nfa = Self::unit();
for elt in elts.into_iter().map(Self::from_tree) {
nfa = nfa.concat(elt?);
}
nfa
}
})
}
/// Concatenate two `Nfa`s.
pub(crate) fn concat(self, other: Self) -> Self {
if self.start == self.accepting {
return other;
} else if other.start == other.accepting {
return self;
}
let start = self.start;
let accepting = other.accepting;
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions;
// the iteration order doesn't matter
#[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
for (source, transition) in other.transitions {
let fix_state = |state| if state == other.start { self.accepting } else { state };
let entry = transitions.entry(fix_state(source)).or_default();
for (edge, destinations) in transition {
let entry = entry.entry(edge.clone()).or_default();
for destination in destinations {
entry.insert(fix_state(destination));
}
}
}
Self { transitions, start, accepting }
}
/// Compute the union of two `Nfa`s.
pub(crate) fn union(self, other: Self) -> Self {
let start = self.start;
let accepting = self.accepting;
let mut transitions: Map<State, Map<Transition<R>, Set<State>>> = self.transitions.clone();
// the iteration order doesn't matter
#[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
for (&(mut source), transition) in other.transitions.iter() {
// if source is starting state of `other`, replace with starting state of `self`
if source == other.start {
source = self.start;
}
let entry = transitions.entry(source).or_default();
for (edge, destinations) in transition {
let entry = entry.entry(edge.clone()).or_default();
// the iteration order doesn't matter
#[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))]
for &(mut destination) in destinations {
// if dest is accepting state of `other`, replace with accepting state of `self`
if destination == other.accepting {
destination = self.accepting;
}
entry.insert(destination);
}
}
}
Self { transitions, start, accepting }
}
pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> {
self.transitions.get(&start)
}
}
impl State {
pub(crate) fn new() -> Self {
static COUNTER: AtomicU32 = AtomicU32::new(0);
Self(COUNTER.fetch_add(1, Ordering::SeqCst))
}
}

View File

@ -0,0 +1,471 @@
use super::{Byte, Def, Ref};
#[cfg(test)]
mod tests;
/// A tree-based representation of a type layout.
///
/// Invariants:
/// 1. All paths through the layout have the same length (in bytes).
///
/// Nice-to-haves:
/// 1. An `Alt` is never directly nested beneath another `Alt`.
/// 2. A `Seq` is never directly nested beneath another `Seq`.
/// 3. `Seq`s and `Alt`s with a single member do not exist.
#[derive(Clone, Debug, Hash, PartialEq, Eq)]
pub(crate) enum Tree<D, R>
where
D: Def,
R: Ref,
{
/// A sequence of successive layouts.
Seq(Vec<Self>),
/// A choice between alternative layouts.
Alt(Vec<Self>),
/// A definition node.
Def(D),
/// A reference node.
Ref(R),
/// A byte node.
Byte(Byte),
}
impl<D, R> Tree<D, R>
where
D: Def,
R: Ref,
{
/// A `Tree` consisting only of a definition node.
pub(crate) fn def(def: D) -> Self {
Self::Def(def)
}
/// A `Tree` representing an uninhabited type.
pub(crate) fn uninhabited() -> Self {
Self::Alt(vec![])
}
/// A `Tree` representing a zero-sized type.
pub(crate) fn unit() -> Self {
Self::Seq(Vec::new())
}
/// A `Tree` containing a single, uninitialized byte.
pub(crate) fn uninit() -> Self {
Self::Byte(Byte::Uninit)
}
/// A `Tree` representing the layout of `bool`.
pub(crate) fn bool() -> Self {
Self::from_bits(0x00).or(Self::from_bits(0x01))
}
/// A `Tree` whose layout matches that of a `u8`.
pub(crate) fn u8() -> Self {
Self::Alt((0u8..=255).map(Self::from_bits).collect())
}
/// A `Tree` whose layout accepts exactly the given bit pattern.
pub(crate) fn from_bits(bits: u8) -> Self {
Self::Byte(Byte::Init(bits))
}
/// A `Tree` whose layout is a number of the given width.
pub(crate) fn number(width_in_bytes: usize) -> Self {
Self::Seq(vec![Self::u8(); width_in_bytes])
}
/// A `Tree` whose layout is entirely padding of the given width.
pub(crate) fn padding(width_in_bytes: usize) -> Self {
Self::Seq(vec![Self::uninit(); width_in_bytes])
}
/// Remove all `Def` nodes, and all branches of the layout for which `f` produces false.
pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R>
where
F: Fn(D) -> bool,
{
match self {
Self::Seq(elts) => elts
.into_iter()
.map(|elt| elt.prune(f))
.try_fold(Tree::unit(), |elts, elt| {
if elt == Tree::uninhabited() {
Err(Tree::uninhabited())
} else {
Ok(elts.then(elt))
}
})
.into_ok_or_err(),
Self::Alt(alts) => alts
.into_iter()
.map(|alt| alt.prune(f))
.fold(Tree::uninhabited(), |alts, alt| alts.or(alt)),
Self::Byte(b) => Tree::Byte(b),
Self::Ref(r) => Tree::Ref(r),
Self::Def(d) => {
if !f(d) {
Tree::uninhabited()
} else {
Tree::unit()
}
}
}
}
/// Produces `true` if `Tree` is an inhabited type; otherwise false.
pub(crate) fn is_inhabited(&self) -> bool {
match self {
Self::Seq(elts) => elts.into_iter().all(|elt| elt.is_inhabited()),
Self::Alt(alts) => alts.into_iter().any(|alt| alt.is_inhabited()),
Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true,
}
}
}
impl<D, R> Tree<D, R>
where
D: Def,
R: Ref,
{
/// Produces a new `Tree` where `other` is sequenced after `self`.
pub(crate) fn then(self, other: Self) -> Self {
match (self, other) {
(Self::Seq(elts), other) | (other, Self::Seq(elts)) if elts.len() == 0 => other,
(Self::Seq(mut lhs), Self::Seq(mut rhs)) => {
lhs.append(&mut rhs);
Self::Seq(lhs)
}
(Self::Seq(mut lhs), rhs) => {
lhs.push(rhs);
Self::Seq(lhs)
}
(lhs, Self::Seq(mut rhs)) => {
rhs.insert(0, lhs);
Self::Seq(rhs)
}
(lhs, rhs) => Self::Seq(vec![lhs, rhs]),
}
}
/// Produces a new `Tree` accepting either `self` or `other` as alternative layouts.
pub(crate) fn or(self, other: Self) -> Self {
match (self, other) {
(Self::Alt(alts), other) | (other, Self::Alt(alts)) if alts.len() == 0 => other,
(Self::Alt(mut lhs), Self::Alt(rhs)) => {
lhs.extend(rhs);
Self::Alt(lhs)
}
(Self::Alt(mut alts), alt) | (alt, Self::Alt(mut alts)) => {
alts.push(alt);
Self::Alt(alts)
}
(lhs, rhs) => Self::Alt(vec![lhs, rhs]),
}
}
}
#[derive(Debug, Copy, Clone)]
pub(crate) enum Err {
/// The layout of the type is unspecified.
Unspecified,
/// This error will be surfaced elsewhere by rustc, so don't surface it.
Unknown,
}
#[cfg(feature = "rustc")]
pub(crate) mod rustc {
use super::{Err, Tree};
use crate::layout::rustc::{Def, Ref};
use rustc_middle::ty;
use rustc_middle::ty::layout::LayoutError;
use rustc_middle::ty::util::Discr;
use rustc_middle::ty::AdtDef;
use rustc_middle::ty::ParamEnv;
use rustc_middle::ty::SubstsRef;
use rustc_middle::ty::Ty;
use rustc_middle::ty::TyCtxt;
use rustc_middle::ty::VariantDef;
use rustc_target::abi::Align;
use std::alloc;
impl<'tcx> From<LayoutError<'tcx>> for Err {
fn from(err: LayoutError<'tcx>) -> Self {
match err {
LayoutError::Unknown(..) => Self::Unknown,
err @ _ => unimplemented!("{:?}", err),
}
}
}
trait LayoutExt {
fn clamp_align(&self, min_align: Align, max_align: Align) -> Self;
}
impl LayoutExt for alloc::Layout {
fn clamp_align(&self, min_align: Align, max_align: Align) -> Self {
let min_align = min_align.bytes().try_into().unwrap();
let max_align = max_align.bytes().try_into().unwrap();
Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap()
}
}
struct LayoutSummary {
total_align: Align,
total_size: usize,
discriminant_size: usize,
discriminant_align: Align,
}
impl LayoutSummary {
fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, LayoutError<'tcx>> {
use rustc_middle::ty::ParamEnvAnd;
use rustc_target::abi::{TyAndLayout, Variants};
let param_env = ParamEnv::reveal_all();
let param_env_and_type = ParamEnvAnd { param_env, value: ty };
let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
let total_size: usize = layout.size().bytes_usize();
let total_align: Align = layout.align().abi;
let discriminant_align: Align;
let discriminant_size: usize;
if let Variants::Multiple { tag, .. } = layout.variants() {
discriminant_align = tag.align(&ctx).abi;
discriminant_size = tag.size(&ctx).bytes_usize();
} else {
discriminant_align = Align::ONE;
discriminant_size = 0;
};
Ok(Self { total_align, total_size, discriminant_align, discriminant_size })
}
fn into(&self) -> alloc::Layout {
alloc::Layout::from_size_align(
self.total_size,
self.total_align.bytes().try_into().unwrap(),
)
.unwrap()
}
}
impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> {
use rustc_middle::ty::FloatTy::*;
use rustc_middle::ty::IntTy::*;
use rustc_middle::ty::UintTy::*;
use rustc_target::abi::HasDataLayout;
let target = tcx.data_layout();
match ty.kind() {
ty::Bool => Ok(Self::bool()),
ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()),
ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)),
ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)),
ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)),
ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)),
ty::Int(Isize) | ty::Uint(Usize) => {
Ok(Self::number(target.pointer_size.bytes_usize()))
}
ty::Tuple(members) => {
if members.len() == 0 {
Ok(Tree::unit())
} else {
Err(Err::Unspecified)
}
}
ty::Array(ty, len) => {
let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap();
let elt = Tree::from_ty(*ty, tcx)?;
Ok(std::iter::repeat(elt)
.take(len as usize)
.fold(Tree::unit(), |tree, elt| tree.then(elt)))
}
ty::Adt(adt_def, substs_ref) => {
use rustc_middle::ty::AdtKind;
// If the layout is ill-specified, halt.
if !(adt_def.repr().c() || adt_def.repr().int.is_some()) {
return Err(Err::Unspecified);
}
// Compute a summary of the type's layout.
let layout_summary = LayoutSummary::from_ty(ty, tcx)?;
// The layout begins with this adt's visibility.
let vis = Self::def(Def::Adt(*adt_def));
// And is followed the layout(s) of its variants
Ok(vis.then(match adt_def.adt_kind() {
AdtKind::Struct => Self::from_repr_c_variant(
ty,
*adt_def,
substs_ref,
&layout_summary,
None,
adt_def.non_enum_variant(),
tcx,
)?,
AdtKind::Enum => {
tracing::trace!(?adt_def, "treeifying enum");
let mut tree = Tree::uninhabited();
for (idx, discr) in adt_def.discriminants(tcx) {
tree = tree.or(Self::from_repr_c_variant(
ty,
*adt_def,
substs_ref,
&layout_summary,
Some(discr),
adt_def.variant(idx),
tcx,
)?);
}
tree
}
AdtKind::Union => {
// is the layout well-defined?
if !adt_def.repr().c() {
return Err(Err::Unspecified);
}
let ty_layout = layout_of(tcx, ty)?;
let mut tree = Tree::uninhabited();
for field in adt_def.all_fields() {
let variant_ty = field.ty(tcx, substs_ref);
let variant_layout = layout_of(tcx, variant_ty)?;
let padding_needed = ty_layout.size() - variant_layout.size();
let variant = Self::def(Def::Field(field))
.then(Self::from_ty(variant_ty, tcx)?)
.then(Self::padding(padding_needed));
tree = tree.or(variant);
}
tree
}
}))
}
_ => Err(Err::Unspecified),
}
}
fn from_repr_c_variant(
ty: Ty<'tcx>,
adt_def: AdtDef<'tcx>,
substs_ref: SubstsRef<'tcx>,
layout_summary: &LayoutSummary,
discr: Option<Discr<'tcx>>,
variant_def: &'tcx VariantDef,
tcx: TyCtxt<'tcx>,
) -> Result<Self, Err> {
let mut tree = Tree::unit();
let repr = adt_def.repr();
let min_align = repr.align.unwrap_or(Align::ONE);
let max_align = repr.pack.unwrap_or(Align::MAX);
let clamp =
|align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap();
let variant_span = tracing::trace_span!(
"treeifying variant",
min_align = ?min_align,
max_align = ?max_align,
)
.entered();
let mut variant_layout = alloc::Layout::from_size_align(
0,
layout_summary.total_align.bytes().try_into().unwrap(),
)
.unwrap();
// The layout of the variant is prefixed by the discriminant, if any.
if let Some(discr) = discr {
tracing::trace!(?discr, "treeifying discriminant");
let discr_layout = alloc::Layout::from_size_align(
layout_summary.discriminant_size,
clamp(layout_summary.discriminant_align),
)
.unwrap();
tracing::trace!(?discr_layout, "computed discriminant layout");
variant_layout = variant_layout.extend(discr_layout).unwrap().0;
tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size));
}
// Next come fields.
let fields_span = tracing::trace_span!("treeifying fields").entered();
for field_def in variant_def.fields.iter() {
let field_ty = field_def.ty(tcx, substs_ref);
let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered();
// begin with the field's visibility
tree = tree.then(Self::def(Def::Field(field_def)));
// compute the field's layout charactaristics
let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align);
// next comes the field's padding
let padding_needed = variant_layout.padding_needed_for(field_layout.align());
if padding_needed > 0 {
tree = tree.then(Self::padding(padding_needed));
}
// finally, the field's layout
tree = tree.then(Self::from_ty(field_ty, tcx)?);
// extend the variant layout with the field layout
variant_layout = variant_layout.extend(field_layout).unwrap().0;
}
drop(fields_span);
// finally: padding
let padding_span = tracing::trace_span!("adding trailing padding").entered();
let padding_needed = layout_summary.total_size - variant_layout.size();
if padding_needed > 0 {
tree = tree.then(Self::padding(padding_needed));
};
drop(padding_span);
drop(variant_span);
Ok(tree)
}
pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
// FIXME(@jswrenn): I'm certain this is missing needed endian nuance.
let bytes = discr.val.to_ne_bytes();
let bytes = &bytes[..size];
Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect())
}
}
fn layout_of<'tcx>(
ctx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
) -> Result<alloc::Layout, LayoutError<'tcx>> {
use rustc_middle::ty::ParamEnvAnd;
use rustc_target::abi::TyAndLayout;
let param_env = ParamEnv::reveal_all();
let param_env_and_type = ParamEnvAnd { param_env, value: ty };
let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
let layout = alloc::Layout::from_size_align(
layout.size().bytes_usize(),
layout.align().abi.bytes().try_into().unwrap(),
)
.unwrap();
tracing::trace!(?ty, ?layout, "computed layout for type");
Ok(layout)
}
}

View File

@ -0,0 +1,80 @@
use super::Tree;
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
pub enum Def {
Visible,
Invisible,
}
impl super::Def for Def {}
mod prune {
use super::*;
mod should_simplify {
use super::*;
#[test]
fn seq_1() {
let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::from_bits(0x00));
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
}
#[test]
fn seq_2() {
let layout: Tree<Def, !> =
Tree::from_bits(0x00).then(Tree::def(Def::Visible)).then(Tree::from_bits(0x01));
assert_eq!(
layout.prune(&|d| matches!(d, Def::Visible)),
Tree::from_bits(0x00).then(Tree::from_bits(0x01))
);
}
}
mod should_reject {
use super::*;
#[test]
fn invisible_def() {
let layout: Tree<Def, !> = Tree::def(Def::Invisible);
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
}
#[test]
fn invisible_def_in_seq_len_2() {
let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Invisible));
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
}
#[test]
fn invisible_def_in_seq_len_3() {
let layout: Tree<Def, !> =
Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Invisible));
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited());
}
}
mod should_accept {
use super::*;
#[test]
fn visible_def() {
let layout: Tree<Def, !> = Tree::def(Def::Visible);
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
}
#[test]
fn visible_def_in_seq_len_2() {
let layout: Tree<Def, !> = Tree::def(Def::Visible).then(Tree::def(Def::Visible));
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit());
}
#[test]
fn visible_def_in_seq_len_3() {
let layout: Tree<Def, !> =
Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Visible));
assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00));
}
}
}

View File

@ -0,0 +1,117 @@
#![feature(
alloc_layout_extra,
control_flow_enum,
decl_macro,
iterator_try_reduce,
never_type,
result_into_ok_or_err
)]
#![allow(dead_code, unused_variables)]
#[macro_use]
extern crate tracing;
#[cfg(feature = "rustc")]
pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set};
#[cfg(not(feature = "rustc"))]
pub(crate) use std::collections::{HashMap as Map, HashSet as Set};
pub(crate) mod layout;
pub(crate) mod maybe_transmutable;
#[derive(Default)]
pub struct Assume {
pub alignment: bool,
pub lifetimes: bool,
pub validity: bool,
pub visibility: bool,
}
/// The type encodes answers to the question: "Are these types transmutable?"
#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
pub enum Answer<R>
where
R: layout::Ref,
{
/// `Src` is transmutable into `Dst`.
Yes,
/// `Src` is NOT transmutable into `Dst`.
No(Reason),
/// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
IfTransmutable { src: R, dst: R },
/// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
IfAll(Vec<Answer<R>>),
/// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
IfAny(Vec<Answer<R>>),
}
/// Answers: Why wasn't the source type transmutable into the destination type?
#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)]
pub enum Reason {
/// The layout of the source type is unspecified.
SrcIsUnspecified,
/// The layout of the destination type is unspecified.
DstIsUnspecified,
/// The layout of the destination type is bit-incompatible with the source type.
DstIsBitIncompatible,
/// There aren't any public constructors for `Dst`.
DstIsPrivate,
/// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
DstIsTooBig,
}
#[cfg(feature = "rustc")]
mod rustc {
use rustc_infer::infer::InferCtxt;
use rustc_macros::{TypeFoldable, TypeVisitable};
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::Binder;
use rustc_middle::ty::Ty;
/// The source and destination types of a transmutation.
#[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
pub struct Types<'tcx> {
/// The source type.
pub src: Ty<'tcx>,
/// The destination type.
pub dst: Ty<'tcx>,
}
pub struct TransmuteTypeEnv<'cx, 'tcx> {
infcx: &'cx InferCtxt<'cx, 'tcx>,
}
impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self {
Self { infcx }
}
#[allow(unused)]
pub fn is_transmutable(
&mut self,
cause: ObligationCause<'tcx>,
src_and_dst: Binder<'tcx, Types<'tcx>>,
scope: Ty<'tcx>,
assume: crate::Assume,
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
let src = src_and_dst.map_bound(|types| types.src).skip_binder();
let dst = src_and_dst.map_bound(|types| types.dst).skip_binder();
crate::maybe_transmutable::MaybeTransmutableQuery::new(
src,
dst,
scope,
assume,
self.infcx.tcx,
)
.answer()
}
}
}
#[cfg(feature = "rustc")]
pub use rustc::*;

View File

@ -0,0 +1,320 @@
use crate::Map;
use crate::{Answer, Reason};
#[cfg(test)]
mod tests;
mod query_context;
use query_context::QueryContext;
use crate::layout::{self, dfa, Byte, Dfa, Nfa, Tree, Uninhabited};
pub(crate) struct MaybeTransmutableQuery<L, C>
where
C: QueryContext,
{
src: L,
dst: L,
scope: <C as QueryContext>::Scope,
assume: crate::Assume,
context: C,
}
impl<L, C> MaybeTransmutableQuery<L, C>
where
C: QueryContext,
{
pub(crate) fn new(
src: L,
dst: L,
scope: <C as QueryContext>::Scope,
assume: crate::Assume,
context: C,
) -> Self {
Self { src, dst, scope, assume, context }
}
pub(crate) fn map_layouts<F, M>(
self,
f: F,
) -> Result<MaybeTransmutableQuery<M, C>, Answer<<C as QueryContext>::Ref>>
where
F: FnOnce(
L,
L,
<C as QueryContext>::Scope,
&C,
) -> Result<(M, M), Answer<<C as QueryContext>::Ref>>,
{
let Self { src, dst, scope, assume, context } = self;
let (src, dst) = f(src, dst, scope, &context)?;
Ok(MaybeTransmutableQuery { src, dst, scope, assume, context })
}
}
#[cfg(feature = "rustc")]
mod rustc {
use super::*;
use crate::layout::tree::Err;
use rustc_middle::ty::Ty;
use rustc_middle::ty::TyCtxt;
impl<'tcx> MaybeTransmutableQuery<Ty<'tcx>, TyCtxt<'tcx>> {
/// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s,
/// then computes an answer using those trees.
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
let query_or_answer = self.map_layouts(|src, dst, scope, &context| {
// Convert `src` and `dst` from their rustc representations, to `Tree`-based
// representations. If these conversions fail, conclude that the transmutation is
// unacceptable; the layouts of both the source and destination types must be
// well-defined.
let src = Tree::from_ty(src, context).map_err(|err| match err {
// Answer `Yes` here, because "Unknown Type" will already be reported by
// rustc. No need to spam the user with more errors.
Err::Unknown => Answer::Yes,
Err::Unspecified => Answer::No(Reason::SrcIsUnspecified),
})?;
let dst = Tree::from_ty(dst, context).map_err(|err| match err {
Err::Unknown => Answer::Yes,
Err::Unspecified => Answer::No(Reason::DstIsUnspecified),
})?;
Ok((src, dst))
});
match query_or_answer {
Ok(query) => query.answer(),
Err(answer) => answer,
}
}
}
}
impl<C> MaybeTransmutableQuery<Tree<<C as QueryContext>::Def, <C as QueryContext>::Ref>, C>
where
C: QueryContext,
{
/// Answers whether a `Tree` is transmutable into another `Tree`.
///
/// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`,
/// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs.
#[inline(always)]
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
let assume_visibility = self.assume.visibility;
let query_or_answer = self.map_layouts(|src, dst, scope, context| {
// Remove all `Def` nodes from `src`, without checking their visibility.
let src = src.prune(&|def| true);
tracing::trace!(?src, "pruned src");
// Remove all `Def` nodes from `dst`, additionally...
let dst = if assume_visibility {
// ...if visibility is assumed, don't check their visibility.
dst.prune(&|def| true)
} else {
// ...otherwise, prune away all unreachable paths through the `Dst` layout.
dst.prune(&|def| context.is_accessible_from(def, scope))
};
tracing::trace!(?dst, "pruned dst");
// Convert `src` from a tree-based representation to an NFA-based representation.
// If the conversion fails because `src` is uninhabited, conclude that the transmutation
// is acceptable, because instances of the `src` type do not exist.
let src = Nfa::from_tree(src).map_err(|Uninhabited| Answer::Yes)?;
// Convert `dst` from a tree-based representation to an NFA-based representation.
// If the conversion fails because `src` is uninhabited, conclude that the transmutation
// is unacceptable, because instances of the `dst` type do not exist.
let dst =
Nfa::from_tree(dst).map_err(|Uninhabited| Answer::No(Reason::DstIsPrivate))?;
Ok((src, dst))
});
match query_or_answer {
Ok(query) => query.answer(),
Err(answer) => answer,
}
}
}
impl<C> MaybeTransmutableQuery<Nfa<<C as QueryContext>::Ref>, C>
where
C: QueryContext,
{
/// Answers whether a `Nfa` is transmutable into another `Nfa`.
///
/// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
#[inline(always)]
#[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))]
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
let query_or_answer = self
.map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst))));
match query_or_answer {
Ok(query) => query.answer(),
Err(answer) => answer,
}
}
}
impl<C> MaybeTransmutableQuery<Dfa<<C as QueryContext>::Ref>, C>
where
C: QueryContext,
{
/// Answers whether a `Nfa` is transmutable into another `Nfa`.
///
/// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs.
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
MaybeTransmutableQuery {
src: &self.src,
dst: &self.dst,
scope: self.scope,
assume: self.assume,
context: self.context,
}
.answer()
}
}
impl<'l, C> MaybeTransmutableQuery<&'l Dfa<<C as QueryContext>::Ref>, C>
where
C: QueryContext,
{
pub(crate) fn answer(&mut self) -> Answer<<C as QueryContext>::Ref> {
self.answer_memo(&mut Map::default(), self.src.start, self.dst.start)
}
#[inline(always)]
#[instrument(level = "debug", skip(self))]
fn answer_memo(
&self,
cache: &mut Map<(dfa::State, dfa::State), Answer<<C as QueryContext>::Ref>>,
src_state: dfa::State,
dst_state: dfa::State,
) -> Answer<<C as QueryContext>::Ref> {
if let Some(answer) = cache.get(&(src_state, dst_state)) {
answer.clone()
} else {
let answer = if dst_state == self.dst.accepting {
// truncation: `size_of(Src) >= size_of(Dst)`
Answer::Yes
} else if src_state == self.src.accepting {
// extension: `size_of(Src) >= size_of(Dst)`
if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) {
self.answer_memo(cache, src_state, dst_state_prime)
} else {
Answer::No(Reason::DstIsTooBig)
}
} else {
let src_quantification = if self.assume.validity {
// if the compiler may assume that the programmer is doing additional validity checks,
// (e.g.: that `src != 3u8` when the destination type is `bool`)
// then there must exist at least one transition out of `src_state` such that the transmute is viable...
there_exists
} else {
// if the compiler cannot assume that the programmer is doing additional validity checks,
// then for all transitions out of `src_state`, such that the transmute is viable...
// then there must exist at least one transition out of `src_state` such that the transmute is viable...
for_all
};
src_quantification(
self.src.bytes_from(src_state).unwrap_or(&Map::default()),
|(&src_validity, &src_state_prime)| {
if let Some(dst_state_prime) = self.dst.byte_from(dst_state, src_validity) {
self.answer_memo(cache, src_state_prime, dst_state_prime)
} else if let Some(dst_state_prime) =
self.dst.byte_from(dst_state, Byte::Uninit)
{
self.answer_memo(cache, src_state_prime, dst_state_prime)
} else {
Answer::No(Reason::DstIsBitIncompatible)
}
},
)
};
cache.insert((src_state, dst_state), answer.clone());
answer
}
}
}
impl<R> Answer<R>
where
R: layout::Ref,
{
pub(crate) fn and(self, rhs: Self) -> Self {
match (self, rhs) {
(Self::No(reason), _) | (_, Self::No(reason)) => Self::No(reason),
(Self::Yes, Self::Yes) => Self::Yes,
(Self::IfAll(mut lhs), Self::IfAll(ref mut rhs)) => {
lhs.append(rhs);
Self::IfAll(lhs)
}
(constraint, Self::IfAll(mut constraints))
| (Self::IfAll(mut constraints), constraint) => {
constraints.push(constraint);
Self::IfAll(constraints)
}
(lhs, rhs) => Self::IfAll(vec![lhs, rhs]),
}
}
pub(crate) fn or(self, rhs: Self) -> Self {
match (self, rhs) {
(Self::Yes, _) | (_, Self::Yes) => Self::Yes,
(Self::No(lhr), Self::No(rhr)) => Self::No(lhr),
(Self::IfAny(mut lhs), Self::IfAny(ref mut rhs)) => {
lhs.append(rhs);
Self::IfAny(lhs)
}
(constraint, Self::IfAny(mut constraints))
| (Self::IfAny(mut constraints), constraint) => {
constraints.push(constraint);
Self::IfAny(constraints)
}
(lhs, rhs) => Self::IfAny(vec![lhs, rhs]),
}
}
}
pub fn for_all<R, I, F>(iter: I, f: F) -> Answer<R>
where
R: layout::Ref,
I: IntoIterator,
F: FnMut(<I as IntoIterator>::Item) -> Answer<R>,
{
use std::ops::ControlFlow::{Break, Continue};
let (Continue(result) | Break(result)) =
iter.into_iter().map(f).try_fold(Answer::Yes, |constraints, constraint| {
match constraint.and(constraints) {
Answer::No(reason) => Break(Answer::No(reason)),
maybe => Continue(maybe),
}
});
result
}
pub fn there_exists<R, I, F>(iter: I, f: F) -> Answer<R>
where
R: layout::Ref,
I: IntoIterator,
F: FnMut(<I as IntoIterator>::Item) -> Answer<R>,
{
use std::ops::ControlFlow::{Break, Continue};
let (Continue(result) | Break(result)) = iter.into_iter().map(f).try_fold(
Answer::No(Reason::DstIsBitIncompatible),
|constraints, constraint| match constraint.or(constraints) {
Answer::Yes => Break(Answer::Yes),
maybe => Continue(maybe),
},
);
result
}

View File

@ -0,0 +1,93 @@
use crate::layout;
/// Context necessary to answer the question "Are these types transmutable?".
pub(crate) trait QueryContext {
type Def: layout::Def;
type Ref: layout::Ref;
type Scope: Copy;
/// Is `def` accessible from the defining module of `scope`?
fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool;
fn min_align(&self, reference: Self::Ref) -> usize;
}
#[cfg(test)]
pub(crate) mod test {
use super::QueryContext;
pub(crate) struct UltraMinimal;
#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)]
pub(crate) enum Def {
Visible,
Invisible,
}
impl crate::layout::Def for Def {}
impl QueryContext for UltraMinimal {
type Def = Def;
type Ref = !;
type Scope = ();
fn is_accessible_from(&self, def: Def, scope: ()) -> bool {
matches!(Def::Visible, def)
}
fn min_align(&self, reference: !) -> usize {
unimplemented!()
}
}
}
#[cfg(feature = "rustc")]
mod rustc {
use super::*;
use rustc_middle::ty::{Ty, TyCtxt};
impl<'tcx> super::QueryContext for TyCtxt<'tcx> {
type Def = layout::rustc::Def<'tcx>;
type Ref = layout::rustc::Ref<'tcx>;
type Scope = Ty<'tcx>;
#[instrument(level = "debug", skip(self))]
fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool {
use layout::rustc::Def;
use rustc_middle::ty;
let parent = if let ty::Adt(adt_def, ..) = scope.kind() {
use rustc_middle::ty::DefIdTree;
let parent = self.parent(adt_def.did());
parent
} else {
// Is this always how we want to handle a non-ADT scope?
return false;
};
let def_id = match def {
Def::Adt(adt_def) => adt_def.did(),
Def::Variant(variant_def) => variant_def.def_id,
Def::Field(field_def) => field_def.did,
Def::Primitive => {
// primitives do not have a def_id, but they're always accessible
return true;
}
};
let ret = if self.visibility(def_id).is_accessible_from(parent, *self) {
true
} else {
false
};
tracing::trace!(?ret, "ret");
ret
}
fn min_align(&self, reference: Self::Ref) -> usize {
unimplemented!()
}
}
}

View File

@ -0,0 +1,115 @@
use super::query_context::test::{Def, UltraMinimal};
use crate::maybe_transmutable::MaybeTransmutableQuery;
use crate::{layout, Answer, Reason, Set};
use itertools::Itertools;
mod bool {
use super::*;
#[test]
fn should_permit_identity_transmutation_tree() {
println!("{:?}", layout::Tree::<!, !>::bool());
let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
layout::Tree::<Def, !>::bool(),
layout::Tree::<Def, !>::bool(),
(),
crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
UltraMinimal,
)
.answer();
assert_eq!(answer, Answer::Yes);
}
#[test]
fn should_permit_identity_transmutation_dfa() {
let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new(
layout::Dfa::<!>::bool(),
layout::Dfa::<!>::bool(),
(),
crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false },
UltraMinimal,
)
.answer();
assert_eq!(answer, Answer::Yes);
}
#[test]
fn should_permit_validity_expansion_and_reject_contraction() {
let un = layout::Tree::<Def, !>::uninhabited();
let b0 = layout::Tree::<Def, !>::from_bits(0);
let b1 = layout::Tree::<Def, !>::from_bits(1);
let b2 = layout::Tree::<Def, !>::from_bits(2);
let alts = [b0, b1, b2];
let into_layout = |alts: Vec<_>| {
alts.into_iter().fold(layout::Tree::<Def, !>::uninhabited(), layout::Tree::<Def, !>::or)
};
let into_set = |alts: Vec<_>| {
#[cfg(feature = "rustc")]
let mut set = Set::default();
#[cfg(not(feature = "rustc"))]
let mut set = Set::new();
set.extend(alts);
set
};
for src_alts in alts.clone().into_iter().powerset() {
let src_layout = into_layout(src_alts.clone());
let src_set = into_set(src_alts.clone());
for dst_alts in alts.clone().into_iter().powerset().filter(|alts| !alts.is_empty()) {
let dst_layout = into_layout(dst_alts.clone());
let dst_set = into_set(dst_alts.clone());
if src_set.is_subset(&dst_set) {
assert_eq!(
Answer::Yes,
MaybeTransmutableQuery::new(
src_layout.clone(),
dst_layout.clone(),
(),
crate::Assume { validity: false, ..crate::Assume::default() },
UltraMinimal,
)
.answer(),
"{:?} SHOULD be transmutable into {:?}",
src_layout,
dst_layout
);
} else if !src_set.is_disjoint(&dst_set) {
assert_eq!(
Answer::Yes,
MaybeTransmutableQuery::new(
src_layout.clone(),
dst_layout.clone(),
(),
crate::Assume { validity: true, ..crate::Assume::default() },
UltraMinimal,
)
.answer(),
"{:?} SHOULD be transmutable (assuming validity) into {:?}",
src_layout,
dst_layout
);
} else {
assert_eq!(
Answer::No(Reason::DstIsBitIncompatible),
MaybeTransmutableQuery::new(
src_layout.clone(),
dst_layout.clone(),
(),
crate::Assume { validity: false, ..crate::Assume::default() },
UltraMinimal,
)
.answer(),
"{:?} should NOT be transmutable into {:?}",
src_layout,
dst_layout
);
}
}
}
}
}

View File

@ -27,6 +27,10 @@ mod valid_align;
// alignment as a parameter, such as `Layout::padding_needed_for`.
pub(crate) use valid_align::ValidAlign;
mod transmutability;
#[unstable(feature = "transmutability", issue = "99571")]
pub use transmutability::{Assume, BikeshedIntrinsicFrom};
#[stable(feature = "rust1", since = "1.0.0")]
#[doc(inline)]
pub use crate::intrinsics::transmute;

View File

@ -0,0 +1,43 @@
/// Are values of a type transmutable into values of another type?
///
/// This trait is implemented on-the-fly by the compiler for types `Src` and `Self` when the bits of
/// any value of type `Self` are safely transmutable into a value of type `Dst`, in a given `Context`,
/// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied.
#[unstable(feature = "transmutability", issue = "99571")]
#[cfg_attr(not(bootstrap), lang = "transmute_trait")]
#[rustc_on_unimplemented(
message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.",
label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`."
)]
pub unsafe trait BikeshedIntrinsicFrom<
Src,
Context,
const ASSUME_ALIGNMENT: bool,
const ASSUME_LIFETIMES: bool,
const ASSUME_VALIDITY: bool,
const ASSUME_VISIBILITY: bool,
> where
Src: ?Sized,
{
}
/// What transmutation safety conditions shall the compiler assume that *you* are checking?
#[unstable(feature = "transmutability", issue = "99571")]
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct Assume {
/// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that
/// destination referents do not have stricter alignment requirements than source referents.
pub alignment: bool,
/// When `true`, the compiler assume that *you* are ensuring that lifetimes are not extended in a manner
/// that violates Rust's memory model.
pub lifetimes: bool,
/// When `true`, the compiler assumes that *you* are ensuring that the source type is actually a valid
/// instance of the destination type.
pub validity: bool,
/// When `true`, the compiler assumes that *you* have ensured that it is safe for you to violate the
/// type and field privacy of the destination type (and sometimes of the source type, too).
pub visibility: bool,
}

View File

@ -0,0 +1,73 @@
// check-pass
//! The implementation should behave correctly when the `ASSUME` parameters are
//! provided indirectly through an abstraction.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<
Src,
Dst,
Context,
const ASSUME_ALIGNMENT: bool,
const ASSUME_LIFETIMES: bool,
const ASSUME_VALIDITY: bool,
const ASSUME_VISIBILITY: bool,
>()
where
Dst: BikeshedIntrinsicFrom<
Src,
Context,
ASSUME_ALIGNMENT,
ASSUME_LIFETIMES,
ASSUME_VALIDITY,
ASSUME_VISIBILITY,
>,
{}
}
fn direct() {
struct Context;
#[repr(C)] struct Src;
#[repr(C)] struct Dst;
assert::is_transmutable::<Src, Dst, Context, false, false, false, false>();
}
fn via_const() {
struct Context;
#[repr(C)] struct Src;
#[repr(C)] struct Dst;
const FALSE: bool = false;
assert::is_transmutable::<Src, Dst, Context, FALSE, FALSE, FALSE, FALSE>();
}
fn via_associated_const() {
struct Context;
#[repr(C)] struct Src;
#[repr(C)] struct Dst;
trait Trait {
const FALSE: bool = true;
}
struct Ty;
impl Trait for Ty {}
assert::is_transmutable::<
Src,
Dst,
Context,
{Ty::FALSE},
{Ty::FALSE},
{Ty::FALSE},
{Ty::FALSE}
>();
}

View File

@ -0,0 +1,41 @@
// check-pass
//! An array must have the correct length.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn array_like<T, E, const N: usize>()
where
T: BikeshedIntrinsicFrom<[E; N], Context, false, false, false, true>,
[E; N]: BikeshedIntrinsicFrom<T, Context, false, false, false, true>
{}
}
fn len_0() {
type Array = [u8; 0];
#[repr(C)] struct Struct();
assert::array_like::<Struct, u8, 0>();
}
fn len_1() {
type Array = [u8; 1];
#[repr(C)] struct Struct(u8);
assert::array_like::<Struct, u8, 1>();
}
fn len_2() {
type Array = [u8; 2];
#[repr(C)] struct Struct(u8, u8);
assert::array_like::<Struct, u8, 2>();
}
fn len_3() {
type Array = [u8; 3];
#[repr(C)] struct Struct(u8, u8, u8);
assert::array_like::<Struct, u8, 3>();
}

View File

@ -0,0 +1,44 @@
// check-pass
//! An array must have the correct length.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_have_len_0() {
type Array = [u8; 0];
#[repr(C)] struct Struct();
assert::is_maybe_transmutable::<Array, Struct>();
assert::is_maybe_transmutable::<Struct, Array>();
}
fn should_have_len_1() {
type Array = [u8; 1];
#[repr(C)] struct Struct(u8);
assert::is_maybe_transmutable::<Array, Struct>();
assert::is_maybe_transmutable::<Struct, Array>();
}
fn should_have_len_2() {
type Array = [u8; 2];
#[repr(C)] struct Struct(u8, u8);
assert::is_maybe_transmutable::<Array, Struct>();
assert::is_maybe_transmutable::<Struct, Array>();
}
fn should_have_len_3() {
type Array = [u8; 3];
#[repr(C)] struct Struct(u8, u8, u8);
assert::is_maybe_transmutable::<Array, Struct>();
assert::is_maybe_transmutable::<Struct, Array>();
}

View File

@ -0,0 +1,55 @@
// check-pass
//! An array must inherit the alignment of its inner type.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
#[repr(C)]
union Uninit {
a: (),
b: OxFF,
}
#[repr(C, align(2))] struct align_2(Ox00);
fn len_0() {
#[repr(C)] struct ImplicitlyPadded([align_2; 0], Ox01);
#[repr(C)] struct ExplicitlyPadded(Ox01, Uninit);
#[repr(C)] struct Struct();
assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
}
fn len_1() {
#[repr(C)] struct ImplicitlyPadded([align_2; 1], Ox01);
#[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox01, Uninit);
#[repr(C)] struct Struct();
assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
}
fn len_2() {
#[repr(C)] struct ImplicitlyPadded([align_2; 2], Ox01);
#[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox00, Uninit, Ox01, Uninit);
#[repr(C)] struct Struct();
assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
}

View File

@ -0,0 +1,61 @@
//! An array must have a well-defined layout to participate in a transmutation.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_reject_repr_rust()
{
fn unit() {
type repr_rust = [String; 0];
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn singleton() {
type repr_rust = [String; 1];
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn duplex() {
type repr_rust = [String; 2];
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
}
fn should_accept_repr_C()
{
fn unit() {
#[repr(C)] struct repr_c(u8, u16, u8);
type array = [repr_c; 0];
assert::is_maybe_transmutable::<array, ()>();
assert::is_maybe_transmutable::<i128, array>();
}
fn singleton() {
#[repr(C)] struct repr_c(u8, u16, u8);
type array = [repr_c; 1];
assert::is_maybe_transmutable::<array, repr_c>();
assert::is_maybe_transmutable::<repr_c, array>();
}
fn duplex() {
#[repr(C)] struct repr_c(u8, u16, u8);
#[repr(C)] struct duplex(repr_c, repr_c);
type array = [repr_c; 2];
assert::is_maybe_transmutable::<array, duplex>();
assert::is_maybe_transmutable::<duplex, array>();
}
}

View File

@ -0,0 +1,99 @@
error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:21:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:22:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 0]`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:27:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:28:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 1]`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:33:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:34:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `[String; 2]`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,149 @@
//! An enum with a primitive repr should have exactly the size of that primitive.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
#[repr(C)]
struct Zst;
#[derive(Clone, Copy)]
#[repr(i8)] enum V0i8 { V }
#[repr(u8)] enum V0u8 { V }
#[repr(i16)] enum V0i16 { V }
#[repr(u16)] enum V0u16 { V }
#[repr(i32)] enum V0i32 { V }
#[repr(u32)] enum V0u32 { V }
#[repr(i64)] enum V0i64 { V }
#[repr(u64)] enum V0u64 { V }
#[repr(isize)] enum V0isize { V }
#[repr(usize)] enum V0usize { V }
fn n8() {
struct Context;
type Smaller = Zst;
type Analog = u8;
type Larger = u16;
fn i_should_have_correct_length() {
type Current = V0i8;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
fn u_should_have_correct_length() {
type Current = V0u8;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
}
fn n16() {
struct Context;
type Smaller = u8;
type Analog = u16;
type Larger = u32;
fn i_should_have_correct_length() {
type Current = V0i16;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
fn u_should_have_correct_length() {
type Current = V0u16;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
}
fn n32() {
struct Context;
type Smaller = u16;
type Analog = u32;
type Larger = u64;
fn i_should_have_correct_length() {
type Current = V0i32;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
fn u_should_have_correct_length() {
type Current = V0u32;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
}
fn n64() {
struct Context;
type Smaller = u32;
type Analog = u64;
type Larger = u128;
fn i_should_have_correct_length() {
type Current = V0i64;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
fn u_should_have_correct_length() {
type Current = V0u64;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
}
fn nsize() {
struct Context;
type Smaller = u8;
type Analog = usize;
type Larger = [usize; 2];
fn i_should_have_correct_length() {
type Current = V0isize;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
fn u_should_have_correct_length() {
type Current = V0usize;
assert::is_transmutable::<Smaller, Current, Context>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<Current, Analog, Context>();
assert::is_transmutable::<Current, Larger, Context>(); //~ ERROR cannot be safely transmuted
}
}

View File

@ -0,0 +1,323 @@
error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:41:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0i8`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:43:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0i8, n8::Context, true, true, true, true>` is not implemented for `u16`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:49:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Zst, n8::Context, true, true, true, true>` is not implemented for `V0u8`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:51:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0u8, n8::Context, true, true, true, true>` is not implemented for `u16`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:65:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0i16`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:67:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0i16, n16::Context, true, true, true, true>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:73:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, n16::Context, true, true, true, true>` is not implemented for `V0u16`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:75:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0u16, n16::Context, true, true, true, true>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:89:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0i32`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:91:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0i32, n32::Context, true, true, true, true>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:97:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, n32::Context, true, true, true, true>` is not implemented for `V0u32`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:99:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0u32, n32::Context, true, true, true, true>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:113:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0i64`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:115:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0i64, n64::Context, true, true, true, true>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:121:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u32, n64::Context, true, true, true, true>` is not implemented for `V0u64`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:123:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0u64, n64::Context, true, true, true, true>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:137:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0isize`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:139:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0isize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:145:44
|
LL | assert::is_transmutable::<Smaller, Current, Context>();
| ^^^^^^^ `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, nsize::Context, true, true, true, true>` is not implemented for `V0usize`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
--> $DIR/primitive_reprs_should_have_correct_length.rs:147:44
|
LL | assert::is_transmutable::<Current, Larger, Context>();
| ^^^^^^ `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<V0usize, nsize::Context, true, true, true, true>` is not implemented for `[usize; 2]`
note: required by a bound in `is_transmutable`
--> $DIR/primitive_reprs_should_have_correct_length.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to 20 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,117 @@
//! An enum must have a well-defined layout to participate in a transmutation.
#![crate_type = "lib"]
#![feature(repr128)]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_reject_repr_rust() {
fn void() {
enum repr_rust {}
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn singleton() {
enum repr_rust { V }
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn duplex() {
enum repr_rust { A, B }
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
}
fn should_accept_primitive_reprs()
{
fn should_accept_repr_i8() {
#[repr(i8)] enum repr_i8 { V }
assert::is_maybe_transmutable::<repr_i8, ()>();
assert::is_maybe_transmutable::<i8, repr_i8>();
}
fn should_accept_repr_u8() {
#[repr(u8)] enum repr_u8 { V }
assert::is_maybe_transmutable::<repr_u8, ()>();
assert::is_maybe_transmutable::<u8, repr_u8>();
}
fn should_accept_repr_i16() {
#[repr(i16)] enum repr_i16 { V }
assert::is_maybe_transmutable::<repr_i16, ()>();
assert::is_maybe_transmutable::<i16, repr_i16>();
}
fn should_accept_repr_u16() {
#[repr(u16)] enum repr_u16 { V }
assert::is_maybe_transmutable::<repr_u16, ()>();
assert::is_maybe_transmutable::<u16, repr_u16>();
}
fn should_accept_repr_i32() {
#[repr(i32)] enum repr_i32 { V }
assert::is_maybe_transmutable::<repr_i32, ()>();
assert::is_maybe_transmutable::<i32, repr_i32>();
}
fn should_accept_repr_u32() {
#[repr(u32)] enum repr_u32 { V }
assert::is_maybe_transmutable::<repr_u32, ()>();
assert::is_maybe_transmutable::<u32, repr_u32>();
}
fn should_accept_repr_i64() {
#[repr(i64)] enum repr_i64 { V }
assert::is_maybe_transmutable::<repr_i64, ()>();
assert::is_maybe_transmutable::<i64, repr_i64>();
}
fn should_accept_repr_u64() {
#[repr(u64)] enum repr_u64 { V }
assert::is_maybe_transmutable::<repr_u64, ()>();
assert::is_maybe_transmutable::<u64, repr_u64>();
}
fn should_accept_repr_i128() {
#[repr(i128)] enum repr_i128 { V }
assert::is_maybe_transmutable::<repr_i128, ()>();
assert::is_maybe_transmutable::<i128, repr_i128>();
}
fn should_accept_repr_u128() {
#[repr(u128)] enum repr_u128 { V }
assert::is_maybe_transmutable::<repr_u128, ()>();
assert::is_maybe_transmutable::<u128, repr_u128>();
}
fn should_accept_repr_isize() {
#[repr(isize)] enum repr_isize { V }
assert::is_maybe_transmutable::<repr_isize, ()>();
assert::is_maybe_transmutable::<isize, repr_isize>();
}
fn should_accept_repr_usize() {
#[repr(usize)] enum repr_usize { V }
assert::is_maybe_transmutable::<repr_usize, ()>();
assert::is_maybe_transmutable::<usize, repr_usize>();
}
}
fn should_accept_repr_C() {
#[repr(C)] enum repr_c { V }
assert::is_maybe_transmutable::<repr_c, ()>();
assert::is_maybe_transmutable::<i128, repr_c>();
}

View File

@ -0,0 +1,99 @@
error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:21:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<void::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:22:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `void::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:27:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<singleton::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:28:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `singleton::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:33:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<duplex::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:34:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `duplex::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:14:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error: aborting due to 6 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,32 @@
// check-pass
//! The payloads of an enum variant should be ordered after its tag.
#![crate_type = "lib"]
#![feature(arbitrary_enum_discriminant)]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
#[repr(u8)] enum V0 { V = 0 }
#[repr(u8)] enum V1 { V = 1 }
#[repr(u8)] enum V2 { V = 2 }
#[repr(u8)] enum E01 { V0(V1) = 0u8 }
#[repr(u8)] enum E012 { V0(V1, V2) = 0u8 }
fn should_order_tag_and_fields_correctly() {
// An implementation that (incorrectly) arranges E01 as [0x01, 0x00] will,
// in principle, reject this transmutation.
assert::is_transmutable::<E01, V0>();
// Again, but with one more field.
assert::is_transmutable::<E012, E01>();
}

View File

@ -0,0 +1,40 @@
//! The variants of an enum must be padded with uninit bytes such that they have
//! the same length (in bytes).
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
#[derive(Clone, Copy)]
#[repr(C)] struct Zst;
#[derive(Clone, Copy)]
#[repr(u8)] enum V0 { V = 0 }
#[derive(Clone, Copy)]
#[repr(u8)] enum V2 { V = 2 }
#[repr(C, u8)]
enum Lopsided {
Smol(Zst),
Lorg(V0),
}
#[repr(C)] struct Src(V0, Zst, V2);
#[repr(C)] struct Dst(Lopsided, V2);
fn should_pad_variants() {
struct Context;
// If the implementation (incorrectly) fails to pad `Lopsided::Smol` with
// an uninitialized byte, this transmutation might be (wrongly) accepted:
assert::is_transmutable::<Src, Dst, Context>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
--> $DIR/should_pad_variants.rs:39:36
|
LL | assert::is_transmutable::<Src, Dst, Context>();
| ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_pad_variants.rs:13:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,33 @@
//! The target endianness should be a consideration in computing the layout of
//! an enum with a multi-byte tag.
#![crate_type = "lib"]
#![feature(arbitrary_enum_discriminant)]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
#[repr(u16)] enum Src { V = 0xCAFE }
#[repr(u8)] enum OxCA { V = 0xCA }
#[repr(u8)] enum OxFE { V = 0xFE }
#[cfg(target_endian = "big")] #[repr(C)] struct Expected(OxCA, OxFE);
#[cfg(target_endian = "big")] #[repr(C)] struct Unexpected(OxFE, OxCA);
#[cfg(target_endian = "little")] #[repr(C)] struct Expected(OxFE, OxCA);
#[cfg(target_endian = "little")] #[repr(C)] struct Unexpected(OxCA, OxFE);
fn should_respect_endianness() {
assert::is_transmutable::<Src, Expected>();
assert::is_transmutable::<Src, Unexpected>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
--> $DIR/should_respect_endianness.rs:32:36
|
LL | assert::is_transmutable::<Src, Unexpected>();
| ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Src, assert::Context, true, true, true, true>` is not implemented for `Unexpected`
note: required by a bound in `is_transmutable`
--> $DIR/should_respect_endianness.rs:15:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,9 @@
// The trait must not be available if its feature flag is absent.
#![crate_type = "lib"]
use std::mem::BikeshedIntrinsicFrom;
//~^ ERROR use of unstable library feature 'transmutability' [E0658]
use std::mem::Assume;
//~^ ERROR use of unstable library feature 'transmutability' [E0658]

View File

@ -0,0 +1,21 @@
error[E0658]: use of unstable library feature 'transmutability'
--> $DIR/feature-missing.rs:5:5
|
LL | use std::mem::BikeshedIntrinsicFrom;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: see issue #99571 <https://github.com/rust-lang/rust/issues/99571> for more information
= help: add `#![feature(transmutability)]` to the crate attributes to enable
error[E0658]: use of unstable library feature 'transmutability'
--> $DIR/feature-missing.rs:8:5
|
LL | use std::mem::Assume;
| ^^^^^^^^^^^^^^^^
|
= note: see issue #99571 <https://github.com/rust-lang/rust/issues/99571> for more information
= help: add `#![feature(transmutability)]` to the crate attributes to enable
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0658`.

View File

@ -0,0 +1,21 @@
// An unknown destination type should be gracefully handled.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
{}
}
fn should_gracefully_handle_unknown_dst() {
struct Context;
struct Src;
assert::is_transmutable::<Src, Dst, Context>(); //~ cannot find type
}

View File

@ -0,0 +1,12 @@
error[E0412]: cannot find type `Dst` in this scope
--> $DIR/unknown_dst.rs:20:36
|
LL | fn should_gracefully_handle_unknown_dst() {
| - help: you might be missing a type parameter: `<Dst>`
...
LL | assert::is_transmutable::<Src, Dst, Context>();
| ^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0412`.

View File

@ -0,0 +1,21 @@
// An unknown source type should be gracefully handled.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
{}
}
fn should_gracefully_handle_unknown_src() {
struct Context;
#[repr(C)] struct Dst;
assert::is_transmutable::<Src, Dst, Context>(); //~ cannot find type
}

View File

@ -0,0 +1,12 @@
error[E0412]: cannot find type `Src` in this scope
--> $DIR/unknown_src.rs:20:31
|
LL | fn should_gracefully_handle_unknown_src() {
| - help: you might be missing a type parameter: `<Src>`
...
LL | assert::is_transmutable::<Src, Dst, Context>();
| ^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0412`.

View File

@ -0,0 +1,22 @@
// An unknown destination type should be gracefully handled.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
{}
}
fn should_gracefully_handle_unknown_dst_field() {
struct Context;
#[repr(C)] struct Src;
#[repr(C)] struct Dst(Missing); //~ cannot find type
assert::is_transmutable::<Src, Dst, Context>();
}

View File

@ -0,0 +1,9 @@
error[E0412]: cannot find type `Missing` in this scope
--> $DIR/unknown_src_field.rs:20:27
|
LL | #[repr(C)] struct Dst(Missing);
| ^^^^^^^ not found in this scope
error: aborting due to previous error
For more information about this error, try `rustc --explain E0412`.

View File

@ -0,0 +1,40 @@
//! The implementation must behave well if const values of wrong types are
//! provided.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<
Src,
Dst,
Context,
const ASSUME_ALIGNMENT: bool,
const ASSUME_LIFETIMES: bool,
const ASSUME_VALIDITY: bool,
const ASSUME_VISIBILITY: bool,
>()
where
Dst: BikeshedIntrinsicFrom<
Src,
Context,
ASSUME_ALIGNMENT,
ASSUME_LIFETIMES,
ASSUME_VALIDITY,
ASSUME_VISIBILITY,
>,
{}
}
fn test() {
struct Context;
#[repr(C)] struct Src;
#[repr(C)] struct Dst;
assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>(); //~ ERROR mismatched types
assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>(); //~ ERROR mismatched types
assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>(); //~ ERROR mismatched types
assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>(); //~ ERROR mismatched types
}

View File

@ -0,0 +1,27 @@
error[E0308]: mismatched types
--> $DIR/wrong-type-assume.rs:36:51
|
LL | assert::is_transmutable::<Src, Dst, Context, {0u8}, false, false, false>();
| ^^^ expected `bool`, found `u8`
error[E0308]: mismatched types
--> $DIR/wrong-type-assume.rs:37:58
|
LL | assert::is_transmutable::<Src, Dst, Context, false, {0u8}, false, false>();
| ^^^ expected `bool`, found `u8`
error[E0308]: mismatched types
--> $DIR/wrong-type-assume.rs:38:65
|
LL | assert::is_transmutable::<Src, Dst, Context, false, false, {0u8}, false>();
| ^^^ expected `bool`, found `u8`
error[E0308]: mismatched types
--> $DIR/wrong-type-assume.rs:39:72
|
LL | assert::is_transmutable::<Src, Dst, Context, false, false, false, {0u8}>();
| ^^^ expected `bool`, found `u8`
error: aborting due to 4 previous errors
For more information about this error, try `rustc --explain E0308`.

View File

@ -0,0 +1,25 @@
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
#![allow(incomplete_features)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
{}
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
{}
}
fn contrast_with_u8() {
assert::is_transmutable::<u8, bool>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u8, bool>();
assert::is_transmutable::<bool, u8>();
}

View File

@ -0,0 +1,19 @@
error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
--> $DIR/bool.rs:22:35
|
LL | assert::is_transmutable::<u8, bool>();
| ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, true>` is not implemented for `bool`
note: required by a bound in `is_transmutable`
--> $DIR/bool.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,128 @@
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
#![allow(incomplete_features)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
struct Context;
pub fn is_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
{}
}
fn should_accept_identity() {
assert::is_transmutable::< i8, i8>();
assert::is_transmutable::< u8, u8>();
assert::is_transmutable::< i16, i16>();
assert::is_transmutable::< u16, u16>();
assert::is_transmutable::< i32, i32>();
assert::is_transmutable::< f32, f32>();
assert::is_transmutable::< u32, u32>();
assert::is_transmutable::< i64, i64>();
assert::is_transmutable::< f64, f64>();
assert::is_transmutable::< u64, u64>();
assert::is_transmutable::< i128, i128>();
assert::is_transmutable::< u128, u128>();
assert::is_transmutable::<isize, isize>();
assert::is_transmutable::<usize, usize>();
}
fn should_be_bitransmutable() {
assert::is_transmutable::< i8, u8>();
assert::is_transmutable::< u8, i8>();
assert::is_transmutable::< i16, u16>();
assert::is_transmutable::< u16, i16>();
assert::is_transmutable::< i32, f32>();
assert::is_transmutable::< i32, u32>();
assert::is_transmutable::< f32, i32>();
assert::is_transmutable::< f32, u32>();
assert::is_transmutable::< u32, i32>();
assert::is_transmutable::< u32, f32>();
assert::is_transmutable::< u64, i64>();
assert::is_transmutable::< u64, f64>();
assert::is_transmutable::< i64, u64>();
assert::is_transmutable::< i64, f64>();
assert::is_transmutable::< f64, u64>();
assert::is_transmutable::< f64, i64>();
assert::is_transmutable::< u128, i128>();
assert::is_transmutable::< i128, u128>();
assert::is_transmutable::<isize, usize>();
assert::is_transmutable::<usize, isize>();
}
fn should_reject_extension() {
assert::is_transmutable::< i8, i16>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, u16>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, i32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, f32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, u32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, u64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, i64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, f64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i8, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, i16>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, u16>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, i32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, f32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, u32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, u64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, i64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, f64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u8, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i16, i32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i16, f32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i16, u32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i16, u64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i16, i64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i16, f64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i16, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i16, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u16, i32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u16, f32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u16, u32>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u16, u64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u16, i64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u16, f64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u16, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u16, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i32, u64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i32, i64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i32, f64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i32, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i32, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< f32, u64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< f32, i64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< f32, f64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< f32, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< f32, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u32, u64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u32, i64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u32, f64>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u32, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u32, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u64, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< u64, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i64, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< i64, i128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< f64, u128>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::< f64, i128>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,915 @@
error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:62:40
|
LL | assert::is_transmutable::< i8, i16>();
| ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i16`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:63:40
|
LL | assert::is_transmutable::< i8, u16>();
| ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u16`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:64:40
|
LL | assert::is_transmutable::< i8, i32>();
| ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:65:40
|
LL | assert::is_transmutable::< i8, f32>();
| ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:66:40
|
LL | assert::is_transmutable::< i8, u32>();
| ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:67:40
|
LL | assert::is_transmutable::< i8, u64>();
| ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:68:40
|
LL | assert::is_transmutable::< i8, i64>();
| ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:69:40
|
LL | assert::is_transmutable::< i8, f64>();
| ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:70:39
|
LL | assert::is_transmutable::< i8, u128>();
| ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:71:39
|
LL | assert::is_transmutable::< i8, i128>();
| ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i8, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:73:40
|
LL | assert::is_transmutable::< u8, i16>();
| ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i16`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:74:40
|
LL | assert::is_transmutable::< u8, u16>();
| ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u16`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:75:40
|
LL | assert::is_transmutable::< u8, i32>();
| ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:76:40
|
LL | assert::is_transmutable::< u8, f32>();
| ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:77:40
|
LL | assert::is_transmutable::< u8, u32>();
| ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:78:40
|
LL | assert::is_transmutable::< u8, u64>();
| ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:79:40
|
LL | assert::is_transmutable::< u8, i64>();
| ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:80:40
|
LL | assert::is_transmutable::< u8, f64>();
| ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:81:39
|
LL | assert::is_transmutable::< u8, u128>();
| ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:82:39
|
LL | assert::is_transmutable::< u8, i128>();
| ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u8, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:84:40
|
LL | assert::is_transmutable::< i16, i32>();
| ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:85:40
|
LL | assert::is_transmutable::< i16, f32>();
| ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:86:40
|
LL | assert::is_transmutable::< i16, u32>();
| ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:87:40
|
LL | assert::is_transmutable::< i16, u64>();
| ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:88:40
|
LL | assert::is_transmutable::< i16, i64>();
| ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:89:40
|
LL | assert::is_transmutable::< i16, f64>();
| ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:90:39
|
LL | assert::is_transmutable::< i16, u128>();
| ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:91:39
|
LL | assert::is_transmutable::< i16, i128>();
| ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i16, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:93:40
|
LL | assert::is_transmutable::< u16, i32>();
| ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:94:40
|
LL | assert::is_transmutable::< u16, f32>();
| ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:95:40
|
LL | assert::is_transmutable::< u16, u32>();
| ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u32`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:96:40
|
LL | assert::is_transmutable::< u16, u64>();
| ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:97:40
|
LL | assert::is_transmutable::< u16, i64>();
| ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:98:40
|
LL | assert::is_transmutable::< u16, f64>();
| ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:99:39
|
LL | assert::is_transmutable::< u16, u128>();
| ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:100:39
|
LL | assert::is_transmutable::< u16, i128>();
| ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u16, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:102:40
|
LL | assert::is_transmutable::< i32, u64>();
| ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:103:40
|
LL | assert::is_transmutable::< i32, i64>();
| ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:104:40
|
LL | assert::is_transmutable::< i32, f64>();
| ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:105:39
|
LL | assert::is_transmutable::< i32, u128>();
| ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:106:39
|
LL | assert::is_transmutable::< i32, i128>();
| ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i32, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:108:40
|
LL | assert::is_transmutable::< f32, u64>();
| ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:109:40
|
LL | assert::is_transmutable::< f32, i64>();
| ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:110:40
|
LL | assert::is_transmutable::< f32, f64>();
| ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:111:39
|
LL | assert::is_transmutable::< f32, u128>();
| ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:112:39
|
LL | assert::is_transmutable::< f32, i128>();
| ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<f32, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:114:40
|
LL | assert::is_transmutable::< u32, u64>();
| ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:115:40
|
LL | assert::is_transmutable::< u32, i64>();
| ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:116:40
|
LL | assert::is_transmutable::< u32, f64>();
| ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `f64`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:117:39
|
LL | assert::is_transmutable::< u32, u128>();
| ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:118:39
|
LL | assert::is_transmutable::< u32, i128>();
| ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u32, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:120:39
|
LL | assert::is_transmutable::< u64, u128>();
| ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:121:39
|
LL | assert::is_transmutable::< u64, i128>();
| ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u64, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:123:39
|
LL | assert::is_transmutable::< i64, u128>();
| ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:124:39
|
LL | assert::is_transmutable::< i64, i128>();
| ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<i64, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:126:39
|
LL | assert::is_transmutable::< f64, u128>();
| ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `u128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
--> $DIR/numbers.rs:127:39
|
LL | assert::is_transmutable::< f64, i128>();
| ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<f64, assert::Context, false, false, false, false>` is not implemented for `i128`
note: required by a bound in `is_transmutable`
--> $DIR/numbers.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to 57 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,24 @@
//! The unit type, `()`, should be one byte.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
#[repr(C)]
struct Zst;
fn should_have_correct_size() {
struct Context;
assert::is_transmutable::<(), Zst, Context>();
assert::is_transmutable::<Zst, (), Context>();
assert::is_transmutable::<(), u8, Context>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
--> $DIR/unit.rs:23:35
|
LL | assert::is_transmutable::<(), u8, Context>();
| ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8`
note: required by a bound in `is_transmutable`
--> $DIR/unit.rs:12:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,20 @@
//! Transmutations involving references are not yet supported.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn not_yet_implemented() {
#[repr(C)] struct Unit;
assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
--> $DIR/references.rs:19:52
|
LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>();
| ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/references.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 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,36 @@
// check-pass
//! The presence of an `align(X)` annotation must be accounted for.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_pad_explicitly_aligned_field() {
#[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
#[repr(C)]
pub union Uninit {
a: (),
b: V0u8,
}
#[repr(C, align(2))] struct align_2(V0u8);
#[repr(C)] struct ImplicitlyPadded(align_2, V0u8);
#[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8);
// An implementation that (incorrectly) does not place a padding byte after
// `align_2` will, incorrectly, reject the following transmutations.
assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
}

View File

@ -0,0 +1,35 @@
// check-pass
//! The presence of an `align(X)` annotation must be accounted for.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_pad_explicitly_packed_field() {
#[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
#[derive(Clone, Copy)] #[repr(u32)] enum V0u32 { V = 0 }
#[repr(C)]
pub union Uninit {
a: (),
b: V0u8,
}
#[repr(C, packed(2))] struct ImplicitlyPadded(V0u8, V0u32);
#[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8, V0u8, V0u8, V0u8);
// An implementation that (incorrectly) does not place a padding byte after
// `align_2` will, incorrectly, reject the following transmutations.
assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
}

View File

@ -0,0 +1,76 @@
//! A struct must have a well-defined layout to participate in a transmutation.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_reject_repr_rust()
{
fn unit() {
struct repr_rust;
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn tuple() {
struct repr_rust();
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn braces() {
struct repr_rust{}
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn aligned() {
#[repr(align(1))] struct repr_rust{}
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn packed() {
#[repr(packed)] struct repr_rust{}
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn nested() {
struct repr_rust;
#[repr(C)] struct repr_c(repr_rust);
assert::is_maybe_transmutable::<repr_c, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_c>(); //~ ERROR cannot be safely transmuted
}
}
fn should_accept_repr_C()
{
fn unit() {
#[repr(C)] struct repr_c;
assert::is_maybe_transmutable::<repr_c, ()>();
assert::is_maybe_transmutable::<i128, repr_c>();
}
fn tuple() {
#[repr(C)] struct repr_c();
assert::is_maybe_transmutable::<repr_c, ()>();
assert::is_maybe_transmutable::<i128, repr_c>();
}
fn braces() {
#[repr(C)] struct repr_c{}
assert::is_maybe_transmutable::<repr_c, ()>();
assert::is_maybe_transmutable::<i128, repr_c>();
}
}

View File

@ -0,0 +1,195 @@
error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:21:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::unit::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:22:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::unit::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:27:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::tuple::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:28:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::tuple::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:33:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::braces::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:34:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::braces::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:39:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<aligned::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:40:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `aligned::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:45:52
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<packed::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:46:47
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `packed::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:52:49
|
LL | assert::is_maybe_transmutable::<repr_c, ()>();
| ^^ `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<nested::repr_c, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:53:47
|
LL | assert::is_maybe_transmutable::<u128, repr_c>();
| ^^^^^^ `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `nested::repr_c`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,31 @@
// check-pass
//! The fields of a struct should be laid out in lexical order.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
#[repr(u8)] enum V0 { V = 0 }
#[repr(u8)] enum V1 { V = 1 }
#[repr(u8)] enum V2 { V = 2 }
#[repr(C)] struct S01(V0, V1);
#[repr(C)] struct S012(V0, V1, V2);
fn should_order_tag_and_fields_correctly() {
// An implementation that (incorrectly) arranges S01 as [0x01, 0x00] will,
// in principle, reject this transmutation.
assert::is_transmutable::<S01, V0>();
// Again, but with one more field.
assert::is_transmutable::<S012, S01>();
}

View File

@ -0,0 +1,31 @@
// check-pass
#![crate_type = "lib"]
#![feature(transmutability)]
#![feature(marker_trait_attr)]
#![allow(dead_code)]
#![allow(incomplete_features)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
{}
}
fn should_match_bool() {
#[derive(Copy, Clone)] #[repr(u8)] pub enum False { V = 0 }
#[derive(Copy, Clone)] #[repr(u8)] pub enum True { V = 1 }
#[repr(C)]
pub union Bool {
pub f: False,
pub t: True,
}
assert::is_transmutable::<Bool, bool>();
assert::is_transmutable::<bool, Bool>();
}

View File

@ -0,0 +1,40 @@
// check-pass
//! The presence of an `align(X)` annotation must be accounted for.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_pad_explicitly_aligned_field() {
#[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
#[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
#[repr(C)]
pub union Uninit {
a: (),
b: V1u8,
}
#[repr(C, align(2))]
pub union align_2 {
a: V0u8,
}
#[repr(C)] struct ImplicitlyPadded(align_2, V0u8);
#[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8);
// An implementation that (incorrectly) does not place a padding byte after
// `align_2` will, incorrectly, reject the following transmutations.
assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
}

View File

@ -0,0 +1,41 @@
// check-pass
//! The presence of an `align(X)` annotation must be accounted for.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_pad_explicitly_packed_field() {
#[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 }
#[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 }
#[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 }
#[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 }
#[repr(C)]
pub union Uninit {
a: (),
b: V1u8,
}
#[repr(C, packed(2))]
pub union Packed {
a: [V3u32; 0],
b: V0u8,
}
#[repr(C)] struct ImplicitlyPadded(Packed, V2u8);
#[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V2u8);
assert::is_maybe_transmutable::<ImplicitlyPadded, ExplicitlyPadded>();
assert::is_maybe_transmutable::<ExplicitlyPadded, ImplicitlyPadded>();
}

View File

@ -0,0 +1,37 @@
//! A struct must have a well-defined layout to participate in a transmutation.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
fn should_reject_repr_rust()
{
union repr_rust {
a: u8
}
assert::is_maybe_transmutable::<repr_rust, ()>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<u128, repr_rust>(); //~ ERROR cannot be safely transmuted
}
fn should_accept_repr_C()
{
#[repr(C)]
union repr_c {
a: u8
}
struct repr_rust;
assert::is_maybe_transmutable::<repr_c, ()>();
assert::is_maybe_transmutable::<u128, repr_c>();
}

View File

@ -0,0 +1,35 @@
error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:23:48
|
LL | assert::is_maybe_transmutable::<repr_rust, ()>();
| ^^ `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<should_reject_repr_rust::repr_rust, assert::Context, true, true, true, true>` is not implemented for `()`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
--> $DIR/should_require_well_defined_layout.rs:24:43
|
LL | assert::is_maybe_transmutable::<u128, repr_rust>();
| ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<u128, assert::Context, true, true, true, true>` is not implemented for `should_reject_repr_rust::repr_rust`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_require_well_defined_layout.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,40 @@
//! The variants of a union must be padded with uninit bytes such that they have
//! the same length (in bytes).
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
{}
}
#[derive(Clone, Copy)]
#[repr(C)] struct Zst;
#[derive(Clone, Copy)]
#[repr(u8)] enum V0 { V = 0 }
#[derive(Clone, Copy)]
#[repr(u8)] enum V2 { V = 2 }
#[repr(C)]
union Lopsided {
smol: Zst,
lorg: V0,
}
#[repr(C)] struct Src(V0, Zst, V2);
#[repr(C)] struct Dst(V0, Lopsided, V2);
fn should_pad_variants() {
struct Context;
// If the implementation (incorrectly) fails to pad `Lopsided::smol` with
// an uninitialized byte, this transmutation might be (wrongly) accepted:
assert::is_transmutable::<Src, Dst, Context>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
--> $DIR/should_pad_variants.rs:39:36
|
LL | assert::is_transmutable::<Src, Dst, Context>();
| ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Src, should_pad_variants::Context, true, true, true, true>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_pad_variants.rs:13:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, true, true, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,39 @@
// check-pass
//! If validity is assumed, there need only be one matching bit-pattern between
//! the source and destination types.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
// validity IS assumed --------------------------------^^^^
{}
}
#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F }
#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
fn test() {
#[repr(C)]
union A {
a: Ox00,
b: Ox7F,
}
#[repr(C)]
union B {
a: Ox7F,
b: OxFF,
}
assert::is_maybe_transmutable::<A, B>();
assert::is_maybe_transmutable::<B, A>();
}

View File

@ -0,0 +1,36 @@
//! Validity may not be contracted, unless validity is assumed.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
{}
}
#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
fn test() {
#[repr(C)]
union Subset {
a: Ox00,
b: OxFF,
}
#[repr(C)]
union Superset {
a: Ox00,
b: OxFF,
c: Ox01,
}
assert::is_transmutable::<Superset, Subset>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
--> $DIR/should_reject_contraction.rs:35:41
|
LL | assert::is_transmutable::<Superset, Subset>();
| ^^^^^^ `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Superset, assert::Context, false, false, false, true>` is not implemented for `Subset`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_contraction.rs:13:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,36 @@
//! Validity must be satisfiable, even if validity is assumed.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_maybe_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
// validity IS assumed --------------------------------^^^^
{}
}
#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 }
#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
fn test() {
#[repr(C)]
union A {
a: Ox00,
b: OxFF,
}
#[repr(C)]
union B {
c: Ox01,
}
assert::is_maybe_transmutable::<A, B>(); //~ ERROR cannot be safely transmuted
assert::is_maybe_transmutable::<B, A>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,35 @@
error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
--> $DIR/should_reject_disjoint.rs:34:40
|
LL | assert::is_maybe_transmutable::<A, B>();
| ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, true, true>` is not implemented for `B`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_reject_disjoint.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
--> $DIR/should_reject_disjoint.rs:35:40
|
LL | assert::is_maybe_transmutable::<B, A>();
| ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, true, true>` is not implemented for `A`
note: required by a bound in `is_maybe_transmutable`
--> $DIR/should_reject_disjoint.rs:13:14
|
LL | pub fn is_maybe_transmutable<Src, Dst>()
| --------------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, true, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,38 @@
//! ALL valid bit patterns of the source must be valid bit patterns of the
//! destination type, unless validity is assumed.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code, incomplete_features, non_camel_case_types)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub struct Context;
pub fn is_transmutable<Src, Dst>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
// validity is NOT assumed ----------------------------^^^^^
{}
}
#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 }
#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F }
#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF }
fn test() {
#[repr(C)]
union A {
a: Ox00,
b: Ox7F,
}
#[repr(C)]
union B {
a: Ox7F,
b: OxFF,
}
assert::is_transmutable::<A, B>(); //~ ERROR cannot be safely transmuted
assert::is_transmutable::<B, A>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,35 @@
error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
--> $DIR/should_reject_intersecting.rs:36:34
|
LL | assert::is_transmutable::<A, B>();
| ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<A, assert::Context, false, false, false, true>` is not implemented for `B`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_intersecting.rs:14:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
--> $DIR/should_reject_intersecting.rs:37:34
|
LL | assert::is_transmutable::<B, A>();
| ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<B, assert::Context, false, false, false, true>` is not implemented for `A`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_intersecting.rs:14:14
|
LL | pub fn is_transmutable<Src, Dst>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,38 @@
// check-pass
//! If visibility is assumed, a transmutation should be accepted even if the
//! destination type contains a private field.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
// visibility IS assumed -------------------------------------^^^^
{}
}
mod src {
#[repr(C)] pub(self) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(self) field: Zst,
}
}
mod dst {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Dst {
pub(self) field: Zst, // <- private field
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
}

View File

@ -0,0 +1,39 @@
// check-pass
//! If visibility is assumed, a transmutation should be accepted even if the
//! destination type contains a private variant.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
// visibility IS assumed -------------------------------------^^^^
{}
}
mod src {
#[repr(C)] pub(self) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(self) field: Zst,
}
}
mod dst {
#[derive(Copy, Clone)]
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) union Dst {
pub(self) field: Zst, // <- private variant
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
}

View File

@ -0,0 +1,46 @@
// check-pass
//! Unless visibility is assumed, a transmutation should be rejected if the
//! destination type contains an unreachable field (e.g., a public field with a
//! private type). (This rule is distinct from type privacy, which still may
//! forbid naming such types.)
//!
//! This test exercises a tricky-to-implement instance of this principle: the
//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is
//! unreachable from `Context`.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
// visibility IS assumed -------------------------------------^^^^
{}
}
mod src {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(in super) field: Zst,
}
}
mod dst {
mod private {
#[repr(C)] pub struct Zst; // <- unreachable type
}
#[repr(C)] pub(in super) struct Dst {
pub(in super) field: private::Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
}

View File

@ -0,0 +1,39 @@
//! If visibility is assumed, a transmutation should be accepted even if the
//! destination type contains an unreachable field (e.g., a public field with a
//! private type). (This rule is distinct from type privacy, which still may
//! forbid naming such types.)
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
// visibility IS assumed -------------------------------------^^^^
{}
}
mod src {
#[repr(C)] pub(self) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(self) field: Zst,
}
}
mod dst {
#[repr(C)] pub(self) struct Zst; // <- unreachable type
#[repr(C)] pub(in super) struct Dst {
pub(in super) field: Zst, //~ ERROR private type
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
}

View File

@ -0,0 +1,12 @@
error[E0446]: private type `dst::Zst` in public interface
--> $DIR/should_accept_if_dst_has_unreachable_field.rs:32:9
|
LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type
| -------------------- `dst::Zst` declared as private
...
LL | pub(in super) field: Zst,
| ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
error: aborting due to previous error
For more information about this error, try `rustc --explain E0446`.

View File

@ -0,0 +1,40 @@
//! If visibility is assumed, a transmutation should be accepted even if the
//! destination type contains an unreachable field (e.g., a public field with a
//! private type). (This rule is distinct from type privacy, which still may
//! forbid naming such types.)
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, true>
// visibility IS assumed -------------------------------------^^^^
{}
}
mod src {
#[repr(C)] pub(self) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(self) field: Zst,
}
}
mod dst {
#[repr(C)] pub(in super) struct Zst;
// unreachable type
#[repr(C)] pub(self) struct Dst {
pub(in super) field: Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR `Dst` is private
}

View File

@ -0,0 +1,15 @@
error[E0603]: struct `Dst` is private
--> $DIR/should_accept_if_dst_has_unreachable_ty.rs:39:46
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^ private struct
|
note: the struct `Dst` is defined here
--> $DIR/should_accept_if_dst_has_unreachable_ty.rs:32:16
|
LL | #[repr(C)] pub(self) struct Dst {
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0603`.

View File

@ -0,0 +1,38 @@
// check-pass
//! The presence of a private field in the source type does not affect
//! transmutability.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(self) field: Zst, // <- private field
}
}
mod dst {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Dst {
pub(in super) field: Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
}

View File

@ -0,0 +1,39 @@
// check-pass
//! The presence of a private variant in the source type does not affect
//! transmutability.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[derive(Copy, Clone)]
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) union Src {
pub(self) field: Zst, // <- private variant
}
}
mod dst {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Dst {
pub(in super) field: Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
}

View File

@ -0,0 +1,38 @@
//! The presence of an unreachable field in the source type (e.g., a public
//! field with a private type does not affect transmutability. (This rule is
//! distinct from type privacy, which still may forbid naming such types.)
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[repr(C)] pub(self) struct Zst; // <- unreachable type
#[repr(C)] pub(in super) struct Src {
pub(in super) field: Zst, //~ ERROR private type
}
}
mod dst {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Dst {
pub(in super) field: Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
}

View File

@ -0,0 +1,12 @@
error[E0446]: private type `src::Zst` in public interface
--> $DIR/should_accept_if_src_has_unreachable_field.rs:23:9
|
LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type
| -------------------- `src::Zst` declared as private
...
LL | pub(in super) field: Zst,
| ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type
error: aborting due to previous error
For more information about this error, try `rustc --explain E0446`.

View File

@ -0,0 +1,39 @@
//! The presence of an unreachable source type (i.e., the source type is
//! private) does not affect transmutability. (This rule is distinct from type
//! privacy, which still may forbid naming such types.)
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[repr(C)] pub(in super) struct Zst;
// unreachable type
#[repr(C)] pub(self) struct Src {
pub(in super) field: Zst,
}
}
mod dst {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Dst {
pub(in super) field: Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR `Src` is private
}

View File

@ -0,0 +1,15 @@
error[E0603]: struct `Src` is private
--> $DIR/should_accept_if_src_has_unreachable_ty.rs:38:36
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^ private struct
|
note: the struct `Src` is defined here
--> $DIR/should_accept_if_src_has_unreachable_ty.rs:23:16
|
LL | #[repr(C)] pub(self) struct Src {
| ^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error
For more information about this error, try `rustc --explain E0603`.

View File

@ -0,0 +1,37 @@
//! Unless visibility is assumed, a transmutation should be rejected if the
//! destination type contains a private field.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(in super) field: Zst,
}
}
mod dst {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Dst {
pub(self) field: Zst, // <- private field
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
--> $DIR/should_reject_if_dst_has_private_field.rs:36:41
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_if_dst_has_private_field.rs:13:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,38 @@
//! Unless visibility is assumed, a transmutation should be rejected if the
//! destination type contains a private variant.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(in super) field: Zst,
}
}
mod dst {
#[derive(Copy, Clone)]
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) union Dst {
pub(self) field: Zst, // <- private variant
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
--> $DIR/should_reject_if_dst_has_private_variant.rs:37:41
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_if_dst_has_private_variant.rs:13:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,52 @@
// check-pass
//! NOTE: This test documents a known-bug in the implementation of the
//! transmutability trait. Once fixed, the above "check-pass" header should be
//! removed, and an "ERROR cannot be safely transmuted" annotation should be added at the end
//! of the line starting with `assert::is_transmutable`.
//!
//! Unless visibility is assumed, a transmutation should be rejected if the
//! destination type contains an unreachable field (e.g., a public field with a
//! private type). (This rule is distinct from type privacy, which still may
//! forbid naming such types.)
//!
//! This test exercises a tricky-to-implement instance of this principle: the
//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is
//! unreachable from `Context`. Consequently, the transmute from `Src` to `Dst`
//! SHOULD be rejected.
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(in super) field: Zst,
}
}
mod dst {
mod private {
#[repr(C)] pub struct Zst; // <- unreachable type
}
#[repr(C)] pub(in super) struct Dst {
pub(in super) field: private::Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
}

View File

@ -0,0 +1,39 @@
//! Unless visibility is assumed, a transmutation should be rejected if the
//! destination type contains an unreachable field (e.g., a public field with a
//! private type). (This rule is distinct from type privacy, which still may
//! forbid naming such types.)
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(in super) field: Zst,
}
}
mod dst {
#[repr(C)] pub(self) struct Zst; // <- unreachable type
#[repr(C)] pub(in super) struct Dst {
pub(in super) field: Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>(); //~ ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,19 @@
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
--> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0277`.

View File

@ -0,0 +1,42 @@
//! Unless visibility is assumed, a transmutation should be rejected if the
//! destination type contains an unreachable field (e.g., a public field with a
//! private type). (This rule is distinct from type privacy, which still may
//! forbid naming such types.)
#![crate_type = "lib"]
#![feature(transmutability)]
#![allow(dead_code)]
mod assert {
use std::mem::BikeshedIntrinsicFrom;
pub fn is_transmutable<Src, Dst, Context>()
where
Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
// visibility is NOT assumed ---------------------------------^^^^^
{}
}
mod src {
#[repr(C)] pub(in super) struct Zst;
#[repr(C)] pub(in super) struct Src {
pub(in super) field: Zst,
}
}
mod dst {
#[repr(C)] pub(in super) struct Zst;
// unreachable type
#[repr(C)] pub(self) struct Dst {
pub(in super) field: Zst,
}
}
fn test() {
struct Context;
assert::is_transmutable::<src::Src, dst::Dst, Context>();
//~^ ERROR `Dst` is private
//~| ERROR cannot be safely transmuted
}

View File

@ -0,0 +1,32 @@
error[E0603]: struct `Dst` is private
--> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:46
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^ private struct
|
note: the struct `Dst` is defined here
--> $DIR/should_reject_if_dst_has_unreachable_ty.rs:32:16
|
LL | #[repr(C)] pub(self) struct Dst {
| ^^^^^^^^^^^^^^^^^^^^
error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
--> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41
|
LL | assert::is_transmutable::<src::Src, dst::Dst, Context>();
| ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`.
|
= help: the trait `BikeshedIntrinsicFrom<Src, test::Context, false, false, false, false>` is not implemented for `Dst`
note: required by a bound in `is_transmutable`
--> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14
|
LL | pub fn is_transmutable<Src, Dst, Context>()
| --------------- required by a bound in this
LL | where
LL | Dst: BikeshedIntrinsicFrom<Src, Context, false, false, false, false>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable`
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0277, E0603.
For more information about an error, try `rustc --explain E0277`.