From 8f1cec8d8472c3ffacedd4783c64182a407c72df Mon Sep 17 00:00:00 2001 From: Bryan Garza <1396101+bryangarza@users.noreply.github.com> Date: Fri, 21 Apr 2023 16:49:36 -0700 Subject: [PATCH] Safe Transmute: Enable handling references, including recursive types This patch enables support for references in Safe Transmute, by generating nested obligations during trait selection. Specifically, when we call `confirm_transmutability_candidate(...)`, we now recursively traverse the `rustc_transmute::Answer` tree and create obligations for all the `Answer` variants, some of which include multiple nested `Answer`s. Also, to handle recursive types, enable support for coinduction for the Safe Transmute trait (`BikeshedIntrinsicFrom`) by adding the `#[rustc_coinduction]` annotation. Also fix some small logic issues when reducing the `or` and `and` combinations in `rustc_transmute`, so that we don't end up with additional redundant `Answer`s in the tree. Co-authored-by: Jack Wrenn <jack@wrenn.fyi> --- .../src/traits/error_reporting/mod.rs | 10 +- .../src/traits/select/confirmation.rs | 61 ++++++- compiler/rustc_transmute/src/layout/mod.rs | 37 ++-- compiler/rustc_transmute/src/layout/tree.rs | 11 ++ compiler/rustc_transmute/src/lib.rs | 11 +- .../src/maybe_transmutable/mod.rs | 170 ++++++++++++++---- library/core/src/mem/transmutability.rs | 1 + .../should_require_well_defined_layout.stderr | 6 +- ...ve_reprs_should_have_correct_length.stderr | 20 +-- .../should_require_well_defined_layout.stderr | 6 +- .../enums/should_pad_variants.stderr | 2 +- .../recursive-wrapper-types-bit-compatible.rs | 27 +++ ...ursive-wrapper-types-bit-compatible.stderr | 25 +++ ...ecursive-wrapper-types-bit-incompatible.rs | 25 +++ ...sive-wrapper-types-bit-incompatible.stderr | 25 +++ .../references/recursive-wrapper-types.rs | 26 +++ .../u8-to-unit.rs} | 12 +- .../u8-to-unit.stderr} | 10 +- .../references/unit-to-itself.rs | 24 +++ .../transmutability/references/unit-to-u8.rs | 24 +++ .../unit-to-u8.stderr} | 10 +- tests/ui/transmutability/region-infer.stderr | 2 +- .../should_require_well_defined_layout.stderr | 12 +- .../should_require_well_defined_layout.stderr | 2 +- .../unions/should_pad_variants.stderr | 2 +- .../ui/transmute/transmute-padding-ice.stderr | 2 +- 26 files changed, 460 insertions(+), 103 deletions(-) create mode 100644 tests/ui/transmutability/references/recursive-wrapper-types-bit-compatible.rs create mode 100644 tests/ui/transmutability/references/recursive-wrapper-types-bit-compatible.stderr create mode 100644 tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.rs create mode 100644 tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.stderr create mode 100644 tests/ui/transmutability/references/recursive-wrapper-types.rs rename tests/ui/transmutability/{references.rs => references/u8-to-unit.rs} (55%) rename tests/ui/transmutability/{references.next.stderr => references/u8-to-unit.stderr} (63%) create mode 100644 tests/ui/transmutability/references/unit-to-itself.rs create mode 100644 tests/ui/transmutability/references/unit-to-u8.rs rename tests/ui/transmutability/{references.current.stderr => references/unit-to-u8.stderr} (76%) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index dc43a3d154a..7e132e0ab60 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -2783,6 +2783,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { rustc_transmute::Reason::DstIsTooBig => { format!("The size of `{src}` is smaller than the size of `{dst}`") } + rustc_transmute::Reason::DstHasStricterAlignment => { + format!( + "The alignment of `{src}` should be stricter than that of `{dst}`, but it is not" + ) + } + rustc_transmute::Reason::DstIsMoreUnique => { + format!("`{src}` is a shared reference, but `{dst}` is a unique reference") + } }; (custom_err_msg, Some(reason_msg)) } @@ -2791,7 +2799,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { span, "Inconsistent rustc_transmute::is_transmutable(...) result, got Yes", ), - _ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"), + other => span_bug!(span, "Unsupported rustc_transmute::Answer variant: `{other:?}`"), } } diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 0d9f55d4c2e..9b28873f709 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -13,7 +13,7 @@ use rustc_infer::infer::{DefineOpaqueTypes, InferOk}; use rustc_middle::traits::SelectionOutputTypeParameterMismatch; use rustc_middle::ty::{ self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate, - TraitRef, Ty, TyCtxt, TypeVisitableExt, + TraitPredicate, TraitRef, Ty, TyCtxt, TypeVisitableExt, }; use rustc_session::config::TraitSolver; use rustc_span::def_id::DefId; @@ -279,10 +279,61 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSourceBuiltinData { nested: obligations } } + #[instrument(skip(self))] fn confirm_transmutability_candidate( &mut self, obligation: &TraitObligation<'tcx>, ) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + fn flatten_answer_tree<'tcx>( + tcx: TyCtxt<'tcx>, + obligation: &TraitObligation<'tcx>, + predicate: TraitPredicate<'tcx>, + answer: rustc_transmute::Answer<rustc_transmute::layout::rustc::Ref<'tcx>>, + ) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> { + match answer { + rustc_transmute::Answer::Yes => Ok(vec![]), + rustc_transmute::Answer::No(_) => Err(Unimplemented), + // FIXME(bryangarza): Add separate `IfAny` case, instead of treating as `IfAll` + rustc_transmute::Answer::IfAll(answers) + | rustc_transmute::Answer::IfAny(answers) => { + let mut nested = vec![]; + for flattened in answers + .into_iter() + .map(|answer| flatten_answer_tree(tcx, obligation, predicate, answer)) + { + nested.extend(flattened?); + } + Ok(nested) + } + rustc_transmute::Answer::IfTransmutable { src, dst } => { + let trait_def_id = obligation.predicate.def_id(); + let scope = predicate.trait_ref.substs.type_at(2); + let assume_const = predicate.trait_ref.substs.const_at(3); + let make_obl = |from_ty, to_ty| { + let trait_ref1 = tcx.mk_trait_ref( + trait_def_id, + [ + ty::GenericArg::from(to_ty), + ty::GenericArg::from(from_ty), + ty::GenericArg::from(scope), + ty::GenericArg::from(assume_const), + ], + ); + Obligation::with_depth( + tcx, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.param_env, + trait_ref1, + ) + }; + + // // FIXME(bryangarza): Check src.mutability or dst.mutability to know whether dst -> src obligation is needed + Ok(vec![make_obl(src.ty, dst.ty), make_obl(dst.ty, src.ty)]) + } + } + } + debug!(?obligation, "confirm_transmutability_candidate"); // We erase regions here because transmutability calls layout queries, @@ -312,10 +363,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { assume, ); - match maybe_transmutable { - rustc_transmute::Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }), - _ => Err(Unimplemented), - } + info!(?maybe_transmutable); + let nested = flatten_answer_tree(self.tcx(), obligation, predicate, maybe_transmutable)?; + info!(?nested); + Ok(ImplSourceBuiltinData { nested }) } /// This handles the case where an `auto trait Foo` impl is being used. diff --git a/compiler/rustc_transmute/src/layout/mod.rs b/compiler/rustc_transmute/src/layout/mod.rs index f8d05bc89d2..b318447e581 100644 --- a/compiler/rustc_transmute/src/layout/mod.rs +++ b/compiler/rustc_transmute/src/layout/mod.rs @@ -30,33 +30,46 @@ impl fmt::Debug for Byte { } pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone {} -pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone {} +pub trait Ref: Debug + Hash + Eq + PartialEq + Copy + Clone { + fn min_align(&self) -> usize { + 1 + } + + fn is_mutable(&self) -> bool { + false + } +} impl Def for ! {} impl Ref for ! {} #[cfg(feature = "rustc")] -pub(crate) mod rustc { +pub mod rustc { use rustc_middle::mir::Mutability; - use rustc_middle::ty; - use rustc_middle::ty::Region; - use rustc_middle::ty::Ty; + use rustc_middle::ty::{self, Ty}; /// A reference in the layout. #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)] pub struct Ref<'tcx> { - lifetime: Region<'tcx>, - ty: Ty<'tcx>, - mutability: Mutability, + pub lifetime: ty::Region<'tcx>, + pub ty: Ty<'tcx>, + pub mutability: Mutability, + pub align: usize, } - impl<'tcx> super::Ref for Ref<'tcx> {} + impl<'tcx> super::Ref for Ref<'tcx> { + fn min_align(&self) -> usize { + self.align + } - impl<'tcx> Ref<'tcx> { - pub fn min_align(&self) -> usize { - todo!() + fn is_mutable(&self) -> bool { + match self.mutability { + Mutability::Mut => true, + Mutability::Not => false, + } } } + impl<'tcx> Ref<'tcx> {} /// A visibility node in the layout. #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index a6d88b1342a..ed9309b015d 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -365,6 +365,17 @@ pub(crate) mod rustc { } })) } + + ty::Ref(lifetime, ty, mutability) => { + let align = layout_of(tcx, *ty)?.align(); + Ok(Tree::Ref(Ref { + lifetime: *lifetime, + ty: *ty, + mutability: *mutability, + align, + })) + } + _ => Err(Err::Unspecified), } } diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 77c0526e3aa..c4a99d9eb89 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -8,7 +8,7 @@ extern crate tracing; pub(crate) use rustc_data_structures::fx::{FxIndexMap as Map, FxIndexSet as Set}; -pub(crate) mod layout; +pub mod layout; pub(crate) mod maybe_transmutable; #[derive(Default)] @@ -21,10 +21,7 @@ pub struct Assume { /// The type encodes answers to the question: "Are these types transmutable?" #[derive(Debug, Hash, Eq, PartialEq, PartialOrd, Ord, Clone)] -pub enum Answer<R> -where - R: layout::Ref, -{ +pub enum Answer<R> { /// `Src` is transmutable into `Dst`. Yes, @@ -54,6 +51,10 @@ pub enum Reason { DstIsPrivate, /// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized. DstIsTooBig, + /// Src should have a stricter alignment than Dst, but it does not. + DstHasStricterAlignment, + /// Can't go from shared pointer to unique pointer + DstIsMoreUnique, } #[cfg(feature = "rustc")] diff --git a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs index 2e2fb90e71c..d1077488c79 100644 --- a/compiler/rustc_transmute/src/maybe_transmutable/mod.rs +++ b/compiler/rustc_transmute/src/maybe_transmutable/mod.rs @@ -1,13 +1,13 @@ -use crate::Map; -use crate::{Answer, Reason}; - +pub(crate) mod query_context; #[cfg(test)] mod tests; -mod query_context; -use query_context::QueryContext; +use crate::{ + layout::{self, dfa, Byte, Dfa, Nfa, Ref, Tree, Uninhabited}, + maybe_transmutable::query_context::QueryContext, + Answer, Map, Reason, +}; -use crate::layout::{self, dfa, Byte, Dfa, Nfa, Tree, Uninhabited}; pub(crate) struct MaybeTransmutableQuery<L, C> where C: QueryContext, @@ -53,6 +53,7 @@ where } } +// FIXME: Nix this cfg, so we can write unit tests independently of rustc #[cfg(feature = "rustc")] mod rustc { use super::*; @@ -77,12 +78,11 @@ mod rustc { match (src, dst) { // Answer `Yes` here, because 'unknown layout' and type errors will already // be reported by rustc. No need to spam the user with more errors. - (Err(Err::TypeError(_)), _) => Err(Answer::Yes), - (_, Err(Err::TypeError(_))) => Err(Answer::Yes), - (Err(Err::Unknown), _) => Err(Answer::Yes), - (_, Err(Err::Unknown)) => Err(Answer::Yes), - (Err(Err::Unspecified), _) => Err(Answer::No(Reason::SrcIsUnspecified)), - (_, Err(Err::Unspecified)) => Err(Answer::No(Reason::DstIsUnspecified)), + (Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => Err(Answer::Yes), + (Err(Err::Unknown), _) | (_, Err(Err::Unknown)) => Err(Answer::Yes), + (Err(Err::Unspecified), _) | (_, Err(Err::Unspecified)) => { + Err(Answer::No(Reason::SrcIsUnspecified)) + } (Ok(src), Ok(dst)) => Ok((src, dst)), } }); @@ -214,34 +214,99 @@ where Answer::No(Reason::DstIsTooBig) } } else { - let src_quantification = if self.assume.validity { + let src_quantifier = 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 + Quantifier::ThereExists } 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 + // then there must exist at least one transition out of `dst_state` such that the transmute is viable... + Quantifier::ForAll }; - 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) - } - }, - ) + let bytes_answer = src_quantifier.apply( + // for each of the byte transitions out of the `src_state`... + self.src.bytes_from(src_state).unwrap_or(&Map::default()).into_iter().map( + |(&src_validity, &src_state_prime)| { + // ...try to find a matching transition out of `dst_state`. + 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) = + // otherwise, see if `dst_state` has any outgoing `Uninit` transitions + // (any init byte is a valid uninit byte) + self.dst.byte_from(dst_state, Byte::Uninit) + { + self.answer_memo(cache, src_state_prime, dst_state_prime) + } else { + // otherwise, we've exhausted our options. + // the DFAs, from this point onwards, are bit-incompatible. + Answer::No(Reason::DstIsBitIncompatible) + } + }, + ), + ); + + // The below early returns reflect how this code would behave: + // if self.assume.validity { + // bytes_answer.or(refs_answer) + // } else { + // bytes_answer.and(refs_answer) + // } + // ...if `refs_answer` was computed lazily. The below early + // returns can be deleted without impacting the correctness of + // the algoritm; only its performance. + match bytes_answer { + Answer::No(..) if !self.assume.validity => return bytes_answer, + Answer::Yes if self.assume.validity => return bytes_answer, + _ => {} + }; + + let refs_answer = src_quantifier.apply( + // for each reference transition out of `src_state`... + self.src.refs_from(src_state).unwrap_or(&Map::default()).into_iter().map( + |(&src_ref, &src_state_prime)| { + // ...there exists a reference transition out of `dst_state`... + Quantifier::ThereExists.apply( + self.dst + .refs_from(dst_state) + .unwrap_or(&Map::default()) + .into_iter() + .map(|(&dst_ref, &dst_state_prime)| { + if !src_ref.is_mutable() && dst_ref.is_mutable() { + Answer::No(Reason::DstIsMoreUnique) + } else if !self.assume.alignment + && src_ref.min_align() < dst_ref.min_align() + { + Answer::No(Reason::DstHasStricterAlignment) + } else { + // ...such that `src` is transmutable into `dst`, if + // `src_ref` is transmutability into `dst_ref`. + Answer::IfTransmutable { src: src_ref, dst: dst_ref } + .and(self.answer_memo( + cache, + src_state_prime, + dst_state_prime, + )) + } + }), + ) + }, + ), + ); + + if self.assume.validity { + bytes_answer.or(refs_answer) + } else { + bytes_answer.and(refs_answer) + } }; - cache.insert((src_state, dst_state), answer.clone()); + if let Some(..) = cache.insert((src_state, dst_state), answer.clone()) { + panic!("failed to correctly cache transmutability") + } answer } } @@ -253,17 +318,21 @@ where { 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::No(reason)) | (Self::No(reason), _) => Self::No(reason), + + (Self::Yes, other) | (other, Self::Yes) => other, + (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]), } } @@ -271,7 +340,7 @@ where 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), + (other, Self::No(reason)) | (Self::No(reason), other) => other, (Self::IfAny(mut lhs), Self::IfAny(ref mut rhs)) => { lhs.append(rhs); Self::IfAny(lhs) @@ -319,3 +388,36 @@ where ); result } + +pub enum Quantifier { + ThereExists, + ForAll, +} + +impl Quantifier { + pub fn apply<R, I>(&self, iter: I) -> Answer<R> + where + R: layout::Ref, + I: IntoIterator<Item = Answer<R>>, + { + use std::ops::ControlFlow::{Break, Continue}; + + let (init, try_fold_f): (_, fn(_, _) -> _) = match self { + Self::ThereExists => { + (Answer::No(Reason::DstIsBitIncompatible), |accum: Answer<R>, next| { + match accum.or(next) { + Answer::Yes => Break(Answer::Yes), + maybe => Continue(maybe), + } + }) + } + Self::ForAll => (Answer::Yes, |accum: Answer<R>, next| match accum.and(next) { + Answer::No(reason) => Break(Answer::No(reason)), + maybe => Continue(maybe), + }), + }; + + let (Continue(result) | Break(result)) = iter.into_iter().try_fold(init, try_fold_f); + result + } +} diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 87ae30619c6..d0c30e715d5 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -5,6 +5,7 @@ /// notwithstanding whatever safety checks you have asked the compiler to [`Assume`] are satisfied. #[unstable(feature = "transmutability", issue = "99571")] #[lang = "transmute_trait"] +#[rustc_coinductive] pub unsafe trait BikeshedIntrinsicFrom<Src, Context, const ASSUME: Assume = { Assume::NOTHING }> where Src: ?Sized, diff --git a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr index 1a0a5d3ae94..4a0cd176408 100644 --- a/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/arrays/should_require_well_defined_layout.stderr @@ -23,7 +23,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 0]` in the defin --> $DIR/should_require_well_defined_layout.rs:27:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `[String; 0]` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 @@ -65,7 +65,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 1]` in the defin --> $DIR/should_require_well_defined_layout.rs:33:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `[String; 1]` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 @@ -107,7 +107,7 @@ error[E0277]: `u128` cannot be safely transmuted into `[String; 2]` in the defin --> $DIR/should_require_well_defined_layout.rs:39:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `[String; 2]` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 diff --git a/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr b/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr index 9877a6606a9..77d2dc4f50c 100644 --- a/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr +++ b/tests/ui/transmutability/enums/repr/primitive_reprs_should_have_correct_length.stderr @@ -24,7 +24,7 @@ error[E0277]: `V0i8` cannot be safely transmuted into `u16` in the defining scop --> $DIR/primitive_reprs_should_have_correct_length.rs:50:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0i8` is smaller than the size of `u16` + | ^^^^^^ At least one value of `V0i8` isn't a bit-valid value of `u16` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -68,7 +68,7 @@ error[E0277]: `V0u8` cannot be safely transmuted into `u16` in the defining scop --> $DIR/primitive_reprs_should_have_correct_length.rs:58:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0u8` is smaller than the size of `u16` + | ^^^^^^ At least one value of `V0u8` isn't a bit-valid value of `u16` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -112,7 +112,7 @@ error[E0277]: `V0i16` cannot be safely transmuted into `u32` in the defining sco --> $DIR/primitive_reprs_should_have_correct_length.rs:74:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0i16` is smaller than the size of `u32` + | ^^^^^^ At least one value of `V0i16` isn't a bit-valid value of `u32` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -156,7 +156,7 @@ error[E0277]: `V0u16` cannot be safely transmuted into `u32` in the defining sco --> $DIR/primitive_reprs_should_have_correct_length.rs:82:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0u16` is smaller than the size of `u32` + | ^^^^^^ At least one value of `V0u16` isn't a bit-valid value of `u32` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -200,7 +200,7 @@ error[E0277]: `V0i32` cannot be safely transmuted into `u64` in the defining sco --> $DIR/primitive_reprs_should_have_correct_length.rs:98:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0i32` is smaller than the size of `u64` + | ^^^^^^ At least one value of `V0i32` isn't a bit-valid value of `u64` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -244,7 +244,7 @@ error[E0277]: `V0u32` cannot be safely transmuted into `u64` in the defining sco --> $DIR/primitive_reprs_should_have_correct_length.rs:106:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0u32` is smaller than the size of `u64` + | ^^^^^^ At least one value of `V0u32` isn't a bit-valid value of `u64` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -288,7 +288,7 @@ error[E0277]: `V0i64` cannot be safely transmuted into `u128` in the defining sc --> $DIR/primitive_reprs_should_have_correct_length.rs:122:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0i64` is smaller than the size of `u128` + | ^^^^^^ At least one value of `V0i64` isn't a bit-valid value of `u128` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -332,7 +332,7 @@ error[E0277]: `V0u64` cannot be safely transmuted into `u128` in the defining sc --> $DIR/primitive_reprs_should_have_correct_length.rs:130:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0u64` is smaller than the size of `u128` + | ^^^^^^ At least one value of `V0u64` isn't a bit-valid value of `u128` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -376,7 +376,7 @@ error[E0277]: `V0isize` cannot be safely transmuted into `[usize; 2]` in the def --> $DIR/primitive_reprs_should_have_correct_length.rs:146:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0isize` is smaller than the size of `[usize; 2]` + | ^^^^^^ At least one value of `V0isize` isn't a bit-valid value of `[usize; 2]` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 @@ -420,7 +420,7 @@ error[E0277]: `V0usize` cannot be safely transmuted into `[usize; 2]` in the def --> $DIR/primitive_reprs_should_have_correct_length.rs:154:44 | LL | assert::is_transmutable::<Current, Larger, Context>(); - | ^^^^^^ The size of `V0usize` is smaller than the size of `[usize; 2]` + | ^^^^^^ At least one value of `V0usize` isn't a bit-valid value of `[usize; 2]` | note: required by a bound in `is_transmutable` --> $DIR/primitive_reprs_should_have_correct_length.rs:12:14 diff --git a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr index 1612b6b3661..6508d535b05 100644 --- a/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/enums/repr/should_require_well_defined_layout.stderr @@ -24,7 +24,7 @@ error[E0277]: `u128` cannot be safely transmuted into `void::repr_rust` in the d --> $DIR/should_require_well_defined_layout.rs:29:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `void::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 @@ -68,7 +68,7 @@ error[E0277]: `u128` cannot be safely transmuted into `singleton::repr_rust` in --> $DIR/should_require_well_defined_layout.rs:35:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `singleton::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 @@ -112,7 +112,7 @@ error[E0277]: `u128` cannot be safely transmuted into `duplex::repr_rust` in the --> $DIR/should_require_well_defined_layout.rs:41:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `duplex::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:14:14 diff --git a/tests/ui/transmutability/enums/should_pad_variants.stderr b/tests/ui/transmutability/enums/should_pad_variants.stderr index bfbef8b25fc..c82a7968022 100644 --- a/tests/ui/transmutability/enums/should_pad_variants.stderr +++ b/tests/ui/transmutability/enums/should_pad_variants.stderr @@ -2,7 +2,7 @@ error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope --> $DIR/should_pad_variants.rs:44:36 | LL | assert::is_transmutable::<Src, Dst, Context>(); - | ^^^ The size of `Src` is smaller than the size of `Dst` + | ^^^ At least one value of `Src` isn't a bit-valid value of `Dst` | note: required by a bound in `is_transmutable` --> $DIR/should_pad_variants.rs:13:14 diff --git a/tests/ui/transmutability/references/recursive-wrapper-types-bit-compatible.rs b/tests/ui/transmutability/references/recursive-wrapper-types-bit-compatible.rs new file mode 100644 index 00000000000..918147a0862 --- /dev/null +++ b/tests/ui/transmutability/references/recursive-wrapper-types-bit-compatible.rs @@ -0,0 +1,27 @@ +// check-fail +#![feature(transmutability)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + pub struct Context; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, Context, { + Assume { + alignment: true, + lifetimes: false, + safety: true, + validity: false, + } + }> + {} +} + +fn main() { + #[repr(C)] struct A(bool, &'static A); + #[repr(C)] struct B(u8, &'static B); + // FIXME(bryangarza): Make 2 variants of this test, depending on mutability. + // Right now, we are being strict by default and checking A->B and B->A both. + assert::is_maybe_transmutable::<&'static A, &'static B>(); //~ ERROR `B` cannot be safely transmuted into `A` +} diff --git a/tests/ui/transmutability/references/recursive-wrapper-types-bit-compatible.stderr b/tests/ui/transmutability/references/recursive-wrapper-types-bit-compatible.stderr new file mode 100644 index 00000000000..fac0e4f032e --- /dev/null +++ b/tests/ui/transmutability/references/recursive-wrapper-types-bit-compatible.stderr @@ -0,0 +1,25 @@ +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context` + --> $DIR/recursive-wrapper-types-bit-compatible.rs:26:49 + | +LL | assert::is_maybe_transmutable::<&'static A, &'static B>(); + | ^^^^^^^^^^ At least one value of `B` isn't a bit-valid value of `A` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/recursive-wrapper-types-bit-compatible.rs:10:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, Context, { + | ______________^ +LL | | Assume { +LL | | alignment: true, +LL | | lifetimes: false, +... | +LL | | } +LL | | }> + | |__________^ required by this bound in `is_maybe_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.rs b/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.rs new file mode 100644 index 00000000000..6dcb7df9feb --- /dev/null +++ b/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.rs @@ -0,0 +1,25 @@ +// check-fail +#![feature(transmutability)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + pub struct Context; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, Context, { + Assume { + alignment: true, + lifetimes: false, + safety: true, + validity: false, + } + }> + {} +} + +fn main() { + #[repr(C)] struct A(bool, &'static A); + #[repr(C)] struct B(u8, &'static B); + assert::is_maybe_transmutable::<&'static B, &'static A>(); //~ ERROR `B` cannot be safely transmuted into `A` +} diff --git a/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.stderr b/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.stderr new file mode 100644 index 00000000000..ecfe4865962 --- /dev/null +++ b/tests/ui/transmutability/references/recursive-wrapper-types-bit-incompatible.stderr @@ -0,0 +1,25 @@ +error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of `assert::Context` + --> $DIR/recursive-wrapper-types-bit-incompatible.rs:24:49 + | +LL | assert::is_maybe_transmutable::<&'static B, &'static A>(); + | ^^^^^^^^^^ At least one value of `B` isn't a bit-valid value of `A` + | +note: required by a bound in `is_maybe_transmutable` + --> $DIR/recursive-wrapper-types-bit-incompatible.rs:10:14 + | +LL | pub fn is_maybe_transmutable<Src, Dst>() + | --------------------- required by a bound in this function +LL | where +LL | Dst: BikeshedIntrinsicFrom<Src, Context, { + | ______________^ +LL | | Assume { +LL | | alignment: true, +LL | | lifetimes: false, +... | +LL | | } +LL | | }> + | |__________^ required by this bound in `is_maybe_transmutable` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/transmutability/references/recursive-wrapper-types.rs b/tests/ui/transmutability/references/recursive-wrapper-types.rs new file mode 100644 index 00000000000..090c1fea6db --- /dev/null +++ b/tests/ui/transmutability/references/recursive-wrapper-types.rs @@ -0,0 +1,26 @@ +// check-pass +#![feature(transmutability)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + pub struct Context; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, Context, { + Assume { + alignment: true, + lifetimes: false, + safety: true, + validity: false, + } + }> + {} +} + +fn main() { + #[repr(C)] struct A(&'static B); + #[repr(C)] struct B(&'static A); + assert::is_maybe_transmutable::<&'static A, &'static B>(); + assert::is_maybe_transmutable::<&'static B, &'static A>(); +} diff --git a/tests/ui/transmutability/references.rs b/tests/ui/transmutability/references/u8-to-unit.rs similarity index 55% rename from tests/ui/transmutability/references.rs rename to tests/ui/transmutability/references/u8-to-unit.rs index 8c2b25ebba1..b7dd638b952 100644 --- a/tests/ui/transmutability/references.rs +++ b/tests/ui/transmutability/references/u8-to-unit.rs @@ -1,11 +1,5 @@ -// revisions: current next -//[next] compile-flags: -Ztrait-solver=next - -//! Transmutations involving references are not yet supported. - -#![crate_type = "lib"] +// check-fail #![feature(transmutability)] -#![allow(dead_code, incomplete_features, non_camel_case_types)] mod assert { use std::mem::{Assume, BikeshedIntrinsicFrom}; @@ -24,7 +18,7 @@ mod assert { {} } -fn not_yet_implemented() { +fn main() { #[repr(C)] struct Unit; - assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); //~ ERROR cannot be safely transmuted + assert::is_maybe_transmutable::<&'static u8, &'static Unit>(); //~ ERROR `Unit` cannot be safely transmuted into `u8` } diff --git a/tests/ui/transmutability/references.next.stderr b/tests/ui/transmutability/references/u8-to-unit.stderr similarity index 63% rename from tests/ui/transmutability/references.next.stderr rename to tests/ui/transmutability/references/u8-to-unit.stderr index 819c9b92bc8..81b0b57f0cf 100644 --- a/tests/ui/transmutability/references.next.stderr +++ b/tests/ui/transmutability/references/u8-to-unit.stderr @@ -1,11 +1,11 @@ -error[E0277]: `&Unit` cannot be safely transmuted into `&Unit` in the defining scope of `assert::Context` - --> $DIR/references.rs:29:52 +error[E0277]: `Unit` cannot be safely transmuted into `u8` in the defining scope of `assert::Context` + --> $DIR/u8-to-unit.rs:23:50 | -LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); - | ^^^^^^^^^^^^^ `&Unit` does not have a well-specified layout +LL | assert::is_maybe_transmutable::<&'static u8, &'static Unit>(); + | ^^^^^^^^^^^^^ The size of `Unit` is smaller than the size of `u8` | note: required by a bound in `is_maybe_transmutable` - --> $DIR/references.rs:16:14 + --> $DIR/u8-to-unit.rs:10:14 | LL | pub fn is_maybe_transmutable<Src, Dst>() | --------------------- required by a bound in this function diff --git a/tests/ui/transmutability/references/unit-to-itself.rs b/tests/ui/transmutability/references/unit-to-itself.rs new file mode 100644 index 00000000000..04a7e16d7cc --- /dev/null +++ b/tests/ui/transmutability/references/unit-to-itself.rs @@ -0,0 +1,24 @@ +// check-pass +#![feature(transmutability)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + pub struct Context; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, Context, { + Assume { + alignment: true, + lifetimes: false, + safety: true, + validity: false, + } + }> + {} +} + +fn main() { + #[repr(C)] struct Unit; + assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); +} diff --git a/tests/ui/transmutability/references/unit-to-u8.rs b/tests/ui/transmutability/references/unit-to-u8.rs new file mode 100644 index 00000000000..73e1db3d2d5 --- /dev/null +++ b/tests/ui/transmutability/references/unit-to-u8.rs @@ -0,0 +1,24 @@ +// check-fail +#![feature(transmutability)] + +mod assert { + use std::mem::{Assume, BikeshedIntrinsicFrom}; + pub struct Context; + + pub fn is_maybe_transmutable<Src, Dst>() + where + Dst: BikeshedIntrinsicFrom<Src, Context, { + Assume { + alignment: true, + lifetimes: true, + safety: true, + validity: true, + } + }> + {} +} + +fn main() { + #[repr(C)] struct Unit; + assert::is_maybe_transmutable::<&'static Unit, &'static u8>(); //~ ERROR `Unit` cannot be safely transmuted into `u8` +} diff --git a/tests/ui/transmutability/references.current.stderr b/tests/ui/transmutability/references/unit-to-u8.stderr similarity index 76% rename from tests/ui/transmutability/references.current.stderr rename to tests/ui/transmutability/references/unit-to-u8.stderr index 819c9b92bc8..f2b72357f79 100644 --- a/tests/ui/transmutability/references.current.stderr +++ b/tests/ui/transmutability/references/unit-to-u8.stderr @@ -1,11 +1,11 @@ -error[E0277]: `&Unit` cannot be safely transmuted into `&Unit` in the defining scope of `assert::Context` - --> $DIR/references.rs:29:52 +error[E0277]: `Unit` cannot be safely transmuted into `u8` in the defining scope of `assert::Context` + --> $DIR/unit-to-u8.rs:23:52 | -LL | assert::is_maybe_transmutable::<&'static Unit, &'static Unit>(); - | ^^^^^^^^^^^^^ `&Unit` does not have a well-specified layout +LL | assert::is_maybe_transmutable::<&'static Unit, &'static u8>(); + | ^^^^^^^^^^^ The size of `Unit` is smaller than the size of `u8` | note: required by a bound in `is_maybe_transmutable` - --> $DIR/references.rs:16:14 + --> $DIR/unit-to-u8.rs:10:14 | LL | pub fn is_maybe_transmutable<Src, Dst>() | --------------------- required by a bound in this function diff --git a/tests/ui/transmutability/region-infer.stderr b/tests/ui/transmutability/region-infer.stderr index d6b65e9e4a0..307d0dfe50d 100644 --- a/tests/ui/transmutability/region-infer.stderr +++ b/tests/ui/transmutability/region-infer.stderr @@ -2,7 +2,7 @@ error[E0277]: `()` cannot be safely transmuted into `W<'_>` in the defining scop --> $DIR/region-infer.rs:20:5 | LL | test(); - | ^^^^ `W<'_>` does not have a well-specified layout + | ^^^^ The size of `()` is smaller than the size of `W<'_>` | note: required by a bound in `test` --> $DIR/region-infer.rs:11:12 diff --git a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr index 4c5062cd3b3..7f26bc49817 100644 --- a/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/structs/repr/should_require_well_defined_layout.stderr @@ -24,7 +24,7 @@ error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust:: --> $DIR/should_require_well_defined_layout.rs:29:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `should_reject_repr_rust::unit::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 @@ -68,7 +68,7 @@ error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust:: --> $DIR/should_require_well_defined_layout.rs:35:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `should_reject_repr_rust::tuple::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 @@ -112,7 +112,7 @@ error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust:: --> $DIR/should_require_well_defined_layout.rs:41:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `should_reject_repr_rust::braces::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 @@ -156,7 +156,7 @@ error[E0277]: `u128` cannot be safely transmuted into `aligned::repr_rust` in th --> $DIR/should_require_well_defined_layout.rs:47:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `aligned::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 @@ -200,7 +200,7 @@ error[E0277]: `u128` cannot be safely transmuted into `packed::repr_rust` in the --> $DIR/should_require_well_defined_layout.rs:53:47 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `packed::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 @@ -244,7 +244,7 @@ error[E0277]: `u128` cannot be safely transmuted into `nested::repr_c` in the de --> $DIR/should_require_well_defined_layout.rs:60:47 | LL | assert::is_maybe_transmutable::<u128, repr_c>(); - | ^^^^^^ `nested::repr_c` does not have a well-specified layout + | ^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 diff --git a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr index 4293d34f47b..305ecc71733 100644 --- a/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr +++ b/tests/ui/transmutability/unions/repr/should_require_well_defined_layout.stderr @@ -24,7 +24,7 @@ error[E0277]: `u128` cannot be safely transmuted into `should_reject_repr_rust:: --> $DIR/should_require_well_defined_layout.rs:31:43 | LL | assert::is_maybe_transmutable::<u128, repr_rust>(); - | ^^^^^^^^^ `should_reject_repr_rust::repr_rust` does not have a well-specified layout + | ^^^^^^^^^ `u128` does not have a well-specified layout | note: required by a bound in `is_maybe_transmutable` --> $DIR/should_require_well_defined_layout.rs:13:14 diff --git a/tests/ui/transmutability/unions/should_pad_variants.stderr b/tests/ui/transmutability/unions/should_pad_variants.stderr index bfbef8b25fc..c82a7968022 100644 --- a/tests/ui/transmutability/unions/should_pad_variants.stderr +++ b/tests/ui/transmutability/unions/should_pad_variants.stderr @@ -2,7 +2,7 @@ error[E0277]: `Src` cannot be safely transmuted into `Dst` in the defining scope --> $DIR/should_pad_variants.rs:44:36 | LL | assert::is_transmutable::<Src, Dst, Context>(); - | ^^^ The size of `Src` is smaller than the size of `Dst` + | ^^^ At least one value of `Src` isn't a bit-valid value of `Dst` | note: required by a bound in `is_transmutable` --> $DIR/should_pad_variants.rs:13:14 diff --git a/tests/ui/transmute/transmute-padding-ice.stderr b/tests/ui/transmute/transmute-padding-ice.stderr index f5480e0b9fb..2739fd16645 100644 --- a/tests/ui/transmute/transmute-padding-ice.stderr +++ b/tests/ui/transmute/transmute-padding-ice.stderr @@ -2,7 +2,7 @@ error[E0277]: `B` cannot be safely transmuted into `A` in the defining scope of --> $DIR/transmute-padding-ice.rs:27:40 | LL | assert::is_maybe_transmutable::<B, A>(); - | ^ The size of `B` is smaller than the size of `A` + | ^ At least one value of `B` isn't a bit-valid value of `A` | note: required by a bound in `is_maybe_transmutable` --> $DIR/transmute-padding-ice.rs:11:14