rust-lang/rust · critical

discr subgoal...

Error message

discr subgoal...

What it means

Inside the next trait solver's DiscriminantKind handling (computing <T as DiscriminantKind>::Discriminant), when the self type is ty::UnsafeBinder the code cannot derive a discriminant type and panics with unimplemented!("discr subgoal..."). It is a FIXME(unsafe_binders) placeholder: unsafe binder types are an unstable feature whose interaction with discriminant computation has not been finished.

Solutions

  1. Do not wrap enum types that need discriminant queries in an unsafe binder; operate on the unwrapped inner type.
  2. Disable the unsafe_binders feature and use a raw pointer / transmute-based alternative for the unsafe access.
  3. Switch to the classic trait solver if the code path does not strictly require the next solver.
  4. Wait for / upstream a fix for the FIXME(unsafe_binders) discriminant subgoal; report on the unsafe_binders tracking issue.

Example fix

// before
#![feature(unsafe_binders)]
let b: unsafe_binder<'_, Enum> = bind(value);
let d = mem::discriminant(&b); // panics: discr subgoal

// after: unwrap before querying discriminant
let d = mem::discriminant(&value);
Defensive patterns

Strategy: validation

Validate before calling

// Avoid querying discriminants on unsafe-binder-wrapped enum types.
// Validate by not wrapping enums that need DiscriminantKind:
fn needs_discriminant<T>() { let _ = std::mem::discriminant; }

Prevention

When it happens

Trigger: Using unsafe binder types (#![feature(unsafe_binders)]) with code that needs the DiscriminantKind impl / discriminant type — e.g. mem::discriminant, match on a value whose type is wrapped in an unsafe binder, or any intrinsic that queries the discriminant type — while running under the next trait solver.

Common situations: Experimental code enabling #![feature(unsafe_binders)] on a recent nightly, especially when the compiler auto-derives DiscriminantKind for enums behind an unsafe binder. Not reachable on stable.

Related errors


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

Appendix: source

Thrown at compiler/rustc_next_trait_solver/src/solve/normalizes_to.rs:1008

            | ty::FnDef(..)
            | ty::FnPtr(..)
            | ty::Closure(..)
            | ty::CoroutineClosure(..)
            | ty::Infer(ty::IntVar(..) | ty::FloatVar(..))
            | ty::Coroutine(..)
            | ty::CoroutineWitness(..)
            | ty::Never
            | ty::Foreign(..)
            | ty::Adt(_, _)
            | ty::Str
            | ty::Slice(_)
            | ty::Dynamic(_, _)
            | ty::Tuple(_)
            | ty::Error(_) => self_ty.discriminant_ty(ecx.cx()),

            ty::UnsafeBinder(_) => {
                // FIXME(unsafe_binders): instantiate this with placeholders?? i guess??
                unimplemented!("discr subgoal...")
            }

            // Given an alias, parameter, or placeholder we add an impl candidate normalizing to a rigid
            // alias. In case there's a where-bound further constraining this alias it is preferred over
            // this impl candidate anyways. It's still a bit scuffed.
            ty::Alias(ty::IsRigid::Yes, _) | ty::Param(_) | ty::Placeholder(..) => {
                return ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| {
                    ecx.instantiate_normalizes_to_as_rigid(goal)?;
                    ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
                });
            }

            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
            | ty::Alias(ty::IsRigid::No, _)
            | ty::Bound(..) => panic!(
                "unexpected self ty `{:?}` when normalizing `<T as DiscriminantKind>::Discriminant`",
                goal.predicate.self_ty()
            ),

View on GitHub (pinned to 7088e4b63a)