rust-lang/rust · error

Fn* are not yet const

Error message

Fn* are not yet const

What it means

An `unimplemented!("Fn* are not yet const")` ICE in the next (new) trait solver's effect-goal handling (`consider_builtin_fn_ptr_trait_candidate`). When the new solver must produce a candidate proving that a function-pointer type satisfies a const-calling-convention `Fn`/`FnMut`/`FnOnce` obligation, no candidate exists yet and it panics at effect_goals.rs:292.

Solutions

  1. Do not enable `-Znext-solver` for crates that need const function-pointer calls.
  2. Replace the function-pointer call in const context with a direct (monomorphized) function call or a closure that the solver can handle.
  3. Track the upstream const-`Fn*` work for the next solver; upgrade when implemented.

Example fix

// before (next solver + const fn-pointer call -> ICE)
const fn run(f: fn() -> i32) -> i32 { f() }
// compiled with: -Znext-solver

// after — call directly, or drop -Znext-solver
const fn run() -> i32 { 42 }
Defensive patterns

Strategy: fallback

Validate before calling

# Detect next-solver + const fn-pointer calls
if [[ "${RUSTFLAGS:-}" == *next-solver* ]]; then
  rg -nE 'const fn .*\bfn\(' src/ && echo "avoid: const Fn* calls unsupported in the next solver"
fi

Prevention

When it happens

Trigger: Enabling the next trait solver (`-Znext-solver`) and requiring a const `Fn`/`FnMut`/`FnOnce` impl for a function pointer (e.g. calling a function pointer inside a `const fn` in a context the new solver must evaluate).

Common situations: Nightly + `-Znext-solver` + const-eval code that invokes a function pointer in const context. Not reachable on stable or with the old solver.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/768caf97a28a075b. Report an issue: GitHub.

Appendix: source

Thrown at compiler/rustc_next_trait_solver/src/solve/effect_goals.rs:292

                        goal.with(
                            cx,
                            ty::ClauseKind::HostEffect(
                                goal.predicate.with_replaced_self_ty(cx, ty),
                            ),
                        )
                    }),
                )
            })?;

            ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
        })
    }

    fn consider_builtin_fn_ptr_trait_candidate(
        _ecx: &mut EvalCtxt<'_, D>,
        _goal: Goal<I, Self>,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        unimplemented!("Fn* are not yet const")
    }

    #[instrument(level = "trace", skip_all, ret)]
    fn consider_builtin_fn_trait_candidates(
        ecx: &mut EvalCtxt<'_, D>,
        goal: Goal<I, Self>,
        _kind: rustc_type_ir::ClosureKind,
    ) -> Result<Candidate<I>, NoSolutionOrRerunNonErased> {
        let cx = ecx.cx();

        let self_ty = goal.predicate.self_ty();
        let (inputs_and_output, def_id, args) =
            structural_traits::extract_fn_def_from_const_callable(cx, self_ty)?;
        let (inputs, output) = ecx.instantiate_binder_with_infer(inputs_and_output);

        // A built-in `Fn` impl only holds if the output is sized.
        // (FIXME: technically we only need to check this if the type is a fn ptr...)
        let output_is_sized_pred =

View on GitHub (pinned to 7088e4b63a)