about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-09-09 08:54:29 +0000
committerbors <bors@rust-lang.org>2018-09-09 08:54:29 +0000
commitdf6ba0c4acceb5f63090bb20bd23f29c4f439376 (patch)
treed860adafcbc8edaa2d572daf3133b8690e3381d9 /src/libsyntax
parent3d2fc456a91e898f735f97f1a9ea79432da4e1a5 (diff)
parentb9e7574bf2d760fc011cc90890f3280c474746e4 (diff)
downloadrust-df6ba0c4acceb5f63090bb20bd23f29c4f439376.tar.gz
rust-df6ba0c4acceb5f63090bb20bd23f29c4f439376.zip
Auto merge of #53998 - eddyb:issue-53728, r=oli-obk
rustc_codegen_llvm: don't assume offsets are always aligned.

Fixes #53728 by taking into account not just overall type alignment and the field's alignment when determining whether a field is aligned or not ("packed"), but also the field's offset within the type.

Previously, rustc assumed that the offset was always at least as aligned as `min(struct.align, field.align)`. However, there's no real reason to have that assumption, and it obviously can't always be true after we implement `#[repr(align(N), pack(K))]`. There's also a case today where that assumption is not true, involving niche discriminants in enums:

Suppose that we have the code in #53728:
```Rust
#[repr(u16)]
enum DeviceKind {
    Nil = 0,
}

#[repr(packed)]
struct DeviceInfo {
    endianness: u8,
    device_kind: DeviceKind,
}

struct Wrapper {
    device_info: DeviceInfo,
    data: u32
}
```

Observe the layout of `Option<Wrapper>`. It has an alignment of 4 because of the `u32`. `device_info.device_kind` is a good niche field to use, which means the enum ends up with this layout:
```
size = 8
align = 4
fields = [
    { offset=1, type=u16 } // discriminant, .<Some>.device_info.device_kind
]
```

And here we have an discriminant with alignment 2 (`u16`) but offset 1.
Diffstat (limited to 'src/libsyntax')
0 files changed, 0 insertions, 0 deletions