From 8b99c61701cd3230bb24fba970d2f400e6e09fa1 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 12 May 2018 18:47:20 +0200 Subject: [PATCH 1/5] Ensure that statics are always ByRef --- src/librustc_codegen_llvm/mir/constant.rs | 49 +------- src/librustc_mir/interpret/const_eval.rs | 145 +++++++++------------- src/test/codegen/link_section.rs | 8 +- 3 files changed, 69 insertions(+), 133 deletions(-) diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs index c2638d2d41070..66a8b3ca36fb0 100644 --- a/src/librustc_codegen_llvm/mir/constant.rs +++ b/src/librustc_codegen_llvm/mir/constant.rs @@ -81,49 +81,6 @@ pub fn primval_to_llvm(cx: &CodegenCx, } } -fn const_value_to_llvm<'tcx>(cx: &CodegenCx<'_, 'tcx>, val: ConstValue, ty: Ty<'tcx>) -> ValueRef { - let layout = cx.layout_of(ty); - - if layout.is_zst() { - return C_undef(layout.immediate_llvm_type(cx)); - } - - match val { - ConstValue::ByVal(x) => { - let scalar = match layout.abi { - layout::Abi::Scalar(ref x) => x, - _ => bug!("const_value_to_llvm: invalid ByVal layout: {:#?}", layout) - }; - primval_to_llvm( - cx, - x, - scalar, - layout.immediate_llvm_type(cx), - ) - }, - ConstValue::ByValPair(a, b) => { - let (a_scalar, b_scalar) = match layout.abi { - layout::Abi::ScalarPair(ref a, ref b) => (a, b), - _ => bug!("const_value_to_llvm: invalid ByValPair layout: {:#?}", layout) - }; - let a_llval = primval_to_llvm( - cx, - a, - a_scalar, - layout.scalar_pair_element_llvm_type(cx, 0), - ); - let b_llval = primval_to_llvm( - cx, - b, - b_scalar, - layout.scalar_pair_element_llvm_type(cx, 1), - ); - C_struct(cx, &[a_llval, b_llval], false) - }, - ConstValue::ByRef(alloc) => const_alloc_to_llvm(cx, alloc), - } -} - pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { let mut llvals = Vec::with_capacity(alloc.relocations.len() + 1); let layout = cx.data_layout(); @@ -171,11 +128,11 @@ pub fn codegen_static_initializer<'a, 'tcx>( let param_env = ty::ParamEnv::reveal_all(); let static_ = cx.tcx.const_eval(param_env.and(cid))?; - let val = match static_.val { - ConstVal::Value(val) => val, + let alloc = match static_.val { + ConstVal::Value(ConstValue::ByRef(alloc)) => alloc, _ => bug!("static const eval returned {:#?}", static_), }; - Ok(const_value_to_llvm(cx, val, static_.ty)) + Ok(const_alloc_to_llvm(cx, alloc)) } impl<'a, 'tcx> FunctionCx<'a, 'tcx> { diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 7d0c16de0a440..1f368cd3dfc1a 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -98,59 +98,32 @@ pub fn value_to_const_value<'tcx>( mut val: Value, ty: Ty<'tcx>, ) -> &'tcx ty::Const<'tcx> { - let result = (|| { + let val = (|| { // Convert to ByVal or ByValPair if possible if let Value::ByRef(ptr, align) = val { if let Some(read_val) = ecx.try_read_value(ptr, align, ty)? { val = read_val; } } - - let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap(); - - if layout.is_zst() { - return Ok(ty::Const::from_const_value( - ecx.tcx.tcx, - ConstValue::ByVal(PrimVal::Undef), - ty)); - } - - let val = match layout.abi { - layout::Abi::Scalar(..) => { - if let Value::ByVal(val) = val { - ConstValue::ByVal(val) - } else { - bug!("expected ByVal value, got {:?}", val); - } - } - layout::Abi::ScalarPair(..) => { - if let Value::ByValPair(a, b) = val { - ConstValue::ByValPair(a, b) - } else { - bug!("expected ByValPair value, got {:?}", val); - } + match val { + Value::ByVal(val) => Ok(ConstValue::ByVal(val)), + Value::ByValPair(a, b) => Ok(ConstValue::ByValPair(a, b)), + Value::ByRef(ptr, align) => { + let ptr = ptr.primval.to_ptr().unwrap(); + assert_eq!(ptr.offset, 0); + let alloc = ecx.memory.get(ptr.alloc_id)?; + assert!(alloc.align.abi() >= layout.align.abi()); + assert!(alloc.bytes.len() as u64 == layout.size.bytes()); + let mut alloc = alloc.clone(); + // The align field is meaningless for values, so just use the layout's align + alloc.align = layout.align; + let alloc = ecx.tcx.intern_const_alloc(alloc); + Ok(ConstValue::ByRef(alloc)) } - _ => { - if let Value::ByRef(ptr, _) = val { - let ptr = ptr.primval.to_ptr().unwrap(); - assert_eq!(ptr.offset, 0); - let alloc = ecx.memory.get(ptr.alloc_id)?; - assert!(alloc.align.abi() >= layout.align.abi()); - assert!(alloc.bytes.len() as u64 == layout.size.bytes()); - let mut alloc = alloc.clone(); - // The align field is meaningless for values, so just use the layout's align - alloc.align = layout.align; - let alloc = ecx.tcx.intern_const_alloc(alloc); - ConstValue::ByRef(alloc) - } else { - bug!("expected ByRef value, got {:?}", val); - } - }, - }; - Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, ty)) + } })(); match result { - Ok(v) => v, + Ok(v) => ty::Const::from_const_value(tcx, val, ty), Err(mut err) => { ecx.report(&mut err, true, None); bug!("miri error occured when converting Value to ConstValue") @@ -182,49 +155,49 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>( ) -> EvalResult<'tcx, (Value, Pointer, Ty<'tcx>)> { debug!("eval_body: {:?}, {:?}", cid, param_env); let tcx = ecx.tcx.tcx; - let mut mir = match mir { - Some(mir) => mir, - None => ecx.load_mir(cid.instance.def)?, - }; - if let Some(index) = cid.promoted { - mir = &mir.promoted[index]; - } - let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let mutability = tcx.is_static(cid.instance.def_id()); - let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); - trace!("const_eval: pushing stack frame for global: {}{}", name, prom); - assert!(mir.arg_count == 0); - ecx.push_stack_frame( - cid.instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup, - )?; + let mut mir = match mir { + Some(mir) => mir, + None => ecx.load_mir(cid.instance.def)?, + }; + if let Some(index) = cid.promoted { + mir = &mir.promoted[index]; + } + let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); + let is_static = tcx.is_static(cid.instance.def_id()); + let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable { + Mutability::Mutable + } else { + Mutability::Immutable + }; + let cleanup = StackPopCleanup::MarkStatic(mutability); + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("const_eval: pushing stack frame for global: {}{}", name, prom); + assert!(mir.arg_count == 0); + ecx.push_stack_frame( + cid.instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup, + )?; - while ecx.step()? {} - let ptr = ptr.into(); - // always try to read the value and report errors - let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { - Some(val) => val, - // point at the allocation - _ => Value::ByRef(ptr, layout.align), - }; - Ok((value, ptr, layout.ty)) + while ecx.step()? {} + let ptr = ptr.into(); + // always try to read the value and report errors + let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { + Some(val) if is_static.is_none() => val, + // point at the allocation + _ => Value::ByRef(ptr, layout.align), + }; + Ok((value, ptr, layout.ty)) } pub struct CompileTimeEvaluator; diff --git a/src/test/codegen/link_section.rs b/src/test/codegen/link_section.rs index 1879002e7f3d7..415ee6eb7eab8 100644 --- a/src/test/codegen/link_section.rs +++ b/src/test/codegen/link_section.rs @@ -12,11 +12,17 @@ #![crate_type = "lib"] -// CHECK: @VAR1 = constant i32 1, section ".test_one" +// CHECK: @VAR1 = constant <{ [4 x i8] }> <{ [4 x i8] c"\01\00\00\00" }>, section ".test_one" #[no_mangle] #[link_section = ".test_one"] +#[cfg(target_endian = "little")] pub static VAR1: u32 = 1; +#[no_mangle] +#[link_section = ".test_one"] +#[cfg(target_endian = "big")] +pub static VAR1: u32 = 0x01000000; + pub enum E { A(u32), B(f32) From 76ddede5c2d2abc4c3b97dd383fcd6809384c323 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 13 May 2018 19:52:53 +0200 Subject: [PATCH 2/5] Reintroduce some sanity checks --- src/librustc_mir/interpret/const_eval.rs | 7 +++++++ src/librustc_mir/interpret/eval_context.rs | 4 ---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 1f368cd3dfc1a..239d9a051c6b7 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -98,6 +98,13 @@ pub fn value_to_const_value<'tcx>( mut val: Value, ty: Ty<'tcx>, ) -> &'tcx ty::Const<'tcx> { + let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap(); + match (val, &layout.abi) { + (Value::ByRef(..), _) | + (Value::ByVal(_), &layout::Abi::Scalar(_)) | + (Value::ByValPair(..), &layout::Abi::ScalarPair(..)) => {}, + _ => bug!("bad value/layout combo: {:#?}, {:#?}", val, layout), + } let val = (|| { // Convert to ByVal or ByValPair if possible if let Value::ByRef(ptr, align) = val { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 03137619edaf4..b91a4ba864ade 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1416,10 +1416,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let layout = self.layout_of(ty)?; self.memory.check_align(ptr, ptr_align)?; - if layout.size.bytes() == 0 { - return Ok(Some(Value::ByVal(PrimVal::Undef))); - } - let ptr = ptr.to_ptr()?; // Not the right place to do this From 6630678428ee7857da4880dfbab519286e436adc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 14 May 2018 18:54:24 +0200 Subject: [PATCH 3/5] Go through an allocation when accessing fields of constants --- src/librustc/ich/impls_ty.rs | 3 +- src/librustc/mir/interpret/value.rs | 8 ++-- src/librustc/ty/sty.rs | 11 +---- src/librustc_codegen_llvm/mir/constant.rs | 2 +- src/librustc_codegen_llvm/mir/operand.rs | 12 ++++-- src/librustc_mir/interpret/const_eval.rs | 36 +++++++++-------- src/librustc_mir/interpret/eval_context.rs | 4 +- src/librustc_mir/monomorphize/collector.rs | 2 +- src/test/ui/const-eval/issue-50706.rs | 47 ++++++++++++++++++++++ 9 files changed, 87 insertions(+), 38 deletions(-) create mode 100644 src/test/ui/const-eval/issue-50706.rs diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs index 31dce2a14c2b7..74b8b816848ac 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -401,8 +401,9 @@ for ::mir::interpret::ConstValue<'gcx> { a.hash_stable(hcx, hasher); b.hash_stable(hcx, hasher); } - ByRef(alloc) => { + ByRef(alloc, offset) => { alloc.hash_stable(hcx, hasher); + offset.hash_stable(hcx, hasher); } } } diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index 7bd84a607e714..ad076fe681bee 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -9,12 +9,12 @@ use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation}; /// matches Value's optimizations for easy conversions between these two types #[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] pub enum ConstValue<'tcx> { - // Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef + /// Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef ByVal(PrimVal), - // Used only for types with layout::abi::ScalarPair + /// Used only for types with layout::abi::ScalarPair ByValPair(PrimVal, PrimVal), - // Used only for the remaining cases - ByRef(&'tcx Allocation), + /// Used only for the remaining cases. An allocation + offset into the allocation + ByRef(&'tcx Allocation, u64), } impl<'tcx> ConstValue<'tcx> { diff --git a/src/librustc/ty/sty.rs b/src/librustc/ty/sty.rs index 4493c66859314..0b8f10d311d54 100644 --- a/src/librustc/ty/sty.rs +++ b/src/librustc/ty/sty.rs @@ -19,7 +19,7 @@ use ty::subst::{Substs, Subst, Kind, UnpackedKind}; use ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable}; use ty::{Slice, TyS}; use util::captures::Captures; -use mir::interpret::{Allocation, PrimVal, MemoryPointer, Value, ConstValue}; +use mir::interpret::{PrimVal, MemoryPointer, Value, ConstValue}; use std::iter; use std::cmp::Ordering; @@ -1767,15 +1767,6 @@ impl<'tcx> Const<'tcx> { Self::from_const_val(tcx, ConstVal::Value(val), ty) } - #[inline] - pub fn from_alloc( - tcx: TyCtxt<'_, '_, 'tcx>, - alloc: &'tcx Allocation, - ty: Ty<'tcx>, - ) -> &'tcx Self { - Self::from_const_value(tcx, ConstValue::ByRef(alloc), ty) - } - #[inline] pub fn from_byval_value( tcx: TyCtxt<'_, '_, 'tcx>, diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs index 66a8b3ca36fb0..9fd2f1bdd7a33 100644 --- a/src/librustc_codegen_llvm/mir/constant.rs +++ b/src/librustc_codegen_llvm/mir/constant.rs @@ -129,7 +129,7 @@ pub fn codegen_static_initializer<'a, 'tcx>( let static_ = cx.tcx.const_eval(param_env.and(cid))?; let alloc = match static_.val { - ConstVal::Value(ConstValue::ByRef(alloc)) => alloc, + ConstVal::Value(ConstValue::ByRef(alloc, 0)) => alloc, _ => bug!("static const eval returned {:#?}", static_), }; Ok(const_alloc_to_llvm(cx, alloc)) diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index 62ef58f825504..f6dc81a4706c0 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use llvm::ValueRef; +use llvm::{ValueRef, LLVMConstInBoundsGEP}; use rustc::middle::const_val::ConstEvalErr; use rustc::mir; use rustc::mir::interpret::ConstValue; @@ -137,9 +137,15 @@ impl<'a, 'tcx> OperandRef<'tcx> { ); OperandValue::Pair(a_llval, b_llval) }, - ConstValue::ByRef(alloc) => { + ConstValue::ByRef(alloc, offset) => { let init = const_alloc_to_llvm(bx.cx, alloc); - let llval = consts::addr_of(bx.cx, init, layout.align, "byte_str"); + let base_addr = consts::addr_of(bx.cx, init, layout.align, "byte_str"); + + let llval = unsafe { LLVMConstInBoundsGEP( + consts::bitcast(base_addr, Type::i8p(bx.cx)), + &C_usize(bx.cx, offset), + 1, + )}; let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to()); return Ok(PlaceRef::new_sized(llval, layout, alloc.align).load(bx)); }, diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 239d9a051c6b7..48ab9c8e5dbcd 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -422,22 +422,23 @@ pub fn const_val_field<'a, 'tcx>( let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap(); let result = (|| { let value = ecx.const_value_to_value(value, ty)?; - let (field, ty) = match value { - Value::ByValPair(..) | Value::ByVal(_) => - ecx.read_field(value, variant, field, ty)?.expect("const_val_field on non-field"), - Value::ByRef(ptr, align) => { - let place = Place::Ptr { - ptr, - align, - extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant), - }; - let layout = ecx.layout_of(ty)?; - let (place, layout) = ecx.place_field(place, field, layout)?; - let (ptr, align) = place.to_ptr_align(); - (Value::ByRef(ptr, align), layout.ty) - } + let layout = ecx.layout_of(ty)?; + let (ptr, align) = match value { + Value::ByRef(ptr, align) => (ptr, align), + Value::ByValPair(..) | Value::ByVal(_) => { + let ptr = ecx.alloc_ptr(ty)?.into(); + ecx.write_value_to_ptr(value, ptr, ty)?; + (ptr, layout.align) + }, }; - Ok(value_to_const_value(&ecx, field, ty)) + let place = Place::Ptr { + ptr, + align, + extra: variant.map_or(PlaceExtra::None, PlaceExtra::DowncastVariant), + }; + let (place, layout) = ecx.place_field(place, field, layout)?; + let (ptr, align) = place.to_ptr_align(); + Ok((Value::ByRef(ptr, align), layout.ty)) })(); result.map_err(|err| { let (trace, span) = ecx.generate_stacktrace(None); @@ -478,7 +479,10 @@ pub fn const_value_to_allocation_provider<'a, 'tcx>( (val, ty): (ConstValue<'tcx>, Ty<'tcx>), ) -> &'tcx Allocation { match val { - ConstValue::ByRef(alloc) => return alloc, + ConstValue::ByRef(alloc, offset) => { + assert_eq!(offset, 0); + return alloc; + }, _ => () } let result = || -> EvalResult<'tcx, &'tcx Allocation> { diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index b91a4ba864ade..1c32c1a940431 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -243,10 +243,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M _ty: Ty<'tcx>, ) -> EvalResult<'tcx, Value> { match val { - ConstValue::ByRef(alloc) => { + ConstValue::ByRef(alloc, offset) => { // FIXME: Allocate new AllocId for all constants inside let id = self.memory.allocate_value(alloc.clone(), Some(MemoryKind::Stack))?; - Ok(Value::ByRef(MemoryPointer::new(id, 0).into(), alloc.align)) + Ok(Value::ByRef(MemoryPointer::new(id, offset).into(), alloc.align)) }, ConstValue::ByValPair(a, b) => Ok(Value::ByValPair(a, b)), ConstValue::ByVal(val) => Ok(Value::ByVal(val)), diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs index c62eb1cf1855f..100edd6b4ffe5 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/src/librustc_mir/monomorphize/collector.rs @@ -1249,7 +1249,7 @@ fn collect_const<'a, 'tcx>( ConstVal::Value(ConstValue::ByValPair(PrimVal::Ptr(ptr), _)) | ConstVal::Value(ConstValue::ByVal(PrimVal::Ptr(ptr))) => collect_miri(tcx, ptr.alloc_id, output), - ConstVal::Value(ConstValue::ByRef(alloc)) => { + ConstVal::Value(ConstValue::ByRef(alloc, _offset)) => { for &id in alloc.relocations.values() { collect_miri(tcx, id, output); } diff --git a/src/test/ui/const-eval/issue-50706.rs b/src/test/ui/const-eval/issue-50706.rs new file mode 100644 index 0000000000000..2b0082d95b306 --- /dev/null +++ b/src/test/ui/const-eval/issue-50706.rs @@ -0,0 +1,47 @@ +// Copyright 2018 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// compile-pass + +pub struct Stats; + +#[derive(PartialEq, Eq)] +pub struct StatVariant { + pub id: u8, + _priv: (), +} + +#[derive(PartialEq, Eq)] +pub struct Stat { + pub variant: StatVariant, + pub index: usize, + _priv: (), +} + +impl Stats { + pub const TEST: StatVariant = StatVariant{id: 0, _priv: (),}; + #[allow(non_upper_case_globals)] + pub const A: Stat = Stat{ + variant: Self::TEST, + index: 0, + _priv: (),}; +} + +impl Stat { + pub fn from_index(variant: StatVariant, index: usize) -> Option { + let stat = Stat{variant, index, _priv: (),}; + match stat { + Stats::A => Some(Stats::A), + _ => None, + } + } +} + +fn main() {} From 3e933f4d8caf1cd37f69ea1283eff9c566db7cc3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 17 May 2018 16:14:30 +0200 Subject: [PATCH 4/5] Keep statics' constant as ByRef --- src/librustc_mir/interpret/const_eval.rs | 50 +++++++++++++--------- src/librustc_mir/interpret/eval_context.rs | 14 ++++++ 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index 48ab9c8e5dbcd..ec696ec82b9d7 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -95,42 +95,35 @@ pub fn eval_body<'a, 'tcx>( pub fn value_to_const_value<'tcx>( ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>, - mut val: Value, + val: Value, ty: Ty<'tcx>, ) -> &'tcx ty::Const<'tcx> { - let layout = tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap(); + let layout = ecx.tcx.layout_of(ty::ParamEnv::reveal_all().and(ty)).unwrap(); match (val, &layout.abi) { + (Value::ByVal(PrimVal::Undef), _) if layout.is_zst() => {}, (Value::ByRef(..), _) | (Value::ByVal(_), &layout::Abi::Scalar(_)) | (Value::ByValPair(..), &layout::Abi::ScalarPair(..)) => {}, _ => bug!("bad value/layout combo: {:#?}, {:#?}", val, layout), } let val = (|| { - // Convert to ByVal or ByValPair if possible - if let Value::ByRef(ptr, align) = val { - if let Some(read_val) = ecx.try_read_value(ptr, align, ty)? { - val = read_val; - } - } match val { Value::ByVal(val) => Ok(ConstValue::ByVal(val)), Value::ByValPair(a, b) => Ok(ConstValue::ByValPair(a, b)), Value::ByRef(ptr, align) => { let ptr = ptr.primval.to_ptr().unwrap(); - assert_eq!(ptr.offset, 0); let alloc = ecx.memory.get(ptr.alloc_id)?; - assert!(alloc.align.abi() >= layout.align.abi()); - assert!(alloc.bytes.len() as u64 == layout.size.bytes()); + assert!(alloc.align.abi() >= align.abi()); + assert!(alloc.bytes.len() as u64 - ptr.offset >= layout.size.bytes()); let mut alloc = alloc.clone(); - // The align field is meaningless for values, so just use the layout's align - alloc.align = layout.align; + alloc.align = align; let alloc = ecx.tcx.intern_const_alloc(alloc); - Ok(ConstValue::ByRef(alloc)) + Ok(ConstValue::ByRef(alloc, ptr.offset)) } } })(); - match result { - Ok(v) => ty::Const::from_const_value(tcx, val, ty), + match val { + Ok(val) => ty::Const::from_const_value(ecx.tcx.tcx, val, ty), Err(mut err) => { ecx.report(&mut err, true, None); bug!("miri error occured when converting Value to ConstValue") @@ -427,7 +420,7 @@ pub fn const_val_field<'a, 'tcx>( Value::ByRef(ptr, align) => (ptr, align), Value::ByValPair(..) | Value::ByVal(_) => { let ptr = ecx.alloc_ptr(ty)?.into(); - ecx.write_value_to_ptr(value, ptr, ty)?; + ecx.write_value_to_ptr(value, ptr, layout.align, ty)?; (ptr, layout.align) }, }; @@ -438,7 +431,21 @@ pub fn const_val_field<'a, 'tcx>( }; let (place, layout) = ecx.place_field(place, field, layout)?; let (ptr, align) = place.to_ptr_align(); - Ok((Value::ByRef(ptr, align), layout.ty)) + let mut new_value = Value::ByRef(ptr, align); + new_value = ecx.try_read_by_ref(new_value, layout.ty)?; + use rustc_data_structures::indexed_vec::Idx; + match (value, new_value) { + (Value::ByVal(_), Value::ByRef(..)) | + (Value::ByValPair(..), Value::ByRef(..)) | + (Value::ByVal(_), Value::ByValPair(..)) => bug!( + "field {} of {:?} yielded {:?}", + field.index(), + value, + new_value, + ), + _ => {}, + } + Ok(value_to_const_value(&ecx, new_value, layout.ty)) })(); result.map_err(|err| { let (trace, span) = ecx.generate_stacktrace(None); @@ -535,8 +542,11 @@ pub fn const_eval_provider<'a, 'tcx>( }; let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env); - res.map(|(val, _, miri_ty)| { - value_to_const_value(&ecx, val, miri_ty) + res.and_then(|(mut val, _, miri_ty)| { + if tcx.is_static(def_id).is_none() { + val = ecx.try_read_by_ref(val, miri_ty)?; + } + Ok(value_to_const_value(&ecx, val, miri_ty)) }).map_err(|mut err| { if tcx.is_static(def_id).is_some() { ecx.report(&mut err, true, None); diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 1c32c1a940431..7ad507331fa74 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -1412,10 +1412,24 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M Ok(()) } + pub fn try_read_by_ref(&self, mut val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { + // Convert to ByVal or ByValPair if possible + if let Value::ByRef(ptr, align) = val { + if let Some(read_val) = self.try_read_value(ptr, align, ty)? { + val = read_val; + } + } + Ok(val) + } + pub fn try_read_value(&self, ptr: Pointer, ptr_align: Align, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { let layout = self.layout_of(ty)?; self.memory.check_align(ptr, ptr_align)?; + if layout.size.bytes() == 0 { + return Ok(Some(Value::ByVal(PrimVal::Undef))); + } + let ptr = ptr.to_ptr()?; // Not the right place to do this From 7c25aa79c5aa7ea8dd2ebe3c99d483df08bd01ec Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 19 May 2018 16:37:29 +0200 Subject: [PATCH 5/5] Use `Size` instead of `u64` in mir interpretation --- src/librustc/mir/interpret/error.rs | 15 +- src/librustc/mir/interpret/mod.rs | 71 ++++---- src/librustc/mir/interpret/value.rs | 20 +-- src/librustc/mir/mod.rs | 2 +- src/librustc_codegen_llvm/mir/constant.rs | 9 +- src/librustc_codegen_llvm/mir/operand.rs | 2 +- src/librustc_mir/hair/cx/mod.rs | 6 +- src/librustc_mir/hair/pattern/_match.rs | 2 +- src/librustc_mir/hair/pattern/mod.rs | 5 +- src/librustc_mir/interpret/cast.rs | 4 +- src/librustc_mir/interpret/const_eval.rs | 10 +- src/librustc_mir/interpret/eval_context.rs | 59 ++++--- src/librustc_mir/interpret/machine.rs | 3 +- src/librustc_mir/interpret/memory.rs | 169 ++++++++++--------- src/librustc_mir/interpret/place.rs | 20 +-- src/librustc_mir/interpret/terminator/mod.rs | 2 +- src/librustc_target/abi/mod.rs | 2 +- 17 files changed, 204 insertions(+), 197 deletions(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 1e1d50c3fc036..6885bf89cc8b6 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -2,6 +2,7 @@ use std::{fmt, env}; use mir; use ty::{FnSig, Ty, layout}; +use ty::layout::{Size, Align}; use super::{ MemoryPointer, Lock, AccessKind @@ -47,7 +48,7 @@ pub enum EvalErrorKind<'tcx, O> { PointerOutOfBounds { ptr: MemoryPointer, access: bool, - allocation_size: u64, + allocation_size: Size, }, InvalidNullPointerUsage, ReadPointerAsBytes, @@ -71,8 +72,8 @@ pub enum EvalErrorKind<'tcx, O> { TlsOutOfBounds, AbiViolation(String), AlignmentCheckFailed { - required: u64, - has: u64, + required: Align, + has: Align, }, MemoryLockViolation { ptr: MemoryPointer, @@ -108,7 +109,7 @@ pub enum EvalErrorKind<'tcx, O> { DeallocatedWrongMemoryKind(String, String), ReallocateNonBasePtr, DeallocateNonBasePtr, - IncorrectAllocationInformation(u64, usize, u64, u64), + IncorrectAllocationInformation(Size, Size, Align, Align), Layout(layout::LayoutError<'tcx>), HeapAllocZeroBytes, HeapAllocNonPowerOfTwoAlignment(u64), @@ -269,7 +270,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { PointerOutOfBounds { ptr, access, allocation_size } => { write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", if access { "memory access" } else { "pointer computed" }, - ptr.offset, ptr.alloc_id, allocation_size) + ptr.offset.bytes(), ptr.alloc_id, allocation_size.bytes()) }, MemoryLockViolation { ptr, len, frame, access, ref lock } => { write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}", @@ -305,7 +306,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c), AlignmentCheckFailed { required, has } => write!(f, "tried to access memory with alignment {}, but alignment {} is required", - has, required), + has.abi(), required.abi()), TypeNotPrimitive(ty) => write!(f, "expected primitive type, got {}", ty), Layout(ref err) => @@ -315,7 +316,7 @@ impl<'tcx, O: fmt::Debug> fmt::Debug for EvalErrorKind<'tcx, O> { MachineError(ref inner) => write!(f, "{}", inner), IncorrectAllocationInformation(size, size2, align, align2) => - write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size, align, size2, align2), + write!(f, "incorrect alloc info: expected size {} and align {}, got size {} and align {}", size.bytes(), align.abi(), size2.bytes(), align2.abi()), _ => write!(f, "{}", self.description()), } } diff --git a/src/librustc/mir/interpret/mod.rs b/src/librustc/mir/interpret/mod.rs index 31885c1e0205e..d4f18acf8ad54 100644 --- a/src/librustc/mir/interpret/mod.rs +++ b/src/librustc/mir/interpret/mod.rs @@ -17,7 +17,7 @@ use std::fmt; use mir; use hir::def_id::DefId; use ty::{self, TyCtxt}; -use ty::layout::{self, Align, HasDataLayout}; +use ty::layout::{self, Align, HasDataLayout, Size}; use middle::region; use std::iter; use std::io; @@ -109,42 +109,42 @@ impl PointerArithmetic for T {} #[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)] pub struct MemoryPointer { pub alloc_id: AllocId, - pub offset: u64, + pub offset: Size, } impl<'tcx> MemoryPointer { - pub fn new(alloc_id: AllocId, offset: u64) -> Self { + pub fn new(alloc_id: AllocId, offset: Size) -> Self { MemoryPointer { alloc_id, offset } } pub(crate) fn wrapping_signed_offset(self, i: i64, cx: C) -> Self { MemoryPointer::new( self.alloc_id, - cx.data_layout().wrapping_signed_offset(self.offset, i), + Size::from_bytes(cx.data_layout().wrapping_signed_offset(self.offset.bytes(), i)), ) } pub fn overflowing_signed_offset(self, i: i128, cx: C) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset, i); - (MemoryPointer::new(self.alloc_id, res), over) + let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset.bytes(), i); + (MemoryPointer::new(self.alloc_id, Size::from_bytes(res)), over) } pub(crate) fn signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { Ok(MemoryPointer::new( self.alloc_id, - cx.data_layout().signed_offset(self.offset, i)?, + Size::from_bytes(cx.data_layout().signed_offset(self.offset.bytes(), i)?), )) } - pub fn overflowing_offset(self, i: u64, cx: C) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_offset(self.offset, i); - (MemoryPointer::new(self.alloc_id, res), over) + pub fn overflowing_offset(self, i: Size, cx: C) -> (Self, bool) { + let (res, over) = cx.data_layout().overflowing_offset(self.offset.bytes(), i.bytes()); + (MemoryPointer::new(self.alloc_id, Size::from_bytes(res)), over) } - pub fn offset(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { + pub fn offset(self, i: Size, cx: C) -> EvalResult<'tcx, Self> { Ok(MemoryPointer::new( self.alloc_id, - cx.data_layout().offset(self.offset, i)?, + Size::from_bytes(cx.data_layout().offset(self.offset.bytes(), i.bytes())?), )) } } @@ -244,7 +244,7 @@ pub struct Allocation { pub bytes: Vec, /// Maps from byte addresses to allocations. /// Only the first byte of a pointer is inserted into the map. - pub relocations: BTreeMap, + pub relocations: BTreeMap, /// Denotes undefined memory. Reading from undefined memory is forbidden in miri pub undef_mask: UndefMask, /// The alignment of the allocation to detect unaligned reads. @@ -257,8 +257,8 @@ pub struct Allocation { impl Allocation { pub fn from_bytes(slice: &[u8], align: Align) -> Self { - let mut undef_mask = UndefMask::new(0); - undef_mask.grow(slice.len() as u64, true); + let mut undef_mask = UndefMask::new(Size::from_bytes(0)); + undef_mask.grow(Size::from_bytes(slice.len() as u64), true); Self { bytes: slice.to_owned(), relocations: BTreeMap::new(), @@ -272,10 +272,10 @@ impl Allocation { Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap()) } - pub fn undef(size: u64, align: Align) -> Self { - assert_eq!(size as usize as u64, size); + pub fn undef(size: Size, align: Align) -> Self { + assert_eq!(size.bytes() as usize as u64, size.bytes()); Allocation { - bytes: vec![0; size as usize], + bytes: vec![0; size.bytes() as usize], relocations: BTreeMap::new(), undef_mask: UndefMask::new(size), align, @@ -331,35 +331,35 @@ const BLOCK_SIZE: u64 = 64; #[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)] pub struct UndefMask { blocks: Vec, - len: u64, + len: Size, } impl_stable_hash_for!(struct mir::interpret::UndefMask{blocks, len}); impl UndefMask { - pub fn new(size: u64) -> Self { + pub fn new(size: Size) -> Self { let mut m = UndefMask { blocks: vec![], - len: 0, + len: Size::from_bytes(0), }; m.grow(size, false); m } /// Check whether the range `start..end` (end-exclusive) is entirely defined. - pub fn is_range_defined(&self, start: u64, end: u64) -> bool { + pub fn is_range_defined(&self, start: Size, end: Size) -> bool { if end > self.len { return false; } - for i in start..end { - if !self.get(i) { + for i in start.bytes()..end.bytes() { + if !self.get(Size::from_bytes(i)) { return false; } } true } - pub fn set_range(&mut self, start: u64, end: u64, new_state: bool) { + pub fn set_range(&mut self, start: Size, end: Size, new_state: bool) { let len = self.len; if end > len { self.grow(end - len, new_state); @@ -367,18 +367,18 @@ impl UndefMask { self.set_range_inbounds(start, end, new_state); } - pub fn set_range_inbounds(&mut self, start: u64, end: u64, new_state: bool) { - for i in start..end { - self.set(i, new_state); + pub fn set_range_inbounds(&mut self, start: Size, end: Size, new_state: bool) { + for i in start.bytes()..end.bytes() { + self.set(Size::from_bytes(i), new_state); } } - pub fn get(&self, i: u64) -> bool { + pub fn get(&self, i: Size) -> bool { let (block, bit) = bit_index(i); (self.blocks[block] & 1 << bit) != 0 } - pub fn set(&mut self, i: u64, new_state: bool) { + pub fn set(&mut self, i: Size, new_state: bool) { let (block, bit) = bit_index(i); if new_state { self.blocks[block] |= 1 << bit; @@ -387,10 +387,10 @@ impl UndefMask { } } - pub fn grow(&mut self, amount: u64, new_state: bool) { - let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len; - if amount > unused_trailing_bits { - let additional_blocks = amount / BLOCK_SIZE + 1; + pub fn grow(&mut self, amount: Size, new_state: bool) { + let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len.bytes(); + if amount.bytes() > unused_trailing_bits { + let additional_blocks = amount.bytes() / BLOCK_SIZE + 1; assert_eq!(additional_blocks as usize as u64, additional_blocks); self.blocks.extend( iter::repeat(0).take(additional_blocks as usize), @@ -402,7 +402,8 @@ impl UndefMask { } } -fn bit_index(bits: u64) -> (usize, usize) { +fn bit_index(bits: Size) -> (usize, usize) { + let bits = bits.bytes(); let a = bits / BLOCK_SIZE; let b = bits % BLOCK_SIZE; assert_eq!(a as usize as u64, a); diff --git a/src/librustc/mir/interpret/value.rs b/src/librustc/mir/interpret/value.rs index ad076fe681bee..5ac2f7f356ead 100644 --- a/src/librustc/mir/interpret/value.rs +++ b/src/librustc/mir/interpret/value.rs @@ -1,6 +1,6 @@ #![allow(unknown_lints)] -use ty::layout::{Align, HasDataLayout}; +use ty::layout::{Align, HasDataLayout, Size}; use ty; use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation}; @@ -14,7 +14,7 @@ pub enum ConstValue<'tcx> { /// Used only for types with layout::abi::ScalarPair ByValPair(PrimVal, PrimVal), /// Used only for the remaining cases. An allocation + offset into the allocation - ByRef(&'tcx Allocation, u64), + ByRef(&'tcx Allocation, Size), } impl<'tcx> ConstValue<'tcx> { @@ -129,13 +129,13 @@ impl<'tcx> Pointer { } } - pub fn offset(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { + pub fn offset(self, i: Size, cx: C) -> EvalResult<'tcx, Self> { let layout = cx.data_layout(); match self.primval { PrimVal::Bytes(b) => { assert_eq!(b as u64 as u128, b); Ok(Pointer::from( - PrimVal::Bytes(layout.offset(b as u64, i)? as u128), + PrimVal::Bytes(layout.offset(b as u64, i.bytes())? as u128), )) } PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from), @@ -336,25 +336,25 @@ impl PrimValKind { } } - pub fn from_uint_size(size: u64) -> Self { - match size { + pub fn from_uint_size(size: Size) -> Self { + match size.bytes() { 1 => PrimValKind::U8, 2 => PrimValKind::U16, 4 => PrimValKind::U32, 8 => PrimValKind::U64, 16 => PrimValKind::U128, - _ => bug!("can't make uint with size {}", size), + _ => bug!("can't make uint with size {}", size.bytes()), } } - pub fn from_int_size(size: u64) -> Self { - match size { + pub fn from_int_size(size: Size) -> Self { + match size.bytes() { 1 => PrimValKind::I8, 2 => PrimValKind::I16, 4 => PrimValKind::I32, 8 => PrimValKind::I64, 16 => PrimValKind::I128, - _ => bug!("can't make int with size {}", size), + _ => bug!("can't make int with size {}", size.bytes()), } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 40e9b687f0ccc..f42f876510de7 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -1913,7 +1913,7 @@ pub fn print_miri_value(value: Value, ty: Ty, f: &mut W) -> fmt::Resul .get_alloc(ptr.alloc_id); if let Some(alloc) = alloc { assert_eq!(len as usize as u128, len); - let slice = &alloc.bytes[(ptr.offset as usize)..][..(len as usize)]; + 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) diff --git a/src/librustc_codegen_llvm/mir/constant.rs b/src/librustc_codegen_llvm/mir/constant.rs index 9fd2f1bdd7a33..36c1d335ec4d7 100644 --- a/src/librustc_codegen_llvm/mir/constant.rs +++ b/src/librustc_codegen_llvm/mir/constant.rs @@ -16,7 +16,7 @@ use rustc::mir; use rustc_data_structures::indexed_vec::Idx; use rustc::mir::interpret::{GlobalId, MemoryPointer, PrimVal, Allocation, ConstValue}; use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar}; +use rustc::ty::layout::{self, HasDataLayout, LayoutOf, Scalar, Size}; use builder::Builder; use common::{CodegenCx}; use common::{C_bytes, C_struct, C_uint_big, C_undef, C_usize}; @@ -68,7 +68,7 @@ pub fn primval_to_llvm(cx: &CodegenCx, let llval = unsafe { llvm::LLVMConstInBoundsGEP( consts::bitcast(base_addr, Type::i8p(cx)), - &C_usize(cx, ptr.offset), + &C_usize(cx, ptr.offset.bytes()), 1, ) }; if scalar.value != layout::Pointer { @@ -88,6 +88,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { let mut next_offset = 0; for (&offset, &alloc_id) in &alloc.relocations { + let offset = offset.bytes(); assert_eq!(offset as usize as u64, offset); let offset = offset as usize; if offset > next_offset { @@ -99,7 +100,7 @@ pub fn const_alloc_to_llvm(cx: &CodegenCx, alloc: &Allocation) -> ValueRef { ).expect("const_alloc_to_llvm: could not read relocation pointer") as u64; llvals.push(primval_to_llvm( cx, - PrimVal::Ptr(MemoryPointer { alloc_id, offset: ptr_offset }), + PrimVal::Ptr(MemoryPointer { alloc_id, offset: Size::from_bytes(ptr_offset) }), &Scalar { value: layout::Primitive::Pointer, valid_range: 0..=!0 @@ -129,7 +130,7 @@ pub fn codegen_static_initializer<'a, 'tcx>( let static_ = cx.tcx.const_eval(param_env.and(cid))?; let alloc = match static_.val { - ConstVal::Value(ConstValue::ByRef(alloc, 0)) => alloc, + ConstVal::Value(ConstValue::ByRef(alloc, n)) if n.bytes() == 0 => alloc, _ => bug!("static const eval returned {:#?}", static_), }; Ok(const_alloc_to_llvm(cx, alloc)) diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index f6dc81a4706c0..91e3937333419 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -143,7 +143,7 @@ impl<'a, 'tcx> OperandRef<'tcx> { let llval = unsafe { LLVMConstInBoundsGEP( consts::bitcast(base_addr, Type::i8p(bx.cx)), - &C_usize(bx.cx, offset), + &C_usize(bx.cx, offset.bytes()), 1, )}; let llval = consts::bitcast(llval, layout.llvm_type(bx.cx).ptr_to()); diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index b01b3542136c4..4739c0e92ed2b 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -21,7 +21,7 @@ use rustc::hir::def_id::{DefId, LOCAL_CRATE}; use rustc::hir::map::blocks::FnLikeNode; use rustc::middle::region; use rustc::infer::InferCtxt; -use rustc::ty::layout::IntegerExt; +use rustc::ty::layout::{IntegerExt, Size}; use rustc::ty::subst::Subst; use rustc::ty::{self, Ty, TyCtxt, layout}; use rustc::ty::subst::Substs; @@ -182,7 +182,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { LitKind::Str(ref s, _) => { let s = s.as_str(); let id = self.tcx.allocate_cached(s.as_bytes()); - let ptr = MemoryPointer::new(id, 0); + let ptr = MemoryPointer::new(id, Size::from_bytes(0)); ConstValue::ByValPair( PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128), @@ -190,7 +190,7 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> { }, LitKind::ByteStr(ref data) => { let id = self.tcx.allocate_cached(data); - let ptr = MemoryPointer::new(id, 0); + let ptr = MemoryPointer::new(id, Size::from_bytes(0)); ConstValue::ByVal(PrimVal::Ptr(ptr)) }, LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)), diff --git a/src/librustc_mir/hair/pattern/_match.rs b/src/librustc_mir/hair/pattern/_match.rs index f930d47dc0bd3..0c2645b4c5cdc 100644 --- a/src/librustc_mir/hair/pattern/_match.rs +++ b/src/librustc_mir/hair/pattern/_match.rs @@ -191,7 +191,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { .interpret_interner .get_alloc(ptr.alloc_id) .unwrap(); - assert_eq!(ptr.offset, 0); + assert_eq!(ptr.offset.bytes(), 0); // FIXME: check length alloc.bytes.iter().map(|b| { &*pattern_arena.alloc(Pattern { diff --git a/src/librustc_mir/hair/pattern/mod.rs b/src/librustc_mir/hair/pattern/mod.rs index 749e574ff7ad4..0368e6595c18d 100644 --- a/src/librustc_mir/hair/pattern/mod.rs +++ b/src/librustc_mir/hair/pattern/mod.rs @@ -22,6 +22,7 @@ use rustc::middle::const_val::ConstVal; use rustc::mir::{fmt_const_val, Field, BorrowKind, Mutability}; use rustc::mir::interpret::{PrimVal, GlobalId, ConstValue}; use rustc::ty::{self, TyCtxt, AdtDef, Ty, Region}; +use rustc::ty::layout::Size; use rustc::ty::subst::{Substs, Kind}; use rustc::hir::{self, PatKind, RangeEnd}; use rustc::hir::def::{Def, CtorKind}; @@ -1083,7 +1084,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, LitKind::Str(ref s, _) => { let s = s.as_str(); let id = tcx.allocate_cached(s.as_bytes()); - let ptr = MemoryPointer::new(id, 0); + let ptr = MemoryPointer::new(id, Size::from_bytes(0)); ConstValue::ByValPair( PrimVal::Ptr(ptr), PrimVal::from_u128(s.len() as u128), @@ -1091,7 +1092,7 @@ fn lit_to_const<'a, 'tcx>(lit: &'tcx ast::LitKind, }, LitKind::ByteStr(ref data) => { let id = tcx.allocate_cached(data); - let ptr = MemoryPointer::new(id, 0); + let ptr = MemoryPointer::new(id, Size::from_bytes(0)); ConstValue::ByVal(PrimVal::Ptr(ptr)) }, LitKind::Byte(n) => ConstValue::ByVal(PrimVal::Bytes(n as u128)), diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs index 002b5eb187db3..b5568b833397f 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/src/librustc_mir/interpret/cast.rs @@ -73,7 +73,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { match dest_ty.sty { // float -> uint TyUint(t) => { - let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8); + let width = t.bit_width().unwrap_or(self.memory.pointer_size().bytes() as usize * 8); match fty { FloatTy::F32 => Ok(PrimVal::Bytes(Single::from_bits(bits).to_u128(width).value)), FloatTy::F64 => Ok(PrimVal::Bytes(Double::from_bits(bits).to_u128(width).value)), @@ -81,7 +81,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { }, // float -> int TyInt(t) => { - let width = t.bit_width().unwrap_or(self.memory.pointer_size() as usize * 8); + let width = t.bit_width().unwrap_or(self.memory.pointer_size().bytes() as usize * 8); match fty { FloatTy::F32 => Ok(PrimVal::from_i128(Single::from_bits(bits).to_i128(width).value)), FloatTy::F64 => Ok(PrimVal::from_i128(Double::from_bits(bits).to_i128(width).value)), diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index ec696ec82b9d7..c514381703000 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -114,7 +114,7 @@ pub fn value_to_const_value<'tcx>( let ptr = ptr.primval.to_ptr().unwrap(); let alloc = ecx.memory.get(ptr.alloc_id)?; assert!(alloc.align.abi() >= align.abi()); - assert!(alloc.bytes.len() as u64 - ptr.offset >= layout.size.bytes()); + assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= layout.size.bytes()); let mut alloc = alloc.clone(); alloc.align = align; let alloc = ecx.tcx.intern_const_alloc(alloc); @@ -165,7 +165,7 @@ fn eval_body_using_ecx<'a, 'mir, 'tcx>( let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( - layout.size.bytes(), + layout.size, layout.align, None, )?; @@ -470,7 +470,7 @@ pub fn const_variant_index<'a, 'tcx>( let (ptr, align) = match value { Value::ByValPair(..) | Value::ByVal(_) => { let layout = ecx.layout_of(ty)?; - let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?; + let ptr = ecx.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))?; let ptr: Pointer = ptr.into(); ecx.write_value_to_ptr(value, ptr, layout.align, ty)?; (ptr, layout.align) @@ -487,7 +487,7 @@ pub fn const_value_to_allocation_provider<'a, 'tcx>( ) -> &'tcx Allocation { match val { ConstValue::ByRef(alloc, offset) => { - assert_eq!(offset, 0); + assert_eq!(offset.bytes(), 0); return alloc; }, _ => () @@ -500,7 +500,7 @@ pub fn const_value_to_allocation_provider<'a, 'tcx>( ()); let value = ecx.const_value_to_value(val, ty)?; let layout = ecx.layout_of(ty)?; - let ptr = ecx.memory.allocate(layout.size.bytes(), layout.align, Some(MemoryKind::Stack))?; + let ptr = ecx.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack))?; ecx.write_value_to_ptr(value, ptr.into(), layout.align, ty)?; let alloc = ecx.memory.get(ptr.alloc_id)?; Ok(tcx.intern_const_alloc(alloc.clone())) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 7ad507331fa74..1b4cdccee76bd 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -207,8 +207,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let layout = self.layout_of(ty)?; assert!(!layout.is_unsized(), "cannot alloc memory for unsized type"); - let size = layout.size.bytes(); - self.memory.allocate(size, layout.align, Some(MemoryKind::Stack)) + self.memory.allocate(layout.size, layout.align, Some(MemoryKind::Stack)) } pub fn memory(&self) -> &Memory<'a, 'mir, 'tcx, M> { @@ -598,14 +597,14 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ) } }; - let elem_size = self.layout_of(elem_ty)?.size.bytes(); + let elem_size = self.layout_of(elem_ty)?.size; let value = self.eval_operand(operand)?.value; let (dest, dest_align) = self.force_allocation(dest)?.to_ptr_align(); // FIXME: speed up repeat filling for i in 0..length { - let elem_dest = dest.offset(i * elem_size, &self)?; + let elem_dest = dest.offset(elem_size * i as u64, &self)?; self.write_value_to_ptr(value, elem_dest, dest_align, elem_ty)?; } } @@ -1027,7 +1026,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M .interpret_interner .cache_static(gid.instance.def_id()); let layout = self.layout_of(ty)?; - let ptr = MemoryPointer::new(alloc_id, 0); + let ptr = MemoryPointer::new(alloc_id, Size::from_bytes(0)); return Ok(Value::ByRef(ptr.into(), layout.align)) } let cv = self.const_eval(gid)?; @@ -1195,7 +1194,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } else { let dest_ptr = self.alloc_ptr(dest_ty)?.into(); let layout = self.layout_of(dest_ty)?; - self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size.bytes(), false)?; + self.memory.copy(src_ptr, align.min(layout.align), dest_ptr, layout.align, layout.size, false)?; write_dest(self, Value::ByRef(dest_ptr, layout.align))?; } } else { @@ -1217,7 +1216,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M trace!("write_value_to_ptr: {:#?}, {}, {:#?}", value, dest_ty, layout); match value { Value::ByRef(ptr, align) => { - self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size.bytes(), false) + self.memory.copy(ptr, align.min(layout.align), dest, dest_align.min(layout.align), layout.size, false) } Value::ByVal(primval) => { let signed = match layout.abi { @@ -1228,7 +1227,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M _ if primval.is_undef() => false, _ => bug!("write_value_to_ptr: invalid ByVal layout: {:#?}", layout) }; - self.memory.write_primval(dest, dest_align, primval, layout.size.bytes(), signed) + self.memory.write_primval(dest, dest_align, primval, layout.size, signed) } Value::ByValPair(a_val, b_val) => { trace!("write_value_to_ptr valpair: {:#?}", layout); @@ -1239,10 +1238,10 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let (a_size, b_size) = (a.size(&self), b.size(&self)); let a_ptr = dest; let b_offset = a_size.abi_align(b.align(&self)); - let b_ptr = dest.offset(b_offset.bytes(), &self)?.into(); + let b_ptr = dest.offset(b_offset, &self)?.into(); // TODO: What about signedess? - self.memory.write_primval(a_ptr, dest_align, a_val, a_size.bytes(), false)?; - self.memory.write_primval(b_ptr, dest_align, b_val, b_size.bytes(), false) + self.memory.write_primval(a_ptr, dest_align, a_val, a_size, false)?; + self.memory.write_primval(b_ptr, dest_align, b_val, b_size, false) } } } @@ -1257,11 +1256,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ty::TyInt(int_ty) => { use syntax::ast::IntTy::*; let size = match int_ty { - I8 => 1, - I16 => 2, - I32 => 4, - I64 => 8, - I128 => 16, + I8 => Size::from_bytes(1), + I16 => Size::from_bytes(2), + I32 => Size::from_bytes(4), + I64 => Size::from_bytes(8), + I128 => Size::from_bytes(16), Isize => self.memory.pointer_size(), }; PrimValKind::from_int_size(size) @@ -1270,11 +1269,11 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ty::TyUint(uint_ty) => { use syntax::ast::UintTy::*; let size = match uint_ty { - U8 => 1, - U16 => 2, - U32 => 4, - U64 => 8, - U128 => 16, + U8 => Size::from_bytes(1), + U16 => Size::from_bytes(2), + U32 => Size::from_bytes(4), + U64 => Size::from_bytes(8), + U128 => Size::from_bytes(16), Usize => self.memory.pointer_size(), }; PrimValKind::from_uint_size(size) @@ -1297,8 +1296,8 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M layout::Abi::Scalar(ref scalar) => { use rustc::ty::layout::Primitive::*; match scalar.value { - Int(i, false) => PrimValKind::from_uint_size(i.size().bytes()), - Int(i, true) => PrimValKind::from_int_size(i.size().bytes()), + Int(i, false) => PrimValKind::from_uint_size(i.size()), + Int(i, true) => PrimValKind::from_int_size(i.size()), F32 => PrimValKind::F32, F64 => PrimValKind::F64, Pointer => PrimValKind::Ptr, @@ -1372,7 +1371,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M ) -> EvalResult<'tcx> { match ty.sty { ty::TyBool => { - let val = self.memory.read_primval(ptr, ptr_align, 1)?; + let val = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(1))?; match val { PrimVal::Bytes(0) | PrimVal::Bytes(1) => (), // TODO: This seems a little overeager, should reading at bool type already be insta-UB? @@ -1380,7 +1379,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } } ty::TyChar => { - let c = self.memory.read_primval(ptr, ptr_align, 4)?.to_bytes()? as u32; + let c = self.memory.read_primval(ptr, ptr_align, Size::from_bytes(4))?.to_bytes()? as u32; match ::std::char::from_u32(c) { Some(..) => (), None => return err!(InvalidChar(c as u128)), @@ -1402,7 +1401,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M } if let layout::Abi::Scalar(ref scalar) = self.layout_of(ty)?.abi { - let size = scalar.value.size(self).bytes(); + let size = scalar.value.size(self); self.memory.read_primval(ptr, ptr_align, size)?; } } @@ -1437,7 +1436,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M match layout.abi { layout::Abi::Scalar(..) => { - let primval = self.memory.read_primval(ptr, ptr_align, layout.size.bytes())?; + let primval = self.memory.read_primval(ptr, ptr_align, layout.size)?; Ok(Some(Value::ByVal(primval))) } layout::Abi::ScalarPair(ref a, ref b) => { @@ -1445,9 +1444,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M let (a_size, b_size) = (a.size(self), b.size(self)); let a_ptr = ptr; let b_offset = a_size.abi_align(b.align(self)); - let b_ptr = ptr.offset(b_offset.bytes(), self)?.into(); - let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size.bytes())?; - let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size.bytes())?; + let b_ptr = ptr.offset(b_offset, self)?.into(); + let a_val = self.memory.read_primval(a_ptr, ptr_align, a_size)?; + let b_val = self.memory.read_primval(b_ptr, ptr_align, b_size)?; Ok(Some(Value::ByValPair(a_val, b_val))) } _ => Ok(None), diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs index 5af0a053e9239..a5c94e4fcecfc 100644 --- a/src/librustc_mir/interpret/machine.rs +++ b/src/librustc_mir/interpret/machine.rs @@ -7,6 +7,7 @@ use super::{EvalContext, Place, ValTy, Memory}; use rustc::mir; use rustc::ty::{self, Ty}; +use rustc::ty::layout::Size; use syntax::codemap::Span; use syntax::ast::Mutability; @@ -92,7 +93,7 @@ pub trait Machine<'mir, 'tcx>: Sized { fn check_locks<'a>( _mem: &Memory<'a, 'mir, 'tcx, Self>, _ptr: MemoryPointer, - _size: u64, + _size: Size, _access: AccessKind, ) -> EvalResult<'tcx> { Ok(()) diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index ba1c05deef1b4..755eaa443b6cd 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -5,7 +5,7 @@ use rustc::hir::def_id::DefId; use rustc::ty::Instance; use rustc::ty::ParamEnv; use rustc::ty::maps::TyCtxtAt; -use rustc::ty::layout::{self, Align, TargetDataLayout}; +use rustc::ty::layout::{self, Align, TargetDataLayout, Size}; use syntax::ast::Mutability; use rustc::middle::const_val::{ConstVal, ErrKind}; @@ -73,12 +73,12 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn create_fn_alloc(&mut self, instance: Instance<'tcx>) -> MemoryPointer { let id = self.tcx.interpret_interner.create_fn_alloc(instance); - MemoryPointer::new(id, 0) + MemoryPointer::new(id, Size::from_bytes(0)) } pub fn allocate_cached(&mut self, bytes: &[u8]) -> MemoryPointer { let id = self.tcx.allocate_cached(bytes); - MemoryPointer::new(id, 0) + MemoryPointer::new(id, Size::from_bytes(0)) } /// kind is `None` for statics @@ -105,24 +105,24 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { /// kind is `None` for statics pub fn allocate( &mut self, - size: u64, + size: Size, align: Align, kind: Option>, ) -> EvalResult<'tcx, MemoryPointer> { let id = self.allocate_value(Allocation::undef(size, align), kind)?; - Ok(MemoryPointer::new(id, 0)) + Ok(MemoryPointer::new(id, Size::from_bytes(0))) } pub fn reallocate( &mut self, ptr: MemoryPointer, - old_size: u64, + old_size: Size, old_align: Align, - new_size: u64, + new_size: Size, new_align: Align, kind: MemoryKind, ) -> EvalResult<'tcx, MemoryPointer> { - if ptr.offset != 0 { + if ptr.offset.bytes() != 0 { return err!(ReallocateNonBasePtr); } if self.alloc_map.contains_key(&ptr.alloc_id) { @@ -163,10 +163,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn deallocate( &mut self, ptr: MemoryPointer, - size_and_align: Option<(u64, Align)>, + size_and_align: Option<(Size, Align)>, kind: MemoryKind, ) -> EvalResult<'tcx> { - if ptr.offset != 0 { + if ptr.offset.bytes() != 0 { return err!(DeallocateNonBasePtr); } @@ -208,8 +208,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { )); } if let Some((size, align)) = size_and_align { - if size != alloc.bytes.len() as u64 || align != alloc.align { - return err!(IncorrectAllocationInformation(size, alloc.bytes.len(), align.abi(), alloc.align.abi())); + if size.bytes() != alloc.bytes.len() as u64 || align != alloc.align { + return err!(IncorrectAllocationInformation(size, Size::from_bytes(alloc.bytes.len() as u64), align, alloc.align)); } } @@ -218,8 +218,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { Ok(()) } - pub fn pointer_size(&self) -> u64 { - self.tcx.data_layout.pointer_size.bytes() + pub fn pointer_size(&self) -> Size { + self.tcx.data_layout.pointer_size } pub fn endianness(&self) -> layout::Endian { @@ -232,10 +232,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { let (offset, alloc_align) = match ptr.into_inner_primval() { PrimVal::Ptr(ptr) => { let alloc = self.get(ptr.alloc_id)?; - (ptr.offset, alloc.align) + (ptr.offset.bytes(), alloc.align) } PrimVal::Bytes(bytes) => { - let v = ((bytes as u128) % (1 << self.pointer_size())) as u64; + let v = ((bytes as u128) % (1 << self.pointer_size().bytes())) as u64; if v == 0 { return err!(InvalidNullPointerUsage); } @@ -247,16 +247,17 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // Check alignment if alloc_align.abi() < required_align.abi() { return err!(AlignmentCheckFailed { - has: alloc_align.abi(), - required: required_align.abi(), + has: alloc_align, + required: required_align, }); } if offset % required_align.abi() == 0 { Ok(()) } else { + let has = offset % required_align.abi(); err!(AlignmentCheckFailed { - has: offset % required_align.abi(), - required: required_align.abi(), + has: Align::from_bytes(has, has).unwrap(), + required: required_align, }) } } @@ -264,11 +265,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx> { let alloc = self.get(ptr.alloc_id)?; let allocation_size = alloc.bytes.len() as u64; - if ptr.offset > allocation_size { + if ptr.offset.bytes() > allocation_size { return err!(PointerOutOfBounds { ptr, access, - allocation_size, + allocation_size: Size::from_bytes(allocation_size), }); } Ok(()) @@ -354,7 +355,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } pub fn get_fn(&self, ptr: MemoryPointer) -> EvalResult<'tcx, Instance<'tcx>> { - if ptr.offset != 0 { + if ptr.offset.bytes() != 0 { return err!(InvalidFunctionPointer); } debug!("reading fn ptr: {}", ptr.alloc_id); @@ -419,15 +420,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { }; for i in 0..(alloc.bytes.len() as u64) { + let i = Size::from_bytes(i); if let Some(&target_id) = alloc.relocations.get(&i) { if allocs_seen.insert(target_id) { allocs_to_print.push_back(target_id); } relocations.push((i, target_id)); } - if alloc.undef_mask.is_range_defined(i, i + 1) { + if alloc.undef_mask.is_range_defined(i, i + Size::from_bytes(1)) { // this `as usize` is fine, since `i` came from a `usize` - write!(msg, "{:02x} ", alloc.bytes[i as usize]).unwrap(); + write!(msg, "{:02x} ", alloc.bytes[i.bytes() as usize]).unwrap(); } else { msg.push_str("__ "); } @@ -444,11 +446,11 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { if !relocations.is_empty() { msg.clear(); write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces. - let mut pos = 0; - let relocation_width = (self.pointer_size() - 1) * 3; + let mut pos = Size::from_bytes(0); + let relocation_width = (self.pointer_size().bytes() - 1) * 3; for (i, target_id) in relocations { // this `as usize` is fine, since we can't print more chars than `usize::MAX` - write!(msg, "{:1$}", "", ((i - pos) * 3) as usize).unwrap(); + write!(msg, "{:1$}", "", ((i - pos) * 3).bytes() as usize).unwrap(); let target = format!("({})", target_id); // this `as usize` is fine, since we can't print more chars than `usize::MAX` write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap(); @@ -476,45 +478,45 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { fn get_bytes_unchecked( &self, ptr: MemoryPointer, - size: u64, + size: Size, align: Align, ) -> EvalResult<'tcx, &[u8]> { // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL self.check_align(ptr.into(), align)?; - if size == 0 { + if size.bytes() == 0 { return Ok(&[]); } M::check_locks(self, ptr, size, AccessKind::Read)?; self.check_bounds(ptr.offset(size, self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) let alloc = self.get(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - assert_eq!(size as usize as u64, size); - let offset = ptr.offset as usize; - Ok(&alloc.bytes[offset..offset + size as usize]) + assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes()); + assert_eq!(size.bytes() as usize as u64, size.bytes()); + let offset = ptr.offset.bytes() as usize; + Ok(&alloc.bytes[offset..offset + size.bytes() as usize]) } fn get_bytes_unchecked_mut( &mut self, ptr: MemoryPointer, - size: u64, + size: Size, align: Align, ) -> EvalResult<'tcx, &mut [u8]> { // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL self.check_align(ptr.into(), align)?; - if size == 0 { + if size.bytes() == 0 { return Ok(&mut []); } M::check_locks(self, ptr, size, AccessKind::Write)?; self.check_bounds(ptr.offset(size, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) let alloc = self.get_mut(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - assert_eq!(size as usize as u64, size); - let offset = ptr.offset as usize; - Ok(&mut alloc.bytes[offset..offset + size as usize]) + assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes()); + assert_eq!(size.bytes() as usize as u64, size.bytes()); + let offset = ptr.offset.bytes() as usize; + Ok(&mut alloc.bytes[offset..offset + size.bytes() as usize]) } - fn get_bytes(&self, ptr: MemoryPointer, size: u64, align: Align) -> EvalResult<'tcx, &[u8]> { - assert_ne!(size, 0); + fn get_bytes(&self, ptr: MemoryPointer, size: Size, align: Align) -> EvalResult<'tcx, &[u8]> { + assert_ne!(size.bytes(), 0); if self.relocations(ptr, size)?.count() != 0 { return err!(ReadPointerAsBytes); } @@ -525,10 +527,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { fn get_bytes_mut( &mut self, ptr: MemoryPointer, - size: u64, + size: Size, align: Align, ) -> EvalResult<'tcx, &mut [u8]> { - assert_ne!(size, 0); + assert_ne!(size.bytes(), 0); self.clear_relocations(ptr, size)?; self.mark_definedness(ptr.into(), size, true)?; self.get_bytes_unchecked_mut(ptr, size, align) @@ -594,13 +596,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { src_align: Align, dest: Pointer, dest_align: Align, - size: u64, + size: Size, nonoverlapping: bool, ) -> EvalResult<'tcx> { // Empty accesses don't need to be valid pointers, but they should still be aligned self.check_align(src, src_align)?; self.check_align(dest, dest_align)?; - if size == 0 { + if size.bytes() == 0 { return Ok(()); } let src = src.to_ptr()?; @@ -625,7 +627,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and // `dest` could possibly overlap. unsafe { - assert_eq!(size as usize as u64, size); + assert_eq!(size.bytes() as usize as u64, size.bytes()); if src.alloc_id == dest.alloc_id { if nonoverlapping { if (src.offset <= dest.offset && src.offset + size > dest.offset) || @@ -636,9 +638,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { )); } } - ptr::copy(src_bytes, dest_bytes, size as usize); + ptr::copy(src_bytes, dest_bytes, size.bytes() as usize); } else { - ptr::copy_nonoverlapping(src_bytes, dest_bytes, size as usize); + ptr::copy_nonoverlapping(src_bytes, dest_bytes, size.bytes() as usize); } } @@ -651,26 +653,27 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn read_c_str(&self, ptr: MemoryPointer) -> EvalResult<'tcx, &[u8]> { let alloc = self.get(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - let offset = ptr.offset as usize; + assert_eq!(ptr.offset.bytes() as usize as u64, ptr.offset.bytes()); + let offset = ptr.offset.bytes() as usize; match alloc.bytes[offset..].iter().position(|&c| c == 0) { Some(size) => { - if self.relocations(ptr, (size + 1) as u64)?.count() != 0 { + let p1 = Size::from_bytes((size + 1) as u64); + if self.relocations(ptr, p1)?.count() != 0 { return err!(ReadPointerAsBytes); } - self.check_defined(ptr, (size + 1) as u64)?; - M::check_locks(self, ptr, (size + 1) as u64, AccessKind::Read)?; + self.check_defined(ptr, p1)?; + M::check_locks(self, ptr, p1, AccessKind::Read)?; Ok(&alloc.bytes[offset..offset + size]) } None => err!(UnterminatedCString(ptr)), } } - pub fn read_bytes(&self, ptr: Pointer, size: u64) -> EvalResult<'tcx, &[u8]> { + pub fn read_bytes(&self, ptr: Pointer, size: Size) -> EvalResult<'tcx, &[u8]> { // Empty accesses don't need to be valid pointers, but they should still be non-NULL let align = Align::from_bytes(1, 1).unwrap(); self.check_align(ptr, align)?; - if size == 0 { + if size.bytes() == 0 { return Ok(&[]); } self.get_bytes(ptr.to_ptr()?, size, align) @@ -683,16 +686,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { if src.is_empty() { return Ok(()); } - let bytes = self.get_bytes_mut(ptr.to_ptr()?, src.len() as u64, align)?; + let bytes = self.get_bytes_mut(ptr.to_ptr()?, Size::from_bytes(src.len() as u64), align)?; bytes.clone_from_slice(src); Ok(()) } - pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: u64) -> EvalResult<'tcx> { + pub fn write_repeat(&mut self, ptr: Pointer, val: u8, count: Size) -> EvalResult<'tcx> { // Empty accesses don't need to be valid pointers, but they should still be non-NULL let align = Align::from_bytes(1, 1).unwrap(); self.check_align(ptr, align)?; - if count == 0 { + if count.bytes() == 0 { return Ok(()); } let bytes = self.get_bytes_mut(ptr.to_ptr()?, count, align)?; @@ -702,7 +705,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { Ok(()) } - pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: u64) -> EvalResult<'tcx, PrimVal> { + pub fn read_primval(&self, ptr: MemoryPointer, ptr_align: Align, size: Size) -> EvalResult<'tcx, PrimVal> { self.check_relocation_edges(ptr, size)?; // Make sure we don't read part of a pointer as a pointer let endianness = self.endianness(); let bytes = self.get_bytes_unchecked(ptr, size, ptr_align.min(self.int_align(size)))?; @@ -721,7 +724,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { } else { let alloc = self.get(ptr.alloc_id)?; match alloc.relocations.get(&ptr.offset) { - Some(&alloc_id) => return Ok(PrimVal::Ptr(MemoryPointer::new(alloc_id, bytes as u64))), + Some(&alloc_id) => return Ok(PrimVal::Ptr(MemoryPointer::new(alloc_id, Size::from_bytes(bytes as u64)))), None => {}, } } @@ -733,13 +736,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { self.read_primval(ptr, ptr_align, self.pointer_size()) } - pub fn write_primval(&mut self, ptr: Pointer, ptr_align: Align, val: PrimVal, size: u64, signed: bool) -> EvalResult<'tcx> { + pub fn write_primval(&mut self, ptr: Pointer, ptr_align: Align, val: PrimVal, size: Size, signed: bool) -> EvalResult<'tcx> { let endianness = self.endianness(); let bytes = match val { PrimVal::Ptr(val) => { assert_eq!(size, self.pointer_size()); - val.offset as u128 + val.offset.bytes() as u128 } PrimVal::Bytes(bytes) => bytes, @@ -782,16 +785,16 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { self.write_primval(ptr.into(), ptr_align, val, ptr_size, false) } - fn int_align(&self, size: u64) -> Align { + fn int_align(&self, size: Size) -> Align { // We assume pointer-sized integers have the same alignment as pointers. // We also assume signed and unsigned integers of the same size have the same alignment. - let ity = match size { + let ity = match size.bytes() { 1 => layout::I8, 2 => layout::I16, 4 => layout::I32, 8 => layout::I64, 16 => layout::I128, - _ => bug!("bad integer size: {}", size), + _ => bug!("bad integer size: {}", size.bytes()), }; ity.align(self) } @@ -802,14 +805,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { fn relocations( &self, ptr: MemoryPointer, - size: u64, - ) -> EvalResult<'tcx, btree_map::Range> { - let start = ptr.offset.saturating_sub(self.pointer_size() - 1); + size: Size, + ) -> EvalResult<'tcx, btree_map::Range> { + let start = ptr.offset.bytes().saturating_sub(self.pointer_size().bytes() - 1); let end = ptr.offset + size; - Ok(self.get(ptr.alloc_id)?.relocations.range(start..end)) + Ok(self.get(ptr.alloc_id)?.relocations.range(Size::from_bytes(start)..end)) } - fn clear_relocations(&mut self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { + fn clear_relocations(&mut self, ptr: MemoryPointer, size: Size) -> EvalResult<'tcx> { // Find all relocations overlapping the given range. let keys: Vec<_> = self.relocations(ptr, size)?.map(|(&k, _)| k).collect(); if keys.is_empty() { @@ -841,9 +844,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { Ok(()) } - fn check_relocation_edges(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { - let overlapping_start = self.relocations(ptr, 0)?.count(); - let overlapping_end = self.relocations(ptr.offset(size, self)?, 0)?.count(); + fn check_relocation_edges(&self, ptr: MemoryPointer, size: Size) -> EvalResult<'tcx> { + let overlapping_start = self.relocations(ptr, Size::from_bytes(0))?.count(); + let overlapping_end = self.relocations(ptr.offset(size, self)?, Size::from_bytes(0))?.count(); if overlapping_start + overlapping_end != 0 { return err!(ReadPointerAsBytes); } @@ -858,26 +861,26 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { &mut self, src: MemoryPointer, dest: MemoryPointer, - size: u64, + size: Size, ) -> EvalResult<'tcx> { // The bits have to be saved locally before writing to dest in case src and dest overlap. - assert_eq!(size as usize as u64, size); - let mut v = Vec::with_capacity(size as usize); - for i in 0..size { - let defined = self.get(src.alloc_id)?.undef_mask.get(src.offset + i); + assert_eq!(size.bytes() as usize as u64, size.bytes()); + let mut v = Vec::with_capacity(size.bytes() as usize); + for i in 0..size.bytes() { + let defined = self.get(src.alloc_id)?.undef_mask.get(src.offset + Size::from_bytes(i)); v.push(defined); } for (i, defined) in v.into_iter().enumerate() { self.get_mut(dest.alloc_id)?.undef_mask.set( dest.offset + - i as u64, + Size::from_bytes(i as u64), defined, ); } Ok(()) } - fn check_defined(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { + fn check_defined(&self, ptr: MemoryPointer, size: Size) -> EvalResult<'tcx> { let alloc = self.get(ptr.alloc_id)?; if !alloc.undef_mask.is_range_defined( ptr.offset, @@ -892,10 +895,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'a, 'mir, 'tcx, M> { pub fn mark_definedness( &mut self, ptr: Pointer, - size: u64, + size: Size, new_state: bool, ) -> EvalResult<'tcx> { - if size == 0 { + if size.bytes() == 0 { return Ok(()); } let ptr = ptr.to_ptr()?; diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 883b17b8584fb..6ccbcf07370b0 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -1,6 +1,6 @@ use rustc::mir; use rustc::ty::{self, Ty, TyCtxt}; -use rustc::ty::layout::{self, Align, LayoutOf, TyLayout}; +use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, Size}; use rustc_data_structures::indexed_vec::Idx; use rustc::mir::interpret::{GlobalId, Value, PrimVal, EvalResult, Pointer, MemoryPointer}; @@ -210,7 +210,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { }; let alloc = Machine::init_static(self, cid)?; Place::Ptr { - ptr: MemoryPointer::new(alloc, 0).into(), + ptr: MemoryPointer::new(alloc, Size::from_bytes(0)).into(), align: layout.align, extra: PlaceExtra::None, } @@ -267,9 +267,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { base_layout.ty, base_ptr.to_value_with_vtable(tab), )?; - offset.abi_align(align).bytes() + offset.abi_align(align) } - _ => offset.bytes(), + _ => offset, }; let ptr = base_ptr.offset(offset, &self)?; @@ -325,14 +325,14 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let (base_ptr, align) = base.to_ptr_align(); let (elem_ty, len) = base.elem_ty_and_len(outer_ty, self.tcx.tcx); - let elem_size = self.layout_of(elem_ty)?.size.bytes(); + let elem_size = self.layout_of(elem_ty)?.size; assert!( n < len, "Tried to access element {} of array/slice with length {}", n, len ); - let ptr = base_ptr.offset(n * elem_size, &*self)?; + let ptr = base_ptr.offset(elem_size * n, &*self)?; Ok(Place::Ptr { ptr, align, @@ -401,7 +401,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let (base_ptr, align) = base.to_ptr_align(); let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx); - let elem_size = self.layout_of(elem_ty)?.size.bytes(); + let elem_size = self.layout_of(elem_ty)?.size; assert!(n >= min_length as u64); let index = if from_end { @@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { u64::from(offset) }; - let ptr = base_ptr.offset(index * elem_size, &self)?; + let ptr = base_ptr.offset(elem_size * index, &self)?; Ok(Place::Ptr { ptr, align, extra: PlaceExtra::None }) } @@ -420,9 +420,9 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { let (base_ptr, align) = base.to_ptr_align(); let (elem_ty, n) = base.elem_ty_and_len(base_ty, self.tcx.tcx); - let elem_size = self.layout_of(elem_ty)?.size.bytes(); + let elem_size = self.layout_of(elem_ty)?.size; assert!(u64::from(from) <= n - u64::from(to)); - let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?; + let ptr = base_ptr.offset(elem_size * u64::from(from), &self)?; // sublicing arrays produces arrays let extra = if self.type_is_sized(base_ty) { PlaceExtra::None diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs index c61487f106b66..c5b823ca87b52 100644 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ b/src/librustc_mir/interpret/terminator/mod.rs @@ -341,7 +341,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> { Value::ByRef(ptr, align) => { for (i, arg_local) in arg_locals.enumerate() { let field = layout.field(&self, i)?; - let offset = layout.fields.offset(i).bytes(); + let offset = layout.fields.offset(i); let arg = Value::ByRef(ptr.offset(offset, &self)?, align.min(field.align)); let dest = diff --git a/src/librustc_target/abi/mod.rs b/src/librustc_target/abi/mod.rs index 6cd8e267ec5c1..2075400d04f51 100644 --- a/src/librustc_target/abi/mod.rs +++ b/src/librustc_target/abi/mod.rs @@ -221,7 +221,7 @@ pub enum Endian { } /// Size of a type in bytes. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Size { raw: u64 }