diff --git a/Cargo.lock b/Cargo.lock index ef9f91fdb434b..38ea849a58c05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4588,6 +4588,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_transmute", "smallvec", "tracing", ] @@ -4612,6 +4613,27 @@ dependencies = [ "tracing", ] +[[package]] +name = "rustc_transmute" +version = "0.1.0" +dependencies = [ + "rustc_ast", + "rustc_attr", + "rustc_data_structures", + "rustc_errors", + "rustc_hir", + "rustc_index", + "rustc_infer", + "rustc_macros", + "rustc_middle", + "rustc_parse_format", + "rustc_session", + "rustc_span", + "rustc_target", + "smallvec", + "tracing", +] + [[package]] name = "rustc_ty_utils" version = "0.0.0" diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index def0c1d06871b..3b8eb0e54f308 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -218,6 +218,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); diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 71ee00c602a3d..3d1ab8e6881d9 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -101,6 +101,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), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2b079696be245..ddaae35c4ef35 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -752,6 +752,10 @@ impl<'tcx> TraitPredicate<'tcx> { pub fn self_ty(self) -> Ty<'tcx> { self.trait_ref.self_ty() } + + pub fn substs(self) -> SubstsRef<'tcx> { + self.trait_ref.substs + } } impl<'tcx> PolyTraitPredicate<'tcx> { @@ -763,6 +767,10 @@ impl<'tcx> PolyTraitPredicate<'tcx> { pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> { self.map_bound(|trait_ref| trait_ref.self_ty()) } + + pub fn substs(self) -> ty::Binder<'tcx, SubstsRef<'tcx>> { + self.map_bound(|trait_ref| trait_ref.substs()) + } } #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)] @@ -1588,6 +1596,40 @@ impl VariantDef { } } +impl PartialOrd for VariantDef { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(&other)) + } +} + +/// There should be only one VariantDef for each `def_id`, therefore +/// it is fine to implement `Ord` only based on `def_id`. +impl Ord for VariantDef { + fn cmp(&self, other: &Self) -> Ordering { + self.def_id.cmp(&other.def_id) + } +} + +/// There should be only one VariantDef for each `def_id`, therefore +/// it is fine to implement `PartialEq` only based on `def_id`. +impl PartialEq for VariantDef { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.def_id == other.def_id + } +} + +impl Eq for VariantDef {} + +/// There should be only one VariantDef for each `def_id`, therefore +/// it is fine to implement `Hash` only based on `def_id`. +impl Hash for VariantDef { + #[inline] + fn hash(&self, s: &mut H) { + 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`. @@ -1608,6 +1650,40 @@ pub struct FieldDef { pub vis: Visibility, } +impl PartialOrd for FieldDef { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(&other)) + } +} + +/// There should be only one FieldDef for each `did`, therefore +/// it is fine to implement `Ord` only based on `did`. +impl Ord for FieldDef { + fn cmp(&self, other: &Self) -> Ordering { + self.did.cmp(&other.did) + } +} + +/// There should be only one FieldDef for each `did`, therefore +/// it is fine to implement `PartialEq` only based on `did`. +impl PartialEq for FieldDef { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.did == other.did + } +} + +impl Eq for FieldDef {} + +/// There should be only one FieldDef for each `did`, therefore +/// it is fine to implement `Hash` only based on `did`. +impl Hash for FieldDef { + #[inline] + fn hash(&self, s: &mut H) { + self.did.hash(s) + } +} + bitflags! { #[derive(TyEncodable, TyDecodable, Default, HashStable)] pub struct ReprFlags: u8 { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 84cf8878af809..1eb67f347c730 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1338,6 +1338,7 @@ symbols! { trait_alias, trait_upcasting, transmute, + transmute_trait, transparent, transparent_enums, transparent_unions, diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index a57ad8f2bbd1b..eb3f0c4bca68c 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -504,6 +504,7 @@ pub struct 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 { @@ -536,7 +537,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)); } diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index d59bdae0332cb..73a9aef8d30a0 100644 --- a/compiler/rustc_trait_selection/Cargo.toml +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -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" } smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 017f47d4357fb..b7473fbc76c20 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -300,6 +300,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_builtin_bound_candidates(sized_conditions, &mut candidates); } else if lang_items.unsize_trait() == Some(def_id) { self.assemble_candidates_for_unsizing(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.drop_trait() == Some(def_id) && obligation.predicate.skip_binder().constness == ty::BoundConstness::ConstIfConst { @@ -876,6 +880,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; } + fn assemble_candidates_for_transmutability( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if obligation.potentially_has_param_types_or_consts() { + return candidates.ambiguous = false; + } + + if obligation.has_infer_types_or_consts() { + return candidates.ambiguous = true; + } + + candidates.vec.push(TransmutabilityCandidate); + } + fn assemble_candidates_for_trait_alias( &mut self, obligation: &TraitObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index b7fc578ea3bd3..1983846fe59ac 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -90,6 +90,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(ImplSource::Builtin(data)) } + TransmutabilityCandidate => { + self.confirm_transmutability_candidate(obligation).map(ImplSource::Builtin) + } + ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); @@ -294,6 +298,54 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSourceBuiltinData { nested: obligations } } + fn confirm_transmutability_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + debug!(?obligation, "confirm_transmutability_candidate"); + + let substs = obligation.predicate.substs(); + + let type_at = |i| substs.map_bound(|s| s.type_at(i)); + let bool_at = |i| { + substs + .skip_binder() + .const_at(i) + .try_eval_bool(self.tcx(), obligation.param_env) + .unwrap() + }; + + let src_and_dst = + substs.map_bound(|s| rustc_transmute::Types { src: s.type_at(1), dst: s.type_at(0) }); + + let scope = type_at(2).skip_binder(); + let assume_alignment: bool = bool_at(3); + let assume_lifetimes: bool = bool_at(4); + let assume_validity: bool = bool_at(5); + let assume_visibility: bool = 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_alignment, + assume_lifetimes, + assume_validity, + assume_visibility, + ); + + 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: /// diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index bb3b3203a7c20..9e2035f14ebd6 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1551,6 +1551,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } + // FIXME + (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, + // (*) ( BuiltinCandidate { has_nested: false } diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml new file mode 100644 index 0000000000000..cf56d444c773d --- /dev/null +++ b/compiler/rustc_transmute/Cargo.toml @@ -0,0 +1,23 @@ +[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] +rustc_parse_format = { path = "../rustc_parse_format" } +tracing = "0.1" +rustc_attr = { path = "../rustc_attr" } +rustc_middle = { path = "../rustc_middle" } +rustc_ast = { path = "../rustc_ast" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_macros = { path = "../rustc_macros" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +smallvec = { version = "1.6.1", features = ["union", "may_dangle"] } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs new file mode 100644 index 0000000000000..fd7e405a13244 --- /dev/null +++ b/compiler/rustc_transmute/src/lib.rs @@ -0,0 +1,80 @@ +#![feature(alloc_layout_extra, control_flow_enum, iterator_try_reduce)] +#![allow(unused_imports, dead_code, unused_variables)] +use rustc_infer::infer::InferCtxt; +use rustc_macros::TypeFoldable; +use rustc_middle::traits::ObligationCause; +use rustc_middle::ty::Binder; +use rustc_middle::ty::Ty; + +pub(crate) use rustc_data_structures::fx::FxHashMap as Map; +pub(crate) use rustc_data_structures::fx::FxHashSet as Set; + +mod nfa; +pub use nfa::Nfa; + +mod maybe_transmutable; +pub use maybe_transmutable::maybe_transmutable; + +#[derive(TypeFoldable, Debug, Clone, Copy)] +pub struct Types<'tcx> { + pub src: Ty<'tcx>, + pub dst: Ty<'tcx>, +} + +/// The type encodes answers to the question: "Are these types transmutable?" +#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)] +pub enum Answer<'tcx> { + /// `Src` is transmutable into `Dst`. + Yes, + + /// `Src` is NOT transmutable into `Dst`. + No, + + /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`. + IfTransmutable { src: nfa::Ref<'tcx>, dst: nfa::Ref<'tcx> }, + + /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met. + IfAll(Vec>), + + /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met. + IfAny(Vec>), +} + +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_alignment: bool, + assume_lifetimes: bool, + assume_validity: bool, + assume_visibility: bool, + ) -> Answer<'tcx> { + let src_ty = src_and_dst.map_bound(|types| types.src).skip_binder(); + let dst_ty = src_and_dst.map_bound(|types| types.dst).skip_binder(); + + let answer = maybe_transmutable( + src_ty, + dst_ty, + scope, + assume_alignment, + assume_lifetimes, + assume_validity, + assume_visibility, + false, + self.infcx.tcx, + ); + + answer + } +} diff --git a/compiler/rustc_transmute/src/maybe_transmutable.rs b/compiler/rustc_transmute/src/maybe_transmutable.rs new file mode 100644 index 0000000000000..5f097fa206d35 --- /dev/null +++ b/compiler/rustc_transmute/src/maybe_transmutable.rs @@ -0,0 +1,248 @@ +use crate::nfa::{Byte, Nfa, State, Transition}; +use crate::Answer; +use crate::{Map, Set}; + +use rustc_middle::ty::layout::HasTyCtxt; +use rustc_middle::ty::Ty; +use rustc_middle::ty::TyCtxt; + +pub fn maybe_transmutable<'tcx>( + src_ty: Ty<'tcx>, + dst_ty: Ty<'tcx>, + scope: Ty<'tcx>, + assume_alignment: bool, + assume_lifetimes: bool, + assume_validity: bool, + assume_visibility: bool, + within_references: bool, + tcx: TyCtxt<'tcx>, +) -> Answer<'tcx> { + let src_nfa = &(if let Ok(nfa) = Nfa::from_ty(src_ty, tcx) { nfa } else { return Answer::No }); + let dst_nfa = &(if let Ok(nfa) = Nfa::from_ty(dst_ty, tcx) { nfa } else { return Answer::No }); + + MaybeTransmutableQuery { + src_nfa, + dst_nfa, + scope, + assume_alignment, + assume_lifetimes, + assume_validity, + assume_visibility, + within_references, + tcx: tcx.tcx(), + cache: Map::default(), + } + .answer(src_nfa.start, dst_nfa.start) +} + +struct MaybeTransmutableQuery<'tcx, 'nfa, C> +where + C: HasTyCtxt<'tcx>, +{ + src_nfa: &'nfa Nfa<'tcx>, + dst_nfa: &'nfa Nfa<'tcx>, + scope: Ty<'tcx>, + assume_alignment: bool, + assume_lifetimes: bool, + assume_validity: bool, + assume_visibility: bool, + within_references: bool, + tcx: C, + cache: Map<(State, State), Answer<'tcx>>, +} + +impl<'tcx, 'nfa, C> MaybeTransmutableQuery<'tcx, 'nfa, C> +where + C: HasTyCtxt<'tcx>, +{ + pub fn answer(&mut self, src_state: State, dst_state: State) -> Answer<'tcx> { + let empty_map = Map::default(); + let empty_set = Set::default(); + if dst_state == self.dst_nfa.accepting { + // truncation: `size_of(Src) >= size_of(Dst)` + Answer::Yes + } else if (src_state == self.src_nfa.accepting) && !self.within_references { + // extension: `size_of(Src) < size_of(Dst)` + // the remaining bytes of Dst must accept `Uninit` + let dst_state_primes = self + .dst_nfa + .edges_from(dst_state) + .unwrap_or(&empty_map) + .get(&Transition::Byte(Byte::Uninit)) + .unwrap_or(&empty_set); + + there_exists(dst_state_primes, |&dst_state_prime| { + self.answer_cached(src_state, dst_state_prime) + }) + } 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_nfa.edges_from(src_state).unwrap_or(&empty_map), + |(&src_transition, src_state_primes)| { + let dst_quantification = if self.assume_validity { + // for some successive src state reached via `src_transition`... + there_exists + } else { + // for all successive src states reached via `src_transition`... + for_all + }; + dst_quantification(src_state_primes, |&(mut src_state_prime)| { + let dst_transitions = + self.dst_nfa.edges_from(dst_state).unwrap_or(&empty_map); + // there must exist at least one dst_transition + there_exists(dst_transitions, |(&dst_transition, dst_state_primes)| { + // that is compatible with the src_transition + (match (src_transition, dst_transition) { + // check visibility constraint in the dst nfa + (_, Transition::Vis(vis)) => { + // if the dst transition is a visibility constraint we don't advance src_state_prime + src_state_prime = src_state; + // check the visibility constraint, if needed + if self.assume_visibility { + // if visibility is assumed, we don't need to actually check the visibility constraint + Answer::Yes + } else { + // otherwise, we do + vis.is_accessible_from(self.scope, self.tcx.tcx()) + } + } + // ignore visibility constraints in the dst nfa + (Transition::Vis(..), _) => { + // advance the src state, but not the dst state + return self.answer_cached(src_state_prime, dst_state); + } + (Transition::Byte(src_byte), Transition::Byte(dst_byte)) + if src_byte == dst_byte => + { + Answer::Yes + } + (Transition::Byte(_), Transition::Byte(Byte::Uninit)) => { + Answer::Yes + } + (Transition::Ref(src), Transition::Ref(dst)) + if src.min_align() >= dst.min_align() => + { + Answer::IfTransmutable { src: src.clone(), dst: dst.clone() } + } + _ => Answer::No, + }) + .and(there_exists( + dst_state_primes, + |&dst_state_prime| { + // such that successive bytes of `src` are transmutable + // into some path of successive bytes of `dst` + self.answer_cached(src_state_prime, dst_state_prime) + }, + )) + }) + }) + }, + ) + } + } + + #[inline(always)] + fn answer_cached(&mut self, src_state_prime: State, dst_state_prime: State) -> Answer<'tcx> { + if let Some(result) = self.cache.get(&(src_state_prime, dst_state_prime)) { + result.clone() + } else { + let result = self.answer(src_state_prime, dst_state_prime); + self.cache.insert((src_state_prime, dst_state_prime), result.clone()); + result + } + } +} + +pub fn is_compatible<'tcx>( + src_transition: &Transition<'tcx>, + dst_transition: &Transition<'tcx>, +) -> Answer<'tcx> { + match (src_transition, dst_transition) { + (Transition::Byte(src_byte), Transition::Byte(dst_byte)) if src_byte == dst_byte => { + Answer::Yes + } + (Transition::Byte(_), Transition::Byte(Byte::Uninit)) => Answer::Yes, + (Transition::Ref(src), Transition::Ref(dst)) if src.min_align() >= dst.min_align() => { + Answer::IfTransmutable { src: src.clone(), dst: dst.clone() } + } + _ => Answer::No, + } +} + +impl<'tcx> Answer<'tcx> { + fn and(self, rhs: Self) -> Self { + match (self, rhs) { + (Self::No, _) | (_, Self::No) => Self::No, + (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]), + } + } + + fn or(self, rhs: Self) -> Self { + match (self, rhs) { + (Self::Yes, _) | (_, Self::Yes) => Self::Yes, + (Self::No, Self::No) => Self::No, + (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<'tcx, I, F>(iter: I, f: F) -> Answer<'tcx> +where + I: IntoIterator, + F: FnMut(::Item) -> Answer<'tcx>, +{ + 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 => Break(Answer::No), + maybe => Continue(maybe), + } + }); + result +} + +pub fn there_exists<'tcx, I, F>(iter: I, f: F) -> Answer<'tcx> +where + I: IntoIterator, + F: FnMut(::Item) -> Answer<'tcx>, +{ + use std::ops::ControlFlow::{Break, Continue}; + let (Continue(result) | Break(result)) = + iter.into_iter().map(f).try_fold(Answer::No, |constraints, constraint| { + match constraint.or(constraints) { + Answer::Yes => Break(Answer::Yes), + maybe => Continue(maybe), + } + }); + result +} diff --git a/compiler/rustc_transmute/src/nfa.rs b/compiler/rustc_transmute/src/nfa.rs new file mode 100644 index 0000000000000..ad0a68c4649ed --- /dev/null +++ b/compiler/rustc_transmute/src/nfa.rs @@ -0,0 +1,325 @@ +use crate::Answer; +use rustc_data_structures::fx::FxHashMap as Map; +use rustc_data_structures::fx::FxHashSet as Set; +use rustc_middle::mir::Mutability; +use rustc_middle::ty; +use rustc_middle::ty::Region; +use rustc_middle::ty::Ty; +use rustc_middle::ty::TyCtxt; +use rustc_span::def_id::DefId; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::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(Debug)] +pub struct Nfa<'tcx> { + pub transitions: Map, Set>>, + pub start: State, + pub accepting: State, +} + +impl<'tcx> Nfa<'tcx> { + /// Construct an `Nfa` containing a single visibility constraint. + pub fn vis(vis: Vis<'tcx>) -> Self { + let mut transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = State::new(); + + let source = transitions.entry(start).or_default(); + let edge = source.entry(Transition::Vis(vis)).or_default(); + edge.insert(accepting); + + Nfa { transitions, start, accepting } + } + + // Constructs an `Nfa` that describes the layout of `()`. + pub fn unit() -> Self { + let transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = start; + Nfa { transitions, start, accepting } + } + + // Constructs an `Nfa` that describes the layout of a padding byte. + pub fn uninit() -> Self { + let mut transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = State::new(); + + let source = transitions.entry(start).or_default(); + let edge = source.entry(Transition::Byte(Byte::Uninit)).or_default(); + edge.insert(accepting); + + Nfa { transitions, start, accepting } + } + + // Constructs an `Nfa` that describes the layout of `bool` + pub fn bool() -> Self { + let mut transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = State::new(); + + let source = transitions.entry(start).or_default(); + (0..=1).map(Byte::Init).map(Transition::Byte).for_each(|instance| { + let edge = source.entry(instance).or_default(); + edge.insert(accepting); + }); + + Nfa { transitions, start, accepting } + } + + // Constructs an `Nfa` that describes the layout of `u8` + pub fn u8() -> Self { + let mut transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = State::new(); + + let source = transitions.entry(start).or_default(); + (0..=u8::MAX).map(Byte::Init).map(Transition::Byte).for_each(|instance| { + let edge = source.entry(instance).or_default(); + edge.insert(accepting); + }); + + Nfa { transitions, start, accepting } + } + + // Constructs an `Nfa` that describes the layout of primitive number type (e.g., `u8`, `f32`, `i64`) of + // `width_in_bytes` size. + #[allow(non_snake_case)] + pub fn number(width_in_bytes: usize) -> Self { + core::iter::repeat_with(Self::u8) + .take(width_in_bytes) + .reduce(|a, b| a.concat(b)) + .unwrap_or_else(Self::unit) + } + + // Constructs an `Nfa` that describes the layout of padding of `width_in_bytes` size. + #[allow(non_snake_case)] + pub fn padding(width_in_bytes: usize) -> Self { + core::iter::repeat_with(Self::uninit) + .take(width_in_bytes) + .reduce(|a, b| a.concat(b)) + .unwrap_or_else(Self::unit) + } + + pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result { + use rustc_middle::ty::FloatTy::*; + use rustc_middle::ty::IntTy::*; + use rustc_middle::ty::TyKind::*; + use rustc_middle::ty::UintTy::*; + use rustc_target::abi::Align; + use rustc_target::abi::HasDataLayout; + use std::alloc::Layout; + use std::iter; + + fn layout_of<'tcx>(ctx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Layout { + use rustc_middle::ty::{ParamEnv, 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).unwrap(); + Layout::from_size_align( + layout.size.bytes_usize(), + layout.align.abi.bytes().try_into().unwrap(), + ) + .unwrap() + } + + let target = tcx.data_layout(); + + match ty.kind() { + Bool => Ok(Self::bool()), + + Int(I8) | Uint(U8) => Ok(Self::u8()), + Int(I16) | Uint(U16) => Ok(Self::number(2)), + Int(I32) | Uint(U32) | Float(F32) => Ok(Self::number(4)), + Int(I64) | Uint(U64) | Float(F64) => Ok(Self::number(8)), + Int(I128) | Uint(U128) => Ok(Self::number(16)), + Int(Isize) | Uint(Usize) => Ok(Self::number(target.pointer_size.bytes_usize())), + + Adt(adt_def, substs_ref) => { + use rustc_middle::ty::AdtKind::*; + match adt_def.adt_kind() { + Struct => { + let repr = adt_def.repr; + + // is the layout well-defined? + if !repr.c() { + return Err(()); + } + + let max_align = repr.align.unwrap_or(Align::MAX); + + let size_and_align = layout_of(tcx, ty); + let mut struct_layout = + Layout::from_size_align(0, size_and_align.align()).unwrap(); + + let vis = Self::vis(Vis::Adt(*adt_def)); + + let fields = adt_def.all_fields().try_fold(vis, |nfa, field_def| { + let field_vis = Self::vis(Vis::Field(field_def)); + let field_ty = field_def.ty(tcx, substs_ref); + let field_layout = layout_of(tcx, field_ty); + + let padding_needed = struct_layout + .padding_needed_for(field_layout.align()) + .min(max_align.bytes().try_into().unwrap()); + + let padding = Self::padding(padding_needed); + + struct_layout = struct_layout.extend(field_layout).unwrap().0; + // FIXME: does where `field_vis` go matter? test this! + Ok(nfa + .concat(padding) + .concat(field_vis) + .concat(Self::from_ty(field_ty, tcx)?)) + })?; + + let padding_needed = + struct_layout.pad_to_align().size() - struct_layout.size(); + let padding = Self::padding(padding_needed); + let result = fields.concat(padding); + Ok(result) + } + _ => return Err((/* FIXME: implement this for other kinds of types */)), + } + } + + _ => Err(()), + } + } + + pub fn edges_from(&self, start: State) -> Option<&Map, Set>> { + self.transitions.get(&start) + } + + /// Concatenate two `Nfa`s. + pub 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, Set>> = self.transitions; + + 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 fn union(&self, other: &Self) -> Self { + let start = self.start; + let accepting = self.accepting; + + let mut transitions: Map, Set>> = + self.transitions.clone(); + + 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(); + 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 } + } +} + +/// The states in a `Nfa` represent byte offsets. +#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] +pub struct State(u64); + +impl State { + pub fn new() -> Self { + static COUNTER: AtomicU64 = AtomicU64::new(0); + Self(COUNTER.fetch_add(1, Ordering::SeqCst)) + } +} + +/// The transitions between states in a `Nfa` reflect bit validity. +#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] +pub enum Transition<'tcx> { + Byte(Byte), + Ref(Ref<'tcx>), + Vis(Vis<'tcx>), +} + +/// An instance of a byte is either initialized to a particular value, or uninitialized. +#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] +pub enum Byte { + Uninit, + Init(u8), +} + +#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] +pub struct Ref<'tcx> { + lifetime: Region<'tcx>, + ty: Ty<'tcx>, + mutability: Mutability, +} + +impl<'tcx> Ref<'tcx> { + pub fn min_align(&self) -> usize { + todo!() + } +} + +#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] +pub enum Vis<'tcx> { + Adt(&'tcx ty::AdtDef), + Variant(&'tcx ty::VariantDef), + Field(&'tcx ty::FieldDef), + Primitive, +} + +impl<'tcx> Vis<'tcx> { + /// Is `self` accessible from the defining module of `scope`? + pub fn is_accessible_from(self, scope: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Answer<'tcx> { + use rustc_middle::ty::TyKind::*; + let module = if let Adt(adt_def, ..) = scope.kind() { + use rustc_middle::ty::DefIdTree; + tcx.parent(adt_def.did).unwrap() + } else { + // is this reachable? + return Answer::No; + }; + let def_id = match self { + Vis::Adt(&ty::AdtDef { did, .. }) + | Vis::Variant(&ty::VariantDef { def_id: did, .. }) + | Vis::Field(&ty::FieldDef { did, .. }) => did, + Vis::Primitive => return Answer::Yes, + }; + if tcx.visibility(def_id).is_accessible_from(module, tcx) { + Answer::Yes + } else { + Answer::No + } + } +} diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 989ec0639cd6b..63e00854f419f 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -21,6 +21,10 @@ mod maybe_uninit; #[stable(feature = "maybe_uninit", since = "1.36.0")] pub use maybe_uninit::MaybeUninit; +mod transmutability; +#[unstable(feature = "transmutability", issue = "none")] +pub use transmutability::{Assume, BikeshedIntrinsicFrom}; + #[stable(feature = "rust1", since = "1.0.0")] #[doc(inline)] pub use crate::intrinsics::transmute; diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs new file mode 100644 index 0000000000000..52342f8a0ecd6 --- /dev/null +++ b/library/core/src/mem/transmutability.rs @@ -0,0 +1,39 @@ +/// 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 = "none")] +#[cfg_attr(not(bootstrap), lang = "transmute_trait")] +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 = "none")] +#[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, +} diff --git a/src/test/ui/transmutability/assume_validity.rs b/src/test/ui/transmutability/assume_validity.rs new file mode 100644 index 0000000000000..cffbff07f1342 --- /dev/null +++ b/src/test/ui/transmutability/assume_validity.rs @@ -0,0 +1,128 @@ +#![feature(transmutability)] +#![feature(marker_trait_attr)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +fn test_assume_validity() { + // if the compiler can assume that the programmer is performing additional validity + // checks, a transmute from bool to u8 can be sound + assert_is_transmutable_assume_validity::(); + + // ...but even with validity assumed, the compiler will still reject transmutations + // that couldn't *possibly* be valid. e.g.: an uninit byte cannot become an initialized byte. + #[repr(C, align(2))] pub struct BoolThenPadding(pub bool); + assert_is_transmutable_any::(); //~ ERROR not satisfied +} + +use std::mem::BikeshedIntrinsicFrom; + +struct Context; + +/// Assert that `Src` is transmutable to `Dst` under all combinations of options +/// where validity is assumed. +fn assert_is_transmutable_assume_validity() +where + Dst: + // Uncomment once visibility checking is implemented: + /* + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + */ BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom +{} + +/// Assert that `Src` is transmutable to `Dst` for at least one combination of options, +/// except those where validity is assumed. +fn assert_is_transmutable_any() +where + Dst: BikeshedIntrinsicFromAny +{} + +#[marker] +trait BikeshedIntrinsicFromAny {} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +fn main() {} diff --git a/src/test/ui/transmutability/assume_validity.stderr b/src/test/ui/transmutability/assume_validity.stderr new file mode 100644 index 0000000000000..8433fcba423f9 --- /dev/null +++ b/src/test/ui/transmutability/assume_validity.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `u16: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/assume_validity.rs:14:51 + | +LL | assert_is_transmutable_any::(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u16` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/assume_validity.rs:42:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/numbers.rs b/src/test/ui/transmutability/numbers.rs new file mode 100644 index 0000000000000..fd3454ffd67af --- /dev/null +++ b/src/test/ui/transmutability/numbers.rs @@ -0,0 +1,217 @@ +#![feature(transmutability)] +#![feature(marker_trait_attr)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +fn test_identity() { + assert_is_transmutable_all::< bool, bool>(); + assert_is_transmutable_all::< i8, i8>(); + assert_is_transmutable_all::< u8, u8>(); + assert_is_transmutable_all::< i16, i16>(); + assert_is_transmutable_all::< u16, u16>(); + assert_is_transmutable_all::< i32, i32>(); + assert_is_transmutable_all::< f32, f32>(); + assert_is_transmutable_all::< u32, u32>(); + assert_is_transmutable_all::< i64, i64>(); + assert_is_transmutable_all::< f64, f64>(); + assert_is_transmutable_all::< u64, u64>(); + assert_is_transmutable_all::< i128, i128>(); + assert_is_transmutable_all::< u128, u128>(); + assert_is_transmutable_all::(); + assert_is_transmutable_all::(); +} + +fn test_same_size() { + assert_is_transmutable_all::< bool, i8>(); + assert_is_transmutable_all::< bool, u8>(); + assert_is_transmutable_any::< i8, bool>(); //~ ERROR not satisfied + assert_is_transmutable_all::< i8, u8>(); + assert_is_transmutable_any::< u8, bool>(); //~ ERROR not satisfied + assert_is_transmutable_all::< u8, i8>(); + + assert_is_transmutable_all::< i16, u16>(); + assert_is_transmutable_all::< u16, i16>(); + + assert_is_transmutable_all::< i32, f32>(); + assert_is_transmutable_all::< i32, u32>(); + assert_is_transmutable_all::< f32, i32>(); + assert_is_transmutable_all::< f32, u32>(); + assert_is_transmutable_all::< u32, i32>(); + assert_is_transmutable_all::< u32, f32>(); + + assert_is_transmutable_all::< u64, i64>(); + assert_is_transmutable_all::< u64, f64>(); + assert_is_transmutable_all::< i64, u64>(); + assert_is_transmutable_all::< i64, f64>(); + assert_is_transmutable_all::< f64, u64>(); + assert_is_transmutable_all::< f64, i64>(); + + assert_is_transmutable_all::< u128, i128>(); + assert_is_transmutable_all::< i128, u128>(); + + assert_is_transmutable_all::(); + assert_is_transmutable_all::(); +} + +fn test_extension() { + assert_is_transmutable_any::< bool, i16>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, u16>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, i32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, f32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, u32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, u64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, i64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, f64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< bool, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< i8, i16>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, u16>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, i32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, f32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, u32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, u64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, i64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, f64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i8, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< u8, i16>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, u16>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, i32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, f32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, u32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, u64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, i64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, f64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u8, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< i16, i32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i16, f32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i16, u32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i16, u64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i16, i64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i16, f64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i16, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i16, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< u16, i32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u16, f32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u16, u32>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u16, u64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u16, i64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u16, f64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u16, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u16, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< i32, u64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i32, i64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i32, f64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i32, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i32, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< f32, u64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< f32, i64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< f32, f64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< f32, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< f32, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< u32, u64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u32, i64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u32, f64>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u32, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u32, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< u64, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< u64, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< i64, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< i64, i128>(); //~ ERROR not satisfied + + assert_is_transmutable_any::< f64, u128>(); //~ ERROR not satisfied + assert_is_transmutable_any::< f64, i128>(); //~ ERROR not satisfied +} + + +use std::mem::BikeshedIntrinsicFrom; + +struct Context; + +/// Assert that `Src` is transmutable to `Dst` under all combinations of options. +fn assert_is_transmutable_all() +where + Dst: + // Uncomment once visibility checking is implemented: + /* BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + */ BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom +{} + +/// Assert that `Src` is transmutable to `Dst` for at least one combination of options, +/// except those where validity is assumed. +fn assert_is_transmutable_any() +where + Dst: BikeshedIntrinsicFromAny +{} + +#[marker] +trait BikeshedIntrinsicFromAny {} + +// Uncomment once visibility checking is implemented: +/* +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} +*/ + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +fn main() {} diff --git a/src/test/ui/transmutability/numbers.stderr b/src/test/ui/transmutability/numbers.stderr new file mode 100644 index 0000000000000..3092c23dd5665 --- /dev/null +++ b/src/test/ui/transmutability/numbers.stderr @@ -0,0 +1,1038 @@ +error[E0277]: the trait bound `bool: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:27:42 + | +LL | assert_is_transmutable_any::< i8, bool>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `bool` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `bool: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:29:42 + | +LL | assert_is_transmutable_any::< u8, bool>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `bool` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i16: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:57:43 + | +LL | assert_is_transmutable_any::< bool, i16>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i16` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:58:43 + | +LL | assert_is_transmutable_any::< bool, u16>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u16` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:59:43 + | +LL | assert_is_transmutable_any::< bool, i32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:60:43 + | +LL | assert_is_transmutable_any::< bool, f32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:61:43 + | +LL | assert_is_transmutable_any::< bool, u32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:62:43 + | +LL | assert_is_transmutable_any::< bool, u64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:63:43 + | +LL | assert_is_transmutable_any::< bool, i64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:64:43 + | +LL | assert_is_transmutable_any::< bool, f64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:65:42 + | +LL | assert_is_transmutable_any::< bool, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:66:42 + | +LL | assert_is_transmutable_any::< bool, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i16: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:68:43 + | +LL | assert_is_transmutable_any::< i8, i16>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i16` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:69:43 + | +LL | assert_is_transmutable_any::< i8, u16>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u16` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:70:43 + | +LL | assert_is_transmutable_any::< i8, i32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:71:43 + | +LL | assert_is_transmutable_any::< i8, f32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:72:43 + | +LL | assert_is_transmutable_any::< i8, u32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:73:43 + | +LL | assert_is_transmutable_any::< i8, u64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:74:43 + | +LL | assert_is_transmutable_any::< i8, i64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:75:43 + | +LL | assert_is_transmutable_any::< i8, f64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:76:42 + | +LL | assert_is_transmutable_any::< i8, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:77:42 + | +LL | assert_is_transmutable_any::< i8, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i16: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:79:43 + | +LL | assert_is_transmutable_any::< u8, i16>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i16` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:80:43 + | +LL | assert_is_transmutable_any::< u8, u16>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u16` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:81:43 + | +LL | assert_is_transmutable_any::< u8, i32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:82:43 + | +LL | assert_is_transmutable_any::< u8, f32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:83:43 + | +LL | assert_is_transmutable_any::< u8, u32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:84:43 + | +LL | assert_is_transmutable_any::< u8, u64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:85:43 + | +LL | assert_is_transmutable_any::< u8, i64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:86:43 + | +LL | assert_is_transmutable_any::< u8, f64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:87:42 + | +LL | assert_is_transmutable_any::< u8, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:88:42 + | +LL | assert_is_transmutable_any::< u8, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:90:43 + | +LL | assert_is_transmutable_any::< i16, i32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:91:43 + | +LL | assert_is_transmutable_any::< i16, f32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:92:43 + | +LL | assert_is_transmutable_any::< i16, u32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:93:43 + | +LL | assert_is_transmutable_any::< i16, u64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:94:43 + | +LL | assert_is_transmutable_any::< i16, i64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:95:43 + | +LL | assert_is_transmutable_any::< i16, f64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:96:42 + | +LL | assert_is_transmutable_any::< i16, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:97:42 + | +LL | assert_is_transmutable_any::< i16, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:99:43 + | +LL | assert_is_transmutable_any::< u16, i32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:100:43 + | +LL | assert_is_transmutable_any::< u16, f32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:101:43 + | +LL | assert_is_transmutable_any::< u16, u32>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u32` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:102:43 + | +LL | assert_is_transmutable_any::< u16, u64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:103:43 + | +LL | assert_is_transmutable_any::< u16, i64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:104:43 + | +LL | assert_is_transmutable_any::< u16, f64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:105:42 + | +LL | assert_is_transmutable_any::< u16, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:106:42 + | +LL | assert_is_transmutable_any::< u16, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:108:43 + | +LL | assert_is_transmutable_any::< i32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:109:43 + | +LL | assert_is_transmutable_any::< i32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:110:43 + | +LL | assert_is_transmutable_any::< i32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:111:42 + | +LL | assert_is_transmutable_any::< i32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:112:42 + | +LL | assert_is_transmutable_any::< i32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:114:43 + | +LL | assert_is_transmutable_any::< f32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:115:43 + | +LL | assert_is_transmutable_any::< f32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:116:43 + | +LL | assert_is_transmutable_any::< f32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:117:42 + | +LL | assert_is_transmutable_any::< f32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:118:42 + | +LL | assert_is_transmutable_any::< f32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:120:43 + | +LL | assert_is_transmutable_any::< u32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:121:43 + | +LL | assert_is_transmutable_any::< u32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:122:43 + | +LL | assert_is_transmutable_any::< u32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `f64` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:123:42 + | +LL | assert_is_transmutable_any::< u32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:124:42 + | +LL | assert_is_transmutable_any::< u32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:126:42 + | +LL | assert_is_transmutable_any::< u64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:127:42 + | +LL | assert_is_transmutable_any::< u64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:129:42 + | +LL | assert_is_transmutable_any::< i64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:130:42 + | +LL | assert_is_transmutable_any::< i64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:132:42 + | +LL | assert_is_transmutable_any::< f64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/numbers.rs:133:42 + | +LL | assert_is_transmutable_any::< f64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `i128` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/numbers.rs:168:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error: aborting due to 69 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/structs.rs b/src/test/ui/transmutability/structs.rs new file mode 100644 index 0000000000000..2b7e360f10ef3 --- /dev/null +++ b/src/test/ui/transmutability/structs.rs @@ -0,0 +1,160 @@ +#![feature(transmutability)] +#![feature(marker_trait_attr)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +fn test_well_defined() { + #[repr(C)] struct WellDefined; + pub struct Unspecified; + + assert_is_transmutable_all::(); + assert_is_transmutable_any::(); //~ ERROR not satisfied + assert_is_transmutable_any::(); //~ ERROR not satisfied + assert_is_transmutable_any::(); //~ ERROR not satisfied +} + +fn truncation() { + #[repr(C)] pub struct Zst; + + assert_is_transmutable_all::(); +} + +fn extension() { + #[repr(C, align(8))] pub struct U8ThenPadding(pub u8); + + // a `u8` is extensible to `U8ThenPadding` + assert_is_transmutable_all::(); + // a `U8ThenPadding` is truncatable to a `u8` + assert_is_transmutable_all::(); + // a `U8ThenPadding` is NOT extensible to a `u16`. + assert_is_transmutable_any::(); //~ ERROR not satisfied +} + +fn same_size() { + #[repr(C)] pub struct Padded(pub u16, pub u8); + #[repr(C)] pub struct Unpadded(pub u16, pub u16); + + assert_is_transmutable_all::(); + assert_is_transmutable_any::(); //~ ERROR not satisfied +} + +use std::mem::BikeshedIntrinsicFrom; + +struct Context; + +/// Assert that `Src` is transmutable to `Dst` under all combinations of options. +fn assert_is_transmutable_all() +where + Dst: + // Uncomment once visibility checking is implemented: + /* BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + */ BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom + + BikeshedIntrinsicFrom +{} + +/// Assert that `Src` is transmutable to `Dst` for at least one combination of options. +fn assert_is_transmutable_any() +where + Dst: BikeshedIntrinsicFromAny +{} + +#[marker] +trait BikeshedIntrinsicFromAny {} + +// Uncomment once visibility checking is implemented: +/* +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} +*/ + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +impl BikeshedIntrinsicFromAny for Dst +where + Dst: BikeshedIntrinsicFrom +{} + +fn main() {} diff --git a/src/test/ui/transmutability/structs.stderr b/src/test/ui/transmutability/structs.stderr new file mode 100644 index 0000000000000..1fbf3d2c03d35 --- /dev/null +++ b/src/test/ui/transmutability/structs.stderr @@ -0,0 +1,78 @@ +error[E0277]: the trait bound `Unspecified: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/structs.rs:11:47 + | +LL | assert_is_transmutable_any::(); + | ^^^^^^^^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `Unspecified` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/structs.rs:71:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `WellDefined: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/structs.rs:12:47 + | +LL | assert_is_transmutable_any::(); + | ^^^^^^^^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `WellDefined` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/structs.rs:71:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `Unspecified: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/structs.rs:13:47 + | +LL | assert_is_transmutable_any::(); + | ^^^^^^^^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `Unspecified` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/structs.rs:71:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/structs.rs:30:49 + | +LL | assert_is_transmutable_any::(); + | ^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `u16` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/structs.rs:71:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error[E0277]: the trait bound `Unpadded: BikeshedIntrinsicFromAny` is not satisfied + --> $DIR/structs.rs:38:42 + | +LL | assert_is_transmutable_any::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFromAny` is not implemented for `Unpadded` + | +note: required by a bound in `assert_is_transmutable_any` + --> $DIR/structs.rs:71:11 + | +LL | fn assert_is_transmutable_any() + | -------------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFromAny + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert_is_transmutable_any` + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/assume.rs b/src/test/ui/transmutability/visibility/assume.rs new file mode 100644 index 0000000000000..8afbcffa291eb --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume.rs @@ -0,0 +1,151 @@ +//! The destination type, its fields, and its fields' types (and so on) must be visible from +//! `Context`. However, this check is relaxed if visibility is assumed. + +#![feature(transmutability)] +#![allow(dead_code)] + +// all involved types and fields are public +mod all_visible { + mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} + } + + 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(in super) field: Zst, + } + } + + const _: () = {|| { + struct Context; + assert::is_transmutable::(); + };}; +} + +// the field of `Dst` is private +mod dst_field_private { + mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} + } + + 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 + } + } + + const _: () = {|| { + struct Context; + assert::is_transmutable::(); + };}; +} + +// the type of `Dst` is private +mod dst_type_private { + 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(self) struct Dst { // <- private type + pub(in super) field: Zst, + } + + use std::mem::BikeshedIntrinsicFrom; + + pub trait IsTransmutable {} + + impl IsTransmutable for () + where + Dst: BikeshedIntrinsicFrom + {} + + pub fn is_transmutable() + where + (): IsTransmutable + {} + } + + const _: () = {|| { + pub(self) struct Context; + dst::is_transmutable::(); + };}; +} + +// the type of `Dst`'s field is private +// as far as transmutation is concerned, `field` being private is fine so long as validity is +// assumed. however, the priv-in-pub lint currently rejects this code. +mod dst_field_type_private { + 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; // <- private type + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, //~ ERROR private type `dst_field_type_private::dst::Zst` in public interface + } + + use std::mem::BikeshedIntrinsicFrom; + + pub trait IsTransmutable {} + + impl IsTransmutable for () + where + Dst: BikeshedIntrinsicFrom + {} + + pub fn is_transmutable() + where + (): IsTransmutable + {} + } + + const _: () = {|| { + pub(self) struct Context; + dst::is_transmutable::(); + };}; +} + +fn main() {} diff --git a/src/test/ui/transmutability/visibility/assume.stderr b/src/test/ui/transmutability/visibility/assume.stderr new file mode 100644 index 0000000000000..2995e3d7353a5 --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume.stderr @@ -0,0 +1,12 @@ +error[E0446]: private type `dst_field_type_private::dst::Zst` in public interface + --> $DIR/assume.rs:127:13 + | +LL | #[repr(C)] pub(self) struct Zst; // <- private type + | --------------------- `dst_field_type_private::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`. diff --git a/src/test/ui/transmutability/visibility/dst.rs b/src/test/ui/transmutability/visibility/dst.rs new file mode 100644 index 0000000000000..8444b7077010a --- /dev/null +++ b/src/test/ui/transmutability/visibility/dst.rs @@ -0,0 +1,116 @@ +//! The destination type, its fields, and its fields' types (and so on) must be visible from +//! `Context`. + +#![feature(transmutability)] +#![allow(dead_code)] + +// the field of `Dst` is private +mod dst_field_private { + mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} + } + + 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 + } + } + + const _: () = {|| { + struct Context; + assert::is_transmutable::(); //~ ERROR not satisfied + };}; +} + +// the type of `Dst` is private +mod dst_type_private { + 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(self) struct Dst { // <- private type + pub(in super) field: Zst, + } + + use std::mem::BikeshedIntrinsicFrom; + + pub trait IsTransmutable {} + + impl IsTransmutable for Dst + where + Dst: BikeshedIntrinsicFrom + {} + + pub fn is_transmutable() + where + Dst: IsTransmutable + {} + } + + const _: () = {|| { + pub(self) struct Context; + dst::is_transmutable::(); //~ ERROR not satisfied + };}; +} + +// the type of `Dst`'s field is private +mod dst_field_type_private { + 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; // <- private type + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } + + use std::mem::BikeshedIntrinsicFrom; + + pub trait IsTransmutable {} + + impl IsTransmutable for Dst + where + Dst: BikeshedIntrinsicFrom + {} + + pub fn is_transmutable() + where + Dst: IsTransmutable + {} + } + + const _: () = {|| { + pub(self) struct Context; + dst::is_transmutable::(); //~ ERROR not satisfied + };}; +} + +fn main() {} diff --git a/src/test/ui/transmutability/visibility/dst.stderr b/src/test/ui/transmutability/visibility/dst.stderr new file mode 100644 index 0000000000000..8516d843a7152 --- /dev/null +++ b/src/test/ui/transmutability/visibility/dst.stderr @@ -0,0 +1,58 @@ +error[E0277]: the trait bound `dst_field_private::dst::Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/dst.rs:36:45 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `dst_field_private::dst::Dst` + | +note: required by a bound in `assert::is_transmutable` + --> $DIR/dst.rs:14:18 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `assert::is_transmutable` + +error[E0277]: the trait bound `dst_type_private::dst::Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/dst.rs:74:9 + | +LL | dst::is_transmutable::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `dst_type_private::dst::Dst` + | +note: required because of the requirements on the impl of `dst_type_private::dst::IsTransmutable` for `dst_type_private::dst::Dst` + --> $DIR/dst.rs:61:28 + | +LL | impl IsTransmutable for Dst + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ +note: required by a bound in `dst_type_private::dst::is_transmutable` + --> $DIR/dst.rs:68:18 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: IsTransmutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `dst_type_private::dst::is_transmutable` + +error[E0277]: the trait bound `dst_field_type_private::dst::Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/dst.rs:112:9 + | +LL | dst::is_transmutable::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `dst_field_type_private::dst::Dst` + | +note: required because of the requirements on the impl of `dst_field_type_private::dst::IsTransmutable` for `dst_field_type_private::dst::Dst` + --> $DIR/dst.rs:99:28 + | +LL | impl IsTransmutable for Dst + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ +note: required by a bound in `dst_field_type_private::dst::is_transmutable` + --> $DIR/dst.rs:106:18 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: IsTransmutable + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `dst_field_type_private::dst::is_transmutable` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/src.rs b/src/test/ui/transmutability/visibility/src.rs new file mode 100644 index 0000000000000..bf3c8f00e0e8b --- /dev/null +++ b/src/test/ui/transmutability/visibility/src.rs @@ -0,0 +1,140 @@ +//! The visibilities of the `Src` type, its fields, and its fields' types (and so on) generally do +//! not matter. + +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +// all involved types and fields are public +mod all_visible { + 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(in super) field: Zst, + } + } + + const _: () = {|| { + struct Context; + crate::assert::is_transmutable::(); + };}; +} + +// the field of `Src` is private +mod src_field_private { + 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, + } + } + + const _: () = {|| { + struct Context; + crate::assert::is_transmutable::(); + };}; +} + +// the type of `Src` is private +mod src_type_private { + mod src { + use std::mem::BikeshedIntrinsicFrom; + + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(self) struct Src { // <- private type + pub(in super) field: Zst, + } + + pub trait IsTransmutable {} + + impl IsTransmutable for Dst + where + Dst: BikeshedIntrinsicFrom + {} + + pub fn is_transmutable() + where + Dst: IsTransmutable + {} + } + + mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } + } + + const _: () = {|| { + pub(self) struct Context; + src::is_transmutable::(); + };}; +} + +// the type of `Src`'s field is private +mod src_field_type_private { + mod src { + #[repr(C)] pub(self) struct Zst; // <- private type + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, //~ ERROR private type `src_field_type_private::src::Zst` in public interface + } + + use std::mem::BikeshedIntrinsicFrom; + + pub trait IsTransmutable {} + + impl IsTransmutable for Dst + where + Dst: BikeshedIntrinsicFrom + {} + + pub fn is_transmutable() + where + Dst: IsTransmutable + {} + } + + mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } + } + + const _: () = {|| { + pub(self) struct Context; + src::is_transmutable::(); + };}; +} + +fn main() {} diff --git a/src/test/ui/transmutability/visibility/src.stderr b/src/test/ui/transmutability/visibility/src.stderr new file mode 100644 index 0000000000000..d0eb2c4e161e7 --- /dev/null +++ b/src/test/ui/transmutability/visibility/src.stderr @@ -0,0 +1,12 @@ +error[E0446]: private type `src_field_type_private::src::Zst` in public interface + --> $DIR/src.rs:108:13 + | +LL | #[repr(C)] pub(self) struct Zst; // <- private type + | --------------------- `src_field_type_private::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`.