Skip to content

#[derivative(Debug)] does not work well with packed structs #82

Closed
@rijenkii

Description

@rijenkii

Example:

#[derive(Copy, Clone, derivative::Derivative)]
#[derivative(Debug)]
#[repr(C, packed)]
struct Test {
    a: u8,
    b: u32
}
warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
 --> src/lib.rs:1:23
  |
1 | #[derive(Copy, Clone, derivative::Derivative)]
  |                       ^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: `#[warn(safe_packed_borrows)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
  = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
  = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

Default #[derive(Debug)] requires that the struct also derives Copy and Clone:

warning: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
 --> src/main.rs:1:10
  |
1 | #[derive(Debug)]
  |          ^^^^^
  |
  = note: `#[warn(safe_packed_borrows)]` on by default
  = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
  = note: for more information, see issue #46043 <https://github.com/rust-lang/rust/issues/46043>
  = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

After adding #[derive(Copy, Clone)], default Debug expands to the following (notice the copying of the fields):

impl ::core::fmt::Debug for Test {
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match *self {
            Test {
                a: __self_0_0,
                b: __self_0_1,
            } => {
                let mut debug_trait_builder = f.debug_struct("Test");
                let _ = debug_trait_builder.field("a", &&(__self_0_0));
                let _ = debug_trait_builder.field("b", &&(__self_0_1));
                debug_trait_builder.finish()
            }
        }
    }
}

#[derivative(Debug)] just always references the fields instead, and referencing fields in a packed struct is -- as far as I can tell -- bad:

impl ::std::fmt::Debug for Test {
    fn fmt(&self, __f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        match *self {
            Test {
                a: ref __arg_0,
                b: ref __arg_1,
            } => {
                let mut __debug_trait_builder = __f.debug_struct("Test");
                let _ = __debug_trait_builder.field("a", &__arg_0);
                let _ = __debug_trait_builder.field("b", &__arg_1);
                __debug_trait_builder.finish()
            }
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThe crate does not work as expected

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions