mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
* test runner is improved to respect `error.SkipZigTest`
* start code is improved to `@setAlignStack(16)` before calling main()
* the newly passing behavior test has a workaround for the fact that
stage2 cannot yet call `std.Target.x86.featureSetHas()` at comptime.
This is blocking on comptime closures. The workaround is that there
is a new decl `@import("builtin").stage2_x86_cx16` which is a `bool`.
* Implement `@setAlignStack`. This language feature should be re-evaluated
at some point - I'll file an issue for it.
* LLVM backend: apply/remove the cold attribute and noinline attribute
where appropriate.
* LLVM backend: loads and stores are properly annotated with alignment
and volatile attributes.
* LLVM backend: allocas are properly annotated with alignment.
* Type: fix integers reporting wrong alignment for 256-bit integers and
beyond. Once you get to 16 byte aligned, there is no further
alignment for larger integers.
1810 lines
55 KiB
Zig
1810 lines
55 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("compile_errors.zig").addCases(ctx);
|
|
try @import("stage2/cbe.zig").addCases(ctx);
|
|
try @import("stage2/arm.zig").addCases(ctx);
|
|
try @import("stage2/aarch64.zig").addCases(ctx);
|
|
try @import("stage2/llvm.zig").addCases(ctx);
|
|
try @import("stage2/wasm.zig").addCases(ctx);
|
|
try @import("stage2/darwin.zig").addCases(ctx);
|
|
try @import("stage2/riscv64.zig").addCases(ctx);
|
|
try @import("stage2/plan9.zig").addCases(ctx);
|
|
|
|
{
|
|
var case = ctx.exe("hello world with updates", linux_x64);
|
|
|
|
case.addError("", &[_][]const u8{
|
|
":95:9: error: struct 'tmp.tmp' 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("unused vars", linux_x64);
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ const x = 1;
|
|
\\}
|
|
, &.{":2:11: error: unused local constant"});
|
|
}
|
|
{
|
|
var case = ctx.exe("@TypeOf", linux_x64);
|
|
case.addCompareOutput(
|
|
\\pub fn main() void {
|
|
\\ var x: usize = 0;
|
|
\\ _ = x;
|
|
\\ 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 {
|
|
\\ _ = @TypeOf(true, 1);
|
|
\\}
|
|
, &[_][]const u8{
|
|
":2:9: error: incompatible types: 'bool' and 'comptime_int'",
|
|
":2:17: note: type 'bool' here",
|
|
":2:23: note: type 'comptime_int' here",
|
|
});
|
|
}
|
|
|
|
{
|
|
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
|
|
\\ \\
|
|
\\ ;
|
|
\\ _ = ignore;
|
|
\\ 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("try in comptime in struct in test", linux_x64);
|
|
case.addError(
|
|
\\test "@unionInit on union w/ tag but no fields" {
|
|
\\ const S = struct {
|
|
\\ comptime {
|
|
\\ try expect(false);
|
|
\\ }
|
|
\\ };
|
|
\\ _ = S;
|
|
\\}
|
|
,
|
|
&.{":4:13: error: 'try' outside function 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' not allowed inside defer expression",
|
|
":10:8: error: cannot return from defer expression",
|
|
});
|
|
|
|
ctx.compileError("ambiguous references", linux_x64,
|
|
\\const T = struct {
|
|
\\ const T = struct {
|
|
\\ fn f() void {
|
|
\\ _ = T;
|
|
\\ }
|
|
\\ };
|
|
\\};
|
|
, &.{
|
|
":4:17: error: ambiguous reference",
|
|
":2:5: note: declared here",
|
|
":1:1: note: also declared here",
|
|
});
|
|
|
|
ctx.compileError("inner func accessing outer var", linux_x64,
|
|
\\pub fn f() void {
|
|
\\ var bar: bool = true;
|
|
\\ const S = struct {
|
|
\\ fn baz() bool {
|
|
\\ return bar;
|
|
\\ }
|
|
\\ };
|
|
\\ _ = S;
|
|
\\}
|
|
, &.{
|
|
":5:20: error: mutable 'bar' not accessible from here",
|
|
":2:9: note: declared mutable here",
|
|
":3:15: note: crosses namespace boundary here",
|
|
});
|
|
|
|
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.exe("intToPtr", linux_x64);
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ _ = @intToPtr(*u8, 0);
|
|
\\}
|
|
, &[_][]const u8{
|
|
":2:24: error: pointer type '*u8' does not allow address zero",
|
|
});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ _ = @intToPtr(*u32, 2);
|
|
\\}
|
|
, &[_][]const u8{
|
|
":2:25: error: pointer type '*u32' requires aligned address",
|
|
});
|
|
}
|
|
|
|
{
|
|
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 local variable 'i'",
|
|
":2:9: note: previous declaration 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 local constant 'c'",
|
|
":4:19: note: previous declaration here",
|
|
});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var i = 0;
|
|
\\ for ("n") |_, i| {
|
|
\\ }
|
|
\\}
|
|
, &[_][]const u8{
|
|
":3:19: error: redeclaration of local variable 'i'",
|
|
":2:9: note: previous declaration here",
|
|
});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var i = 0;
|
|
\\ for ("n") |i| {
|
|
\\ }
|
|
\\}
|
|
, &[_][]const u8{
|
|
":3:16: error: redeclaration of local variable 'i'",
|
|
":2:9: note: previous declaration here",
|
|
});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var i = 0;
|
|
\\ while ("n") |i| {
|
|
\\ }
|
|
\\}
|
|
, &[_][]const u8{
|
|
":3:18: error: redeclaration of local variable 'i'",
|
|
":2:9: note: previous declaration here",
|
|
});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var i = 0;
|
|
\\ while ("n") |bruh| {
|
|
\\ _ = bruh;
|
|
\\ } else |i| {
|
|
\\
|
|
\\ }
|
|
\\}
|
|
, &[_][]const u8{
|
|
":5:13: error: redeclaration of local variable 'i'",
|
|
":2:9: note: previous declaration here",
|
|
});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var i = 0;
|
|
\\ if (true) |i| {}
|
|
\\}
|
|
, &[_][]const u8{
|
|
":3:16: error: redeclaration of local variable 'i'",
|
|
":2:9: note: previous declaration here",
|
|
});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var i = 0;
|
|
\\ if (true) |i| {} else |e| {}
|
|
\\}
|
|
, &[_][]const u8{
|
|
":3:16: error: redeclaration of local variable 'i'",
|
|
":2:9: note: previous declaration here",
|
|
});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var i = 0;
|
|
\\ if (true) |_| {} else |i| {}
|
|
\\}
|
|
, &[_][]const u8{
|
|
":3:28: error: redeclaration of local variable 'i'",
|
|
":2:9: note: previous declaration 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;
|
|
\\ _ = bruh;
|
|
\\ 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 {
|
|
\\ const x = foo + foo;
|
|
\\ _ = x;
|
|
\\}
|
|
\\extern var foo: i32;
|
|
, &[_][]const u8{":2:15: 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 here",
|
|
});
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("bad inferred variable type", linux_x64);
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var x = null;
|
|
\\ _ = x;
|
|
\\}
|
|
, &[_][]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 {
|
|
\\ _ = arg;
|
|
\\}
|
|
,
|
|
"",
|
|
);
|
|
}
|
|
{
|
|
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("runtime bitwise and", linux_x64);
|
|
|
|
case.addCompareOutput(
|
|
\\pub fn main() void {
|
|
\\ var i: u32 = 10;
|
|
\\ var j: u32 = 11;
|
|
\\ assert(i & 1 == 0);
|
|
\\ assert(j & 1 == 1);
|
|
\\ var m1: u32 = 0b1111;
|
|
\\ var m2: u32 = 0b0000;
|
|
\\ assert(m1 & 0b1010 == 0b1010);
|
|
\\ assert(m2 & 0b1010 == 0b0000);
|
|
\\}
|
|
\\fn assert(b: bool) void {
|
|
\\ if (!b) unreachable;
|
|
\\}
|
|
,
|
|
"",
|
|
);
|
|
}
|
|
{
|
|
var case = ctx.exe("runtime bitwise or", linux_x64);
|
|
|
|
case.addCompareOutput(
|
|
\\pub fn main() void {
|
|
\\ var i: u32 = 10;
|
|
\\ var j: u32 = 11;
|
|
\\ assert(i | 1 == 11);
|
|
\\ assert(j | 1 == 11);
|
|
\\ var m1: u32 = 0b1111;
|
|
\\ var m2: u32 = 0b0000;
|
|
\\ assert(m1 | 0b1010 == 0b1111);
|
|
\\ assert(m2 | 0b1010 == 0b1010);
|
|
\\}
|
|
\\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 };
|
|
\\ E.A catch {};
|
|
\\ E.B catch {};
|
|
\\ E.C catch {};
|
|
\\ E.D catch {};
|
|
\\ const E2 = error { X, Y } || @TypeOf(error.Z);
|
|
\\ E2.X catch {};
|
|
\\ E2.Y catch {};
|
|
\\ E2.Z catch {};
|
|
\\ assert(anyerror || error { Z } == anyerror);
|
|
\\}
|
|
\\fn assert(b: bool) void {
|
|
\\ if (!b) unreachable;
|
|
\\}
|
|
,
|
|
"",
|
|
);
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ const z = true || false;
|
|
\\ _ = z;
|
|
\\}
|
|
, &.{
|
|
":2:15: error: expected error set type, found 'bool'",
|
|
":2:20: note: '||' merges error sets; 'or' performs boolean OR",
|
|
});
|
|
}
|
|
{
|
|
var case = ctx.exe("error set equality", linux_x64);
|
|
|
|
case.addCompareOutput(
|
|
\\pub fn main() void {
|
|
\\ assert(@TypeOf(error.Foo) == @TypeOf(error.Foo));
|
|
\\ assert(@TypeOf(error.Bar) != @TypeOf(error.Foo));
|
|
\\ assert(anyerror == anyerror);
|
|
\\ assert(error{Foo} != error{Foo});
|
|
\\ // TODO put inferred error sets here when @typeInfo works
|
|
\\}
|
|
\\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}" (60)
|
|
\\ : "rcx", "r11", "memory"
|
|
\\ );
|
|
\\ _ = x;
|
|
\\}
|
|
, &[_][]const u8{":4:27: error: expected type, found comptime_int"});
|
|
case.addError(
|
|
\\const S = struct {
|
|
\\ comptime {
|
|
\\ asm volatile (
|
|
\\ \\zig_moment:
|
|
\\ \\syscall
|
|
\\ );
|
|
\\ }
|
|
\\};
|
|
\\pub fn main() void {
|
|
\\ _ = S;
|
|
\\}
|
|
, &.{":3:13: error: volatile is meaningless on global assembly"});
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var bruh: u32 = 1;
|
|
\\ asm (""
|
|
\\ :
|
|
\\ : [bruh] "{rax}" (4)
|
|
\\ : "memory"
|
|
\\ );
|
|
\\}
|
|
, &.{":3:5: error: assembly expression with no output must be marked volatile"});
|
|
case.addError(
|
|
\\pub fn main() void {}
|
|
\\comptime {
|
|
\\ asm (""
|
|
\\ :
|
|
\\ : [bruh] "{rax}" (4)
|
|
\\ : "memory"
|
|
\\ );
|
|
\\}
|
|
, &.{":3:5: error: global assembly cannot have inputs, outputs, or clobbers"});
|
|
}
|
|
{
|
|
var case = ctx.exe("comptime var", linux_x64);
|
|
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var a: u32 = 0;
|
|
\\ comptime var b: u32 = 0;
|
|
\\ if (a == 0) b = 3;
|
|
\\}
|
|
, &.{
|
|
":4:21: error: store to comptime variable depends on runtime condition",
|
|
":4:11: note: runtime condition here",
|
|
});
|
|
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ var a: u32 = 0;
|
|
\\ comptime var b: u32 = 0;
|
|
\\ switch (a) {
|
|
\\ 0 => {},
|
|
\\ else => b = 3,
|
|
\\ }
|
|
\\}
|
|
, &.{
|
|
":6:21: error: store to comptime variable depends on runtime condition",
|
|
":4:13: note: runtime condition here",
|
|
});
|
|
|
|
case.addCompareOutput(
|
|
\\pub fn main() void {
|
|
\\ comptime var len: u32 = 5;
|
|
\\ print(len);
|
|
\\ len += 9;
|
|
\\ print(len);
|
|
\\}
|
|
\\
|
|
\\fn print(len: usize) void {
|
|
\\ asm volatile ("syscall"
|
|
\\ :
|
|
\\ : [number] "{rax}" (1),
|
|
\\ [arg1] "{rdi}" (1),
|
|
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
|
|
\\ [arg3] "{rdx}" (len)
|
|
\\ : "rcx", "r11", "memory"
|
|
\\ );
|
|
\\ return;
|
|
\\}
|
|
, "HelloHello, World!\n");
|
|
|
|
case.addError(
|
|
\\comptime {
|
|
\\ var x: i32 = 1;
|
|
\\ x += 1;
|
|
\\ if (x != 1) unreachable;
|
|
\\}
|
|
\\pub fn main() void {}
|
|
, &.{":4:17: error: unable to resolve comptime value"});
|
|
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ comptime var i: u64 = 0;
|
|
\\ while (i < 5) : (i += 1) {}
|
|
\\}
|
|
, &.{
|
|
":3:24: error: cannot store to comptime variable in non-inline loop",
|
|
":3:5: note: non-inline loop here",
|
|
});
|
|
|
|
case.addCompareOutput(
|
|
\\pub fn main() void {
|
|
\\ var a: u32 = 0;
|
|
\\ if (a == 0) {
|
|
\\ comptime var b: u32 = 0;
|
|
\\ b = 1;
|
|
\\ }
|
|
\\}
|
|
\\comptime {
|
|
\\ var x: i32 = 1;
|
|
\\ x += 1;
|
|
\\ if (x != 2) unreachable;
|
|
\\}
|
|
, "");
|
|
|
|
case.addCompareOutput(
|
|
\\pub fn main() void {
|
|
\\ comptime var i: u64 = 2;
|
|
\\ inline while (i < 6) : (i+=1) {
|
|
\\ print(i);
|
|
\\ }
|
|
\\}
|
|
\\fn print(len: usize) void {
|
|
\\ asm volatile ("syscall"
|
|
\\ :
|
|
\\ : [number] "{rax}" (1),
|
|
\\ [arg1] "{rdi}" (1),
|
|
\\ [arg2] "{rsi}" (@ptrToInt("Hello")),
|
|
\\ [arg3] "{rdx}" (len)
|
|
\\ : "rcx", "r11", "memory"
|
|
\\ );
|
|
\\ return;
|
|
\\}
|
|
, "HeHelHellHello");
|
|
}
|
|
|
|
{
|
|
var case = ctx.exe("double ampersand", linux_x64);
|
|
|
|
case.addError(
|
|
\\pub const a = if (true && false) 1 else 2;
|
|
, &[_][]const u8{":1:24: error: `&&` is invalid; note that `and` is boolean AND"});
|
|
|
|
case.addError(
|
|
\\pub fn main() void {
|
|
\\ const a = true;
|
|
\\ const b = false;
|
|
\\ _ = a & &b;
|
|
\\}
|
|
, &[_][]const u8{
|
|
":4:11: error: incompatible types: 'bool' and '*const bool'",
|
|
":4:9: note: type 'bool' here",
|
|
":4:13: note: type '*const bool' here",
|
|
});
|
|
|
|
case.addCompareOutput(
|
|
\\pub fn main() void {
|
|
\\ const b: u8 = 1;
|
|
\\ _ = &&b;
|
|
\\}
|
|
, "");
|
|
}
|
|
}
|