#[repr(align(4))] struct has 8 byte alignment

8314c1e
Opened by gnzlbg at 2025-03-25 19:38:51

See it live:

#![allow(non_camel_case_types)]
pub enum c_void {}

type uintptr_t = usize;
type int16_t = u16;
type uint16_t = int16_t;
type uint32_t = u32;
type intptr_t = uintptr_t;

#[repr(C)]
#[repr(align(4))]
pub struct kevent {
    pub ident: uintptr_t,
    pub filter: int16_t,
    pub flags: uint16_t,
    pub fflags: uint32_t,
    pub data: intptr_t,
    pub udata: *mut c_void,
}

fn main() {
    assert_eq!(::std::mem::align_of::<kevent>(), 4); // ERROR: 8 != 4
}

No warning, no error, nu nothing.

This is https://github.com/rust-lang/libc/issues/914

  1. cc #33626

    If we follow the text of the original RFC 1358, this is intended:

    // Lowering has no effect
    #[repr(align = "1")]
    struct Align1(i32);
    

    so the problem is missing diagnostic. Not sure if portability lint is needed due to the pointer-sized things.

    kennytm at 2018-02-12 12:24:34

  2. Might be that what we need here is just repr(packed): https://github.com/rust-lang/rust/issues/33158

    gnzlbg at 2018-02-12 13:01:47

  3. It would be nice to have a lint to warn you you when #[repr(align(N))] has no effect due to the struct's natural alignment already being that high.

    Peter Atashian at 2018-02-12 17:00:56

  4. How would that lint work portably? What say you wanted 8 byte alignment on all targets with

    #[repr(align = "8")]
    struct Align8(usize);
    

    the lint would fire on 64-bit targets.

    James Duley at 2018-02-14 23:08:46

  5. In that case you can just #[allow(whatever_the_lint_name_is_idk)]

    Peter Atashian at 2018-02-15 03:00:17

  6. Or use #[cfg_attr(not(target_pointer_width="8"), repr(align(8)))]

    Hanna Kruppe at 2018-02-15 08:10:09

  7. Btw, why doesn't #[repr(align(16))] work on struct members? It's inconvenient to have to wrap a member in another type just to specify the alignment.

    Boscop at 2020-06-13 03:28:01

  8. Probably because you can't do that in C. At least for __declspec(align) it cannot be applied to individual fields.

    Peter Atashian at 2020-06-13 03:55:51

  9. @retep998 Just because it's not possible in C doesn't mean it can't be possible in LLVM / Rust. Even if it's only possible on a struct, rustc could auto-generate a wrapper struct for the codegen and auto-wrap the member in it, if it has that attribute.

    Boscop at 2020-06-13 23:17:13

  10. @Boscop I'm not saying we shouldn't have that feature, I'm just explaining why we don't have that yet. Feel free to open an issue or PR about that extension of #[repr(align)]. This issue isn't really the place for it.

    Peter Atashian at 2020-06-14 00:50:05

  11. Prior art: In C++, an alignas specifier lower than the natural alignment is a hard error. (Reference: this page; search for "ill-formed".)

    comex at 2020-07-13 02:04:06

  12. It would be nice to have a lint to warn you when #[repr(align(N))] has no effect due to the struct's natural alignment already being that high.

    I don't think there needs to be a warning when the natural alignment is N. But there should be a warning, at a minimum, when the natural alignment is larger than N. Especially when repr(C, align(N)) is used, it is likely something is assuming the alignment is never more than N.

    Brian Smith at 2025-03-25 19:38:51