From 96b26b308dbfb5acde0ede785dcbb7d276ef98f2 Mon Sep 17 00:00:00 2001 From: Emilio Cobos Álvarez Date: Sat, 10 Mar 2018 07:06:36 +0100 Subject: codegen: support repr(align). Fixes #917 --- src/codegen/mod.rs | 16 ++++++++++++++++ src/features.rs | 8 ++++++++ tests/expectations/tests/repr-align.rs | 35 ++++++++++++++++++++++++++++++++++ tests/headers/repr-align.hpp | 6 ++++++ 4 files changed, 65 insertions(+) create mode 100644 tests/expectations/tests/repr-align.rs create mode 100644 tests/headers/repr-align.hpp diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 1801520a..950708a0 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1527,6 +1527,7 @@ impl CodeGenerator for CompInfo { }); } + let mut explicit_align = None; if is_opaque { // Opaque item should not have generated methods, fields. debug_assert!(fields.is_empty()); @@ -1534,6 +1535,8 @@ impl CodeGenerator for CompInfo { match layout { Some(l) => { + explicit_align = Some(l.align); + let ty = helpers::blob(l); fields.push(quote! { pub _bindgen_opaque_blob: #ty , @@ -1555,6 +1558,7 @@ impl CodeGenerator for CompInfo { if layout.align == 1 { packed = true; } else { + explicit_align = Some(layout.align); let ty = helpers::blob(Layout::new(0, layout.align)); fields.push(quote! { pub __bindgen_align: #ty , @@ -1637,6 +1641,18 @@ impl CodeGenerator for CompInfo { attributes.push(attributes::repr("C")); } + if ctx.options().rust_features().repr_align() { + if let Some(explicit) = explicit_align { + // Ensure that the struct has the correct alignment even in + // presence of alignas. + let explicit = helpers::ast_ty::int_expr(explicit as i64); + attributes.push(quote! { + #[repr(align(#explicit))] + }); + } + } + + let mut derives = vec![]; if item.can_derive_debug(ctx) { derives.push("Debug"); diff --git a/src/features.rs b/src/features.rs index d4fbd928..fe4f8453 100644 --- a/src/features.rs +++ b/src/features.rs @@ -92,6 +92,8 @@ macro_rules! rust_target_base { => Stable_1_19 => 1.19; /// Rust stable 1.21 => Stable_1_21 => 1.21; + /// Rust stable 1.24 + => Stable_1_24 => 1.24; /// Nightly rust => Nightly => nightly; ); @@ -144,6 +146,8 @@ rust_feature_def!( => thiscall_abi; /// builtin impls for `Clone` ([PR](https://github.com/rust-lang/rust/pull/43690)) => builtin_clone_impls; + /// repr(align) https://github.com/rust-lang/rust/pull/47006 + => repr_align; ); impl From for RustFeatures { @@ -158,6 +162,10 @@ impl From for RustFeatures { features.builtin_clone_impls = true; } + if rust_target >= RustTarget::Stable_1_24 { + features.repr_align = true; + } + if rust_target >= RustTarget::Nightly { features.thiscall_abi = true; } diff --git a/tests/expectations/tests/repr-align.rs b/tests/expectations/tests/repr-align.rs new file mode 100644 index 00000000..be9ce9ad --- /dev/null +++ b/tests/expectations/tests/repr-align.rs @@ -0,0 +1,35 @@ +/* automatically generated by rust-bindgen */ + +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] + +#[repr(C)] +#[repr(align(8))] +#[derive(Debug, Default, Copy, Clone)] +pub struct a { + pub b: ::std::os::raw::c_int, + pub c: ::std::os::raw::c_int, + pub __bindgen_align: [u64; 0usize], +} +#[test] +fn bindgen_test_layout_a() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(a)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(a)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).b as *const _ as usize }, + 0usize, + concat!("Offset of field: ", stringify!(a), "::", stringify!(b)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).c as *const _ as usize }, + 4usize, + concat!("Offset of field: ", stringify!(a), "::", stringify!(c)) + ); +} diff --git a/tests/headers/repr-align.hpp b/tests/headers/repr-align.hpp new file mode 100644 index 00000000..f0629496 --- /dev/null +++ b/tests/headers/repr-align.hpp @@ -0,0 +1,6 @@ +// bindgen-flags: --rust-target 1.24 -- -std=c++11 + +struct alignas(8) a { + int b; + int c; +}; -- cgit v1.2.3 From b91583f101eca2c80b9424968a0e68fefc3571af Mon Sep 17 00:00:00 2001 From: Emilio Cobos Álvarez Date: Sat, 10 Mar 2018 07:15:10 +0100 Subject: Add a kill-switch for untagged unions. Otherwise we can't use repr(align) on stylo. --- src/codegen/impl_partialeq.rs | 2 +- src/codegen/mod.rs | 10 +++++----- src/features.rs | 14 ++++---------- src/ir/analysis/derive_copy.rs | 2 +- src/ir/analysis/derive_debug.rs | 4 ++-- src/ir/analysis/derive_default.rs | 4 ++-- src/ir/analysis/derive_hash.rs | 4 ++-- src/ir/analysis/derive_partialeq_or_partialord.rs | 4 ++-- src/ir/comp.rs | 2 +- src/lib.rs | 6 ++++++ 10 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/codegen/impl_partialeq.rs b/src/codegen/impl_partialeq.rs index 02783808..31c2c979 100644 --- a/src/codegen/impl_partialeq.rs +++ b/src/codegen/impl_partialeq.rs @@ -20,7 +20,7 @@ pub fn gen_partialeq_impl( &self._bindgen_opaque_blob[..] == &other._bindgen_opaque_blob[..] }); } else if comp_info.kind() == CompKind::Union { - assert!(!ctx.options().rust_features().untagged_union()); + assert!(!ctx.options().rust_features().untagged_union); tokens.push(quote! { &self.bindgen_union_field[..] == &other.bindgen_union_field[..] }); diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 950708a0..a6ab3997 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1641,7 +1641,7 @@ impl CodeGenerator for CompInfo { attributes.push(attributes::repr("C")); } - if ctx.options().rust_features().repr_align() { + if ctx.options().rust_features().repr_align { if let Some(explicit) = explicit_align { // Ensure that the struct has the correct alignment even in // presence of alignas. @@ -1671,7 +1671,7 @@ impl CodeGenerator for CompInfo { if item.can_derive_copy(ctx) && !item.annotations().disallow_copy() { derives.push("Copy"); - if ctx.options().rust_features().builtin_clone_impls() || + if ctx.options().rust_features().builtin_clone_impls || used_template_params.is_some() { // FIXME: This requires extra logic if you have a big array in a @@ -2012,7 +2012,7 @@ impl MethodCodegen for Method { _ => panic!("How in the world?"), }; - if let (Abi::ThisCall, false) = (signature.abi(), ctx.options().rust_features().thiscall_abi()) { + if let (Abi::ThisCall, false) = (signature.abi(), ctx.options().rust_features().thiscall_abi) { return; } @@ -3183,7 +3183,7 @@ impl TryToRustTy for FunctionSig { let abi = self.abi(); match abi { - Abi::ThisCall if !ctx.options().rust_features().thiscall_abi() => { + Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => { warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); Ok(quote::Tokens::new()) } @@ -3280,7 +3280,7 @@ impl CodeGenerator for Function { } let abi = match signature.abi() { - Abi::ThisCall if !ctx.options().rust_features().thiscall_abi() => { + Abi::ThisCall if !ctx.options().rust_features().thiscall_abi => { warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); return; } diff --git a/src/features.rs b/src/features.rs index fe4f8453..1b490f54 100644 --- a/src/features.rs +++ b/src/features.rs @@ -113,7 +113,10 @@ macro_rules! rust_feature_def { #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] pub struct RustFeatures { $( - $feature: bool, + $( + #[$attr] + )* + pub $feature: bool, )* } @@ -126,15 +129,6 @@ macro_rules! rust_feature_def { )* } } - - $( - $( - #[$attr] - )* - pub fn $feature(&self) -> bool { - self.$feature - } - )* } } } diff --git a/src/ir/analysis/derive_copy.rs b/src/ir/analysis/derive_copy.rs index 94d457d5..69725ead 100644 --- a/src/ir/analysis/derive_copy.rs +++ b/src/ir/analysis/derive_copy.rs @@ -234,7 +234,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveCopy<'ctx> { } if info.kind() == CompKind::Union { - if !self.ctx.options().rust_features().untagged_union() { + if !self.ctx.options().rust_features().untagged_union { // NOTE: If there's no template parameters we can derive // copy unconditionally, since arrays are magical for // rustc, and __BindgenUnionField always implements diff --git a/src/ir/analysis/derive_debug.rs b/src/ir/analysis/derive_debug.rs index a1743ae9..b191d37d 100644 --- a/src/ir/analysis/derive_debug.rs +++ b/src/ir/analysis/derive_debug.rs @@ -150,7 +150,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDebug<'ctx> { }); return if layout_can_derive && !(ty.is_union() && - self.ctx.options().rust_features().untagged_union()) { + self.ctx.options().rust_features().untagged_union) { trace!(" we can trivially derive Debug for the layout"); ConstrainResult::Same } else { @@ -235,7 +235,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDebug<'ctx> { ); if info.kind() == CompKind::Union { - if self.ctx.options().rust_features().untagged_union() { + if self.ctx.options().rust_features().untagged_union { trace!(" cannot derive Debug for Rust unions"); return self.insert(id); } diff --git a/src/ir/analysis/derive_default.rs b/src/ir/analysis/derive_default.rs index 2c79a437..e319166d 100644 --- a/src/ir/analysis/derive_default.rs +++ b/src/ir/analysis/derive_default.rs @@ -177,7 +177,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDefault<'ctx> { }); return if layout_can_derive && !(ty.is_union() && - self.ctx.options().rust_features().untagged_union()) { + self.ctx.options().rust_features().untagged_union) { trace!(" we can trivially derive Default for the layout"); ConstrainResult::Same } else { @@ -271,7 +271,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveDefault<'ctx> { } if info.kind() == CompKind::Union { - if self.ctx.options().rust_features().untagged_union() { + if self.ctx.options().rust_features().untagged_union { trace!(" cannot derive Default for Rust unions"); return self.insert(id); } diff --git a/src/ir/analysis/derive_hash.rs b/src/ir/analysis/derive_hash.rs index 3fc31b39..c23a891e 100644 --- a/src/ir/analysis/derive_hash.rs +++ b/src/ir/analysis/derive_hash.rs @@ -137,7 +137,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveHash<'ctx> { }); return if layout_can_derive && !(ty.is_union() && - self.ctx.options().rust_features().untagged_union()) { + self.ctx.options().rust_features().untagged_union) { trace!(" we can trivially derive Hash for the layout"); ConstrainResult::Same } else { @@ -257,7 +257,7 @@ impl<'ctx> MonotoneFramework for CannotDeriveHash<'ctx> { } if info.kind() == CompKind::Union { - if self.ctx.options().rust_features().untagged_union() { + if self.ctx.options().rust_features().untagged_union { trace!(" cannot derive Hash for Rust unions"); return self.insert(id); } diff --git a/src/ir/analysis/derive_partialeq_or_partialord.rs b/src/ir/analysis/derive_partialeq_or_partialord.rs index 2641d2b3..cebdceef 100644 --- a/src/ir/analysis/derive_partialeq_or_partialord.rs +++ b/src/ir/analysis/derive_partialeq_or_partialord.rs @@ -119,7 +119,7 @@ impl<'ctx> CannotDerivePartialEqOrPartialOrd<'ctx> { trace!("ty: {:?}", ty); if item.is_opaque(self.ctx, &()) { if ty.is_union() - && self.ctx.options().rust_features().untagged_union() + && self.ctx.options().rust_features().untagged_union { trace!( " cannot derive `PartialEq`/`PartialOrd` for Rust unions" @@ -242,7 +242,7 @@ impl<'ctx> CannotDerivePartialEqOrPartialOrd<'ctx> { } if info.kind() == CompKind::Union { - if self.ctx.options().rust_features().untagged_union() { + if self.ctx.options().rust_features().untagged_union { trace!( " cannot derive `PartialEq`/`PartialOrd` for Rust unions" ); diff --git a/src/ir/comp.rs b/src/ir/comp.rs index 24909cb5..131851fd 100644 --- a/src/ir/comp.rs +++ b/src/ir/comp.rs @@ -1543,7 +1543,7 @@ impl CompInfo { /// 1. Current RustTarget allows for `untagged_union` /// 2. Each field can derive `Copy` pub fn can_be_rust_union(&self, ctx: &BindgenContext) -> bool { - if !ctx.options().rust_features().untagged_union() { + if !ctx.options().rust_features().untagged_union { return false; } diff --git a/src/lib.rs b/src/lib.rs index db58f6f4..6346ff80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -600,6 +600,12 @@ impl Builder { self } + /// Disable support for native Rust unions, if supported. + pub fn disable_untagged_union(mut self) -> Self { + self.options.rust_features.untagged_union = false; + self + } + /// Set the output graphviz file. pub fn emit_ir_graphviz>(mut self, path: T) -> Builder { let path = path.into(); -- cgit v1.2.3 From cd7e095091c4c8526aabd8aa7447bec67ddb95e2 Mon Sep 17 00:00:00 2001 From: Emilio Cobos Álvarez Date: Sat, 10 Mar 2018 07:19:15 +0100 Subject: Breaking version bump. --- Cargo.lock | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9842eccf..9fbb7087 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ dependencies = [ [[package]] name = "bindgen" -version = "0.33.2" +version = "0.34.0" dependencies = [ "cexpr 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index e1f95541..d8444ff0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ name = "bindgen" readme = "README.md" repository = "https://github.com/rust-lang-nursery/rust-bindgen" documentation = "https://docs.rs/bindgen" -version = "0.33.2" +version = "0.34.0" build = "build.rs" include = [ -- cgit v1.2.3 From 965dff29049c792f9243f2bbb9f5e64ba0b2ce52 Mon Sep 17 00:00:00 2001 From: Emilio Cobos Álvarez Date: Sat, 10 Mar 2018 07:45:08 +0100 Subject: tests: Add a test for alignas(double). --- tests/expectations/tests/repr-align.rs | 31 +++++++++++++++++++++++++++++++ tests/headers/repr-align.hpp | 5 +++++ 2 files changed, 36 insertions(+) diff --git a/tests/expectations/tests/repr-align.rs b/tests/expectations/tests/repr-align.rs index be9ce9ad..9689dacd 100644 --- a/tests/expectations/tests/repr-align.rs +++ b/tests/expectations/tests/repr-align.rs @@ -33,3 +33,34 @@ fn bindgen_test_layout_a() { concat!("Offset of field: ", stringify!(a), "::", stringify!(c)) ); } +#[repr(C)] +#[repr(align(8))] +#[derive(Debug, Default, Copy, Clone)] +pub struct b { + pub b: ::std::os::raw::c_int, + pub c: ::std::os::raw::c_int, + pub __bindgen_align: [u64; 0usize], +} +#[test] +fn bindgen_test_layout_b() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(b)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(b)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).b as *const _ as usize }, + 0usize, + concat!("Offset of field: ", stringify!(b), "::", stringify!(b)) + ); + assert_eq!( + unsafe { &(*(::std::ptr::null::())).c as *const _ as usize }, + 4usize, + concat!("Offset of field: ", stringify!(b), "::", stringify!(c)) + ); +} diff --git a/tests/headers/repr-align.hpp b/tests/headers/repr-align.hpp index f0629496..5e1b60ab 100644 --- a/tests/headers/repr-align.hpp +++ b/tests/headers/repr-align.hpp @@ -4,3 +4,8 @@ struct alignas(8) a { int b; int c; }; + +struct alignas(double) b { + int b; + int c; +}; -- cgit v1.2.3 From 853ae4d96c7c1b33965fabd822ee9a7201847597 Mon Sep 17 00:00:00 2001 From: Emilio Cobos Álvarez Date: Tue, 13 Mar 2018 12:22:11 +0100 Subject: tests: Test repr(align()) only on nightly for now, make it 1.25 to reflect reality. --- src/features.rs | 7 ++++--- tests/expectations/tests/repr-align.rs | 1 + tests/headers/repr-align.hpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/features.rs b/src/features.rs index 1b490f54..866d7126 100644 --- a/src/features.rs +++ b/src/features.rs @@ -92,8 +92,8 @@ macro_rules! rust_target_base { => Stable_1_19 => 1.19; /// Rust stable 1.21 => Stable_1_21 => 1.21; - /// Rust stable 1.24 - => Stable_1_24 => 1.24; + /// Rust stable 1.25 + => Stable_1_25 => 1.25; /// Nightly rust => Nightly => nightly; ); @@ -156,7 +156,7 @@ impl From for RustFeatures { features.builtin_clone_impls = true; } - if rust_target >= RustTarget::Stable_1_24 { + if rust_target >= RustTarget::Stable_1_25 { features.repr_align = true; } @@ -191,6 +191,7 @@ mod test { test_target("1.0", RustTarget::Stable_1_0); test_target("1.19", RustTarget::Stable_1_19); test_target("1.21", RustTarget::Stable_1_21); + test_target("1.25", RustTarget::Stable_1_25); test_target("nightly", RustTarget::Nightly); } } diff --git a/tests/expectations/tests/repr-align.rs b/tests/expectations/tests/repr-align.rs index 9689dacd..1827ca9d 100644 --- a/tests/expectations/tests/repr-align.rs +++ b/tests/expectations/tests/repr-align.rs @@ -1,6 +1,7 @@ /* automatically generated by rust-bindgen */ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#![cfg(feature = "nightly")] #[repr(C)] #[repr(align(8))] diff --git a/tests/headers/repr-align.hpp b/tests/headers/repr-align.hpp index 5e1b60ab..3347594b 100644 --- a/tests/headers/repr-align.hpp +++ b/tests/headers/repr-align.hpp @@ -1,4 +1,4 @@ -// bindgen-flags: --rust-target 1.24 -- -std=c++11 +// bindgen-flags: --raw-line '#![cfg(feature = "nightly")]' --rust-target 1.25 -- -std=c++11 struct alignas(8) a { int b; -- cgit v1.2.3