authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-28 17:41:45-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-28 17:41:45-07:00
log98009a2f66de32d1ea4df41cc03d5ad3d723b3ed
tree6835afcef70cffd09159cd890b5ab1fc4104f139
parent5479c0f9ac7f7ed4808141ce518d3553240fd01b

C backend: implement trunc instruction

Note that there is not any test coverage yet for integer truncation involving non-power-of-two integers.

5 files changed, 462 insertions(+), 467 deletions(-)

src/codegen/c.zig+1-11
...@@ -1089,7 +1089,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1089,7 +1089,6 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1089 .call => try airCall(f, inst),1089 .call => try airCall(f, inst),
1090 .dbg_stmt => try airDbgStmt(f, inst),1090 .dbg_stmt => try airDbgStmt(f, inst),
1091 .intcast => try airIntCast(f, inst),1091 .intcast => try airIntCast(f, inst),
1092 .trunc => try airTrunc(f, inst),
1093 .bool_to_int => try airBoolToInt(f, inst),1092 .bool_to_int => try airBoolToInt(f, inst),
1094 .load => try airLoad(f, inst),1093 .load => try airLoad(f, inst),
1095 .ret => try airRet(f, inst),1094 .ret => try airRet(f, inst),
...@@ -1117,6 +1116,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO...@@ -1117,6 +1116,7 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
1117 .float_to_int,1116 .float_to_int,
1118 .fptrunc,1117 .fptrunc,
1119 .fpext,1118 .fpext,
1119 .trunc,
1120 => try airSimpleCast(f, inst),1120 => try airSimpleCast(f, inst),
11211121
1122 .ptrtoint => try airPtrToInt(f, inst),1122 .ptrtoint => try airPtrToInt(f, inst),
...@@ -1366,16 +1366,6 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -1366,16 +1366,6 @@ fn airIntCast(f: *Function, inst: Air.Inst.Index) !CValue {
1366 return local;1366 return local;
1367}1367}
13681368
1369fn airTrunc(f: *Function, inst: Air.Inst.Index) !CValue {
1370 if (f.liveness.isUnused(inst))
1371 return CValue.none;
1372
1373 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
1374 const operand = try f.resolveInst(ty_op.operand);
1375 _ = operand;
1376 return f.fail("TODO: C backend: airTrunc", .{});
1377}
1378
1379fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {1369fn airBoolToInt(f: *Function, inst: Air.Inst.Index) !CValue {
1380 if (f.liveness.isUnused(inst))1370 if (f.liveness.isUnused(inst))
1381 return CValue.none;1371 return CValue.none;
src/codegen/llvm.zig+1-2
...@@ -3153,8 +3153,7 @@ pub const FuncGen = struct {...@@ -3153,8 +3153,7 @@ pub const FuncGen = struct {
3153 }3153 }
31543154
3155 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {3155 fn airTrunc(self: *FuncGen, inst: Air.Inst.Index) !?*const llvm.Value {
3156 if (self.liveness.isUnused(inst))3156 if (self.liveness.isUnused(inst)) return null;
3157 return null;
31583157
3159 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3158 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
3160 const operand = try self.resolveInst(ty_op.operand);3159 const operand = try self.resolveInst(ty_op.operand);
test/behavior.zig+2-1
...@@ -2,6 +2,7 @@ const builtin = @import("builtin");...@@ -2,6 +2,7 @@ const builtin = @import("builtin");
22
3test {3test {
4 // Tests that pass for stage1, stage2, and the C backend.4 // Tests that pass for stage1, stage2, and the C backend.
5 _ = @import("behavior/basic.zig");
5 _ = @import("behavior/bool.zig");6 _ = @import("behavior/bool.zig");
6 _ = @import("behavior/if.zig");7 _ = @import("behavior/if.zig");
78
...@@ -10,7 +11,7 @@ test {...@@ -10,7 +11,7 @@ test {
10 _ = @import("behavior/align.zig");11 _ = @import("behavior/align.zig");
11 _ = @import("behavior/array.zig");12 _ = @import("behavior/array.zig");
12 _ = @import("behavior/atomics.zig");13 _ = @import("behavior/atomics.zig");
13 _ = @import("behavior/basic.zig");14 _ = @import("behavior/basic_llvm.zig");
14 _ = @import("behavior/bitcast.zig");15 _ = @import("behavior/bitcast.zig");
15 _ = @import("behavior/bugs/394.zig");16 _ = @import("behavior/bugs/394.zig");
16 _ = @import("behavior/bugs/624.zig");17 _ = @import("behavior/bugs/624.zig");
test/behavior/basic.zig-453
...@@ -21,456 +21,3 @@ test "truncate" {...@@ -21,456 +21,3 @@ test "truncate" {
21fn testTruncate(x: u32) u8 {21fn testTruncate(x: u32) u8 {
22 return @truncate(u8, x);22 return @truncate(u8, x);
23}23}
24
25const g1: i32 = 1233 + 1;
26var g2: i32 = 0;
27
28test "global variables" {
29 try expect(g2 == 0);
30 g2 = g1;
31 try expect(g2 == 1234);
32}
33
34test "comptime keyword on expressions" {
35 const x: i32 = comptime x: {
36 break :x 1 + 2 + 3;
37 };
38 try expect(x == comptime 6);
39}
40
41test "type equality" {
42 try expect(*const u8 != *u8);
43}
44
45test "pointer dereferencing" {
46 var x = @as(i32, 3);
47 const y = &x;
48
49 y.* += 1;
50
51 try expect(x == 4);
52 try expect(y.* == 4);
53}
54
55test "const expression eval handling of variables" {
56 var x = true;
57 while (x) {
58 x = false;
59 }
60}
61
62test "character literals" {
63 try expect('\'' == single_quote);
64}
65const single_quote = '\'';
66
67test "non const ptr to aliased type" {
68 const int = i32;
69 try expect(?*int == ?*i32);
70}
71
72test "cold function" {
73 thisIsAColdFn();
74 comptime thisIsAColdFn();
75}
76
77fn thisIsAColdFn() void {
78 @setCold(true);
79}
80
81test "unicode escape in character literal" {
82 var a: u24 = '\u{01f4a9}';
83 try expect(a == 128169);
84}
85
86test "unicode character in character literal" {
87 try expect('💩' == 128169);
88}
89
90fn first4KeysOfHomeRow() []const u8 {
91 return "aoeu";
92}
93
94test "return string from function" {
95 try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
96}
97
98test "hex escape" {
99 try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
100}
101
102test "multiline string" {
103 const s1 =
104 \\one
105 \\two)
106 \\three
107 ;
108 const s2 = "one\ntwo)\nthree";
109 try expect(mem.eql(u8, s1, s2));
110}
111
112test "multiline string comments at start" {
113 const s1 =
114 //\\one
115 \\two)
116 \\three
117 ;
118 const s2 = "two)\nthree";
119 try expect(mem.eql(u8, s1, s2));
120}
121
122test "multiline string comments at end" {
123 const s1 =
124 \\one
125 \\two)
126 //\\three
127 ;
128 const s2 = "one\ntwo)";
129 try expect(mem.eql(u8, s1, s2));
130}
131
132test "multiline string comments in middle" {
133 const s1 =
134 \\one
135 //\\two)
136 \\three
137 ;
138 const s2 = "one\nthree";
139 try expect(mem.eql(u8, s1, s2));
140}
141
142test "multiline string comments at multiple places" {
143 const s1 =
144 \\one
145 //\\two
146 \\three
147 //\\four
148 \\five
149 ;
150 const s2 = "one\nthree\nfive";
151 try expect(mem.eql(u8, s1, s2));
152}
153
154test "call result of if else expression" {
155 try expect(mem.eql(u8, f2(true), "a"));
156 try expect(mem.eql(u8, f2(false), "b"));
157}
158fn f2(x: bool) []const u8 {
159 return (if (x) fA else fB)();
160}
161fn fA() []const u8 {
162 return "a";
163}
164fn fB() []const u8 {
165 return "b";
166}
167
168test "string concatenation" {
169 try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
170}
171
172test "array mult operator" {
173 try expect(mem.eql(u8, "ab" ** 5, "ababababab"));
174}
175
176test "memcpy and memset intrinsics" {
177 try testMemcpyMemset();
178 // TODO add comptime test coverage
179 //comptime try testMemcpyMemset();
180}
181
182fn testMemcpyMemset() !void {
183 var foo: [20]u8 = undefined;
184 var bar: [20]u8 = undefined;
185
186 @memset(&foo, 'A', foo.len);
187 @memcpy(&bar, &foo, bar.len);
188
189 try expect(bar[0] == 'A');
190 try expect(bar[11] == 'A');
191 try expect(bar[19] == 'A');
192}
193
194const OpaqueA = opaque {};
195const OpaqueB = opaque {};
196
197test "opaque types" {
198 try expect(*OpaqueA != *OpaqueB);
199 if (!builtin.zig_is_stage2) {
200 try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
201 try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
202 }
203}
204
205test "variable is allowed to be a pointer to an opaque type" {
206 var x: i32 = 1234;
207 _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x));
208}
209fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
210 var a = ptr;
211 return a;
212}
213
214const global_a: i32 = 1234;
215const global_b: *const i32 = &global_a;
216const global_c: *const f32 = @ptrCast(*const f32, global_b);
217test "compile time global reinterpret" {
218 const d = @ptrCast(*const i32, global_c);
219 try expect(d.* == 1234);
220}
221
222test "cast undefined" {
223 const array: [100]u8 = undefined;
224 const slice = @as([]const u8, &array);
225 testCastUndefined(slice);
226}
227fn testCastUndefined(x: []const u8) void {
228 _ = x;
229}
230
231test "implicit cast after unreachable" {
232 try expect(outer() == 1234);
233}
234fn inner() i32 {
235 return 1234;
236}
237fn outer() i64 {
238 return inner();
239}
240
241test "take address of parameter" {
242 try testTakeAddressOfParameter(12.34);
243}
244fn testTakeAddressOfParameter(f: f32) !void {
245 const f_ptr = &f;
246 try expect(f_ptr.* == 12.34);
247}
248
249test "pointer to void return type" {
250 try testPointerToVoidReturnType();
251}
252fn testPointerToVoidReturnType() anyerror!void {
253 const a = testPointerToVoidReturnType2();
254 return a.*;
255}
256const test_pointer_to_void_return_type_x = void{};
257fn testPointerToVoidReturnType2() *const void {
258 return &test_pointer_to_void_return_type_x;
259}
260
261test "array 2D const double ptr" {
262 const rect_2d_vertexes = [_][1]f32{
263 [_]f32{1.0},
264 [_]f32{2.0},
265 };
266 try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
267}
268
269fn testArray2DConstDoublePtr(ptr: *const f32) !void {
270 const ptr2 = @ptrCast([*]const f32, ptr);
271 try expect(ptr2[0] == 1.0);
272 try expect(ptr2[1] == 2.0);
273}
274
275test "double implicit cast in same expression" {
276 var x = @as(i32, @as(u16, nine()));
277 try expect(x == 9);
278}
279fn nine() u8 {
280 return 9;
281}
282
283test "comptime if inside runtime while which unconditionally breaks" {
284 testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
285 comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
286}
287fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
288 while (cond) {
289 if (false) {}
290 break;
291 }
292}
293
294test "implicit comptime while" {
295 while (false) {
296 @compileError("bad");
297 }
298}
299
300fn fnThatClosesOverLocalConst() type {
301 const c = 1;
302 return struct {
303 fn g() i32 {
304 return c;
305 }
306 };
307}
308
309test "function closes over local const" {
310 const x = fnThatClosesOverLocalConst().g();
311 try expect(x == 1);
312}
313
314test "volatile load and store" {
315 var number: i32 = 1234;
316 const ptr = @as(*volatile i32, &number);
317 ptr.* += 1;
318 try expect(ptr.* == 1235);
319}
320
321test "struct inside function" {
322 try testStructInFn();
323 comptime try testStructInFn();
324}
325
326fn testStructInFn() !void {
327 const BlockKind = u32;
328
329 const Block = struct {
330 kind: BlockKind,
331 };
332
333 var block = Block{ .kind = 1234 };
334
335 block.kind += 1;
336
337 try expect(block.kind == 1235);
338}
339
340test "fn call returning scalar optional in equality expression" {
341 try expect(getNull() == null);
342}
343
344fn getNull() ?*i32 {
345 return null;
346}
347
348var global_foo: *i32 = undefined;
349
350test "global variable assignment with optional unwrapping with var initialized to undefined" {
351 const S = struct {
352 var data: i32 = 1234;
353 fn foo() ?*i32 {
354 return &data;
355 }
356 };
357 global_foo = S.foo() orelse {
358 @panic("bad");
359 };
360 try expect(global_foo.* == 1234);
361}
362
363test "peer result location with typed parent, runtime condition, comptime prongs" {
364 const S = struct {
365 fn doTheTest(arg: i32) i32 {
366 const st = Structy{
367 .bleh = if (arg == 1) 1 else 1,
368 };
369
370 if (st.bleh == 1)
371 return 1234;
372 return 0;
373 }
374
375 const Structy = struct {
376 bleh: i32,
377 };
378 };
379 try expect(S.doTheTest(0) == 1234);
380 try expect(S.doTheTest(1) == 1234);
381}
382
383fn ZA() type {
384 return struct {
385 b: B(),
386
387 const Self = @This();
388
389 fn B() type {
390 return struct {
391 const Self = @This();
392 };
393 }
394 };
395}
396test "non-ambiguous reference of shadowed decls" {
397 try expect(ZA().B().Self != ZA().Self);
398}
399
400test "use of declaration with same name as primitive" {
401 const S = struct {
402 const @"u8" = u16;
403 const alias = @"u8";
404 };
405 const a: S.u8 = 300;
406 try expect(a == 300);
407
408 const b: S.alias = 300;
409 try expect(b == 300);
410
411 const @"u8" = u16;
412 const c: @"u8" = 300;
413 try expect(c == 300);
414}
415
416fn emptyFn() void {}
417
418test "constant equal function pointers" {
419 const alias = emptyFn;
420 try expect(comptime x: {
421 break :x emptyFn == alias;
422 });
423}
424
425test "multiline string literal is null terminated" {
426 const s1 =
427 \\one
428 \\two)
429 \\three
430 ;
431 const s2 = "one\ntwo)\nthree";
432 try expect(std.cstr.cmp(s1, s2) == 0);
433}
434
435test "self reference through fn ptr field" {
436 const S = struct {
437 const A = struct {
438 f: fn (A) u8,
439 };
440
441 fn foo(a: A) u8 {
442 _ = a;
443 return 12;
444 }
445 };
446 var a: S.A = undefined;
447 a.f = S.foo;
448 try expect(a.f(a) == 12);
449}
450
451test "global variable initialized to global variable array element" {
452 try expect(global_ptr == &gdt[0]);
453}
454const GDTEntry = struct {
455 field: i32,
456};
457var gdt = [_]GDTEntry{
458 GDTEntry{ .field = 1 },
459 GDTEntry{ .field = 2 },
460};
461var global_ptr = &gdt[0];
462
463test "global constant is loaded with a runtime-known index" {
464 const S = struct {
465 fn doTheTest() !void {
466 var index: usize = 1;
467 const ptr = &pieces[index].field;
468 try expect(ptr.* == 2);
469 }
470 const Piece = struct {
471 field: i32,
472 };
473 const pieces = [_]Piece{ Piece{ .field = 1 }, Piece{ .field = 2 }, Piece{ .field = 3 } };
474 };
475 try S.doTheTest();
476}
test/behavior/basic_llvm.zig created+458
...@@ -0,0 +1,458 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const mem = std.mem;
4const expect = std.testing.expect;
5const expectEqualStrings = std.testing.expectEqualStrings;
6
7const g1: i32 = 1233 + 1;
8var g2: i32 = 0;
9
10test "global variables" {
11 try expect(g2 == 0);
12 g2 = g1;
13 try expect(g2 == 1234);
14}
15
16test "comptime keyword on expressions" {
17 const x: i32 = comptime x: {
18 break :x 1 + 2 + 3;
19 };
20 try expect(x == comptime 6);
21}
22
23test "type equality" {
24 try expect(*const u8 != *u8);
25}
26
27test "pointer dereferencing" {
28 var x = @as(i32, 3);
29 const y = &x;
30
31 y.* += 1;
32
33 try expect(x == 4);
34 try expect(y.* == 4);
35}
36
37test "const expression eval handling of variables" {
38 var x = true;
39 while (x) {
40 x = false;
41 }
42}
43
44test "character literals" {
45 try expect('\'' == single_quote);
46}
47const single_quote = '\'';
48
49test "non const ptr to aliased type" {
50 const int = i32;
51 try expect(?*int == ?*i32);
52}
53
54test "cold function" {
55 thisIsAColdFn();
56 comptime thisIsAColdFn();
57}
58
59fn thisIsAColdFn() void {
60 @setCold(true);
61}
62
63test "unicode escape in character literal" {
64 var a: u24 = '\u{01f4a9}';
65 try expect(a == 128169);
66}
67
68test "unicode character in character literal" {
69 try expect('💩' == 128169);
70}
71
72fn first4KeysOfHomeRow() []const u8 {
73 return "aoeu";
74}
75
76test "return string from function" {
77 try expect(mem.eql(u8, first4KeysOfHomeRow(), "aoeu"));
78}
79
80test "hex escape" {
81 try expect(mem.eql(u8, "\x68\x65\x6c\x6c\x6f", "hello"));
82}
83
84test "multiline string" {
85 const s1 =
86 \\one
87 \\two)
88 \\three
89 ;
90 const s2 = "one\ntwo)\nthree";
91 try expect(mem.eql(u8, s1, s2));
92}
93
94test "multiline string comments at start" {
95 const s1 =
96 //\\one
97 \\two)
98 \\three
99 ;
100 const s2 = "two)\nthree";
101 try expect(mem.eql(u8, s1, s2));
102}
103
104test "multiline string comments at end" {
105 const s1 =
106 \\one
107 \\two)
108 //\\three
109 ;
110 const s2 = "one\ntwo)";
111 try expect(mem.eql(u8, s1, s2));
112}
113
114test "multiline string comments in middle" {
115 const s1 =
116 \\one
117 //\\two)
118 \\three
119 ;
120 const s2 = "one\nthree";
121 try expect(mem.eql(u8, s1, s2));
122}
123
124test "multiline string comments at multiple places" {
125 const s1 =
126 \\one
127 //\\two
128 \\three
129 //\\four
130 \\five
131 ;
132 const s2 = "one\nthree\nfive";
133 try expect(mem.eql(u8, s1, s2));
134}
135
136test "call result of if else expression" {
137 try expect(mem.eql(u8, f2(true), "a"));
138 try expect(mem.eql(u8, f2(false), "b"));
139}
140fn f2(x: bool) []const u8 {
141 return (if (x) fA else fB)();
142}
143fn fA() []const u8 {
144 return "a";
145}
146fn fB() []const u8 {
147 return "b";
148}
149
150test "string concatenation" {
151 try expect(mem.eql(u8, "OK" ++ " IT " ++ "WORKED", "OK IT WORKED"));
152}
153
154test "array mult operator" {
155 try expect(mem.eql(u8, "ab" ** 5, "ababababab"));
156}
157
158test "memcpy and memset intrinsics" {
159 try testMemcpyMemset();
160 // TODO add comptime test coverage
161 //comptime try testMemcpyMemset();
162}
163
164fn testMemcpyMemset() !void {
165 var foo: [20]u8 = undefined;
166 var bar: [20]u8 = undefined;
167
168 @memset(&foo, 'A', foo.len);
169 @memcpy(&bar, &foo, bar.len);
170
171 try expect(bar[0] == 'A');
172 try expect(bar[11] == 'A');
173 try expect(bar[19] == 'A');
174}
175
176const OpaqueA = opaque {};
177const OpaqueB = opaque {};
178
179test "opaque types" {
180 try expect(*OpaqueA != *OpaqueB);
181 if (!builtin.zig_is_stage2) {
182 try expect(mem.eql(u8, @typeName(OpaqueA), "OpaqueA"));
183 try expect(mem.eql(u8, @typeName(OpaqueB), "OpaqueB"));
184 }
185}
186
187test "variable is allowed to be a pointer to an opaque type" {
188 var x: i32 = 1234;
189 _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x));
190}
191fn hereIsAnOpaqueType(ptr: *OpaqueA) *OpaqueA {
192 var a = ptr;
193 return a;
194}
195
196const global_a: i32 = 1234;
197const global_b: *const i32 = &global_a;
198const global_c: *const f32 = @ptrCast(*const f32, global_b);
199test "compile time global reinterpret" {
200 const d = @ptrCast(*const i32, global_c);
201 try expect(d.* == 1234);
202}
203
204test "cast undefined" {
205 const array: [100]u8 = undefined;
206 const slice = @as([]const u8, &array);
207 testCastUndefined(slice);
208}
209fn testCastUndefined(x: []const u8) void {
210 _ = x;
211}
212
213test "implicit cast after unreachable" {
214 try expect(outer() == 1234);
215}
216fn inner() i32 {
217 return 1234;
218}
219fn outer() i64 {
220 return inner();
221}
222
223test "take address of parameter" {
224 try testTakeAddressOfParameter(12.34);
225}
226fn testTakeAddressOfParameter(f: f32) !void {
227 const f_ptr = &f;
228 try expect(f_ptr.* == 12.34);
229}
230
231test "pointer to void return type" {
232 try testPointerToVoidReturnType();
233}
234fn testPointerToVoidReturnType() anyerror!void {
235 const a = testPointerToVoidReturnType2();
236 return a.*;
237}
238const test_pointer_to_void_return_type_x = void{};
239fn testPointerToVoidReturnType2() *const void {
240 return &test_pointer_to_void_return_type_x;
241}
242
243test "array 2D const double ptr" {
244 const rect_2d_vertexes = [_][1]f32{
245 [_]f32{1.0},
246 [_]f32{2.0},
247 };
248 try testArray2DConstDoublePtr(&rect_2d_vertexes[0][0]);
249}
250
251fn testArray2DConstDoublePtr(ptr: *const f32) !void {
252 const ptr2 = @ptrCast([*]const f32, ptr);
253 try expect(ptr2[0] == 1.0);
254 try expect(ptr2[1] == 2.0);
255}
256
257test "double implicit cast in same expression" {
258 var x = @as(i32, @as(u16, nine()));
259 try expect(x == 9);
260}
261fn nine() u8 {
262 return 9;
263}
264
265test "comptime if inside runtime while which unconditionally breaks" {
266 testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
267 comptime testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(true);
268}
269fn testComptimeIfInsideRuntimeWhileWhichUnconditionallyBreaks(cond: bool) void {
270 while (cond) {
271 if (false) {}
272 break;
273 }
274}
275
276test "implicit comptime while" {
277 while (false) {
278 @compileError("bad");
279 }
280}
281
282fn fnThatClosesOverLocalConst() type {
283 const c = 1;
284 return struct {
285 fn g() i32 {
286 return c;
287 }
288 };
289}
290
291test "function closes over local const" {
292 const x = fnThatClosesOverLocalConst().g();
293 try expect(x == 1);
294}
295
296test "volatile load and store" {
297 var number: i32 = 1234;
298 const ptr = @as(*volatile i32, &number);
299 ptr.* += 1;
300 try expect(ptr.* == 1235);
301}
302
303test "struct inside function" {
304 try testStructInFn();
305 comptime try testStructInFn();
306}
307
308fn testStructInFn() !void {
309 const BlockKind = u32;
310
311 const Block = struct {
312 kind: BlockKind,
313 };
314
315 var block = Block{ .kind = 1234 };
316
317 block.kind += 1;
318
319 try expect(block.kind == 1235);
320}
321
322test "fn call returning scalar optional in equality expression" {
323 try expect(getNull() == null);
324}
325
326fn getNull() ?*i32 {
327 return null;
328}
329
330var global_foo: *i32 = undefined;
331
332test "global variable assignment with optional unwrapping with var initialized to undefined" {
333 const S = struct {
334 var data: i32 = 1234;
335 fn foo() ?*i32 {
336 return &data;
337 }
338 };
339 global_foo = S.foo() orelse {
340 @panic("bad");
341 };
342 try expect(global_foo.* == 1234);
343}
344
345test "peer result location with typed parent, runtime condition, comptime prongs" {
346 const S = struct {
347 fn doTheTest(arg: i32) i32 {
348 const st = Structy{
349 .bleh = if (arg == 1) 1 else 1,
350 };
351
352 if (st.bleh == 1)
353 return 1234;
354 return 0;
355 }
356
357 const Structy = struct {
358 bleh: i32,
359 };
360 };
361 try expect(S.doTheTest(0) == 1234);
362 try expect(S.doTheTest(1) == 1234);
363}
364
365fn ZA() type {
366 return struct {
367 b: B(),
368
369 const Self = @This();
370
371 fn B() type {
372 return struct {
373 const Self = @This();
374 };
375 }
376 };
377}
378test "non-ambiguous reference of shadowed decls" {
379 try expect(ZA().B().Self != ZA().Self);
380}
381
382test "use of declaration with same name as primitive" {
383 const S = struct {
384 const @"u8" = u16;
385 const alias = @"u8";
386 };
387 const a: S.u8 = 300;
388 try expect(a == 300);
389
390 const b: S.alias = 300;
391 try expect(b == 300);
392
393 const @"u8" = u16;
394 const c: @"u8" = 300;
395 try expect(c == 300);
396}
397
398fn emptyFn() void {}
399
400test "constant equal function pointers" {
401 const alias = emptyFn;
402 try expect(comptime x: {
403 break :x emptyFn == alias;
404 });
405}
406
407test "multiline string literal is null terminated" {
408 const s1 =
409 \\one
410 \\two)
411 \\three
412 ;
413 const s2 = "one\ntwo)\nthree";
414 try expect(std.cstr.cmp(s1, s2) == 0);
415}
416
417test "self reference through fn ptr field" {
418 const S = struct {
419 const A = struct {
420 f: fn (A) u8,
421 };
422
423 fn foo(a: A) u8 {
424 _ = a;
425 return 12;
426 }
427 };
428 var a: S.A = undefined;
429 a.f = S.foo;
430 try expect(a.f(a) == 12);
431}
432
433test "global variable initialized to global variable array element" {
434 try expect(global_ptr == &gdt[0]);
435}
436const GDTEntry = struct {
437 field: i32,
438};
439var gdt = [_]GDTEntry{
440 GDTEntry{ .field = 1 },
441 GDTEntry{ .field = 2 },
442};
443var global_ptr = &gdt[0];
444
445test "global constant is loaded with a runtime-known index" {
446 const S = struct {
447 fn doTheTest() !void {
448 var index: usize = 1;
449 const ptr = &pieces[index].field;
450 try expect(ptr.* == 2);
451 }
452 const Piece = struct {
453 field: i32,
454 };
455 const pieces = [_]Piece{ Piece{ .field = 1 }, Piece{ .field = 2 }, Piece{ .field = 3 } };
456 };
457 try S.doTheTest();
458}