Skip to content

[MIR] Implement translation of references to various items #29907

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 18, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
@@ -698,10 +698,20 @@ pub struct Constant<'tcx> {
pub literal: Literal<'tcx>,
}

#[derive(Clone, Copy, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum ItemKind {
Constant,
Function,
Struct,
Variant,
Method,
}

#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Literal<'tcx> {
Item {
def_id: DefId,
kind: ItemKind,
substs: &'tcx Substs<'tcx>,
},
Value {
1 change: 1 addition & 0 deletions src/librustc_mir/build/misc.rs
Original file line number Diff line number Diff line change
@@ -66,6 +66,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
-> Operand<'tcx> {
let literal = Literal::Item {
def_id: item_ref.def_id,
kind: item_ref.kind,
substs: item_ref.substs,
};
self.literal_operand(span, item_ref.ty, literal)
36 changes: 30 additions & 6 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
@@ -480,6 +480,7 @@ fn method_callee<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>,
kind: ExprKind::Literal {
literal: Literal::Item {
def_id: callee.def_id,
kind: ItemKind::Method,
substs: callee.substs,
},
},
@@ -514,16 +515,39 @@ fn convert_arm<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<

fn convert_path_expr<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> ExprKind<'tcx> {
let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
match cx.tcx.def_map.borrow()[&expr.id].full_def() {
// Otherwise there may be def_map borrow conflicts
let def = cx.tcx.def_map.borrow()[&expr.id].full_def();
match def {
def::DefVariant(_, def_id, false) |
def::DefStruct(def_id) |
def::DefFn(def_id, _) |
def::DefConst(def_id) |
def::DefMethod(def_id) |
def::DefAssociatedConst(def_id) =>
def::DefMethod(def_id) => {
let kind = match def {
def::DefVariant(..) => ItemKind::Variant,
def::DefStruct(..) => ItemKind::Struct,
def::DefFn(..) => ItemKind::Function,
def::DefMethod(..) => ItemKind::Method,
_ => panic!()
};
ExprKind::Literal {
literal: Literal::Item { def_id: def_id, substs: substs }
},
literal: Literal::Item { def_id: def_id, kind: kind, substs: substs }
}
},
def::DefConst(def_id) |
def::DefAssociatedConst(def_id) => {
if let Some(v) = cx.try_const_eval_literal(expr) {
ExprKind::Literal { literal: v }
} else {
ExprKind::Literal {
literal: Literal::Item {
def_id: def_id,
kind: ItemKind::Constant,
substs: substs
}
}
}
}


def::DefStatic(node_id, _) =>
ExprKind::StaticRef {
8 changes: 8 additions & 0 deletions src/librustc_mir/hair/cx/mod.rs
Original file line number Diff line number Diff line change
@@ -76,6 +76,13 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
Literal::Value { value: const_eval::eval_const_expr(self.tcx, e) }
}

pub fn try_const_eval_literal(&mut self, e: &hir::Expr) -> Option<Literal<'tcx>> {
let hint = const_eval::EvalHint::ExprTypeChecked;
const_eval::eval_const_expr_partial(self.tcx, e, hint, None)
.ok()
.map(|v| Literal::Value { value: v })
}

pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
self.cmp_method_ref(eq_def_id, "eq", ty)
@@ -132,6 +139,7 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> {
let method_ty = method_ty.ty.subst(self.tcx, &substs);
return ItemRef {
ty: method_ty,
kind: ItemKind::Method,
def_id: method.def_id,
substs: self.tcx.mk_substs(substs),
};
6 changes: 5 additions & 1 deletion src/librustc_mir/hair/cx/pattern.rs
Original file line number Diff line number Diff line change
@@ -97,7 +97,11 @@ impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
Literal::Value { value: value }
} else {
let substs = self.cx.tcx.mk_substs(Substs::empty());
Literal::Item { def_id: def_id, substs: substs }
Literal::Item {
def_id: def_id,
kind: ItemKind::Constant,
substs: substs
}
};
PatternKind::Constant { value: literal }
}
3 changes: 2 additions & 1 deletion src/librustc_mir/hair/mod.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
//! unit-tested and separated from the Rust source and compiler data
//! structures.

use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp};
use rustc::mir::repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp, ItemKind};
use rustc::middle::def_id::DefId;
use rustc::middle::region::CodeExtent;
use rustc::middle::subst::Substs;
@@ -29,6 +29,7 @@ pub mod cx;
#[derive(Clone, Debug)]
pub struct ItemRef<'tcx> {
pub ty: Ty<'tcx>,
pub kind: ItemKind,
pub def_id: DefId,
pub substs: &'tcx Substs<'tcx>,
}
15 changes: 7 additions & 8 deletions src/librustc_trans/trans/consts.rs
Original file line number Diff line number Diff line change
@@ -108,12 +108,13 @@ pub fn const_lit(cx: &CrateContext, e: &hir::Expr, lit: &ast::Lit)
}
}

pub fn trans_constval<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
pub fn trans_constval<'blk, 'tcx>(bcx: common::Block<'blk, 'tcx>,
cv: &ConstVal,
ty: Ty<'tcx>,
param_substs: &'tcx Substs<'tcx>)
-> ValueRef
{
let ccx = bcx.ccx();
let llty = type_of::type_of(ccx, ty);
match *cv {
ConstVal::Float(v) => C_floating_f64(v, llty),
@@ -123,19 +124,17 @@ pub fn trans_constval<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
ConstVal::ByteStr(ref v) => addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
ConstVal::Struct(id) | ConstVal::Tuple(id) => {
let expr = ccx.tcx().map.expect_expr(id);
let expr = bcx.tcx().map.expect_expr(id);
match const_expr(ccx, expr, param_substs, None, TrueConst::Yes) {
Ok((val, _)) => val,
Err(e) => panic!("const eval failure: {}", e.description()),
}
},
ConstVal::Function(_) => {
unimplemented!()
ConstVal::Array(id, _) | ConstVal::Repeat(id, _) => {
let expr = bcx.tcx().map.expect_expr(id);
expr::trans(bcx, expr).datum.val
},
ConstVal::Array(..) => {
unimplemented!()
},
ConstVal::Repeat(..) => {
ConstVal::Function(_) => {
unimplemented!()
},
}
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/meth.rs
Original file line number Diff line number Diff line change
@@ -473,7 +473,7 @@ fn trans_trait_callee_from_llval<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
///
/// In fact, all virtual calls can be thought of as normal trait calls
/// that go through this shim function.
fn trans_object_shim<'a, 'tcx>(
pub fn trans_object_shim<'a, 'tcx>(
ccx: &'a CrateContext<'a, 'tcx>,
upcast_trait_ref: ty::PolyTraitRef<'tcx>,
method_id: DefId,
20 changes: 9 additions & 11 deletions src/librustc_trans/trans/mir/constant.rs
Original file line number Diff line number Diff line change
@@ -14,7 +14,8 @@ use rustc::mir::repr as mir;
use trans::consts;
use trans::common::{self, Block};

use super::operand::OperandRef;

use super::operand::{OperandRef, OperandValue};
use super::MirContext;

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
@@ -24,14 +25,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
ty: Ty<'tcx>)
-> OperandRef<'tcx>
{
use super::operand::OperandValue::{Ref, Immediate};

let ccx = bcx.ccx();
let val = consts::trans_constval(ccx, cv, ty, bcx.fcx.param_substs);
let val = consts::trans_constval(bcx, cv, ty, bcx.fcx.param_substs);
let val = if common::type_is_immediate(ccx, ty) {
Immediate(val)
OperandValue::Immediate(val)
} else {
Ref(val)
OperandValue::Ref(val)
};

assert!(!ty.has_erasable_regions());
@@ -47,13 +46,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
constant: &mir::Constant<'tcx>)
-> OperandRef<'tcx>
{
let constant_ty = bcx.monomorphize(&constant.ty);
let ty = bcx.monomorphize(&constant.ty);
match constant.literal {
mir::Literal::Item { .. } => {
unimplemented!()
}
mir::Literal::Item { def_id, kind, substs } =>
self.trans_item_ref(bcx, ty, kind, substs, def_id),
mir::Literal::Value { ref value } => {
self.trans_constval(bcx, value, constant_ty)
self.trans_constval(bcx, value, ty)
}
}
}
160 changes: 160 additions & 0 deletions src/librustc_trans/trans/mir/did.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
// 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.

//! Code for translating references to other items (DefIds).

use syntax::codemap::DUMMY_SP;
use rustc::front::map;
use rustc::middle::ty::{self, Ty, HasTypeFlags};
use rustc::middle::subst::Substs;
use rustc::middle::const_eval;
use rustc::middle::def_id::DefId;
use rustc::middle::subst;
use rustc::middle::traits;
use rustc::mir::repr::ItemKind;
use trans::common::{Block, fulfill_obligation};
use trans::base;
use trans::expr;
use trans::monomorphize;
use trans::meth;
use trans::inline;

use super::MirContext;
use super::operand::{OperandRef, OperandValue};

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
/// Translate reference to item.
pub fn trans_item_ref(&mut self,
bcx: Block<'bcx, 'tcx>,
ty: Ty<'tcx>,
kind: ItemKind,
substs: &'tcx Substs<'tcx>,
did: DefId)
-> OperandRef<'tcx> {
match kind {
ItemKind::Function |
ItemKind::Struct |
ItemKind::Variant => self.trans_fn_ref(bcx, ty, substs, did),
ItemKind::Method => match bcx.tcx().impl_or_trait_item(did).container() {
ty::ImplContainer(_) => self.trans_fn_ref(bcx, ty, substs, did),
ty::TraitContainer(tdid) => self.trans_static_method(bcx, ty, did, tdid, substs)
},
ItemKind::Constant => {
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);
let expr = const_eval::lookup_const_by_id(bcx.tcx(), did, None)
.expect("def was const, but lookup_const_by_id failed");
// FIXME: this is falling back to translating from HIR. This is not easy to fix,
// because we would have somehow adapt const_eval to work on MIR rather than HIR.
let d = expr::trans(bcx, expr);
OperandRef::from_rvalue_datum(d.datum.to_rvalue_datum(d.bcx, "").datum)
}
}
}

/// Translates references to a function-like items.
///
/// That includes regular functions, non-static methods, struct and enum variant constructors,
/// closures and possibly more.
///
/// This is an adaptation of callee::trans_fn_ref_with_substs.
pub fn trans_fn_ref(&mut self,
bcx: Block<'bcx, 'tcx>,
ty: Ty<'tcx>,
substs: &'tcx Substs<'tcx>,
did: DefId)
-> OperandRef<'tcx> {
let did = inline::maybe_instantiate_inline(bcx.ccx(), did);

if !substs.types.is_empty() || is_named_tuple_constructor(bcx.tcx(), did) {
let (val, fn_ty, _) = monomorphize::monomorphic_fn(bcx.ccx(), did, substs, None);
// FIXME: cast fnptr to proper type if necessary
OperandRef {
ty: fn_ty,
val: OperandValue::Immediate(val)
}
} else {
let val = if let Some(node_id) = bcx.tcx().map.as_local_node_id(did) {
base::get_item_val(bcx.ccx(), node_id)
} else {
base::trans_external_path(bcx.ccx(), did, ty)
};
// FIXME: cast fnptr to proper type if necessary
OperandRef {
ty: ty,
val: OperandValue::Immediate(val)
}
}
}

/// Translates references to static methods.
///
/// This is an adaptation of meth::trans_static_method_callee
pub fn trans_static_method(&mut self,
bcx: Block<'bcx, 'tcx>,
ty: Ty<'tcx>,
method_id: DefId,
trait_id: DefId,
substs: &'tcx Substs<'tcx>)
-> OperandRef<'tcx> {
let ccx = bcx.ccx();
let tcx = bcx.tcx();
let mname = tcx.item_name(method_id);
let subst::SeparateVecsPerParamSpace {
types: rcvr_type,
selfs: rcvr_self,
fns: rcvr_method
} = substs.clone().types.split();
let trait_substs = Substs::erased(
subst::VecPerParamSpace::new(rcvr_type, rcvr_self, Vec::new())
);
let trait_substs = tcx.mk_substs(trait_substs);
let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, trait_substs));
let vtbl = fulfill_obligation(ccx, DUMMY_SP, trait_ref);
match vtbl {
traits::VtableImpl(traits::VtableImplData { impl_def_id, substs: imp_substs, .. }) => {
assert!(!imp_substs.types.needs_infer());
let subst::SeparateVecsPerParamSpace {
types: impl_type,
selfs: impl_self,
fns: _
} = imp_substs.types.split();
let callee_substs = Substs::erased(
subst::VecPerParamSpace::new(impl_type, impl_self, rcvr_method)
);
let mth = tcx.get_impl_method(impl_def_id, callee_substs, mname);
let mthsubsts = tcx.mk_substs(mth.substs);
self.trans_fn_ref(bcx, ty, mthsubsts, mth.method.def_id)
},
traits::VtableObject(ref data) => {
let idx = traits::get_vtable_index_of_object_method(tcx, data, method_id);
OperandRef::from_rvalue_datum(
meth::trans_object_shim(ccx, data.upcast_trait_ref.clone(), method_id, idx)
)
}
_ => {
tcx.sess.bug(&format!("static call to invalid vtable: {:?}", vtbl));
}
}
}
}

fn is_named_tuple_constructor(tcx: &ty::ctxt, def_id: DefId) -> bool {
let node_id = match tcx.map.as_local_node_id(def_id) {
Some(n) => n,
None => { return false; }
};
match tcx.map.find(node_id).expect("local item should be in ast map") {
map::NodeVariant(v) => {
v.node.data.is_tuple()
}
map::NodeStructCtor(_) => true,
_ => false
}
}
1 change: 1 addition & 0 deletions src/librustc_trans/trans/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -192,3 +192,4 @@ mod lvalue;
mod rvalue;
mod operand;
mod statement;
mod did;
10 changes: 10 additions & 0 deletions src/librustc_trans/trans/mir/operand.rs
Original file line number Diff line number Diff line change
@@ -76,6 +76,16 @@ impl<'tcx> OperandRef<'tcx> {
}
}
}

pub fn from_rvalue_datum(datum: datum::Datum<'tcx, datum::Rvalue>) -> OperandRef {
OperandRef {
ty: datum.ty,
val: match datum.kind.mode {
datum::RvalueMode::ByRef => OperandValue::Ref(datum.val),
datum::RvalueMode::ByValue => OperandValue::Immediate(datum.val),
}
}
}
}

impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
28 changes: 28 additions & 0 deletions src/test/auxiliary/mir_external_refs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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.


pub struct S(pub u8);

impl S {
pub fn hey() -> u8 { 24 }
}

pub trait X {
fn hoy(&self) -> u8 { 25 }
}

impl X for S {}

pub enum E {
U(u8)
}

pub fn regular_fn() -> u8 { 12 }
218 changes: 218 additions & 0 deletions src/test/run-pass/mir_refs_correct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
// 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)]
// aux-build:mir_external_refs.rs


extern crate mir_external_refs as ext;

struct S(u8);

impl S {
fn hey() -> u8 { 42 }
fn hey2(&self) -> u8 { 44 }
}

trait X {
fn hoy(&self) -> u8 { 43 }
fn hoy2() -> u8 { 45 }
}

trait F<U> {
fn f(self, other: U) -> u64;
}

impl F<u32> for u32 {
fn f(self, other: u32) -> u64 { self as u64 + other as u64 }
}

impl F<u64> for u32 {
fn f(self, other: u64) -> u64 { self as u64 - other }
}

impl F<u64> for u64 {
fn f(self, other: u64) -> u64 { self * other }
}

impl F<u32> for u64 {
fn f(self, other: u32) -> u64 { self ^ other as u64 }
}

trait T<I, O> {
fn staticmeth(i: I, o: O) -> (I, O) { (i, o) }
}

impl<I, O> T<I, O> for O {}

impl X for S {}

enum E {
U(u8)
}

const C: u8 = 84;
const C2: [u8; 5] = [42; 5];
const C3: [u8; 3] = [42, 41, 40];

fn regular() -> u8 {
21
}

fn parametric<T>(u: T) -> T {
u
}

#[rustc_mir]
fn t1() -> fn()->u8 {
regular
}

#[rustc_mir]
fn t2() -> fn(u8)->E {
E::U
}

#[rustc_mir]
fn t3() -> fn(u8)->S {
S
}

#[rustc_mir]
fn t4() -> fn()->u8 {
S::hey
}

#[rustc_mir]
fn t5() -> fn(&S)-> u8 {
<S as X>::hoy
}


#[rustc_mir]
fn t6() -> fn()->u8{
ext::regular_fn
}

#[rustc_mir]
fn t7() -> fn(u8)->ext::E {
ext::E::U
}

#[rustc_mir]
fn t8() -> fn(u8)->ext::S {
ext::S
}

#[rustc_mir]
fn t9() -> fn()->u8 {
ext::S::hey
}

#[rustc_mir]
fn t10() -> fn(&ext::S)->u8 {
<ext::S as ext::X>::hoy
}

#[rustc_mir]
fn t11() -> fn(u8)->u8 {
parametric
}

#[rustc_mir]
fn t12() -> u8 {
C
}

#[rustc_mir]
fn t13() -> [u8; 5] {
C2
}

#[rustc_mir]
fn t13_2() -> [u8; 3] {
C3
}

#[rustc_mir]
fn t14() -> fn()-> u8 {
<S as X>::hoy2
}

#[rustc_mir]
fn t15() -> fn(&S)-> u8 {
S::hey2
}

#[rustc_mir]
fn t16() -> fn(u32, u32)->u64 {
F::f
}

#[rustc_mir]
fn t17() -> fn(u32, u64)->u64 {
F::f
}

#[rustc_mir]
fn t18() -> fn(u64, u64)->u64 {
F::f
}

#[rustc_mir]
fn t19() -> fn(u64, u32)->u64 {
F::f
}

#[rustc_mir]
fn t20() -> fn(u64, u32)->(u64, u32) {
<u32 as T<_, _>>::staticmeth
}

fn main(){
unsafe {
assert_eq!(t1()(), regular());

assert!(::std::mem::transmute::<_, *mut ()>(t2()) ==
::std::mem::transmute::<_, *mut ()>(E::U));
assert!(::std::mem::transmute::<_, *mut ()>(t3()) ==
::std::mem::transmute::<_, *mut ()>(S));

assert_eq!(t4()(), S::hey());
let s = S(42);
assert_eq!(t5()(&s), <S as X>::hoy(&s));


assert_eq!(t6()(), ext::regular_fn());
assert!(::std::mem::transmute::<_, *mut ()>(t7()) ==
::std::mem::transmute::<_, *mut ()>(ext::E::U));
assert!(::std::mem::transmute::<_, *mut ()>(t8()) ==
::std::mem::transmute::<_, *mut ()>(ext::S));

assert_eq!(t9()(), ext::S::hey());
let sext = ext::S(6);
assert_eq!(t10()(&sext), <ext::S as ext::X>::hoy(&sext));

let p = parametric::<u8>;
assert!(::std::mem::transmute::<_, *mut ()>(t11()) ==
::std::mem::transmute::<_, *mut ()>(p));

assert_eq!(t12(), C);
assert_eq!(t13(), C2);
assert_eq!(t13_2(), C3);

assert_eq!(t14()(), <S as X>::hoy2());
assert_eq!(t15()(&s), S::hey2(&s));
assert_eq!(t16()(10u32, 20u32), F::f(10u32, 20u32));
assert_eq!(t17()(30u32, 10u64), F::f(30u32, 10u64));
assert_eq!(t18()(50u64, 5u64), F::f(50u64, 5u64));
assert_eq!(t19()(322u64, 2u32), F::f(322u64, 2u32));
assert_eq!(t20()(123u64, 38u32), <u32 as T<_, _>>::staticmeth(123, 38));
}
}