2022-08-15 23:21:39 +00:00
|
|
|
use std::ops::ControlFlow;
|
2021-07-03 16:18:13 +00:00
|
|
|
|
|
|
|
use super::{Byte, Def, Ref};
|
2024-07-28 22:13:50 +00:00
|
|
|
|
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 {
|
2024-10-28 00:21:23 +00:00
|
|
|
use rustc_abi::{
|
|
|
|
FieldIdx, FieldsShape, Layout, Size, TagEncoding, TyAndLayout, VariantIdx, Variants,
|
|
|
|
};
|
2024-08-14 20:10:28 +00:00
|
|
|
use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError};
|
2023-04-06 01:58:53 +00:00
|
|
|
use rustc_middle::ty::{self, AdtDef, AdtKind, List, ScalarInt, Ty, TyCtxt, TypeVisitableExt};
|
|
|
|
use rustc_span::ErrorGuaranteed;
|
2024-07-28 22:13:50 +00:00
|
|
|
|
2023-04-06 01:58:53 +00:00
|
|
|
use super::Tree;
|
2024-08-21 17:01:32 +00:00
|
|
|
use crate::layout::rustc::{Def, Ref, layout_of};
|
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 {
|
2024-10-01 20:52:17 +00:00
|
|
|
LayoutError::Unknown(..)
|
|
|
|
| LayoutError::ReferencesError(..)
|
|
|
|
| LayoutError::NormalizationFailure(..) => 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),
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
|
2024-09-15 19:59:51 +00:00
|
|
|
pub(crate) fn from_ty(ty: Ty<'tcx>, cx: LayoutCx<'tcx>) -> Result<Self, Err> {
|
2024-10-28 00:21:23 +00:00
|
|
|
use rustc_abi::HasDataLayout;
|
2024-08-21 17:01:32 +00:00
|
|
|
let layout = layout_of(cx, ty)?;
|
2021-07-03 16:18:13 +00:00
|
|
|
|
2024-08-14 20:10:28 +00:00
|
|
|
if let Err(e) = ty.error_reported() {
|
2023-04-06 01:58:53 +00:00
|
|
|
return Err(Err::TypeError(e));
|
|
|
|
}
|
|
|
|
|
2024-09-15 20:16:21 +00:00
|
|
|
let target = cx.data_layout();
|
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 pointer_size = target.pointer_size;
|
2021-07-03 16:18:13 +00:00
|
|
|
|
2024-08-14 20:10:28 +00:00
|
|
|
match 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
|
|
|
}
|
|
|
|
|
2024-08-14 20:10:28 +00:00
|
|
|
ty::Tuple(members) => Self::from_tuple((ty, 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) => {
|
2024-08-14 20:10:28 +00:00
|
|
|
let FieldsShape::Array { stride, count } = &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
|
|
|
};
|
2024-08-21 17:01:32 +00:00
|
|
|
let inner_layout = layout_of(cx, *inner_ty)?;
|
2024-08-14 20:10:28 +00:00
|
|
|
assert_eq!(*stride, inner_layout.size);
|
|
|
|
let elt = Tree::from_ty(*inner_ty, cx)?;
|
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
|
|
|
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
|
|
|
|
2024-08-14 20:10:28 +00:00
|
|
|
ty::Adt(adt_def, _args_ref) if !ty.is_box() => match adt_def.adt_kind() {
|
|
|
|
AdtKind::Struct => Self::from_struct((ty, layout), *adt_def, cx),
|
|
|
|
AdtKind::Enum => Self::from_enum((ty, layout), *adt_def, cx),
|
|
|
|
AdtKind::Union => Self::from_union((ty, layout), *adt_def, cx),
|
|
|
|
},
|
2023-04-21 23:49:36 +00:00
|
|
|
|
|
|
|
ty::Ref(lifetime, ty, mutability) => {
|
2024-08-21 17:01:32 +00:00
|
|
|
let layout = layout_of(cx, *ty)?;
|
2024-08-14 20:10:28 +00:00
|
|
|
let align = layout.align.abi.bytes_usize();
|
|
|
|
let size = 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(
|
2024-08-14 20:10:28 +00:00
|
|
|
(ty, layout): (Ty<'tcx>, Layout<'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
|
|
|
members: &'tcx List<Ty<'tcx>>,
|
2024-09-15 19:59:51 +00:00
|
|
|
cx: LayoutCx<'tcx>,
|
2021-07-03 16:18:13 +00:00
|
|
|
) -> Result<Self, Err> {
|
2024-08-14 20:10:28 +00:00
|
|
|
match &layout.fields {
|
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
|
|
|
FieldsShape::Primitive => {
|
|
|
|
assert_eq!(members.len(), 1);
|
|
|
|
let inner_ty = members[0];
|
2024-08-21 17:01:32 +00:00
|
|
|
let inner_layout = layout_of(cx, inner_ty)?;
|
2024-08-14 20:10:28 +00:00
|
|
|
Self::from_ty(inner_ty, cx)
|
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
|
|
|
}
|
|
|
|
FieldsShape::Arbitrary { offsets, .. } => {
|
|
|
|
assert_eq!(offsets.len(), members.len());
|
2024-08-14 20:10:28 +00:00
|
|
|
Self::from_variant(Def::Primitive, None, (ty, layout), layout.size, cx)
|
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
|
|
|
}
|
|
|
|
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(
|
2024-08-14 20:10:28 +00:00
|
|
|
(ty, layout): (Ty<'tcx>, Layout<'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
|
|
|
def: AdtDef<'tcx>,
|
2024-09-15 19:59:51 +00:00
|
|
|
cx: LayoutCx<'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
|
|
|
) -> Result<Self, Err> {
|
|
|
|
assert!(def.is_struct());
|
|
|
|
let def = Def::Adt(def);
|
2024-08-14 20:10:28 +00:00
|
|
|
Self::from_variant(def, None, (ty, layout), layout.size, cx)
|
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 an enum.
|
|
|
|
///
|
|
|
|
/// # Panics
|
|
|
|
///
|
|
|
|
/// Panics if `def` is not an enum definition.
|
|
|
|
fn from_enum(
|
2024-08-14 20:10:28 +00:00
|
|
|
(ty, layout): (Ty<'tcx>, Layout<'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
|
|
|
def: AdtDef<'tcx>,
|
2024-09-15 19:59:51 +00:00
|
|
|
cx: LayoutCx<'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
|
|
|
) -> Result<Self, Err> {
|
|
|
|
assert!(def.is_enum());
|
|
|
|
|
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.
|
2024-09-14 21:52:03 +00:00
|
|
|
let layout_of_variant = |index, encoding: Option<TagEncoding<VariantIdx>>| {
|
2024-09-15 20:16:21 +00:00
|
|
|
let tag = cx.tcx().tag_for_variant((cx.tcx().erase_regions(ty), index));
|
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
|
|
|
let variant_def = Def::Variant(def.variant(index));
|
2024-08-14 20:10:28 +00:00
|
|
|
let variant_layout = ty_variant(cx, (ty, layout), index);
|
2024-09-14 21:52:03 +00:00
|
|
|
Self::from_variant(
|
|
|
|
variant_def,
|
|
|
|
tag.map(|tag| (tag, index, encoding.unwrap())),
|
|
|
|
(ty, variant_layout),
|
|
|
|
layout.size,
|
|
|
|
cx,
|
|
|
|
)
|
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
|
|
|
};
|
|
|
|
|
|
|
|
// We consider three kinds of enums, each demanding a different
|
|
|
|
// treatment of their layout computation:
|
safe transmute: support non-ZST, variantful, uninhabited enums
Previously, `Tree::from_enum`'s implementation branched into three disjoint
cases:
1. enums that uninhabited
2. enums for which all but one variant is uninhabited
3. enums with multiple inhabited variants
This branching (incorrectly) did not differentiate between variantful and
variantless uninhabited enums. In both cases, we assumed (and asserted) that
uninhabited enums are zero-sized types. This assumption is false for enums like:
enum Uninhabited { A(!, u128) }
...which, currently, has the same size as `u128`. This faulty assumption
manifested as the ICE reported in #126460.
In this PR, we revise the first case of `Tree::from_enum` to consider only the
narrow category of "enums that are uninhabited ZSTs". These enums, whose layouts
are described with `Variants::Single { index }`, are special in their layouts
otherwise resemble the `!` type and cannot be descended into like typical enums.
This first case captures uninhabited enums like:
enum Uninhabited { A(!, !), B(!) }
The second case is revised to consider the broader category of "enums that defer
their layout to one of their variants"; i.e., enums whose layouts are described
with `Variants::Single { index }` and that do have a variant at `index`. This
second case captures uninhabited enums that are not ZSTs, like:
enum Uninhabited { A(!, u128) }
...which represent their variants with `Variants::Single`.
Finally, the third case is revised to cover the broader category of "enums with
multiple variants", which captures uninhabited, non-ZST enums like:
enum Uninhabited { A(u8, !), B(!, u32) }
...which represent their variants with `Variants::Multiple`.
This PR also adds a comment requested by RalfJung in his review of #126358 to
`compiler/rustc_const_eval/src/interpret/discriminant.rs`.
Fixes #126460
2024-06-14 17:02:07 +00:00
|
|
|
// 1. enums that are uninhabited ZSTs
|
|
|
|
// 2. enums that delegate their layout to a variant
|
|
|
|
// 3. enums with multiple variants
|
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
|
|
|
match layout.variants() {
|
2024-10-28 04:34:49 +00:00
|
|
|
Variants::Single { .. } if layout.is_uninhabited() && layout.size == Size::ZERO => {
|
safe transmute: support non-ZST, variantful, uninhabited enums
Previously, `Tree::from_enum`'s implementation branched into three disjoint
cases:
1. enums that uninhabited
2. enums for which all but one variant is uninhabited
3. enums with multiple inhabited variants
This branching (incorrectly) did not differentiate between variantful and
variantless uninhabited enums. In both cases, we assumed (and asserted) that
uninhabited enums are zero-sized types. This assumption is false for enums like:
enum Uninhabited { A(!, u128) }
...which, currently, has the same size as `u128`. This faulty assumption
manifested as the ICE reported in #126460.
In this PR, we revise the first case of `Tree::from_enum` to consider only the
narrow category of "enums that are uninhabited ZSTs". These enums, whose layouts
are described with `Variants::Single { index }`, are special in their layouts
otherwise resemble the `!` type and cannot be descended into like typical enums.
This first case captures uninhabited enums like:
enum Uninhabited { A(!, !), B(!) }
The second case is revised to consider the broader category of "enums that defer
their layout to one of their variants"; i.e., enums whose layouts are described
with `Variants::Single { index }` and that do have a variant at `index`. This
second case captures uninhabited enums that are not ZSTs, like:
enum Uninhabited { A(!, u128) }
...which represent their variants with `Variants::Single`.
Finally, the third case is revised to cover the broader category of "enums with
multiple variants", which captures uninhabited, non-ZST enums like:
enum Uninhabited { A(u8, !), B(!, u32) }
...which represent their variants with `Variants::Multiple`.
This PR also adds a comment requested by RalfJung in his review of #126358 to
`compiler/rustc_const_eval/src/interpret/discriminant.rs`.
Fixes #126460
2024-06-14 17:02:07 +00:00
|
|
|
// The layout representation of uninhabited, ZST enums is
|
|
|
|
// defined to be like that of the `!` type, as opposed of a
|
|
|
|
// typical enum. Consequently, they cannot be descended into
|
|
|
|
// as if they typical enums. We therefore special-case this
|
|
|
|
// scenario and simply return an uninhabited `Tree`.
|
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
|
|
|
Ok(Self::uninhabited())
|
|
|
|
}
|
|
|
|
Variants::Single { index } => {
|
safe transmute: support non-ZST, variantful, uninhabited enums
Previously, `Tree::from_enum`'s implementation branched into three disjoint
cases:
1. enums that uninhabited
2. enums for which all but one variant is uninhabited
3. enums with multiple inhabited variants
This branching (incorrectly) did not differentiate between variantful and
variantless uninhabited enums. In both cases, we assumed (and asserted) that
uninhabited enums are zero-sized types. This assumption is false for enums like:
enum Uninhabited { A(!, u128) }
...which, currently, has the same size as `u128`. This faulty assumption
manifested as the ICE reported in #126460.
In this PR, we revise the first case of `Tree::from_enum` to consider only the
narrow category of "enums that are uninhabited ZSTs". These enums, whose layouts
are described with `Variants::Single { index }`, are special in their layouts
otherwise resemble the `!` type and cannot be descended into like typical enums.
This first case captures uninhabited enums like:
enum Uninhabited { A(!, !), B(!) }
The second case is revised to consider the broader category of "enums that defer
their layout to one of their variants"; i.e., enums whose layouts are described
with `Variants::Single { index }` and that do have a variant at `index`. This
second case captures uninhabited enums that are not ZSTs, like:
enum Uninhabited { A(!, u128) }
...which represent their variants with `Variants::Single`.
Finally, the third case is revised to cover the broader category of "enums with
multiple variants", which captures uninhabited, non-ZST enums like:
enum Uninhabited { A(u8, !), B(!, u32) }
...which represent their variants with `Variants::Multiple`.
This PR also adds a comment requested by RalfJung in his review of #126358 to
`compiler/rustc_const_eval/src/interpret/discriminant.rs`.
Fixes #126460
2024-06-14 17:02:07 +00:00
|
|
|
// `Variants::Single` on enums with variants denotes that
|
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
|
|
|
// the enum delegates its layout to the variant at `index`.
|
2024-09-14 21:52:03 +00:00
|
|
|
layout_of_variant(*index, None)
|
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
|
|
|
}
|
2024-09-14 21:52:03 +00:00
|
|
|
Variants::Multiple { tag, tag_encoding, tag_field, .. } => {
|
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
|
|
|
// `Variants::Multiple` denotes an enum with multiple
|
safe transmute: support non-ZST, variantful, uninhabited enums
Previously, `Tree::from_enum`'s implementation branched into three disjoint
cases:
1. enums that uninhabited
2. enums for which all but one variant is uninhabited
3. enums with multiple inhabited variants
This branching (incorrectly) did not differentiate between variantful and
variantless uninhabited enums. In both cases, we assumed (and asserted) that
uninhabited enums are zero-sized types. This assumption is false for enums like:
enum Uninhabited { A(!, u128) }
...which, currently, has the same size as `u128`. This faulty assumption
manifested as the ICE reported in #126460.
In this PR, we revise the first case of `Tree::from_enum` to consider only the
narrow category of "enums that are uninhabited ZSTs". These enums, whose layouts
are described with `Variants::Single { index }`, are special in their layouts
otherwise resemble the `!` type and cannot be descended into like typical enums.
This first case captures uninhabited enums like:
enum Uninhabited { A(!, !), B(!) }
The second case is revised to consider the broader category of "enums that defer
their layout to one of their variants"; i.e., enums whose layouts are described
with `Variants::Single { index }` and that do have a variant at `index`. This
second case captures uninhabited enums that are not ZSTs, like:
enum Uninhabited { A(!, u128) }
...which represent their variants with `Variants::Single`.
Finally, the third case is revised to cover the broader category of "enums with
multiple variants", which captures uninhabited, non-ZST enums like:
enum Uninhabited { A(u8, !), B(!, u32) }
...which represent their variants with `Variants::Multiple`.
This PR also adds a comment requested by RalfJung in his review of #126358 to
`compiler/rustc_const_eval/src/interpret/discriminant.rs`.
Fixes #126460
2024-06-14 17:02:07 +00:00
|
|
|
// variants. The layout of such an enum is the disjunction
|
|
|
|
// of the layouts of its tagged variants.
|
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
|
|
|
|
|
|
|
// 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)| {
|
2024-09-14 21:52:03 +00:00
|
|
|
let variant = layout_of_variant(idx, Some(tag_encoding.clone()))?;
|
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
|
|
|
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>,
|
2024-09-14 21:52:03 +00:00
|
|
|
tag: Option<(ScalarInt, VariantIdx, TagEncoding<VariantIdx>)>,
|
2024-08-14 20:10:28 +00:00
|
|
|
(ty, layout): (Ty<'tcx>, Layout<'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
|
|
|
total_size: Size,
|
2024-09-15 19:59:51 +00:00
|
|
|
cx: LayoutCx<'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
|
|
|
) -> Result<Self, Err> {
|
|
|
|
// This constructor does not support non-`FieldsShape::Arbitrary`
|
|
|
|
// layouts.
|
2024-08-14 20:10:28 +00:00
|
|
|
let FieldsShape::Arbitrary { offsets, memory_index } = layout.fields() else {
|
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
|
|
|
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.
|
2024-08-14 20:10:28 +00:00
|
|
|
assert!(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.
|
2024-09-14 21:52:03 +00:00
|
|
|
if let Some((tag, index, encoding)) = &tag {
|
|
|
|
match encoding {
|
|
|
|
TagEncoding::Direct => {
|
|
|
|
size += tag.size();
|
|
|
|
}
|
|
|
|
TagEncoding::Niche { niche_variants, .. } => {
|
|
|
|
if !niche_variants.contains(index) {
|
|
|
|
size += tag.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-09-15 20:16:21 +00:00
|
|
|
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();
|
2024-08-14 20:10:28 +00:00
|
|
|
for (memory_idx, &field_idx) in inverse_memory_index.iter_enumerated() {
|
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
|
|
|
// Add interfield padding.
|
2024-08-14 20:10:28 +00:00
|
|
|
let padding_needed = offsets[field_idx] - size;
|
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 padding = Self::padding(padding_needed.bytes_usize());
|
|
|
|
|
2024-08-14 20:10:28 +00:00
|
|
|
let field_ty = ty_field(cx, (ty, layout), field_idx);
|
2024-08-21 17:01:32 +00:00
|
|
|
let field_layout = layout_of(cx, field_ty)?;
|
2024-08-14 20:10:28 +00:00
|
|
|
let field_tree = Self::from_ty(field_ty, cx)?;
|
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
|
|
|
|
|
|
|
struct_tree = struct_tree.then(padding).then(field_tree);
|
|
|
|
|
2024-08-14 20:10:28 +00:00
|
|
|
size += padding_needed + field_layout.size;
|
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
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2024-10-28 00:21:23 +00:00
|
|
|
use rustc_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(
|
2024-08-14 20:10:28 +00:00
|
|
|
(ty, layout): (Ty<'tcx>, Layout<'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
|
|
|
def: AdtDef<'tcx>,
|
2024-09-15 19:59:51 +00:00
|
|
|
cx: LayoutCx<'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
|
|
|
) -> Result<Self, Err> {
|
|
|
|
assert!(def.is_union());
|
|
|
|
|
|
|
|
// This constructor does not support non-`FieldsShape::Union`
|
|
|
|
// layouts. Fields of this shape are all placed at offset 0.
|
2024-08-14 20:10:28 +00:00
|
|
|
let FieldsShape::Union(fields) = layout.fields() else {
|
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
|
|
|
return Err(Err::NotYetSupported);
|
|
|
|
};
|
|
|
|
|
|
|
|
let fields = &def.non_enum_variant().fields;
|
|
|
|
let fields = fields.iter_enumerated().try_fold(
|
|
|
|
Self::uninhabited(),
|
2024-08-14 20:10:28 +00:00
|
|
|
|fields, (idx, field_def)| {
|
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 field_def = Def::Field(field_def);
|
2024-08-14 20:10:28 +00:00
|
|
|
let field_ty = ty_field(cx, (ty, layout), idx);
|
2024-08-21 17:01:32 +00:00
|
|
|
let field_layout = layout_of(cx, field_ty)?;
|
2024-08-14 20:10:28 +00:00
|
|
|
let field = Self::from_ty(field_ty, cx)?;
|
|
|
|
let trailing_padding_needed = layout.size - field_layout.size;
|
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 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
|
|
|
}
|
2024-08-14 20:10:28 +00:00
|
|
|
|
|
|
|
fn ty_field<'tcx>(
|
2024-09-15 19:59:51 +00:00
|
|
|
cx: LayoutCx<'tcx>,
|
2024-08-14 20:10:28 +00:00
|
|
|
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
|
|
|
i: FieldIdx,
|
|
|
|
) -> Ty<'tcx> {
|
|
|
|
match ty.kind() {
|
|
|
|
ty::Adt(def, args) => {
|
|
|
|
match layout.variants {
|
|
|
|
Variants::Single { index } => {
|
|
|
|
let field = &def.variant(index).fields[i];
|
2024-09-15 20:16:21 +00:00
|
|
|
field.ty(cx.tcx(), args)
|
2024-08-14 20:10:28 +00:00
|
|
|
}
|
|
|
|
// Discriminant field for enums (where applicable).
|
|
|
|
Variants::Multiple { tag, .. } => {
|
|
|
|
assert_eq!(i.as_usize(), 0);
|
2024-09-15 20:16:21 +00:00
|
|
|
ty::layout::PrimitiveExt::to_ty(&tag.primitive(), cx.tcx())
|
2024-08-14 20:10:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ty::Tuple(fields) => fields[i.as_usize()],
|
|
|
|
kind @ _ => unimplemented!(
|
|
|
|
"only a subset of `Ty::ty_and_layout_field`'s functionality is implemented. implementation needed for {:?}",
|
|
|
|
kind
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn ty_variant<'tcx>(
|
2024-09-15 19:59:51 +00:00
|
|
|
cx: LayoutCx<'tcx>,
|
2024-08-14 20:10:28 +00:00
|
|
|
(ty, layout): (Ty<'tcx>, Layout<'tcx>),
|
|
|
|
i: VariantIdx,
|
|
|
|
) -> Layout<'tcx> {
|
2024-09-15 20:16:21 +00:00
|
|
|
let ty = cx.tcx().erase_regions(ty);
|
2024-08-14 20:10:28 +00:00
|
|
|
TyAndLayout { ty, layout }.for_variant(&cx, i).layout
|
|
|
|
}
|
2021-07-03 16:18:13 +00:00
|
|
|
}
|