Skip to content

Commit 80b9fc9

Browse files
committed
Clean up function calling
Still not as clean as I'd like it, but better
1 parent b6bf0a9 commit 80b9fc9

File tree

2 files changed

+99
-118
lines changed

2 files changed

+99
-118
lines changed

src/librustc_mir/interpret/terminator/drop.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,25 +43,21 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
4343
_ => (instance, place),
4444
};
4545

46-
let fn_sig = instance.ty(*self.tcx).fn_sig(*self.tcx);
47-
let fn_sig = self.tcx.normalize_erasing_late_bound_regions(self.param_env, &fn_sig);
48-
4946
let arg = OpTy {
5047
op: Operand::Immediate(place.to_ref(&self)),
5148
layout: self.layout_of(self.tcx.mk_mut_ptr(place.layout.ty))?,
5249
};
5350

54-
// This should always be (), but getting it from the sig seems
55-
// easier than creating a layout of ().
56-
let dest = PlaceTy::null(&self, self.layout_of(fn_sig.output())?);
51+
let ty = self.tcx.mk_tup((&[] as &[ty::Ty<'tcx>]).iter()); // return type is ()
52+
let dest = PlaceTy::null(&self, self.layout_of(ty)?);
5753

5854
self.eval_fn_call(
5955
instance,
6056
&[arg],
6157
Some(dest),
6258
Some(target),
6359
span,
64-
fn_sig,
60+
None,
6561
)
6662
}
6763
}

src/librustc_mir/interpret/terminator/mod.rs

Lines changed: 96 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ use syntax::source_map::Span;
1515
use rustc_target::spec::abi::Abi;
1616

1717
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+
};
2121

2222
mod drop;
2323

@@ -96,44 +96,44 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
9696
let instance_ty = instance.ty(*self.tcx);
9797
match instance_ty.sty {
9898
ty::FnDef(..) => {
99-
let real_sig = instance_ty.fn_sig(*self.tcx);
10099
let sig = self.tcx.normalize_erasing_late_bound_regions(
101-
ty::ParamEnv::reveal_all(),
100+
self.param_env,
102101
&sig,
103102
);
103+
let real_sig = instance_ty.fn_sig(*self.tcx);
104104
let real_sig = self.tcx.normalize_erasing_late_bound_regions(
105-
ty::ParamEnv::reveal_all(),
105+
self.param_env,
106106
&real_sig,
107107
);
108108
if !self.check_sig_compat(sig, real_sig)? {
109109
return err!(FunctionPointerTyMismatch(real_sig, sig));
110110
}
111+
(instance, sig)
111112
}
112113
ref other => bug!("instance def ty: {:?}", other),
113114
}
114-
(instance, sig)
115115
}
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+
},
120124
_ => {
121125
let msg = format!("can't handle callee of type {:?}", func.layout.ty);
122126
return err!(Unimplemented(msg));
123127
}
124128
};
125129
let args = self.eval_operands(args)?;
126-
let sig = self.tcx.normalize_erasing_late_bound_regions(
127-
ty::ParamEnv::reveal_all(),
128-
&sig,
129-
);
130130
self.eval_fn_call(
131131
fn_def,
132132
&args[..],
133133
dest,
134134
ret,
135135
terminator.source_info.span,
136-
sig,
136+
Some(sig),
137137
)?;
138138
}
139139

@@ -275,19 +275,19 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
275275
return Ok(false);
276276
}
277277

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!
278280
fn eval_fn_call(
279281
&mut self,
280282
instance: ty::Instance<'tcx>,
281283
args: &[OpTy<'tcx>],
282284
dest: Option<PlaceTy<'tcx>>,
283285
ret: Option<mir::BasicBlock>,
284286
span: Span,
285-
sig: ty::FnSig<'tcx>,
287+
sig: Option<ty::FnSig<'tcx>>,
286288
) -> EvalResult<'tcx> {
287289
trace!("eval_fn_call: {:#?}", instance);
288-
if let Some(place) = dest {
289-
assert_eq!(place.layout.ty, sig.output());
290-
}
290+
291291
match instance.def {
292292
ty::InstanceDef::Intrinsic(..) => {
293293
// 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> {
303303
self.dump_place(*dest);
304304
Ok(())
305305
}
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 { .. } |
358307
ty::InstanceDef::FnPtrShim(..) |
359308
ty::InstanceDef::DropGlue(..) |
360309
ty::InstanceDef::CloneShim(..) |
@@ -376,58 +325,94 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
376325
StackPopCleanup::Goto(ret),
377326
)?;
378327

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?
381340
trace!("ABI: {:?}", sig.abi);
382341
trace!(
383342
"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<_>>()
386346
);
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());
396367
}
397368

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)?;
418376
}
419-
} else {
420-
bug!(
421-
"rust-call ABI tuple argument was {:#?}",
422-
layout
423-
);
424377
}
378+
379+
// that should be it
380+
assert!(arg_locals.next().is_none());
425381
}
426382
_ => {
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();
428402
let dest = self.eval_place(&mir::Place::Local(arg_local))?;
429403
self.copy_op(op, dest)?;
430404
}
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());
431416
}
432417
}
433418
Ok(())

0 commit comments

Comments
 (0)