layout tests fail for max_align_t on debian sid.i386
While working on updating the rust-bindgen package in debian sid, I ran into a bindgen layout error with leptonica-sys. After some experimentation this failure seems to be caused by building bindings for stddef.h.
As a reduced testcase the following commands
echo '#include <stddef.h>' > wrapper.h
bindgen wrapper.h
resulted in
/* automatically generated by rust-bindgen 0.70.1 */
pub type wchar_t = ::std::os::raw::c_int;
#[repr(C)]
#[repr(align(8))]
#[derive(Debug, Copy, Clone)]
pub struct max_align_t {
pub __clang_max_align_nonce1: ::std::os::raw::c_longlong,
pub __clang_max_align_nonce2: f64,
}
#[allow(clippy::unnecessary_operation, clippy::identity_op)]
const _: () = {
["Size of max_align_t"][::std::mem::size_of::<max_align_t>() - 24usize];
["Alignment of max_align_t"][::std::mem::align_of::<max_align_t>() - 8usize];
["Offset of field: max_align_t::__clang_max_align_nonce1"]
[::std::mem::offset_of!(max_align_t, __clang_max_align_nonce1) - 0usize];
["Offset of field: max_align_t::__clang_max_align_nonce2"]
[::std::mem::offset_of!(max_align_t, __clang_max_align_nonce2) - 8usize];
};
I wrote a small c test program to see what size the c compilers thought max_align_t should have, worryingly gcc and clang gave different results with gcc giving a result of 48 and clang a result of only 24.
max_align_t does not seem to be defined in any system headers, so I presume there is some built-in magic going on in gcc and clang.
max_align_t comes from /usr/lib/clang/18/include/__stddef_max_align_t.h on my system:
/*===---- __stddef_max_align_t.h - Definition of max_align_t ---------------===
*
* Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
* See https://llvm.org/LICENSE.txt for license information.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*
*===-----------------------------------------------------------------------===
*/
#ifndef __CLANG_MAX_ALIGN_T_DEFINED
#define __CLANG_MAX_ALIGN_T_DEFINED
#if defined(_MSC_VER)
typedef double max_align_t;
#elif defined(__APPLE__)
typedef long double max_align_t;
#else
// Define 'max_align_t' to match the GCC definition.
typedef struct {
long long __clang_max_align_nonce1
__attribute__((__aligned__(__alignof__(long long))));
long double __clang_max_align_nonce2
__attribute__((__aligned__(__alignof__(long double))));
} max_align_t;
#endif
#endif
so it seems clang is trying to match gcc's definition of it. In either case, I think part of the issue here is that long double is not being translated properly by bindgen or something. So definitely a bug in our side.
@pvdrz #2403 fixes this, but it has been waiting for review for over two years. It blocks the generation of function bindings taking or returning long double by value, as they cannot be represented in Rust, and then uses a struct __BindgenLongDouble with the correct size and alignment to represent long double. Would you be able to have a look?