X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=compiler%2Frustc_middle%2Fsrc%2Fmir%2Finterpret%2Fvalue.rs;fp=compiler%2Frustc_middle%2Fsrc%2Fmir%2Finterpret%2Fvalue.rs;h=834c114ee1c58d9067fc6ef4f161447200f5725a;hb=064997fbe6bce23c6cacf3455701f324c19f25ad;hp=e80918d5e5d032228ee7d329f9611a742d36471a;hpb=923072b8013b17b229df96598af0b6e0f8f869eb;p=rustc.git diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index e80918d5e5..834c114ee1 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -29,11 +29,14 @@ pub struct ConstAlloc<'tcx> { #[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] pub enum ConstValue<'tcx> { - /// Used only for types with `layout::abi::Scalar` ABI and ZSTs. + /// Used only for types with `layout::abi::Scalar` ABI. /// /// Not using the enum `Value` to encode that this must not be `Uninit`. Scalar(Scalar), + /// Only used for ZSTs. + ZeroSized, + /// Used only for `&[u8]` and `&str` Slice { data: ConstAllocation<'tcx>, start: usize, end: usize }, @@ -55,6 +58,7 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> { fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option> { Some(match self { ConstValue::Scalar(s) => ConstValue::Scalar(s), + ConstValue::ZeroSized => ConstValue::ZeroSized, ConstValue::Slice { data, start, end } => { ConstValue::Slice { data: tcx.lift(data)?, start, end } } @@ -69,7 +73,7 @@ impl<'tcx> ConstValue<'tcx> { #[inline] pub fn try_to_scalar(&self) -> Option> { match *self { - ConstValue::ByRef { .. } | ConstValue::Slice { .. } => None, + ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None, ConstValue::Scalar(val) => Some(val), } } @@ -111,10 +115,6 @@ impl<'tcx> ConstValue<'tcx> { pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self { ConstValue::Scalar(Scalar::from_machine_usize(i, cx)) } - - pub fn zst() -> Self { - Self::Scalar(Scalar::ZST) - } } /// A `Scalar` represents an immediate, primitive value existing outside of a @@ -126,7 +126,7 @@ impl<'tcx> ConstValue<'tcx> { /// Do *not* match on a `Scalar`! Use the various `to_*` methods instead. #[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, TyEncodable, TyDecodable, Hash)] #[derive(HashStable)] -pub enum Scalar { +pub enum Scalar { /// The raw bytes of a simple value. Int(ScalarInt), @@ -137,7 +137,7 @@ pub enum Scalar { /// We also store the size of the pointer, such that a `Scalar` always knows how big it is. /// The size is always the pointer size of the current target, but this is not information /// that we always have readily available. - Ptr(Pointer, u8), + Ptr(Pointer, u8), } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -145,7 +145,7 @@ static_assert_size!(Scalar, 24); // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. -impl fmt::Debug for Scalar { +impl fmt::Debug for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "{:?}", ptr), @@ -154,7 +154,7 @@ impl fmt::Debug for Scalar { } } -impl fmt::Display for Scalar { +impl fmt::Display for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr), @@ -163,48 +163,47 @@ impl fmt::Display for Scalar { } } -impl fmt::LowerHex for Scalar { +impl fmt::LowerHex for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr), - Scalar::Int(int) => write!(f, "0x{:x}", int), + Scalar::Int(int) => write!(f, "{:#x}", int), } } } -impl From for Scalar { +impl From for Scalar { #[inline(always)] fn from(f: Single) -> Self { Scalar::from_f32(f) } } -impl From for Scalar { +impl From for Scalar { #[inline(always)] fn from(f: Double) -> Self { Scalar::from_f64(f) } } -impl From for Scalar { +impl From for Scalar { #[inline(always)] fn from(ptr: ScalarInt) -> Self { Scalar::Int(ptr) } } -impl Scalar { - pub const ZST: Self = Scalar::Int(ScalarInt::ZST); - +impl Scalar { #[inline(always)] - pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { + pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { Scalar::Ptr(ptr, u8::try_from(cx.pointer_size().bytes()).unwrap()) } - /// Create a Scalar from a pointer with an `Option<_>` tag (where `None` represents a plain integer). - pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { + /// Create a Scalar from a pointer with an `Option<_>` provenance (where `None` represents a + /// plain integer / "invalid" pointer). + pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { match ptr.into_parts() { - (Some(tag), offset) => Scalar::from_pointer(Pointer::new(tag, offset), cx), + (Some(prov), offset) => Scalar::from_pointer(Pointer::new(prov, offset), cx), (None, offset) => { Scalar::Int(ScalarInt::try_from_uint(offset.bytes(), cx.pointer_size()).unwrap()) } @@ -312,7 +311,7 @@ impl Scalar { pub fn to_bits_or_ptr_internal( self, target_size: Size, - ) -> Result>, ScalarSizeMismatch> { + ) -> Result>, ScalarSizeMismatch> { assert_ne!(target_size.bytes(), 0, "you should never look at the bits of a ZST"); Ok(match self { Scalar::Int(int) => Ok(int.to_bits(target_size).map_err(|size| { @@ -331,7 +330,20 @@ impl Scalar { } } -impl<'tcx, Tag: Provenance> Scalar { +impl<'tcx, Prov: Provenance> Scalar { + pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer>> { + match self + .to_bits_or_ptr_internal(cx.pointer_size()) + .map_err(|s| err_ub!(ScalarSizeMismatch(s)))? + { + Err(ptr) => Ok(ptr.into()), + Ok(bits) => { + let addr = u64::try_from(bits).unwrap(); + Ok(Pointer::from_addr(addr)) + } + } + } + /// Fundamental scalar-to-int (cast) operation. Many convenience wrappers exist below, that you /// likely want to use instead. /// @@ -343,13 +355,13 @@ impl<'tcx, Tag: Provenance> Scalar { match self { Scalar::Int(int) => Ok(int), Scalar::Ptr(ptr, sz) => { - if Tag::OFFSET_IS_ADDR { + if Prov::OFFSET_IS_ADDR { Ok(ScalarInt::try_from_uint(ptr.offset.bytes(), Size::from_bytes(sz)).unwrap()) } else { // We know `offset` is relative, since `OFFSET_IS_ADDR == false`. - let (tag, offset) = ptr.into_parts(); + let (prov, offset) = ptr.into_parts(); // Because `OFFSET_IS_ADDR == false`, this unwrap can never fail. - Err(Scalar::Ptr(Pointer::new(tag.get_alloc_id().unwrap(), offset), sz)) + Err(Scalar::Ptr(Pointer::new(prov.get_alloc_id().unwrap(), offset), sz)) } } } @@ -491,24 +503,24 @@ impl<'tcx, Tag: Provenance> Scalar { } #[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)] -pub enum ScalarMaybeUninit { - Scalar(Scalar), +pub enum ScalarMaybeUninit { + Scalar(Scalar), Uninit, } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ScalarMaybeUninit, 24); -impl From> for ScalarMaybeUninit { +impl From> for ScalarMaybeUninit { #[inline(always)] - fn from(s: Scalar) -> Self { + fn from(s: Scalar) -> Self { ScalarMaybeUninit::Scalar(s) } } // We want the `Debug` output to be readable as it is used by `derive(Debug)` for // all the Miri types. -impl fmt::Debug for ScalarMaybeUninit { +impl fmt::Debug for ScalarMaybeUninit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ScalarMaybeUninit::Uninit => write!(f, ""), @@ -517,7 +529,7 @@ impl fmt::Debug for ScalarMaybeUninit { } } -impl fmt::LowerHex for ScalarMaybeUninit { +impl fmt::LowerHex for ScalarMaybeUninit { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"), @@ -526,19 +538,19 @@ impl fmt::LowerHex for ScalarMaybeUninit { } } -impl ScalarMaybeUninit { +impl ScalarMaybeUninit { #[inline] - pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { + pub fn from_pointer(ptr: Pointer, cx: &impl HasDataLayout) -> Self { ScalarMaybeUninit::Scalar(Scalar::from_pointer(ptr, cx)) } #[inline] - pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { + pub fn from_maybe_pointer(ptr: Pointer>, cx: &impl HasDataLayout) -> Self { ScalarMaybeUninit::Scalar(Scalar::from_maybe_pointer(ptr, cx)) } #[inline] - pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar> { + pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar> { match self { ScalarMaybeUninit::Scalar(scalar) => Ok(scalar), ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)), @@ -546,7 +558,12 @@ impl ScalarMaybeUninit { } } -impl<'tcx, Tag: Provenance> ScalarMaybeUninit { +impl<'tcx, Prov: Provenance> ScalarMaybeUninit { + #[inline(always)] + pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer>> { + self.check_init()?.to_pointer(cx) + } + #[inline(always)] pub fn to_bool(self) -> InterpResult<'tcx, bool> { self.check_init()?.to_bool()