about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2013-10-30 13:26:29 -0700
committerbors <bors@rust-lang.org>2013-10-30 13:26:29 -0700
commit6789a77fa02b5f7c3f9ca0261a5387a951d23caf (patch)
tree0a3ae54f592906aa204f4336e870fd843c3f3855
parent623daf66a96065333579eb2e551ba71f8f8000b9 (diff)
parenteee892c4beec9d037cfa68089334af7c9dd07401 (diff)
downloadrust-6789a77fa02b5f7c3f9ca0261a5387a951d23caf.tar.gz
rust-6789a77fa02b5f7c3f9ca0261a5387a951d23caf.zip
auto merge of #10172 : pythonesque/rust/issue-9890, r=thestinger
-rw-r--r--src/librustc/middle/trans/tvec.rs168
-rw-r--r--src/test/run-pass/zero-size-type-destructors.rs29
2 files changed, 126 insertions, 71 deletions
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);
-
-    // 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;
+    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);
+
+        // 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 <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));
+}