Add support to casting closure to function pointer#2124
Add support to casting closure to function pointer#2124celinval merged 6 commits intomodel-checking:mainfrom
Conversation
Change function declaration and call to ignore arguments that are ZST, and implement the closure to function pointer by reifying it to its FnOnce implementation. The casting of closures to function pointers rely on the fact that the closures do not capture anything. Those closures are represented by empty structures, which should get pruned from its argument list of the FnOnce::call_once implementation.
Can you explain this a bit more? This is something Rust does, but we didn't do, but that deficiency wasn't exposed by anything until now?
Looking forward to this |
tedinski
left a comment
There was a problem hiding this comment.
Is fn_abi... your next priority? I hope so, the only reservations I have here are really how complicated this code is getting.
Maybe I wasn't clear. The only closures that can be casted to function pointers are the ones that don't capture anything. Their FnOnce shim will have an empty structure as the first argument, which is ignored, and the final signature matches the signature of the function pointer that we are casting it to. We didn't support closure to function pointer before, so this wasn't a problem. We also duplicate a lot of the code that is related to function ABI to overcome other issues. |
I totally agree, this is a temporary solution but it does unblock users that are currently affected by this issue. |
| let var_ty = self.monomorphize(ldata.ty); | ||
| let var_type = self.codegen_ty(var_ty); |
There was a problem hiding this comment.
is ty vs type a standard convention to distinguish between MIR and GOTO?
There was a problem hiding this comment.
Not a standard convention. I tend to used it often when I need to use both in the same function though.
I think it's much better than using t for both though. I think we should avoid shadowing variables, especially when they represent different things, not just a different state of same thing.
Do you have any other suggestion?
| let index_param = tupe.clone().member(&i.to_string(), &self.symbol_table); | ||
| fargs.push(index_param); | ||
| if let ty::Tuple(tupled_args) = tuple_ty.kind() { | ||
| for (idx, arg_ty) in tupled_args.iter().enumerate() { |
There was a problem hiding this comment.
Is this ordering deterministic?
There was a problem hiding this comment.
I didn't dive deep into that since we already had this assumption in this code. I just merged the two loops together.
| if self.operand_ty(o).is_bool() { | ||
| self.codegen_operand(o).cast_to(Type::c_bool()) | ||
| /// When `skip_zst` is set to `true`, the return value will not include any argument that is ZST. | ||
| /// This is used because we ignore ZST arguments, except for intrinsics. |
There was a problem hiding this comment.
why can't we ignore them for instrinsics?
There was a problem hiding this comment.
Because our intrinsics implementation have assumptions about the number of parameters. BTW, I think this is also true for other backends.
| let (name, _) = self.codegen_spread_arg_name(&lc); | ||
| ident = name; | ||
| .filter_map(|(i, t)| { | ||
| if self.is_zst(*t) && !(i == 0 && is_vtable_shim) { |
There was a problem hiding this comment.
This is a complicated check. Can we simplify?
There was a problem hiding this comment.
I don't think it's worth it. I could split it, but it will just complicate the code flow. We should really be looking at the FnAbi to decide how to codegen parameters.
| // See https://github.com/model-checking/kani/issues/274 for more details. | ||
| None | ||
| } else { | ||
| let lc = Local::from_usize(i + 1); |
There was a problem hiding this comment.
If I'm not wrong, that's because the variable 0 is the return value.
There was a problem hiding this comment.
@danielsn is there anything else you would like me to change? Can I go ahead and merge it as is?
Conflicts:
kani-compiler/src/codegen_cprover_gotoc/codegen/function.rs
Description of changes:
Change function declaration and call to ignore arguments that are ZST, and implement the closure to function pointer by reifying it to its FnOnce implementation.
The casting of closures to function pointers rely on the fact that the closures do not capture anything. Those closures are represented by empty structures, which should get pruned from its argument list of the FnOnce::call_once implementation.
Resolved issues:
Resolves #274
Related RFC:
Optional #ISSUE-NUMBER.
Call-outs:
This change is manually inspecting the arguments and ignoring the ZST ones. However, I believe the long term solution is to change how we gather information about the function signature. We currently use (
fn_sig()), when we should be usingfn_abi_of_instance()instead. Unfortunately, that is a big change. So I'll work on it separately as part of #1365.Testing:
How is this change tested? New tests
Is this a refactor change? Kinda
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses.