99// except according to those terms.
1010
1111use llvm:: { BasicBlockRef , ValueRef } ;
12+ use rustc:: middle:: ty;
1213use rustc:: mir:: repr as mir;
14+ use syntax:: abi:: Abi ;
1315use trans:: adt;
16+ use trans:: attributes;
1417use trans:: base;
1518use trans:: build;
16- use trans:: attributes;
1719use trans:: common:: { self , Block } ;
1820use trans:: debuginfo:: DebugLoc ;
21+ use trans:: foreign;
1922use trans:: type_of;
2023use trans:: type_:: Type ;
2124
@@ -57,7 +60,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
5760 // The else branch of the Switch can't be hit, so branch to an unreachable
5861 // instruction so LLVM knows that
5962 let unreachable_blk = self . unreachable_block ( ) ;
60-
6163 let switch = build:: Switch ( bcx, discr, unreachable_blk. llbb , targets. len ( ) ) ;
6264 assert_eq ! ( adt_def. variants. len( ) , targets. len( ) ) ;
6365 for ( adt_variant, target) in adt_def. variants . iter ( ) . zip ( targets) {
@@ -98,12 +100,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
98100 let debugloc = DebugLoc :: None ;
99101 // The arguments we'll be passing. Plus one to account for outptr, if used.
100102 let mut llargs = Vec :: with_capacity ( args. len ( ) + 1 ) ;
103+ // Types of the arguments. We do not preallocate, because this vector is only
104+ // filled when `is_foreign` is `true` and foreign calls are minority of the cases.
105+ let mut arg_tys = Vec :: new ( ) ;
106+
107+ // Foreign-ABI functions are translated differently
108+ let is_foreign = if let ty:: TyBareFn ( _, ref f) = callee. ty . sty {
109+ // We do not translate intrinsics here (they shouldn’t be functions)
110+ assert ! ( f. abi != Abi :: RustIntrinsic && f. abi != Abi :: PlatformIntrinsic ) ;
111+ f. abi != Abi :: Rust && f. abi != Abi :: RustCall
112+ } else {
113+ false
114+ } ;
101115
102116 // Prepare the return value destination
103117 let ( ret_dest_ty, must_copy_dest) = if let Some ( d) = kind. destination ( ) {
104118 let dest = self . trans_lvalue ( bcx, d) ;
105119 let ret_ty = dest. ty . to_ty ( bcx. tcx ( ) ) ;
106- if type_of:: return_uses_outptr ( bcx. ccx ( ) , ret_ty) {
120+ if !is_foreign && type_of:: return_uses_outptr ( bcx. ccx ( ) , ret_ty) {
107121 llargs. push ( dest. llval ) ;
108122 ( Some ( ( dest, ret_ty) ) , false )
109123 } else {
@@ -115,30 +129,35 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
115129
116130 // Process the rest of the args.
117131 for arg in args {
118- match self . trans_operand ( bcx, arg) . val {
132+ let operand = self . trans_operand ( bcx, arg) ;
133+ match operand. val {
119134 Ref ( llval) | Immediate ( llval) => llargs. push ( llval) ,
120135 FatPtr ( b, e) => {
121136 llargs. push ( b) ;
122137 llargs. push ( e) ;
123138 }
124139 }
140+ if is_foreign {
141+ arg_tys. push ( operand. ty ) ;
142+ }
125143 }
126144
127145 // Many different ways to call a function handled here
128- match ( base:: avoid_invoke ( bcx) , kind) {
146+ match ( is_foreign , base:: avoid_invoke ( bcx) , kind) {
129147 // The two cases below are the only ones to use LLVM’s `invoke`.
130- ( false , & mir:: CallKind :: DivergingCleanup ( cleanup) ) => {
148+ ( false , false , & mir:: CallKind :: DivergingCleanup ( cleanup) ) => {
131149 let cleanup = self . bcx ( cleanup) ;
132150 let landingpad = self . make_landing_pad ( cleanup) ;
151+ let unreachable_blk = self . unreachable_block ( ) ;
133152 build:: Invoke ( bcx,
134153 callee. immediate ( ) ,
135154 & llargs[ ..] ,
136- self . unreachable_block ( ) . llbb ,
155+ unreachable_blk . llbb ,
137156 landingpad. llbb ,
138157 Some ( attrs) ,
139158 debugloc) ;
140159 } ,
141- ( false , & mir:: CallKind :: ConvergingCleanup { ref targets, .. } ) => {
160+ ( false , false , & mir:: CallKind :: ConvergingCleanup { ref targets, .. } ) => {
142161 let cleanup = self . bcx ( targets. 1 ) ;
143162 let landingpad = self . make_landing_pad ( cleanup) ;
144163 let ( target, postinvoke) = if must_copy_dest {
@@ -184,14 +203,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
184203 build:: Br ( target, postinvoketarget. llbb , debugloc) ;
185204 }
186205 } ,
187- ( _, & mir:: CallKind :: DivergingCleanup ( _) ) |
188- ( _, & mir:: CallKind :: Diverging ) => {
206+ ( false , _, & mir:: CallKind :: DivergingCleanup ( _) ) |
207+ ( false , _, & mir:: CallKind :: Diverging ) => {
189208 build:: Call ( bcx, callee. immediate ( ) , & llargs[ ..] , Some ( attrs) , debugloc) ;
190209 build:: Unreachable ( bcx) ;
191210 }
192- ( _, k@& mir:: CallKind :: ConvergingCleanup { .. } ) |
193- ( _, k@& mir:: CallKind :: Converging { .. } ) => {
194- // Bug #20046
211+ ( false , _, k@& mir:: CallKind :: ConvergingCleanup { .. } ) |
212+ ( false , _, k@& mir:: CallKind :: Converging { .. } ) => {
213+ // FIXME: Bug #20046
195214 let target = match * k {
196215 mir:: CallKind :: ConvergingCleanup { targets, .. } => targets. 0 ,
197216 mir:: CallKind :: Converging { target, .. } => target,
@@ -209,6 +228,25 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
209228 }
210229 build:: Br ( bcx, self . llblock ( target) , debugloc) ;
211230 }
231+ // Foreign functions
232+ ( true , _, k) => {
233+ let ( dest, _) = ret_dest_ty
234+ . expect ( "return destination is not set" ) ;
235+ bcx = foreign:: trans_native_call ( bcx,
236+ callee. ty ,
237+ callee. immediate ( ) ,
238+ dest. llval ,
239+ & llargs[ ..] ,
240+ arg_tys,
241+ debugloc) ;
242+ match * k {
243+ mir:: CallKind :: ConvergingCleanup { targets, .. } =>
244+ build:: Br ( bcx, self . llblock ( targets. 0 ) , debugloc) ,
245+ mir:: CallKind :: Converging { target, .. } =>
246+ build:: Br ( bcx, self . llblock ( target) , debugloc) ,
247+ _ => ( )
248+ } ;
249+ } ,
212250 }
213251 }
214252 }
0 commit comments