Skip to content

Privately uninhabited types can affect how pattern matches are borrow-checked #137999

Closed
@meithecatte

Description

@meithecatte

The following code compiles:

mod m {
    enum Void {}
    
    pub struct Internal {
        _v: Void,
    }

    pub enum Test {
        A(u32, u32),
        B(Internal),
    }
}

use m::Test;

pub fn meow(x: &mut Test) {
    let r1: &mut u32 = match x {
        Test::A(a, _) => a,
        _ => todo!(),
    };

    let r2: &mut u32 = match x {
        Test::A(_, b) => b,
        _ => todo!(),
    };

    let _ = *r1;
    let _ = *r2;
}

However, it only compiles because the _v private field is uninhabited – changing its type to () makes it fail compilation with the following error:

error[E0503]: cannot use `*x` because it was mutably borrowed
  --> src/lib.rs:22:30
   |
18 |         Test::A(a, _) => a,
   |                 - `x.0` is borrowed here
...
22 |     let r2: &mut u32 = match x {
   |                              ^ use of borrowed `x.0`
...
27 |     let _ = *r1;
   |             --- borrow later used here

As discussed on Zulip, the compiler makes efforts to not make it possible to observe a type being privately uninhabited, and so this is a bug.

Meta

rustc --version --verbose:

rustc 1.87.0-nightly (f4a216d28 2025-03-02)
binary: rustc
commit-hash: f4a216d28ee635afce685b4206e713579f66e130
commit-date: 2025-03-02
host: x86_64-unknown-linux-gnu
release: 1.87.0-nightly
LLVM version: 20.1.0

As I discovered this bug while reading rustc sources, I am working on a PR to fix this.

@rustbot claim

Metadata

Metadata

Assignees

Labels

A-borrow-checkerArea: The borrow checkerC-bugCategory: This is a bug.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions