Skip to content

assoc types in binders can pass wf check but error when trying to normalize via impl #161405

Description

@carlini

I've been using LLMs to find soundness issues in various programs, including rust. This bug was discussed on zulip (t-types thread) where @lcnr diagnosed the root cause and believes it affects stable (and also identified the regressing PR). Filing the bug here.

I tried this code:

#![forbid(unsafe_code)]
use std::any::type_name;

trait Overlap {
    type Out;
}

impl<T: ?Sized + Gated> Overlap for T
where
    for<'a> <T as Gated>::Assoc<'a>: Copy,
{
    type Out = usize;
}

impl Overlap for str {
    type Out = &'static u64;
}

trait Gated {
    type Assoc<'a>: Copy
    where
        Self: Sized;
}
impl Gated for str {}

fn cast<T: ?Sized + Gated>() -> <T as Overlap>::Out {
    println!("cast: Out = {}", type_name::<<T as Overlap>::Out>()); // usize
    8
}

fn main() {
    let r = cast::<str>();
    println!("main: Out = {} = {r:p}", type_name::<<str as Overlap>::Out>()); // &u64 = 0x8
    println!("{}", *r); // SIGSEGV
}

compiled with -Znext-solver.

I expected to see this happen: the program is rejected

Instead, this happened: -Znext-solver accepts it and the program prints

cast: Out = usize
main: Out = &u64 = 0x8
Segmentation fault

From @lcnr's analysis, the underlying issue also affects stable, : https://rust.godbolt.org/z/7scG3Pqjh (and a second demonstration in impossible_predicates: https://rust.godbolt.org/z/fG6v7K6fP). Also found the regression to be #144064 (comment) (https://rust.godbolt.org/z/Mb4ExdjeG).

Meta

nightly: rustc 1.100.0-nightly (8fa1c96cf 2026-08-17)
stable (old solver rejects the program above; stable godbolt link above shows the underlying issue): rustc 1.97.1 (8bab26f4f 2026-07-14)

Root cause (analysis by lcnr)

<T as Gated>::Assoc<'a>: Copy does not make sense because the associated type is only well-formed if T is Sized — now clearly, this should not be allowed. This error is ignored in WF check. This error is not ignored when actually normalizing, because we've instantiated the binder at this point.

What exactly is going on:

  • we have a type which implements a trait, with a GAT where-clause that may not hold
  • trying to normalize that where-clause for this type always errors as normalization rechecks GAT item bounds
  • we don't check GAT where-clauses in well-formedness checking of the impl if they reference bound variables
  • using an item bound does not need to prove GAT where-bounds
  • this means using an impl with that where-clause must use an item bound instead of actually the impl itself, causing the impl to be applicable
  • when normalizing via a concrete impl [it] does check GAT where-clauses, so the impl no longer applies

A stupid fix would be to not check GAT where-clauses in coherence when using impls — [but that is] insufficient, [it] also causes problems in impossible_predicates (godbolt link above). The proper fix is the higher-ranked region rework.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-GATsArea: Generic associated types (GATs)A-coherenceArea: CoherenceA-higher-rankedArea: Higher-ranked things (e.g., lifetimes, types, trait bounds aka HRTBs)A-impossible-boundsArea: Issues related to have impossible trait bounds in scope (impossible predicates)C-bugCategory: This is a bug.I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessP-mediumMedium priorityT-typesRelevant to the types team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    Status
    new solver everywhere

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions