diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index e6a7c20f79379..5b82912658783 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -313,7 +313,7 @@ impl_stable_hash_for!( impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] { Unevaluated(def_id, substs), Scalar(val), - ScalarPair(a, b), + Slice(id, alloc), ByRef(id, alloc, offset), } ); diff --git a/src/librustc/mir/interpret/allocation.rs b/src/librustc/mir/interpret/allocation.rs index ab3bc4cdf9fb6..ec48e4eba5679 100644 --- a/src/librustc/mir/interpret/allocation.rs +++ b/src/librustc/mir/interpret/allocation.rs @@ -15,7 +15,7 @@ use super::{ truncate, }; -use ty::layout::{Size, Align}; +use ty::layout::{Size, Align, self}; use syntax::ast::Mutability; use std::iter; use mir; @@ -325,6 +325,33 @@ impl<'tcx, Tag: Copy, Extra> Allocation { Ok(()) } + pub fn write_scalar_pair( + &mut self, + cx: &impl HasDataLayout, + ptr: Pointer, + a_val: ScalarMaybeUndef, + b_val: ScalarMaybeUndef, + layout: layout::TyLayout<'tcx>, + ) -> EvalResult<'tcx> + // FIXME: Working around https://github.com/rust-lang/rust/issues/56209 + where Extra: AllocationExtra + { + let (a, b) = match layout.abi { + layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value), + _ => bug!("write_scalar_pair: invalid ScalarPair layout: {:#?}", layout), + }; + let (a_size, b_size) = (a.size(cx), b.size(cx)); + let b_offset = a_size.align_to(b.align(cx).abi); + let b_ptr = ptr.offset(b_offset, cx)?; + + // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, + // but that does not work: We could be a newtype around a pair, then the + // fields do not match the `ScalarPair` components. + + self.write_scalar(cx, ptr, a_val, a_size)?; + self.write_scalar(cx, b_ptr, b_val, b_size) + } + /// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`. pub fn write_repeat( &mut self, @@ -400,6 +427,28 @@ impl<'tcx, Tag: Copy, Extra> Allocation { self.read_scalar(cx, ptr, cx.data_layout().pointer_size) } + pub fn read_usize( + &self, + cx: &impl HasDataLayout, + ptr: Pointer, + ) -> EvalResult<'tcx, u64> + // FIXME: Working around https://github.com/rust-lang/rust/issues/56209 + where Extra: AllocationExtra + { + self.read_ptr_sized(cx, ptr)?.not_undef()?.to_usize(cx) + } + + pub fn read_ptr( + &self, + cx: &impl HasDataLayout, + ptr: Pointer, + ) -> EvalResult<'tcx, Pointer> + // FIXME: Working around https://github.com/rust-lang/rust/issues/56209 + where Extra: AllocationExtra + { + self.read_ptr_sized(cx, ptr)?.not_undef()?.to_ptr() + } + /// Write a *non-ZST* scalar /// /// zsts can't be read out of two reasons: diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 4bcba9d54674e..231818b6ab723 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -10,7 +10,7 @@ use std::fmt; -use crate::ty::{Ty, subst::Substs, layout::{HasDataLayout, Size}}; +use crate::ty::{Ty, subst::Substs, layout::{HasDataLayout, Size}, TyCtxt}; use crate::hir::def_id::DefId; use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate}; @@ -39,10 +39,13 @@ pub enum ConstValue<'tcx> { /// Not using the enum `Value` to encode that this must not be `Undef` Scalar(Scalar), - /// Used only for *fat pointers* with layout::abi::ScalarPair + /// Strings and byte strings have a custom variant for performance reasons. + /// Otherwise we'd be converting + /// from an allocation of a pointer + length to the pointer + length and back all the tim /// - /// Needed for pattern matching code related to slices and strings. - ScalarPair(Scalar, Scalar), + /// The allocation of the bytes of the string. The size of the allocation is the length + /// of the string in bytes + Slice(AllocId, &'tcx Allocation), /// An allocation + offset into the allocation. /// Invariant: The AllocId matches the allocation. @@ -54,8 +57,8 @@ impl<'tcx> ConstValue<'tcx> { pub fn try_to_scalar(&self) -> Option { match *self { ConstValue::Unevaluated(..) | - ConstValue::ByRef(..) | - ConstValue::ScalarPair(..) => None, + ConstValue::Slice(..) | + ConstValue::ByRef(..) => None, ConstValue::Scalar(val) => Some(val), } } @@ -71,20 +74,32 @@ impl<'tcx> ConstValue<'tcx> { } #[inline] - pub fn new_slice( - val: Scalar, - len: u64, - cx: &impl HasDataLayout - ) -> Self { - ConstValue::ScalarPair(val, Scalar::Bits { - bits: len as u128, - size: cx.data_layout().pointer_size.bytes() as u8, - }) + /// Used for trait object fat pointers + fn new_ptr_sized_seq(scalars: &[Scalar], tcx: TyCtxt<'_, '_, 'tcx>) -> Self { + let mut allocation = Allocation::undef( + tcx.data_layout.pointer_size * scalars.len() as u64, + tcx.data_layout.pointer_align.abi, + Default::default(), + ); + let alloc_id = tcx.alloc_map.lock().reserve(); + let mut ptr = Pointer::from(alloc_id); + for &scalar in scalars { + allocation.write_scalar( + &tcx, + ptr, + scalar.into(), + tcx.data_layout.pointer_size, + ).unwrap(); + ptr = ptr.offset(tcx.data_layout.pointer_size, &tcx).unwrap(); + } + let allocation = tcx.intern_const_alloc(allocation); + tcx.alloc_map.lock().set_id_memory(alloc_id, allocation); + ConstValue::ByRef(alloc_id, allocation, Size::ZERO) } #[inline] - pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self { - ConstValue::ScalarPair(val, Scalar::Ptr(vtable)) + pub fn new_dyn_trait(val: Scalar, vtable: Pointer, tcx: TyCtxt<'_, '_, 'tcx>) -> Self { + Self::new_ptr_sized_seq(&[val, Scalar::Ptr(vtable)], tcx) } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index af1255c438a95..09923b79ea34d 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -2623,23 +2623,11 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: &ty::Const<'_>) -> fmt::Resu return write!(f, "{}", item_path_str(did)); } // print string literals - if let ConstValue::ScalarPair(ptr, len) = value { - if let Scalar::Ptr(ptr) = ptr { - if let Scalar::Bits { bits: len, .. } = len { - if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty { - return ty::tls::with(|tcx| { - let alloc = tcx.alloc_map.lock().get(ptr.alloc_id); - if let Some(interpret::AllocType::Memory(alloc)) = alloc { - assert_eq!(len as usize as u128, len); - let slice = - &alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)]; - let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri"); - write!(f, "{:?}", s) - } else { - write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len) - } - }); - } + if let ConstValue::Slice(_, alloc) = value { + if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty { + return match ::std::str::from_utf8(&alloc.bytes) { + Ok(s) => write!(f, "{:?}", s), + Err(_) => write!(f, "broken str slice: {:?}", alloc), } } } diff --git a/src/librustc/ty/context.rs b/src/librustc/ty/context.rs index 5780fbe55ad1f..ce914fd44ec09 100644 --- a/src/librustc/ty/context.rs +++ b/src/librustc/ty/context.rs @@ -1053,11 +1053,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { } /// Allocates a byte or string literal for `mir::interpret`, read-only - pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { + pub fn allocate_bytes(self, bytes: &[u8]) -> (interpret::AllocId, &'tcx Allocation) { // create an allocation that just contains these bytes let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes, ()); let alloc = self.intern_const_alloc(alloc); - self.alloc_map.lock().allocate(alloc) + (self.alloc_map.lock().allocate(alloc), alloc) } pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability { diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index d6aeb288b5cdc..dfe46af172fba 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -1032,8 +1032,8 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self { match *self { ConstValue::Scalar(v) => ConstValue::Scalar(v), - ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b), ConstValue::ByRef(id, alloc, offset) => ConstValue::ByRef(id, alloc, offset), + ConstValue::Slice(id, alloc) => ConstValue::Slice(id, alloc), ConstValue::Unevaluated(def_id, substs) => { ConstValue::Unevaluated(def_id, substs.fold_with(folder)) } @@ -1043,7 +1043,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> { fn super_visit_with>(&self, visitor: &mut V) -> bool { match *self { ConstValue::Scalar(_) | - ConstValue::ScalarPair(_, _) | + ConstValue::Slice(..) | ConstValue::ByRef(_, _, _) => false, ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor), } diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/src/librustc_codegen_ssa/mir/operand.rs index 92d0219caf06b..7028b953d8abd 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/src/librustc_codegen_ssa/mir/operand.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use rustc::mir::interpret::{ConstValue, ErrorHandled}; +use rustc::mir::interpret::{ConstValue, ErrorHandled, Scalar}; use rustc::mir; use rustc::ty; -use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, HasTyCtxt}; use base; use MemFlags; @@ -85,36 +85,42 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> { return Ok(OperandRef::new_zst(bx.cx(), layout)); } + let imm = |x| { + let scalar = match layout.abi { + layout::Abi::Scalar(ref x) => x, + _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) + }; + let llval = bx.cx().scalar_to_backend( + x, + scalar, + bx.cx().immediate_backend_type(layout), + ); + OperandValue::Immediate(llval) + }; + let val = match val.val { ConstValue::Unevaluated(..) => bug!(), - ConstValue::Scalar(x) => { - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("from_const: invalid ByVal layout: {:#?}", layout) - }; - let llval = bx.cx().scalar_to_backend( - x, - scalar, - bx.cx().immediate_backend_type(layout), - ); - OperandValue::Immediate(llval) - }, - ConstValue::ScalarPair(a, b) => { - let (a_scalar, b_scalar) = match layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), + ConstValue::Scalar(x) => imm(x), + ConstValue::Slice(id, alloc) => { + match layout.ty.builtin_deref(false).unwrap().ty.sty { + ty::TyKind::Str => { + let a_scalar = match layout.abi { + layout::Abi::ScalarPair(ref a, _) => a, + _ => bug!("from_const: invalid layout: {:#?}", layout) + }; + let a_llval = bx.cx().scalar_to_backend( + Scalar::Ptr(id.into()), + a_scalar, + bx.cx().scalar_pair_element_backend_type(layout, 0, true), + ); + let b_llval = bx.cx().const_usize(alloc.bytes.len() as u64); + OperandValue::Pair(a_llval, b_llval) + }, + ty::TyKind::Array(u, _) if u == bx.cx().tcx().types.u8 => { + imm(Scalar::Ptr(id.into())) + } _ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout) - }; - let a_llval = bx.cx().scalar_to_backend( - a, - a_scalar, - bx.cx().scalar_pair_element_backend_type(layout, 0, true), - ); - let b_llval = bx.cx().scalar_to_backend( - b, - b_scalar, - bx.cx().scalar_pair_element_backend_type(layout, 1, true), - ); - OperandValue::Pair(a_llval, b_llval) + } }, ConstValue::ByRef(_, alloc, offset) => { return Ok(bx.load_operand(bx.cx().from_const_alloc(layout, alloc, offset))); diff --git a/src/librustc_mir/const_eval.rs b/src/librustc_mir/const_eval.rs index 291b5c170ef36..f6c0242165d29 100644 --- a/src/librustc_mir/const_eval.rs +++ b/src/librustc_mir/const_eval.rs @@ -21,7 +21,7 @@ use rustc::hir::def::Def; use rustc::mir::interpret::{ConstEvalErr, ErrorHandled}; use rustc::mir; use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt}; -use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx}; +use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx, Size}; use rustc::ty::subst::Subst; use rustc::traits::Reveal; use rustc_data_structures::indexed_vec::IndexVec; @@ -141,8 +141,22 @@ pub fn op_to_const<'tcx>( }, Ok(Immediate::Scalar(x)) => ConstValue::Scalar(x.not_undef()?), - Ok(Immediate::ScalarPair(a, b)) => - ConstValue::ScalarPair(a.not_undef()?, b.not_undef()?), + Ok(Immediate::ScalarPair(a, b)) => { + // create an allocation just for the fat pointer + let mut allocation = Allocation::undef( + op.layout.size, + op.layout.align.abi, + Default::default(), + ); + let alloc_id = ecx.tcx.alloc_map.lock().reserve(); + let ptr = Pointer::from(alloc_id); + // write the fat pointer into the allocation + allocation.write_scalar_pair(&ecx.tcx.tcx, ptr, a, b, op.layout)?; + // intern everything + let allocation = ecx.tcx.intern_const_alloc(allocation); + ecx.tcx.alloc_map.lock().set_id_memory(alloc_id, allocation); + ConstValue::ByRef(alloc_id, allocation, Size::ZERO) + }, }; Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty)) } @@ -150,7 +164,7 @@ pub fn const_to_op<'tcx>( ecx: &CompileTimeEvalContext<'_, '_, 'tcx>, cnst: &ty::Const<'tcx>, ) -> EvalResult<'tcx, OpTy<'tcx>> { - let op = ecx.const_value_to_op(cnst.val)?; + let op = ecx.const_value_to_op(cnst)?; Ok(OpTy { op, layout: ecx.layout_of(cnst.ty)? }) } diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 733580b3ce2fd..ba4991c61dd81 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -165,12 +165,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { let lit = match *lit { LitKind::Str(ref s, _) => { let s = s.as_str(); - let id = self.tcx.allocate_bytes(s.as_bytes()); - ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &self.tcx) + let (id, a) = self.tcx.allocate_bytes(s.as_bytes()); + ConstValue::Slice(id, a) }, LitKind::ByteStr(ref data) => { - let id = self.tcx.allocate_bytes(data); - ConstValue::Scalar(Scalar::Ptr(id.into())) + let (id, a) = self.tcx.allocate_bytes(data); + ConstValue::Slice(id, a) }, LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits { bits: n as u128, diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index fd869d6c334ab..5bdada17f09f8 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -1387,20 +1387,12 @@ fn slice_pat_covered_by_constructor<'tcx>( ) -> Result { let data: &[u8] = match *ctor { ConstantValue(const_val) => { - let val = match const_val.val { - ConstValue::Unevaluated(..) | - ConstValue::ByRef(..) => bug!("unexpected ConstValue: {:?}", const_val), - ConstValue::Scalar(val) | ConstValue::ScalarPair(val, _) => val, - }; - if let Ok(ptr) = val.to_ptr() { - let is_array_ptr = const_val.ty - .builtin_deref(true) - .and_then(|t| t.ty.builtin_index()) - .map_or(false, |t| t == tcx.types.u8); - assert!(is_array_ptr); - tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id).bytes.as_ref() - } else { - bug!("unexpected non-ptr ConstantValue") + match const_val.val { + ConstValue::Slice(_, alloc) => { + assert!(alloc.relocations.len() == 0); + &alloc.bytes + } + _ => bug!("unexpected ConstValue: {:#?}", const_val), } } _ => bug!() diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 941744c0aab7c..b19ebfccb58e7 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -1263,31 +1263,16 @@ pub fn compare_const_vals<'a, 'tcx>( if let ty::Ref(_, rty, _) = ty.value.sty { if let ty::Str = rty.sty { - match (a.val, b.val) { + return match (a.val, b.val) { ( - ConstValue::ScalarPair( - Scalar::Ptr(ptr_a), - len_a, - ), - ConstValue::ScalarPair( - Scalar::Ptr(ptr_b), - len_b, - ), - ) if ptr_a.offset.bytes() == 0 && ptr_b.offset.bytes() == 0 => { - if let Ok(len_a) = len_a.to_bits(tcx.data_layout.pointer_size) { - if let Ok(len_b) = len_b.to_bits(tcx.data_layout.pointer_size) { - if len_a == len_b { - let map = tcx.alloc_map.lock(); - let alloc_a = map.unwrap_memory(ptr_a.alloc_id); - let alloc_b = map.unwrap_memory(ptr_b.alloc_id); - if alloc_a.bytes.len() as u128 == len_a { - return from_bool(alloc_a == alloc_b); - } - } - } - } + ConstValue::Slice(_, alloc_a), + ConstValue::Slice(_, alloc_b), + ) => { + assert!(alloc_a.relocations.len() == 0); + assert!(alloc_b.relocations.len() == 0); + from_bool(alloc_a.bytes == alloc_b.bytes) } - _ => (), + _ => bug!("str constants not `Slice`: {:#?}, {:#?}", a, b), } } } @@ -1313,12 +1298,12 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, let lit = match *lit { LitKind::Str(ref s, _) => { let s = s.as_str(); - let id = tcx.allocate_bytes(s.as_bytes()); - ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &tcx) + let (id, a) = tcx.allocate_bytes(s.as_bytes()); + ConstValue::Slice(id, a) }, LitKind::ByteStr(ref data) => { - let id = tcx.allocate_bytes(data); - ConstValue::Scalar(Scalar::Ptr(id.into())) + let (id, a) = tcx.allocate_bytes(data); + ConstValue::Slice(id, a) }, LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits { bits: n as u128, diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index 97d7e1586b811..33c55242c90b0 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -124,7 +124,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } pub fn allocate_static_bytes(&mut self, bytes: &[u8]) -> Pointer { - Pointer::from(self.tcx.allocate_bytes(bytes)) + Pointer::from(self.tcx.allocate_bytes(bytes).0) } pub fn allocate_with( diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 83ceadada65ce..c2515f16341e2 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -15,6 +15,7 @@ use std::convert::TryInto; use rustc::mir; use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt, VariantIdx}; +use rustc::ty::{self, TyKind}; use rustc::mir::interpret::{ GlobalId, AllocId, @@ -527,7 +528,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> let ty = self.monomorphize(mir_op.ty(self.mir(), *self.tcx), self.substs()); self.layout_of(ty) })?; - let op = self.const_value_to_op(constant.literal.val)?; + let op = self.const_value_to_op(constant.literal)?; OpTy { op, layout } } }; @@ -550,10 +551,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> // `eval_operand`, ideally). pub(crate) fn const_value_to_op( &self, - val: ConstValue<'tcx>, + cnst: &ty::Const<'tcx>, ) -> EvalResult<'tcx, Operand> { - trace!("const_value_to_op: {:?}", val); - match val { + trace!("const_value_to_op: {:?}", cnst); + match cnst.val { ConstValue::Unevaluated(def_id, substs) => { let instance = self.resolve(def_id, substs)?; Ok(*OpTy::from(self.const_eval_raw(GlobalId { @@ -568,11 +569,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> MemPlace::from_ptr(Pointer::new(id, offset), alloc.align) ).with_default_tag()) }, - ConstValue::ScalarPair(a, b) => - Ok(Operand::Immediate(Immediate::ScalarPair( - a.into(), - b.into(), - )).with_default_tag()), + ConstValue::Slice(alloc_id, allocation) => { + let fat = match cnst.ty.builtin_deref(false).unwrap().ty.sty { + TyKind::Str => true, + TyKind::Slice(inner) if inner == self.tcx.types.u8 => true, + TyKind::Array(inner, _) if inner == self.tcx.types.u8 => false, + _ => bug!("expected slice, got {:?}", cnst.ty), + }; + if fat { + Ok(Operand::Immediate(Immediate::ScalarPair( + Scalar::from(Pointer::from(alloc_id)).with_default_tag().into(), + Scalar::from_uint( + allocation.bytes.len() as u64, + self.tcx.data_layout.pointer_size, + ).into(), + ))) + } else { + Ok(Operand::Immediate(Immediate::Scalar( + ScalarMaybeUndef::from(Scalar::from(Pointer::from(alloc_id))) + )).with_default_tag()) + } + } ConstValue::Scalar(x) => Ok(Operand::Immediate(Immediate::Scalar(x.into())).with_default_tag()), } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 1b47530eaec65..4c33b373df38e 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -748,28 +748,10 @@ where ) } Immediate::ScalarPair(a_val, b_val) => { - let (a, b) = match dest.layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value), - _ => bug!("write_immediate_to_mplace: invalid ScalarPair layout: {:#?}", - dest.layout) - }; - let (a_size, b_size) = (a.size(self), b.size(self)); - let b_offset = a_size.align_to(b.align(self).abi); - let b_align = ptr_align.restrict_for_offset(b_offset); - let b_ptr = ptr.offset(b_offset, self)?; - - self.memory.check_align(b_ptr.into(), b_align)?; - - // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, - // but that does not work: We could be a newtype around a pair, then the - // fields do not match the `ScalarPair` components. - + let tcx = self.tcx; self.memory .get_mut(ptr.alloc_id)? - .write_scalar(tcx, ptr, a_val, a_size)?; - self.memory - .get_mut(b_ptr.alloc_id)? - .write_scalar(tcx, b_ptr, b_val, b_size) + .write_scalar_pair(&tcx.tcx, ptr, a_val, b_val, dest.layout) } } } diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index 7531f62fdab7b..8c6294b1a7c96 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1263,19 +1263,14 @@ fn collect_const<'a, 'tcx>( }; match val { ConstValue::Unevaluated(..) => bug!("const eval yielded unevaluated const"), - ConstValue::ScalarPair(Scalar::Ptr(a), Scalar::Ptr(b)) => { - collect_miri(tcx, a.alloc_id, output); - collect_miri(tcx, b.alloc_id, output); - } - ConstValue::ScalarPair(_, Scalar::Ptr(ptr)) | - ConstValue::ScalarPair(Scalar::Ptr(ptr), _) | ConstValue::Scalar(Scalar::Ptr(ptr)) => collect_miri(tcx, ptr.alloc_id, output), - ConstValue::ByRef(_id, alloc, _offset) => { + ConstValue::Slice(_, alloc) | + ConstValue::ByRef(_, alloc, _) => { for &((), id) in alloc.relocations.values() { collect_miri(tcx, id, output); } } - _ => {}, + ConstValue::Scalar(Scalar::Bits { .. }) => {}, } }