auto merge of #10172 : pythonesque/rust/issue-9890, r=thestinger
This commit is contained in:
commit
6789a77fa0
2 changed files with 125 additions and 70 deletions
|
@ -22,7 +22,7 @@ use middle::trans::datum::*;
|
||||||
use middle::trans::expr::{Dest, Ignore, SaveIn};
|
use middle::trans::expr::{Dest, Ignore, SaveIn};
|
||||||
use middle::trans::expr;
|
use middle::trans::expr;
|
||||||
use middle::trans::glue;
|
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::trans::type_of;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use util::common::indenter;
|
use util::common::indenter;
|
||||||
|
@ -144,16 +144,19 @@ pub struct VecTypes {
|
||||||
vec_ty: ty::t,
|
vec_ty: ty::t,
|
||||||
unit_ty: ty::t,
|
unit_ty: ty::t,
|
||||||
llunit_ty: Type,
|
llunit_ty: Type,
|
||||||
llunit_size: ValueRef
|
llunit_size: ValueRef,
|
||||||
|
llunit_alloc_size: uint
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VecTypes {
|
impl VecTypes {
|
||||||
pub fn to_str(&self, ccx: &CrateContext) -> ~str {
|
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.vec_ty),
|
||||||
ty_to_str(ccx.tcx, self.unit_ty),
|
ty_to_str(ccx.tcx, self.unit_ty),
|
||||||
ccx.tn.type_to_str(self.llunit_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)
|
expr::trans_to_datum(bcx, element)
|
||||||
});
|
});
|
||||||
|
|
||||||
let next_bcx = sub_block(bcx, "expr_repeat: while next");
|
iter_vec_loop(bcx, lldest, vt,
|
||||||
let loop_bcx = loop_scope_block(bcx, next_bcx, None, "expr_repeat", None);
|
C_uint(bcx.ccx(), count), |set_bcx, lleltptr, _| {
|
||||||
let cond_bcx = scope_block(loop_bcx, None, "expr_repeat: loop cond");
|
elem.copy_to(set_bcx, INIT, lleltptr)
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 unit_ty = ty::sequence_element_type(bcx.tcx(), vec_ty);
|
||||||
let llunit_ty = type_of::type_of(ccx, unit_ty);
|
let llunit_ty = type_of::type_of(ccx, unit_ty);
|
||||||
let llunit_size = nonzero_llsize_of(ccx, llunit_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,
|
VecTypes {vec_ty: vec_ty,
|
||||||
unit_ty: unit_ty,
|
unit_ty: unit_ty,
|
||||||
llunit_ty: llunit_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 {
|
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 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,
|
pub fn iter_vec_raw(bcx: @mut Block, data_ptr: ValueRef, vec_ty: ty::t,
|
||||||
fill: ValueRef, f: iter_vec_block) -> @mut Block {
|
fill: ValueRef, f: iter_vec_block) -> @mut Block {
|
||||||
let _icx = push_ctxt("tvec::iter_vec_raw");
|
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.
|
// Now perform the iteration.
|
||||||
// FIXME (#3729): Optimize this when the size of the unit type is
|
let header_bcx = base::sub_block(bcx, "iter_vec_loop_header");
|
||||||
// statically known to not use pointer casts, which tend to confuse
|
Br(bcx, header_bcx.llbb);
|
||||||
// LLVM.
|
let data_ptr =
|
||||||
let data_end_ptr = pointer_add_byte(bcx, data_ptr, fill);
|
Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
|
||||||
|
let not_yet_at_end =
|
||||||
// Now perform the iteration.
|
ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
|
||||||
let header_bcx = base::sub_block(bcx, "iter_vec_loop_header");
|
let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body");
|
||||||
Br(bcx, header_bcx.llbb);
|
let next_bcx = base::sub_block(header_bcx, "iter_vec_next");
|
||||||
let data_ptr =
|
CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
|
||||||
Phi(header_bcx, val_ty(data_ptr), [data_ptr], [bcx.llbb]);
|
let body_bcx = f(body_bcx, data_ptr, vt.unit_ty);
|
||||||
let not_yet_at_end =
|
AddIncomingToPhi(data_ptr, InBoundsGEP(body_bcx, data_ptr,
|
||||||
ICmp(header_bcx, lib::llvm::IntULT, data_ptr, data_end_ptr);
|
[C_int(bcx.ccx(), 1)]),
|
||||||
let body_bcx = base::sub_block(header_bcx, "iter_vec_loop_body");
|
body_bcx.llbb);
|
||||||
let next_bcx = base::sub_block(header_bcx, "iter_vec_next");
|
Br(body_bcx, header_bcx.llbb);
|
||||||
CondBr(header_bcx, not_yet_at_end, body_bcx.llbb, next_bcx.llbb);
|
next_bcx
|
||||||
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;
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn iter_vec_uniq(bcx: @mut Block, vptr: ValueRef, vec_ty: ty::t,
|
pub fn iter_vec_uniq(bcx: @mut Block, vptr: ValueRef, vec_ty: ty::t,
|
||||||
|
|
29
src/test/run-pass/zero-size-type-destructors.rs
Normal file
29
src/test/run-pass/zero-size-type-destructors.rs
Normal file
|
@ -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 <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.
|
||||||
|
|
||||||
|
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));
|
||||||
|
}
|
Loading…
Reference in a new issue