Skip to content

Fix monomorphization of unboxed closures #18144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/librustc/metadata/tydecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -465,9 +465,12 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
return ty::mk_struct(st.tcx, did, substs);
}
'k' => {
assert_eq!(next(st), '[');
let did = parse_def(st, NominalType, |x,y| conv(x,y));
let region = parse_region(st, conv);
return ty::mk_unboxed_closure(st.tcx, did, region);
let region = parse_region(st, |x,y| conv(x,y));
let substs = parse_substs(st, |x,y| conv(x,y));
assert_eq!(next(st), ']');
return ty::mk_unboxed_closure(st.tcx, did, region, substs);
}
'e' => {
return ty::mk_err();
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/metadata/tyencode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,11 @@ fn enc_sty(w: &mut SeekableMemWriter, cx: &ctxt, st: &ty::sty) {
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
ty::ty_unboxed_closure(def, region) => {
mywrite!(w, "k{}", (cx.ds)(def));
ty::ty_unboxed_closure(def, region, ref substs) => {
mywrite!(w, "k[{}|", (cx.ds)(def));
enc_region(w, cx, region);
enc_substs(w, cx, substs);
mywrite!(w, "]");
}
ty::ty_err => {
mywrite!(w, "e");
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,7 @@ impl<'t,'tcx,TYPER:Typer<'tcx>> MemCategorizationContext<'t,TYPER> {
};
self.cat_upvar(id, span, var_id, fn_node_id, kind, mode, false)
}
ty::ty_unboxed_closure(closure_id, _) => {
ty::ty_unboxed_closure(closure_id, _, _) => {
let unboxed_closures = self.typer.unboxed_closures().borrow();
let kind = (*unboxed_closures)[closure_id].kind;
let mode = self.typer.capture_mode(fn_node_id);
Expand Down
31 changes: 18 additions & 13 deletions src/librustc/middle/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ enum Candidate {
BuiltinCandidate(ty::BuiltinBound),
ParamCandidate(VtableParamData),
ImplCandidate(ast::DefId),
UnboxedClosureCandidate(/* closure */ ast::DefId),
UnboxedClosureCandidate(/* closure */ ast::DefId, Substs),
ErrorCandidate,
}

Expand Down Expand Up @@ -995,8 +995,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};

let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
let closure_def_id = match ty::get(self_ty).sty {
ty::ty_unboxed_closure(id, _) => id,
let (closure_def_id, substs) = match ty::get(self_ty).sty {
ty::ty_unboxed_closure(id, _, ref substs) => (id, substs.clone()),
ty::ty_infer(ty::TyVar(_)) => {
candidates.ambiguous = true;
return Ok(());
Expand All @@ -1019,7 +1019,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
};

if closure_kind == kind {
candidates.vec.push(UnboxedClosureCandidate(closure_def_id));
candidates.vec.push(UnboxedClosureCandidate(closure_def_id, substs.clone()));
}

Ok(())
Expand Down Expand Up @@ -1383,7 +1383,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(If(tys.clone()))
}

ty::ty_unboxed_closure(def_id, _) => {
ty::ty_unboxed_closure(def_id, _, ref substs) => {
// FIXME -- This case is tricky. In the case of by-ref
// closures particularly, we need the results of
// inference to decide how to reflect the type of each
Expand All @@ -1407,7 +1407,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map(|freevar| {
let freevar_def_id = freevar.def.def_id();
self.typer.node_ty(freevar_def_id.node)
.unwrap_or(ty::mk_err())
.unwrap_or(ty::mk_err()).subst(self.tcx(), substs)
})
.collect();
Ok(If(tys))
Expand Down Expand Up @@ -1548,8 +1548,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
Ok(VtableImpl(vtable_impl))
}

UnboxedClosureCandidate(closure_def_id) => {
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id));
UnboxedClosureCandidate(closure_def_id, ref substs) => {
try!(self.confirm_unboxed_closure_candidate(obligation, closure_def_id, substs));
Ok(VtableUnboxedClosure(closure_def_id))
}
}
Expand Down Expand Up @@ -1646,12 +1646,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {

fn confirm_unboxed_closure_candidate(&mut self,
obligation: &Obligation,
closure_def_id: ast::DefId)
closure_def_id: ast::DefId,
substs: &Substs)
-> Result<(),SelectionError>
{
debug!("confirm_unboxed_closure_candidate({},{})",
debug!("confirm_unboxed_closure_candidate({},{},{})",
obligation.repr(self.tcx()),
closure_def_id.repr(self.tcx()));
closure_def_id.repr(self.tcx()),
substs.repr(self.tcx()));

let closure_type = match self.typer.unboxed_closures().borrow().find(&closure_def_id) {
Some(closure) => closure.closure_type.clone(),
Expand All @@ -1678,7 +1680,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let trait_ref = Rc::new(ty::TraitRef {
def_id: obligation.trait_ref.def_id,
substs: Substs::new_trait(
vec![arguments_tuple, new_signature.output],
vec![arguments_tuple.subst(self.tcx(), substs),
new_signature.output.subst(self.tcx(), substs)],
vec![],
obligation.self_ty())
});
Expand Down Expand Up @@ -1959,7 +1962,9 @@ impl Repr for Candidate {
match *self {
ErrorCandidate => format!("ErrorCandidate"),
BuiltinCandidate(b) => format!("BuiltinCandidate({})", b),
UnboxedClosureCandidate(c) => format!("MatchedUnboxedClosureCandidate({})", c),
UnboxedClosureCandidate(c, ref s) => {
format!("MatchedUnboxedClosureCandidate({},{})", c, s.repr(tcx))
}
ParamCandidate(ref a) => format!("ParamCandidate({})", a.repr(tcx)),
ImplCandidate(a) => format!("ImplCandidate({})", a.repr(tcx)),
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/middle/trans/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ fn represent_type_uncached(cx: &CrateContext, t: ty::t) -> Repr {

return Univariant(mk_struct(cx, ftys.as_slice(), packed, t), dtor)
}
ty::ty_unboxed_closure(def_id, _) => {
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
ty::ty_unboxed_closure(def_id, _, ref substs) => {
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs);
let upvar_types = upvars.iter().map(|u| u.ty).collect::<Vec<_>>();
return Univariant(mk_struct(cx, upvar_types.as_slice(), false, t),
false)
Expand Down
30 changes: 14 additions & 16 deletions src/librustc/middle/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,21 +253,19 @@ fn get_extern_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str, did: ast::De
}

pub fn self_type_for_unboxed_closure(ccx: &CrateContext,
closure_id: ast::DefId)
closure_id: ast::DefId,
fn_ty: ty::t)
-> ty::t {
let unboxed_closure_type = ty::mk_unboxed_closure(ccx.tcx(),
closure_id,
ty::ReStatic);
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
let unboxed_closure = &(*unboxed_closures)[closure_id];
match unboxed_closure.kind {
ty::FnUnboxedClosureKind => {
ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type)
ty::mk_imm_rptr(ccx.tcx(), ty::ReStatic, fn_ty)
}
ty::FnMutUnboxedClosureKind => {
ty::mk_mut_rptr(ccx.tcx(), ty::ReStatic, unboxed_closure_type)
ty::mk_mut_rptr(ccx.tcx(), ty::ReStatic, fn_ty)
}
ty::FnOnceUnboxedClosureKind => unboxed_closure_type,
ty::FnOnceUnboxedClosureKind => fn_ty
}
}

Expand All @@ -285,14 +283,14 @@ pub fn decl_rust_fn(ccx: &CrateContext, fn_ty: ty::t, name: &str) -> ValueRef {
ty::ty_closure(ref f) => {
(f.sig.inputs.clone(), f.sig.output, f.abi, Some(Type::i8p(ccx)))
}
ty::ty_unboxed_closure(closure_did, _) => {
ty::ty_unboxed_closure(closure_did, _, ref substs) => {
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
let unboxed_closure = &(*unboxed_closures)[closure_did];
let function_type = unboxed_closure.closure_type.clone();
let self_type = self_type_for_unboxed_closure(ccx, closure_did);
let self_type = self_type_for_unboxed_closure(ccx, closure_did, fn_ty);
let llenvironment_type = type_of_explicit_arg(ccx, self_type);
(function_type.sig.inputs.clone(),
function_type.sig.output,
(function_type.sig.inputs.iter().map(|t| t.subst(ccx.tcx(), substs)).collect(),
function_type.sig.output.subst(ccx.tcx(), substs),
RustCall,
Some(llenvironment_type))
}
Expand Down Expand Up @@ -738,9 +736,9 @@ pub fn iter_structural_ty<'a, 'blk, 'tcx>(cx: Block<'blk, 'tcx>,
}
})
}
ty::ty_unboxed_closure(def_id, _) => {
ty::ty_unboxed_closure(def_id, _, ref substs) => {
let repr = adt::represent_type(cx.ccx(), t);
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id);
let upvars = ty::unboxed_closure_upvars(cx.tcx(), def_id, substs);
for (i, upvar) in upvars.iter().enumerate() {
let llupvar = adt::trans_field_ptr(cx, &*repr, data_ptr, 0, i);
cx = f(cx, llupvar, upvar.ty);
Expand Down Expand Up @@ -2351,12 +2349,12 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
let (fn_sig, abi, has_env) = match ty::get(fn_ty).sty {
ty::ty_closure(ref f) => (f.sig.clone(), f.abi, true),
ty::ty_bare_fn(ref f) => (f.sig.clone(), f.abi, false),
ty::ty_unboxed_closure(closure_did, _) => {
ty::ty_unboxed_closure(closure_did, _, ref substs) => {
let unboxed_closures = ccx.tcx().unboxed_closures.borrow();
let ref function_type = (*unboxed_closures)[closure_did]
.closure_type;

(function_type.sig.clone(), RustCall, true)
(function_type.sig.subst(ccx.tcx(), substs), RustCall, true)
}
_ => ccx.sess().bug("expected closure or function.")
};
Expand All @@ -2371,7 +2369,7 @@ pub fn get_fn_llvm_attributes(ccx: &CrateContext, fn_ty: ty::t)
// These have an odd calling convention, so we need to manually
// unpack the input ty's
let input_tys = match ty::get(fn_ty).sty {
ty::ty_unboxed_closure(_, _) => {
ty::ty_unboxed_closure(_, _, _) => {
assert!(abi == RustCall);

match ty::get(fn_sig.inputs[0]).sty {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/trans/callee.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ pub fn trans_fn_ref_with_substs(
};

// If this is an unboxed closure, redirect to it.
match closure::get_or_create_declaration_if_unboxed_closure(ccx, def_id) {
match closure::get_or_create_declaration_if_unboxed_closure(bcx, def_id) {
None => {}
Some(llfn) => return llfn,
}
Expand Down
33 changes: 22 additions & 11 deletions src/librustc/middle/trans/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use middle::trans::common::*;
use middle::trans::datum::{Datum, DatumBlock, Expr, Lvalue, rvalue_scratch_datum};
use middle::trans::debuginfo;
use middle::trans::expr;
use middle::trans::monomorphize::MonoId;
use middle::trans::type_of::*;
use middle::trans::type_::Type;
use middle::ty;
Expand Down Expand Up @@ -312,7 +313,8 @@ fn load_unboxed_closure_environment<'blk, 'tcx>(
}

// Special case for small by-value selfs.
let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id);
let self_type = self_type_for_unboxed_closure(bcx.ccx(), closure_id,
node_id_type(bcx, closure_id.node));
let kind = kind_for_unboxed_closure(bcx.ccx(), closure_id);
let llenv = if kind == ty::FnOnceUnboxedClosureKind &&
!arg_is_indirect(bcx.ccx(), self_type) {
Expand Down Expand Up @@ -418,15 +420,26 @@ pub fn trans_expr_fn<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,

/// Returns the LLVM function declaration for an unboxed closure, creating it
/// if necessary. If the ID does not correspond to a closure ID, returns None.
pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
closure_id: ast::DefId)
-> Option<ValueRef> {
pub fn get_or_create_declaration_if_unboxed_closure<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
closure_id: ast::DefId)
-> Option<ValueRef> {
let ccx = bcx.ccx();
if !ccx.tcx().unboxed_closures.borrow().contains_key(&closure_id) {
// Not an unboxed closure.
return None
}

match ccx.unboxed_closure_vals().borrow().find(&closure_id) {
let function_type = node_id_type(bcx, closure_id.node);
let params = match ty::get(function_type).sty {
ty::ty_unboxed_closure(_, _, ref substs) => substs.types.clone(),
_ => unreachable!()
};
let mono_id = MonoId {
def: closure_id,
params: params
};

match ccx.unboxed_closure_vals().borrow().find(&mono_id) {
Some(llfn) => {
debug!("get_or_create_declaration_if_unboxed_closure(): found \
closure");
Expand All @@ -435,9 +448,7 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,
None => {}
}

let function_type = ty::mk_unboxed_closure(ccx.tcx(),
closure_id,
ty::ReStatic);
let function_type = node_id_type(bcx, closure_id.node);
let symbol = ccx.tcx().map.with_path(closure_id.node, |path| {
mangle_internal_name_by_path_and_seq(path, "unboxed_closure")
});
Expand All @@ -449,9 +460,9 @@ pub fn get_or_create_declaration_if_unboxed_closure(ccx: &CrateContext,

debug!("get_or_create_declaration_if_unboxed_closure(): inserting new \
closure {} (type {})",
closure_id,
mono_id,
ccx.tn().type_to_string(val_ty(llfn)));
ccx.unboxed_closure_vals().borrow_mut().insert(closure_id, llfn);
ccx.unboxed_closure_vals().borrow_mut().insert(mono_id, llfn);

Some(llfn)
}
Expand All @@ -469,7 +480,7 @@ pub fn trans_unboxed_closure<'blk, 'tcx>(

let closure_id = ast_util::local_def(id);
let llfn = get_or_create_declaration_if_unboxed_closure(
bcx.ccx(),
bcx,
closure_id).unwrap();

let unboxed_closures = bcx.tcx().unboxed_closures.borrow();
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/trans/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ pub struct LocalCrateContext {
builder: BuilderRef_res,

/// Holds the LLVM values for closure IDs.
unboxed_closure_vals: RefCell<DefIdMap<ValueRef>>,
unboxed_closure_vals: RefCell<HashMap<MonoId, ValueRef>>,

dbg_cx: Option<debuginfo::CrateDebugContext>,

Expand Down Expand Up @@ -419,7 +419,7 @@ impl LocalCrateContext {
int_type: Type::from_ref(ptr::null_mut()),
opaque_vec_type: Type::from_ref(ptr::null_mut()),
builder: BuilderRef_res(llvm::LLVMCreateBuilderInContext(llcx)),
unboxed_closure_vals: RefCell::new(DefIdMap::new()),
unboxed_closure_vals: RefCell::new(HashMap::new()),
dbg_cx: dbg_cx,
eh_personality: RefCell::new(None),
intrinsics: RefCell::new(HashMap::new()),
Expand Down Expand Up @@ -689,7 +689,7 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> {
self.local.opaque_vec_type
}

pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell<DefIdMap<ValueRef>> {
pub fn unboxed_closure_vals<'a>(&'a self) -> &'a RefCell<HashMap<MonoId,ValueRef>> {
&self.local.unboxed_closure_vals
}

Expand Down
10 changes: 5 additions & 5 deletions src/librustc/middle/trans/debuginfo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ use llvm;
use llvm::{ModuleRef, ContextRef, ValueRef};
use llvm::debuginfo::*;
use metadata::csearch;
use middle::subst;
use middle::subst::{mod, Subst};
use middle::trans::adt;
use middle::trans::common::*;
use middle::trans::machine;
Expand Down Expand Up @@ -460,9 +460,9 @@ impl TypeMap {
closure_ty.clone(),
&mut unique_type_id);
},
ty::ty_unboxed_closure(ref def_id, _) => {
ty::ty_unboxed_closure(ref def_id, _, ref substs) => {
let closure_ty = cx.tcx().unboxed_closures.borrow()
.find(def_id).unwrap().closure_type.clone();
.find(def_id).unwrap().closure_type.subst(cx.tcx(), substs);
self.get_unique_type_id_of_closure_type(cx,
closure_ty,
&mut unique_type_id);
Expand Down Expand Up @@ -2911,9 +2911,9 @@ fn type_metadata(cx: &CrateContext,
ty::ty_closure(ref closurety) => {
subroutine_type_metadata(cx, unique_type_id, &closurety.sig, usage_site_span)
}
ty::ty_unboxed_closure(ref def_id, _) => {
ty::ty_unboxed_closure(ref def_id, _, ref substs) => {
let sig = cx.tcx().unboxed_closures.borrow()
.find(def_id).unwrap().closure_type.sig.clone();
.find(def_id).unwrap().closure_type.sig.subst(cx.tcx(), substs);
subroutine_type_metadata(cx, unique_type_id, &sig, usage_site_span)
}
ty::ty_struct(def_id, ref substs) => {
Expand Down
Loading