Use the slice repr for ~[T]

This commit is contained in:
Nick Cameron 2014-04-25 15:14:52 +12:00
parent 5fb2dfaa20
commit 34d607f9c9
16 changed files with 247 additions and 264 deletions

View File

@ -92,6 +92,8 @@ use core::iter::{range_step, MultiplicativeIterator};
use MutableSeq;
use vec::Vec;
#[cfg(not(stage0))]
use raw::Slice;
pub use core::slice::{Chunks, Slice, ImmutableSlice, ImmutablePartialEqSlice};
pub use core::slice::{ImmutableOrdSlice, MutableSlice, Items, MutItems};
@ -282,6 +284,64 @@ pub trait CloneableVector<T> {
impl<'a, T: Clone> CloneableVector<T> for &'a [T] {
/// Returns a copy of `v`.
#[cfg(not(stage0))]
fn to_owned(&self) -> ~[T] {
use num::CheckedMul;
use option::Expect;
let len = self.len();
if len == 0 {
unsafe {
let slice: Slice<T> = Slice{data: 0 as *T, len: 0};
mem::transmute(slice)
}
} else {
let unit_size = mem::size_of::<T>();
let data_size = if unit_size == 0 {
len
} else {
let data_size = len.checked_mul(&unit_size);
data_size.expect("overflow in from_iter()")
};
unsafe {
// this should pass the real required alignment
let ret = allocate(data_size, 8) as *mut T;
if unit_size > 0 {
// Be careful with the following loop. We want it to be optimized
// to a memcpy (or something similarly fast) when T is Copy. LLVM
// is easily confused, so any extra operations during the loop can
// prevent this optimization.
let mut i = 0;
let p = &mut (*ret) as *mut _ as *mut T;
try_finally(
&mut i, (),
|i, ()| while *i < len {
mem::move_val_init(
&mut(*p.offset(*i as int)),
self.unsafe_ref(*i).clone());
*i += 1;
},
|i| if *i < len {
// we must be failing, clean up after ourselves
for j in range(0, *i as int) {
ptr::read(&*p.offset(j));
}
// FIXME: #13994 (should pass align and size here)
deallocate(ret as *mut u8, 0, 8);
});
}
let slice: Slice<T> = Slice{data: ret as *T, len: len};
mem::transmute(slice)
}
}
}
/// Returns a copy of `v`.
// NOTE: remove after snapshot
#[cfg(stage0)]
#[inline]
fn to_vec(&self) -> Vec<T> { Vec::from_slice(*self) }

View File

@ -174,7 +174,7 @@ pub unsafe fn overwrite<T>(dst: *mut T, src: T) {
/// Deprecated, use `overwrite` instead
#[inline]
#[deprecated = "use ptr::write"]
#[deprecated = "this function has been renamed to overwrite()"]
pub unsafe fn move_val_init<T>(dst: &mut T, src: T) {
ptr::write(dst, src)
}

View File

@ -305,8 +305,7 @@ impl Case {
// Box<T> could either be a thin or fat pointer depending on T
ty::ty_uniq(t) => match ty::get(t).sty {
// Box<[T]>/Box<str> might be FatPointer in a post DST world
ty::ty_vec(_, None) | ty::ty_str => continue,
ty::ty_vec(_, None) | return Some(FatPointer(i, slice_elt_base)),
// Box<Trait> is a pair of pointers: the actual object and a vtable
ty::ty_trait(..) => return Some(FatPointer(i, trt_field_box)),
@ -326,7 +325,6 @@ impl Case {
// Anything else is not a pointer
_ => continue
}
}

View File

@ -195,6 +195,16 @@ pub fn decl_fn(ccx: &CrateContext, name: &str, cc: llvm::CallConv,
llvm::NoReturnAttribute as uint64_t)
}
}
// `~` pointer return values never alias because ownership is transferred
ty::ty_uniq(t)
=> match ty::get(t).sty {
ty::ty_vec(_, None) | ty::ty_str | ty::ty_trait(..) => {}
_ => unsafe {
llvm::LLVMAddReturnAttribute(llfn,
lib::llvm::NoAliasAttribute as c_uint,
lib::llvm::NoReturnAttribute as uint64_t);
}
},
_ => {}
}
@ -364,20 +374,19 @@ fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId {
// a given type, but with a potentially dynamic size.
pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>,
ptr_ty: ty::t,
llty_ptr: Type,
info_ty: ty::t,
size: ValueRef,
align: ValueRef)
-> Result<'a> {
let _icx = push_ctxt("malloc_raw_exchange");
let ccx = bcx.ccx();
// Allocate space:
let r = callee::trans_lang_call(bcx,
require_alloc_fn(bcx, ptr_ty, ExchangeMallocFnLangItem),
require_alloc_fn(bcx, info_ty, ExchangeMallocFnLangItem),
[size, align],
None);
let llty_ptr = type_of::type_of(ccx, ptr_ty);
Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
}
@ -731,8 +740,8 @@ pub fn iter_structural_ty<'r,
}
}
ty::ty_vec(_, Some(n)) => {
let (base, len) = tvec::get_fixed_base_and_len(cx, av, n);
let unit_ty = ty::sequence_element_type(cx.tcx(), t);
let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n);
cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f);
}
ty::ty_tup(ref args) => {

View File

@ -2718,81 +2718,6 @@ fn fixed_vec_metadata(cx: &CrateContext,
return MetadataCreationResult::new(metadata, false);
}
fn heap_vec_metadata(cx: &CrateContext,
vec_pointer_type: ty::t,
element_type: ty::t,
unique_type_id: UniqueTypeId,
span: Span)
-> MetadataCreationResult {
let element_type_metadata = type_metadata(cx, element_type, span);
let element_llvm_type = type_of::type_of(cx, element_type);
let (element_size, element_align) = size_and_align_of(cx, element_llvm_type);
return_if_metadata_created_in_meantime!(cx, unique_type_id);
let vecbox_llvm_type = Type::vec(cx, &element_llvm_type);
let vec_pointer_type_name = compute_debuginfo_type_name(cx,
vec_pointer_type,
true);
let vec_pointer_type_name = vec_pointer_type_name.as_slice();
let member_llvm_types = vecbox_llvm_type.field_types();
let int_type_metadata = type_metadata(cx, ty::mk_int(), span);
let array_type_metadata = unsafe {
llvm::LLVMDIBuilderCreateArrayType(
DIB(cx),
bytes_to_bits(element_size),
bytes_to_bits(element_align),
element_type_metadata,
create_DIArray(DIB(cx), [llvm::LLVMDIBuilderGetOrCreateSubrange(DIB(cx), 0, 0)]))
};
let member_descriptions = [
MemberDescription {
name: "fill".to_string(),
llvm_type: *member_llvm_types.get(0),
type_metadata: int_type_metadata,
offset: ComputedMemberOffset,
},
MemberDescription {
name: "alloc".to_string(),
llvm_type: *member_llvm_types.get(1),
type_metadata: int_type_metadata,
offset: ComputedMemberOffset,
},
MemberDescription {
name: "elements".to_string(),
llvm_type: *member_llvm_types.get(2),
type_metadata: array_type_metadata,
offset: ComputedMemberOffset,
}
];
assert!(member_descriptions.len() == member_llvm_types.len());
let loc = span_start(cx, span);
let file_metadata = file_metadata(cx, loc.file.name.as_slice());
let vec_box_unique_id = debug_context(cx).type_map
.borrow_mut()
.get_unique_type_id_of_heap_vec_box(cx,
element_type);
let vecbox_metadata = composite_type_metadata(cx,
vecbox_llvm_type,
vec_pointer_type_name,
vec_box_unique_id,
member_descriptions,
UNKNOWN_SCOPE_METADATA,
file_metadata,
span);
MetadataCreationResult::new(pointer_type_metadata(cx,
vec_pointer_type,
vecbox_metadata), false)
}
fn vec_slice_metadata(cx: &CrateContext,
vec_type: ty::t,
element_type: ty::t,
@ -2995,11 +2920,13 @@ fn type_metadata(cx: &CrateContext,
ty::ty_uniq(pointee_type) => {
match ty::get(pointee_type).sty {
ty::ty_vec(ref mt, None) => {
heap_vec_metadata(cx, pointee_type, mt.ty, unique_type_id, usage_site_span)
let vec_metadata = vec_slice_metadata(cx, t, mt.ty, usage_site_span);
pointer_type_metadata(cx, t, vec_metadata)
}
ty::ty_str => {
let i8_t = ty::mk_i8();
heap_vec_metadata(cx, pointee_type, i8_t, unique_type_id, usage_site_span)
let vec_metadata = vec_slice_metadata(cx, t, i8_t, usage_site_span);
pointer_type_metadata(cx, t, vec_metadata)
}
ty::ty_trait(..) => {
MetadataCreationResult::new(

View File

@ -395,8 +395,8 @@ fn trans_datum_unadjusted<'a>(bcx: &'a Block<'a>,
ast::ExprField(ref base, ident, _) => {
trans_rec_field(bcx, &**base, ident.node)
}
ast::ExprIndex(ref base, ref idx) => {
trans_index(bcx, expr, &**base, &**idx, MethodCall::expr(expr.id))
ast::ExprIndex(base, idx) => {
trans_index(bcx, expr.span, &**base, &**idx, MethodCall::expr(expr.id))
}
ast::ExprVstore(ref contents, ast::ExprVstoreUniq) => {
fcx.push_ast_cleanup_scope(contents.id);
@ -465,7 +465,7 @@ fn trans_rec_field<'a>(bcx: &'a Block<'a>,
}
fn trans_index<'a>(bcx: &'a Block<'a>,
index_expr: &ast::Expr,
sp: codemap::Span,
base: &ast::Expr,
idx: &ast::Expr,
method_call: MethodCall)
@ -1256,10 +1256,8 @@ fn trans_uniq_expr<'a>(bcx: &'a Block<'a>,
let llty = type_of::type_of(bcx.ccx(), contents_ty);
let size = llsize_of(bcx.ccx(), llty);
let align = C_uint(bcx.ccx(), llalign_of_min(bcx.ccx(), llty) as uint);
// We need to a make a pointer type because box_ty is ty_bot
// if content_ty is, e.g. box fail!().
let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size, align);
let llty_ptr = llty.ptr_to();
let Result { bcx, val } = malloc_raw_dyn(bcx, llty_ptr, box_ty, size, align);
// Unique boxes do not allocate for zero-size types. The standard library
// may assume that `free` is never called on the pointer returned for
// `Box<ZeroSizeType>`.

View File

@ -51,7 +51,7 @@ pub fn trans_free<'a>(cx: &'a Block<'a>, v: ValueRef) -> &'a Block<'a> {
Some(expr::Ignore)).bcx
}
fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64,
pub fn trans_exchange_free<'a>(cx: &'a Block<'a>, v: ValueRef, size: u64,
align: u64) -> &'a Block<'a> {
let _icx = push_ctxt("trans_exchange_free");
let ccx = cx.ccx();
@ -120,8 +120,8 @@ pub fn drop_ty<'a>(bcx: &'a Block<'a>, v: ValueRef, t: ty::t)
-> &'a Block<'a> {
// NB: v is an *alias* of type t here, not a direct value.
let _icx = push_ctxt("drop_ty");
let ccx = bcx.ccx();
if ty::type_needs_drop(bcx.tcx(), t) {
let ccx = bcx.ccx();
let glue = get_drop_glue(ccx, t);
let glue_type = get_drop_glue_type(ccx, t);
let ptr = if glue_type != t {
@ -277,23 +277,11 @@ fn make_drop_glue<'a>(bcx: &'a Block<'a>, v0: ValueRef, t: ty::t) -> &'a Block<'
ty::ty_uniq(content_ty) => {
match ty::get(content_ty).sty {
ty::ty_vec(mt, None) => {
let llbox = Load(bcx, v0);
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, mt.ty);
// FIXME: #13994: the old `Box<[T]>` will not support sized deallocation
trans_exchange_free(bcx, llbox, 0, 8)
})
tvec::make_drop_glue_unboxed(bcx, v0, mt.ty)
}
ty::ty_str => {
let llbox = Load(bcx, v0);
let not_null = IsNotNull(bcx, llbox);
with_cond(bcx, not_null, |bcx| {
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, unit_ty);
// FIXME: #13994: the old `Box<str>` will not support sized deallocation
trans_exchange_free(bcx, llbox, 0, 8)
})
let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
tvec::make_drop_glue_unboxed(bcx, v0, unit_ty)
}
ty::ty_trait(..) => {
let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);

View File

@ -164,6 +164,10 @@ impl<'a, 'b> Reflector<'a, 'b> {
});
self.visit("box", extra.as_slice())
}
ty::ty_ptr(ref mt) => {
let extra = self.c_mt(mt);
self.visit("ptr", extra.as_slice())
}
ty::ty_uniq(typ) => {
match ty::get(typ).sty {
ty::ty_vec(ref mt, None) => {
@ -188,17 +192,12 @@ impl<'a, 'b> Reflector<'a, 'b> {
}
}
}
ty::ty_ptr(ref mt) => {
let extra = self.c_mt(mt);
self.visit("ptr", extra.as_slice())
}
ty::ty_rptr(_, ref mt) => {
match ty::get(mt.ty).sty {
ty::ty_vec(ref mt, None) => {
let (name, extra) = ("slice".to_string(), Vec::new());
let extra = Vec::new();
let extra = extra.append(self.c_mt(mt).as_slice());
self.visit(format!("evec_{}", name).as_slice(),
extra.as_slice())
self.visit("evec_slice", extra.as_slice())
}
ty::ty_str => self.visit("estr_slice", &[]),
ty::ty_trait(..) => {

View File

@ -17,7 +17,6 @@ use middle::lang_items::StrDupUniqFnLangItem;
use middle::trans::base::*;
use middle::trans::base;
use middle::trans::build::*;
use middle::trans::callee;
use middle::trans::cleanup;
use middle::trans::cleanup::CleanupMethods;
use middle::trans::common::*;
@ -25,7 +24,7 @@ use middle::trans::datum::*;
use middle::trans::expr::{Dest, Ignore, SaveIn};
use middle::trans::expr;
use middle::trans::glue;
use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc};
use middle::trans::machine::{nonzero_llsize_of, llsize_of_alloc};
use middle::trans::type_::Type;
use middle::trans::type_of;
use middle::ty;
@ -34,14 +33,14 @@ use util::ppaux::ty_to_string;
use syntax::ast;
use syntax::parse::token::InternedString;
pub fn get_fill(bcx: &Block, vptr: ValueRef) -> ValueRef {
let _icx = push_ctxt("tvec::get_fill");
Load(bcx, GEPi(bcx, vptr, [0u, abi::vec_elt_fill]))
fn get_len(bcx: &Block, vptr: ValueRef) -> ValueRef {
let _icx = push_ctxt("tvec::get_lenl");
Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_len]))
}
pub fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef {
fn get_dataptr(bcx: &Block, vptr: ValueRef) -> ValueRef {
let _icx = push_ctxt("tvec::get_dataptr");
GEPi(bcx, vptr, [0u, abi::vec_elt_elems, 0u])
Load(bcx, GEPi(bcx, vptr, [0u, abi::slice_elt_base]))
}
pub fn pointer_add_byte(bcx: &Block, ptr: ValueRef, bytes: ValueRef) -> ValueRef {
@ -56,13 +55,21 @@ pub fn make_drop_glue_unboxed<'a>(
vptr: ValueRef,
unit_ty: ty::t)
-> &'a Block<'a> {
let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
let tcx = bcx.tcx();
if ty::type_needs_drop(tcx, unit_ty) {
let fill = get_fill(bcx, vptr);
let not_null = IsNotNull(bcx, vptr);
with_cond(bcx, not_null, |bcx| {
let tcx = bcx.tcx();
let _icx = push_ctxt("tvec::make_drop_glue_unboxed");
let len = get_len(bcx, vptr);
let dataptr = get_dataptr(bcx, vptr);
iter_vec_raw(bcx, dataptr, unit_ty, fill, glue::drop_ty)
} else { bcx }
let bcx = if ty::type_needs_drop(tcx, unit_ty) {
iter_vec_raw(bcx, dataptr, unit_ty, len, glue::drop_ty)
} else {
bcx
};
glue::trans_exchange_free(bcx, dataptr, 0, 8)
})
}
pub struct VecTypes {
@ -112,12 +119,11 @@ pub fn trans_fixed_vstore<'a>(
};
}
pub fn trans_slice_vstore<'a>(
bcx: &'a Block<'a>,
vstore_expr: &ast::Expr,
content_expr: &ast::Expr,
dest: expr::Dest)
-> &'a Block<'a> {
pub fn trans_slice_vstore<'a>(bcx: &'a Block<'a>,
vstore_expr: &ast::Expr,
content_expr: &ast::Expr,
dest: expr::Dest)
-> &'a Block<'a> {
/*!
* &[...] allocates memory on the stack and writes the values into it,
* returning a slice (pair of ptr, len). &"..." is similar except that
@ -150,17 +156,16 @@ pub fn trans_slice_vstore<'a>(
// Handle the &[...] case:
let vt = vec_types_from_expr(bcx, vstore_expr);
let count = elements_required(bcx, content_expr);
debug!("vt={}, count={:?}", vt.to_string(ccx), count);
debug!(" vt={}, count={:?}", vt.to_str(ccx), count);
let llcount = C_uint(ccx, count);
let llfixed;
if count == 0 {
let llfixed = if count == 0 {
// Just create a zero-sized alloca to preserve
// the non-null invariant of the inner slice ptr
llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
base::arrayalloca(bcx, vt.llunit_ty, llcount)
} else {
// Make a fixed-length backing array and allocate it on the stack.
llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
let llfixed = base::arrayalloca(bcx, vt.llunit_ty, llcount);
// Arrange for the backing array to be cleaned up.
let fixed_ty = ty::mk_vec(bcx.tcx(),
@ -176,7 +181,9 @@ pub fn trans_slice_vstore<'a>(
// Generate the content into the backing array.
bcx = write_content(bcx, &vt, vstore_expr,
content_expr, SaveIn(llfixed));
}
llfixed
};
// Finally, create the slice pair itself.
match dest {
@ -198,7 +205,7 @@ pub fn trans_lit_str<'a>(
-> &'a Block<'a> {
/*!
* Literal strings translate to slices into static memory. This is
* different from trans_slice_vstore() above because it does need to copy
* different from trans_slice_vstore() above because it doesn't need to copy
* the content anywhere.
*/
@ -214,17 +221,14 @@ pub fn trans_lit_str<'a>(
let llbytes = C_uint(bcx.ccx(), bytes);
let llcstr = C_cstr(bcx.ccx(), str_lit, false);
let llcstr = llvm::LLVMConstPointerCast(llcstr, Type::i8p(bcx.ccx()).to_ref());
Store(bcx, llcstr,
GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
Store(bcx, llbytes,
GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
Store(bcx, llcstr, GEPi(bcx, lldest, [0u, abi::slice_elt_base]));
Store(bcx, llbytes, GEPi(bcx, lldest, [0u, abi::slice_elt_len]));
bcx
}
}
}
}
pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
vstore_expr: &ast::Expr,
content_expr: &ast::Expr)
@ -238,74 +242,47 @@ pub fn trans_uniq_vstore<'a>(bcx: &'a Block<'a>,
let fcx = bcx.fcx;
let ccx = fcx.ccx;
// Handle "".to_string().
match content_expr.node {
ast::ExprLit(lit) => {
match lit.node {
ast::LitStr(ref s, _) => {
let llptrval = C_cstr(ccx, (*s).clone(), false);
let llptrval = PointerCast(bcx, llptrval, Type::i8p(ccx));
let llsizeval = C_uint(ccx, s.get().len());
let typ = ty::mk_uniq(bcx.tcx(), ty::mk_str(bcx.tcx()));
let lldestval = rvalue_scratch_datum(bcx,
typ,
"");
let alloc_fn = langcall(bcx,
Some(lit.span),
"",
StrDupUniqFnLangItem);
let bcx = callee::trans_lang_call(
bcx,
alloc_fn,
[ llptrval, llsizeval ],
Some(expr::SaveIn(lldestval.val))).bcx;
return DatumBlock::new(bcx, lldestval).to_expr_datumblock();
}
_ => {}
}
}
_ => {}
}
let vec_ty = node_id_type(bcx, vstore_expr.id);
let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
let vt = vec_types_from_expr(bcx, vstore_expr);
let count = elements_required(bcx, content_expr);
debug!(" vt={}, count={:?}", vt.to_str(ccx), count);
let llcount = C_uint(ccx, count);
let vec_ty = node_id_type(bcx, vstore_expr.id);
let llunitty = type_of::type_of(ccx, vt.unit_ty);
let unit_sz = nonzero_llsize_of(ccx, llunitty);
let unit_sz = nonzero_llsize_of(ccx, type_of::type_of(ccx, vt.unit_ty));
let fill = Mul(bcx, C_uint(ccx, count), unit_sz);
let alloc = if count < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) }
else { fill };
let vecsize = Add(bcx, alloc, llsize_of(ccx, ccx.opaque_vec_type));
// ~[T] is not going to be changed to support alignment, since it's obsolete.
let alloc = if count < 4u {
Mul(bcx, C_int(ccx, 4), unit_sz)
} else {
fill
};
let llty_ptr = type_of::type_of(ccx, vt.unit_ty).ptr_to();
let align = C_uint(ccx, 8);
let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize, align);
Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill]));
Store(bcx, alloc, GEPi(bcx, val, [0u, abi::vec_elt_alloc]));
let Result { bcx: bcx, val: dataptr } = malloc_raw_dyn(bcx,
llty_ptr,
vec_ty,
alloc,
align);
// Create a temporary scope lest execution should fail while
// constructing the vector.
let temp_scope = fcx.push_custom_cleanup_scope();
// FIXME: #13994: the old `Box<[T]> will not support sized deallocation, this is a placeholder
let content_ty = vt.unit_ty;
// FIXME: #13994: the old `Box<[T]> will not support sized deallocation,
// this is a placeholder
fcx.schedule_free_value(cleanup::CustomScope(temp_scope),
val, cleanup::HeapExchange, content_ty);
dataptr, cleanup::HeapExchange, vt.unit_ty);
let dataptr = get_dataptr(bcx, val);
debug!(" alloc_uniq_vec() returned dataptr={}, len={}",
bcx.val_to_str(dataptr), count);
debug!("alloc_uniq_vec() returned val={}, dataptr={}",
bcx.val_to_string(val), bcx.val_to_string(dataptr));
let bcx = write_content(bcx, &vt, vstore_expr,
content_expr, SaveIn(dataptr));
let bcx = write_content(bcx, &vt, vstore_expr,
content_expr, SaveIn(dataptr));
fcx.pop_custom_cleanup_scope(temp_scope);
immediate_rvalue_bcx(bcx, val, vec_ty).to_expr_datumblock()
let scratch = rvalue_scratch_datum(bcx, vec_ty, "");
Store(bcx, dataptr, GEPi(bcx, scratch.val, [0u, abi::slice_elt_base]));
Store(bcx, llcount, GEPi(bcx, scratch.val, [0u, abi::slice_elt_len]));
DatumBlock(bcx, scratch.to_expr_datum())
}
pub fn write_content<'a>(
@ -451,21 +428,19 @@ pub fn elements_required(bcx: &Block, content_expr: &ast::Expr) -> uint {
}
}
pub fn get_fixed_base_and_byte_len(bcx: &Block,
llval: ValueRef,
unit_ty: ty::t,
vec_length: uint)
-> (ValueRef, ValueRef) {
pub fn get_fixed_base_and_len(bcx: &Block,
llval: ValueRef,
vec_length: uint)
-> (ValueRef, ValueRef) {
/*!
* Converts a fixed-length vector into the slice pair.
* The vector should be stored in `llval` which should be by ref.
*/
let ccx = bcx.ccx();
let vt = vec_types(bcx, unit_ty);
let base = GEPi(bcx, llval, [0u, 0u]);
let len = Mul(bcx, C_uint(ccx, vec_length), vt.llunit_size);
let base = GEPi(bcx, llval, [0u, abi::slice_elt_base]);
let len = C_uint(ccx, vec_length);
(base, len)
}
@ -488,23 +463,13 @@ pub fn get_base_and_len(bcx: &Block,
let base = GEPi(bcx, llval, [0u, 0u]);
(base, C_uint(ccx, n))
}
ty::ty_rptr(_, mt) => match ty::get(mt.ty).sty {
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => match ty::get(ty).sty {
ty::ty_vec(_, None) | ty::ty_str => {
assert!(!type_is_immediate(bcx.ccx(), vec_ty));
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)
let len = Load(bcx, GEPi(bcx, llval, [0u, abi::slice_elt_len]));
(base, len)
}
_ => ccx.sess().bug("unexpected type (ty_rptr) in get_base_and_len"),
},
ty::ty_uniq(t) => match ty::get(t).sty {
ty::ty_vec(_, None) | ty::ty_str => {
assert!(type_is_immediate(bcx.ccx(), vec_ty));
let vt = vec_types(bcx, ty::sequence_element_type(bcx.tcx(), vec_ty));
let body = Load(bcx, llval);
(get_dataptr(bcx, body), UDiv(bcx, get_fill(bcx, body), vt.llunit_size))
}
_ => ccx.sess().bug("unexpected type (ty_uniq) in get_base_and_len"),
_ => ccx.sess().bug("unexpected type in get_base_and_len"),
},
_ => ccx.sess().bug("unexpected type in get_base_and_len"),
}
@ -576,13 +541,15 @@ pub fn iter_vec_raw<'r,
bcx: &'b Block<'b>,
data_ptr: ValueRef,
unit_ty: ty::t,
fill: ValueRef,
len: ValueRef,
f: iter_vec_block<'r,'b>)
-> &'b Block<'b> {
let _icx = push_ctxt("tvec::iter_vec_raw");
let fcx = bcx.fcx;
let vt = vec_types(bcx, unit_ty);
let fill = Mul(bcx, len, vt.llunit_size);
if vt.llunit_alloc_size == 0 {
// Special-case vectors with elements of size 0 so they don't go out of bounds (#9890)
iter_vec_loop(bcx, data_ptr, &vt, fill, f)

View File

@ -215,7 +215,7 @@ impl Type {
pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
Type::struct_(ccx,
[Type::int(ccx), Type::int(ccx), Type::array(ty, 0)],
[Type::array(ty, 0), Type::int(ccx)],
false)
}

View File

@ -169,14 +169,8 @@ pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
ty::ty_box(..) |
ty::ty_ptr(..) => Type::i8p(cx),
ty::ty_uniq(ty) => {
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
match ty::get(ty).sty {
ty::ty_trait(..) => Type::opaque_trait(cx),
_ => Type::i8p(cx),
}
}
ty::ty_rptr(_, mt) => {
match ty::get(mt.ty).sty {
ty::ty_vec(_, None) | ty::ty_str => {
Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false)
}
@ -283,17 +277,10 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
ty::ty_box(typ) => {
Type::at_box(cx, type_of(cx, typ)).ptr_to()
}
ty::ty_uniq(typ) => {
match ty::get(typ).sty {
ty::ty_vec(mt, None) => Type::vec(cx, &type_of(cx, mt.ty)).ptr_to(),
ty::ty_str => Type::vec(cx, &Type::i8(cx)).ptr_to(),
ty::ty_trait(..) => Type::opaque_trait(cx),
_ => type_of(cx, typ).ptr_to(),
}
}
ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(),
ty::ty_rptr(_, ref mt) => {
match ty::get(mt.ty).sty {
ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) => {
match ty::get(ty).sty {
ty::ty_vec(mt, None) => {
let p_ty = type_of(cx, mt.ty).ptr_to();
let u_ty = Type::uint_from_ty(cx, ast::TyU);
@ -304,7 +291,7 @@ pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
cx.tn.find_type("str_slice").unwrap()
}
ty::ty_trait(..) => Type::opaque_trait(cx),
_ => type_of(cx, mt.ty).ptr_to(),
_ => type_of(cx, ty).ptr_to(),
}
}

View File

@ -1816,8 +1816,7 @@ pub fn type_is_boxed(ty: t) -> bool {
pub fn type_is_region_ptr(ty: t) -> bool {
match get(ty).sty {
ty_rptr(_, mt) => match get(mt.ty).sty {
// FIXME(nrc, DST) slices weren't regarded as rptrs, so we preserve this
// odd behaviour for now. (But ~[] were unique. I have no idea why).
// DST pointers should not be treated like regular pointers.
ty_vec(_, None) | ty_str | ty_trait(..) => false,
_ => true
},

View File

@ -23,11 +23,5 @@ pub static fn_field_box: uint = 1u;
pub static trt_field_vtable: uint = 0u;
pub static trt_field_box: uint = 1u;
pub static vec_elt_fill: uint = 0u;
pub static vec_elt_alloc: uint = 1u;
pub static vec_elt_elems: uint = 2u;
pub static slice_elt_base: uint = 0u;
pub static slice_elt_len: uint = 1u;

View File

@ -18,6 +18,7 @@ use std::path;
use std::rc::Rc;
use std::gc::{Gc, GC};
use std::cell::{Cell, RefCell};
use std::strbuf::StrBuf;
pub trait Encoder<E> {
// Primitive types:

View File

@ -268,7 +268,19 @@ pub struct Tm {
pub tm_nsec: i32,
}
impl Tm {
pub fn tm_zone<'a>(&'a self) -> &'a str {
self.tm_zone.as_slice()
}
}
pub fn empty_tm() -> Tm {
// 64 is the max size of the timezone buffer allocated on windows
// in rust_localtime. In glibc the max timezone size is supposedly 3.
let mut zone = StrBuf::new();
for _ in range(0, 64) {
zone.push_char(' ')
}
Tm {
tm_sec: 0_i32,
tm_min: 0_i32,
@ -280,6 +292,7 @@ pub fn empty_tm() -> Tm {
tm_yday: 0_i32,
tm_isdst: 0_i32,
tm_gmtoff: 0_i32,
tm_zone: zone,
tm_nsec: 0_i32,
}
}
@ -760,6 +773,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> {
'Z' => {
if match_str(s, pos, "UTC") || match_str(s, pos, "GMT") {
tm.tm_gmtoff = 0_i32;
tm.tm_zone = "UTC".into_strbuf();
Ok(pos + 3u)
} else {
// It's odd, but to maintain compatibility with c's
@ -784,6 +798,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> {
let (v, pos) = item;
if v == 0_i32 {
tm.tm_gmtoff = 0_i32;
tm.tm_zone = "UTC".into_strbuf();
}
Ok(pos)
@ -813,6 +828,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> {
tm_yday: 0_i32,
tm_isdst: 0_i32,
tm_gmtoff: 0_i32,
tm_zone: StrBuf::new(),
tm_nsec: 0_i32,
};
let mut pos = 0u;
@ -859,6 +875,7 @@ pub fn strptime(s: &str, format: &str) -> Result<Tm, String> {
tm_yday: tm.tm_yday,
tm_isdst: tm.tm_isdst,
tm_gmtoff: tm.tm_gmtoff,
tm_zone: tm.tm_zone.clone(),
tm_nsec: tm.tm_nsec,
})
} else { result }
@ -1060,7 +1077,7 @@ pub fn strftime(format: &str, tm: &Tm) -> String {
'w' => (tm.tm_wday as int).to_string(),
'Y' => (tm.tm_year as int + 1900).to_string(),
'y' => format!("{:02d}", (tm.tm_year as int + 1900) % 100),
'Z' => "".to_string(), // FIXME(pcwalton): Implement this.
'Z' => tm.tm_zone.as_slice().to_owned(),
'z' => {
let sign = if tm.tm_gmtoff > 0_i32 { '+' } else { '-' };
let mut m = num::abs(tm.tm_gmtoff) / 60_i32;
@ -1186,6 +1203,7 @@ mod tests {
assert_eq!(utc.tm_yday, 43_i32);
assert_eq!(utc.tm_isdst, 0_i32);
assert_eq!(utc.tm_gmtoff, 0_i32);
assert_eq!(utc.tm_zone(), "UTC");
assert_eq!(utc.tm_nsec, 54321_i32);
}
@ -1207,6 +1225,12 @@ mod tests {
assert_eq!(local.tm_yday, 43_i32);
assert_eq!(local.tm_isdst, 0_i32);
assert_eq!(local.tm_gmtoff, -28800_i32);
// FIXME (#2350): We should probably standardize on the timezone
// abbreviation.
let zone = local.tm_zone();
assert!(zone == "PST" || zone == "Pacific Standard Time");
assert_eq!(local.tm_nsec, 54321_i32);
}
@ -1249,6 +1273,7 @@ mod tests {
assert!(tm.tm_wday == 0_i32);
assert!(tm.tm_isdst == 0_i32);
assert!(tm.tm_gmtoff == 0_i32);
assert!(tm.tm_zone() == "");
assert!(tm.tm_nsec == 0_i32);
}
Err(_) => ()
@ -1272,6 +1297,7 @@ mod tests {
assert!(tm.tm_yday == 0_i32);
assert!(tm.tm_isdst == 0_i32);
assert!(tm.tm_gmtoff == 0_i32);
assert!(tm.tm_zone() == "");
assert!(tm.tm_nsec == 12340000_i32);
}
}
@ -1383,10 +1409,10 @@ mod tests {
assert!(test("6", "%w"));
assert!(test("2009", "%Y"));
assert!(test("09", "%y"));
assert!(strptime("-0000", "%z").unwrap().tm_gmtoff ==
0);
assert!(strptime("-0800", "%z").unwrap().tm_gmtoff ==
0);
assert!(strptime("UTC", "%Z").unwrap().tm_zone() == "UTC");
assert!(strptime("PST", "%Z").unwrap().tm_zone() == "");
assert!(strptime("-0000", "%z").unwrap().tm_gmtoff == 0);
assert!(strptime("-0800", "%z").unwrap().tm_gmtoff == 0);
assert!(test("%", "%%"));
// Test for #7256

View File

@ -127,6 +127,15 @@ rust_list_dir_wfd_fp_buf(void* wfd) {
}
#endif
typedef struct
{
size_t fill; // in bytes; if zero, heapified
size_t alloc; // in bytes
uint8_t *data;
} rust_vec;
typedef rust_vec rust_str_buf;
typedef struct {
int32_t tm_sec;
int32_t tm_min;
@ -138,6 +147,7 @@ typedef struct {
int32_t tm_yday;
int32_t tm_isdst;
int32_t tm_gmtoff;
rust_str_buf tm_zone;
int32_t tm_nsec;
} rust_tm;
@ -154,10 +164,8 @@ void rust_tm_to_tm(rust_tm* in_tm, struct tm* out_tm) {
out_tm->tm_isdst = in_tm->tm_isdst;
}
void tm_to_rust_tm(struct tm* in_tm,
rust_tm* out_tm,
int32_t gmtoff,
int32_t nsec) {
void tm_to_rust_tm(struct tm* in_tm, rust_tm* out_tm, int32_t gmtoff,
const char *zone, int32_t nsec) {
out_tm->tm_sec = in_tm->tm_sec;
out_tm->tm_min = in_tm->tm_min;
out_tm->tm_hour = in_tm->tm_hour;
@ -169,6 +177,13 @@ void tm_to_rust_tm(struct tm* in_tm,
out_tm->tm_isdst = in_tm->tm_isdst;
out_tm->tm_gmtoff = gmtoff;
out_tm->tm_nsec = nsec;
if (zone != NULL) {
size_t size = strlen(zone);
assert(out_tm->tm_zone.alloc >= size);
memcpy(out_tm->tm_zone.data, zone, size);
out_tm->tm_zone.fill = size;
}
}
#if defined(__WIN32__)
@ -210,7 +225,7 @@ rust_gmtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
time_t s = sec;
GMTIME(&s, &tm);
tm_to_rust_tm(&tm, timeptr, 0, nsec);
tm_to_rust_tm(&tm, timeptr, 0, "UTC", nsec);
}
void
@ -219,13 +234,28 @@ rust_localtime(int64_t sec, int32_t nsec, rust_tm *timeptr) {
time_t s = sec;
LOCALTIME(&s, &tm);
const char* zone = NULL;
#if defined(__WIN32__)
int32_t gmtoff = -timezone;
wchar_t wbuffer[64] = {0};
char buffer[256] = {0};
// strftime("%Z") can contain non-UTF-8 characters on non-English locale (issue #9418),
// so time zone should be converted from UTF-16 string.
// Since wcsftime depends on setlocale() result,
// instead we convert it using MultiByteToWideChar.
if (strftime(buffer, sizeof(buffer) / sizeof(char), "%Z", &tm) > 0) {
// ANSI -> UTF-16
MultiByteToWideChar(CP_ACP, 0, buffer, -1, wbuffer, sizeof(wbuffer) / sizeof(wchar_t));
// UTF-16 -> UTF-8
WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, sizeof(buffer), NULL, NULL);
zone = buffer;
}
#else
int32_t gmtoff = tm.tm_gmtoff;
zone = tm.tm_zone;
#endif
tm_to_rust_tm(&tm, timeptr, gmtoff, nsec);
tm_to_rust_tm(&tm, timeptr, gmtoff, zone, nsec);
}
int64_t