Rollup merge of #137776 - nnethercote:rustc_transmute-cleanups, r=jswrenn
Some `rustc_transmute` cleanups A number of small things that can be removed. r? ``@jswrenn``
This commit is contained in:
commit
b6c1b635f7
14 changed files with 32 additions and 85 deletions
|
@ -4501,8 +4501,6 @@ dependencies = [
|
||||||
"rustc_abi",
|
"rustc_abi",
|
||||||
"rustc_data_structures",
|
"rustc_data_structures",
|
||||||
"rustc_hir",
|
"rustc_hir",
|
||||||
"rustc_infer",
|
|
||||||
"rustc_macros",
|
|
||||||
"rustc_middle",
|
"rustc_middle",
|
||||||
"rustc_span",
|
"rustc_span",
|
||||||
"tracing",
|
"tracing",
|
||||||
|
|
|
@ -102,7 +102,6 @@ pub trait SolverDelegate: Deref<Target = Self::Infcx> + Sized {
|
||||||
|
|
||||||
fn is_transmutable(
|
fn is_transmutable(
|
||||||
&self,
|
&self,
|
||||||
param_env: <Self::Interner as Interner>::ParamEnv,
|
|
||||||
dst: <Self::Interner as Interner>::Ty,
|
dst: <Self::Interner as Interner>::Ty,
|
||||||
src: <Self::Interner as Interner>::Ty,
|
src: <Self::Interner as Interner>::Ty,
|
||||||
assume: <Self::Interner as Interner>::Const,
|
assume: <Self::Interner as Interner>::Const,
|
||||||
|
|
|
@ -1091,12 +1091,11 @@ where
|
||||||
|
|
||||||
pub(super) fn is_transmutable(
|
pub(super) fn is_transmutable(
|
||||||
&mut self,
|
&mut self,
|
||||||
param_env: I::ParamEnv,
|
|
||||||
dst: I::Ty,
|
dst: I::Ty,
|
||||||
src: I::Ty,
|
src: I::Ty,
|
||||||
assume: I::Const,
|
assume: I::Const,
|
||||||
) -> Result<Certainty, NoSolution> {
|
) -> Result<Certainty, NoSolution> {
|
||||||
self.delegate.is_transmutable(param_env, dst, src, assume)
|
self.delegate.is_transmutable(dst, src, assume)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -617,7 +617,6 @@ where
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let certainty = ecx.is_transmutable(
|
let certainty = ecx.is_transmutable(
|
||||||
goal.param_env,
|
|
||||||
goal.predicate.trait_ref.args.type_at(0),
|
goal.predicate.trait_ref.args.type_at(0),
|
||||||
goal.predicate.trait_ref.args.type_at(1),
|
goal.predicate.trait_ref.args.type_at(1),
|
||||||
assume,
|
assume,
|
||||||
|
|
|
@ -2533,9 +2533,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
return GetSafeTransmuteErrorAndReason::Silent;
|
return GetSafeTransmuteErrorAndReason::Silent;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(assume) =
|
let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else {
|
||||||
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
|
|
||||||
else {
|
|
||||||
self.dcx().span_delayed_bug(
|
self.dcx().span_delayed_bug(
|
||||||
span,
|
span,
|
||||||
"Unable to construct rustc_transmute::Assume where it was previously possible",
|
"Unable to construct rustc_transmute::Assume where it was previously possible",
|
||||||
|
@ -2547,11 +2545,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
||||||
let src = trait_pred.trait_ref.args.type_at(1);
|
let src = trait_pred.trait_ref.args.type_at(1);
|
||||||
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
|
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
|
||||||
|
|
||||||
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
match rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx)
|
||||||
obligation.cause,
|
.is_transmutable(src_and_dst, assume)
|
||||||
src_and_dst,
|
{
|
||||||
assume,
|
|
||||||
) {
|
|
||||||
Answer::No(reason) => {
|
Answer::No(reason) => {
|
||||||
let safe_transmute_explanation = match reason {
|
let safe_transmute_explanation = match reason {
|
||||||
rustc_transmute::Reason::SrcIsNotYetSupported => {
|
rustc_transmute::Reason::SrcIsNotYetSupported => {
|
||||||
|
|
|
@ -7,7 +7,6 @@ use rustc_infer::infer::canonical::{
|
||||||
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
|
Canonical, CanonicalExt as _, CanonicalQueryInput, CanonicalVarInfo, CanonicalVarValues,
|
||||||
};
|
};
|
||||||
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
|
use rustc_infer::infer::{InferCtxt, RegionVariableOrigin, TyCtxtInferExt};
|
||||||
use rustc_infer::traits::ObligationCause;
|
|
||||||
use rustc_infer::traits::solve::Goal;
|
use rustc_infer::traits::solve::Goal;
|
||||||
use rustc_middle::ty::fold::TypeFoldable;
|
use rustc_middle::ty::fold::TypeFoldable;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt as _};
|
||||||
|
@ -222,7 +221,6 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
||||||
// register candidates. We probably need to register >1 since we may have an OR of ANDs.
|
// register candidates. We probably need to register >1 since we may have an OR of ANDs.
|
||||||
fn is_transmutable(
|
fn is_transmutable(
|
||||||
&self,
|
&self,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
dst: Ty<'tcx>,
|
dst: Ty<'tcx>,
|
||||||
src: Ty<'tcx>,
|
src: Ty<'tcx>,
|
||||||
assume: ty::Const<'tcx>,
|
assume: ty::Const<'tcx>,
|
||||||
|
@ -231,16 +229,14 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
|
||||||
// which will ICE for region vars.
|
// which will ICE for region vars.
|
||||||
let (dst, src) = self.tcx.erase_regions((dst, src));
|
let (dst, src) = self.tcx.erase_regions((dst, src));
|
||||||
|
|
||||||
let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, param_env, assume) else {
|
let Some(assume) = rustc_transmute::Assume::from_const(self.tcx, assume) else {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
|
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
|
||||||
match rustc_transmute::TransmuteTypeEnv::new(&self.0).is_transmutable(
|
match rustc_transmute::TransmuteTypeEnv::new(self.0.tcx)
|
||||||
ObligationCause::dummy(),
|
.is_transmutable(rustc_transmute::Types { src, dst }, assume)
|
||||||
rustc_transmute::Types { src, dst },
|
{
|
||||||
assume,
|
|
||||||
) {
|
|
||||||
rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
|
rustc_transmute::Answer::Yes => Ok(Certainty::Yes),
|
||||||
rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
|
rustc_transmute::Answer::No(_) | rustc_transmute::Answer::If(_) => Err(NoSolution),
|
||||||
}
|
}
|
||||||
|
|
|
@ -414,9 +414,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
if self.tcx().features().generic_const_exprs() {
|
if self.tcx().features().generic_const_exprs() {
|
||||||
assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
|
assume = crate::traits::evaluate_const(self.infcx, assume, obligation.param_env)
|
||||||
}
|
}
|
||||||
let Some(assume) =
|
let Some(assume) = rustc_transmute::Assume::from_const(self.infcx.tcx, assume) else {
|
||||||
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
|
|
||||||
else {
|
|
||||||
return Err(Unimplemented);
|
return Err(Unimplemented);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -424,12 +422,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
let src = predicate.trait_ref.args.type_at(1);
|
let src = predicate.trait_ref.args.type_at(1);
|
||||||
|
|
||||||
debug!(?src, ?dst);
|
debug!(?src, ?dst);
|
||||||
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
|
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx.tcx);
|
||||||
let maybe_transmutable = transmute_env.is_transmutable(
|
let maybe_transmutable =
|
||||||
obligation.cause.clone(),
|
transmute_env.is_transmutable(rustc_transmute::Types { dst, src }, assume);
|
||||||
rustc_transmute::Types { dst, src },
|
|
||||||
assume,
|
|
||||||
);
|
|
||||||
|
|
||||||
let fully_flattened = match maybe_transmutable {
|
let fully_flattened = match maybe_transmutable {
|
||||||
Answer::No(_) => Err(Unimplemented)?,
|
Answer::No(_) => Err(Unimplemented)?,
|
||||||
|
|
|
@ -8,8 +8,6 @@ edition = "2024"
|
||||||
rustc_abi = { path = "../rustc_abi", optional = true }
|
rustc_abi = { path = "../rustc_abi", optional = true }
|
||||||
rustc_data_structures = { path = "../rustc_data_structures" }
|
rustc_data_structures = { path = "../rustc_data_structures" }
|
||||||
rustc_hir = { path = "../rustc_hir", optional = true }
|
rustc_hir = { path = "../rustc_hir", optional = true }
|
||||||
rustc_infer = { path = "../rustc_infer", optional = true }
|
|
||||||
rustc_macros = { path = "../rustc_macros", optional = true }
|
|
||||||
rustc_middle = { path = "../rustc_middle", optional = true }
|
rustc_middle = { path = "../rustc_middle", optional = true }
|
||||||
rustc_span = { path = "../rustc_span", optional = true }
|
rustc_span = { path = "../rustc_span", optional = true }
|
||||||
tracing = "0.1"
|
tracing = "0.1"
|
||||||
|
@ -19,8 +17,6 @@ tracing = "0.1"
|
||||||
rustc = [
|
rustc = [
|
||||||
"dep:rustc_abi",
|
"dep:rustc_abi",
|
||||||
"dep:rustc_hir",
|
"dep:rustc_hir",
|
||||||
"dep:rustc_infer",
|
|
||||||
"dep:rustc_macros",
|
|
||||||
"dep:rustc_middle",
|
"dep:rustc_middle",
|
||||||
"dep:rustc_span",
|
"dep:rustc_span",
|
||||||
]
|
]
|
||||||
|
|
|
@ -38,7 +38,7 @@ impl<R> Transitions<R>
|
||||||
where
|
where
|
||||||
R: Ref,
|
R: Ref,
|
||||||
{
|
{
|
||||||
#[allow(dead_code)]
|
#[cfg(test)]
|
||||||
fn insert(&mut self, transition: Transition<R>, state: State) {
|
fn insert(&mut self, transition: Transition<R>, state: State) {
|
||||||
match transition {
|
match transition {
|
||||||
Transition::Byte(b) => {
|
Transition::Byte(b) => {
|
||||||
|
@ -86,15 +86,6 @@ impl<R> Dfa<R>
|
||||||
where
|
where
|
||||||
R: Ref,
|
R: Ref,
|
||||||
{
|
{
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) fn unit() -> Self {
|
|
||||||
let transitions: Map<State, Transitions<R>> = Map::default();
|
|
||||||
let start = State::new();
|
|
||||||
let accepting = start;
|
|
||||||
|
|
||||||
Self { transitions, start, accepting }
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) fn bool() -> Self {
|
pub(crate) fn bool() -> Self {
|
||||||
let mut transitions: Map<State, Transitions<R>> = Map::default();
|
let mut transitions: Map<State, Transitions<R>> = Map::default();
|
||||||
|
|
|
@ -159,11 +159,6 @@ where
|
||||||
}
|
}
|
||||||
Self { transitions, start, accepting }
|
Self { transitions, start, accepting }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub(crate) fn edges_from(&self, start: State) -> Option<&Map<Transition<R>, Set<State>>> {
|
|
||||||
self.transitions.get(&start)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
|
|
@ -237,7 +237,7 @@ pub(crate) mod rustc {
|
||||||
|
|
||||||
ty::Tuple(members) => Self::from_tuple((ty, layout), members, cx),
|
ty::Tuple(members) => Self::from_tuple((ty, layout), members, cx),
|
||||||
|
|
||||||
ty::Array(inner_ty, len) => {
|
ty::Array(inner_ty, _len) => {
|
||||||
let FieldsShape::Array { stride, count } = &layout.fields else {
|
let FieldsShape::Array { stride, count } = &layout.fields else {
|
||||||
return Err(Err::NotYetSupported);
|
return Err(Err::NotYetSupported);
|
||||||
};
|
};
|
||||||
|
@ -282,7 +282,6 @@ pub(crate) mod rustc {
|
||||||
FieldsShape::Primitive => {
|
FieldsShape::Primitive => {
|
||||||
assert_eq!(members.len(), 1);
|
assert_eq!(members.len(), 1);
|
||||||
let inner_ty = members[0];
|
let inner_ty = members[0];
|
||||||
let inner_layout = layout_of(cx, inner_ty)?;
|
|
||||||
Self::from_ty(inner_ty, cx)
|
Self::from_ty(inner_ty, cx)
|
||||||
}
|
}
|
||||||
FieldsShape::Arbitrary { offsets, .. } => {
|
FieldsShape::Arbitrary { offsets, .. } => {
|
||||||
|
@ -345,7 +344,7 @@ pub(crate) mod rustc {
|
||||||
// the enum delegates its layout to the variant at `index`.
|
// the enum delegates its layout to the variant at `index`.
|
||||||
layout_of_variant(*index, None)
|
layout_of_variant(*index, None)
|
||||||
}
|
}
|
||||||
Variants::Multiple { tag, tag_encoding, tag_field, .. } => {
|
Variants::Multiple { tag: _, tag_encoding, tag_field, .. } => {
|
||||||
// `Variants::Multiple` denotes an enum with multiple
|
// `Variants::Multiple` denotes an enum with multiple
|
||||||
// variants. The layout of such an enum is the disjunction
|
// variants. The layout of such an enum is the disjunction
|
||||||
// of the layouts of its tagged variants.
|
// of the layouts of its tagged variants.
|
||||||
|
@ -356,7 +355,7 @@ pub(crate) mod rustc {
|
||||||
|
|
||||||
let variants = def.discriminants(cx.tcx()).try_fold(
|
let variants = def.discriminants(cx.tcx()).try_fold(
|
||||||
Self::uninhabited(),
|
Self::uninhabited(),
|
||||||
|variants, (idx, ref discriminant)| {
|
|variants, (idx, _discriminant)| {
|
||||||
let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?;
|
let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?;
|
||||||
Result::<Self, Err>::Ok(variants.or(variant))
|
Result::<Self, Err>::Ok(variants.or(variant))
|
||||||
},
|
},
|
||||||
|
@ -414,7 +413,7 @@ pub(crate) mod rustc {
|
||||||
|
|
||||||
// Append the fields, in memory order, to the layout.
|
// Append the fields, in memory order, to the layout.
|
||||||
let inverse_memory_index = memory_index.invert_bijective_mapping();
|
let inverse_memory_index = memory_index.invert_bijective_mapping();
|
||||||
for (memory_idx, &field_idx) in inverse_memory_index.iter_enumerated() {
|
for &field_idx in inverse_memory_index.iter() {
|
||||||
// Add interfield padding.
|
// Add interfield padding.
|
||||||
let padding_needed = offsets[field_idx] - size;
|
let padding_needed = offsets[field_idx] - size;
|
||||||
let padding = Self::padding(padding_needed.bytes_usize());
|
let padding = Self::padding(padding_needed.bytes_usize());
|
||||||
|
@ -468,15 +467,14 @@ pub(crate) mod rustc {
|
||||||
|
|
||||||
// This constructor does not support non-`FieldsShape::Union`
|
// This constructor does not support non-`FieldsShape::Union`
|
||||||
// layouts. Fields of this shape are all placed at offset 0.
|
// layouts. Fields of this shape are all placed at offset 0.
|
||||||
let FieldsShape::Union(fields) = layout.fields() else {
|
let FieldsShape::Union(_fields) = layout.fields() else {
|
||||||
return Err(Err::NotYetSupported);
|
return Err(Err::NotYetSupported);
|
||||||
};
|
};
|
||||||
|
|
||||||
let fields = &def.non_enum_variant().fields;
|
let fields = &def.non_enum_variant().fields;
|
||||||
let fields = fields.iter_enumerated().try_fold(
|
let fields = fields.iter_enumerated().try_fold(
|
||||||
Self::uninhabited(),
|
Self::uninhabited(),
|
||||||
|fields, (idx, field_def)| {
|
|fields, (idx, _field_def)| {
|
||||||
let field_def = Def::Field(field_def);
|
|
||||||
let field_ty = ty_field(cx, (ty, layout), idx);
|
let field_ty = ty_field(cx, (ty, layout), idx);
|
||||||
let field_layout = layout_of(cx, field_ty)?;
|
let field_layout = layout_of(cx, field_ty)?;
|
||||||
let field = Self::from_ty(field_ty, cx)?;
|
let field = Self::from_ty(field_ty, cx)?;
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
// tidy-alphabetical-start
|
// tidy-alphabetical-start
|
||||||
#![allow(unused_variables)]
|
|
||||||
#![feature(alloc_layout_extra)]
|
|
||||||
#![feature(never_type)]
|
#![feature(never_type)]
|
||||||
#![warn(unreachable_pub)]
|
#![warn(unreachable_pub)]
|
||||||
// tidy-alphabetical-end
|
// tidy-alphabetical-end
|
||||||
|
@ -81,15 +79,12 @@ pub enum Reason<T> {
|
||||||
#[cfg(feature = "rustc")]
|
#[cfg(feature = "rustc")]
|
||||||
mod rustc {
|
mod rustc {
|
||||||
use rustc_hir::lang_items::LangItem;
|
use rustc_hir::lang_items::LangItem;
|
||||||
use rustc_infer::infer::InferCtxt;
|
use rustc_middle::ty::{Const, Ty, TyCtxt};
|
||||||
use rustc_macros::TypeVisitable;
|
|
||||||
use rustc_middle::traits::ObligationCause;
|
|
||||||
use rustc_middle::ty::{Const, ParamEnv, Ty, TyCtxt};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// The source and destination types of a transmutation.
|
/// The source and destination types of a transmutation.
|
||||||
#[derive(TypeVisitable, Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Types<'tcx> {
|
pub struct Types<'tcx> {
|
||||||
/// The source type.
|
/// The source type.
|
||||||
pub src: Ty<'tcx>,
|
pub src: Ty<'tcx>,
|
||||||
|
@ -97,27 +92,22 @@ mod rustc {
|
||||||
pub dst: Ty<'tcx>,
|
pub dst: Ty<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TransmuteTypeEnv<'cx, 'tcx> {
|
pub struct TransmuteTypeEnv<'tcx> {
|
||||||
infcx: &'cx InferCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'cx, 'tcx> TransmuteTypeEnv<'cx, 'tcx> {
|
impl<'tcx> TransmuteTypeEnv<'tcx> {
|
||||||
pub fn new(infcx: &'cx InferCtxt<'tcx>) -> Self {
|
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||||
Self { infcx }
|
Self { tcx }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
pub fn is_transmutable(
|
pub fn is_transmutable(
|
||||||
&mut self,
|
&mut self,
|
||||||
cause: ObligationCause<'tcx>,
|
|
||||||
types: Types<'tcx>,
|
types: Types<'tcx>,
|
||||||
assume: crate::Assume,
|
assume: crate::Assume,
|
||||||
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
|
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
|
||||||
crate::maybe_transmutable::MaybeTransmutableQuery::new(
|
crate::maybe_transmutable::MaybeTransmutableQuery::new(
|
||||||
types.src,
|
types.src, types.dst, assume, self.tcx,
|
||||||
types.dst,
|
|
||||||
assume,
|
|
||||||
self.infcx.tcx,
|
|
||||||
)
|
)
|
||||||
.answer()
|
.answer()
|
||||||
}
|
}
|
||||||
|
@ -125,11 +115,7 @@ mod rustc {
|
||||||
|
|
||||||
impl Assume {
|
impl Assume {
|
||||||
/// Constructs an `Assume` from a given const-`Assume`.
|
/// Constructs an `Assume` from a given const-`Assume`.
|
||||||
pub fn from_const<'tcx>(
|
pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option<Self> {
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
param_env: ParamEnv<'tcx>,
|
|
||||||
ct: Const<'tcx>,
|
|
||||||
) -> Option<Self> {
|
|
||||||
use rustc_middle::ty::ScalarInt;
|
use rustc_middle::ty::ScalarInt;
|
||||||
use rustc_span::sym;
|
use rustc_span::sym;
|
||||||
|
|
||||||
|
|
|
@ -79,12 +79,12 @@ where
|
||||||
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
|
pub(crate) fn answer(self) -> Answer<<C as QueryContext>::Ref> {
|
||||||
let Self { src, dst, assume, context } = self;
|
let Self { src, dst, assume, context } = self;
|
||||||
|
|
||||||
// Unconditionally all `Def` nodes from `src`, without pruning away the
|
// Unconditionally remove all `Def` nodes from `src`, without pruning away the
|
||||||
// branches they appear in. This is valid to do for value-to-value
|
// branches they appear in. This is valid to do for value-to-value
|
||||||
// transmutations, but not for `&mut T` to `&mut U`; we will need to be
|
// transmutations, but not for `&mut T` to `&mut U`; we will need to be
|
||||||
// more sophisticated to handle transmutations between mutable
|
// more sophisticated to handle transmutations between mutable
|
||||||
// references.
|
// references.
|
||||||
let src = src.prune(&|def| false);
|
let src = src.prune(&|_def| false);
|
||||||
|
|
||||||
if src.is_inhabited() && !dst.is_inhabited() {
|
if src.is_inhabited() && !dst.is_inhabited() {
|
||||||
return Answer::No(Reason::DstUninhabited);
|
return Answer::No(Reason::DstUninhabited);
|
||||||
|
@ -96,7 +96,7 @@ where
|
||||||
let dst = if assume.safety {
|
let dst = if assume.safety {
|
||||||
// ...if safety is assumed, don't check if they carry safety
|
// ...if safety is assumed, don't check if they carry safety
|
||||||
// invariants; retain all paths.
|
// invariants; retain all paths.
|
||||||
dst.prune(&|def| false)
|
dst.prune(&|_def| false)
|
||||||
} else {
|
} else {
|
||||||
// ...otherwise, prune away all paths with safety invariants from
|
// ...otherwise, prune away all paths with safety invariants from
|
||||||
// the `Dst` layout.
|
// the `Dst` layout.
|
||||||
|
|
|
@ -92,7 +92,6 @@ mod bool {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_permit_validity_expansion_and_reject_contraction() {
|
fn should_permit_validity_expansion_and_reject_contraction() {
|
||||||
let un = layout::Tree::<Def, !>::uninhabited();
|
|
||||||
let b0 = layout::Tree::<Def, !>::from_bits(0);
|
let b0 = layout::Tree::<Def, !>::from_bits(0);
|
||||||
let b1 = layout::Tree::<Def, !>::from_bits(1);
|
let b1 = layout::Tree::<Def, !>::from_bits(1);
|
||||||
let b2 = layout::Tree::<Def, !>::from_bits(2);
|
let b2 = layout::Tree::<Def, !>::from_bits(2);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue