9
9
// except according to those terms.
10
10
11
11
use llvm:: { BasicBlockRef , ValueRef } ;
12
+ use rustc:: middle:: ty;
12
13
use rustc:: mir:: repr as mir;
14
+ use syntax:: abi:: Abi ;
13
15
use trans:: adt;
16
+ use trans:: attributes;
14
17
use trans:: base;
15
18
use trans:: build;
16
- use trans:: attributes;
17
19
use trans:: common:: { self , Block } ;
18
20
use trans:: debuginfo:: DebugLoc ;
21
+ use trans:: foreign;
19
22
use trans:: type_of;
20
23
use trans:: type_:: Type ;
21
24
@@ -98,12 +101,24 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
98
101
let debugloc = DebugLoc :: None ;
99
102
// The arguments we'll be passing. Plus one to account for outptr, if used.
100
103
let mut llargs = Vec :: with_capacity ( args. len ( ) + 1 ) ;
104
+ // Types of the arguments. We do not preallocate, because this vector is only
105
+ // filled when `is_foreign` is `true` and foreign calls are minority of the cases.
106
+ let mut arg_tys = Vec :: new ( ) ;
107
+
108
+ // Foreign-ABI functions are translated differently
109
+ let is_foreign = if let ty:: TyBareFn ( _, ref f) = callee. ty . sty {
110
+ // We do not translate intrinsics here (they shouldn’t be functions)
111
+ assert ! ( f. abi != Abi :: RustIntrinsic && f. abi != Abi :: PlatformIntrinsic ) ;
112
+ f. abi != Abi :: Rust && f. abi != Abi :: RustCall
113
+ } else {
114
+ false
115
+ } ;
101
116
102
117
// Prepare the return value destination
103
118
let ( ret_dest_ty, must_copy_dest) = if let Some ( ref d) = kind. destination ( ) {
104
119
let dest = self . trans_lvalue ( bcx, d) ;
105
120
let ret_ty = dest. ty . to_ty ( bcx. tcx ( ) ) ;
106
- if type_of:: return_uses_outptr ( bcx. ccx ( ) , ret_ty) {
121
+ if !is_foreign && type_of:: return_uses_outptr ( bcx. ccx ( ) , ret_ty) {
107
122
llargs. push ( dest. llval ) ;
108
123
( Some ( ( dest, ret_ty) ) , false )
109
124
} else {
@@ -115,19 +130,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
115
130
116
131
// Process the rest of the args.
117
132
for arg in args {
118
- match self . trans_operand ( bcx, arg) . val {
133
+ let operand = self . trans_operand ( bcx, arg) ;
134
+ match operand. val {
119
135
Ref ( llval) | Immediate ( llval) => llargs. push ( llval) ,
120
136
FatPtr ( b, e) => {
121
137
llargs. push ( b) ;
122
138
llargs. push ( e) ;
123
139
}
124
140
}
141
+ if is_foreign {
142
+ arg_tys. push ( operand. ty ) ;
143
+ }
125
144
}
126
145
127
146
// Many different ways to call a function handled here
128
- match ( base:: avoid_invoke ( bcx) , kind) {
147
+ match ( is_foreign , base:: avoid_invoke ( bcx) , kind) {
129
148
// The two cases below are the only ones to use LLVM’s `invoke`.
130
- ( false , & mir:: CallKind :: DivergingCleanup ( cleanup) ) => {
149
+ ( false , false , & mir:: CallKind :: DivergingCleanup ( cleanup) ) => {
131
150
let cleanup = self . bcx ( cleanup) ;
132
151
let landingpad = self . make_landing_pad ( cleanup) ;
133
152
build:: Invoke ( bcx,
@@ -138,7 +157,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
138
157
Some ( attrs) ,
139
158
debugloc) ;
140
159
} ,
141
- ( false , & mir:: CallKind :: ConvergingCleanup { ref targets, .. } ) => {
160
+ ( false , false , & mir:: CallKind :: ConvergingCleanup { ref targets, .. } ) => {
142
161
let cleanup = self . bcx ( targets. 1 ) ;
143
162
let landingpad = self . make_landing_pad ( cleanup) ;
144
163
let ( target, postinvoke) = if must_copy_dest {
@@ -184,14 +203,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
184
203
build:: Br ( target, postinvoketarget. llbb , debugloc) ;
185
204
}
186
205
} ,
187
- ( _, & mir:: CallKind :: DivergingCleanup ( _) ) |
188
- ( _, & mir:: CallKind :: Diverging ) => {
206
+ ( false , _, & mir:: CallKind :: DivergingCleanup ( _) ) |
207
+ ( false , _, & mir:: CallKind :: Diverging ) => {
189
208
build:: Call ( bcx, callee. immediate ( ) , & llargs[ ..] , Some ( attrs) , debugloc) ;
190
209
build:: Unreachable ( bcx) ;
191
210
}
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
195
214
let target = match * k {
196
215
mir:: CallKind :: ConvergingCleanup { targets, .. } => targets. 0 ,
197
216
mir:: CallKind :: Converging { target, .. } => target,
@@ -209,6 +228,25 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
209
228
}
210
229
build:: Br ( bcx, self . llblock ( target) , debugloc) ;
211
230
}
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
+ } ,
212
250
}
213
251
}
214
252
}
0 commit comments