2020-08-21 01:25:09 +01:00
|
|
|
const std = @import("std");
|
avoid calling into stage1 backend when AstGen fails
The motivation for this commit is that there exists source files which
produce ast-check errors, but crash stage1 or otherwise trigger stage1
bugs. Previously to this commit, Zig would run AstGen, collect the
compile errors, run stage1, report stage1 compile errors and exit if
any, and then report AstGen compile errors.
The main change in this commit is to report AstGen errors prior to
invoking stage1, and in fact if any AstGen errors occur, do not invoke
stage1 at all.
This caused most of the compile error tests to fail due to things such
as unused local variables and mismatched stage1/stage2 error messages.
It was taking a long time to update the test cases one-by-one, so I
took this opportunity to unify the stage1 and stage2 testing harness,
specifically with regards to compile errors. In this way we can start
keeping track of which tests pass for 1, 2, or both.
`zig build test-compile-errors` no longer works; it is now integrated
into `zig build test-stage2`.
This is one step closer to executing compile error tests in parallel; in
fact the ThreadPool object is already in scope.
There are some cases where the stage1 compile errors were actually
better; those are left failing in this commit, to be addressed in a
follow-up commit.
Other changes in this commit:
* build.zig: improve support for -Dstage1 used with the test step.
* AstGen: minor cosmetic changes to error messages.
* stage2: add -fstage1 and -fno-stage1 flags. This now allows one to
download a binary of the zig compiler and use the llvm backend of
self-hosted. This was also needed for hooking up the test harness.
However, I realized that stage1 calls exit() and also has memory
leaks, so had to complicate the test harness by not using this flag
after all and instead invoking as a child process.
- These CLI flags will disappear once we start shipping the
self-hosted compiler as the main compiler. Until then, they can be
used to try out the work-in-progress stage2.
* stage2: select the LLVM backend by default for release modes, as long
as the target architecture is supported by LLVM.
* test harness: support setting the optimize mode
2021-06-30 19:27:39 +01:00
|
|
|
const TestContext = @import("../src/test.zig").TestContext;
|
2019-11-23 20:56:05 +00:00
|
|
|
|
2020-09-14 03:17:58 +01:00
|
|
|
// 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.
|
|
|
|
|
2020-08-21 01:25:09 +01:00
|
|
|
const linux_x64 = std.zig.CrossTarget{
|
|
|
|
.cpu_arch = .x86_64,
|
|
|
|
.os_tag = .linux,
|
|
|
|
};
|
|
|
|
|
2019-11-23 20:56:05 +00:00
|
|
|
pub fn addCases(ctx: *TestContext) !void {
|
2021-11-19 21:41:10 +00:00
|
|
|
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);
|
2020-08-22 21:36:08 +01:00
|
|
|
|
2020-08-21 01:25:09 +01:00
|
|
|
{
|
|
|
|
var case = ctx.exe("hello world with updates", linux_x64);
|
|
|
|
|
2021-05-14 04:44:34 +01:00
|
|
|
case.addError("", &[_][]const u8{
|
2021-11-28 19:31:12 +00:00
|
|
|
":99:9: error: struct 'tmp.tmp' has no member named 'main'",
|
2021-05-14 04:44:34 +01:00
|
|
|
});
|
2020-08-21 01:25:09 +01:00
|
|
|
|
|
|
|
// Incorrect return type
|
|
|
|
case.addError(
|
2021-05-05 21:16:14 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\}
|
|
|
|
, &[_][]const u8{":2:1: error: expected noreturn, found void"});
|
|
|
|
|
|
|
|
// Regular old hello world
|
|
|
|
case.addCompareOutput(
|
2021-05-05 21:16:14 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"Hello, World!\n",
|
|
|
|
);
|
2021-05-17 22:39:56 +01:00
|
|
|
|
stage2: fix deletion of Decls that get re-referenced
When scanDecls happens, we create stub Decl objects that
have not been semantically analyzed. When they get referenced,
they get semantically analyzed.
Before this commit, when they got unreferenced, they were completely
deleted, including deleted from the containing Namespace.
However, if the update did not cause the containing Namespace to get
deleted, for example, if `std.builtin.ExportOptions` is no longer
referenced, but `std.builtin` is still referenced, and then `ExportOptions`
gets referenced again, the Namespace would be incorrectly missing the
Decl, so we get an incorrect "no such member" error.
The solution is to, when dealing with a no longer referenced Decl
objects during an update, clear them to the state they would be in
on a fresh scanDecl, rather than completely deleting them.
2021-05-18 20:35:36 +01:00
|
|
|
// Convert to pub fn main
|
2020-08-21 01:25:09 +01:00
|
|
|
case.addCompareOutput(
|
stage2: fix deletion of Decls that get re-referenced
When scanDecls happens, we create stub Decl objects that
have not been semantically analyzed. When they get referenced,
they get semantically analyzed.
Before this commit, when they got unreferenced, they were completely
deleted, including deleted from the containing Namespace.
However, if the update did not cause the containing Namespace to get
deleted, for example, if `std.builtin.ExportOptions` is no longer
referenced, but `std.builtin` is still referenced, and then `ExportOptions`
gets referenced again, the Namespace would be incorrectly missing the
Decl, so we get an incorrect "no such member" error.
The solution is to, when dealing with a no longer referenced Decl
objects during an update, clear them to the state they would be in
on a fresh scanDecl, rather than completely deleting them.
2021-05-18 20:35:36 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ print();
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn print() void {
|
|
|
|
\\ asm volatile ("syscall"
|
|
|
|
\\ :
|
|
|
|
\\ : [number] "{rax}" (1),
|
|
|
|
\\ [arg1] "{rdi}" (1),
|
stage2: fix deletion of Decls that get re-referenced
When scanDecls happens, we create stub Decl objects that
have not been semantically analyzed. When they get referenced,
they get semantically analyzed.
Before this commit, when they got unreferenced, they were completely
deleted, including deleted from the containing Namespace.
However, if the update did not cause the containing Namespace to get
deleted, for example, if `std.builtin.ExportOptions` is no longer
referenced, but `std.builtin` is still referenced, and then `ExportOptions`
gets referenced again, the Namespace would be incorrectly missing the
Decl, so we get an incorrect "no such member" error.
The solution is to, when dealing with a no longer referenced Decl
objects during an update, clear them to the state they would be in
on a fresh scanDecl, rather than completely deleting them.
2021-05-18 20:35:36 +01:00
|
|
|
\\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
|
|
|
|
\\ [arg3] "{rdx}" (14)
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ : "rcx", "r11", "memory"
|
|
|
|
\\ );
|
|
|
|
\\ return;
|
|
|
|
\\}
|
stage2: fix deletion of Decls that get re-referenced
When scanDecls happens, we create stub Decl objects that
have not been semantically analyzed. When they get referenced,
they get semantically analyzed.
Before this commit, when they got unreferenced, they were completely
deleted, including deleted from the containing Namespace.
However, if the update did not cause the containing Namespace to get
deleted, for example, if `std.builtin.ExportOptions` is no longer
referenced, but `std.builtin` is still referenced, and then `ExportOptions`
gets referenced again, the Namespace would be incorrectly missing the
Decl, so we get an incorrect "no such member" error.
The solution is to, when dealing with a no longer referenced Decl
objects during an update, clear them to the state they would be in
on a fresh scanDecl, rather than completely deleting them.
2021-05-18 20:35:36 +01:00
|
|
|
,
|
|
|
|
"Hello, World!\n",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Now change the message only
|
|
|
|
case.addCompareOutput(
|
|
|
|
\\pub fn main() void {
|
|
|
|
\\ print();
|
|
|
|
\\}
|
2020-08-21 01:25:09 +01:00
|
|
|
\\
|
stage2: fix deletion of Decls that get re-referenced
When scanDecls happens, we create stub Decl objects that
have not been semantically analyzed. When they get referenced,
they get semantically analyzed.
Before this commit, when they got unreferenced, they were completely
deleted, including deleted from the containing Namespace.
However, if the update did not cause the containing Namespace to get
deleted, for example, if `std.builtin.ExportOptions` is no longer
referenced, but `std.builtin` is still referenced, and then `ExportOptions`
gets referenced again, the Namespace would be incorrectly missing the
Decl, so we get an incorrect "no such member" error.
The solution is to, when dealing with a no longer referenced Decl
objects during an update, clear them to the state they would be in
on a fresh scanDecl, rather than completely deleting them.
2021-05-18 20:35:36 +01:00
|
|
|
\\fn print() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ asm volatile ("syscall"
|
|
|
|
\\ :
|
stage2: fix deletion of Decls that get re-referenced
When scanDecls happens, we create stub Decl objects that
have not been semantically analyzed. When they get referenced,
they get semantically analyzed.
Before this commit, when they got unreferenced, they were completely
deleted, including deleted from the containing Namespace.
However, if the update did not cause the containing Namespace to get
deleted, for example, if `std.builtin.ExportOptions` is no longer
referenced, but `std.builtin` is still referenced, and then `ExportOptions`
gets referenced again, the Namespace would be incorrectly missing the
Decl, so we get an incorrect "no such member" error.
The solution is to, when dealing with a no longer referenced Decl
objects during an update, clear them to the state they would be in
on a fresh scanDecl, rather than completely deleting them.
2021-05-18 20:35:36 +01:00
|
|
|
\\ : [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)
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ : "rcx", "r11", "memory"
|
|
|
|
\\ );
|
stage2: fix deletion of Decls that get re-referenced
When scanDecls happens, we create stub Decl objects that
have not been semantically analyzed. When they get referenced,
they get semantically analyzed.
Before this commit, when they got unreferenced, they were completely
deleted, including deleted from the containing Namespace.
However, if the update did not cause the containing Namespace to get
deleted, for example, if `std.builtin.ExportOptions` is no longer
referenced, but `std.builtin` is still referenced, and then `ExportOptions`
gets referenced again, the Namespace would be incorrectly missing the
Decl, so we get an incorrect "no such member" error.
The solution is to, when dealing with a no longer referenced Decl
objects during an update, clear them to the state they would be in
on a fresh scanDecl, rather than completely deleting them.
2021-05-18 20:35:36 +01:00
|
|
|
\\ return;
|
2020-08-21 01:25:09 +01:00
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"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(
|
stage2: fix deletion of Decls that get re-referenced
When scanDecls happens, we create stub Decl objects that
have not been semantically analyzed. When they get referenced,
they get semantically analyzed.
Before this commit, when they got unreferenced, they were completely
deleted, including deleted from the containing Namespace.
However, if the update did not cause the containing Namespace to get
deleted, for example, if `std.builtin.ExportOptions` is no longer
referenced, but `std.builtin` is still referenced, and then `ExportOptions`
gets referenced again, the Namespace would be incorrectly missing the
Decl, so we get an incorrect "no such member" error.
The solution is to, when dealing with a no longer referenced Decl
objects during an update, clear them to the state they would be in
on a fresh scanDecl, rather than completely deleting them.
2021-05-18 20:35:36 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"Hello, World!\n",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2021-01-02 02:24:02 +00:00
|
|
|
var case = ctx.exe("adding numbers at runtime and comptime", linux_x64);
|
2020-08-21 01:25:09 +01:00
|
|
|
case.addCompareOutput(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
2021-01-02 20:40:23 +00:00
|
|
|
// comptime function call
|
2021-01-02 02:24:02 +00:00
|
|
|
case.addCompareOutput(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-01-02 02:24:02 +00:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2021-01-02 20:40:23 +00:00
|
|
|
// Inline function call
|
|
|
|
case.addCompareOutput(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-01-02 20:40:23 +00:00
|
|
|
\\ var x: usize = 3;
|
|
|
|
\\ const y = add(1, 2, x);
|
|
|
|
\\ exit(y - 6);
|
|
|
|
\\}
|
|
|
|
\\
|
2021-01-11 15:03:09 +00:00
|
|
|
\\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
|
2021-01-02 20:40:23 +00:00
|
|
|
\\ return a + b + c;
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn exit(code: usize) noreturn {
|
|
|
|
\\ asm volatile ("syscall"
|
|
|
|
\\ :
|
|
|
|
\\ : [number] "{rax}" (231),
|
|
|
|
\\ [arg1] "{rdi}" (code)
|
|
|
|
\\ : "rcx", "r11", "memory"
|
|
|
|
\\ );
|
|
|
|
\\ unreachable;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2020-08-21 01:25:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2020-09-01 07:34:58 +01:00
|
|
|
var case = ctx.exe("subtracting numbers at runtime", linux_x64);
|
2020-08-21 01:25:09 +01:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ sub(7, 4);
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn sub(a: u32, b: u32) void {
|
|
|
|
\\ if (a - b != 3) unreachable;
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
2021-06-09 01:32:44 +01:00
|
|
|
{
|
|
|
|
var case = ctx.exe("unused vars", linux_x64);
|
|
|
|
case.addError(
|
|
|
|
\\pub fn main() void {
|
|
|
|
\\ const x = 1;
|
|
|
|
\\}
|
|
|
|
, &.{":2:11: error: unused local constant"});
|
|
|
|
}
|
2020-12-22 23:26:36 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("@TypeOf", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-12-22 23:26:36 +00:00
|
|
|
\\ var x: usize = 0;
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ _ = x;
|
2020-12-22 23:26:36 +00:00
|
|
|
\\ const z = @TypeOf(x, @as(u128, 5));
|
|
|
|
\\ assert(z == u128);
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\pub fn assert(ok: bool) void {
|
|
|
|
\\ if (!ok) unreachable; // assertion failure
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-12-22 23:26:36 +00:00
|
|
|
\\ const z = @TypeOf(true);
|
|
|
|
\\ assert(z == bool);
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\pub fn assert(ok: bool) void {
|
|
|
|
\\ if (!ok) unreachable; // assertion failure
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
case.addError(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ _ = @TypeOf(true, 1);
|
2020-12-22 23:26:36 +00:00
|
|
|
\\}
|
2021-06-23 16:52:46 +01:00
|
|
|
, &[_][]const u8{
|
|
|
|
":2:9: error: incompatible types: 'bool' and 'comptime_int'",
|
|
|
|
":2:17: note: type 'bool' here",
|
|
|
|
":2:23: note: type 'comptime_int' here",
|
|
|
|
});
|
2020-12-22 23:26:36 +00:00
|
|
|
}
|
2020-08-21 01:25:09 +01:00
|
|
|
|
2021-04-09 06:51:00 +01:00
|
|
|
{
|
|
|
|
var case = ctx.exe("multiplying numbers at runtime and comptime", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-14 04:44:34 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-04-09 06:51:00 +01:00
|
|
|
\\ 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(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn _start() noreturn {
|
2021-04-09 06:51:00 +01:00
|
|
|
\\ 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(
|
2021-05-14 04:44:34 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-04-09 06:51:00 +01:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2020-08-21 01:25:09 +01:00
|
|
|
{
|
|
|
|
var case = ctx.exe("assert function", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// 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(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// More stress on the liveness detection.
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Requires a second move. The register allocator should figure out to re-use rax.
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Now we test integer return values.
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Local mutable variables.
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Optionals
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ const a: u32 = 2;
|
|
|
|
\\ const b: ?u32 = a;
|
|
|
|
\\ const c = b.?;
|
|
|
|
\\ if (c != 2) unreachable;
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// While loops
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"hello\nhello\nhello\nhello\n",
|
|
|
|
);
|
|
|
|
|
2021-03-25 07:37:52 +00:00
|
|
|
// inline while requires the condition to be comptime known.
|
|
|
|
case.addError(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-25 07:37:52 +00:00
|
|
|
\\ 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"});
|
|
|
|
|
2020-08-21 01:25:09 +01:00
|
|
|
// Labeled blocks (no conditional branch)
|
2021-03-25 03:58:38 +00:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-25 03:58:38 +00:00
|
|
|
\\ 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
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2020-08-21 01:25:09 +01:00
|
|
|
|
|
|
|
// This catches a possible bug in the logic for re-using dying operands.
|
2021-03-25 03:58:38 +00:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-25 03:58:38 +00:00
|
|
|
\\ 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
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2020-08-22 07:36:21 +01:00
|
|
|
|
|
|
|
// Spilling registers to the stack.
|
2021-03-25 03:58:38 +00:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-04-09 07:05:53 +01:00
|
|
|
\\ assert(add(3, 4) == 1221);
|
2021-04-09 06:51:00 +01:00
|
|
|
\\ assert(mul(3, 4) == 21609);
|
2021-03-25 03:58:38 +00:00
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\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
|
2021-04-09 07:05:53 +01:00
|
|
|
\\ 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;
|
2021-03-25 03:58:38 +00:00
|
|
|
\\ };
|
2021-04-09 07:05:53 +01:00
|
|
|
\\ const y = x + a; // 1218
|
|
|
|
\\ const z = y + a; // 1221
|
2021-03-25 03:58:38 +00:00
|
|
|
\\ return z;
|
|
|
|
\\}
|
|
|
|
\\
|
2021-04-09 06:51:00 +01:00
|
|
|
\\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;
|
2021-03-25 03:58:38 +00:00
|
|
|
\\ };
|
2021-04-09 06:51:00 +01:00
|
|
|
\\ const y = x * a; // 7203
|
|
|
|
\\ const z = y * a; // 21609
|
2021-03-25 03:58:38 +00:00
|
|
|
\\ return z;
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\pub fn assert(ok: bool) void {
|
|
|
|
\\ if (!ok) unreachable; // assertion failure
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2020-08-26 09:00:04 +01:00
|
|
|
|
|
|
|
// Reusing the registers of dead operands playing nicely with conditional branching.
|
2021-03-25 03:58:38 +00:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-25 03:58:38 +00:00
|
|
|
\\ 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
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2020-08-21 01:25:09 +01:00
|
|
|
|
|
|
|
// Character literals and multiline strings.
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-12-06 17:36:49 +00:00
|
|
|
\\ const ignore =
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ \\ cool thx
|
|
|
|
\\ \\
|
|
|
|
\\ ;
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ _ = ignore;
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ add('ぁ', '\x03');
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn add(a: u32, b: u32) void {
|
|
|
|
\\ assert(a + b == 12356);
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\pub fn assert(ok: bool) void {
|
|
|
|
\\ if (!ok) unreachable; // assertion failure
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-21 01:25:09 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Global const.
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-21 01:25:09 +01:00
|
|
|
\\ 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
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-25 17:59:35 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Array access.
|
2021-03-25 20:03:54 +00:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-25 20:03:54 +00:00
|
|
|
\\ assert("hello"[0] == 'h');
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\pub fn assert(ok: bool) void {
|
|
|
|
\\ if (!ok) unreachable; // assertion failure
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2020-08-26 19:07:56 +01:00
|
|
|
|
2021-04-09 05:56:42 +01:00
|
|
|
// Array access to a global array.
|
|
|
|
case.addCompareOutput(
|
|
|
|
\\const hello = "hello".*;
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-04-09 05:56:42 +01:00
|
|
|
\\ assert(hello[1] == 'e');
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\pub fn assert(ok: bool) void {
|
|
|
|
\\ if (!ok) unreachable; // assertion failure
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
2020-08-26 19:07:56 +01:00
|
|
|
// 64bit set stack
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2020-08-26 19:07:56 +01:00
|
|
|
\\ var i: u64 = 0xFFEEDDCCBBAA9988;
|
|
|
|
\\ assert(i == 0xFFEEDDCCBBAA9988);
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\pub fn assert(ok: bool) void {
|
|
|
|
\\ if (!ok) unreachable; // assertion failure
|
|
|
|
\\}
|
2020-09-27 10:27:40 +01:00
|
|
|
,
|
2020-08-26 19:07:56 +01:00
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
// Basic for loop
|
2021-03-26 02:25:26 +00:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-26 02:25:26 +00:00
|
|
|
\\ 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",
|
|
|
|
);
|
2020-08-21 01:25:09 +01:00
|
|
|
}
|
|
|
|
|
2021-03-26 02:39:30 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("basic import", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-26 02:39:30 +00:00
|
|
|
\\ @import("print.zig").print();
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"Hello, World!\n",
|
|
|
|
);
|
|
|
|
try case.files.append(.{
|
2021-08-29 18:41:57 +01:00
|
|
|
.src =
|
2021-03-26 02:39:30 +00:00
|
|
|
\\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",
|
|
|
|
});
|
|
|
|
}
|
2021-04-28 22:01:24 +01:00
|
|
|
{
|
|
|
|
var case = ctx.exe("redundant comptime", linux_x64);
|
|
|
|
case.addError(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-04-28 22:01:24 +01:00
|
|
|
\\ var a: comptime u32 = 0;
|
|
|
|
\\}
|
|
|
|
,
|
2021-05-14 07:51:22 +01:00
|
|
|
&.{":2:12: error: redundant comptime keyword in already comptime scope"},
|
2021-04-28 22:01:24 +01:00
|
|
|
);
|
|
|
|
case.addError(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-04-28 22:01:24 +01:00
|
|
|
\\ comptime {
|
|
|
|
\\ var a: u32 = comptime 0;
|
|
|
|
\\ }
|
|
|
|
\\}
|
|
|
|
,
|
2021-05-14 07:51:22 +01:00
|
|
|
&.{":3:22: error: redundant comptime keyword in already comptime scope"},
|
2021-04-28 22:01:24 +01:00
|
|
|
);
|
|
|
|
}
|
2021-06-13 20:27:27 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
\\ }
|
|
|
|
\\ };
|
2021-06-10 02:35:42 +01:00
|
|
|
\\ _ = S;
|
2021-06-13 20:27:27 +01:00
|
|
|
\\}
|
|
|
|
,
|
2021-07-11 15:03:47 +01:00
|
|
|
&.{":4:13: error: 'try' outside function scope"},
|
2021-06-13 20:27:27 +01:00
|
|
|
);
|
|
|
|
}
|
2021-04-09 05:09:21 +01:00
|
|
|
{
|
|
|
|
var case = ctx.exe("import private", linux_x64);
|
|
|
|
case.addError(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-04-09 05:09:21 +01:00
|
|
|
\\ @import("print.zig").print();
|
|
|
|
\\}
|
|
|
|
,
|
stage2: entry point via std lib and proper updated file detection
Instead of Module setting up the root_scope with the root source file,
instead, Module relies on the package table graph being set up properly,
and inside `update()`, it does the equivalent of `_ = @import("std");`.
This, in term, imports start.zig, which has the logic to call main (or
not). `Module` no longer has `root_scope` - the root source file is no
longer special, it's just in the package table mapped to "root".
I also went ahead and implemented proper detection of updated files.
mtime, inode, size, and source hash are kept in `Scope.File`.
During an update, iterate over `import_table` and stat each file to find
out which ones are updated.
The source hash is redundant with the source hash used by the struct
decl that corresponds to the file, so it should be removed in a future
commit before merging the branch.
* AstGen: add "previously declared here" notes for variables shadowing
decls.
* Parse imports as structs. Module now calls `AstGen.structDeclInner`,
which is called by `AstGen.containerDecl`.
- `importFile` is a bit kludgy with how it handles the top level Decl
that kinda gets merged into the struct decl at the end of the
function. Be on the look out for bugs related to that as well as
possibly cleaner ways to implement this.
* Module: factor out lookupDeclName into lookupIdentifier and lookupNa
* Rename `Scope.Container` to `Scope.Namespace`.
* Delete some dead code.
This branch won't work until `usingnamespace` is implemented because it
relies on `@import("builtin").OutputMode` and `OutputMode` comes from a
`usingnamespace`.
2021-04-10 07:17:50 +01:00
|
|
|
&.{
|
|
|
|
":2:25: error: 'print' is not marked 'pub'",
|
|
|
|
"print.zig:2:1: note: declared here",
|
|
|
|
},
|
2021-04-09 05:09:21 +01:00
|
|
|
);
|
|
|
|
try case.files.append(.{
|
2021-08-29 18:41:57 +01:00
|
|
|
.src =
|
stage2: entry point via std lib and proper updated file detection
Instead of Module setting up the root_scope with the root source file,
instead, Module relies on the package table graph being set up properly,
and inside `update()`, it does the equivalent of `_ = @import("std");`.
This, in term, imports start.zig, which has the logic to call main (or
not). `Module` no longer has `root_scope` - the root source file is no
longer special, it's just in the package table mapped to "root".
I also went ahead and implemented proper detection of updated files.
mtime, inode, size, and source hash are kept in `Scope.File`.
During an update, iterate over `import_table` and stat each file to find
out which ones are updated.
The source hash is redundant with the source hash used by the struct
decl that corresponds to the file, so it should be removed in a future
commit before merging the branch.
* AstGen: add "previously declared here" notes for variables shadowing
decls.
* Parse imports as structs. Module now calls `AstGen.structDeclInner`,
which is called by `AstGen.containerDecl`.
- `importFile` is a bit kludgy with how it handles the top level Decl
that kinda gets merged into the struct decl at the end of the
function. Be on the look out for bugs related to that as well as
possibly cleaner ways to implement this.
* Module: factor out lookupDeclName into lookupIdentifier and lookupNa
* Rename `Scope.Container` to `Scope.Namespace`.
* Delete some dead code.
This branch won't work until `usingnamespace` is implemented because it
relies on `@import("builtin").OutputMode` and `OutputMode` comes from a
`usingnamespace`.
2021-04-10 07:17:50 +01:00
|
|
|
\\// dummy comment to make print be on line 2
|
2021-04-09 05:09:21 +01:00
|
|
|
\\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",
|
|
|
|
});
|
|
|
|
}
|
2020-09-09 17:24:21 +01:00
|
|
|
|
stage2: entry point via std lib and proper updated file detection
Instead of Module setting up the root_scope with the root source file,
instead, Module relies on the package table graph being set up properly,
and inside `update()`, it does the equivalent of `_ = @import("std");`.
This, in term, imports start.zig, which has the logic to call main (or
not). `Module` no longer has `root_scope` - the root source file is no
longer special, it's just in the package table mapped to "root".
I also went ahead and implemented proper detection of updated files.
mtime, inode, size, and source hash are kept in `Scope.File`.
During an update, iterate over `import_table` and stat each file to find
out which ones are updated.
The source hash is redundant with the source hash used by the struct
decl that corresponds to the file, so it should be removed in a future
commit before merging the branch.
* AstGen: add "previously declared here" notes for variables shadowing
decls.
* Parse imports as structs. Module now calls `AstGen.structDeclInner`,
which is called by `AstGen.containerDecl`.
- `importFile` is a bit kludgy with how it handles the top level Decl
that kinda gets merged into the struct decl at the end of the
function. Be on the look out for bugs related to that as well as
possibly cleaner ways to implement this.
* Module: factor out lookupDeclName into lookupIdentifier and lookupNa
* Rename `Scope.Container` to `Scope.Namespace`.
* Delete some dead code.
This branch won't work until `usingnamespace` is implemented because it
relies on `@import("builtin").OutputMode` and `OutputMode` comes from a
`usingnamespace`.
2021-04-10 07:17:50 +01:00
|
|
|
ctx.compileError("function redeclaration", linux_x64,
|
2021-04-09 04:37:19 +01:00
|
|
|
\\// dummy comment
|
2020-08-21 01:25:09 +01:00
|
|
|
\\fn entry() void {}
|
|
|
|
\\fn entry() void {}
|
2021-05-14 07:51:22 +01:00
|
|
|
\\
|
|
|
|
\\fn foo() void {
|
|
|
|
\\ var foo = 1234;
|
|
|
|
\\}
|
2021-04-09 04:37:19 +01:00
|
|
|
, &[_][]const u8{
|
2021-05-14 07:51:22 +01:00
|
|
|
":3:1: error: redeclaration of 'entry'",
|
2021-05-14 08:08:29 +01:00
|
|
|
":2:1: note: other declaration here",
|
2021-05-14 07:51:22 +01:00
|
|
|
":6:9: error: local shadows declaration of 'foo'",
|
|
|
|
":5:1: note: declared here",
|
2021-04-09 04:37:19 +01:00
|
|
|
});
|
|
|
|
|
2021-05-20 21:03:50 +01:00
|
|
|
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();
|
|
|
|
\\}
|
2021-05-29 01:29:56 +01:00
|
|
|
, &[_][]const u8{
|
2021-07-02 01:28:21 +01:00
|
|
|
":7:8: error: 'try' not allowed inside defer expression",
|
2021-05-20 21:03:50 +01:00
|
|
|
":10:8: error: cannot return from defer expression",
|
|
|
|
});
|
|
|
|
|
2021-05-28 02:29:14 +01:00
|
|
|
ctx.compileError("ambiguous references", linux_x64,
|
|
|
|
\\const T = struct {
|
|
|
|
\\ const T = struct {
|
|
|
|
\\ fn f() void {
|
|
|
|
\\ _ = T;
|
|
|
|
\\ }
|
|
|
|
\\ };
|
|
|
|
\\};
|
|
|
|
, &.{
|
|
|
|
":4:17: error: ambiguous reference",
|
2021-08-28 23:15:46 +01:00
|
|
|
":2:5: note: declared here",
|
|
|
|
":1:1: note: also declared here",
|
2021-05-28 02:29:14 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
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;
|
|
|
|
\\ }
|
|
|
|
\\ };
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ _ = S;
|
2021-05-28 02:29:14 +01:00
|
|
|
\\}
|
|
|
|
, &.{
|
2021-08-28 23:15:46 +01:00
|
|
|
":5:20: error: mutable 'bar' not accessible from here",
|
|
|
|
":2:9: note: declared mutable here",
|
|
|
|
":3:15: note: crosses namespace boundary here",
|
2021-05-28 02:29:14 +01:00
|
|
|
});
|
|
|
|
|
stage2: entry point via std lib and proper updated file detection
Instead of Module setting up the root_scope with the root source file,
instead, Module relies on the package table graph being set up properly,
and inside `update()`, it does the equivalent of `_ = @import("std");`.
This, in term, imports start.zig, which has the logic to call main (or
not). `Module` no longer has `root_scope` - the root source file is no
longer special, it's just in the package table mapped to "root".
I also went ahead and implemented proper detection of updated files.
mtime, inode, size, and source hash are kept in `Scope.File`.
During an update, iterate over `import_table` and stat each file to find
out which ones are updated.
The source hash is redundant with the source hash used by the struct
decl that corresponds to the file, so it should be removed in a future
commit before merging the branch.
* AstGen: add "previously declared here" notes for variables shadowing
decls.
* Parse imports as structs. Module now calls `AstGen.structDeclInner`,
which is called by `AstGen.containerDecl`.
- `importFile` is a bit kludgy with how it handles the top level Decl
that kinda gets merged into the struct decl at the end of the
function. Be on the look out for bugs related to that as well as
possibly cleaner ways to implement this.
* Module: factor out lookupDeclName into lookupIdentifier and lookupNa
* Rename `Scope.Container` to `Scope.Namespace`.
* Delete some dead code.
This branch won't work until `usingnamespace` is implemented because it
relies on `@import("builtin").OutputMode` and `OutputMode` comes from a
`usingnamespace`.
2021-04-10 07:17:50 +01:00
|
|
|
ctx.compileError("global variable redeclaration", linux_x64,
|
2021-04-09 04:37:19 +01:00
|
|
|
\\// dummy comment
|
|
|
|
\\var foo = false;
|
|
|
|
\\var foo = true;
|
|
|
|
, &[_][]const u8{
|
2021-05-14 08:08:29 +01:00
|
|
|
":3:1: error: redeclaration of 'foo'",
|
|
|
|
":2:1: note: other declaration here",
|
2021-04-09 04:37:19 +01:00
|
|
|
});
|
2020-08-21 01:25:09 +01:00
|
|
|
|
2020-12-26 16:28:11 +00:00
|
|
|
ctx.compileError("compileError", linux_x64,
|
2021-05-17 22:39:56 +01:00
|
|
|
\\export fn foo() void {
|
2020-12-26 16:28:11 +00:00
|
|
|
\\ @compileError("this is an error");
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{":2:3: error: this is an error"});
|
2020-12-28 18:24:53 +00:00
|
|
|
|
2021-06-21 16:47:34 +01:00
|
|
|
{
|
|
|
|
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",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2021-03-26 02:39:30 +00:00
|
|
|
{
|
|
|
|
var case = ctx.obj("variable shadowing", linux_x64);
|
|
|
|
case.addError(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-26 02:39:30 +00:00
|
|
|
\\ var i: u32 = 10;
|
|
|
|
\\ var i: u32 = 10;
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
2021-07-02 20:33:05 +01:00
|
|
|
":3:9: error: redeclaration of local variable 'i'",
|
|
|
|
":2:9: note: previous declaration here",
|
2021-03-26 02:39:30 +00:00
|
|
|
});
|
|
|
|
case.addError(
|
|
|
|
\\var testing: i64 = 10;
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-26 02:39:30 +00:00
|
|
|
\\ var testing: i64 = 20;
|
|
|
|
\\}
|
2021-05-14 08:08:29 +01:00
|
|
|
, &[_][]const u8{
|
|
|
|
":3:9: error: local shadows declaration of 'testing'",
|
|
|
|
":1:1: note: declared here",
|
|
|
|
});
|
2021-05-29 01:29:56 +01:00
|
|
|
case.addError(
|
|
|
|
\\fn a() type {
|
|
|
|
\\ return struct {
|
|
|
|
\\ pub fn b() void {
|
|
|
|
\\ const c = 6;
|
|
|
|
\\ const c = 69;
|
|
|
|
\\ }
|
|
|
|
\\ };
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
2021-07-02 20:33:05 +01:00
|
|
|
":5:19: error: redeclaration of local constant 'c'",
|
|
|
|
":4:19: note: previous declaration here",
|
2021-05-29 01:29:56 +01:00
|
|
|
});
|
2021-07-14 23:03:15 +01:00
|
|
|
case.addError(
|
|
|
|
\\pub fn main() void {
|
|
|
|
\\ var i = 0;
|
2021-08-31 06:02:34 +01:00
|
|
|
\\ for ("n") |_, i| {
|
2021-07-14 23:03:15 +01:00
|
|
|
\\ }
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
2021-08-31 06:02:34 +01:00
|
|
|
":3:19: error: redeclaration of local variable 'i'",
|
2021-07-14 23:03:15 +01:00
|
|
|
":2:9: note: previous declaration here",
|
|
|
|
});
|
|
|
|
case.addError(
|
|
|
|
\\pub fn main() void {
|
|
|
|
\\ var i = 0;
|
2021-08-31 06:02:34 +01:00
|
|
|
\\ for ("n") |i| {
|
2021-07-14 23:03:15 +01:00
|
|
|
\\ }
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
2021-08-31 06:02:34 +01:00
|
|
|
":3:16: error: redeclaration of local variable 'i'",
|
2021-07-14 23:03:15 +01:00
|
|
|
":2:9: note: previous declaration here",
|
|
|
|
});
|
|
|
|
case.addError(
|
|
|
|
\\pub fn main() void {
|
|
|
|
\\ var i = 0;
|
2021-08-31 06:02:34 +01:00
|
|
|
\\ while ("n") |i| {
|
2021-07-14 23:03:15 +01:00
|
|
|
\\ }
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
2021-08-31 06:02:34 +01:00
|
|
|
":3:18: error: redeclaration of local variable 'i'",
|
2021-07-14 23:03:15 +01:00
|
|
|
":2:9: note: previous declaration here",
|
|
|
|
});
|
|
|
|
case.addError(
|
|
|
|
\\pub fn main() void {
|
|
|
|
\\ var i = 0;
|
2021-08-31 06:02:34 +01:00
|
|
|
\\ while ("n") |bruh| {
|
2021-07-14 23:03:15 +01:00
|
|
|
\\ _ = bruh;
|
|
|
|
\\ } else |i| {
|
|
|
|
\\
|
|
|
|
\\ }
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
":5:13: error: redeclaration of local variable 'i'",
|
|
|
|
":2:9: note: previous declaration here",
|
|
|
|
});
|
2021-07-14 23:17:55 +01:00
|
|
|
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",
|
|
|
|
});
|
2021-03-26 02:39:30 +00:00
|
|
|
}
|
2021-01-17 05:51:01 +00:00
|
|
|
|
2021-03-26 03:11:23 +00:00
|
|
|
{
|
|
|
|
// 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(
|
2021-05-16 05:20:06 +01:00
|
|
|
\\export fn _start() noreturn {
|
2021-03-26 03:11:23 +00:00
|
|
|
\\ const b = true;
|
|
|
|
\\ var f: u32 = 1;
|
|
|
|
\\ @compileLog(b, 20, f, x);
|
|
|
|
\\ @compileLog(1000);
|
|
|
|
\\ var bruh: usize = true;
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ _ = bruh;
|
2021-03-26 03:11:23 +00:00
|
|
|
\\ unreachable;
|
|
|
|
\\}
|
|
|
|
\\export fn other() void {
|
|
|
|
\\ @compileLog(1234);
|
|
|
|
\\}
|
|
|
|
\\fn x() void {}
|
|
|
|
, &[_][]const u8{
|
|
|
|
":6:23: error: expected usize, found bool",
|
|
|
|
});
|
2021-01-17 05:51:01 +00:00
|
|
|
|
2021-03-26 03:11:23 +00:00
|
|
|
// Now only compile log statements remain. One per Decl.
|
|
|
|
case.addError(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\export fn _start() noreturn {
|
2021-03-26 03:11:23 +00:00
|
|
|
\\ 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",
|
|
|
|
});
|
|
|
|
}
|
2020-12-06 17:36:49 +00:00
|
|
|
|
2021-03-26 06:00:38 +00:00
|
|
|
{
|
|
|
|
var case = ctx.obj("extern variable has no type", linux_x64);
|
|
|
|
case.addError(
|
|
|
|
\\comptime {
|
stage2: more principled approach to comptime references
* AIR no longer has a `variables` array. Instead of the `varptr`
instruction, Sema emits a constant with a `decl_ref`.
* AIR no longer has a `ref` instruction. There is no longer any
instruction that takes a value and returns a pointer to it. If this
is desired, Sema must either create an anynomous Decl and return a
constant `decl_ref`, or in the case of a runtime value, emit an
`alloc` instruction, `store` the value to it, and then return the
`alloc`.
* The `ref_val` Value Tag is eliminated. `decl_ref` should be used
instead. Also added is `eu_payload_ptr` which points to the payload
of an error union, given an error union pointer.
In general, Sema should avoid calling `analyzeRef` if it can be helped.
For example in the case of field_val and elem_val, there should never be
a reason to create a temporary (alloc or decl). Recent previous commits
made progress along that front.
There is a new abstraction in Sema, which looks like this:
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
// here 'anon_decl.arena()` may be used
const decl = try anon_decl.finish(ty, val);
// decl is typically now used with `decl_ref`.
This pattern is used to upgrade `ref_val` usages to `decl_ref` usages.
Additional improvements:
* Sema: fix source location resolution for calling convention
expression.
* Sema: properly report "unable to resolve comptime value" for loads of
global variables. There is now a set of functions which can be
called if the callee wants to obtain the Value even if the tag is
`variable` (indicating comptime-known address but runtime-known value).
* Sema: `coerce` resolves builtin types before checking equality.
* Sema: fix `u1_type` missing from `addType`, making this type have a
slightly more efficient representation in AIR.
* LLVM backend: fix `genTypedValue` for tags `decl_ref` and `variable`
to properly do an LLVMConstBitCast.
* Remove unused parameter from `Value.toEnum`.
After this commit, some test cases are no longer passing. This is due to
the more principled approach to comptime references causing more
anonymous decls to get sent to the linker for codegen. However, in all
these cases the decls are not actually referenced by the runtime machine
code. A future commit in this branch will implement garbage collection
of decls so that unused decls do not get sent to the linker for codegen.
This will make the tests go back to passing.
2021-07-29 23:59:51 +01:00
|
|
|
\\ const x = foo + foo;
|
|
|
|
\\ _ = x;
|
2021-03-26 06:00:38 +00:00
|
|
|
\\}
|
|
|
|
\\extern var foo: i32;
|
stage2: more principled approach to comptime references
* AIR no longer has a `variables` array. Instead of the `varptr`
instruction, Sema emits a constant with a `decl_ref`.
* AIR no longer has a `ref` instruction. There is no longer any
instruction that takes a value and returns a pointer to it. If this
is desired, Sema must either create an anynomous Decl and return a
constant `decl_ref`, or in the case of a runtime value, emit an
`alloc` instruction, `store` the value to it, and then return the
`alloc`.
* The `ref_val` Value Tag is eliminated. `decl_ref` should be used
instead. Also added is `eu_payload_ptr` which points to the payload
of an error union, given an error union pointer.
In general, Sema should avoid calling `analyzeRef` if it can be helped.
For example in the case of field_val and elem_val, there should never be
a reason to create a temporary (alloc or decl). Recent previous commits
made progress along that front.
There is a new abstraction in Sema, which looks like this:
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
// here 'anon_decl.arena()` may be used
const decl = try anon_decl.finish(ty, val);
// decl is typically now used with `decl_ref`.
This pattern is used to upgrade `ref_val` usages to `decl_ref` usages.
Additional improvements:
* Sema: fix source location resolution for calling convention
expression.
* Sema: properly report "unable to resolve comptime value" for loads of
global variables. There is now a set of functions which can be
called if the callee wants to obtain the Value even if the tag is
`variable` (indicating comptime-known address but runtime-known value).
* Sema: `coerce` resolves builtin types before checking equality.
* Sema: fix `u1_type` missing from `addType`, making this type have a
slightly more efficient representation in AIR.
* LLVM backend: fix `genTypedValue` for tags `decl_ref` and `variable`
to properly do an LLVMConstBitCast.
* Remove unused parameter from `Value.toEnum`.
After this commit, some test cases are no longer passing. This is due to
the more principled approach to comptime references causing more
anonymous decls to get sent to the linker for codegen. However, in all
these cases the decls are not actually referenced by the runtime machine
code. A future commit in this branch will implement garbage collection
of decls so that unused decls do not get sent to the linker for codegen.
This will make the tests go back to passing.
2021-07-29 23:59:51 +01:00
|
|
|
, &[_][]const u8{":2:15: error: unable to resolve comptime value"});
|
2021-03-26 06:00:38 +00:00
|
|
|
case.addError(
|
2021-05-16 05:20:06 +01:00
|
|
|
\\export fn entry() void {
|
2021-03-26 06:00:38 +00:00
|
|
|
\\ _ = foo;
|
|
|
|
\\}
|
|
|
|
\\extern var foo;
|
|
|
|
, &[_][]const u8{":4:8: error: unable to infer variable type"});
|
|
|
|
}
|
2020-12-26 00:17:36 +00:00
|
|
|
|
2021-03-27 01:26:39 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("break/continue", linux_x64);
|
2020-12-26 00:36:12 +00:00
|
|
|
|
2021-03-27 01:26:39 +00:00
|
|
|
// Break out of loop
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 01:26:39 +00:00
|
|
|
\\ while (true) {
|
|
|
|
\\ break;
|
|
|
|
\\ }
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 01:26:39 +00:00
|
|
|
\\ foo: while (true) {
|
|
|
|
\\ break :foo;
|
|
|
|
\\ }
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2020-12-26 00:17:36 +00:00
|
|
|
|
2021-03-27 01:26:39 +00:00
|
|
|
// Continue in loop
|
|
|
|
case.addCompareOutput(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-03-27 01:26:39 +00:00
|
|
|
\\ 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(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-03-27 01:26:39 +00:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
2020-12-26 00:36:12 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
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) {}
|
|
|
|
\\}
|
2021-02-20 04:47:11 +00:00
|
|
|
, &[_][]const u8{":2:5: error: unused while loop label"});
|
2021-03-27 01:35:15 +00:00
|
|
|
case.addError(
|
|
|
|
\\comptime {
|
|
|
|
\\ foo: for ("foo") |_| {}
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{":2:5: error: unused for loop label"});
|
2021-01-17 07:14:24 +00:00
|
|
|
case.addError(
|
|
|
|
\\comptime {
|
|
|
|
\\ blk: {blk: {}}
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
":2:11: error: redefinition of label 'blk'",
|
2021-07-02 20:33:05 +01:00
|
|
|
":2:5: note: previous definition here",
|
2021-01-17 07:14:24 +00:00
|
|
|
});
|
2020-12-26 00:36:12 +00:00
|
|
|
}
|
2021-01-01 00:24:36 +00:00
|
|
|
|
2021-03-27 01:35:15 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("bad inferred variable type", linux_x64);
|
|
|
|
case.addError(
|
2021-05-14 08:08:29 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 01:35:15 +00:00
|
|
|
\\ var x = null;
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ _ = x;
|
2021-03-27 01:35:15 +00:00
|
|
|
\\}
|
2021-05-14 08:08:29 +01:00
|
|
|
, &[_][]const u8{
|
|
|
|
":2:9: error: variable of type '@Type(.Null)' must be const or comptime",
|
|
|
|
});
|
2021-03-27 01:35:15 +00:00
|
|
|
}
|
2021-01-02 21:28:03 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
var case = ctx.exe("compile error in inline fn call fixed", linux_x64);
|
|
|
|
case.addError(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-01-02 21:28:03 +00:00
|
|
|
\\ var x: usize = 3;
|
|
|
|
\\ const y = add(10, 2, x);
|
|
|
|
\\ exit(y - 6);
|
|
|
|
\\}
|
|
|
|
\\
|
2021-01-11 15:03:09 +00:00
|
|
|
\\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
|
2021-01-02 21:28:03 +00:00
|
|
|
\\ 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(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-01-02 21:28:03 +00:00
|
|
|
\\ var x: usize = 3;
|
|
|
|
\\ const y = add(1, 2, x);
|
|
|
|
\\ exit(y - 6);
|
|
|
|
\\}
|
|
|
|
\\
|
2021-01-11 15:03:09 +00:00
|
|
|
\\fn add(a: usize, b: usize, c: usize) callconv(.Inline) usize {
|
2021-01-02 21:28:03 +00:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
2021-01-03 05:42:07 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("recursive inline function", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-01-03 05:42:07 +00:00
|
|
|
\\ const y = fibonacci(7);
|
|
|
|
\\ exit(y - 21);
|
|
|
|
\\}
|
|
|
|
\\
|
2021-01-11 15:03:09 +00:00
|
|
|
\\fn fibonacci(n: usize) callconv(.Inline) usize {
|
2021-01-03 05:42:07 +00:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2021-03-24 06:13:01 +00:00
|
|
|
// 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").
|
2021-01-03 05:42:07 +00:00
|
|
|
case.addError(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-01-03 05:42:07 +00:00
|
|
|
\\ const y = fibonacci(999);
|
|
|
|
\\ exit(y - 21);
|
|
|
|
\\}
|
|
|
|
\\
|
2021-01-11 15:03:09 +00:00
|
|
|
\\fn fibonacci(n: usize) callconv(.Inline) usize {
|
2021-01-03 05:42:07 +00:00
|
|
|
\\ 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;
|
|
|
|
\\}
|
2021-03-24 06:13:01 +00:00
|
|
|
, &[_][]const u8{":8:21: error: evaluation exceeded 1000 backwards branches"});
|
2021-01-08 22:08:45 +00:00
|
|
|
}
|
2021-03-27 06:46:37 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("orelse at comptime", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 06:46:37 +00:00
|
|
|
\\ const i: ?u64 = 0;
|
2021-05-17 22:39:56 +01:00
|
|
|
\\ const result = i orelse 5;
|
|
|
|
\\ assert(result == 0);
|
2021-03-27 06:46:37 +00:00
|
|
|
\\}
|
|
|
|
\\fn assert(b: bool) void {
|
|
|
|
\\ if (!b) unreachable;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 06:46:37 +00:00
|
|
|
\\ const i: ?u64 = null;
|
2021-05-17 22:39:56 +01:00
|
|
|
\\ const result = i orelse 5;
|
|
|
|
\\ assert(result == 5);
|
2021-03-27 06:46:37 +00:00
|
|
|
\\}
|
|
|
|
\\fn assert(b: bool) void {
|
|
|
|
\\ if (!b) unreachable;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
2021-01-19 21:08:43 +00:00
|
|
|
|
|
|
|
{
|
|
|
|
var case = ctx.exe("only 1 function and it gets updated", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-01-19 21:08:43 +00:00
|
|
|
\\ asm volatile ("syscall"
|
|
|
|
\\ :
|
|
|
|
\\ : [number] "{rax}" (60), // exit
|
|
|
|
\\ [arg1] "{rdi}" (0)
|
|
|
|
\\ : "rcx", "r11", "memory"
|
|
|
|
\\ );
|
|
|
|
\\ unreachable;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
case.addCompareOutput(
|
2021-05-07 01:48:38 +01:00
|
|
|
\\pub export fn _start() noreturn {
|
2021-01-19 21:08:43 +00:00
|
|
|
\\ asm volatile ("syscall"
|
|
|
|
\\ :
|
|
|
|
\\ : [number] "{rax}" (231), // exit_group
|
|
|
|
\\ [arg1] "{rdi}" (0)
|
|
|
|
\\ : "rcx", "r11", "memory"
|
|
|
|
\\ );
|
|
|
|
\\ unreachable;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
2021-02-12 20:40:44 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("passing u0 to function", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-02-12 20:40:44 +00:00
|
|
|
\\ doNothing(0);
|
|
|
|
\\}
|
2021-06-20 02:10:22 +01:00
|
|
|
\\fn doNothing(arg: u0) void {
|
|
|
|
\\ _ = arg;
|
|
|
|
\\}
|
2021-02-12 20:40:44 +00:00
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
2021-03-27 06:46:37 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("catch at comptime", linux_x64);
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 06:46:37 +00:00
|
|
|
\\ const i: anyerror!u64 = 0;
|
|
|
|
\\ const caught = i catch 5;
|
|
|
|
\\ assert(caught == 0);
|
|
|
|
\\}
|
|
|
|
\\fn assert(b: bool) void {
|
|
|
|
\\ if (!b) unreachable;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 06:46:37 +00:00
|
|
|
\\ const i: anyerror!u64 = error.B;
|
|
|
|
\\ const caught = i catch 5;
|
|
|
|
\\ assert(caught == 5);
|
|
|
|
\\}
|
|
|
|
\\fn assert(b: bool) void {
|
|
|
|
\\ if (!b) unreachable;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
|
2021-03-28 07:55:19 +01:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-28 07:55:19 +01:00
|
|
|
\\ 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
|
|
|
|
\\}
|
|
|
|
, "");
|
2021-03-27 06:46:37 +00:00
|
|
|
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 06:46:37 +00:00
|
|
|
\\ const a: anyerror!u32 = error.B;
|
|
|
|
\\ _ = &(a catch |err| assert(err == error.B));
|
|
|
|
\\}
|
|
|
|
\\fn assert(b: bool) void {
|
|
|
|
\\ if (!b) unreachable;
|
|
|
|
\\}
|
|
|
|
, "");
|
|
|
|
|
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-27 06:46:37 +00:00
|
|
|
\\ const a: anyerror!u32 = error.Bar;
|
|
|
|
\\ a catch |err| assert(err == error.Bar);
|
|
|
|
\\}
|
|
|
|
\\fn assert(b: bool) void {
|
|
|
|
\\ if (!b) unreachable;
|
|
|
|
\\}
|
|
|
|
, "");
|
|
|
|
}
|
2021-08-19 02:29:32 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
2021-03-29 03:38:19 +01:00
|
|
|
{
|
|
|
|
var case = ctx.exe("merge error sets", linux_x64);
|
2021-01-14 15:14:29 +00:00
|
|
|
|
2021-03-29 03:38:19 +01:00
|
|
|
case.addCompareOutput(
|
2021-05-17 22:39:56 +01:00
|
|
|
\\pub fn main() void {
|
2021-03-29 03:38:19 +01:00
|
|
|
\\ const E = error{ A, B, D } || error { A, B, C };
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ E.A catch {};
|
|
|
|
\\ E.B catch {};
|
|
|
|
\\ E.C catch {};
|
|
|
|
\\ E.D catch {};
|
2021-03-29 03:38:19 +01:00
|
|
|
\\ const E2 = error { X, Y } || @TypeOf(error.Z);
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ E2.X catch {};
|
|
|
|
\\ E2.Y catch {};
|
|
|
|
\\ E2.Z catch {};
|
2021-03-29 03:38:19 +01:00
|
|
|
\\ assert(anyerror || error { Z } == anyerror);
|
|
|
|
\\}
|
|
|
|
\\fn assert(b: bool) void {
|
|
|
|
\\ if (!b) unreachable;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
2021-07-06 01:17:51 +01:00
|
|
|
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",
|
|
|
|
});
|
2021-03-29 03:38:19 +01:00
|
|
|
}
|
2021-08-17 15:49:17 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
\\}
|
|
|
|
,
|
|
|
|
"",
|
|
|
|
);
|
|
|
|
}
|
2021-05-04 22:23:53 +01:00
|
|
|
{
|
|
|
|
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),
|
stage2 generics improvements: anytype and param type exprs
AstGen result locations now have a `coerced_ty` tag which is the same as
`ty` except it assumes that Sema will do a coercion, so it does not
redundantly add an `as` instruction into the ZIR code. This results in
cleaner ZIR and about a 14% reduction of ZIR bytes.
param and param_comptime ZIR instructions now have a block body for
their type expressions. This allows Sema to skip evaluation of the
block in the case that the parameter is comptime-provided. It also
allows a new mechanism to function: when evaluating type expressions of
generic functions, if it would depend on another parameter, it returns
`error.GenericPoison` which bubbles up and then is caught by the
param/param_comptime instruction and then handled.
This allows parameters to be evaluated independently so that the type
info for functions which have comptime or anytype parameters will still
have types populated for parameters that do not depend on values of
previous parameters (because evaluation of their param blocks will return
successfully instead of `error.GenericPoison`).
It also makes iteration over the block that contains function parameters
slightly more efficient since it now only contains the param
instructions.
Finally, it fixes the case where a generic function type expression contains
a function prototype. Formerly, this situation would cause shared state
to clobber each other; now it is in a proper tree structure so that
can't happen. This fix also required adding a field to Sema
`comptime_args_fn_inst` to make sure that the `comptime_args` field
passed into Sema is applied to the correct `func` instruction.
Source location for `node_offset_asm_ret_ty` is fixed; it was pointing at
the asm output name rather than the return type as intended.
Generic function instantiation is fixed, notably with respect to
parameter type expressions that depend on previous parameters, and with
respect to types which must be always comptime-known. This involves
passing all the comptime arguments at a callsite of a generic function,
and allowing the generic function semantic analysis to coerce the values
to the proper types (since it has access to the evaluated parameter type
expressions) and then decide based on the type whether the parameter is
runtime known or not. In the case of explicitly marked `comptime`
parameters, there is a check at the semantic analysis of the `call`
instruction.
Semantic analysis of `call` instructions does type coercion on the
arguments, which is needed both for generic functions and to make up for
using `coerced_ty` result locations (mentioned above).
Tasks left in this branch:
* Implement the memoization table.
* Add test coverage.
* Improve error reporting and source locations for compile errors.
2021-08-05 05:11:31 +01:00
|
|
|
\\ [arg1] "{rdi}" (60)
|
2021-05-04 22:23:53 +01:00
|
|
|
\\ : "rcx", "r11", "memory"
|
|
|
|
\\ );
|
2021-06-12 19:48:13 +01:00
|
|
|
\\ _ = x;
|
2021-05-04 22:23:53 +01:00
|
|
|
\\}
|
|
|
|
, &[_][]const u8{":4:27: error: expected type, found comptime_int"});
|
2021-06-22 17:04:19 +01:00
|
|
|
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"});
|
2021-05-04 22:23:53 +01:00
|
|
|
}
|
2021-06-06 19:08:31 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
\\}
|
2021-06-07 21:49:28 +01:00
|
|
|
\\pub fn main() void {}
|
2021-06-06 19:08:31 +01:00
|
|
|
, &.{":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;
|
|
|
|
\\}
|
|
|
|
, "");
|
2021-06-07 21:49:28 +01:00
|
|
|
|
|
|
|
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");
|
2021-06-06 19:08:31 +01:00
|
|
|
}
|
2021-06-20 19:04:14 +01:00
|
|
|
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
\\}
|
2021-07-09 13:43:19 +01:00
|
|
|
, &[_][]const u8{
|
|
|
|
":4:11: error: incompatible types: 'bool' and '*const bool'",
|
|
|
|
":4:9: note: type 'bool' here",
|
|
|
|
":4:13: note: type '*const bool' here",
|
|
|
|
});
|
2021-06-20 19:04:14 +01:00
|
|
|
|
|
|
|
case.addCompareOutput(
|
|
|
|
\\pub fn main() void {
|
|
|
|
\\ const b: u8 = 1;
|
|
|
|
\\ _ = &&b;
|
|
|
|
\\}
|
|
|
|
, "");
|
|
|
|
}
|
2021-08-27 03:26:05 +01:00
|
|
|
|
|
|
|
{
|
|
|
|
var case = ctx.exe("setting an address space on a local variable", linux_x64);
|
|
|
|
case.addError(
|
|
|
|
\\export fn entry() i32 {
|
|
|
|
\\ var foo: i32 addrspace(".general") = 1234;
|
|
|
|
\\ return foo;
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
":2:28: error: cannot set address space of local variable 'foo'",
|
|
|
|
});
|
|
|
|
}
|
2021-11-13 17:52:17 +00:00
|
|
|
{
|
|
|
|
var case = ctx.exe("issue 10138: callee preserved regs working", linux_x64);
|
|
|
|
case.addCompareOutput(
|
|
|
|
\\pub fn main() void {
|
|
|
|
\\ const fd = open();
|
|
|
|
\\ _ = write(fd, "a", 1);
|
|
|
|
\\ _ = close(fd);
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn open() usize {
|
|
|
|
\\ return 42;
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn write(fd: usize, a: [*]const u8, len: usize) usize {
|
|
|
|
\\ return syscall4(.WRITE, fd, @ptrToInt(a), len);
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn syscall4(n: enum { WRITE }, a: usize, b: usize, c: usize) usize {
|
|
|
|
\\ _ = n;
|
|
|
|
\\ _ = a;
|
|
|
|
\\ _ = b;
|
|
|
|
\\ _ = c;
|
|
|
|
\\ return 23;
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn close(fd: usize) usize {
|
|
|
|
\\ if (fd != 42)
|
|
|
|
\\ unreachable;
|
|
|
|
\\ return 0;
|
|
|
|
\\}
|
|
|
|
, "");
|
|
|
|
}
|
2019-11-23 20:56:05 +00:00
|
|
|
}
|