Check borrowed inputs on the declared signature - #19
Merged
Merged
Conversation
Since nightly-2026-08-22, mock! and replace! no longer compile for safe signatures with borrowed inputs, such as mock!(session, env::var_os::<&str>, fn(&str) -> Option<OsString>). rustc reports "higher-ranked lifetime error" from the probe traits in macros/src/signature.rs. cargo-bisect-rustc points at rust-lang/rust#160619, which enables the next-generation trait solver by default on nightly; stable 1.98 and beta 1.99 still compile the code, and -Znext-solver=coherence restores it on nightly. The probes asked whether the source function accepts any lifetime for an input, and relied on that answer to pick a trait impl: if it did, the declared signature had to accept any lifetime too, and otherwise a fallback impl accepted a static-only source. The next solver ignores lifetimes when it picks an impl, so it chose the strict impl for every source. Proving that impl then fails for static-only sources, and for generic sources such as var_os::<&str>, whose input lifetime is an inference variable that cannot satisfy a higher-ranked bound. The probes now inspect the declared function pointer instead. The impl is chosen only by whether an input is a shared or mutable reference, and its method then requires that input to accept any lifetime. No lifetime decides which impl applies, so both solvers treat the code the same way, and the declared pointer has no inference variables to trip over. This is stricter than before: a safe signature can no longer declare a 'static borrowed input, even for a function that only accepts 'static borrows. Such functions are declared with an unsafe fn signature, which is checked only as a function pointer, as extern and unsafe signatures already are. The static_length test now uses that form, and the mock! and replace! docs say so. Declaring 'static for a source that accepts any lifetime stays rejected, including through a type alias and for mutable borrows.
This was referenced Sep 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes
mock!andreplace!on nightly Rust.Since nightly-2026-08-22, signatures with borrowed inputs such as
fn(&str)fail with "higher-ranked lifetime error". rust-lang/rust#160619 turned on the new trait solver, and the old check relied on lifetimes to pick a trait impl, which the new solver no longer does.The check now looks at the declared signature: each borrowed input must accept a borrow of a local value. Stable and nightly behave the same.
One change for users: a function that only takes
'staticborrows now needsunsafe fn(&'static str)instead offn(&'static str).Tested on stable, beta and nightly with both solvers: https://github.com/XTSoftwareLabs/shimforge/actions/runs/34768702371