diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 37dc873d60..e6a3558646 100644 --- a/test/behavior/struct.zig +++ b/test/behavior/struct.zig @@ -1249,6 +1249,20 @@ test "store to comptime field" { } } +test "struct field init value is size of the struct" { + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + + const namespace = struct { + const S = extern struct { + size: u8 = @sizeOf(S), + blah: u16, + }; + }; + var s: namespace.S = .{ .blah = 1234 }; + _ = &s; + try expect(s.size == 4); +} + test "under-aligned struct field" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO @@ -1696,19 +1710,41 @@ test "comptimeness of optional and error union payload is analyzed properly" { try std.testing.expectEqual(3, x); } +test "initializer uses own alignment" { + const S = struct { + x: u32 = @alignOf(@This()) + 1, + }; + + var s: S = .{}; + _ = &s; + try expectEqual(4, @alignOf(S)); + try expectEqual(@as(usize, 5), s.x); +} + +test "initializer uses own size" { + const S = struct { + x: u32 = @sizeOf(@This()) + 1, + }; + + var s: S = .{}; + _ = &s; + try expectEqual(4, @sizeOf(S)); + try expectEqual(@as(usize, 5), s.x); +} + test "initializer takes a pointer to a variable inside its struct" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; const namespace = struct { const S = struct { - x: *u32 = &S.int, - var int: u32 = undefined; + s: *S = &S.instance, + var instance: S = undefined; }; fn doTheTest() !void { var foo: S = .{}; _ = &foo; - try expectEqual(&S.int, foo.x); + try expectEqual(&S.instance, foo.s); } }; @@ -1739,6 +1775,22 @@ test "circular dependency through pointer field of a struct" { try expect(outer.middle.inner == null); } +test "field calls do not force struct field init resolution" { + const S = struct { + x: u32 = blk: { + _ = @TypeOf(make().dummyFn()); // runtime field call - S not fully resolved - dummyFn call should not force field init resolution + break :blk 123; + }, + dummyFn: *const fn () void = undefined, + fn make() @This() { + return .{}; + } + }; + var s: S = .{}; + _ = &s; + try expect(s.x == 123); +} + test "tuple with comptime-only field" { const S = struct { fn getTuple() struct { comptime_int } { diff --git a/test/behavior/union.zig b/test/behavior/union.zig index b081d9b33a..9badc9dabd 100644 --- a/test/behavior/union.zig +++ b/test/behavior/union.zig @@ -1796,6 +1796,55 @@ test "reinterpret packed union inside packed struct" { try S.doTheTest(); } +test "inner struct initializer uses union layout" { + const namespace = struct { + const U = union { + a: struct { + x: u32 = @alignOf(U) + 1, + }, + b: struct { + y: u16 = @sizeOf(U) + 2, + }, + }; + }; + + { + const u: namespace.U = .{ .a = .{} }; + try expectEqual(4, @alignOf(namespace.U)); + try expectEqual(@as(usize, 5), u.a.x); + } + + { + const u: namespace.U = .{ .b = .{} }; + try expectEqual(@as(usize, @sizeOf(namespace.U) + 2), u.b.y); + } +} + +test "inner struct initializer uses packed union layout" { + const namespace = struct { + const U = packed union { + a: packed struct { + x: u32 = @alignOf(U) + 1, + }, + b: packed struct(u32) { + y: u16 = @sizeOf(U) + 2, + padding: u16 = 0, + }, + }; + }; + + { + const u: namespace.U = .{ .a = .{} }; + try expectEqual(4, @alignOf(namespace.U)); + try expectEqual(@as(usize, 5), u.a.x); + } + + { + const u: namespace.U = .{ .b = .{} }; + try expectEqual(@as(usize, @sizeOf(namespace.U) + 2), u.b.y); + } +} + test "extern union initialized via reintepreted struct field initializer" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;