]> git.lizzy.rs Git - rust.git/commitdiff
Add closure support (fixes #2)
authorbjorn3 <bjorn3@users.noreply.github.com>
Fri, 20 Jul 2018 11:38:49 +0000 (13:38 +0200)
committerbjorn3 <bjorn3@users.noreply.github.com>
Thu, 26 Jul 2018 08:14:27 +0000 (10:14 +0200)
build.sh
example.rs
mini_core.rs
src/abi.rs

index 85c673d1377c4b3f93a28b174a858bb8f1e66610..724f5deedfc93b9c17d49df3b0464985c0697aac 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -3,3 +3,5 @@ cargo build || exit 1
 rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so mini_core.rs --crate-name mini_core --crate-type lib -Og &&
 rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so -L crate=. example.rs --crate-type lib -Og &&
 rustc -Zcodegen-backend=$(pwd)/target/debug/librustc_codegen_cranelift.so ./target/libcore/src/libcore/lib.rs --crate-type lib -Og
+
+rm libmini_core.rlib libexample.rlib
index 0df10254f760b6b41663baa5286990486c315b5f..0f37d7f4c363592c8084cf2e56448aeadf7267e1 100644 (file)
@@ -60,7 +60,7 @@ fn cmp_raw_ptr(a: *const u8, b: *const u8) -> bool {
     a == b
 }
 
-fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize) {
+fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize, u8, u32) {
     (
         a as u8,
         a as u16,
@@ -70,6 +70,8 @@ fn int_cast(a: u16, b: i16) -> (u8, u16, u32, usize, i8, i16, i32, isize) {
         a as i16,
         a as i32,
         a as isize,
+        b as u8,
+        b as u32
     )
 }
 
@@ -107,3 +109,9 @@ fn use_size_of() -> usize {
 fn use_const() -> u8 {
     Abc
 }
+
+fn call_closure() {
+    (|_, _, _| {
+
+    })(0u8, 42u8, 0u8)
+}
index efd0b8818b123e5c7576917ae6648daf16555cba..d4844cc0be2d9879e919043d66d93e63e328173d 100644 (file)
@@ -1,4 +1,4 @@
-#![feature(no_core, lang_items, intrinsics)]
+#![feature(no_core, lang_items, intrinsics, unboxed_closures)]
 #![no_core]
 #![allow(dead_code)]
 
@@ -55,6 +55,20 @@ fn eq(&self, other: &*const T) -> bool { *self == *other }
     fn ne(&self, other: &*const T) -> bool { *self != *other }
 }
 
+#[lang = "fn_once"]
+#[rustc_paren_sugar]
+trait FnOnce<Args> {
+    type Output;
+
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+#[lang = "fn_mut"]
+#[rustc_paren_sugar]
+trait FnMut<Args> : FnOnce<Args> {
+    extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
+}
+
 #[lang="panic"]
 pub fn panic(_expr_file_line_col: &(&'static str, &'static str, u32, u32)) -> ! {
     loop {}
index e228b863b1ce1bd54490c8f69c2abef5bcfe4e67..a36ac1611a1942271392667ba86fe0577d217139 100644 (file)
@@ -7,12 +7,22 @@
 
 pub fn cton_sig_from_fn_ty<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn_ty: Ty<'tcx>) -> Signature {
     let sig = ty_fn_sig(tcx, fn_ty);
-    let sig = tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &sig);
     assert!(!sig.variadic, "Variadic function are not yet supported");
     let (call_conv, inputs, _output): (CallConv, Vec<Ty>, Ty) = match sig.abi {
         Abi::Rust => (CallConv::SystemV, sig.inputs().to_vec(), sig.output()),
         Abi::RustCall => {
-            unimplemented!("rust-call");
+            println!("rust-call sig: {:?} inputs: {:?} output: {:?}", sig, sig.inputs(), sig.output());
+            let extra_args = match sig.inputs().last().unwrap().sty {
+                ty::TyTuple(ref tupled_arguments) => tupled_arguments,
+                _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
+            };
+            let mut inputs: Vec<Ty> = sig.inputs()[0..sig.inputs().len() - 1].to_vec();
+            inputs.extend(extra_args.into_iter());
+            (
+                CallConv::SystemV,
+                inputs,
+                sig.output(),
+            )
         }
         Abi::System => bug!("system abi should be selected elsewhere"),
         // 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<
 fn ty_fn_sig<'a, 'tcx>(
     tcx: TyCtxt<'a, 'tcx, 'tcx>,
     ty: Ty<'tcx>
-) -> ty::PolyFnSig<'tcx> {
-    match ty.sty {
+) -> ty::FnSig<'tcx> {
+    let sig = match ty.sty {
         ty::TyFnDef(..) |
         // Shims currently have type TyFnPtr. Not sure this should remain.
         ty::TyFnPtr(_) => ty.fn_sig(tcx),
@@ -73,7 +83,8 @@ fn ty_fn_sig<'a, 'tcx>(
             })
         }
         _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
-    }
+    };
+    tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &sig)
 }
 
 impl<'a, 'tcx: 'a> FunctionCx<'a, 'tcx> {
@@ -91,8 +102,7 @@ pub fn get_function_ref(&mut self, inst: Instance<'tcx>) -> FuncRef {
     }
 
     fn self_sig(&self) -> FnSig<'tcx> {
-        let sig = ty_fn_sig(self.tcx, self.instance.ty(self.tcx));
-        self.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &sig)
+        ty_fn_sig(self.tcx, self.instance.ty(self.tcx))
     }
 
     fn return_type(&self) -> Ty<'tcx> {
@@ -153,6 +163,8 @@ pub fn codegen_call<'a, 'tcx: 'a>(
     destination: &Option<(Place<'tcx>, BasicBlock)>,
 ) {
     let func = ::base::trans_operand(fx, func);
+    let fn_ty = func.layout().ty;
+    let sig = ty_fn_sig(fx.tcx, fn_ty);
 
     let return_place = if let Some((place, _)) = destination {
         Some(::base::trans_place(fx, place))
@@ -160,29 +172,33 @@ pub fn codegen_call<'a, 'tcx: 'a>(
         None
     };
 
-    let args = args
-        .into_iter()
-        .map(|arg| {
-            let arg = ::base::trans_operand(fx, arg);
-            if let Some(_) = fx.cton_type(arg.layout().ty) {
-                arg.load_value(fx)
-            } else {
-                arg.force_stack(fx)
-            }
-        })
-        .collect::<Vec<_>>();
+    // Unpack arguments tuple for closures
+    let args = if sig.abi == Abi::RustCall {
+        assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
+        let self_arg = ::base::trans_operand(fx, &args[0]);
+        let pack_arg = ::base::trans_operand(fx, &args[1]);
+        let mut args = Vec::new();
+        args.push(self_arg);
+        match pack_arg.layout().ty.sty {
+            ty::TyTuple(ref tupled_arguments) => {
+                for (i, _) in tupled_arguments.iter().enumerate() {
+                    args.push(pack_arg.value_field(fx, mir::Field::new(i)));
+                }
+            },
+            _ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
+        }
+        args
+    } else {
+        args
+            .into_iter()
+            .map(|arg| {
+                ::base::trans_operand(fx, arg)
+            })
+            .collect::<Vec<_>>()
+    };
 
-    let fn_ty = func.layout().ty;
     if let TypeVariants::TyFnDef(def_id, substs) = fn_ty.sty {
-        let instance = ty::Instance::resolve(
-            fx.tcx,
-            ParamEnv::reveal_all(),
-            def_id,
-            substs
-        ).unwrap();
-
-        // Handle intrinsics old codegen wants Expr's for, ourselves.
-        if let InstanceDef::Intrinsic(def_id) = instance.def {
+        if sig.abi == Abi::RustIntrinsic {
             let intrinsic = fx.tcx.item_name(def_id).as_str();
             let intrinsic = &intrinsic[..];
 
@@ -218,17 +234,23 @@ pub fn codegen_call<'a, 'tcx: 'a>(
         None => fx.bcx.ins().iconst(types::I64, 0),
     };
 
-    let args = Some(return_ptr).into_iter().chain(args).collect::<Vec<_>>();
+    let call_args = Some(return_ptr).into_iter().chain(args.into_iter().map(|arg| {
+        if fx.cton_type(arg.layout().ty).is_some() {
+            arg.load_value(fx)
+        } else {
+            arg.force_stack(fx)
+        }
+    })).collect::<Vec<_>>();
 
     match func {
         CValue::Func(func, _) => {
-            fx.bcx.ins().call(func, &args);
+            fx.bcx.ins().call(func, &call_args);
         }
         func => {
             let func_ty = func.layout().ty;
             let func = func.load_value(fx);
             let sig = fx.bcx.import_signature(cton_sig_from_fn_ty(fx.tcx, func_ty));
-            fx.bcx.ins().call_indirect(sig, func, &args);
+            fx.bcx.ins().call_indirect(sig, func, &call_args);
         }
     }
     if let Some((_, dest)) = *destination {