diff --git a/src/librustc/middle/trans/tvec.rs b/src/librustc/middle/trans/tvec.rs index 38c5e0b55f7..1f9e9037179 100644 --- a/src/librustc/middle/trans/tvec.rs +++ b/src/librustc/middle/trans/tvec.rs @@ -22,7 +22,7 @@ use middle::trans::datum::*; use middle::trans::expr::{Dest, Ignore, SaveIn}; use middle::trans::expr; use middle::trans::glue; -use middle::trans::machine::{llsize_of, nonzero_llsize_of}; +use middle::trans::machine::{llsize_of, nonzero_llsize_of, llsize_of_alloc}; use middle::trans::type_of; use middle::ty; use util::common::indenter; @@ -144,16 +144,19 @@ pub struct VecTypes { vec_ty: ty::t, unit_ty: ty::t, llunit_ty: Type, - llunit_size: ValueRef + llunit_size: ValueRef, + llunit_alloc_size: uint } impl VecTypes { pub fn to_str(&self, ccx: &CrateContext) -> ~str { - format!("VecTypes \\{vec_ty={}, unit_ty={}, llunit_ty={}, llunit_size={}\\}", + format!("VecTypes \\{vec_ty={}, unit_ty={}, llunit_ty={}, llunit_size={}, \ + llunit_alloc_size={}\\}", ty_to_str(ccx.tcx, self.vec_ty), ty_to_str(ccx.tcx, self.unit_ty), ccx.tn.type_to_str(self.llunit_ty), - ccx.tn.val_to_str(self.llunit_size)) + ccx.tn.val_to_str(self.llunit_size), + self.llunit_alloc_size) } } @@ -416,48 +419,10 @@ pub fn write_content(bcx: @mut Block, expr::trans_to_datum(bcx, element) }); - let next_bcx = sub_block(bcx, "expr_repeat: while next"); - let loop_bcx = loop_scope_block(bcx, next_bcx, None, "expr_repeat", None); - let cond_bcx = scope_block(loop_bcx, None, "expr_repeat: loop cond"); - let set_bcx = scope_block(loop_bcx, None, "expr_repeat: body: set"); - let inc_bcx = scope_block(loop_bcx, None, "expr_repeat: body: inc"); - Br(bcx, loop_bcx.llbb); - - let loop_counter = { - // i = 0 - let i = alloca(loop_bcx, bcx.ccx().int_type, "__i"); - Store(loop_bcx, C_uint(bcx.ccx(), 0), i); - - Br(loop_bcx, cond_bcx.llbb); - i - }; - - { // i < count - let lhs = Load(cond_bcx, loop_counter); - let rhs = C_uint(bcx.ccx(), count); - let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs); - - CondBr(cond_bcx, cond_val, set_bcx.llbb, next_bcx.llbb); - } - - { // v[i] = elem - let i = Load(set_bcx, loop_counter); - let lleltptr = InBoundsGEP(set_bcx, lldest, [i]); - let set_bcx = elem.copy_to(set_bcx, INIT, lleltptr); - - Br(set_bcx, inc_bcx.llbb); - } - - { // i += 1 - let i = Load(inc_bcx, loop_counter); - let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1)); - Store(inc_bcx, plusone, loop_counter); - - Br(inc_bcx, cond_bcx.llbb); - } - - return next_bcx; - + iter_vec_loop(bcx, lldest, vt, + C_uint(bcx.ccx(), count), |set_bcx, lleltptr, _| { + elem.copy_to(set_bcx, INIT, lleltptr) + }) } } } @@ -478,11 +443,13 @@ pub fn vec_types(bcx: @mut Block, vec_ty: ty::t) -> VecTypes { let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); let llunit_ty = type_of::type_of(ccx, unit_ty); let llunit_size = nonzero_llsize_of(ccx, llunit_ty); + let llunit_alloc_size = llsize_of_alloc(ccx, llunit_ty); VecTypes {vec_ty: vec_ty, unit_ty: unit_ty, llunit_ty: llunit_ty, - llunit_size: llunit_size} + llunit_size: llunit_size, + llunit_alloc_size: llunit_alloc_size} } pub fn elements_required(bcx: @mut Block, content_expr: &ast::Expr) -> uint { @@ -574,35 +541,94 @@ pub fn get_base_and_len(bcx: @mut Block, llval: ValueRef, vec_ty: ty::t) -> (Val pub type iter_vec_block<'self> = &'self fn(@mut Block, ValueRef, ty::t) -> @mut Block; +pub fn iter_vec_loop(bcx: @mut Block, + data_ptr: ValueRef, + vt: &VecTypes, + count: ValueRef, + f: iter_vec_block + ) -> @mut Block { + let _icx = push_ctxt("tvec::iter_vec_loop"); + + let next_bcx = sub_block(bcx, "iter_vec_loop: while next"); + let loop_bcx = loop_scope_block(bcx, next_bcx, None, "iter_vec_loop", None); + let cond_bcx = scope_block(loop_bcx, None, "iter_vec_loop: loop cond"); + let body_bcx = scope_block(loop_bcx, None, "iter_vec_loop: body: main"); + let inc_bcx = scope_block(loop_bcx, None, "iter_vec_loop: loop inc"); + Br(bcx, loop_bcx.llbb); + + let loop_counter = { + // i = 0 + let i = alloca(loop_bcx, bcx.ccx().int_type, "__i"); + Store(loop_bcx, C_uint(bcx.ccx(), 0), i); + + Br(loop_bcx, cond_bcx.llbb); + i + }; + + { // i < count + let lhs = Load(cond_bcx, loop_counter); + let rhs = count; + let cond_val = ICmp(cond_bcx, lib::llvm::IntULT, lhs, rhs); + + CondBr(cond_bcx, cond_val, body_bcx.llbb, next_bcx.llbb); + } + + { // loop body + let i = Load(body_bcx, loop_counter); + let lleltptr = if vt.llunit_alloc_size == 0 { + data_ptr + } else { + InBoundsGEP(body_bcx, data_ptr, [i]) + }; + let body_bcx = f(body_bcx, lleltptr, vt.unit_ty); + + Br(body_bcx, inc_bcx.llbb); + } + + { // i += 1 + let i = Load(inc_bcx, loop_counter); + let plusone = Add(inc_bcx, i, C_uint(bcx.ccx(), 1)); + Store(inc_bcx, plusone, loop_counter); + + Br(inc_bcx, cond_bcx.llbb); + } + + next_bcx +} + pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t, fill: ValueRef, f: iter_vec_block) -> @mut Block { let _icx = push_ctxt("tvec::iter_vec_raw"); - let unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty); + let vt = vec_types(bcx, vec_ty); + if (vt.llunit_alloc_size == 0) { + // Special-case vectors with elements of size 0 so they don't go out of bounds (#9890) + iter_vec_loop(bcx, data_ptr, &vt, fill, f) + } else { + // Calculate the last pointer address we want to handle. + // FIXME (#3729): Optimize this when the size of the unit type is + // statically known to not use pointer casts, which tend to confuse + // LLVM. + let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill); - // Calculate the last pointer address we want to handle. - // FIXME (#3729): Optimize this when the size of the unit type is - // statically known to not use pointer casts, which tend to confuse - // LLVM. - let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill); - - // Now perform the iteration. - let header_bcx = base::sub_block(bcx, "iter_vec_loop_header"); - Br(bcx, header_bcx.llbb); - let data_ptr = - Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]); - let not_yet_at_end = - ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr); - let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body"); - let next_bcx = base::sub_block(header_bcx, "iter_vec_next"); - CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb); - let body_bcx = f(body_bcx, data_ptr, unit_ty); - AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr, - [C_int(bcx.ccx(), 1)]), - body_bcx.llbb); - Br(body_bcx, header_bcx.llbb); - return next_bcx; + // Now perform the iteration. + let header_bcx = base::sub_block(bcx, "iter_vec_loop_header"); + Br(bcx, header_bcx.llbb); + let data_ptr = + Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]); + let not_yet_at_end = + ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr); + let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body"); + let next_bcx = base::sub_block(header_bcx, "iter_vec_next"); + CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb); + let body_bcx = f(body_bcx, data_ptr, vt.unit_ty); + AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr, + [C_int(bcx.ccx(), 1)]), + body_bcx.llbb); + Br(body_bcx, header_bcx.llbb); + next_bcx + } } pub fn iter_vec_uniq(bcx: @mut Block, vptr: ValueRef, vec_ty: ty::t, diff --git a/src/test/run-pass/zero-size-type-destructors.rs b/src/test/run-pass/zero-size-type-destructors.rs new file mode 100644 index 00000000000..fd272a47de9 --- /dev/null +++ b/src/test/run-pass/zero-size-type-destructors.rs @@ -0,0 +1,29 @@ +// Copyright 2013 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. + +static mut destructions : int = 3; + +pub fn foo() { + #[unsafe_no_drop_flag] + struct Foo; + + impl Drop for Foo { + fn drop(&mut self) { + unsafe { destructions -= 1 }; + } + }; + + let _x = [Foo, Foo, Foo]; +} + +pub fn main() { + foo(); + assert!((unsafe { destructions } == 0)); +}