mirror of
https://github.com/rust-lang/rust.git
synced 2024-10-31 22:41:50 +00:00
[MIR] Initial implementation for translating calls.
This commit is contained in:
parent
4eadabd9f8
commit
a6b861b197
@ -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 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
100
src/test/run-pass/mir_trans_calls.rs
Normal file
100
src/test/run-pass/mir_trans_calls.rs
Normal file
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T: Bar>(x: &T, a: isize) -> isize {
|
||||
// Test calling extension method on generic callee
|
||||
x.extension_method(a)
|
||||
}
|
||||
|
||||
trait One<T = Self> {
|
||||
fn one() -> T;
|
||||
}
|
||||
impl One for isize {
|
||||
fn one() -> isize { 1 }
|
||||
}
|
||||
|
||||
#[rustc_mir]
|
||||
fn test7() -> isize {
|
||||
// Test calling trait static method
|
||||
<isize as One>::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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user