From cf7bb3c180da0dcf2360967698e6b19fd4e21d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 19 Sep 2018 02:36:48 +0200 Subject: [PATCH 1/5] Add detection for i128 / u128 support. --- src/features.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/features.rs b/src/features.rs index 257d769797..671464ab7c 100644 --- a/src/features.rs +++ b/src/features.rs @@ -96,6 +96,8 @@ macro_rules! rust_target_base { => Stable_1_21 => 1.21; /// Rust stable 1.25 => Stable_1_25 => 1.25; + /// Rust stable 1.26 + => Stable_1_26 => 1.26; /// Nightly rust => Nightly => nightly; ); @@ -172,6 +174,10 @@ rust_feature_def!( /// repr(align) ([PR](https://github.com/rust-lang/rust/pull/47006)) => repr_align; } + Stable_1_26 { + /// [i128 / u128 support](https://doc.rust-lang.org/std/primitive.i128.html) + => i128_and_u128; + } Nightly { /// `thiscall` calling convention ([Tracking issue](https://github.com/rust-lang/rust/issues/42202)) => thiscall_abi; From 9087c2f065c8ae868ad418afee0c4bc5921337e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 19 Sep 2018 02:48:16 +0200 Subject: [PATCH 2/5] codegen: Generate u128 / i128 when available. --- src/codegen/mod.rs | 20 +++++++++---- tests/expectations/tests/i128.rs | 48 ++++++++++++++++++++++++++++++++ tests/headers/i128.h | 6 ++++ 3 files changed, 69 insertions(+), 5 deletions(-) create mode 100644 tests/expectations/tests/i128.rs create mode 100644 tests/headers/i128.h diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 8aa8d348ba..86a29c50da 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -3059,11 +3059,21 @@ impl TryToRustTy for Type { #ident }) } - // FIXME: This doesn't generate the proper alignment, but we - // can't do better right now. We should be able to use - // i128/u128 when they're available. - IntKind::U128 | IntKind::I128 => { - Ok(quote! { [u64; 2] }) + IntKind::U128 => { + Ok(if ctx.options().rust_features.i128_and_u128 { + quote! { u128 } + } else { + // Best effort thing, but wrong alignment + // unfortunately. + quote! { [u64; 2] } + }) + } + IntKind::I128 => { + Ok(if ctx.options().rust_features.i128_and_u128 { + quote! { i128 } + } else { + quote! { [u64; 2] } + }) } } } diff --git a/tests/expectations/tests/i128.rs b/tests/expectations/tests/i128.rs new file mode 100644 index 0000000000..cd91f141d7 --- /dev/null +++ b/tests/expectations/tests/i128.rs @@ -0,0 +1,48 @@ +/* automatically generated by rust-bindgen */ + +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct foo { + pub my_signed: i128, + pub my_unsigned: u128, +} +#[test] +fn bindgen_test_layout_foo() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(foo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 16usize, + concat!("Alignment of ", stringify!(foo)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).my_signed as *const _ as usize }, + 0usize, + concat!( + "Offset of field: ", + stringify!(foo), + "::", + stringify!(my_signed) + ) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).my_unsigned as *const _ as usize }, + 16usize, + concat!( + "Offset of field: ", + stringify!(foo), + "::", + stringify!(my_unsigned) + ) + ); +} diff --git a/tests/headers/i128.h b/tests/headers/i128.h new file mode 100644 index 0000000000..6ec399c726 --- /dev/null +++ b/tests/headers/i128.h @@ -0,0 +1,6 @@ +// bindgen-flags: --rust-target 1.26 + +struct foo { + __int128 my_signed; + unsigned __int128 my_unsigned; +}; From 7455e3b5b98c392bd4c313b851cda2857581ed8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 19 Sep 2018 03:04:47 +0200 Subject: [PATCH 3/5] Teach the blob code to generate i128 / u128 if available. This is very mechanical and boring, but needed. --- src/codegen/helpers.rs | 10 ++-- src/codegen/impl_debug.rs | 2 +- src/codegen/mod.rs | 20 ++++---- src/codegen/struct_layout.rs | 2 +- src/ir/analysis/derive_copy.rs | 2 +- src/ir/analysis/derive_debug.rs | 6 +-- src/ir/analysis/derive_default.rs | 4 +- src/ir/analysis/derive_hash.rs | 8 +-- .../derive_partialeq_or_partialord.rs | 8 +-- src/ir/context.rs | 2 +- src/ir/derive.rs | 20 ++++---- src/ir/function.rs | 17 +++---- src/ir/item.rs | 2 +- src/ir/layout.rs | 50 ++++++++++--------- 14 files changed, 77 insertions(+), 76 deletions(-) diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs index b7c3df7ff4..55430fe9e7 100644 --- a/src/codegen/helpers.rs +++ b/src/codegen/helpers.rs @@ -59,14 +59,14 @@ pub mod attributes { /// Generates a proper type for a field or type with a given `Layout`, that is, /// a type with the correct size and alignment restrictions. -pub fn blob(layout: Layout) -> quote::Tokens { +pub fn blob(ctx: &BindgenContext, layout: Layout) -> quote::Tokens { let opaque = layout.opaque(); // FIXME(emilio, #412): We fall back to byte alignment, but there are // some things that legitimately are more than 8-byte aligned. // // Eventually we should be able to `unwrap` here, but... - let ty_name = match opaque.known_rust_type_for_array() { + let ty_name = match opaque.known_rust_type_for_array(ctx) { Some(ty) => ty, None => { warn!("Found unknown alignment on code generation!"); @@ -76,7 +76,7 @@ pub fn blob(layout: Layout) -> quote::Tokens { let ty_name = Term::new(ty_name, Span::call_site()); - let data_len = opaque.array_size().unwrap_or(layout.size); + let data_len = opaque.array_size(ctx).unwrap_or(layout.size); if data_len == 1 { quote! { @@ -90,8 +90,8 @@ pub fn blob(layout: Layout) -> quote::Tokens { } /// Integer type of the same size as the given `Layout`. -pub fn integer_type(layout: Layout) -> Option { - let name = Layout::known_type_for_size(layout.size)?; +pub fn integer_type(ctx: &BindgenContext, layout: Layout) -> Option { + let name = Layout::known_type_for_size(ctx, layout.size)?; let name = Term::new(name, Span::call_site()); Some(quote! { #name }) } diff --git a/src/codegen/impl_debug.rs b/src/codegen/impl_debug.rs index 0f8e4d96ee..2c6d36d930 100644 --- a/src/codegen/impl_debug.rs +++ b/src/codegen/impl_debug.rs @@ -236,7 +236,7 @@ impl<'a> ImplDebug<'a> for Item { let inner_type = ctx.resolve_type(inner).canonical_type(ctx); match *inner_type.kind() { TypeKind::Function(ref sig) - if !sig.can_trivially_derive_debug() => { + if !sig.can_trivially_derive_debug(ctx) => { Some((format!("{}: FunctionPointer", name), vec![])) } _ => debug_print(name, quote! { #name_ident }), diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 86a29c50da..b518891635 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1185,7 +1185,7 @@ impl Bitfield { let bitfield_ty_layout = bitfield_ty.layout(ctx).expect( "Bitfield without layout? Gah!", ); - let bitfield_int_ty = helpers::blob(bitfield_ty_layout); + let bitfield_int_ty = helpers::blob(ctx, bitfield_ty_layout); let offset = self.offset_into_unit(); let width = self.width() as u8; @@ -1367,7 +1367,7 @@ impl<'a> FieldCodegen<'a> for Bitfield { let bitfield_ty_layout = bitfield_ty.layout(ctx).expect( "Bitfield without layout? Gah!", ); - let bitfield_int_ty = match helpers::integer_type(bitfield_ty_layout) { + let bitfield_int_ty = match helpers::integer_type(ctx, bitfield_ty_layout) { Some(int_ty) => { *bitfield_representable_as_int = true; int_ty @@ -1547,7 +1547,7 @@ impl CodeGenerator for CompInfo { } let layout = layout.expect("Unable to get layout information?"); - let ty = helpers::blob(layout); + let ty = helpers::blob(ctx, layout); fields.push(if self.can_be_rust_union(ctx) { quote! { @@ -1572,7 +1572,7 @@ impl CodeGenerator for CompInfo { Some(l) => { explicit_align = Some(l.align); - let ty = helpers::blob(l); + let ty = helpers::blob(ctx, l); fields.push(quote! { pub _bindgen_opaque_blob: #ty , }); @@ -1595,7 +1595,7 @@ impl CodeGenerator for CompInfo { } else { explicit_align = Some(layout.align); if !ctx.options().rust_features.repr_align { - let ty = helpers::blob(Layout::new(0, layout.align)); + let ty = helpers::blob(ctx, Layout::new(0, layout.align)); fields.push(quote! { pub __bindgen_align: #ty , }); @@ -1629,7 +1629,7 @@ impl CodeGenerator for CompInfo { }; if has_address { - let ty = helpers::blob(Layout::new(1, 1)); + let ty = helpers::blob(ctx, Layout::new(1, 1)); fields.push(quote! { pub _address: #ty, }); @@ -2800,7 +2800,7 @@ trait TryToOpaque { extra: &Self::Extra, ) -> error::Result { self.try_get_layout(ctx, extra).map(|layout| { - helpers::blob(layout) + helpers::blob(ctx, layout) }) } } @@ -2827,7 +2827,7 @@ trait ToOpaque: TryToOpaque { extra: &Self::Extra, ) -> quote::Tokens { let layout = self.get_layout(ctx, extra); - helpers::blob(layout) + helpers::blob(ctx, layout) } } @@ -2885,7 +2885,7 @@ where |_| if let Ok(layout) = self.try_get_layout(ctx, extra) { - Ok(helpers::blob(layout)) + Ok(helpers::blob(ctx, layout)) } else { Err(error::Error::NoLayoutForOpaqueBlob) }, @@ -3037,7 +3037,7 @@ impl TryToRustTy for Type { IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")), IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")), IntKind::WChar { size } => { - let ty = Layout::known_type_for_size(size) + let ty = Layout::known_type_for_size(ctx, size) .expect("Non-representable wchar_t?"); let ident = ctx.rust_ident_raw(ty); Ok(quote! { #ident }) diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs index 6de7e03069..b70fb658bc 100644 --- a/src/codegen/struct_layout.rs +++ b/src/codegen/struct_layout.rs @@ -306,7 +306,7 @@ impl<'a> StructLayoutTracker<'a> { } fn padding_field(&mut self, layout: Layout) -> quote::Tokens { - let ty = helpers::blob(layout); + let ty = helpers::blob(self.ctx, layout); let padding_count = self.padding_count; self.padding_count += 1; diff --git a/src/ir/analysis/derive_copy.rs b/src/ir/analysis/derive_copy.rs index fbe6e882e4..9d0bcd190f 100644 --- a/src/ir/analysis/derive_copy.rs +++ b/src/ir/analysis/derive_copy.rs @@ -149,7 +149,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveCopy<'ctx> { if item.is_opaque(self.ctx, &()) { let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_copy() + l.opaque().can_trivially_derive_copy(self.ctx) }); return if layout_can_derive { trace!(" we can trivially derive Copy for the layout"); diff --git a/src/ir/analysis/derive_debug.rs b/src/ir/analysis/derive_debug.rs index 5839f9ed1c..9210148a8b 100644 --- a/src/ir/analysis/derive_debug.rs +++ b/src/ir/analysis/derive_debug.rs @@ -146,7 +146,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDebug<'ctx> { if item.is_opaque(self.ctx, &()) { let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_debug() + l.opaque().can_trivially_derive_debug(self.ctx) }); return if layout_can_derive && !(ty.is_union() && @@ -242,7 +242,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDebug<'ctx> { } if ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_debug() + l.opaque().can_trivially_derive_debug(self.ctx) }) { trace!(" union layout can trivially derive Debug"); @@ -299,7 +299,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDebug<'ctx> { let inner_type = self.ctx.resolve_type(inner).canonical_type(self.ctx); if let TypeKind::Function(ref sig) = *inner_type.kind() { - if !sig.can_trivially_derive_debug() { + if !sig.can_trivially_derive_debug(self.ctx) { trace!( " function pointer that can't trivially derive Debug" ); diff --git a/src/ir/analysis/derive_default.rs b/src/ir/analysis/derive_default.rs index cc322e9bcd..2ff07ce9e8 100644 --- a/src/ir/analysis/derive_default.rs +++ b/src/ir/analysis/derive_default.rs @@ -173,7 +173,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDefault<'ctx> { if item.is_opaque(self.ctx, &()) { let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_default() + l.opaque().can_trivially_derive_default(self.ctx) }); return if layout_can_derive && !(ty.is_union() && @@ -278,7 +278,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDefault<'ctx> { } if ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_default() + l.opaque().can_trivially_derive_default(self.ctx) }) { trace!(" union layout can trivially derive Default"); diff --git a/src/ir/analysis/derive_hash.rs b/src/ir/analysis/derive_hash.rs index 18c14a31aa..eee6d6f072 100644 --- a/src/ir/analysis/derive_hash.rs +++ b/src/ir/analysis/derive_hash.rs @@ -133,7 +133,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveHash<'ctx> { if item.is_opaque(self.ctx, &()) { let layout_can_derive = ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_hash() + l.opaque().can_trivially_derive_hash(self.ctx) }); return if layout_can_derive && !(ty.is_union() && @@ -218,7 +218,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveHash<'ctx> { let inner_type = self.ctx.resolve_type(inner).canonical_type(self.ctx); if let TypeKind::Function(ref sig) = *inner_type.kind() { - if !sig.can_trivially_derive_hash() { + if !sig.can_trivially_derive_hash(self.ctx) { trace!( " function pointer that can't trivially derive Hash" ); @@ -230,7 +230,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveHash<'ctx> { } TypeKind::Function(ref sig) => { - if !sig.can_trivially_derive_hash() { + if !sig.can_trivially_derive_hash(self.ctx) { trace!(" function that can't trivially derive Hash"); return self.insert(id); } @@ -275,7 +275,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveHash<'ctx> { } if ty.layout(self.ctx).map_or(true, |l| { - l.opaque().can_trivially_derive_hash() + l.opaque().can_trivially_derive_hash(self.ctx) }) { trace!(" union layout can trivially derive Hash"); diff --git a/src/ir/analysis/derive_partialeq_or_partialord.rs b/src/ir/analysis/derive_partialeq_or_partialord.rs index c643a90b17..5a9a21c553 100644 --- a/src/ir/analysis/derive_partialeq_or_partialord.rs +++ b/src/ir/analysis/derive_partialeq_or_partialord.rs @@ -129,7 +129,7 @@ impl<'ctx> CannotDerivePartialEqOrPartialOrd<'ctx> { let layout_can_derive = ty.layout(self.ctx) .map_or(CanDerive::Yes, |l| { - l.opaque().can_trivially_derive_partialeq_or_partialord() + l.opaque().can_trivially_derive_partialeq_or_partialord(self.ctx) }); match layout_can_derive { @@ -210,7 +210,7 @@ impl<'ctx> CannotDerivePartialEqOrPartialOrd<'ctx> { let inner_type = self.ctx.resolve_type(inner).canonical_type(self.ctx); if let TypeKind::Function(ref sig) = *inner_type.kind() { - if sig.can_trivially_derive_partialeq_or_partialord() + if sig.can_trivially_derive_partialeq_or_partialord(self.ctx) != CanDerive::Yes { trace!( @@ -224,7 +224,7 @@ impl<'ctx> CannotDerivePartialEqOrPartialOrd<'ctx> { } TypeKind::Function(ref sig) => { - if sig.can_trivially_derive_partialeq_or_partialord() + if sig.can_trivially_derive_partialeq_or_partialord(self.ctx) != CanDerive::Yes { trace!( @@ -258,7 +258,7 @@ impl<'ctx> CannotDerivePartialEqOrPartialOrd<'ctx> { let layout_can_derive = ty.layout(self.ctx).map_or(CanDerive::Yes, |l| { l.opaque() - .can_trivially_derive_partialeq_or_partialord() + .can_trivially_derive_partialeq_or_partialord(self.ctx) }); match layout_can_derive { CanDerive::Yes => { diff --git a/src/ir/context.rs b/src/ir/context.rs index bd353a5f1f..3f69aca18b 100644 --- a/src/ir/context.rs +++ b/src/ir/context.rs @@ -226,7 +226,7 @@ where } } -impl<'a, T> CanDeriveCopy<'a> for T +impl CanDeriveCopy for T where T: Copy + Into { diff --git a/src/ir/derive.rs b/src/ir/derive.rs index 65c221582a..71854d2e52 100644 --- a/src/ir/derive.rs +++ b/src/ir/derive.rs @@ -30,15 +30,15 @@ pub trait CanDeriveDebug { pub trait CanTriviallyDeriveDebug { /// Return `true` if `Debug` can trivially be derived for this thing, /// `false` otherwise. - fn can_trivially_derive_debug(&self) -> bool; + fn can_trivially_derive_debug(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive `Copy` /// for a given thing. -pub trait CanDeriveCopy<'a> { +pub trait CanDeriveCopy { /// Return `true` if `Copy` can be derived for this thing, `false` /// otherwise. - fn can_derive_copy(&'a self, ctx: &'a BindgenContext) -> bool; + fn can_derive_copy(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can trivially @@ -47,7 +47,7 @@ pub trait CanDeriveCopy<'a> { pub trait CanTriviallyDeriveCopy { /// Return `true` if `Copy` can be trivially derived for this thing, `false` /// otherwise. - fn can_trivially_derive_copy(&self) -> bool; + fn can_trivially_derive_copy(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive @@ -64,7 +64,7 @@ pub trait CanDeriveDefault { pub trait CanTriviallyDeriveDefault { /// Return `true` if `Default` can trivially derived for this thing, `false` /// otherwise. - fn can_trivially_derive_default(&self) -> bool; + fn can_trivially_derive_default(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can derive `Hash` @@ -111,7 +111,7 @@ pub trait CanDeriveOrd { pub trait CanTriviallyDeriveHash { /// Return `true` if `Hash` can trivially be derived for this thing, `false` /// otherwise. - fn can_trivially_derive_hash(&self) -> bool; + fn can_trivially_derive_hash(&self, ctx: &BindgenContext) -> bool; } /// A trait that encapsulates the logic for whether or not we can trivially @@ -120,11 +120,11 @@ pub trait CanTriviallyDeriveHash { pub trait CanTriviallyDerivePartialEqOrPartialOrd { /// Return `Yes` if `PartialEq` or `PartialOrd` can trivially be derived /// for this thing. - fn can_trivially_derive_partialeq_or_partialord(&self) -> CanDerive; + fn can_trivially_derive_partialeq_or_partialord(&self, ctx: &BindgenContext) -> CanDerive; } /// Whether it is possible or not to automatically derive trait for an item. -/// +/// /// ```ignore /// No /// ^ @@ -134,7 +134,7 @@ pub trait CanTriviallyDerivePartialEqOrPartialOrd { /// | /// Yes /// ``` -/// +/// /// Initially we assume that we can derive trait for all types and then /// update our understanding as we learn more about each type. #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord)] @@ -144,7 +144,7 @@ pub enum CanDerive { /// The only thing that stops us from automatically deriving is that /// array with more than maximum number of elements is used. - /// + /// /// This means we probably can "manually" implement such trait. ArrayTooLarge, diff --git a/src/ir/function.rs b/src/ir/function.rs index 5e8d2fc8d5..f7f4398bf6 100644 --- a/src/ir/function.rs +++ b/src/ir/function.rs @@ -581,26 +581,23 @@ impl Trace for FunctionSig { } impl CanTriviallyDeriveDebug for FunctionSig { - fn can_trivially_derive_debug(&self) -> bool { + fn can_trivially_derive_debug(&self, _: &BindgenContext) -> bool { self.function_pointers_can_derive() } } impl CanTriviallyDeriveHash for FunctionSig { - fn can_trivially_derive_hash(&self) -> bool { + fn can_trivially_derive_hash(&self, _: &BindgenContext) -> bool { self.function_pointers_can_derive() } } impl CanTriviallyDerivePartialEqOrPartialOrd for FunctionSig { - fn can_trivially_derive_partialeq_or_partialord(&self) -> CanDerive { - if self.argument_types.len() > RUST_DERIVE_FUNPTR_LIMIT { - return CanDerive::No; - } - - match self.abi { - Abi::C | Abi::Unknown(..) => CanDerive::Yes, - _ => CanDerive::No, + fn can_trivially_derive_partialeq_or_partialord(&self, _: &BindgenContext) -> CanDerive { + if self.function_pointers_can_derive() { + CanDerive::Yes + } else { + CanDerive::No } } } diff --git a/src/ir/item.rs b/src/ir/item.rs index a7ced3d0e0..27e3d2f88d 100644 --- a/src/ir/item.rs +++ b/src/ir/item.rs @@ -329,7 +329,7 @@ impl CanDeriveDefault for Item { } } -impl<'a> CanDeriveCopy<'a> for Item { +impl CanDeriveCopy for Item { fn can_derive_copy(&self, ctx: &BindgenContext) -> bool { self.id().can_derive_copy(ctx) } diff --git a/src/ir/layout.rs b/src/ir/layout.rs index aa7dc5661a..c34da0e1de 100644 --- a/src/ir/layout.rs +++ b/src/ir/layout.rs @@ -36,8 +36,12 @@ fn test_layout_for_size() { impl Layout { /// Gets the integer type name for a given known size. - pub fn known_type_for_size(size: usize) -> Option<&'static str> { + pub fn known_type_for_size( + ctx: &BindgenContext, + size: usize, + ) -> Option<&'static str> { Some(match size { + 16 if ctx.options().rust_features.i128_and_u128 => "u128", 8 => "u64", 4 => "u32", 2 => "u16", @@ -105,14 +109,14 @@ impl Opaque { /// Return the known rust type we should use to create a correctly-aligned /// field with this layout. - pub fn known_rust_type_for_array(&self) -> Option<&'static str> { - Layout::known_type_for_size(self.0.align) + pub fn known_rust_type_for_array(&self,ctx: &BindgenContext) -> Option<&'static str> { + Layout::known_type_for_size(ctx, self.0.align) } /// Return the array size that an opaque type for this layout should have if /// we know the correct type for it, or `None` otherwise. - pub fn array_size(&self) -> Option { - if self.known_rust_type_for_array().is_some() { + pub fn array_size(&self, ctx: &BindgenContext) -> Option { + if self.known_rust_type_for_array(ctx).is_some() { Some(self.0.size / cmp::max(self.0.align, 1)) } else { None @@ -122,45 +126,45 @@ impl Opaque { /// Return `true` if this opaque layout's array size will fit within the /// maximum number of array elements that Rust allows deriving traits /// with. Return `false` otherwise. - pub fn array_size_within_derive_limit(&self) -> bool { - self.array_size().map_or(false, |size| { + pub fn array_size_within_derive_limit(&self, ctx: &BindgenContext) -> bool { + self.array_size(ctx).map_or(false, |size| { size <= RUST_DERIVE_IN_ARRAY_LIMIT }) } } impl CanTriviallyDeriveDebug for Opaque { - fn can_trivially_derive_debug(&self) -> bool { - self.array_size_within_derive_limit() + fn can_trivially_derive_debug(&self, ctx: &BindgenContext) -> bool { + self.array_size_within_derive_limit(ctx) } } impl CanTriviallyDeriveDefault for Opaque { - fn can_trivially_derive_default(&self) -> bool { - self.array_size_within_derive_limit() + fn can_trivially_derive_default(&self, ctx: &BindgenContext) -> bool { + self.array_size_within_derive_limit(ctx) } } impl CanTriviallyDeriveCopy for Opaque { - fn can_trivially_derive_copy(&self) -> bool { - self.array_size_within_derive_limit() + fn can_trivially_derive_copy(&self, ctx: &BindgenContext) -> bool { + self.array_size_within_derive_limit(ctx) } } impl CanTriviallyDeriveHash for Opaque { - fn can_trivially_derive_hash(&self) -> bool { - self.array_size_within_derive_limit() + fn can_trivially_derive_hash(&self, ctx: &BindgenContext) -> bool { + self.array_size_within_derive_limit(ctx) } } impl CanTriviallyDerivePartialEqOrPartialOrd for Opaque { - fn can_trivially_derive_partialeq_or_partialord(&self) -> CanDerive { - self.array_size().map_or(CanDerive::No, |size| { - if size <= RUST_DERIVE_IN_ARRAY_LIMIT { - CanDerive::Yes - } else { - CanDerive::ArrayTooLarge - } - }) + fn can_trivially_derive_partialeq_or_partialord(&self, ctx: &BindgenContext) -> CanDerive { + // TODO(emilio): This is inconsistent with the rest of the + // CanTriviallyDerive* traits. + if self.array_size_within_derive_limit(ctx) { + CanDerive::Yes + } else { + CanDerive::ArrayTooLarge + } } } From 25eafd79d34c89b463b3aa38fdf84c17b6a430d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 19 Sep 2018 03:35:05 +0200 Subject: [PATCH 4/5] Teach the float code about u128. --- src/codegen/helpers.rs | 43 ++++++++++++++----- src/codegen/mod.rs | 4 +- tests/expectations/tests/convert-floats.rs | 11 +++-- tests/expectations/tests/long_double.rs | 32 ++++++++++++++ .../expectations/tests/union_bitfield_1_0.rs | 12 +++++- 5 files changed, 85 insertions(+), 17 deletions(-) create mode 100644 tests/expectations/tests/long_double.rs diff --git a/src/codegen/helpers.rs b/src/codegen/helpers.rs index 55430fe9e7..343f1e30f7 100644 --- a/src/codegen/helpers.rs +++ b/src/codegen/helpers.rs @@ -122,6 +122,7 @@ pub fn bitfield_unit(ctx: &BindgenContext, layout: Layout) -> quote::Tokens { pub mod ast_ty { use ir::context::BindgenContext; use ir::function::FunctionSig; + use ir::layout::Layout; use ir::ty::FloatKind; use quote; use proc_macro2; @@ -144,22 +145,44 @@ pub mod ast_ty { pub fn float_kind_rust_type( ctx: &BindgenContext, fk: FloatKind, + layout: Option, ) -> quote::Tokens { - // TODO: we probably should just take the type layout into - // account? + // TODO: we probably should take the type layout into account more + // often? // // Also, maybe this one shouldn't be the default? - // - // FIXME: `c_longdouble` doesn't seem to be defined in some - // systems, so we use `c_double` directly. match (fk, ctx.options().convert_floats) { (FloatKind::Float, true) => quote! { f32 }, - (FloatKind::Double, true) | - (FloatKind::LongDouble, true) => quote! { f64 }, + (FloatKind::Double, true) => quote! { f64 }, (FloatKind::Float, false) => raw_type(ctx, "c_float"), - (FloatKind::Double, false) | - (FloatKind::LongDouble, false) => raw_type(ctx, "c_double"), - (FloatKind::Float128, _) => quote! { [u8; 16] }, + (FloatKind::Double, false) => raw_type(ctx, "c_double"), + (FloatKind::LongDouble, _) => { + match layout { + Some(layout) => { + match layout.size { + 4 => quote! { f32 }, + 8 => quote! { f64 }, + // TODO(emilio): If rust ever gains f128 we should + // use it here and below. + _ => super::integer_type(ctx, layout).unwrap_or(quote! { f64 }), + } + } + None => { + debug_assert!( + false, + "How didn't we know the layout for a primitive type?" + ); + quote! { f64 } + } + } + } + (FloatKind::Float128, _) => { + if ctx.options().rust_features.i128_and_u128 { + quote! { u128 } + } else { + quote! { [u64; 2] } + } + } } } diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index b518891635..67d6b6d576 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -3077,9 +3077,9 @@ impl TryToRustTy for Type { } } } - TypeKind::Float(fk) => Ok(float_kind_rust_type(ctx, fk)), + TypeKind::Float(fk) => Ok(float_kind_rust_type(ctx, fk, self.layout(ctx))), TypeKind::Complex(fk) => { - let float_path = float_kind_rust_type(ctx, fk); + let float_path = float_kind_rust_type(ctx, fk, self.layout(ctx)); ctx.generated_bindgen_complex(); Ok(if ctx.options().enable_cxx_namespaces { diff --git a/tests/expectations/tests/convert-floats.rs b/tests/expectations/tests/convert-floats.rs index e1e93a1343..e6abee16d6 100644 --- a/tests/expectations/tests/convert-floats.rs +++ b/tests/expectations/tests/convert-floats.rs @@ -1,8 +1,11 @@ /* automatically generated by rust-bindgen */ - -#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] - +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] #[repr(C)] @@ -16,7 +19,7 @@ pub struct foo { pub bar: ::std::os::raw::c_float, pub baz: ::std::os::raw::c_float, pub bazz: ::std::os::raw::c_double, - pub bazzz: *mut ::std::os::raw::c_double, + pub bazzz: *mut f64, pub complexFloat: __BindgenComplex<::std::os::raw::c_float>, pub complexDouble: __BindgenComplex<::std::os::raw::c_double>, } diff --git a/tests/expectations/tests/long_double.rs b/tests/expectations/tests/long_double.rs new file mode 100644 index 0000000000..05d56414ac --- /dev/null +++ b/tests/expectations/tests/long_double.rs @@ -0,0 +1,32 @@ +/* automatically generated by rust-bindgen */ + +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct foo { + pub bar: u128, +} +#[test] +fn bindgen_test_layout_foo() { + assert_eq!( + ::std::mem::size_of::(), + 16usize, + concat!("Size of: ", stringify!(foo)) + ); + assert_eq!( + ::std::mem::align_of::(), + 16usize, + concat!("Alignment of ", stringify!(foo)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).bar as *const _ as usize }, + 0usize, + concat!("Offset of field: ", stringify!(foo), "::", stringify!(bar)) + ); +} diff --git a/tests/expectations/tests/union_bitfield_1_0.rs b/tests/expectations/tests/union_bitfield_1_0.rs index b33d9873eb..adab161e16 100644 --- a/tests/expectations/tests/union_bitfield_1_0.rs +++ b/tests/expectations/tests/union_bitfield_1_0.rs @@ -1,6 +1,11 @@ /* automatically generated by rust-bindgen */ -#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#![allow( + dead_code, + non_snake_case, + non_camel_case_types, + non_upper_case_globals +)] #[repr(C)] #[derive(Copy, Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)] @@ -279,3 +284,8 @@ impl Default for HasBigBitfield { unsafe { ::std::mem::zeroed() } } } +impl ::std::cmp::PartialEq for HasBigBitfield { + fn eq(&self, other: &HasBigBitfield) -> bool { + &self.bindgen_union_field[..] == &other.bindgen_union_field[..] + } +} From c09c74e18b6ce8b69626a59737d8e82a3eb1d1b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 19 Sep 2018 16:13:30 +0200 Subject: [PATCH 5/5] Always force repr(align) attributes for stuff with alignment >= 16 To work-around some cases of https://github.com/rust-lang/rust/issues/54341. Other cases where u128 and u64 are mixed in fields might not behave correctly, but the field offset assertions would catch them. Fixes #1370 --- src/codegen/struct_layout.rs | 17 +++++++++++------ tests/expectations/tests/i128.rs | 1 + tests/expectations/tests/long_double.rs | 1 + 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/codegen/struct_layout.rs b/src/codegen/struct_layout.rs index b70fb658bc..0ea23ddf4d 100644 --- a/src/codegen/struct_layout.rs +++ b/src/codegen/struct_layout.rs @@ -287,18 +287,23 @@ impl<'a> StructLayoutTracker<'a> { } pub fn requires_explicit_align(&self, layout: Layout) -> bool { + let repr_align = self.ctx.options().rust_features().repr_align; + + // Always force explicit repr(align) for stuff more than 16-byte aligned + // to work-around https://github.com/rust-lang/rust/issues/54341. + // + // Worst-case this just generates redundant alignment attributes. + if repr_align && self.max_field_align >= 16 { + return true; + } + if self.max_field_align >= layout.align { return false; } - // At this point we require explicit alignment, but we may not be able - // to generate the right bits, let's double check. - if self.ctx.options().rust_features().repr_align { - return true; - } // We can only generate up-to a word of alignment unless we support // repr(align). - layout.align <= self.ctx.target_pointer_size() + repr_align || layout.align <= self.ctx.target_pointer_size() } fn padding_bytes(&self, layout: Layout) -> usize { diff --git a/tests/expectations/tests/i128.rs b/tests/expectations/tests/i128.rs index cd91f141d7..1fae2bee8c 100644 --- a/tests/expectations/tests/i128.rs +++ b/tests/expectations/tests/i128.rs @@ -8,6 +8,7 @@ )] #[repr(C)] +#[repr(align(16))] #[derive(Debug, Default, Copy, Clone)] pub struct foo { pub my_signed: i128, diff --git a/tests/expectations/tests/long_double.rs b/tests/expectations/tests/long_double.rs index 05d56414ac..632eeb5a69 100644 --- a/tests/expectations/tests/long_double.rs +++ b/tests/expectations/tests/long_double.rs @@ -8,6 +8,7 @@ )] #[repr(C)] +#[repr(align(16))] #[derive(Debug, Default, Copy, Clone)] pub struct foo { pub bar: u128,