Files
zig/test/stage2/test.zig
Andrew Kelley 3f5ca3920a AstGen: properly restore previous state after temporary changes
Before this, if a compile error occurred, it would cause the previous
value for e.g. the function scope to not get reset. If the AstGen
process continued, it would result in a violation of the data
guarantees that it relies on.

This commit takes advantage of defer to ensure the previous value is
always reset, even in the case of an error.

Closes #8920
2021-05-28 17:29:56 -07:00

1424 lines
44 KiB
Zig

const std = @import("std");
const TestContext = @import("../../src/test.zig").TestContext;
// Self-hosted has differing levels of support for various architectures. For now we pass explicit
// target parameters to each test case. At some point we will take this to the next level and have
// a set of targets that all test cases run on unless specifically overridden. For now, each test
// case applies to only the specified target.
const linux_x64 = std.zig.CrossTarget{
.cpu_arch = .x86_64,
.os_tag = .linux,
};
pub fn addCases(ctx: *TestContext) !void {
try @import("cbe.zig").addCases(ctx);
try @import("arm.zig").addCases(ctx);
try @import("aarch64.zig").addCases(ctx);
try @import("llvm.zig").addCases(ctx);
try @import("wasm.zig").addCases(ctx);
try @import("darwin.zig").addCases(ctx);
try @import("riscv64.zig").addCases(ctx);
{
var case = ctx.exe("hello world with updates", linux_x64);
case.addError("", &[_][]const u8{
":84:9: error: struct 'test_case.test_case' has no member named 'main'",
});
// Incorrect return type
case.addError(
\\pub export fn _start() noreturn {
\\}
, &[_][]const u8{":2:1: error: expected noreturn, found void"});
// Regular old hello world
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ print();
\\
\\ exit();
\\}
\\
\\fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (1),
\\ [arg1] "{rdi}" (1),
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
\\ [arg3] "{rdx}" (14)
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
\\
\\fn exit() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"Hello, World!\n",
);
// Convert to pub fn main
case.addCompareOutput(
\\pub fn main() void {
\\ print();
\\}
\\
\\fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (1),
\\ [arg1] "{rdi}" (1),
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
\\ [arg3] "{rdx}" (14)
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
,
"Hello, World!\n",
);
// Now change the message only
case.addCompareOutput(
\\pub fn main() void {
\\ print();
\\}
\\
\\fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (1),
\\ [arg1] "{rdi}" (1),
\\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
\\ [arg3] "{rdx}" (104)
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
,
"What is up? This is a longer message that will force the data to be relocated in virtual address space.\n",
);
// Now we print it twice.
case.addCompareOutput(
\\pub fn main() void {
\\ print();
\\ print();
\\}
\\
\\fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (1),
\\ [arg1] "{rdi}" (1),
\\ [arg2] "{rsi}" (@ptrToInt("What is up? This is a longer message that will force the data to be relocated in virtual address space.\n")),
\\ [arg3] "{rdx}" (104)
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
,
\\What is up? This is a longer message that will force the data to be relocated in virtual address space.
\\What is up? This is a longer message that will force the data to be relocated in virtual address space.
\\
);
}
{
var case = ctx.exe("adding numbers at comptime", linux_x64);
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (1),
\\ [arg1] "{rdi}" (1),
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
\\ [arg3] "{rdx}" (10 + 4)
\\ : "rcx", "r11", "memory"
\\ );
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (@as(usize, 230) + @as(usize, 1)),
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"Hello, World!\n",
);
}
{
var case = ctx.exe("adding numbers at runtime and comptime", linux_x64);
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ add(3, 4);
\\
\\ exit();
\\}
\\
\\fn add(a: u32, b: u32) void {
\\ if (a + b != 7) unreachable;
\\}
\\
\\fn exit() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
// comptime function call
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ exit();
\\}
\\
\\fn add(a: u32, b: u32) u32 {
\\ return a + b;
\\}
\\
\\const x = add(3, 4);
\\
\\fn exit() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (x - 7)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
// Inline function call
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ var x: usize = 3;
\\ const y = add(1, 2, x);
\\ exit(y - 6);
\\}
\\
\\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
\\ return a + b + c;
\\}
\\
\\fn exit(code: usize) noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (code)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
}
{
var case = ctx.exe("subtracting numbers at runtime", linux_x64);
case.addCompareOutput(
\\pub fn main() void {
\\ sub(7, 4);
\\}
\\
\\fn sub(a: u32, b: u32) void {
\\ if (a - b != 3) unreachable;
\\}
,
"",
);
}
{
var case = ctx.exe("@TypeOf", linux_x64);
case.addCompareOutput(
\\pub fn main() void {
\\ var x: usize = 0;
\\ const z = @TypeOf(x, @as(u128, 5));
\\ assert(z == u128);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
case.addCompareOutput(
\\pub fn main() void {
\\ const z = @TypeOf(true);
\\ assert(z == bool);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
case.addError(
\\pub fn main() void {
\\ const z = @TypeOf(true, 1);
\\}
, &[_][]const u8{":2:15: error: incompatible types: 'bool' and 'comptime_int'"});
}
{
var case = ctx.exe("multiplying numbers at runtime and comptime", linux_x64);
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ mul(3, 4);
\\
\\ exit();
\\}
\\
\\fn mul(a: u32, b: u32) void {
\\ if (a * b != 12) unreachable;
\\}
\\
\\fn exit() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
// comptime function call
case.addCompareOutput(
\\pub fn _start() noreturn {
\\ exit();
\\}
\\
\\fn mul(a: u32, b: u32) u32 {
\\ return a * b;
\\}
\\
\\const x = mul(3, 4);
\\
\\fn exit() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (x - 12)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
// Inline function call
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ var x: usize = 5;
\\ const y = mul(2, 3, x);
\\ exit(y - 30);
\\}
\\
\\fn mul(a: usize, b: usize, c: usize) callconv(.Inline) usize {
\\ return a * b * c;
\\}
\\
\\fn exit(code: usize) noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (code)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
}
{
var case = ctx.exe("assert function", linux_x64);
case.addCompareOutput(
\\pub fn main() void {
\\ add(3, 4);
\\}
\\
\\fn add(a: u32, b: u32) void {
\\ assert(a + b == 7);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
\\
\\fn exit() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
// Tests copying a register. For the `c = a + b`, it has to
// preserve both a and b, because they are both used later.
case.addCompareOutput(
\\pub fn main() void {
\\ add(3, 4);
\\}
\\
\\fn add(a: u32, b: u32) void {
\\ const c = a + b; // 7
\\ const d = a + c; // 10
\\ const e = d + b; // 14
\\ assert(e == 14);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// More stress on the liveness detection.
case.addCompareOutput(
\\pub fn main() void {
\\ add(3, 4);
\\}
\\
\\fn add(a: u32, b: u32) void {
\\ const c = a + b; // 7
\\ const d = a + c; // 10
\\ const e = d + b; // 14
\\ const f = d + e; // 24
\\ const g = e + f; // 38
\\ const h = f + g; // 62
\\ const i = g + h; // 100
\\ assert(i == 100);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Requires a second move. The register allocator should figure out to re-use rax.
case.addCompareOutput(
\\pub fn main() void {
\\ add(3, 4);
\\}
\\
\\fn add(a: u32, b: u32) void {
\\ const c = a + b; // 7
\\ const d = a + c; // 10
\\ const e = d + b; // 14
\\ const f = d + e; // 24
\\ const g = e + f; // 38
\\ const h = f + g; // 62
\\ const i = g + h; // 100
\\ const j = i + d; // 110
\\ assert(j == 110);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Now we test integer return values.
case.addCompareOutput(
\\pub fn main() void {
\\ assert(add(3, 4) == 7);
\\ assert(add(20, 10) == 30);
\\}
\\
\\fn add(a: u32, b: u32) u32 {
\\ return a + b;
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Local mutable variables.
case.addCompareOutput(
\\pub fn main() void {
\\ assert(add(3, 4) == 7);
\\ assert(add(20, 10) == 30);
\\}
\\
\\fn add(a: u32, b: u32) u32 {
\\ var x: u32 = undefined;
\\ x = 0;
\\ x += a;
\\ x += b;
\\ return x;
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Optionals
case.addCompareOutput(
\\pub fn main() void {
\\ const a: u32 = 2;
\\ const b: ?u32 = a;
\\ const c = b.?;
\\ if (c != 2) unreachable;
\\}
,
"",
);
// While loops
case.addCompareOutput(
\\pub fn main() void {
\\ var i: u32 = 0;
\\ while (i < 4) : (i += 1) print();
\\ assert(i == 4);
\\}
\\
\\fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (1),
\\ [arg1] "{rdi}" (1),
\\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
\\ [arg3] "{rdx}" (6)
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"hello\nhello\nhello\nhello\n",
);
// inline while requires the condition to be comptime known.
case.addError(
\\pub fn main() void {
\\ var i: u32 = 0;
\\ inline while (i < 4) : (i += 1) print();
\\ assert(i == 4);
\\}
\\
\\fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (1),
\\ [arg1] "{rdi}" (1),
\\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
\\ [arg3] "{rdx}" (6)
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
, &[_][]const u8{":3:21: error: unable to resolve comptime value"});
// Labeled blocks (no conditional branch)
case.addCompareOutput(
\\pub fn main() void {
\\ assert(add(3, 4) == 20);
\\}
\\
\\fn add(a: u32, b: u32) u32 {
\\ const x: u32 = blk: {
\\ const c = a + b; // 7
\\ const d = a + c; // 10
\\ const e = d + b; // 14
\\ break :blk e;
\\ };
\\ const y = x + a; // 17
\\ const z = y + a; // 20
\\ return z;
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// This catches a possible bug in the logic for re-using dying operands.
case.addCompareOutput(
\\pub fn main() void {
\\ assert(add(3, 4) == 116);
\\}
\\
\\fn add(a: u32, b: u32) u32 {
\\ const x: u32 = blk: {
\\ const c = a + b; // 7
\\ const d = a + c; // 10
\\ const e = d + b; // 14
\\ const f = d + e; // 24
\\ const g = e + f; // 38
\\ const h = f + g; // 62
\\ const i = g + h; // 100
\\ const j = i + d; // 110
\\ break :blk j;
\\ };
\\ const y = x + a; // 113
\\ const z = y + a; // 116
\\ return z;
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Spilling registers to the stack.
case.addCompareOutput(
\\pub fn main() void {
\\ assert(add(3, 4) == 1221);
\\ assert(mul(3, 4) == 21609);
\\}
\\
\\fn add(a: u32, b: u32) u32 {
\\ const x: u32 = blk: {
\\ const c = a + b; // 7
\\ const d = a + c; // 10
\\ const e = d + b; // 14
\\ const f = d + e; // 24
\\ const g = e + f; // 38
\\ const h = f + g; // 62
\\ const i = g + h; // 100
\\ const j = i + d; // 110
\\ const k = i + j; // 210
\\ const l = j + k; // 320
\\ const m = l + c; // 327
\\ const n = m + d; // 337
\\ const o = n + e; // 351
\\ const p = o + f; // 375
\\ const q = p + g; // 413
\\ const r = q + h; // 475
\\ const s = r + i; // 575
\\ const t = s + j; // 685
\\ const u = t + k; // 895
\\ const v = u + l; // 1215
\\ break :blk v;
\\ };
\\ const y = x + a; // 1218
\\ const z = y + a; // 1221
\\ return z;
\\}
\\
\\fn mul(a: u32, b: u32) u32 {
\\ const x: u32 = blk: {
\\ const c = a * a * a * a; // 81
\\ const d = a * a * a * b; // 108
\\ const e = a * a * b * a; // 108
\\ const f = a * a * b * b; // 144
\\ const g = a * b * a * a; // 108
\\ const h = a * b * a * b; // 144
\\ const i = a * b * b * a; // 144
\\ const j = a * b * b * b; // 192
\\ const k = b * a * a * a; // 108
\\ const l = b * a * a * b; // 144
\\ const m = b * a * b * a; // 144
\\ const n = b * a * b * b; // 192
\\ const o = b * b * a * a; // 144
\\ const p = b * b * a * b; // 192
\\ const q = b * b * b * a; // 192
\\ const r = b * b * b * b; // 256
\\ const s = c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r; // 2401
\\ break :blk s;
\\ };
\\ const y = x * a; // 7203
\\ const z = y * a; // 21609
\\ return z;
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Reusing the registers of dead operands playing nicely with conditional branching.
case.addCompareOutput(
\\pub fn main() void {
\\ assert(add(3, 4) == 791);
\\ assert(add(4, 3) == 79);
\\}
\\
\\fn add(a: u32, b: u32) u32 {
\\ const x: u32 = if (a < b) blk: {
\\ const c = a + b; // 7
\\ const d = a + c; // 10
\\ const e = d + b; // 14
\\ const f = d + e; // 24
\\ const g = e + f; // 38
\\ const h = f + g; // 62
\\ const i = g + h; // 100
\\ const j = i + d; // 110
\\ const k = i + j; // 210
\\ const l = k + c; // 217
\\ const m = l + d; // 227
\\ const n = m + e; // 241
\\ const o = n + f; // 265
\\ const p = o + g; // 303
\\ const q = p + h; // 365
\\ const r = q + i; // 465
\\ const s = r + j; // 575
\\ const t = s + k; // 785
\\ break :blk t;
\\ } else blk: {
\\ const t = b + b + a; // 10
\\ const c = a + t; // 14
\\ const d = c + t; // 24
\\ const e = d + t; // 34
\\ const f = e + t; // 44
\\ const g = f + t; // 54
\\ const h = c + g; // 68
\\ break :blk h + b; // 71
\\ };
\\ const y = x + a; // 788, 75
\\ const z = y + a; // 791, 79
\\ return z;
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Character literals and multiline strings.
case.addCompareOutput(
\\pub fn main() void {
\\ const ignore =
\\ \\ cool thx
\\ \\
\\ ;
\\ add('ぁ', '\x03');
\\}
\\
\\fn add(a: u32, b: u32) void {
\\ assert(a + b == 12356);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Global const.
case.addCompareOutput(
\\pub fn main() void {
\\ add(aa, bb);
\\}
\\
\\const aa = 'ぁ';
\\const bb = '\x03';
\\
\\fn add(a: u32, b: u32) void {
\\ assert(a + b == 12356);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Array access.
case.addCompareOutput(
\\pub fn main() void {
\\ assert("hello"[0] == 'h');
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Array access to a global array.
case.addCompareOutput(
\\const hello = "hello".*;
\\pub fn main() void {
\\ assert(hello[1] == 'e');
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// 64bit set stack
case.addCompareOutput(
\\pub fn main() void {
\\ var i: u64 = 0xFFEEDDCCBBAA9988;
\\ assert(i == 0xFFEEDDCCBBAA9988);
\\}
\\
\\pub fn assert(ok: bool) void {
\\ if (!ok) unreachable; // assertion failure
\\}
,
"",
);
// Basic for loop
case.addCompareOutput(
\\pub fn main() void {
\\ for ("hello") |_| print();
\\}
\\
\\fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (1),
\\ [arg1] "{rdi}" (1),
\\ [arg2] "{rsi}" (@ptrToInt("hello\n")),
\\ [arg3] "{rdx}" (6)
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
,
"hello\nhello\nhello\nhello\nhello\n",
);
}
{
var case = ctx.exe("basic import", linux_x64);
case.addCompareOutput(
\\pub fn main() void {
\\ @import("print.zig").print();
\\}
,
"Hello, World!\n",
);
try case.files.append(.{
.src =
\\pub fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (@as(usize, 1)),
\\ [arg1] "{rdi}" (@as(usize, 1)),
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
\\ [arg3] "{rdx}" (@as(usize, 14))
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
,
.path = "print.zig",
});
}
{
var case = ctx.exe("redundant comptime", linux_x64);
case.addError(
\\pub fn main() void {
\\ var a: comptime u32 = 0;
\\}
,
&.{":2:12: error: redundant comptime keyword in already comptime scope"},
);
case.addError(
\\pub fn main() void {
\\ comptime {
\\ var a: u32 = comptime 0;
\\ }
\\}
,
&.{":3:22: error: redundant comptime keyword in already comptime scope"},
);
}
{
var case = ctx.exe("import private", linux_x64);
case.addError(
\\pub fn main() void {
\\ @import("print.zig").print();
\\}
,
&.{
":2:25: error: 'print' is not marked 'pub'",
"print.zig:2:1: note: declared here",
},
);
try case.files.append(.{
.src =
\\// dummy comment to make print be on line 2
\\fn print() void {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (@as(usize, 1)),
\\ [arg1] "{rdi}" (@as(usize, 1)),
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
\\ [arg3] "{rdx}" (@as(usize, 14))
\\ : "rcx", "r11", "memory"
\\ );
\\ return;
\\}
,
.path = "print.zig",
});
}
ctx.compileError("function redeclaration", linux_x64,
\\// dummy comment
\\fn entry() void {}
\\fn entry() void {}
\\
\\fn foo() void {
\\ var foo = 1234;
\\}
, &[_][]const u8{
":3:1: error: redeclaration of 'entry'",
":2:1: note: other declaration here",
":6:9: error: local shadows declaration of 'foo'",
":5:1: note: declared here",
});
ctx.compileError("returns in try", linux_x64,
\\pub fn main() !void {
\\ try a();
\\ try b();
\\}
\\
\\pub fn a() !void {
\\ defer try b();
\\}
\\pub fn b() !void {
\\ defer return a();
\\}
, &[_][]const u8{
":7:8: error: try is not allowed inside defer expression",
":10:8: error: cannot return from defer expression",
});
ctx.compileError("global variable redeclaration", linux_x64,
\\// dummy comment
\\var foo = false;
\\var foo = true;
, &[_][]const u8{
":3:1: error: redeclaration of 'foo'",
":2:1: note: other declaration here",
});
ctx.compileError("compileError", linux_x64,
\\export fn foo() void {
\\ @compileError("this is an error");
\\}
, &[_][]const u8{":2:3: error: this is an error"});
{
var case = ctx.obj("variable shadowing", linux_x64);
case.addError(
\\pub fn main() void {
\\ var i: u32 = 10;
\\ var i: u32 = 10;
\\}
, &[_][]const u8{
":3:9: error: redeclaration of 'i'",
":2:9: note: previously declared here",
});
case.addError(
\\var testing: i64 = 10;
\\pub fn main() void {
\\ var testing: i64 = 20;
\\}
, &[_][]const u8{
":3:9: error: local shadows declaration of 'testing'",
":1:1: note: declared here",
});
case.addError(
\\fn a() type {
\\ return struct {
\\ pub fn b() void {
\\ const c = 6;
\\ const c = 69;
\\ }
\\ };
\\}
, &[_][]const u8{
":5:19: error: redeclaration of 'c'",
":4:19: note: previously declared here",
});
}
{
// TODO make the test harness support checking the compile log output too
var case = ctx.obj("@compileLog", linux_x64);
// The other compile error prevents emission of a "found compile log" statement.
case.addError(
\\export fn _start() noreturn {
\\ const b = true;
\\ var f: u32 = 1;
\\ @compileLog(b, 20, f, x);
\\ @compileLog(1000);
\\ var bruh: usize = true;
\\ unreachable;
\\}
\\export fn other() void {
\\ @compileLog(1234);
\\}
\\fn x() void {}
, &[_][]const u8{
":6:23: error: expected usize, found bool",
});
// Now only compile log statements remain. One per Decl.
case.addError(
\\export fn _start() noreturn {
\\ const b = true;
\\ var f: u32 = 1;
\\ @compileLog(b, 20, f, x);
\\ @compileLog(1000);
\\ unreachable;
\\}
\\export fn other() void {
\\ @compileLog(1234);
\\}
\\fn x() void {}
, &[_][]const u8{
":9:5: error: found compile log statement",
":4:5: note: also here",
});
}
{
var case = ctx.obj("extern variable has no type", linux_x64);
case.addError(
\\comptime {
\\ _ = foo;
\\}
\\extern var foo: i32;
, &[_][]const u8{":2:9: error: unable to resolve comptime value"});
case.addError(
\\export fn entry() void {
\\ _ = foo;
\\}
\\extern var foo;
, &[_][]const u8{":4:8: error: unable to infer variable type"});
}
{
var case = ctx.exe("break/continue", linux_x64);
// Break out of loop
case.addCompareOutput(
\\pub fn main() void {
\\ while (true) {
\\ break;
\\ }
\\}
,
"",
);
case.addCompareOutput(
\\pub fn main() void {
\\ foo: while (true) {
\\ break :foo;
\\ }
\\}
,
"",
);
// Continue in loop
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ var i: u64 = 0;
\\ while (true) : (i+=1) {
\\ if (i == 4) exit();
\\ continue;
\\ }
\\}
\\
\\fn exit() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ var i: u64 = 0;
\\ foo: while (true) : (i+=1) {
\\ if (i == 4) exit();
\\ continue :foo;
\\ }
\\}
\\
\\fn exit() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
}
{
var case = ctx.exe("unused labels", linux_x64);
case.addError(
\\comptime {
\\ foo: {}
\\}
, &[_][]const u8{":2:5: error: unused block label"});
case.addError(
\\comptime {
\\ foo: while (true) {}
\\}
, &[_][]const u8{":2:5: error: unused while loop label"});
case.addError(
\\comptime {
\\ foo: for ("foo") |_| {}
\\}
, &[_][]const u8{":2:5: error: unused for loop label"});
case.addError(
\\comptime {
\\ blk: {blk: {}}
\\}
, &[_][]const u8{
":2:11: error: redefinition of label 'blk'",
":2:5: note: previous definition is here",
});
}
{
var case = ctx.exe("bad inferred variable type", linux_x64);
case.addError(
\\pub fn main() void {
\\ var x = null;
\\}
, &[_][]const u8{
":2:9: error: variable of type '@Type(.Null)' must be const or comptime",
});
}
{
var case = ctx.exe("compile error in inline fn call fixed", linux_x64);
case.addError(
\\pub export fn _start() noreturn {
\\ var x: usize = 3;
\\ const y = add(10, 2, x);
\\ exit(y - 6);
\\}
\\
\\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
\\ if (a == 10) @compileError("bad");
\\ return a + b + c;
\\}
\\
\\fn exit(code: usize) noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (code)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
, &[_][]const u8{":8:18: error: bad"});
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ var x: usize = 3;
\\ const y = add(1, 2, x);
\\ exit(y - 6);
\\}
\\
\\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
\\ if (a == 10) @compileError("bad");
\\ return a + b + c;
\\}
\\
\\fn exit(code: usize) noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (code)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
}
{
var case = ctx.exe("recursive inline function", linux_x64);
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ const y = fibonacci(7);
\\ exit(y - 21);
\\}
\\
\\fn fibonacci(n: usize) callconv(.Inline) usize {
\\ if (n <= 2) return n;
\\ return fibonacci(n - 2) + fibonacci(n - 1);
\\}
\\
\\fn exit(code: usize) noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (code)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
// This additionally tests that the compile error reports the correct source location.
// Without storing source locations relative to the owner decl, the compile error
// here would be off by 2 bytes (from the "7" -> "999").
case.addError(
\\pub export fn _start() noreturn {
\\ const y = fibonacci(999);
\\ exit(y - 21);
\\}
\\
\\fn fibonacci(n: usize) callconv(.Inline) usize {
\\ if (n <= 2) return n;
\\ return fibonacci(n - 2) + fibonacci(n - 1);
\\}
\\
\\fn exit(code: usize) noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (code)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
, &[_][]const u8{":8:21: error: evaluation exceeded 1000 backwards branches"});
}
{
var case = ctx.exe("orelse at comptime", linux_x64);
case.addCompareOutput(
\\pub fn main() void {
\\ const i: ?u64 = 0;
\\ const result = i orelse 5;
\\ assert(result == 0);
\\}
\\fn assert(b: bool) void {
\\ if (!b) unreachable;
\\}
,
"",
);
case.addCompareOutput(
\\pub fn main() void {
\\ const i: ?u64 = null;
\\ const result = i orelse 5;
\\ assert(result == 5);
\\}
\\fn assert(b: bool) void {
\\ if (!b) unreachable;
\\}
,
"",
);
}
{
var case = ctx.exe("only 1 function and it gets updated", linux_x64);
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (60), // exit
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
case.addCompareOutput(
\\pub export fn _start() noreturn {
\\ asm volatile ("syscall"
\\ :
\\ : [number] "{rax}" (231), // exit_group
\\ [arg1] "{rdi}" (0)
\\ : "rcx", "r11", "memory"
\\ );
\\ unreachable;
\\}
,
"",
);
}
{
var case = ctx.exe("passing u0 to function", linux_x64);
case.addCompareOutput(
\\pub fn main() void {
\\ doNothing(0);
\\}
\\fn doNothing(arg: u0) void {}
,
"",
);
}
{
var case = ctx.exe("catch at comptime", linux_x64);
case.addCompareOutput(
\\pub fn main() void {
\\ const i: anyerror!u64 = 0;
\\ const caught = i catch 5;
\\ assert(caught == 0);
\\}
\\fn assert(b: bool) void {
\\ if (!b) unreachable;
\\}
,
"",
);
case.addCompareOutput(
\\pub fn main() void {
\\ const i: anyerror!u64 = error.B;
\\ const caught = i catch 5;
\\ assert(caught == 5);
\\}
\\fn assert(b: bool) void {
\\ if (!b) unreachable;
\\}
,
"",
);
case.addCompareOutput(
\\pub fn main() void {
\\ const a: anyerror!comptime_int = 42;
\\ const b: *const comptime_int = &(a catch unreachable);
\\ assert(b.* == 42);
\\}
\\fn assert(b: bool) void {
\\ if (!b) unreachable; // assertion failure
\\}
, "");
case.addCompareOutput(
\\pub fn main() void {
\\ const a: anyerror!u32 = error.B;
\\ _ = &(a catch |err| assert(err == error.B));
\\}
\\fn assert(b: bool) void {
\\ if (!b) unreachable;
\\}
, "");
case.addCompareOutput(
\\pub fn main() void {
\\ const a: anyerror!u32 = error.Bar;
\\ a catch |err| assert(err == error.Bar);
\\}
\\fn assert(b: bool) void {
\\ if (!b) unreachable;
\\}
, "");
}
{
var case = ctx.exe("merge error sets", linux_x64);
case.addCompareOutput(
\\pub fn main() void {
\\ const E = error{ A, B, D } || error { A, B, C };
\\ const a = E.A;
\\ const b = E.B;
\\ const c = E.C;
\\ const d = E.D;
\\ const E2 = error { X, Y } || @TypeOf(error.Z);
\\ const x = E2.X;
\\ const y = E2.Y;
\\ const z = E2.Z;
\\ assert(anyerror || error { Z } == anyerror);
\\}
\\fn assert(b: bool) void {
\\ if (!b) unreachable;
\\}
,
"",
);
}
{
var case = ctx.exe("inline assembly", linux_x64);
case.addError(
\\pub fn main() void {
\\ const number = 1234;
\\ const x = asm volatile ("syscall"
\\ : [o] "{rax}" (-> number)
\\ : [number] "{rax}" (231),
\\ [arg1] "{rdi}" (code)
\\ : "rcx", "r11", "memory"
\\ );
\\}
, &[_][]const u8{":4:27: error: expected type, found comptime_int"});
}
}