From 9639cafd3625429ea558d3202cffdfc851fcf9cf Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Mon, 8 Sep 2014 19:27:06 -0400 Subject: [PATCH] fixes for Box<[T]> The pointer in the slice must not be null, because enum representations make that assumption. The `exchange_malloc` function returns a non-null sentinel for the zero size case, and it must not be passed to the `exchange_free` lang item. Since the length is always equal to the true capacity, a branch on the length is enough for most types. Slices of zero size types are statically special cased to never attempt deallocation. This is the same implementation as `Vec`. Closes #14395 --- src/liballoc/heap.rs | 6 ---- src/librustc/middle/trans/expr.rs | 28 ++++--------------- src/librustc/middle/trans/tvec.rs | 21 ++++++++------ .../run-pass/empty-allocation-non-null.rs | 6 ++++ 4 files changed, 24 insertions(+), 37 deletions(-) diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index c72a77702afff..30377a33bfee4 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -12,7 +12,6 @@ // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` // and `nonnull` -use core::ptr::RawPtr; #[cfg(not(test))] use core::raw; #[cfg(stage0, not(test))] use util; @@ -70,11 +69,6 @@ pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint, /// the value returned by `usable_size` for the requested size. #[inline] pub unsafe fn deallocate(ptr: *mut u8, size: uint, align: uint) { - // FIXME(14395) This is only required for DST ~[T], it should be removed once - // we fix that representation to not use null pointers. - if ptr.is_null() { - return; - } imp::deallocate(ptr, size, align) } diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index 0421aef45ef9c..b6bfb525add24 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -412,29 +412,11 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let vec_ty = ty::mk_uniq(tcx, ty::mk_vec(tcx, unit_ty, None)); let scratch = rvalue_scratch_datum(bcx, vec_ty, "__unsize_unique"); - if len == 0 { - Store(bcx, - C_null(type_of::type_of(bcx.ccx(), unit_ty).ptr_to()), - get_dataptr(bcx, scratch.val)); - } else { - // Box<[(), ..n]> will not allocate, but ~[()] expects an - // allocation of n bytes, so we must allocate here (yuck). - let llty = type_of::type_of(bcx.ccx(), unit_ty); - if llsize_of_alloc(bcx.ccx(), llty) == 0 { - let ptr_unit_ty = type_of::type_of(bcx.ccx(), unit_ty).ptr_to(); - let align = C_uint(bcx.ccx(), 8); - let alloc_result = malloc_raw_dyn(bcx, ptr_unit_ty, vec_ty, ll_len, align); - bcx = alloc_result.bcx; - let base = get_dataptr(bcx, scratch.val); - Store(bcx, alloc_result.val, base); - } else { - let base = get_dataptr(bcx, scratch.val); - let base = PointerCast(bcx, - base, - type_of::type_of(bcx.ccx(), datum_ty).ptr_to()); - bcx = lval.store_to(bcx, base); - } - } + let base = get_dataptr(bcx, scratch.val); + let base = PointerCast(bcx, + base, + type_of::type_of(bcx.ccx(), datum_ty).ptr_to()); + bcx = lval.store_to(bcx, base); Store(bcx, ll_len, get_len(bcx, scratch.val)); DatumBlock::new(bcx, scratch.to_expr_datum()) diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 00b9977c7523c..c0d19b31cb8ed 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -72,14 +72,19 @@ pub fn make_drop_glue_unboxed<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, }; if should_deallocate { - let not_null = IsNotNull(bcx, dataptr); - with_cond(bcx, not_null, |bcx| { - let llty = type_of::type_of(ccx, unit_ty); - let llsize = machine::llsize_of(ccx, llty); - let llalign = C_uint(ccx, machine::llalign_of_min(ccx, llty) as uint); - let size = Mul(bcx, llsize, get_len(bcx, vptr)); - glue::trans_exchange_free_dyn(bcx, dataptr, size, llalign) - }) + let llty = type_of::type_of(ccx, unit_ty); + let unit_size = llsize_of_alloc(ccx, llty); + if unit_size != 0 { + let len = get_len(bcx, vptr); + let not_empty = ICmp(bcx, llvm::IntNE, len, C_uint(ccx, 0)); + with_cond(bcx, not_empty, |bcx| { + let llalign = C_uint(ccx, machine::llalign_of_min(ccx, llty) as uint); + let size = Mul(bcx, C_uint(ccx, unit_size as uint), len); + glue::trans_exchange_free_dyn(bcx, dataptr, size, llalign) + }) + } else { + bcx + } } else { bcx } diff --git a/src/test/run-pass/empty-allocation-non-null.rs b/src/test/run-pass/empty-allocation-non-null.rs index 15544468ae992..56eb340ef59ac 100644 --- a/src/test/run-pass/empty-allocation-non-null.rs +++ b/src/test/run-pass/empty-allocation-non-null.rs @@ -11,6 +11,12 @@ pub fn main() { assert!(Some(box() ()).is_some()); + let xs: Box<[()]> = box []; + assert!(Some(xs).is_some()); + struct Foo; assert!(Some(box Foo).is_some()); + + let ys: Box<[Foo]> = box []; + assert!(Some(ys).is_some()); }