99// except according to those terms.
1010
1111use rustc:: hir;
12+ use rustc:: hir:: def_id:: DefId ;
1213use rustc:: infer;
14+ use rustc:: middle:: region:: ROOT_CODE_EXTENT ;
1315use rustc:: mir:: * ;
1416use rustc:: mir:: transform:: MirSource ;
1517use rustc:: ty:: { self , Ty } ;
18+ use rustc:: ty:: subst:: Subst ;
1619use rustc:: ty:: maps:: Providers ;
1720
1821use rustc_data_structures:: indexed_vec:: { IndexVec , Idx } ;
1922
2023use syntax:: abi:: Abi ;
2124use syntax:: ast;
22- use syntax:: codemap:: DUMMY_SP ;
2325use syntax_pos:: Span ;
2426
2527use 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+
54112fn 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
0 commit comments