@@ -15,9 +15,9 @@ use syntax::source_map::Span;
15
15
use rustc_target:: spec:: abi:: Abi ;
16
16
17
17
use rustc:: mir:: interpret:: { EvalResult , Scalar } ;
18
- use super :: { EvalContext , Machine , Value , OpTy , Place , PlaceTy , ValTy , Operand , StackPopCleanup } ;
19
-
20
- use rustc_data_structures :: indexed_vec :: Idx ;
18
+ use super :: {
19
+ EvalContext , Machine , Value , OpTy , Place , PlaceTy , ValTy , Operand , StackPopCleanup
20
+ } ;
21
21
22
22
mod drop;
23
23
@@ -96,44 +96,44 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
96
96
let instance_ty = instance. ty ( * self . tcx ) ;
97
97
match instance_ty. sty {
98
98
ty:: FnDef ( ..) => {
99
- let real_sig = instance_ty. fn_sig ( * self . tcx ) ;
100
99
let sig = self . tcx . normalize_erasing_late_bound_regions (
101
- ty :: ParamEnv :: reveal_all ( ) ,
100
+ self . param_env ,
102
101
& sig,
103
102
) ;
103
+ let real_sig = instance_ty. fn_sig ( * self . tcx ) ;
104
104
let real_sig = self . tcx . normalize_erasing_late_bound_regions (
105
- ty :: ParamEnv :: reveal_all ( ) ,
105
+ self . param_env ,
106
106
& real_sig,
107
107
) ;
108
108
if !self . check_sig_compat ( sig, real_sig) ? {
109
109
return err ! ( FunctionPointerTyMismatch ( real_sig, sig) ) ;
110
110
}
111
+ ( instance, sig)
111
112
}
112
113
ref other => bug ! ( "instance def ty: {:?}" , other) ,
113
114
}
114
- ( instance, sig)
115
115
}
116
- ty:: FnDef ( def_id, substs) => (
117
- self . resolve ( def_id, substs) ?,
118
- func. layout . ty . fn_sig ( * self . tcx ) ,
119
- ) ,
116
+ ty:: FnDef ( def_id, substs) => {
117
+ let sig = func. layout . ty . fn_sig ( * self . tcx ) ;
118
+ let sig = self . tcx . normalize_erasing_late_bound_regions (
119
+ self . param_env ,
120
+ & sig,
121
+ ) ;
122
+ ( self . resolve ( def_id, substs) ?, sig)
123
+ } ,
120
124
_ => {
121
125
let msg = format ! ( "can't handle callee of type {:?}" , func. layout. ty) ;
122
126
return err ! ( Unimplemented ( msg) ) ;
123
127
}
124
128
} ;
125
129
let args = self . eval_operands ( args) ?;
126
- let sig = self . tcx . normalize_erasing_late_bound_regions (
127
- ty:: ParamEnv :: reveal_all ( ) ,
128
- & sig,
129
- ) ;
130
130
self . eval_fn_call (
131
131
fn_def,
132
132
& args[ ..] ,
133
133
dest,
134
134
ret,
135
135
terminator. source_info . span ,
136
- sig,
136
+ Some ( sig) ,
137
137
) ?;
138
138
}
139
139
@@ -275,19 +275,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
275
275
return Ok ( false ) ;
276
276
}
277
277
278
+ /// Call this function -- pushing the stack frame and initializing the arguments.
279
+ /// `sig` is ptional in case of FnPtr/FnDef -- but mandatory for closures!
278
280
fn eval_fn_call (
279
281
& mut self ,
280
282
instance : ty:: Instance < ' tcx > ,
281
283
args : & [ OpTy < ' tcx > ] ,
282
284
dest : Option < PlaceTy < ' tcx > > ,
283
285
ret : Option < mir:: BasicBlock > ,
284
286
span : Span ,
285
- sig : ty:: FnSig < ' tcx > ,
287
+ sig : Option < ty:: FnSig < ' tcx > > ,
286
288
) -> EvalResult < ' tcx > {
287
289
trace ! ( "eval_fn_call: {:#?}" , instance) ;
288
- if let Some ( place) = dest {
289
- assert_eq ! ( place. layout. ty, sig. output( ) ) ;
290
- }
290
+
291
291
match instance. def {
292
292
ty:: InstanceDef :: Intrinsic ( ..) => {
293
293
// The intrinsic itself cannot diverge, so if we got here without a return
@@ -303,58 +303,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
303
303
self . dump_place ( * dest) ;
304
304
Ok ( ( ) )
305
305
}
306
- // FIXME: figure out why we can't just go through the shim
307
- ty:: InstanceDef :: ClosureOnceShim { .. } => {
308
- let mir = match M :: find_fn ( self , instance, args, dest, ret) ? {
309
- Some ( mir) => mir,
310
- None => return Ok ( ( ) ) ,
311
- } ;
312
-
313
- let return_place = match dest {
314
- Some ( place) => * place,
315
- None => Place :: null ( & self ) ,
316
- } ;
317
- self . push_stack_frame (
318
- instance,
319
- span,
320
- mir,
321
- return_place,
322
- StackPopCleanup :: Goto ( ret) ,
323
- ) ?;
324
-
325
- // Pass the arguments
326
- let mut arg_locals = self . frame ( ) . mir . args_iter ( ) ;
327
- match sig. abi {
328
- // closure as closure once
329
- Abi :: RustCall => {
330
- for ( arg_local, & op) in arg_locals. zip ( args) {
331
- let dest = self . eval_place ( & mir:: Place :: Local ( arg_local) ) ?;
332
- self . copy_op ( op, dest) ?;
333
- }
334
- }
335
- // non capture closure as fn ptr
336
- // need to inject zst ptr for closure object (aka do nothing)
337
- // and need to pack arguments
338
- Abi :: Rust => {
339
- trace ! (
340
- "args: {:#?}" ,
341
- self . frame( ) . mir. args_iter( ) . zip( args. iter( ) )
342
- . map( |( local, arg) | ( local, * * arg, arg. layout. ty) )
343
- . collect:: <Vec <_>>( )
344
- ) ;
345
- let local = arg_locals. nth ( 1 ) . unwrap ( ) ;
346
- for ( i, & op) in args. into_iter ( ) . enumerate ( ) {
347
- let dest = self . eval_place ( & mir:: Place :: Local ( local) . field (
348
- mir:: Field :: new ( i) ,
349
- op. layout . ty ,
350
- ) ) ?;
351
- self . copy_op ( op, dest) ?;
352
- }
353
- }
354
- _ => bug ! ( "bad ABI for ClosureOnceShim: {:?}" , sig. abi) ,
355
- }
356
- Ok ( ( ) )
357
- }
306
+ ty:: InstanceDef :: ClosureOnceShim { .. } |
358
307
ty:: InstanceDef :: FnPtrShim ( ..) |
359
308
ty:: InstanceDef :: DropGlue ( ..) |
360
309
ty:: InstanceDef :: CloneShim ( ..) |
@@ -376,58 +325,94 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
376
325
StackPopCleanup :: Goto ( ret) ,
377
326
) ?;
378
327
379
- // Pass the arguments
380
- let mut arg_locals = self . frame ( ) . mir . args_iter ( ) ;
328
+ // If we didn't get a signture, ask `fn_sig`
329
+ let sig = sig. unwrap_or_else ( || {
330
+ let fn_sig = instance. ty ( * self . tcx ) . fn_sig ( * self . tcx ) ;
331
+ self . tcx . normalize_erasing_late_bound_regions ( self . param_env , & fn_sig)
332
+ } ) ;
333
+ assert_eq ! ( sig. inputs( ) . len( ) , args. len( ) ) ;
334
+ // We can't test the types, as it is fine if the types are ABI-compatible but
335
+ // not equal.
336
+
337
+ // Figure out how to pass which arguments.
338
+ // FIXME: Somehow this is horribly full of special cases here, and codegen has
339
+ // none of that. What is going on?
381
340
trace ! ( "ABI: {:?}" , sig. abi) ;
382
341
trace ! (
383
342
"args: {:#?}" ,
384
- self . frame( ) . mir. args_iter( ) . zip( args. iter( ) )
385
- . map( |( local, arg) | ( local, * * arg, arg. layout. ty) ) . collect:: <Vec <_>>( )
343
+ args. iter( )
344
+ . map( |arg| ( arg. layout. ty, format!( "{:?}" , * * arg) ) )
345
+ . collect:: <Vec <_>>( )
386
346
) ;
387
- match sig. abi {
388
- Abi :: RustCall => {
389
- assert_eq ! ( args. len( ) , 2 ) ;
390
-
391
- {
392
- // write first argument
393
- let first_local = arg_locals. next ( ) . unwrap ( ) ;
394
- let dest = self . eval_place ( & mir:: Place :: Local ( first_local) ) ?;
395
- self . copy_op ( args[ 0 ] , dest) ?;
347
+ trace ! (
348
+ "locals: {:#?}" ,
349
+ mir. args_iter( )
350
+ . map( |local|
351
+ ( local, self . layout_of_local( self . cur_frame( ) , local) . unwrap( ) . ty)
352
+ )
353
+ . collect:: <Vec <_>>( )
354
+ ) ;
355
+ match instance. def {
356
+ ty:: InstanceDef :: ClosureOnceShim { .. } if sig. abi == Abi :: Rust => {
357
+ // this has an entirely ridicolous calling convention where it uses the
358
+ // "Rust" ABI, but arguments come in untupled and are supposed to be tupled
359
+ // for the callee! The function's first argument is a ZST, and then
360
+ // there comes a tuple for the rest.
361
+ let mut arg_locals = mir. args_iter ( ) ;
362
+
363
+ { // the ZST. nothing to write.
364
+ let arg_local = arg_locals. next ( ) . unwrap ( ) ;
365
+ let dest = self . eval_place ( & mir:: Place :: Local ( arg_local) ) ?;
366
+ assert ! ( dest. layout. is_zst( ) ) ;
396
367
}
397
368
398
- // unpack and write all other args
399
- let layout = args[ 1 ] . layout ;
400
- if let ty:: Tuple ( _) = layout. ty . sty {
401
- if layout. is_zst ( ) {
402
- // Nothing to do, no need to unpack zsts
403
- return Ok ( ( ) ) ;
404
- }
405
- if self . frame ( ) . mir . args_iter ( ) . count ( ) == layout. fields . count ( ) + 1 {
406
- for ( i, arg_local) in arg_locals. enumerate ( ) {
407
- let arg = self . operand_field ( args[ 1 ] , i as u64 ) ?;
408
- let dest = self . eval_place ( & mir:: Place :: Local ( arg_local) ) ?;
409
- self . copy_op ( arg, dest) ?;
410
- }
411
- } else {
412
- trace ! ( "manual impl of rust-call ABI" ) ;
413
- // called a manual impl of a rust-call function
414
- let dest = self . eval_place (
415
- & mir:: Place :: Local ( arg_locals. next ( ) . unwrap ( ) ) ,
416
- ) ?;
417
- self . copy_op ( args[ 1 ] , dest) ?;
369
+ { // the tuple argument.
370
+ let arg_local = arg_locals. next ( ) . unwrap ( ) ;
371
+ let dest = self . eval_place ( & mir:: Place :: Local ( arg_local) ) ?;
372
+ assert_eq ! ( dest. layout. fields. count( ) , args. len( ) ) ;
373
+ for ( i, & op) in args. iter ( ) . enumerate ( ) {
374
+ let dest_field = self . place_field ( dest, i as u64 ) ?;
375
+ self . copy_op ( op, dest_field) ?;
418
376
}
419
- } else {
420
- bug ! (
421
- "rust-call ABI tuple argument was {:#?}" ,
422
- layout
423
- ) ;
424
377
}
378
+
379
+ // that should be it
380
+ assert ! ( arg_locals. next( ) . is_none( ) ) ;
425
381
}
426
382
_ => {
427
- for ( arg_local, & op) in arg_locals. zip ( args) {
383
+ // overloaded-calls-simple.rs in miri's test suite demomstrates that there is
384
+ // no way to predict, from the ABI and instance.def, whether the function
385
+ // wants arguments passed with untupling or not. So we just make it
386
+ // depend on the number of arguments...
387
+ let untuple =
388
+ sig. abi == Abi :: RustCall && !args. is_empty ( ) && args. len ( ) != mir. arg_count ;
389
+ let ( normal_args, untuple_arg) = if untuple {
390
+ let ( tup, args) = args. split_last ( ) . unwrap ( ) ;
391
+ trace ! ( "eval_fn_call: Will pass last argument by untupling" ) ;
392
+ ( args, Some ( tup) )
393
+ } else {
394
+ ( & args[ ..] , None )
395
+ } ;
396
+
397
+ // Pass the arguments.
398
+ let mut arg_locals = mir. args_iter ( ) ;
399
+ // First the normal ones.
400
+ for & op in normal_args {
401
+ let arg_local = arg_locals. next ( ) . unwrap ( ) ;
428
402
let dest = self . eval_place ( & mir:: Place :: Local ( arg_local) ) ?;
429
403
self . copy_op ( op, dest) ?;
430
404
}
405
+ // The the ones to untuple.
406
+ if let Some ( & untuple_arg) = untuple_arg {
407
+ for i in 0 ..untuple_arg. layout . fields . count ( ) {
408
+ let arg_local = arg_locals. next ( ) . unwrap ( ) ;
409
+ let dest = self . eval_place ( & mir:: Place :: Local ( arg_local) ) ?;
410
+ let op = self . operand_field ( untuple_arg, i as u64 ) ?;
411
+ self . copy_op ( op, dest) ?;
412
+ }
413
+ }
414
+ // That should be it.
415
+ assert ! ( arg_locals. next( ) . is_none( ) ) ;
431
416
}
432
417
}
433
418
Ok ( ( ) )
0 commit comments