Fix transmute goal
This commit is contained in:
parent
38bbcc001e
commit
9453d2cfeb
9 changed files with 236 additions and 117 deletions
|
@ -2247,124 +2247,143 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||
span: Span,
|
||||
) -> GetSafeTransmuteErrorAndReason {
|
||||
use rustc_transmute::Answer;
|
||||
self.probe(|_| {
|
||||
// We don't assemble a transmutability candidate for types that are generic
|
||||
// and we should have ambiguity for types that still have non-region infer.
|
||||
if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() {
|
||||
return GetSafeTransmuteErrorAndReason::Default;
|
||||
}
|
||||
|
||||
// We don't assemble a transmutability candidate for types that are generic
|
||||
// and we should have ambiguity for types that still have non-region infer.
|
||||
if obligation.predicate.has_non_region_param() || obligation.has_non_region_infer() {
|
||||
return GetSafeTransmuteErrorAndReason::Default;
|
||||
}
|
||||
// Erase regions because layout code doesn't particularly care about regions.
|
||||
let trait_ref =
|
||||
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
|
||||
|
||||
// Erase regions because layout code doesn't particularly care about regions.
|
||||
let trait_ref =
|
||||
self.tcx.erase_regions(self.tcx.instantiate_bound_regions_with_erased(trait_ref));
|
||||
let src_and_dst = rustc_transmute::Types {
|
||||
dst: trait_ref.args.type_at(0),
|
||||
src: trait_ref.args.type_at(1),
|
||||
};
|
||||
|
||||
let src_and_dst = rustc_transmute::Types {
|
||||
dst: trait_ref.args.type_at(0),
|
||||
src: trait_ref.args.type_at(1),
|
||||
};
|
||||
let Some(assume) = rustc_transmute::Assume::from_const(
|
||||
self.infcx.tcx,
|
||||
obligation.param_env,
|
||||
trait_ref.args.const_at(2),
|
||||
) else {
|
||||
self.dcx().span_delayed_bug(
|
||||
span,
|
||||
"Unable to construct rustc_transmute::Assume where it was previously possible",
|
||||
);
|
||||
return GetSafeTransmuteErrorAndReason::Silent;
|
||||
};
|
||||
let ocx = ObligationCtxt::new(self);
|
||||
let Ok(assume) = ocx.structurally_normalize_const(
|
||||
&obligation.cause,
|
||||
obligation.param_env,
|
||||
trait_ref.args.const_at(2),
|
||||
) else {
|
||||
self.dcx().span_delayed_bug(
|
||||
span,
|
||||
"Unable to construct rustc_transmute::Assume where it was previously possible",
|
||||
);
|
||||
return GetSafeTransmuteErrorAndReason::Silent;
|
||||
};
|
||||
|
||||
let dst = trait_ref.args.type_at(0);
|
||||
let src = trait_ref.args.type_at(1);
|
||||
let Some(assume) =
|
||||
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
|
||||
else {
|
||||
self.dcx().span_delayed_bug(
|
||||
span,
|
||||
"Unable to construct rustc_transmute::Assume where it was previously possible",
|
||||
);
|
||||
return GetSafeTransmuteErrorAndReason::Silent;
|
||||
};
|
||||
|
||||
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
|
||||
let dst = trait_ref.args.type_at(0);
|
||||
let src = trait_ref.args.type_at(1);
|
||||
let err_msg = format!("`{src}` cannot be safely transmuted into `{dst}`");
|
||||
|
||||
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
||||
obligation.cause,
|
||||
src_and_dst,
|
||||
assume,
|
||||
) {
|
||||
Answer::No(reason) => {
|
||||
let safe_transmute_explanation = match reason {
|
||||
rustc_transmute::Reason::SrcIsNotYetSupported => {
|
||||
format!("analyzing the transmutability of `{src}` is not yet supported")
|
||||
}
|
||||
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
|
||||
obligation.cause,
|
||||
src_and_dst,
|
||||
assume,
|
||||
) {
|
||||
Answer::No(reason) => {
|
||||
let safe_transmute_explanation = match reason {
|
||||
rustc_transmute::Reason::SrcIsNotYetSupported => {
|
||||
format!("analyzing the transmutability of `{src}` is not yet supported")
|
||||
}
|
||||
|
||||
rustc_transmute::Reason::DstIsNotYetSupported => {
|
||||
format!("analyzing the transmutability of `{dst}` is not yet supported")
|
||||
}
|
||||
rustc_transmute::Reason::DstIsNotYetSupported => {
|
||||
format!("analyzing the transmutability of `{dst}` is not yet supported")
|
||||
}
|
||||
|
||||
rustc_transmute::Reason::DstIsBitIncompatible => {
|
||||
format!("at least one value of `{src}` isn't a bit-valid value of `{dst}`")
|
||||
}
|
||||
rustc_transmute::Reason::DstIsBitIncompatible => {
|
||||
format!(
|
||||
"at least one value of `{src}` isn't a bit-valid value of `{dst}`"
|
||||
)
|
||||
}
|
||||
|
||||
rustc_transmute::Reason::DstUninhabited => {
|
||||
format!("`{dst}` is uninhabited")
|
||||
}
|
||||
rustc_transmute::Reason::DstUninhabited => {
|
||||
format!("`{dst}` is uninhabited")
|
||||
}
|
||||
|
||||
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
|
||||
format!("`{dst}` may carry safety invariants")
|
||||
rustc_transmute::Reason::DstMayHaveSafetyInvariants => {
|
||||
format!("`{dst}` may carry safety invariants")
|
||||
}
|
||||
rustc_transmute::Reason::DstIsTooBig => {
|
||||
format!("the size of `{src}` is smaller than the size of `{dst}`")
|
||||
}
|
||||
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
|
||||
let src_size = src.size;
|
||||
let dst_size = dst.size;
|
||||
format!(
|
||||
"the referent size of `{src}` ({src_size} bytes) \
|
||||
is smaller than that of `{dst}` ({dst_size} bytes)"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::SrcSizeOverflow => {
|
||||
format!(
|
||||
"values of the type `{src}` are too big for the target architecture"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::DstSizeOverflow => {
|
||||
format!(
|
||||
"values of the type `{dst}` are too big for the target architecture"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::DstHasStricterAlignment {
|
||||
src_min_align,
|
||||
dst_min_align,
|
||||
} => {
|
||||
format!(
|
||||
"the minimum alignment of `{src}` ({src_min_align}) should \
|
||||
be greater than that of `{dst}` ({dst_min_align})"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::DstIsMoreUnique => {
|
||||
format!(
|
||||
"`{src}` is a shared reference, but `{dst}` is a unique reference"
|
||||
)
|
||||
}
|
||||
// Already reported by rustc
|
||||
rustc_transmute::Reason::TypeError => {
|
||||
return GetSafeTransmuteErrorAndReason::Silent;
|
||||
}
|
||||
rustc_transmute::Reason::SrcLayoutUnknown => {
|
||||
format!("`{src}` has an unknown layout")
|
||||
}
|
||||
rustc_transmute::Reason::DstLayoutUnknown => {
|
||||
format!("`{dst}` has an unknown layout")
|
||||
}
|
||||
};
|
||||
GetSafeTransmuteErrorAndReason::Error {
|
||||
err_msg,
|
||||
safe_transmute_explanation: Some(safe_transmute_explanation),
|
||||
}
|
||||
rustc_transmute::Reason::DstIsTooBig => {
|
||||
format!("the size of `{src}` is smaller than the size of `{dst}`")
|
||||
}
|
||||
rustc_transmute::Reason::DstRefIsTooBig { src, dst } => {
|
||||
let src_size = src.size;
|
||||
let dst_size = dst.size;
|
||||
format!(
|
||||
"the referent size of `{src}` ({src_size} bytes) is smaller than that of `{dst}` ({dst_size} bytes)"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::SrcSizeOverflow => {
|
||||
format!(
|
||||
"values of the type `{src}` are too big for the target architecture"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::DstSizeOverflow => {
|
||||
format!(
|
||||
"values of the type `{dst}` are too big for the target architecture"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::DstHasStricterAlignment {
|
||||
src_min_align,
|
||||
dst_min_align,
|
||||
} => {
|
||||
format!(
|
||||
"the minimum alignment of `{src}` ({src_min_align}) should be greater than that of `{dst}` ({dst_min_align})"
|
||||
)
|
||||
}
|
||||
rustc_transmute::Reason::DstIsMoreUnique => {
|
||||
format!("`{src}` is a shared reference, but `{dst}` is a unique reference")
|
||||
}
|
||||
// Already reported by rustc
|
||||
rustc_transmute::Reason::TypeError => {
|
||||
return GetSafeTransmuteErrorAndReason::Silent;
|
||||
}
|
||||
rustc_transmute::Reason::SrcLayoutUnknown => {
|
||||
format!("`{src}` has an unknown layout")
|
||||
}
|
||||
rustc_transmute::Reason::DstLayoutUnknown => {
|
||||
format!("`{dst}` has an unknown layout")
|
||||
}
|
||||
};
|
||||
GetSafeTransmuteErrorAndReason::Error {
|
||||
err_msg,
|
||||
safe_transmute_explanation: Some(safe_transmute_explanation),
|
||||
}
|
||||
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
|
||||
Answer::Yes => span_bug!(
|
||||
span,
|
||||
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
|
||||
),
|
||||
// Reached when a different obligation (namely `Freeze`) causes the
|
||||
// transmutability analysis to fail. In this case, silence the
|
||||
// transmutability error message in favor of that more specific
|
||||
// error.
|
||||
Answer::If(_) => GetSafeTransmuteErrorAndReason::Error {
|
||||
err_msg,
|
||||
safe_transmute_explanation: None,
|
||||
},
|
||||
}
|
||||
// Should never get a Yes at this point! We already ran it before, and did not get a Yes.
|
||||
Answer::Yes => span_bug!(
|
||||
span,
|
||||
"Inconsistent rustc_transmute::is_transmutable(...) result, got Yes",
|
||||
),
|
||||
// Reached when a different obligation (namely `Freeze`) causes the
|
||||
// transmutability analysis to fail. In this case, silence the
|
||||
// transmutability error message in favor of that more specific
|
||||
// error.
|
||||
Answer::If(_) => {
|
||||
GetSafeTransmuteErrorAndReason::Error { err_msg, safe_transmute_explanation: None }
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// For effects predicates such as `<u32 as Add>::Effects: Compat<host>`, pretend that the
|
||||
|
|
|
@ -329,4 +329,15 @@ where
|
|||
.at(cause, param_env)
|
||||
.structurally_normalize(value, &mut **self.engine.borrow_mut())
|
||||
}
|
||||
|
||||
pub fn structurally_normalize_const(
|
||||
&self,
|
||||
cause: &ObligationCause<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
value: ty::Const<'tcx>,
|
||||
) -> Result<ty::Const<'tcx>, Vec<E>> {
|
||||
self.infcx
|
||||
.at(cause, param_env)
|
||||
.structurally_normalize_const(value, &mut **self.engine.borrow_mut())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -405,11 +405,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||
|
||||
let predicate = obligation.predicate.skip_binder();
|
||||
|
||||
let Some(assume) = rustc_transmute::Assume::from_const(
|
||||
self.infcx.tcx,
|
||||
obligation.param_env,
|
||||
predicate.trait_ref.args.const_at(2),
|
||||
) else {
|
||||
let mut assume = predicate.trait_ref.args.const_at(2);
|
||||
// FIXME(min_generic_const_exprs): We should shallowly normalize this.
|
||||
if self.tcx().features().generic_const_exprs {
|
||||
assume = assume.normalize_internal(self.tcx(), obligation.param_env);
|
||||
}
|
||||
let Some(assume) =
|
||||
rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, assume)
|
||||
else {
|
||||
return Err(Unimplemented);
|
||||
};
|
||||
|
||||
|
|
|
@ -82,6 +82,8 @@ impl<'tcx> At<'_, 'tcx> {
|
|||
}
|
||||
|
||||
Ok(self.infcx.resolve_vars_if_possible(new_infer_ct))
|
||||
} else if self.infcx.tcx.features().generic_const_exprs {
|
||||
Ok(ct.normalize_internal(self.infcx.tcx, self.param_env))
|
||||
} else {
|
||||
Ok(self.normalize(ct).into_value_registering_obligations(self.infcx, fulfill_cx))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue