diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs index d7026b722af..265969c52b3 100644 --- a/src/librustc_trans/trans/mir/block.rs +++ b/src/librustc_trans/trans/mir/block.rs @@ -9,14 +9,18 @@ // except according to those terms. use llvm::BasicBlockRef; +use middle::infer; +use middle::ty; use rustc::mir::repr as mir; use trans::adt; use trans::base; use trans::build; -use trans::common::Block; +use trans::common::{self, Block}; use trans::debuginfo::DebugLoc; +use trans::type_of; use super::MirContext; +use super::operand::OperandValue::{FatPtr, Immediate, Ref}; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_block(&mut self, bb: mir::BasicBlock) { @@ -101,29 +105,65 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) { base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None); } - mir::Terminator::Call { .. } => { - unimplemented!() - //let llbb = unimplemented!(); // self.make_landing_pad(panic_bb); - // - //let tr_dest = self.trans_lvalue(bcx, &data.destination); - // - //// Create the callee. This will always be a fn - //// ptr and hence a kind of scalar. - //let callee = self.trans_operand(bcx, &data.func); - // - //// Process the arguments. - // - //let args = unimplemented!(); - // - //callee::trans_call_inner(bcx, - // DebugLoc::None, - // |bcx, _| Callee { - // bcx: bcx, - // data: CalleeData::Fn(callee.llval), - // ty: callee.ty, - // }, - // args, - // Some(Dest::SaveIn(tr_dest.llval))); + mir::Terminator::Call { ref data, targets } => { + // The location we'll write the result of the call into. + let call_dest = self.trans_lvalue(bcx, &data.destination); + + // Create the callee. This will always be a fn + // ptr and hence a kind of scalar. + let callee = self.trans_operand(bcx, &data.func); + let ret_ty = if let ty::TyBareFn(_, ref f) = callee.ty.sty { + let sig = bcx.tcx().erase_late_bound_regions(&f.sig); + let sig = infer::normalize_associated_type(bcx.tcx(), &sig); + sig.output + } else { + panic!("trans_block: expected TyBareFn as callee"); + }; + + // The arguments we'll be passing + let mut llargs = vec![]; + + // Does the fn use an outptr? If so, that's the first arg. + if let ty::FnConverging(ret_ty) = ret_ty { + if type_of::return_uses_outptr(bcx.ccx(), ret_ty) { + llargs.push(call_dest.llval); + } + } + + // Process the rest of the args. + for arg in &data.args { + let arg_op = self.trans_operand(bcx, arg); + match arg_op.val { + Ref(llval) | Immediate(llval) => llargs.push(llval), + FatPtr(base, extra) => { + // The two words in a fat ptr are passed separately + llargs.push(base); + llargs.push(extra); + } + } + } + + // FIXME: Handle panics + //let panic_bb = self.llblock(targets.1); + //self.make_landing_pad(panic_bb); + + // Do the actual call. + let (llret, b) = base::invoke(bcx, + callee.immediate(), + &llargs[..], + callee.ty, + DebugLoc::None); + bcx = b; + + // Copy the return value into the destination. + if let ty::FnConverging(ret_ty) = ret_ty { + if !type_of::return_uses_outptr(bcx.ccx(), ret_ty) && + !common::type_is_zero_size(bcx.ccx(), ret_ty) { + base::store_ty(bcx, llret, call_dest.llval, ret_ty); + } + } + + build::Br(bcx, self.llblock(targets.0), DebugLoc::None) } } } diff --git a/src/test/run-pass/mir_trans_calls.rs b/src/test/run-pass/mir_trans_calls.rs new file mode 100644 index 00000000000..2335a3c3348 --- /dev/null +++ b/src/test/run-pass/mir_trans_calls.rs @@ -0,0 +1,100 @@ +// Copyright 2015 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(rustc_attrs)] + +#[rustc_mir] +fn test1(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { + // Test passing a number of arguments including a fat pointer. + // Also returning via an out pointer + fn callee(a: isize, b: (i32, i32), c: &[i32]) -> (isize, (i32, i32), &[i32]) { + (a, b, c) + } + callee(a, b, c) +} + +#[rustc_mir] +fn test2(a: isize) -> isize { + // Test passing a single argument. + // Not using out pointer. + fn callee(a: isize) -> isize { + a + } + callee(a) +} + +struct Foo; +impl Foo { + fn inherent_method(&self, a: isize) -> isize { a } +} + +#[rustc_mir] +fn test3(x: &Foo, a: isize) -> isize { + // Test calling inherent method + x.inherent_method(a) +} + +trait Bar { + fn extension_method(&self, a: isize) -> isize { a } +} +impl Bar for Foo {} + +#[rustc_mir] +fn test4(x: &Foo, a: isize) -> isize { + // Test calling extension method + x.extension_method(a) +} + +#[rustc_mir] +fn test5(x: &Bar, a: isize) -> isize { + // Test calling method on trait object + x.extension_method(a) +} + +#[rustc_mir] +fn test6(x: &T, a: isize) -> isize { + // Test calling extension method on generic callee + x.extension_method(a) +} + +trait One { + fn one() -> T; +} +impl One for isize { + fn one() -> isize { 1 } +} + +#[rustc_mir] +fn test7() -> isize { + // Test calling trait static method + ::one() +} + +struct Two; +impl Two { + fn two() -> isize { 2 } +} + +#[rustc_mir] +fn test8() -> isize { + // Test calling impl static method + Two::two() +} + +fn main() { + assert_eq!(test1(1, (2, 3), &[4, 5, 6]), (1, (2, 3), &[4, 5, 6][..])); + assert_eq!(test2(98), 98); + assert_eq!(test3(&Foo, 42), 42); + assert_eq!(test4(&Foo, 970), 970); + assert_eq!(test5(&Foo, 8576), 8576); + assert_eq!(test6(&Foo, 12367), 12367); + assert_eq!(test7(), 1); + assert_eq!(test8(), 2); +}