about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorDaniel Micay <danielmicay@gmail.com>2014-04-02 17:23:52 -0400
committerAlex Crichton <alex@alexcrichton.com>2014-04-03 13:43:35 -0700
commit898669c4e203ae91e2048fb6c0f8591c867bccc6 (patch)
tree00dd1385c83fb35dff75055f477bcc795732d6f8 /src
parent1ac8b34ccd02965886d3ca0bd83115c7f7b73729 (diff)
downloadrust-898669c4e203ae91e2048fb6c0f8591c867bccc6.tar.gz
rust-898669c4e203ae91e2048fb6c0f8591c867bccc6.zip
fix Option<~ZeroSizeType>
1778b6361627c5894bf75ffecf427573af02d390 provided the guarantee of no
`exchange_free` calls for ~ZeroSizeType, so a sentinel can now be used
without overhead.

Closes #11998
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/trans/expr.rs21
-rw-r--r--src/libstd/rt/global_heap.rs13
-rw-r--r--src/test/run-pass/empty-allocation-non-null.rs19
3 files changed, 44 insertions, 9 deletions
diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs
index bd8c84e85e5..49a4a3ed25c 100644
--- a/src/librustc/middle/trans/expr.rs
+++ b/src/librustc/middle/trans/expr.rs
@@ -67,7 +67,7 @@ use middle::typeck::MethodCall;
 use util::common::indenter;
 use util::ppaux::Repr;
 use util::nodemap::NodeMap;
-use middle::trans::machine::llsize_of;
+use middle::trans::machine::{llsize_of, llsize_of_alloc};
 use middle::trans::type_::Type;
 
 use std::slice;
@@ -1200,12 +1200,19 @@ fn trans_boxed_expr<'a>(bcx: &'a Block<'a>,
         let size = llsize_of(bcx.ccx(), llty);
         let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty,
                                                            heap_exchange, size);
-        let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
-        fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
-                                val, heap_exchange);
-        let bcx = trans_into(bcx, contents, SaveIn(val));
-        fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
-        immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
+        // Unique boxes do not allocate for zero-size types. The standard library may assume
+        // that `free` is never called on the pointer returned for `~ZeroSizeType`.
+        if llsize_of_alloc(bcx.ccx(), llty) == 0 {
+            let bcx = trans_into(bcx, contents, SaveIn(val));
+            immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
+        } else {
+            let custom_cleanup_scope = fcx.push_custom_cleanup_scope();
+            fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope),
+                                    val, heap_exchange);
+            let bcx = trans_into(bcx, contents, SaveIn(val));
+            fcx.pop_custom_cleanup_scope(custom_cleanup_scope);
+            immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock()
+        }
     } else {
         let base::MallocResult { bcx, smart_ptr: bx, body } =
             base::malloc_general(bcx, contents_ty, heap);
diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs
index 23b23cf8af0..3917857e1af 100644
--- a/src/libstd/rt/global_heap.rs
+++ b/src/libstd/rt/global_heap.rs
@@ -64,12 +64,21 @@ pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 {
     }
 }
 
+// The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size
+// allocations can point to this `static`. It would be incorrect to use a null
+// pointer, due to enums assuming types like unique pointers are never null.
+static EMPTY: () = ();
+
 /// The allocator for unique pointers without contained managed pointers.
 #[cfg(not(test))]
 #[lang="exchange_malloc"]
 #[inline]
-pub unsafe fn exchange_malloc(size: uint) -> *u8 {
-    malloc_raw(size) as *u8
+pub unsafe fn exchange_malloc(size: uint) -> *mut u8 {
+    if size == 0 {
+        &EMPTY as *() as *mut u8
+    } else {
+        malloc_raw(size)
+    }
 }
 
 // FIXME: #7496
diff --git a/src/test/run-pass/empty-allocation-non-null.rs b/src/test/run-pass/empty-allocation-non-null.rs
new file mode 100644
index 00000000000..9695296ec15
--- /dev/null
+++ b/src/test/run-pass/empty-allocation-non-null.rs
@@ -0,0 +1,19 @@
+// Copyright 2014 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 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub fn main() {
+    assert!(Some(~()).is_some());
+
+    struct Foo;
+    assert!(Some(~Foo).is_some());
+
+    let xs: ~[()] = ~[];
+    assert!(Some(xs).is_some());
+}