From 420b4260b4000af2b1ffb579fb7df5e437e0faa2 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 14 Oct 2013 22:43:03 -0400 Subject: [PATCH 1/6] fix bounds checking failure message casting the `uint` to an `int` can result in printing high values as negative intege --- src/libstd/unstable/lang.rs | 2 +- src/test/run-fail/small-negative-indexing.rs | 19 ------------------ src/test/run-fail/vec-underrun.rs | 21 -------------------- 3 files changed, 1 insertion(+), 41 deletions(-) delete mode 100644 src/test/run-fail/small-negative-indexing.rs delete mode 100644 src/test/run-fail/vec-underrun.rs diff --git a/src/libstd/unstable/lang.rs b/src/libstd/unstable/lang.rs index 6f2928e99fe..e30d0e77367 100644 --- a/src/libstd/unstable/lang.rs +++ b/src/libstd/unstable/lang.rs @@ -25,7 +25,7 @@ pub fn fail_(expr: *c_char, file: *c_char, line: size_t) -> ! { pub fn fail_bounds_check(file: *c_char, line: size_t, index: size_t, len: size_t) { let msg = format!("index out of bounds: the len is {} but the index is {}", - len as int, index as int); + len as uint, index as uint); do msg.with_c_str |buf| { fail_(buf, file, line); } diff --git a/src/test/run-fail/small-negative-indexing.rs b/src/test/run-fail/small-negative-indexing.rs deleted file mode 100644 index a016af24451..00000000000 --- a/src/test/run-fail/small-negative-indexing.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2012 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. - -// error-pattern:index out of bounds: the len is 1024 but the index is -1 - -use std::vec; - -fn main() { - let v = vec::from_fn(1024u, {|n| n}); - // this should trip a bounds check - error2!("{:?}", v[-1i8]); -} diff --git a/src/test/run-fail/vec-underrun.rs b/src/test/run-fail/vec-underrun.rs deleted file mode 100644 index 99ce79b3b6c..00000000000 --- a/src/test/run-fail/vec-underrun.rs +++ /dev/null @@ -1,21 +0,0 @@ -// -*- rust -*- -// Copyright 2012 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. - - -// error-pattern:index out of bounds: the len is 2 but the index is -1 -fn main() { - let v: ~[int] = ~[10, 20]; - let x: int = 0; - assert_eq!(v[x], 10); - // Bounds-check failure. - - assert_eq!(v[x - 1], 20); -} From aa93381e1459c5e739fab400ce8f5f83c9466804 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 14 Oct 2013 23:25:33 -0400 Subject: [PATCH 2/6] fix overflow on bounds checks Closes #9020 --- src/librustc/middle/trans/expr.rs | 6 ++---- src/test/run-fail/bounds-check-no-overflow.rs | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 src/test/run-fail/bounds-check-no-overflow.rs diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 7d772a997c1..12bb71d19ed 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -972,8 +972,6 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { let vt = tvec::vec_types(bcx, base_datum.ty); base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz"); - let scaled_ix = Mul(bcx, ix_val, vt.llunit_size); - base::maybe_name_value(bcx.ccx(), scaled_ix, "scaled_ix"); let (bcx, base, len) = base_datum.get_vec_base_and_len(bcx, index_expr.span, @@ -982,9 +980,9 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { debug2!("trans_index: base {}", bcx.val_to_str(base)); debug2!("trans_index: len {}", bcx.val_to_str(len)); - let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len); + let unscaled_len = UDiv(bcx, len, vt.llunit_size); + let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, unscaled_len); let bcx = do with_cond(bcx, bounds_check) |bcx| { - let unscaled_len = UDiv(bcx, len, vt.llunit_size); controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, unscaled_len) }; diff --git a/src/test/run-fail/bounds-check-no-overflow.rs b/src/test/run-fail/bounds-check-no-overflow.rs new file mode 100644 index 00000000000..679f060a55d --- /dev/null +++ b/src/test/run-fail/bounds-check-no-overflow.rs @@ -0,0 +1,19 @@ +// Copyright 2013 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. + +// error-pattern:index out of bounds: the len is 3 but the index is + +use std::uint::max_value; +use std::sys::size_of; + +fn main() { + let xs = [1, 2, 3]; + xs[max_value / size_of::() + 1]; +} From e1a26ad2713994ccba65d62ca64a2eb5db4eaf81 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Oct 2013 00:37:32 -0400 Subject: [PATCH 3/6] use element count in slices, not size in bytes This allows the indexing bounds check or other comparisons against an element length to avoid a multiplication by the size. --- src/librustc/middle/trans/_match.rs | 2 +- src/librustc/middle/trans/base.rs | 14 ++--- src/librustc/middle/trans/consts.rs | 48 ++++++--------- src/librustc/middle/trans/debuginfo.rs | 2 +- src/librustc/middle/trans/expr.rs | 6 +- src/librustc/middle/trans/tvec.rs | 6 +- src/libstd/rand/mod.rs | 14 +++-- src/libstd/repr.rs | 35 ++++++----- src/libstd/vec.rs | 81 ++++++++++++++++++++++++++ src/test/debug-info/vec-slices.rs | 22 +++---- 10 files changed, 154 insertions(+), 76 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index a159512aee5..15c1f8ea339 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1059,7 +1059,7 @@ fn extract_vec_elems(bcx: @mut Block, Store(bcx, slice_begin, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]) ); - Store(bcx, slice_len, + Store(bcx, UDiv(bcx, slice_len, vt.llunit_size), GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]) ); elems[n] = scratch.val; diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index 1822237f45c..d9f16a4efe6 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -54,7 +54,7 @@ use middle::trans::glue; use middle::trans::inline; use middle::trans::llrepr::LlvmRepr; use middle::trans::machine; -use middle::trans::machine::{llalign_of_min, llsize_of, llsize_of_alloc}; +use middle::trans::machine::{llalign_of_min, llsize_of}; use middle::trans::meth; use middle::trans::monomorphize; use middle::trans::tvec; @@ -2910,7 +2910,7 @@ pub fn decl_gc_metadata(ccx: &mut CrateContext, llmod_id: &str) { } } -pub fn create_module_map(ccx: &mut CrateContext) -> (ValueRef, uint, uint) { +pub fn create_module_map(ccx: &mut CrateContext) -> (ValueRef, uint) { let str_slice_type = Type::struct_([Type::i8p(), ccx.int_type], false); let elttype = Type::struct_([str_slice_type, ccx.int_type], false); let maptype = Type::array(&elttype, ccx.module_data.len() as u64); @@ -2942,7 +2942,7 @@ pub fn create_module_map(ccx: &mut CrateContext) -> (ValueRef, uint, uint) { unsafe { llvm::LLVMSetInitializer(map, C_array(elttype, elts)); } - return (map, keys.len(), llsize_of_alloc(ccx, elttype)); + return (map, keys.len()) } @@ -3004,19 +3004,17 @@ pub fn fill_crate_map(ccx: &mut CrateContext, map: ValueRef) { lib::llvm::SetLinkage(vec_elements, lib::llvm::InternalLinkage); llvm::LLVMSetInitializer(vec_elements, C_array(ccx.int_type, subcrates)); - let (mod_map, mod_count, mod_struct_size) = create_module_map(ccx); + let (mod_map, mod_count) = create_module_map(ccx); llvm::LLVMSetInitializer(map, C_struct( [C_i32(2), C_struct([ p2i(ccx, mod_map), - // byte size of the module map array, an entry consists of two integers - C_int(ccx, ((mod_count * mod_struct_size) as int)) + C_uint(ccx, mod_count) ], false), C_struct([ p2i(ccx, vec_elements), - // byte size of the subcrates array, an entry consists of an integer - C_int(ccx, (subcrates.len() * llsize_of_alloc(ccx, ccx.int_type)) as int) + C_uint(ccx, subcrates.len()) ], false) ], false)); } diff --git a/src/librustc/middle/trans/consts.rs b/src/librustc/middle/trans/consts.rs index 00431501e64..f85b8de35dd 100644 --- a/src/librustc/middle/trans/consts.rs +++ b/src/librustc/middle/trans/consts.rs @@ -83,23 +83,18 @@ pub fn const_ptrcast(cx: &mut CrateContext, a: ValueRef, t: Type) -> ValueRef { } } -pub fn const_vec(cx: @mut CrateContext, e: &ast::Expr, es: &[@ast::Expr]) - -> (ValueRef, ValueRef, Type, bool) { - unsafe { - let vec_ty = ty::expr_ty(cx.tcx, e); - let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty); - let llunitty = type_of::type_of(cx, unit_ty); - let unit_sz = machine::llsize_of(cx, llunitty); - let sz = llvm::LLVMConstMul(C_uint(cx, es.len()), unit_sz); - let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e))); - // If the vector contains enums, an LLVM array won't work. - let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) { - C_struct(vs, false) - } else { - C_array(llunitty, vs) - }; - return (v, sz, llunitty, inlineable.iter().fold(true, |a, &b| a && b)); - } +fn const_vec(cx: @mut CrateContext, e: &ast::Expr, es: &[@ast::Expr]) -> (ValueRef, Type, bool) { + let vec_ty = ty::expr_ty(cx.tcx, e); + let unit_ty = ty::sequence_element_type(cx.tcx, vec_ty); + let llunitty = type_of::type_of(cx, unit_ty); + let (vs, inlineable) = vec::unzip(es.iter().map(|e| const_expr(cx, *e))); + // If the vector contains enums, an LLVM array won't work. + let v = if vs.iter().any(|vi| val_ty(*vi) != llunitty) { + C_struct(vs, false) + } else { + C_array(llunitty, vs) + }; + (v, llunitty, inlineable.iter().fold(true, |a, &b| a && b)) } fn const_addr_of(cx: &mut CrateContext, cv: ValueRef) -> ValueRef { @@ -225,9 +220,8 @@ pub fn const_expr(cx: @mut CrateContext, e: &ast::Expr) -> (ValueRef, bool) { assert_eq!(abi::slice_elt_len, 1); match ty::get(ty).sty { - ty::ty_evec(_, ty::vstore_fixed(*)) => { - let size = machine::llsize_of(cx, val_ty(llconst)); - llconst = C_struct([llptr, size], false); + ty::ty_evec(_, ty::vstore_fixed(len)) => { + llconst = C_struct([llptr, C_uint(cx, len)], false); } _ => {} } @@ -412,14 +406,8 @@ fn const_expr_unadjusted(cx: @mut CrateContext, (bv, C_uint(cx, u)), ty::vstore_slice(_) => { - let unit_ty = ty::sequence_element_type(cx.tcx, bt); - let llunitty = type_of::type_of(cx, unit_ty); - let unit_sz = machine::llsize_of(cx, llunitty); - let e1 = const_get_elt(cx, bv, [0]); - (const_deref_ptr(cx, e1), - llvm::LLVMConstUDiv(const_get_elt(cx, bv, [1]), - unit_sz)) + (const_deref_ptr(cx, e1), const_get_elt(cx, bv, [1])) }, _ => cx.sess.span_bug(base.span, "index-expr base must be fixed-size or slice") @@ -538,7 +526,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, } } ast::ExprVec(ref es, ast::MutImmutable) => { - let (v, _, _, inlineable) = const_vec(cx, e, *es); + let (v, _, inlineable) = const_vec(cx, e, *es); (v, inlineable) } ast::ExprVstore(sub, ast::ExprVstoreSlice) => { @@ -550,7 +538,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, } } ast::ExprVec(ref es, ast::MutImmutable) => { - let (cv, sz, llunitty, _) = const_vec(cx, e, *es); + let (cv, llunitty, _) = const_vec(cx, e, *es); let llty = val_ty(cv); let gv = do "const".with_c_str |name| { llvm::LLVMAddGlobal(cx.llmod, llty.to_ref(), name) @@ -559,7 +547,7 @@ fn const_expr_unadjusted(cx: @mut CrateContext, llvm::LLVMSetGlobalConstant(gv, True); SetLinkage(gv, PrivateLinkage); let p = const_ptrcast(cx, gv, llunitty); - (C_struct([p, sz], false), false) + (C_struct([p, C_uint(cx, es.len())], false), false) } _ => cx.sess.span_bug(e.span, "bad const-slice expr") } diff --git a/src/librustc/middle/trans/debuginfo.rs b/src/librustc/middle/trans/debuginfo.rs index a982a4767fd..5ebecca0562 100644 --- a/src/librustc/middle/trans/debuginfo.rs +++ b/src/librustc/middle/trans/debuginfo.rs @@ -1865,7 +1865,7 @@ fn vec_slice_metadata(cx: &mut CrateContext, offset: ComputedMemberOffset, }, MemberDescription { - name: @"size_in_bytes", + name: @"length", llvm_type: member_llvm_types[1], type_metadata: type_metadata(cx, ty::mk_uint(), span), offset: ComputedMemberOffset, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 12bb71d19ed..a58151fb265 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -274,8 +274,12 @@ pub fn trans_to_datum(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { ty::vstore_slice(ty::re_static)); let scratch = scratch_datum(bcx, slice_ty, "__adjust", false); + + let vt = tvec::vec_types(bcx, datum.ty); + let unscaled_len = UDiv(bcx, len, vt.llunit_size); + Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); - Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); + Store(bcx, unscaled_len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); DatumBlock {bcx: bcx, datum: scratch} } diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 7bcbedf50f7..0340779d0c5 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -237,8 +237,7 @@ pub fn trans_slice_vstore(bcx: @mut Block, Ignore => {} SaveIn(lldest) => { Store(bcx, llfixed, GEPi(bcx, lldest, [0u, abi::slice_elt_base])); - let lllen = Mul(bcx, llcount, vt.llunit_size); - Store(bcx, lllen, GEPi(bcx, lldest, [0u, abi::slice_elt_len])); + Store(bcx, llcount, GEPi(bcx, lldest, [0u, abi::slice_elt_len])); } } @@ -529,7 +528,8 @@ pub fn get_base_and_len(bcx: @mut Block, } ty::vstore_slice(_) => { let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base])); - let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); + let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); + let len = Mul(bcx, count, vt.llunit_size); (base, len) } ty::vstore_uniq | ty::vstore_box => { diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index b800c7b03af..1e76effd0d2 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -52,6 +52,8 @@ fn main () { ``` */ +use sys::size_of; +use unstable::raw::Slice; use cast; use container::Container; use iter::{Iterator, range}; @@ -133,10 +135,10 @@ pub trait Rng { /// println!("{:?}", v); /// } /// ``` - fn fill_bytes(&mut self, mut dest: &mut [u8]) { - // this relies on the lengths being transferred correctly when - // transmuting between vectors like this. - let as_u64: &mut &mut [u64] = unsafe { cast::transmute(&mut dest) }; + fn fill_bytes(&mut self, dest: &mut [u8]) { + let mut slice: Slice = unsafe { cast::transmute_copy(&dest) }; + slice.len /= size_of::(); + let as_u64: &mut [u64] = unsafe { cast::transmute(slice) }; for dest in as_u64.mut_iter() { *dest = self.next_u64(); } @@ -147,7 +149,9 @@ pub trait Rng { // space for a u32 if remaining >= 4 { - let as_u32: &mut &mut [u32] = unsafe { cast::transmute(&mut dest) }; + let mut slice: Slice = unsafe { cast::transmute_copy(&dest) }; + slice.len /= size_of::(); + let as_u32: &mut [u32] = unsafe { cast::transmute(slice) }; as_u32[as_u32.len() - 1] = self.next_u32(); remaining -= 4; } diff --git a/src/libstd/repr.rs b/src/libstd/repr.rs index ff2663fb1f7..49d5bb3918b 100644 --- a/src/libstd/repr.rs +++ b/src/libstd/repr.rs @@ -186,12 +186,7 @@ impl<'self> ReprVisitor<'self> { } } - pub fn write_vec_range(&mut self, - _mtbl: uint, - ptr: *(), - len: uint, - inner: *TyDesc) - -> bool { + pub fn write_vec_range(&mut self, ptr: *(), len: uint, inner: *TyDesc) -> bool { let mut p = ptr as *u8; let (sz, al) = unsafe { ((*inner).size, (*inner).align) }; self.writer.write(['[' as u8]); @@ -213,13 +208,8 @@ impl<'self> ReprVisitor<'self> { true } - pub fn write_unboxed_vec_repr(&mut self, - mtbl: uint, - v: &raw::Vec<()>, - inner: *TyDesc) - -> bool { - self.write_vec_range(mtbl, ptr::to_unsafe_ptr(&v.data), - v.fill, inner) + pub fn write_unboxed_vec_repr(&mut self, _: uint, v: &raw::Vec<()>, inner: *TyDesc) -> bool { + self.write_vec_range(ptr::to_unsafe_ptr(&v.data), v.fill, inner) } fn write_escaped_char(&mut self, ch: char, is_str: bool) { @@ -377,19 +367,32 @@ impl<'self> TyVisitor for ReprVisitor<'self> { } } + #[cfg(stage0)] fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool { do self.get::> |this, s| { this.writer.write(['&' as u8]); this.write_mut_qualifier(mtbl); - this.write_vec_range(mtbl, s.data, s.len, inner); + this.write_vec_range(s.data, s.len, inner); + } + } + + #[cfg(not(stage0))] + fn visit_evec_slice(&mut self, mtbl: uint, inner: *TyDesc) -> bool { + do self.get::> |this, s| { + this.writer.write(['&' as u8]); + this.write_mut_qualifier(mtbl); + let size = unsafe { + if (*inner).size == 0 { 1 } else { (*inner).size } + }; + this.write_vec_range(s.data, s.len * size, inner); } } fn visit_evec_fixed(&mut self, n: uint, sz: uint, _align: uint, - mtbl: uint, inner: *TyDesc) -> bool { + _: uint, inner: *TyDesc) -> bool { let assumed_size = if sz == 0 { n } else { sz }; do self.get::<()> |this, b| { - this.write_vec_range(mtbl, ptr::to_unsafe_ptr(b), assumed_size, inner); + this.write_vec_range(ptr::to_unsafe_ptr(b), assumed_size, inner); } } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 77e38b48067..93374d97db5 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -974,6 +974,7 @@ pub trait ImmutableVector<'self, T> { impl<'self,T> ImmutableVector<'self, T> for &'self [T] { #[inline] + #[cfg(stage0)] fn slice(&self, start: uint, end: uint) -> &'self [T] { assert!(start <= end); assert!(end <= self.len()); @@ -986,10 +987,27 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { } } } + + #[inline] + #[cfg(not(stage0))] + fn slice(&self, start: uint, end: uint) -> &'self [T] { + assert!(start <= end); + assert!(end <= self.len()); + do self.as_imm_buf |p, _len| { + unsafe { + cast::transmute(Slice { + data: ptr::offset(p, start as int), + len: (end - start) + }) + } + } + } + #[inline] fn slice_from(&self, start: uint) -> &'self [T] { self.slice(start, self.len()) } + #[inline] fn slice_to(&self, end: uint) -> &'self [T] { self.slice(0, end) @@ -1130,10 +1148,18 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] { } #[inline] + #[cfg(stage0)] fn as_imm_buf(&self, f: &fn(*T, uint) -> U) -> U { let s = self.repr(); f(s.data, s.len / sys::nonzero_size_of::()) } + + #[inline] + #[cfg(not(stage0))] + fn as_imm_buf(&self, f: &fn(*T, uint) -> U) -> U { + let s = self.repr(); + f(s.data, s.len) + } } /// Extension methods for vectors contain `Eq` elements. @@ -1899,6 +1925,7 @@ pub trait MutableVector<'self, T> { impl<'self,T> MutableVector<'self, T> for &'self mut [T] { #[inline] + #[cfg(stage0)] fn mut_slice(self, start: uint, end: uint) -> &'self mut [T] { assert!(start <= end); assert!(end <= self.len()); @@ -1912,6 +1939,21 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { } } + #[inline] + #[cfg(not(stage0))] + fn mut_slice(self, start: uint, end: uint) -> &'self mut [T] { + assert!(start <= end); + assert!(end <= self.len()); + do self.as_mut_buf |p, _len| { + unsafe { + cast::transmute(Slice { + data: ptr::mut_offset(p, start as int) as *T, + len: (end - start) + }) + } + } + } + #[inline] fn mut_slice_from(self, start: uint) -> &'self mut [T] { let len = self.len(); @@ -1991,11 +2033,18 @@ impl<'self,T> MutableVector<'self, T> for &'self mut [T] { } #[inline] + #[cfg(stage0)] fn as_mut_buf(self, f: &fn(*mut T, uint) -> U) -> U { let Slice{ data, len } = self.repr(); f(data as *mut T, len / sys::nonzero_size_of::()) } + #[inline] + #[cfg(not(stage0))] + fn as_mut_buf(self, f: &fn(*mut T, uint) -> U) -> U { + let Slice{ data, len } = self.repr(); + f(data as *mut T, len) + } } /// Trait for &[T] where T is Cloneable @@ -2083,6 +2132,7 @@ pub mod raw { * not bytes). */ #[inline] + #[cfg(stage0)] pub unsafe fn buf_as_slice(p: *T, len: uint, f: &fn(v: &[T]) -> U) -> U { @@ -2097,6 +2147,22 @@ pub mod raw { * not bytes). */ #[inline] + #[cfg(not(stage0))] + pub unsafe fn buf_as_slice(p: *T, + len: uint, + f: &fn(v: &[T]) -> U) -> U { + f(cast::transmute(Slice { + data: p, + len: len + })) + } + + /** + * Form a slice from a pointer and length (as a number of units, + * not bytes). + */ + #[inline] + #[cfg(stage0)] pub unsafe fn mut_buf_as_slice(p: *mut T, len: uint, f: &fn(v: &mut [T]) -> U) -> U { @@ -2106,6 +2172,21 @@ pub mod raw { })) } + /** + * Form a slice from a pointer and length (as a number of units, + * not bytes). + */ + #[inline] + #[cfg(not(stage0))] + pub unsafe fn mut_buf_as_slice(p: *mut T, + len: uint, + f: &fn(v: &mut [T]) -> U) -> U { + f(cast::transmute(Slice { + data: p as *T, + len: len + })) + } + /** * Unchecked vector indexing. */ diff --git a/src/test/debug-info/vec-slices.rs b/src/test/debug-info/vec-slices.rs index 9e5fb9236db..1b6dfaecfcd 100644 --- a/src/test/debug-info/vec-slices.rs +++ b/src/test/debug-info/vec-slices.rs @@ -13,33 +13,33 @@ // debugger:rbreak zzz // debugger:run // debugger:finish -// debugger:print empty.size_in_bytes +// debugger:print empty.length // check:$1 = 0 -// debugger:print singleton.size_in_bytes -// check:$2 = 8 +// debugger:print singleton.length +// check:$2 = 1 // debugger:print *((int64_t[1]*)(singleton.data_ptr)) // check:$3 = {1} -// debugger:print multiple.size_in_bytes -// check:$4 = 32 +// debugger:print multiple.length +// check:$4 = 4 // debugger:print *((int64_t[4]*)(multiple.data_ptr)) // check:$5 = {2, 3, 4, 5} -// debugger:print slice_of_slice.size_in_bytes -// check:$6 = 16 +// debugger:print slice_of_slice.length +// check:$6 = 2 // debugger:print *((int64_t[2]*)(slice_of_slice.data_ptr)) // check:$7 = {3, 4} -// debugger:print padded_tuple.size_in_bytes -// check:$8 = 16 +// debugger:print padded_tuple.length +// check:$8 = 2 // debugger:print padded_tuple.data_ptr[0] // check:$9 = {6, 7} // debugger:print padded_tuple.data_ptr[1] // check:$10 = {8, 9} -// debugger:print padded_struct.size_in_bytes -// check:$11 = 24 +// debugger:print padded_struct.length +// check:$11 = 2 // debugger:print padded_struct.data_ptr[0] // check:$12 = {x = 10, y = 11, z = 12} // debugger:print padded_struct.data_ptr[1] From 1e128d7931aea612073cdb49381b591bb812543a Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Tue, 15 Oct 2013 19:34:45 -0400 Subject: [PATCH 4/6] remove executable flag from source file --- src/test/run-pass/generic-static-methods.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/test/run-pass/generic-static-methods.rs diff --git a/src/test/run-pass/generic-static-methods.rs b/src/test/run-pass/generic-static-methods.rs old mode 100755 new mode 100644 From ef3ec1fe97f6dbb641349e41cb252d611def91a5 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 16 Oct 2013 11:59:35 -0400 Subject: [PATCH 5/6] rename `base_and_len` -> `base_and_byte_len` --- src/librustc/middle/trans/_match.rs | 7 ++----- src/librustc/middle/trans/base.rs | 2 +- src/librustc/middle/trans/controlflow.rs | 2 +- src/librustc/middle/trans/datum.rs | 20 ++++++++++---------- src/librustc/middle/trans/expr.rs | 6 +++--- src/librustc/middle/trans/tvec.rs | 4 ++-- 6 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index 15c1f8ea339..dc07852ad91 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1025,8 +1025,7 @@ fn extract_vec_elems(bcx: @mut Block, -> ExtractedBlock { let _icx = push_ctxt("match::extract_vec_elems"); let vec_datum = match_datum(bcx, val, pat_id); - let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, - pat_id, 0); + let (bcx, base, len) = vec_datum.get_vec_base_and_byte_len(bcx, pat_span, pat_id, 0); let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id)); let mut elems = do vec::from_fn(elem_count) |i| { @@ -1647,9 +1646,7 @@ fn compile_submatch_continue(mut bcx: @mut Block, vec_len(*) => { let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id)); let unboxed = load_if_immediate(bcx, val, vt.vec_ty); - let (_, len) = tvec::get_base_and_len( - bcx, unboxed, vt.vec_ty - ); + let (_, len) = tvec::get_base_and_byte_len(bcx, unboxed, vt.vec_ty); test_val = SDiv(bcx, len, vt.llunit_size); kind = compare_vec_len; } diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs index d9f16a4efe6..e28d6a6899c 100644 --- a/src/librustc/middle/trans/base.rs +++ b/src/librustc/middle/trans/base.rs @@ -745,7 +745,7 @@ pub fn iter_structural_ty(cx: @mut Block, av: ValueRef, t: ty::t, } ty::ty_estr(ty::vstore_fixed(_)) | ty::ty_evec(_, ty::vstore_fixed(_)) => { - let (base, len) = tvec::get_base_and_len(cx, av, t); + let (base, len) = tvec::get_base_and_byte_len(cx, av, t); cx = tvec::iter_vec_raw(cx, base, t, len, f); } ty::ty_tup(ref args) => { diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 105cb6e5606..3055c1e64fc 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -305,7 +305,7 @@ pub fn trans_fail_expr(bcx: @mut Block, bcx, expr::trans_to_datum(bcx, arg_expr)); if ty::type_is_str(arg_datum.ty) { - let (lldata, _) = arg_datum.get_vec_base_and_len_no_root(bcx); + let (lldata, _) = arg_datum.get_vec_base_and_byte_len_no_root(bcx); return trans_fail_value(bcx, sp_opt, lldata); } else if bcx.unreachable || ty::type_is_bot(arg_datum.ty) { return bcx; diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 3de3f99020e..34f1a6fa2a7 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -770,28 +770,28 @@ impl Datum { DatumBlock { bcx: bcx, datum: datum } } - pub fn get_vec_base_and_len(&self, - mut bcx: @mut Block, - span: Span, - expr_id: ast::NodeId, - derefs: uint) - -> (@mut Block, ValueRef, ValueRef) { + pub fn get_vec_base_and_byte_len(&self, + mut bcx: @mut Block, + span: Span, + expr_id: ast::NodeId, + derefs: uint) + -> (@mut Block, ValueRef, ValueRef) { //! Converts a vector into the slice pair. Performs rooting //! and write guards checks. // only imp't for @[] and @str, but harmless bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs); - let (base, len) = self.get_vec_base_and_len_no_root(bcx); + let (base, len) = self.get_vec_base_and_byte_len_no_root(bcx); (bcx, base, len) } - pub fn get_vec_base_and_len_no_root(&self, bcx: @mut Block) - -> (ValueRef, ValueRef) { + pub fn get_vec_base_and_byte_len_no_root(&self, bcx: @mut Block) + -> (ValueRef, ValueRef) { //! Converts a vector into the slice pair. Des not root //! nor perform write guard checks. let llval = self.to_appropriate_llval(bcx); - tvec::get_base_and_len(bcx, llval, self.ty) + tvec::get_base_and_byte_len(bcx, llval, self.ty) } pub fn root_and_write_guard(&self, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index a58151fb265..81ab3b5f2ec 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -265,7 +265,7 @@ pub fn trans_to_datum(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { let unit_ty = ty::sequence_element_type(tcx, datum.ty); let (bcx, base, len) = - datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1); + datum.get_vec_base_and_byte_len(bcx, expr.span, expr.id, autoderefs+1); // this type may have a different region/mutability than the // real one, but it will have the same runtime representation @@ -978,8 +978,8 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz"); let (bcx, base, len) = - base_datum.get_vec_base_and_len(bcx, index_expr.span, - index_expr.id, 0); + base_datum.get_vec_base_and_byte_len(bcx, index_expr.span, + index_expr.id, 0); debug2!("trans_index: base {}", bcx.val_to_str(base)); debug2!("trans_index: len {}", bcx.val_to_str(len)); diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 0340779d0c5..eab642ccb91 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -501,7 +501,7 @@ pub fn elements_required(bcx: @mut Block, content_expr: &ast::Expr) -> uint { } } -pub fn get_base_and_len(bcx: @mut Block, +pub fn get_base_and_byte_len(bcx: @mut Block, llval: ValueRef, vec_ty: ty::t) -> (ValueRef, ValueRef) { //! @@ -509,7 +509,7 @@ pub fn get_base_and_len(bcx: @mut Block, // Converts a vector into the slice pair. The vector should be stored in // `llval` which should be either immediate or by-ref as appropriate for // the vector type. If you have a datum, you would probably prefer to - // call `Datum::get_base_and_len()` which will handle any conversions for + // call `Datum::get_base_and_byte_len()` which will handle any conversions for // you. let ccx = bcx.ccx(); From bd7610f3e3861f5b2323ef03ed1c3ccbb7acef55 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 16 Oct 2013 12:04:51 -0400 Subject: [PATCH 6/6] introduce `base_and_len` fns for element length --- src/librustc/middle/trans/_match.rs | 20 ++++------- src/librustc/middle/trans/controlflow.rs | 2 +- src/librustc/middle/trans/datum.rs | 24 +++++++++++++ src/librustc/middle/trans/expr.rs | 16 +++------ src/librustc/middle/trans/tvec.rs | 43 +++++++++++++++++++++--- 5 files changed, 75 insertions(+), 30 deletions(-) diff --git a/src/librustc/middle/trans/_match.rs b/src/librustc/middle/trans/_match.rs index dc07852ad91..dbcfb4eebbf 100644 --- a/src/librustc/middle/trans/_match.rs +++ b/src/librustc/middle/trans/_match.rs @@ -1025,7 +1025,7 @@ fn extract_vec_elems(bcx: @mut Block, -> ExtractedBlock { let _icx = push_ctxt("match::extract_vec_elems"); let vec_datum = match_datum(bcx, val, pat_id); - let (bcx, base, len) = vec_datum.get_vec_base_and_byte_len(bcx, pat_span, pat_id, 0); + let (bcx, base, len) = vec_datum.get_vec_base_and_len(bcx, pat_span, pat_id, 0); let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id)); let mut elems = do vec::from_fn(elem_count) |i| { @@ -1042,13 +1042,9 @@ fn extract_vec_elems(bcx: @mut Block, }; if slice.is_some() { let n = slice.unwrap(); - let slice_offset = Mul(bcx, vt.llunit_size, - C_int(bcx.ccx(), n as int) - ); - let slice_begin = tvec::pointer_add(bcx, base, slice_offset); - let slice_len_offset = Mul(bcx, vt.llunit_size, - C_int(bcx.ccx(), (elem_count - 1u) as int) - ); + let slice_byte_offset = Mul(bcx, vt.llunit_size, C_uint(bcx.ccx(), n)); + let slice_begin = tvec::pointer_add_byte(bcx, base, slice_byte_offset); + let slice_len_offset = C_uint(bcx.ccx(), elem_count - 1u); let slice_len = Sub(bcx, len, slice_len_offset); let slice_ty = ty::mk_evec(bcx.tcx(), ty::mt {ty: vt.unit_ty, mutbl: ast::MutImmutable}, @@ -1058,9 +1054,7 @@ fn extract_vec_elems(bcx: @mut Block, Store(bcx, slice_begin, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]) ); - Store(bcx, UDiv(bcx, slice_len, vt.llunit_size), - GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]) - ); + Store(bcx, slice_len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); elems[n] = scratch.val; scratch.add_clean(bcx); } @@ -1646,8 +1640,8 @@ fn compile_submatch_continue(mut bcx: @mut Block, vec_len(*) => { let vt = tvec::vec_types(bcx, node_id_type(bcx, pat_id)); let unboxed = load_if_immediate(bcx, val, vt.vec_ty); - let (_, len) = tvec::get_base_and_byte_len(bcx, unboxed, vt.vec_ty); - test_val = SDiv(bcx, len, vt.llunit_size); + let (_, len) = tvec::get_base_and_len(bcx, unboxed, vt.vec_ty); + test_val = len; kind = compare_vec_len; } } diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs index 3055c1e64fc..105cb6e5606 100644 --- a/src/librustc/middle/trans/controlflow.rs +++ b/src/librustc/middle/trans/controlflow.rs @@ -305,7 +305,7 @@ pub fn trans_fail_expr(bcx: @mut Block, bcx, expr::trans_to_datum(bcx, arg_expr)); if ty::type_is_str(arg_datum.ty) { - let (lldata, _) = arg_datum.get_vec_base_and_byte_len_no_root(bcx); + let (lldata, _) = arg_datum.get_vec_base_and_len_no_root(bcx); return trans_fail_value(bcx, sp_opt, lldata); } else if bcx.unreachable || ty::type_is_bot(arg_datum.ty) { return bcx; diff --git a/src/librustc/middle/trans/datum.rs b/src/librustc/middle/trans/datum.rs index 34f1a6fa2a7..6411283b79d 100644 --- a/src/librustc/middle/trans/datum.rs +++ b/src/librustc/middle/trans/datum.rs @@ -794,6 +794,30 @@ impl Datum { tvec::get_base_and_byte_len(bcx, llval, self.ty) } + pub fn get_vec_base_and_len(&self, + mut bcx: @mut Block, + span: Span, + expr_id: ast::NodeId, + derefs: uint) + -> (@mut Block, ValueRef, ValueRef) { + //! Converts a vector into the slice pair. Performs rooting + //! and write guards checks. + + // only imp't for @[] and @str, but harmless + bcx = write_guard::root_and_write_guard(self, bcx, span, expr_id, derefs); + let (base, len) = self.get_vec_base_and_len_no_root(bcx); + (bcx, base, len) + } + + pub fn get_vec_base_and_len_no_root(&self, bcx: @mut Block) + -> (ValueRef, ValueRef) { + //! Converts a vector into the slice pair. Des not root + //! nor perform write guard checks. + + let llval = self.to_appropriate_llval(bcx); + tvec::get_base_and_len(bcx, llval, self.ty) + } + pub fn root_and_write_guard(&self, bcx: @mut Block, span: Span, diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 81ab3b5f2ec..48d3e3f7c58 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -265,7 +265,7 @@ pub fn trans_to_datum(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { let unit_ty = ty::sequence_element_type(tcx, datum.ty); let (bcx, base, len) = - datum.get_vec_base_and_byte_len(bcx, expr.span, expr.id, autoderefs+1); + datum.get_vec_base_and_len(bcx, expr.span, expr.id, autoderefs+1); // this type may have a different region/mutability than the // real one, but it will have the same runtime representation @@ -275,11 +275,8 @@ pub fn trans_to_datum(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { let scratch = scratch_datum(bcx, slice_ty, "__adjust", false); - let vt = tvec::vec_types(bcx, datum.ty); - let unscaled_len = UDiv(bcx, len, vt.llunit_size); - Store(bcx, base, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base])); - Store(bcx, unscaled_len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); + Store(bcx, len, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len])); DatumBlock {bcx: bcx, datum: scratch} } @@ -978,17 +975,14 @@ fn trans_lvalue_unadjusted(bcx: @mut Block, expr: &ast::Expr) -> DatumBlock { base::maybe_name_value(bcx.ccx(), vt.llunit_size, "unit_sz"); let (bcx, base, len) = - base_datum.get_vec_base_and_byte_len(bcx, index_expr.span, - index_expr.id, 0); + base_datum.get_vec_base_and_len(bcx, index_expr.span, index_expr.id, 0); debug2!("trans_index: base {}", bcx.val_to_str(base)); debug2!("trans_index: len {}", bcx.val_to_str(len)); - let unscaled_len = UDiv(bcx, len, vt.llunit_size); - let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, unscaled_len); + let bounds_check = ICmp(bcx, lib::llvm::IntUGE, ix_val, len); let bcx = do with_cond(bcx, bounds_check) |bcx| { - controlflow::trans_fail_bounds_check(bcx, index_expr.span, - ix_val, unscaled_len) + controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len) }; let elt = InBoundsGEP(bcx, base, [ix_val]); let elt = PointerCast(bcx, elt, vt.llunit_ty.ptr_to()); diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index eab642ccb91..bde98eff41c 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -77,8 +77,8 @@ pub fn get_dataptr(bcx: @mut Block, vptr: ValueRef) -> ValueRef { GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u]) } -pub fn pointer_add(bcx: @mut Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef { - let _icx = push_ctxt("tvec::pointer_add"); +pub fn pointer_add_byte(bcx: @mut Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef { + let _icx = push_ctxt("tvec::pointer_add_byte"); let old_ty = val_ty(ptr); let bptr = PointerCast(bcx, ptr, Type::i8p()); return PointerCast(bcx, InBoundsGEP(bcx, bptr, [bytes]), old_ty); @@ -501,8 +501,7 @@ pub fn elements_required(bcx: @mut Block, content_expr: &ast::Expr) -> uint { } } -pub fn get_base_and_byte_len(bcx: @mut Block, - llval: ValueRef, +pub fn get_base_and_byte_len(bcx: @mut Block, llval: ValueRef, vec_ty: ty::t) -> (ValueRef, ValueRef) { //! // @@ -539,6 +538,40 @@ pub fn get_base_and_byte_len(bcx: @mut Block, } } +pub fn get_base_and_len(bcx: @mut Block, llval: ValueRef, vec_ty: ty::t) -> (ValueRef, ValueRef) { + //! + // + // Converts a vector into the slice pair. The vector should be stored in + // `llval` which should be either immediate or by-ref as appropriate for + // the vector type. If you have a datum, you would probably prefer to + // call `Datum::get_base_and_len()` which will handle any conversions for + // you. + + let ccx = bcx.ccx(); + let vt = vec_types(bcx, vec_ty); + + let vstore = match ty::get(vt.vec_ty).sty { + ty::ty_estr(vst) | ty::ty_evec(_, vst) => vst, + _ => ty::vstore_uniq + }; + + match vstore { + ty::vstore_fixed(n) => { + let base = GEPi(bcx, llval, [0u, 0u]); + (base, C_uint(ccx, n)) + } + ty::vstore_slice(_) => { + let base = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_base])); + let count = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len])); + (base, count) + } + ty::vstore_uniq | ty::vstore_box => { + let body = get_bodyptr(bcx, llval, vec_ty); + (get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size)) + } + } +} + pub type iter_vec_block<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block; pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t, @@ -551,7 +584,7 @@ pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t, // FIXME (#3729): Optimize this when the size of the unit type is // statically known to not use pointer casts, which tend to confuse // LLVM. - let data_end_ptr = pointer_add(bcx, data_ptr, fill); + let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill); // Now perform the iteration. let header_bcx = base::sub_block(bcx, "iter_vec_loop_header");