about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJed Davis <jld@panix.com>2013-01-08 00:24:43 -0800
committerTim Chevalier <chevalier@alum.wellesley.edu>2013-01-13 14:37:59 -0800
commit1b01629f189f1c4050bd5c7eac81e44ba2c7a76f (patch)
treea958ba05b82b2948ca24891931c704f69ad9014f
parentea53c48ca23ec4e46454d48936c209d2a67cf892 (diff)
Make vectors (& old ports) of zero-size types allocate one byte each.
-rw-r--r--src/libcore/oldcomm.rs3
-rw-r--r--src/libcore/sys.rs21
-rw-r--r--src/libcore/vec.rs32
-rw-r--r--src/librustc/middle/trans/machine.rs11
-rw-r--r--src/librustc/middle/trans/tvec.rs7
5 files changed, 59 insertions, 15 deletions
diff --git a/src/libcore/oldcomm.rs b/src/libcore/oldcomm.rs
index 65aaf1fe428..ae3116b08f0 100644
--- a/src/libcore/oldcomm.rs
+++ b/src/libcore/oldcomm.rs
@@ -91,7 +91,8 @@ pub enum Chan<T: Owned> {
 /// Constructs a port
 pub fn Port<T: Owned>() -> Port<T> {
     unsafe {
-        Port_(@PortPtr(rustrt::new_port(sys::size_of::<T>() as size_t)))
+        Port_(@PortPtr(rustrt::new_port(sys::nonzero_size_of::<T>()
+                                        as size_t)))
     }
 }
 
diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs
index ad9c3d1e51d..322aa895eb4 100644
--- a/src/libcore/sys.rs
+++ b/src/libcore/sys.rs
@@ -88,6 +88,17 @@ pub pure fn size_of<T>() -> uint {
 }
 
 /**
+ * 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<T>() -> uint {
+    let s = size_of::<T>();
+    if s == 0 { 1 } else { s }
+}
+
+/**
  * Returns the ABI-required minimum alignment of a type
  *
  * This is the alignment used for struct fields. It may be smaller
@@ -146,7 +157,7 @@ pub pure fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
 #[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() {
@@ -172,6 +183,14 @@ pub mod tests {
     }
 
     #[test]
+    pub fn nonzero_size_of_basic() {
+        type Z = [i8 * 0];
+        assert size_of::<Z>() == 0u;
+        assert nonzero_size_of::<Z>() == 1u;
+        assert nonzero_size_of::<uint>() == size_of::<uint>();
+    }
+
+    #[test]
     pub fn align_of_basic() {
         assert pref_align_of::<u8>() == 1u;
         assert pref_align_of::<u16>() == 2u;
diff --git a/src/libcore/vec.rs b/src/libcore/vec.rs
index b9cefa89aa7..29767f3c1e0 100644
--- a/src/libcore/vec.rs
+++ b/src/libcore/vec.rs
@@ -103,7 +103,7 @@ pub fn reserve_at_least<T>(v: &mut ~[T], n: uint) {
 pub pure fn capacity<T>(v: &const ~[T]) -> uint {
     unsafe {
         let repr: **raw::VecRepr = ::cast::transmute(v);
-        (**repr).unboxed.alloc / sys::size_of::<T>()
+        (**repr).unboxed.alloc / sys::nonzero_size_of::<T>()
     }
 }
 
@@ -276,7 +276,7 @@ pub pure fn view<T>(v: &r/[T], start: uint, end: uint) -> &r/[T] {
         unsafe {
             ::cast::reinterpret_cast(
                 &(ptr::offset(p, start),
-                  (end - start) * sys::size_of::<T>()))
+                  (end - start) * sys::nonzero_size_of::<T>()))
         }
     }
 }
@@ -289,7 +289,7 @@ pub pure fn mut_view<T>(v: &r/[mut T], start: uint, end: uint) -> &r/[mut T] {
         unsafe {
             ::cast::reinterpret_cast(
                 &(ptr::mut_offset(p, start),
-                  (end - start) * sys::size_of::<T>()))
+                  (end - start) * sys::nonzero_size_of::<T>()))
         }
     }
 }
@@ -303,7 +303,7 @@ pub pure fn const_view<T>(v: &r/[const T], start: uint,
         unsafe {
             ::cast::reinterpret_cast(
                 &(ptr::const_offset(p, start),
-                  (end - start) * sys::size_of::<T>()))
+                  (end - start) * sys::nonzero_size_of::<T>()))
         }
     }
 }
@@ -608,7 +608,7 @@ pub fn push<T>(v: &mut ~[T], initval: T) {
 unsafe fn push_fast<T>(v: &mut ~[T], initval: T) {
     let repr: **raw::VecRepr = ::cast::transmute(v);
     let fill = (**repr).unboxed.fill;
-    (**repr).unboxed.fill += sys::size_of::<T>();
+    (**repr).unboxed.fill += sys::nonzero_size_of::<T>();
     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 pure fn as_imm_buf<T,U>(s: &[T],
         let v : *(*T,uint) =
             ::cast::reinterpret_cast(&addr_of(&s));
         let (buf,len) = *v;
-        f(buf, len / sys::size_of::<T>())
+        f(buf, len / sys::nonzero_size_of::<T>())
     }
 }
 
@@ -1462,7 +1462,7 @@ pub pure fn as_const_buf<T,U>(s: &[const T],
         let v : *(*const T,uint) =
             ::cast::reinterpret_cast(&addr_of(&s));
         let (buf,len) = *v;
-        f(buf, len / sys::size_of::<T>())
+        f(buf, len / sys::nonzero_size_of::<T>())
     }
 }
 
@@ -1475,7 +1475,7 @@ pub pure fn as_mut_buf<T,U>(s: &[mut T],
         let v : *(*mut T,uint) =
             ::cast::reinterpret_cast(&addr_of(&s));
         let (buf,len) = *v;
-        f(buf, len / sys::size_of::<T>())
+        f(buf, len / sys::nonzero_size_of::<T>())
     }
 }
 
@@ -1992,7 +1992,7 @@ pub mod raw {
     #[inline(always)]
     pub unsafe fn set_len<T>(v: &mut ~[T], new_len: uint) {
         let repr: **VecRepr = ::cast::transmute(v);
-        (**repr).unboxed.fill = new_len * sys::size_of::<T>();
+        (**repr).unboxed.fill = new_len * sys::nonzero_size_of::<T>();
     }
 
     /**
@@ -2032,7 +2032,7 @@ pub mod raw {
     pub unsafe fn buf_as_slice<T,U>(p: *T,
                                     len: uint,
                                     f: fn(v: &[T]) -> U) -> U {
-        let pair = (p, len * sys::size_of::<T>());
+        let pair = (p, len * sys::nonzero_size_of::<T>());
         let v : *(&blk/[T]) =
             ::cast::reinterpret_cast(&addr_of(&pair));
         f(*v)
@@ -2502,6 +2502,18 @@ mod tests {
     }
 
     #[test]
+    fn test_len_divzero() {
+        type Z = [i8 * 0];
+        let v0 : &[Z] = &[];
+        let v1 : &[Z] = &[[]];
+        let v2 : &[Z] = &[[], []];
+        assert(sys::size_of::<Z>() == 0);
+        assert(len(v0) == 0);
+        assert(len(v1) == 1);
+        assert(len(v2) == 2);
+    }
+
+    #[test]
     fn test_head() {
         let a = ~[11, 12];
         assert (head(a) == 11);
diff --git a/src/librustc/middle/trans/machine.rs b/src/librustc/middle/trans/machine.rs
index 0e778e2d705..bc1cd5ec911 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 e85b7fe14dc..9db607773eb 100644
--- a/src/librustc/middle/trans/tvec.rs
+++ b/src/librustc/middle/trans/tvec.rs
@@ -17,7 +17,7 @@ use middle::trans::datum::*;
 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,