re-enable test-cases and get them all passing

Instead of using `zig test` to build a special version of the compiler
that runs all the test-cases, the zig build system is now used as much
as possible - all with the basic steps found in the standard library.

For incremental compilation tests (the ones that look like foo.0.zig,
foo.1.zig, foo.2.zig, etc.), a special version of the compiler is
compiled into a utility executable called "check-case" which checks
exactly one sequence of incremental updates in an independent
subprocess. Previously, all incremental and non-incremental test cases
were done in the same test runner process.

The compile error checking code is now simpler, but also a bit
rudimentary, and so it additionally makes sure that the actual compile
errors do not include *extra* messages, and it makes sure that the
actual compile errors output in the same order as expected. It is also
based on the "ends-with" property of each line rather than the previous
logic, which frankly I didn't want to touch with a ten-meter pole. The
compile error test cases have been updated to pass in light of these
differences.

Previously, 'error' mode with 0 compile errors was used to shoehorn in a
different kind of test-case - one that only checks if a piece of code
compiles without errors. Now there is a 'compile' mode of test-cases,
and 'error' must be only used when there are greater than 0 errors.

link test cases are updated to omit the target object format argument
when calling checkObject since that is no longer needed.

The test/stage2 directory is removed; the 2 files within are moved to be
directly in the test/ directory.
This commit is contained in:
Andrew Kelley 2023-03-09 18:22:51 -07:00
parent 7cc4a6965c
commit 29cfd47d65
79 changed files with 1805 additions and 2343 deletions

View File

@ -53,13 +53,14 @@ pub fn build(b: *std.Build) !void {
const docs_step = b.step("docs", "Build documentation");
docs_step.dependOn(&docgen_cmd.step);
const test_cases = b.addTest(.{
.root_source_file = .{ .path = "src/test.zig" },
const check_case_exe = b.addExecutable(.{
.name = "check-case",
.root_source_file = .{ .path = "test/src/Cases.zig" },
.optimize = optimize,
});
test_cases.main_pkg_path = ".";
test_cases.stack_size = stack_size;
test_cases.single_threaded = single_threaded;
check_case_exe.main_pkg_path = ".";
check_case_exe.stack_size = stack_size;
check_case_exe.single_threaded = single_threaded;
const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false;
const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
@ -178,7 +179,7 @@ pub fn build(b: *std.Build) !void {
if (target.isWindows() and target.getAbi() == .gnu) {
// LTO is currently broken on mingw, this can be removed when it's fixed.
exe.want_lto = false;
test_cases.want_lto = false;
check_case_exe.want_lto = false;
}
const exe_options = b.addOptions();
@ -196,7 +197,7 @@ pub fn build(b: *std.Build) !void {
if (link_libc) {
exe.linkLibC();
test_cases.linkLibC();
check_case_exe.linkLibC();
}
const is_debug = optimize == .Debug;
@ -282,14 +283,14 @@ pub fn build(b: *std.Build) !void {
}
try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
try addCmakeCfgOptionsToExe(b, cfg, test_cases, use_zig_libcxx);
try addCmakeCfgOptionsToExe(b, cfg, check_case_exe, use_zig_libcxx);
} else {
// Here we are -Denable-llvm but no cmake integration.
try addStaticLlvmOptionsToExe(exe);
try addStaticLlvmOptionsToExe(test_cases);
try addStaticLlvmOptionsToExe(check_case_exe);
}
if (target.isWindows()) {
inline for (.{ exe, test_cases }) |artifact| {
inline for (.{ exe, check_case_exe }) |artifact| {
artifact.linkSystemLibrary("version");
artifact.linkSystemLibrary("uuid");
artifact.linkSystemLibrary("ole32");
@ -334,8 +335,9 @@ pub fn build(b: *std.Build) !void {
const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
const test_cases_options = b.addOptions();
test_cases.addOptions("build_options", test_cases_options);
check_case_exe.addOptions("build_options", test_cases_options);
test_cases_options.addOption(bool, "enable_tracy", false);
test_cases_options.addOption(bool, "enable_logging", enable_logging);
test_cases_options.addOption(bool, "enable_link_snapshots", enable_link_snapshots);
test_cases_options.addOption(bool, "skip_non_native", skip_non_native);
@ -358,12 +360,6 @@ pub fn build(b: *std.Build) !void {
test_cases_options.addOption(std.SemanticVersion, "semver", semver);
test_cases_options.addOption(?[]const u8, "test_filter", test_filter);
const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
test_cases_step.dependOn(&test_cases.step);
if (!skip_stage2_tests) {
test_step.dependOn(test_cases_step);
}
var chosen_opt_modes_buf: [4]builtin.Mode = undefined;
var chosen_mode_index: usize = 0;
if (!skip_debug) {
@ -386,21 +382,20 @@ pub fn build(b: *std.Build) !void {
const fmt_include_paths = &.{ "doc", "lib", "src", "test", "tools", "build.zig" };
const fmt_exclude_paths = &.{"test/cases"};
const check_fmt = b.addFmt(.{
.paths = fmt_include_paths,
.exclude_paths = fmt_exclude_paths,
.check = true,
});
const do_fmt = b.addFmt(.{
.paths = fmt_include_paths,
.exclude_paths = fmt_exclude_paths,
});
const test_fmt_step = b.step("test-fmt", "Check whether source files have conforming formatting");
test_fmt_step.dependOn(&check_fmt.step);
b.step("test-fmt", "Check source files having conforming formatting").dependOn(&b.addFmt(.{
.paths = fmt_include_paths,
.exclude_paths = fmt_exclude_paths,
.check = true,
}).step);
const do_fmt_step = b.step("fmt", "Modify source files in place to have conforming formatting");
do_fmt_step.dependOn(&do_fmt.step);
const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
try tests.addCases(b, test_cases_step, test_filter, check_case_exe);
if (!skip_stage2_tests) test_step.dependOn(test_cases_step);
test_step.dependOn(tests.addModuleTests(b, .{
.test_filter = test_filter,
@ -475,6 +470,9 @@ pub fn build(b: *std.Build) !void {
}));
try addWasiUpdateStep(b, version);
b.step("fmt", "Modify source files in place to have conforming formatting")
.dependOn(&do_fmt.step);
}
fn addWasiUpdateStep(b: *std.Build, version: [:0]const u8) !void {

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,8 @@
const std = @import("std");
const TestContext = @import("../src/test.zig").TestContext;
const Cases = @import("src/Cases.zig");
pub fn addCases(ctx: *TestContext) !void {
try @import("compile_errors.zig").addCases(ctx);
try @import("stage2/cbe.zig").addCases(ctx);
try @import("stage2/nvptx.zig").addCases(ctx);
pub fn addCases(cases: *Cases) !void {
try @import("compile_errors.zig").addCases(cases);
try @import("cbe.zig").addCases(cases);
try @import("nvptx.zig").addCases(cases);
}

View File

@ -21,3 +21,4 @@ pub export fn entry1() void {
// :9:15: error: access of union field 'a' while field 'b' is active
// :2:21: note: union declared here
// :14:16: error: access of union field 'a' while field 'b' is active
// :2:21: note: union declared here

View File

@ -4,4 +4,4 @@ const bogus = @import("bogus-does-not-exist.zig",);
// backend=stage2
// target=native
//
// :1:23: error: unable to load '${DIR}bogus-does-not-exist.zig': FileNotFound
// bogus-does-not-exist.zig': FileNotFound

View File

@ -45,4 +45,6 @@ pub export fn entry2() void {
// :22:13: error: unable to resolve comptime value
// :22:13: note: condition in comptime switch must be comptime-known
// :21:17: note: expression is evaluated at comptime because the function returns a comptime-only type 'tmp.S'
// :2:12: note: struct requires comptime because of this field
// :2:12: note: use '*const fn() void' for a function pointer type
// :32:19: note: called from here

View File

@ -32,6 +32,7 @@ export fn d() void {
// :3:8: error: opaque types have unknown size and therefore cannot be directly embedded in structs
// :1:11: note: opaque declared here
// :7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions
// :1:11: note: opaque declared here
// :19:18: error: opaque types have unknown size and therefore cannot be directly embedded in structs
// :18:22: note: opaque declared here
// :24:23: error: opaque types have unknown size and therefore cannot be directly embedded in structs

View File

@ -12,6 +12,6 @@ comptime { _ = entry2; }
// backend=stage2
// target=native
//
// :1:15: error: comptime parameters not allowed in function with calling convention 'C'
// :5:30: error: comptime parameters not allowed in function with calling convention 'C'
// :6:30: error: generic parameters not allowed in function with calling convention 'C'
// :1:15: error: comptime parameters not allowed in function with calling convention 'C'

View File

@ -27,4 +27,5 @@ export fn entry4() void {
// :1:17: note: opaque declared here
// :8:28: error: parameter of type '@TypeOf(null)' not allowed
// :12:8: error: parameter of opaque type 'tmp.FooType' not allowed
// :1:17: note: opaque declared here
// :17:8: error: parameter of type '@TypeOf(null)' not allowed

View File

@ -24,9 +24,9 @@ export fn quux() u32 {
// :8:5: error: expected type 'void', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set'
// :7:17: note: function cannot return an error
// :11:15: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32'
// :10:17: note: function cannot return an error
// :11:15: note: cannot convert error union to payload type
// :11:15: note: consider using 'try', 'catch', or 'if'
// :10:17: note: function cannot return an error
// :15:14: error: expected type 'u32', found '@typeInfo(@typeInfo(@TypeOf(tmp.bar)).Fn.return_type.?).ErrorUnion.error_set!u32'
// :15:14: note: cannot convert error union to payload type
// :15:14: note: consider using 'try', 'catch', or 'if'

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
_ = {}
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
({})
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
_ = comptime {}
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
comptime ({})
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
defer ({})
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,7 +3,10 @@ export fn entry() void {
var good = {};
_ = for(foo()) |_| {}
var bad = {};
_ = good;
_ = bad;
}
fn foo() void {}
// error
// backend=stage2

View File

@ -3,7 +3,10 @@ export fn entry() void {
var good = {};
for(foo()) |_| ({})
var bad = {};
_ = good;
_ = bad;
}
fn foo() void {}
// error
// backend=stage2

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
_ = if(true) {} else if(true) {} else {}
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
if(true) ({}) else if(true) ({}) else ({})
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
_ = if(true) {} else if(true) {}
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
if(true) ({}) else if(true) ({})
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
_ = if(true) {} else {}
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
if(true) ({}) else ({})
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
_ = if(true) {}
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
if(true) ({})
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,7 +3,10 @@ export fn entry() void {
var good = {};
_ = if (foo()) |_| {}
var bad = {};
_ = good;
_ = bad;
}
fn foo() void {}
// error
// backend=stage2

View File

@ -3,7 +3,10 @@ export fn entry() void {
var good = {};
if (foo()) |_| ({})
var bad = {};
_ = good;
_ = bad;
}
fn foo() void {}
// error
// backend=stage2

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
_ = while(true):({}) {}
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
while(true):({}) ({})
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
_ = while(true) {}
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -3,6 +3,8 @@ export fn entry() void {
var good = {};
while(true) 1
var bad = {};
_ = good;
_ = bad;
}
// error

View File

@ -9,4 +9,4 @@ export fn entry() void {
// target=native
//
// :3:38: error: enum 'builtin.OptimizeMode' has no member named 'x86'
// :?:18: note: enum declared here
// : note: enum declared here

View File

@ -73,11 +73,11 @@ pub export fn entry8() void {
//
// :6:19: error: value stored in comptime field does not match the default value of the field
// :14:19: error: value stored in comptime field does not match the default value of the field
// :53:16: error: value stored in comptime field does not match the default value of the field
// :19:38: error: value stored in comptime field does not match the default value of the field
// :31:19: error: value stored in comptime field does not match the default value of the field
// :25:29: note: default value set here
// :41:16: error: value stored in comptime field does not match the default value of the field
// :45:12: error: value stored in comptime field does not match the default value of the field
// :53:16: error: value stored in comptime field does not match the default value of the field
// :66:43: error: value stored in comptime field does not match the default value of the field
// :59:35: error: value stored in comptime field does not match the default value of the field

View File

@ -25,5 +25,6 @@ export fn e() void {
// :4:7: error: no field named 'foo' in struct 'tmp.A'
// :1:11: note: struct declared here
// :10:17: error: no field named 'bar' in struct 'tmp.A'
// :1:11: note: struct declared here
// :18:45: error: no field named 'f' in struct 'tmp.e.B'
// :14:15: note: struct declared here

View File

@ -5,5 +5,7 @@
// target=x86_64-linux
// output_mode=Exe
//
// :?:?: error: root struct of file 'tmp' has no member named 'main'
// :?:?: note: called from here
// : error: root struct of file 'tmp' has no member named 'main'
// : note: called from here
// : note: called from here
// : note: called from here

View File

@ -5,6 +5,8 @@ fn main() void {}
// target=x86_64-linux
// output_mode=Exe
//
// :?:?: error: 'main' is not marked 'pub'
// : error: 'main' is not marked 'pub'
// :1:1: note: declared here
// :?:?: note: called from here
// : note: called from here
// : note: called from here
// : note: called from here

View File

@ -15,5 +15,6 @@ export fn entry() void {
// target=native
//
// :9:51: error: values of type '[]const builtin.Type.StructField' must be comptime-known, but index value is runtime-known
// :?:21: note: struct requires comptime because of this field
// :?:21: note: types are not available at runtime
// : note: struct requires comptime because of this field
// : note: types are not available at runtime
// : struct requires comptime because of this field

View File

@ -13,6 +13,6 @@ comptime {
// target=native
//
// :7:16: error: expected type 'tmp.Foo', found 'tmp.Bar'
// :1:13: note: struct declared here
// :2:13: note: struct declared here
// :1:13: note: struct declared here
// :4:18: note: parameter type declared here

View File

@ -28,10 +28,11 @@ export fn u2m() void {
// target=native
//
// :9:1: error: union initializer must initialize one field
// :1:12: note: union declared here
// :14:20: error: cannot initialize multiple union fields at once, unions can only have one active field
// :14:31: note: additional initializer here
// :1:12: note: union declared here
// :18:21: error: union initializer must initialize one field
// :22:20: error: cannot initialize multiple union fields at once, unions can only have one active field
// :22:31: note: additional initializer here
// :1:12: note: union declared here
// :5:12: note: union declared here

View File

@ -5,7 +5,7 @@ pub fn main() void {
_ = entry;
}
// error
// compile
// output_mode=Exe
// backend=llvm
// target=x86_64-linux,x86_64-macos

View File

@ -5,7 +5,7 @@ pub fn main() void {
_ = entry;
}
// error
// compile
// output_mode=Exe
// backend=stage2,llvm
// target=x86_64-linux,x86_64-macos

View File

@ -6,7 +6,7 @@ pub fn main() void {
_ = entry;
}
// error
// compile
// output_mode=Exe
// backend=llvm
// target=x86_64-linux,x86_64-macos

View File

@ -6,7 +6,7 @@ pub fn main() void {
_ = entry;
}
// error
// compile
// output_mode=Exe
// backend=stage2,llvm
// target=x86_64-linux,x86_64-macos

View File

@ -5,7 +5,7 @@ pub fn main() void {
_ = entry;
}
// error
// compile
// output_mode=Exe
// backend=stage2,llvm
// target=x86_64-linux,x86_64-macos

View File

@ -5,7 +5,7 @@ pub fn main() void {
_ = entry;
}
// error
// compile
// output_mode=Exe
// backend=stage2,llvm
// target=x86_64-linux,x86_64-macos

View File

@ -5,7 +5,7 @@ pub fn main() void {
_ = entry;
}
// error
// compile
// output_mode=Exe
// backend=stage2,llvm
// target=x86_64-linux,x86_64-macos

View File

@ -5,7 +5,7 @@ pub fn main() void {
_ = entry;
}
// error
// compile
// output_mode=Exe
// backend=stage2,llvm
// target=x86_64-linux,x86_64-macos

View File

@ -1,5 +1,5 @@
const std = @import("std");
const TestContext = @import("../../src/test.zig").TestContext;
const Cases = @import("src/Cases.zig");
// These tests should work with all platforms, but we're using linux_x64 for
// now for consistency. Will be expanded eventually.
@ -8,7 +8,7 @@ const linux_x64 = std.zig.CrossTarget{
.os_tag = .linux,
};
pub fn addCases(ctx: *TestContext) !void {
pub fn addCases(ctx: *Cases) !void {
{
var case = ctx.exeFromCompiledC("hello world with updates", .{});
@ -71,7 +71,7 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
var case = ctx.exeFromCompiledC("@intToError", .{});
var case = ctx.exeFromCompiledC("intToError", .{});
case.addCompareOutput(
\\pub export fn main() c_int {
@ -837,7 +837,7 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
var case = ctx.exeFromCompiledC("shift right + left", .{});
var case = ctx.exeFromCompiledC("shift right and left", .{});
case.addCompareOutput(
\\pub export fn main() c_int {
\\ var i: u32 = 16;
@ -883,7 +883,7 @@ pub fn addCases(ctx: *TestContext) !void {
{
// TODO: add u64 tests, ran into issues with the literal generated for std.math.maxInt(u64)
var case = ctx.exeFromCompiledC("add/sub wrapping operations", .{});
var case = ctx.exeFromCompiledC("add and sub wrapping operations", .{});
case.addCompareOutput(
\\pub export fn main() c_int {
\\ // Addition
@ -932,7 +932,7 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
var case = ctx.exeFromCompiledC("@rem", linux_x64);
var case = ctx.exeFromCompiledC("rem", linux_x64);
case.addCompareOutput(
\\fn assert(ok: bool) void {
\\ if (!ok) unreachable;
@ -947,69 +947,4 @@ pub fn addCases(ctx: *TestContext) !void {
\\}
, "");
}
ctx.h("simple header", linux_x64,
\\export fn start() void{}
,
\\zig_extern void start(void);
\\
);
ctx.h("header with single param function", linux_x64,
\\export fn start(a: u8) void{
\\ _ = a;
\\}
,
\\zig_extern void start(uint8_t const a0);
\\
);
ctx.h("header with multiple param function", linux_x64,
\\export fn start(a: u8, b: u8, c: u8) void{
\\ _ = a; _ = b; _ = c;
\\}
,
\\zig_extern void start(uint8_t const a0, uint8_t const a1, uint8_t const a2);
\\
);
ctx.h("header with u32 param function", linux_x64,
\\export fn start(a: u32) void{ _ = a; }
,
\\zig_extern void start(uint32_t const a0);
\\
);
ctx.h("header with usize param function", linux_x64,
\\export fn start(a: usize) void{ _ = a; }
,
\\zig_extern void start(uintptr_t const a0);
\\
);
ctx.h("header with bool param function", linux_x64,
\\export fn start(a: bool) void{_ = a;}
,
\\zig_extern void start(bool const a0);
\\
);
ctx.h("header with noreturn function", linux_x64,
\\export fn start() noreturn {
\\ unreachable;
\\}
,
\\zig_extern zig_noreturn void start(void);
\\
);
ctx.h("header with multiple functions", linux_x64,
\\export fn a() void{}
\\export fn b() void{}
\\export fn c() void{}
,
\\zig_extern void a(void);
\\zig_extern void b(void);
\\zig_extern void c(void);
\\
);
ctx.h("header with multiple includes", linux_x64,
\\export fn start(a: u32, b: usize) void{ _ = a; _ = b; }
,
\\zig_extern void start(uint32_t const a0, uintptr_t const a1);
\\
);
}

View File

@ -1,146 +1,10 @@
const std = @import("std");
const builtin = @import("builtin");
const TestContext = @import("../src/test.zig").TestContext;
pub fn addCases(ctx: *TestContext) !void {
{
const case = ctx.obj("wrong same named struct", .{});
case.backend = .stage1;
case.addSourceFile("a.zig",
\\pub const Foo = struct {
\\ x: i32,
\\};
);
case.addSourceFile("b.zig",
\\pub const Foo = struct {
\\ z: f64,
\\};
);
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",
});
}
{
const case = ctx.obj("multiple files with private function error", .{});
case.backend = .stage1;
case.addSourceFile("foo.zig",
\\fn privateFunction() void { }
);
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",
});
}
{
const case = ctx.obj("multiple files with private member instance function (canonical invocation) error", .{});
case.backend = .stage1;
case.addSourceFile("foo.zig",
\\pub const Foo = struct {
\\ fn privateFunction(self: *Foo) void { _ = self; }
\\};
);
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",
});
}
{
const case = ctx.obj("multiple files with private member instance function error", .{});
case.backend = .stage1;
case.addSourceFile("foo.zig",
\\pub const Foo = struct {
\\ fn privateFunction(self: *Foo) void { _ = self; }
\\};
);
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",
});
}
{
const case = ctx.obj("export collision", .{});
case.backend = .stage1;
case.addSourceFile("foo.zig",
\\export fn bar() void {}
\\pub const baz = 1234;
);
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",
});
}
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'",
});
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'",
});
const Cases = @import("src/Cases.zig");
pub fn addCases(ctx: *Cases) !void {
{
const case = ctx.obj("multiline error messages", .{});
case.backend = .stage2;
case.addError(
\\comptime {
@ -176,7 +40,6 @@ pub fn addCases(ctx: *TestContext) !void {
{
const case = ctx.obj("isolated carriage return in multiline string literal", .{});
case.backend = .stage2;
case.addError("const foo = \\\\\test\r\r rogue carriage return\n;", &[_][]const u8{
":1:19: error: expected ';' after declaration",
@ -195,16 +58,6 @@ pub fn addCases(ctx: *TestContext) !void {
{
const case = ctx.obj("argument causes error", .{});
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 {
@ -216,15 +69,18 @@ pub fn addCases(ctx: *TestContext) !void {
":3:12: note: argument to function being called at comptime must be comptime-known",
":2:55: note: expression is evaluated at comptime because the generic function was instantiated with a comptime-only return type",
});
case.addSourceFile("b.zig",
\\pub const ElfDynLib = struct {
\\ pub fn lookup(self: *ElfDynLib, comptime T: type) ?T {
\\ _ = self;
\\ return undefined;
\\ }
\\};
);
}
{
const case = ctx.obj("astgen failure in file struct", .{});
case.backend = .stage2;
case.addSourceFile("b.zig",
\\+
);
case.addError(
\\pub export fn entry() void {
@ -233,21 +89,13 @@ pub fn addCases(ctx: *TestContext) !void {
, &[_][]const u8{
":1:1: error: expected type expression, found '+'",
});
case.addSourceFile("b.zig",
\\+
);
}
{
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");
@ -259,44 +107,19 @@ pub fn addCases(ctx: *TestContext) !void {
":4:23: error: value stored in comptime field does not match the default value of the field",
":2:25: note: default value set here",
});
case.addSourceFile("a.zig",
\\pub const S = struct {
\\ comptime foo: u32 = 1,
\\ bar: u32,
\\ pub fn foo(x: @This()) void {
\\ _ = x;
\\ }
\\};
);
}
// 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",
//});
//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",
//});
{
const case = ctx.obj("file in multiple modules", .{});
case.backend = .stage2;
case.addSourceFile("foo.zig",
\\const dummy = 0;
);
case.addDepModule("foo", "foo.zig");
case.addError(
@ -309,5 +132,8 @@ pub fn addCases(ctx: *TestContext) !void {
":1:1: note: root of module root.foo",
":3:17: note: imported from module root",
});
case.addSourceFile("foo.zig",
\\const dummy = 0;
);
}
}

View File

@ -13,7 +13,7 @@ pub fn build(b: *std.Build) void {
// Without -dead_strip, we expect `iAmUnused` symbol present
const exe = createScenario(b, optimize, target, "no-gc");
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkInSymtab();
check.checkNext("{*} (__TEXT,__text) external _iAmUnused");
@ -27,7 +27,7 @@ pub fn build(b: *std.Build) void {
const exe = createScenario(b, optimize, target, "yes-gc");
exe.link_gc_sections = true;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkInSymtab();
check.checkNotPresent("{*} (__TEXT,__text) external _iAmUnused");

View File

@ -18,7 +18,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
// Without -dead_strip_dylibs we expect `-la` to include liba.dylib in the final executable
const exe = createScenario(b, optimize, "no-dead-strip");
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("cmd LOAD_DYLIB");
check.checkNext("name {*}Cocoa");

View File

@ -24,7 +24,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
dylib.addCSourceFile("a.c", &.{});
dylib.linkLibC();
const check_dylib = dylib.checkObject(.macho);
const check_dylib = dylib.checkObject();
check_dylib.checkStart("cmd ID_DYLIB");
check_dylib.checkNext("name @rpath/liba.dylib");
check_dylib.checkNext("timestamp 2");
@ -44,7 +44,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.addRPathDirectorySource(dylib.getOutputDirectorySource());
exe.linkLibC();
const check_exe = exe.checkObject(.macho);
const check_exe = exe.checkObject();
check_exe.checkStart("cmd LOAD_DYLIB");
check_exe.checkNext("name @rpath/liba.dylib");
check_exe.checkNext("timestamp 2");

View File

@ -22,7 +22,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.linkLibC();
exe.entry_symbol_name = "_non_main";
const check_exe = exe.checkObject(.macho);
const check_exe = exe.checkObject();
check_exe.checkStart("segname __TEXT");
check_exe.checkNext("vmaddr {vmaddr}");

View File

@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
const exe = simpleExe(b, optimize);
exe.headerpad_max_install_names = true;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("sectname __text");
check.checkNext("offset {offset}");
@ -45,7 +45,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
const exe = simpleExe(b, optimize);
exe.headerpad_size = 0x10000;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("sectname __text");
check.checkNext("offset {offset}");
check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x10000 } });
@ -62,7 +62,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.headerpad_max_install_names = true;
exe.headerpad_size = 0x10000;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("sectname __text");
check.checkNext("offset {offset}");
check.checkComputeCompare("offset", .{ .op = .gte, .value = .{ .literal = 0x10000 } });
@ -79,7 +79,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.headerpad_size = 0x1000;
exe.headerpad_max_install_names = true;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("sectname __text");
check.checkNext("offset {offset}");

View File

@ -22,7 +22,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
.target = target,
});
const check = obj.checkObject(.macho);
const check = obj.checkObject();
check.checkInSymtab();
check.checkNext("{*} (__DATA,__TestGlobal) external _test_global");

View File

@ -25,7 +25,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.linkFrameworkNeeded("Cocoa");
exe.dead_strip_dylibs = true;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("cmd LOAD_DYLIB");
check.checkNext("name {*}Cocoa");
test_step.dependOn(&check.step);

View File

@ -38,7 +38,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.addRPathDirectorySource(dylib.getOutputDirectorySource());
exe.dead_strip_dylibs = true;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("cmd LOAD_DYLIB");
check.checkNext("name @rpath/liba.dylib");

View File

@ -19,7 +19,7 @@ pub fn build(b: *std.Build) void {
exe.linkLibC();
exe.pagezero_size = 0x4000;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("LC 0");
check.checkNext("segname __PAGEZERO");
check.checkNext("vmaddr 0");
@ -41,7 +41,7 @@ pub fn build(b: *std.Build) void {
exe.linkLibC();
exe.pagezero_size = 0;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("LC 0");
check.checkNext("segname __TEXT");
check.checkNext("vmaddr 0");

View File

@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
const exe = createScenario(b, optimize, target, "search_dylibs_first");
exe.search_strategy = .dylibs_first;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("cmd LOAD_DYLIB");
check.checkNext("name @rpath/libsearch_dylibs_first.dylib");

View File

@ -24,7 +24,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.linkLibC();
exe.stack_size = 0x100000000;
const check_exe = exe.checkObject(.macho);
const check_exe = exe.checkObject();
check_exe.checkStart("cmd MAIN");
check_exe.checkNext("stacksize 100000000");

View File

@ -24,7 +24,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
});
exe.linkLibC();
const check_exe = exe.checkObject(.macho);
const check_exe = exe.checkObject();
check_exe.checkStart("cmd SEGMENT_64");
check_exe.checkNext("segname __LINKEDIT");

View File

@ -31,7 +31,7 @@ fn testUnwindInfo(
const exe = createScenario(b, optimize, target, name);
exe.link_gc_sections = dead_strip;
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("segname __TEXT");
check.checkNext("sectname __gcc_except_tab");
check.checkNext("sectname __unwind_info");

View File

@ -22,7 +22,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.linkLibC();
exe.linkFrameworkWeak("Cocoa");
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("cmd LOAD_WEAK_DYLIB");
check.checkNext("name {*}Cocoa");
test_step.dependOn(&check.step);

View File

@ -36,7 +36,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
exe.addLibraryPathDirectorySource(dylib.getOutputDirectorySource());
exe.addRPathDirectorySource(dylib.getOutputDirectorySource());
const check = exe.checkObject(.macho);
const check = exe.checkObject();
check.checkStart("cmd LOAD_WEAK_DYLIB");
check.checkNext("name @rpath/liba.dylib");

View File

@ -25,7 +25,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
lib.use_lld = false;
lib.strip = false;
const check = lib.checkObject(.wasm);
const check = lib.checkObject();
check.checkStart("Section custom");
check.checkNext("name __truncsfhf2"); // Ensure it was imported and resolved

View File

@ -19,7 +19,7 @@ pub fn build(b: *std.Build) void {
lib.use_lld = false;
// Verify the result contains the features explicitly set on the target for the library.
const check = lib.checkObject(.wasm);
const check = lib.checkObject();
check.checkStart("name target_features");
check.checkNext("features 1");
check.checkNext("+ atomics");

View File

@ -19,7 +19,7 @@ pub fn build(b: *std.Build) void {
lib.import_memory = true;
lib.install();
const check_lib = lib.checkObject(.wasm);
const check_lib = lib.checkObject();
// since we import memory, make sure it exists with the correct naming
check_lib.checkStart("Section import");

View File

@ -19,7 +19,7 @@ pub fn build(b: *std.Build) void {
lib.export_symbol_names = &.{ "foo", "bar" };
lib.global_base = 0; // put data section at address 0 to make data symbols easier to parse
const check_lib = lib.checkObject(.wasm);
const check_lib = lib.checkObject();
check_lib.checkStart("Section global");
check_lib.checkNext("entries 3");

View File

@ -42,19 +42,19 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
force_export.use_llvm = false;
force_export.use_lld = false;
const check_no_export = no_export.checkObject(.wasm);
const check_no_export = no_export.checkObject();
check_no_export.checkStart("Section export");
check_no_export.checkNext("entries 1");
check_no_export.checkNext("name memory");
check_no_export.checkNext("kind memory");
const check_dynamic_export = dynamic_export.checkObject(.wasm);
const check_dynamic_export = dynamic_export.checkObject();
check_dynamic_export.checkStart("Section export");
check_dynamic_export.checkNext("entries 2");
check_dynamic_export.checkNext("name foo");
check_dynamic_export.checkNext("kind function");
const check_force_export = force_export.checkObject(.wasm);
const check_force_export = force_export.checkObject();
check_force_export.checkStart("Section export");
check_force_export.checkNext("entries 2");
check_force_export.checkNext("name foo");

View File

@ -20,7 +20,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
lib.import_symbols = true; // import `a` and `b`
lib.rdynamic = true; // export `foo`
const check_lib = lib.checkObject(.wasm);
const check_lib = lib.checkObject();
check_lib.checkStart("Section import");
check_lib.checkNext("entries 2"); // a.hello & b.hello
check_lib.checkNext("module a");

View File

@ -42,9 +42,9 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
regular_table.use_llvm = false;
regular_table.use_lld = false;
const check_import = import_table.checkObject(.wasm);
const check_export = export_table.checkObject(.wasm);
const check_regular = regular_table.checkObject(.wasm);
const check_import = import_table.checkObject();
const check_export = export_table.checkObject();
const check_regular = regular_table.checkObject();
check_import.checkStart("Section import");
check_import.checkNext("entries 1");

View File

@ -32,7 +32,7 @@ pub fn build(b: *std.Build) void {
lib.addObject(c_obj);
// Verify the result contains the features from the C Object file.
const check = lib.checkObject(.wasm);
const check = lib.checkObject();
check.checkStart("name target_features");
check.checkNext("features 7");
check.checkNext("+ atomics");

View File

@ -27,7 +27,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
const version_fmt = "version " ++ builtin.zig_version_string;
const check_lib = lib.checkObject(.wasm);
const check_lib = lib.checkObject();
check_lib.checkStart("name producers");
check_lib.checkNext("fields 2");
check_lib.checkNext("field_name language");

View File

@ -24,7 +24,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
lib.strip = false;
lib.install();
const check_lib = lib.checkObject(.wasm);
const check_lib = lib.checkObject();
check_lib.checkStart("Section data");
check_lib.checkNext("entries 2"); // rodata & data, no bss because we're exporting memory

View File

@ -25,7 +25,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
lib.stack_size = std.wasm.page_size * 2; // set an explicit stack size
lib.install();
const check_lib = lib.checkObject(.wasm);
const check_lib = lib.checkObject();
// ensure global exists and its initial value is equal to explitic stack size
check_lib.checkStart("Section global");

View File

@ -24,7 +24,7 @@ fn add(b: *std.Build, test_step: *std.Build.Step, optimize: std.builtin.Optimize
lib.strip = false;
lib.install();
const check_lib = lib.checkObject(.wasm);
const check_lib = lib.checkObject();
check_lib.checkStart("Section type");
// only 2 entries, although we have 3 functions.
// This is to test functions with the same function signature

View File

@ -1,11 +1,11 @@
const std = @import("std");
const TestContext = @import("../../src/test.zig").TestContext;
const Cases = @import("src/Cases.zig");
pub fn addCases(ctx: *TestContext) !void {
pub fn addCases(ctx: *Cases) !void {
{
var case = addPtx(ctx, "nvptx: simple addition and subtraction");
var case = addPtx(ctx, "simple addition and subtraction");
case.compiles(
case.addCompile(
\\fn add(a: i32, b: i32) i32 {
\\ return a + b;
\\}
@ -20,9 +20,9 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
var case = addPtx(ctx, "nvptx: read special registers");
var case = addPtx(ctx, "read special registers");
case.compiles(
case.addCompile(
\\fn threadIdX() u32 {
\\ return asm ("mov.u32 \t%[r], %tid.x;"
\\ : [r] "=r" (-> u32),
@ -37,9 +37,9 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
var case = addPtx(ctx, "nvptx: address spaces");
var case = addPtx(ctx, "address spaces");
case.compiles(
case.addCompile(
\\var x: i32 addrspace(.global) = 0;
\\
\\pub export fn increment(out: *i32) callconv(.PtxKernel) void {
@ -50,8 +50,8 @@ pub fn addCases(ctx: *TestContext) !void {
}
{
var case = addPtx(ctx, "nvptx: reduce in shared mem");
case.compiles(
var case = addPtx(ctx, "reduce in shared mem");
case.addCompile(
\\fn threadIdX() u32 {
\\ return asm ("mov.u32 \t%[r], %tid.x;"
\\ : [r] "=r" (-> u32),
@ -88,16 +88,15 @@ const nvptx_target = std.zig.CrossTarget{
};
pub fn addPtx(
ctx: *TestContext,
ctx: *Cases,
name: []const u8,
) *TestContext.Case {
ctx.cases.append(TestContext.Case{
) *Cases.Case {
ctx.cases.append(.{
.name = name,
.target = nvptx_target,
.updates = std.ArrayList(TestContext.Update).init(ctx.cases.allocator),
.updates = std.ArrayList(Cases.Update).init(ctx.cases.allocator),
.output_mode = .Obj,
.files = std.ArrayList(TestContext.File).init(ctx.cases.allocator),
.deps = std.ArrayList(TestContext.DepModule).init(ctx.cases.allocator),
.deps = std.ArrayList(Cases.DepModule).init(ctx.cases.allocator),
.link_libc = false,
.backend = .llvm,
// Bug in Debug mode

1587
test/src/Cases.zig Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1055,3 +1055,30 @@ pub fn addCAbiTests(b: *std.Build, skip_non_native: bool, skip_release: bool) *S
}
return step;
}
pub fn addCases(
b: *std.Build,
parent_step: *Step,
opt_test_filter: ?[]const u8,
check_case_exe: *std.Build.CompileStep,
) !void {
const arena = b.allocator;
const gpa = b.allocator;
var cases = @import("src/Cases.zig").init(gpa, arena);
var dir = try b.build_root.handle.openIterableDir("test/cases", .{});
defer dir.close();
cases.addFromDir(dir);
try @import("cases.zig").addCases(&cases);
const cases_dir_path = try b.build_root.join(b.allocator, &.{ "test", "cases" });
cases.lowerToBuildSteps(
b,
parent_step,
opt_test_filter,
cases_dir_path,
check_case_exe,
);
}