about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/middle/trans/base.rs89
-rw-r--r--src/librustc/middle/trans/callee.rs2
-rw-r--r--src/librustc/middle/trans/common.rs9
-rw-r--r--src/librustc/middle/trans/controlflow.rs4
-rw-r--r--src/librustc/middle/trans/foreign.rs27
-rw-r--r--src/librustc/middle/trans/glue.rs41
-rw-r--r--src/librustc/middle/trans/reflect.rs9
7 files changed, 113 insertions, 68 deletions
diff --git a/src/librustc/middle/trans/base.rs b/src/librustc/middle/trans/base.rs
index c0336c8e60d..bbd676c87b4 100644
--- a/src/librustc/middle/trans/base.rs
+++ b/src/librustc/middle/trans/base.rs
@@ -1102,11 +1102,6 @@ pub fn trans_trace(bcx: block, sp_opt: Option<span>, trace_str: @str) {
     Call(bcx, ccx.upcalls.trace, args);
 }
 
-pub fn build_return(bcx: block) {
-    let _icx = push_ctxt("build_return");
-    Br(bcx, bcx.fcx.llreturn);
-}
-
 pub fn ignore_lhs(_bcx: block, local: &ast::local) -> bool {
     match local.node.pat.node {
         ast::pat_wild => true, _ => false
@@ -1364,6 +1359,42 @@ pub fn cleanup_and_leave(bcx: block,
     }
 }
 
+pub fn cleanup_block(bcx: block, upto: Option<BasicBlockRef>) -> block{
+    let _icx = push_ctxt("cleanup_block");
+    let mut cur = bcx;
+    let mut bcx = bcx;
+    loop {
+        debug!("cleanup_block: %s", cur.to_str());
+
+        if bcx.sess().trace() {
+            trans_trace(
+                bcx, None,
+                (fmt!("cleanup_block(%s)", cur.to_str())).to_managed());
+        }
+
+        let mut cur_scope = cur.scope;
+        loop {
+            cur_scope = match cur_scope {
+                Some (inf) => {
+                    bcx = trans_block_cleanups_(bcx, inf.cleanups.to_owned(), false);
+                    inf.parent
+                }
+                None => break
+            }
+        }
+
+        match upto {
+          Some(bb) => { if cur.llbb == bb { break; } }
+          _ => ()
+        }
+        cur = match cur.parent {
+          Some(next) => next,
+          None => { assert!(upto.is_none()); break; }
+        };
+    }
+    bcx
+}
+
 pub fn cleanup_and_Br(bcx: block, upto: block, target: BasicBlockRef) {
     let _icx = push_ctxt("cleanup_and_Br");
     cleanup_and_leave(bcx, Some(upto.llbb), Some(target));
@@ -1544,7 +1575,6 @@ pub fn arrayalloca(cx: block, ty: Type, v: ValueRef) -> ValueRef {
 
 pub struct BasicBlocks {
     sa: BasicBlockRef,
-    rt: BasicBlockRef
 }
 
 // Creates the standard set of basic blocks for a function
@@ -1554,12 +1584,18 @@ pub fn mk_standard_basic_blocks(llfn: ValueRef) -> BasicBlocks {
         BasicBlocks {
             sa: str::as_c_str("static_allocas",
                            |buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf)),
-            rt: str::as_c_str("return",
-                           |buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf))
         }
     }
 }
 
+pub fn mk_return_basic_block(llfn: ValueRef) -> BasicBlockRef {
+    unsafe {
+        let cx = task_llcx();
+        str::as_c_str("return",
+                      |buf| llvm::LLVMAppendBasicBlockInContext(cx, llfn, buf))
+    }
+}
+
 // Creates and returns space for, or returns the argument representing, the
 // slot where the return value of the function must go.
 pub fn make_return_pointer(fcx: fn_ctxt, output_type: ty::t) -> ValueRef {
@@ -1613,7 +1649,7 @@ pub fn new_fn_ctxt_w_id(ccx: @mut CrateContext,
           llretptr: None,
           llstaticallocas: llbbs.sa,
           llloadenv: None,
-          llreturn: llbbs.rt,
+          llreturn: None,
           llself: None,
           personality: None,
           loop_ret: None,
@@ -1757,16 +1793,24 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
 
 // Ties up the llstaticallocas -> llloadenv -> lltop edges,
 // and builds the return block.
-pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) {
+pub fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef, last_bcx: block) {
     let _icx = push_ctxt("finish_fn");
     tie_up_header_blocks(fcx, lltop);
-    build_return_block(fcx);
+
+    let ret_cx = match fcx.llreturn {
+        Some(llreturn) => {
+            if !last_bcx.terminated {
+                Br(last_bcx, llreturn);
+            }
+            raw_block(fcx, false, llreturn)
+        }
+        None => last_bcx
+    };
+    build_return_block(fcx, ret_cx);
 }
 
 // Builds the return block for a function.
-pub fn build_return_block(fcx: fn_ctxt) {
-    let ret_cx = raw_block(fcx, false, fcx.llreturn);
-
+pub fn build_return_block(fcx: fn_ctxt, ret_cx: block) {
     // Return the value if this function immediate; otherwise, return void.
     if fcx.llretptr.is_some() && fcx.has_immediate_return_value {
         Ret(ret_cx, Load(ret_cx, fcx.llretptr.get()))
@@ -1854,16 +1898,21 @@ pub fn trans_closure(ccx: @mut CrateContext,
     }
 
     finish(bcx);
-    cleanup_and_Br(bcx, bcx_top, fcx.llreturn);
+    match fcx.llreturn {
+        Some(llreturn) => cleanup_and_Br(bcx, bcx_top, llreturn),
+        None => bcx = cleanup_block(bcx, Some(bcx_top.llbb))
+    };
 
     // Put return block after all other blocks.
     // This somewhat improves single-stepping experience in debugger.
     unsafe {
-        llvm::LLVMMoveBasicBlockAfter(fcx.llreturn, bcx.llbb);
+        for fcx.llreturn.iter().advance |&llreturn| {
+            llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb);
+        }
     }
 
     // Insert the mandatory first few basic blocks before lltop.
-    finish_fn(fcx, lltop);
+    finish_fn(fcx, lltop, bcx);
 }
 
 // trans_fn: creates an LLVM function corresponding to a source language
@@ -2046,8 +2095,7 @@ pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
         let arg_ty = arg_tys[i];
         memcpy_ty(bcx, lldestptr, llarg, arg_ty);
     }
-    build_return(bcx);
-    finish_fn(fcx, lltop);
+    finish_fn(fcx, lltop, bcx);
 }
 
 pub fn trans_enum_def(ccx: @mut CrateContext, enum_definition: &ast::enum_def,
@@ -2288,8 +2336,7 @@ pub fn create_entry_wrapper(ccx: @mut CrateContext,
         let args = ~[llenvarg];
         Call(bcx, main_llfn, args);
 
-        build_return(bcx);
-        finish_fn(fcx, lltop);
+        finish_fn(fcx, lltop, bcx);
         return llfdecl;
     }
 
diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs
index 01bd69f24fc..7b7989879a6 100644
--- a/src/librustc/middle/trans/callee.rs
+++ b/src/librustc/middle/trans/callee.rs
@@ -704,7 +704,7 @@ pub fn trans_call_inner(in_cx: block,
                         Store(bcx, C_bool(false), bcx.fcx.llretptr.get());
                     }
                 }
-                base::cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
+                base::cleanup_and_leave(bcx, None, Some(bcx.fcx.get_llreturn()));
                 Unreachable(bcx);
                 bcx
             }
diff --git a/src/librustc/middle/trans/common.rs b/src/librustc/middle/trans/common.rs
index 1a45ce36af2..2e016377e75 100644
--- a/src/librustc/middle/trans/common.rs
+++ b/src/librustc/middle/trans/common.rs
@@ -184,7 +184,7 @@ pub struct fn_ctxt_ {
     // (LLVM requires that arguments be copied to local allocas before
     // allowing most any operation to be performed on them.)
     llloadenv: Option<BasicBlockRef>,
-    llreturn: BasicBlockRef,
+    llreturn: Option<BasicBlockRef>,
     // The 'self' value currently in use in this function, if there
     // is one.
     //
@@ -251,6 +251,13 @@ impl fn_ctxt_ {
         }
     }
 
+    pub fn get_llreturn(&mut self) -> BasicBlockRef {
+        if self.llreturn.is_none() {
+            self.llreturn = Some(base::mk_return_basic_block(self.llfn));
+        }
+
+        self.llreturn.get()
+    }
 }
 
 pub type fn_ctxt = @mut fn_ctxt_;
diff --git a/src/librustc/middle/trans/controlflow.rs b/src/librustc/middle/trans/controlflow.rs
index 6cbd6304847..e9eb7ff086d 100644
--- a/src/librustc/middle/trans/controlflow.rs
+++ b/src/librustc/middle/trans/controlflow.rs
@@ -279,7 +279,7 @@ pub fn trans_break_cont(bcx: block,
                         // This is a return from a loop body block
                         None => {
                             Store(bcx, C_bool(!to_end), bcx.fcx.llretptr.get());
-                            cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
+                            cleanup_and_leave(bcx, None, Some(bcx.fcx.get_llreturn()));
                             Unreachable(bcx);
                             return bcx;
                         }
@@ -328,7 +328,7 @@ pub fn trans_ret(bcx: block, e: Option<@ast::expr>) -> block {
       }
       _ => ()
     }
-    cleanup_and_leave(bcx, None, Some(bcx.fcx.llreturn));
+    cleanup_and_leave(bcx, None, Some(bcx.fcx.get_llreturn()));
     Unreachable(bcx);
     return bcx;
 }
diff --git a/src/librustc/middle/trans/foreign.rs b/src/librustc/middle/trans/foreign.rs
index 9019cd72ff8..1ad5a543e66 100644
--- a/src/librustc/middle/trans/foreign.rs
+++ b/src/librustc/middle/trans/foreign.rs
@@ -164,7 +164,10 @@ fn build_shim_fn_(ccx: @mut CrateContext,
     // follow the normal Rust calling conventions.
     tie_up_header_blocks(fcx, lltop);
 
-    let ret_cx = raw_block(fcx, false, fcx.llreturn);
+    let ret_cx = match fcx.llreturn {
+        Some(llreturn) => raw_block(fcx, false, llreturn),
+        None => bcx
+    };
     RetVoid(ret_cx);
 
     return llshimfn;
@@ -217,7 +220,10 @@ fn build_wrap_fn_(ccx: @mut CrateContext,
     tie_up_header_blocks(fcx, lltop);
 
     // Then return according to the C ABI.
-    let return_context = raw_block(fcx, false, fcx.llreturn);
+    let return_context = match fcx.llreturn {
+        Some(llreturn) => raw_block(fcx, false, llreturn),
+        None => bcx
+    };
 
     let llfunctiontype = val_ty(llwrapfn);
     let llfunctiontype = llfunctiontype.element_type();
@@ -388,7 +394,6 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
                                      tys.ret_def,
                                      llargbundle,
                                      llretval);
-            build_return(bcx);
         }
 
         let lname = link_name(ccx, foreign_item);
@@ -438,8 +443,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
         if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
             Store(bcx, retval, fcx.llretptr.get());
         }
-        build_return(bcx);
-        finish_fn(fcx, lltop);
+        finish_fn(fcx, lltop, bcx);
     }
 
     // FIXME (#2535): this is very shaky and probably gets ABIs wrong all
@@ -467,8 +471,7 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
         if !ty::type_is_nil(ret_ty) && !ty::type_is_bot(ret_ty) {
             Store(bcx, retval, fcx.llretptr.get());
         }
-        build_return(bcx);
-        finish_fn(fcx, lltop);
+        finish_fn(fcx, lltop, bcx);
     }
 
     fn build_wrap_fn(ccx: @mut CrateContext,
@@ -534,7 +537,6 @@ pub fn trans_foreign_mod(ccx: @mut CrateContext,
                 let llretptr = load_inbounds(bcx, llargbundle, [0, arg_count]);
                 Store(bcx, Load(bcx, llretptr), retptr);
             }
-            build_return(bcx);
         }
     }
 }
@@ -629,8 +631,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
             }
         }
 
-        build_return(bcx);
-        finish_fn(fcx, lltop);
+        finish_fn(fcx, lltop, bcx);
 
         return;
     }
@@ -1124,8 +1125,7 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
             ccx.sess.span_bug(item.span, "unknown intrinsic");
         }
     }
-    build_return(bcx);
-    finish_fn(fcx, lltop);
+    finish_fn(fcx, lltop, bcx);
 }
 
 /**
@@ -1257,8 +1257,6 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext,
                 // NB: The return pointer in the Rust ABI function is wired
                 // directly into the return slot in the shim struct.
             }
-
-            build_return(bcx);
         }
 
         let shim_name = link::mangle_internal_name_by_path(
@@ -1314,7 +1312,6 @@ pub fn trans_foreign_fn(ccx: @mut CrateContext,
         fn build_ret(bcx: block, tys: &ShimTypes, llargbundle: ValueRef) {
             let _icx = push_ctxt("foreign::foreign::wrap::build_ret");
             tys.fn_ty.build_wrap_ret(bcx, tys.llsig.llarg_tys, llargbundle);
-            build_return(bcx);
         }
     }
 
diff --git a/src/librustc/middle/trans/glue.rs b/src/librustc/middle/trans/glue.rs
index b6f226683df..418c89e603d 100644
--- a/src/librustc/middle/trans/glue.rs
+++ b/src/librustc/middle/trans/glue.rs
@@ -348,9 +348,9 @@ pub fn call_tydesc_glue(cx: block, v: ValueRef, t: ty::t, field: uint)
     return cx;
 }
 
-pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
+pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
     let _icx = push_ctxt("make_visit_glue");
-    let bcx = do with_scope(bcx, None, "visitor cleanup") |bcx| {
+    do with_scope(bcx, None, "visitor cleanup") |bcx| {
         let mut bcx = bcx;
         let (visitor_trait, object_ty) = ty::visitor_object_ty(bcx.tcx());
         let v = PointerCast(bcx, v, type_of::type_of(bcx.ccx(), object_ty).ptr_to());
@@ -358,14 +358,13 @@ pub fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
         // The visitor is a boxed object and needs to be dropped
         add_clean(bcx, v, object_ty);
         bcx
-    };
-    build_return(bcx);
+    }
 }
 
-pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
+pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
     // NB: v0 is an *alias* of type t here, not a direct value.
     let _icx = push_ctxt("make_free_glue");
-    let bcx = match ty::get(t).sty {
+    match ty::get(t).sty {
       ty::ty_box(body_mt) => {
         let v = Load(bcx, v);
         let body = GEPi(bcx, v, [0u, abi::box_field_body]);
@@ -389,9 +388,7 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
         tvec::make_uniq_free_glue(bcx, v, t)
       }
       ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
-        make_free_glue(bcx, v,
-                       tvec::expand_boxed_vec_ty(bcx.tcx(), t));
-        return;
+        make_free_glue(bcx, v, tvec::expand_boxed_vec_ty(bcx.tcx(), t))
       }
       ty::ty_closure(_) => {
         closure::make_closure_glue(bcx, v, t, free_ty)
@@ -400,8 +397,7 @@ pub fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
         closure::make_opaque_cbox_free_glue(bcx, ck, v)
       }
       _ => bcx
-    };
-    build_return(bcx);
+    }
 }
 
 pub fn trans_struct_drop_flag(bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::def_id,
@@ -475,11 +471,11 @@ pub fn trans_struct_drop(mut bcx: block, t: ty::t, v0: ValueRef, dtor_did: ast::
     bcx
 }
 
-pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
+pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) -> block {
     // NB: v0 is an *alias* of type t here, not a direct value.
     let _icx = push_ctxt("make_drop_glue");
     let ccx = bcx.ccx();
-    let bcx = match ty::get(t).sty {
+    match ty::get(t).sty {
       ty::ty_box(_) | ty::ty_opaque_box |
       ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) => {
         decr_refcnt_maybe_free(bcx, Load(bcx, v0), Some(v0), t)
@@ -542,8 +538,7 @@ pub fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
             iter_structural_ty(bcx, v0, t, drop_ty)
         } else { bcx }
       }
-    };
-    build_return(bcx);
+    }
 }
 
 // box_ptr_ptr is optional, it is constructed if not supplied.
@@ -569,10 +564,10 @@ pub fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef,
 }
 
 
-pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
+pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) -> block {
     let _icx = push_ctxt("make_take_glue");
     // NB: v is a *pointer* to type t here, not a direct value.
-    let bcx = match ty::get(t).sty {
+    match ty::get(t).sty {
       ty::ty_box(_) | ty::ty_opaque_box |
       ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) => {
         incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
@@ -638,9 +633,7 @@ pub fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
         iter_structural_ty(bcx, v, t, take_ty)
       }
       _ => bcx
-    };
-
-    build_return(bcx);
+    }
 }
 
 pub fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
@@ -690,7 +683,7 @@ pub fn declare_tydesc(ccx: &mut CrateContext, t: ty::t) -> @mut tydesc_info {
     return inf;
 }
 
-pub type glue_helper<'self> = &'self fn(block, ValueRef, ty::t);
+pub type glue_helper<'self> = &'self fn(block, ValueRef, ty::t) -> block;
 
 pub fn declare_generic_glue(ccx: &mut CrateContext, t: ty::t, llfnty: Type,
                             name: &str) -> ValueRef {
@@ -723,11 +716,9 @@ pub fn make_generic_glue_inner(ccx: @mut CrateContext,
     let llrawptr0 = unsafe { llvm::LLVMGetParam(llfn, rawptr0_arg as c_uint) };
     let llty = type_of(ccx, t);
     let llrawptr0 = PointerCast(bcx, llrawptr0, llty.ptr_to());
-    helper(bcx, llrawptr0, t);
+    let bcx = helper(bcx, llrawptr0, t);
 
-    // This is from the general finish fn, but that emits a ret {} that we don't want
-    Br(raw_block(fcx, false, fcx.llstaticallocas), lltop);
-    RetVoid(raw_block(fcx, false, fcx.llreturn));
+    finish_fn(fcx, lltop, bcx);
 
     return llfn;
 }
diff --git a/src/librustc/middle/trans/reflect.rs b/src/librustc/middle/trans/reflect.rs
index a3b544dbc61..dee40f32169 100644
--- a/src/librustc/middle/trans/reflect.rs
+++ b/src/librustc/middle/trans/reflect.rs
@@ -299,12 +299,15 @@ impl Reflector {
                     //
                     llvm::LLVMGetParam(llfdecl, fcx.arg_pos(0u) as c_uint)
                 };
-                let bcx = top_scope_block(fcx, None);
+                let mut bcx = top_scope_block(fcx, None);
                 let arg = BitCast(bcx, arg, llptrty);
                 let ret = adt::trans_get_discr(bcx, repr, arg);
                 Store(bcx, ret, fcx.llretptr.get());
-                cleanup_and_Br(bcx, bcx, fcx.llreturn);
-                finish_fn(fcx, bcx.llbb);
+                match fcx.llreturn {
+                    Some(llreturn) => cleanup_and_Br(bcx, bcx, llreturn),
+                    None => bcx = cleanup_block(bcx, Some(bcx.llbb))
+                };
+                finish_fn(fcx, bcx.llbb, bcx);
                 llfdecl
             };