rust-lang / rust-bindgen

Automatically generates Rust FFI bindings to C (and some C++) libraries.
https://rust-lang.github.io/rust-bindgen/
BSD 3-Clause "New" or "Revised" License
4.47k stars 699 forks source link

Packed structures with 0-sized arrays are not deriving clone/copy #1333

Open gpace1 opened 6 years ago

gpace1 commented 6 years ago

I think bindgen does this for any packed struct that doesn't contain a 0-sized array.

Input C/C++ Header

// test.h
#ifdef __cplusplus
extern "C" {
#endif

typedef struct {

        unsigned char data[0];

       // rustc will not complain about the generating bindings if the struct is "0-sized"
        unsigned short more_data;

}__attribute__((packed)) test_struct;

#ifdef __cplusplus
}
#endif

Bindgen Invocation

let bindings = bindgen::builder()
    .header("test.h")
    .generate()
    .unwrap();

Actual Results

Generated bindings:

 1  /* automatically generated by rust-bindgen */
 2
 3  #[repr(C)]
 4  #[derive(Default)]
 5  pub struct __IncompleteArrayField<T>(::std::marker::PhantomData<T>);
 6  impl<T> __IncompleteArrayField<T> {
 7      #[inline]
 8      pub fn new() -> Self {
 9          __IncompleteArrayField(::std::marker::PhantomData)
10      }
11      #[inline]
12      pub unsafe fn as_ptr(&self) -> *const T {
13          ::std::mem::transmute(self)
14      }
15      #[inline]
16      pub unsafe fn as_mut_ptr(&mut self) -> *mut T {
17          ::std::mem::transmute(self)
18      }
19      #[inline]
20      pub unsafe fn as_slice(&self, len: usize) -> &[T] {
21          ::std::slice::from_raw_parts(self.as_ptr(), len)
22      }
23      #[inline]
24      pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] {
25          ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len)
26      }
27  }
28  impl<T> ::std::fmt::Debug for __IncompleteArrayField<T> {
29      fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
30          fmt.write_str("__IncompleteArrayField")
31      }
32  }
33  impl<T> ::std::clone::Clone for __IncompleteArrayField<T> {
34      #[inline]
35      fn clone(&self) -> Self {
36          Self::new()
37      }
38  }
39  impl<T> ::std::marker::Copy for __IncompleteArrayField<T> {}
40  #[repr(C, packed)]
41  #[derive(Debug)]
42  pub struct test_struct {
43      pub data: __IncompleteArrayField<::std::os::raw::c_uchar>,
44      pub more_data: ::std::os::raw::c_ushort,
45  }
46 // removed test

Rust warning about this

  --> src/bindings.rs:41:10
   |
41 | #[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>

Expected Results

test_struct should derive both clone & copy to get rid of the safe_packed_borrows rustc warning

emilio commented 6 years ago

I think that the reason for not deriving copy / clone for incomplete arrays is because they are usually used to allocate past yourself when the array is the last member.

gpace1 commented 6 years ago

This is still a problem isn't it? I'm now not sure how to go about getting around the eventual error without explicitly defining the structure yourself (which may be the only solution to this).

emilio commented 6 years ago

The way to go here would be to teach #[derive(Debug)] about these I think. I asked in that rustc issue.