Repository: rust-lang/rust-bindgen (Rust)

Issue:
`#[derive]` is used on `#[repr(packed)]` struct that does not derive Copy (E0133)
<!-- Thanks for filing a bindgen issue! We appreciate it :-) -->
Thank you @emilio for fixing the last issue.

I have another issue here.
I am using rust 1.53 and bindgen 0.59.1

### Input C/C++ Header

```C++
struct packed_wo_copy {
        short f1;
        char f2[0];
} __attribute__((packed));

```


### Actual Results


```rust
#[repr(C)]
#[derive(Default)]
pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>, [T; 0]);
impl<T> __IncompleteArrayField<T> {
    #[inline]
    pub const fn new() -> Self {
        __IncompleteArrayField(::std::marker::PhantomData, [])
    }
    #[inline]
    pub fn as_ptr(&self) -> *const T {
        self as *const _ as *const T
    }
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut T {
        self as *mut _ as *mut T
    }
    #[inline]
    pub unsafe fn as_slice(&self, len: usize) -> &[T] {
        ::std::slice::from_raw_parts(self.as_ptr(), len)
    }
    #[inline]
    pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
        ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
    }
}
impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
        fmt.write_str("__IncompleteArrayField")
    }
}
#[repr(C, packed)]
#[derive(Debug)]
pub struct packed_wo_copy {
    pub f1: ::std::os::raw::c_short,
    pub f2: __IncompleteArrayField<::std::os::raw::c_char>,
}
```

and compilation errors generated when compiling the bindings with rustc

```
warning: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
  --> packed.rs:34:10
   |
34 | #[derive(Debug)]
   |          ^^^^^
   |
   = note: `#[warn(unaligned_references)]` 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
   = note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

warning: 1 warning emitted
```

### Expected Results

Maybe no `Debug` derivative?


Discussion:
Is this a regression from 0.59 as well?
@emilio
It seems not a regression.
I just tested the input with bindgen 0.40, 0.50, 0.58, but the same compilation warning raises.
Hitting this error as well (when generating bindings to kernel structs for eBPF), with the newest bindgen and rust nightly.
Actually now it's an error, not a warning:

```
error: `#[derive]` can't be used on a `#[repr(packed)]` struct that does not derive Copy (error E0133)
     --> src/vmlinux.rs:11701:10
      |
11701 | #[derive(Debug)]
      |          ^^^^^
      |
      = note: `#[deny(unaligned_references)]` 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 #82523 <https://github.com/rust-lang/rust/issues/82523>
      = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info)
```



Patch:
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 99cdf3c86b..4fcbaefd97 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -110,17 +110,13 @@ bitflags! {
     }
 }
 
-fn derives_of_item(item: &Item, ctx: &BindgenContext) -> DerivableTraits {
+fn derives_of_item(
+    item: &Item,
+    ctx: &BindgenContext,
+    packed: bool,
+) -> DerivableTraits {
     let mut derivable_traits = DerivableTraits::empty();
 
-    if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() {
-        derivable_traits |= DerivableTraits::DEBUG;
-    }
-
-    if item.can_derive_default(ctx) && !item.annotations().disallow_default() {
-        derivable_traits |= DerivableTraits::DEFAULT;
-    }
-
     let all_template_params = item.all_template_params(ctx);
 
     if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() {
@@ -137,6 +133,18 @@ fn derives_of_item(item: &Item, ctx: &BindgenContext) -> DerivableTraits {
             // It's not hard to fix though.
             derivable_traits |= DerivableTraits::CLONE;
         }
+    } else if packed {
+        // If the struct or union is packed, deriving from Copy is required for
+        // deriving from any other trait.
+        return derivable_traits;
+    }
+
+    if item.can_derive_debug(ctx) && !item.annotations().disallow_debug() {
+        derivable_traits |= DerivableTraits::DEBUG;
+    }
+
+    if item.can_derive_default(ctx) && !item.annotations().disallow_default() {
+        derivable_traits |= DerivableTraits::DEFAULT;
     }
 
     if item.can_derive_hash(ctx) {
@@ -926,7 +934,9 @@ impl CodeGenerator for Type {
 
                         let mut attributes =
                             vec![attributes::repr("transparent")];
-                        let derivable_traits = derives_of_item(item, ctx);
+                        let packed = false; // Types can't be packed in Rust.
+                        let derivable_traits =
+                            derives_of_item(item, ctx, packed);
                         if !derivable_traits.is_empty() {
                             let derives: Vec<_> = derivable_traits.into();
                             attributes.push(attributes::derives(&derives))
@@ -2026,7 +2036,7 @@ impl CodeGenerator for CompInfo {
             }
         }
 
-        let derivable_traits = derives_of_item(item, ctx);
+        let derivable_traits = derives_of_item(item, ctx, packed);
         if !derivable_traits.contains(DerivableTraits::DEBUG) {
             needs_debug_impl = ctx.options().derive_debug &&
                 ctx.options().impl_debug &&
@@ -3048,7 +3058,8 @@ impl CodeGenerator for Enum {
         }
 
         if !variation.is_const() {
-            let mut derives = derives_of_item(item, ctx);
+            let packed = false; // Enums can't be packed in Rust.
+            let mut derives = derives_of_item(item, ctx, packed);
             // For backwards compat, enums always derive
             // Clone/Eq/PartialEq/Hash, even if we don't generate those by
             // default.


Test patch:
diff --git a/tests/expectations/tests/packed-vtable.rs b/tests/expectations/tests/packed-vtable.rs
index 0069eada96..71688151f5 100644
--- a/tests/expectations/tests/packed-vtable.rs
+++ b/tests/expectations/tests/packed-vtable.rs
@@ -9,7 +9,6 @@
 #[repr(C)]
 pub struct PackedVtable__bindgen_vtable(::std::os::raw::c_void);
 #[repr(C, packed)]
-#[derive(Debug)]
 pub struct PackedVtable {
     pub vtable_: *const PackedVtable__bindgen_vtable,
 }