transmutability: shift abstraction boundary

Previously, `rustc_transmute`'s layout representations were genericized
over `R`, a reference. Now, it's instead genericized over
representations of type and region. This allows us to move reference
transmutability logic from `rustc_trait_selection` to
`rustc_transmutability` (and thus unit test it independently of the
compiler), and — in a follow-up PR — will make it possible to support
analyzing function pointer transmutability with minimal surgery.
This commit is contained in:
Jack Wrenn
2025-06-04 15:58:01 +00:00
parent 7c10378e1f
commit e9eae28eee
14 changed files with 385 additions and 357 deletions

View File

@@ -19,23 +19,29 @@ pub struct Assume {
/// Either transmutation is allowed, we have an error, or we have an optional
/// Condition that must hold.
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub enum Answer<R> {
pub enum Answer<R, T> {
Yes,
No(Reason<R>),
If(Condition<R>),
No(Reason<T>),
If(Condition<R, T>),
}
/// A condition which must hold for safe transmutation to be possible.
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
pub enum Condition<R> {
pub enum Condition<R, T> {
/// `Src` is transmutable into `Dst`, if `src` is transmutable into `dst`.
IfTransmutable { src: R, dst: R },
Transmutable { src: T, dst: T },
/// The region `long` must outlive `short`.
Outlives { long: R, short: R },
/// The `ty` is immutable.
Immutable { ty: T },
/// `Src` is transmutable into `Dst`, if all of the enclosed requirements are met.
IfAll(Vec<Condition<R>>),
IfAll(Vec<Condition<R, T>>),
/// `Src` is transmutable into `Dst` if any of the enclosed requirements are met.
IfAny(Vec<Condition<R>>),
IfAny(Vec<Condition<R, T>>),
}
/// Answers "why wasn't the source type transmutable into the destination type?"
@@ -53,12 +59,16 @@ pub enum Reason<T> {
DstMayHaveSafetyInvariants,
/// `Dst` is larger than `Src`, and the excess bytes were not exclusively uninitialized.
DstIsTooBig,
/// A referent of `Dst` is larger than a referent in `Src`.
/// `Dst` is larger `Src`.
DstRefIsTooBig {
/// The referent of the source type.
src: T,
/// The size of the source type's referent.
src_size: usize,
/// The too-large referent of the destination type.
dst: T,
/// The size of the destination type's referent.
dst_size: usize,
},
/// Src should have a stricter alignment than Dst, but it does not.
DstHasStricterAlignment { src_min_align: usize, dst_min_align: usize },
@@ -79,7 +89,7 @@ pub enum Reason<T> {
#[cfg(feature = "rustc")]
mod rustc {
use rustc_hir::lang_items::LangItem;
use rustc_middle::ty::{Const, Ty, TyCtxt};
use rustc_middle::ty::{Const, Region, Ty, TyCtxt};
use super::*;
@@ -105,7 +115,7 @@ mod rustc {
&mut self,
types: Types<'tcx>,
assume: crate::Assume,
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
) -> crate::Answer<Region<'tcx>, Ty<'tcx>> {
crate::maybe_transmutable::MaybeTransmutableQuery::new(
types.src, types.dst, assume, self.tcx,
)