#[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 },
fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<ConstValue<'tcx>> {
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 }
}
#[inline]
pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
match *self {
- ConstValue::ByRef { .. } | ConstValue::Slice { .. } => None,
+ ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
ConstValue::Scalar(val) => Some(val),
}
}
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
/// 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<Tag = AllocId> {
+pub enum Scalar<Prov = AllocId> {
/// The raw bytes of a simple value.
Int(ScalarInt),
/// 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<Tag>, u8),
+ Ptr(Pointer<Prov>, u8),
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
// We want the `Debug` output to be readable as it is used by `derive(Debug)` for
// all the Miri types.
-impl<Tag: Provenance> fmt::Debug for Scalar<Tag> {
+impl<Prov: Provenance> fmt::Debug for Scalar<Prov> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Scalar::Ptr(ptr, _size) => write!(f, "{:?}", ptr),
}
}
-impl<Tag: Provenance> fmt::Display for Scalar<Tag> {
+impl<Prov: Provenance> fmt::Display for Scalar<Prov> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Scalar::Ptr(ptr, _size) => write!(f, "pointer to {:?}", ptr),
}
}
-impl<Tag: Provenance> fmt::LowerHex for Scalar<Tag> {
+impl<Prov: Provenance> fmt::LowerHex for Scalar<Prov> {
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<Tag> From<Single> for Scalar<Tag> {
+impl<Prov> From<Single> for Scalar<Prov> {
#[inline(always)]
fn from(f: Single) -> Self {
Scalar::from_f32(f)
}
}
-impl<Tag> From<Double> for Scalar<Tag> {
+impl<Prov> From<Double> for Scalar<Prov> {
#[inline(always)]
fn from(f: Double) -> Self {
Scalar::from_f64(f)
}
}
-impl<Tag> From<ScalarInt> for Scalar<Tag> {
+impl<Prov> From<ScalarInt> for Scalar<Prov> {
#[inline(always)]
fn from(ptr: ScalarInt) -> Self {
Scalar::Int(ptr)
}
}
-impl<Tag> Scalar<Tag> {
- pub const ZST: Self = Scalar::Int(ScalarInt::ZST);
-
+impl<Prov> Scalar<Prov> {
#[inline(always)]
- pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
+ pub fn from_pointer(ptr: Pointer<Prov>, 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<Option<Tag>>, 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<Option<Prov>>, 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())
}
pub fn to_bits_or_ptr_internal(
self,
target_size: Size,
- ) -> Result<Result<u128, Pointer<Tag>>, ScalarSizeMismatch> {
+ ) -> Result<Result<u128, Pointer<Prov>>, 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| {
}
}
-impl<'tcx, Tag: Provenance> Scalar<Tag> {
+impl<'tcx, Prov: Provenance> Scalar<Prov> {
+ pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer<Option<Prov>>> {
+ 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.
///
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))
}
}
}
}
#[derive(Clone, Copy, Eq, PartialEq, TyEncodable, TyDecodable, HashStable, Hash)]
-pub enum ScalarMaybeUninit<Tag = AllocId> {
- Scalar(Scalar<Tag>),
+pub enum ScalarMaybeUninit<Prov = AllocId> {
+ Scalar(Scalar<Prov>),
Uninit,
}
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
static_assert_size!(ScalarMaybeUninit, 24);
-impl<Tag> From<Scalar<Tag>> for ScalarMaybeUninit<Tag> {
+impl<Prov> From<Scalar<Prov>> for ScalarMaybeUninit<Prov> {
#[inline(always)]
- fn from(s: Scalar<Tag>) -> Self {
+ fn from(s: Scalar<Prov>) -> 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<Tag: Provenance> fmt::Debug for ScalarMaybeUninit<Tag> {
+impl<Prov: Provenance> fmt::Debug for ScalarMaybeUninit<Prov> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ScalarMaybeUninit::Uninit => write!(f, "<uninitialized>"),
}
}
-impl<Tag: Provenance> fmt::LowerHex for ScalarMaybeUninit<Tag> {
+impl<Prov: Provenance> fmt::LowerHex for ScalarMaybeUninit<Prov> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ScalarMaybeUninit::Uninit => write!(f, "uninitialized bytes"),
}
}
-impl<Tag> ScalarMaybeUninit<Tag> {
+impl<Prov> ScalarMaybeUninit<Prov> {
#[inline]
- pub fn from_pointer(ptr: Pointer<Tag>, cx: &impl HasDataLayout) -> Self {
+ pub fn from_pointer(ptr: Pointer<Prov>, cx: &impl HasDataLayout) -> Self {
ScalarMaybeUninit::Scalar(Scalar::from_pointer(ptr, cx))
}
#[inline]
- pub fn from_maybe_pointer(ptr: Pointer<Option<Tag>>, cx: &impl HasDataLayout) -> Self {
+ pub fn from_maybe_pointer(ptr: Pointer<Option<Prov>>, cx: &impl HasDataLayout) -> Self {
ScalarMaybeUninit::Scalar(Scalar::from_maybe_pointer(ptr, cx))
}
#[inline]
- pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Tag>> {
+ pub fn check_init<'tcx>(self) -> InterpResult<'tcx, Scalar<Prov>> {
match self {
ScalarMaybeUninit::Scalar(scalar) => Ok(scalar),
ScalarMaybeUninit::Uninit => throw_ub!(InvalidUninitBytes(None)),
}
}
-impl<'tcx, Tag: Provenance> ScalarMaybeUninit<Tag> {
+impl<'tcx, Prov: Provenance> ScalarMaybeUninit<Prov> {
+ #[inline(always)]
+ pub fn to_pointer(self, cx: &impl HasDataLayout) -> InterpResult<'tcx, Pointer<Option<Prov>>> {
+ self.check_init()?.to_pointer(cx)
+ }
+
#[inline(always)]
pub fn to_bool(self) -> InterpResult<'tcx, bool> {
self.check_init()?.to_bool()