1 use super::{Byte, Def, Ref};
6 /// A tree-based representation of a type layout.
9 /// 1. All paths through the layout have the same length (in bytes).
12 /// 1. An `Alt` is never directly nested beneath another `Alt`.
13 /// 2. A `Seq` is never directly nested beneath another `Seq`.
14 /// 3. `Seq`s and `Alt`s with a single member do not exist.
15 #[derive(Clone, Debug, Hash, PartialEq, Eq)]
16 pub(crate) enum Tree<D, R>
21 /// A sequence of successive layouts.
23 /// A choice between alternative layouts.
25 /// A definition node.
38 /// A `Tree` consisting only of a definition node.
39 pub(crate) fn def(def: D) -> Self {
43 /// A `Tree` representing an uninhabited type.
44 pub(crate) fn uninhabited() -> Self {
48 /// A `Tree` representing a zero-sized type.
49 pub(crate) fn unit() -> Self {
53 /// A `Tree` containing a single, uninitialized byte.
54 pub(crate) fn uninit() -> Self {
55 Self::Byte(Byte::Uninit)
58 /// A `Tree` representing the layout of `bool`.
59 pub(crate) fn bool() -> Self {
60 Self::from_bits(0x00).or(Self::from_bits(0x01))
63 /// A `Tree` whose layout matches that of a `u8`.
64 pub(crate) fn u8() -> Self {
65 Self::Alt((0u8..=255).map(Self::from_bits).collect())
68 /// A `Tree` whose layout accepts exactly the given bit pattern.
69 pub(crate) fn from_bits(bits: u8) -> Self {
70 Self::Byte(Byte::Init(bits))
73 /// A `Tree` whose layout is a number of the given width.
74 pub(crate) fn number(width_in_bytes: usize) -> Self {
75 Self::Seq(vec![Self::u8(); width_in_bytes])
78 /// A `Tree` whose layout is entirely padding of the given width.
79 pub(crate) fn padding(width_in_bytes: usize) -> Self {
80 Self::Seq(vec![Self::uninit(); width_in_bytes])
83 /// Remove all `Def` nodes, and all branches of the layout for which `f` produces false.
84 pub(crate) fn prune<F>(self, f: &F) -> Tree<!, R>
89 Self::Seq(elts) => elts
91 .map(|elt| elt.prune(f))
92 .try_fold(Tree::unit(), |elts, elt| {
93 if elt == Tree::uninhabited() {
94 Err(Tree::uninhabited())
100 Self::Alt(alts) => alts
102 .map(|alt| alt.prune(f))
103 .fold(Tree::uninhabited(), |alts, alt| alts.or(alt)),
104 Self::Byte(b) => Tree::Byte(b),
105 Self::Ref(r) => Tree::Ref(r),
116 /// Produces `true` if `Tree` is an inhabited type; otherwise false.
117 pub(crate) fn is_inhabited(&self) -> bool {
119 Self::Seq(elts) => elts.into_iter().all(|elt| elt.is_inhabited()),
120 Self::Alt(alts) => alts.into_iter().any(|alt| alt.is_inhabited()),
121 Self::Byte(..) | Self::Ref(..) | Self::Def(..) => true,
126 impl<D, R> Tree<D, R>
131 /// Produces a new `Tree` where `other` is sequenced after `self`.
132 pub(crate) fn then(self, other: Self) -> Self {
133 match (self, other) {
134 (Self::Seq(elts), other) | (other, Self::Seq(elts)) if elts.len() == 0 => other,
135 (Self::Seq(mut lhs), Self::Seq(mut rhs)) => {
136 lhs.append(&mut rhs);
139 (Self::Seq(mut lhs), rhs) => {
143 (lhs, Self::Seq(mut rhs)) => {
147 (lhs, rhs) => Self::Seq(vec![lhs, rhs]),
151 /// Produces a new `Tree` accepting either `self` or `other` as alternative layouts.
152 pub(crate) fn or(self, other: Self) -> Self {
153 match (self, other) {
154 (Self::Alt(alts), other) | (other, Self::Alt(alts)) if alts.len() == 0 => other,
155 (Self::Alt(mut lhs), Self::Alt(rhs)) => {
159 (Self::Alt(mut alts), alt) | (alt, Self::Alt(mut alts)) => {
163 (lhs, rhs) => Self::Alt(vec![lhs, rhs]),
168 #[derive(Debug, Copy, Clone)]
169 pub(crate) enum Err {
170 /// The layout of the type is unspecified.
172 /// This error will be surfaced elsewhere by rustc, so don't surface it.
176 #[cfg(feature = "rustc")]
177 pub(crate) mod rustc {
178 use super::{Err, Tree};
179 use crate::layout::rustc::{Def, Ref};
181 use rustc_middle::ty;
182 use rustc_middle::ty::layout::LayoutError;
183 use rustc_middle::ty::util::Discr;
184 use rustc_middle::ty::AdtDef;
185 use rustc_middle::ty::ParamEnv;
186 use rustc_middle::ty::SubstsRef;
187 use rustc_middle::ty::Ty;
188 use rustc_middle::ty::TyCtxt;
189 use rustc_middle::ty::VariantDef;
190 use rustc_target::abi::Align;
193 impl<'tcx> From<LayoutError<'tcx>> for Err {
194 fn from(err: LayoutError<'tcx>) -> Self {
196 LayoutError::Unknown(..) => Self::Unknown,
197 err @ _ => unimplemented!("{:?}", err),
203 fn clamp_align(&self, min_align: Align, max_align: Align) -> Self;
206 impl LayoutExt for alloc::Layout {
207 fn clamp_align(&self, min_align: Align, max_align: Align) -> Self {
208 let min_align = min_align.bytes().try_into().unwrap();
209 let max_align = max_align.bytes().try_into().unwrap();
210 Self::from_size_align(self.size(), self.align().clamp(min_align, max_align)).unwrap()
214 struct LayoutSummary {
217 discriminant_size: usize,
218 discriminant_align: Align,
222 fn from_ty<'tcx>(ty: Ty<'tcx>, ctx: TyCtxt<'tcx>) -> Result<Self, LayoutError<'tcx>> {
223 use rustc_middle::ty::ParamEnvAnd;
224 use rustc_target::abi::{TyAndLayout, Variants};
226 let param_env = ParamEnv::reveal_all();
227 let param_env_and_type = ParamEnvAnd { param_env, value: ty };
228 let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
230 let total_size: usize = layout.size().bytes_usize();
231 let total_align: Align = layout.align().abi;
232 let discriminant_align: Align;
233 let discriminant_size: usize;
235 if let Variants::Multiple { tag, .. } = layout.variants() {
236 discriminant_align = tag.align(&ctx).abi;
237 discriminant_size = tag.size(&ctx).bytes_usize();
239 discriminant_align = Align::ONE;
240 discriminant_size = 0;
243 Ok(Self { total_align, total_size, discriminant_align, discriminant_size })
246 fn into(&self) -> alloc::Layout {
247 alloc::Layout::from_size_align(
249 self.total_align.bytes().try_into().unwrap(),
255 impl<'tcx> Tree<Def<'tcx>, Ref<'tcx>> {
256 pub fn from_ty(ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Result<Self, Err> {
257 use rustc_middle::ty::FloatTy::*;
258 use rustc_middle::ty::IntTy::*;
259 use rustc_middle::ty::UintTy::*;
260 use rustc_target::abi::HasDataLayout;
262 let target = tcx.data_layout();
265 ty::Bool => Ok(Self::bool()),
267 ty::Int(I8) | ty::Uint(U8) => Ok(Self::u8()),
268 ty::Int(I16) | ty::Uint(U16) => Ok(Self::number(2)),
269 ty::Int(I32) | ty::Uint(U32) | ty::Float(F32) => Ok(Self::number(4)),
270 ty::Int(I64) | ty::Uint(U64) | ty::Float(F64) => Ok(Self::number(8)),
271 ty::Int(I128) | ty::Uint(U128) => Ok(Self::number(16)),
272 ty::Int(Isize) | ty::Uint(Usize) => {
273 Ok(Self::number(target.pointer_size.bytes_usize()))
276 ty::Tuple(members) => {
277 if members.len() == 0 {
280 Err(Err::Unspecified)
284 ty::Array(ty, len) => {
285 let len = len.try_eval_usize(tcx, ParamEnv::reveal_all()).unwrap();
286 let elt = Tree::from_ty(*ty, tcx)?;
287 Ok(std::iter::repeat(elt)
289 .fold(Tree::unit(), |tree, elt| tree.then(elt)))
292 ty::Adt(adt_def, substs_ref) => {
293 use rustc_middle::ty::AdtKind;
295 // If the layout is ill-specified, halt.
296 if !(adt_def.repr().c() || adt_def.repr().int.is_some()) {
297 return Err(Err::Unspecified);
300 // Compute a summary of the type's layout.
301 let layout_summary = LayoutSummary::from_ty(ty, tcx)?;
303 // The layout begins with this adt's visibility.
304 let vis = Self::def(Def::Adt(*adt_def));
306 // And is followed the layout(s) of its variants
307 Ok(vis.then(match adt_def.adt_kind() {
308 AdtKind::Struct => Self::from_repr_c_variant(
314 adt_def.non_enum_variant(),
318 tracing::trace!(?adt_def, "treeifying enum");
319 let mut tree = Tree::uninhabited();
321 for (idx, discr) in adt_def.discriminants(tcx) {
322 tree = tree.or(Self::from_repr_c_variant(
328 adt_def.variant(idx),
336 // is the layout well-defined?
337 if !adt_def.repr().c() {
338 return Err(Err::Unspecified);
341 let ty_layout = layout_of(tcx, ty)?;
343 let mut tree = Tree::uninhabited();
345 for field in adt_def.all_fields() {
346 let variant_ty = field.ty(tcx, substs_ref);
347 let variant_layout = layout_of(tcx, variant_ty)?;
348 let padding_needed = ty_layout.size() - variant_layout.size();
349 let variant = Self::def(Def::Field(field))
350 .then(Self::from_ty(variant_ty, tcx)?)
351 .then(Self::padding(padding_needed));
353 tree = tree.or(variant);
360 _ => Err(Err::Unspecified),
364 fn from_repr_c_variant(
366 adt_def: AdtDef<'tcx>,
367 substs_ref: SubstsRef<'tcx>,
368 layout_summary: &LayoutSummary,
369 discr: Option<Discr<'tcx>>,
370 variant_def: &'tcx VariantDef,
372 ) -> Result<Self, Err> {
373 let mut tree = Tree::unit();
375 let repr = adt_def.repr();
376 let min_align = repr.align.unwrap_or(Align::ONE);
377 let max_align = repr.pack.unwrap_or(Align::MAX);
380 |align: Align| align.clamp(min_align, max_align).bytes().try_into().unwrap();
382 let variant_span = tracing::trace_span!(
383 "treeifying variant",
384 min_align = ?min_align,
385 max_align = ?max_align,
389 let mut variant_layout = alloc::Layout::from_size_align(
391 layout_summary.total_align.bytes().try_into().unwrap(),
395 // The layout of the variant is prefixed by the discriminant, if any.
396 if let Some(discr) = discr {
397 tracing::trace!(?discr, "treeifying discriminant");
398 let discr_layout = alloc::Layout::from_size_align(
399 layout_summary.discriminant_size,
400 clamp(layout_summary.discriminant_align),
403 tracing::trace!(?discr_layout, "computed discriminant layout");
404 variant_layout = variant_layout.extend(discr_layout).unwrap().0;
405 tree = tree.then(Self::from_disr(discr, tcx, layout_summary.discriminant_size));
409 let fields_span = tracing::trace_span!("treeifying fields").entered();
410 for field_def in variant_def.fields.iter() {
411 let field_ty = field_def.ty(tcx, substs_ref);
412 let _span = tracing::trace_span!("treeifying field", field = ?field_ty).entered();
414 // begin with the field's visibility
415 tree = tree.then(Self::def(Def::Field(field_def)));
417 // compute the field's layout charactaristics
418 let field_layout = layout_of(tcx, field_ty)?.clamp_align(min_align, max_align);
420 // next comes the field's padding
421 let padding_needed = variant_layout.padding_needed_for(field_layout.align());
422 if padding_needed > 0 {
423 tree = tree.then(Self::padding(padding_needed));
426 // finally, the field's layout
427 tree = tree.then(Self::from_ty(field_ty, tcx)?);
429 // extend the variant layout with the field layout
430 variant_layout = variant_layout.extend(field_layout).unwrap().0;
435 let padding_span = tracing::trace_span!("adding trailing padding").entered();
436 let padding_needed = layout_summary.total_size - variant_layout.size();
437 if padding_needed > 0 {
438 tree = tree.then(Self::padding(padding_needed));
445 pub fn from_disr(discr: Discr<'tcx>, tcx: TyCtxt<'tcx>, size: usize) -> Self {
446 // FIXME(@jswrenn): I'm certain this is missing needed endian nuance.
447 let bytes = discr.val.to_ne_bytes();
448 let bytes = &bytes[..size];
449 Self::Seq(bytes.into_iter().copied().map(|b| Self::from_bits(b)).collect())
456 ) -> Result<alloc::Layout, LayoutError<'tcx>> {
457 use rustc_middle::ty::ParamEnvAnd;
458 use rustc_target::abi::TyAndLayout;
460 let param_env = ParamEnv::reveal_all();
461 let param_env_and_type = ParamEnvAnd { param_env, value: ty };
462 let TyAndLayout { layout, .. } = ctx.layout_of(param_env_and_type)?;
463 let layout = alloc::Layout::from_size_align(
464 layout.size().bytes_usize(),
465 layout.align().abi.bytes().try_into().unwrap(),
468 tracing::trace!(?ty, ?layout, "computed layout for type");