From bc4a1dea416e1695cf77acd17ea743d4d802bae0 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Sat, 3 Jul 2021 12:18:13 -0400 Subject: [PATCH 01/13] Initial (incomplete) implementation of transmutability trait. This initial implementation handles transmutations between types with specified layouts, except when references are involved. Co-authored-by: Igor null --- Cargo.lock | 15 + compiler/rustc_hir/src/lang_items.rs | 3 + compiler/rustc_middle/src/traits/select.rs | 4 + compiler/rustc_middle/src/ty/mod.rs | 42 +- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/abi/mod.rs | 3 +- compiler/rustc_trait_selection/Cargo.toml | 1 + .../src/traits/select/candidate_assembly.rs | 23 + .../src/traits/select/confirmation.rs | 52 ++ .../src/traits/select/mod.rs | 3 + compiler/rustc_transmute/Cargo.toml | 28 + compiler/rustc_transmute/src/layout/dfa.rs | 184 ++++ compiler/rustc_transmute/src/layout/mod.rs | 71 ++ compiler/rustc_transmute/src/layout/nfa.rs | 179 ++++ compiler/rustc_transmute/src/layout/tree.rs | 479 ++++++++++ .../rustc_transmute/src/layout/tree/tests.rs | 80 ++ compiler/rustc_transmute/src/lib.rs | 114 +++ .../src/maybe_transmutable/mod.rs | 320 +++++++ .../src/maybe_transmutable/query_context.rs | 93 ++ .../src/maybe_transmutable/tests.rs | 115 +++ library/core/src/mem/mod.rs | 4 + library/core/src/mem/transmutability.rs | 39 + .../abstraction/const_generic_fn.rs | 41 + .../arrays/should_have_correct_length.rs | 44 + .../arrays/should_inherit_alignment.rs | 55 ++ .../should_require_well_defined_layout.rs | 61 ++ .../should_require_well_defined_layout.stderr | 93 ++ ...mitive_reprs_should_have_correct_length.rs | 149 +++ ...ve_reprs_should_have_correct_length.stderr | 303 +++++++ .../should_require_well_defined_layout.rs | 117 +++ .../should_require_well_defined_layout.stderr | 93 ++ .../enums/should_order_correctly.rs | 32 + .../enums/should_pad_variants.rs | 40 + .../enums/should_pad_variants.stderr | 18 + .../enums/should_respect_endianness.rs | 33 + .../enums/should_respect_endianness.stderr | 18 + .../unknown_dst.rs | 21 + .../unknown_dst.stderr | 12 + .../unknown_src.rs | 21 + .../unknown_src.stderr | 12 + .../unknown_src_field.rs | 22 + .../unknown_src_field.stderr | 9 + .../ui/transmutability/primitives/bool.rs | 25 + .../ui/transmutability/primitives/bool.stderr | 18 + .../ui/transmutability/primitives/numbers.rs | 128 +++ .../transmutability/primitives/numbers.stderr | 858 ++++++++++++++++++ .../ui/transmutability/primitives/unit.rs | 24 + .../ui/transmutability/primitives/unit.stderr | 18 + src/test/ui/transmutability/references.rs | 20 + src/test/ui/transmutability/references.stderr | 18 + .../structs/repr/should_handle_align.rs | 36 + .../structs/repr/should_handle_packed.rs | 35 + .../should_require_well_defined_layout.rs | 76 ++ .../should_require_well_defined_layout.stderr | 183 ++++ .../structs/should_order_fields_correctly.rs | 31 + src/test/ui/transmutability/unions/boolish.rs | 31 + .../unions/repr/should_handle_align.rs | 40 + .../unions/repr/should_handle_packed.rs | 41 + .../should_require_well_defined_layout.rs | 37 + .../should_require_well_defined_layout.stderr | 33 + .../unions/should_pad_variants.rs | 40 + .../unions/should_pad_variants.stderr | 18 + ...mit_intersecting_if_validity_is_assumed.rs | 39 + .../unions/should_reject_contraction.rs | 36 + .../unions/should_reject_contraction.stderr | 18 + .../unions/should_reject_disjoint.rs | 36 + .../unions/should_reject_disjoint.stderr | 33 + .../unions/should_reject_intersecting.rs | 38 + .../unions/should_reject_intersecting.stderr | 33 + .../should_accept_if_dst_has_private_field.rs | 38 + ...hould_accept_if_dst_has_private_variant.rs | 39 + ...ept_if_dst_has_tricky_unreachable_field.rs | 46 + ...uld_accept_if_dst_has_unreachable_field.rs | 39 + ...accept_if_dst_has_unreachable_field.stderr | 12 + ...should_accept_if_dst_has_unreachable_ty.rs | 40 + ...ld_accept_if_dst_has_unreachable_ty.stderr | 15 + .../should_accept_if_src_has_private_field.rs | 38 + ...hould_accept_if_src_has_private_variant.rs | 39 + ...uld_accept_if_src_has_unreachable_field.rs | 38 + ...accept_if_src_has_unreachable_field.stderr | 12 + ...should_accept_if_src_has_unreachable_ty.rs | 39 + ...ld_accept_if_src_has_unreachable_ty.stderr | 15 + .../should_reject_if_dst_has_private_field.rs | 37 + ...uld_reject_if_dst_has_private_field.stderr | 18 + ...hould_reject_if_dst_has_private_variant.rs | 38 + ...d_reject_if_dst_has_private_variant.stderr | 18 + ...ect_if_dst_has_tricky_unreachable_field.rs | 52 ++ ...uld_reject_if_dst_has_unreachable_field.rs | 39 + ...reject_if_dst_has_unreachable_field.stderr | 18 + ...should_reject_if_dst_has_unreachable_ty.rs | 42 + ...ld_reject_if_dst_has_unreachable_ty.stderr | 31 + 91 files changed, 5691 insertions(+), 2 deletions(-) create mode 100644 compiler/rustc_transmute/Cargo.toml create mode 100644 compiler/rustc_transmute/src/layout/dfa.rs create mode 100644 compiler/rustc_transmute/src/layout/mod.rs create mode 100644 compiler/rustc_transmute/src/layout/nfa.rs create mode 100644 compiler/rustc_transmute/src/layout/tree.rs create mode 100644 compiler/rustc_transmute/src/layout/tree/tests.rs create mode 100644 compiler/rustc_transmute/src/lib.rs create mode 100644 compiler/rustc_transmute/src/maybe_transmutable/mod.rs create mode 100644 compiler/rustc_transmute/src/maybe_transmutable/query_context.rs create mode 100644 compiler/rustc_transmute/src/maybe_transmutable/tests.rs create mode 100644 library/core/src/mem/transmutability.rs create mode 100644 src/test/ui/transmutability/abstraction/const_generic_fn.rs create mode 100644 src/test/ui/transmutability/arrays/should_have_correct_length.rs create mode 100644 src/test/ui/transmutability/arrays/should_inherit_alignment.rs create mode 100644 src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs create mode 100644 src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr create mode 100644 src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs create mode 100644 src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr create mode 100644 src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs create mode 100644 src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr create mode 100644 src/test/ui/transmutability/enums/should_order_correctly.rs create mode 100644 src/test/ui/transmutability/enums/should_pad_variants.rs create mode 100644 src/test/ui/transmutability/enums/should_pad_variants.stderr create mode 100644 src/test/ui/transmutability/enums/should_respect_endianness.rs create mode 100644 src/test/ui/transmutability/enums/should_respect_endianness.stderr create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr create mode 100644 src/test/ui/transmutability/primitives/bool.rs create mode 100644 src/test/ui/transmutability/primitives/bool.stderr create mode 100644 src/test/ui/transmutability/primitives/numbers.rs create mode 100644 src/test/ui/transmutability/primitives/numbers.stderr create mode 100644 src/test/ui/transmutability/primitives/unit.rs create mode 100644 src/test/ui/transmutability/primitives/unit.stderr create mode 100644 src/test/ui/transmutability/references.rs create mode 100644 src/test/ui/transmutability/references.stderr create mode 100644 src/test/ui/transmutability/structs/repr/should_handle_align.rs create mode 100644 src/test/ui/transmutability/structs/repr/should_handle_packed.rs create mode 100644 src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs create mode 100644 src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr create mode 100644 src/test/ui/transmutability/structs/should_order_fields_correctly.rs create mode 100644 src/test/ui/transmutability/unions/boolish.rs create mode 100644 src/test/ui/transmutability/unions/repr/should_handle_align.rs create mode 100644 src/test/ui/transmutability/unions/repr/should_handle_packed.rs create mode 100644 src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs create mode 100644 src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr create mode 100644 src/test/ui/transmutability/unions/should_pad_variants.rs create mode 100644 src/test/ui/transmutability/unions/should_pad_variants.stderr create mode 100644 src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs create mode 100644 src/test/ui/transmutability/unions/should_reject_contraction.rs create mode 100644 src/test/ui/transmutability/unions/should_reject_contraction.stderr create mode 100644 src/test/ui/transmutability/unions/should_reject_disjoint.rs create mode 100644 src/test/ui/transmutability/unions/should_reject_disjoint.stderr create mode 100644 src/test/ui/transmutability/unions/should_reject_intersecting.rs create mode 100644 src/test/ui/transmutability/unions/should_reject_intersecting.stderr create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs create mode 100644 src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs create mode 100644 src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs create mode 100644 src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr diff --git a/Cargo.lock b/Cargo.lock index 2325d0f3bf263..16b67526cffa0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4553,6 +4553,7 @@ dependencies = [ "rustc_session", "rustc_span", "rustc_target", + "rustc_transmute", "smallvec", "tracing", ] @@ -4577,6 +4578,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "rustc_transmute" +version = "0.1.0" +dependencies = [ + "itertools", + "rustc_data_structures", + "rustc_infer", + "rustc_macros", + "rustc_middle", + "rustc_span", + "rustc_target", + "tracing", +] + [[package]] name = "rustc_ty_utils" version = "0.0.0" diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 13b3e954e1f58..c337be12ae492 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -191,6 +191,9 @@ language_item_table! { CoerceUnsized, sym::coerce_unsized, coerce_unsized_trait, Target::Trait, GenericRequirement::Minimum(1); DispatchFromDyn, sym::dispatch_from_dyn, dispatch_from_dyn_trait, Target::Trait, GenericRequirement::Minimum(1); + // language items relating to transmutability + TransmuteTrait, sym::transmute_trait, transmute_trait, Target::Trait, GenericRequirement::Exact(6); + Add(Op), sym::add, add_trait, Target::Trait, GenericRequirement::Exact(1); Sub(Op), sym::sub, sub_trait, Target::Trait, GenericRequirement::Exact(1); Mul(Op), sym::mul, mul_trait, Target::Trait, GenericRequirement::Exact(1); diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 0ca5a532b7542..e836ba47eed7a 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -109,6 +109,10 @@ pub enum SelectionCandidate<'tcx> { /// `false` if there are no *further* obligations. has_nested: bool, }, + + /// Implementation of transmutability trait. + TransmutabilityCandidate, + ParamCandidate(ty::PolyTraitPredicate<'tcx>), ImplCandidate(DefId), AutoImplCandidate(DefId), diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 31c523aaca9ae..5fda1e6538e91 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -48,7 +48,7 @@ pub use subst::*; pub use vtable::*; use std::fmt::Debug; -use std::hash::Hash; +use std::hash::{Hash, Hasher}; use std::ops::ControlFlow; use std::{fmt, str}; @@ -1724,6 +1724,26 @@ impl VariantDef { } } +/// 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`. @@ -1744,6 +1764,26 @@ pub struct FieldDef { pub vis: Visibility, } +/// 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 c75b6772487f9..632d2c13d74ef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1462,6 +1462,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 b35502d9ee42b..0758bf7c7cb07 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -508,6 +508,7 @@ impl fmt::Debug for Align { impl Align { pub const ONE: Align = Align { pow2: 0 }; + pub const MAX: Align = Align { pow2: 29 }; #[inline] pub fn from_bits(bits: u64) -> Result { @@ -540,7 +541,7 @@ impl Align { if bytes != 1 { return Err(not_power_of_2(align)); } - if pow2 > 29 { + if pow2 > Self::MAX.pow2 { return Err(too_large(align)); } diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml index aebeb49e623b9..566f236f26a8c 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", features = ["rustc"] } smallvec = { version = "1.8.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 6e8581128dd8e..a18b835e70ce1 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -305,6 +305,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_candidates_for_unsizing(obligation, &mut candidates); } else if lang_items.destruct_trait() == Some(def_id) { self.assemble_const_destruct_candidates(obligation, &mut candidates); + } else if lang_items.transmute_trait() == Some(def_id) { + // User-defined transmutability impls are permitted. + self.assemble_candidates_from_impls(obligation, &mut candidates); + self.assemble_candidates_for_transmutability(obligation, &mut candidates); } else { if lang_items.clone_trait() == Some(def_id) { // Same builtin conditions as `Copy`, i.e., every type which has builtin support @@ -873,6 +877,25 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { }; } + #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] + fn assemble_candidates_for_transmutability( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + if obligation.has_param_types_or_consts() { + candidates.ambiguous = false; + return; + } + + if obligation.has_infer_types_or_consts() { + candidates.ambiguous = true; + return; + } + + candidates.vec.push(TransmutabilityCandidate); + } + #[tracing::instrument(level = "debug", skip(self, obligation, candidates))] fn assemble_candidates_for_trait_alias( &mut self, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index d4c9fd1c5f9cd..a609fb2b17266 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -48,6 +48,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Builtin(data) } + TransmutabilityCandidate => { + let data = self.confirm_transmutability_candidate(obligation)?; + ImplSource::Builtin(data) + } + ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param.map_bound(|t| t.trait_ref)); @@ -267,6 +272,53 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSourceBuiltinData { nested: obligations } } + fn confirm_transmutability_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + debug!(?obligation, "confirm_transmutability_candidate"); + + let predicate = obligation.predicate; + + let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i)); + let bool_at = |i| { + predicate + .skip_binder() + .trait_ref + .substs + .const_at(i) + .try_eval_bool(self.tcx(), obligation.param_env) + .unwrap() + }; + + let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { + src: p.trait_ref.substs.type_at(1), + dst: p.trait_ref.substs.type_at(0), + }); + + let scope = type_at(2).skip_binder(); + + let assume = rustc_transmute::Assume { + alignment: bool_at(3), + lifetimes: bool_at(4), + validity: bool_at(5), + visibility: bool_at(6), + }; + + let cause = obligation.cause.clone(); + + let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx); + + let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume); + + use rustc_transmute::Answer; + + match maybe_transmutable { + Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }), + _ => Err(Unimplemented), + } + } + /// This handles the case where an `auto trait Foo` impl is being used. /// The idea is that the impl applies to `X : Foo` if the following conditions are met: /// diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 17f34012d1dd3..9ca23228b9879 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1630,6 +1630,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); } + // FIXME(@jswrenn): this should probably be more sophisticated + (TransmutabilityCandidate, _) | (_, TransmutabilityCandidate) => false, + // (*) ( BuiltinCandidate { has_nested: false } diff --git a/compiler/rustc_transmute/Cargo.toml b/compiler/rustc_transmute/Cargo.toml new file mode 100644 index 0000000000000..9dc96e08a8e27 --- /dev/null +++ b/compiler/rustc_transmute/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "rustc_transmute" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +tracing = "0.1" +rustc_data_structures = { path = "../rustc_data_structures", optional = true} +rustc_infer = { path = "../rustc_infer", optional = true} +rustc_macros = { path = "../rustc_macros", optional = true} +rustc_middle = { path = "../rustc_middle", optional = true} +rustc_span = { path = "../rustc_span", optional = true} +rustc_target = { path = "../rustc_target", optional = true} + +[features] +rustc = [ + "rustc_middle", + "rustc_data_structures", + "rustc_infer", + "rustc_macros", + "rustc_span", + "rustc_target", +] + +[dev-dependencies] +itertools = "0.10.1" \ No newline at end of file diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs new file mode 100644 index 0000000000000..cdd3195712d26 --- /dev/null +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -0,0 +1,184 @@ +use super::{nfa, Byte, Nfa, Ref}; +use crate::Map; +use std::fmt; +use std::sync::atomic::{AtomicU64, Ordering}; + +#[derive(PartialEq, Clone, Debug)] +pub(crate) struct Dfa +where + R: Ref, +{ + pub(crate) transitions: Map>, + pub(crate) start: State, + pub(crate) accepting: State, +} + +#[derive(PartialEq, Clone, Debug)] +pub(crate) struct Transitions +where + R: Ref, +{ + byte_transitions: Map, + ref_transitions: Map, +} + +impl Default for Transitions +where + R: Ref, +{ + fn default() -> Self { + Self { byte_transitions: Map::default(), ref_transitions: Map::default() } + } +} + +impl Transitions +where + R: Ref, +{ + fn insert(&mut self, transition: Transition, state: State) { + match transition { + Transition::Byte(b) => { + self.byte_transitions.insert(b, state); + } + Transition::Ref(r) => { + self.ref_transitions.insert(r, state); + } + } + } +} + +/// The states in a `Nfa` represent byte offsets. +#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] +pub(crate) struct State(u64); + +#[derive(Hash, Eq, PartialEq, Clone, Copy)] +pub(crate) enum Transition +where + R: Ref, +{ + Byte(Byte), + Ref(R), +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "S_{}", self.0) + } +} + +impl fmt::Debug for Transition +where + R: Ref, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self { + Self::Byte(b) => b.fmt(f), + Self::Ref(r) => r.fmt(f), + } + } +} + +impl Dfa +where + R: Ref, +{ + pub(crate) fn unit() -> Self { + let transitions: Map> = Map::default(); + let start = State::new(); + let accepting = start; + + Self { transitions, start, accepting } + } + + #[cfg(test)] + pub(crate) fn bool() -> Self { + let mut transitions: Map> = Map::default(); + let start = State::new(); + let accepting = State::new(); + + transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x00)), accepting); + + transitions.entry(start).or_default().insert(Transition::Byte(Byte::Init(0x01)), accepting); + + Self { transitions, start, accepting } + } + + #[tracing::instrument] + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + pub(crate) fn from_nfa(nfa: Nfa) -> Self { + let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa; + + let mut dfa_transitions: Map> = Map::default(); + let mut nfa_to_dfa: Map = Map::default(); + let dfa_start = State::new(); + nfa_to_dfa.insert(nfa_start, dfa_start); + + let mut queue = vec![(nfa_start, dfa_start)]; + + while let Some((nfa_state, dfa_state)) = queue.pop() { + if nfa_state == nfa_accepting { + continue; + } + + for (nfa_transition, next_nfa_states) in nfa_transitions[&nfa_state].iter() { + let dfa_transitions = + dfa_transitions.entry(dfa_state).or_insert_with(Default::default); + + let mapped_state = next_nfa_states.iter().find_map(|x| nfa_to_dfa.get(x).copied()); + + let next_dfa_state = match nfa_transition { + &nfa::Transition::Byte(b) => *dfa_transitions + .byte_transitions + .entry(b) + .or_insert_with(|| mapped_state.unwrap_or_else(State::new)), + &nfa::Transition::Ref(r) => *dfa_transitions + .ref_transitions + .entry(r) + .or_insert_with(|| mapped_state.unwrap_or_else(State::new)), + }; + + for &next_nfa_state in next_nfa_states { + nfa_to_dfa.entry(next_nfa_state).or_insert_with(|| { + queue.push((next_nfa_state, next_dfa_state)); + next_dfa_state + }); + } + } + } + + let dfa_accepting = nfa_to_dfa[&nfa_accepting]; + + Self { transitions: dfa_transitions, start: dfa_start, accepting: dfa_accepting } + } + + pub(crate) fn bytes_from(&self, start: State) -> Option<&Map> { + Some(&self.transitions.get(&start)?.byte_transitions) + } + + pub(crate) fn byte_from(&self, start: State, byte: Byte) -> Option { + self.transitions.get(&start)?.byte_transitions.get(&byte).copied() + } + + pub(crate) fn refs_from(&self, start: State) -> Option<&Map> { + Some(&self.transitions.get(&start)?.ref_transitions) + } +} + +impl State { + pub(crate) fn new() -> Self { + static COUNTER: AtomicU64 = AtomicU64::new(0); + Self(COUNTER.fetch_add(1, Ordering::SeqCst)) + } +} + +impl From> for Transition +where + R: Ref, +{ + fn from(nfa_transition: nfa::Transition) -> Self { + match nfa_transition { + nfa::Transition::Byte(byte) => Transition::Byte(byte), + nfa::Transition::Ref(r) => Transition::Ref(r), + } + } +} diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs new file mode 100644 index 0000000000000..cbf92bdacd6f0 --- /dev/null +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -0,0 +1,71 @@ +use std::fmt::{self, Debug}; +use std::hash::Hash; + +pub(crate) mod tree; +pub(crate) use tree::Tree; + +pub(crate) mod nfa; +pub(crate) use nfa::Nfa; + +pub(crate) mod dfa; +pub(crate) use dfa::Dfa; + +#[derive(Debug)] +pub(crate) struct Uninhabited; + +/// An instance of a byte is either initialized to a particular value, or uninitialized. +#[derive(Hash, Eq, PartialEq, Clone, Copy)] +pub(crate) enum Byte { + Uninit, + Init(u8), +} + +impl fmt::Debug for Byte { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self { + Self::Uninit => f.write_str("??u8"), + Self::Init(b) => write!(f, "{:#04x}u8", b), + } + } +} + +pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {} +pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {} + +impl Def for ! {} +impl Ref for ! {} + +#[cfg(feature = "rustc")] +pub(crate) mod rustc { + use rustc_middle::mir::Mutability; + use rustc_middle::ty; + use rustc_middle::ty::Region; + use rustc_middle::ty::Ty; + + /// A reference in the layout [`Nfa`]. + #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] + pub struct Ref<'tcx> { + lifetime: Region<'tcx>, + ty: Ty<'tcx>, + mutability: Mutability, + } + + impl<'tcx> super::Ref for Ref<'tcx> {} + + impl<'tcx> Ref<'tcx> { + pub fn min_align(&self) -> usize { + todo!() + } + } + + /// A visibility node in the layout [`Nfa`]. + #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] + pub enum Def<'tcx> { + Adt(ty::AdtDef<'tcx>), + Variant(&'tcx ty::VariantDef), + Field(&'tcx ty::FieldDef), + Primitive, + } + + impl<'tcx> super::Def for Def<'tcx> {} +} diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs new file mode 100644 index 0000000000000..817e426ba274e --- /dev/null +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -0,0 +1,179 @@ +use super::{Byte, Ref, Tree, Uninhabited}; +use crate::{Map, Set}; +use std::fmt; +use std::sync::atomic::{AtomicU64, Ordering}; + +/// A non-deterministic finite automaton (NFA) that represents the layout of a type. +/// The transmutability of two given types is computed by comparing their `Nfa`s. +#[derive(PartialEq, Debug)] +pub(crate) struct Nfa +where + R: Ref, +{ + pub(crate) transitions: Map, Set>>, + pub(crate) start: State, + pub(crate) accepting: State, +} + +/// The states in a `Nfa` represent byte offsets. +#[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] +pub(crate) struct State(u64); + +/// The transitions between states in a `Nfa` reflect bit validity. +#[derive(Hash, Eq, PartialEq, Clone, Copy)] +pub(crate) enum Transition +where + R: Ref, +{ + Byte(Byte), + Ref(R), +} + +impl fmt::Debug for State { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "S_{}", self.0) + } +} + +impl fmt::Debug for Transition +where + R: Ref, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self { + Self::Byte(b) => b.fmt(f), + Self::Ref(r) => r.fmt(f), + } + } +} + +impl Nfa +where + R: Ref, +{ + pub(crate) fn unit() -> Self { + let transitions: Map, Set>> = Map::default(); + let start = State::new(); + let accepting = start; + + Nfa { transitions, start, accepting } + } + + pub(crate) fn from_byte(byte: Byte) -> Self { + let mut transitions: Map, 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)).or_default(); + edge.insert(accepting); + + Nfa { transitions, start, accepting } + } + + pub(crate) fn from_ref(r: R) -> 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::Ref(r)).or_default(); + edge.insert(accepting); + + Nfa { transitions, start, accepting } + } + + pub(crate) fn from_tree(tree: Tree) -> Result { + Ok(match tree { + Tree::Byte(b) => Self::from_byte(b), + Tree::Def(..) => unreachable!(), + Tree::Ref(r) => Self::from_ref(r), + Tree::Alt(alts) => { + let mut alts = alts.into_iter().map(Self::from_tree); + let mut nfa = alts.next().ok_or(Uninhabited)??; + for alt in alts { + nfa = nfa.union(&alt?); + } + nfa + } + Tree::Seq(elts) => { + let mut nfa = Self::unit(); + for elt in elts.into_iter().map(Self::from_tree) { + nfa = nfa.concat(elt?); + } + nfa + } + }) + } + + /// Concatenate two `Nfa`s. + pub(crate) fn concat(self, other: Self) -> Self { + if self.start == self.accepting { + return other; + } else if other.start == other.accepting { + return self; + } + + let start = self.start; + let accepting = other.accepting; + + let mut transitions: Map, Set>> = self.transitions; + + // the iteration order doesn't matter + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + for (source, transition) in other.transitions { + let fix_state = |state| if state == other.start { self.accepting } else { state }; + let entry = transitions.entry(fix_state(source)).or_default(); + for (edge, destinations) in transition { + let entry = entry.entry(edge.clone()).or_default(); + for destination in destinations { + entry.insert(fix_state(destination)); + } + } + } + + Self { transitions, start, accepting } + } + + /// Compute the union of two `Nfa`s. + pub(crate) fn union(&self, other: &Self) -> Self { + let start = self.start; + let accepting = self.accepting; + + let mut transitions: Map, Set>> = self.transitions.clone(); + + // the iteration order doesn't matter + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + for (&(mut source), transition) in other.transitions.iter() { + // if source is starting state of `other`, replace with starting state of `self` + if source == other.start { + source = self.start; + } + let entry = transitions.entry(source).or_default(); + for (edge, destinations) in transition { + let entry = entry.entry(edge.clone()).or_default(); + // the iteration order doesn't matter + #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] + for &(mut destination) in destinations { + // if dest is accepting state of `other`, replace with accepting state of `self` + if destination == other.accepting { + destination = self.accepting; + } + entry.insert(destination); + } + } + } + Self { transitions, start, accepting } + } + + pub(crate) fn edges_from(&self, start: State) -> Option<&Map, Set>> { + self.transitions.get(&start) + } +} + +impl State { + pub(crate) fn new() -> Self { + static COUNTER: AtomicU64 = AtomicU64::new(0); + Self(COUNTER.fetch_add(1, Ordering::SeqCst)) + } +} diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs new file mode 100644 index 0000000000000..67b401855d4be --- /dev/null +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -0,0 +1,479 @@ +use super::{Byte, Def, Ref}; + +#[cfg(test)] +mod tests; + +/// A tree-based representation of a type layout. +/// +/// Invariants: +/// 1. All paths through the layout have the same length (in bytes). +/// +/// Nice-to-haves: +/// 1. An `Alt` is never directly nested beneath another `Alt`. +/// 2. A `Seq` is never directly nested beneath another `Seq`. +/// 3. `Seq`s and `Alt`s with a single member do not exist. +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub(crate) enum Tree +where + D: Def, + R: Ref, +{ + /// A sequence of successive layouts. + Seq(Vec), + /// A choice between alternative layouts. + Alt(Vec), + /// A definition node. + Def(D), + /// A reference node. + Ref(R), + /// A byte node. + Byte(Byte), +} + +impl Tree +where + D: Def, + R: Ref, +{ + /// A `Tree` consisting only of a definition node. + pub(crate) fn def(def: D) -> Self { + Self::Def(def) + } + + /// A `Tree` representing an uninhabited type. + pub(crate) fn uninhabited() -> Self { + Self::Alt(vec![]) + } + + /// A `Tree` representing a zero-sized type. + pub(crate) fn unit() -> Self { + Self::Seq(Vec::new()) + } + + /// A `Tree` containing a single, uninitialized byte. + pub(crate) fn uninit() -> Self { + Self::Byte(Byte::Uninit) + } + + /// A `Tree` representing the layout of `bool`. + pub(crate) fn bool() -> Self { + Self::from_bits(0x00).or(Self::from_bits(0x01)) + } + + /// A `Tree` whose layout matches that of a `u8`. + pub(crate) fn u8() -> Self { + Self::Alt((0u8..=255).map(Self::from_bits).collect()) + } + + /// A `Tree` whose layout accepts exactly the given bit pattern. + pub(crate) fn from_bits(bits: u8) -> Self { + Self::Byte(Byte::Init(bits)) + } + + /// A `Tree` whose layout is a number of the given width. + pub(crate) fn number(width_in_bytes: usize) -> Self { + Self::Seq(vec![Self::u8(); width_in_bytes]) + } + + /// A `Tree` whose layout is entirely padding of the given width. + #[tracing::instrument] + pub(crate) fn padding(width_in_bytes: usize) -> Self { + Self::Seq(vec![Self::uninit(); width_in_bytes]) + } + + /// Remove all `Def` nodes, and all branches of the layout for which `f` produces false. + pub(crate) fn prune(self, f: &F) -> Tree + where + F: Fn(D) -> bool, + { + match self { + Self::Seq(elts) => elts + .into_iter() + .map(|elt| elt.prune(f)) + .try_fold(Tree::unit(), |elts, elt| { + if elt == Tree::uninhabited() { + Err(Tree::uninhabited()) + } else { + Ok(elts.then(elt)) + } + }) + .into_ok_or_err(), + Self::Alt(alts) => alts + .into_iter() + .map(|alt| alt.prune(f)) + .fold(Tree::uninhabited(), |alts, alt| alts.or(alt)), + Self::Byte(b) => Tree::Byte(b), + Self::Ref(r) => Tree::Ref(r), + Self::Def(d) => { + if !f(d) { + Tree::uninhabited() + } else { + Tree::unit() + } + } + } + } + + /// Produces `true` if `Tree` is an inhabited type; otherwise false. + pub(crate) fn is_inhabited(&self) -> bool { + match self { + Self::Seq(elts) => elts.into_iter().all(|elt| elt.is_inhabited()), + Self::Alt(alts) => alts.into_iter().any(|alt| alt.is_inhabited()), + Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true, + } + } +} + +impl Tree +where + D: Def, + R: Ref, +{ + /// Produces a new `Tree` where `other` is sequenced after `self`. + pub(crate) fn then(self, other: Self) -> Self { + match (self, other) { + (Self::Seq(elts), other) | (other, Self::Seq(elts)) if elts.len() == 0 => other, + (Self::Seq(mut lhs), Self::Seq(mut rhs)) => { + lhs.append(&mut rhs); + Self::Seq(lhs) + } + (Self::Seq(mut lhs), rhs) => { + lhs.push(rhs); + Self::Seq(lhs) + } + (lhs, Self::Seq(mut rhs)) => { + rhs.insert(0, lhs); + Self::Seq(rhs) + } + (lhs, rhs) => Self::Seq(vec![lhs, rhs]), + } + } + + /// Produces a new `Tree` accepting either `self` or `other` as alternative layouts. + pub(crate) fn or(self, other: Self) -> Self { + match (self, other) { + (Self::Alt(alts), other) | (other, Self::Alt(alts)) if alts.len() == 0 => other, + (Self::Alt(mut lhs), Self::Alt(rhs)) => { + lhs.extend(rhs); + Self::Alt(lhs) + } + (Self::Alt(mut alts), alt) | (alt, Self::Alt(mut alts)) => { + alts.push(alt); + Self::Alt(alts) + } + (lhs, rhs) => Self::Alt(vec![lhs, rhs]), + } + } +} + +#[derive(Debug, Copy, Clone)] +pub(crate) enum Err { + /// The layout of the type is unspecified. + Unspecified, + /// This error will be surfaced elsewhere by rustc, so don't surface it. + Unknown, +} + +#[cfg(feature = "rustc")] +pub(crate) mod rustc { + use super::{Err, Tree}; + use crate::layout::rustc::{Def, Ref}; + + use rustc_middle::ty; + use rustc_middle::ty::layout::LayoutError; + use rustc_middle::ty::util::Discr; + use rustc_middle::ty::AdtDef; + use rustc_middle::ty::ParamEnv; + use rustc_middle::ty::SubstsRef; + use rustc_middle::ty::Ty; + use rustc_middle::ty::TyCtxt; + use rustc_middle::ty::VariantDef; + use rustc_target::abi::Align; + use std::alloc; + + impl<'tcx> From> for Err { + fn from(err: LayoutError<'tcx>) -> Self { + match err { + LayoutError::Unknown(..) => Self::Unknown, + err @ _ => unimplemented!("{:?}", err), + } + } + } + + trait LayoutExt { + fn clamp_align(&self, min_align: Align, max_align: Align) -> Self; + } + + impl LayoutExt for alloc::Layout { + fn clamp_align(&self, min_align: Align, max_align: Align) -> Self { + let min_align = min_align.bytes().try_into().unwrap(); + let max_align = max_align.bytes().try_into().unwrap(); + Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap() + } + } + + struct LayoutSummary { + total_align: Align, + total_size: usize, + discriminant_size: usize, + discriminant_align: Align, + } + + impl LayoutSummary { + fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result> { + use rustc_middle::ty::ParamEnvAnd; + use rustc_target::abi::{TyAndLayout, Variants}; + + let param_env = ParamEnv::reveal_all(); + let param_env_and_type = ParamEnvAnd { param_env, value: ty }; + let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?; + + let total_size: usize = layout.size().bytes_usize(); + let total_align: Align = layout.align().abi; + let discriminant_align: Align; + let discriminant_size: usize; + + if let Variants::Multiple { tag, .. } = layout.variants() { + discriminant_align = tag.align(&ctx).abi; + discriminant_size = tag.size(&ctx).bytes_usize(); + } else { + discriminant_align = Align::ONE; + discriminant_size = 0; + }; + + Ok(Self { total_align, total_size, discriminant_align, discriminant_size }) + } + + fn into(&self) -> alloc::Layout { + alloc::Layout::from_size_align( + self.total_size, + self.total_align.bytes().try_into().unwrap(), + ) + .unwrap() + } + } + + impl<'tcx> Tree, Ref<'tcx>> { + 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::UintTy::*; + use rustc_target::abi::HasDataLayout; + + let target = tcx.data_layout(); + + match ty.kind() { + ty::Bool => Ok(Self::bool()), + + ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()), + ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)), + ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)), + ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)), + ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)), + ty::Int(Isize) | ty::Uint(Usize) => { + Ok(Self::number(target.pointer_size.bytes_usize())) + } + + ty::Tuple(members) => { + if members.len() == 0 { + Ok(Tree::unit()) + } else { + Err(Err::Unspecified) + } + } + + ty::Array(ty, len) => { + let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap(); + let elt = Tree::from_ty(*ty, tcx)?; + Ok(std::iter::repeat(elt) + .take(len as usize) + .fold(Tree::unit(), |tree, elt| tree.then(elt))) + } + + ty::Adt(adt_def, substs_ref) => { + use rustc_middle::ty::AdtKind; + + // If the layout is ill-specified, halt. + if !(adt_def.repr().c() || adt_def.repr().int.is_some()) { + return Err(Err::Unspecified); + } + + // Compute a summary of the type's layout. + let layout_summary = LayoutSummary::from_ty(ty, tcx)?; + + // The layout begins with this adt's visibility. + let vis = Self::def(Def::Adt(*adt_def)); + + // And is followed the layout(s) of its variants + Ok(vis.then(match adt_def.adt_kind() { + AdtKind::Struct => Self::from_repr_c_variant( + ty, + *adt_def, + substs_ref, + &layout_summary, + None, + adt_def.non_enum_variant(), + tcx, + )?, + AdtKind::Enum => { + tracing::trace!( + adt_def = ?adt_def, + "treeifying enum" + ); + let mut tree = Tree::uninhabited(); + + for (idx, discr) in adt_def.discriminants(tcx) { + tree = tree.or(Self::from_repr_c_variant( + ty, + *adt_def, + substs_ref, + &layout_summary, + Some(discr), + adt_def.variant(idx), + tcx, + )?); + } + + tree + } + AdtKind::Union => { + // is the layout well-defined? + if !adt_def.repr().c() { + return Err(Err::Unspecified); + } + + let ty_layout = layout_of(tcx, ty)?; + + let mut tree = Tree::uninhabited(); + + for field in adt_def.all_fields() { + let variant_ty = field.ty(tcx, substs_ref); + let variant_layout = layout_of(tcx, variant_ty)?; + let padding_needed = ty_layout.size() - variant_layout.size(); + let variant = Self::def(Def::Field(field)) + .then(Self::from_ty(variant_ty, tcx)?) + .then(Self::padding(padding_needed)); + + tree = tree.or(variant); + } + + tree + } + })) + } + _ => Err(Err::Unspecified), + } + } + + fn from_repr_c_variant( + ty: Ty<'tcx>, + adt_def: AdtDef<'tcx>, + substs_ref: SubstsRef<'tcx>, + layout_summary: &LayoutSummary, + discr: Option>, + variant_def: &'tcx VariantDef, + tcx: TyCtxt<'tcx>, + ) -> Result { + let mut tree = Tree::unit(); + + let repr = adt_def.repr(); + let min_align = repr.align.unwrap_or(Align::ONE); + let max_align = repr.pack.unwrap_or(Align::MAX); + + let clamp = + |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap(); + + let variant_span = tracing::trace_span!( + "treeifying variant", + min_align = ?min_align, + max_align = ?max_align, + ) + .entered(); + + let mut variant_layout = alloc::Layout::from_size_align( + 0, + layout_summary.total_align.bytes().try_into().unwrap(), + ) + .unwrap(); + + // The layout of the variant is prefixed by the discriminant, if any. + if let Some(discr) = discr { + tracing::trace!(discr = ?discr, "treeifying discriminant"); + let discr_layout = alloc::Layout::from_size_align( + layout_summary.discriminant_size, + clamp(layout_summary.discriminant_align), + ) + .unwrap(); + tracing::trace!(discr_layout = ?discr_layout, "computed discriminant layout"); + variant_layout = variant_layout.extend(discr_layout).unwrap().0; + tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size)); + } + + // Next come fields. + let fields_span = tracing::trace_span!("treeifying fields").entered(); + for field_def in variant_def.fields.iter() { + let field_ty = field_def.ty(tcx, substs_ref); + let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered(); + + // begin with the field's visibility + tree = tree.then(Self::def(Def::Field(field_def))); + + // compute the field's layout charactaristics + let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align); + + // next comes the field's padding + let padding_needed = variant_layout.padding_needed_for(field_layout.align()); + if padding_needed > 0 { + tree = tree.then(Self::padding(padding_needed)); + } + + // finally, the field's layout + tree = tree.then(Self::from_ty(field_ty, tcx)?); + + // extend the variant layout with the field layout + variant_layout = variant_layout.extend(field_layout).unwrap().0; + } + drop(fields_span); + + // finally: padding + let padding_span = tracing::trace_span!("adding trailing padding").entered(); + let padding_needed = layout_summary.total_size - variant_layout.size(); + if padding_needed > 0 { + tree = tree.then(Self::padding(padding_needed)); + }; + drop(padding_span); + drop(variant_span); + Ok(tree) + } + + pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self { + // FIXME(@jswrenn): I'm certain this is missing needed endian nuance. + let bytes = discr.val.to_ne_bytes(); + let bytes = &bytes[..size]; + Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect()) + } + } + + fn layout_of<'tcx>( + ctx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + ) -> Result> { + use rustc_middle::ty::ParamEnvAnd; + use rustc_target::abi::TyAndLayout; + + let param_env = ParamEnv::reveal_all(); + let param_env_and_type = ParamEnvAnd { param_env, value: ty }; + let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?; + let layout = alloc::Layout::from_size_align( + layout.size().bytes_usize(), + layout.align().abi.bytes().try_into().unwrap(), + ) + .unwrap(); + tracing::trace!( + ty = ?ty, + layout = ?layout, + "computed layout for type" + ); + Ok(layout) + } +} diff --git a/compiler/rustc_transmute/src/layout/tree/tests.rs b/compiler/rustc_transmute/src/layout/tree/tests.rs new file mode 100644 index 0000000000000..90515e92f7aef --- /dev/null +++ b/compiler/rustc_transmute/src/layout/tree/tests.rs @@ -0,0 +1,80 @@ +use super::Tree; + +#[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] +pub enum Def { + Visible, + Invisible, +} + +impl super::Def for Def {} + +mod prune { + use super::*; + + mod should_simplify { + use super::*; + + #[test] + fn seq_1() { + let layout: Tree = Tree::def(Def::Visible).then(Tree::from_bits(0x00)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00)); + } + + #[test] + fn seq_2() { + let layout: Tree = + Tree::from_bits(0x00).then(Tree::def(Def::Visible)).then(Tree::from_bits(0x01)); + + assert_eq!( + layout.prune(&|d| matches!(d, Def::Visible)), + Tree::from_bits(0x00).then(Tree::from_bits(0x01)) + ); + } + } + + mod should_reject { + use super::*; + + #[test] + fn invisible_def() { + let layout: Tree = Tree::def(Def::Invisible); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited()); + } + + #[test] + fn invisible_def_in_seq_len_2() { + let layout: Tree = Tree::def(Def::Visible).then(Tree::def(Def::Invisible)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited()); + } + + #[test] + fn invisible_def_in_seq_len_3() { + let layout: Tree = + Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Invisible)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::uninhabited()); + } + } + + mod should_accept { + use super::*; + + #[test] + fn visible_def() { + let layout: Tree = Tree::def(Def::Visible); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit()); + } + + #[test] + fn visible_def_in_seq_len_2() { + let layout: Tree = Tree::def(Def::Visible).then(Tree::def(Def::Visible)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::unit()); + } + + #[test] + fn visible_def_in_seq_len_3() { + let layout: Tree = + Tree::def(Def::Visible).then(Tree::from_bits(0x00)).then(Tree::def(Def::Visible)); + assert_eq!(layout.prune(&|d| matches!(d, Def::Visible)), Tree::from_bits(0x00)); + } + } +} diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs new file mode 100644 index 0000000000000..9f7508fdd716a --- /dev/null +++ b/compiler/rustc_transmute/src/lib.rs @@ -0,0 +1,114 @@ +#![feature( + alloc_layout_extra, + control_flow_enum, + decl_macro, + iterator_try_reduce, + never_type, + result_into_ok_or_err +)] +#![allow(dead_code, unused_variables)] + +#[cfg(feature = "rustc")] +pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set}; + +#[cfg(not(feature = "rustc"))] +pub(crate) use std::collections::{HashMap as Map, HashSet as Set}; + +pub(crate) mod layout; +pub(crate) mod maybe_transmutable; + +#[derive(Default)] +pub struct Assume { + pub alignment: bool, + pub lifetimes: bool, + pub validity: bool, + pub visibility: bool, +} + +/// The type encodes answers to the question: "Are these types transmutable?" +#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)] +pub enum Answer +where + R: layout::Ref, +{ + /// `Src` is transmutable into `Dst`. + Yes, + + /// `Src` is NOT transmutable into `Dst`. + No(Reason), + + /// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`. + IfTransmutable { src: R, dst: R }, + + /// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met. + IfAll(Vec>), + + /// `Src` is transmutable into `Dst` if any of the enclosed requirements are met. + IfAny(Vec>), +} + +/// Answers: Why wasn't the source type transmutable into the destination type? +#[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)] +pub enum Reason { + /// The layout of the source type is unspecified. + SrcIsUnspecified, + /// The layout of the destination type is unspecified. + DstIsUnspecified, + /// The layout of the destination type is bit-incompatible with the source type. + DstIsBitIncompatible, + /// There aren't any public constructors for `Dst`. + DstIsPrivate, + /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized. + DstIsTooBig, +} + +#[cfg(feature = "rustc")] +mod rustc { + use rustc_infer::infer::InferCtxt; + use rustc_macros::{TypeFoldable, TypeVisitable}; + use rustc_middle::traits::ObligationCause; + use rustc_middle::ty::Binder; + use rustc_middle::ty::Ty; + + /// The source and destination types of a transmutation. + #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)] + pub struct Types<'tcx> { + /// The source type. + pub src: Ty<'tcx>, + /// The destination type. + pub dst: Ty<'tcx>, + } + + pub struct TransmuteTypeEnv<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + } + + impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> { + pub fn new(infcx: &'cx InferCtxt<'cx, 'tcx>) -> Self { + Self { infcx } + } + + #[allow(unused)] + pub fn is_transmutable( + &mut self, + cause: ObligationCause<'tcx>, + src_and_dst: Binder<'tcx, Types<'tcx>>, + scope: Ty<'tcx>, + assume: crate::Assume, + ) -> crate::Answer> { + let src = src_and_dst.map_bound(|types| types.src).skip_binder(); + let dst = src_and_dst.map_bound(|types| types.dst).skip_binder(); + crate::maybe_transmutable::MaybeTransmutableQuery::new( + src, + dst, + scope, + assume, + self.infcx.tcx, + ) + .answer() + } + } +} + +#[cfg(feature = "rustc")] +pub use rustc::*; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs new file mode 100644 index 0000000000000..ef3852001a806 --- /dev/null +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -0,0 +1,320 @@ +use crate::Map; +use crate::{Answer, Reason}; + +#[cfg(test)] +mod tests; + +mod query_context; +use query_context::QueryContext; + +use crate::layout::{self, dfa, Byte, Dfa, Nfa, Tree, Uninhabited}; +pub(crate) struct MaybeTransmutableQuery +where + C: QueryContext, +{ + src: L, + dst: L, + scope: ::Scope, + assume: crate::Assume, + context: C, +} + +impl MaybeTransmutableQuery +where + C: QueryContext, +{ + pub(crate) fn new( + src: L, + dst: L, + scope: ::Scope, + assume: crate::Assume, + context: C, + ) -> Self { + Self { src, dst, scope, assume, context } + } + + pub(crate) fn map_layouts( + self, + f: F, + ) -> Result, Answer<::Ref>> + where + F: FnOnce( + L, + L, + ::Scope, + &C, + ) -> Result<(M, M), Answer<::Ref>>, + { + let Self { src, dst, scope, assume, context } = self; + + let (src, dst) = f(src, dst, scope, &context)?; + + Ok(MaybeTransmutableQuery { src, dst, scope, assume, context }) + } +} + +#[cfg(feature = "rustc")] +mod rustc { + use super::*; + use crate::layout::tree::Err; + + use rustc_middle::ty::Ty; + use rustc_middle::ty::TyCtxt; + + impl<'tcx> MaybeTransmutableQuery, TyCtxt<'tcx>> { + /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, + /// then computes an answer using those trees. + #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + pub fn answer(self) -> Answer< as QueryContext>::Ref> { + let query_or_answer = self.map_layouts(|src, dst, scope, &context| { + // Convert `src` and `dst` from their rustc representations, to `Tree`-based + // representations. If these conversions fail, conclude that the transmutation is + // unacceptable; the layouts of both the source and destination types must be + // well-defined. + let src = Tree::from_ty(src, context).map_err(|err| match err { + // Answer `Yes` here, because "Unknown Type" will already be reported by + // rustc. No need to spam the user with more errors. + Err::Unknown => Answer::Yes, + Err::Unspecified => Answer::No(Reason::SrcIsUnspecified), + })?; + + let dst = Tree::from_ty(dst, context).map_err(|err| match err { + Err::Unknown => Answer::Yes, + Err::Unspecified => Answer::No(Reason::DstIsUnspecified), + })?; + + Ok((src, dst)) + }); + + match query_or_answer { + Ok(query) => query.answer(), + Err(answer) => answer, + } + } + } +} + +impl MaybeTransmutableQuery::Def, ::Ref>, C> +where + C: QueryContext, +{ + /// Answers whether a `Tree` is transmutable into another `Tree`. + /// + /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`, + /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs. + #[inline(always)] + #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + pub(crate) fn answer(self) -> Answer<::Ref> { + let assume_visibility = self.assume.visibility; + let query_or_answer = self.map_layouts(|src, dst, scope, context| { + // Remove all `Def` nodes from `src`, without checking their visibility. + let src = src.prune(&|def| true); + + tracing::trace!(src = ?src, "pruned src"); + + // Remove all `Def` nodes from `dst`, additionally... + let dst = if assume_visibility { + // ...if visibility is assumed, don't check their visibility. + dst.prune(&|def| true) + } else { + // ...otherwise, prune away all unreachable paths through the `Dst` layout. + dst.prune(&|def| context.is_accessible_from(def, scope)) + }; + + tracing::trace!(dst = ?dst, "pruned dst"); + + // Convert `src` from a tree-based representation to an NFA-based representation. + // If the conversion fails because `src` is uninhabited, conclude that the transmutation + // is acceptable, because instances of the `src` type do not exist. + let src = Nfa::from_tree(src).map_err(|Uninhabited| Answer::Yes)?; + + // Convert `dst` from a tree-based representation to an NFA-based representation. + // If the conversion fails because `src` is uninhabited, conclude that the transmutation + // is unacceptable, because instances of the `dst` type do not exist. + let dst = + Nfa::from_tree(dst).map_err(|Uninhabited| Answer::No(Reason::DstIsPrivate))?; + + Ok((src, dst)) + }); + + match query_or_answer { + Ok(query) => query.answer(), + Err(answer) => answer, + } + } +} + +impl MaybeTransmutableQuery::Ref>, C> +where + C: QueryContext, +{ + /// Answers whether a `Nfa` is transmutable into another `Nfa`. + /// + /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. + #[inline(always)] + #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + pub(crate) fn answer(self) -> Answer<::Ref> { + let query_or_answer = self + .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst)))); + + match query_or_answer { + Ok(query) => query.answer(), + Err(answer) => answer, + } + } +} + +impl MaybeTransmutableQuery::Ref>, C> +where + C: QueryContext, +{ + /// Answers whether a `Nfa` is transmutable into another `Nfa`. + /// + /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. + pub(crate) fn answer(self) -> Answer<::Ref> { + MaybeTransmutableQuery { + src: &self.src, + dst: &self.dst, + scope: self.scope, + assume: self.assume, + context: self.context, + } + .answer() + } +} + +impl<'l, C> MaybeTransmutableQuery<&'l Dfa<::Ref>, C> +where + C: QueryContext, +{ + pub(crate) fn answer(&mut self) -> Answer<::Ref> { + self.answer_memo(&mut Map::default(), self.src.start, self.dst.start) + } + + #[inline(always)] + #[tracing::instrument(skip(self))] + fn answer_memo( + &self, + cache: &mut Map<(dfa::State, dfa::State), Answer<::Ref>>, + src_state: dfa::State, + dst_state: dfa::State, + ) -> Answer<::Ref> { + if let Some(answer) = cache.get(&(src_state, dst_state)) { + answer.clone() + } else { + let answer = if dst_state == self.dst.accepting { + // truncation: `size_of(Src) >= size_of(Dst)` + Answer::Yes + } else if src_state == self.src.accepting { + // extension: `size_of(Src) >= size_of(Dst)` + if let Some(dst_state_prime) = self.dst.byte_from(dst_state, Byte::Uninit) { + self.answer_memo(cache, src_state, dst_state_prime) + } else { + Answer::No(Reason::DstIsTooBig) + } + } else { + let src_quantification = if self.assume.validity { + // if the compiler may assume that the programmer is doing additional validity checks, + // (e.g.: that `src != 3u8` when the destination type is `bool`) + // then there must exist at least one transition out of `src_state` such that the transmute is viable... + there_exists + } else { + // if the compiler cannot assume that the programmer is doing additional validity checks, + // then for all transitions out of `src_state`, such that the transmute is viable... + // then there must exist at least one transition out of `src_state` such that the transmute is viable... + for_all + }; + + src_quantification( + self.src.bytes_from(src_state).unwrap_or(&Map::default()), + |(&src_validity, &src_state_prime)| { + if let Some(dst_state_prime) = self.dst.byte_from(dst_state, src_validity) { + self.answer_memo(cache, src_state_prime, dst_state_prime) + } else if let Some(dst_state_prime) = + self.dst.byte_from(dst_state, Byte::Uninit) + { + self.answer_memo(cache, src_state_prime, dst_state_prime) + } else { + Answer::No(Reason::DstIsBitIncompatible) + } + }, + ) + }; + cache.insert((src_state, dst_state), answer.clone()); + answer + } + } +} + +impl Answer +where + R: layout::Ref, +{ + pub(crate) fn and(self, rhs: Self) -> Self { + match (self, rhs) { + (Self::No(reason), _) | (_, Self::No(reason)) => Self::No(reason), + (Self::Yes, Self::Yes) => Self::Yes, + (Self::IfAll(mut lhs), Self::IfAll(ref mut rhs)) => { + lhs.append(rhs); + Self::IfAll(lhs) + } + (constraint, Self::IfAll(mut constraints)) + | (Self::IfAll(mut constraints), constraint) => { + constraints.push(constraint); + Self::IfAll(constraints) + } + (lhs, rhs) => Self::IfAll(vec![lhs, rhs]), + } + } + + pub(crate) fn or(self, rhs: Self) -> Self { + match (self, rhs) { + (Self::Yes, _) | (_, Self::Yes) => Self::Yes, + (Self::No(lhr), Self::No(rhr)) => Self::No(lhr), + (Self::IfAny(mut lhs), Self::IfAny(ref mut rhs)) => { + lhs.append(rhs); + Self::IfAny(lhs) + } + (constraint, Self::IfAny(mut constraints)) + | (Self::IfAny(mut constraints), constraint) => { + constraints.push(constraint); + Self::IfAny(constraints) + } + (lhs, rhs) => Self::IfAny(vec![lhs, rhs]), + } + } +} + +pub fn for_all(iter: I, f: F) -> Answer +where + R: layout::Ref, + I: IntoIterator, + F: FnMut(::Item) -> Answer, +{ + use std::ops::ControlFlow::{Break, Continue}; + let (Continue(result) | Break(result)) = + iter.into_iter().map(f).try_fold(Answer::Yes, |constraints, constraint| { + match constraint.and(constraints) { + Answer::No(reason) => Break(Answer::No(reason)), + maybe => Continue(maybe), + } + }); + result +} + +pub fn there_exists(iter: I, f: F) -> Answer +where + R: layout::Ref, + I: IntoIterator, + F: FnMut(::Item) -> Answer, +{ + use std::ops::ControlFlow::{Break, Continue}; + let (Continue(result) | Break(result)) = iter.into_iter().map(f).try_fold( + Answer::No(Reason::DstIsBitIncompatible), + |constraints, constraint| match constraint.or(constraints) { + Answer::Yes => Break(Answer::Yes), + maybe => Continue(maybe), + }, + ); + result +} diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs new file mode 100644 index 0000000000000..ab9bcd232f0d0 --- /dev/null +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -0,0 +1,93 @@ +use crate::layout; + +/// Context necessary to answer the question "Are these types transmutable?". +pub(crate) trait QueryContext { + type Def: layout::Def; + type Ref: layout::Ref; + type Scope: Copy; + + /// Is `def` accessible from the defining module of `scope`? + fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool; + + fn min_align(&self, reference: Self::Ref) -> usize; +} + +#[cfg(test)] +pub(crate) mod test { + use super::QueryContext; + + pub(crate) struct UltraMinimal; + + #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] + pub(crate) enum Def { + Visible, + Invisible, + } + + impl crate::layout::Def for Def {} + + impl QueryContext for UltraMinimal { + type Def = Def; + type Ref = !; + type Scope = (); + + fn is_accessible_from(&self, def: Def, scope: ()) -> bool { + matches!(Def::Visible, def) + } + + fn min_align(&self, reference: !) -> usize { + unimplemented!() + } + } +} + +#[cfg(feature = "rustc")] +mod rustc { + use super::*; + use rustc_middle::ty::{Ty, TyCtxt}; + + impl<'tcx> super::QueryContext for TyCtxt<'tcx> { + type Def = layout::rustc::Def<'tcx>; + type Ref = layout::rustc::Ref<'tcx>; + + type Scope = Ty<'tcx>; + + #[tracing::instrument(skip(self))] + fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool { + use layout::rustc::Def; + use rustc_middle::ty; + + let parent = if let ty::Adt(adt_def, ..) = scope.kind() { + use rustc_middle::ty::DefIdTree; + let parent = self.parent(adt_def.did()); + parent + } else { + // Is this always how we want to handle a non-ADT scope? + return false; + }; + + let def_id = match def { + Def::Adt(adt_def) => adt_def.did(), + Def::Variant(variant_def) => variant_def.def_id, + Def::Field(field_def) => field_def.did, + Def::Primitive => { + // primitives do not have a def_id, but they're always accessible + return true; + } + }; + + let ret = if self.visibility(def_id).is_accessible_from(parent, *self) { + true + } else { + false + }; + + tracing::trace!(ret = ?ret, "ret"); + ret + } + + fn min_align(&self, reference: Self::Ref) -> usize { + unimplemented!() + } + } +} diff --git a/compiler/rustc_transmute/src/maybe_transmutable/tests.rs b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs new file mode 100644 index 0000000000000..d9d125687f656 --- /dev/null +++ b/compiler/rustc_transmute/src/maybe_transmutable/tests.rs @@ -0,0 +1,115 @@ +use super::query_context::test::{Def, UltraMinimal}; +use crate::maybe_transmutable::MaybeTransmutableQuery; +use crate::{layout, Answer, Reason, Set}; +use itertools::Itertools; + +mod bool { + use super::*; + + #[test] + fn should_permit_identity_transmutation_tree() { + println!("{:?}", layout::Tree::::bool()); + let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( + layout::Tree::::bool(), + layout::Tree::::bool(), + (), + crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false }, + UltraMinimal, + ) + .answer(); + assert_eq!(answer, Answer::Yes); + } + + #[test] + fn should_permit_identity_transmutation_dfa() { + let answer = crate::maybe_transmutable::MaybeTransmutableQuery::new( + layout::Dfa::::bool(), + layout::Dfa::::bool(), + (), + crate::Assume { alignment: false, lifetimes: false, validity: true, visibility: false }, + UltraMinimal, + ) + .answer(); + assert_eq!(answer, Answer::Yes); + } + + #[test] + fn should_permit_validity_expansion_and_reject_contraction() { + let un = layout::Tree::::uninhabited(); + let b0 = layout::Tree::::from_bits(0); + let b1 = layout::Tree::::from_bits(1); + let b2 = layout::Tree::::from_bits(2); + + let alts = [b0, b1, b2]; + + let into_layout = |alts: Vec<_>| { + alts.into_iter().fold(layout::Tree::::uninhabited(), layout::Tree::::or) + }; + + let into_set = |alts: Vec<_>| { + #[cfg(feature = "rustc")] + let mut set = Set::default(); + #[cfg(not(feature = "rustc"))] + let mut set = Set::new(); + set.extend(alts); + set + }; + + for src_alts in alts.clone().into_iter().powerset() { + let src_layout = into_layout(src_alts.clone()); + let src_set = into_set(src_alts.clone()); + + for dst_alts in alts.clone().into_iter().powerset().filter(|alts| !alts.is_empty()) { + let dst_layout = into_layout(dst_alts.clone()); + let dst_set = into_set(dst_alts.clone()); + + if src_set.is_subset(&dst_set) { + assert_eq!( + Answer::Yes, + MaybeTransmutableQuery::new( + src_layout.clone(), + dst_layout.clone(), + (), + crate::Assume { validity: false, ..crate::Assume::default() }, + UltraMinimal, + ) + .answer(), + "{:?} SHOULD be transmutable into {:?}", + src_layout, + dst_layout + ); + } else if !src_set.is_disjoint(&dst_set) { + assert_eq!( + Answer::Yes, + MaybeTransmutableQuery::new( + src_layout.clone(), + dst_layout.clone(), + (), + crate::Assume { validity: true, ..crate::Assume::default() }, + UltraMinimal, + ) + .answer(), + "{:?} SHOULD be transmutable (assuming validity) into {:?}", + src_layout, + dst_layout + ); + } else { + assert_eq!( + Answer::No(Reason::DstIsBitIncompatible), + MaybeTransmutableQuery::new( + src_layout.clone(), + dst_layout.clone(), + (), + crate::Assume { validity: false, ..crate::Assume::default() }, + UltraMinimal, + ) + .answer(), + "{:?} should NOT be transmutable into {:?}", + src_layout, + dst_layout + ); + } + } + } + } +} diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 234fa213da89f..add65a3be5042 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -27,6 +27,10 @@ mod valid_align; // alignment as a parameter, such as `Layout::padding_needed_for`. pub(crate) use valid_align::ValidAlign; +mod transmutability; +#[unstable(feature = "transmutability", issue = "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/abstraction/const_generic_fn.rs b/src/test/ui/transmutability/abstraction/const_generic_fn.rs new file mode 100644 index 0000000000000..94c38bb28f7e2 --- /dev/null +++ b/src/test/ui/transmutability/abstraction/const_generic_fn.rs @@ -0,0 +1,41 @@ +// check-pass +//! An array must have the correct length. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn array_like() + where + T: BikeshedIntrinsicFrom<[E; N], Context, false, false, false, true>, + [E; N]: BikeshedIntrinsicFrom + {} +} + +fn len_0() { + type Array = [u8; 0]; + #[repr(C)] struct Struct(); + assert::array_like::(); +} + +fn len_1() { + type Array = [u8; 1]; + #[repr(C)] struct Struct(u8); + assert::array_like::(); +} + +fn len_2() { + type Array = [u8; 2]; + #[repr(C)] struct Struct(u8, u8); + assert::array_like::(); +} + +fn len_3() { + type Array = [u8; 3]; + #[repr(C)] struct Struct(u8, u8, u8); + assert::array_like::(); +} diff --git a/src/test/ui/transmutability/arrays/should_have_correct_length.rs b/src/test/ui/transmutability/arrays/should_have_correct_length.rs new file mode 100644 index 0000000000000..bfe6d830a1be7 --- /dev/null +++ b/src/test/ui/transmutability/arrays/should_have_correct_length.rs @@ -0,0 +1,44 @@ +// check-pass +//! An array must have the correct length. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_have_len_0() { + type Array = [u8; 0]; + #[repr(C)] struct Struct(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn should_have_len_1() { + type Array = [u8; 1]; + #[repr(C)] struct Struct(u8); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn should_have_len_2() { + type Array = [u8; 2]; + #[repr(C)] struct Struct(u8, u8); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn should_have_len_3() { + type Array = [u8; 3]; + #[repr(C)] struct Struct(u8, u8, u8); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/arrays/should_inherit_alignment.rs b/src/test/ui/transmutability/arrays/should_inherit_alignment.rs new file mode 100644 index 0000000000000..fcb1765ea6bb4 --- /dev/null +++ b/src/test/ui/transmutability/arrays/should_inherit_alignment.rs @@ -0,0 +1,55 @@ +// check-pass +//! An array must inherit the alignment of its inner type. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +#[repr(C)] +union Uninit { + a: (), + b: OxFF, +} + +#[repr(C, align(2))] struct align_2(Ox00); + +fn len_0() { + #[repr(C)] struct ImplicitlyPadded([align_2; 0], Ox01); + #[repr(C)] struct ExplicitlyPadded(Ox01, Uninit); + + #[repr(C)] struct Struct(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn len_1() { + #[repr(C)] struct ImplicitlyPadded([align_2; 1], Ox01); + #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox01, Uninit); + + #[repr(C)] struct Struct(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} + +fn len_2() { + #[repr(C)] struct ImplicitlyPadded([align_2; 2], Ox01); + #[repr(C)] struct ExplicitlyPadded(Ox00, Uninit, Ox00, Uninit, Ox01, Uninit); + + #[repr(C)] struct Struct(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs new file mode 100644 index 0000000000000..36f9ceb0da7a6 --- /dev/null +++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs @@ -0,0 +1,61 @@ +//! An array must have a well-defined layout to participate in a transmutation. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_reject_repr_rust() +{ + fn unit() { + type repr_rust = [String; 0]; + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn singleton() { + type repr_rust = [String; 1]; + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn duplex() { + type repr_rust = [String; 2]; + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } +} + +fn should_accept_repr_C() +{ + fn unit() { + #[repr(C)] struct repr_c(u8, u16, u8); + type array = [repr_c; 0]; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn singleton() { + #[repr(C)] struct repr_c(u8, u16, u8); + type array = [repr_c; 1]; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn duplex() { + #[repr(C)] struct repr_c(u8, u16, u8); + #[repr(C)] struct duplex(repr_c, repr_c); + type array = [repr_c; 2]; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } +} diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr new file mode 100644 index 0000000000000..109e58c4093cb --- /dev/null +++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr @@ -0,0 +1,93 @@ +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:21:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `[String; 0]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:22:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 0]` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:27:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `[String; 1]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:28:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 1]` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:33:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `[String; 2]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:34:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 2]` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs new file mode 100644 index 0000000000000..cd411a4b838e0 --- /dev/null +++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs @@ -0,0 +1,149 @@ +//! An enum with a primitive repr should have exactly the size of that primitive. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(C)] +struct Zst; + +#[derive(Clone, Copy)] +#[repr(i8)] enum V0i8 { V } +#[repr(u8)] enum V0u8 { V } +#[repr(i16)] enum V0i16 { V } +#[repr(u16)] enum V0u16 { V } +#[repr(i32)] enum V0i32 { V } +#[repr(u32)] enum V0u32 { V } +#[repr(i64)] enum V0i64 { V } +#[repr(u64)] enum V0u64 { V } +#[repr(isize)] enum V0isize { V } +#[repr(usize)] enum V0usize { V } + +fn n8() { + struct Context; + + type Smaller = Zst; + type Analog = u8; + type Larger = u16; + + fn i_should_have_correct_length() { + type Current = V0i8; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0u8; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} + +fn n16() { + struct Context; + + type Smaller = u8; + type Analog = u16; + type Larger = u32; + + fn i_should_have_correct_length() { + type Current = V0i16; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0u16; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} + +fn n32() { + struct Context; + + type Smaller = u16; + type Analog = u32; + type Larger = u64; + + fn i_should_have_correct_length() { + type Current = V0i32; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0u32; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} + +fn n64() { + struct Context; + + type Smaller = u32; + type Analog = u64; + type Larger = u128; + + fn i_should_have_correct_length() { + type Current = V0i64; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0u64; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} + +fn nsize() { + struct Context; + + type Smaller = u8; + type Analog = usize; + type Larger = [usize; 2]; + + fn i_should_have_correct_length() { + type Current = V0isize; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } + + fn u_should_have_correct_length() { + type Current = V0usize; + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied + } +} diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr new file mode 100644 index 0000000000000..da24c6a021efe --- /dev/null +++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr @@ -0,0 +1,303 @@ +error[E0277]: the trait bound `V0i8: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:41:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i8` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:43:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0u8: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:49:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u8` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:51:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0i16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:65:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i16` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:67:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:73:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:75:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:89:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:91:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:97:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:99:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:113:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:115:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:121:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:123:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0isize: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:137:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0isize` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `[usize; 2]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:139:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `V0usize: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:145:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0usize` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `[usize; 2]: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/primitive_reprs_should_have_correct_length.rs:147:44 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` + | +note: required by a bound in `is_transmutable` + --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 20 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs new file mode 100644 index 0000000000000..24a88d6ac95cc --- /dev/null +++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs @@ -0,0 +1,117 @@ +//! An enum must have a well-defined layout to participate in a transmutation. + +#![crate_type = "lib"] +#![feature(repr128)] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_reject_repr_rust() { + fn void() { + enum repr_rust {} + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn singleton() { + enum repr_rust { V } + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn duplex() { + enum repr_rust { A, B } + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } +} + +fn should_accept_primitive_reprs() +{ + fn should_accept_repr_i8() { + #[repr(i8)] enum repr_i8 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u8() { + #[repr(u8)] enum repr_u8 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_i16() { + #[repr(i16)] enum repr_i16 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u16() { + #[repr(u16)] enum repr_u16 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_i32() { + #[repr(i32)] enum repr_i32 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u32() { + #[repr(u32)] enum repr_u32 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_i64() { + #[repr(i64)] enum repr_i64 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u64() { + #[repr(u64)] enum repr_u64 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_i128() { + #[repr(i128)] enum repr_i128 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_u128() { + #[repr(u128)] enum repr_u128 { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_isize() { + #[repr(isize)] enum repr_isize { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn should_accept_repr_usize() { + #[repr(usize)] enum repr_usize { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } +} + +fn should_accept_repr_C() { + #[repr(C)] enum repr_c { V } + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr new file mode 100644 index 0000000000000..1bfbff68f06cb --- /dev/null +++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr @@ -0,0 +1,93 @@ +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:21:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `void::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:22:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `void::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:27:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `singleton::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:28:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `singleton::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:33:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `duplex::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:34:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `duplex::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:14:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/enums/should_order_correctly.rs b/src/test/ui/transmutability/enums/should_order_correctly.rs new file mode 100644 index 0000000000000..6558d2658ee45 --- /dev/null +++ b/src/test/ui/transmutability/enums/should_order_correctly.rs @@ -0,0 +1,32 @@ +// check-pass +//! The payloads of an enum variant should be ordered after its tag. + +#![crate_type = "lib"] +#![feature(arbitrary_enum_discriminant)] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(u8)] enum V0 { V = 0 } +#[repr(u8)] enum V1 { V = 1 } +#[repr(u8)] enum V2 { V = 2 } + +#[repr(u8)] enum E01 { V0(V1) = 0u8 } +#[repr(u8)] enum E012 { V0(V1, V2) = 0u8 } + +fn should_order_tag_and_fields_correctly() { + // An implementation that (incorrectly) arranges E01 as [0x01, 0x00] will, + // in principle, reject this transmutation. + assert::is_transmutable::(); + // Again, but with one more field. + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/enums/should_pad_variants.rs b/src/test/ui/transmutability/enums/should_pad_variants.rs new file mode 100644 index 0000000000000..87951586523de --- /dev/null +++ b/src/test/ui/transmutability/enums/should_pad_variants.rs @@ -0,0 +1,40 @@ +//! The variants of an enum must be padded with uninit bytes such that they have +//! the same length (in bytes). + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[derive(Clone, Copy)] +#[repr(C)] struct Zst; + +#[derive(Clone, Copy)] +#[repr(u8)] enum V0 { V = 0 } + +#[derive(Clone, Copy)] +#[repr(u8)] enum V2 { V = 2 } + +#[repr(C, u8)] +enum Lopsided { + Smol(Zst), + Lorg(V0), +} + +#[repr(C)] struct Src(V0, Zst, V2); +#[repr(C)] struct Dst(Lopsided, V2); + +fn should_pad_variants() { + struct Context; + // If the implementation (incorrectly) fails to pad `Lopsided::Smol` with + // an uninitialized byte, this transmutation might be (wrongly) accepted: + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/enums/should_pad_variants.stderr b/src/test/ui/transmutability/enums/should_pad_variants.stderr new file mode 100644 index 0000000000000..b940ca077d4ad --- /dev/null +++ b/src/test/ui/transmutability/enums/should_pad_variants.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_pad_variants.rs:39:36 + | +LL | assert::is_transmutable::(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_pad_variants.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.rs b/src/test/ui/transmutability/enums/should_respect_endianness.rs new file mode 100644 index 0000000000000..9bab44e1d914f --- /dev/null +++ b/src/test/ui/transmutability/enums/should_respect_endianness.rs @@ -0,0 +1,33 @@ +//! The target endianness should be a consideration in computing the layout of +//! an enum with a multi-byte tag. + +#![crate_type = "lib"] +#![feature(arbitrary_enum_discriminant)] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(u16)] enum Src { V = 0xCAFE } + +#[repr(u8)] enum OxCA { V = 0xCA } +#[repr(u8)] enum OxFE { V = 0xFE } + +#[cfg(target_endian = "big")] #[repr(C)] struct Expected(OxCA, OxFE); +#[cfg(target_endian = "big")] #[repr(C)] struct Unexpected(OxFE, OxCA); + +#[cfg(target_endian = "little")] #[repr(C)] struct Expected(OxFE, OxCA); +#[cfg(target_endian = "little")] #[repr(C)] struct Unexpected(OxCA, OxFE); + +fn should_respect_endianness() { + assert::is_transmutable::(); + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.stderr b/src/test/ui/transmutability/enums/should_respect_endianness.stderr new file mode 100644 index 0000000000000..3f3335d4a1b8f --- /dev/null +++ b/src/test/ui/transmutability/enums/should_respect_endianness.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Unexpected: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_respect_endianness.rs:32:36 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Unexpected` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_respect_endianness.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs new file mode 100644 index 0000000000000..e13462d390b03 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.rs @@ -0,0 +1,21 @@ +// An unknown destination type should be gracefully handled. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_gracefully_handle_unknown_dst() { + struct Context; + struct Src; + assert::is_transmutable::(); //~ cannot find type +} diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr new file mode 100644 index 0000000000000..85087282d3a6e --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_dst.stderr @@ -0,0 +1,12 @@ +error[E0412]: cannot find type `Dst` in this scope + --> $DIR/unknown_dst.rs:20:36 + | +LL | fn should_gracefully_handle_unknown_dst() { + | - help: you might be missing a type parameter: `` +... +LL | assert::is_transmutable::(); + | ^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs new file mode 100644 index 0000000000000..dc51e2a8f4d2b --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.rs @@ -0,0 +1,21 @@ +// An unknown source type should be gracefully handled. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_gracefully_handle_unknown_src() { + struct Context; + #[repr(C)] struct Dst; + assert::is_transmutable::(); //~ cannot find type +} diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr new file mode 100644 index 0000000000000..9bedbe87c3f7f --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src.stderr @@ -0,0 +1,12 @@ +error[E0412]: cannot find type `Src` in this scope + --> $DIR/unknown_src.rs:20:31 + | +LL | fn should_gracefully_handle_unknown_src() { + | - help: you might be missing a type parameter: `` +... +LL | assert::is_transmutable::(); + | ^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs new file mode 100644 index 0000000000000..86fc8bd6b2856 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.rs @@ -0,0 +1,22 @@ +// An unknown destination type should be gracefully handled. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_gracefully_handle_unknown_dst_field() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst(Missing); //~ cannot find type + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr new file mode 100644 index 0000000000000..475e6f429f3c9 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/unknown_src_field.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `Missing` in this scope + --> $DIR/unknown_src_field.rs:20:27 + | +LL | #[repr(C)] struct Dst(Missing); + | ^^^^^^^ not found in this scope + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/transmutability/primitives/bool.rs b/src/test/ui/transmutability/primitives/bool.rs new file mode 100644 index 0000000000000..13cecd1d8b7ea --- /dev/null +++ b/src/test/ui/transmutability/primitives/bool.rs @@ -0,0 +1,25 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn contrast_with_u8() { + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/primitives/bool.stderr b/src/test/ui/transmutability/primitives/bool.stderr new file mode 100644 index 0000000000000..f05bb433ec844 --- /dev/null +++ b/src/test/ui/transmutability/primitives/bool.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `bool: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/bool.rs:22:35 + | +LL | assert::is_transmutable::(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `bool` + | +note: required by a bound in `is_transmutable` + --> $DIR/bool.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/primitives/numbers.rs b/src/test/ui/transmutability/primitives/numbers.rs new file mode 100644 index 0000000000000..3dbdfab9686a8 --- /dev/null +++ b/src/test/ui/transmutability/primitives/numbers.rs @@ -0,0 +1,128 @@ +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_accept_identity() { + assert::is_transmutable::< i8, i8>(); + assert::is_transmutable::< u8, u8>(); + assert::is_transmutable::< i16, i16>(); + assert::is_transmutable::< u16, u16>(); + assert::is_transmutable::< i32, i32>(); + assert::is_transmutable::< f32, f32>(); + assert::is_transmutable::< u32, u32>(); + assert::is_transmutable::< i64, i64>(); + assert::is_transmutable::< f64, f64>(); + assert::is_transmutable::< u64, u64>(); + assert::is_transmutable::< i128, i128>(); + assert::is_transmutable::< u128, u128>(); + assert::is_transmutable::(); + assert::is_transmutable::(); +} + +fn should_be_bitransmutable() { + assert::is_transmutable::< i8, u8>(); + assert::is_transmutable::< u8, i8>(); + + assert::is_transmutable::< i16, u16>(); + assert::is_transmutable::< u16, i16>(); + + assert::is_transmutable::< i32, f32>(); + assert::is_transmutable::< i32, u32>(); + assert::is_transmutable::< f32, i32>(); + assert::is_transmutable::< f32, u32>(); + assert::is_transmutable::< u32, i32>(); + assert::is_transmutable::< u32, f32>(); + + assert::is_transmutable::< u64, i64>(); + assert::is_transmutable::< u64, f64>(); + assert::is_transmutable::< i64, u64>(); + assert::is_transmutable::< i64, f64>(); + assert::is_transmutable::< f64, u64>(); + assert::is_transmutable::< f64, i64>(); + + assert::is_transmutable::< u128, i128>(); + assert::is_transmutable::< i128, u128>(); + + assert::is_transmutable::(); + assert::is_transmutable::(); +} + +fn should_reject_extension() { + assert::is_transmutable::< i8, i16>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, u16>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, i32>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, f32>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, u32>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< u8, i16>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, u16>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, i32>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, f32>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, u32>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< u8, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< i16, i32>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, f32>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, u32>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< i16, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< u16, i32>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, f32>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, u32>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< u16, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< i32, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< i32, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< i32, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< i32, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< i32, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< f32, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< f32, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< f32, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< f32, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< f32, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< u32, u64>(); //~ ERROR not satisfied + assert::is_transmutable::< u32, i64>(); //~ ERROR not satisfied + assert::is_transmutable::< u32, f64>(); //~ ERROR not satisfied + assert::is_transmutable::< u32, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< u32, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< u64, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< u64, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< i64, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< i64, i128>(); //~ ERROR not satisfied + + assert::is_transmutable::< f64, u128>(); //~ ERROR not satisfied + assert::is_transmutable::< f64, i128>(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/primitives/numbers.stderr b/src/test/ui/transmutability/primitives/numbers.stderr new file mode 100644 index 0000000000000..6bd3379dfd1a4 --- /dev/null +++ b/src/test/ui/transmutability/primitives/numbers.stderr @@ -0,0 +1,858 @@ +error[E0277]: the trait bound `i16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:62:40 + | +LL | assert::is_transmutable::< i8, i16>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i16` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:63:40 + | +LL | assert::is_transmutable::< i8, u16>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:64:40 + | +LL | assert::is_transmutable::< i8, i32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:65:40 + | +LL | assert::is_transmutable::< i8, f32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:66:40 + | +LL | assert::is_transmutable::< i8, u32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:67:40 + | +LL | assert::is_transmutable::< i8, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:68:40 + | +LL | assert::is_transmutable::< i8, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:69:40 + | +LL | assert::is_transmutable::< i8, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:70:39 + | +LL | assert::is_transmutable::< i8, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:71:39 + | +LL | assert::is_transmutable::< i8, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:73:40 + | +LL | assert::is_transmutable::< u8, i16>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i16` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:74:40 + | +LL | assert::is_transmutable::< u8, u16>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:75:40 + | +LL | assert::is_transmutable::< u8, i32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:76:40 + | +LL | assert::is_transmutable::< u8, f32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:77:40 + | +LL | assert::is_transmutable::< u8, u32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:78:40 + | +LL | assert::is_transmutable::< u8, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:79:40 + | +LL | assert::is_transmutable::< u8, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:80:40 + | +LL | assert::is_transmutable::< u8, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:81:39 + | +LL | assert::is_transmutable::< u8, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:82:39 + | +LL | assert::is_transmutable::< u8, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:84:40 + | +LL | assert::is_transmutable::< i16, i32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:85:40 + | +LL | assert::is_transmutable::< i16, f32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:86:40 + | +LL | assert::is_transmutable::< i16, u32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:87:40 + | +LL | assert::is_transmutable::< i16, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:88:40 + | +LL | assert::is_transmutable::< i16, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:89:40 + | +LL | assert::is_transmutable::< i16, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:90:39 + | +LL | assert::is_transmutable::< i16, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:91:39 + | +LL | assert::is_transmutable::< i16, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:93:40 + | +LL | assert::is_transmutable::< u16, i32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:94:40 + | +LL | assert::is_transmutable::< u16, f32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:95:40 + | +LL | assert::is_transmutable::< u16, u32>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:96:40 + | +LL | assert::is_transmutable::< u16, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:97:40 + | +LL | assert::is_transmutable::< u16, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:98:40 + | +LL | assert::is_transmutable::< u16, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:99:39 + | +LL | assert::is_transmutable::< u16, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:100:39 + | +LL | assert::is_transmutable::< u16, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:102:40 + | +LL | assert::is_transmutable::< i32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:103:40 + | +LL | assert::is_transmutable::< i32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:104:40 + | +LL | assert::is_transmutable::< i32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:105:39 + | +LL | assert::is_transmutable::< i32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:106:39 + | +LL | assert::is_transmutable::< i32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:108:40 + | +LL | assert::is_transmutable::< f32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:109:40 + | +LL | assert::is_transmutable::< f32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:110:40 + | +LL | assert::is_transmutable::< f32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:111:39 + | +LL | assert::is_transmutable::< f32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:112:39 + | +LL | assert::is_transmutable::< f32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:114:40 + | +LL | assert::is_transmutable::< u32, u64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:115:40 + | +LL | assert::is_transmutable::< u32, i64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:116:40 + | +LL | assert::is_transmutable::< u32, f64>(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:117:39 + | +LL | assert::is_transmutable::< u32, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:118:39 + | +LL | assert::is_transmutable::< u32, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:120:39 + | +LL | assert::is_transmutable::< u64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:121:39 + | +LL | assert::is_transmutable::< u64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:123:39 + | +LL | assert::is_transmutable::< i64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:124:39 + | +LL | assert::is_transmutable::< i64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:126:39 + | +LL | assert::is_transmutable::< f64, u128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/numbers.rs:127:39 + | +LL | assert::is_transmutable::< f64, i128>(); + | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | +note: required by a bound in `is_transmutable` + --> $DIR/numbers.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 57 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/primitives/unit.rs b/src/test/ui/transmutability/primitives/unit.rs new file mode 100644 index 0000000000000..a9c618188bf41 --- /dev/null +++ b/src/test/ui/transmutability/primitives/unit.rs @@ -0,0 +1,24 @@ +//! The unit type, `()`, should be one byte. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(C)] +struct Zst; + +fn should_have_correct_size() { + struct Context; + assert::is_transmutable::<(), Zst, Context>(); + assert::is_transmutable::(); + assert::is_transmutable::<(), u8, Context>(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/primitives/unit.stderr b/src/test/ui/transmutability/primitives/unit.stderr new file mode 100644 index 0000000000000..f602612feea93 --- /dev/null +++ b/src/test/ui/transmutability/primitives/unit.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `u8: BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not satisfied + --> $DIR/unit.rs:23:35 + | +LL | assert::is_transmutable::<(), u8, Context>(); + | ^^ the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8` + | +note: required by a bound in `is_transmutable` + --> $DIR/unit.rs:12:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/references.rs b/src/test/ui/transmutability/references.rs new file mode 100644 index 0000000000000..c7d24aaf1caa8 --- /dev/null +++ b/src/test/ui/transmutability/references.rs @@ -0,0 +1,20 @@ +//! Transmutations involving references are not yet supported. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn not_yet_implemented() { + #[repr(C)] struct Unit; + assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/references.stderr b/src/test/ui/transmutability/references.stderr new file mode 100644 index 0000000000000..7199e169e2977 --- /dev/null +++ b/src/test/ui/transmutability/references.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `&'static Unit: BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not satisfied + --> $DIR/references.rs:19:52 + | +LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); + | ^^^^^^^^^^^^^ the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/references.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/structs/repr/should_handle_align.rs b/src/test/ui/transmutability/structs/repr/should_handle_align.rs new file mode 100644 index 0000000000000..71720165ab063 --- /dev/null +++ b/src/test/ui/transmutability/structs/repr/should_handle_align.rs @@ -0,0 +1,36 @@ +// check-pass +//! The presence of an `align(X)` annotation must be accounted for. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_pad_explicitly_aligned_field() { + #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } + + #[repr(C)] + pub union Uninit { + a: (), + b: V0u8, + } + + #[repr(C, align(2))] struct align_2(V0u8); + + #[repr(C)] struct ImplicitlyPadded(align_2, V0u8); + #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8); + + // An implementation that (incorrectly) does not place a padding byte after + // `align_2` will, incorrectly, reject the following transmutations. + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/structs/repr/should_handle_packed.rs b/src/test/ui/transmutability/structs/repr/should_handle_packed.rs new file mode 100644 index 0000000000000..ae8acf5041897 --- /dev/null +++ b/src/test/ui/transmutability/structs/repr/should_handle_packed.rs @@ -0,0 +1,35 @@ +// check-pass +//! The presence of an `align(X)` annotation must be accounted for. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_pad_explicitly_packed_field() { + #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } + #[derive(Clone, Copy)] #[repr(u32)] enum V0u32 { V = 0 } + + #[repr(C)] + pub union Uninit { + a: (), + b: V0u8, + } + + #[repr(C, packed(2))] struct ImplicitlyPadded(V0u8, V0u32); + #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8, V0u8, V0u8, V0u8); + + // An implementation that (incorrectly) does not place a padding byte after + // `align_2` will, incorrectly, reject the following transmutations. + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs new file mode 100644 index 0000000000000..63419aceb6ce9 --- /dev/null +++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs @@ -0,0 +1,76 @@ +//! A struct must have a well-defined layout to participate in a transmutation. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_reject_repr_rust() +{ + fn unit() { + struct repr_rust; + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn tuple() { + struct repr_rust(); + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn braces() { + struct repr_rust{} + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn aligned() { + #[repr(align(1))] struct repr_rust{} + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn packed() { + #[repr(packed)] struct repr_rust{} + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } + + fn nested() { + struct repr_rust; + #[repr(C)] struct repr_c(repr_rust); + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + } +} + +fn should_accept_repr_C() +{ + fn unit() { + #[repr(C)] struct repr_c; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn tuple() { + #[repr(C)] struct repr_c(); + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } + + fn braces() { + #[repr(C)] struct repr_c{} + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); + } +} diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr new file mode 100644 index 0000000000000..ab582dd668807 --- /dev/null +++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr @@ -0,0 +1,183 @@ +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:21:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `should_reject_repr_rust::unit::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:22:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::unit::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:27:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `should_reject_repr_rust::tuple::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:28:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::tuple::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:33:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `should_reject_repr_rust::braces::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:34:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::braces::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:39:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `aligned::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:40:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `aligned::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:45:52 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `packed::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:46:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `packed::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:52:49 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `nested::repr_c: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:53:47 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `nested::repr_c` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/structs/should_order_fields_correctly.rs b/src/test/ui/transmutability/structs/should_order_fields_correctly.rs new file mode 100644 index 0000000000000..db49b914fe065 --- /dev/null +++ b/src/test/ui/transmutability/structs/should_order_fields_correctly.rs @@ -0,0 +1,31 @@ +// check-pass +//! The fields of a struct should be laid out in lexical order. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[repr(u8)] enum V0 { V = 0 } +#[repr(u8)] enum V1 { V = 1 } +#[repr(u8)] enum V2 { V = 2 } + +#[repr(C)] struct S01(V0, V1); +#[repr(C)] struct S012(V0, V1, V2); + +fn should_order_tag_and_fields_correctly() { + // An implementation that (incorrectly) arranges S01 as [0x01, 0x00] will, + // in principle, reject this transmutation. + assert::is_transmutable::(); + // Again, but with one more field. + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/boolish.rs b/src/test/ui/transmutability/unions/boolish.rs new file mode 100644 index 0000000000000..975118b99b7ba --- /dev/null +++ b/src/test/ui/transmutability/unions/boolish.rs @@ -0,0 +1,31 @@ +// check-pass + +#![crate_type = "lib"] +#![feature(transmutability)] +#![feature(marker_trait_attr)] +#![allow(dead_code)] +#![allow(incomplete_features)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_match_bool() { + #[derive(Copy, Clone)] #[repr(u8)] pub enum False { V = 0 } + #[derive(Copy, Clone)] #[repr(u8)] pub enum True { V = 1 } + + #[repr(C)] + pub union Bool { + pub f: False, + pub t: True, + } + + assert::is_transmutable::(); + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/repr/should_handle_align.rs b/src/test/ui/transmutability/unions/repr/should_handle_align.rs new file mode 100644 index 0000000000000..e215799a23240 --- /dev/null +++ b/src/test/ui/transmutability/unions/repr/should_handle_align.rs @@ -0,0 +1,40 @@ +// check-pass +//! The presence of an `align(X)` annotation must be accounted for. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_pad_explicitly_aligned_field() { + #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } + #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 } + + #[repr(C)] + pub union Uninit { + a: (), + b: V1u8, + } + + #[repr(C, align(2))] + pub union align_2 { + a: V0u8, + } + + #[repr(C)] struct ImplicitlyPadded(align_2, V0u8); + #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V0u8); + + // An implementation that (incorrectly) does not place a padding byte after + // `align_2` will, incorrectly, reject the following transmutations. + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/repr/should_handle_packed.rs b/src/test/ui/transmutability/unions/repr/should_handle_packed.rs new file mode 100644 index 0000000000000..34a53c7a80c42 --- /dev/null +++ b/src/test/ui/transmutability/unions/repr/should_handle_packed.rs @@ -0,0 +1,41 @@ +// check-pass +//! The presence of an `align(X)` annotation must be accounted for. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_pad_explicitly_packed_field() { + #[derive(Clone, Copy)] #[repr(u8)] enum V0u8 { V = 0 } + #[derive(Clone, Copy)] #[repr(u8)] enum V1u8 { V = 1 } + #[derive(Clone, Copy)] #[repr(u8)] enum V2u8 { V = 2 } + #[derive(Clone, Copy)] #[repr(u32)] enum V3u32 { V = 3 } + + #[repr(C)] + pub union Uninit { + a: (), + b: V1u8, + } + + #[repr(C, packed(2))] + pub union Packed { + a: [V3u32; 0], + b: V0u8, + } + + #[repr(C)] struct ImplicitlyPadded(Packed, V2u8); + #[repr(C)] struct ExplicitlyPadded(V0u8, Uninit, V2u8); + + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs new file mode 100644 index 0000000000000..d6e28d7f0db3f --- /dev/null +++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs @@ -0,0 +1,37 @@ +//! A struct must have a well-defined layout to participate in a transmutation. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +fn should_reject_repr_rust() +{ + union repr_rust { + a: u8 + } + + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied +} + +fn should_accept_repr_C() +{ + #[repr(C)] + union repr_c { + a: u8 + } + + struct repr_rust; + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr new file mode 100644 index 0000000000000..c24193f9a6d77 --- /dev/null +++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:23:48 + | +LL | assert::is_maybe_transmutable::(); + | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `should_reject_repr_rust::repr_rust: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_require_well_defined_layout.rs:24:43 + | +LL | assert::is_maybe_transmutable::(); + | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::repr_rust` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_require_well_defined_layout.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/unions/should_pad_variants.rs b/src/test/ui/transmutability/unions/should_pad_variants.rs new file mode 100644 index 0000000000000..d4126693f9284 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_pad_variants.rs @@ -0,0 +1,40 @@ +//! The variants of a union must be padded with uninit bytes such that they have +//! the same length (in bytes). + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[derive(Clone, Copy)] +#[repr(C)] struct Zst; + +#[derive(Clone, Copy)] +#[repr(u8)] enum V0 { V = 0 } + +#[derive(Clone, Copy)] +#[repr(u8)] enum V2 { V = 2 } + +#[repr(C)] +union Lopsided { + smol: Zst, + lorg: V0, +} + +#[repr(C)] struct Src(V0, Zst, V2); +#[repr(C)] struct Dst(V0, Lopsided, V2); + +fn should_pad_variants() { + struct Context; + // If the implementation (incorrectly) fails to pad `Lopsided::smol` with + // an uninitialized byte, this transmutation might be (wrongly) accepted: + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/unions/should_pad_variants.stderr b/src/test/ui/transmutability/unions/should_pad_variants.stderr new file mode 100644 index 0000000000000..b940ca077d4ad --- /dev/null +++ b/src/test/ui/transmutability/unions/should_pad_variants.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_pad_variants.rs:39:36 + | +LL | assert::is_transmutable::(); + | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_pad_variants.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs b/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs new file mode 100644 index 0000000000000..2493d71554ad3 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_permit_intersecting_if_validity_is_assumed.rs @@ -0,0 +1,39 @@ +// check-pass +//! If validity is assumed, there need only be one matching bit-pattern between +//! the source and destination types. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + // validity IS assumed --------------------------------^^^^ + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +fn test() { + #[repr(C)] + union A { + a: Ox00, + b: Ox7F, + } + + #[repr(C)] + union B { + a: Ox7F, + b: OxFF, + } + + assert::is_maybe_transmutable::(); + assert::is_maybe_transmutable::(); +} diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.rs b/src/test/ui/transmutability/unions/should_reject_contraction.rs new file mode 100644 index 0000000000000..34b31595193dd --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_contraction.rs @@ -0,0 +1,36 @@ +//! Validity may not be contracted, unless validity is assumed. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +fn test() { + #[repr(C)] + union Subset { + a: Ox00, + b: OxFF, + } + + #[repr(C)] + union Superset { + a: Ox00, + b: OxFF, + c: Ox01, + } + + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.stderr b/src/test/ui/transmutability/unions/should_reject_contraction.stderr new file mode 100644 index 0000000000000..1465c3df22837 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_contraction.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Subset: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_contraction.rs:35:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Subset` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_contraction.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.rs b/src/test/ui/transmutability/unions/should_reject_disjoint.rs new file mode 100644 index 0000000000000..b4b06c571315e --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_disjoint.rs @@ -0,0 +1,36 @@ +//! Validity must be satisfiable, even if validity is assumed. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_maybe_transmutable() + where + Dst: BikeshedIntrinsicFrom + // validity IS assumed --------------------------------^^^^ + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox01 { V = 0x01 } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +fn test() { + #[repr(C)] + union A { + a: Ox00, + b: OxFF, + } + + #[repr(C)] + union B { + c: Ox01, + } + + assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.stderr b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr new file mode 100644 index 0000000000000..a140f0c506b3b --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `B: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_disjoint.rs:34:40 + | +LL | assert::is_maybe_transmutable::(); + | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `B` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_reject_disjoint.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error[E0277]: the trait bound `A: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_disjoint.rs:35:40 + | +LL | assert::is_maybe_transmutable::(); + | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `A` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/should_reject_disjoint.rs:13:14 + | +LL | pub fn is_maybe_transmutable() + | --------------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.rs b/src/test/ui/transmutability/unions/should_reject_intersecting.rs new file mode 100644 index 0000000000000..1ed7d2a0bd9a0 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_intersecting.rs @@ -0,0 +1,38 @@ +//! ALL valid bit patterns of the source must be valid bit patterns of the +//! destination type, unless validity is assumed. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + pub struct Context; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // validity is NOT assumed ----------------------------^^^^^ + {} +} + +#[derive(Clone, Copy)] #[repr(u8)] enum Ox00 { V = 0x00 } +#[derive(Clone, Copy)] #[repr(u8)] enum Ox7F { V = 0x7F } +#[derive(Clone, Copy)] #[repr(u8)] enum OxFF { V = 0xFF } + +fn test() { + #[repr(C)] + union A { + a: Ox00, + b: Ox7F, + } + + #[repr(C)] + union B { + a: Ox7F, + b: OxFF, + } + + assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.stderr b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr new file mode 100644 index 0000000000000..43e642b569152 --- /dev/null +++ b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr @@ -0,0 +1,33 @@ +error[E0277]: the trait bound `B: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_intersecting.rs:36:34 + | +LL | assert::is_transmutable::(); + | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `B` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_intersecting.rs:14:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error[E0277]: the trait bound `A: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_intersecting.rs:37:34 + | +LL | assert::is_transmutable::(); + | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `A` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_intersecting.rs:14:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs new file mode 100644 index 0000000000000..5a8c810494c58 --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_field.rs @@ -0,0 +1,38 @@ +// check-pass +//! If visibility is assumed, a transmutation should be accepted even if the +//! destination type contains a private field. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(self) field: Zst, // <- private field + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs new file mode 100644 index 0000000000000..77ab4fa6bff4b --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_private_variant.rs @@ -0,0 +1,39 @@ +// check-pass +//! If visibility is assumed, a transmutation should be accepted even if the +//! destination type contains a private variant. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, + } +} + +mod dst { + #[derive(Copy, Clone)] + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) union Dst { + pub(self) field: Zst, // <- private variant + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs new file mode 100644 index 0000000000000..2421b24cbf07f --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_tricky_unreachable_field.rs @@ -0,0 +1,46 @@ +// check-pass +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) +//! +//! This test exercises a tricky-to-implement instance of this principle: the +//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is +//! unreachable from `Context`. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + mod private { + #[repr(C)] pub struct Zst; // <- unreachable type + } + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: private::Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs new file mode 100644 index 0000000000000..80b454fda560f --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.rs @@ -0,0 +1,39 @@ +//! If visibility is assumed, a transmutation should be accepted even if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(self) struct Zst; // <- unreachable type + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, //~ ERROR private type + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr new file mode 100644 index 0000000000000..be83b7ce33f24 --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_field.stderr @@ -0,0 +1,12 @@ +error[E0446]: private type `dst::Zst` in public interface + --> $DIR/should_accept_if_dst_has_unreachable_field.rs:32:9 + | +LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type + | -------------------- `dst::Zst` declared as private +... +LL | pub(in super) field: Zst, + | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0446`. diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs new file mode 100644 index 0000000000000..7c53c91e4eda7 --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.rs @@ -0,0 +1,40 @@ +//! If visibility is assumed, a transmutation should be accepted even if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility IS assumed -------------------------------------^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + // unreachable type + #[repr(C)] pub(self) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR `Dst` is private +} diff --git a/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr new file mode 100644 index 0000000000000..827df05decb8f --- /dev/null +++ b/src/test/ui/transmutability/visibility/assume/should_accept_if_dst_has_unreachable_ty.stderr @@ -0,0 +1,15 @@ +error[E0603]: struct `Dst` is private + --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:39:46 + | +LL | assert::is_transmutable::(); + | ^^^ private struct + | +note: the struct `Dst` is defined here + --> $DIR/should_accept_if_dst_has_unreachable_ty.rs:32:16 + | +LL | #[repr(C)] pub(self) struct Dst { + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs new file mode 100644 index 0000000000000..c3f298f016325 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_field.rs @@ -0,0 +1,38 @@ +// check-pass +//! The presence of a private field in the source type does not affect +//! transmutability. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(self) field: Zst, // <- private field + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs new file mode 100644 index 0000000000000..73f6aece51eb5 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_private_variant.rs @@ -0,0 +1,39 @@ +// check-pass +//! The presence of a private variant in the source type does not affect +//! transmutability. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[derive(Copy, Clone)] + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) union Src { + pub(self) field: Zst, // <- private variant + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs new file mode 100644 index 0000000000000..6d602601e96ab --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.rs @@ -0,0 +1,38 @@ +//! The presence of an unreachable field in the source type (e.g., a public +//! field with a private type does not affect transmutability. (This rule is +//! distinct from type privacy, which still may forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(self) struct Zst; // <- unreachable type + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, //~ ERROR private type + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr new file mode 100644 index 0000000000000..3f7d08d0ae248 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_field.stderr @@ -0,0 +1,12 @@ +error[E0446]: private type `src::Zst` in public interface + --> $DIR/should_accept_if_src_has_unreachable_field.rs:23:9 + | +LL | #[repr(C)] pub(self) struct Zst; // <- unreachable type + | -------------------- `src::Zst` declared as private +... +LL | pub(in super) field: Zst, + | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0446`. diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs new file mode 100644 index 0000000000000..1943fb8716a11 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.rs @@ -0,0 +1,39 @@ +//! The presence of an unreachable source type (i.e., the source type is +//! private) does not affect transmutability. (This rule is distinct from type +//! privacy, which still may forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + // unreachable type + #[repr(C)] pub(self) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR `Src` is private +} diff --git a/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr new file mode 100644 index 0000000000000..e961984e18932 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_accept_if_src_has_unreachable_ty.stderr @@ -0,0 +1,15 @@ +error[E0603]: struct `Src` is private + --> $DIR/should_accept_if_src_has_unreachable_ty.rs:38:36 + | +LL | assert::is_transmutable::(); + | ^^^ private struct + | +note: the struct `Src` is defined here + --> $DIR/should_accept_if_src_has_unreachable_ty.rs:23:16 + | +LL | #[repr(C)] pub(self) struct Src { + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0603`. diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs new file mode 100644 index 0000000000000..04cb6885887f4 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs @@ -0,0 +1,37 @@ +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains a private field. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Dst { + pub(self) field: Zst, // <- private field + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr new file mode 100644 index 0000000000000..4dfbfaeafb648 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_if_dst_has_private_field.rs:36:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_if_dst_has_private_field.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs new file mode 100644 index 0000000000000..768e7bc559efe --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs @@ -0,0 +1,38 @@ +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains a private variant. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[derive(Copy, Clone)] + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) union Dst { + pub(self) field: Zst, // <- private variant + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr new file mode 100644 index 0000000000000..ed834a1bd2587 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_if_dst_has_private_variant.rs:37:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_if_dst_has_private_variant.rs:13:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs new file mode 100644 index 0000000000000..c44fed4cce392 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs @@ -0,0 +1,52 @@ +// check-pass +//! NOTE: This test documents a known-bug in the implementation of the +//! transmutability trait. Once fixed, the above "check-pass" header should be +//! removed, and an "ERROR not satisfied" annotation should be added at the end +//! of the line starting with `assert::is_transmutable`. +//! +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) +//! +//! This test exercises a tricky-to-implement instance of this principle: the +//! "pub-in-priv trick". In the below example, the type `dst::private::Zst` is +//! unreachable from `Context`. Consequently, the transmute from `Src` to `Dst` +//! SHOULD be rejected. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + mod private { + #[repr(C)] pub struct Zst; // <- unreachable type + } + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: private::Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs new file mode 100644 index 0000000000000..dbef149bacc99 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs @@ -0,0 +1,39 @@ +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(self) struct Zst; // <- unreachable type + + #[repr(C)] pub(in super) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); //~ ERROR not satisfied +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr new file mode 100644 index 0000000000000..3029d6ab8eeee --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr @@ -0,0 +1,18 @@ +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs new file mode 100644 index 0000000000000..c5947eceb656e --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs @@ -0,0 +1,42 @@ +//! Unless visibility is assumed, a transmutation should be rejected if the +//! destination type contains an unreachable field (e.g., a public field with a +//! private type). (This rule is distinct from type privacy, which still may +//! forbid naming such types.) + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable() + where + Dst: BikeshedIntrinsicFrom + // visibility is NOT assumed ---------------------------------^^^^^ + {} +} + +mod src { + #[repr(C)] pub(in super) struct Zst; + + #[repr(C)] pub(in super) struct Src { + pub(in super) field: Zst, + } +} + +mod dst { + #[repr(C)] pub(in super) struct Zst; + + // unreachable type + #[repr(C)] pub(self) struct Dst { + pub(in super) field: Zst, + } +} + +fn test() { + struct Context; + assert::is_transmutable::(); + //~^ ERROR `Dst` is private + //~| ERROR not satisfied +} diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr new file mode 100644 index 0000000000000..2fd3889032149 --- /dev/null +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr @@ -0,0 +1,31 @@ +error[E0603]: struct `Dst` is private + --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:46 + | +LL | assert::is_transmutable::(); + | ^^^ private struct + | +note: the struct `Dst` is defined here + --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:32:16 + | +LL | #[repr(C)] pub(self) struct Dst { + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied + --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41 + | +LL | assert::is_transmutable::(); + | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | +note: required by a bound in `is_transmutable` + --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14 + | +LL | pub fn is_transmutable() + | --------------- required by a bound in this +LL | where +LL | Dst: BikeshedIntrinsicFrom + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0603. +For more information about an error, try `rustc --explain E0277`. From 18751a708a5831dffcd3b95755496efdaf7ae7a0 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 20 Jul 2022 19:57:55 +0000 Subject: [PATCH 02/13] safe transmute: gracefully handle const params of wrong types ref: https://github.com/rust-lang/rust/pull/92268/files#r925244819 --- .../src/traits/select/confirmation.rs | 2 +- .../wrong-type-assume.rs | 40 +++++++++++++++++++ .../wrong-type-assume.stderr | 27 +++++++++++++ 3 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index a609fb2b17266..672c9b7b088df 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -288,7 +288,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .substs .const_at(i) .try_eval_bool(self.tcx(), obligation.param_env) - .unwrap() + .unwrap_or(true) }; let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types { diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs new file mode 100644 index 0000000000000..bd36748e7901b --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.rs @@ -0,0 +1,40 @@ +//! The implementation must behave well if const values of wrong types are +//! provided. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable< + Src, + Dst, + Context, + const ASSUME_ALIGNMENT: bool, + const ASSUME_LIFETIMES: bool, + const ASSUME_VALIDITY: bool, + const ASSUME_VISIBILITY: bool, + >() + where + Dst: BikeshedIntrinsicFrom< + Src, + Context, + ASSUME_ALIGNMENT, + ASSUME_LIFETIMES, + ASSUME_VALIDITY, + ASSUME_VISIBILITY, + >, + {} +} + +fn test() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + assert::is_transmutable::(); //~ ERROR mismatched types + assert::is_transmutable::(); //~ ERROR mismatched types + assert::is_transmutable::(); //~ ERROR mismatched types + assert::is_transmutable::(); //~ ERROR mismatched types +} diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr new file mode 100644 index 0000000000000..e1464e02352c6 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/wrong-type-assume.stderr @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/wrong-type-assume.rs:36:51 + | +LL | assert::is_transmutable::(); + | ^^^ expected `bool`, found `u8` + +error[E0308]: mismatched types + --> $DIR/wrong-type-assume.rs:37:58 + | +LL | assert::is_transmutable::(); + | ^^^ expected `bool`, found `u8` + +error[E0308]: mismatched types + --> $DIR/wrong-type-assume.rs:38:65 + | +LL | assert::is_transmutable::(); + | ^^^ expected `bool`, found `u8` + +error[E0308]: mismatched types + --> $DIR/wrong-type-assume.rs:39:72 + | +LL | assert::is_transmutable::(); + | ^^^ expected `bool`, found `u8` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0308`. From 8c5c291882d3cafd26757bb1326fc3b3135a87f5 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 20 Jul 2022 20:03:06 +0000 Subject: [PATCH 03/13] safe transmute: test when `ASSUME` params are passed indirectly ref: https://github.com/rust-lang/rust/pull/92268/files#r925258420 --- .../abstraction/abstracted_assume.rs | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/test/ui/transmutability/abstraction/abstracted_assume.rs diff --git a/src/test/ui/transmutability/abstraction/abstracted_assume.rs b/src/test/ui/transmutability/abstraction/abstracted_assume.rs new file mode 100644 index 0000000000000..2abbbf3c158d6 --- /dev/null +++ b/src/test/ui/transmutability/abstraction/abstracted_assume.rs @@ -0,0 +1,73 @@ +// check-pass +//! The implementation should behave correctly when the `ASSUME` parameters are +//! provided indirectly through an abstraction. + +#![crate_type = "lib"] +#![feature(transmutability)] +#![allow(dead_code, incomplete_features, non_camel_case_types)] + +mod assert { + use std::mem::BikeshedIntrinsicFrom; + + pub fn is_transmutable< + Src, + Dst, + Context, + const ASSUME_ALIGNMENT: bool, + const ASSUME_LIFETIMES: bool, + const ASSUME_VALIDITY: bool, + const ASSUME_VISIBILITY: bool, + >() + where + Dst: BikeshedIntrinsicFrom< + Src, + Context, + ASSUME_ALIGNMENT, + ASSUME_LIFETIMES, + ASSUME_VALIDITY, + ASSUME_VISIBILITY, + >, + {} +} + +fn direct() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + + assert::is_transmutable::(); +} + +fn via_const() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + + const FALSE: bool = false; + + assert::is_transmutable::(); +} + +fn via_associated_const() { + struct Context; + #[repr(C)] struct Src; + #[repr(C)] struct Dst; + + trait Trait { + const FALSE: bool = true; + } + + struct Ty; + + impl Trait for Ty {} + + assert::is_transmutable::< + Src, + Dst, + Context, + {Ty::FALSE}, + {Ty::FALSE}, + {Ty::FALSE}, + {Ty::FALSE} + >(); +} From 0fa70c3b1272c986eed27f838b645892ad435772 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Wed, 20 Jul 2022 20:21:57 +0000 Subject: [PATCH 04/13] safe transmute: revise `Hash`, `PartialEq` impls on `VariantDef`, `FieldDef` Exhaustively destructure parameter(s) so that changes to type definitions will lead to compile errors, thus reminding contributors to re-assess the assumptions underpinning these impls. ref: https://github.com/rust-lang/rust/pull/92268/#discussion_r925241377 ref: https://github.com/rust-lang/rust/pull/92268/#discussion_r925241718 --- compiler/rustc_middle/src/ty/mod.rs | 73 ++++++++++++++++++++++++----- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5fda1e6538e91..ce931d0fcd3be 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1724,23 +1724,56 @@ impl VariantDef { } } -/// 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 + // There should be only one `VariantDef` for each `def_id`, therefore + // it is fine to implement `PartialEq` only based on `def_id`. + // + // Below, we exhaustively destructure `self` and `other` so that if the + // definition of `VariantDef` changes, a compile-error will be produced, + // reminding us to revisit this assumption. + + let Self { + def_id: lhs_def_id, + ctor_def_id: _, + name: _, + discr: _, + fields: _, + ctor_kind: _, + flags: _, + } = &self; + + let Self { + def_id: rhs_def_id, + ctor_def_id: _, + name: _, + discr: _, + fields: _, + ctor_kind: _, + flags: _, + } = other; + + lhs_def_id == rhs_def_id } } impl Eq for VariantDef {} -/// 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) + // There should be only one `VariantDef` for each `def_id`, therefore + // it is fine to implement `Hash` only based on `def_id`. + // + // Below, we exhaustively destructure `self` so that if the definition + // of `VariantDef` changes, a compile-error will be produced, reminding + // us to revisit this assumption. + + let Self { def_id, ctor_def_id: _, name: _, discr: _, fields: _, ctor_kind: _, flags: _ } = + &self; + + def_id.hash(s) } } @@ -1764,23 +1797,39 @@ pub struct FieldDef { pub vis: Visibility, } -/// 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 + // There should be only one `FieldDef` for each `did`, therefore it is + // fine to implement `PartialEq` only based on `did`. + // + // Below, we exhaustively destructure `self` so that if the definition + // of `FieldDef` changes, a compile-error will be produced, reminding + // us to revisit this assumption. + + let Self { did: lhs_did, name: _, vis: _ } = &self; + + let Self { did: rhs_did, name: _, vis: _ } = other; + + lhs_did == rhs_did } } impl Eq for FieldDef {} -/// 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) + // There should be only one `FieldDef` for each `did`, therefore it is + // fine to implement `Hash` only based on `did`. + // + // Below, we exhaustively destructure `self` so that if the definition + // of `FieldDef` changes, a compile-error will be produced, reminding + // us to revisit this assumption. + + let Self { did, name: _, vis: _ } = &self; + + did.hash(s) } } From c0d0ce95ebdab2817b2b6240f802b5814a1dfcfe Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 17:28:24 +0000 Subject: [PATCH 05/13] safe transmute: tweak tracing ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925246903 ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925250811 ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925255782 --- compiler/rustc_transmute/src/layout/dfa.rs | 2 +- compiler/rustc_transmute/src/layout/tree.rs | 16 ++++------------ compiler/rustc_transmute/src/lib.rs | 3 +++ .../src/maybe_transmutable/mod.rs | 12 ++++++------ .../src/maybe_transmutable/query_context.rs | 4 ++-- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index cdd3195712d26..f2742dc8ee5ad 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -103,7 +103,7 @@ where Self { transitions, start, accepting } } - #[tracing::instrument] + #[instrument(level = "DEBUG")] #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] pub(crate) fn from_nfa(nfa: Nfa) -> Self { let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa; diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index 67b401855d4be..70b3ba02b05b5 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -76,7 +76,6 @@ where } /// A `Tree` whose layout is entirely padding of the given width. - #[tracing::instrument] pub(crate) fn padding(width_in_bytes: usize) -> Self { Self::Seq(vec![Self::uninit(); width_in_bytes]) } @@ -316,10 +315,7 @@ pub(crate) mod rustc { tcx, )?, AdtKind::Enum => { - tracing::trace!( - adt_def = ?adt_def, - "treeifying enum" - ); + tracing::trace!(?adt_def, "treeifying enum"); let mut tree = Tree::uninhabited(); for (idx, discr) in adt_def.discriminants(tcx) { @@ -398,13 +394,13 @@ pub(crate) mod rustc { // The layout of the variant is prefixed by the discriminant, if any. if let Some(discr) = discr { - tracing::trace!(discr = ?discr, "treeifying discriminant"); + tracing::trace!(?discr, "treeifying discriminant"); let discr_layout = alloc::Layout::from_size_align( layout_summary.discriminant_size, clamp(layout_summary.discriminant_align), ) .unwrap(); - tracing::trace!(discr_layout = ?discr_layout, "computed discriminant layout"); + tracing::trace!(?discr_layout, "computed discriminant layout"); variant_layout = variant_layout.extend(discr_layout).unwrap().0; tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size)); } @@ -469,11 +465,7 @@ pub(crate) mod rustc { layout.align().abi.bytes().try_into().unwrap(), ) .unwrap(); - tracing::trace!( - ty = ?ty, - layout = ?layout, - "computed layout for type" - ); + tracing::trace!(?ty, ?layout, "computed layout for type"); Ok(layout) } } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 9f7508fdd716a..cfc7c752a6bd6 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -8,6 +8,9 @@ )] #![allow(dead_code, unused_variables)] +#[macro_use] +extern crate tracing; + #[cfg(feature = "rustc")] pub(crate) use rustc_data_structures::fx::{FxHashMap as Map, FxHashSet as Set}; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index ef3852001a806..8fb85527a0f0a 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -64,7 +64,7 @@ mod rustc { impl<'tcx> MaybeTransmutableQuery, TyCtxt<'tcx>> { /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, /// then computes an answer using those trees. - #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub fn answer(self) -> Answer< as QueryContext>::Ref> { let query_or_answer = self.map_layouts(|src, dst, scope, &context| { // Convert `src` and `dst` from their rustc representations, to `Tree`-based @@ -103,14 +103,14 @@ where /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`, /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs. #[inline(always)] - #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { let assume_visibility = self.assume.visibility; let query_or_answer = self.map_layouts(|src, dst, scope, context| { // Remove all `Def` nodes from `src`, without checking their visibility. let src = src.prune(&|def| true); - tracing::trace!(src = ?src, "pruned src"); + tracing::trace!(?src, "pruned src"); // Remove all `Def` nodes from `dst`, additionally... let dst = if assume_visibility { @@ -121,7 +121,7 @@ where dst.prune(&|def| context.is_accessible_from(def, scope)) }; - tracing::trace!(dst = ?dst, "pruned dst"); + tracing::trace!(?dst, "pruned dst"); // Convert `src` from a tree-based representation to an NFA-based representation. // If the conversion fails because `src` is uninhabited, conclude that the transmutation @@ -152,7 +152,7 @@ where /// /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. #[inline(always)] - #[tracing::instrument(skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { let query_or_answer = self .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst)))); @@ -192,7 +192,7 @@ where } #[inline(always)] - #[tracing::instrument(skip(self))] + #[instrument(level = "DEBUG", skip(self))] fn answer_memo( &self, cache: &mut Map<(dfa::State, dfa::State), Answer<::Ref>>, diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index ab9bcd232f0d0..1a66b6cfe00ef 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -52,7 +52,7 @@ mod rustc { type Scope = Ty<'tcx>; - #[tracing::instrument(skip(self))] + #[instrument(level = "DEBUG", skip(self))] fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool { use layout::rustc::Def; use rustc_middle::ty; @@ -82,7 +82,7 @@ mod rustc { false }; - tracing::trace!(ret = ?ret, "ret"); + tracing::trace!(?ret, "ret"); ret } From 4a15157baddb266af94a58a0b9c88cf6f5c6540c Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 17:38:25 +0000 Subject: [PATCH 06/13] safe transmute: don't mark user impls as unambiguous ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925243794 --- .../src/traits/select/candidate_assembly.rs | 1 - 1 file changed, 1 deletion(-) 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 a18b835e70ce1..a60ce0f3437e0 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -884,7 +884,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidates: &mut SelectionCandidateSet<'tcx>, ) { if obligation.has_param_types_or_consts() { - candidates.ambiguous = false; return; } From 402644f72f61a28b3690a565be82d2178cd44800 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 17:43:25 +0000 Subject: [PATCH 07/13] safe transmute: test to ensure that trait is correctly feature-gated ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925265476 --- .../malformed-program-gracefulness/feature-missing.rs | 6 ++++++ .../feature-missing.stderr | 11 +++++++++++ 2 files changed, 17 insertions(+) create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs create mode 100644 src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs new file mode 100644 index 0000000000000..12018f3161a75 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs @@ -0,0 +1,6 @@ +// The trait must not be available if its feature flag is absent. + +#![crate_type = "lib"] + +use std::mem::BikeshedIntrinsicFrom; +//~^ ERROR use of unstable library feature 'transmutability' [E0658] diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr new file mode 100644 index 0000000000000..4b51850634af1 --- /dev/null +++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'transmutability' + --> $DIR/feature-missing.rs:5:5 + | +LL | use std::mem::BikeshedIntrinsicFrom; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(transmutability)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. From 21d1ab4877c96a2b2fa802444f3a3d311a96beef Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 17:53:01 +0000 Subject: [PATCH 08/13] safe transmute: add `rustc_on_unimplemented` to `BikeshedIntrinsicFrom` ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925266583 --- library/core/src/mem/transmutability.rs | 4 + .../should_require_well_defined_layout.rs | 12 +- .../should_require_well_defined_layout.stderr | 30 +- ...mitive_reprs_should_have_correct_length.rs | 40 +-- ...ve_reprs_should_have_correct_length.stderr | 100 +++--- .../should_require_well_defined_layout.rs | 12 +- .../should_require_well_defined_layout.stderr | 30 +- .../enums/should_pad_variants.rs | 2 +- .../enums/should_pad_variants.stderr | 5 +- .../enums/should_respect_endianness.rs | 2 +- .../enums/should_respect_endianness.stderr | 5 +- .../ui/transmutability/primitives/bool.rs | 2 +- .../ui/transmutability/primitives/bool.stderr | 5 +- .../ui/transmutability/primitives/numbers.rs | 132 ++++---- .../transmutability/primitives/numbers.stderr | 285 +++++++++++------- .../ui/transmutability/primitives/unit.rs | 2 +- .../ui/transmutability/primitives/unit.stderr | 5 +- src/test/ui/transmutability/references.rs | 2 +- src/test/ui/transmutability/references.stderr | 5 +- .../should_require_well_defined_layout.rs | 24 +- .../should_require_well_defined_layout.stderr | 60 ++-- .../should_require_well_defined_layout.rs | 4 +- .../should_require_well_defined_layout.stderr | 10 +- .../unions/should_pad_variants.rs | 2 +- .../unions/should_pad_variants.stderr | 5 +- .../unions/should_reject_contraction.rs | 2 +- .../unions/should_reject_contraction.stderr | 5 +- .../unions/should_reject_disjoint.rs | 4 +- .../unions/should_reject_disjoint.stderr | 10 +- .../unions/should_reject_intersecting.rs | 4 +- .../unions/should_reject_intersecting.stderr | 10 +- .../should_reject_if_dst_has_private_field.rs | 2 +- ...uld_reject_if_dst_has_private_field.stderr | 5 +- ...hould_reject_if_dst_has_private_variant.rs | 2 +- ...d_reject_if_dst_has_private_variant.stderr | 5 +- ...ect_if_dst_has_tricky_unreachable_field.rs | 2 +- ...uld_reject_if_dst_has_unreachable_field.rs | 2 +- ...reject_if_dst_has_unreachable_field.stderr | 5 +- ...should_reject_if_dst_has_unreachable_ty.rs | 2 +- ...ld_reject_if_dst_has_unreachable_ty.stderr | 5 +- 40 files changed, 486 insertions(+), 364 deletions(-) diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 52342f8a0ecd6..820a7582b113b 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -5,6 +5,10 @@ /// 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")] +#[rustc_on_unimplemented( + message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", + label = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`." +)] pub unsafe trait BikeshedIntrinsicFrom< Src, Context, diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs index 36f9ceb0da7a6..8e69527c1862c 100644 --- a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs +++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.rs @@ -18,20 +18,20 @@ fn should_reject_repr_rust() { fn unit() { type repr_rust = [String; 0]; - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn singleton() { type repr_rust = [String; 1]; - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn duplex() { type repr_rust = [String; 2]; - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } } diff --git a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr index 109e58c4093cb..eae0c947d4253 100644 --- a/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr +++ b/src/test/ui/transmutability/arrays/should_require_well_defined_layout.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not satisfied +error[E0277]: `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:21:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()` + | ^^ `[String; 0]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom<[String; 0], assert::Context, true, true, true, true>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `[String; 0]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:22:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 0]` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 0]` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 0]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not satisfied +error[E0277]: `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:27:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()` + | ^^ `[String; 1]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom<[String; 1], assert::Context, true, true, true, true>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `[String; 1]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:28:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 1]` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 1]` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 1]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not satisfied +error[E0277]: `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:33:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()` + | ^^ `[String; 2]` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom<[String; 2], assert::Context, true, true, true, true>` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `[String; 2]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:34:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 2]` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `[String; 2]` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[String; 2]` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs index cd411a4b838e0..18e02b0d2b908 100644 --- a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs +++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.rs @@ -38,17 +38,17 @@ fn n8() { fn i_should_have_correct_length() { type Current = V0i8; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0u8; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } @@ -62,17 +62,17 @@ fn n16() { fn i_should_have_correct_length() { type Current = V0i16; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0u16; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } @@ -86,17 +86,17 @@ fn n32() { fn i_should_have_correct_length() { type Current = V0i32; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0u32; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } @@ -110,17 +110,17 @@ fn n64() { fn i_should_have_correct_length() { type Current = V0i64; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0u64; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } @@ -134,16 +134,16 @@ fn nsize() { fn i_should_have_correct_length() { type Current = V0isize; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } fn u_should_have_correct_length() { type Current = V0usize; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } } diff --git a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr index da24c6a021efe..fa2e3b89b079a 100644 --- a/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr +++ b/src/test/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `V0i8: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:41:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i8` + | ^^^^^^^ `Zst` cannot be safely transmuted into `V0i8` in the defining scope of `n8::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i8` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:43:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | ^^^^^^ `V0i8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0u8: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:49:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u8` + | ^^^^^^^ `Zst` cannot be safely transmuted into `V0u8` in the defining scope of `n8::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u8` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:51:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | ^^^^^^ `V0u8` cannot be safely transmuted into `u16` in the defining scope of `n8::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0i16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:65:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i16` + | ^^^^^^^ `u8` cannot be safely transmuted into `V0i16` in the defining scope of `n16::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:67:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^^^^ `V0i16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -88,12 +94,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:73:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u16` + | ^^^^^^^ `u8` cannot be safely transmuted into `V0u16` in the defining scope of `n16::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u16` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -103,12 +110,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:75:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^^^^ `V0u16` cannot be safely transmuted into `u32` in the defining scope of `n16::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -118,12 +126,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:89:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i32` + | ^^^^^^^ `u16` cannot be safely transmuted into `V0i32` in the defining scope of `n32::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -133,12 +142,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:91:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^^^^ `V0i32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -148,12 +158,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:97:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u32` + | ^^^^^^^ `u16` cannot be safely transmuted into `V0u32` in the defining scope of `n32::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u32` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -163,12 +174,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:99:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^^^^ `V0u32` cannot be safely transmuted into `u64` in the defining scope of `n32::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -178,12 +190,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:113:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0i64` + | ^^^^^^^ `u32` cannot be safely transmuted into `V0i64` in the defining scope of `n64::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0i64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -193,12 +206,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:115:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^^^ `V0i64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -208,12 +222,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:121:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0u64` + | ^^^^^^^ `u32` cannot be safely transmuted into `V0u64` in the defining scope of `n64::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0u64` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -223,12 +238,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:123:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^^^ `V0u64` cannot be safely transmuted into `u128` in the defining scope of `n64::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -238,12 +254,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0isize: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:137:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0isize` + | ^^^^^^^ `u8` cannot be safely transmuted into `V0isize` in the defining scope of `nsize::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0isize` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -253,12 +270,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `[usize; 2]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:139:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` + | ^^^^^^ `V0isize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -268,12 +286,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `V0usize: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:145:44 | LL | assert::is_transmutable::(); - | ^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `V0usize` + | ^^^^^^^ `u8` cannot be safely transmuted into `V0usize` in the defining scope of `nsize::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `V0usize` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | @@ -283,12 +302,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `[usize; 2]: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. --> $DIR/primitive_reprs_should_have_correct_length.rs:147:44 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` + | ^^^^^^ `V0usize` cannot be safely transmuted into `[usize; 2]` in the defining scope of `nsize::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `[usize; 2]` note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 | diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs index 24a88d6ac95cc..978a12648f03a 100644 --- a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs +++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.rs @@ -18,20 +18,20 @@ mod assert { fn should_reject_repr_rust() { fn void() { enum repr_rust {} - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn singleton() { enum repr_rust { V } - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn duplex() { enum repr_rust { A, B } - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } } diff --git a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr index 1bfbff68f06cb..3273e87c89ff4 100644 --- a/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr +++ b/src/test/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:21:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `void::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `void::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:22:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `void::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `void::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `void::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:27:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `singleton::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `singleton::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:28:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `singleton::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `singleton::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `singleton::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:33:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `duplex::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `duplex::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:34:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `duplex::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `duplex::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `duplex::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 | diff --git a/src/test/ui/transmutability/enums/should_pad_variants.rs b/src/test/ui/transmutability/enums/should_pad_variants.rs index 87951586523de..466b6c8a15b52 100644 --- a/src/test/ui/transmutability/enums/should_pad_variants.rs +++ b/src/test/ui/transmutability/enums/should_pad_variants.rs @@ -36,5 +36,5 @@ fn should_pad_variants() { struct Context; // If the implementation (incorrectly) fails to pad `Lopsided::Smol` with // an uninitialized byte, this transmutation might be (wrongly) accepted: - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/enums/should_pad_variants.stderr b/src/test/ui/transmutability/enums/should_pad_variants.stderr index b940ca077d4ad..429f7211d17a8 100644 --- a/src/test/ui/transmutability/enums/should_pad_variants.stderr +++ b/src/test/ui/transmutability/enums/should_pad_variants.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. --> $DIR/should_pad_variants.rs:39:36 | LL | assert::is_transmutable::(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_pad_variants.rs:13:14 | diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.rs b/src/test/ui/transmutability/enums/should_respect_endianness.rs index 9bab44e1d914f..67a3c4e94ba8f 100644 --- a/src/test/ui/transmutability/enums/should_respect_endianness.rs +++ b/src/test/ui/transmutability/enums/should_respect_endianness.rs @@ -29,5 +29,5 @@ mod assert { fn should_respect_endianness() { assert::is_transmutable::(); - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/enums/should_respect_endianness.stderr b/src/test/ui/transmutability/enums/should_respect_endianness.stderr index 3f3335d4a1b8f..78023cb378aca 100644 --- a/src/test/ui/transmutability/enums/should_respect_endianness.stderr +++ b/src/test/ui/transmutability/enums/should_respect_endianness.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Unexpected: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`. --> $DIR/should_respect_endianness.rs:32:36 | LL | assert::is_transmutable::(); - | ^^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Unexpected` + | ^^^^^^^^^^ `Src` cannot be safely transmuted into `Unexpected` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Unexpected` note: required by a bound in `is_transmutable` --> $DIR/should_respect_endianness.rs:15:14 | diff --git a/src/test/ui/transmutability/primitives/bool.rs b/src/test/ui/transmutability/primitives/bool.rs index 13cecd1d8b7ea..4f79bc2533708 100644 --- a/src/test/ui/transmutability/primitives/bool.rs +++ b/src/test/ui/transmutability/primitives/bool.rs @@ -19,7 +19,7 @@ mod assert { } fn contrast_with_u8() { - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted assert::is_maybe_transmutable::(); assert::is_transmutable::(); } diff --git a/src/test/ui/transmutability/primitives/bool.stderr b/src/test/ui/transmutability/primitives/bool.stderr index f05bb433ec844..dc740251c871e 100644 --- a/src/test/ui/transmutability/primitives/bool.stderr +++ b/src/test/ui/transmutability/primitives/bool.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `bool: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. --> $DIR/bool.rs:22:35 | LL | assert::is_transmutable::(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `bool` + | ^^^^ `u8` cannot be safely transmuted into `bool` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `bool` note: required by a bound in `is_transmutable` --> $DIR/bool.rs:12:14 | diff --git a/src/test/ui/transmutability/primitives/numbers.rs b/src/test/ui/transmutability/primitives/numbers.rs index 3dbdfab9686a8..a5f79065d8aad 100644 --- a/src/test/ui/transmutability/primitives/numbers.rs +++ b/src/test/ui/transmutability/primitives/numbers.rs @@ -59,70 +59,70 @@ fn should_be_bitransmutable() { } fn should_reject_extension() { - assert::is_transmutable::< i8, i16>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, u16>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, i32>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, f32>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, u32>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< i8, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< u8, i16>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, u16>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, i32>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, f32>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, u32>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< u8, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< i16, i32>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, f32>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, u32>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< i16, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< u16, i32>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, f32>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, u32>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< u16, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< i32, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< i32, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< i32, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< i32, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< i32, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< f32, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< f32, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< f32, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< f32, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< f32, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< u32, u64>(); //~ ERROR not satisfied - assert::is_transmutable::< u32, i64>(); //~ ERROR not satisfied - assert::is_transmutable::< u32, f64>(); //~ ERROR not satisfied - assert::is_transmutable::< u32, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< u32, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< u64, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< u64, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< i64, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< i64, i128>(); //~ ERROR not satisfied - - assert::is_transmutable::< f64, u128>(); //~ ERROR not satisfied - assert::is_transmutable::< f64, i128>(); //~ ERROR not satisfied + assert::is_transmutable::< i8, i16>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, u16>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, i32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, f32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, u32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i8, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< u8, i16>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, u16>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, i32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, f32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, u32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u8, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< i16, i32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, f32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, u32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i16, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< u16, i32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, f32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, u32>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u16, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< i32, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i32, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i32, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i32, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i32, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< f32, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f32, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f32, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f32, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f32, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< u32, u64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u32, i64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u32, f64>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u32, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u32, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< u64, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< u64, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< i64, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< i64, i128>(); //~ ERROR cannot be safely transmuted + + assert::is_transmutable::< f64, u128>(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::< f64, i128>(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/primitives/numbers.stderr b/src/test/ui/transmutability/primitives/numbers.stderr index 6bd3379dfd1a4..9b802a444e86a 100644 --- a/src/test/ui/transmutability/primitives/numbers.stderr +++ b/src/test/ui/transmutability/primitives/numbers.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `i16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:62:40 | LL | assert::is_transmutable::< i8, i16>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i16` + | ^^^ `i8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:63:40 | LL | assert::is_transmutable::< i8, u16>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | ^^^ `i8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:64:40 | LL | assert::is_transmutable::< i8, i32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | ^^^ `i8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:65:40 | LL | assert::is_transmutable::< i8, f32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | ^^^ `i8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:66:40 | LL | assert::is_transmutable::< i8, u32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^ `i8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:67:40 | LL | assert::is_transmutable::< i8, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `i8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -88,12 +94,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:68:40 | LL | assert::is_transmutable::< i8, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `i8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -103,12 +110,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:69:40 | LL | assert::is_transmutable::< i8, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `i8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -118,12 +126,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:70:39 | LL | assert::is_transmutable::< i8, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `i8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -133,12 +142,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:71:39 | LL | assert::is_transmutable::< i8, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `i8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -148,12 +158,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:73:40 | LL | assert::is_transmutable::< u8, i16>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i16` + | ^^^ `u8` cannot be safely transmuted into `i16` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -163,12 +174,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u16: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:74:40 | LL | assert::is_transmutable::< u8, u16>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u16` + | ^^^ `u8` cannot be safely transmuted into `u16` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u16` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -178,12 +190,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:75:40 | LL | assert::is_transmutable::< u8, i32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | ^^^ `u8` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -193,12 +206,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:76:40 | LL | assert::is_transmutable::< u8, f32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | ^^^ `u8` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -208,12 +222,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:77:40 | LL | assert::is_transmutable::< u8, u32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^ `u8` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -223,12 +238,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:78:40 | LL | assert::is_transmutable::< u8, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `u8` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -238,12 +254,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:79:40 | LL | assert::is_transmutable::< u8, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `u8` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -253,12 +270,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:80:40 | LL | assert::is_transmutable::< u8, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `u8` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -268,12 +286,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:81:39 | LL | assert::is_transmutable::< u8, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `u8` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -283,12 +302,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:82:39 | LL | assert::is_transmutable::< u8, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `u8` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -298,12 +318,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:84:40 | LL | assert::is_transmutable::< i16, i32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | ^^^ `i16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -313,12 +334,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:85:40 | LL | assert::is_transmutable::< i16, f32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | ^^^ `i16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -328,12 +350,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:86:40 | LL | assert::is_transmutable::< i16, u32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^ `i16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -343,12 +366,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:87:40 | LL | assert::is_transmutable::< i16, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `i16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -358,12 +382,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:88:40 | LL | assert::is_transmutable::< i16, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `i16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -373,12 +398,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:89:40 | LL | assert::is_transmutable::< i16, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `i16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -388,12 +414,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:90:39 | LL | assert::is_transmutable::< i16, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `i16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -403,12 +430,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:91:39 | LL | assert::is_transmutable::< i16, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `i16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -418,12 +446,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:93:40 | LL | assert::is_transmutable::< u16, i32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i32` + | ^^^ `u16` cannot be safely transmuted into `i32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -433,12 +462,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:94:40 | LL | assert::is_transmutable::< u16, f32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f32` + | ^^^ `u16` cannot be safely transmuted into `f32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -448,12 +478,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u32: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:95:40 | LL | assert::is_transmutable::< u16, u32>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u32` + | ^^^ `u16` cannot be safely transmuted into `u32` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u32` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -463,12 +494,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:96:40 | LL | assert::is_transmutable::< u16, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `u16` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -478,12 +510,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:97:40 | LL | assert::is_transmutable::< u16, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `u16` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -493,12 +526,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:98:40 | LL | assert::is_transmutable::< u16, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `u16` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -508,12 +542,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:99:39 | LL | assert::is_transmutable::< u16, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `u16` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -523,12 +558,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:100:39 | LL | assert::is_transmutable::< u16, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `u16` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -538,12 +574,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:102:40 | LL | assert::is_transmutable::< i32, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `i32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -553,12 +590,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:103:40 | LL | assert::is_transmutable::< i32, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `i32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -568,12 +606,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:104:40 | LL | assert::is_transmutable::< i32, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `i32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -583,12 +622,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:105:39 | LL | assert::is_transmutable::< i32, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `i32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -598,12 +638,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:106:39 | LL | assert::is_transmutable::< i32, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `i32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -613,12 +654,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:108:40 | LL | assert::is_transmutable::< f32, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `f32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -628,12 +670,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:109:40 | LL | assert::is_transmutable::< f32, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `f32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -643,12 +686,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:110:40 | LL | assert::is_transmutable::< f32, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `f32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -658,12 +702,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:111:39 | LL | assert::is_transmutable::< f32, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `f32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -673,12 +718,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:112:39 | LL | assert::is_transmutable::< f32, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `f32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -688,12 +734,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:114:40 | LL | assert::is_transmutable::< u32, u64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u64` + | ^^^ `u32` cannot be safely transmuted into `u64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -703,12 +750,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:115:40 | LL | assert::is_transmutable::< u32, i64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i64` + | ^^^ `u32` cannot be safely transmuted into `i64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -718,12 +766,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `f64: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:116:40 | LL | assert::is_transmutable::< u32, f64>(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `f64` + | ^^^ `u32` cannot be safely transmuted into `f64` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `f64` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -733,12 +782,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:117:39 | LL | assert::is_transmutable::< u32, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `u32` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -748,12 +798,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:118:39 | LL | assert::is_transmutable::< u32, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `u32` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -763,12 +814,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:120:39 | LL | assert::is_transmutable::< u64, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `u64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -778,12 +830,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:121:39 | LL | assert::is_transmutable::< u64, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `u64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -793,12 +846,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:123:39 | LL | assert::is_transmutable::< i64, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `i64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -808,12 +862,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:124:39 | LL | assert::is_transmutable::< i64, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `i64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -823,12 +878,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `u128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:126:39 | LL | assert::is_transmutable::< f64, u128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `u128` + | ^^^^ `f64` cannot be safely transmuted into `u128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `u128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | @@ -838,12 +894,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `i128: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. --> $DIR/numbers.rs:127:39 | LL | assert::is_transmutable::< f64, i128>(); - | ^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `i128` + | ^^^^ `f64` cannot be safely transmuted into `i128` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `i128` note: required by a bound in `is_transmutable` --> $DIR/numbers.rs:12:14 | diff --git a/src/test/ui/transmutability/primitives/unit.rs b/src/test/ui/transmutability/primitives/unit.rs index a9c618188bf41..86d4740300dff 100644 --- a/src/test/ui/transmutability/primitives/unit.rs +++ b/src/test/ui/transmutability/primitives/unit.rs @@ -20,5 +20,5 @@ fn should_have_correct_size() { struct Context; assert::is_transmutable::<(), Zst, Context>(); assert::is_transmutable::(); - assert::is_transmutable::<(), u8, Context>(); //~ ERROR not satisfied + assert::is_transmutable::<(), u8, Context>(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/primitives/unit.stderr b/src/test/ui/transmutability/primitives/unit.stderr index f602612feea93..cf27c0d17b337 100644 --- a/src/test/ui/transmutability/primitives/unit.stderr +++ b/src/test/ui/transmutability/primitives/unit.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `u8: BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not satisfied +error[E0277]: `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. --> $DIR/unit.rs:23:35 | LL | assert::is_transmutable::<(), u8, Context>(); - | ^^ the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8` + | ^^ `()` cannot be safely transmuted into `u8` in the defining scope of `should_have_correct_size::Context`. | + = help: the trait `BikeshedIntrinsicFrom<(), should_have_correct_size::Context, true, true, true, true>` is not implemented for `u8` note: required by a bound in `is_transmutable` --> $DIR/unit.rs:12:14 | diff --git a/src/test/ui/transmutability/references.rs b/src/test/ui/transmutability/references.rs index c7d24aaf1caa8..c6fd4c43e95c0 100644 --- a/src/test/ui/transmutability/references.rs +++ b/src/test/ui/transmutability/references.rs @@ -16,5 +16,5 @@ mod assert { fn not_yet_implemented() { #[repr(C)] struct Unit; - assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR not satisfied + assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/references.stderr b/src/test/ui/transmutability/references.stderr index 7199e169e2977..17ffcf64177e3 100644 --- a/src/test/ui/transmutability/references.stderr +++ b/src/test/ui/transmutability/references.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `&'static Unit: BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not satisfied +error[E0277]: `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. --> $DIR/references.rs:19:52 | LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); - | ^^^^^^^^^^^^^ the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit` + | ^^^^^^^^^^^^^ `&'static Unit` cannot be safely transmuted into `&'static Unit` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom<&'static Unit, assert::Context, true, true, true, true>` is not implemented for `&'static Unit` note: required by a bound in `is_maybe_transmutable` --> $DIR/references.rs:13:14 | diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs index 63419aceb6ce9..556be989dbc25 100644 --- a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs +++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.rs @@ -18,39 +18,39 @@ fn should_reject_repr_rust() { fn unit() { struct repr_rust; - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn tuple() { struct repr_rust(); - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn braces() { struct repr_rust{} - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn aligned() { #[repr(align(1))] struct repr_rust{} - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn packed() { #[repr(packed)] struct repr_rust{} - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn nested() { struct repr_rust; #[repr(C)] struct repr_c(repr_rust); - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } } diff --git a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr index ab582dd668807..07355f7c2ad26 100644 --- a/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr +++ b/src/test/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:21:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `should_reject_repr_rust::unit::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `should_reject_repr_rust::unit::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:22:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::unit::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::unit::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::unit::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -28,12 +30,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:27:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `should_reject_repr_rust::tuple::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -43,12 +46,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `should_reject_repr_rust::tuple::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:28:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::tuple::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::tuple::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::tuple::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -58,12 +62,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:33:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `should_reject_repr_rust::braces::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -73,12 +78,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `should_reject_repr_rust::braces::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:34:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::braces::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::braces::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::braces::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -88,12 +94,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:39:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `aligned::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -103,12 +110,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `aligned::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:40:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `aligned::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `aligned::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `aligned::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -118,12 +126,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:45:52 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `packed::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -133,12 +142,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `packed::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:46:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `packed::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `packed::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `packed::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -148,12 +158,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:52:49 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `nested::repr_c` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -163,12 +174,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `nested::repr_c: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:53:47 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `nested::repr_c` + | ^^^^^^ `u128` cannot be safely transmuted into `nested::repr_c` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `nested::repr_c` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs index d6e28d7f0db3f..cec8e389f444e 100644 --- a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs +++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.rs @@ -20,8 +20,8 @@ fn should_reject_repr_rust() a: u8 } - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } fn should_accept_repr_C() diff --git a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr index c24193f9a6d77..2ed01b159ab0b 100644 --- a/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr +++ b/src/test/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `(): BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:23:48 | LL | assert::is_maybe_transmutable::(); - | ^^ the trait `BikeshedIntrinsicFrom` is not implemented for `()` + | ^^ `should_reject_repr_rust::repr_rust` cannot be safely transmuted into `()` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `()` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `should_reject_repr_rust::repr_rust: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`. --> $DIR/should_require_well_defined_layout.rs:24:43 | LL | assert::is_maybe_transmutable::(); - | ^^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::repr_rust` + | ^^^^^^^^^ `u128` cannot be safely transmuted into `should_reject_repr_rust::repr_rust` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `should_reject_repr_rust::repr_rust` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/should_pad_variants.rs b/src/test/ui/transmutability/unions/should_pad_variants.rs index d4126693f9284..c4757900f9c3e 100644 --- a/src/test/ui/transmutability/unions/should_pad_variants.rs +++ b/src/test/ui/transmutability/unions/should_pad_variants.rs @@ -36,5 +36,5 @@ fn should_pad_variants() { struct Context; // If the implementation (incorrectly) fails to pad `Lopsided::smol` with // an uninitialized byte, this transmutation might be (wrongly) accepted: - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/unions/should_pad_variants.stderr b/src/test/ui/transmutability/unions/should_pad_variants.stderr index b940ca077d4ad..429f7211d17a8 100644 --- a/src/test/ui/transmutability/unions/should_pad_variants.stderr +++ b/src/test/ui/transmutability/unions/should_pad_variants.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. --> $DIR/should_pad_variants.rs:39:36 | LL | assert::is_transmutable::(); - | ^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `should_pad_variants::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_pad_variants.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.rs b/src/test/ui/transmutability/unions/should_reject_contraction.rs index 34b31595193dd..e8138d0e046c5 100644 --- a/src/test/ui/transmutability/unions/should_reject_contraction.rs +++ b/src/test/ui/transmutability/unions/should_reject_contraction.rs @@ -32,5 +32,5 @@ fn test() { c: Ox01, } - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/unions/should_reject_contraction.stderr b/src/test/ui/transmutability/unions/should_reject_contraction.stderr index 1465c3df22837..99f5890081728 100644 --- a/src/test/ui/transmutability/unions/should_reject_contraction.stderr +++ b/src/test/ui/transmutability/unions/should_reject_contraction.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Subset: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`. --> $DIR/should_reject_contraction.rs:35:41 | LL | assert::is_transmutable::(); - | ^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Subset` + | ^^^^^^ `Superset` cannot be safely transmuted into `Subset` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Subset` note: required by a bound in `is_transmutable` --> $DIR/should_reject_contraction.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.rs b/src/test/ui/transmutability/unions/should_reject_disjoint.rs index b4b06c571315e..16160e29a5469 100644 --- a/src/test/ui/transmutability/unions/should_reject_disjoint.rs +++ b/src/test/ui/transmutability/unions/should_reject_disjoint.rs @@ -31,6 +31,6 @@ fn test() { c: Ox01, } - assert::is_maybe_transmutable::(); //~ ERROR not satisfied - assert::is_maybe_transmutable::(); //~ ERROR not satisfied + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/unions/should_reject_disjoint.stderr b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr index a140f0c506b3b..5714e2bf320c5 100644 --- a/src/test/ui/transmutability/unions/should_reject_disjoint.stderr +++ b/src/test/ui/transmutability/unions/should_reject_disjoint.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `B: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. --> $DIR/should_reject_disjoint.rs:34:40 | LL | assert::is_maybe_transmutable::(); - | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `B` + | ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `B` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_reject_disjoint.rs:13:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_maybe_transmutable` -error[E0277]: the trait bound `A: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. --> $DIR/should_reject_disjoint.rs:35:40 | LL | assert::is_maybe_transmutable::(); - | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `A` + | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `A` note: required by a bound in `is_maybe_transmutable` --> $DIR/should_reject_disjoint.rs:13:14 | diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.rs b/src/test/ui/transmutability/unions/should_reject_intersecting.rs index 1ed7d2a0bd9a0..58e399fb96225 100644 --- a/src/test/ui/transmutability/unions/should_reject_intersecting.rs +++ b/src/test/ui/transmutability/unions/should_reject_intersecting.rs @@ -33,6 +33,6 @@ fn test() { b: OxFF, } - assert::is_transmutable::(); //~ ERROR not satisfied - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/unions/should_reject_intersecting.stderr b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr index 43e642b569152..92689a5f828b4 100644 --- a/src/test/ui/transmutability/unions/should_reject_intersecting.stderr +++ b/src/test/ui/transmutability/unions/should_reject_intersecting.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `B: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. --> $DIR/should_reject_intersecting.rs:36:34 | LL | assert::is_transmutable::(); - | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `B` + | ^ `A` cannot be safely transmuted into `B` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `B` note: required by a bound in `is_transmutable` --> $DIR/should_reject_intersecting.rs:14:14 | @@ -13,12 +14,13 @@ LL | where LL | Dst: BikeshedIntrinsicFrom | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `is_transmutable` -error[E0277]: the trait bound `A: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. --> $DIR/should_reject_intersecting.rs:37:34 | LL | assert::is_transmutable::(); - | ^ the trait `BikeshedIntrinsicFrom` is not implemented for `A` + | ^ `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `A` note: required by a bound in `is_transmutable` --> $DIR/should_reject_intersecting.rs:14:14 | diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs index 04cb6885887f4..fcf3f3a527805 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.rs @@ -33,5 +33,5 @@ mod dst { fn test() { struct Context; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr index 4dfbfaeafb648..85124019e7f03 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_field.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. --> $DIR/should_reject_if_dst_has_private_field.rs:36:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_private_field.rs:13:14 | diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs index 768e7bc559efe..566b56467124f 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.rs @@ -34,5 +34,5 @@ mod dst { fn test() { struct Context; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr index ed834a1bd2587..0be564d93e2d8 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_private_variant.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. --> $DIR/should_reject_if_dst_has_private_variant.rs:37:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_private_variant.rs:13:14 | diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs index c44fed4cce392..35fff5966c85b 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_tricky_unreachable_field.rs @@ -1,7 +1,7 @@ // check-pass //! NOTE: This test documents a known-bug in the implementation of the //! transmutability trait. Once fixed, the above "check-pass" header should be -//! removed, and an "ERROR not satisfied" annotation should be added at the end +//! removed, and an "ERROR cannot be safely transmuted" annotation should be added at the end //! of the line starting with `assert::is_transmutable`. //! //! Unless visibility is assumed, a transmutation should be rejected if the diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs index dbef149bacc99..42799d803b028 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.rs @@ -35,5 +35,5 @@ mod dst { fn test() { struct Context; - assert::is_transmutable::(); //~ ERROR not satisfied + assert::is_transmutable::(); //~ ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr index 3029d6ab8eeee..95c68d452010b 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_field.stderr @@ -1,9 +1,10 @@ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. --> $DIR/should_reject_if_dst_has_unreachable_field.rs:38:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_unreachable_field.rs:15:14 | diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs index c5947eceb656e..e13b32b30d964 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.rs @@ -38,5 +38,5 @@ fn test() { struct Context; assert::is_transmutable::(); //~^ ERROR `Dst` is private - //~| ERROR not satisfied + //~| ERROR cannot be safely transmuted } diff --git a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr index 2fd3889032149..3391839e39e02 100644 --- a/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr +++ b/src/test/ui/transmutability/visibility/should_reject_if_dst_has_unreachable_ty.stderr @@ -10,12 +10,13 @@ note: the struct `Dst` is defined here LL | #[repr(C)] pub(self) struct Dst { | ^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `Dst: BikeshedIntrinsicFrom` is not satisfied +error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:39:41 | LL | assert::is_transmutable::(); - | ^^^^^^^^ the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` + | ^^^^^^^^ `Src` cannot be safely transmuted into `Dst` in the defining scope of `test::Context`. | + = help: the trait `BikeshedIntrinsicFrom` is not implemented for `Dst` note: required by a bound in `is_transmutable` --> $DIR/should_reject_if_dst_has_unreachable_ty.rs:15:14 | From b78c3daad0f0b7490988f4957bab7bc53049b3bb Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 18:18:36 +0000 Subject: [PATCH 09/13] safe transmute: reference tracking issue ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925266769 --- library/core/src/mem/mod.rs | 2 +- library/core/src/mem/transmutability.rs | 4 ++-- .../feature-missing.rs | 3 +++ .../feature-missing.stderr | 12 +++++++++++- 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index add65a3be5042..b1cf5bd92d252 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -28,7 +28,7 @@ mod valid_align; pub(crate) use valid_align::ValidAlign; mod transmutability; -#[unstable(feature = "transmutability", issue = "none")] +#[unstable(feature = "transmutability", issue = "99571")] pub use transmutability::{Assume, BikeshedIntrinsicFrom}; #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 820a7582b113b..b59a5b89d839f 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -3,7 +3,7 @@ /// 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")] +#[unstable(feature = "transmutability", issue = "99571")] #[cfg_attr(not(bootstrap), lang = "transmute_trait")] #[rustc_on_unimplemented( message = "`{Src}` cannot be safely transmuted into `{Self}` in the defining scope of `{Context}`.", @@ -22,7 +22,7 @@ pub unsafe trait BikeshedIntrinsicFrom< } /// What transmutation safety conditions shall the compiler assume that *you* are checking? -#[unstable(feature = "transmutability", issue = "none")] +#[unstable(feature = "transmutability", issue = "99571")] #[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct Assume { /// When `true`, the compiler assumes that *you* are ensuring (either dynamically or statically) that diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs index 12018f3161a75..30c381745d0f9 100644 --- a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs +++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.rs @@ -4,3 +4,6 @@ use std::mem::BikeshedIntrinsicFrom; //~^ ERROR use of unstable library feature 'transmutability' [E0658] + +use std::mem::Assume; +//~^ ERROR use of unstable library feature 'transmutability' [E0658] diff --git a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr index 4b51850634af1..ba8093f861465 100644 --- a/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr +++ b/src/test/ui/transmutability/malformed-program-gracefulness/feature-missing.stderr @@ -4,8 +4,18 @@ error[E0658]: use of unstable library feature 'transmutability' LL | use std::mem::BikeshedIntrinsicFrom; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | + = note: see issue #99571 for more information = help: add `#![feature(transmutability)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: use of unstable library feature 'transmutability' + --> $DIR/feature-missing.rs:8:5 + | +LL | use std::mem::Assume; + | ^^^^^^^^^^^^^^^^ + | + = note: see issue #99571 for more information + = help: add `#![feature(transmutability)]` to the crate attributes to enable + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 226860304603f63440e9d097cd09dce45160bfbb Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 18:22:04 +0000 Subject: [PATCH 10/13] safe transmute: tweak `Nfa::union` to consume params by value ref: https://github.com/rust-lang/rust/pull/92268#discussion_r925274516 --- compiler/rustc_transmute/src/layout/nfa.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs index 817e426ba274e..3b2548e7aedf7 100644 --- a/compiler/rustc_transmute/src/layout/nfa.rs +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -92,7 +92,7 @@ where let mut alts = alts.into_iter().map(Self::from_tree); let mut nfa = alts.next().ok_or(Uninhabited)??; for alt in alts { - nfa = nfa.union(&alt?); + nfa = nfa.union(alt?); } nfa } @@ -136,7 +136,7 @@ where } /// Compute the union of two `Nfa`s. - pub(crate) fn union(&self, other: &Self) -> Self { + pub(crate) fn union(self, other: Self) -> Self { let start = self.start; let accepting = self.accepting; From aee5f31c682664bd2e42be6b3fefdd3dd8a390e8 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 21 Jul 2022 21:57:51 +0000 Subject: [PATCH 11/13] safe transmute: lowercase tracing levels ref: https://github.com/rust-lang/rust/pull/92268#discussion_r927095154 --- compiler/rustc_transmute/src/layout/dfa.rs | 2 +- compiler/rustc_transmute/src/maybe_transmutable/mod.rs | 8 ++++---- .../src/maybe_transmutable/query_context.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index f2742dc8ee5ad..09a60cf6a626a 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -103,7 +103,7 @@ where Self { transitions, start, accepting } } - #[instrument(level = "DEBUG")] + #[instrument(level = "debug")] #[cfg_attr(feature = "rustc", allow(rustc::potential_query_instability))] pub(crate) fn from_nfa(nfa: Nfa) -> Self { let Nfa { transitions: nfa_transitions, start: nfa_start, accepting: nfa_accepting } = nfa; diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 8fb85527a0f0a..076d922d1b72b 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -64,7 +64,7 @@ mod rustc { impl<'tcx> MaybeTransmutableQuery, TyCtxt<'tcx>> { /// This method begins by converting `src` and `dst` from `Ty`s to `Tree`s, /// then computes an answer using those trees. - #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub fn answer(self) -> Answer< as QueryContext>::Ref> { let query_or_answer = self.map_layouts(|src, dst, scope, &context| { // Convert `src` and `dst` from their rustc representations, to `Tree`-based @@ -103,7 +103,7 @@ where /// This method begins by de-def'ing `src` and `dst`, and prunes private paths from `dst`, /// then converts `src` and `dst` to `Nfa`s, and computes an answer using those NFAs. #[inline(always)] - #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { let assume_visibility = self.assume.visibility; let query_or_answer = self.map_layouts(|src, dst, scope, context| { @@ -152,7 +152,7 @@ where /// /// This method converts `src` and `dst` to DFAs, then computes an answer using those DFAs. #[inline(always)] - #[instrument(level = "DEBUG", skip(self), fields(src = ?self.src, dst = ?self.dst))] + #[instrument(level = "debug", skip(self), fields(src = ?self.src, dst = ?self.dst))] pub(crate) fn answer(self) -> Answer<::Ref> { let query_or_answer = self .map_layouts(|src, dst, scope, context| Ok((Dfa::from_nfa(src), Dfa::from_nfa(dst)))); @@ -192,7 +192,7 @@ where } #[inline(always)] - #[instrument(level = "DEBUG", skip(self))] + #[instrument(level = "debug", skip(self))] fn answer_memo( &self, cache: &mut Map<(dfa::State, dfa::State), Answer<::Ref>>, diff --git a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs index 1a66b6cfe00ef..9c2cf4c9a9238 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/query_context.rs @@ -52,7 +52,7 @@ mod rustc { type Scope = Ty<'tcx>; - #[instrument(level = "DEBUG", skip(self))] + #[instrument(level = "debug", skip(self))] fn is_accessible_from(&self, def: Self::Def, scope: Self::Scope) -> bool { use layout::rustc::Def; use rustc_middle::ty; From e8a1925b64197576b83dfba8b75a80ca705edbdd Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Thu, 28 Jul 2022 13:47:11 +0000 Subject: [PATCH 12/13] safe transmute: use `AtomicU32` `State` ids to appease mips ...instead of `AtomicU64`, which is unavailable. ref: https://github.com/rust-lang/rust/pull/92268#issuecomment-1197797990 --- compiler/rustc_transmute/src/layout/dfa.rs | 6 +++--- compiler/rustc_transmute/src/layout/nfa.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/dfa.rs b/compiler/rustc_transmute/src/layout/dfa.rs index 09a60cf6a626a..b60ea6e7a24f2 100644 --- a/compiler/rustc_transmute/src/layout/dfa.rs +++ b/compiler/rustc_transmute/src/layout/dfa.rs @@ -1,7 +1,7 @@ use super::{nfa, Byte, Nfa, Ref}; use crate::Map; use std::fmt; -use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering}; #[derive(PartialEq, Clone, Debug)] pub(crate) struct Dfa @@ -49,7 +49,7 @@ where /// The states in a `Nfa` represent byte offsets. #[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] -pub(crate) struct State(u64); +pub(crate) struct State(u32); #[derive(Hash, Eq, PartialEq, Clone, Copy)] pub(crate) enum Transition @@ -166,7 +166,7 @@ where impl State { pub(crate) fn new() -> Self { - static COUNTER: AtomicU64 = AtomicU64::new(0); + static COUNTER: AtomicU32 = AtomicU32::new(0); Self(COUNTER.fetch_add(1, Ordering::SeqCst)) } } diff --git a/compiler/rustc_transmute/src/layout/nfa.rs b/compiler/rustc_transmute/src/layout/nfa.rs index 3b2548e7aedf7..f25e3c1fd8a30 100644 --- a/compiler/rustc_transmute/src/layout/nfa.rs +++ b/compiler/rustc_transmute/src/layout/nfa.rs @@ -1,7 +1,7 @@ use super::{Byte, Ref, Tree, Uninhabited}; use crate::{Map, Set}; use std::fmt; -use std::sync::atomic::{AtomicU64, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering}; /// A non-deterministic finite automaton (NFA) that represents the layout of a type. /// The transmutability of two given types is computed by comparing their `Nfa`s. @@ -17,7 +17,7 @@ where /// The states in a `Nfa` represent byte offsets. #[derive(Hash, Eq, PartialEq, PartialOrd, Ord, Copy, Clone)] -pub(crate) struct State(u64); +pub(crate) struct State(u32); /// The transitions between states in a `Nfa` reflect bit validity. #[derive(Hash, Eq, PartialEq, Clone, Copy)] @@ -173,7 +173,7 @@ where impl State { pub(crate) fn new() -> Self { - static COUNTER: AtomicU64 = AtomicU64::new(0); + static COUNTER: AtomicU32 = AtomicU32::new(0); Self(COUNTER.fetch_add(1, Ordering::SeqCst)) } } From 965ffb0b5cf3372900ce473f244ec33270058888 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Tue, 2 Aug 2022 14:44:23 +0000 Subject: [PATCH 13/13] safe transmute: fix broken intradoc link --- compiler/rustc_transmute/src/layout/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index cbf92bdacd6f0..07035ebdfb167 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -42,7 +42,7 @@ pub(crate) mod rustc { use rustc_middle::ty::Region; use rustc_middle::ty::Ty; - /// A reference in the layout [`Nfa`]. + /// A reference in the layout. #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] pub struct Ref<'tcx> { lifetime: Region<'tcx>, @@ -58,7 +58,7 @@ pub(crate) mod rustc { } } - /// A visibility node in the layout [`Nfa`]. + /// A visibility node in the layout. #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] pub enum Def<'tcx> { Adt(ty::AdtDef<'tcx>),