Skip to content

#[non_exhaustive] stucts can be matched exhaustively using constants as patterns #119264

Open

Description

In rust-lang/rfcs#3535 (comment) it was noticed that it is possible to match a #[non_exhaustive] struct exhaustively outside the originating crate,
if constants for all posible states are accessible or definable in the other crate.

As a result adding fields such that the struct has new states is a breaking change, as the existing constants won't be able to cover all states anymore.
Which makes #[non_exhaustive] ineffective.

For Example:

// bar/src/lib.rs
#[non_exhaustive]
#[derive(PartialEq, Eq)]
pub struct Bar(bool);
pub const TRUE: Bar = Bar(true);
pub const FALSE: Bar = Bar(false);
// foo/src/main.rs
fn main() {
    match bar::TRUE {
        bar::TRUE => {}
        bar::FALSE => {}
    }
}

Changing the bar crate to the following is then a breaking change:

// bar/src/lib.rs
#[non_exhaustive]
#[derive(PartialEq, Eq)]
pub struct Bar(bool, bool);
pub const TRUE: Bar = Bar(true, true);
pub const FALSE: Bar = Bar(false, false);

This breaks the foo crate, eventhough Bar was marked #[non_exhaustive] to allow expanding.

Reproduction Repo

Meta

rustc +stable --version
rustc 1.74.1 (a28077b28 2023-12-04)
rustc +beta --version
rustc 1.76.0-beta.1 (0e09125c6 2023-12-21)
rustc +nightly --version
rustc 1.77.0-nightly (d6d7a9386 2023-12-22)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    A-patternsRelating to patterns and pattern matchingC-bugCategory: This is a bug.F-non_exhaustive`#![feature(non_exhaustive)]`T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.T-langRelevant to the language 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