Skip to content

field_representing_type_raw mishandles const generics #162127

Open

Description

@theemathas

I am filing this issue on behalf of @carlini, who discovered this bug with an LLM (labelled as "bug 4" at https://rust-lang.zulipchat.com/#narrow/channel/364551-t-types.2Ftrait-system-refactor/topic/Reporting.20a.20collection.20of.20soundness.20bugs.20in.20next-solver/near/617737394)

The following code is unsound. It reads the local variable after the variable has already gone out of scope, when compiled with -Znext-solver. It is possible that a similar unsoundness can also happen on the old solver, but I haven't figured out how.

It appears that the compiler doesn't realize that the two Pick implementations overlap, using two different lifetimes for <W<0> as Pick<'a, 'b>>::Out. I don't quite understand why the compiler seems to think that FieldRepresentingType<Left, 0, F>: Field and FieldRepresentingType<Right, 0, F>: Field can't both hold simultaneously.

Note that this code (and comments in it) are generated by an LLM. I did not verify the correctness of the comments.

cc @BennoLossin, who worked on field_projections

// Old solver: `W<0>: Pick<'_, 'static>` is ambiguous at the call in `main` (both impls apply).
// -Znext-solver: its builtin `FieldRepresentingType<_, 0, F>: Field` candidate answers
// `NoSolution` while `F` is still an inference variable, so coherence believes the two
// impls never overlap and each is then selected alone -- turning `&'a u8` into `&'static u8`.
#![feature(field_projections, field_representing_type_raw)] // needed because: both gates required to name `FieldRepresentingType`
#![allow(incomplete_features, internal_features, dead_code)]
#![forbid(unsafe_code)]

use core::field::{Field, FieldRepresentingType};

struct Left { l: u8 }  // needed because: two distinct structs make the two impl bounds distinct
struct Right { r: u8 }

struct W<const F: u32>;

trait Pick<'a, 'b> {
    type Out;
}

// Both impls apply at `W<0>` (field 0 exists in `Left` and `Right`); coherence should reject.
impl<'a, 'b, const F: u32> Pick<'a, 'b> for W<F>
where
    FieldRepresentingType<Left, 0, F>: Field,
{
    type Out = &'a u8;
}

impl<'a, 'b, const F: u32> Pick<'a, 'b> for W<F>
where
    FieldRepresentingType<Right, 0, F>: Field,
{
    type Out = &'b u8; // needed because: a literal `&'static u8` here hits a mono recursion limit under -Znext-solver
}

// Only the `Left` bound in scope: `Out` normalizes to `&'a u8`.
fn into_out<'a, const F: u32>(x: &'a u8) -> <W<F> as Pick<'a, 'static>>::Out
where
    FieldRepresentingType<Left, 0, F>: Field,
{
    x
}

// Only the `Right` bound in scope: `Out` normalizes to `&'static u8`.
fn out_into_static<'a, const F: u32>(y: <W<F> as Pick<'a, 'static>>::Out) -> &'static u8
where
    FieldRepresentingType<Right, 0, F>: Field,
{
    y
}

fn launder<'a, const F: u32>(x: &'a u8) -> &'static u8
where
    W<F>: Pick<'a, 'static>, // needed because: keeps `Out` rigid here so the value crosses unnormalized
    FieldRepresentingType<Left, 0, F>: Field,
    FieldRepresentingType<Right, 0, F>: Field,
{
    out_into_static::<F>(into_out::<F>(x))
}

fn main() {
    let escaped: &'static u8 = {
        let local = 42u8;
        launder::<0>(&local) // `&local` escapes its block as `&'static u8`
    };
    println!("{escaped}");
}

Meta

Reproducible with 1.100.0-nightly (2026-08-31 0dfb098f3aeecbe38c25)

Activity

  1. added
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
    on Sep 1, 2026
  2. added
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Sep 1, 2026
  3. added
    C-bugCategory: This is a bug.
    A-const-genericsArea: const generics (parameters and arguments)
    T-typesRelevant to the types team, which will review and decide on the PR/issue.
    WG-trait-system-refactorThe Rustc Trait System Refactor Initiative (-Znext-solver)
    on Sep 1, 2026
  4. removed
    needs-triageThis issue may need triage. Remove when done. See docs forge.rust-lang.org/release/issue-triaging
    on Sep 3, 2026
  5. BennoLossin commented on Sep 3, 2026

    @BennoLossin
    Contributor

    our current plan is to remove FieldRepresentingType in the future and replace it with a compiler builtin type (a new TyKind), so I'm not concerned about this at all. that type is behind an internal feature for this reason (using it without the macro is very likely unsound). the reason this is a problem is that the Field impl check doesn't support const generics in FieldRepresentingType, it expects concrete instantiations (since field_of! always sets the variant and field index appropriately and there is no way to make that generic).

  6. added a commit that references this issue on Oct 2, 2026
  7. added a commit that references this issue on Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-coherenceArea: CoherenceA-const-genericsArea: const generics (parameters and arguments)A-trait-systemArea: Trait systemC-bugCategory: This is a bug.F-field_projections`#![feature(field_projections)]`I-unsoundIssue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/SoundnessT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-typesRelevant to the types team, which will review and decide on the PR/issue.WG-trait-system-refactorThe Rustc Trait System Refactor Initiative (-Znext-solver)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions