fix Option<~ZeroSizeType>

1778b63616 provided the guarantee of no
`exchange_free` calls for ~ZeroSizeType, so a sentinel can now be used
without overhead.

Closes #11998
This commit is contained in:
Daniel Micay 2014-04-02 17:23:52 -04:00 committed by Alex Crichton
parent 1ac8b34ccd
commit 898669c4e2
3 changed files with 44 additions and 9 deletions

View File

@ -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);

View File

@ -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

View File

@ -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());
}