diff --git a/src/Module.zig b/src/Module.zig index 936e912e59..93e4b87d5b 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1281,7 +1281,7 @@ pub const Union = struct { var payload_align: u32 = 0; const fields = u.fields.values(); for (fields) |field, i| { - if (!field.ty.hasRuntimeBits()) continue; + if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; const field_align = a: { if (field.abi_align.tag() == .abi_align_default) { diff --git a/src/Sema.zig b/src/Sema.zig index 29cad45f9a..7644bc1d77 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -9955,6 +9955,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. .BoundFn, .Opaque, => return sema.fail(block, src, "no size available for type '{}'", .{operand_ty}), + .Type, .EnumLiteral, .ComptimeFloat, diff --git a/src/type.zig b/src/type.zig index 7b8dd1396b..e2b9c4fe0f 100644 --- a/src/type.zig +++ b/src/type.zig @@ -1967,7 +1967,9 @@ pub const Type = extern union { /// There are two reasons a type will return false: /// * the type is a comptime-only type. For example, the type `type` itself. /// * the type has only one possible value, making its ABI size 0. - pub fn hasRuntimeBits(ty: Type) bool { + /// When `ignore_comptime_only` is true, then types that are comptime only + /// may return false positives. + pub fn hasRuntimeBitsAdvanced(ty: Type, ignore_comptime_only: bool) bool { return switch (ty.tag()) { .u1, .u8, @@ -2063,7 +2065,7 @@ pub const Type = extern union { .const_slice, .mut_slice, .pointer, - => !ty.comptimeOnly(), + => if (ignore_comptime_only) true else !comptimeOnly(ty), .@"struct" => { const struct_obj = ty.castTag(.@"struct").?.data; @@ -2075,7 +2077,7 @@ pub const Type = extern union { } assert(struct_obj.haveFieldTypes()); for (struct_obj.fields.values()) |value| { - if (value.ty.hasRuntimeBits()) + if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) return true; } else { return false; @@ -2093,14 +2095,14 @@ pub const Type = extern union { .enum_numbered, .enum_nonexhaustive => { var buffer: Payload.Bits = undefined; const int_tag_ty = ty.intTagType(&buffer); - return int_tag_ty.hasRuntimeBits(); + return int_tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only); }, .@"union" => { const union_obj = ty.castTag(.@"union").?.data; assert(union_obj.haveFieldTypes()); for (union_obj.fields.values()) |value| { - if (value.ty.hasRuntimeBits()) + if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) return true; } else { return false; @@ -2108,27 +2110,29 @@ pub const Type = extern union { }, .union_tagged => { const union_obj = ty.castTag(.union_tagged).?.data; - if (union_obj.tag_ty.hasRuntimeBits()) { + if (union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) { return true; } assert(union_obj.haveFieldTypes()); for (union_obj.fields.values()) |value| { - if (value.ty.hasRuntimeBits()) + if (value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) return true; } else { return false; } }, - .array, .vector => ty.arrayLen() != 0 and ty.elemType().hasRuntimeBits(), + .array, .vector => ty.arrayLen() != 0 and + ty.elemType().hasRuntimeBitsAdvanced(ignore_comptime_only), .array_u8 => ty.arrayLen() != 0, - .array_sentinel => ty.childType().hasRuntimeBits(), + .array_sentinel => ty.childType().hasRuntimeBitsAdvanced(ignore_comptime_only), .int_signed, .int_unsigned => ty.cast(Payload.Bits).?.data != 0, .error_union => { const payload = ty.castTag(.error_union).?.data; - return payload.error_set.hasRuntimeBits() or payload.payload.hasRuntimeBits(); + return payload.error_set.hasRuntimeBitsAdvanced(ignore_comptime_only) or + payload.payload.hasRuntimeBitsAdvanced(ignore_comptime_only); }, .tuple, .anon_struct => { @@ -2136,7 +2140,7 @@ pub const Type = extern union { for (tuple.types) |field_ty, i| { const val = tuple.values[i]; if (val.tag() != .unreachable_value) continue; // comptime field - if (field_ty.hasRuntimeBits()) return true; + if (field_ty.hasRuntimeBitsAdvanced(ignore_comptime_only)) return true; } return false; }, @@ -2148,6 +2152,14 @@ pub const Type = extern union { }; } + pub fn hasRuntimeBits(ty: Type) bool { + return hasRuntimeBitsAdvanced(ty, false); + } + + pub fn hasRuntimeBitsIgnoreComptime(ty: Type) bool { + return hasRuntimeBitsAdvanced(ty, true); + } + pub fn isFnOrHasRuntimeBits(ty: Type) bool { switch (ty.zigTypeTag()) { .Fn => { diff --git a/test/behavior/for.zig b/test/behavior/for.zig index c35d0b9b1c..44c135197a 100644 --- a/test/behavior/for.zig +++ b/test/behavior/for.zig @@ -178,7 +178,8 @@ fn mangleString(s: []u8) void { } test "for copies its payload" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO const S = struct { fn doTheTest() !void { @@ -186,7 +187,7 @@ test "for copies its payload" { for (x) |value, i| { // Modify the original array x[i] += 99; - try expectEqual(value, i + 1); + try expect(value == i + 1); } } }; diff --git a/test/behavior/sizeof_and_typeof.zig b/test/behavior/sizeof_and_typeof.zig index 57e6e2093e..75db442fc7 100644 --- a/test/behavior/sizeof_and_typeof.zig +++ b/test/behavior/sizeof_and_typeof.zig @@ -233,7 +233,10 @@ test "@bitSizeOf" { } test "@sizeOf comparison against zero" { - if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage1) { + // stage1 gets the wrong answer for size of pointers to zero bit types + return error.SkipZigTest; + } const S0 = struct { f: *@This(), @@ -263,12 +266,13 @@ test "@sizeOf comparison against zero" { }; const S = struct { fn doTheTest(comptime T: type, comptime result: bool) !void { - try expectEqual(result, @sizeOf(T) > 0); + try expect(result == (@sizeOf(T) > 0)); } }; // Zero-sized type try S.doTheTest(u0, false); - try S.doTheTest(*u0, false); + // Pointers to zero sized types still have addresses. + try S.doTheTest(*u0, true); // Non byte-sized type try S.doTheTest(u1, true); try S.doTheTest(*u1, true);