Skip to content

The "cannot create non-exhaustive struct using struct expression" warning should silence the "cannot construct Foo with struct literal syntax due to private fields" warning #147513

Closed

Description

@Darksonn

Code

// src/lib.rs
#[non_exhaustive]
pub struct Foo {
    pub my_field: u32,
    private_field: i32,
}
// src/main.rs
use exhaustive_test::Foo;

fn main() {
    let foo = Foo {
        my_field: 10,
    };
}

Current output

error[E0639]: cannot create non-exhaustive struct using struct expression
 --> src/main.rs:4:15
  |
4 |       let foo = Foo {
  |  _______________^
5 | |         my_field: 10,
6 | |     };
  | |_____^

error: cannot construct `Foo` with struct literal syntax due to private fields
 --> src/main.rs:4:15
  |
4 |     let foo = Foo {
  |               ^^^
  |
  = note: ...and other private field `private_field` that was not provided

Desired output

error[E0639]: cannot create non-exhaustive struct using struct expression
 --> src/main.rs:4:15
  |
4 |       let foo = Foo {
  |  _______________^
5 | |         my_field: 10,
6 | |     };
  | |_____^

Rationale and extra context

There is no reason to provide two errors for the same issue, and the #[non_exhaustive] issue is the one that should be highlighted since it's explicitly chosen by the struct author.

Other cases

If there is no private field, then the correct output is created.

Rust Version

$ rustc +nightly --version --verbose
rustc 1.92.0-nightly (b6f0945e4 2025-10-08)
binary: rustc
commit-hash: b6f0945e4681bc4d2faa7c22c5f61dc36abf7dd2
commit-date: 2025-10-08
host: x86_64-unknown-linux-gnu
release: 1.92.0-nightly
LLVM version: 21.1.2

Anything else?

No response

Activity

  1. added
    A-diagnosticsArea: Messages for errors, warnings, and lints
    T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
    on Oct 9, 2025
  2. added
    D-verboseDiagnostics: Too much output caused by a single piece of incorrect code.
    on Oct 9, 2025
  3. chenyukang commented on Oct 9, 2025

    @chenyukang
    Member

    I don't think we need to fix this, it's not the same issue.
    if you remove the non_exhaustive attribute from struct, the first error will disappear, but now we still need to fix the second one, the second one pointing out private fields which is meaningful.

  4. Darksonn commented on Oct 9, 2025

    @Darksonn
    MemberAuthor

    @chenyukang What you're saying assumes that removing #[non_exhaustive] is the correct solution when you get this error, but generally that is not the right solution. In fact, the error only occurs if the struct is from another crate, and you probably can't modify your dependencies.

  5. chenyukang commented on Oct 9, 2025

    @chenyukang
    Member

    The main reason to keep them is there are two different issues, two standalone one's from different check.

    I think compiler should give as much useful and necessary information for the issues in code, but also need avoid to be too noisy of course.

  6. Darksonn commented on Oct 10, 2025

    @Darksonn
    MemberAuthor

    So the context where this came up for me is a type like this one:

    #[derive(FromBytes, IntoBytes)]
    #[repr(C)]
    #[non_exhaustive]
    pub struct MyDataType {
        pub value_1: u64,
        pub value_2: u32,
        _pad: [u8; 4],
    }

    I'm using the type for IPC by sending the bytes verbatim over the wire. I'm promising that I won't ever change the size of this struct in the future, and that the existing fields will never go away or be moved to a different offset. However, I may add additional fields in the future (using the space currently occupied by _pad).

    Here, the _pad field serves two purposes:

    1. Ensure that MyDataType contains no uninit bytes.
    2. Ensure that if a new field is added in the future, then moves of MyDataType retain the bytes stored in the padding.

    In this case, if the user tries to construct this struct, then I want them to get the #[non_exhaustive] error message telling them "hey, there might be additional fields in the future", but I don't really want the user to care about the private _pad field.

  7. chenyukang commented on Oct 11, 2025

    @chenyukang
    Member

    yeah, this seems a reasonable reason for hiding the later one.

  8. self-assigned this
    on Oct 11, 2025
  9. chenyukang commented on Oct 11, 2025

    @chenyukang
    Member

    Fired PR #147585

    also remove the similar error:

    error[E0063]: missing field `missing_field` in initializer of `Foo`
  10. added a commit that references this issue on Dec 9, 2025
    3c19acc
  11. added a commit that references this issue on Dec 9, 2025
    6973225
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-diagnosticsArea: Messages for errors, warnings, and lintsD-verboseDiagnostics: Too much output caused by a single piece of incorrect code.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