| use std::fmt::{self, Debug}; | |
| use std::hash::Hash; | |
| use std::ops::RangeInclusive; | |
| pub(crate) mod tree; | |
| pub(crate) use tree::Tree; | |
| pub(crate) mod dfa; | |
| pub(crate) use dfa::{Dfa, union}; | |
| #[derive(Debug)] | |
| pub(crate) struct Uninhabited; | |
| /// A half-open range of byte values, which may include an uninitialized byte. | |
| /// | |
| /// The range is `[start, end)`. Values `0..=255` represent initialized bytes, | |
| /// and `256` represents an uninitialized byte. A range containing that value | |
| /// therefore has an exclusive upper bound of `257`. | |
| #[derive(Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] | |
| pub(crate) struct Byte { | |
| // Store the endpoints separately because `Range` is not `Copy`. | |
| pub(crate) start: u16, | |
| pub(crate) end: u16, | |
| } | |
| impl Byte { | |
| const UNINIT: u16 = 256; | |
| #[inline] | |
| fn new(range: RangeInclusive<u8>) -> Self { | |
| let start: u16 = (*range.start()).into(); | |
| let end: u16 = (*range.end()).into(); | |
| Byte { start, end: end + 1 } | |
| } | |
| #[inline] | |
| fn from_val(val: u8) -> Self { | |
| let val: u16 = val.into(); | |
| Byte { start: val, end: val + 1 } | |
| } | |
| /// A byte that may be initialized to any value or uninitialized. | |
| #[inline] | |
| fn uninit() -> Byte { | |
| Byte { start: 0, end: Self::UNINIT + 1 } | |
| } | |
| #[inline] | |
| fn is_empty(&self) -> bool { | |
| self.start == self.end | |
| } | |
| #[inline] | |
| fn contains_uninit(&self) -> bool { | |
| self.start <= Self::UNINIT && Self::UNINIT < self.end | |
| } | |
| } | |
| impl fmt::Debug for Byte { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| if self.start == Self::UNINIT && self.end == Self::UNINIT + 1 { | |
| write!(f, "uninit") | |
| } else if self.start <= Self::UNINIT && self.end == Self::UNINIT + 1 { | |
| write!(f, "{}..{}|uninit", self.start, self.end - 1) | |
| } else { | |
| write!(f, "{}..{}", self.start, self.end) | |
| } | |
| } | |
| } | |
| impl From<RangeInclusive<u8>> for Byte { | |
| fn from(src: RangeInclusive<u8>) -> Self { | |
| Self::new(src) | |
| } | |
| } | |
| impl From<u8> for Byte { | |
| #[inline] | |
| fn from(src: u8) -> Self { | |
| Self::from_val(src) | |
| } | |
| } | |
| /// A reference, i.e., `&'region T` or `&'region mut T`. | |
| #[derive(Debug, Hash, Eq, PartialEq, Ord, PartialOrd, Clone, Copy)] | |
| pub(crate) struct Reference<R, T> | |
| where | |
| R: Region, | |
| T: Type, | |
| { | |
| pub(crate) region: R, | |
| pub(crate) is_mut: bool, | |
| pub(crate) referent: T, | |
| pub(crate) referent_size: usize, | |
| pub(crate) referent_align: usize, | |
| } | |
| impl<R, T> fmt::Display for Reference<R, T> | |
| where | |
| R: Region, | |
| T: Type, | |
| { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| f.write_str("&")?; | |
| if self.is_mut { | |
| f.write_str("mut ")?; | |
| } | |
| self.referent.fmt(f) | |
| } | |
| } | |
| pub(crate) trait Def: Debug + Hash + Eq + PartialEq + Copy + Clone { | |
| fn has_safety_invariants(&self) -> bool; | |
| } | |
| pub(crate) trait Region: Debug + Hash + Eq + PartialEq + Copy + Clone {} | |
| pub(crate) trait Type: Debug + Hash + Eq + PartialEq + Copy + Clone {} | |
| impl Def for ! { | |
| fn has_safety_invariants(&self) -> bool { | |
| unreachable!() | |
| } | |
| } | |
| impl Region for ! {} | |
| impl Type for ! {} | |
| #[cfg(test)] | |
| impl Region for usize {} | |
| #[cfg(test)] | |
| impl Type for () {} | |
| #[cfg(feature = "rustc")] | |
| pub mod rustc { | |
| use rustc_abi::Layout; | |
| use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, LayoutError}; | |
| use rustc_middle::ty::{self, Region, Ty}; | |
| /// A layout annotation used to check for safety invariants during pruning. | |
| #[derive(Debug, Hash, Eq, PartialEq, Clone, Copy)] | |
| pub enum Def<'tcx> { | |
| Adt(ty::AdtDef<'tcx>), | |
| Variant(&'tcx ty::VariantDef), | |
| Field(&'tcx ty::FieldDef), | |
| Primitive, | |
| } | |
| impl<'tcx> super::Def for Def<'tcx> { | |
| fn has_safety_invariants(&self) -> bool { | |
| // Conservatively treat every ADT, variant, and field definition as | |
| // potentially carrying safety invariants. This check does not | |
| // inspect `unsafe` field annotations. | |
| self != &Self::Primitive | |
| } | |
| } | |
| impl<'tcx> super::Region for Region<'tcx> {} | |
| impl<'tcx> super::Type for Ty<'tcx> {} | |
| pub(crate) fn layout_of<'tcx>( | |
| cx: LayoutCx<'tcx>, | |
| ty: Ty<'tcx>, | |
| ) -> Result<Layout<'tcx>, &'tcx LayoutError<'tcx>> { | |
| use rustc_middle::ty::layout::LayoutOf; | |
| let ty = cx.tcx().erase_and_anonymize_regions(ty); | |
| cx.layout_of(ty).map(|tl| tl.layout) | |
| } | |
| } |