authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-24 20:27:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-08-24 22:20:31-07:00
log7453f56e678c80928ababa2868c69cfe41647fed
tree689bfb73cab6314cb91898b174fcf12d50196009
parentaf19909b9cde3d009f0306ac825f39912644bca6

stage2: explicitly tagged enums no longer have one possible value

Previously, Zig had inconsistent semantics for an enum like this: `enum(u8){zero = 0}` Although in theory this can only hold one possible value, the tag `zero`, Zig no longer will treat the type this way. It will do loads and stores, as if the type has runtime bits. Closes #12619 Tests passed locally: * test-behavior * test-cases

10 files changed, 113 insertions(+), 60 deletions(-)

lib/std/elf.zig+7-7
...@@ -3,7 +3,7 @@ const io = std.io;...@@ -3,7 +3,7 @@ const io = std.io;
3const os = std.os;3const os = std.os;
4const math = std.math;4const math = std.math;
5const mem = std.mem;5const mem = std.mem;
6const debug = std.debug;6const assert = std.debug.assert;
7const File = std.fs.File;7const File = std.fs.File;
8const native_endian = @import("builtin").target.cpu.arch.endian();8const native_endian = @import("builtin").target.cpu.arch.endian();
99
...@@ -872,14 +872,14 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {...@@ -872,14 +872,14 @@ pub const Elf_MIPS_ABIFlags_v0 = extern struct {
872};872};
873873
874comptime {874comptime {
875 debug.assert(@sizeOf(Elf32_Ehdr) == 52);875 assert(@sizeOf(Elf32_Ehdr) == 52);
876 debug.assert(@sizeOf(Elf64_Ehdr) == 64);876 assert(@sizeOf(Elf64_Ehdr) == 64);
877877
878 debug.assert(@sizeOf(Elf32_Phdr) == 32);878 assert(@sizeOf(Elf32_Phdr) == 32);
879 debug.assert(@sizeOf(Elf64_Phdr) == 56);879 assert(@sizeOf(Elf64_Phdr) == 56);
880880
881 debug.assert(@sizeOf(Elf32_Shdr) == 40);881 assert(@sizeOf(Elf32_Shdr) == 40);
882 debug.assert(@sizeOf(Elf64_Shdr) == 64);882 assert(@sizeOf(Elf64_Shdr) == 64);
883}883}
884884
885pub const Auxv = switch (@sizeOf(usize)) {885pub const Auxv = switch (@sizeOf(usize)) {
src/Module.zig+14-12
...@@ -1368,18 +1368,20 @@ pub const Union = struct {...@@ -1368,18 +1368,20 @@ pub const Union = struct {
1368 }1368 }
1369 }1369 }
1370 payload_align = @maximum(payload_align, 1);1370 payload_align = @maximum(payload_align, 1);
1371 if (!have_tag or fields.len <= 1) return .{1371 if (!have_tag or !u.tag_ty.hasRuntimeBits()) {
1372 .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align),1372 return .{
1373 .abi_align = payload_align,1373 .abi_size = std.mem.alignForwardGeneric(u64, payload_size, payload_align),
1374 .most_aligned_field = most_aligned_field,1374 .abi_align = payload_align,
1375 .most_aligned_field_size = most_aligned_field_size,1375 .most_aligned_field = most_aligned_field,
1376 .biggest_field = biggest_field,1376 .most_aligned_field_size = most_aligned_field_size,
1377 .payload_size = payload_size,1377 .biggest_field = biggest_field,
1378 .payload_align = payload_align,1378 .payload_size = payload_size,
1379 .tag_align = 0,1379 .payload_align = payload_align,
1380 .tag_size = 0,1380 .tag_align = 0,
1381 .padding = 0,1381 .tag_size = 0,
1382 };1382 .padding = 0,
1383 };
1384 }
1383 // Put the tag before or after the payload depending on which one's1385 // Put the tag before or after the payload depending on which one's
1384 // alignment is greater.1386 // alignment is greater.
1385 const tag_size = u.tag_ty.abiSize(target);1387 const tag_size = u.tag_ty.abiSize(target);
src/Sema.zig+7
...@@ -28844,6 +28844,10 @@ pub fn typeHasOnePossibleValue(...@@ -28844,6 +28844,10 @@ pub fn typeHasOnePossibleValue(
28844 .enum_numbered => {28844 .enum_numbered => {
28845 const resolved_ty = try sema.resolveTypeFields(block, src, ty);28845 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
28846 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;28846 const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;
28847 // An explicit tag type is always provided for enum_numbered.
28848 if (enum_obj.tag_ty.hasRuntimeBits()) {
28849 return null;
28850 }
28847 if (enum_obj.fields.count() == 1) {28851 if (enum_obj.fields.count() == 1) {
28848 if (enum_obj.values.count() == 0) {28852 if (enum_obj.values.count() == 0) {
28849 return Value.zero; // auto-numbered28853 return Value.zero; // auto-numbered
...@@ -28857,6 +28861,9 @@ pub fn typeHasOnePossibleValue(...@@ -28857,6 +28861,9 @@ pub fn typeHasOnePossibleValue(
28857 .enum_full => {28861 .enum_full => {
28858 const resolved_ty = try sema.resolveTypeFields(block, src, ty);28862 const resolved_ty = try sema.resolveTypeFields(block, src, ty);
28859 const enum_obj = resolved_ty.castTag(.enum_full).?.data;28863 const enum_obj = resolved_ty.castTag(.enum_full).?.data;
28864 if (enum_obj.tag_ty.hasRuntimeBits()) {
28865 return null;
28866 }
28860 if (enum_obj.fields.count() == 1) {28867 if (enum_obj.fields.count() == 1) {
28861 if (enum_obj.values.count() == 0) {28868 if (enum_obj.values.count() == 0) {
28862 return Value.zero; // auto-numbered28869 return Value.zero; // auto-numbered
src/arch/x86_64/CodeGen.zig+2-2
...@@ -6524,13 +6524,13 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {...@@ -6524,13 +6524,13 @@ fn airCmpxchg(self: *Self, inst: Air.Inst.Index) !void {
6524 const extra = self.air.extraData(Air.Block, ty_pl.payload);6524 const extra = self.air.extraData(Air.Block, ty_pl.payload);
6525 _ = ty_pl;6525 _ = ty_pl;
6526 _ = extra;6526 _ = extra;
6527 return self.fail("TODO implement airCmpxchg for {}", .{self.target.cpu.arch});6527 return self.fail("TODO implement x86 airCmpxchg", .{});
6528 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });6528 // return self.finishAir(inst, result, .{ extra.ptr, extra.expected_value, extra.new_value });
6529}6529}
65306530
6531fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {6531fn airAtomicRmw(self: *Self, inst: Air.Inst.Index) !void {
6532 _ = inst;6532 _ = inst;
6533 return self.fail("TODO implement airCmpxchg for {}", .{self.target.cpu.arch});6533 return self.fail("TODO implement x86 airAtomicRaw", .{});
6534}6534}
65356535
6536fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {6536fn airAtomicLoad(self: *Self, inst: Air.Inst.Index) !void {
src/codegen/llvm.zig+4-4
...@@ -1860,7 +1860,7 @@ pub const Object = struct {...@@ -1860,7 +1860,7 @@ pub const Object = struct {
1860 var offset: u64 = 0;1860 var offset: u64 = 0;
18611861
1862 for (fields.values()) |field, i| {1862 for (fields.values()) |field, i| {
1863 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;1863 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
18641864
1865 const field_size = field.ty.abiSize(target);1865 const field_size = field.ty.abiSize(target);
1866 const field_align = field.alignment(target, layout);1866 const field_align = field.alignment(target, layout);
...@@ -2764,7 +2764,7 @@ pub const DeclGen = struct {...@@ -2764,7 +2764,7 @@ pub const DeclGen = struct {
2764 var any_underaligned_fields = false;2764 var any_underaligned_fields = false;
27652765
2766 for (struct_obj.fields.values()) |field| {2766 for (struct_obj.fields.values()) |field| {
2767 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;2767 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
27682768
2769 const field_align = field.alignment(target, struct_obj.layout);2769 const field_align = field.alignment(target, struct_obj.layout);
2770 const field_ty_align = field.ty.abiAlignment(target);2770 const field_ty_align = field.ty.abiAlignment(target);
...@@ -3443,7 +3443,7 @@ pub const DeclGen = struct {...@@ -3443,7 +3443,7 @@ pub const DeclGen = struct {
3443 var need_unnamed = false;3443 var need_unnamed = false;
34443444
3445 for (struct_obj.fields.values()) |field, i| {3445 for (struct_obj.fields.values()) |field, i| {
3446 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;3446 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
34473447
3448 const field_align = field.alignment(target, struct_obj.layout);3448 const field_align = field.alignment(target, struct_obj.layout);
3449 big_align = @maximum(big_align, field_align);3449 big_align = @maximum(big_align, field_align);
...@@ -9477,7 +9477,7 @@ fn llvmFieldIndex(...@@ -9477,7 +9477,7 @@ fn llvmFieldIndex(
94779477
9478 var llvm_field_index: c_uint = 0;9478 var llvm_field_index: c_uint = 0;
9479 for (ty.structFields().values()) |field, i| {9479 for (ty.structFields().values()) |field, i| {
9480 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime()) continue;9480 if (field.is_comptime or !field.ty.hasRuntimeBits()) continue;
94819481
9482 const field_align = field.alignment(target, layout);9482 const field_align = field.alignment(target, layout);
9483 big_align = @maximum(big_align, field_align);9483 big_align = @maximum(big_align, field_align);
src/type.zig+33-18
...@@ -2310,6 +2310,8 @@ pub const Type = extern union {...@@ -2310,6 +2310,8 @@ pub const Type = extern union {
2310 /// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`2310 /// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`
2311 /// hasRuntimeBits()=true and abiSize()=42311 /// hasRuntimeBits()=true and abiSize()=4
2312 /// * the type has only one possible value, making its ABI size 0.2312 /// * the type has only one possible value, making its ABI size 0.
2313 /// - an enum with an explicit tag type has the ABI size of the integer tag type,
2314 /// making it one-possible-value only if the integer tag type has 0 bits.
2313 /// When `ignore_comptime_only` is true, then types that are comptime only2315 /// When `ignore_comptime_only` is true, then types that are comptime only
2314 /// may return false positives.2316 /// may return false positives.
2315 pub fn hasRuntimeBitsAdvanced(2317 pub fn hasRuntimeBitsAdvanced(
...@@ -2452,9 +2454,9 @@ pub const Type = extern union {...@@ -2452,9 +2454,9 @@ pub const Type = extern union {
2452 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);2454 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2453 }2455 }
2454 assert(struct_obj.haveFieldTypes());2456 assert(struct_obj.haveFieldTypes());
2455 for (struct_obj.fields.values()) |value| {2457 for (struct_obj.fields.values()) |field| {
2456 if (value.is_comptime) continue;2458 if (field.is_comptime) continue;
2457 if (try value.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))2459 if (try field.ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit))
2458 return true;2460 return true;
2459 } else {2461 } else {
2460 return false;2462 return false;
...@@ -2463,7 +2465,7 @@ pub const Type = extern union {...@@ -2463,7 +2465,7 @@ pub const Type = extern union {
24632465
2464 .enum_full => {2466 .enum_full => {
2465 const enum_full = ty.castTag(.enum_full).?.data;2467 const enum_full = ty.castTag(.enum_full).?.data;
2466 return enum_full.fields.count() >= 2;2468 return enum_full.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit);
2467 },2469 },
2468 .enum_simple => {2470 .enum_simple => {
2469 const enum_simple = ty.castTag(.enum_simple).?.data;2471 const enum_simple = ty.castTag(.enum_simple).?.data;
...@@ -2490,9 +2492,10 @@ pub const Type = extern union {...@@ -2490,9 +2492,10 @@ pub const Type = extern union {
2490 },2492 },
2491 .union_safety_tagged, .union_tagged => {2493 .union_safety_tagged, .union_tagged => {
2492 const union_obj = ty.cast(Payload.Union).?.data;2494 const union_obj = ty.cast(Payload.Union).?.data;
2493 if (union_obj.fields.count() > 0 and try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {2495 if (try union_obj.tag_ty.hasRuntimeBitsAdvanced(ignore_comptime_only, sema_kit)) {
2494 return true;2496 return true;
2495 }2497 }
2498
2496 if (sema_kit) |sk| {2499 if (sema_kit) |sk| {
2497 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);2500 _ = try sk.sema.resolveTypeFields(sk.block, sk.src, ty);
2498 }2501 }
...@@ -3125,7 +3128,11 @@ pub const Type = extern union {...@@ -3125,7 +3128,11 @@ pub const Type = extern union {
3125 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },3128 .lazy => |arena| return AbiAlignmentAdvanced{ .val = try Value.Tag.lazy_align.create(arena, ty) },
3126 };3129 };
3127 if (union_obj.fields.count() == 0) {3130 if (union_obj.fields.count() == 0) {
3128 return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) };3131 if (have_tag) {
3132 return abiAlignmentAdvanced(union_obj.tag_ty, target, strat);
3133 } else {
3134 return AbiAlignmentAdvanced{ .scalar = @boolToInt(union_obj.layout == .Extern) };
3135 }
3129 }3136 }
31303137
3131 var max_align: u32 = 0;3138 var max_align: u32 = 0;
...@@ -4991,14 +4998,18 @@ pub const Type = extern union {...@@ -4991,14 +4998,18 @@ pub const Type = extern union {
49914998
4992 .enum_numbered => {4999 .enum_numbered => {
4993 const enum_numbered = ty.castTag(.enum_numbered).?.data;5000 const enum_numbered = ty.castTag(.enum_numbered).?.data;
4994 if (enum_numbered.fields.count() == 1) {5001 // An explicit tag type is always provided for enum_numbered.
4995 return enum_numbered.values.keys()[0];5002 if (enum_numbered.tag_ty.hasRuntimeBits()) {
4996 } else {
4997 return null;5003 return null;
4998 }5004 }
5005 assert(enum_numbered.fields.count() == 1);
5006 return enum_numbered.values.keys()[0];
4999 },5007 },
5000 .enum_full => {5008 .enum_full => {
5001 const enum_full = ty.castTag(.enum_full).?.data;5009 const enum_full = ty.castTag(.enum_full).?.data;
5010 if (enum_full.tag_ty.hasRuntimeBits()) {
5011 return null;
5012 }
5002 if (enum_full.fields.count() == 1) {5013 if (enum_full.fields.count() == 1) {
5003 if (enum_full.values.count() == 0) {5014 if (enum_full.values.count() == 0) {
5004 return Value.zero;5015 return Value.zero;
...@@ -5333,7 +5344,8 @@ pub const Type = extern union {...@@ -5333,7 +5344,8 @@ pub const Type = extern union {
5333 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty,5344 .enum_numbered => return ty.castTag(.enum_numbered).?.data.tag_ty,
5334 .enum_simple => {5345 .enum_simple => {
5335 const enum_simple = ty.castTag(.enum_simple).?.data;5346 const enum_simple = ty.castTag(.enum_simple).?.data;
5336 const bits = std.math.log2_int_ceil(usize, enum_simple.fields.count());5347 const field_count = enum_simple.fields.count();
5348 const bits: u16 = if (field_count == 0) 0 else std.math.log2_int_ceil(usize, field_count);
5337 buffer.* = .{5349 buffer.* = .{
5338 .base = .{ .tag = .int_unsigned },5350 .base = .{ .tag = .int_unsigned },
5339 .data = bits,5351 .data = bits,
...@@ -5653,19 +5665,22 @@ pub const Type = extern union {...@@ -5653,19 +5665,22 @@ pub const Type = extern union {
5653 target: Target,5665 target: Target,
56545666
5655 pub fn next(it: *StructOffsetIterator) ?FieldOffset {5667 pub fn next(it: *StructOffsetIterator) ?FieldOffset {
5656 if (it.struct_obj.fields.count() <= it.field)5668 const i = it.field;
5669 if (it.struct_obj.fields.count() <= i)
5657 return null;5670 return null;
56585671
5659 const field = it.struct_obj.fields.values()[it.field];5672 const field = it.struct_obj.fields.values()[i];
5660 defer it.field += 1;5673 it.field += 1;
5661 if (!field.ty.hasRuntimeBits() or field.is_comptime)5674
5662 return FieldOffset{ .field = it.field, .offset = it.offset };5675 if (field.is_comptime or !field.ty.hasRuntimeBits()) {
5676 return FieldOffset{ .field = i, .offset = it.offset };
5677 }
56635678
5664 const field_align = field.alignment(it.target, it.struct_obj.layout);5679 const field_align = field.alignment(it.target, it.struct_obj.layout);
5665 it.big_align = @maximum(it.big_align, field_align);5680 it.big_align = @maximum(it.big_align, field_align);
5666 it.offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);5681 const field_offset = std.mem.alignForwardGeneric(u64, it.offset, field_align);
5667 defer it.offset += field.ty.abiSize(it.target);5682 it.offset = field_offset + field.ty.abiSize(it.target);
5668 return FieldOffset{ .field = it.field, .offset = it.offset };5683 return FieldOffset{ .field = i, .offset = field_offset };
5669 }5684 }
5670 };5685 };
56715686
test/behavior.zig-1
...@@ -26,7 +26,6 @@ test {...@@ -26,7 +26,6 @@ test {
26 _ = @import("behavior/bugs/920.zig");26 _ = @import("behavior/bugs/920.zig");
27 _ = @import("behavior/bugs/1025.zig");27 _ = @import("behavior/bugs/1025.zig");
28 _ = @import("behavior/bugs/1076.zig");28 _ = @import("behavior/bugs/1076.zig");
29 _ = @import("behavior/bugs/1111.zig");
30 _ = @import("behavior/bugs/1277.zig");29 _ = @import("behavior/bugs/1277.zig");
31 _ = @import("behavior/bugs/1310.zig");30 _ = @import("behavior/bugs/1310.zig");
32 _ = @import("behavior/bugs/1381.zig");31 _ = @import("behavior/bugs/1381.zig");
test/behavior/bugs/1111.zig deleted-11
...@@ -1,11 +0,0 @@
1const Foo = enum(c_int) {
2 Bar = -1,
3};
4
5test "issue 1111 fixed" {
6 const v = Foo.Bar;
7
8 switch (v) {
9 Foo.Bar => return,
10 }
11}
test/behavior/enum.zig+42
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const assert = std.debug.assert;
4const mem = std.mem;5const mem = std.mem;
5const Tag = std.meta.Tag;6const Tag = std.meta.Tag;
67
...@@ -1128,3 +1129,44 @@ test "tag name functions are unique" {...@@ -1128,3 +1129,44 @@ test "tag name functions are unique" {
1128 _ = a;1129 _ = a;
1129 }1130 }
1130}1131}
1132
1133test "size of enum with only one tag which has explicit integer tag type" {
1134 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
1135 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
1136 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
1137
1138 const E = enum(u8) { nope = 10 };
1139 const S0 = struct { e: E };
1140 const S1 = extern struct { e: E };
1141 //const U = union(E) { nope: void };
1142 comptime assert(@sizeOf(E) == 1);
1143 comptime assert(@sizeOf(S0) == 1);
1144 comptime assert(@sizeOf(S1) == 1);
1145 //comptime assert(@sizeOf(U) == 1);
1146
1147 var s1: S1 = undefined;
1148 s1.e = .nope;
1149 try expect(s1.e == .nope);
1150 const ptr = @ptrCast(*u8, &s1);
1151 try expect(ptr.* == 10);
1152
1153 var s0: S0 = undefined;
1154 s0.e = .nope;
1155 try expect(s0.e == .nope);
1156}
1157
1158test "switch on an extern enum with negative value" {
1159 // TODO x86, wasm backends fail because they assume that enum tag types are unsigned
1160 if (@import("builtin").zig_backend == .stage2_x86_64) return error.SkipZigTest;
1161 if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest;
1162
1163 const Foo = enum(c_int) {
1164 Bar = -1,
1165 };
1166
1167 const v = Foo.Bar;
1168
1169 switch (v) {
1170 Foo.Bar => return,
1171 }
1172}
test/behavior/union.zig+4-5
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const builtin = @import("builtin");1const builtin = @import("builtin");
2const std = @import("std");2const std = @import("std");
3const expect = std.testing.expect;3const expect = std.testing.expect;
4const assert = std.debug.assert;
4const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
5const Tag = std.meta.Tag;6const Tag = std.meta.Tag;
67
...@@ -1065,6 +1066,8 @@ test "@unionInit on union with tag but no fields" {...@@ -1065,6 +1066,8 @@ test "@unionInit on union with tag but no fields" {
1065 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO1066 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
1066 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO1067 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1067 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO1068 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1069 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1070 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
10681071
1069 const S = struct {1072 const S = struct {
1070 const Type = enum(u8) { no_op = 105 };1073 const Type = enum(u8) { no_op = 105 };
...@@ -1079,11 +1082,7 @@ test "@unionInit on union with tag but no fields" {...@@ -1079,11 +1082,7 @@ test "@unionInit on union with tag but no fields" {
1079 };1082 };
10801083
1081 comptime {1084 comptime {
1082 if (builtin.zig_backend == .stage1) {1085 assert(@sizeOf(Data) == 1);
1083 // stage1 gets the wrong answer here
1084 } else {
1085 std.debug.assert(@sizeOf(Data) == 0);
1086 }
1087 }1086 }
10881087
1089 fn doTheTest() !void {1088 fn doTheTest() !void {