2021-07-03 16:18:13 +00:00
|
|
|
use super::{Byte, Def, Ref};
|
2022-08-15 23:21:39 +00:00
|
|
|
use std::ops::ControlFlow;
|
2021-07-03 16:18:13 +00:00
|
|
|
|
|
|
|
#[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<D, R>
|
|
|
|
where
|
|
|
|
D: Def,
|
|
|
|
R: Ref,
|
|
|
|
{
|
|
|
|
/// A sequence of successive layouts.
|
|
|
|
Seq(Vec<Self>),
|
|
|
|
/// A choice between alternative layouts.
|
|
|
|
Alt(Vec<Self>),
|
|
|
|
/// A definition node.
|
|
|
|
Def(D),
|
|
|
|
/// A reference node.
|
|
|
|
Ref(R),
|
|
|
|
/// A byte node.
|
|
|
|
Byte(Byte),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<D, R> Tree<D, R>
|
|
|
|
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.
|
|
|
|
pub(crate) fn padding(width_in_bytes: usize) -> Self {
|
|
|
|
Self::Seq(vec![Self::uninit(); width_in_bytes])
|
|
|
|
}
|
|
|
|
|
2024-02-26 16:49:25 +00:00
|
|
|
/// Remove all `Def` nodes, and all branches of the layout for which `f`
|
|
|
|
/// produces `true`.
|
2021-07-03 16:18:13 +00:00
|
|
|
pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R>
|
|
|
|
where
|
|
|
|
F: Fn(D) -> bool,
|
|
|
|
{
|
|
|
|
match self {
|
2022-08-15 18:11:56 +00:00
|
|
|
Self::Seq(elts) => match elts.into_iter().map(|elt| elt.prune(f)).try_fold(
|
|
|
|
Tree::unit(),
|
|
|
|
|elts, elt| {
|
2021-07-03 16:18:13 +00:00
|
|
|
if elt == Tree::uninhabited() {
|
2022-08-15 23:21:39 +00:00
|
|
|
ControlFlow::Break(Tree::uninhabited())
|
2021-07-03 16:18:13 +00:00
|
|
|
} else {
|
2022-08-15 23:21:39 +00:00
|
|
|
ControlFlow::Continue(elts.then(elt))
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
2022-08-15 18:11:56 +00:00
|
|
|
},
|
|
|
|
) {
|
2022-08-15 23:21:39 +00:00
|
|
|
ControlFlow::Break(node) | ControlFlow::Continue(node) => node,
|
2022-08-15 18:11:56 +00:00
|
|
|
},
|
2021-07-03 16:18:13 +00:00
|
|
|
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) => {
|
2024-02-26 16:49:25 +00:00
|
|
|
if f(d) {
|
2021-07-03 16:18:13 +00:00
|
|
|
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<D, R> Tree<D, R>
|
|
|
|
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]),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(feature = "rustc")]
|
|
|
|
pub(crate) mod rustc {
|
2023-04-06 01:58:53 +00:00
|
|
|
use super::Tree;
|
2021-07-03 16:18:13 +00:00
|
|
|
use crate::layout::rustc::{Def, Ref};
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
use rustc_middle::ty::layout::HasTyCtxt;
|
|
|
|
use rustc_middle::ty::layout::LayoutCx;
|
2021-07-03 16:18:13 +00:00
|
|
|
use rustc_middle::ty::layout::LayoutError;
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
use rustc_middle::ty::layout::LayoutOf;
|
2021-07-03 16:18:13 +00:00
|
|
|
use rustc_middle::ty::AdtDef;
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
use rustc_middle::ty::AdtKind;
|
|
|
|
use rustc_middle::ty::List;
|
2024-03-20 17:45:14 +00:00
|
|
|
use rustc_middle::ty::ScalarInt;
|
2023-04-06 01:58:53 +00:00
|
|
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
|
|
|
use rustc_span::ErrorGuaranteed;
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
use rustc_target::abi::FieldsShape;
|
|
|
|
use rustc_target::abi::Size;
|
|
|
|
use rustc_target::abi::TyAndLayout;
|
|
|
|
use rustc_target::abi::Variants;
|
2021-07-03 16:18:13 +00:00
|
|
|
|
2023-04-06 01:58:53 +00:00
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
pub(crate) enum Err {
|
2024-03-15 17:11:11 +00:00
|
|
|
/// The layout of the type is not yet supported.
|
|
|
|
NotYetSupported,
|
2023-04-06 01:58:53 +00:00
|
|
|
/// This error will be surfaced elsewhere by rustc, so don't surface it.
|
2023-06-12 23:35:23 +00:00
|
|
|
UnknownLayout,
|
2023-09-03 02:58:13 +00:00
|
|
|
/// Overflow size
|
|
|
|
SizeOverflow,
|
2023-04-06 01:58:53 +00:00
|
|
|
TypeError(ErrorGuaranteed),
|
|
|
|
}
|
|
|
|
|
2023-04-30 21:05:27 +00:00
|
|
|
impl<'tcx> From<&LayoutError<'tcx>> for Err {
|
|
|
|
fn from(err: &LayoutError<'tcx>) -> Self {
|
2021-07-03 16:18:13 +00:00
|
|
|
match err {
|
2023-07-16 23:26:02 +00:00
|
|
|
LayoutError::Unknown(..) | LayoutError::ReferencesError(..) => Self::UnknownLayout,
|
2023-09-03 02:58:13 +00:00
|
|
|
LayoutError::SizeOverflow(..) => Self::SizeOverflow,
|
2024-01-09 14:46:30 +00:00
|
|
|
LayoutError::Cycle(err) => Self::TypeError(*err),
|
2023-04-15 17:17:08 +00:00
|
|
|
err => unimplemented!("{:?}", err),
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
pub fn from_ty(
|
|
|
|
ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
|
|
|
|
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
|
|
|
) -> Result<Self, Err> {
|
2021-07-03 16:18:13 +00:00
|
|
|
use rustc_target::abi::HasDataLayout;
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
if let Err(e) = ty_and_layout.ty.error_reported() {
|
2023-04-06 01:58:53 +00:00
|
|
|
return Err(Err::TypeError(e));
|
|
|
|
}
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
let target = cx.tcx.data_layout();
|
|
|
|
let pointer_size = target.pointer_size;
|
2021-07-03 16:18:13 +00:00
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
match ty_and_layout.ty.kind() {
|
2021-07-03 16:18:13 +00:00
|
|
|
ty::Bool => Ok(Self::bool()),
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
ty::Float(nty) => {
|
|
|
|
let width = nty.bit_width() / 8;
|
|
|
|
Ok(Self::number(width as _))
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
ty::Int(nty) => {
|
|
|
|
let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8;
|
|
|
|
Ok(Self::number(width as _))
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
ty::Uint(nty) => {
|
|
|
|
let width = nty.normalize(pointer_size.bits() as _).bit_width().unwrap() / 8;
|
|
|
|
Ok(Self::number(width as _))
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
ty::Tuple(members) => Self::from_tuple(ty_and_layout, members, cx),
|
2021-07-03 16:18:13 +00:00
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
ty::Array(inner_ty, len) => {
|
|
|
|
let FieldsShape::Array { stride, count } = &ty_and_layout.fields else {
|
2024-03-15 17:11:11 +00:00
|
|
|
return Err(Err::NotYetSupported);
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
};
|
|
|
|
let inner_ty_and_layout = cx.layout_of(*inner_ty)?;
|
|
|
|
assert_eq!(*stride, inner_ty_and_layout.size);
|
|
|
|
let elt = Tree::from_ty(inner_ty_and_layout, cx)?;
|
|
|
|
Ok(std::iter::repeat(elt)
|
|
|
|
.take(*count as usize)
|
|
|
|
.fold(Tree::unit(), |tree, elt| tree.then(elt)))
|
|
|
|
}
|
2021-07-03 16:18:13 +00:00
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
ty::Adt(adt_def, _args_ref) if !ty_and_layout.ty.is_box() => {
|
|
|
|
match adt_def.adt_kind() {
|
|
|
|
AdtKind::Struct => Self::from_struct(ty_and_layout, *adt_def, cx),
|
|
|
|
AdtKind::Enum => Self::from_enum(ty_and_layout, *adt_def, cx),
|
|
|
|
AdtKind::Union => Self::from_union(ty_and_layout, *adt_def, cx),
|
|
|
|
}
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
2023-04-21 23:49:36 +00:00
|
|
|
|
|
|
|
ty::Ref(lifetime, ty, mutability) => {
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
let ty_and_layout = cx.layout_of(*ty)?;
|
2024-05-01 13:57:33 +00:00
|
|
|
let align = ty_and_layout.align.abi.bytes_usize();
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
let size = ty_and_layout.size.bytes_usize();
|
2023-04-21 23:49:36 +00:00
|
|
|
Ok(Tree::Ref(Ref {
|
|
|
|
lifetime: *lifetime,
|
|
|
|
ty: *ty,
|
|
|
|
mutability: *mutability,
|
|
|
|
align,
|
2024-03-13 00:11:36 +00:00
|
|
|
size,
|
2023-04-21 23:49:36 +00:00
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2024-03-15 17:11:11 +00:00
|
|
|
_ => Err(Err::NotYetSupported),
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
/// Constructs a `Tree` from a tuple.
|
|
|
|
fn from_tuple(
|
|
|
|
ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
|
|
|
|
members: &'tcx List<Ty<'tcx>>,
|
|
|
|
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
2021-07-03 16:18:13 +00:00
|
|
|
) -> Result<Self, Err> {
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
match &ty_and_layout.fields {
|
|
|
|
FieldsShape::Primitive => {
|
|
|
|
assert_eq!(members.len(), 1);
|
|
|
|
let inner_ty = members[0];
|
|
|
|
let inner_ty_and_layout = cx.layout_of(inner_ty)?;
|
|
|
|
assert_eq!(ty_and_layout.layout, inner_ty_and_layout.layout);
|
|
|
|
Self::from_ty(inner_ty_and_layout, cx)
|
|
|
|
}
|
|
|
|
FieldsShape::Arbitrary { offsets, .. } => {
|
|
|
|
assert_eq!(offsets.len(), members.len());
|
|
|
|
Self::from_variant(Def::Primitive, None, ty_and_layout, ty_and_layout.size, cx)
|
|
|
|
}
|
|
|
|
FieldsShape::Array { .. } | FieldsShape::Union(_) => Err(Err::NotYetSupported),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a `Tree` from a struct.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if `def` is not a struct definition.
|
|
|
|
fn from_struct(
|
|
|
|
ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
|
|
|
|
def: AdtDef<'tcx>,
|
|
|
|
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
|
|
|
) -> Result<Self, Err> {
|
|
|
|
assert!(def.is_struct());
|
|
|
|
let def = Def::Adt(def);
|
|
|
|
Self::from_variant(def, None, ty_and_layout, ty_and_layout.size, cx)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Constructs a `Tree` from an enum.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if `def` is not an enum definition.
|
|
|
|
fn from_enum(
|
|
|
|
ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
|
|
|
|
def: AdtDef<'tcx>,
|
|
|
|
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
|
|
|
) -> Result<Self, Err> {
|
|
|
|
assert!(def.is_enum());
|
|
|
|
let layout = ty_and_layout.layout;
|
|
|
|
|
safe transmute: support `Variants::Single` enums
Previously, the implementation of `Tree::from_enum` incorrectly
treated enums with `Variants::Single` and `Variants::Multiple`
identically. This is incorrect for `Variants::Single` enums,
which delegate their layout to that of a variant with a particular
index (or no variant at all if the enum is empty).
This flaw manifested first as an ICE. `Tree::from_enum` attempted
to compute the tag of variants other than the one at
`Variants::Single`'s `index`, and fell afoul of a sanity-checking
assertion in `compiler/rustc_const_eval/src/interpret/discriminant.rs`.
This assertion is non-load-bearing, and can be removed; the routine
its in is well-behaved even without it.
With the assertion removed, the proximate issue becomes apparent:
calling `Tree::from_variant` on a variant that does not exist is
ill-defined. A sanity check the given variant has
`FieldShapes::Arbitrary` fails, and the analysis is (correctly)
aborted with `Err::NotYetSupported`.
This commit corrects this chain of failures by ensuring that
`Tree::from_variant` is not called on variants that are, as far as
layout is concerned, nonexistent. Specifically, the implementation
of `Tree::from_enum` is now partitioned into three cases:
1. enums that are uninhabited
2. enums for which all but one variant is uninhabited
3. enums with multiple inhabited variants
`Tree::from_variant` is now only invoked in the third case. In the
first case, `Tree::uninhabited()` is produced. In the second case,
the layout is delegated to `Variants::Single`'s index.
Fixes #125811
2024-06-12 22:07:37 +00:00
|
|
|
// Computes the variant of a given index.
|
|
|
|
let layout_of_variant = |index| {
|
|
|
|
let tag = cx.tcx.tag_for_variant((ty_and_layout.ty, index));
|
|
|
|
let variant_def = Def::Variant(def.variant(index));
|
|
|
|
let variant_ty_and_layout = ty_and_layout.for_variant(&cx, index);
|
|
|
|
Self::from_variant(variant_def, tag, variant_ty_and_layout, layout.size, cx)
|
|
|
|
};
|
|
|
|
|
|
|
|
// We consider three kinds of enums, each demanding a different
|
|
|
|
// treatment of their layout computation:
|
|
|
|
// 1. enums that are uninhabited
|
|
|
|
// 2. enums for which all but one variant is uninhabited
|
|
|
|
// 3. enums with multiple inhabited variants
|
|
|
|
match layout.variants() {
|
|
|
|
_ if layout.abi.is_uninhabited() => {
|
|
|
|
// Uninhabited enums are usually (always?) zero-sized. In
|
|
|
|
// the (unlikely?) event that an uninhabited enum is
|
|
|
|
// non-zero-sized, this assert will trigger an ICE, and this
|
|
|
|
// code should be modified such that a `layout.size` amount
|
|
|
|
// of uninhabited bytes is returned instead.
|
|
|
|
//
|
|
|
|
// Uninhabited enums are currently implemented such that
|
|
|
|
// their layout is described with `Variants::Single`, even
|
|
|
|
// though they don't necessarily have a 'single' variant to
|
|
|
|
// defer to. That said, we don't bother specifically
|
|
|
|
// matching on `Variants::Single` in this arm because the
|
|
|
|
// behavioral principles here remain true even if, for
|
|
|
|
// whatever reason, the compiler describes an uninhabited
|
|
|
|
// enum with `Variants::Multiple`.
|
|
|
|
assert_eq!(layout.size, Size::ZERO);
|
|
|
|
Ok(Self::uninhabited())
|
|
|
|
}
|
|
|
|
Variants::Single { index } => {
|
|
|
|
// `Variants::Single` on non-uninhabited enums denotes that
|
|
|
|
// the enum delegates its layout to the variant at `index`.
|
|
|
|
layout_of_variant(*index)
|
|
|
|
}
|
|
|
|
Variants::Multiple { tag_field, .. } => {
|
|
|
|
// `Variants::Multiple` denotes an enum with multiple
|
|
|
|
// inhabited variants. The layout of such an enum is the
|
|
|
|
// disjunction of the layouts of its tagged variants.
|
|
|
|
|
|
|
|
// For enums (but not coroutines), the tag field is
|
|
|
|
// currently always the first field of the layout.
|
|
|
|
assert_eq!(*tag_field, 0);
|
|
|
|
|
|
|
|
let variants = def.discriminants(cx.tcx()).try_fold(
|
|
|
|
Self::uninhabited(),
|
|
|
|
|variants, (idx, ref discriminant)| {
|
|
|
|
let variant = layout_of_variant(idx)?;
|
|
|
|
Result::<Self, Err>::Ok(variants.or(variant))
|
|
|
|
},
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
)?;
|
2021-07-03 16:18:13 +00:00
|
|
|
|
safe transmute: support `Variants::Single` enums
Previously, the implementation of `Tree::from_enum` incorrectly
treated enums with `Variants::Single` and `Variants::Multiple`
identically. This is incorrect for `Variants::Single` enums,
which delegate their layout to that of a variant with a particular
index (or no variant at all if the enum is empty).
This flaw manifested first as an ICE. `Tree::from_enum` attempted
to compute the tag of variants other than the one at
`Variants::Single`'s `index`, and fell afoul of a sanity-checking
assertion in `compiler/rustc_const_eval/src/interpret/discriminant.rs`.
This assertion is non-load-bearing, and can be removed; the routine
its in is well-behaved even without it.
With the assertion removed, the proximate issue becomes apparent:
calling `Tree::from_variant` on a variant that does not exist is
ill-defined. A sanity check the given variant has
`FieldShapes::Arbitrary` fails, and the analysis is (correctly)
aborted with `Err::NotYetSupported`.
This commit corrects this chain of failures by ensuring that
`Tree::from_variant` is not called on variants that are, as far as
layout is concerned, nonexistent. Specifically, the implementation
of `Tree::from_enum` is now partitioned into three cases:
1. enums that are uninhabited
2. enums for which all but one variant is uninhabited
3. enums with multiple inhabited variants
`Tree::from_variant` is now only invoked in the third case. In the
first case, `Tree::uninhabited()` is produced. In the second case,
the layout is delegated to `Variants::Single`'s index.
Fixes #125811
2024-06-12 22:07:37 +00:00
|
|
|
return Ok(Self::def(Def::Adt(def)).then(variants));
|
|
|
|
}
|
|
|
|
}
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
}
|
2021-07-03 16:18:13 +00:00
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
/// Constructs a `Tree` from a 'variant-like' layout.
|
|
|
|
///
|
|
|
|
/// A 'variant-like' layout includes those of structs and, of course,
|
|
|
|
/// enum variants. Pragmatically speaking, this method supports anything
|
|
|
|
/// with `FieldsShape::Arbitrary`.
|
|
|
|
///
|
|
|
|
/// Note: This routine assumes that the optional `tag` is the first
|
|
|
|
/// field, and enum callers should check that `tag_field` is, in fact,
|
|
|
|
/// `0`.
|
|
|
|
fn from_variant(
|
|
|
|
def: Def<'tcx>,
|
|
|
|
tag: Option<ScalarInt>,
|
|
|
|
ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
|
|
|
|
total_size: Size,
|
|
|
|
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
|
|
|
) -> Result<Self, Err> {
|
|
|
|
// This constructor does not support non-`FieldsShape::Arbitrary`
|
|
|
|
// layouts.
|
|
|
|
let FieldsShape::Arbitrary { offsets, memory_index } = ty_and_layout.layout.fields()
|
|
|
|
else {
|
|
|
|
return Err(Err::NotYetSupported);
|
|
|
|
};
|
2021-07-03 16:18:13 +00:00
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
// When this function is invoked with enum variants,
|
|
|
|
// `ty_and_layout.size` does not encompass the entire size of the
|
|
|
|
// enum. We rely on `total_size` for this.
|
|
|
|
assert!(ty_and_layout.size <= total_size);
|
2021-07-03 16:18:13 +00:00
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
let mut size = Size::ZERO;
|
|
|
|
let mut struct_tree = Self::def(def);
|
2021-07-03 16:18:13 +00:00
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
// If a `tag` is provided, place it at the start of the layout.
|
|
|
|
if let Some(tag) = tag {
|
|
|
|
size += tag.size();
|
|
|
|
struct_tree = struct_tree.then(Self::from_tag(tag, cx.tcx));
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
// Append the fields, in memory order, to the layout.
|
|
|
|
let inverse_memory_index = memory_index.invert_bijective_mapping();
|
|
|
|
for (memory_idx, field_idx) in inverse_memory_index.iter_enumerated() {
|
|
|
|
// Add interfield padding.
|
|
|
|
let padding_needed = offsets[*field_idx] - size;
|
|
|
|
let padding = Self::padding(padding_needed.bytes_usize());
|
|
|
|
|
|
|
|
let field_ty_and_layout = ty_and_layout.field(&cx, field_idx.as_usize());
|
|
|
|
let field_tree = Self::from_ty(field_ty_and_layout, cx)?;
|
|
|
|
|
|
|
|
struct_tree = struct_tree.then(padding).then(field_tree);
|
|
|
|
|
|
|
|
size += padding_needed + field_ty_and_layout.size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add trailing padding.
|
|
|
|
let padding_needed = total_size - size;
|
|
|
|
let trailing_padding = Self::padding(padding_needed.bytes_usize());
|
|
|
|
|
|
|
|
Ok(struct_tree.then(trailing_padding))
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
/// Constructs a `Tree` representing the value of a enum tag.
|
|
|
|
fn from_tag(tag: ScalarInt, tcx: TyCtxt<'tcx>) -> Self {
|
2022-09-20 20:03:43 +00:00
|
|
|
use rustc_target::abi::Endian;
|
2024-03-20 17:45:14 +00:00
|
|
|
let size = tag.size();
|
2024-06-08 14:13:45 +00:00
|
|
|
let bits = tag.to_bits(size);
|
2022-09-20 20:03:43 +00:00
|
|
|
let bytes: [u8; 16];
|
|
|
|
let bytes = match tcx.data_layout.endian {
|
|
|
|
Endian::Little => {
|
2024-03-20 17:45:14 +00:00
|
|
|
bytes = bits.to_le_bytes();
|
|
|
|
&bytes[..size.bytes_usize()]
|
2022-09-20 20:03:43 +00:00
|
|
|
}
|
|
|
|
Endian::Big => {
|
2024-03-20 17:45:14 +00:00
|
|
|
bytes = bits.to_be_bytes();
|
|
|
|
&bytes[bytes.len() - size.bytes_usize()..]
|
2022-09-20 20:03:43 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
Self::Seq(bytes.iter().map(|&b| Self::from_bits(b)).collect())
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
|
Compute transmutability from `rustc_target::abi::Layout`
In its first step of computing transmutability, `rustc_transmutability`
constructs a byte-level representation of type layout (`Tree`). Previously, this
representation was computed for ADTs by inspecting the ADT definition and
performing our own layout computations. This process was error-prone, verbose,
and limited our ability to analyze many types (particularly default-repr types).
In this PR, we instead construct `Tree`s from `rustc_target::abi::Layout`s. This
helps ensure that layout optimizations are reflected our analyses, and increases
the kinds of types we can now analyze, including:
- default repr ADTs
- transparent unions
- `UnsafeCell`-containing types
Overall, this PR expands the expressvity of `rustc_transmutability` to be much
closer to the transmutability analysis performed by miri. Future PRs will work
to close the remaining gaps (e.g., support for `Box`, raw pointers, `NonZero*`,
coroutines, etc.).
2024-03-19 14:49:13 +00:00
|
|
|
/// Constructs a `Tree` from a union.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if `def` is not a union definition.
|
|
|
|
fn from_union(
|
|
|
|
ty_and_layout: TyAndLayout<'tcx, Ty<'tcx>>,
|
|
|
|
def: AdtDef<'tcx>,
|
|
|
|
cx: LayoutCx<'tcx, TyCtxt<'tcx>>,
|
|
|
|
) -> Result<Self, Err> {
|
|
|
|
assert!(def.is_union());
|
|
|
|
|
|
|
|
let union_layout = ty_and_layout.layout;
|
|
|
|
|
|
|
|
// This constructor does not support non-`FieldsShape::Union`
|
|
|
|
// layouts. Fields of this shape are all placed at offset 0.
|
|
|
|
let FieldsShape::Union(fields) = union_layout.fields() else {
|
|
|
|
return Err(Err::NotYetSupported);
|
|
|
|
};
|
|
|
|
|
|
|
|
let fields = &def.non_enum_variant().fields;
|
|
|
|
let fields = fields.iter_enumerated().try_fold(
|
|
|
|
Self::uninhabited(),
|
|
|
|
|fields, (idx, ref field_def)| {
|
|
|
|
let field_def = Def::Field(field_def);
|
|
|
|
let field_ty_and_layout = ty_and_layout.field(&cx, idx.as_usize());
|
|
|
|
let field = Self::from_ty(field_ty_and_layout, cx)?;
|
|
|
|
let trailing_padding_needed = union_layout.size - field_ty_and_layout.size;
|
|
|
|
let trailing_padding = Self::padding(trailing_padding_needed.bytes_usize());
|
|
|
|
let field_and_padding = field.then(trailing_padding);
|
|
|
|
Result::<Self, Err>::Ok(fields.or(field_and_padding))
|
|
|
|
},
|
|
|
|
)?;
|
|
|
|
|
|
|
|
Ok(Self::def(Def::Adt(def)).then(fields))
|
|
|
|
}
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
}
|