From 6049b628ad734dd49add077f81a22b713ed495de Mon Sep 17 00:00:00 2001 From: Patrick Walton Date: Thu, 21 Aug 2014 10:04:52 -0700 Subject: [PATCH] librustc: Create unboxing shims as necessary for unboxed closures. Closes #16591. --- src/librustc/middle/trans/callee.rs | 16 ++--- src/librustc/middle/trans/meth.rs | 58 ++++++++++++++++++- .../unboxed-closures-unboxing-shim.rs | 19 ++++++ 3 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 src/test/run-pass/unboxed-closures-unboxing-shim.rs diff --git a/src/librustc/middle/trans/callee.rs b/src/librustc/middle/trans/callee.rs index e397ee94c8a..d50b30c7545 100644 --- a/src/librustc/middle/trans/callee.rs +++ b/src/librustc/middle/trans/callee.rs @@ -288,7 +288,7 @@ fn resolve_default_method_vtables(bcx: &Block, /// `Trait` so that a by-value self method can be called. pub fn trans_unboxing_shim(bcx: &Block, llshimmedfn: ValueRef, - method: &ty::Method, + fty: &ty::BareFnTy, method_id: ast::DefId, substs: subst::Substs) -> ValueRef { @@ -297,29 +297,29 @@ pub fn trans_unboxing_shim(bcx: &Block, let tcx = bcx.tcx(); // Transform the self type to `Box`. - let self_type = *method.fty.sig.inputs.get(0); + let self_type = *fty.sig.inputs.get(0); let boxed_self_type = ty::mk_uniq(tcx, self_type); let boxed_function_type = ty::FnSig { - binder_id: method.fty.sig.binder_id, - inputs: method.fty.sig.inputs.iter().enumerate().map(|(i, typ)| { + binder_id: fty.sig.binder_id, + inputs: fty.sig.inputs.iter().enumerate().map(|(i, typ)| { if i == 0 { boxed_self_type } else { *typ } }).collect(), - output: method.fty.sig.output, + output: fty.sig.output, variadic: false, }; let boxed_function_type = ty::BareFnTy { - fn_style: method.fty.fn_style, - abi: method.fty.abi, + fn_style: fty.fn_style, + abi: fty.abi, sig: boxed_function_type, }; let boxed_function_type = ty::mk_bare_fn(tcx, boxed_function_type).subst(tcx, &substs); let function_type = - ty::mk_bare_fn(tcx, method.fty.clone()).subst(tcx, &substs); + ty::mk_bare_fn(tcx, (*fty).clone()).subst(tcx, &substs); let function_name = ty::with_path(tcx, method_id, |path| { link::mangle_internal_name_by_path_and_seq(path, "unboxing_shim") diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index 31f2a3df662..a9a308fc16d 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -515,13 +515,65 @@ fn get_vtable(bcx: &Block, bcx, closure_def_id); - let llfn = trans_fn_ref_with_vtables( + let mut llfn = trans_fn_ref_with_vtables( bcx, closure_def_id, ExprId(0), - callee_substs, + callee_substs.clone(), VecPerParamSpace::empty()); + { + let unboxed_closures = bcx.tcx() + .unboxed_closures + .borrow(); + let closure_info = + unboxed_closures.find(&closure_def_id) + .expect("get_vtable(): didn't find \ + unboxed closure"); + if closure_info.kind == ty::FnOnceUnboxedClosureKind { + // Untuple the arguments and create an unboxing shim. + let mut new_inputs = vec![ + ty::mk_unboxed_closure(bcx.tcx(), + closure_def_id, + ty::ReStatic) + ]; + match ty::get(closure_info.closure_type + .sig + .inputs[0]).sty { + ty::ty_tup(ref elements) => { + for element in elements.iter() { + new_inputs.push(*element) + } + } + ty::ty_nil => {} + _ => { + bcx.tcx().sess.bug("get_vtable(): closure \ + type wasn't a tuple") + } + } + + let closure_type = ty::BareFnTy { + fn_style: closure_info.closure_type.fn_style, + abi: Rust, + sig: ty::FnSig { + binder_id: closure_info.closure_type + .sig + .binder_id, + inputs: new_inputs, + output: closure_info.closure_type.sig.output, + variadic: false, + }, + }; + debug!("get_vtable(): closure type is {}", + closure_type.repr(bcx.tcx())); + llfn = trans_unboxing_shim(bcx, + llfn, + &closure_type, + closure_def_id, + callee_substs); + } + } + (vec!(llfn)).move_iter() } _ => ccx.sess().bug("get_vtable: expected a static origin"), @@ -603,7 +655,7 @@ fn emit_vtable_methods(bcx: &Block, if m.explicit_self == ty::ByValueExplicitSelfCategory { fn_ref = trans_unboxing_shim(bcx, fn_ref, - &*m, + &m.fty, m_id, substs.clone()); } diff --git a/src/test/run-pass/unboxed-closures-unboxing-shim.rs b/src/test/run-pass/unboxed-closures-unboxing-shim.rs new file mode 100644 index 00000000000..0a7baa3ba36 --- /dev/null +++ b/src/test/run-pass/unboxed-closures-unboxing-shim.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(unboxed_closures, unboxed_closure_sugar)] + +use std::ops::FnOnce; + +fn main() { + let task: Box<|: int| -> int> = box |: x| x; + assert!(task.call_once((1234i,)) == 1234i); +} +