authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 16:02:42-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-09 16:02:42-07:00
log3b6e8fa59e6fb933e8279ba676ef986739665247
tree5308495e3c5600b17af1bf96fdb68d23ecd4e4a2
parentfd85cfe15457bd695b978e327ce8af84c7990c28

Sema: fix crash with `@sizeOf` on unions


5 files changed, 35 insertions(+), 17 deletions(-)

src/Module.zig+1-1
......@@ -1281,7 +1281,7 @@ pub const Union = struct {
12811281 var payload_align: u32 = 0;
12821282 const fields = u.fields.values();
12831283 for (fields) |field, i| {
1284 if (!field.ty.hasRuntimeBits()) continue;
1284 if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue;
12851285
12861286 const field_align = a: {
12871287 if (field.abi_align.tag() == .abi_align_default) {
src/Sema.zig+1
......@@ -9955,6 +9955,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
99559955 .BoundFn,
99569956 .Opaque,
99579957 => return sema.fail(block, src, "no size available for type '{}'", .{operand_ty}),
9958
99589959 .Type,
99599960 .EnumLiteral,
99609961 .ComptimeFloat,
src/type.zig+23-11
......@@ -1967,7 +1967,9 @@ pub const Type = extern union {
19671967 /// There are two reasons a type will return false:
19681968 /// * the type is a comptime-only type. For example, the type `type` itself.
19691969 /// * the type has only one possible value, making its ABI size 0.
1970 pub fn hasRuntimeBits(ty: Type) bool {
1970 /// When `ignore_comptime_only` is true, then types that are comptime only
1971 /// may return false positives.
1972 pub fn hasRuntimeBitsAdvanced(ty: Type, ignore_comptime_only: bool) bool {
19711973 return switch (ty.tag()) {
19721974 .u1,
19731975 .u8,
......@@ -2063,7 +2065,7 @@ pub const Type = extern union {
20632065 .const_slice,
20642066 .mut_slice,
20652067 .pointer,
2066 => !ty.comptimeOnly(),
2068 => if (ignore_comptime_only) true else !comptimeOnly(ty),
20672069
20682070 .@"struct" => {
20692071 const struct_obj = ty.castTag(.@"struct").?.data;
......@@ -2075,7 +2077,7 @@ pub const Type = extern union {
20752077 }
20762078 assert(struct_obj.haveFieldTypes());
20772079 for (struct_obj.fields.values()) |value| {
2078 if (value.ty.hasRuntimeBits())
2080 if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only))
20792081 return true;
20802082 } else {
20812083 return false;
......@@ -2093,14 +2095,14 @@ pub const Type = extern union {
20932095 .enum_numbered, .enum_nonexhaustive => {
20942096 var buffer: Payload.Bits = undefined;
20952097 const int_tag_ty = ty.intTagType(&buffer);
2096 return int_tag_ty.hasRuntimeBits();
2098 return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only);
20972099 },
20982100
20992101 .@"union" => {
21002102 const union_obj = ty.castTag(.@"union").?.data;
21012103 assert(union_obj.haveFieldTypes());
21022104 for (union_obj.fields.values()) |value| {
2103 if (value.ty.hasRuntimeBits())
2105 if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only))
21042106 return true;
21052107 } else {
21062108 return false;
......@@ -2108,27 +2110,29 @@ pub const Type = extern union {
21082110 },
21092111 .union_tagged => {
21102112 const union_obj = ty.castTag(.union_tagged).?.data;
2111 if (union_obj.tag_ty.hasRuntimeBits()) {
2113 if (union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) {
21122114 return true;
21132115 }
21142116 assert(union_obj.haveFieldTypes());
21152117 for (union_obj.fields.values()) |value| {
2116 if (value.ty.hasRuntimeBits())
2118 if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only))
21172119 return true;
21182120 } else {
21192121 return false;
21202122 }
21212123 },
21222124
2123 .array, .vector => ty.arrayLen() != 0 and ty.elemType().hasRuntimeBits(),
2125 .array, .vector => ty.arrayLen() != 0 and
2126 ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only),
21242127 .array_u8 => ty.arrayLen() != 0,
2125 .array_sentinel => ty.childType().hasRuntimeBits(),
2128 .array_sentinel => ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only),
21262129
21272130 .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data != 0,
21282131
21292132 .error_union => {
21302133 const payload = ty.castTag(.error_union).?.data;
2131 return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits();
2134 return payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only) or
2135 payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only);
21322136 },
21332137
21342138 .tuple, .anon_struct => {
......@@ -2136,7 +2140,7 @@ pub const Type = extern union {
21362140 for (tuple.types) |field_ty, i| {
21372141 const val = tuple.values[i];
21382142 if (val.tag() != .unreachable_value) continue; // comptime field
2139 if (field_ty.hasRuntimeBits()) return true;
2143 if (field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) return true;
21402144 }
21412145 return false;
21422146 },
......@@ -2148,6 +2152,14 @@ pub const Type = extern union {
21482152 };
21492153 }
21502154
2155 pub fn hasRuntimeBits(ty: Type) bool {
2156 return hasRuntimeBitsAdvanced(ty, false);
2157 }
2158
2159 pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool {
2160 return hasRuntimeBitsAdvanced(ty, true);
2161 }
2162
21512163 pub fn isFnOrHasRuntimeBits(ty: Type) bool {
21522164 switch (ty.zigTypeTag()) {
21532165 .Fn => {
test/behavior/for.zig+3-2
......@@ -178,7 +178,8 @@ fn mangleString(s: []u8) void {
178178}
179179
180180test "for copies its payload" {
181 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
181 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
182 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
182183
183184 const S = struct {
184185 fn doTheTest() !void {
......@@ -186,7 +187,7 @@ test "for copies its payload" {
186187 for (x) |value, i| {
187188 // Modify the original array
188189 x[i] += 99;
189 try expectEqual(value, i + 1);
190 try expect(value == i + 1);
190191 }
191192 }
192193 };
test/behavior/sizeof_and_typeof.zig+7-3
......@@ -233,7 +233,10 @@ test "@bitSizeOf" {
233233}
234234
235235test "@sizeOf comparison against zero" {
236 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
236 if (builtin.zig_backend == .stage1) {
237 // stage1 gets the wrong answer for size of pointers to zero bit types
238 return error.SkipZigTest;
239 }
237240
238241 const S0 = struct {
239242 f: *@This(),
......@@ -263,12 +266,13 @@ test "@sizeOf comparison against zero" {
263266 };
264267 const S = struct {
265268 fn doTheTest(comptime T: type, comptime result: bool) !void {
266 try expectEqual(result, @sizeOf(T) > 0);
269 try expect(result == (@sizeOf(T) > 0));
267270 }
268271 };
269272 // Zero-sized type
270273 try S.doTheTest(u0, false);
271 try S.doTheTest(*u0, false);
274 // Pointers to zero sized types still have addresses.
275 try S.doTheTest(*u0, true);
272276 // Non byte-sized type
273277 try S.doTheTest(u1, true);
274278 try S.doTheTest(*u1, true);