Skip to content

disallow left over bits in packed unions #21286

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

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions doc/langref.html.in
Original file line number Diff line number Diff line change
Expand Up @@ -2188,8 +2188,7 @@ or
</li>
<li>{#syntax#}bool{#endsyntax#} fields use exactly 1 bit.</li>
<li>An {#link|enum#} field uses exactly the bit width of its integer tag type.</li>
<li>A {#link|packed union#} field uses exactly the bit width of the union field with
the largest bit width.</li>
<li>A {#link|packed union#} field uses exactly the bit width of its backing integer type.</li>
</ul>
<p>
This means that a {#syntax#}packed struct{#endsyntax#} can participate
Expand Down Expand Up @@ -2405,8 +2404,11 @@ or
{#header_close#}

{#header_open|packed union#}
<p>A {#syntax#}packed union{#endsyntax#} has well-defined in-memory layout and is eligible
to be in a {#link|packed struct#}.</p>
<p>
A {#syntax#}packed union{#endsyntax#} has well-defined in-memory layout and is eligible
to be in a {#link|packed struct#}. It's required to have a backing integer type and
all fields must have the same bit width as the backing integer type.
</p>
{#header_close#}

{#header_open|Anonymous Union Literals#}
Expand Down
10 changes: 5 additions & 5 deletions lib/std/macho.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2110,8 +2110,8 @@ pub const UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK: u32 = 0x00FFF000;
pub const UNWIND_ARM64_DWARF_SECTION_OFFSET: u32 = 0x00FFFFFF;

pub const CompactUnwindEncoding = packed struct(u32) {
value: packed union {
x86_64: packed union {
value: packed union(u24) {
x86_64: packed union(u24) {
frame: packed struct(u24) {
reg4: u3,
reg3: u3,
Expand All @@ -2124,7 +2124,7 @@ pub const CompactUnwindEncoding = packed struct(u32) {
frameless: packed struct(u24) {
stack_reg_permutation: u10,
stack_reg_count: u3,
stack: packed union {
stack: packed union(u11) {
direct: packed struct(u11) {
_: u3,
stack_size: u8,
Expand All @@ -2137,7 +2137,7 @@ pub const CompactUnwindEncoding = packed struct(u32) {
},
dwarf: u24,
},
arm64: packed union {
arm64: packed union(u24) {
frame: packed struct(u24) {
x_reg_pairs: packed struct(u5) {
x19_x20: u1,
Expand All @@ -2161,7 +2161,7 @@ pub const CompactUnwindEncoding = packed struct(u32) {
dwarf: u24,
},
},
mode: packed union {
mode: packed union(u4) {
x86_64: UNWIND_X86_64_MODE,
arm64: UNWIND_ARM64_MODE,
},
Expand Down
41 changes: 23 additions & 18 deletions lib/std/meta.zig
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ test containerLayout {
const U1 = union {
a: u8,
};
const U2 = packed union {
const U2 = packed union(u8) {
a: u8,
};
const U3 = extern union {
Expand Down Expand Up @@ -1190,29 +1190,29 @@ test hasMethod {
pub inline fn hasUniqueRepresentation(comptime T: type) bool {
return switch (@typeInfo(T)) {
else => false, // TODO can we know if it's true for some of these types ?

.@"anyframe",
.@"enum",
.error_set,
.@"fn",
=> true,

.bool => false,

.int => |info| @sizeOf(T) * 8 == info.bits,

.pointer => |info| info.size != .Slice,

.optional => |info| switch (@typeInfo(info.child)) {
.pointer => |ptr| !ptr.is_allowzero and switch (ptr.size) {
.Slice, .C => false,
.One, .Many => true,
},
else => false,
},

.@"union" => |info| {
if (info.layout == .@"packed") {
const tag_type = info.tag_type.?; // packed unions require a integer tag type
return @sizeOf(tag_type) * 8 == @bitSizeOf(tag_type);
}
return false;
},
.array => |info| hasUniqueRepresentation(info.child),

.@"struct" => |info| {
if (info.layout == .@"packed") return @sizeOf(T) * 8 == @bitSizeOf(T);

Expand All @@ -1225,7 +1225,6 @@ pub inline fn hasUniqueRepresentation(comptime T: type) bool {

return @sizeOf(T) == sum_size;
},

.vector => |info| hasUniqueRepresentation(info.child) and
@sizeOf(T) == @sizeOf(info.child) * info.len,
};
Expand Down Expand Up @@ -1274,34 +1273,40 @@ test hasUniqueRepresentation {

try testing.expect(hasUniqueRepresentation(TestStruct6));

const TestUnion1 = packed union {
const TestUnion1 = packed union(u32) {
a: u32,
b: u16,
b: i32,
};

try testing.expect(!hasUniqueRepresentation(TestUnion1));
try testing.expect(hasUniqueRepresentation(TestUnion1));

const TestUnion2 = extern union {
a: u32,
b: u16,
const TestUnion2 = packed union(u20) {
a: u20,
b: i20,
};

try testing.expect(!hasUniqueRepresentation(TestUnion2));

const TestUnion3 = union {
const TestUnion3 = extern union {
a: u32,
b: u16,
};

try testing.expect(!hasUniqueRepresentation(TestUnion3));

const TestUnion4 = union(enum) {
const TestUnion4 = union {
a: u32,
b: u16,
};

try testing.expect(!hasUniqueRepresentation(TestUnion4));

const TestUnion5 = union(enum) {
a: u32,
b: u16,
};

try testing.expect(!hasUniqueRepresentation(TestUnion5));

inline for ([_]type{ i0, u8, i16, u32, i64 }) |T| {
try testing.expect(hasUniqueRepresentation(T));
}
Expand Down
Loading
Loading