Skip to content

Commit 874208b

Browse files
committed
Add closure support (fixes #2)
1 parent ae44a1a commit 874208b

File tree

4 files changed

+79
-33
lines changed

4 files changed

+79
-33
lines changed

build.sh

+2
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ cargo build || exit 1
33
rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so mini_core.rs --crate-name mini_core --crate-type lib -Og &&
44
rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so -L crate=. example.rs --crate-type lib -Og &&
55
rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so ./target/libcore/src/libcore/lib.rs --crate-type lib -Og
6+
7+
rm libmini_core.rlib libexample.rlib

example.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool {
6060
a == b
6161
}
6262

63-
fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize) {
63+
fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
6464
(
6565
a as u8,
6666
a as u16,
@@ -70,6 +70,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize) {
7070
a as i16,
7171
a as i32,
7272
a as isize,
73+
b as u8,
74+
b as u32
7375
)
7476
}
7577

@@ -107,3 +109,9 @@ const Abc: u8 = 6 * 7;
107109
fn use_const() -> u8 {
108110
Abc
109111
}
112+
113+
fn call_closure() {
114+
(|_, _, _| {
115+
116+
})(0u8, 42u8, 0u8)
117+
}

mini_core.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#![feature(no_core, lang_items, intrinsics)]
1+
#![feature(no_core, lang_items, intrinsics, unboxed_closures)]
22
#![no_core]
33
#![allow(dead_code)]
44

@@ -55,6 +55,20 @@ impl<T: ?Sized> PartialEq for *const T {
5555
fn ne(&self, other: &*const T) -> bool { *self != *other }
5656
}
5757

58+
#[lang = "fn_once"]
59+
#[rustc_paren_sugar]
60+
trait FnOnce<Args> {
61+
type Output;
62+
63+
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
64+
}
65+
66+
#[lang = "fn_mut"]
67+
#[rustc_paren_sugar]
68+
trait FnMut<Args> : FnOnce<Args> {
69+
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
70+
}
71+
5872
#[lang="panic"]
5973
pub fn panic(_expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
6074
loop {}

src/abi.rs

+53-31
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,22 @@ use prelude::*;
77

88
pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_ty: Ty<'tcx>) -> Signature {
99
let sig = ty_fn_sig(tcx, fn_ty);
10-
let sig = tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &sig);
1110
assert!(!sig.variadic, "Variadic function are not yet supported");
1211
let (call_conv, inputs, _output): (CallConv, Vec<Ty>, Ty) = match sig.abi {
1312
Abi::Rust => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
1413
Abi::RustCall => {
15-
unimplemented!("rust-call");
14+
println!("rust-call sig: {:?} inputs: {:?} output: {:?}", sig, sig.inputs(), sig.output());
15+
let extra_args = match sig.inputs().last().unwrap().sty {
16+
ty::TyTuple(ref tupled_arguments) => tupled_arguments,
17+
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
18+
};
19+
let mut inputs: Vec<Ty> = sig.inputs()[0..sig.inputs().len() - 1].to_vec();
20+
inputs.extend(extra_args.into_iter());
21+
(
22+
CallConv::SystemV,
23+
inputs,
24+
sig.output(),
25+
)
1626
}
1727
Abi::System => bug!("system abi should be selected elsewhere"),
1828
// TODO: properly implement intrinsics
@@ -32,8 +42,8 @@ pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_ty: Ty<
3242
fn ty_fn_sig<'a, 'tcx>(
3343
tcx: TyCtxt<'a, 'tcx, 'tcx>,
3444
ty: Ty<'tcx>
35-
) -> ty::PolyFnSig<'tcx> {
36-
match ty.sty {
45+
) -> ty::FnSig<'tcx> {
46+
let sig = match ty.sty {
3747
ty::TyFnDef(..) |
3848
// Shims currently have type TyFnPtr. Not sure this should remain.
3949
ty::TyFnPtr(_) => ty.fn_sig(tcx),
@@ -73,7 +83,8 @@ fn ty_fn_sig<'a, 'tcx>(
7383
})
7484
}
7585
_ => bug!("unexpected type {:?} to ty_fn_sig", ty)
76-
}
86+
};
87+
tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &sig)
7788
}
7889

7990
impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> {
@@ -91,8 +102,7 @@ impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> {
91102
}
92103

93104
fn self_sig(&self) -> FnSig<'tcx> {
94-
let sig = ty_fn_sig(self.tcx, self.instance.ty(self.tcx));
95-
self.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &sig)
105+
ty_fn_sig(self.tcx, self.instance.ty(self.tcx))
96106
}
97107

98108
fn return_type(&self) -> Ty<'tcx> {
@@ -153,36 +163,42 @@ pub fn codegen_call<'a, 'tcx: 'a>(
153163
destination: &Option<(Place<'tcx>, BasicBlock)>,
154164
) {
155165
let func = ::base::trans_operand(fx, func);
166+
let fn_ty = func.layout().ty;
167+
let sig = ty_fn_sig(fx.tcx, fn_ty);
156168

157169
let return_place = if let Some((place, _)) = destination {
158170
Some(::base::trans_place(fx, place))
159171
} else {
160172
None
161173
};
162174

163-
let args = args
164-
.into_iter()
165-
.map(|arg| {
166-
let arg = ::base::trans_operand(fx, arg);
167-
if let Some(_) = fx.cton_type(arg.layout().ty) {
168-
arg.load_value(fx)
169-
} else {
170-
arg.force_stack(fx)
171-
}
172-
})
173-
.collect::<Vec<_>>();
175+
// Unpack arguments tuple for closures
176+
let args = if sig.abi == Abi::RustCall {
177+
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
178+
let self_arg = ::base::trans_operand(fx, &args[0]);
179+
let pack_arg = ::base::trans_operand(fx, &args[1]);
180+
let mut args = Vec::new();
181+
args.push(self_arg);
182+
match pack_arg.layout().ty.sty {
183+
ty::TyTuple(ref tupled_arguments) => {
184+
for (i, _) in tupled_arguments.iter().enumerate() {
185+
args.push(pack_arg.value_field(fx, mir::Field::new(i)));
186+
}
187+
},
188+
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
189+
}
190+
args
191+
} else {
192+
args
193+
.into_iter()
194+
.map(|arg| {
195+
::base::trans_operand(fx, arg)
196+
})
197+
.collect::<Vec<_>>()
198+
};
174199

175-
let fn_ty = func.layout().ty;
176200
if let TypeVariants::TyFnDef(def_id, substs) = fn_ty.sty {
177-
let instance = ty::Instance::resolve(
178-
fx.tcx,
179-
ParamEnv::reveal_all(),
180-
def_id,
181-
substs
182-
).unwrap();
183-
184-
// Handle intrinsics old codegen wants Expr's for, ourselves.
185-
if let InstanceDef::Intrinsic(def_id) = instance.def {
201+
if sig.abi == Abi::RustIntrinsic {
186202
let intrinsic = fx.tcx.item_name(def_id).as_str();
187203
let intrinsic = &intrinsic[..];
188204

@@ -218,17 +234,23 @@ pub fn codegen_call<'a, 'tcx: 'a>(
218234
None => fx.bcx.ins().iconst(types::I64, 0),
219235
};
220236

221-
let args = Some(return_ptr).into_iter().chain(args).collect::<Vec<_>>();
237+
let call_args = Some(return_ptr).into_iter().chain(args.into_iter().map(|arg| {
238+
if fx.cton_type(arg.layout().ty).is_some() {
239+
arg.load_value(fx)
240+
} else {
241+
arg.force_stack(fx)
242+
}
243+
})).collect::<Vec<_>>();
222244

223245
match func {
224246
CValue::Func(func, _) => {
225-
fx.bcx.ins().call(func, &args);
247+
fx.bcx.ins().call(func, &call_args);
226248
}
227249
func => {
228250
let func_ty = func.layout().ty;
229251
let func = func.load_value(fx);
230252
let sig = fx.bcx.import_signature(cton_sig_from_fn_ty(fx.tcx, func_ty));
231-
fx.bcx.ins().call_indirect(sig, func, &args);
253+
fx.bcx.ins().call_indirect(sig, func, &call_args);
232254
}
233255
}
234256
if let Some((_, dest)) = *destination {

0 commit comments

Comments
 (0)