rust-lang / rust-lang/rust-clippy
ICE: Unstable fingerprints for `evaluate_obligation` during incremental clippy with async closures + blanket-impl trait
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 13.5k
- Forks
- 2.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 32
Description
Summary
cargo clippy panics with "Found unstable fingerprints for evaluate_obligation" on every incremental rebuild when an async function chains .filter_map(async |...|) (via a blanket-impl indirection trait resembling futures_util::fns::FnMut1) and the future_not_send lint (nursery group) is enabled.
The ICE reproduces deterministically: first cargo clippy succeeds, then any subsequent incremental run (touch src/main.rs && cargo clippy) crashes.
Minimal reproduction
Three files, one crate (lib + bin targets):
Cargo.toml
[package]
name = "ice-repro"
version = "0.1.0"
edition = "2024"
[profile.dev]
incremental = true
[lints.clippy]
nursery = { level = "warn", priority = -1 }
src/lib.rs
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
pub trait FnMut1<A> {
type Output;
fn call_mut(&mut self, arg: A) -> Self::Output;
}
impl<T, A, R> FnMut1<A> for T
where
T: FnMut(A) -> R,
{
type Output = R;
fn call_mut(&mut self, arg: A) -> R {
self(arg)
}
}
pub trait Stream {
type Item;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
}
pub struct Iter<I>(pub I);
impl<I: Iterator> Stream for Iter<I> {
type Item = I::Item;
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Pending
}
}
pub struct FilterMap<S, F>(pub S, pub F);
impl<S, F, T> Stream for FilterMap<S, F>
where
S: Stream,
F: FnMut1<S::Item, Output: Future<Output = Option<T>>>,
{
type Item = T;
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Pending
}
}
pub struct Fold<S, F, A>(pub S, pub F, pub Option<A>);
impl<S, F, Fut, A> Future for Fold<S, F, A>
where
S: Stream,
F: FnMut(A, S::Item) -> Fut,
Fut: Future<Output = A>,
{
type Output = A;
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<A> {
Poll::Pending
}
}
pub trait StreamExt: Stream + Sized {
fn filter_map<F, Fut, T>(self, f: F) -> FilterMap<Self, F>
where
F: FnMut1<Self::Item, Output = Fut>,
Fut: Future<Output = Option<T>>,
{
FilterMap(self, f)
}
fn fold<F, Fut, A>(self, acc: A, f: F) -> Fold<Self, F, A>
where
F: FnMut(A, Self::Item) -> Fut,
Fut: Future<Output = A>,
{
Fold(self, f, Some(acc))
}
}
impl<S: Stream> StreamExt for S {}
pub fn iter<I: IntoIterator>(i: I) -> Iter<I::IntoIter> {
Iter(i.into_iter())
}
src/main.rs
#![allow(unused)]
use ice_repro::{StreamExt, iter};
async fn find_latest(dirs: &[String]) -> Option<String> {
iter(dirs.iter())
.filter_map(async |d: &String| -> Option<String> { Some(d.clone()) })
.filter_map(async |d: String| -> Option<String> { Some(d) })
.fold(None, async |_: Option<String>, b: String| -> Option<String> { Some(b) })
.await
}
fn main() {}
Steps to reproduce
cargo clippy # first pass: populates incremental cache
touch src/main.rs # invalidate the binary target
cargo clippy # second pass: ICE
Notes
All four of the following appear to be required to trigger the crash:
incremental = true- clippy's
future_not_sendlint enabled (vianursery = "warn") - a blanket impl indirection trait in a separate compilation unit
- Two chained
.filter_map(async |...|)calls +.fold(...).await
In practice this affects any project that uses futures::StreamExt::filter_map with async closures and has nursery lints enabled. futures_util::fns::FnMut1 is the real-world equivalent of the FnMut1 trait in the repro. The underlying bug appears to be in rustc's incremental compilation fingerprint verification (rustc_middle::verify_ich), not in clippy itself -- clippy's future_not_send lint merely exercises the affected code path.
Version
rustc 1.96.0-nightly (b41f22de2 2026-03-08)
binary: rustc
commit-hash: b41f22de2a13a0babd28771e96feef4c309f54aa
commit-date: 2026-03-08
host: x86_64-unknown-linux-gnu
release: 1.96.0-nightly
LLVM version: 22.1.0
Tested on current stable (0.1.94 4a4ef493e3 2026-03-02) as well.
Error output
Backtrace
thread 'rustc' panicked at /rustc-dev/b41f22de2a13a0babd28771e96feef4c309f54aa/compiler/rustc_middle/src/verify_ich.rs:80:9:
Found unstable fingerprints for evaluate_obligation(49b9c257e6e345e6-85c3452aa79dbe26): Ok(EvaluatedToOk)
stack backtrace:
0: 0x14f15cbef72b - <std[f377252fd1978e75]::backtrace::Backtrace>::create
1: 0x14f15cbef675 - <std[f377252fd1978e75]::backtrace::Backtrace>::force_capture
2: 0x14f15bbf3a6b - std[f377252fd1978e75]::panicking::update_hook::<alloc[7d80c8e5f2bc07aa]::boxed::Box<rustc_driver_impl[a7e284e8ff2767b6]::install_ice_hook::{closure#1}>>::{closure#0}
3: 0x14f15cc01ca2 - std[f377252fd1978e75]::panicking::panic_with_hook
4: 0x14f15cbe46f8 - std[f377252fd1978e75]::panicking::panic_handler::{closure#0}
5: 0x14f15cbdb429 - std[f377252fd1978e75]::sys::backtrace::__rust_end_short_backtrace::<std[f377252fd1978e75]::panicking::panic_handler::{closure#0}, !>
6: 0x14f15cbe615d - __rustc[d65e30e194c7d9cd]::rust_begin_unwind
7: 0x14f1597aa0cc - core[40ef8ddb62afa269]::panicking::panic_fmt
8: 0x14f15c22e485 - rustc_middle[6d7cfdcb6c95edb7]::verify_ich::incremental_verify_ich_failed
9: 0x14f15db8bbff - rustc_middle[6d7cfdcb6c95edb7]::verify_ich::incremental_verify_ich::<rustc_middle[6d7cfdcb6c95edb7]::query::erase::ErasedData<[u8; 2usize]>>
10: 0x14f15da0503c - rustc_query_impl[5ff32ada1adb4c7a]::execution::try_execute_query::<rustc_middle[6d7cfdcb6c95edb7]::query::caches::DefaultCache<rustc_type_ir[cecd37ed784ac10d]::canonical::CanonicalQueryInput<rustc_middle[6d7cfdcb6c95edb7]::ty::context::TyCtxt, rustc_middle[6d7cfdcb6c95edb7]::ty::ParamEnvAnd<rustc_middle[6d7cfdcb6c95edb7]::ty::predicate::Predicate>>, rustc_middle[6d7cfdcb6c95edb7]::query::erase::ErasedData<[u8; 2usize]>>, true>
11: 0x14f15da02fc2 - rustc_query_impl[5ff32ada1adb4c7a]::query_impl::evaluate_obligation::execute_query_incr::__rust_end_short_backtrace
12: 0x14f15dac756b - <rustc_trait_selection[1844f0ca5ec2ecf5]::traits::fulfill::FulfillProcessor as rustc_data_structures[86b662b2b592701f]::obligation_forest::ObligationProcessor>::process_obligation
13: 0x14f15d2b8dc1 - <rustc_data_structures[86b662b2b592701f]::obligation_forest::ObligationForest<rustc_trait_selection[1844f0ca5ec2ecf5]::traits::fulfill::PendingPredicateObligation>>::process_obligations::<rustc_trait_selection[1844f0ca5ec2ecf5]::traits::fulfill::FulfillProcessor>
14: 0x14f15dc454b9 - <rustc_trait_selection[1844f0ca5ec2ecf5]::traits::engine::ObligationCtxt>::make_canonicalized_query_response::<()>
15: 0x14f15dc3f460 - rustc_traits[ab8d48508fb7851e]::type_op::type_op_prove_predicate
16: 0x14f15db37576 - rustc_query_impl[5ff32ada1adb4c7a]::execution::try_execute_query::<rustc_middle[6d7cfdcb6c95edb7]::query::caches::DefaultCache<rustc_type_ir[cecd37ed784ac10d]::canonical::CanonicalQueryInput<rustc_middle[6d7cfdcb6c95edb7]::ty::context::TyCtxt, rustc_middle[6d7cfdcb6c95edb7]::ty::ParamEnvAnd<rustc_middle[6d7cfdcb6c95edb7]::traits::query::type_op::ProvePredicate>>, rustc_middle[6d7cfdcb6c95edb7]::query::erase::ErasedData<[u8; 8usize]>>, true>
17: 0x14f15db3616b - rustc_query_impl[5ff32ada1adb4c7a]::query_impl::type_op_prove_predicate::execute_query_incr::__rust_end_short_backtrace
18: 0x14f15d9e6a9d - <rustc_borrowck[2d9d68db0deb061]::type_check::TypeChecker>::normalize_and_prove_instantiated_predicates
19: 0x14f15a84af56 - <rustc_borrowck[2d9d68db0deb061]::type_check::TypeChecker as rustc_middle[6d7cfdcb6c95edb7]::mir::visit::Visitor>::visit_operand
20: 0x14f15e21885d - <rustc_borrowck[2d9d68db0deb061]::type_check::TypeChecker as rustc_middle[6d7cfdcb6c95edb7]::mir::visit::Visitor>::visit_body
21: 0x14f15e201f62 - rustc_borrowck[2d9d68db0deb061]::type_check::type_check
22: 0x14f15e3f3314 - <rustc_borrowck[2d9d68db0deb061]::root_cx::BorrowCheckRootCtxt>::do_mir_borrowck
23: 0x14f15e3eec6f - rustc_borrowck[2d9d68db0deb061]::mir_borrowck
24: 0x14f15e3eeab5 - rustc_query_impl[5ff32ada1adb4c7a]::query_impl::mir_borrowck::invoke_provider_fn::__rust_begin_short_backtrace
25: 0x14f15d455c57 - rustc_query_impl[5ff32ada1adb4c7a]::execution::try_execute_query::<rustc_data_structures[86b662b2b592701f]::vec_cache::VecCache<rustc_span[825691e18cdd0684]::def_id::LocalDefId, rustc_middle[6d7cfdcb6c95edb7]::query::erase::ErasedData<[u8; 8usize]>, rustc_middle[6d7cfdcb6c95edb7]::dep_graph::graph::DepNodeIndex>, true>
26: 0x14f15d44dc0e - rustc_query_impl[5ff32ada1adb4c7a]::query_impl::mir_borrowck::execute_query_incr::__rust_end_short_backtrace
27: 0x14f15e27d68e - rustc_hir_analysis[c936938903594311]::collect::type_of::opaque::find_opaque_ty_constraints_for_rpit
28: 0x14f15e27d366 - rustc_hir_analysis[c936938903594311]::collect::type_of::type_of_opaque
29: 0x14f15d45dab2 - rustc_query_impl[5ff32ada1adb4c7a]::execution::try_execute_query::<rustc_middle[6d7cfdcb6c95edb7]::query::caches::DefIdCache<rustc_middle[6d7cfdcb6c95edb7]::query::erase::ErasedData<[u8; 8usize]>>, true>
30: 0x14f15e81071c - rustc_query_impl[5ff32ada1adb4c7a]::query_impl::type_of_opaque::execute_query_incr::__rust_end_short_backtrace
31: 0x14f15d6dbbf3 - <rustc_trait_selection[1844f0ca5ec2ecf5]::traits::select::SelectionContext>::confirm_auto_impl_candidate::{closure#0}
32: 0x14f15d37a603 - <rustc_trait_selection[1844f0ca5ec2ecf5]::traits::select::SelectionContext>::poly_select::{closure#0}
33: 0x14f15dac3bb9 - <rustc_trait_selection[1844f0ca5ec2ecf5]::traits::fulfill::FulfillProcessor as rustc_data_structures[86b662b2b592701f]::obligation_forest::ObligationProcessor>::process_obligation
34: 0x14f15d2b8dc1 - <rustc_data_structures[86b662b2b592701f]::obligation_forest::ObligationForest<rustc_trait_selection[1844f0ca5ec2ecf5]::traits::fulfill::PendingPredicateObligation>>::process_obligations::<rustc_trait_selection[1844f0ca5ec2ecf5]::traits::fulfill::FulfillProcessor>
35: 0x14f15dc19a30 - <rustc_trait_selection[1844f0ca5ec2ecf5]::traits::fulfill::FulfillmentContext<rustc_trait_selection[1844f0ca5ec2ecf5]::traits::FulfillmentError> as rustc_infer[f695937d0203f373]::traits::engine::TraitEngine<rustc_trait_selection[1844f0ca5ec2ecf5]::traits::FulfillmentError>>::evaluate_obligations_error_on_ambiguity
36: 0x55dc5fa4bcd1 - <rustc_trait_selection[1844f0ca5ec2ecf5]::traits::engine::ObligationCtxt<rustc_trait_selection[1844f0ca5ec2ecf5]::traits::FulfillmentError>>::evaluate_obligations_error_on_ambiguity
37: 0x55dc5fb59d46 - <clippy_lints[42090889051f29c9]::future_not_send::FutureNotSend as rustc_lint[52e19671ac4a625f]::passes::LateLintPass>::check_fn
38: 0x14f15c15cdd8 - <rustc_lint[52e19671ac4a625f]::late::LateContextAndPass<rustc_lint[52e19671ac4a625f]::late::RuntimeCombinedLateLintPass> as rustc_hir[88d14f16e404e101]::intravisit::Visitor>::visit_fn
39: 0x14f15c170e4c - <rustc_lint[52e19671ac4a625f]::late::LateContextAndPass<rustc_lint[52e19671ac4a625f]::late::RuntimeCombinedLateLintPass> as rustc_hir[88d14f16e404e101]::intravisit::Visitor>::visit_nested_item
40: 0x14f15c0fbeb9 - <rustc_lint[52e19671ac4a625f]::late::LateContextAndPass<rustc_lint[52e19671ac4a625f]::late::RuntimeCombinedLateLintPass>>::process_mod
41: 0x14f15e0b3177 - rustc_lint[52e19671ac4a625f]::late::check_crate::{closure#0}
42: 0x14f15e0b247f - rustc_lint[52e19671ac4a625f]::late::check_crate
43: 0x14f15e0af83e - rustc_interface[5f8c59f625471e6f]::passes::analysis::{closure#0}::{closure#0}::{closure#2}
44: 0x14f15e0af61f - rustc_data_structures[86b662b2b592701f]::sync::parallel::par_fns
45: 0x14f15e0af5bc - rustc_interface[5f8c59f625471e6f]::passes::analysis::{closure#0}::{closure#0}
46: 0x14f15e0af61f - rustc_data_structures[86b662b2b592701f]::sync::parallel::par_fns
47: 0x14f15d44fdf1 - rustc_interface[5f8c59f625471e6f]::passes::analysis
48: 0x14f15e88798f - rustc_query_impl[5ff32ada1adb4c7a]::execution::try_execute_query::<rustc_middle[6d7cfdcb6c95edb7]::query::caches::SingleCache<rustc_middle[6d7cfdcb6c95edb7]::query::erase::ErasedData<[u8; 0usize]>>, true>
49: 0x14f15e8872de - rustc_query_impl[5ff32ada1adb4c7a]::query_impl::analysis::execute_query_incr::__rust_end_short_backtrace
50: 0x14f15e4eb788 - rustc_interface[5f8c59f625471e6f]::interface::run_compiler::<(), rustc_driver_impl[a7e284e8ff2767b6]::run_compiler::{closure#0}>::{closure#1}
51: 0x14f15e51ea7e - std[f377252fd1978e75]::sys::backtrace::__rust_begin_short_backtrace::<rustc_interface[5f8c59f625471e6f]::util::run_in_thread_with_globals<rustc_interface[5f8c59f625471e6f]::util::run_in_thread_pool_with_globals<rustc_interface[5f8c59f625471e6f]::interface::run_compiler<(), rustc_driver_impl[a7e284e8ff2767b6]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>
52: 0x14f15e51f320 - <std[f377252fd1978e75]::thread::lifecycle::spawn_unchecked<rustc_interface[5f8c59f625471e6f]::util::run_in_thread_with_globals<rustc_interface[5f8c59f625471e6f]::util::run_in_thread_pool_with_globals<rustc_interface[5f8c59f625471e6f]::interface::run_compiler<(), rustc_driver_impl[a7e284e8ff2767b6]::run_compiler::{closure#0}>::{closure#1}, ()>::{closure#0}, ()>::{closure#0}::{closure#0}, ()>::{closure#1} as core[40ef8ddb62afa269]::ops::function::FnOnce<()>>::call_once::{shim:vtable#0}
53: 0x14f15e5201ac - <std[f377252fd1978e75]::sys::thread::unix::Thread>::new::thread_start
54: 0x14f1578621cf - start_thread
at /usr/src/debug/glibc-2.28-211.el8.x86_64/nptl/pthread_create.c:479:8
55: 0x14f1574cde73 - clone
at /usr/src/debug/glibc-2.28-211.el8.x86_64/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95:0
56: 0x0 - <unknown>
rustc version: 1.96.0-nightly (b41f22de2 2026-03-08)
platform: x86_64-unknown-linux-gnu
query stack during panic:
#0 [evaluate_obligation] evaluating trait selection obligation `{async closure@src/main.rs:8:21: 8:56}: ice_repro::FnMut1<alloc::string::String>`
#1 [type_op_prove_predicate] evaluating `type_op_prove_predicate` `ProvePredicate { predicate: Binder { value: TraitPredicate(<{async closure@src/main.rs:8:21: 8:56} as ice_repro::FnMut1<alloc::string::String>>, polarity:Positive), bound_vars: [] } }`
#2 [mir_borrowck] borrow-checking `find_latest`
#3 [type_of_opaque] computing type of opaque `find_latest::{opaque#0}`
#4 [analysis] running analysis passes on crate `ice_repro`
end of query stack
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the three-file reproduction in Cargo.toml, src/lib.rs, and src/main.rs, then run cargo clippy, touch src/main.rs, and run it again. Read rustc_middle/src/verify_ich.rs and the future_not_send lint entry point shown in the backtrace. Done means the incremental second run completes without the unstable-fingerprint ICE for this reproduction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers, devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100