authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-22 21:02:24-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-09-22 21:06:00-07:00
log736d14fd5fa5feea83a6efce8b606b62bf165033
treeda48c5f1743c7418ed51c5f9769236529a988be8
parent0ec01e58b429e96d50411f74a0005076c24dda0c

stage2: fix AstGen for some struct syntaxes

* AstGen: fix not emitting `struct_init_empty` when an explicit type is present in struct initialization syntax. * AstGen: these two syntaxes now lower to identical ZIR: - `var a = A{ .b = c };` - `var a = @as(A, .{ .b = c });` * Zir: clarify `auto_enum_tag` in the doc comments. * LLVM Backend: fix lowering of function return types when the type has 0 bits.

6 files changed, 1027 insertions(+), 961 deletions(-)

src/AstGen.zig+79-31
...@@ -1357,7 +1357,14 @@ fn structInitExpr(...@@ -1357,7 +1357,14 @@ fn structInitExpr(
1357 const array_type: Ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) {1357 const array_type: Ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) {
1358 .array_type => tree.arrayType(struct_init.ast.type_expr),1358 .array_type => tree.arrayType(struct_init.ast.type_expr),
1359 .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr),1359 .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr),
1360 else => break :array,1360 else => {
1361 if (struct_init.ast.fields.len == 0) {
1362 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1363 const result = try gz.addUnNode(.struct_init_empty, ty_inst, node);
1364 return rvalue(gz, rl, result, node);
1365 }
1366 break :array;
1367 },
1361 };1368 };
1362 const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and1369 const is_inferred_array_len = node_tags[array_type.ast.elem_count] == .identifier and
1363 // This intentionally does not support `@"_"` syntax.1370 // This intentionally does not support `@"_"` syntax.
...@@ -1419,8 +1426,8 @@ fn structInitExpr(...@@ -1419,8 +1426,8 @@ fn structInitExpr(
1419 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);1426 const result = try structInitExprRlTy(gz, scope, node, struct_init, inner_ty_inst, .struct_init);
1420 return rvalue(gz, rl, result, node);1427 return rvalue(gz, rl, result, node);
1421 },1428 },
1422 .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, node, struct_init, ptr_inst),1429 .ptr, .inferred_ptr => |ptr_inst| return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst),
1423 .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, node, struct_init, block_gz.rl_ptr),1430 .block_ptr => |block_gz| return structInitExprRlPtr(gz, scope, rl, node, struct_init, block_gz.rl_ptr),
1424 }1431 }
1425}1432}
14261433
...@@ -1459,6 +1466,26 @@ fn structInitExprRlNone(...@@ -1459,6 +1466,26 @@ fn structInitExprRlNone(
1459}1466}
14601467
1461fn structInitExprRlPtr(1468fn structInitExprRlPtr(
1469 gz: *GenZir,
1470 scope: *Scope,
1471 rl: ResultLoc,
1472 node: Ast.Node.Index,
1473 struct_init: Ast.full.StructInit,
1474 result_ptr: Zir.Inst.Ref,
1475) InnerError!Zir.Inst.Ref {
1476 if (struct_init.ast.type_expr == 0) {
1477 return structInitExprRlPtrInner(gz, scope, node, struct_init, result_ptr);
1478 }
1479 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
1480
1481 var as_scope = try gz.makeCoercionScope(scope, ty_inst, result_ptr);
1482 defer as_scope.instructions.deinit(gz.astgen.gpa);
1483
1484 const result = try structInitExprRlPtrInner(&as_scope, scope, node, struct_init, as_scope.rl_ptr);
1485 return as_scope.finishCoercion(gz, rl, node, result, ty_inst);
1486}
1487
1488fn structInitExprRlPtrInner(
1462 gz: *GenZir,1489 gz: *GenZir,
1463 scope: *Scope,1490 scope: *Scope,
1464 node: Ast.Node.Index,1491 node: Ast.Node.Index,
...@@ -1472,9 +1499,6 @@ fn structInitExprRlPtr(...@@ -1472,9 +1499,6 @@ fn structInitExprRlPtr(
1472 const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len);1499 const field_ptr_list = try gpa.alloc(Zir.Inst.Index, struct_init.ast.fields.len);
1473 defer gpa.free(field_ptr_list);1500 defer gpa.free(field_ptr_list);
14741501
1475 if (struct_init.ast.type_expr != 0)
1476 _ = try typeExpr(gz, scope, struct_init.ast.type_expr);
1477
1478 for (struct_init.ast.fields) |field_init, i| {1502 for (struct_init.ast.fields) |field_init, i| {
1479 const name_token = tree.firstToken(field_init) - 2;1503 const name_token = tree.firstToken(field_init) - 2;
1480 const str_index = try astgen.identAsString(name_token);1504 const str_index = try astgen.identAsString(name_token);
...@@ -1489,7 +1513,7 @@ fn structInitExprRlPtr(...@@ -1489,7 +1513,7 @@ fn structInitExprRlPtr(
1489 .body_len = @intCast(u32, field_ptr_list.len),1513 .body_len = @intCast(u32, field_ptr_list.len),
1490 });1514 });
1491 try astgen.extra.appendSlice(gpa, field_ptr_list);1515 try astgen.extra.appendSlice(gpa, field_ptr_list);
1492 return .void_value;1516 return Zir.Inst.Ref.void_value;
1493}1517}
14941518
1495fn structInitExprRlTy(1519fn structInitExprRlTy(
...@@ -6902,35 +6926,13 @@ fn asRlPtr(...@@ -6902,35 +6926,13 @@ fn asRlPtr(
6902 operand_node: Ast.Node.Index,6926 operand_node: Ast.Node.Index,
6903 dest_type: Zir.Inst.Ref,6927 dest_type: Zir.Inst.Ref,
6904) InnerError!Zir.Inst.Ref {6928) InnerError!Zir.Inst.Ref {
6905 // Detect whether this expr() call goes into rvalue() to store the result into the
6906 // result location. If it does, elide the coerce_result_ptr instruction
6907 // as well as the store instruction, instead passing the result as an rvalue.
6908 const astgen = parent_gz.astgen;6929 const astgen = parent_gz.astgen;
69096930
6910 var as_scope = parent_gz.makeSubBlock(scope);6931 var as_scope = try parent_gz.makeCoercionScope(scope, dest_type, result_ptr);
6911 defer as_scope.instructions.deinit(astgen.gpa);6932 defer as_scope.instructions.deinit(astgen.gpa);
69126933
6913 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
6914 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);6934 const result = try reachableExpr(&as_scope, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node, src_node);
6915 const parent_zir = &parent_gz.instructions;6935 return as_scope.finishCoercion(parent_gz, rl, operand_node, result, dest_type);
6916 if (as_scope.rvalue_rl_count == 1) {
6917 // Busted! This expression didn't actually need a pointer.
6918 const zir_tags = astgen.instructions.items(.tag);
6919 const zir_datas = astgen.instructions.items(.data);
6920 try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len);
6921 for (as_scope.instructions.items) |src_inst| {
6922 if (indexToRef(src_inst) == as_scope.rl_ptr) continue;
6923 if (zir_tags[src_inst] == .store_to_block_ptr) {
6924 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
6925 }
6926 parent_zir.appendAssumeCapacity(src_inst);
6927 }
6928 const casted_result = try parent_gz.addBin(.as, dest_type, result);
6929 return rvalue(parent_gz, rl, casted_result, operand_node);
6930 } else {
6931 try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items);
6932 return result;
6933 }
6934}6936}
69356937
6936fn bitCast(6938fn bitCast(
...@@ -9108,6 +9110,52 @@ const GenZir = struct {...@@ -9108,6 +9110,52 @@ const GenZir = struct {
9108 };9110 };
9109 }9111 }
91109112
9113 fn makeCoercionScope(
9114 parent_gz: *GenZir,
9115 scope: *Scope,
9116 dest_type: Zir.Inst.Ref,
9117 result_ptr: Zir.Inst.Ref,
9118 ) !GenZir {
9119 // Detect whether this expr() call goes into rvalue() to store the result into the
9120 // result location. If it does, elide the coerce_result_ptr instruction
9121 // as well as the store instruction, instead passing the result as an rvalue.
9122 var as_scope = parent_gz.makeSubBlock(scope);
9123 errdefer as_scope.instructions.deinit(parent_gz.astgen.gpa);
9124 as_scope.rl_ptr = try as_scope.addBin(.coerce_result_ptr, dest_type, result_ptr);
9125
9126 return as_scope;
9127 }
9128
9129 fn finishCoercion(
9130 as_scope: *GenZir,
9131 parent_gz: *GenZir,
9132 rl: ResultLoc,
9133 src_node: Ast.Node.Index,
9134 result: Zir.Inst.Ref,
9135 dest_type: Zir.Inst.Ref,
9136 ) !Zir.Inst.Ref {
9137 const astgen = as_scope.astgen;
9138 const parent_zir = &parent_gz.instructions;
9139 if (as_scope.rvalue_rl_count == 1) {
9140 // Busted! This expression didn't actually need a pointer.
9141 const zir_tags = astgen.instructions.items(.tag);
9142 const zir_datas = astgen.instructions.items(.data);
9143 try parent_zir.ensureUnusedCapacity(astgen.gpa, as_scope.instructions.items.len);
9144 for (as_scope.instructions.items) |src_inst| {
9145 if (indexToRef(src_inst) == as_scope.rl_ptr) continue;
9146 if (zir_tags[src_inst] == .store_to_block_ptr) {
9147 if (zir_datas[src_inst].bin.lhs == as_scope.rl_ptr) continue;
9148 }
9149 parent_zir.appendAssumeCapacity(src_inst);
9150 }
9151 const casted_result = try parent_gz.addBin(.as, dest_type, result);
9152 return rvalue(parent_gz, rl, casted_result, src_node);
9153 } else {
9154 try parent_zir.appendSlice(astgen.gpa, as_scope.instructions.items);
9155 return result;
9156 }
9157 }
9158
9111 const Label = struct {9159 const Label = struct {
9112 token: Ast.TokenIndex,9160 token: Ast.TokenIndex,
9113 block_inst: Zir.Inst.Index,9161 block_inst: Zir.Inst.Index,
src/Zir.zig+6-2
...@@ -2650,8 +2650,12 @@ pub const Inst = struct {...@@ -2650,8 +2650,12 @@ pub const Inst = struct {
2650 has_decls_len: bool,2650 has_decls_len: bool,
2651 name_strategy: NameStrategy,2651 name_strategy: NameStrategy,
2652 layout: std.builtin.TypeInfo.ContainerLayout,2652 layout: std.builtin.TypeInfo.ContainerLayout,
2653 /// false: union(tag_type)2653 /// has_tag_type | auto_enum_tag | result
2654 /// true: union(enum(tag_type))2654 /// -------------------------------------
2655 /// false | false | union { }
2656 /// false | true | union(enum) { }
2657 /// true | true | union(enum(T)) { }
2658 /// true | false | union(T) { }
2655 auto_enum_tag: bool,2659 auto_enum_tag: bool,
2656 _: u6 = undefined,2660 _: u6 = undefined,
2657 };2661 };
src/codegen/llvm.zig+6-1
...@@ -563,8 +563,13 @@ pub const DeclGen = struct {...@@ -563,8 +563,13 @@ pub const DeclGen = struct {
563 }563 }
564 }564 }
565565
566 const llvm_ret_ty = if (!return_type.hasCodeGenBits())
567 self.context.voidType()
568 else
569 try self.llvmType(return_type);
570
566 const fn_type = llvm.functionType(571 const fn_type = llvm.functionType(
567 try self.llvmType(return_type),572 llvm_ret_ty,
568 llvm_param_buffer.ptr,573 llvm_param_buffer.ptr,
569 llvm_params_len,574 llvm_params_len,
570 .False,575 .False,
test/behavior.zig+2-1
...@@ -13,6 +13,7 @@ test {...@@ -13,6 +13,7 @@ test {
13 _ = @import("behavior/atomics.zig");13 _ = @import("behavior/atomics.zig");
14 _ = @import("behavior/sizeof_and_typeof.zig");14 _ = @import("behavior/sizeof_and_typeof.zig");
15 _ = @import("behavior/translate_c_macros.zig");15 _ = @import("behavior/translate_c_macros.zig");
16 _ = @import("behavior/struct.zig");
16 _ = @import("behavior/union.zig");17 _ = @import("behavior/union.zig");
17 _ = @import("behavior/widening.zig");18 _ = @import("behavior/widening.zig");
1819
...@@ -135,7 +136,7 @@ test {...@@ -135,7 +136,7 @@ test {
135 _ = @import("behavior/sizeof_and_typeof_stage1.zig");136 _ = @import("behavior/sizeof_and_typeof_stage1.zig");
136 _ = @import("behavior/slice.zig");137 _ = @import("behavior/slice.zig");
137 _ = @import("behavior/slice_sentinel_comptime.zig");138 _ = @import("behavior/slice_sentinel_comptime.zig");
138 _ = @import("behavior/struct.zig");139 _ = @import("behavior/struct_stage1.zig");
139 _ = @import("behavior/struct_contains_null_ptr_itself.zig");140 _ = @import("behavior/struct_contains_null_ptr_itself.zig");
140 _ = @import("behavior/struct_contains_slice_of_itself.zig");141 _ = @import("behavior/struct_contains_slice_of_itself.zig");
141 _ = @import("behavior/switch.zig");142 _ = @import("behavior/switch.zig");
test/behavior/struct.zig+6-926
...@@ -5,949 +5,29 @@ const expect = std.testing.expect;...@@ -5,949 +5,29 @@ const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;5const expectEqual = std.testing.expectEqual;
6const expectEqualSlices = std.testing.expectEqualSlices;6const expectEqualSlices = std.testing.expectEqualSlices;
7const maxInt = std.math.maxInt;7const maxInt = std.math.maxInt;
8
8const StructWithNoFields = struct {9const StructWithNoFields = struct {
9 fn add(a: i32, b: i32) i32 {10 fn add(a: i32, b: i32) i32 {
10 return a + b;11 return a + b;
11 }12 }
12};13};
13const empty_global_instance = StructWithNoFields{};
14
15top_level_field: i32,
16
17test "top level fields" {
18 var instance = @This(){
19 .top_level_field = 1234,
20 };
21 instance.top_level_field += 1;
22 try expectEqual(@as(i32, 1235), instance.top_level_field);
23}
2414
25test "call struct static method" {15test "call struct static method" {
26 const result = StructWithNoFields.add(3, 4);16 const result = StructWithNoFields.add(3, 4);
27 try expect(result == 7);17 try expect(result == 7);
28}18}
2919
30test "return empty struct instance" {
31 _ = returnEmptyStructInstance();
32}
33fn returnEmptyStructInstance() StructWithNoFields {
34 return empty_global_instance;
35}
36
37const should_be_11 = StructWithNoFields.add(5, 6);20const should_be_11 = StructWithNoFields.add(5, 6);
3821
39test "invoke static method in global scope" {22test "invoke static method in global scope" {
40 try expect(should_be_11 == 11);23 try expect(should_be_11 == 11);
41}24}
4225
43test "void struct fields" {26const empty_global_instance = StructWithNoFields{};
44 const foo = VoidStructFieldsFoo{
45 .a = void{},
46 .b = 1,
47 .c = void{},
48 };
49 try expect(foo.b == 1);
50 try expect(@sizeOf(VoidStructFieldsFoo) == 4);
51}
52const VoidStructFieldsFoo = struct {
53 a: void,
54 b: i32,
55 c: void,
56};
57
58test "structs" {
59 var foo: StructFoo = undefined;
60 @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
61 foo.a += 1;
62 foo.b = foo.a == 1;
63 try testFoo(foo);
64 testMutation(&foo);
65 try expect(foo.c == 100);
66}
67const StructFoo = struct {
68 a: i32,
69 b: bool,
70 c: f32,
71};
72fn testFoo(foo: StructFoo) !void {
73 try expect(foo.b);
74}
75fn testMutation(foo: *StructFoo) void {
76 foo.c = 100;
77}
78
79const Node = struct {
80 val: Val,
81 next: *Node,
82};
83
84const Val = struct {
85 x: i32,
86};
87
88test "struct point to self" {
89 var root: Node = undefined;
90 root.val.x = 1;
91
92 var node: Node = undefined;
93 node.next = &root;
94 node.val.x = 2;
95
96 root.next = &node;
97
98 try expect(node.next.next.next.val.x == 1);
99}
100
101test "struct byval assign" {
102 var foo1: StructFoo = undefined;
103 var foo2: StructFoo = undefined;
104
105 foo1.a = 1234;
106 foo2.a = 0;
107 try expect(foo2.a == 0);
108 foo2 = foo1;
109 try expect(foo2.a == 1234);
110}
111
112fn structInitializer() void {
113 const val = Val{ .x = 42 };
114 try expect(val.x == 42);
115}
116
117test "fn call of struct field" {
118 const Foo = struct {
119 ptr: fn () i32,
120 };
121 const S = struct {
122 fn aFunc() i32 {
123 return 13;
124 }
125
126 fn callStructField(foo: Foo) i32 {
127 return foo.ptr();
128 }
129 };
130
131 try expect(S.callStructField(Foo{ .ptr = S.aFunc }) == 13);
132}
133
134test "store member function in variable" {
135 const instance = MemberFnTestFoo{ .x = 1234 };
136 const memberFn = MemberFnTestFoo.member;
137 const result = memberFn(instance);
138 try expect(result == 1234);
139}
140const MemberFnTestFoo = struct {
141 x: i32,
142 fn member(foo: MemberFnTestFoo) i32 {
143 return foo.x;
144 }
145};
146
147test "call member function directly" {
148 const instance = MemberFnTestFoo{ .x = 1234 };
149 const result = MemberFnTestFoo.member(instance);
150 try expect(result == 1234);
151}
152
153test "member functions" {
154 const r = MemberFnRand{ .seed = 1234 };
155 try expect(r.getSeed() == 1234);
156}
157const MemberFnRand = struct {
158 seed: u32,
159 pub fn getSeed(r: *const MemberFnRand) u32 {
160 return r.seed;
161 }
162};
163
164test "return struct byval from function" {
165 const bar = makeBar2(1234, 5678);
166 try expect(bar.y == 5678);
167}
168const Bar = struct {
169 x: i32,
170 y: i32,
171};
172fn makeBar2(x: i32, y: i32) Bar {
173 return Bar{
174 .x = x,
175 .y = y,
176 };
177}
178
179test "empty struct method call" {
180 const es = EmptyStruct{};
181 try expect(es.method() == 1234);
182}
183const EmptyStruct = struct {
184 fn method(es: *const EmptyStruct) i32 {
185 _ = es;
186 return 1234;
187 }
188};
189
190test "return empty struct from fn" {
191 _ = testReturnEmptyStructFromFn();
192}
193const EmptyStruct2 = struct {};
194fn testReturnEmptyStructFromFn() EmptyStruct2 {
195 return EmptyStruct2{};
196}
197
198test "pass slice of empty struct to fn" {
199 try expect(testPassSliceOfEmptyStructToFn(&[_]EmptyStruct2{EmptyStruct2{}}) == 1);
200}
201fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
202 return slice.len;
203}
204
205const APackedStruct = packed struct {
206 x: u8,
207 y: u8,
208};
209
210test "packed struct" {
211 var foo = APackedStruct{
212 .x = 1,
213 .y = 2,
214 };
215 foo.y += 1;
216 const four = foo.x + foo.y;
217 try expect(four == 4);
218}
219
220const BitField1 = packed struct {
221 a: u3,
222 b: u3,
223 c: u2,
224};
225
226const bit_field_1 = BitField1{
227 .a = 1,
228 .b = 2,
229 .c = 3,
230};
231
232test "bit field access" {
233 var data = bit_field_1;
234 try expect(getA(&data) == 1);
235 try expect(getB(&data) == 2);
236 try expect(getC(&data) == 3);
237 comptime try expect(@sizeOf(BitField1) == 1);
238
239 data.b += 1;
240 try expect(data.b == 3);
241
242 data.a += 1;
243 try expect(data.a == 2);
244 try expect(data.b == 3);
245}
246
247fn getA(data: *const BitField1) u3 {
248 return data.a;
249}
250
251fn getB(data: *const BitField1) u3 {
252 return data.b;
253}
254
255fn getC(data: *const BitField1) u2 {
256 return data.c;
257}
258
259const Foo24Bits = packed struct {
260 field: u24,
261};
262const Foo96Bits = packed struct {
263 a: u24,
264 b: u24,
265 c: u24,
266 d: u24,
267};
268
269test "packed struct 24bits" {
270 comptime {
271 try expect(@sizeOf(Foo24Bits) == 4);
272 if (@sizeOf(usize) == 4) {
273 try expect(@sizeOf(Foo96Bits) == 12);
274 } else {
275 try expect(@sizeOf(Foo96Bits) == 16);
276 }
277 }
278
279 var value = Foo96Bits{
280 .a = 0,
281 .b = 0,
282 .c = 0,
283 .d = 0,
284 };
285 value.a += 1;
286 try expect(value.a == 1);
287 try expect(value.b == 0);
288 try expect(value.c == 0);
289 try expect(value.d == 0);
290
291 value.b += 1;
292 try expect(value.a == 1);
293 try expect(value.b == 1);
294 try expect(value.c == 0);
295 try expect(value.d == 0);
296
297 value.c += 1;
298 try expect(value.a == 1);
299 try expect(value.b == 1);
300 try expect(value.c == 1);
301 try expect(value.d == 0);
302
303 value.d += 1;
304 try expect(value.a == 1);
305 try expect(value.b == 1);
306 try expect(value.c == 1);
307 try expect(value.d == 1);
308}
309
310const Foo32Bits = packed struct {
311 field: u24,
312 pad: u8,
313};
314
315const FooArray24Bits = packed struct {
316 a: u16,
317 b: [2]Foo32Bits,
318 c: u16,
319};
320
321// TODO revisit this test when doing https://github.com/ziglang/zig/issues/1512
322test "packed array 24bits" {
323 comptime {
324 try expect(@sizeOf([9]Foo32Bits) == 9 * 4);
325 try expect(@sizeOf(FooArray24Bits) == 2 + 2 * 4 + 2);
326 }
327
328 var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1);
329 bytes[bytes.len - 1] = 0xaa;
330 const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
331 try expect(ptr.a == 0);
332 try expect(ptr.b[0].field == 0);
333 try expect(ptr.b[1].field == 0);
334 try expect(ptr.c == 0);
335
336 ptr.a = maxInt(u16);
337 try expect(ptr.a == maxInt(u16));
338 try expect(ptr.b[0].field == 0);
339 try expect(ptr.b[1].field == 0);
340 try expect(ptr.c == 0);
341
342 ptr.b[0].field = maxInt(u24);
343 try expect(ptr.a == maxInt(u16));
344 try expect(ptr.b[0].field == maxInt(u24));
345 try expect(ptr.b[1].field == 0);
346 try expect(ptr.c == 0);
347
348 ptr.b[1].field = maxInt(u24);
349 try expect(ptr.a == maxInt(u16));
350 try expect(ptr.b[0].field == maxInt(u24));
351 try expect(ptr.b[1].field == maxInt(u24));
352 try expect(ptr.c == 0);
353
354 ptr.c = maxInt(u16);
355 try expect(ptr.a == maxInt(u16));
356 try expect(ptr.b[0].field == maxInt(u24));
357 try expect(ptr.b[1].field == maxInt(u24));
358 try expect(ptr.c == maxInt(u16));
359
360 try expect(bytes[bytes.len - 1] == 0xaa);
361}
362
363const FooStructAligned = packed struct {
364 a: u8,
365 b: u8,
366};
367
368const FooArrayOfAligned = packed struct {
369 a: [2]FooStructAligned,
370};
371
372test "aligned array of packed struct" {
373 comptime {
374 try expect(@sizeOf(FooStructAligned) == 2);
375 try expect(@sizeOf(FooArrayOfAligned) == 2 * 2);
376 }
377
378 var bytes = [_]u8{0xbb} ** @sizeOf(FooArrayOfAligned);
379 const ptr = &std.mem.bytesAsSlice(FooArrayOfAligned, bytes[0..])[0];
380
381 try expect(ptr.a[0].a == 0xbb);
382 try expect(ptr.a[0].b == 0xbb);
383 try expect(ptr.a[1].a == 0xbb);
384 try expect(ptr.a[1].b == 0xbb);
385}
386
387test "runtime struct initialization of bitfield" {
388 const s1 = Nibbles{
389 .x = x1,
390 .y = x1,
391 };
392 const s2 = Nibbles{
393 .x = @intCast(u4, x2),
394 .y = @intCast(u4, x2),
395 };
396
397 try expect(s1.x == x1);
398 try expect(s1.y == x1);
399 try expect(s2.x == @intCast(u4, x2));
400 try expect(s2.y == @intCast(u4, x2));
401}
402
403var x1 = @as(u4, 1);
404var x2 = @as(u8, 2);
405
406const Nibbles = packed struct {
407 x: u4,
408 y: u4,
409};
410
411const Bitfields = packed struct {
412 f1: u16,
413 f2: u16,
414 f3: u8,
415 f4: u8,
416 f5: u4,
417 f6: u4,
418 f7: u8,
419};
420
421test "native bit field understands endianness" {
422 var all: u64 = if (native_endian != .Little)
423 0x1111222233445677
424 else
425 0x7765443322221111;
426 var bytes: [8]u8 = undefined;
427 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
428 var bitfields = @ptrCast(*Bitfields, &bytes).*;
429
430 try expect(bitfields.f1 == 0x1111);
431 try expect(bitfields.f2 == 0x2222);
432 try expect(bitfields.f3 == 0x33);
433 try expect(bitfields.f4 == 0x44);
434 try expect(bitfields.f5 == 0x5);
435 try expect(bitfields.f6 == 0x6);
436 try expect(bitfields.f7 == 0x77);
437}
438
439test "align 1 field before self referential align 8 field as slice return type" {
440 const result = alloc(Expr);
441 try expect(result.len == 0);
442}
443
444const Expr = union(enum) {
445 Literal: u8,
446 Question: *Expr,
447};
448
449fn alloc(comptime T: type) []T {
450 return &[_]T{};
451}
452
453test "call method with mutable reference to struct with no fields" {
454 const S = struct {
455 fn doC(s: *const @This()) bool {
456 _ = s;
457 return true;
458 }
459 fn do(s: *@This()) bool {
460 _ = s;
461 return true;
462 }
463 };
464
465 var s = S{};
466 try expect(S.doC(&s));
467 try expect(s.doC());
468 try expect(S.do(&s));
469 try expect(s.do());
470}
471
472test "implicit cast packed struct field to const ptr" {
473 const LevelUpMove = packed struct {
474 move_id: u9,
475 level: u7,
476
477 fn toInt(value: u7) u7 {
478 return value;
479 }
480 };
481
482 var lup: LevelUpMove = undefined;
483 lup.level = 12;
484 const res = LevelUpMove.toInt(lup.level);
485 try expect(res == 12);
486}
487
488test "pointer to packed struct member in a stack variable" {
489 const S = packed struct {
490 a: u2,
491 b: u2,
492 };
493
494 var s = S{ .a = 2, .b = 0 };
495 var b_ptr = &s.b;
496 try expect(s.b == 0);
497 b_ptr.* = 2;
498 try expect(s.b == 2);
499}
500
501test "non-byte-aligned array inside packed struct" {
502 const Foo = packed struct {
503 a: bool,
504 b: [0x16]u8,
505 };
506 const S = struct {
507 fn bar(slice: []const u8) !void {
508 try expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu");
509 }
510 fn doTheTest() !void {
511 var foo = Foo{
512 .a = true,
513 .b = "abcdefghijklmnopqurstu".*,
514 };
515 const value = foo.b;
516 try bar(&value);
517 }
518 };
519 try S.doTheTest();
520 comptime try S.doTheTest();
521}
522
523test "packed struct with u0 field access" {
524 const S = packed struct {
525 f0: u0,
526 };
527 var s = S{ .f0 = 0 };
528 comptime try expect(s.f0 == 0);
529}
530
531const S0 = struct {
532 bar: S1,
533
534 pub const S1 = struct {
535 value: u8,
536 };
537
538 fn init() @This() {
539 return S0{ .bar = S1{ .value = 123 } };
540 }
541};
542
543var g_foo: S0 = S0.init();
544
545test "access to global struct fields" {
546 g_foo.bar.value = 42;
547 try expect(g_foo.bar.value == 42);
548}
549
550test "packed struct with fp fields" {
551 const S = packed struct {
552 data: [3]f32,
553
554 pub fn frob(self: *@This()) void {
555 self.data[0] += self.data[1] + self.data[2];
556 self.data[1] += self.data[0] + self.data[2];
557 self.data[2] += self.data[0] + self.data[1];
558 }
559 };
560
561 var s: S = undefined;
562 s.data[0] = 1.0;
563 s.data[1] = 2.0;
564 s.data[2] = 3.0;
565 s.frob();
566 try expectEqual(@as(f32, 6.0), s.data[0]);
567 try expectEqual(@as(f32, 11.0), s.data[1]);
568 try expectEqual(@as(f32, 20.0), s.data[2]);
569}
570
571test "use within struct scope" {
572 const S = struct {
573 usingnamespace struct {
574 pub fn inner() i32 {
575 return 42;
576 }
577 };
578 };
579 try expectEqual(@as(i32, 42), S.inner());
580}
581
582test "default struct initialization fields" {
583 const S = struct {
584 a: i32 = 1234,
585 b: i32,
586 };
587 const x = S{
588 .b = 5,
589 };
590 var five: i32 = 5;
591 const y = S{
592 .b = five,
593 };
594 if (x.a + x.b != 1239) {
595 @compileError("it should be comptime known");
596 }
597 try expectEqual(y, x);
598 try expectEqual(1239, x.a + x.b);
599}
600
601test "fn with C calling convention returns struct by value" {
602 const S = struct {
603 fn entry() !void {
604 var x = makeBar(10);
605 try expectEqual(@as(i32, 10), x.handle);
606 }
607
608 const ExternBar = extern struct {
609 handle: i32,
610 };
611
612 fn makeBar(t: i32) callconv(.C) ExternBar {
613 return ExternBar{
614 .handle = t,
615 };
616 }
617 };
618 try S.entry();
619 comptime try S.entry();
620}
621
622test "for loop over pointers to struct, getting field from struct pointer" {
623 const S = struct {
624 const Foo = struct {
625 name: []const u8,
626 };
627
628 var ok = true;
629
630 fn eql(a: []const u8) bool {
631 _ = a;
632 return true;
633 }
634
635 const ArrayList = struct {
636 fn toSlice(self: *ArrayList) []*Foo {
637 _ = self;
638 return @as([*]*Foo, undefined)[0..0];
639 }
640 };
641
642 fn doTheTest() !void {
643 var objects: ArrayList = undefined;
644
645 for (objects.toSlice()) |obj| {
646 if (eql(obj.name)) {
647 ok = false;
648 }
649 }
650
651 try expect(ok);
652 }
653 };
654 try S.doTheTest();
655}
656
657test "zero-bit field in packed struct" {
658 const S = packed struct {
659 x: u10,
660 y: void,
661 };
662 var x: S = undefined;
663 _ = x;
664}
665
666test "struct field init with catch" {
667 const S = struct {
668 fn doTheTest() !void {
669 var x: anyerror!isize = 1;
670 var req = Foo{
671 .field = x catch undefined,
672 };
673 try expect(req.field == 1);
674 }
675
676 pub const Foo = extern struct {
677 field: isize,
678 };
679 };
680 try S.doTheTest();
681 comptime try S.doTheTest();
682}
683
684test "packed struct with non-ABI-aligned field" {
685 const S = packed struct {
686 x: u9,
687 y: u183,
688 };
689 var s: S = undefined;
690 s.x = 1;
691 s.y = 42;
692 try expect(s.x == 1);
693 try expect(s.y == 42);
694}
695
696test "non-packed struct with u128 entry in union" {
697 const U = union(enum) {
698 Num: u128,
699 Void,
700 };
701
702 const S = struct {
703 f1: U,
704 f2: U,
705 };
706
707 var sx: S = undefined;
708 var s = &sx;
709 try std.testing.expect(@ptrToInt(&s.f2) - @ptrToInt(&s.f1) == @offsetOf(S, "f2"));
710 var v2 = U{ .Num = 123 };
711 s.f2 = v2;
712 try std.testing.expect(s.f2.Num == 123);
713}
714
715test "packed struct field passed to generic function" {
716 const S = struct {
717 const P = packed struct {
718 b: u5,
719 g: u5,
720 r: u5,
721 a: u1,
722 };
723
724 fn genericReadPackedField(ptr: anytype) u5 {
725 return ptr.*;
726 }
727 };
728
729 var p: S.P = undefined;
730 p.b = 29;
731 var loaded = S.genericReadPackedField(&p.b);
732 try expect(loaded == 29);
733}
734
735test "anonymous struct literal syntax" {
736 const S = struct {
737 const Point = struct {
738 x: i32,
739 y: i32,
740 };
741
742 fn doTheTest() !void {
743 var p: Point = .{
744 .x = 1,
745 .y = 2,
746 };
747 try expect(p.x == 1);
748 try expect(p.y == 2);
749 }
750 };
751 try S.doTheTest();
752 comptime try S.doTheTest();
753}
754
755test "fully anonymous struct" {
756 const S = struct {
757 fn doTheTest() !void {
758 try dump(.{
759 .int = @as(u32, 1234),
760 .float = @as(f64, 12.34),
761 .b = true,
762 .s = "hi",
763 });
764 }
765 fn dump(args: anytype) !void {
766 try expect(args.int == 1234);
767 try expect(args.float == 12.34);
768 try expect(args.b);
769 try expect(args.s[0] == 'h');
770 try expect(args.s[1] == 'i');
771 }
772 };
773 try S.doTheTest();
774 comptime try S.doTheTest();
775}
776
777test "fully anonymous list literal" {
778 const S = struct {
779 fn doTheTest() !void {
780 try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" });
781 }
782 fn dump(args: anytype) !void {
783 try expect(args.@"0" == 1234);
784 try expect(args.@"1" == 12.34);
785 try expect(args.@"2");
786 try expect(args.@"3"[0] == 'h');
787 try expect(args.@"3"[1] == 'i');
788 }
789 };
790 try S.doTheTest();
791 comptime try S.doTheTest();
792}
793
794test "anonymous struct literal assigned to variable" {
795 var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) };
796 try expect(vec.@"0" == 22);
797 try expect(vec.@"1" == 55);
798 try expect(vec.@"2" == 99);
799}
800
801test "struct with var field" {
802 const Point = struct {
803 x: anytype,
804 y: anytype,
805 };
806 const pt = Point{
807 .x = 1,
808 .y = 2,
809 };
810 try expect(pt.x == 1);
811 try expect(pt.y == 2);
812}
813
814test "comptime struct field" {
815 const T = struct {
816 a: i32,
817 comptime b: i32 = 1234,
818 };
819
820 var foo: T = undefined;
821 comptime try expect(foo.b == 1234);
822}
823
824test "anon struct literal field value initialized with fn call" {
825 const S = struct {
826 fn doTheTest() !void {
827 var x = .{foo()};
828 try expectEqualSlices(u8, x[0], "hi");
829 }
830 fn foo() []const u8 {
831 return "hi";
832 }
833 };
834 try S.doTheTest();
835 comptime try S.doTheTest();
836}
837
838test "self-referencing struct via array member" {
839 const T = struct {
840 children: [1]*@This(),
841 };
842 var x: T = undefined;
843 x = T{ .children = .{&x} };
844 try expect(x.children[0] == &x);
845}
846
847test "struct with union field" {
848 const Value = struct {
849 ref: u32 = 2,
850 kind: union(enum) {
851 None: usize,
852 Bool: bool,
853 },
854 };
855
856 var True = Value{
857 .kind = .{ .Bool = true },
858 };
859 try expectEqual(@as(u32, 2), True.ref);
860 try expectEqual(true, True.kind.Bool);
861}
862
863test "type coercion of anon struct literal to struct" {
864 const S = struct {
865 const S2 = struct {
866 A: u32,
867 B: []const u8,
868 C: void,
869 D: Foo = .{},
870 };
871
872 const Foo = struct {
873 field: i32 = 1234,
874 };
875
876 fn doTheTest() !void {
877 var y: u32 = 42;
878 const t0 = .{ .A = 123, .B = "foo", .C = {} };
879 const t1 = .{ .A = y, .B = "foo", .C = {} };
880 const y0: S2 = t0;
881 var y1: S2 = t1;
882 try expect(y0.A == 123);
883 try expect(std.mem.eql(u8, y0.B, "foo"));
884 try expect(y0.C == {});
885 try expect(y0.D.field == 1234);
886 try expect(y1.A == y);
887 try expect(std.mem.eql(u8, y1.B, "foo"));
888 try expect(y1.C == {});
889 try expect(y1.D.field == 1234);
890 }
891 };
892 try S.doTheTest();
893 comptime try S.doTheTest();
894}
895
896test "type coercion of pointer to anon struct literal to pointer to struct" {
897 const S = struct {
898 const S2 = struct {
899 A: u32,
900 B: []const u8,
901 C: void,
902 D: Foo = .{},
903 };
904
905 const Foo = struct {
906 field: i32 = 1234,
907 };
90827
909 fn doTheTest() !void {28test "return empty struct instance" {
910 var y: u32 = 42;29 _ = returnEmptyStructInstance();
911 const t0 = &.{ .A = 123, .B = "foo", .C = {} };
912 const t1 = &.{ .A = y, .B = "foo", .C = {} };
913 const y0: *const S2 = t0;
914 var y1: *const S2 = t1;
915 try expect(y0.A == 123);
916 try expect(std.mem.eql(u8, y0.B, "foo"));
917 try expect(y0.C == {});
918 try expect(y0.D.field == 1234);
919 try expect(y1.A == y);
920 try expect(std.mem.eql(u8, y1.B, "foo"));
921 try expect(y1.C == {});
922 try expect(y1.D.field == 1234);
923 }
924 };
925 try S.doTheTest();
926 comptime try S.doTheTest();
927}30}
92831fn returnEmptyStructInstance() StructWithNoFields {
929test "packed struct with undefined initializers" {32 return empty_global_instance;
930 const S = struct {
931 const P = packed struct {
932 a: u3,
933 _a: u3 = undefined,
934 b: u3,
935 _b: u3 = undefined,
936 c: u3,
937 _c: u3 = undefined,
938 };
939
940 fn doTheTest() !void {
941 var p: P = undefined;
942 p = P{ .a = 2, .b = 4, .c = 6 };
943 // Make sure the compiler doesn't touch the unprefixed fields.
944 // Use expect since i386-linux doesn't like expectEqual
945 try expect(p.a == 2);
946 try expect(p.b == 4);
947 try expect(p.c == 6);
948 }
949 };
950
951 try S.doTheTest();
952 comptime try S.doTheTest();
953}33}
test/behavior/struct_stage1.zig created+928
...@@ -0,0 +1,928 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const native_endian = builtin.target.cpu.arch.endian();
4const expect = std.testing.expect;
5const expectEqual = std.testing.expectEqual;
6const expectEqualSlices = std.testing.expectEqualSlices;
7const maxInt = std.math.maxInt;
8top_level_field: i32,
9
10test "top level fields" {
11 var instance = @This(){
12 .top_level_field = 1234,
13 };
14 instance.top_level_field += 1;
15 try expectEqual(@as(i32, 1235), instance.top_level_field);
16}
17
18test "void struct fields" {
19 const foo = VoidStructFieldsFoo{
20 .a = void{},
21 .b = 1,
22 .c = void{},
23 };
24 try expect(foo.b == 1);
25 try expect(@sizeOf(VoidStructFieldsFoo) == 4);
26}
27const VoidStructFieldsFoo = struct {
28 a: void,
29 b: i32,
30 c: void,
31};
32
33test "structs" {
34 var foo: StructFoo = undefined;
35 @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));
36 foo.a += 1;
37 foo.b = foo.a == 1;
38 try testFoo(foo);
39 testMutation(&foo);
40 try expect(foo.c == 100);
41}
42const StructFoo = struct {
43 a: i32,
44 b: bool,
45 c: f32,
46};
47fn testFoo(foo: StructFoo) !void {
48 try expect(foo.b);
49}
50fn testMutation(foo: *StructFoo) void {
51 foo.c = 100;
52}
53
54const Node = struct {
55 val: Val,
56 next: *Node,
57};
58
59const Val = struct {
60 x: i32,
61};
62
63test "struct point to self" {
64 var root: Node = undefined;
65 root.val.x = 1;
66
67 var node: Node = undefined;
68 node.next = &root;
69 node.val.x = 2;
70
71 root.next = &node;
72
73 try expect(node.next.next.next.val.x == 1);
74}
75
76test "struct byval assign" {
77 var foo1: StructFoo = undefined;
78 var foo2: StructFoo = undefined;
79
80 foo1.a = 1234;
81 foo2.a = 0;
82 try expect(foo2.a == 0);
83 foo2 = foo1;
84 try expect(foo2.a == 1234);
85}
86
87fn structInitializer() void {
88 const val = Val{ .x = 42 };
89 try expect(val.x == 42);
90}
91
92test "fn call of struct field" {
93 const Foo = struct {
94 ptr: fn () i32,
95 };
96 const S = struct {
97 fn aFunc() i32 {
98 return 13;
99 }
100
101 fn callStructField(foo: Foo) i32 {
102 return foo.ptr();
103 }
104 };
105
106 try expect(S.callStructField(Foo{ .ptr = S.aFunc }) == 13);
107}
108
109test "store member function in variable" {
110 const instance = MemberFnTestFoo{ .x = 1234 };
111 const memberFn = MemberFnTestFoo.member;
112 const result = memberFn(instance);
113 try expect(result == 1234);
114}
115const MemberFnTestFoo = struct {
116 x: i32,
117 fn member(foo: MemberFnTestFoo) i32 {
118 return foo.x;
119 }
120};
121
122test "call member function directly" {
123 const instance = MemberFnTestFoo{ .x = 1234 };
124 const result = MemberFnTestFoo.member(instance);
125 try expect(result == 1234);
126}
127
128test "member functions" {
129 const r = MemberFnRand{ .seed = 1234 };
130 try expect(r.getSeed() == 1234);
131}
132const MemberFnRand = struct {
133 seed: u32,
134 pub fn getSeed(r: *const MemberFnRand) u32 {
135 return r.seed;
136 }
137};
138
139test "return struct byval from function" {
140 const bar = makeBar2(1234, 5678);
141 try expect(bar.y == 5678);
142}
143const Bar = struct {
144 x: i32,
145 y: i32,
146};
147fn makeBar2(x: i32, y: i32) Bar {
148 return Bar{
149 .x = x,
150 .y = y,
151 };
152}
153
154test "empty struct method call" {
155 const es = EmptyStruct{};
156 try expect(es.method() == 1234);
157}
158const EmptyStruct = struct {
159 fn method(es: *const EmptyStruct) i32 {
160 _ = es;
161 return 1234;
162 }
163};
164
165test "return empty struct from fn" {
166 _ = testReturnEmptyStructFromFn();
167}
168const EmptyStruct2 = struct {};
169fn testReturnEmptyStructFromFn() EmptyStruct2 {
170 return EmptyStruct2{};
171}
172
173test "pass slice of empty struct to fn" {
174 try expect(testPassSliceOfEmptyStructToFn(&[_]EmptyStruct2{EmptyStruct2{}}) == 1);
175}
176fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize {
177 return slice.len;
178}
179
180const APackedStruct = packed struct {
181 x: u8,
182 y: u8,
183};
184
185test "packed struct" {
186 var foo = APackedStruct{
187 .x = 1,
188 .y = 2,
189 };
190 foo.y += 1;
191 const four = foo.x + foo.y;
192 try expect(four == 4);
193}
194
195const BitField1 = packed struct {
196 a: u3,
197 b: u3,
198 c: u2,
199};
200
201const bit_field_1 = BitField1{
202 .a = 1,
203 .b = 2,
204 .c = 3,
205};
206
207test "bit field access" {
208 var data = bit_field_1;
209 try expect(getA(&data) == 1);
210 try expect(getB(&data) == 2);
211 try expect(getC(&data) == 3);
212 comptime try expect(@sizeOf(BitField1) == 1);
213
214 data.b += 1;
215 try expect(data.b == 3);
216
217 data.a += 1;
218 try expect(data.a == 2);
219 try expect(data.b == 3);
220}
221
222fn getA(data: *const BitField1) u3 {
223 return data.a;
224}
225
226fn getB(data: *const BitField1) u3 {
227 return data.b;
228}
229
230fn getC(data: *const BitField1) u2 {
231 return data.c;
232}
233
234const Foo24Bits = packed struct {
235 field: u24,
236};
237const Foo96Bits = packed struct {
238 a: u24,
239 b: u24,
240 c: u24,
241 d: u24,
242};
243
244test "packed struct 24bits" {
245 comptime {
246 try expect(@sizeOf(Foo24Bits) == 4);
247 if (@sizeOf(usize) == 4) {
248 try expect(@sizeOf(Foo96Bits) == 12);
249 } else {
250 try expect(@sizeOf(Foo96Bits) == 16);
251 }
252 }
253
254 var value = Foo96Bits{
255 .a = 0,
256 .b = 0,
257 .c = 0,
258 .d = 0,
259 };
260 value.a += 1;
261 try expect(value.a == 1);
262 try expect(value.b == 0);
263 try expect(value.c == 0);
264 try expect(value.d == 0);
265
266 value.b += 1;
267 try expect(value.a == 1);
268 try expect(value.b == 1);
269 try expect(value.c == 0);
270 try expect(value.d == 0);
271
272 value.c += 1;
273 try expect(value.a == 1);
274 try expect(value.b == 1);
275 try expect(value.c == 1);
276 try expect(value.d == 0);
277
278 value.d += 1;
279 try expect(value.a == 1);
280 try expect(value.b == 1);
281 try expect(value.c == 1);
282 try expect(value.d == 1);
283}
284
285const Foo32Bits = packed struct {
286 field: u24,
287 pad: u8,
288};
289
290const FooArray24Bits = packed struct {
291 a: u16,
292 b: [2]Foo32Bits,
293 c: u16,
294};
295
296// TODO revisit this test when doing https://github.com/ziglang/zig/issues/1512
297test "packed array 24bits" {
298 comptime {
299 try expect(@sizeOf([9]Foo32Bits) == 9 * 4);
300 try expect(@sizeOf(FooArray24Bits) == 2 + 2 * 4 + 2);
301 }
302
303 var bytes = [_]u8{0} ** (@sizeOf(FooArray24Bits) + 1);
304 bytes[bytes.len - 1] = 0xaa;
305 const ptr = &std.mem.bytesAsSlice(FooArray24Bits, bytes[0 .. bytes.len - 1])[0];
306 try expect(ptr.a == 0);
307 try expect(ptr.b[0].field == 0);
308 try expect(ptr.b[1].field == 0);
309 try expect(ptr.c == 0);
310
311 ptr.a = maxInt(u16);
312 try expect(ptr.a == maxInt(u16));
313 try expect(ptr.b[0].field == 0);
314 try expect(ptr.b[1].field == 0);
315 try expect(ptr.c == 0);
316
317 ptr.b[0].field = maxInt(u24);
318 try expect(ptr.a == maxInt(u16));
319 try expect(ptr.b[0].field == maxInt(u24));
320 try expect(ptr.b[1].field == 0);
321 try expect(ptr.c == 0);
322
323 ptr.b[1].field = maxInt(u24);
324 try expect(ptr.a == maxInt(u16));
325 try expect(ptr.b[0].field == maxInt(u24));
326 try expect(ptr.b[1].field == maxInt(u24));
327 try expect(ptr.c == 0);
328
329 ptr.c = maxInt(u16);
330 try expect(ptr.a == maxInt(u16));
331 try expect(ptr.b[0].field == maxInt(u24));
332 try expect(ptr.b[1].field == maxInt(u24));
333 try expect(ptr.c == maxInt(u16));
334
335 try expect(bytes[bytes.len - 1] == 0xaa);
336}
337
338const FooStructAligned = packed struct {
339 a: u8,
340 b: u8,
341};
342
343const FooArrayOfAligned = packed struct {
344 a: [2]FooStructAligned,
345};
346
347test "aligned array of packed struct" {
348 comptime {
349 try expect(@sizeOf(FooStructAligned) == 2);
350 try expect(@sizeOf(FooArrayOfAligned) == 2 * 2);
351 }
352
353 var bytes = [_]u8{0xbb} ** @sizeOf(FooArrayOfAligned);
354 const ptr = &std.mem.bytesAsSlice(FooArrayOfAligned, bytes[0..])[0];
355
356 try expect(ptr.a[0].a == 0xbb);
357 try expect(ptr.a[0].b == 0xbb);
358 try expect(ptr.a[1].a == 0xbb);
359 try expect(ptr.a[1].b == 0xbb);
360}
361
362test "runtime struct initialization of bitfield" {
363 const s1 = Nibbles{
364 .x = x1,
365 .y = x1,
366 };
367 const s2 = Nibbles{
368 .x = @intCast(u4, x2),
369 .y = @intCast(u4, x2),
370 };
371
372 try expect(s1.x == x1);
373 try expect(s1.y == x1);
374 try expect(s2.x == @intCast(u4, x2));
375 try expect(s2.y == @intCast(u4, x2));
376}
377
378var x1 = @as(u4, 1);
379var x2 = @as(u8, 2);
380
381const Nibbles = packed struct {
382 x: u4,
383 y: u4,
384};
385
386const Bitfields = packed struct {
387 f1: u16,
388 f2: u16,
389 f3: u8,
390 f4: u8,
391 f5: u4,
392 f6: u4,
393 f7: u8,
394};
395
396test "native bit field understands endianness" {
397 var all: u64 = if (native_endian != .Little)
398 0x1111222233445677
399 else
400 0x7765443322221111;
401 var bytes: [8]u8 = undefined;
402 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);
403 var bitfields = @ptrCast(*Bitfields, &bytes).*;
404
405 try expect(bitfields.f1 == 0x1111);
406 try expect(bitfields.f2 == 0x2222);
407 try expect(bitfields.f3 == 0x33);
408 try expect(bitfields.f4 == 0x44);
409 try expect(bitfields.f5 == 0x5);
410 try expect(bitfields.f6 == 0x6);
411 try expect(bitfields.f7 == 0x77);
412}
413
414test "align 1 field before self referential align 8 field as slice return type" {
415 const result = alloc(Expr);
416 try expect(result.len == 0);
417}
418
419const Expr = union(enum) {
420 Literal: u8,
421 Question: *Expr,
422};
423
424fn alloc(comptime T: type) []T {
425 return &[_]T{};
426}
427
428test "call method with mutable reference to struct with no fields" {
429 const S = struct {
430 fn doC(s: *const @This()) bool {
431 _ = s;
432 return true;
433 }
434 fn do(s: *@This()) bool {
435 _ = s;
436 return true;
437 }
438 };
439
440 var s = S{};
441 try expect(S.doC(&s));
442 try expect(s.doC());
443 try expect(S.do(&s));
444 try expect(s.do());
445}
446
447test "implicit cast packed struct field to const ptr" {
448 const LevelUpMove = packed struct {
449 move_id: u9,
450 level: u7,
451
452 fn toInt(value: u7) u7 {
453 return value;
454 }
455 };
456
457 var lup: LevelUpMove = undefined;
458 lup.level = 12;
459 const res = LevelUpMove.toInt(lup.level);
460 try expect(res == 12);
461}
462
463test "pointer to packed struct member in a stack variable" {
464 const S = packed struct {
465 a: u2,
466 b: u2,
467 };
468
469 var s = S{ .a = 2, .b = 0 };
470 var b_ptr = &s.b;
471 try expect(s.b == 0);
472 b_ptr.* = 2;
473 try expect(s.b == 2);
474}
475
476test "non-byte-aligned array inside packed struct" {
477 const Foo = packed struct {
478 a: bool,
479 b: [0x16]u8,
480 };
481 const S = struct {
482 fn bar(slice: []const u8) !void {
483 try expectEqualSlices(u8, slice, "abcdefghijklmnopqurstu");
484 }
485 fn doTheTest() !void {
486 var foo = Foo{
487 .a = true,
488 .b = "abcdefghijklmnopqurstu".*,
489 };
490 const value = foo.b;
491 try bar(&value);
492 }
493 };
494 try S.doTheTest();
495 comptime try S.doTheTest();
496}
497
498test "packed struct with u0 field access" {
499 const S = packed struct {
500 f0: u0,
501 };
502 var s = S{ .f0 = 0 };
503 comptime try expect(s.f0 == 0);
504}
505
506const S0 = struct {
507 bar: S1,
508
509 pub const S1 = struct {
510 value: u8,
511 };
512
513 fn init() @This() {
514 return S0{ .bar = S1{ .value = 123 } };
515 }
516};
517
518var g_foo: S0 = S0.init();
519
520test "access to global struct fields" {
521 g_foo.bar.value = 42;
522 try expect(g_foo.bar.value == 42);
523}
524
525test "packed struct with fp fields" {
526 const S = packed struct {
527 data: [3]f32,
528
529 pub fn frob(self: *@This()) void {
530 self.data[0] += self.data[1] + self.data[2];
531 self.data[1] += self.data[0] + self.data[2];
532 self.data[2] += self.data[0] + self.data[1];
533 }
534 };
535
536 var s: S = undefined;
537 s.data[0] = 1.0;
538 s.data[1] = 2.0;
539 s.data[2] = 3.0;
540 s.frob();
541 try expectEqual(@as(f32, 6.0), s.data[0]);
542 try expectEqual(@as(f32, 11.0), s.data[1]);
543 try expectEqual(@as(f32, 20.0), s.data[2]);
544}
545
546test "use within struct scope" {
547 const S = struct {
548 usingnamespace struct {
549 pub fn inner() i32 {
550 return 42;
551 }
552 };
553 };
554 try expectEqual(@as(i32, 42), S.inner());
555}
556
557test "default struct initialization fields" {
558 const S = struct {
559 a: i32 = 1234,
560 b: i32,
561 };
562 const x = S{
563 .b = 5,
564 };
565 var five: i32 = 5;
566 const y = S{
567 .b = five,
568 };
569 if (x.a + x.b != 1239) {
570 @compileError("it should be comptime known");
571 }
572 try expectEqual(y, x);
573 try expectEqual(1239, x.a + x.b);
574}
575
576test "fn with C calling convention returns struct by value" {
577 const S = struct {
578 fn entry() !void {
579 var x = makeBar(10);
580 try expectEqual(@as(i32, 10), x.handle);
581 }
582
583 const ExternBar = extern struct {
584 handle: i32,
585 };
586
587 fn makeBar(t: i32) callconv(.C) ExternBar {
588 return ExternBar{
589 .handle = t,
590 };
591 }
592 };
593 try S.entry();
594 comptime try S.entry();
595}
596
597test "for loop over pointers to struct, getting field from struct pointer" {
598 const S = struct {
599 const Foo = struct {
600 name: []const u8,
601 };
602
603 var ok = true;
604
605 fn eql(a: []const u8) bool {
606 _ = a;
607 return true;
608 }
609
610 const ArrayList = struct {
611 fn toSlice(self: *ArrayList) []*Foo {
612 _ = self;
613 return @as([*]*Foo, undefined)[0..0];
614 }
615 };
616
617 fn doTheTest() !void {
618 var objects: ArrayList = undefined;
619
620 for (objects.toSlice()) |obj| {
621 if (eql(obj.name)) {
622 ok = false;
623 }
624 }
625
626 try expect(ok);
627 }
628 };
629 try S.doTheTest();
630}
631
632test "zero-bit field in packed struct" {
633 const S = packed struct {
634 x: u10,
635 y: void,
636 };
637 var x: S = undefined;
638 _ = x;
639}
640
641test "struct field init with catch" {
642 const S = struct {
643 fn doTheTest() !void {
644 var x: anyerror!isize = 1;
645 var req = Foo{
646 .field = x catch undefined,
647 };
648 try expect(req.field == 1);
649 }
650
651 pub const Foo = extern struct {
652 field: isize,
653 };
654 };
655 try S.doTheTest();
656 comptime try S.doTheTest();
657}
658
659test "packed struct with non-ABI-aligned field" {
660 const S = packed struct {
661 x: u9,
662 y: u183,
663 };
664 var s: S = undefined;
665 s.x = 1;
666 s.y = 42;
667 try expect(s.x == 1);
668 try expect(s.y == 42);
669}
670
671test "non-packed struct with u128 entry in union" {
672 const U = union(enum) {
673 Num: u128,
674 Void,
675 };
676
677 const S = struct {
678 f1: U,
679 f2: U,
680 };
681
682 var sx: S = undefined;
683 var s = &sx;
684 try std.testing.expect(@ptrToInt(&s.f2) - @ptrToInt(&s.f1) == @offsetOf(S, "f2"));
685 var v2 = U{ .Num = 123 };
686 s.f2 = v2;
687 try std.testing.expect(s.f2.Num == 123);
688}
689
690test "packed struct field passed to generic function" {
691 const S = struct {
692 const P = packed struct {
693 b: u5,
694 g: u5,
695 r: u5,
696 a: u1,
697 };
698
699 fn genericReadPackedField(ptr: anytype) u5 {
700 return ptr.*;
701 }
702 };
703
704 var p: S.P = undefined;
705 p.b = 29;
706 var loaded = S.genericReadPackedField(&p.b);
707 try expect(loaded == 29);
708}
709
710test "anonymous struct literal syntax" {
711 const S = struct {
712 const Point = struct {
713 x: i32,
714 y: i32,
715 };
716
717 fn doTheTest() !void {
718 var p: Point = .{
719 .x = 1,
720 .y = 2,
721 };
722 try expect(p.x == 1);
723 try expect(p.y == 2);
724 }
725 };
726 try S.doTheTest();
727 comptime try S.doTheTest();
728}
729
730test "fully anonymous struct" {
731 const S = struct {
732 fn doTheTest() !void {
733 try dump(.{
734 .int = @as(u32, 1234),
735 .float = @as(f64, 12.34),
736 .b = true,
737 .s = "hi",
738 });
739 }
740 fn dump(args: anytype) !void {
741 try expect(args.int == 1234);
742 try expect(args.float == 12.34);
743 try expect(args.b);
744 try expect(args.s[0] == 'h');
745 try expect(args.s[1] == 'i');
746 }
747 };
748 try S.doTheTest();
749 comptime try S.doTheTest();
750}
751
752test "fully anonymous list literal" {
753 const S = struct {
754 fn doTheTest() !void {
755 try dump(.{ @as(u32, 1234), @as(f64, 12.34), true, "hi" });
756 }
757 fn dump(args: anytype) !void {
758 try expect(args.@"0" == 1234);
759 try expect(args.@"1" == 12.34);
760 try expect(args.@"2");
761 try expect(args.@"3"[0] == 'h');
762 try expect(args.@"3"[1] == 'i');
763 }
764 };
765 try S.doTheTest();
766 comptime try S.doTheTest();
767}
768
769test "anonymous struct literal assigned to variable" {
770 var vec = .{ @as(i32, 22), @as(i32, 55), @as(i32, 99) };
771 try expect(vec.@"0" == 22);
772 try expect(vec.@"1" == 55);
773 try expect(vec.@"2" == 99);
774}
775
776test "struct with var field" {
777 const Point = struct {
778 x: anytype,
779 y: anytype,
780 };
781 const pt = Point{
782 .x = 1,
783 .y = 2,
784 };
785 try expect(pt.x == 1);
786 try expect(pt.y == 2);
787}
788
789test "comptime struct field" {
790 const T = struct {
791 a: i32,
792 comptime b: i32 = 1234,
793 };
794
795 var foo: T = undefined;
796 comptime try expect(foo.b == 1234);
797}
798
799test "anon struct literal field value initialized with fn call" {
800 const S = struct {
801 fn doTheTest() !void {
802 var x = .{foo()};
803 try expectEqualSlices(u8, x[0], "hi");
804 }
805 fn foo() []const u8 {
806 return "hi";
807 }
808 };
809 try S.doTheTest();
810 comptime try S.doTheTest();
811}
812
813test "self-referencing struct via array member" {
814 const T = struct {
815 children: [1]*@This(),
816 };
817 var x: T = undefined;
818 x = T{ .children = .{&x} };
819 try expect(x.children[0] == &x);
820}
821
822test "struct with union field" {
823 const Value = struct {
824 ref: u32 = 2,
825 kind: union(enum) {
826 None: usize,
827 Bool: bool,
828 },
829 };
830
831 var True = Value{
832 .kind = .{ .Bool = true },
833 };
834 try expectEqual(@as(u32, 2), True.ref);
835 try expectEqual(true, True.kind.Bool);
836}
837
838test "type coercion of anon struct literal to struct" {
839 const S = struct {
840 const S2 = struct {
841 A: u32,
842 B: []const u8,
843 C: void,
844 D: Foo = .{},
845 };
846
847 const Foo = struct {
848 field: i32 = 1234,
849 };
850
851 fn doTheTest() !void {
852 var y: u32 = 42;
853 const t0 = .{ .A = 123, .B = "foo", .C = {} };
854 const t1 = .{ .A = y, .B = "foo", .C = {} };
855 const y0: S2 = t0;
856 var y1: S2 = t1;
857 try expect(y0.A == 123);
858 try expect(std.mem.eql(u8, y0.B, "foo"));
859 try expect(y0.C == {});
860 try expect(y0.D.field == 1234);
861 try expect(y1.A == y);
862 try expect(std.mem.eql(u8, y1.B, "foo"));
863 try expect(y1.C == {});
864 try expect(y1.D.field == 1234);
865 }
866 };
867 try S.doTheTest();
868 comptime try S.doTheTest();
869}
870
871test "type coercion of pointer to anon struct literal to pointer to struct" {
872 const S = struct {
873 const S2 = struct {
874 A: u32,
875 B: []const u8,
876 C: void,
877 D: Foo = .{},
878 };
879
880 const Foo = struct {
881 field: i32 = 1234,
882 };
883
884 fn doTheTest() !void {
885 var y: u32 = 42;
886 const t0 = &.{ .A = 123, .B = "foo", .C = {} };
887 const t1 = &.{ .A = y, .B = "foo", .C = {} };
888 const y0: *const S2 = t0;
889 var y1: *const S2 = t1;
890 try expect(y0.A == 123);
891 try expect(std.mem.eql(u8, y0.B, "foo"));
892 try expect(y0.C == {});
893 try expect(y0.D.field == 1234);
894 try expect(y1.A == y);
895 try expect(std.mem.eql(u8, y1.B, "foo"));
896 try expect(y1.C == {});
897 try expect(y1.D.field == 1234);
898 }
899 };
900 try S.doTheTest();
901 comptime try S.doTheTest();
902}
903
904test "packed struct with undefined initializers" {
905 const S = struct {
906 const P = packed struct {
907 a: u3,
908 _a: u3 = undefined,
909 b: u3,
910 _b: u3 = undefined,
911 c: u3,
912 _c: u3 = undefined,
913 };
914
915 fn doTheTest() !void {
916 var p: P = undefined;
917 p = P{ .a = 2, .b = 4, .c = 6 };
918 // Make sure the compiler doesn't touch the unprefixed fields.
919 // Use expect since i386-linux doesn't like expectEqual
920 try expect(p.a == 2);
921 try expect(p.b == 4);
922 try expect(p.c == 6);
923 }
924 };
925
926 try S.doTheTest();
927 comptime try S.doTheTest();
928}