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.).
This commit is contained in:
Jack Wrenn
2024-03-19 14:49:13 +00:00
parent d6eb0f5a09
commit 3aa14e3b2e
32 changed files with 905 additions and 789 deletions

View File

@@ -33,6 +33,9 @@ mod rustc {
use super::*;
use crate::layout::tree::rustc::Err;
use rustc_middle::ty::layout::LayoutCx;
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::ParamEnv;
use rustc_middle::ty::Ty;
use rustc_middle::ty::TyCtxt;
@@ -43,12 +46,20 @@ mod rustc {
pub fn answer(self) -> Answer<<TyCtxt<'tcx> as QueryContext>::Ref> {
let Self { src, dst, assume, context } = self;
let layout_cx = LayoutCx { tcx: context, param_env: ParamEnv::reveal_all() };
let layout_of = |ty| {
layout_cx
.layout_of(ty)
.map_err(|_| Err::NotYetSupported)
.and_then(|tl| Tree::from_ty(tl, layout_cx))
};
// Convert `src` and `dst` from their rustc representations, to `Tree`-based
// representations. If these conversions fail, conclude that the transmutation is
// unacceptable; the layouts of both the source and destination types must be
// well-defined.
let src = Tree::from_ty(src, context);
let dst = Tree::from_ty(dst, context);
let src = layout_of(src);
let dst = layout_of(dst);
match (src, dst) {
(Err(Err::TypeError(_)), _) | (_, Err(Err::TypeError(_))) => {
@@ -86,6 +97,10 @@ where
// references.
let src = src.prune(&|def| false);
if src.is_inhabited() && !dst.is_inhabited() {
return Answer::No(Reason::DstUninhabited);
}
trace!(?src, "pruned src");
// Remove all `Def` nodes from `dst`, additionally...