blob: cd88c745b7161188f013b74380e2e54c33d30108 [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CRUBIT_RS_BINDINGS_FROM_CC_TEST_STRUCT_NO_UNIQUE_ADDRESS_NO_UNIQUE_ADDRESS_H_
#define CRUBIT_RS_BINDINGS_FROM_CC_TEST_STRUCT_NO_UNIQUE_ADDRESS_NO_UNIQUE_ADDRESS_H_
#pragma clang lifetime_elision
// The no_unique_address.h header is present both in
// rs_bindings_from_cc/test/struct/no_unique_address/ and in
// rs_bindings_from_cc/test/golden/ because the format provides end-to-end
// coverage for working accessor functions, while the latter helps manually
// inspect and verify the expected layout of the generated Rust struct.
struct Struct final {
static Struct Make(int f1, char f2) { return Struct{f1, f2}; }
// Nobody would ever use a no_unique_address int/char field, this is just
// enough to test that the transmute is correct.
[[no_unique_address]] int field1 = 1;
[[no_unique_address]] char field2 = 2;
};
// Regression test for b/232418721. This tests that the offset of `field2` is
// correct (given its alignment requirements there need to be 3 bytes of padding
// between `field1` and `field2`). The verification is mostly done through
// compile-time assertions of field offsets in the generated Rust code. Before
// cl/448287893 `field2` would be incorrectly placed at offset 1.
struct PaddingBetweenFields final {
static PaddingBetweenFields Make(char f1, int f2) {
return PaddingBetweenFields{f1, f2};
}
char field1 = 1; // size: 1, alignment: 1 => offset: 0
[[no_unique_address]] int field2 = 2; // size: 4, alignment: 4 => offset: 4
};
// Layout properties of FieldInTailPadding_InnerStruct look as follows:
// - alignment: 4 (because of `inner_int_field`)
// - dsize (size without padding): 5
// (4 bytes for `inner_int_field`, 1 byte for `inner_char_field`)
// - size: 8 (dsize adjusted up to account for alignment)
struct FieldInTailPadding_InnerStruct {
int inner_int_field; // size: 4, alignment: 4 => offset: 0
char inner_char_field; // size: 1, alignment: 1 => offset: 4
// User-defined destructor to make this struct non-POD for the purposes of
// layout.
~FieldInTailPadding_InnerStruct() {}
};
// Regression test against b/232418721#comment7. This tests that the offset of
// `char_in_tail_padding_of_prev_field`` is correct - because of
// `no_unique_address` this field should be laid out inside the tail padding of
// `inner_struct` (i.e. offset of `char_in_tail_padding_of_prev_field`` should
// be 5 = dsize of `s` rather than 8 = size of `s`). The verification is mostly
// done through compile-time assertions of field offsets in the generated Rust
// code. The initial alignment-based fix idea for b/232418721 would incorrectly
// put `char_in_tail_padding_of_prev_field` at offset 8.
struct FieldInTailPadding {
FieldInTailPadding(int inner_int, char inner_char, char outer_char) {
inner_struct.inner_int_field = inner_int;
inner_struct.inner_char_field = inner_char;
char_in_tail_padding_of_prev_field = outer_char;
}
[[no_unique_address]] FieldInTailPadding_InnerStruct inner_struct;
char char_in_tail_padding_of_prev_field; // offset: 5 (dsize of `s`).
};
#endif // CRUBIT_RS_BINDINGS_FROM_CC_TEST_STRUCT_NO_UNIQUE_ADDRESS_NO_UNIQUE_ADDRESS_H_