Repository navigation
mir-importer: require closure receiver for rust-call lowering - #214
Conversation
|
Hey @nihalpasham, sorry to land a whole batch on you at once today (#181–#214). Quick map to make triage easier:
They should all be independent, merge or close in whatever order suits you, no rush on any. The Really enjoying putting the compiler through its paces, and glad to shape how I contribute around whatever's easiest for you! |
|
Thanks for these. Just a heads-up. I'll need some time to review these as I am working through a couple of large ticket items. |
Signed-off-by: nik <[email protected]>
…/double-ref closure coverage Explain in receiver_is_closure why typing the base local (ignoring place.projection) and peeling a single reference is sound for the rust-call receiver: rustc materializes the closure-trait receiver as the closure by value or one &/&mut borrow in its own temporary, never an in-place projection of a larger aggregate and never behind multiple references. Add two device_closures kernels that lock this in as permanent coverage: a genuine closure called through a struct field projection ((holder.f)(x)) and one called through a double reference ((**rr)(x)). Both must still unpack the rust-call tuple; the generated .ll confirms each inlines the closure body (mul by factor) and the module passes LLVM verification, which the misclassification bug would have failed.
4236277 to
c82dcfc
Compare
|
LGTM.
|
Closes #213.
Problem
translate_callspecial-cases closure trait calls because rust-call ABI passes arguments as a tuple while the closure body expects unpacked arguments. The old predicate looked for names containingcall_once,call_mut, or ending in::call, and then checked whether any generic substitution text containedClosure.That is too broad. A normal wrapper method named
callcan have a closure as a generic parameter while still expecting its tuple argument as one ordinary method argument. Onupstream/mainwith only the regression applied,ClosureWrapper<F>::call(&self, (u32,))is misclassified and LLVM verification fails:Fix
Require the rust-call receiver to actually be a closure before using
translate_closure_call.The new
receiver_is_closurehelper inspects the first call operand, resolves its MIR local or constant type, unwraps references, and matchesRigidTy::Closure. If the receiver is an ordinary ADT such asClosureWrapper<F>, the call stays on the normal call-lowering path and keeps its tuple argument intact.Diligence
I checked the sibling closure-call paths:
translate_closure_callstill handles the genuine closure trait ABI path, including by-valuecall_onceand by-referencecall/call_mutreceivers.extract_closure_body_namealready requires the receiver operand to be a closure or reference-to-closure before resolving a closure body.The initial wrapper regression used
#[inline(always)], which let rustc optimize the wrapper method away before import. The committed regression uses#[inline(never)]so the importer must classify the ordinary wrapper call.Tests
Extended
crates/rustc-codegen-cuda/examples/device_closureswith:ClosureWrapper<F>, whereF: Fn(u32) -> u32;ClosureWrapper::call(&self, (u32,)) -> u32;test_wrapper_method_named_call, which stores a captured closure in the wrapper and calls the wrapper method from a kernel.The existing device closure tests still exercise genuine closure calls, including closure trait calls through
FnOnce.Validation
Verified the regression fails on
upstream/mainby applying only the example change and running:Verified the patched branch with: