Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate sensible code for long double / stuff that has more than 64-bit alignment. #550

Closed
tov opened this issue Mar 1, 2017 · 20 comments

Comments

@tov
Copy link

tov commented Mar 1, 2017

Input C/C++ Header

typedef struct {
    long double ld;
} max_align;

Bindgen Invokation

$ bindgen input.h > lib.rs

This is with both bindgen 0.22 and HEAD, on both of these:

  • Linux stewie 4.4.0-57-generic Don't force users to manually install llvm/clang #78-Ubuntu SMP Fri Dec 9 23:50:32 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
  • Darwin sublevel 16.4.0 Darwin Kernel Version 16.4.0: Thu Dec 22 22:53:21 PST 2016; root:xnu-3789.41.3~3/RELEASE_X86_64 x86_64

Actual Results

/* automatically generated by rust-bindgen */

#[repr(C)]
#[derive(Debug, Copy)]
pub struct max_align {
    pub ld: f64,
}
#[test]
fn bindgen_test_layout_max_align() {
    assert_eq!(::std::mem::size_of::<max_align>() , 16usize , concat ! (
               "Size of: " , stringify ! ( max_align ) ));
    assert_eq! (unsafe {
                & ( * ( 0 as * const max_align ) ) . ld as * const _ as usize
                } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( max_align ) , "::" ,
                stringify ! ( ld ) ));
}
impl Clone for max_align {
    fn clone(&self) -> Self { *self }
}

The generated test is that sizeof(max_align) == 16. This may be true for the original C struct, but it's not true for the generated Rust struct.

Expected Results

I’m not sure how the struct should be translated, since Rust doesn’t have f80 or whatever, but even without a sane translation, the generated test should pass, right?

Does this have something to do with #468? That shows the same code (from <stddef.h>) that led me to discover this problem. The translation that it shows includes padding that I'm not seeing.

RUST_LOG=bindgen Output

INFO:bindgen: Clang Version: clang version 3.8.0-2ubuntu4 (tags/RELEASE_380/final)
WARN:bindgen: Using clang (3, 8), expected (3, 9)
DEBUG:bindgen::ir::context: BindgenContext::add_item(Item { id: ItemId(0), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Module(Module { name: Some("root"), kind: Normal, children_ids: [] }) }, declaration: None, loc: None
DEBUG:bindgen::ir::context: builtin_or_resolved_ty: Type(max_align, kind: Record, decl: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")), canon: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), Some(Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), None
DEBUG:bindgen::ir::context: Not resolved, maybe builtin?
DEBUG:bindgen::ir::context: builtin_or_resolved_ty: Type(max_align, kind: Record, decl: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")), canon: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), Some(Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), None
DEBUG:bindgen::ir::context: Not resolved, maybe builtin?
DEBUG:bindgen::ir::ty: from_clang_ty: ItemId(1), ty: Type(max_align, kind: Record, decl: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")), canon: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), loc: Some(Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")))
DEBUG:bindgen::ir::ty: currently_parsed_types: [PartialType { decl: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")), id: ItemId(1) }]
DEBUG:bindgen::ir::comp: CompInfo::from_ty(Struct, Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")))
DEBUG:bindgen::ir::item: from_ty_or_ref_with_id: ItemId(2) Type(long double, kind: LongDouble, decl: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None), canon: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None)), Some(Cursor(ld kind: FieldDecl, loc: ffi.h:2:17, usr: Some("c:@SA@max_align@FI@ld"))), Some(ItemId(1))
DEBUG:bindgen::ir::context: builtin_or_resolved_ty: Type(long double, kind: LongDouble, decl: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None), canon: Cursor( kind: NoDeclFound, loc: builtin definitions, usr: None)), Some(Cursor(ld kind: FieldDecl, loc: ffi.h:2:17, usr: Some("c:@SA@max_align@FI@ld"))), Some(ItemId(1))
DEBUG:bindgen::ir::context: Not resolved, maybe builtin?
DEBUG:bindgen::ir::context: add_builtin_item: item = Item { id: ItemId(3), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("long double"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: Float(LongDouble), is_const: false }) }
DEBUG:bindgen::ir::item: ItemId(3) already resolved: Some(Cursor(ld kind: FieldDecl, loc: ffi.h:2:17, usr: Some("c:@SA@max_align@FI@ld")))
DEBUG:bindgen::ir::context: BindgenContext::add_item(Item { id: ItemId(1), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("max_align"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: Comp(CompInfo { kind: Struct, fields: [Field { name: Some("ld"), ty: ItemId(3), comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, bitfield: None, mutable: false, offset: Some(0) }], template_args: [], methods: [], constructors: [], base_members: [], ref_template: None, inner_types: [], inner_vars: [], has_vtable: false, has_destructor: false, has_nonempty_base: false, has_non_type_template_params: false, packed: false, found_unknown_attr: false, detect_derive_debug_cycle: Cell { value: false }, detect_derive_default_cycle: Cell { value: false }, detect_has_destructor_cycle: Cell { value: false }, is_forward_declaration: false }), is_const: false }) }, declaration: Some(Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), loc: Some(Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")))
DEBUG:bindgen::ir::context: builtin_or_resolved_ty: Type(max_align, kind: Typedef, decl: Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align")), canon: Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align"))), Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align"))), None
DEBUG:bindgen::ir::context: Not resolved, maybe builtin?
DEBUG:bindgen::ir::context: builtin_or_resolved_ty: Type(max_align, kind: Typedef, decl: Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align")), canon: Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align"))), Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align"))), None
DEBUG:bindgen::ir::context: Not resolved, maybe builtin?
DEBUG:bindgen::ir::ty: from_clang_ty: ItemId(4), ty: Type(max_align, kind: Typedef, decl: Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align")), canon: Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align"))), loc: Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align")))
DEBUG:bindgen::ir::ty: currently_parsed_types: [PartialType { decl: Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align")), id: ItemId(4) }]
DEBUG:bindgen::ir::item: from_ty_or_ref_with_id: ItemId(5) Type(struct max_align, kind: Unexposed, decl: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")), canon: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align"))), None
DEBUG:bindgen::ir::context: builtin_or_resolved_ty: Type(struct max_align, kind: Unexposed, decl: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")), canon: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align"))), None
DEBUG:bindgen::ir::context: Already resolved ty ItemId(1), CanonicalTypeDeclaration(Type(struct max_align, kind: Unexposed, decl: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")), canon: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))), Type(struct max_align, kind: Unexposed, decl: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align")), canon: Cursor( kind: StructDecl, loc: ffi.h:1:9, usr: Some("c:@SA@max_align"))) Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align")))
DEBUG:bindgen::ir::context: add_builtin_item: item = Item { id: ItemId(5), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("struct max_align"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: ResolvedTypeRef(ItemId(1)), is_const: false }) }
DEBUG:bindgen::ir::item: ItemId(5) already resolved: Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align")))
DEBUG:bindgen::ir::context: BindgenContext::add_item(Item { id: ItemId(4), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("max_align"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: Alias(ItemId(5)), is_const: false }) }, declaration: Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align"))), loc: Some(Cursor(max_align kind: TypedefDecl, loc: ffi.h:3:3, usr: Some("c:ffi.h@T@max_align")))
DEBUG:bindgen::ir::context: No replacements to process
DEBUG:bindgen::codegen: codegen: BindgenOptions { hidden_types: RegexSet { items: [], set: Some(RegexSet([])) }, opaque_types: RegexSet { items: [], set: Some(RegexSet([])) }, whitelisted_types: RegexSet { items: [], set: Some(RegexSet([])) }, whitelisted_functions: RegexSet { items: [], set: Some(RegexSet([])) }, whitelisted_vars: RegexSet { items: [], set: Some(RegexSet([])) }, bitfield_enums: RegexSet { items: [], set: Some(RegexSet([])) }, constified_enums: RegexSet { items: [], set: Some(RegexSet([])) }, builtins: false, links: [], emit_ast: false, emit_ir: false, emit_ir_graphviz: None, enable_cxx_namespaces: false, disable_name_namespacing: false, derive_debug: true, derive_default: false, unstable_rust: true, use_core: false, ctypes_prefix: None, namespaced_constants: true, msvc_mangling: false, convert_floats: true, raw_lines: [], clang_args: ["-isystem", "/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0", "-isystem", "/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/x86_64-linux-gnu/c++/5.4.0", "-isystem", "/usr/bin/../lib/gcc/x86_64-linux-gnu/5.4.0/../../../../include/c++/5.4.0/backward", "-isystem", "/usr/local/include", "-isystem", "/usr/lib/llvm-3.8/bin/../lib/clang/3.8.0/include", "-isystem", "/usr/include/x86_64-linux-gnu", "-isystem", "/usr/include", "ffi.h"], input_header: Some("ffi.h"), dummy_uses: None, type_chooser: None, codegen_config: CodegenConfig { functions: true, types: true, vars: true, methods: true, constructors: true }, conservative_inline_namespaces: false, generate_comments: true, whitelist_recursively: true, objc_extern_crate: false, enable_mangling: true, prepend_enum_name: true }
DEBUG:bindgen::codegen: <Item as CodeGenerator>::codegen: self = Item { id: ItemId(0), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Module(Module { name: Some("root"), kind: Normal, children_ids: [ItemId(1), ItemId(4)] }) }
DEBUG:bindgen::codegen: <Module as CodeGenerator>::codegen: item = Item { id: ItemId(0), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Module(Module { name: Some("root"), kind: Normal, children_ids: [ItemId(1), ItemId(4)] }) }
DEBUG:bindgen::codegen: <Item as CodeGenerator>::codegen: self = Item { id: ItemId(1), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("max_align"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: Comp(CompInfo { kind: Struct, fields: [Field { name: Some("ld"), ty: ItemId(3), comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, bitfield: None, mutable: false, offset: Some(0) }], template_args: [], methods: [], constructors: [], base_members: [], ref_template: None, inner_types: [], inner_vars: [], has_vtable: false, has_destructor: false, has_nonempty_base: false, has_non_type_template_params: false, packed: false, found_unknown_attr: false, detect_derive_debug_cycle: Cell { value: false }, detect_derive_default_cycle: Cell { value: false }, detect_has_destructor_cycle: Cell { value: false }, is_forward_declaration: false }), is_const: false }) }
DEBUG:bindgen::codegen: <Type as CodeGenerator>::codegen: item = Item { id: ItemId(1), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("max_align"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: Comp(CompInfo { kind: Struct, fields: [Field { name: Some("ld"), ty: ItemId(3), comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, bitfield: None, mutable: false, offset: Some(0) }], template_args: [], methods: [], constructors: [], base_members: [], ref_template: None, inner_types: [], inner_vars: [], has_vtable: false, has_destructor: false, has_nonempty_base: false, has_non_type_template_params: false, packed: false, found_unknown_attr: false, detect_derive_debug_cycle: Cell { value: false }, detect_derive_default_cycle: Cell { value: false }, detect_has_destructor_cycle: Cell { value: false }, is_forward_declaration: false }), is_const: false }) }
DEBUG:bindgen::codegen: <CompInfo as CodeGenerator>::codegen: item = Item { id: ItemId(1), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("max_align"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: Comp(CompInfo { kind: Struct, fields: [Field { name: Some("ld"), ty: ItemId(3), comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, bitfield: None, mutable: false, offset: Some(0) }], template_args: [], methods: [], constructors: [], base_members: [], ref_template: None, inner_types: [], inner_vars: [], has_vtable: false, has_destructor: false, has_nonempty_base: false, has_non_type_template_params: false, packed: false, found_unknown_attr: false, detect_derive_debug_cycle: Cell { value: false }, detect_derive_default_cycle: Cell { value: false }, detect_has_destructor_cycle: Cell { value: false }, is_forward_declaration: false }), is_const: false }) }
DEBUG:bindgen::codegen::struct_layout: Offset: <padding>: 0 -> 0
DEBUG:bindgen::codegen::struct_layout: align field ld to 0/0 with 0 padding bytes Layout { size: 16, align: 16, packed: false }
DEBUG:bindgen::codegen::struct_layout: Offset: ld: 0 -> 16
DEBUG:bindgen::codegen: <Item as CodeGenerator>::codegen: self = Item { id: ItemId(4), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("max_align"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: Alias(ItemId(5)), is_const: false }) }
DEBUG:bindgen::codegen: <Type as CodeGenerator>::codegen: item = Item { id: ItemId(4), local_id: Cell { value: None }, next_child_local_id: Cell { value: 1 }, canonical_name_cache: RefCell { value: None }, comment: None, annotations: Annotations { opaque: false, hide: false, use_instead_of: None, disallow_copy: false, private_fields: None, accessor_kind: None, constify_enum_variant: false }, parent_id: ItemId(0), kind: Type(Type { name: Some("max_align"), layout: Some(Layout { size: 16, align: 16, packed: false }), kind: Alias(ItemId(5)), is_const: false }) }
@tov tov changed the title Fails its own generated test for struct containing long double Fails its own generated test for struct containing long double Mar 1, 2017
@emilio
Copy link
Contributor

emilio commented Mar 1, 2017

Yeah, this is known. We don't have any way of generating larger floats in rust though, so I don't know what could we do here :(. The test seems to be doing its job.

Does this have something to do with #468? That shows the same code (from <stddef.h>) that led me to discover this problem. The translation that it shows includes padding that I'm not seeing.

The padding in #468 was there, though incorrectly (and the code that generated the padding caused a few other bugs). I cleaned that up in #512.

We could generate [u64; 2] or something similar for long double if we detect it's more than 64-bit, if that works for you.

@tov
Copy link
Author

tov commented Mar 1, 2017

I suppose the test is doing its job, yes :) But because Clang’s <stddef.h> has a struct with a long double, it makes any header that includes <stddef.h> fail the generated tests.

I think that [u64; 2] would be a more appropriate translation of long double, or even better, [u8; sizeof(long double)]. Though for my purposes, being able to suppress the tests is just as good.

@emilio
Copy link
Contributor

emilio commented Mar 1, 2017

Note that you should be able to just do --blacklist-type max_align_t (or the equivalent with the builder API) to do that.

@tov
Copy link
Author

tov commented Mar 1, 2017

Oh, that should work. Thanks!

@Rufflewind
Copy link

To clarify, @emilio is referring to bindgen::Builder::hide_type.

Rufflewind added a commit to Rufflewind/rsmpi that referenced this issue Mar 28, 2017
Rufflewind added a commit to Rufflewind/rsmpi that referenced this issue Mar 29, 2017
Rufflewind added a commit to Rufflewind/rsmpi that referenced this issue Mar 29, 2017
@emilio emilio changed the title Fails its own generated test for struct containing long double Generate sensible code for long double / stuff that has more than 64-bit alignment. Apr 22, 2017
bsteinb pushed a commit to rsmpi/rsmpi that referenced this issue May 20, 2017
drahnr added a commit to fff-rs/rust-cublas that referenced this issue Jun 19, 2017
drahnr added a commit to fff-rs/rust-cudnn that referenced this issue Jun 19, 2017
@lukaslueg
Copy link

This currently prevents anything that does include <stddef.h> from building.

@fitzgen
Copy link
Member

fitzgen commented Jul 13, 2017

@lukaslueg see the workarounds above: #550 (comment) and #550 (comment)

Rust has no way to set these alignments, so our hands are tied for the moment.

Aaron1011 added a commit to Aaron1011/fast-zsh that referenced this issue Jul 27, 2017
Until rust-lang/rust-bindgen#550 is
resolved, this is necessary for the generated tests to pass.
oconnor663 added a commit to oconnor663/blake2_c.rs that referenced this issue Nov 5, 2017
As part of doing this, we blacklist the max_align_t type. This was
causing a generated test failure. See:
rust-lang/rust-bindgen#550
dylanmckay added a commit to dylanmckay/simavr-sys that referenced this issue Nov 16, 2017
bors-servo pushed a commit that referenced this issue Dec 9, 2017
Enable Cargo features for quickchecking crate

Logic to enable/disable special casing (due to known issues #550, #684, and #1153) has been exposed as features in the `quickchecking` crate's Cargo.toml file and corresponding `cfg` attributes in the source.

In addition to adding Cargo features, this PR represents the following:
- Documentation in `bindgen`'s CONTRIBUTING.md that points to a new README.md located in the `quickchecking` crate's directory.
- The Debug trait was implemented for the `HeaderC` type. This enables failing property tests to be reported as C source code rather than a Rust data structure.
- The ArrayDimensionC type is now used in header generation for union, struct, and basic declarations.

Thanks for taking a look and for any feedback!

Closes #1169

r? @fitzgen
slyphon added a commit to slyphon/pelikan that referenced this issue Jun 29, 2018
slyphon added a commit to slyphon/pelikan that referenced this issue Jun 30, 2018
saulius added a commit to RoaringBitmap/croaring-rs that referenced this issue Jul 2, 2018
@gnzlbg
Copy link
Contributor

gnzlbg commented Aug 13, 2018

#[repr(align(...))] has been available in nightly for a while

gibix added a commit to gibix/aom-rs that referenced this issue Aug 23, 2018
A simple workaround for
rust-lang/rust-bindgen#550
that turned on a test error.
lu-zero pushed a commit to rust-av/aom-rs that referenced this issue Aug 23, 2018
* Update to the current bindgen
* workaround broken max_align_t codegen
    See rust-lang/rust-bindgen#550
gibix added a commit to gibix/aom-rs that referenced this issue Aug 24, 2018
A simple workaround for
rust-lang/rust-bindgen#550 that turned on
a test error.
norru added a commit to itadinanta/ofx-rs that referenced this issue Oct 18, 2018
@norru
Copy link

norru commented Oct 18, 2018

Just got this error myself, here's a case for you:

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct max_align_t {
    pub __clang_max_align_nonce1: ::std::os::raw::c_longlong,
    pub __bindgen_padding_0: u64,
    pub __clang_max_align_nonce2: f64,
}
#[test]
fn bindgen_test_layout_max_align_t() {
    assert_eq!(
        ::std::mem::size_of::<max_align_t>(),
        32usize,
        concat!("Size of: ", stringify!(max_align_t))
    );
    assert_eq!(
        unsafe {
            &(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce1 as *const _ as usize
        },
        0usize,
        concat!(
            "Offset of field: ",
            stringify!(max_align_t),
            "::",
            stringify!(__clang_max_align_nonce1)
        )
    );
    assert_eq!(
        unsafe {
            &(*(::std::ptr::null::<max_align_t>())).__clang_max_align_nonce2 as *const _ as usize
        },
        16usize,
        concat!(
            "Offset of field: ",
            stringify!(max_align_t),
            "::",
            stringify!(__clang_max_align_nonce2)
        )
    );
}
test bindgen_test_layout_max_align_t ... FAILED

failures:

---- bindgen_test_layout_max_align_t stdout ----
thread 'bindgen_test_layout_max_align_t' panicked at 'assertion failed: `(left == right)`
  left: `24`,
 right: `32`: Size of: max_align_t', /home/nico/Projects/itadinanta/ofx-rs/target/debug/build/ofx_sys-0b6feeb523d786fb/out/bindings.rs:1181:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at libstd/sys/unix/backtrace/tracing/gcc_s.rs:49
   1: std::sys_common::backtrace::print
             at libstd/sys_common/backtrace.rs:71
             at libstd/sys_common/backtrace.rs:59
   2: std::panicking::default_hook::{{closure}}
             at libstd/panicking.rs:211
   3: std::panicking::default_hook
             at libstd/panicking.rs:221
   4: std::panicking::rust_panic_with_hook
             at libstd/panicking.rs:476
   5: std::panicking::continue_panic_fmt
             at libstd/panicking.rs:390
   6: std::panicking::begin_panic_fmt
             at libstd/panicking.rs:345
   7: ofx_sys::bindgen_test_layout_max_align_t
             at /home/nico/Projects/itadinanta/ofx-rs/target/debug/build/ofx_sys-0b6feeb523d786fb/out/bindings.rs:1181
   8: ofx_sys::bindgen_test_layout_max_align_t::{{closure}}
             at /home/nico/Projects/itadinanta/ofx-rs/target/debug/build/ofx_sys-0b6feeb523d786fb/out/bindings.rs:1180
   9: core::ops::function::FnOnce::call_once
             at libcore/ops/function.rs:238
  10: <F as alloc::boxed::FnBox<A>>::call_box
             at libtest/lib.rs:1468
             at libcore/ops/function.rs:238
             at liballoc/boxed.rs:672
  11: __rust_maybe_catch_panic
             at libpanic_unwind/lib.rs:102


failures:
    bindgen_test_layout_max_align_t

test result: FAILED. 40 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out

I've temporarily resolved blacklisting max_align_t as suggested.

@emilio
Copy link
Contributor

emilio commented Oct 18, 2018

This was properly fixed recently with .rust_target(<a version that supports repr(align)>), like 1.26.

See #1391 / #1394 / etc.

@emilio emilio closed this as completed Oct 18, 2018
@fintelia
Copy link

fintelia commented Oct 18, 2018

@emilio This issue still isn't fixed as of bindgen 0.42.2. Those patches only deal with 128 bit ints, but not 80 bit floats. In fact, output is completely unchanged from the original post. Specifically, the struct:

typedef struct {
    long double ld;
} max_align;

Is converted to:

#[repr(C)]
#[derive(Debug, Copy)]
pub struct max_align {
    pub ld: f64,
}

When it instead should be something like:

#[repr(C, align(16))]
#[derive(Debug, Copy)]
pub struct f80([u8; 10]);

#[repr(C)]
#[derive(Debug, Copy)]
pub struct max_align {
    pub ld: f80,
}

@emilio
Copy link
Contributor

emilio commented Oct 18, 2018

In master:

$ cat > t.h                                                                                                                                                                                
typedef struct {
    long double ld;
} max_align;
$ ./target/debug/bindgen --no-layout-tests t.h
/* automatically generated by rust-bindgen */

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct max_align {
    pub ld: f64,
}
$ ./target/debug/bindgen --no-layout-tests --rust-target 1.26 t.h
/* automatically generated by rust-bindgen */

#[repr(C)]
#[repr(align(16))]
#[derive(Debug, Copy, Clone)]
pub struct max_align {
    pub ld: u128,
}

(--no-layout-tests has been added just to avoid clobbering the output, but in master the layout tests should in fact pass).

Note the --rust-target 1.26. That's needed to tell bindgen that it can use repr(align) and u128.

@emilio
Copy link
Contributor

emilio commented Oct 19, 2018

(If for some reason that output can be improved or what not, let's continue that discussion in another issue)

@gnzlbg
Copy link
Contributor

gnzlbg commented Oct 19, 2018

@emilio maybe rust-bindgen should start warning / erroring on long double if --rust-target 1.26 is not used, the repr(C) struct using f64 will introduce undefined behavior when used in C FFI. Users should either not generate bindings for long double types for older rust targets (e.g. by ignoring them), or use a newer rust target.

@emilio
Copy link
Contributor

emilio commented Oct 20, 2018

Yeah, I agree. FWIW tests should fail when that happens, so this already kind-of happens.

But should be trivial to add a warning to the place where we generate the long double, want to submit a patch?

@elichai
Copy link
Contributor

elichai commented Sep 14, 2019

Same problem with bindgen --rust-target "1.21"
Maybe not generating max_align_t when it's not possible is the better way?

@emilio
Copy link
Contributor

emilio commented Sep 15, 2019

Maybe not generating max_align_t when it's not possible is the better way?

Seems very special-casey (if it's just about max_align_t and not long-double in general), and this relies on max_align_t not actually being used for anything else.

Given it produces test failures and that default rust target is newer now iirc, I don't personally think it's worth it, but patch welcome of course :)

drahnr added a commit to fff-rs/juice that referenced this issue Feb 1, 2020
drahnr added a commit to fff-rs/juice that referenced this issue Feb 1, 2020
drahnr added a commit to fff-rs/juice that referenced this issue Feb 1, 2020
drahnr added a commit to fff-rs/juice that referenced this issue Feb 1, 2020
sthiele added a commit to potassco/clingo-sys that referenced this issue Jun 6, 2020
lotem added a commit to lotem/librime-sys that referenced this issue Apr 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants