authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-05 18:45:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-09-05 18:45:24-07:00
log52c6d7a9290d7d6017208e23c6fbac1b8cfeecb8
tree0914aa95d3292107b1b1795184b7a18847744b68
parent1d764c1fdf04829cec5974d82cec901825a80e49

Sema: forbid packed unions with mismatched field bit sizes


1 files changed, 55 insertions(+), 21 deletions(-)

src/Sema.zig+55-21
...@@ -35614,6 +35614,12 @@ fn unionFields(...@@ -35614,6 +35614,12 @@ fn unionFields(
35614 if (small.any_aligned_fields)35614 if (small.any_aligned_fields)
35615 try field_aligns.ensureTotalCapacityPrecise(sema.arena, fields_len);35615 try field_aligns.ensureTotalCapacityPrecise(sema.arena, fields_len);
3561635616
35617 var max_bits: u64 = 0;
35618 var min_bits: u64 = std.math.maxInt(u64);
35619 var max_bits_src: LazySrcLoc = undefined;
35620 var min_bits_src: LazySrcLoc = undefined;
35621 var max_bits_ty: Type = undefined;
35622 var min_bits_ty: Type = undefined;
35617 const bits_per_field = 4;35623 const bits_per_field = 4;
35618 const fields_per_u32 = 32 / bits_per_field;35624 const fields_per_u32 = 32 / bits_per_field;
35619 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;35625 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
...@@ -35622,6 +35628,7 @@ fn unionFields(...@@ -35622,6 +35628,7 @@ fn unionFields(
35622 var cur_bit_bag: u32 = undefined;35628 var cur_bit_bag: u32 = undefined;
35623 var field_i: u32 = 0;35629 var field_i: u32 = 0;
35624 var last_tag_val: ?Value = null;35630 var last_tag_val: ?Value = null;
35631 const layout = union_type.flagsUnordered(ip).layout;
35625 while (field_i < fields_len) : (field_i += 1) {35632 while (field_i < fields_len) : (field_i += 1) {
35626 if (field_i % fields_per_u32 == 0) {35633 if (field_i % fields_per_u32 == 0) {
35627 cur_bit_bag = zir.extra[bit_bag_index];35634 cur_bit_bag = zir.extra[bit_bag_index];
...@@ -35773,31 +35780,45 @@ fn unionFields(...@@ -35773,31 +35780,45 @@ fn unionFields(
35773 };35780 };
35774 return sema.failWithOwnedErrorMsg(&block_scope, msg);35781 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35775 }35782 }
35776 const layout = union_type.flagsUnordered(ip).layout;35783 switch (layout) {
35777 if (layout == .@"extern" and35784 .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) {
35778 !try sema.validateExternType(field_ty, .union_field))35785 const msg = msg: {
35779 {35786 const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
35780 const msg = msg: {35787 errdefer msg.destroy(sema.gpa);
35781 const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
35782 errdefer msg.destroy(sema.gpa);
3578335788
35784 try sema.explainWhyTypeIsNotExtern(msg, type_src, field_ty, .union_field);35789 try sema.explainWhyTypeIsNotExtern(msg, type_src, field_ty, .union_field);
3578535790
35786 try sema.addDeclaredHereNote(msg, field_ty);35791 try sema.addDeclaredHereNote(msg, field_ty);
35787 break :msg msg;35792 break :msg msg;
35788 };35793 };
35789 return sema.failWithOwnedErrorMsg(&block_scope, msg);35794 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35790 } else if (layout == .@"packed" and !try sema.validatePackedType(field_ty)) {35795 },
35791 const msg = msg: {35796 .@"packed" => {
35792 const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});35797 if (!try sema.validatePackedType(field_ty)) {
35793 errdefer msg.destroy(sema.gpa);35798 const msg = msg: {
35799 const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
35800 errdefer msg.destroy(sema.gpa);
3579435801
35795 try sema.explainWhyTypeIsNotPacked(msg, type_src, field_ty);35802 try sema.explainWhyTypeIsNotPacked(msg, type_src, field_ty);
3579635803
35797 try sema.addDeclaredHereNote(msg, field_ty);35804 try sema.addDeclaredHereNote(msg, field_ty);
35798 break :msg msg;35805 break :msg msg;
35799 };35806 };
35800 return sema.failWithOwnedErrorMsg(&block_scope, msg);35807 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35808 }
35809 const field_bits = try field_ty.bitSizeSema(pt);
35810 if (field_bits >= max_bits) {
35811 max_bits = field_bits;
35812 max_bits_src = type_src;
35813 max_bits_ty = field_ty;
35814 }
35815 if (field_bits <= min_bits) {
35816 min_bits = field_bits;
35817 min_bits_src = type_src;
35818 min_bits_ty = field_ty;
35819 }
35820 },
35821 .auto => {},
35801 }35822 }
3580235823
35803 field_types.appendAssumeCapacity(field_ty.toIntern());35824 field_types.appendAssumeCapacity(field_ty.toIntern());
...@@ -35815,6 +35836,19 @@ fn unionFields(...@@ -35815,6 +35836,19 @@ fn unionFields(
35815 union_type.setFieldTypes(ip, field_types.items);35836 union_type.setFieldTypes(ip, field_types.items);
35816 union_type.setFieldAligns(ip, field_aligns.items);35837 union_type.setFieldAligns(ip, field_aligns.items);
3581735838
35839 if (layout == .@"packed" and fields_len != 0 and min_bits != max_bits) {
35840 const msg = msg: {
35841 const msg = try sema.errMsg(src, "packed union has fields with mismatching bit sizes", .{});
35842 errdefer msg.destroy(sema.gpa);
35843 try sema.errNote(min_bits_src, msg, "{d} bits here", .{min_bits});
35844 try sema.addDeclaredHereNote(msg, min_bits_ty);
35845 try sema.errNote(max_bits_src, msg, "{d} bits here", .{max_bits});
35846 try sema.addDeclaredHereNote(msg, max_bits_ty);
35847 break :msg msg;
35848 };
35849 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35850 }
35851
35818 if (explicit_tags_seen.len > 0) {35852 if (explicit_tags_seen.len > 0) {
35819 const tag_ty = union_type.tagTypeUnordered(ip);35853 const tag_ty = union_type.tagTypeUnordered(ip);
35820 const tag_info = ip.loadEnumType(tag_ty);35854 const tag_info = ip.loadEnumType(tag_ty);