]> git.lizzy.rs Git - rust.git/commitdiff
translate closure shims using MIR
authorAriel Ben-Yehuda <ariel.byd@gmail.com>
Wed, 8 Mar 2017 21:19:09 +0000 (23:19 +0200)
committerAriel Ben-Yehuda <ariel.byd@gmail.com>
Sat, 18 Mar 2017 00:53:07 +0000 (02:53 +0200)
src/librustc/ty/instance.rs
src/librustc_mir/shim.rs
src/librustc_trans/callee.rs
src/librustc_trans/cleanup.rs
src/librustc_trans/collector.rs
src/librustc_trans/mir/rvalue.rs
src/librustc_trans/monomorphize.rs
src/test/run-pass/issue-29948.rs

index d93482acbcb5775a10d7d41a5c87edef9bd9d17d..aeb1fe079ff25b4bc3162225030de3390cca94f9 100644 (file)
@@ -34,10 +34,7 @@ pub enum InstanceDef<'tcx> {
     // <Trait as Trait>::fn
     Virtual(DefId, usize),
     // <[mut closure] as FnOnce>::call_once
     // <Trait as Trait>::fn
     Virtual(DefId, usize),
     // <[mut closure] as FnOnce>::call_once
-    ClosureOnceShim {
-        call_once: DefId,
-        closure_did: DefId
-    },
+    ClosureOnceShim { call_once: DefId },
 }
 
 impl<'tcx> InstanceDef<'tcx> {
 }
 
 impl<'tcx> InstanceDef<'tcx> {
@@ -48,9 +45,8 @@ pub fn def_id(&self) -> DefId {
             InstanceDef::FnPtrShim(def_id, _) |
             InstanceDef::Virtual(def_id, _) |
             InstanceDef::Intrinsic(def_id, ) |
             InstanceDef::FnPtrShim(def_id, _) |
             InstanceDef::Virtual(def_id, _) |
             InstanceDef::Intrinsic(def_id, ) |
-            InstanceDef::ClosureOnceShim {
-                call_once: def_id, closure_did: _
-            } => def_id
+            InstanceDef::ClosureOnceShim { call_once: def_id }
+                => def_id
         }
     }
 
         }
     }
 
@@ -98,10 +94,8 @@ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
             InstanceDef::FnPtrShim(_, ty) => {
                 write!(f, " - shim({:?})", ty)
             }
             InstanceDef::FnPtrShim(_, ty) => {
                 write!(f, " - shim({:?})", ty)
             }
-            InstanceDef::ClosureOnceShim {
-                call_once: _, closure_did
-            } => {
-                write!(f, " - shim({:?})", closure_did)
+            InstanceDef::ClosureOnceShim { .. } => {
+                write!(f, " - shim")
             }
         }
     }
             }
         }
     }
index 97c83c7a42e28f368fda4cfe91cb4acefcac8f32..35ad296006dad29f36592c05193de9f236168ef2 100644 (file)
@@ -83,7 +83,25 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
                 None
             )
         }
                 None
             )
         }
-        _ => bug!("unknown shim kind")
+        ty::InstanceDef::ClosureOnceShim { call_once } => {
+            let fn_mut = tcx.lang_items.fn_mut_trait().unwrap();
+            let call_mut = tcx.global_tcx()
+                .associated_items(fn_mut)
+                .find(|it| it.kind == ty::AssociatedKind::Method)
+                .unwrap().def_id;
+
+            build_call_shim(
+                tcx,
+                &param_env,
+                call_once,
+                Adjustment::RefMut,
+                CallKind::Direct(call_mut),
+                None
+            )
+        }
+        ty::InstanceDef::Intrinsic(_) => {
+            bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
+        }
     };
     debug!("make_shim({:?}) = {:?}", instance, result);
 
     };
     debug!("make_shim({:?}) = {:?}", instance, result);
 
@@ -97,6 +115,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 enum Adjustment {
     Identity,
     Deref,
 enum Adjustment {
     Identity,
     Deref,
+    RefMut,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
 }
 
 #[derive(Copy, Clone, Debug, PartialEq)]
@@ -143,18 +162,37 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
 
     debug!("build_call_shim: sig={:?}", sig);
 
 
     debug!("build_call_shim: sig={:?}", sig);
 
-    let local_decls = local_decls_for_sig(&sig);
+    let mut local_decls = local_decls_for_sig(&sig);
     let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
 
     let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
 
-    let rcvr_l = Lvalue::Local(Local::new(1+0));
-
-    let return_block_id = BasicBlock::new(1);
+    let rcvr_arg = Local::new(1+0);
+    let rcvr_l = Lvalue::Local(rcvr_arg);
+    let mut statements = vec![];
 
     let rcvr = match rcvr_adjustment {
         Adjustment::Identity => Operand::Consume(rcvr_l),
         Adjustment::Deref => Operand::Consume(Lvalue::Projection(
             box Projection { base: rcvr_l, elem: ProjectionElem::Deref }
 
     let rcvr = match rcvr_adjustment {
         Adjustment::Identity => Operand::Consume(rcvr_l),
         Adjustment::Deref => Operand::Consume(Lvalue::Projection(
             box Projection { base: rcvr_l, elem: ProjectionElem::Deref }
-        ))
+        )),
+        Adjustment::RefMut => {
+            // let rcvr = &mut rcvr;
+            let re_erased = tcx.mk_region(ty::ReErased);
+            let ref_rcvr = local_decls.push(temp_decl(
+                Mutability::Not,
+                tcx.mk_ref(re_erased, ty::TypeAndMut {
+                    ty: sig.inputs()[0],
+                    mutbl: hir::Mutability::MutMutable
+                })
+            ));
+            statements.push(Statement {
+                source_info: source_info,
+                kind: StatementKind::Assign(
+                    Lvalue::Local(ref_rcvr),
+                    Rvalue::Ref(re_erased, BorrowKind::Mut, rcvr_l)
+                )
+            });
+            Operand::Consume(Lvalue::Local(ref_rcvr))
+        }
     };
 
     let (callee, mut args) = match call_kind {
     };
 
     let (callee, mut args) = match call_kind {
@@ -184,28 +222,57 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
     }
 
     let mut blocks = IndexVec::new();
     }
 
     let mut blocks = IndexVec::new();
-    blocks.push(BasicBlockData {
-        statements: vec![],
-        terminator: Some(Terminator {
-            source_info: source_info,
-            kind: TerminatorKind::Call {
-                func: callee,
-                args: args,
-                destination: Some((Lvalue::Local(RETURN_POINTER),
-                                   return_block_id)),
-                cleanup: None
+    let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
+        blocks.push(BasicBlockData {
+            statements,
+            terminator: Some(Terminator { source_info, kind }),
+            is_cleanup
+        })
+    };
+
+    let have_unwind = match (rcvr_adjustment, tcx.sess.no_landing_pads()) {
+        (Adjustment::RefMut, false) => true,
+        _ => false
+    };
+
+    // BB #0
+    block(&mut blocks, statements, TerminatorKind::Call {
+        func: callee,
+        args: args,
+        destination: Some((Lvalue::Local(RETURN_POINTER),
+                           BasicBlock::new(1))),
+        cleanup: if have_unwind {
+            Some(BasicBlock::new(3))
+        } else {
+            None
+        }
+    }, false);
+
+    if let Adjustment::RefMut = rcvr_adjustment {
+        // BB #1 - drop for Self
+        block(&mut blocks, vec![], TerminatorKind::Drop {
+            location: Lvalue::Local(rcvr_arg),
+            target: BasicBlock::new(2),
+            unwind: if have_unwind {
+                Some(BasicBlock::new(4))
+            } else {
+                None
             }
             }
-        }),
-        is_cleanup: false
-    });
-    blocks.push(BasicBlockData {
-        statements: vec![],
-        terminator: Some(Terminator {
-            source_info: source_info,
-            kind: TerminatorKind::Return
-        }),
-        is_cleanup: false
-    });
+        }, false);
+    }
+    // BB #1/#2 - return
+    block(&mut blocks, vec![], TerminatorKind::Return, false);
+    if have_unwind {
+        // BB #3 - drop if closure panics
+        block(&mut blocks, vec![], TerminatorKind::Drop {
+            location: Lvalue::Local(rcvr_arg),
+            target: BasicBlock::new(4),
+            unwind: None
+        }, true);
+
+        // BB #4 - resume
+        block(&mut blocks, vec![], TerminatorKind::Resume, true);
+    }
 
     let mut mir = Mir::new(
         blocks,
 
     let mut mir = Mir::new(
         blocks,
index 5c7be56b56dad21b384416f3be31968952790dbe..4d0bd9fa201d8db141b6457488019a89863625cb 100644 (file)
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
 //! and methods are represented as just a fn ptr and not a full
 //! closure.
 
-use llvm::{self, ValueRef, get_params};
+use llvm::{self, ValueRef};
 use rustc::hir::def_id::DefId;
 use rustc::hir::def_id::DefId;
-use rustc::ty::subst::{Substs, Subst};
-use abi::{Abi, FnType};
+use rustc::ty::subst::Substs;
 use attributes;
 use attributes;
-use builder::Builder;
 use common::{self, CrateContext};
 use common::{self, CrateContext};
-use cleanup::CleanupScope;
-use mir::lvalue::LvalueRef;
 use monomorphize;
 use consts;
 use declare;
 use monomorphize;
 use consts;
 use declare;
-use value::Value;
 use monomorphize::Instance;
 use monomorphize::Instance;
-use back::symbol_names::symbol_name;
 use trans_item::TransItem;
 use type_of;
 use trans_item::TransItem;
 use type_of;
-use rustc::ty::{self, TypeFoldable};
-use std::iter;
-
-use mir::lvalue::Alignment;
-
-fn trans_fn_once_adapter_shim<'a, 'tcx>(
-    ccx: &'a CrateContext<'a, 'tcx>,
-    def_id: DefId,
-    substs: ty::ClosureSubsts<'tcx>,
-    method_instance: Instance<'tcx>,
-    llreffn: ValueRef)
-    -> ValueRef
-{
-    if let Some(&llfn) = ccx.instances().borrow().get(&method_instance) {
-        return llfn;
-    }
-
-    debug!("trans_fn_once_adapter_shim(def_id={:?}, substs={:?}, llreffn={:?})",
-           def_id, substs, Value(llreffn));
-
-    let tcx = ccx.tcx();
-
-    // Find a version of the closure type. Substitute static for the
-    // region since it doesn't really matter.
-    let closure_ty = tcx.mk_closure_from_closure_substs(def_id, substs);
-    let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
-
-    // Make a version with the type of by-ref closure.
-    let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
-    let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
-    assert_eq!(sig.abi, Abi::RustCall);
-    let llref_fn_sig = tcx.mk_fn_sig(
-        iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()),
-        sig.output(),
-        sig.variadic,
-        sig.unsafety,
-        Abi::RustCall
-    );
-    let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(llref_fn_sig));
-    debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
-           llref_fn_ty);
-
-
-    // Make a version of the closure type with the same arguments, but
-    // with argument #0 being by value.
-    let sig = tcx.mk_fn_sig(
-        iter::once(closure_ty).chain(sig.inputs().iter().cloned()),
-        sig.output(),
-        sig.variadic,
-        sig.unsafety,
-        Abi::RustCall
-    );
-
-    let fn_ty = FnType::new(ccx, sig, &[]);
-    let llonce_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
-
-    // Create the by-value helper.
-    let function_name = symbol_name(method_instance, ccx.shared());
-    let lloncefn = declare::define_internal_fn(ccx, &function_name, llonce_fn_ty);
-    attributes::set_frame_pointer_elimination(ccx, lloncefn);
-
-    let orig_fn_ty = fn_ty;
-    let mut bcx = Builder::new_block(ccx, lloncefn, "entry-block");
-
-    // the first argument (`self`) will be the (by value) closure env.
-
-    let mut llargs = get_params(lloncefn);
-    let fn_ty = FnType::new(ccx, llref_fn_sig, &[]);
-    let self_idx = fn_ty.ret.is_indirect() as usize;
-    let env_arg = &orig_fn_ty.args[0];
-    let env = if env_arg.is_indirect() {
-        LvalueRef::new_sized_ty(llargs[self_idx], closure_ty, Alignment::AbiAligned)
-    } else {
-        let scratch = LvalueRef::alloca(&bcx, closure_ty, "self");
-        let mut llarg_idx = self_idx;
-        env_arg.store_fn_arg(&bcx, &mut llarg_idx, scratch.llval);
-        scratch
-    };
-
-    debug!("trans_fn_once_adapter_shim: env={:?}", env);
-    // Adjust llargs such that llargs[self_idx..] has the call arguments.
-    // For zero-sized closures that means sneaking in a new argument.
-    if env_arg.is_ignore() {
-        llargs.insert(self_idx, env.llval);
-    } else {
-        llargs[self_idx] = env.llval;
-    }
-
-    // Call the by-ref closure body with `self` in a cleanup scope,
-    // to drop `self` when the body returns, or in case it unwinds.
-    let self_scope = CleanupScope::schedule_drop_mem(&bcx, env);
-
-    let llret;
-    if let Some(landing_pad) = self_scope.landing_pad {
-        let normal_bcx = bcx.build_sibling_block("normal-return");
-        llret = bcx.invoke(llreffn, &llargs[..], normal_bcx.llbb(), landing_pad, None);
-        bcx = normal_bcx;
-    } else {
-        llret = bcx.call(llreffn, &llargs[..], None);
-    }
-    fn_ty.apply_attrs_callsite(llret);
-
-    if sig.output().is_never() {
-        bcx.unreachable();
-    } else {
-        self_scope.trans(&bcx);
-
-        if fn_ty.ret.is_indirect() || fn_ty.ret.is_ignore() {
-            bcx.ret_void();
-        } else {
-            bcx.ret(llret);
-        }
-    }
-
-    ccx.instances().borrow_mut().insert(method_instance, lloncefn);
-
-    lloncefn
-}
-
+use rustc::ty::TypeFoldable;
 
 /// Translates a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
 
 /// Translates a reference to a fn/method item, monomorphizing and
 /// inlining as it goes.
@@ -157,11 +33,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>(
 /// # Parameters
 ///
 /// - `ccx`: the crate context
 /// # Parameters
 ///
 /// - `ccx`: the crate context
-/// - `def_id`: def id of the fn or method item being referenced
-/// - `substs`: values for each of the fn/method's parameters
-fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                       instance: Instance<'tcx>)
-                       -> ValueRef
+/// - `instance`: the instance to be instantiated
+pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+                        instance: Instance<'tcx>)
+                        -> ValueRef
 {
     let tcx = ccx.tcx();
 
 {
     let tcx = ccx.tcx();
 
@@ -248,40 +123,6 @@ fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
     llfn
 }
 
     llfn
 }
 
-pub fn get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                        instance: Instance<'tcx>)
-                        -> ValueRef
-{
-    match instance.def {
-        ty::InstanceDef::Intrinsic(_) => {
-            bug!("intrinsic {} getting reified", instance)
-        }
-        ty::InstanceDef::ClosureOnceShim { .. } => {
-            let closure_ty = instance.substs.type_at(0);
-            let (closure_def_id, closure_substs) = match closure_ty.sty {
-                ty::TyClosure(def_id, substs) => (def_id, substs),
-                _ => bug!("bad closure instance {:?}", instance)
-            };
-
-            trans_fn_once_adapter_shim(
-                ccx,
-                closure_def_id,
-                closure_substs,
-                instance,
-                do_get_fn(
-                    ccx,
-                    Instance::new(closure_def_id, closure_substs.substs)
-                )
-            )
-        }
-        ty::InstanceDef::FnPtrShim(..) |
-        ty::InstanceDef::Item(..) |
-        ty::InstanceDef::Virtual(..) => {
-            do_get_fn(ccx, instance)
-        }
-    }
-}
-
 pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     def_id: DefId,
                                     substs: &'tcx Substs<'tcx>)
 pub fn resolve_and_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
                                     def_id: DefId,
                                     substs: &'tcx Substs<'tcx>)
index 5d89a67d3fd80890029273f3c6b01bfc64c406ac..2b2e5e85ea50d3d604ba05512cbc5ad5b2d46a7f 100644 (file)
@@ -93,24 +93,6 @@ fn get_landing_pad<'a>(&self, bcx: &Builder<'a, 'tcx>) -> BasicBlockRef {
 }
 
 impl<'a, 'tcx> CleanupScope<'tcx> {
 }
 
 impl<'a, 'tcx> CleanupScope<'tcx> {
-    /// Schedules a (deep) drop of `val`, which is a pointer to an instance of `ty`
-    pub fn schedule_drop_mem(
-        bcx: &Builder<'a, 'tcx>, val: LvalueRef<'tcx>
-    ) -> CleanupScope<'tcx> {
-        if let LvalueTy::Downcast { .. } = val.ty {
-            bug!("Cannot drop downcast ty yet");
-        }
-        if !bcx.ccx.shared().type_needs_drop(val.ty.to_ty(bcx.tcx())) {
-            return CleanupScope::noop();
-        }
-        let drop = DropValue {
-            val: val,
-            skip_dtor: false,
-        };
-
-        CleanupScope::new(bcx, drop)
-    }
-
     /// Issue #23611: Schedules a (deep) drop of the contents of
     /// `val`, which is a pointer to an instance of struct/enum type
     /// `ty`. The scheduled code handles extracting the discriminant
     /// Issue #23611: Schedules a (deep) drop of the contents of
     /// `val`, which is a pointer to an instance of struct/enum type
     /// `ty`. The scheduled code handles extracting the discriminant
index 40a89783d91cfee51c84915ee4cf7f290d1b9db9..f076fc4710222a50bca3767fb79ae818fd528d87 100644 (file)
@@ -497,11 +497,9 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
                 let source_ty = operand.ty(self.mir, self.scx.tcx());
                 match source_ty.sty {
                     ty::TyClosure(def_id, substs) => {
                 let source_ty = operand.ty(self.mir, self.scx.tcx());
                 match source_ty.sty {
                     ty::TyClosure(def_id, substs) => {
-                        let substs = monomorphize::apply_param_substs(
-                            self.scx, self.param_substs, &substs.substs);
-                        self.output.push(create_fn_trans_item(
-                            Instance::new(def_id, substs)
-                        ));
+                        let instance = monomorphize::resolve_closure(
+                            self.scx, def_id, substs, ty::ClosureKind::FnOnce);
+                        self.output.push(create_fn_trans_item(instance));
                     }
                     _ => bug!(),
                 }
                     }
                     _ => bug!(),
                 }
@@ -601,20 +599,6 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     }
 
     match instance.def {
     }
 
     match instance.def {
-        ty::InstanceDef::ClosureOnceShim { .. } => {
-            // This call will instantiate an FnOnce adapter, which
-            // drops the closure environment. Therefore we need to
-            // make sure that we collect the drop-glue for the
-            // environment type along with the instance.
-
-            let env_ty = instance.substs.type_at(0);
-            let env_ty = glue::get_drop_glue_type(scx, env_ty);
-            if scx.type_needs_drop(env_ty) {
-                let dg = DropGlueKind::Ty(env_ty);
-                output.push(TransItem::DropGlue(dg));
-            }
-            output.push(create_fn_trans_item(instance));
-        }
         ty::InstanceDef::Intrinsic(..) => {
             if !is_direct_call {
                 bug!("intrinsic {:?} being reified", ty);
         ty::InstanceDef::Intrinsic(..) => {
             if !is_direct_call {
                 bug!("intrinsic {:?} being reified", ty);
@@ -632,6 +616,7 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
                 output.push(create_fn_trans_item(instance));
             }
         }
                 output.push(create_fn_trans_item(instance));
             }
         }
+        ty::InstanceDef::ClosureOnceShim { .. } |
         ty::InstanceDef::Item(..) |
         ty::InstanceDef::FnPtrShim(..) => {
             output.push(create_fn_trans_item(instance));
         ty::InstanceDef::Item(..) |
         ty::InstanceDef::FnPtrShim(..) => {
             output.push(create_fn_trans_item(instance));
@@ -645,10 +630,8 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>)
                                   -> bool {
     let def_id = match instance.def {
 fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: &Instance<'tcx>)
                                   -> bool {
     let def_id = match instance.def {
-        ty::InstanceDef::Item(def_id) |
-        ty::InstanceDef::ClosureOnceShim {
-            call_once: _, closure_did: def_id
-        } => def_id,
+        ty::InstanceDef::Item(def_id) => def_id,
+        ty::InstanceDef::ClosureOnceShim { .. } |
         ty::InstanceDef::Virtual(..) |
         ty::InstanceDef::FnPtrShim(..) |
         ty::InstanceDef::Intrinsic(_) => return true
         ty::InstanceDef::Virtual(..) |
         ty::InstanceDef::FnPtrShim(..) |
         ty::InstanceDef::Intrinsic(_) => return true
@@ -885,20 +868,6 @@ fn find_vtable_types_for_unsizing<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
 fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> {
     debug!("create_fn_trans_item(instance={})", instance);
 
 fn create_fn_trans_item<'a, 'tcx>(instance: Instance<'tcx>) -> TransItem<'tcx> {
     debug!("create_fn_trans_item(instance={})", instance);
-    let instance = match instance.def {
-        ty::InstanceDef::ClosureOnceShim { .. } => {
-            // HACK: don't create ClosureOnce trans items for now
-            // have someone else generate the drop glue
-            let closure_ty = instance.substs.type_at(0);
-            match closure_ty.sty {
-                ty::TyClosure(def_id, substs) => {
-                    Instance::new(def_id, substs.substs)
-                }
-                _ => bug!("bad closure instance {:?}", instance)
-            }
-        }
-        _ => instance
-    };
     TransItem::Fn(instance)
 }
 
     TransItem::Fn(instance)
 }
 
index 3832c21d10a49c094d3efda5d39aa664b17edfe3..178347369c91551b38cffddf6b62b51d79b0c581 100644 (file)
@@ -12,7 +12,6 @@
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::layout::Layout;
 use rustc::ty::{self, Ty};
 use rustc::ty::cast::{CastTy, IntTy};
 use rustc::ty::layout::Layout;
-use rustc::ty::subst::{Kind, Subst};
 use rustc::mir::tcx::LvalueTy;
 use rustc::mir;
 use middle::lang_items::ExchangeMallocFnLangItem;
 use rustc::mir::tcx::LvalueTy;
 use rustc::mir;
 use middle::lang_items::ExchangeMallocFnLangItem;
@@ -24,6 +23,7 @@
 use common::{C_integral};
 use adt;
 use machine;
 use common::{C_integral};
 use adt;
 use machine;
+use monomorphize;
 use type_::Type;
 use type_of;
 use tvec;
 use type_::Type;
 use type_of;
 use tvec;
@@ -193,22 +193,9 @@ pub fn trans_rvalue_operand(&mut self,
                     mir::CastKind::ClosureFnPointer => {
                         match operand.ty.sty {
                             ty::TyClosure(def_id, substs) => {
                     mir::CastKind::ClosureFnPointer => {
                         match operand.ty.sty {
                             ty::TyClosure(def_id, substs) => {
-                                // Get the def_id for FnOnce::call_once
-                                let fn_once = bcx.tcx().lang_items.fn_once_trait().unwrap();
-                                let call_once = bcx.tcx()
-                                    .global_tcx().associated_items(fn_once)
-                                    .find(|it| it.kind == ty::AssociatedKind::Method)
-                                    .unwrap().def_id;
-                                // Now create its substs [Closure, Tuple]
-                                let input = bcx.tcx().closure_type(def_id)
-                                    .subst(bcx.tcx(), substs.substs).input(0);
-                                let input =
-                                    bcx.tcx().erase_late_bound_regions_and_normalize(&input);
-                                let substs = bcx.tcx().mk_substs([operand.ty, input]
-                                    .iter().cloned().map(Kind::from));
-                                OperandValue::Immediate(
-                                    callee::resolve_and_get_fn(bcx.ccx, call_once, substs)
-                                )
+                                let instance = monomorphize::resolve_closure(
+                                    bcx.ccx.shared(), def_id, substs, ty::ClosureKind::FnOnce);
+                                OperandValue::Immediate(callee::get_fn(bcx.ccx, instance))
                             }
                             _ => {
                                 bug!("{} cannot be cast to a fn ptr", operand.ty)
                             }
                             _ => {
                                 bug!("{} cannot be cast to a fn ptr", operand.ty)
index bf073d8b97844c58682460c120a380978ed963b0..0d8aa0f4bda0ea0d7fe0a14939a41b484e0a9362 100644 (file)
@@ -37,7 +37,7 @@ fn fn_once_adapter_instance<'a, 'tcx>(
     let call_once = tcx.associated_items(fn_once)
         .find(|it| it.kind == ty::AssociatedKind::Method)
         .unwrap().def_id;
     let call_once = tcx.associated_items(fn_once)
         .find(|it| it.kind == ty::AssociatedKind::Method)
         .unwrap().def_id;
-    let def = ty::InstanceDef::ClosureOnceShim { call_once, closure_did };
+    let def = ty::InstanceDef::ClosureOnceShim { call_once };
 
     let self_ty = tcx.mk_closure_from_closure_substs(
         closure_did, substs);
 
     let self_ty = tcx.mk_closure_from_closure_substs(
         closure_did, substs);
@@ -54,6 +54,54 @@ fn fn_once_adapter_instance<'a, 'tcx>(
     Instance { def, substs }
 }
 
     Instance { def, substs }
 }
 
+fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
+                              trait_closure_kind: ty::ClosureKind)
+                              -> Result<bool, ()>
+{
+    match (actual_closure_kind, trait_closure_kind) {
+        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
+        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
+        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
+            // No adapter needed.
+           Ok(false)
+        }
+        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
+            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
+            // `fn(&mut self, ...)`. In fact, at trans time, these are
+            // basically the same thing, so we can just return llfn.
+            Ok(false)
+        }
+        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
+        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
+            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
+            // self, ...)`.  We want a `fn(self, ...)`. We can produce
+            // this by doing something like:
+            //
+            //     fn call_once(self, ...) { call_mut(&self, ...) }
+            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
+            //
+            // These are both the same at trans time.
+            Ok(true)
+        }
+        _ => Err(()),
+    }
+}
+
+pub fn resolve_closure<'a, 'tcx> (
+    scx: &SharedCrateContext<'a, 'tcx>,
+    def_id: DefId,
+    substs: ty::ClosureSubsts<'tcx>,
+    requested_kind: ty::ClosureKind)
+    -> Instance<'tcx>
+{
+    let actual_kind = scx.tcx().closure_kind(def_id);
+
+    match needs_fn_once_adapter_shim(actual_kind, requested_kind) {
+        Ok(true) => fn_once_adapter_instance(scx.tcx(), def_id, substs),
+        _ => Instance::new(def_id, substs.substs)
+    }
+}
+
 /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we
 /// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
 /// guarantee to us that all nested obligations *could be* resolved if we wanted to.
 /// Attempts to resolve an obligation. The result is a shallow vtable resolution -- meaning that we
 /// do not (necessarily) resolve all nested obligations on the impl. Note that type check should
 /// guarantee to us that all nested obligations *could be* resolved if we wanted to.
@@ -121,39 +169,6 @@ fn fulfill_obligation<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
     })
 }
 
     })
 }
 
-fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
-                              trait_closure_kind: ty::ClosureKind)
-                              -> Result<bool, ()>
-{
-    match (actual_closure_kind, trait_closure_kind) {
-        (ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
-        (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
-        (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
-            // No adapter needed.
-           Ok(false)
-        }
-        (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
-            // The closure fn `llfn` is a `fn(&self, ...)`.  We want a
-            // `fn(&mut self, ...)`. In fact, at trans time, these are
-            // basically the same thing, so we can just return llfn.
-            Ok(false)
-        }
-        (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
-        (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
-            // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut
-            // self, ...)`.  We want a `fn(self, ...)`. We can produce
-            // this by doing something like:
-            //
-            //     fn call_once(self, ...) { call_mut(&self, ...) }
-            //     fn call_once(mut self, ...) { call_mut(&mut self, ...) }
-            //
-            // These are both the same at trans time.
-            Ok(true)
-        }
-        _ => Err(()),
-    }
-}
-
 fn resolve_associated_item<'a, 'tcx>(
     scx: &SharedCrateContext<'a, 'tcx>,
     trait_item: &ty::AssociatedItem,
 fn resolve_associated_item<'a, 'tcx>(
     scx: &SharedCrateContext<'a, 'tcx>,
     trait_item: &ty::AssociatedItem,
@@ -180,16 +195,9 @@ fn resolve_associated_item<'a, 'tcx>(
             ty::Instance::new(def_id, substs)
         }
         traits::VtableClosure(closure_data) => {
             ty::Instance::new(def_id, substs)
         }
         traits::VtableClosure(closure_data) => {
-            let closure_def_id = closure_data.closure_def_id;
             let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
             let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
-            let actual_closure_kind = tcx.closure_kind(closure_def_id);
-
-            match needs_fn_once_adapter_shim(actual_closure_kind,
-                                             trait_closure_kind) {
-                Ok(true) => fn_once_adapter_instance(
-                    tcx, closure_def_id, closure_data.substs),
-                _ => Instance::new(closure_def_id, closure_data.substs.substs),
-            }
+            resolve_closure(scx, closure_data.closure_def_id, closure_data.substs,
+                            trait_closure_kind)
         }
         traits::VtableFnPointer(ref data) => {
             Instance {
         }
         traits::VtableFnPointer(ref data) => {
             Instance {
@@ -279,7 +287,6 @@ pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>,
     AssociatedTypeNormalizer::new(scx).fold(&substituted)
 }
 
     AssociatedTypeNormalizer::new(scx).fold(&substituted)
 }
 
-
 /// Returns the normalized type of a struct field
 pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           param_substs: &Substs<'tcx>,
 /// Returns the normalized type of a struct field
 pub fn field_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           param_substs: &Substs<'tcx>,
index ec2b53313faa79be4c062f3f704c6978a449eff7..281dde15bd336e4d45a2022e6c158e1db3e71aa1 100644 (file)
@@ -8,6 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use std::panic;
+
+impl<'a> panic::UnwindSafe for Foo<'a> {}
+impl<'a> panic::RefUnwindSafe for Foo<'a> {}
+
 struct Foo<'a>(&'a mut bool);
 
 impl<'a> Drop for Foo<'a> {
 struct Foo<'a>(&'a mut bool);
 
 impl<'a> Drop for Foo<'a> {
@@ -28,5 +33,15 @@ fn main() {
         f(x);
     }
     assert!(ran_drop);
         f(x);
     }
     assert!(ran_drop);
-}
 
 
+    let mut ran_drop = false;
+    {
+        let x = Foo(&mut ran_drop);
+        let result = panic::catch_unwind(move || {
+            let x = move || { let _ = x; panic!() };
+            f(x);
+        });
+        assert!(result.is_err());
+    }
+    assert!(ran_drop);
+}