Skip to content

Commit

Permalink
Let Rust derive everything but Default for large arrays in 1.47 and l…
Browse files Browse the repository at this point in the history
…ater

Fixes rust-lang#1977 as of rust-lang/rust#74060 is available since Rust 1.47
Fixes rust-lang#2041.
Closes rust-lang#2070.
  • Loading branch information
Ian P. Cooke authored and LoganBarnett committed Dec 2, 2023
1 parent c549c2a commit d7f03fd
Show file tree
Hide file tree
Showing 35 changed files with 135 additions and 43 deletions.
4 changes: 3 additions & 1 deletion src/codegen/impl_debug.rs
Expand Up @@ -181,7 +181,9 @@ impl<'a> ImplDebug<'a> for Item {
format!("{}: Array with length {}", name, len),
vec![],
))
} else if len < RUST_DERIVE_IN_ARRAY_LIMIT {
} else if len < RUST_DERIVE_IN_ARRAY_LIMIT ||
ctx.options().rust_features().larger_arrays
{
// The simple case
debug_print(name, quote! { #name_ident })
} else {
Expand Down
4 changes: 3 additions & 1 deletion src/codegen/impl_partialeq.rs
Expand Up @@ -114,7 +114,9 @@ fn gen_field(
}

TypeKind::Array(_, len) => {
if len <= RUST_DERIVE_IN_ARRAY_LIMIT {
if len <= RUST_DERIVE_IN_ARRAY_LIMIT ||
ctx.options().rust_features().larger_arrays
{
quote_equals(name_ident)
} else {
quote! {
Expand Down
7 changes: 5 additions & 2 deletions src/codegen/mod.rs
Expand Up @@ -1503,7 +1503,8 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {

// We cannot generate any constructor if the underlying storage can't
// implement AsRef<[u8]> / AsMut<[u8]> / etc.
let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT;
let mut generate_ctor = layout.size <= RUST_DERIVE_IN_ARRAY_LIMIT ||
ctx.options().rust_features().larger_arrays;

let mut access_spec = !fields_should_be_private;
for bf in self.bitfields() {
Expand All @@ -1512,7 +1513,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit {
continue;
}

if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT {
if layout.size > RUST_DERIVE_IN_ARRAY_LIMIT &&
!ctx.options().rust_features().larger_arrays
{
continue;
}

Expand Down
8 changes: 7 additions & 1 deletion src/features.rs
Expand Up @@ -123,6 +123,9 @@ macro_rules! rust_target_base {
/// Rust stable 1.40
/// * `non_exhaustive` enums/structs ([Tracking issue](https://github.com/rust-lang/rust/issues/44109))
=> Stable_1_40 => 1.40;
/// Rust stable 1.47
/// * `larger_arrays` ([Tracking issue](https://github.com/rust-lang/rust/pull/74060))
=> Stable_1_47 => 1.47;
/// Nightly rust
/// * `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202))
=> Nightly => nightly;
Expand All @@ -134,7 +137,7 @@ rust_target_base!(rust_target_def);
rust_target_base!(rust_target_values_def);

/// Latest stable release of Rust
pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_40;
pub const LATEST_STABLE_RUST: RustTarget = RustTarget::Stable_1_47;

/// Create RustFeatures struct definition, new(), and a getter for each field
macro_rules! rust_feature_def {
Expand Down Expand Up @@ -222,6 +225,9 @@ rust_feature_def!(
Stable_1_40 {
=> non_exhaustive;
}
Stable_1_47 {
=> larger_arrays;
}
Nightly {
=> thiscall_abi;
}
Expand Down
21 changes: 14 additions & 7 deletions src/ir/analysis/derive.rs
Expand Up @@ -255,7 +255,7 @@ impl<'ctx> CannotDerive<'ctx> {
return CanDerive::No;
}

if self.derive_trait.can_derive_large_array() {
if self.derive_trait.can_derive_large_array(&self.ctx) {
trace!(" array can derive {}", self.derive_trait);
return CanDerive::Yes;
}
Expand Down Expand Up @@ -377,7 +377,7 @@ impl<'ctx> CannotDerive<'ctx> {
// Bitfield units are always represented as arrays of u8, but
// they're not traced as arrays, so we need to check here
// instead.
if !self.derive_trait.can_derive_large_array() &&
if !self.derive_trait.can_derive_large_array(&self.ctx) &&
info.has_too_large_bitfield_unit() &&
!item.is_opaque(self.ctx, &())
{
Expand Down Expand Up @@ -496,10 +496,17 @@ impl DeriveTrait {
}
}

fn can_derive_large_array(&self) -> bool {
match self {
DeriveTrait::Copy => true,
_ => false,
fn can_derive_large_array(&self, ctx: &BindgenContext) -> bool {
if ctx.options().rust_features().larger_arrays {
match self {
DeriveTrait::Default => false,
_ => true,
}
} else {
match self {
DeriveTrait::Copy => true,
_ => false,
}
}
}

Expand Down Expand Up @@ -686,7 +693,7 @@ impl<'ctx> MonotoneFramework for CannotDerive<'ctx> {
Some(ty) => {
let mut can_derive = self.constrain_type(item, ty);
if let CanDerive::Yes = can_derive {
if !self.derive_trait.can_derive_large_array() &&
if !self.derive_trait.can_derive_large_array(&self.ctx) &&
ty.layout(self.ctx).map_or(false, |l| {
l.align > RUST_DERIVE_IN_ARRAY_LIMIT
})
Expand Down
1 change: 0 additions & 1 deletion src/ir/ty.rs
Expand Up @@ -39,7 +39,6 @@ pub struct Type {
/// traits, and so if we have a type containing an array with more than this
/// many items, we won't be able to derive common traits on that type.
///
/// We need type-level integers yesterday :'(
pub const RUST_DERIVE_IN_ARRAY_LIMIT: usize = 32;

impl Type {
Expand Down
61 changes: 61 additions & 0 deletions tests/expectations/tests/issue-1977-larger-arrays.rs
@@ -0,0 +1,61 @@
#![allow(
dead_code,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]

#[repr(C)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct S {
pub large_array: [::std::os::raw::c_char; 33usize],
}
#[test]
fn bindgen_test_layout_S() {
assert_eq!(
::std::mem::size_of::<S>(),
33usize,
concat!("Size of: ", stringify!(S))
);
assert_eq!(
::std::mem::align_of::<S>(),
1usize,
concat!("Alignment of ", stringify!(S))
);
assert_eq!(
unsafe {
&(*(::std::ptr::null::<S>())).large_array as *const _ as usize
},
0usize,
concat!(
"Offset of field: ",
stringify!(S),
"::",
stringify!(large_array)
)
);
}
impl Default for S {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
#[repr(C)]
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct ST<T> {
pub large_array: [T; 33usize],
pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<T>>,
}
impl<T> Default for ST<T> {
fn default() -> Self {
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
unsafe {
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
s.assume_init()
}
}
}
Expand Up @@ -6,9 +6,7 @@
)]

/// We emit a `[u8; 63usize]` padding field for this struct, which cannot derive
/// Debug/Hash because 63 is over the hard coded limit. (Yes, this struct doesn't end
/// up with the reight alignment, we're waiting on `#[repr(align="N")]` to land
/// in rustc).
/// Debug/Hash because 63 is over the hard coded limit.
#[repr(C)]
#[repr(align(64))]
#[derive(Copy, Clone)]
Expand Down Expand Up @@ -55,7 +53,7 @@ impl ::std::cmp::PartialEq for NoDebug {
/// This should derive Debug/Hash/PartialEq/Eq because the padding size is less than the max derive
/// Debug/Hash/PartialEq/Eq impl for arrays. However, we conservatively don't derive Debug/Hash because
/// we determine Debug derive-ability before we compute padding, which happens at
/// codegen. (Again, we expect to get the alignment wrong for similar reasons.)
/// codegen.
#[repr(C)]
#[repr(align(64))]
#[derive(Copy, Clone)]
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/class.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --with-derive-partialord --with-derive-ord
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --with-derive-partialord --with-derive-ord --rust-target 1.40
//
class C {
int a;
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-bitfield-method-same-name.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-partialeq --impl-partialeq --impl-debug
// bindgen-flags: --with-derive-partialeq --impl-partialeq --impl-debug --rust-target 1.40

/// Because this struct have array larger than 32 items
/// and --with-derive-partialeq --impl-partialeq --impl-debug is provided,
Expand Down
2 changes: 2 additions & 0 deletions tests/headers/derive-clone.h
@@ -1,3 +1,5 @@
// bindgen-flags: --rust-target 1.40
//

/// This struct should derive `Clone`.
struct ShouldDeriveClone {
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-debug-bitfield-core.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --impl-debug --use-core --raw-line "extern crate core;"
// bindgen-flags: --impl-debug --use-core --raw-line "extern crate core;" --rust-target 1.40

class C {
bool a: 1;
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-debug-bitfield.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --impl-debug
// bindgen-flags: --impl-debug --rust-target 1.40

class C {
bool a: 1;
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-debug-function-pointer.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --impl-debug
// bindgen-flags: --impl-debug --rust-target 1.40

class Nice {
typedef void (*Function) (int data);
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-debug-generic.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --impl-debug
// bindgen-flags: --impl-debug --rust-target 1.40

template<typename T>
class Generic {
Expand Down
@@ -1,4 +1,4 @@
// bindgen-flags: --impl-debug
// bindgen-flags: --impl-debug --rust-target 1.40

// This type is opaque because the second template parameter
// is a non-type template parameter
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-debug-opaque.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --opaque-type "Opaque" --impl-debug
// bindgen-flags: --opaque-type "Opaque" --impl-debug --rust-target 1.40

class Opaque {
int i;
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-partialeq-base.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-partialeq --impl-partialeq
// bindgen-flags: --with-derive-partialeq --impl-partialeq --rust-target 1.40

class Base {
int large[33];
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-partialeq-bitfield.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-partialeq --impl-partialeq
// bindgen-flags: --with-derive-partialeq --impl-partialeq --rust-target 1.40

class C {
bool a: 1;
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/derive-partialeq-core.h
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-partialeq --impl-partialeq --use-core --raw-line "extern crate core;"
// bindgen-flags: --with-derive-partialeq --impl-partialeq --use-core --raw-line "extern crate core;" --rust-target 1.40

struct C {
int large_array[420];
Expand Down
2 changes: 2 additions & 0 deletions tests/headers/extern-const-struct.h
@@ -1,3 +1,5 @@
// bindgen-flags: --rust-target 1.40

struct nsFoo {
float details[400];
};
Expand Down
9 changes: 9 additions & 0 deletions tests/headers/issue-1977-larger-arrays.hpp
@@ -0,0 +1,9 @@
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq
//
struct S {
char large_array[33];
};

template<typename T> struct ST {
T large_array[33];
};
2 changes: 1 addition & 1 deletion tests/headers/issue-372.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --enable-cxx-namespaces --rustified-enum ".*"
// bindgen-flags: --enable-cxx-namespaces --rustified-enum ".*" --rust-target 1.40
template <typename a, int b> class c { a e[b]; };
class d;
template <typename g, g f> class C { c<d, f> h; };
Expand Down
8 changes: 3 additions & 5 deletions tests/headers/issue-648-derive-debug-with-padding.h
@@ -1,9 +1,7 @@
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq --rust-target 1.40
/**
* We emit a `[u8; 63usize]` padding field for this struct, which cannot derive
* Debug/Hash because 63 is over the hard coded limit. (Yes, this struct doesn't end
* up with the reight alignment, we're waiting on `#[repr(align="N")]` to land
* in rustc).
* Debug/Hash because 63 is over the hard coded limit.
*/
struct NoDebug {
char c;
Expand All @@ -14,7 +12,7 @@ struct NoDebug {
* This should derive Debug/Hash/PartialEq/Eq because the padding size is less than the max derive
* Debug/Hash/PartialEq/Eq impl for arrays. However, we conservatively don't derive Debug/Hash because
* we determine Debug derive-ability before we compute padding, which happens at
* codegen. (Again, we expect to get the alignment wrong for similar reasons.)
* codegen.
*/
struct ShouldDeriveDebugButDoesNot {
char c[32];
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/layout_array.h
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq --rust-target 1.40
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/layout_array_too_long.h
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq --rustified-enum ".*"
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --impl-partialeq --rustified-enum ".*" --rust-target 1.40
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/layout_eth_conf.h
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --rustified-enum ".*"
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --rustified-enum ".*" --rust-target 1.40
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
Expand Down
1 change: 1 addition & 0 deletions tests/headers/layout_kni_mbuf.h
@@ -1,3 +1,4 @@
// bindgen-flags: --rust-target 1.40

#define RTE_CACHE_LINE_MIN_SIZE 64 /**< Minimum Cache line size. */

Expand Down
2 changes: 1 addition & 1 deletion tests/headers/layout_large_align_field.h
@@ -1,4 +1,4 @@
// bindgen-flags: --rustified-enum ".*"
// bindgen-flags: --rustified-enum ".*" --rust-target 1.40

typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/no_debug_bypass_impl_debug.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --no-debug "NoDebug" --impl-debug
// bindgen-flags: --no-debug "NoDebug" --impl-debug --rust-target 1.40

template<typename T>
class Generic {
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/no_default_bypass_derive_default.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --no-default "NoDefault"
// bindgen-flags: --no-default "NoDefault" --rust-target 1.40

template<typename T>
class Generic {
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/opaque-template-inst-member.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --opaque-type 'OpaqueTemplate' --with-derive-hash --with-derive-partialeq --impl-partialeq --with-derive-eq
// bindgen-flags: --opaque-type 'OpaqueTemplate' --with-derive-hash --with-derive-partialeq --impl-partialeq --with-derive-eq --rust-target 1.40

template<typename T>
class OpaqueTemplate {
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/struct_with_derive_debug.h
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --rust-target 1.40
//
struct LittleArray {
int a[32];
Expand Down
2 changes: 1 addition & 1 deletion tests/headers/struct_with_large_array.hpp
@@ -1,4 +1,4 @@
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq
// bindgen-flags: --with-derive-hash --with-derive-partialeq --with-derive-eq --rust-target 1.40
//
struct S {
char large_array[33];
Expand Down
2 changes: 2 additions & 0 deletions tests/headers/timex.h
@@ -1,3 +1,5 @@
// bindgen-flags: --rust-target 1.40

struct timex {
int tai;

Expand Down

0 comments on commit d7f03fd

Please sign in to comment.