Skip to content

Commit ab8fff2

Browse files
trans: Collect drop-glue translation item for closure env in fn-once-adapters.
1 parent 07191e2 commit ab8fff2

File tree

2 files changed

+110
-20
lines changed

2 files changed

+110
-20
lines changed

src/librustc_trans/callee.rs

+24-9
Original file line numberDiff line numberDiff line change
@@ -235,18 +235,37 @@ fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
235235
trait_closure_kind={:?}, llfn={:?})",
236236
llfn_closure_kind, trait_closure_kind, Value(llfn));
237237

238-
match (llfn_closure_kind, trait_closure_kind) {
238+
match needs_fn_once_adapter_shim(llfn_closure_kind, trait_closure_kind) {
239+
Ok(true) => trans_fn_once_adapter_shim(ccx,
240+
def_id,
241+
substs,
242+
method_instance,
243+
llfn),
244+
Ok(false) => llfn,
245+
Err(()) => {
246+
bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
247+
llfn_closure_kind,
248+
trait_closure_kind);
249+
}
250+
}
251+
}
252+
253+
pub fn needs_fn_once_adapter_shim(actual_closure_kind: ty::ClosureKind,
254+
trait_closure_kind: ty::ClosureKind)
255+
-> Result<bool, ()>
256+
{
257+
match (actual_closure_kind, trait_closure_kind) {
239258
(ty::ClosureKind::Fn, ty::ClosureKind::Fn) |
240259
(ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) |
241260
(ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => {
242261
// No adapter needed.
243-
llfn
262+
Ok(false)
244263
}
245264
(ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => {
246265
// The closure fn `llfn` is a `fn(&self, ...)`. We want a
247266
// `fn(&mut self, ...)`. In fact, at trans time, these are
248267
// basically the same thing, so we can just return llfn.
249-
llfn
268+
Ok(false)
250269
}
251270
(ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) |
252271
(ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => {
@@ -258,13 +277,9 @@ fn trans_closure_method<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
258277
// fn call_once(mut self, ...) { call_mut(&mut self, ...) }
259278
//
260279
// These are both the same at trans time.
261-
trans_fn_once_adapter_shim(ccx, def_id, substs, method_instance, llfn)
262-
}
263-
_ => {
264-
bug!("trans_closure_adapter_shim: cannot convert {:?} to {:?}",
265-
llfn_closure_kind,
266-
trait_closure_kind);
280+
Ok(true)
267281
}
282+
_ => Err(()),
268283
}
269284
}
270285

src/librustc_trans/collector.rs

+86-11
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ use rustc::mir::visit::Visitor as MirVisitor;
205205
use syntax::abi::Abi;
206206
use syntax_pos::DUMMY_SP;
207207
use base::custom_coerce_unsize_info;
208+
use callee::needs_fn_once_adapter_shim;
208209
use context::SharedCrateContext;
209210
use common::fulfill_obligation;
210211
use glue::{self, DropGlueKind};
@@ -568,7 +569,11 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
568569
callee_substs,
569570
self.param_substs);
570571

571-
if let Some((callee_def_id, callee_substs)) = dispatched {
572+
if let StaticDispatchResult::Dispatched {
573+
def_id: callee_def_id,
574+
substs: callee_substs,
575+
fn_once_adjustment,
576+
} = dispatched {
572577
// if we have a concrete impl (which we might not have
573578
// in the case of something compiler generated like an
574579
// object shim or a closure that is handled differently),
@@ -581,6 +586,17 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
581586
callee_substs,
582587
self.param_substs);
583588
self.output.push(trans_item);
589+
590+
// This call will instantiate an FnOnce adapter, which drops
591+
// the closure environment. Therefore we need to make sure
592+
// that we collect the drop-glue for the environment type.
593+
if let Some(env_ty) = fn_once_adjustment {
594+
let env_ty = glue::get_drop_glue_type(self.scx, env_ty);
595+
if self.scx.type_needs_drop(env_ty) {
596+
let dg = DropGlueKind::Ty(env_ty);
597+
self.output.push(TransItem::DropGlue(dg));
598+
}
599+
}
584600
}
585601
}
586602
}
@@ -793,15 +809,13 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
793809
bug!("encountered unexpected type");
794810
}
795811
}
796-
797-
798812
}
799813

800814
fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
801815
fn_def_id: DefId,
802816
fn_substs: &'tcx Substs<'tcx>,
803817
param_substs: &'tcx Substs<'tcx>)
804-
-> Option<(DefId, &'tcx Substs<'tcx>)> {
818+
-> StaticDispatchResult<'tcx> {
805819
debug!("do_static_dispatch(fn_def_id={}, fn_substs={:?}, param_substs={:?})",
806820
def_id_to_string(scx.tcx(), fn_def_id),
807821
fn_substs,
@@ -818,18 +832,38 @@ fn do_static_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
818832
debug!(" => regular function");
819833
// The function is not part of an impl or trait, no dispatching
820834
// to be done
821-
Some((fn_def_id, fn_substs))
835+
StaticDispatchResult::Dispatched {
836+
def_id: fn_def_id,
837+
substs: fn_substs,
838+
fn_once_adjustment: None,
839+
}
822840
}
823841
}
824842

843+
enum StaticDispatchResult<'tcx> {
844+
// The call could be resolved statically as going to the method with
845+
// `def_id` and `substs`.
846+
Dispatched {
847+
def_id: DefId,
848+
substs: &'tcx Substs<'tcx>,
849+
850+
// If this is a call to a closure that needs an FnOnce adjustment,
851+
// this contains the new self type of the call (= type of the closure
852+
// environment)
853+
fn_once_adjustment: Option<ty::Ty<'tcx>>,
854+
},
855+
// This goes to somewhere that we don't know at compile-time
856+
Unknown
857+
}
858+
825859
// Given a trait-method and substitution information, find out the actual
826860
// implementation of the trait method.
827861
fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
828862
trait_method: &ty::AssociatedItem,
829863
trait_id: DefId,
830864
callee_substs: &'tcx Substs<'tcx>,
831865
param_substs: &'tcx Substs<'tcx>)
832-
-> Option<(DefId, &'tcx Substs<'tcx>)> {
866+
-> StaticDispatchResult<'tcx> {
833867
let tcx = scx.tcx();
834868
debug!("do_static_trait_method_dispatch(trait_method={}, \
835869
trait_id={}, \
@@ -850,17 +884,47 @@ fn do_static_trait_method_dispatch<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
850884
// the actual function:
851885
match vtbl {
852886
traits::VtableImpl(impl_data) => {
853-
Some(traits::find_method(tcx, trait_method.name, rcvr_substs, &impl_data))
887+
let (def_id, substs) = traits::find_method(tcx,
888+
trait_method.name,
889+
rcvr_substs,
890+
&impl_data);
891+
StaticDispatchResult::Dispatched {
892+
def_id: def_id,
893+
substs: substs,
894+
fn_once_adjustment: None,
895+
}
854896
}
855897
traits::VtableClosure(closure_data) => {
856-
Some((closure_data.closure_def_id, closure_data.substs.substs))
898+
let closure_def_id = closure_data.closure_def_id;
899+
let trait_closure_kind = tcx.lang_items.fn_trait_kind(trait_id).unwrap();
900+
let actual_closure_kind = tcx.closure_kind(closure_def_id);
901+
902+
let needs_fn_once_adapter_shim =
903+
match needs_fn_once_adapter_shim(actual_closure_kind,
904+
trait_closure_kind) {
905+
Ok(true) => true,
906+
_ => false,
907+
};
908+
909+
let fn_once_adjustment = if needs_fn_once_adapter_shim {
910+
Some(tcx.mk_closure_from_closure_substs(closure_def_id,
911+
closure_data.substs))
912+
} else {
913+
None
914+
};
915+
916+
StaticDispatchResult::Dispatched {
917+
def_id: closure_def_id,
918+
substs: closure_data.substs.substs,
919+
fn_once_adjustment: fn_once_adjustment,
920+
}
857921
}
858922
// Trait object and function pointer shims are always
859923
// instantiated in-place, and as they are just an ABI-adjusting
860924
// indirect call they do not have any dependencies.
861925
traits::VtableFnPointer(..) |
862926
traits::VtableObject(..) => {
863-
None
927+
StaticDispatchResult::Unknown
864928
}
865929
_ => {
866930
bug!("static call to invalid vtable: {:?}", vtbl)
@@ -994,8 +1058,19 @@ fn create_trans_items_for_vtable_methods<'a, 'tcx>(scx: &SharedCrateContext<'a,
9941058
// Walk all methods of the trait, including those of its supertraits
9951059
let methods = traits::get_vtable_methods(scx.tcx(), poly_trait_ref);
9961060
let methods = methods.filter_map(|method| method)
997-
.filter_map(|(def_id, substs)| do_static_dispatch(scx, def_id, substs,
998-
param_substs))
1061+
.filter_map(|(def_id, substs)| {
1062+
if let StaticDispatchResult::Dispatched {
1063+
def_id,
1064+
substs,
1065+
// We already add the drop-glue for the closure env
1066+
// unconditionally below.
1067+
fn_once_adjustment: _ ,
1068+
} = do_static_dispatch(scx, def_id, substs, param_substs) {
1069+
Some((def_id, substs))
1070+
} else {
1071+
None
1072+
}
1073+
})
9991074
.filter(|&(def_id, _)| can_have_local_instance(scx.tcx(), def_id))
10001075
.map(|(def_id, substs)| create_fn_trans_item(scx, def_id, substs, param_substs));
10011076
output.extend(methods);

0 commit comments

Comments
 (0)