rust-lang/rust · error

Fn* are not yet const

Error message

Fn* are not yet const

What it means

`consider_builtin_fn_ptr_trait_candidate` (effect_goals.rs:292) is `unimplemented!` because built-in `Fn`/`FnMut`/`FnOnce` impls for raw fn pointers (`fn(..) -> ..`) are not yet supported under the const/host-effect system. Unlike the truly-unreachable cases, this is a deliberate 'not implemented yet' marker — the compiler knows fn pointers should eventually be const-callable but the candidate builder has not landed.

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 22057b88b0)

Solutions

  1. Avoid invoking the target through a fn pointer — call the `const fn` directly by name so the `FnDef` candidate (which IS handled, effect_goals.rs:296) is used instead of the fn-pointer path.
  2. Remove the `const`/`~const Fn` bound that is forcing the fn-pointer candidate.
  3. Upgrade nightly and track the const-fn-ptr implementation status; report the ICE if still present.
  4. Gate the affected module behind a non-const path until the feature stabilizes.

Example fix

// before: const call through a function pointer triggers the unimplemented path
const fn add(a: u32, b: u32) -> u32 { a + b }
const fn run(f: fn(u32, u32) -> u32) -> u32 { f(1, 2) } // ICE: fn ptr not yet const

// after: call the const fn directly so the FnDef candidate applies
const fn add(a: u32, b: u32) -> u32 { a + b }
const fn run() -> u32 { add(1, 2) }
Defensive patterns

Strategy: validation

Validate before calling

// Fn*/FnMut*/FnOnce are explicitly non-const today. Reject closures passed to const eval.
const fn reject_fn_in_const<F: Fn()>(_f: &F) {} // will fail effect_goals if the next solver reaches it

Type guard

// Narrow away from callable values before entering a const context.
fn is_closure_or_fn<T: ?Sized>() -> bool { false } // approximated; at the type level keep callables out of const generic params

Prevention

When it happens

Trigger: Reached when the next solver, evaluating a `T: const Fn(..)` (or `FnMut`/`FnOnce`) host-effect goal for a function-pointer self type, reaches the fn-pointer built-in candidate branch (effect_goals.rs:288).

Common situations: Calling a `const fn` through a function pointer inside another `const fn`/`const` context under `#![feature(const_for)]`/`host_effects`; storing a `const fn` in a `fn` typed value and then requiring it `~const Fn`.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/768caf97a28a075b.json. Report an issue: GitHub.