diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs index d93482acbcb..aeb1fe079ff 100644 --- a/src/librustc/ty/instance.rs +++ b/src/librustc/ty/instance.rs @@ -34,10 +34,7 @@ pub enum InstanceDef<'tcx> { // ::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> { @@ -48,9 +45,8 @@ impl<'tcx> InstanceDef<'tcx> { 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 @@ impl<'tcx> fmt::Display for Instance<'tcx> { InstanceDef::FnPtrShim(_, ty) => { write!(f, " - shim({:?})", ty) } - InstanceDef::ClosureOnceShim { - call_once: _, closure_did - } => { - write!(f, " - shim({:?})", closure_did) + InstanceDef::ClosureOnceShim { .. } => { + write!(f, " - shim") } } } diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index 97c83c7a42e..35ad296006d 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -83,7 +83,25 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, 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, + ¶m_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); @@ -97,6 +115,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, enum Adjustment { Identity, Deref, + RefMut, } #[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); - 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 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 } - )) + )), + 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 { @@ -184,28 +222,57 @@ fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>, } 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, diff --git a/src/librustc_trans/callee.rs b/src/librustc_trans/callee.rs index 5c7be56b56d..4d0bd9fa201 100644 --- a/src/librustc_trans/callee.rs +++ b/src/librustc_trans/callee.rs @@ -14,142 +14,18 @@ //! 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::ty::subst::{Substs, Subst}; -use abi::{Abi, FnType}; +use rustc::ty::subst::Substs; use attributes; -use builder::Builder; use common::{self, CrateContext}; -use cleanup::CleanupScope; -use mir::lvalue::LvalueRef; use monomorphize; use consts; use declare; -use value::Value; use monomorphize::Instance; -use back::symbol_names::symbol_name; 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. @@ -157,11 +33,10 @@ fn trans_fn_once_adapter_shim<'a, 'tcx>( /// # 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(); @@ -248,40 +123,6 @@ fn do_get_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, 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>) diff --git a/src/librustc_trans/cleanup.rs b/src/librustc_trans/cleanup.rs index 5d89a67d3fd..2b2e5e85ea5 100644 --- a/src/librustc_trans/cleanup.rs +++ b/src/librustc_trans/cleanup.rs @@ -93,24 +93,6 @@ impl<'tcx> DropValue<'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 diff --git a/src/librustc_trans/collector.rs b/src/librustc_trans/collector.rs index 40a89783d91..f076fc47102 100644 --- a/src/librustc_trans/collector.rs +++ b/src/librustc_trans/collector.rs @@ -497,11 +497,9 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { 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!(), } @@ -601,20 +599,6 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, } 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); @@ -632,6 +616,7 @@ fn visit_fn_use<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, output.push(create_fn_trans_item(instance)); } } + ty::InstanceDef::ClosureOnceShim { .. } | 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 { - 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 @@ -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); - 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) } diff --git a/src/librustc_trans/mir/rvalue.rs b/src/librustc_trans/mir/rvalue.rs index 3832c21d10a..178347369c9 100644 --- a/src/librustc_trans/mir/rvalue.rs +++ b/src/librustc_trans/mir/rvalue.rs @@ -12,7 +12,6 @@ use llvm::{self, ValueRef}; 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; @@ -24,6 +23,7 @@ use common::{self, val_ty, C_bool, C_null, C_uint}; use common::{C_integral}; use adt; use machine; +use monomorphize; use type_::Type; use type_of; use tvec; @@ -193,22 +193,9 @@ impl<'a, 'tcx> MirContext<'a, 'tcx> { 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) diff --git a/src/librustc_trans/monomorphize.rs b/src/librustc_trans/monomorphize.rs index bf073d8b978..0d8aa0f4bda 100644 --- a/src/librustc_trans/monomorphize.rs +++ b/src/librustc_trans/monomorphize.rs @@ -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 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); @@ -54,6 +54,54 @@ fn fn_once_adapter_instance<'a, 'tcx>( Instance { def, substs } } +fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind, + trait_closure_kind: ty::ClosureKind) + -> Result +{ + 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. @@ -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 -{ - 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, @@ -180,16 +195,9 @@ fn resolve_associated_item<'a, 'tcx>( 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 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 { @@ -279,7 +287,6 @@ pub fn apply_param_substs<'a, 'tcx, T>(scx: &SharedCrateContext<'a, 'tcx>, 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>, diff --git a/src/test/run-pass/issue-29948.rs b/src/test/run-pass/issue-29948.rs index ec2b53313fa..281dde15bd3 100644 --- a/src/test/run-pass/issue-29948.rs +++ b/src/test/run-pass/issue-29948.rs @@ -8,6 +8,11 @@ // 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> { @@ -28,5 +33,15 @@ fn main() { 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); +}