Skip to content

Commit 65a4266

Browse files
committed
refactor away callee::Callee and translate virtual calls through a MIR shim
These changes are in the same commit to avoid needing to adapt meth::trans_object_shim to the new scheme. One codegen-units test is broken because we instantiate the shims even when they are not needed. This will be fixed in the next PR.
1 parent aac5ba5 commit 65a4266

File tree

13 files changed

+324
-367
lines changed

13 files changed

+324
-367
lines changed

src/librustc_mir/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
2323
#![feature(associated_consts)]
2424
#![feature(box_patterns)]
2525
#![feature(box_syntax)]
26+
#![cfg_attr(stage0, feature(field_init_shorthand))]
2627
#![feature(i128_type)]
2728
#![feature(rustc_diagnostic_macros)]
2829
#![feature(rustc_private)]

src/librustc_mir/mir_map.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -252,12 +252,9 @@ fn closure_self_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
252252
-> Ty<'tcx> {
253253
let closure_ty = tcx.body_tables(body_id).node_id_to_type(closure_expr_id);
254254

255-
// We're just hard-coding the idea that the signature will be
256-
// &self or &mut self and hence will have a bound region with
257-
// number 0, hokey.
258255
let region = ty::Region::ReFree(ty::FreeRegion {
259256
scope: tcx.region_maps.item_extent(body_id.node_id),
260-
bound_region: ty::BoundRegion::BrAnon(0),
257+
bound_region: ty::BoundRegion::BrEnv,
261258
});
262259
let region = tcx.mk_region(region);
263260

src/librustc_mir/shim.rs

Lines changed: 133 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,19 @@
99
// except according to those terms.
1010

1111
use rustc::hir;
12+
use rustc::hir::def_id::DefId;
1213
use rustc::infer;
14+
use rustc::middle::region::ROOT_CODE_EXTENT;
1315
use rustc::mir::*;
1416
use rustc::mir::transform::MirSource;
1517
use rustc::ty::{self, Ty};
18+
use rustc::ty::subst::Subst;
1619
use rustc::ty::maps::Providers;
1720

1821
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
1922

2023
use syntax::abi::Abi;
2124
use syntax::ast;
22-
use syntax::codemap::DUMMY_SP;
2325
use syntax_pos::Span;
2426

2527
use std::cell::RefCell;
@@ -35,11 +37,51 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
3537
-> &'tcx RefCell<Mir<'tcx>>
3638
{
3739
debug!("make_shim({:?})", instance);
40+
let did = instance.def_id();
41+
let span = tcx.def_span(did);
42+
let param_env =
43+
tcx.construct_parameter_environment(span, did, ROOT_CODE_EXTENT);
44+
3845
let result = match instance {
3946
ty::InstanceDef::Item(..) =>
4047
bug!("item {:?} passed to make_shim", instance),
41-
ty::InstanceDef::FnPtrShim(_, ty) => {
42-
build_fn_ptr_shim(tcx, ty, instance.def_ty(tcx))
48+
ty::InstanceDef::FnPtrShim(def_id, ty) => {
49+
let trait_ = tcx.trait_of_item(def_id).unwrap();
50+
let adjustment = match tcx.lang_items.fn_trait_kind(trait_) {
51+
Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
52+
Some(ty::ClosureKind::FnMut) |
53+
Some(ty::ClosureKind::Fn) => Adjustment::Deref,
54+
None => bug!("fn pointer {:?} is not an fn", ty)
55+
};
56+
// HACK: we need the "real" argument types for the MIR,
57+
// but because our substs are (Self, Args), where Args
58+
// is a tuple, we must include the *concrete* argument
59+
// types in the MIR. They will be substituted again with
60+
// the param-substs, but because they are concrete, this
61+
// will not do any harm.
62+
let sig = tcx.erase_late_bound_regions(&ty.fn_sig());
63+
let arg_tys = sig.inputs();
64+
65+
build_call_shim(
66+
tcx,
67+
&param_env,
68+
def_id,
69+
adjustment,
70+
CallKind::Indirect,
71+
Some(arg_tys)
72+
)
73+
}
74+
ty::InstanceDef::Virtual(def_id, _) => {
75+
// We are translating a call back to our def-id, which
76+
// trans::mir knows to turn to an actual virtual call.
77+
build_call_shim(
78+
tcx,
79+
&param_env,
80+
def_id,
81+
Adjustment::Identity,
82+
CallKind::Direct(def_id),
83+
None
84+
)
4385
}
4486
_ => bug!("unknown shim kind")
4587
};
@@ -51,124 +93,135 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
5193
result
5294
}
5395

96+
#[derive(Copy, Clone, Debug, PartialEq)]
97+
enum Adjustment {
98+
Identity,
99+
Deref,
100+
}
101+
102+
#[derive(Copy, Clone, Debug, PartialEq)]
103+
enum CallKind {
104+
Indirect,
105+
Direct(DefId),
106+
}
107+
108+
fn temp_decl(mutability: Mutability, ty: Ty) -> LocalDecl {
109+
LocalDecl { mutability, ty, name: None, source_info: None }
110+
}
111+
54112
fn local_decls_for_sig<'tcx>(sig: &ty::FnSig<'tcx>)
55113
-> IndexVec<Local, LocalDecl<'tcx>>
56114
{
57-
iter::once(LocalDecl {
58-
mutability: Mutability::Mut,
59-
ty: sig.output(),
60-
name: None,
61-
source_info: None
62-
}).chain(sig.inputs().iter().map(|ity| LocalDecl {
63-
mutability: Mutability::Not,
64-
ty: *ity,
65-
name: None,
66-
source_info: None,
67-
})).collect()
115+
iter::once(temp_decl(Mutability::Mut, sig.output()))
116+
.chain(sig.inputs().iter().map(
117+
|ity| temp_decl(Mutability::Not, ity)))
118+
.collect()
68119
}
69120

70-
71-
fn build_fn_ptr_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
72-
fn_ty: Ty<'tcx>,
73-
sig_ty: Ty<'tcx>)
74-
-> Mir<'tcx>
121+
/// Build a "call" shim for `def_id`. The shim calls the
122+
/// function specified by `call_kind`, first adjusting its first
123+
/// argument according to `rcvr_adjustment`.
124+
///
125+
/// If `untuple_args` is a vec of types, the second argument of the
126+
/// function will be untupled as these types.
127+
fn build_call_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
128+
param_env: &ty::ParameterEnvironment<'tcx>,
129+
def_id: DefId,
130+
rcvr_adjustment: Adjustment,
131+
call_kind: CallKind,
132+
untuple_args: Option<&[Ty<'tcx>]>)
133+
-> Mir<'tcx>
75134
{
76-
debug!("build_fn_ptr_shim(fn_ty={:?}, sig_ty={:?})", fn_ty, sig_ty);
77-
let trait_sig = match sig_ty.sty {
78-
ty::TyFnDef(_, _, fty) => tcx.erase_late_bound_regions(&fty),
79-
_ => bug!("unexpected type for shim {:?}", sig_ty)
80-
};
135+
debug!("build_call_shim(def_id={:?}, rcvr_adjustment={:?}, \
136+
call_kind={:?}, untuple_args={:?})",
137+
def_id, rcvr_adjustment, call_kind, untuple_args);
81138

82-
let self_ty = match trait_sig.inputs()[0].sty {
83-
ty::TyParam(..) => fn_ty,
84-
ty::TyRef(r, mt) => tcx.mk_ref(r, ty::TypeAndMut {
85-
ty: fn_ty,
86-
mutbl: mt.mutbl
87-
}),
88-
_ => bug!("unexpected self_ty {:?}", trait_sig),
89-
};
139+
let fn_ty = tcx.item_type(def_id).subst(tcx, param_env.free_substs);
140+
// Not normalizing here without a param env.
141+
let sig = tcx.erase_late_bound_regions(&fn_ty.fn_sig());
142+
let span = tcx.def_span(def_id);
90143

91-
let fn_ptr_sig = match fn_ty.sty {
92-
ty::TyFnPtr(fty) |
93-
ty::TyFnDef(_, _, fty) =>
94-
tcx.erase_late_bound_regions_and_normalize(&fty),
95-
_ => bug!("non-fn-ptr {:?} in build_fn_ptr_shim", fn_ty)
96-
};
97-
98-
let sig = tcx.mk_fn_sig(
99-
[
100-
self_ty,
101-
tcx.intern_tup(fn_ptr_sig.inputs(), false)
102-
].iter().cloned(),
103-
fn_ptr_sig.output(),
104-
false,
105-
hir::Unsafety::Normal,
106-
Abi::RustCall,
107-
);
144+
debug!("build_call_shim: sig={:?}", sig);
108145

109146
let local_decls = local_decls_for_sig(&sig);
110-
let source_info = SourceInfo {
111-
span: DUMMY_SP,
112-
scope: ARGUMENT_VISIBILITY_SCOPE
147+
let source_info = SourceInfo { span, scope: ARGUMENT_VISIBILITY_SCOPE };
148+
149+
let rcvr_l = Lvalue::Local(Local::new(1+0));
150+
151+
let return_block_id = BasicBlock::new(1);
152+
153+
let rcvr = match rcvr_adjustment {
154+
Adjustment::Identity => Operand::Consume(rcvr_l),
155+
Adjustment::Deref => Operand::Consume(Lvalue::Projection(
156+
box Projection { base: rcvr_l, elem: ProjectionElem::Deref }
157+
))
113158
};
114159

115-
let fn_ptr = Lvalue::Local(Local::new(1+0));
116-
let fn_ptr = match trait_sig.inputs()[0].sty {
117-
ty::TyParam(..) => fn_ptr,
118-
ty::TyRef(..) => Lvalue::Projection(box Projection {
119-
base: fn_ptr, elem: ProjectionElem::Deref
120-
}),
121-
_ => bug!("unexpected self_ty {:?}", trait_sig),
160+
let (callee, mut args) = match call_kind {
161+
CallKind::Indirect => (rcvr, vec![]),
162+
CallKind::Direct(def_id) => (
163+
Operand::Constant(Constant {
164+
span: span,
165+
ty: tcx.item_type(def_id).subst(tcx, param_env.free_substs),
166+
literal: Literal::Item { def_id, substs: param_env.free_substs },
167+
}),
168+
vec![rcvr]
169+
)
122170
};
123-
let fn_args = Local::new(1+1);
124171

125-
let return_block_id = BasicBlock::new(1);
172+
if let Some(untuple_args) = untuple_args {
173+
args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
174+
let arg_lv = Lvalue::Local(Local::new(1+1));
175+
Operand::Consume(Lvalue::Projection(box Projection {
176+
base: arg_lv,
177+
elem: ProjectionElem::Field(Field::new(i), *ity)
178+
}))
179+
}));
180+
} else {
181+
args.extend((1..sig.inputs().len()).map(|i| {
182+
Operand::Consume(Lvalue::Local(Local::new(1+i)))
183+
}));
184+
}
126185

127-
// return = ADT(arg0, arg1, ...); return
128-
let start_block = BasicBlockData {
186+
let mut blocks = IndexVec::new();
187+
blocks.push(BasicBlockData {
129188
statements: vec![],
130189
terminator: Some(Terminator {
131190
source_info: source_info,
132191
kind: TerminatorKind::Call {
133-
func: Operand::Consume(fn_ptr),
134-
args: fn_ptr_sig.inputs().iter().enumerate().map(|(i, ity)| {
135-
Operand::Consume(Lvalue::Projection(box Projection {
136-
base: Lvalue::Local(fn_args),
137-
elem: ProjectionElem::Field(
138-
Field::new(i), *ity
139-
)
140-
}))
141-
}).collect(),
142-
// FIXME: can we pass a Some destination for an uninhabited ty?
192+
func: callee,
193+
args: args,
143194
destination: Some((Lvalue::Local(RETURN_POINTER),
144195
return_block_id)),
145196
cleanup: None
146197
}
147198
}),
148199
is_cleanup: false
149-
};
150-
let return_block = BasicBlockData {
200+
});
201+
blocks.push(BasicBlockData {
151202
statements: vec![],
152203
terminator: Some(Terminator {
153204
source_info: source_info,
154205
kind: TerminatorKind::Return
155206
}),
156207
is_cleanup: false
157-
};
208+
});
158209

159210
let mut mir = Mir::new(
160-
vec![start_block, return_block].into_iter().collect(),
211+
blocks,
161212
IndexVec::from_elem_n(
162-
VisibilityScopeData { span: DUMMY_SP, parent_scope: None }, 1
213+
VisibilityScopeData { span: span, parent_scope: None }, 1
163214
),
164215
IndexVec::new(),
165216
sig.output(),
166217
local_decls,
167218
sig.inputs().len(),
168219
vec![],
169-
DUMMY_SP
220+
span
170221
);
171-
mir.spread_arg = Some(fn_args);
222+
if let Abi::RustCall = sig.abi {
223+
mir.spread_arg = Some(Local::new(sig.inputs().len()));
224+
}
172225
mir
173226
}
174227

src/librustc_trans/abi.rs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use llvm::{self, ValueRef, Integer, Pointer, Float, Double, Struct, Array, Vector, AttributePlace};
1212
use base;
1313
use builder::Builder;
14-
use common::{type_is_fat_ptr, C_uint};
14+
use common::{self, type_is_fat_ptr, C_uint};
1515
use context::CrateContext;
1616
use cabi_x86;
1717
use cabi_x86_64;
@@ -334,9 +334,30 @@ impl FnType {
334334
fn_ty
335335
}
336336

337-
pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
337+
pub fn new_vtable<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
338338
sig: ty::FnSig<'tcx>,
339339
extra_args: &[Ty<'tcx>]) -> FnType {
340+
let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
341+
// Don't pass the vtable, it's not an argument of the virtual fn.
342+
fn_ty.args[1].ignore();
343+
fn_ty.adjust_for_abi(ccx, sig);
344+
fn_ty
345+
}
346+
347+
pub fn from_instance<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
348+
instance: &ty::Instance<'tcx>,
349+
extra_args: &[Ty<'tcx>]) -> FnType
350+
{
351+
let ity = common::instance_ty(ccx.shared(), instance);
352+
let sig = common::ty_fn_sig(ccx, ity);
353+
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
354+
355+
Self::new(ccx, sig, extra_args)
356+
}
357+
358+
fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
359+
sig: ty::FnSig<'tcx>,
360+
extra_args: &[Ty<'tcx>]) -> FnType {
340361
use self::Abi::*;
341362
let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) {
342363
RustIntrinsic | PlatformIntrinsic |
@@ -532,9 +553,9 @@ impl FnType {
532553
}
533554
}
534555

535-
pub fn adjust_for_abi<'a, 'tcx>(&mut self,
536-
ccx: &CrateContext<'a, 'tcx>,
537-
sig: ty::FnSig<'tcx>) {
556+
fn adjust_for_abi<'a, 'tcx>(&mut self,
557+
ccx: &CrateContext<'a, 'tcx>,
558+
sig: ty::FnSig<'tcx>) {
538559
let abi = sig.abi;
539560
if abi == Abi::Unadjusted { return }
540561

src/librustc_trans/base.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use abi;
4747
use mir::lvalue::LvalueRef;
4848
use attributes;
4949
use builder::Builder;
50-
use callee::{Callee};
50+
use callee;
5151
use common::{C_bool, C_bytes_in_context, C_i32, C_uint};
5252
use collector::{self, TransItemCollectionMode};
5353
use common::{C_struct_in_context, C_u64, C_undef};
@@ -654,7 +654,7 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
654654
return;
655655
}
656656

657-
let main_llfn = Callee::def(ccx, main_def_id, instance.substs).reify(ccx);
657+
let main_llfn = callee::get_fn(ccx, instance);
658658

659659
let et = ccx.sess().entry_type.get().unwrap();
660660
match et {
@@ -688,8 +688,8 @@ pub fn maybe_create_entry_wrapper(ccx: &CrateContext) {
688688

689689
let (start_fn, args) = if use_start_lang_item {
690690
let start_def_id = ccx.tcx().require_lang_item(StartFnLangItem);
691-
let empty_substs = ccx.tcx().intern_substs(&[]);
692-
let start_fn = Callee::def(ccx, start_def_id, empty_substs).reify(ccx);
691+
let start_instance = Instance::mono(ccx.tcx(), start_def_id);
692+
let start_fn = callee::get_fn(ccx, start_instance);
693693
(start_fn, vec![bld.pointercast(rust_main, Type::i8p(ccx).ptr_to()), get_param(llfn, 0),
694694
get_param(llfn, 1)])
695695
} else {

0 commit comments

Comments
 (0)