Skip to content

Poor diagnostic combining #[derive(Debug)] with #[repr(C, packed)] struct #110777

Open

Description

@jrose-signal

Code

#[derive(Debug)]
pub(crate) struct UInt16LE {
    bytes: [u8; 2],
}

#[derive(Debug)]
#[repr(C, packed)]
pub(crate) struct Header {
    version: u8,
    kind: UInt16LE,
}

Current output

error[E0507]: cannot move out of `self.kind` which is behind a shared reference
  --> src/lib.rs:11:5
   |
7  | #[derive(Debug)]
   |          ----- in this derive macro expansion
...
11 |     kind: UInt16LE,
   |     ^^^^^^^^^^^^^^ move occurs because `self.kind` has type `UInt16LE`, which does not implement the `Copy` trait
   |
   = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)

Desired output

"cannot form reference to `self.kind` because struct `Header` is `repr(packed)`"
"note: `self.kind` has type `UInt16LE`, which does not implement the `Copy` trait"

Rationale and extra context

I thought this was a regression in 1.69, and it sort of was, but presumably the old code was incorrect, since you can't form a reference to a field in a repr(packed) struct. Nothing in the diagnostic pointed me to that, though, so I had to figure out why this struct was different.

Other cases

No response

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 Apr 24, 2023
  2. Lokathor commented on Apr 24, 2023

    @Lokathor
    Contributor

    This diagnostic is poor, but I'd like to point out that packed is pointless in the Header struct and you'd have a better time without it.

  3. jrose-signal commented on Apr 24, 2023

    @jrose-signal
    Author

    This is stripped down from a full example, but you're probably right…it would be enough to use repr(C) and static-assert that the alignment is 1.

  4. RalfJung commented on Apr 24, 2023

    @RalfJung
    Member

    Yeah our diagnostics regressed when we fixed #27060, good point. Not sure how we usually handle special diagnostics for derive -- do we really want code littered all over the compiler that special-cases derive? I don't think we can emit this diagnostic in the derive code itself, but it would still be valuable for compiler maintenance to keep this clean, somehow.

  5. RalfJung commented on Apr 24, 2023

    @RalfJung
    Member

    Also FWIW, the intended fix is to declare UInt16LE as Copy.

    The derive macro has to decide whether to take a reference or a copy without having any type information. And for a packed struct, taking a copy seems like the more promising strategy in general, so that's what we do.

  6. Noratrieb commented on Apr 25, 2023

    @Noratrieb
    Member

    Maybe we could add a PackedDeriveField helper trait (with a T: Copy blanket impl) and add Field: PackedDeriveField trait bounds on the impls. Then, throw a rustc_on_unimplemented on that trait and hope the diagnostics machinery picks it all up.

  7. added a commit that references this issue on Nov 7, 2023
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-diagnosticsArea: Messages for errors, warnings, and lintsA-repr-packedArea: the naughtiest reprT-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