diff --git a/src/libcore/oldcomm.rs b/src/libcore/oldcomm.rs index 65aaf1fe4280..ae3116b08f0c 100644 --- a/src/libcore/oldcomm.rs +++ b/src/libcore/oldcomm.rs @@ -91,7 +91,8 @@ pub enum Chan { /// Constructs a port pub fn Port() -> Port { unsafe { - Port_(@PortPtr(rustrt::new_port(sys::size_of::() as size_t))) + Port_(@PortPtr(rustrt::new_port(sys::nonzero_size_of::() + as size_t))) } } diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs index ad9c3d1e51d1..322aa895eb46 100644 --- a/src/libcore/sys.rs +++ b/src/libcore/sys.rs @@ -87,6 +87,17 @@ pub struct Closure { unsafe { rusti::size_of::() } } +/** + * Returns the size of a type, or 1 if the actual size is zero. + * + * Useful for building structures containing variable-length arrays. + */ +#[inline(always)] +pub pure fn nonzero_size_of() -> uint { + let s = size_of::(); + if s == 0 { 1 } else { s } +} + /** * Returns the ABI-required minimum alignment of a type * @@ -146,7 +157,7 @@ pub struct Closure { #[cfg(test)] pub mod tests { use cast; - use sys::{Closure, pref_align_of, size_of}; + use sys::{Closure, pref_align_of, size_of, nonzero_size_of}; #[test] pub fn size_of_basic() { @@ -171,6 +182,14 @@ pub fn size_of_64() { assert size_of::<*uint>() == 8u; } + #[test] + pub fn nonzero_size_of_basic() { + type Z = [i8 * 0]; + assert size_of::() == 0u; + assert nonzero_size_of::() == 1u; + assert nonzero_size_of::() == size_of::(); + } + #[test] pub fn align_of_basic() { assert pref_align_of::() == 1u; diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs index b9cefa89aa74..29767f3c1e0c 100644 --- a/src/libcore/vec.rs +++ b/src/libcore/vec.rs @@ -103,7 +103,7 @@ pub fn reserve_at_least(v: &mut ~[T], n: uint) { pub pure fn capacity(v: &const ~[T]) -> uint { unsafe { let repr: **raw::VecRepr = ::cast::transmute(v); - (**repr).unboxed.alloc / sys::size_of::() + (**repr).unboxed.alloc / sys::nonzero_size_of::() } } @@ -276,7 +276,7 @@ pub fn reserve_at_least(v: &mut ~[T], n: uint) { unsafe { ::cast::reinterpret_cast( &(ptr::offset(p, start), - (end - start) * sys::size_of::())) + (end - start) * sys::nonzero_size_of::())) } } } @@ -289,7 +289,7 @@ pub fn reserve_at_least(v: &mut ~[T], n: uint) { unsafe { ::cast::reinterpret_cast( &(ptr::mut_offset(p, start), - (end - start) * sys::size_of::())) + (end - start) * sys::nonzero_size_of::())) } } } @@ -303,7 +303,7 @@ pub fn reserve_at_least(v: &mut ~[T], n: uint) { unsafe { ::cast::reinterpret_cast( &(ptr::const_offset(p, start), - (end - start) * sys::size_of::())) + (end - start) * sys::nonzero_size_of::())) } } } @@ -608,7 +608,7 @@ pub fn push(v: &mut ~[T], initval: T) { unsafe fn push_fast(v: &mut ~[T], initval: T) { let repr: **raw::VecRepr = ::cast::transmute(v); let fill = (**repr).unboxed.fill; - (**repr).unboxed.fill += sys::size_of::(); + (**repr).unboxed.fill += sys::nonzero_size_of::(); let p = addr_of(&((**repr).unboxed.data)); let p = ptr::offset(p, fill) as *mut T; rusti::move_val_init(&mut(*p), move initval); @@ -1449,7 +1449,7 @@ pub fn each2(v1: &[U], v2: &[T], f: fn(u: &U, t: &T) -> bool) { let v : *(*T,uint) = ::cast::reinterpret_cast(&addr_of(&s)); let (buf,len) = *v; - f(buf, len / sys::size_of::()) + f(buf, len / sys::nonzero_size_of::()) } } @@ -1462,7 +1462,7 @@ pub fn each2(v1: &[U], v2: &[T], f: fn(u: &U, t: &T) -> bool) { let v : *(*const T,uint) = ::cast::reinterpret_cast(&addr_of(&s)); let (buf,len) = *v; - f(buf, len / sys::size_of::()) + f(buf, len / sys::nonzero_size_of::()) } } @@ -1475,7 +1475,7 @@ pub fn each2(v1: &[U], v2: &[T], f: fn(u: &U, t: &T) -> bool) { let v : *(*mut T,uint) = ::cast::reinterpret_cast(&addr_of(&s)); let (buf,len) = *v; - f(buf, len / sys::size_of::()) + f(buf, len / sys::nonzero_size_of::()) } } @@ -1992,7 +1992,7 @@ pub struct VecRepr { #[inline(always)] pub unsafe fn set_len(v: &mut ~[T], new_len: uint) { let repr: **VecRepr = ::cast::transmute(v); - (**repr).unboxed.fill = new_len * sys::size_of::(); + (**repr).unboxed.fill = new_len * sys::nonzero_size_of::(); } /** @@ -2032,7 +2032,7 @@ pub unsafe fn to_mut_ptr(v: &[mut T]) -> *mut T { pub unsafe fn buf_as_slice(p: *T, len: uint, f: fn(v: &[T]) -> U) -> U { - let pair = (p, len * sys::size_of::()); + let pair = (p, len * sys::nonzero_size_of::()); let v : *(&blk/[T]) = ::cast::reinterpret_cast(&addr_of(&pair)); f(*v) @@ -2501,6 +2501,18 @@ fn test_is_not_empty() { assert (!is_not_empty::(~[])); } + #[test] + fn test_len_divzero() { + type Z = [i8 * 0]; + let v0 : &[Z] = &[]; + let v1 : &[Z] = &[[]]; + let v2 : &[Z] = &[[], []]; + assert(sys::size_of::() == 0); + assert(len(v0) == 0); + assert(len(v1) == 1); + assert(len(v2) == 2); + } + #[test] fn test_head() { let a = ~[11, 12]; diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs index 0e778e2d705a..bc1cd5ec9112 100644 --- a/src/librustc/middle/trans/machine.rs +++ b/src/librustc/middle/trans/machine.rs @@ -132,6 +132,17 @@ pub fn llsize_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef { } } +// Returns the "default" size of t (see above), or 1 if the size would +// be zero. This is important for things like vectors that expect +// space to be consumed. +pub fn nonzero_llsize_of(cx: @crate_ctxt, t: TypeRef) -> ValueRef { + if llbitsize_of_real(cx, t) == 0 { + unsafe { llvm::LLVMConstInt(cx.int_type, 1, False) } + } else { + llsize_of(cx, t) + } +} + // Returns the preferred alignment of the given type for the current target. // The preffered alignment may be larger than the alignment used when // packing the type into structs. This will be used for things like diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index e85b7fe14dc3..9db607773eb4 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -17,7 +17,7 @@ use middle::trans::expr::{Dest, Ignore, SaveIn}; use middle::trans::expr; use middle::trans::glue; -use middle::trans::shape::llsize_of; +use middle::trans::shape::{llsize_of, nonzero_llsize_of}; use middle::trans::type_of; use middle::ty; use util::common::indenter; @@ -96,7 +96,7 @@ fn alloc_vec(bcx: block, unit_ty: ty::t, elts: uint, heap: heap) -> Result { let _icx = bcx.insn_ctxt("tvec::alloc_uniq"); let ccx = bcx.ccx(); let llunitty = type_of::type_of(ccx, unit_ty); - let unit_sz = llsize_of(ccx, llunitty); + let unit_sz = nonzero_llsize_of(ccx, llunitty); let fill = Mul(bcx, C_uint(ccx, elts), unit_sz); let alloc = if elts < 4u { Mul(bcx, C_int(ccx, 4), unit_sz) } @@ -418,7 +418,8 @@ fn vec_types(bcx: block, vec_ty: ty::t) -> VecTypes { let ccx = bcx.ccx(); let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); let llunit_ty = type_of::type_of(ccx, unit_ty); - let llunit_size = llsize_of(ccx, llunit_ty); + let llunit_size = nonzero_llsize_of(ccx, llunit_ty); + VecTypes {vec_ty: vec_ty, unit_ty: unit_ty, llunit_ty: llunit_ty,