You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix stubbing bugs: FFI name resolution and generic parameter validation (#4565)
Fixes three stubbing bugs that block stabilization of the stubbing
feature.
Resolves#1953Resolves#2686Resolves#2673
Partial progress on #2007
## Bug 1: Foreign function stubs fail name resolution (#2686, #2673)
Functions declared in `extern "C" { fn foo(); }` blocks could not be
stubbed because the name resolution algorithm (`resolve_relative`) only
searched top-level module items. Foreign functions are children of
`ForeignMod` HIR items, not top-level items themselves.
Additionally, the stub validation in attributes.rs rejected foreign
functions with "function does not have a body, but is not an extern
function" — the check was intended to catch trait functions without
default bodies, but it also caught `extern "C"` functions.
Fix:
- resolve.rs: When a name is not found as a direct module item, also
search inside `ForeignMod` blocks by iterating their HIR foreign items.
- attributes.rs: Exclude `is_foreign_item` from the no-body rejection.
## Bug 2: Generic parameter names must match (#1953)
Stub validation compared MIR body types directly, which meant `bar<S>()
-> S` was rejected as a stub for `foo<T>() -> T` because the generic
parameter S produced a different Ty than T. The RFC explicitly states
this should work.
Fix:
- stubbing/mod.rs: Build a substitution mapping the stub's generic
parameters to the original's parameters by position, using
`GenericArgs::identity_for_item` as the base to correctly handle parent
type parameters (e.g., methods on `LocalType<T>`). Apply the
substitution to the stub's types before comparing.
## Bug 3: Lifetime mismatch detection (partial, #2007)
Type comparison now uses MIR body types (which have regions erased)
combined with the generic renaming substitution. This means lifetime
differences between the original and stub (e.g., `&'a self` vs `&char`
in method-to-function stubs) no longer cause false rejections. A
documentation note warns users that lifetime mismatches can still cause
subtle verification failures.
## Tests
New tests:
- stub_foreign_function.rs — basic extern "C" function stubbing
- stub_multiple_foreign_functions.rs — multiple foreign functions from
one extern block
- stub_generic_param_rename.rs — single generic param T → S
- stub_generic_multi_param_rename.rs — multiple generic params A, B → X,
Y
Promoted from fixme:
- fixme_issue_1953.rs → stub_generic_param_rename_simple.rs (was
ignored, now passes)
## Documentation
Updated docs/src/reference/experimental/stubbing.md:
- New "Stubbing foreign functions" section with example
- New "Stub compatibility and lifetime considerations" section warning
about lifetime mismatches
## Call-outs
- The generic param renaming uses `GenericArgs::identity_for_item` to
get the full substitution (including parent type `params`), then
overrides the function's own `params` by position. This correctly
handles methods on generic types like `LocalType<T>::pub_fn`.
- Region/lifetime comparison is intentionally relaxed (erased) — the old
code also didn't compare lifetimes (MIR body types have regions erased).
The difference is now documented.
- The FFI fix only handles local extern blocks. Foreign functions from
external crates (e.g., `libc::sysconf`) already worked via
`resolve_in_foreign_module` when the crate was resolved; the issue was
only with local extern "C" declarations.
By submitting this pull request, I confirm that my contribution is made
under the terms of the Apache 2.0 and MIT licenses.
---------
Signed-off-by: Felipe R. Monteiro <felisous@amazon.com>
0 commit comments