From 898669c4e203ae91e2048fb6c0f8591c867bccc6 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 2 Apr 2014 17:23:52 -0400 Subject: [PATCH] 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 --- src/librustc/middle/trans/expr.rs | 21 ++++++++++++------- src/libstd/rt/global_heap.rs | 13 ++++++++++-- .../run-pass/empty-allocation-non-null.rs | 19 +++++++++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 src/test/run-pass/empty-allocation-non-null.rs 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 or the MIT license +// , 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()); +}