2020-02-26 06:18:23 +00:00
|
|
|
const std = @import("std");
|
2021-10-05 07:47:27 +01:00
|
|
|
const builtin = @import("builtin");
|
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;
|
2017-04-19 09:12:22 +01:00
|
|
|
|
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
|
|
|
pub fn addCases(ctx: *TestContext) !void {
|
2022-03-24 05:28:08 +00:00
|
|
|
{
|
|
|
|
const case = ctx.obj("wrong same named struct", .{});
|
|
|
|
case.backend = .stage1;
|
2020-09-26 18:55:56 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addSourceFile("a.zig",
|
|
|
|
\\pub const Foo = struct {
|
|
|
|
\\ x: i32,
|
|
|
|
\\};
|
|
|
|
);
|
2020-09-26 00:14:13 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addSourceFile("b.zig",
|
|
|
|
\\pub const Foo = struct {
|
|
|
|
\\ z: f64,
|
|
|
|
\\};
|
|
|
|
);
|
2020-09-23 20:12:26 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addError(
|
|
|
|
\\const a = @import("a.zig");
|
|
|
|
\\const b = @import("b.zig");
|
|
|
|
\\
|
|
|
|
\\export fn entry() void {
|
|
|
|
\\ var a1: a.Foo = undefined;
|
|
|
|
\\ bar(&a1);
|
|
|
|
\\}
|
|
|
|
\\
|
|
|
|
\\fn bar(x: *b.Foo) void {_ = x;}
|
|
|
|
, &[_][]const u8{
|
|
|
|
"tmp.zig:6:10: error: expected type '*b.Foo', found '*a.Foo'",
|
|
|
|
"tmp.zig:6:10: note: pointer type child 'a.Foo' cannot cast into pointer type child 'b.Foo'",
|
|
|
|
"a.zig:1:17: note: a.Foo declared here",
|
|
|
|
"b.zig:1:17: note: b.Foo declared here",
|
|
|
|
});
|
|
|
|
}
|
2020-09-23 20:12:26 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
{
|
|
|
|
const case = ctx.obj("multiple files with private function error", .{});
|
|
|
|
case.backend = .stage1;
|
2020-09-01 16:29:10 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addSourceFile("foo.zig",
|
|
|
|
\\fn privateFunction() void { }
|
|
|
|
);
|
2020-08-27 20:34:02 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addError(
|
|
|
|
\\const foo = @import("foo.zig",);
|
|
|
|
\\
|
|
|
|
\\export fn callPrivFunction() void {
|
|
|
|
\\ foo.privateFunction();
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
"tmp.zig:4:8: error: 'privateFunction' is private",
|
|
|
|
"foo.zig:1:1: note: declared here",
|
|
|
|
});
|
|
|
|
}
|
2020-09-27 00:40:31 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
{
|
|
|
|
const case = ctx.obj("multiple files with private member instance function (canonical invocation) error", .{});
|
|
|
|
case.backend = .stage1;
|
2020-09-27 00:40:31 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addSourceFile("foo.zig",
|
|
|
|
\\pub const Foo = struct {
|
|
|
|
\\ fn privateFunction(self: *Foo) void { _ = self; }
|
|
|
|
\\};
|
|
|
|
);
|
2020-08-27 20:34:02 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addError(
|
|
|
|
\\const Foo = @import("foo.zig",).Foo;
|
|
|
|
\\
|
|
|
|
\\export fn callPrivFunction() void {
|
|
|
|
\\ var foo = Foo{};
|
|
|
|
\\ Foo.privateFunction(foo);
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
"tmp.zig:5:8: error: 'privateFunction' is private",
|
|
|
|
"foo.zig:2:5: note: declared here",
|
|
|
|
});
|
|
|
|
}
|
2020-04-01 16:02:38 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
{
|
|
|
|
const case = ctx.obj("multiple files with private member instance function error", .{});
|
|
|
|
case.backend = .stage1;
|
2020-04-03 16:41:55 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addSourceFile("foo.zig",
|
|
|
|
\\pub const Foo = struct {
|
|
|
|
\\ fn privateFunction(self: *Foo) void { _ = self; }
|
|
|
|
\\};
|
|
|
|
);
|
2021-01-18 05:36:37 +00:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addError(
|
|
|
|
\\const Foo = @import("foo.zig",).Foo;
|
|
|
|
\\
|
|
|
|
\\export fn callPrivFunction() void {
|
|
|
|
\\ var foo = Foo{};
|
|
|
|
\\ foo.privateFunction();
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
"tmp.zig:5:8: error: 'privateFunction' is private",
|
|
|
|
"foo.zig:2:5: note: declared here",
|
|
|
|
});
|
|
|
|
}
|
2020-04-03 16:41:55 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
{
|
|
|
|
const case = ctx.obj("export collision", .{});
|
|
|
|
case.backend = .stage1;
|
2020-04-03 16:41:55 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addSourceFile("foo.zig",
|
|
|
|
\\export fn bar() void {}
|
|
|
|
\\pub const baz = 1234;
|
|
|
|
);
|
2020-04-03 16:41:55 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
case.addError(
|
|
|
|
\\const foo = @import("foo.zig",);
|
|
|
|
\\
|
|
|
|
\\export fn bar() usize {
|
|
|
|
\\ return foo.baz;
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
"foo.zig:1:1: error: exported symbol collision: 'bar'",
|
|
|
|
"tmp.zig:3:1: note: other symbol here",
|
|
|
|
});
|
|
|
|
}
|
2020-04-03 16:41:55 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
ctx.objErrStage1("non-printable invalid character", "\xff\xfe" ++
|
|
|
|
"fn foo() bool {\r\n" ++
|
|
|
|
" return true;\r\n" ++
|
|
|
|
"}\r\n", &[_][]const u8{
|
|
|
|
"tmp.zig:1:1: error: expected test, comptime, var decl, or container field, found 'invalid bytes'",
|
|
|
|
"tmp.zig:1:1: note: invalid byte: '\\xff'",
|
2020-04-03 16:41:55 +01:00
|
|
|
});
|
2020-04-04 00:11:51 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
ctx.objErrStage1("non-printable invalid character with escape alternative", "fn foo() bool {\n" ++
|
|
|
|
"\treturn true;\n" ++
|
|
|
|
"}\n", &[_][]const u8{
|
|
|
|
"tmp.zig:2:1: error: invalid character: '\\t'",
|
2020-04-04 00:11:51 +01:00
|
|
|
});
|
2020-05-07 00:31:18 +01:00
|
|
|
|
2022-07-11 22:10:39 +01:00
|
|
|
{
|
|
|
|
const case = ctx.obj("multiline error messages", .{});
|
|
|
|
case.backend = .stage2;
|
|
|
|
|
|
|
|
case.addError(
|
|
|
|
\\comptime {
|
|
|
|
\\ @compileError("hello\nworld");
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
\\:2:5: error: hello
|
|
|
|
\\ world
|
|
|
|
});
|
|
|
|
|
|
|
|
case.addError(
|
|
|
|
\\comptime {
|
|
|
|
\\ @compileError(
|
|
|
|
\\ \\
|
|
|
|
\\ \\hello!
|
|
|
|
\\ \\I'm a multiline error message.
|
|
|
|
\\ \\I hope to be very useful!
|
|
|
|
\\ \\
|
|
|
|
\\ \\also I will leave this trailing newline here if you don't mind
|
|
|
|
\\ \\
|
|
|
|
\\ );
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
\\:2:5: error:
|
|
|
|
\\ hello!
|
|
|
|
\\ I'm a multiline error message.
|
|
|
|
\\ I hope to be very useful!
|
|
|
|
\\
|
|
|
|
\\ also I will leave this trailing newline here if you don't mind
|
|
|
|
\\
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-07-15 09:38:16 +01:00
|
|
|
{
|
|
|
|
const case = ctx.obj("missing semicolon at EOF", .{});
|
|
|
|
case.addError(
|
|
|
|
\\const foo = 1
|
|
|
|
, &[_][]const u8{
|
|
|
|
\\:1:14: error: expected ';' after declaration
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-07-25 11:48:21 +01:00
|
|
|
{
|
2022-08-21 15:07:22 +01:00
|
|
|
const case = ctx.obj("argument causes error", .{});
|
2022-07-25 11:48:21 +01:00
|
|
|
case.backend = .stage2;
|
|
|
|
|
|
|
|
case.addSourceFile("b.zig",
|
|
|
|
\\pub const ElfDynLib = struct {
|
|
|
|
\\ pub fn lookup(self: *ElfDynLib, comptime T: type) ?T {
|
|
|
|
\\ _ = self;
|
|
|
|
\\ return undefined;
|
|
|
|
\\ }
|
|
|
|
\\};
|
|
|
|
);
|
|
|
|
|
|
|
|
case.addError(
|
|
|
|
\\pub export fn entry() void {
|
|
|
|
\\ var lib: @import("b.zig").ElfDynLib = undefined;
|
|
|
|
\\ _ = lib.lookup(fn () void);
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
":3:12: error: unable to resolve comptime value",
|
2022-10-05 19:58:23 +01:00
|
|
|
":3:12: note: argument to function being called at comptime must be comptime-known",
|
2022-10-27 17:31:45 +01:00
|
|
|
":2:55: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type",
|
2022-07-25 11:48:21 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-08-21 15:07:22 +01:00
|
|
|
{
|
|
|
|
const case = ctx.obj("astgen failure in file struct", .{});
|
|
|
|
case.backend = .stage2;
|
|
|
|
|
|
|
|
case.addSourceFile("b.zig",
|
2022-11-22 12:10:52 +00:00
|
|
|
\\+
|
2022-08-21 15:07:22 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
case.addError(
|
|
|
|
\\pub export fn entry() void {
|
|
|
|
\\ _ = (@sizeOf(@import("b.zig")));
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
2022-11-22 12:10:52 +00:00
|
|
|
":1:1: error: expected type expression, found '+'",
|
2022-08-21 15:07:22 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-09-24 23:30:15 +01:00
|
|
|
{
|
|
|
|
const case = ctx.obj("invalid store to comptime field", .{});
|
|
|
|
case.backend = .stage2;
|
|
|
|
|
|
|
|
case.addSourceFile("a.zig",
|
|
|
|
\\pub const S = struct {
|
|
|
|
\\ comptime foo: u32 = 1,
|
|
|
|
\\ bar: u32,
|
|
|
|
\\ pub fn foo(x: @This()) void {
|
|
|
|
\\ _ = x;
|
|
|
|
\\ }
|
|
|
|
\\};
|
|
|
|
);
|
|
|
|
|
|
|
|
case.addError(
|
|
|
|
\\const a = @import("a.zig");
|
|
|
|
\\
|
|
|
|
\\export fn entry() void {
|
|
|
|
\\ _ = a.S.foo(a.S{ .foo = 2, .bar = 2 });
|
|
|
|
\\}
|
|
|
|
, &[_][]const u8{
|
|
|
|
":4:23: error: value stored in comptime field does not match the default value of the field",
|
|
|
|
":2:25: note: default value set here",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
// TODO test this in stage2, but we won't even try in stage1
|
|
|
|
//ctx.objErrStage1("inline fn calls itself indirectly",
|
|
|
|
// \\export fn foo() void {
|
|
|
|
// \\ bar();
|
|
|
|
// \\}
|
|
|
|
// \\fn bar() callconv(.Inline) void {
|
|
|
|
// \\ baz();
|
|
|
|
// \\ quux();
|
|
|
|
// \\}
|
|
|
|
// \\fn baz() callconv(.Inline) void {
|
|
|
|
// \\ bar();
|
|
|
|
// \\ quux();
|
|
|
|
// \\}
|
|
|
|
// \\extern fn quux() void;
|
|
|
|
//, &[_][]const u8{
|
|
|
|
// "tmp.zig:4:1: error: unable to inline function",
|
|
|
|
//});
|
2020-05-11 13:06:37 +01:00
|
|
|
|
2022-03-24 05:28:08 +00:00
|
|
|
//ctx.objErrStage1("save reference to inline function",
|
|
|
|
// \\export fn foo() void {
|
|
|
|
// \\ quux(@ptrToInt(bar));
|
|
|
|
// \\}
|
|
|
|
// \\fn bar() callconv(.Inline) void { }
|
|
|
|
// \\extern fn quux(usize) void;
|
|
|
|
//, &[_][]const u8{
|
|
|
|
// "tmp.zig:4:1: error: unable to inline function",
|
|
|
|
//});
|
2017-04-19 09:12:22 +01:00
|
|
|
}
|