authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-12-15 12:47:11-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-12-15 12:47:11-08:00
loge45680cab5e9f5b28fd73ab58dae0c0f487fca48
tree7d95a4a0460ab19d64e80ef64340fda519e4558b
parent09f70bdd91bf498644f7a42800f3e4e4df7040aa
parent04784463772decb18d70734747d3fc89c043b979
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10341 from ziglang/stage2-tests

stage2: refactor x86_64 and macOS tests

6 files changed, 2103 insertions(+), 1997 deletions(-)

src/arch/x86_64/CodeGen.zig+4-4
......@@ -1635,7 +1635,7 @@ fn genBinMathOpMir(
16351635 .tag = mir_tag,
16361636 .ops = (Mir.Ops{
16371637 .reg1 = registerAlias(dst_reg, @intCast(u32, abi_size)),
1638 .reg2 = .ebp,
1638 .reg2 = registerAlias(.rbp, @intCast(u32, abi_size)),
16391639 .flags = 0b01,
16401640 }).encode(),
16411641 .data = .{ .imm = -@intCast(i32, adj_off) },
......@@ -1666,7 +1666,7 @@ fn genBinMathOpMir(
16661666 .tag = mir_tag,
16671667 .ops = (Mir.Ops{
16681668 .reg1 = registerAlias(src_reg, @intCast(u32, abi_size)),
1669 .reg2 = .ebp,
1669 .reg2 = registerAlias(.rbp, @intCast(u32, abi_size)),
16701670 .flags = 0b10,
16711671 }).encode(),
16721672 .data = .{ .imm = -@intCast(i32, adj_off) },
......@@ -2839,7 +2839,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
28392839 .tag = .mov,
28402840 .ops = (Mir.Ops{
28412841 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),
2842 .reg2 = .ebp,
2842 .reg2 = registerAlias(.rbp, @intCast(u32, abi_size)),
28432843 .flags = 0b10,
28442844 }).encode(),
28452845 .data = .{ .imm = -@intCast(i32, adj_off) },
......@@ -3060,7 +3060,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
30603060 .tag = .mov,
30613061 .ops = (Mir.Ops{
30623062 .reg1 = registerAlias(reg, @intCast(u32, abi_size)),
3063 .reg2 = .ebp,
3063 .reg2 = registerAlias(.rbp, @intCast(u32, abi_size)),
30643064 .flags = 0b01,
30653065 }).encode(),
30663066 .data = .{ .imm = ioff },
src/link/MachO.zig+1-2
......@@ -4823,8 +4823,7 @@ fn allocateAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, m
48234823 // should be deleted because the atom that it points to has grown to take up
48244824 // more of the extra capacity.
48254825 if (!big_atom.freeListEligible(self.*)) {
4826 const bl = free_list.swapRemove(i);
4827 bl.deinit(self.base.allocator);
4826 _ = free_list.swapRemove(i);
48284827 } else {
48294828 i += 1;
48304829 }
test/cases.zig+1-1836
......@@ -6,11 +6,6 @@ const TestContext = @import("../src/test.zig").TestContext;
66// a set of targets that all test cases run on unless specifically overridden. For now, each test
77// case applies to only the specified target.
88
9const linux_x64 = std.zig.CrossTarget{
10 .cpu_arch = .x86_64,
11 .os_tag = .linux,
12};
13
149pub fn addCases(ctx: *TestContext) !void {
1510 try @import("compile_errors.zig").addCases(ctx);
1611 try @import("stage2/cbe.zig").addCases(ctx);
......@@ -18,1837 +13,7 @@ pub fn addCases(ctx: *TestContext) !void {
1813 try @import("stage2/aarch64.zig").addCases(ctx);
1914 try @import("stage2/llvm.zig").addCases(ctx);
2015 try @import("stage2/wasm.zig").addCases(ctx);
21 try @import("stage2/darwin.zig").addCases(ctx);
2216 try @import("stage2/riscv64.zig").addCases(ctx);
2317 try @import("stage2/plan9.zig").addCases(ctx);
24
25 {
26 var case = ctx.exe("hello world with updates", linux_x64);
27
28 case.addError("", &[_][]const u8{
29 ":99:9: error: struct 'tmp.tmp' has no member named 'main'",
30 });
31
32 // Incorrect return type
33 case.addError(
34 \\pub export fn _start() noreturn {
35 \\}
36 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
37
38 // Regular old hello world
39 case.addCompareOutput(
40 \\pub export fn _start() noreturn {
41 \\ print();
42 \\
43 \\ exit();
44 \\}
45 \\
46 \\fn print() void {
47 \\ asm volatile ("syscall"
48 \\ :
49 \\ : [number] "{rax}" (1),
50 \\ [arg1] "{rdi}" (1),
51 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
52 \\ [arg3] "{rdx}" (14)
53 \\ : "rcx", "r11", "memory"
54 \\ );
55 \\ return;
56 \\}
57 \\
58 \\fn exit() noreturn {
59 \\ asm volatile ("syscall"
60 \\ :
61 \\ : [number] "{rax}" (231),
62 \\ [arg1] "{rdi}" (0)
63 \\ : "rcx", "r11", "memory"
64 \\ );
65 \\ unreachable;
66 \\}
67 ,
68 "Hello, World!\n",
69 );
70
71 // Convert to pub fn main
72 case.addCompareOutput(
73 \\pub fn main() void {
74 \\ print();
75 \\}
76 \\
77 \\fn print() void {
78 \\ asm volatile ("syscall"
79 \\ :
80 \\ : [number] "{rax}" (1),
81 \\ [arg1] "{rdi}" (1),
82 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
83 \\ [arg3] "{rdx}" (14)
84 \\ : "rcx", "r11", "memory"
85 \\ );
86 \\ return;
87 \\}
88 ,
89 "Hello, World!\n",
90 );
91
92 // Now change the message only
93 case.addCompareOutput(
94 \\pub fn main() void {
95 \\ print();
96 \\}
97 \\
98 \\fn print() void {
99 \\ asm volatile ("syscall"
100 \\ :
101 \\ : [number] "{rax}" (1),
102 \\ [arg1] "{rdi}" (1),
103 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
104 \\ [arg3] "{rdx}" (104)
105 \\ : "rcx", "r11", "memory"
106 \\ );
107 \\ return;
108 \\}
109 ,
110 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
111 );
112 // Now we print it twice.
113 case.addCompareOutput(
114 \\pub fn main() void {
115 \\ print();
116 \\ print();
117 \\}
118 \\
119 \\fn print() void {
120 \\ asm volatile ("syscall"
121 \\ :
122 \\ : [number] "{rax}" (1),
123 \\ [arg1] "{rdi}" (1),
124 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
125 \\ [arg3] "{rdx}" (104)
126 \\ : "rcx", "r11", "memory"
127 \\ );
128 \\ return;
129 \\}
130 ,
131 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
132 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
133 \\
134 );
135 }
136
137 {
138 var case = ctx.exe("adding numbers at comptime", linux_x64);
139 case.addCompareOutput(
140 \\pub export fn _start() noreturn {
141 \\ asm volatile ("syscall"
142 \\ :
143 \\ : [number] "{rax}" (1),
144 \\ [arg1] "{rdi}" (1),
145 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
146 \\ [arg3] "{rdx}" (10 + 4)
147 \\ : "rcx", "r11", "memory"
148 \\ );
149 \\ asm volatile ("syscall"
150 \\ :
151 \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)),
152 \\ [arg1] "{rdi}" (0)
153 \\ : "rcx", "r11", "memory"
154 \\ );
155 \\ unreachable;
156 \\}
157 ,
158 "Hello, World!\n",
159 );
160 }
161
162 {
163 var case = ctx.exe("adding numbers at runtime and comptime", linux_x64);
164 case.addCompareOutput(
165 \\pub export fn _start() noreturn {
166 \\ add(3, 4);
167 \\
168 \\ exit();
169 \\}
170 \\
171 \\fn add(a: u32, b: u32) void {
172 \\ if (a + b != 7) unreachable;
173 \\}
174 \\
175 \\fn exit() noreturn {
176 \\ asm volatile ("syscall"
177 \\ :
178 \\ : [number] "{rax}" (231),
179 \\ [arg1] "{rdi}" (0)
180 \\ : "rcx", "r11", "memory"
181 \\ );
182 \\ unreachable;
183 \\}
184 ,
185 "",
186 );
187 // comptime function call
188 case.addCompareOutput(
189 \\pub export fn _start() noreturn {
190 \\ exit();
191 \\}
192 \\
193 \\fn add(a: u32, b: u32) u32 {
194 \\ return a + b;
195 \\}
196 \\
197 \\const x = add(3, 4);
198 \\
199 \\fn exit() noreturn {
200 \\ asm volatile ("syscall"
201 \\ :
202 \\ : [number] "{rax}" (231),
203 \\ [arg1] "{rdi}" (x - 7)
204 \\ : "rcx", "r11", "memory"
205 \\ );
206 \\ unreachable;
207 \\}
208 ,
209 "",
210 );
211 // Inline function call
212 case.addCompareOutput(
213 \\pub export fn _start() noreturn {
214 \\ var x: usize = 3;
215 \\ const y = add(1, 2, x);
216 \\ exit(y - 6);
217 \\}
218 \\
219 \\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
220 \\ return a + b + c;
221 \\}
222 \\
223 \\fn exit(code: usize) noreturn {
224 \\ asm volatile ("syscall"
225 \\ :
226 \\ : [number] "{rax}" (231),
227 \\ [arg1] "{rdi}" (code)
228 \\ : "rcx", "r11", "memory"
229 \\ );
230 \\ unreachable;
231 \\}
232 ,
233 "",
234 );
235 }
236
237 {
238 var case = ctx.exe("subtracting numbers at runtime", linux_x64);
239 case.addCompareOutput(
240 \\pub fn main() void {
241 \\ sub(7, 4);
242 \\}
243 \\
244 \\fn sub(a: u32, b: u32) void {
245 \\ if (a - b != 3) unreachable;
246 \\}
247 ,
248 "",
249 );
250 }
251 {
252 var case = ctx.exe("unused vars", linux_x64);
253 case.addError(
254 \\pub fn main() void {
255 \\ const x = 1;
256 \\}
257 , &.{":2:11: error: unused local constant"});
258 }
259 {
260 var case = ctx.exe("@TypeOf", linux_x64);
261 case.addCompareOutput(
262 \\pub fn main() void {
263 \\ var x: usize = 0;
264 \\ _ = x;
265 \\ const z = @TypeOf(x, @as(u128, 5));
266 \\ assert(z == u128);
267 \\}
268 \\
269 \\pub fn assert(ok: bool) void {
270 \\ if (!ok) unreachable; // assertion failure
271 \\}
272 ,
273 "",
274 );
275 case.addCompareOutput(
276 \\pub fn main() void {
277 \\ const z = @TypeOf(true);
278 \\ assert(z == bool);
279 \\}
280 \\
281 \\pub fn assert(ok: bool) void {
282 \\ if (!ok) unreachable; // assertion failure
283 \\}
284 ,
285 "",
286 );
287 case.addError(
288 \\pub fn main() void {
289 \\ _ = @TypeOf(true, 1);
290 \\}
291 , &[_][]const u8{
292 ":2:9: error: incompatible types: 'bool' and 'comptime_int'",
293 ":2:17: note: type 'bool' here",
294 ":2:23: note: type 'comptime_int' here",
295 });
296 }
297
298 {
299 var case = ctx.exe("multiplying numbers at runtime and comptime", linux_x64);
300 case.addCompareOutput(
301 \\pub export fn _start() noreturn {
302 \\ mul(3, 4);
303 \\
304 \\ exit();
305 \\}
306 \\
307 \\fn mul(a: u32, b: u32) void {
308 \\ if (a * b != 12) unreachable;
309 \\}
310 \\
311 \\fn exit() noreturn {
312 \\ asm volatile ("syscall"
313 \\ :
314 \\ : [number] "{rax}" (231),
315 \\ [arg1] "{rdi}" (0)
316 \\ : "rcx", "r11", "memory"
317 \\ );
318 \\ unreachable;
319 \\}
320 ,
321 "",
322 );
323 // comptime function call
324 case.addCompareOutput(
325 \\pub fn _start() noreturn {
326 \\ exit();
327 \\}
328 \\
329 \\fn mul(a: u32, b: u32) u32 {
330 \\ return a * b;
331 \\}
332 \\
333 \\const x = mul(3, 4);
334 \\
335 \\fn exit() noreturn {
336 \\ asm volatile ("syscall"
337 \\ :
338 \\ : [number] "{rax}" (231),
339 \\ [arg1] "{rdi}" (x - 12)
340 \\ : "rcx", "r11", "memory"
341 \\ );
342 \\ unreachable;
343 \\}
344 ,
345 "",
346 );
347 // Inline function call
348 case.addCompareOutput(
349 \\pub export fn _start() noreturn {
350 \\ var x: usize = 5;
351 \\ const y = mul(2, 3, x);
352 \\ exit(y - 30);
353 \\}
354 \\
355 \\fn mul(a: usize, b: usize, c: usize) callconv(.Inline) usize {
356 \\ return a * b * c;
357 \\}
358 \\
359 \\fn exit(code: usize) noreturn {
360 \\ asm volatile ("syscall"
361 \\ :
362 \\ : [number] "{rax}" (231),
363 \\ [arg1] "{rdi}" (code)
364 \\ : "rcx", "r11", "memory"
365 \\ );
366 \\ unreachable;
367 \\}
368 ,
369 "",
370 );
371 }
372
373 {
374 var case = ctx.exe("assert function", linux_x64);
375 case.addCompareOutput(
376 \\pub fn main() void {
377 \\ add(3, 4);
378 \\}
379 \\
380 \\fn add(a: u32, b: u32) void {
381 \\ assert(a + b == 7);
382 \\}
383 \\
384 \\pub fn assert(ok: bool) void {
385 \\ if (!ok) unreachable; // assertion failure
386 \\}
387 \\
388 \\fn exit() noreturn {
389 \\ asm volatile ("syscall"
390 \\ :
391 \\ : [number] "{rax}" (231),
392 \\ [arg1] "{rdi}" (0)
393 \\ : "rcx", "r11", "memory"
394 \\ );
395 \\ unreachable;
396 \\}
397 ,
398 "",
399 );
400
401 // Tests copying a register. For the `c = a + b`, it has to
402 // preserve both a and b, because they are both used later.
403 case.addCompareOutput(
404 \\pub fn main() void {
405 \\ add(3, 4);
406 \\}
407 \\
408 \\fn add(a: u32, b: u32) void {
409 \\ const c = a + b; // 7
410 \\ const d = a + c; // 10
411 \\ const e = d + b; // 14
412 \\ assert(e == 14);
413 \\}
414 \\
415 \\pub fn assert(ok: bool) void {
416 \\ if (!ok) unreachable; // assertion failure
417 \\}
418 ,
419 "",
420 );
421
422 // More stress on the liveness detection.
423 case.addCompareOutput(
424 \\pub fn main() void {
425 \\ add(3, 4);
426 \\}
427 \\
428 \\fn add(a: u32, b: u32) void {
429 \\ const c = a + b; // 7
430 \\ const d = a + c; // 10
431 \\ const e = d + b; // 14
432 \\ const f = d + e; // 24
433 \\ const g = e + f; // 38
434 \\ const h = f + g; // 62
435 \\ const i = g + h; // 100
436 \\ assert(i == 100);
437 \\}
438 \\
439 \\pub fn assert(ok: bool) void {
440 \\ if (!ok) unreachable; // assertion failure
441 \\}
442 ,
443 "",
444 );
445
446 // Requires a second move. The register allocator should figure out to re-use rax.
447 case.addCompareOutput(
448 \\pub fn main() void {
449 \\ add(3, 4);
450 \\}
451 \\
452 \\fn add(a: u32, b: u32) void {
453 \\ const c = a + b; // 7
454 \\ const d = a + c; // 10
455 \\ const e = d + b; // 14
456 \\ const f = d + e; // 24
457 \\ const g = e + f; // 38
458 \\ const h = f + g; // 62
459 \\ const i = g + h; // 100
460 \\ const j = i + d; // 110
461 \\ assert(j == 110);
462 \\}
463 \\
464 \\pub fn assert(ok: bool) void {
465 \\ if (!ok) unreachable; // assertion failure
466 \\}
467 ,
468 "",
469 );
470
471 // Now we test integer return values.
472 case.addCompareOutput(
473 \\pub fn main() void {
474 \\ assert(add(3, 4) == 7);
475 \\ assert(add(20, 10) == 30);
476 \\}
477 \\
478 \\fn add(a: u32, b: u32) u32 {
479 \\ return a + b;
480 \\}
481 \\
482 \\pub fn assert(ok: bool) void {
483 \\ if (!ok) unreachable; // assertion failure
484 \\}
485 ,
486 "",
487 );
488
489 // Local mutable variables.
490 case.addCompareOutput(
491 \\pub fn main() void {
492 \\ assert(add(3, 4) == 7);
493 \\ assert(add(20, 10) == 30);
494 \\}
495 \\
496 \\fn add(a: u32, b: u32) u32 {
497 \\ var x: u32 = undefined;
498 \\ x = 0;
499 \\ x += a;
500 \\ x += b;
501 \\ return x;
502 \\}
503 \\
504 \\pub fn assert(ok: bool) void {
505 \\ if (!ok) unreachable; // assertion failure
506 \\}
507 ,
508 "",
509 );
510
511 // Optionals
512 case.addCompareOutput(
513 \\pub fn main() void {
514 \\ const a: u32 = 2;
515 \\ const b: ?u32 = a;
516 \\ const c = b.?;
517 \\ if (c != 2) unreachable;
518 \\}
519 ,
520 "",
521 );
522
523 // While loops
524 case.addCompareOutput(
525 \\pub fn main() void {
526 \\ var i: u32 = 0;
527 \\ while (i < 4) : (i += 1) print();
528 \\ assert(i == 4);
529 \\}
530 \\
531 \\fn print() void {
532 \\ asm volatile ("syscall"
533 \\ :
534 \\ : [number] "{rax}" (1),
535 \\ [arg1] "{rdi}" (1),
536 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
537 \\ [arg3] "{rdx}" (6)
538 \\ : "rcx", "r11", "memory"
539 \\ );
540 \\ return;
541 \\}
542 \\
543 \\pub fn assert(ok: bool) void {
544 \\ if (!ok) unreachable; // assertion failure
545 \\}
546 ,
547 "hello\nhello\nhello\nhello\n",
548 );
549
550 // inline while requires the condition to be comptime known.
551 case.addError(
552 \\pub fn main() void {
553 \\ var i: u32 = 0;
554 \\ inline while (i < 4) : (i += 1) print();
555 \\ assert(i == 4);
556 \\}
557 \\
558 \\fn print() void {
559 \\ asm volatile ("syscall"
560 \\ :
561 \\ : [number] "{rax}" (1),
562 \\ [arg1] "{rdi}" (1),
563 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
564 \\ [arg3] "{rdx}" (6)
565 \\ : "rcx", "r11", "memory"
566 \\ );
567 \\ return;
568 \\}
569 \\
570 \\pub fn assert(ok: bool) void {
571 \\ if (!ok) unreachable; // assertion failure
572 \\}
573 , &[_][]const u8{":3:21: error: unable to resolve comptime value"});
574
575 // Labeled blocks (no conditional branch)
576 case.addCompareOutput(
577 \\pub fn main() void {
578 \\ assert(add(3, 4) == 20);
579 \\}
580 \\
581 \\fn add(a: u32, b: u32) u32 {
582 \\ const x: u32 = blk: {
583 \\ const c = a + b; // 7
584 \\ const d = a + c; // 10
585 \\ const e = d + b; // 14
586 \\ break :blk e;
587 \\ };
588 \\ const y = x + a; // 17
589 \\ const z = y + a; // 20
590 \\ return z;
591 \\}
592 \\
593 \\pub fn assert(ok: bool) void {
594 \\ if (!ok) unreachable; // assertion failure
595 \\}
596 ,
597 "",
598 );
599
600 // This catches a possible bug in the logic for re-using dying operands.
601 case.addCompareOutput(
602 \\pub fn main() void {
603 \\ assert(add(3, 4) == 116);
604 \\}
605 \\
606 \\fn add(a: u32, b: u32) u32 {
607 \\ const x: u32 = blk: {
608 \\ const c = a + b; // 7
609 \\ const d = a + c; // 10
610 \\ const e = d + b; // 14
611 \\ const f = d + e; // 24
612 \\ const g = e + f; // 38
613 \\ const h = f + g; // 62
614 \\ const i = g + h; // 100
615 \\ const j = i + d; // 110
616 \\ break :blk j;
617 \\ };
618 \\ const y = x + a; // 113
619 \\ const z = y + a; // 116
620 \\ return z;
621 \\}
622 \\
623 \\pub fn assert(ok: bool) void {
624 \\ if (!ok) unreachable; // assertion failure
625 \\}
626 ,
627 "",
628 );
629
630 // Spilling registers to the stack.
631 case.addCompareOutput(
632 \\pub fn main() void {
633 \\ assert(add(3, 4) == 1221);
634 \\ assert(mul(3, 4) == 21609);
635 \\}
636 \\
637 \\fn add(a: u32, b: u32) u32 {
638 \\ const x: u32 = blk: {
639 \\ const c = a + b; // 7
640 \\ const d = a + c; // 10
641 \\ const e = d + b; // 14
642 \\ const f = d + e; // 24
643 \\ const g = e + f; // 38
644 \\ const h = f + g; // 62
645 \\ const i = g + h; // 100
646 \\ const j = i + d; // 110
647 \\ const k = i + j; // 210
648 \\ const l = j + k; // 320
649 \\ const m = l + c; // 327
650 \\ const n = m + d; // 337
651 \\ const o = n + e; // 351
652 \\ const p = o + f; // 375
653 \\ const q = p + g; // 413
654 \\ const r = q + h; // 475
655 \\ const s = r + i; // 575
656 \\ const t = s + j; // 685
657 \\ const u = t + k; // 895
658 \\ const v = u + l; // 1215
659 \\ break :blk v;
660 \\ };
661 \\ const y = x + a; // 1218
662 \\ const z = y + a; // 1221
663 \\ return z;
664 \\}
665 \\
666 \\fn mul(a: u32, b: u32) u32 {
667 \\ const x: u32 = blk: {
668 \\ const c = a * a * a * a; // 81
669 \\ const d = a * a * a * b; // 108
670 \\ const e = a * a * b * a; // 108
671 \\ const f = a * a * b * b; // 144
672 \\ const g = a * b * a * a; // 108
673 \\ const h = a * b * a * b; // 144
674 \\ const i = a * b * b * a; // 144
675 \\ const j = a * b * b * b; // 192
676 \\ const k = b * a * a * a; // 108
677 \\ const l = b * a * a * b; // 144
678 \\ const m = b * a * b * a; // 144
679 \\ const n = b * a * b * b; // 192
680 \\ const o = b * b * a * a; // 144
681 \\ const p = b * b * a * b; // 192
682 \\ const q = b * b * b * a; // 192
683 \\ const r = b * b * b * b; // 256
684 \\ const s = c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r; // 2401
685 \\ break :blk s;
686 \\ };
687 \\ const y = x * a; // 7203
688 \\ const z = y * a; // 21609
689 \\ return z;
690 \\}
691 \\
692 \\pub fn assert(ok: bool) void {
693 \\ if (!ok) unreachable; // assertion failure
694 \\}
695 ,
696 "",
697 );
698
699 // Reusing the registers of dead operands playing nicely with conditional branching.
700 case.addCompareOutput(
701 \\pub fn main() void {
702 \\ assert(add(3, 4) == 791);
703 \\ assert(add(4, 3) == 79);
704 \\}
705 \\
706 \\fn add(a: u32, b: u32) u32 {
707 \\ const x: u32 = if (a < b) blk: {
708 \\ const c = a + b; // 7
709 \\ const d = a + c; // 10
710 \\ const e = d + b; // 14
711 \\ const f = d + e; // 24
712 \\ const g = e + f; // 38
713 \\ const h = f + g; // 62
714 \\ const i = g + h; // 100
715 \\ const j = i + d; // 110
716 \\ const k = i + j; // 210
717 \\ const l = k + c; // 217
718 \\ const m = l + d; // 227
719 \\ const n = m + e; // 241
720 \\ const o = n + f; // 265
721 \\ const p = o + g; // 303
722 \\ const q = p + h; // 365
723 \\ const r = q + i; // 465
724 \\ const s = r + j; // 575
725 \\ const t = s + k; // 785
726 \\ break :blk t;
727 \\ } else blk: {
728 \\ const t = b + b + a; // 10
729 \\ const c = a + t; // 14
730 \\ const d = c + t; // 24
731 \\ const e = d + t; // 34
732 \\ const f = e + t; // 44
733 \\ const g = f + t; // 54
734 \\ const h = c + g; // 68
735 \\ break :blk h + b; // 71
736 \\ };
737 \\ const y = x + a; // 788, 75
738 \\ const z = y + a; // 791, 79
739 \\ return z;
740 \\}
741 \\
742 \\pub fn assert(ok: bool) void {
743 \\ if (!ok) unreachable; // assertion failure
744 \\}
745 ,
746 "",
747 );
748
749 // Character literals and multiline strings.
750 case.addCompareOutput(
751 \\pub fn main() void {
752 \\ const ignore =
753 \\ \\ cool thx
754 \\ \\
755 \\ ;
756 \\ _ = ignore;
757 \\ add('ぁ', '\x03');
758 \\}
759 \\
760 \\fn add(a: u32, b: u32) void {
761 \\ assert(a + b == 12356);
762 \\}
763 \\
764 \\pub fn assert(ok: bool) void {
765 \\ if (!ok) unreachable; // assertion failure
766 \\}
767 ,
768 "",
769 );
770
771 // Global const.
772 case.addCompareOutput(
773 \\pub fn main() void {
774 \\ add(aa, bb);
775 \\}
776 \\
777 \\const aa = 'ぁ';
778 \\const bb = '\x03';
779 \\
780 \\fn add(a: u32, b: u32) void {
781 \\ assert(a + b == 12356);
782 \\}
783 \\
784 \\pub fn assert(ok: bool) void {
785 \\ if (!ok) unreachable; // assertion failure
786 \\}
787 ,
788 "",
789 );
790
791 // Array access.
792 case.addCompareOutput(
793 \\pub fn main() void {
794 \\ assert("hello"[0] == 'h');
795 \\}
796 \\
797 \\pub fn assert(ok: bool) void {
798 \\ if (!ok) unreachable; // assertion failure
799 \\}
800 ,
801 "",
802 );
803
804 // Array access to a global array.
805 case.addCompareOutput(
806 \\const hello = "hello".*;
807 \\pub fn main() void {
808 \\ assert(hello[1] == 'e');
809 \\}
810 \\
811 \\pub fn assert(ok: bool) void {
812 \\ if (!ok) unreachable; // assertion failure
813 \\}
814 ,
815 "",
816 );
817
818 // 64bit set stack
819 case.addCompareOutput(
820 \\pub fn main() void {
821 \\ var i: u64 = 0xFFEEDDCCBBAA9988;
822 \\ assert(i == 0xFFEEDDCCBBAA9988);
823 \\}
824 \\
825 \\pub fn assert(ok: bool) void {
826 \\ if (!ok) unreachable; // assertion failure
827 \\}
828 ,
829 "",
830 );
831
832 // Basic for loop
833 case.addCompareOutput(
834 \\pub fn main() void {
835 \\ for ("hello") |_| print();
836 \\}
837 \\
838 \\fn print() void {
839 \\ asm volatile ("syscall"
840 \\ :
841 \\ : [number] "{rax}" (1),
842 \\ [arg1] "{rdi}" (1),
843 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
844 \\ [arg3] "{rdx}" (6)
845 \\ : "rcx", "r11", "memory"
846 \\ );
847 \\ return;
848 \\}
849 ,
850 "hello\nhello\nhello\nhello\nhello\n",
851 );
852 }
853
854 {
855 var case = ctx.exe("basic import", linux_x64);
856 case.addCompareOutput(
857 \\pub fn main() void {
858 \\ @import("print.zig").print();
859 \\}
860 ,
861 "Hello, World!\n",
862 );
863 try case.files.append(.{
864 .src =
865 \\pub fn print() void {
866 \\ asm volatile ("syscall"
867 \\ :
868 \\ : [number] "{rax}" (@as(usize, 1)),
869 \\ [arg1] "{rdi}" (@as(usize, 1)),
870 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
871 \\ [arg3] "{rdx}" (@as(usize, 14))
872 \\ : "rcx", "r11", "memory"
873 \\ );
874 \\ return;
875 \\}
876 ,
877 .path = "print.zig",
878 });
879 }
880 {
881 var case = ctx.exe("redundant comptime", linux_x64);
882 case.addError(
883 \\pub fn main() void {
884 \\ var a: comptime u32 = 0;
885 \\}
886 ,
887 &.{":2:12: error: redundant comptime keyword in already comptime scope"},
888 );
889 case.addError(
890 \\pub fn main() void {
891 \\ comptime {
892 \\ var a: u32 = comptime 0;
893 \\ }
894 \\}
895 ,
896 &.{":3:22: error: redundant comptime keyword in already comptime scope"},
897 );
898 }
899 {
900 var case = ctx.exe("try in comptime in struct in test", linux_x64);
901 case.addError(
902 \\test "@unionInit on union w/ tag but no fields" {
903 \\ const S = struct {
904 \\ comptime {
905 \\ try expect(false);
906 \\ }
907 \\ };
908 \\ _ = S;
909 \\}
910 ,
911 &.{":4:13: error: 'try' outside function scope"},
912 );
913 }
914 {
915 var case = ctx.exe("import private", linux_x64);
916 case.addError(
917 \\pub fn main() void {
918 \\ @import("print.zig").print();
919 \\}
920 ,
921 &.{
922 ":2:25: error: 'print' is not marked 'pub'",
923 "print.zig:2:1: note: declared here",
924 },
925 );
926 try case.files.append(.{
927 .src =
928 \\// dummy comment to make print be on line 2
929 \\fn print() void {
930 \\ asm volatile ("syscall"
931 \\ :
932 \\ : [number] "{rax}" (@as(usize, 1)),
933 \\ [arg1] "{rdi}" (@as(usize, 1)),
934 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
935 \\ [arg3] "{rdx}" (@as(usize, 14))
936 \\ : "rcx", "r11", "memory"
937 \\ );
938 \\ return;
939 \\}
940 ,
941 .path = "print.zig",
942 });
943 }
944
945 ctx.compileError("function redeclaration", linux_x64,
946 \\// dummy comment
947 \\fn entry() void {}
948 \\fn entry() void {}
949 \\
950 \\fn foo() void {
951 \\ var foo = 1234;
952 \\}
953 , &[_][]const u8{
954 ":3:1: error: redeclaration of 'entry'",
955 ":2:1: note: other declaration here",
956 ":6:9: error: local shadows declaration of 'foo'",
957 ":5:1: note: declared here",
958 });
959
960 ctx.compileError("returns in try", linux_x64,
961 \\pub fn main() !void {
962 \\ try a();
963 \\ try b();
964 \\}
965 \\
966 \\pub fn a() !void {
967 \\ defer try b();
968 \\}
969 \\pub fn b() !void {
970 \\ defer return a();
971 \\}
972 , &[_][]const u8{
973 ":7:8: error: 'try' not allowed inside defer expression",
974 ":10:8: error: cannot return from defer expression",
975 });
976
977 ctx.compileError("ambiguous references", linux_x64,
978 \\const T = struct {
979 \\ const T = struct {
980 \\ fn f() void {
981 \\ _ = T;
982 \\ }
983 \\ };
984 \\};
985 , &.{
986 ":4:17: error: ambiguous reference",
987 ":2:5: note: declared here",
988 ":1:1: note: also declared here",
989 });
990
991 ctx.compileError("inner func accessing outer var", linux_x64,
992 \\pub fn f() void {
993 \\ var bar: bool = true;
994 \\ const S = struct {
995 \\ fn baz() bool {
996 \\ return bar;
997 \\ }
998 \\ };
999 \\ _ = S;
1000 \\}
1001 , &.{
1002 ":5:20: error: mutable 'bar' not accessible from here",
1003 ":2:9: note: declared mutable here",
1004 ":3:15: note: crosses namespace boundary here",
1005 });
1006
1007 ctx.compileError("global variable redeclaration", linux_x64,
1008 \\// dummy comment
1009 \\var foo = false;
1010 \\var foo = true;
1011 , &[_][]const u8{
1012 ":3:1: error: redeclaration of 'foo'",
1013 ":2:1: note: other declaration here",
1014 });
1015
1016 ctx.compileError("compileError", linux_x64,
1017 \\export fn foo() void {
1018 \\ @compileError("this is an error");
1019 \\}
1020 , &[_][]const u8{":2:3: error: this is an error"});
1021
1022 {
1023 var case = ctx.exe("intToPtr", linux_x64);
1024 case.addError(
1025 \\pub fn main() void {
1026 \\ _ = @intToPtr(*u8, 0);
1027 \\}
1028 , &[_][]const u8{
1029 ":2:24: error: pointer type '*u8' does not allow address zero",
1030 });
1031 case.addError(
1032 \\pub fn main() void {
1033 \\ _ = @intToPtr(*u32, 2);
1034 \\}
1035 , &[_][]const u8{
1036 ":2:25: error: pointer type '*u32' requires aligned address",
1037 });
1038 }
1039
1040 {
1041 var case = ctx.obj("variable shadowing", linux_x64);
1042 case.addError(
1043 \\pub fn main() void {
1044 \\ var i: u32 = 10;
1045 \\ var i: u32 = 10;
1046 \\}
1047 , &[_][]const u8{
1048 ":3:9: error: redeclaration of local variable 'i'",
1049 ":2:9: note: previous declaration here",
1050 });
1051 case.addError(
1052 \\var testing: i64 = 10;
1053 \\pub fn main() void {
1054 \\ var testing: i64 = 20;
1055 \\}
1056 , &[_][]const u8{
1057 ":3:9: error: local shadows declaration of 'testing'",
1058 ":1:1: note: declared here",
1059 });
1060 case.addError(
1061 \\fn a() type {
1062 \\ return struct {
1063 \\ pub fn b() void {
1064 \\ const c = 6;
1065 \\ const c = 69;
1066 \\ }
1067 \\ };
1068 \\}
1069 , &[_][]const u8{
1070 ":5:19: error: redeclaration of local constant 'c'",
1071 ":4:19: note: previous declaration here",
1072 });
1073 case.addError(
1074 \\pub fn main() void {
1075 \\ var i = 0;
1076 \\ for ("n") |_, i| {
1077 \\ }
1078 \\}
1079 , &[_][]const u8{
1080 ":3:19: error: redeclaration of local variable 'i'",
1081 ":2:9: note: previous declaration here",
1082 });
1083 case.addError(
1084 \\pub fn main() void {
1085 \\ var i = 0;
1086 \\ for ("n") |i| {
1087 \\ }
1088 \\}
1089 , &[_][]const u8{
1090 ":3:16: error: redeclaration of local variable 'i'",
1091 ":2:9: note: previous declaration here",
1092 });
1093 case.addError(
1094 \\pub fn main() void {
1095 \\ var i = 0;
1096 \\ while ("n") |i| {
1097 \\ }
1098 \\}
1099 , &[_][]const u8{
1100 ":3:18: error: redeclaration of local variable 'i'",
1101 ":2:9: note: previous declaration here",
1102 });
1103 case.addError(
1104 \\pub fn main() void {
1105 \\ var i = 0;
1106 \\ while ("n") |bruh| {
1107 \\ _ = bruh;
1108 \\ } else |i| {
1109 \\
1110 \\ }
1111 \\}
1112 , &[_][]const u8{
1113 ":5:13: error: redeclaration of local variable 'i'",
1114 ":2:9: note: previous declaration here",
1115 });
1116 case.addError(
1117 \\pub fn main() void {
1118 \\ var i = 0;
1119 \\ if (true) |i| {}
1120 \\}
1121 , &[_][]const u8{
1122 ":3:16: error: redeclaration of local variable 'i'",
1123 ":2:9: note: previous declaration here",
1124 });
1125 case.addError(
1126 \\pub fn main() void {
1127 \\ var i = 0;
1128 \\ if (true) |i| {} else |e| {}
1129 \\}
1130 , &[_][]const u8{
1131 ":3:16: error: redeclaration of local variable 'i'",
1132 ":2:9: note: previous declaration here",
1133 });
1134 case.addError(
1135 \\pub fn main() void {
1136 \\ var i = 0;
1137 \\ if (true) |_| {} else |i| {}
1138 \\}
1139 , &[_][]const u8{
1140 ":3:28: error: redeclaration of local variable 'i'",
1141 ":2:9: note: previous declaration here",
1142 });
1143 }
1144
1145 {
1146 // TODO make the test harness support checking the compile log output too
1147 var case = ctx.obj("@compileLog", linux_x64);
1148 // The other compile error prevents emission of a "found compile log" statement.
1149 case.addError(
1150 \\export fn _start() noreturn {
1151 \\ const b = true;
1152 \\ var f: u32 = 1;
1153 \\ @compileLog(b, 20, f, x);
1154 \\ @compileLog(1000);
1155 \\ var bruh: usize = true;
1156 \\ _ = bruh;
1157 \\ unreachable;
1158 \\}
1159 \\export fn other() void {
1160 \\ @compileLog(1234);
1161 \\}
1162 \\fn x() void {}
1163 , &[_][]const u8{
1164 ":6:23: error: expected usize, found bool",
1165 });
1166
1167 // Now only compile log statements remain. One per Decl.
1168 case.addError(
1169 \\export fn _start() noreturn {
1170 \\ const b = true;
1171 \\ var f: u32 = 1;
1172 \\ @compileLog(b, 20, f, x);
1173 \\ @compileLog(1000);
1174 \\ unreachable;
1175 \\}
1176 \\export fn other() void {
1177 \\ @compileLog(1234);
1178 \\}
1179 \\fn x() void {}
1180 , &[_][]const u8{
1181 ":9:5: error: found compile log statement",
1182 ":4:5: note: also here",
1183 });
1184 }
1185
1186 {
1187 var case = ctx.obj("extern variable has no type", linux_x64);
1188 case.addError(
1189 \\comptime {
1190 \\ const x = foo + foo;
1191 \\ _ = x;
1192 \\}
1193 \\extern var foo: i32;
1194 , &[_][]const u8{":2:15: error: unable to resolve comptime value"});
1195 case.addError(
1196 \\export fn entry() void {
1197 \\ _ = foo;
1198 \\}
1199 \\extern var foo;
1200 , &[_][]const u8{":4:8: error: unable to infer variable type"});
1201 }
1202
1203 {
1204 var case = ctx.exe("break/continue", linux_x64);
1205
1206 // Break out of loop
1207 case.addCompareOutput(
1208 \\pub fn main() void {
1209 \\ while (true) {
1210 \\ break;
1211 \\ }
1212 \\}
1213 ,
1214 "",
1215 );
1216 case.addCompareOutput(
1217 \\pub fn main() void {
1218 \\ foo: while (true) {
1219 \\ break :foo;
1220 \\ }
1221 \\}
1222 ,
1223 "",
1224 );
1225
1226 // Continue in loop
1227 case.addCompareOutput(
1228 \\pub export fn _start() noreturn {
1229 \\ var i: u64 = 0;
1230 \\ while (true) : (i+=1) {
1231 \\ if (i == 4) exit();
1232 \\ continue;
1233 \\ }
1234 \\}
1235 \\
1236 \\fn exit() noreturn {
1237 \\ asm volatile ("syscall"
1238 \\ :
1239 \\ : [number] "{rax}" (231),
1240 \\ [arg1] "{rdi}" (0)
1241 \\ : "rcx", "r11", "memory"
1242 \\ );
1243 \\ unreachable;
1244 \\}
1245 ,
1246 "",
1247 );
1248 case.addCompareOutput(
1249 \\pub export fn _start() noreturn {
1250 \\ var i: u64 = 0;
1251 \\ foo: while (true) : (i+=1) {
1252 \\ if (i == 4) exit();
1253 \\ continue :foo;
1254 \\ }
1255 \\}
1256 \\
1257 \\fn exit() noreturn {
1258 \\ asm volatile ("syscall"
1259 \\ :
1260 \\ : [number] "{rax}" (231),
1261 \\ [arg1] "{rdi}" (0)
1262 \\ : "rcx", "r11", "memory"
1263 \\ );
1264 \\ unreachable;
1265 \\}
1266 ,
1267 "",
1268 );
1269 }
1270
1271 {
1272 var case = ctx.exe("unused labels", linux_x64);
1273 case.addError(
1274 \\comptime {
1275 \\ foo: {}
1276 \\}
1277 , &[_][]const u8{":2:5: error: unused block label"});
1278 case.addError(
1279 \\comptime {
1280 \\ foo: while (true) {}
1281 \\}
1282 , &[_][]const u8{":2:5: error: unused while loop label"});
1283 case.addError(
1284 \\comptime {
1285 \\ foo: for ("foo") |_| {}
1286 \\}
1287 , &[_][]const u8{":2:5: error: unused for loop label"});
1288 case.addError(
1289 \\comptime {
1290 \\ blk: {blk: {}}
1291 \\}
1292 , &[_][]const u8{
1293 ":2:11: error: redefinition of label 'blk'",
1294 ":2:5: note: previous definition here",
1295 });
1296 }
1297
1298 {
1299 var case = ctx.exe("bad inferred variable type", linux_x64);
1300 case.addError(
1301 \\pub fn main() void {
1302 \\ var x = null;
1303 \\ _ = x;
1304 \\}
1305 , &[_][]const u8{
1306 ":2:9: error: variable of type '@Type(.Null)' must be const or comptime",
1307 });
1308 }
1309
1310 {
1311 var case = ctx.exe("compile error in inline fn call fixed", linux_x64);
1312 case.addError(
1313 \\pub export fn _start() noreturn {
1314 \\ var x: usize = 3;
1315 \\ const y = add(10, 2, x);
1316 \\ exit(y - 6);
1317 \\}
1318 \\
1319 \\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
1320 \\ if (a == 10) @compileError("bad");
1321 \\ return a + b + c;
1322 \\}
1323 \\
1324 \\fn exit(code: usize) noreturn {
1325 \\ asm volatile ("syscall"
1326 \\ :
1327 \\ : [number] "{rax}" (231),
1328 \\ [arg1] "{rdi}" (code)
1329 \\ : "rcx", "r11", "memory"
1330 \\ );
1331 \\ unreachable;
1332 \\}
1333 , &[_][]const u8{":8:18: error: bad"});
1334
1335 case.addCompareOutput(
1336 \\pub export fn _start() noreturn {
1337 \\ var x: usize = 3;
1338 \\ const y = add(1, 2, x);
1339 \\ exit(y - 6);
1340 \\}
1341 \\
1342 \\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
1343 \\ if (a == 10) @compileError("bad");
1344 \\ return a + b + c;
1345 \\}
1346 \\
1347 \\fn exit(code: usize) noreturn {
1348 \\ asm volatile ("syscall"
1349 \\ :
1350 \\ : [number] "{rax}" (231),
1351 \\ [arg1] "{rdi}" (code)
1352 \\ : "rcx", "r11", "memory"
1353 \\ );
1354 \\ unreachable;
1355 \\}
1356 ,
1357 "",
1358 );
1359 }
1360 {
1361 var case = ctx.exe("recursive inline function", linux_x64);
1362 case.addCompareOutput(
1363 \\pub export fn _start() noreturn {
1364 \\ const y = fibonacci(7);
1365 \\ exit(y - 21);
1366 \\}
1367 \\
1368 \\fn fibonacci(n: usize) callconv(.Inline) usize {
1369 \\ if (n <= 2) return n;
1370 \\ return fibonacci(n - 2) + fibonacci(n - 1);
1371 \\}
1372 \\
1373 \\fn exit(code: usize) noreturn {
1374 \\ asm volatile ("syscall"
1375 \\ :
1376 \\ : [number] "{rax}" (231),
1377 \\ [arg1] "{rdi}" (code)
1378 \\ : "rcx", "r11", "memory"
1379 \\ );
1380 \\ unreachable;
1381 \\}
1382 ,
1383 "",
1384 );
1385 // This additionally tests that the compile error reports the correct source location.
1386 // Without storing source locations relative to the owner decl, the compile error
1387 // here would be off by 2 bytes (from the "7" -> "999").
1388 case.addError(
1389 \\pub export fn _start() noreturn {
1390 \\ const y = fibonacci(999);
1391 \\ exit(y - 21);
1392 \\}
1393 \\
1394 \\fn fibonacci(n: usize) callconv(.Inline) usize {
1395 \\ if (n <= 2) return n;
1396 \\ return fibonacci(n - 2) + fibonacci(n - 1);
1397 \\}
1398 \\
1399 \\fn exit(code: usize) noreturn {
1400 \\ asm volatile ("syscall"
1401 \\ :
1402 \\ : [number] "{rax}" (231),
1403 \\ [arg1] "{rdi}" (code)
1404 \\ : "rcx", "r11", "memory"
1405 \\ );
1406 \\ unreachable;
1407 \\}
1408 , &[_][]const u8{":8:21: error: evaluation exceeded 1000 backwards branches"});
1409 }
1410 {
1411 var case = ctx.exe("orelse at comptime", linux_x64);
1412 case.addCompareOutput(
1413 \\pub fn main() void {
1414 \\ const i: ?u64 = 0;
1415 \\ const result = i orelse 5;
1416 \\ assert(result == 0);
1417 \\}
1418 \\fn assert(b: bool) void {
1419 \\ if (!b) unreachable;
1420 \\}
1421 ,
1422 "",
1423 );
1424 case.addCompareOutput(
1425 \\pub fn main() void {
1426 \\ const i: ?u64 = null;
1427 \\ const result = i orelse 5;
1428 \\ assert(result == 5);
1429 \\}
1430 \\fn assert(b: bool) void {
1431 \\ if (!b) unreachable;
1432 \\}
1433 ,
1434 "",
1435 );
1436 }
1437
1438 {
1439 var case = ctx.exe("only 1 function and it gets updated", linux_x64);
1440 case.addCompareOutput(
1441 \\pub export fn _start() noreturn {
1442 \\ asm volatile ("syscall"
1443 \\ :
1444 \\ : [number] "{rax}" (60), // exit
1445 \\ [arg1] "{rdi}" (0)
1446 \\ : "rcx", "r11", "memory"
1447 \\ );
1448 \\ unreachable;
1449 \\}
1450 ,
1451 "",
1452 );
1453 case.addCompareOutput(
1454 \\pub export fn _start() noreturn {
1455 \\ asm volatile ("syscall"
1456 \\ :
1457 \\ : [number] "{rax}" (231), // exit_group
1458 \\ [arg1] "{rdi}" (0)
1459 \\ : "rcx", "r11", "memory"
1460 \\ );
1461 \\ unreachable;
1462 \\}
1463 ,
1464 "",
1465 );
1466 }
1467 {
1468 var case = ctx.exe("passing u0 to function", linux_x64);
1469 case.addCompareOutput(
1470 \\pub fn main() void {
1471 \\ doNothing(0);
1472 \\}
1473 \\fn doNothing(arg: u0) void {
1474 \\ _ = arg;
1475 \\}
1476 ,
1477 "",
1478 );
1479 }
1480 {
1481 var case = ctx.exe("catch at comptime", linux_x64);
1482 case.addCompareOutput(
1483 \\pub fn main() void {
1484 \\ const i: anyerror!u64 = 0;
1485 \\ const caught = i catch 5;
1486 \\ assert(caught == 0);
1487 \\}
1488 \\fn assert(b: bool) void {
1489 \\ if (!b) unreachable;
1490 \\}
1491 ,
1492 "",
1493 );
1494
1495 case.addCompareOutput(
1496 \\pub fn main() void {
1497 \\ const i: anyerror!u64 = error.B;
1498 \\ const caught = i catch 5;
1499 \\ assert(caught == 5);
1500 \\}
1501 \\fn assert(b: bool) void {
1502 \\ if (!b) unreachable;
1503 \\}
1504 ,
1505 "",
1506 );
1507
1508 case.addCompareOutput(
1509 \\pub fn main() void {
1510 \\ const a: anyerror!comptime_int = 42;
1511 \\ const b: *const comptime_int = &(a catch unreachable);
1512 \\ assert(b.* == 42);
1513 \\}
1514 \\fn assert(b: bool) void {
1515 \\ if (!b) unreachable; // assertion failure
1516 \\}
1517 , "");
1518
1519 case.addCompareOutput(
1520 \\pub fn main() void {
1521 \\ const a: anyerror!u32 = error.B;
1522 \\ _ = &(a catch |err| assert(err == error.B));
1523 \\}
1524 \\fn assert(b: bool) void {
1525 \\ if (!b) unreachable;
1526 \\}
1527 , "");
1528
1529 case.addCompareOutput(
1530 \\pub fn main() void {
1531 \\ const a: anyerror!u32 = error.Bar;
1532 \\ a catch |err| assert(err == error.Bar);
1533 \\}
1534 \\fn assert(b: bool) void {
1535 \\ if (!b) unreachable;
1536 \\}
1537 , "");
1538 }
1539 {
1540 var case = ctx.exe("runtime bitwise and", linux_x64);
1541
1542 case.addCompareOutput(
1543 \\pub fn main() void {
1544 \\ var i: u32 = 10;
1545 \\ var j: u32 = 11;
1546 \\ assert(i & 1 == 0);
1547 \\ assert(j & 1 == 1);
1548 \\ var m1: u32 = 0b1111;
1549 \\ var m2: u32 = 0b0000;
1550 \\ assert(m1 & 0b1010 == 0b1010);
1551 \\ assert(m2 & 0b1010 == 0b0000);
1552 \\}
1553 \\fn assert(b: bool) void {
1554 \\ if (!b) unreachable;
1555 \\}
1556 ,
1557 "",
1558 );
1559 }
1560 {
1561 var case = ctx.exe("runtime bitwise or", linux_x64);
1562
1563 case.addCompareOutput(
1564 \\pub fn main() void {
1565 \\ var i: u32 = 10;
1566 \\ var j: u32 = 11;
1567 \\ assert(i | 1 == 11);
1568 \\ assert(j | 1 == 11);
1569 \\ var m1: u32 = 0b1111;
1570 \\ var m2: u32 = 0b0000;
1571 \\ assert(m1 | 0b1010 == 0b1111);
1572 \\ assert(m2 | 0b1010 == 0b1010);
1573 \\}
1574 \\fn assert(b: bool) void {
1575 \\ if (!b) unreachable;
1576 \\}
1577 ,
1578 "",
1579 );
1580 }
1581 {
1582 var case = ctx.exe("merge error sets", linux_x64);
1583
1584 case.addCompareOutput(
1585 \\pub fn main() void {
1586 \\ const E = error{ A, B, D } || error { A, B, C };
1587 \\ E.A catch {};
1588 \\ E.B catch {};
1589 \\ E.C catch {};
1590 \\ E.D catch {};
1591 \\ const E2 = error { X, Y } || @TypeOf(error.Z);
1592 \\ E2.X catch {};
1593 \\ E2.Y catch {};
1594 \\ E2.Z catch {};
1595 \\ assert(anyerror || error { Z } == anyerror);
1596 \\}
1597 \\fn assert(b: bool) void {
1598 \\ if (!b) unreachable;
1599 \\}
1600 ,
1601 "",
1602 );
1603 case.addError(
1604 \\pub fn main() void {
1605 \\ const z = true || false;
1606 \\ _ = z;
1607 \\}
1608 , &.{
1609 ":2:15: error: expected error set type, found 'bool'",
1610 ":2:20: note: '||' merges error sets; 'or' performs boolean OR",
1611 });
1612 }
1613 {
1614 var case = ctx.exe("error set equality", linux_x64);
1615
1616 case.addCompareOutput(
1617 \\pub fn main() void {
1618 \\ assert(@TypeOf(error.Foo) == @TypeOf(error.Foo));
1619 \\ assert(@TypeOf(error.Bar) != @TypeOf(error.Foo));
1620 \\ assert(anyerror == anyerror);
1621 \\ assert(error{Foo} != error{Foo});
1622 \\ // TODO put inferred error sets here when @typeInfo works
1623 \\}
1624 \\fn assert(b: bool) void {
1625 \\ if (!b) unreachable;
1626 \\}
1627 ,
1628 "",
1629 );
1630 }
1631 {
1632 var case = ctx.exe("inline assembly", linux_x64);
1633
1634 case.addError(
1635 \\pub fn main() void {
1636 \\ const number = 1234;
1637 \\ const x = asm volatile ("syscall"
1638 \\ : [o] "{rax}" (-> number)
1639 \\ : [number] "{rax}" (231),
1640 \\ [arg1] "{rdi}" (60)
1641 \\ : "rcx", "r11", "memory"
1642 \\ );
1643 \\ _ = x;
1644 \\}
1645 , &[_][]const u8{":4:27: error: expected type, found comptime_int"});
1646 case.addError(
1647 \\const S = struct {
1648 \\ comptime {
1649 \\ asm volatile (
1650 \\ \\zig_moment:
1651 \\ \\syscall
1652 \\ );
1653 \\ }
1654 \\};
1655 \\pub fn main() void {
1656 \\ _ = S;
1657 \\}
1658 , &.{":3:13: error: volatile is meaningless on global assembly"});
1659 case.addError(
1660 \\pub fn main() void {
1661 \\ var bruh: u32 = 1;
1662 \\ asm (""
1663 \\ :
1664 \\ : [bruh] "{rax}" (4)
1665 \\ : "memory"
1666 \\ );
1667 \\}
1668 , &.{":3:5: error: assembly expression with no output must be marked volatile"});
1669 case.addError(
1670 \\pub fn main() void {}
1671 \\comptime {
1672 \\ asm (""
1673 \\ :
1674 \\ : [bruh] "{rax}" (4)
1675 \\ : "memory"
1676 \\ );
1677 \\}
1678 , &.{":3:5: error: global assembly cannot have inputs, outputs, or clobbers"});
1679 }
1680 {
1681 var case = ctx.exe("comptime var", linux_x64);
1682
1683 case.addError(
1684 \\pub fn main() void {
1685 \\ var a: u32 = 0;
1686 \\ comptime var b: u32 = 0;
1687 \\ if (a == 0) b = 3;
1688 \\}
1689 , &.{
1690 ":4:21: error: store to comptime variable depends on runtime condition",
1691 ":4:11: note: runtime condition here",
1692 });
1693
1694 case.addError(
1695 \\pub fn main() void {
1696 \\ var a: u32 = 0;
1697 \\ comptime var b: u32 = 0;
1698 \\ switch (a) {
1699 \\ 0 => {},
1700 \\ else => b = 3,
1701 \\ }
1702 \\}
1703 , &.{
1704 ":6:21: error: store to comptime variable depends on runtime condition",
1705 ":4:13: note: runtime condition here",
1706 });
1707
1708 case.addCompareOutput(
1709 \\pub fn main() void {
1710 \\ comptime var len: u32 = 5;
1711 \\ print(len);
1712 \\ len += 9;
1713 \\ print(len);
1714 \\}
1715 \\
1716 \\fn print(len: usize) void {
1717 \\ asm volatile ("syscall"
1718 \\ :
1719 \\ : [number] "{rax}" (1),
1720 \\ [arg1] "{rdi}" (1),
1721 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
1722 \\ [arg3] "{rdx}" (len)
1723 \\ : "rcx", "r11", "memory"
1724 \\ );
1725 \\ return;
1726 \\}
1727 , "HelloHello, World!\n");
1728
1729 case.addError(
1730 \\comptime {
1731 \\ var x: i32 = 1;
1732 \\ x += 1;
1733 \\ if (x != 1) unreachable;
1734 \\}
1735 \\pub fn main() void {}
1736 , &.{":4:17: error: unable to resolve comptime value"});
1737
1738 case.addError(
1739 \\pub fn main() void {
1740 \\ comptime var i: u64 = 0;
1741 \\ while (i < 5) : (i += 1) {}
1742 \\}
1743 , &.{
1744 ":3:24: error: cannot store to comptime variable in non-inline loop",
1745 ":3:5: note: non-inline loop here",
1746 });
1747
1748 case.addCompareOutput(
1749 \\pub fn main() void {
1750 \\ var a: u32 = 0;
1751 \\ if (a == 0) {
1752 \\ comptime var b: u32 = 0;
1753 \\ b = 1;
1754 \\ }
1755 \\}
1756 \\comptime {
1757 \\ var x: i32 = 1;
1758 \\ x += 1;
1759 \\ if (x != 2) unreachable;
1760 \\}
1761 , "");
1762
1763 case.addCompareOutput(
1764 \\pub fn main() void {
1765 \\ comptime var i: u64 = 2;
1766 \\ inline while (i < 6) : (i+=1) {
1767 \\ print(i);
1768 \\ }
1769 \\}
1770 \\fn print(len: usize) void {
1771 \\ asm volatile ("syscall"
1772 \\ :
1773 \\ : [number] "{rax}" (1),
1774 \\ [arg1] "{rdi}" (1),
1775 \\ [arg2] "{rsi}" (@ptrToInt("Hello")),
1776 \\ [arg3] "{rdx}" (len)
1777 \\ : "rcx", "r11", "memory"
1778 \\ );
1779 \\ return;
1780 \\}
1781 , "HeHelHellHello");
1782 }
1783
1784 {
1785 var case = ctx.exe("double ampersand", linux_x64);
1786
1787 case.addError(
1788 \\pub const a = if (true && false) 1 else 2;
1789 , &[_][]const u8{":1:24: error: `&&` is invalid; note that `and` is boolean AND"});
1790
1791 case.addError(
1792 \\pub fn main() void {
1793 \\ const a = true;
1794 \\ const b = false;
1795 \\ _ = a & &b;
1796 \\}
1797 , &[_][]const u8{
1798 ":4:11: error: incompatible types: 'bool' and '*const bool'",
1799 ":4:9: note: type 'bool' here",
1800 ":4:13: note: type '*const bool' here",
1801 });
1802
1803 case.addCompareOutput(
1804 \\pub fn main() void {
1805 \\ const b: u8 = 1;
1806 \\ _ = &&b;
1807 \\}
1808 , "");
1809 }
1810
1811 {
1812 var case = ctx.exe("setting an address space on a local variable", linux_x64);
1813 case.addError(
1814 \\export fn entry() i32 {
1815 \\ var foo: i32 addrspace(".general") = 1234;
1816 \\ return foo;
1817 \\}
1818 , &[_][]const u8{
1819 ":2:28: error: cannot set address space of local variable 'foo'",
1820 });
1821 }
1822 {
1823 var case = ctx.exe("issue 10138: callee preserved regs working", linux_x64);
1824 case.addCompareOutput(
1825 \\pub fn main() void {
1826 \\ const fd = open();
1827 \\ _ = write(fd, "a", 1);
1828 \\ _ = close(fd);
1829 \\}
1830 \\
1831 \\fn open() usize {
1832 \\ return 42;
1833 \\}
1834 \\
1835 \\fn write(fd: usize, a: [*]const u8, len: usize) usize {
1836 \\ return syscall4(.WRITE, fd, @ptrToInt(a), len);
1837 \\}
1838 \\
1839 \\fn syscall4(n: enum { WRITE }, a: usize, b: usize, c: usize) usize {
1840 \\ _ = n;
1841 \\ _ = a;
1842 \\ _ = b;
1843 \\ _ = c;
1844 \\ return 23;
1845 \\}
1846 \\
1847 \\fn close(fd: usize) usize {
1848 \\ if (fd != 42)
1849 \\ unreachable;
1850 \\ return 0;
1851 \\}
1852 , "");
1853 }
18 try @import("stage2/x86_64.zig").addCases(ctx);
185419}
test/stage2/aarch64.zig+121-1
......@@ -1,12 +1,18 @@
11const std = @import("std");
2const CrossTarget = std.zig.CrossTarget;
23const TestContext = @import("../../src/test.zig").TestContext;
34
4const linux_aarch64 = std.zig.CrossTarget{
5const linux_aarch64 = CrossTarget{
56 .cpu_arch = .aarch64,
67 .os_tag = .linux,
78};
9const macos_aarch64 = CrossTarget{
10 .cpu_arch = .aarch64,
11 .os_tag = .macos,
12};
813
914pub fn addCases(ctx: *TestContext) !void {
15 // Linux tests
1016 {
1117 var case = ctx.exe("linux_aarch64 hello world", linux_aarch64);
1218 // Regular old hello world
......@@ -97,4 +103,118 @@ pub fn addCases(ctx: *TestContext) !void {
97103 "Hello, World!\n",
98104 );
99105 }
106
107 // macOS tests
108 {
109 var case = ctx.exe("hello world with updates", macos_aarch64);
110 case.addError("", &[_][]const u8{
111 ":99:9: error: struct 'tmp.tmp' has no member named 'main'",
112 });
113
114 // Incorrect return type
115 case.addError(
116 \\pub export fn main() noreturn {
117 \\}
118 , &[_][]const u8{
119 ":2:1: error: expected noreturn, found void",
120 });
121
122 // Regular old hello world
123 case.addCompareOutput(
124 \\extern fn write(usize, usize, usize) usize;
125 \\extern fn exit(usize) noreturn;
126 \\
127 \\pub export fn main() noreturn {
128 \\ print();
129 \\
130 \\ exit(0);
131 \\}
132 \\
133 \\fn print() void {
134 \\ const msg = @ptrToInt("Hello, World!\n");
135 \\ const len = 14;
136 \\ _ = write(1, msg, len);
137 \\}
138 ,
139 "Hello, World!\n",
140 );
141
142 // Now using start.zig without an explicit extern exit fn
143 case.addCompareOutput(
144 \\extern fn write(usize, usize, usize) usize;
145 \\
146 \\pub fn main() void {
147 \\ print();
148 \\}
149 \\
150 \\fn print() void {
151 \\ const msg = @ptrToInt("Hello, World!\n");
152 \\ const len = 14;
153 \\ _ = write(1, msg, len);
154 \\}
155 ,
156 "Hello, World!\n",
157 );
158
159 // Print it 4 times and force growth and realloc.
160 case.addCompareOutput(
161 \\extern fn write(usize, usize, usize) usize;
162 \\
163 \\pub fn main() void {
164 \\ print();
165 \\ print();
166 \\ print();
167 \\ print();
168 \\}
169 \\
170 \\fn print() void {
171 \\ const msg = @ptrToInt("Hello, World!\n");
172 \\ const len = 14;
173 \\ _ = write(1, msg, len);
174 \\}
175 ,
176 \\Hello, World!
177 \\Hello, World!
178 \\Hello, World!
179 \\Hello, World!
180 \\
181 );
182
183 // Print it once, and change the message.
184 case.addCompareOutput(
185 \\extern fn write(usize, usize, usize) usize;
186 \\
187 \\pub fn main() void {
188 \\ print();
189 \\}
190 \\
191 \\fn print() void {
192 \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
193 \\ const len = 104;
194 \\ _ = write(1, msg, len);
195 \\}
196 ,
197 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
198 );
199
200 // Now we print it twice.
201 case.addCompareOutput(
202 \\extern fn write(usize, usize, usize) usize;
203 \\
204 \\pub fn main() void {
205 \\ print();
206 \\ print();
207 \\}
208 \\
209 \\fn print() void {
210 \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
211 \\ const len = 104;
212 \\ _ = write(1, msg, len);
213 \\}
214 ,
215 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
216 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
217 \\
218 );
219 }
100220}
test/stage2/darwin.zig deleted-154
......@@ -1,154 +0,0 @@
1const std = @import("std");
2const TestContext = @import("../../src/test.zig").TestContext;
3
4const archs = [2]std.Target.Cpu.Arch{
5 .aarch64, .x86_64,
6};
7
8pub fn addCases(ctx: *TestContext) !void {
9 for (archs) |arch| {
10 const target: std.zig.CrossTarget = .{
11 .cpu_arch = arch,
12 .os_tag = .macos,
13 };
14 {
15 var case = ctx.exe("darwin hello world with updates", target);
16 case.addError("", &[_][]const u8{
17 ":99:9: error: struct 'tmp.tmp' has no member named 'main'",
18 });
19
20 // Incorrect return type
21 case.addError(
22 \\pub export fn main() noreturn {
23 \\}
24 , &[_][]const u8{
25 ":2:1: error: expected noreturn, found void",
26 });
27
28 // Regular old hello world
29 case.addCompareOutput(
30 \\extern fn write(usize, usize, usize) usize;
31 \\extern fn exit(usize) noreturn;
32 \\
33 \\pub export fn main() noreturn {
34 \\ print();
35 \\
36 \\ exit(0);
37 \\}
38 \\
39 \\fn print() void {
40 \\ const msg = @ptrToInt("Hello, World!\n");
41 \\ const len = 14;
42 \\ _ = write(1, msg, len);
43 \\}
44 ,
45 "Hello, World!\n",
46 );
47
48 // Now using start.zig without an explicit extern exit fn
49 case.addCompareOutput(
50 \\extern fn write(usize, usize, usize) usize;
51 \\
52 \\pub fn main() void {
53 \\ print();
54 \\}
55 \\
56 \\fn print() void {
57 \\ const msg = @ptrToInt("Hello, World!\n");
58 \\ const len = 14;
59 \\ _ = write(1, msg, len);
60 \\}
61 ,
62 "Hello, World!\n",
63 );
64
65 // Print it 4 times and force growth and realloc.
66 case.addCompareOutput(
67 \\extern fn write(usize, usize, usize) usize;
68 \\
69 \\pub fn main() void {
70 \\ print();
71 \\ print();
72 \\ print();
73 \\ print();
74 \\}
75 \\
76 \\fn print() void {
77 \\ const msg = @ptrToInt("Hello, World!\n");
78 \\ const len = 14;
79 \\ _ = write(1, msg, len);
80 \\}
81 ,
82 \\Hello, World!
83 \\Hello, World!
84 \\Hello, World!
85 \\Hello, World!
86 \\
87 );
88
89 // Print it once, and change the message.
90 case.addCompareOutput(
91 \\extern fn write(usize, usize, usize) usize;
92 \\
93 \\pub fn main() void {
94 \\ print();
95 \\}
96 \\
97 \\fn print() void {
98 \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
99 \\ const len = 104;
100 \\ _ = write(1, msg, len);
101 \\}
102 ,
103 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
104 );
105
106 // Now we print it twice.
107 case.addCompareOutput(
108 \\extern fn write(usize, usize, usize) usize;
109 \\
110 \\pub fn main() void {
111 \\ print();
112 \\ print();
113 \\}
114 \\
115 \\fn print() void {
116 \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
117 \\ const len = 104;
118 \\ _ = write(1, msg, len);
119 \\}
120 ,
121 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
122 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
123 \\
124 );
125 }
126 {
127 var case = ctx.exe("corner case - update existing, singular TextBlock", target);
128
129 // This test case also covers an infrequent scenario where the string table *may* be relocated
130 // into the position preceeding the symbol table which results in a dyld error.
131 case.addCompareOutput(
132 \\extern fn exit(usize) noreturn;
133 \\
134 \\pub export fn main() noreturn {
135 \\ exit(0);
136 \\}
137 ,
138 "",
139 );
140
141 case.addCompareOutput(
142 \\extern fn exit(usize) noreturn;
143 \\extern fn write(usize, usize, usize) usize;
144 \\
145 \\pub export fn main() noreturn {
146 \\ _ = write(1, @ptrToInt("Hey!\n"), 5);
147 \\ exit(0);
148 \\}
149 ,
150 "Hey!\n",
151 );
152 }
153 }
154}
test/stage2/x86_64.zig created+1976
......@@ -0,0 +1,1976 @@
1const std = @import("std");
2const CrossTarget = std.zig.CrossTarget;
3const TestContext = @import("../../src/test.zig").TestContext;
4
5const linux_x64 = std.zig.CrossTarget{
6 .cpu_arch = .x86_64,
7 .os_tag = .linux,
8};
9const macos_x64 = CrossTarget{
10 .cpu_arch = .x86_64,
11 .os_tag = .macos,
12};
13const all_targets: []const CrossTarget = &[_]CrossTarget{
14 linux_x64,
15 macos_x64,
16};
17
18pub fn addCases(ctx: *TestContext) !void {
19 try addLinuxTestCases(ctx);
20 try addMacOsTestCases(ctx);
21
22 // Common tests
23 for (all_targets) |target| {
24 {
25 var case = ctx.exe("adding numbers at runtime and comptime", target);
26 case.addCompareOutput(
27 \\pub fn main() void {
28 \\ add(3, 4);
29 \\}
30 \\
31 \\fn add(a: u32, b: u32) void {
32 \\ if (a + b != 7) unreachable;
33 \\}
34 ,
35 "",
36 );
37 // comptime function call
38 case.addCompareOutput(
39 \\pub fn main() void {
40 \\ if (x - 7 != 0) unreachable;
41 \\}
42 \\
43 \\fn add(a: u32, b: u32) u32 {
44 \\ return a + b;
45 \\}
46 \\
47 \\const x = add(3, 4);
48 ,
49 "",
50 );
51 // Inline function call
52 case.addCompareOutput(
53 \\pub fn main() void {
54 \\ var x: usize = 3;
55 \\ const y = add(1, 2, x);
56 \\ if (y - 6 != 0) unreachable;
57 \\}
58 \\
59 \\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
60 \\ return a + b + c;
61 \\}
62 ,
63 "",
64 );
65 }
66
67 {
68 var case = ctx.exe("subtracting numbers at runtime", target);
69 case.addCompareOutput(
70 \\pub fn main() void {
71 \\ sub(7, 4);
72 \\}
73 \\
74 \\fn sub(a: u32, b: u32) void {
75 \\ if (a - b != 3) unreachable;
76 \\}
77 ,
78 "",
79 );
80 }
81
82 {
83 var case = ctx.exe("unused vars", target);
84 case.addError(
85 \\pub fn main() void {
86 \\ const x = 1;
87 \\}
88 , &.{":2:11: error: unused local constant"});
89 }
90
91 {
92 var case = ctx.exe("multiplying numbers at runtime and comptime", target);
93 case.addCompareOutput(
94 \\pub fn main() void {
95 \\ mul(3, 4);
96 \\}
97 \\
98 \\fn mul(a: u32, b: u32) void {
99 \\ if (a * b != 12) unreachable;
100 \\}
101 ,
102 "",
103 );
104 // comptime function call
105 case.addCompareOutput(
106 \\pub fn main() void {
107 \\ if (x - 12 != 0) unreachable;
108 \\}
109 \\
110 \\fn mul(a: u32, b: u32) u32 {
111 \\ return a * b;
112 \\}
113 \\
114 \\const x = mul(3, 4);
115 ,
116 "",
117 );
118 // Inline function call
119 case.addCompareOutput(
120 \\pub fn main() void {
121 \\ var x: usize = 5;
122 \\ const y = mul(2, 3, x);
123 \\ if (y - 30 != 0) unreachable;
124 \\}
125 \\
126 \\fn mul(a: usize, b: usize, c: usize) callconv(.Inline) usize {
127 \\ return a * b * c;
128 \\}
129 ,
130 "",
131 );
132 }
133
134 {
135 var case = ctx.exe("assert function", target);
136 case.addCompareOutput(
137 \\pub fn main() void {
138 \\ add(3, 4);
139 \\}
140 \\
141 \\fn add(a: u32, b: u32) void {
142 \\ assert(a + b == 7);
143 \\}
144 \\
145 \\pub fn assert(ok: bool) void {
146 \\ if (!ok) unreachable; // assertion failure
147 \\}
148 ,
149 "",
150 );
151
152 // Tests copying a register. For the `c = a + b`, it has to
153 // preserve both a and b, because they are both used later.
154 case.addCompareOutput(
155 \\pub fn main() void {
156 \\ add(3, 4);
157 \\}
158 \\
159 \\fn add(a: u32, b: u32) void {
160 \\ const c = a + b; // 7
161 \\ const d = a + c; // 10
162 \\ const e = d + b; // 14
163 \\ assert(e == 14);
164 \\}
165 \\
166 \\pub fn assert(ok: bool) void {
167 \\ if (!ok) unreachable; // assertion failure
168 \\}
169 ,
170 "",
171 );
172
173 // More stress on the liveness detection.
174 case.addCompareOutput(
175 \\pub fn main() void {
176 \\ add(3, 4);
177 \\}
178 \\
179 \\fn add(a: u32, b: u32) void {
180 \\ const c = a + b; // 7
181 \\ const d = a + c; // 10
182 \\ const e = d + b; // 14
183 \\ const f = d + e; // 24
184 \\ const g = e + f; // 38
185 \\ const h = f + g; // 62
186 \\ const i = g + h; // 100
187 \\ assert(i == 100);
188 \\}
189 \\
190 \\pub fn assert(ok: bool) void {
191 \\ if (!ok) unreachable; // assertion failure
192 \\}
193 ,
194 "",
195 );
196
197 // Requires a second move. The register allocator should figure out to re-use rax.
198 case.addCompareOutput(
199 \\pub fn main() void {
200 \\ add(3, 4);
201 \\}
202 \\
203 \\fn add(a: u32, b: u32) void {
204 \\ const c = a + b; // 7
205 \\ const d = a + c; // 10
206 \\ const e = d + b; // 14
207 \\ const f = d + e; // 24
208 \\ const g = e + f; // 38
209 \\ const h = f + g; // 62
210 \\ const i = g + h; // 100
211 \\ const j = i + d; // 110
212 \\ assert(j == 110);
213 \\}
214 \\
215 \\pub fn assert(ok: bool) void {
216 \\ if (!ok) unreachable; // assertion failure
217 \\}
218 ,
219 "",
220 );
221
222 // Now we test integer return values.
223 case.addCompareOutput(
224 \\pub fn main() void {
225 \\ assert(add(3, 4) == 7);
226 \\ assert(add(20, 10) == 30);
227 \\}
228 \\
229 \\fn add(a: u32, b: u32) u32 {
230 \\ return a + b;
231 \\}
232 \\
233 \\pub fn assert(ok: bool) void {
234 \\ if (!ok) unreachable; // assertion failure
235 \\}
236 ,
237 "",
238 );
239
240 // Local mutable variables.
241 case.addCompareOutput(
242 \\pub fn main() void {
243 \\ assert(add(3, 4) == 7);
244 \\ assert(add(20, 10) == 30);
245 \\}
246 \\
247 \\fn add(a: u32, b: u32) u32 {
248 \\ var x: u32 = undefined;
249 \\ x = 0;
250 \\ x += a;
251 \\ x += b;
252 \\ return x;
253 \\}
254 \\
255 \\pub fn assert(ok: bool) void {
256 \\ if (!ok) unreachable; // assertion failure
257 \\}
258 ,
259 "",
260 );
261
262 // Optionals
263 case.addCompareOutput(
264 \\pub fn main() void {
265 \\ const a: u32 = 2;
266 \\ const b: ?u32 = a;
267 \\ const c = b.?;
268 \\ if (c != 2) unreachable;
269 \\}
270 ,
271 "",
272 );
273
274 switch (target.getOsTag()) {
275 .linux => {
276 // While loops
277 case.addCompareOutput(
278 \\pub fn main() void {
279 \\ var i: u32 = 0;
280 \\ while (i < 4) : (i += 1) print();
281 \\ assert(i == 4);
282 \\}
283 \\
284 \\fn print() void {
285 \\ asm volatile ("syscall"
286 \\ :
287 \\ : [number] "{rax}" (1),
288 \\ [arg1] "{rdi}" (1),
289 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
290 \\ [arg3] "{rdx}" (6)
291 \\ : "rcx", "r11", "memory"
292 \\ );
293 \\ return;
294 \\}
295 \\
296 \\pub fn assert(ok: bool) void {
297 \\ if (!ok) unreachable; // assertion failure
298 \\}
299 ,
300 "hello\nhello\nhello\nhello\n",
301 );
302
303 // inline while requires the condition to be comptime known.
304 case.addError(
305 \\pub fn main() void {
306 \\ var i: u32 = 0;
307 \\ inline while (i < 4) : (i += 1) print();
308 \\ assert(i == 4);
309 \\}
310 \\
311 \\fn print() void {
312 \\ asm volatile ("syscall"
313 \\ :
314 \\ : [number] "{rax}" (1),
315 \\ [arg1] "{rdi}" (1),
316 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
317 \\ [arg3] "{rdx}" (6)
318 \\ : "rcx", "r11", "memory"
319 \\ );
320 \\ return;
321 \\}
322 \\
323 \\pub fn assert(ok: bool) void {
324 \\ if (!ok) unreachable; // assertion failure
325 \\}
326 , &[_][]const u8{":3:21: error: unable to resolve comptime value"});
327 },
328 .macos => {
329 // While loops
330 case.addCompareOutput(
331 \\extern fn write(usize, usize, usize) usize;
332 \\
333 \\pub fn main() void {
334 \\ var i: u32 = 0;
335 \\ while (i < 4) : (i += 1) print();
336 \\ assert(i == 4);
337 \\}
338 \\
339 \\fn print() void {
340 \\ _ = write(1, @ptrToInt("hello\n"), 6);
341 \\}
342 \\
343 \\pub fn assert(ok: bool) void {
344 \\ if (!ok) unreachable; // assertion failure
345 \\}
346 ,
347 "hello\nhello\nhello\nhello\n",
348 );
349
350 // inline while requires the condition to be comptime known.
351 case.addError(
352 \\extern fn write(usize, usize, usize) usize;
353 \\
354 \\pub fn main() void {
355 \\ var i: u32 = 0;
356 \\ inline while (i < 4) : (i += 1) print();
357 \\ assert(i == 4);
358 \\}
359 \\
360 \\fn print() void {
361 \\ _ = write(1, @ptrToInt("hello\n"), 6);
362 \\}
363 \\
364 \\pub fn assert(ok: bool) void {
365 \\ if (!ok) unreachable; // assertion failure
366 \\}
367 , &[_][]const u8{":5:21: error: unable to resolve comptime value"});
368 },
369 else => unreachable,
370 }
371
372 // Labeled blocks (no conditional branch)
373 case.addCompareOutput(
374 \\pub fn main() void {
375 \\ assert(add(3, 4) == 20);
376 \\}
377 \\
378 \\fn add(a: u32, b: u32) u32 {
379 \\ const x: u32 = blk: {
380 \\ const c = a + b; // 7
381 \\ const d = a + c; // 10
382 \\ const e = d + b; // 14
383 \\ break :blk e;
384 \\ };
385 \\ const y = x + a; // 17
386 \\ const z = y + a; // 20
387 \\ return z;
388 \\}
389 \\
390 \\pub fn assert(ok: bool) void {
391 \\ if (!ok) unreachable; // assertion failure
392 \\}
393 ,
394 "",
395 );
396
397 // This catches a possible bug in the logic for re-using dying operands.
398 case.addCompareOutput(
399 \\pub fn main() void {
400 \\ assert(add(3, 4) == 116);
401 \\}
402 \\
403 \\fn add(a: u32, b: u32) u32 {
404 \\ const x: u32 = blk: {
405 \\ const c = a + b; // 7
406 \\ const d = a + c; // 10
407 \\ const e = d + b; // 14
408 \\ const f = d + e; // 24
409 \\ const g = e + f; // 38
410 \\ const h = f + g; // 62
411 \\ const i = g + h; // 100
412 \\ const j = i + d; // 110
413 \\ break :blk j;
414 \\ };
415 \\ const y = x + a; // 113
416 \\ const z = y + a; // 116
417 \\ return z;
418 \\}
419 \\
420 \\pub fn assert(ok: bool) void {
421 \\ if (!ok) unreachable; // assertion failure
422 \\}
423 ,
424 "",
425 );
426
427 // Spilling registers to the stack.
428 case.addCompareOutput(
429 \\pub fn main() void {
430 \\ assert(add(3, 4) == 1221);
431 \\ assert(mul(3, 4) == 21609);
432 \\}
433 \\
434 \\fn add(a: u32, b: u32) u32 {
435 \\ const x: u32 = blk: {
436 \\ const c = a + b; // 7
437 \\ const d = a + c; // 10
438 \\ const e = d + b; // 14
439 \\ const f = d + e; // 24
440 \\ const g = e + f; // 38
441 \\ const h = f + g; // 62
442 \\ const i = g + h; // 100
443 \\ const j = i + d; // 110
444 \\ const k = i + j; // 210
445 \\ const l = j + k; // 320
446 \\ const m = l + c; // 327
447 \\ const n = m + d; // 337
448 \\ const o = n + e; // 351
449 \\ const p = o + f; // 375
450 \\ const q = p + g; // 413
451 \\ const r = q + h; // 475
452 \\ const s = r + i; // 575
453 \\ const t = s + j; // 685
454 \\ const u = t + k; // 895
455 \\ const v = u + l; // 1215
456 \\ break :blk v;
457 \\ };
458 \\ const y = x + a; // 1218
459 \\ const z = y + a; // 1221
460 \\ return z;
461 \\}
462 \\
463 \\fn mul(a: u32, b: u32) u32 {
464 \\ const x: u32 = blk: {
465 \\ const c = a * a * a * a; // 81
466 \\ const d = a * a * a * b; // 108
467 \\ const e = a * a * b * a; // 108
468 \\ const f = a * a * b * b; // 144
469 \\ const g = a * b * a * a; // 108
470 \\ const h = a * b * a * b; // 144
471 \\ const i = a * b * b * a; // 144
472 \\ const j = a * b * b * b; // 192
473 \\ const k = b * a * a * a; // 108
474 \\ const l = b * a * a * b; // 144
475 \\ const m = b * a * b * a; // 144
476 \\ const n = b * a * b * b; // 192
477 \\ const o = b * b * a * a; // 144
478 \\ const p = b * b * a * b; // 192
479 \\ const q = b * b * b * a; // 192
480 \\ const r = b * b * b * b; // 256
481 \\ const s = c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r; // 2401
482 \\ break :blk s;
483 \\ };
484 \\ const y = x * a; // 7203
485 \\ const z = y * a; // 21609
486 \\ return z;
487 \\}
488 \\
489 \\pub fn assert(ok: bool) void {
490 \\ if (!ok) unreachable; // assertion failure
491 \\}
492 ,
493 "",
494 );
495
496 // Reusing the registers of dead operands playing nicely with conditional branching.
497 case.addCompareOutput(
498 \\pub fn main() void {
499 \\ assert(add(3, 4) == 791);
500 \\ assert(add(4, 3) == 79);
501 \\}
502 \\
503 \\fn add(a: u32, b: u32) u32 {
504 \\ const x: u32 = if (a < b) blk: {
505 \\ const c = a + b; // 7
506 \\ const d = a + c; // 10
507 \\ const e = d + b; // 14
508 \\ const f = d + e; // 24
509 \\ const g = e + f; // 38
510 \\ const h = f + g; // 62
511 \\ const i = g + h; // 100
512 \\ const j = i + d; // 110
513 \\ const k = i + j; // 210
514 \\ const l = k + c; // 217
515 \\ const m = l + d; // 227
516 \\ const n = m + e; // 241
517 \\ const o = n + f; // 265
518 \\ const p = o + g; // 303
519 \\ const q = p + h; // 365
520 \\ const r = q + i; // 465
521 \\ const s = r + j; // 575
522 \\ const t = s + k; // 785
523 \\ break :blk t;
524 \\ } else blk: {
525 \\ const t = b + b + a; // 10
526 \\ const c = a + t; // 14
527 \\ const d = c + t; // 24
528 \\ const e = d + t; // 34
529 \\ const f = e + t; // 44
530 \\ const g = f + t; // 54
531 \\ const h = c + g; // 68
532 \\ break :blk h + b; // 71
533 \\ };
534 \\ const y = x + a; // 788, 75
535 \\ const z = y + a; // 791, 79
536 \\ return z;
537 \\}
538 \\
539 \\pub fn assert(ok: bool) void {
540 \\ if (!ok) unreachable; // assertion failure
541 \\}
542 ,
543 "",
544 );
545
546 // Character literals and multiline strings.
547 case.addCompareOutput(
548 \\pub fn main() void {
549 \\ const ignore =
550 \\ \\ cool thx
551 \\ \\
552 \\ ;
553 \\ _ = ignore;
554 \\ add('ぁ', '\x03');
555 \\}
556 \\
557 \\fn add(a: u32, b: u32) void {
558 \\ assert(a + b == 12356);
559 \\}
560 \\
561 \\pub fn assert(ok: bool) void {
562 \\ if (!ok) unreachable; // assertion failure
563 \\}
564 ,
565 "",
566 );
567
568 // Global const.
569 case.addCompareOutput(
570 \\pub fn main() void {
571 \\ add(aa, bb);
572 \\}
573 \\
574 \\const aa = 'ぁ';
575 \\const bb = '\x03';
576 \\
577 \\fn add(a: u32, b: u32) void {
578 \\ assert(a + b == 12356);
579 \\}
580 \\
581 \\pub fn assert(ok: bool) void {
582 \\ if (!ok) unreachable; // assertion failure
583 \\}
584 ,
585 "",
586 );
587
588 // Array access.
589 case.addCompareOutput(
590 \\pub fn main() void {
591 \\ assert("hello"[0] == 'h');
592 \\}
593 \\
594 \\pub fn assert(ok: bool) void {
595 \\ if (!ok) unreachable; // assertion failure
596 \\}
597 ,
598 "",
599 );
600
601 // Array access to a global array.
602 case.addCompareOutput(
603 \\const hello = "hello".*;
604 \\pub fn main() void {
605 \\ assert(hello[1] == 'e');
606 \\}
607 \\
608 \\pub fn assert(ok: bool) void {
609 \\ if (!ok) unreachable; // assertion failure
610 \\}
611 ,
612 "",
613 );
614
615 // 64bit set stack
616 case.addCompareOutput(
617 \\pub fn main() void {
618 \\ var i: u64 = 0xFFEEDDCCBBAA9988;
619 \\ assert(i == 0xFFEEDDCCBBAA9988);
620 \\}
621 \\
622 \\pub fn assert(ok: bool) void {
623 \\ if (!ok) unreachable; // assertion failure
624 \\}
625 ,
626 "",
627 );
628
629 switch (target.getOsTag()) {
630 .linux => {
631 // Basic for loop
632 case.addCompareOutput(
633 \\pub fn main() void {
634 \\ for ("hello") |_| print();
635 \\}
636 \\
637 \\fn print() void {
638 \\ asm volatile ("syscall"
639 \\ :
640 \\ : [number] "{rax}" (1),
641 \\ [arg1] "{rdi}" (1),
642 \\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
643 \\ [arg3] "{rdx}" (6)
644 \\ : "rcx", "r11", "memory"
645 \\ );
646 \\ return;
647 \\}
648 ,
649 "hello\nhello\nhello\nhello\nhello\n",
650 );
651 },
652 .macos => {
653 // Basic for loop
654 case.addCompareOutput(
655 \\extern fn write(usize, usize, usize) usize;
656 \\
657 \\pub fn main() void {
658 \\ for ("hello") |_| print();
659 \\}
660 \\
661 \\fn print() void {
662 \\ _ = write(1, @ptrToInt("hello\n"), 6);
663 \\}
664 ,
665 "hello\nhello\nhello\nhello\nhello\n",
666 );
667 },
668 else => unreachable,
669 }
670 }
671
672 {
673 var case = ctx.exe("@TypeOf", target);
674 case.addCompareOutput(
675 \\pub fn main() void {
676 \\ var x: usize = 0;
677 \\ _ = x;
678 \\ const z = @TypeOf(x, @as(u128, 5));
679 \\ assert(z == u128);
680 \\}
681 \\
682 \\pub fn assert(ok: bool) void {
683 \\ if (!ok) unreachable; // assertion failure
684 \\}
685 ,
686 "",
687 );
688 case.addCompareOutput(
689 \\pub fn main() void {
690 \\ const z = @TypeOf(true);
691 \\ assert(z == bool);
692 \\}
693 \\
694 \\pub fn assert(ok: bool) void {
695 \\ if (!ok) unreachable; // assertion failure
696 \\}
697 ,
698 "",
699 );
700 case.addError(
701 \\pub fn main() void {
702 \\ _ = @TypeOf(true, 1);
703 \\}
704 , &[_][]const u8{
705 ":2:9: error: incompatible types: 'bool' and 'comptime_int'",
706 ":2:17: note: type 'bool' here",
707 ":2:23: note: type 'comptime_int' here",
708 });
709 }
710
711 {
712 var case = ctx.exe("basic import", target);
713 case.addCompareOutput(
714 \\pub fn main() void {
715 \\ @import("print.zig").print();
716 \\}
717 ,
718 "Hello, World!\n",
719 );
720 switch (target.getOsTag()) {
721 .linux => try case.files.append(.{
722 .src =
723 \\pub fn print() void {
724 \\ asm volatile ("syscall"
725 \\ :
726 \\ : [number] "{rax}" (@as(usize, 1)),
727 \\ [arg1] "{rdi}" (@as(usize, 1)),
728 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
729 \\ [arg3] "{rdx}" (@as(usize, 14))
730 \\ : "rcx", "r11", "memory"
731 \\ );
732 \\ return;
733 \\}
734 ,
735 .path = "print.zig",
736 }),
737 .macos => try case.files.append(.{
738 .src =
739 \\extern fn write(usize, usize, usize) usize;
740 \\
741 \\pub fn print() void {
742 \\ _ = write(1, @ptrToInt("Hello, World!\n"), 14);
743 \\}
744 ,
745 .path = "print.zig",
746 }),
747 else => unreachable,
748 }
749 }
750
751 {
752 var case = ctx.exe("redundant comptime", target);
753 case.addError(
754 \\pub fn main() void {
755 \\ var a: comptime u32 = 0;
756 \\}
757 ,
758 &.{":2:12: error: redundant comptime keyword in already comptime scope"},
759 );
760 case.addError(
761 \\pub fn main() void {
762 \\ comptime {
763 \\ var a: u32 = comptime 0;
764 \\ }
765 \\}
766 ,
767 &.{":3:22: error: redundant comptime keyword in already comptime scope"},
768 );
769 }
770 {
771 var case = ctx.exe("try in comptime in struct in test", target);
772 case.addError(
773 \\test "@unionInit on union w/ tag but no fields" {
774 \\ const S = struct {
775 \\ comptime {
776 \\ try expect(false);
777 \\ }
778 \\ };
779 \\ _ = S;
780 \\}
781 ,
782 &.{":4:13: error: 'try' outside function scope"},
783 );
784 }
785 {
786 var case = ctx.exe("import private", target);
787 case.addError(
788 \\pub fn main() void {
789 \\ @import("print.zig").print();
790 \\}
791 ,
792 &.{
793 ":2:25: error: 'print' is not marked 'pub'",
794 "print.zig:2:1: note: declared here",
795 },
796 );
797 switch (target.getOsTag()) {
798 .linux => try case.files.append(.{
799 .src =
800 \\// dummy comment to make print be on line 2
801 \\fn print() void {
802 \\ asm volatile ("syscall"
803 \\ :
804 \\ : [number] "{rax}" (@as(usize, 1)),
805 \\ [arg1] "{rdi}" (@as(usize, 1)),
806 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
807 \\ [arg3] "{rdx}" (@as(usize, 14))
808 \\ : "rcx", "r11", "memory"
809 \\ );
810 \\ return;
811 \\}
812 ,
813 .path = "print.zig",
814 }),
815 .macos => try case.files.append(.{
816 .src =
817 \\extern fn write(usize, usize, usize) usize;
818 \\fn print() void {
819 \\ _ = write(1, @ptrToInt("Hello, World!\n"), 14);
820 \\}
821 ,
822 .path = "print.zig",
823 }),
824 else => unreachable,
825 }
826 }
827
828 ctx.compileError("function redeclaration", target,
829 \\// dummy comment
830 \\fn entry() void {}
831 \\fn entry() void {}
832 \\
833 \\fn foo() void {
834 \\ var foo = 1234;
835 \\}
836 , &[_][]const u8{
837 ":3:1: error: redeclaration of 'entry'",
838 ":2:1: note: other declaration here",
839 ":6:9: error: local shadows declaration of 'foo'",
840 ":5:1: note: declared here",
841 });
842
843 ctx.compileError("returns in try", target,
844 \\pub fn main() !void {
845 \\ try a();
846 \\ try b();
847 \\}
848 \\
849 \\pub fn a() !void {
850 \\ defer try b();
851 \\}
852 \\pub fn b() !void {
853 \\ defer return a();
854 \\}
855 , &[_][]const u8{
856 ":7:8: error: 'try' not allowed inside defer expression",
857 ":10:8: error: cannot return from defer expression",
858 });
859
860 ctx.compileError("ambiguous references", target,
861 \\const T = struct {
862 \\ const T = struct {
863 \\ fn f() void {
864 \\ _ = T;
865 \\ }
866 \\ };
867 \\};
868 , &.{
869 ":4:17: error: ambiguous reference",
870 ":2:5: note: declared here",
871 ":1:1: note: also declared here",
872 });
873
874 ctx.compileError("inner func accessing outer var", target,
875 \\pub fn f() void {
876 \\ var bar: bool = true;
877 \\ const S = struct {
878 \\ fn baz() bool {
879 \\ return bar;
880 \\ }
881 \\ };
882 \\ _ = S;
883 \\}
884 , &.{
885 ":5:20: error: mutable 'bar' not accessible from here",
886 ":2:9: note: declared mutable here",
887 ":3:15: note: crosses namespace boundary here",
888 });
889
890 ctx.compileError("global variable redeclaration", target,
891 \\// dummy comment
892 \\var foo = false;
893 \\var foo = true;
894 , &[_][]const u8{
895 ":3:1: error: redeclaration of 'foo'",
896 ":2:1: note: other declaration here",
897 });
898
899 ctx.compileError("compileError", target,
900 \\export fn foo() void {
901 \\ @compileError("this is an error");
902 \\}
903 , &[_][]const u8{":2:3: error: this is an error"});
904
905 {
906 var case = ctx.exe("intToPtr", target);
907 case.addError(
908 \\pub fn main() void {
909 \\ _ = @intToPtr(*u8, 0);
910 \\}
911 , &[_][]const u8{
912 ":2:24: error: pointer type '*u8' does not allow address zero",
913 });
914 case.addError(
915 \\pub fn main() void {
916 \\ _ = @intToPtr(*u32, 2);
917 \\}
918 , &[_][]const u8{
919 ":2:25: error: pointer type '*u32' requires aligned address",
920 });
921 }
922
923 {
924 var case = ctx.obj("variable shadowing", target);
925 case.addError(
926 \\pub fn main() void {
927 \\ var i: u32 = 10;
928 \\ var i: u32 = 10;
929 \\}
930 , &[_][]const u8{
931 ":3:9: error: redeclaration of local variable 'i'",
932 ":2:9: note: previous declaration here",
933 });
934 case.addError(
935 \\var testing: i64 = 10;
936 \\pub fn main() void {
937 \\ var testing: i64 = 20;
938 \\}
939 , &[_][]const u8{
940 ":3:9: error: local shadows declaration of 'testing'",
941 ":1:1: note: declared here",
942 });
943 case.addError(
944 \\fn a() type {
945 \\ return struct {
946 \\ pub fn b() void {
947 \\ const c = 6;
948 \\ const c = 69;
949 \\ }
950 \\ };
951 \\}
952 , &[_][]const u8{
953 ":5:19: error: redeclaration of local constant 'c'",
954 ":4:19: note: previous declaration here",
955 });
956 case.addError(
957 \\pub fn main() void {
958 \\ var i = 0;
959 \\ for ("n") |_, i| {
960 \\ }
961 \\}
962 , &[_][]const u8{
963 ":3:19: error: redeclaration of local variable 'i'",
964 ":2:9: note: previous declaration here",
965 });
966 case.addError(
967 \\pub fn main() void {
968 \\ var i = 0;
969 \\ for ("n") |i| {
970 \\ }
971 \\}
972 , &[_][]const u8{
973 ":3:16: error: redeclaration of local variable 'i'",
974 ":2:9: note: previous declaration here",
975 });
976 case.addError(
977 \\pub fn main() void {
978 \\ var i = 0;
979 \\ while ("n") |i| {
980 \\ }
981 \\}
982 , &[_][]const u8{
983 ":3:18: error: redeclaration of local variable 'i'",
984 ":2:9: note: previous declaration here",
985 });
986 case.addError(
987 \\pub fn main() void {
988 \\ var i = 0;
989 \\ while ("n") |bruh| {
990 \\ _ = bruh;
991 \\ } else |i| {
992 \\
993 \\ }
994 \\}
995 , &[_][]const u8{
996 ":5:13: error: redeclaration of local variable 'i'",
997 ":2:9: note: previous declaration here",
998 });
999 case.addError(
1000 \\pub fn main() void {
1001 \\ var i = 0;
1002 \\ if (true) |i| {}
1003 \\}
1004 , &[_][]const u8{
1005 ":3:16: error: redeclaration of local variable 'i'",
1006 ":2:9: note: previous declaration here",
1007 });
1008 case.addError(
1009 \\pub fn main() void {
1010 \\ var i = 0;
1011 \\ if (true) |i| {} else |e| {}
1012 \\}
1013 , &[_][]const u8{
1014 ":3:16: error: redeclaration of local variable 'i'",
1015 ":2:9: note: previous declaration here",
1016 });
1017 case.addError(
1018 \\pub fn main() void {
1019 \\ var i = 0;
1020 \\ if (true) |_| {} else |i| {}
1021 \\}
1022 , &[_][]const u8{
1023 ":3:28: error: redeclaration of local variable 'i'",
1024 ":2:9: note: previous declaration here",
1025 });
1026 }
1027
1028 {
1029 // TODO make the test harness support checking the compile log output too
1030 var case = ctx.obj("@compileLog", target);
1031 // The other compile error prevents emission of a "found compile log" statement.
1032 case.addError(
1033 \\export fn _start() noreturn {
1034 \\ const b = true;
1035 \\ var f: u32 = 1;
1036 \\ @compileLog(b, 20, f, x);
1037 \\ @compileLog(1000);
1038 \\ var bruh: usize = true;
1039 \\ _ = bruh;
1040 \\ unreachable;
1041 \\}
1042 \\export fn other() void {
1043 \\ @compileLog(1234);
1044 \\}
1045 \\fn x() void {}
1046 , &[_][]const u8{
1047 ":6:23: error: expected usize, found bool",
1048 });
1049
1050 // Now only compile log statements remain. One per Decl.
1051 case.addError(
1052 \\export fn _start() noreturn {
1053 \\ const b = true;
1054 \\ var f: u32 = 1;
1055 \\ @compileLog(b, 20, f, x);
1056 \\ @compileLog(1000);
1057 \\ unreachable;
1058 \\}
1059 \\export fn other() void {
1060 \\ @compileLog(1234);
1061 \\}
1062 \\fn x() void {}
1063 , &[_][]const u8{
1064 ":9:5: error: found compile log statement",
1065 ":4:5: note: also here",
1066 });
1067 }
1068
1069 {
1070 var case = ctx.obj("extern variable has no type", target);
1071 case.addError(
1072 \\comptime {
1073 \\ const x = foo + foo;
1074 \\ _ = x;
1075 \\}
1076 \\extern var foo: i32;
1077 , &[_][]const u8{":2:15: error: unable to resolve comptime value"});
1078 case.addError(
1079 \\export fn entry() void {
1080 \\ _ = foo;
1081 \\}
1082 \\extern var foo;
1083 , &[_][]const u8{":4:8: error: unable to infer variable type"});
1084 }
1085
1086 {
1087 var case = ctx.exe("break/continue", target);
1088
1089 // Break out of loop
1090 case.addCompareOutput(
1091 \\pub fn main() void {
1092 \\ while (true) {
1093 \\ break;
1094 \\ }
1095 \\}
1096 ,
1097 "",
1098 );
1099 case.addCompareOutput(
1100 \\pub fn main() void {
1101 \\ foo: while (true) {
1102 \\ break :foo;
1103 \\ }
1104 \\}
1105 ,
1106 "",
1107 );
1108
1109 // Continue in loop
1110 case.addCompareOutput(
1111 \\pub fn main() void {
1112 \\ var i: u64 = 0;
1113 \\ while (true) : (i+=1) {
1114 \\ if (i == 4) return;
1115 \\ continue;
1116 \\ }
1117 \\}
1118 ,
1119 "",
1120 );
1121 case.addCompareOutput(
1122 \\pub fn main() void {
1123 \\ var i: u64 = 0;
1124 \\ foo: while (true) : (i+=1) {
1125 \\ if (i == 4) return;
1126 \\ continue :foo;
1127 \\ }
1128 \\}
1129 ,
1130 "",
1131 );
1132 }
1133
1134 {
1135 var case = ctx.exe("unused labels", target);
1136 case.addError(
1137 \\comptime {
1138 \\ foo: {}
1139 \\}
1140 , &[_][]const u8{":2:5: error: unused block label"});
1141 case.addError(
1142 \\comptime {
1143 \\ foo: while (true) {}
1144 \\}
1145 , &[_][]const u8{":2:5: error: unused while loop label"});
1146 case.addError(
1147 \\comptime {
1148 \\ foo: for ("foo") |_| {}
1149 \\}
1150 , &[_][]const u8{":2:5: error: unused for loop label"});
1151 case.addError(
1152 \\comptime {
1153 \\ blk: {blk: {}}
1154 \\}
1155 , &[_][]const u8{
1156 ":2:11: error: redefinition of label 'blk'",
1157 ":2:5: note: previous definition here",
1158 });
1159 }
1160
1161 {
1162 var case = ctx.exe("bad inferred variable type", target);
1163 case.addError(
1164 \\pub fn main() void {
1165 \\ var x = null;
1166 \\ _ = x;
1167 \\}
1168 , &[_][]const u8{
1169 ":2:9: error: variable of type '@Type(.Null)' must be const or comptime",
1170 });
1171 }
1172
1173 {
1174 var case = ctx.exe("compile error in inline fn call fixed", target);
1175 case.addError(
1176 \\pub fn main() void {
1177 \\ var x: usize = 3;
1178 \\ const y = add(10, 2, x);
1179 \\ if (y - 6 != 0) unreachable;
1180 \\}
1181 \\
1182 \\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
1183 \\ if (a == 10) @compileError("bad");
1184 \\ return a + b + c;
1185 \\}
1186 , &[_][]const u8{":8:18: error: bad"});
1187
1188 case.addCompareOutput(
1189 \\pub fn main() void {
1190 \\ var x: usize = 3;
1191 \\ const y = add(1, 2, x);
1192 \\ if (y - 6 != 0) unreachable;
1193 \\}
1194 \\
1195 \\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
1196 \\ if (a == 10) @compileError("bad");
1197 \\ return a + b + c;
1198 \\}
1199 ,
1200 "",
1201 );
1202 }
1203 {
1204 var case = ctx.exe("recursive inline function", target);
1205 case.addCompareOutput(
1206 \\pub fn main() void {
1207 \\ const y = fibonacci(7);
1208 \\ if (y - 21 != 0) unreachable;
1209 \\}
1210 \\
1211 \\fn fibonacci(n: usize) callconv(.Inline) usize {
1212 \\ if (n <= 2) return n;
1213 \\ return fibonacci(n - 2) + fibonacci(n - 1);
1214 \\}
1215 ,
1216 "",
1217 );
1218 // This additionally tests that the compile error reports the correct source location.
1219 // Without storing source locations relative to the owner decl, the compile error
1220 // here would be off by 2 bytes (from the "7" -> "999").
1221 case.addError(
1222 \\pub fn main() void {
1223 \\ const y = fibonacci(999);
1224 \\ if (y - 21 != 0) unreachable;
1225 \\}
1226 \\
1227 \\fn fibonacci(n: usize) callconv(.Inline) usize {
1228 \\ if (n <= 2) return n;
1229 \\ return fibonacci(n - 2) + fibonacci(n - 1);
1230 \\}
1231 , &[_][]const u8{":8:21: error: evaluation exceeded 1000 backwards branches"});
1232 }
1233 {
1234 var case = ctx.exe("orelse at comptime", target);
1235 case.addCompareOutput(
1236 \\pub fn main() void {
1237 \\ const i: ?u64 = 0;
1238 \\ const result = i orelse 5;
1239 \\ assert(result == 0);
1240 \\}
1241 \\fn assert(b: bool) void {
1242 \\ if (!b) unreachable;
1243 \\}
1244 ,
1245 "",
1246 );
1247 case.addCompareOutput(
1248 \\pub fn main() void {
1249 \\ const i: ?u64 = null;
1250 \\ const result = i orelse 5;
1251 \\ assert(result == 5);
1252 \\}
1253 \\fn assert(b: bool) void {
1254 \\ if (!b) unreachable;
1255 \\}
1256 ,
1257 "",
1258 );
1259 }
1260
1261 {
1262 var case = ctx.exe("passing u0 to function", target);
1263 case.addCompareOutput(
1264 \\pub fn main() void {
1265 \\ doNothing(0);
1266 \\}
1267 \\fn doNothing(arg: u0) void {
1268 \\ _ = arg;
1269 \\}
1270 ,
1271 "",
1272 );
1273 }
1274
1275 {
1276 var case = ctx.exe("catch at comptime", target);
1277 case.addCompareOutput(
1278 \\pub fn main() void {
1279 \\ const i: anyerror!u64 = 0;
1280 \\ const caught = i catch 5;
1281 \\ assert(caught == 0);
1282 \\}
1283 \\fn assert(b: bool) void {
1284 \\ if (!b) unreachable;
1285 \\}
1286 ,
1287 "",
1288 );
1289
1290 case.addCompareOutput(
1291 \\pub fn main() void {
1292 \\ const i: anyerror!u64 = error.B;
1293 \\ const caught = i catch 5;
1294 \\ assert(caught == 5);
1295 \\}
1296 \\fn assert(b: bool) void {
1297 \\ if (!b) unreachable;
1298 \\}
1299 ,
1300 "",
1301 );
1302
1303 case.addCompareOutput(
1304 \\pub fn main() void {
1305 \\ const a: anyerror!comptime_int = 42;
1306 \\ const b: *const comptime_int = &(a catch unreachable);
1307 \\ assert(b.* == 42);
1308 \\}
1309 \\fn assert(b: bool) void {
1310 \\ if (!b) unreachable; // assertion failure
1311 \\}
1312 , "");
1313
1314 case.addCompareOutput(
1315 \\pub fn main() void {
1316 \\ const a: anyerror!u32 = error.B;
1317 \\ _ = &(a catch |err| assert(err == error.B));
1318 \\}
1319 \\fn assert(b: bool) void {
1320 \\ if (!b) unreachable;
1321 \\}
1322 , "");
1323
1324 case.addCompareOutput(
1325 \\pub fn main() void {
1326 \\ const a: anyerror!u32 = error.Bar;
1327 \\ a catch |err| assert(err == error.Bar);
1328 \\}
1329 \\fn assert(b: bool) void {
1330 \\ if (!b) unreachable;
1331 \\}
1332 , "");
1333 }
1334
1335 {
1336 var case = ctx.exe("runtime bitwise and", target);
1337
1338 case.addCompareOutput(
1339 \\pub fn main() void {
1340 \\ var i: u32 = 10;
1341 \\ var j: u32 = 11;
1342 \\ assert(i & 1 == 0);
1343 \\ assert(j & 1 == 1);
1344 \\ var m1: u32 = 0b1111;
1345 \\ var m2: u32 = 0b0000;
1346 \\ assert(m1 & 0b1010 == 0b1010);
1347 \\ assert(m2 & 0b1010 == 0b0000);
1348 \\}
1349 \\fn assert(b: bool) void {
1350 \\ if (!b) unreachable;
1351 \\}
1352 ,
1353 "",
1354 );
1355 }
1356
1357 {
1358 var case = ctx.exe("runtime bitwise or", target);
1359
1360 case.addCompareOutput(
1361 \\pub fn main() void {
1362 \\ var i: u32 = 10;
1363 \\ var j: u32 = 11;
1364 \\ assert(i | 1 == 11);
1365 \\ assert(j | 1 == 11);
1366 \\ var m1: u32 = 0b1111;
1367 \\ var m2: u32 = 0b0000;
1368 \\ assert(m1 | 0b1010 == 0b1111);
1369 \\ assert(m2 | 0b1010 == 0b1010);
1370 \\}
1371 \\fn assert(b: bool) void {
1372 \\ if (!b) unreachable;
1373 \\}
1374 ,
1375 "",
1376 );
1377 }
1378
1379 {
1380 var case = ctx.exe("merge error sets", target);
1381
1382 case.addCompareOutput(
1383 \\pub fn main() void {
1384 \\ const E = error{ A, B, D } || error { A, B, C };
1385 \\ E.A catch {};
1386 \\ E.B catch {};
1387 \\ E.C catch {};
1388 \\ E.D catch {};
1389 \\ const E2 = error { X, Y } || @TypeOf(error.Z);
1390 \\ E2.X catch {};
1391 \\ E2.Y catch {};
1392 \\ E2.Z catch {};
1393 \\ assert(anyerror || error { Z } == anyerror);
1394 \\}
1395 \\fn assert(b: bool) void {
1396 \\ if (!b) unreachable;
1397 \\}
1398 ,
1399 "",
1400 );
1401 case.addError(
1402 \\pub fn main() void {
1403 \\ const z = true || false;
1404 \\ _ = z;
1405 \\}
1406 , &.{
1407 ":2:15: error: expected error set type, found 'bool'",
1408 ":2:20: note: '||' merges error sets; 'or' performs boolean OR",
1409 });
1410 }
1411
1412 {
1413 var case = ctx.exe("error set equality", target);
1414
1415 case.addCompareOutput(
1416 \\pub fn main() void {
1417 \\ assert(@TypeOf(error.Foo) == @TypeOf(error.Foo));
1418 \\ assert(@TypeOf(error.Bar) != @TypeOf(error.Foo));
1419 \\ assert(anyerror == anyerror);
1420 \\ assert(error{Foo} != error{Foo});
1421 \\ // TODO put inferred error sets here when @typeInfo works
1422 \\}
1423 \\fn assert(b: bool) void {
1424 \\ if (!b) unreachable;
1425 \\}
1426 ,
1427 "",
1428 );
1429 }
1430
1431 {
1432 var case = ctx.exe("comptime var", target);
1433
1434 case.addError(
1435 \\pub fn main() void {
1436 \\ var a: u32 = 0;
1437 \\ comptime var b: u32 = 0;
1438 \\ if (a == 0) b = 3;
1439 \\}
1440 , &.{
1441 ":4:21: error: store to comptime variable depends on runtime condition",
1442 ":4:11: note: runtime condition here",
1443 });
1444
1445 case.addError(
1446 \\pub fn main() void {
1447 \\ var a: u32 = 0;
1448 \\ comptime var b: u32 = 0;
1449 \\ switch (a) {
1450 \\ 0 => {},
1451 \\ else => b = 3,
1452 \\ }
1453 \\}
1454 , &.{
1455 ":6:21: error: store to comptime variable depends on runtime condition",
1456 ":4:13: note: runtime condition here",
1457 });
1458
1459 switch (target.getOsTag()) {
1460 .linux => case.addCompareOutput(
1461 \\pub fn main() void {
1462 \\ comptime var len: u32 = 5;
1463 \\ print(len);
1464 \\ len += 9;
1465 \\ print(len);
1466 \\}
1467 \\
1468 \\fn print(len: usize) void {
1469 \\ asm volatile ("syscall"
1470 \\ :
1471 \\ : [number] "{rax}" (1),
1472 \\ [arg1] "{rdi}" (1),
1473 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
1474 \\ [arg3] "{rdx}" (len)
1475 \\ : "rcx", "r11", "memory"
1476 \\ );
1477 \\ return;
1478 \\}
1479 , "HelloHello, World!\n"),
1480 .macos => case.addCompareOutput(
1481 \\extern fn write(usize, usize, usize) usize;
1482 \\
1483 \\pub fn main() void {
1484 \\ comptime var len: u32 = 5;
1485 \\ print(len);
1486 \\ len += 9;
1487 \\ print(len);
1488 \\}
1489 \\
1490 \\fn print(len: usize) void {
1491 \\ _ = write(1, @ptrToInt("Hello, World!\n"), len);
1492 \\}
1493 , "HelloHello, World!\n"),
1494
1495 else => unreachable,
1496 }
1497
1498 case.addError(
1499 \\comptime {
1500 \\ var x: i32 = 1;
1501 \\ x += 1;
1502 \\ if (x != 1) unreachable;
1503 \\}
1504 \\pub fn main() void {}
1505 , &.{":4:17: error: unable to resolve comptime value"});
1506
1507 case.addError(
1508 \\pub fn main() void {
1509 \\ comptime var i: u64 = 0;
1510 \\ while (i < 5) : (i += 1) {}
1511 \\}
1512 , &.{
1513 ":3:24: error: cannot store to comptime variable in non-inline loop",
1514 ":3:5: note: non-inline loop here",
1515 });
1516
1517 case.addCompareOutput(
1518 \\pub fn main() void {
1519 \\ var a: u32 = 0;
1520 \\ if (a == 0) {
1521 \\ comptime var b: u32 = 0;
1522 \\ b = 1;
1523 \\ }
1524 \\}
1525 \\comptime {
1526 \\ var x: i32 = 1;
1527 \\ x += 1;
1528 \\ if (x != 2) unreachable;
1529 \\}
1530 , "");
1531
1532 switch (target.getOsTag()) {
1533 .linux => case.addCompareOutput(
1534 \\pub fn main() void {
1535 \\ comptime var i: u64 = 2;
1536 \\ inline while (i < 6) : (i+=1) {
1537 \\ print(i);
1538 \\ }
1539 \\}
1540 \\fn print(len: usize) void {
1541 \\ asm volatile ("syscall"
1542 \\ :
1543 \\ : [number] "{rax}" (1),
1544 \\ [arg1] "{rdi}" (1),
1545 \\ [arg2] "{rsi}" (@ptrToInt("Hello")),
1546 \\ [arg3] "{rdx}" (len)
1547 \\ : "rcx", "r11", "memory"
1548 \\ );
1549 \\ return;
1550 \\}
1551 , "HeHelHellHello"),
1552 .macos => case.addCompareOutput(
1553 \\extern fn write(usize, usize, usize) usize;
1554 \\
1555 \\pub fn main() void {
1556 \\ comptime var i: u64 = 2;
1557 \\ inline while (i < 6) : (i+=1) {
1558 \\ print(i);
1559 \\ }
1560 \\}
1561 \\fn print(len: usize) void {
1562 \\ _ = write(1, @ptrToInt("Hello"), len);
1563 \\}
1564 , "HeHelHellHello"),
1565 else => unreachable,
1566 }
1567 }
1568
1569 {
1570 var case = ctx.exe("double ampersand", target);
1571
1572 case.addError(
1573 \\pub const a = if (true && false) 1 else 2;
1574 , &[_][]const u8{":1:24: error: `&&` is invalid; note that `and` is boolean AND"});
1575
1576 case.addError(
1577 \\pub fn main() void {
1578 \\ const a = true;
1579 \\ const b = false;
1580 \\ _ = a & &b;
1581 \\}
1582 , &[_][]const u8{
1583 ":4:11: error: incompatible types: 'bool' and '*const bool'",
1584 ":4:9: note: type 'bool' here",
1585 ":4:13: note: type '*const bool' here",
1586 });
1587
1588 case.addCompareOutput(
1589 \\pub fn main() void {
1590 \\ const b: u8 = 1;
1591 \\ _ = &&b;
1592 \\}
1593 , "");
1594 }
1595
1596 {
1597 var case = ctx.exe("setting an address space on a local variable", target);
1598 case.addError(
1599 \\export fn entry() i32 {
1600 \\ var foo: i32 addrspace(".general") = 1234;
1601 \\ return foo;
1602 \\}
1603 , &[_][]const u8{
1604 ":2:28: error: cannot set address space of local variable 'foo'",
1605 });
1606 }
1607 }
1608}
1609
1610fn addLinuxTestCases(ctx: *TestContext) !void {
1611 // Linux tests
1612 {
1613 var case = ctx.exe("hello world with updates", linux_x64);
1614
1615 case.addError("", &[_][]const u8{
1616 ":99:9: error: struct 'tmp.tmp' has no member named 'main'",
1617 });
1618
1619 // Incorrect return type
1620 case.addError(
1621 \\pub export fn _start() noreturn {
1622 \\}
1623 , &[_][]const u8{":2:1: error: expected noreturn, found void"});
1624
1625 // Regular old hello world
1626 case.addCompareOutput(
1627 \\pub export fn _start() noreturn {
1628 \\ print();
1629 \\
1630 \\ exit();
1631 \\}
1632 \\
1633 \\fn print() void {
1634 \\ asm volatile ("syscall"
1635 \\ :
1636 \\ : [number] "{rax}" (1),
1637 \\ [arg1] "{rdi}" (1),
1638 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
1639 \\ [arg3] "{rdx}" (14)
1640 \\ : "rcx", "r11", "memory"
1641 \\ );
1642 \\ return;
1643 \\}
1644 \\
1645 \\fn exit() noreturn {
1646 \\ asm volatile ("syscall"
1647 \\ :
1648 \\ : [number] "{rax}" (231),
1649 \\ [arg1] "{rdi}" (0)
1650 \\ : "rcx", "r11", "memory"
1651 \\ );
1652 \\ unreachable;
1653 \\}
1654 ,
1655 "Hello, World!\n",
1656 );
1657
1658 // Convert to pub fn main
1659 case.addCompareOutput(
1660 \\pub fn main() void {
1661 \\ print();
1662 \\}
1663 \\
1664 \\fn print() void {
1665 \\ asm volatile ("syscall"
1666 \\ :
1667 \\ : [number] "{rax}" (1),
1668 \\ [arg1] "{rdi}" (1),
1669 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
1670 \\ [arg3] "{rdx}" (14)
1671 \\ : "rcx", "r11", "memory"
1672 \\ );
1673 \\ return;
1674 \\}
1675 ,
1676 "Hello, World!\n",
1677 );
1678
1679 // Now change the message only
1680 case.addCompareOutput(
1681 \\pub fn main() void {
1682 \\ print();
1683 \\}
1684 \\
1685 \\fn print() void {
1686 \\ asm volatile ("syscall"
1687 \\ :
1688 \\ : [number] "{rax}" (1),
1689 \\ [arg1] "{rdi}" (1),
1690 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
1691 \\ [arg3] "{rdx}" (104)
1692 \\ : "rcx", "r11", "memory"
1693 \\ );
1694 \\ return;
1695 \\}
1696 ,
1697 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
1698 );
1699 // Now we print it twice.
1700 case.addCompareOutput(
1701 \\pub fn main() void {
1702 \\ print();
1703 \\ print();
1704 \\}
1705 \\
1706 \\fn print() void {
1707 \\ asm volatile ("syscall"
1708 \\ :
1709 \\ : [number] "{rax}" (1),
1710 \\ [arg1] "{rdi}" (1),
1711 \\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
1712 \\ [arg3] "{rdx}" (104)
1713 \\ : "rcx", "r11", "memory"
1714 \\ );
1715 \\ return;
1716 \\}
1717 ,
1718 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
1719 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
1720 \\
1721 );
1722 }
1723
1724 {
1725 var case = ctx.exe("adding numbers at comptime", linux_x64);
1726 case.addCompareOutput(
1727 \\pub export fn _start() noreturn {
1728 \\ asm volatile ("syscall"
1729 \\ :
1730 \\ : [number] "{rax}" (1),
1731 \\ [arg1] "{rdi}" (1),
1732 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
1733 \\ [arg3] "{rdx}" (10 + 4)
1734 \\ : "rcx", "r11", "memory"
1735 \\ );
1736 \\ asm volatile ("syscall"
1737 \\ :
1738 \\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)),
1739 \\ [arg1] "{rdi}" (0)
1740 \\ : "rcx", "r11", "memory"
1741 \\ );
1742 \\ unreachable;
1743 \\}
1744 ,
1745 "Hello, World!\n",
1746 );
1747 }
1748
1749 {
1750 var case = ctx.exe("only 1 function and it gets updated", linux_x64);
1751 case.addCompareOutput(
1752 \\pub export fn _start() noreturn {
1753 \\ asm volatile ("syscall"
1754 \\ :
1755 \\ : [number] "{rax}" (60), // exit
1756 \\ [arg1] "{rdi}" (0)
1757 \\ : "rcx", "r11", "memory"
1758 \\ );
1759 \\ unreachable;
1760 \\}
1761 ,
1762 "",
1763 );
1764 case.addCompareOutput(
1765 \\pub export fn _start() noreturn {
1766 \\ asm volatile ("syscall"
1767 \\ :
1768 \\ : [number] "{rax}" (231), // exit_group
1769 \\ [arg1] "{rdi}" (0)
1770 \\ : "rcx", "r11", "memory"
1771 \\ );
1772 \\ unreachable;
1773 \\}
1774 ,
1775 "",
1776 );
1777 }
1778 {
1779 var case = ctx.exe("inline assembly", linux_x64);
1780
1781 case.addError(
1782 \\pub fn main() void {
1783 \\ const number = 1234;
1784 \\ const x = asm volatile ("syscall"
1785 \\ : [o] "{rax}" (-> number)
1786 \\ : [number] "{rax}" (231),
1787 \\ [arg1] "{rdi}" (60)
1788 \\ : "rcx", "r11", "memory"
1789 \\ );
1790 \\ _ = x;
1791 \\}
1792 , &[_][]const u8{":4:27: error: expected type, found comptime_int"});
1793 case.addError(
1794 \\const S = struct {
1795 \\ comptime {
1796 \\ asm volatile (
1797 \\ \\zig_moment:
1798 \\ \\syscall
1799 \\ );
1800 \\ }
1801 \\};
1802 \\pub fn main() void {
1803 \\ _ = S;
1804 \\}
1805 , &.{":3:13: error: volatile is meaningless on global assembly"});
1806 case.addError(
1807 \\pub fn main() void {
1808 \\ var bruh: u32 = 1;
1809 \\ asm (""
1810 \\ :
1811 \\ : [bruh] "{rax}" (4)
1812 \\ : "memory"
1813 \\ );
1814 \\}
1815 , &.{":3:5: error: assembly expression with no output must be marked volatile"});
1816 case.addError(
1817 \\pub fn main() void {}
1818 \\comptime {
1819 \\ asm (""
1820 \\ :
1821 \\ : [bruh] "{rax}" (4)
1822 \\ : "memory"
1823 \\ );
1824 \\}
1825 , &.{":3:5: error: global assembly cannot have inputs, outputs, or clobbers"});
1826 }
1827
1828 {
1829 var case = ctx.exe("issue 10138: callee preserved regs working", linux_x64);
1830 case.addCompareOutput(
1831 \\pub fn main() void {
1832 \\ const fd = open();
1833 \\ _ = write(fd, "a", 1);
1834 \\ _ = close(fd);
1835 \\}
1836 \\
1837 \\fn open() usize {
1838 \\ return 42;
1839 \\}
1840 \\
1841 \\fn write(fd: usize, a: [*]const u8, len: usize) usize {
1842 \\ return syscall4(.WRITE, fd, @ptrToInt(a), len);
1843 \\}
1844 \\
1845 \\fn syscall4(n: enum { WRITE }, a: usize, b: usize, c: usize) usize {
1846 \\ _ = n;
1847 \\ _ = a;
1848 \\ _ = b;
1849 \\ _ = c;
1850 \\ return 23;
1851 \\}
1852 \\
1853 \\fn close(fd: usize) usize {
1854 \\ if (fd != 42)
1855 \\ unreachable;
1856 \\ return 0;
1857 \\}
1858 , "");
1859 }
1860}
1861
1862fn addMacOsTestCases(ctx: *TestContext) !void {
1863 // macOS tests
1864 {
1865 var case = ctx.exe("darwin hello world with updates", macos_x64);
1866 case.addError("", &[_][]const u8{
1867 ":99:9: error: struct 'tmp.tmp' has no member named 'main'",
1868 });
1869
1870 // Incorrect return type
1871 case.addError(
1872 \\pub export fn main() noreturn {
1873 \\}
1874 , &[_][]const u8{
1875 ":2:1: error: expected noreturn, found void",
1876 });
1877
1878 // Regular old hello world
1879 case.addCompareOutput(
1880 \\extern fn write(usize, usize, usize) usize;
1881 \\extern fn exit(usize) noreturn;
1882 \\
1883 \\pub export fn main() noreturn {
1884 \\ print();
1885 \\
1886 \\ exit(0);
1887 \\}
1888 \\
1889 \\fn print() void {
1890 \\ const msg = @ptrToInt("Hello, World!\n");
1891 \\ const len = 14;
1892 \\ _ = write(1, msg, len);
1893 \\}
1894 ,
1895 "Hello, World!\n",
1896 );
1897
1898 // Now using start.zig without an explicit extern exit fn
1899 case.addCompareOutput(
1900 \\extern fn write(usize, usize, usize) usize;
1901 \\
1902 \\pub fn main() void {
1903 \\ print();
1904 \\}
1905 \\
1906 \\fn print() void {
1907 \\ const msg = @ptrToInt("Hello, World!\n");
1908 \\ const len = 14;
1909 \\ _ = write(1, msg, len);
1910 \\}
1911 ,
1912 "Hello, World!\n",
1913 );
1914
1915 // Print it 4 times and force growth and realloc.
1916 case.addCompareOutput(
1917 \\extern fn write(usize, usize, usize) usize;
1918 \\
1919 \\pub fn main() void {
1920 \\ print();
1921 \\ print();
1922 \\ print();
1923 \\ print();
1924 \\}
1925 \\
1926 \\fn print() void {
1927 \\ const msg = @ptrToInt("Hello, World!\n");
1928 \\ const len = 14;
1929 \\ _ = write(1, msg, len);
1930 \\}
1931 ,
1932 \\Hello, World!
1933 \\Hello, World!
1934 \\Hello, World!
1935 \\Hello, World!
1936 \\
1937 );
1938
1939 // Print it once, and change the message.
1940 case.addCompareOutput(
1941 \\extern fn write(usize, usize, usize) usize;
1942 \\
1943 \\pub fn main() void {
1944 \\ print();
1945 \\}
1946 \\
1947 \\fn print() void {
1948 \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
1949 \\ const len = 104;
1950 \\ _ = write(1, msg, len);
1951 \\}
1952 ,
1953 "What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
1954 );
1955
1956 // Now we print it twice.
1957 case.addCompareOutput(
1958 \\extern fn write(usize, usize, usize) usize;
1959 \\
1960 \\pub fn main() void {
1961 \\ print();
1962 \\ print();
1963 \\}
1964 \\
1965 \\fn print() void {
1966 \\ const msg = @ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n");
1967 \\ const len = 104;
1968 \\ _ = write(1, msg, len);
1969 \\}
1970 ,
1971 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
1972 \\What is up? This is a longer message that will force the data to be relocated in virtual address space.
1973 \\
1974 );
1975 }
1976}