authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-11 00:50:17-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-07-11 00:50:17-04:00
logc620a1fe3d40d25d6b6654a4c828e8d7d7e37c38
tree4cab564fe918fcc167bfcd52c3a619607f0fc364
parent8fba0a6ae862993afa2aeca774347adc399b3605
parent8197a14ceb2938c64526c7b84e2ac8da343960fa
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #1215 from ziglang/self-hosted-first-test

self-hosted: first passing test

11 files changed, 420 insertions(+), 107 deletions(-)

CMakeLists.txt+1
...@@ -431,6 +431,7 @@ set(ZIG_CPP_SOURCES...@@ -431,6 +431,7 @@ set(ZIG_CPP_SOURCES
431set(ZIG_STD_FILES431set(ZIG_STD_FILES
432 "array_list.zig"432 "array_list.zig"
433 "atomic/index.zig"433 "atomic/index.zig"
434 "atomic/int.zig"
434 "atomic/queue_mpmc.zig"435 "atomic/queue_mpmc.zig"
435 "atomic/queue_mpsc.zig"436 "atomic/queue_mpsc.zig"
436 "atomic/stack.zig"437 "atomic/stack.zig"
build.zig+89-63
...@@ -35,70 +35,27 @@ pub fn build(b: *Builder) !void {...@@ -35,70 +35,27 @@ pub fn build(b: *Builder) !void {
35 "BUILD_INFO",35 "BUILD_INFO",
36 });36 });
37 var index: usize = 0;37 var index: usize = 0;
38 const cmake_binary_dir = nextValue(&index, build_info);38 var ctx = Context{
39 const cxx_compiler = nextValue(&index, build_info);39 .cmake_binary_dir = nextValue(&index, build_info),
40 const llvm_config_exe = nextValue(&index, build_info);40 .cxx_compiler = nextValue(&index, build_info),
41 const lld_include_dir = nextValue(&index, build_info);41 .llvm_config_exe = nextValue(&index, build_info),
42 const lld_libraries = nextValue(&index, build_info);42 .lld_include_dir = nextValue(&index, build_info),
43 const std_files = nextValue(&index, build_info);43 .lld_libraries = nextValue(&index, build_info),
44 const c_header_files = nextValue(&index, build_info);44 .std_files = nextValue(&index, build_info),
45 const dia_guids_lib = nextValue(&index, build_info);45 .c_header_files = nextValue(&index, build_info),
46 .dia_guids_lib = nextValue(&index, build_info),
47 .llvm = undefined,
48 };
49 ctx.llvm = try findLLVM(b, ctx.llvm_config_exe);
4650
47 const llvm = findLLVM(b, llvm_config_exe) catch unreachable;51 var test_stage2 = b.addTest("src-self-hosted/test.zig");
52 test_stage2.setBuildMode(builtin.Mode.Debug);
4853
49 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");54 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
50 exe.setBuildMode(mode);55 exe.setBuildMode(mode);
5156
52 // This is for finding /lib/libz.a on alpine linux.57 try configureStage2(b, test_stage2, ctx);
53 // TODO turn this into -Dextra-lib-path=/lib option58 try configureStage2(b, exe, ctx);
54 exe.addLibPath("/lib");
55
56 exe.addIncludeDir("src");
57 exe.addIncludeDir(cmake_binary_dir);
58 addCppLib(b, exe, cmake_binary_dir, "zig_cpp");
59 if (lld_include_dir.len != 0) {
60 exe.addIncludeDir(lld_include_dir);
61 var it = mem.split(lld_libraries, ";");
62 while (it.next()) |lib| {
63 exe.addObjectFile(lib);
64 }
65 } else {
66 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_wasm");
67 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_elf");
68 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_coff");
69 addCppLib(b, exe, cmake_binary_dir, "embedded_lld_lib");
70 }
71 dependOnLib(exe, llvm);
72
73 if (exe.target.getOs() == builtin.Os.linux) {
74 const libstdcxx_path_padded = try b.exec([][]const u8{
75 cxx_compiler,
76 "-print-file-name=libstdc++.a",
77 });
78 const libstdcxx_path = mem.split(libstdcxx_path_padded, "\r\n").next().?;
79 if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
80 warn(
81 \\Unable to determine path to libstdc++.a
82 \\On Fedora, install libstdc++-static and try again.
83 \\
84 );
85 return error.RequiredLibraryNotFound;
86 }
87 exe.addObjectFile(libstdcxx_path);
88
89 exe.linkSystemLibrary("pthread");
90 } else if (exe.target.isDarwin()) {
91 exe.linkSystemLibrary("c++");
92 }
93
94 if (dia_guids_lib.len != 0) {
95 exe.addObjectFile(dia_guids_lib);
96 }
97
98 if (exe.target.getOs() != builtin.Os.windows) {
99 exe.linkSystemLibrary("xml2");
100 }
101 exe.linkSystemLibrary("c");
10259
103 b.default_step.dependOn(&exe.step);60 b.default_step.dependOn(&exe.step);
10461
...@@ -110,12 +67,16 @@ pub fn build(b: *Builder) !void {...@@ -110,12 +67,16 @@ pub fn build(b: *Builder) !void {
110 exe.setVerboseLink(verbose_link_exe);67 exe.setVerboseLink(verbose_link_exe);
11168
112 b.installArtifact(exe);69 b.installArtifact(exe);
113 installStdLib(b, std_files);70 installStdLib(b, ctx.std_files);
114 installCHeaders(b, c_header_files);71 installCHeaders(b, ctx.c_header_files);
11572
116 const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");73 const test_filter = b.option([]const u8, "test-filter", "Skip tests that do not match filter");
117 const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") orelse false;74 const with_lldb = b.option(bool, "with-lldb", "Run tests in LLDB to get a backtrace if one fails") orelse false;
11875
76 const test_stage2_step = b.step("test-stage2", "Run the stage2 compiler tests");
77 test_stage2_step.dependOn(&test_stage2.step);
78 test_step.dependOn(test_stage2_step);
79
119 test_step.dependOn(docs_step);80 test_step.dependOn(docs_step);
12081
121 test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", with_lldb));82 test_step.dependOn(tests.addPkgTests(b, test_filter, "test/behavior.zig", "behavior", "Run the behavior tests", with_lldb));
...@@ -133,7 +94,7 @@ pub fn build(b: *Builder) !void {...@@ -133,7 +94,7 @@ pub fn build(b: *Builder) !void {
133 test_step.dependOn(tests.addGenHTests(b, test_filter));94 test_step.dependOn(tests.addGenHTests(b, test_filter));
134}95}
13596
136fn dependOnLib(lib_exe_obj: *std.build.LibExeObjStep, dep: *const LibraryDep) void {97fn dependOnLib(lib_exe_obj: var, dep: *const LibraryDep) void {
137 for (dep.libdirs.toSliceConst()) |lib_dir| {98 for (dep.libdirs.toSliceConst()) |lib_dir| {
138 lib_exe_obj.addLibPath(lib_dir);99 lib_exe_obj.addLibPath(lib_dir);
139 }100 }
...@@ -148,7 +109,7 @@ fn dependOnLib(lib_exe_obj: *std.build.LibExeObjStep, dep: *const LibraryDep) vo...@@ -148,7 +109,7 @@ fn dependOnLib(lib_exe_obj: *std.build.LibExeObjStep, dep: *const LibraryDep) vo
148 }109 }
149}110}
150111
151fn addCppLib(b: *Builder, lib_exe_obj: *std.build.LibExeObjStep, cmake_binary_dir: []const u8, lib_name: []const u8) void {112fn addCppLib(b: *Builder, lib_exe_obj: var, cmake_binary_dir: []const u8, lib_name: []const u8) void {
152 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";113 const lib_prefix = if (lib_exe_obj.target.isWindows()) "" else "lib";
153 lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);114 lib_exe_obj.addObjectFile(os.path.join(b.allocator, cmake_binary_dir, "zig_cpp", b.fmt("{}{}{}", lib_prefix, lib_name, lib_exe_obj.target.libFileExt())) catch unreachable);
154}115}
...@@ -254,3 +215,68 @@ fn nextValue(index: *usize, build_info: []const u8) []const u8 {...@@ -254,3 +215,68 @@ fn nextValue(index: *usize, build_info: []const u8) []const u8 {
254 }215 }
255 }216 }
256}217}
218
219fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
220 // This is for finding /lib/libz.a on alpine linux.
221 // TODO turn this into -Dextra-lib-path=/lib option
222 exe.addLibPath("/lib");
223
224 exe.addIncludeDir("src");
225 exe.addIncludeDir(ctx.cmake_binary_dir);
226 addCppLib(b, exe, ctx.cmake_binary_dir, "zig_cpp");
227 if (ctx.lld_include_dir.len != 0) {
228 exe.addIncludeDir(ctx.lld_include_dir);
229 var it = mem.split(ctx.lld_libraries, ";");
230 while (it.next()) |lib| {
231 exe.addObjectFile(lib);
232 }
233 } else {
234 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_wasm");
235 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_elf");
236 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_coff");
237 addCppLib(b, exe, ctx.cmake_binary_dir, "embedded_lld_lib");
238 }
239 dependOnLib(exe, ctx.llvm);
240
241 if (exe.target.getOs() == builtin.Os.linux) {
242 const libstdcxx_path_padded = try b.exec([][]const u8{
243 ctx.cxx_compiler,
244 "-print-file-name=libstdc++.a",
245 });
246 const libstdcxx_path = mem.split(libstdcxx_path_padded, "\r\n").next().?;
247 if (mem.eql(u8, libstdcxx_path, "libstdc++.a")) {
248 warn(
249 \\Unable to determine path to libstdc++.a
250 \\On Fedora, install libstdc++-static and try again.
251 \\
252 );
253 return error.RequiredLibraryNotFound;
254 }
255 exe.addObjectFile(libstdcxx_path);
256
257 exe.linkSystemLibrary("pthread");
258 } else if (exe.target.isDarwin()) {
259 exe.linkSystemLibrary("c++");
260 }
261
262 if (ctx.dia_guids_lib.len != 0) {
263 exe.addObjectFile(ctx.dia_guids_lib);
264 }
265
266 if (exe.target.getOs() != builtin.Os.windows) {
267 exe.linkSystemLibrary("xml2");
268 }
269 exe.linkSystemLibrary("c");
270}
271
272const Context = struct {
273 cmake_binary_dir: []const u8,
274 cxx_compiler: []const u8,
275 llvm_config_exe: []const u8,
276 lld_include_dir: []const u8,
277 lld_libraries: []const u8,
278 std_files: []const u8,
279 c_header_files: []const u8,
280 dia_guids_lib: []const u8,
281 llvm: LibraryDep,
282};
src-self-hosted/errmsg.zig+12-6
...@@ -11,11 +11,15 @@ pub const Color = enum {...@@ -11,11 +11,15 @@ pub const Color = enum {
11 On,11 On,
12};12};
1313
14pub const Span = struct {
15 first: ast.TokenIndex,
16 last: ast.TokenIndex,
17};
18
14pub const Msg = struct {19pub const Msg = struct {
15 path: []const u8,20 path: []const u8,
16 text: []u8,21 text: []u8,
17 first_token: TokenIndex,22 span: Span,
18 last_token: TokenIndex,
19 tree: *ast.Tree,23 tree: *ast.Tree,
20};24};
2125
...@@ -39,8 +43,10 @@ pub fn createFromParseError(...@@ -39,8 +43,10 @@ pub fn createFromParseError(
39 .tree = tree,43 .tree = tree,
40 .path = path,44 .path = path,
41 .text = text_buf.toOwnedSlice(),45 .text = text_buf.toOwnedSlice(),
42 .first_token = loc_token,46 .span = Span{
43 .last_token = loc_token,47 .first = loc_token,
48 .last = loc_token,
49 },
44 });50 });
45 errdefer allocator.destroy(msg);51 errdefer allocator.destroy(msg);
4652
...@@ -48,8 +54,8 @@ pub fn createFromParseError(...@@ -48,8 +54,8 @@ pub fn createFromParseError(
48}54}
4955
50pub fn printToStream(stream: var, msg: *const Msg, color_on: bool) !void {56pub fn printToStream(stream: var, msg: *const Msg, color_on: bool) !void {
51 const first_token = msg.tree.tokens.at(msg.first_token);57 const first_token = msg.tree.tokens.at(msg.span.first);
52 const last_token = msg.tree.tokens.at(msg.last_token);58 const last_token = msg.tree.tokens.at(msg.span.last);
53 const start_loc = msg.tree.tokenLocationPtr(0, first_token);59 const start_loc = msg.tree.tokenLocationPtr(0, first_token);
54 const end_loc = msg.tree.tokenLocationPtr(first_token.end, last_token);60 const end_loc = msg.tree.tokenLocationPtr(first_token.end, last_token);
55 if (!color_on) {61 if (!color_on) {
src-self-hosted/introspect.zig+5
...@@ -53,3 +53,8 @@ pub fn resolveZigLibDir(allocator: *mem.Allocator) ![]u8 {...@@ -53,3 +53,8 @@ pub fn resolveZigLibDir(allocator: *mem.Allocator) ![]u8 {
53 return error.ZigLibDirNotFound;53 return error.ZigLibDirNotFound;
54 };54 };
55}55}
56
57/// Caller must free result
58pub fn resolveZigCacheDir(allocator: *mem.Allocator) ![]u8 {
59 return std.mem.dupe(allocator, u8, "zig-cache");
60}
src-self-hosted/main.zig+18-18
...@@ -481,29 +481,29 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -481,29 +481,29 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
481 module.link_out_file = flags.single("out-file");481 module.link_out_file = flags.single("out-file");
482482
483 try module.build();483 try module.build();
484 const process_build_events_handle = try async<loop.allocator> processBuildEvents(module, true);484 const process_build_events_handle = try async<loop.allocator> processBuildEvents(module, color);
485 defer cancel process_build_events_handle;485 defer cancel process_build_events_handle;
486 loop.run();486 loop.run();
487}487}
488488
489async fn processBuildEvents(module: *Module, watch: bool) void {489async fn processBuildEvents(module: *Module, color: errmsg.Color) void {
490 while (watch) {490 // TODO directly awaiting async should guarantee memory allocation elision
491 // TODO directly awaiting async should guarantee memory allocation elision491 const build_event = await (async module.events.get() catch unreachable);
492 const build_event = await (async module.events.get() catch unreachable);
493492
494 switch (build_event) {493 switch (build_event) {
495 Module.Event.Ok => {494 Module.Event.Ok => {
496 std.debug.warn("Build succeeded\n");495 std.debug.warn("Build succeeded\n");
497 return;496 return;
498 },497 },
499 Module.Event.Error => |err| {498 Module.Event.Error => |err| {
500 std.debug.warn("build failed: {}\n", @errorName(err));499 std.debug.warn("build failed: {}\n", @errorName(err));
501 @panic("TODO error return trace");500 @panic("TODO error return trace");
502 },501 },
503 Module.Event.Fail => |errs| {502 Module.Event.Fail => |msgs| {
504 @panic("TODO print compile error messages");503 for (msgs) |msg| {
505 },504 errmsg.printToFile(&stderr_file, msg, color) catch os.exit(1);
506 }505 }
506 },
507 }507 }
508}508}
509509
src-self-hosted/module.zig+81-17
...@@ -89,12 +89,9 @@ pub const Module = struct {...@@ -89,12 +89,9 @@ pub const Module = struct {
89 /// the build is complete.89 /// the build is complete.
90 build_group: event.Group(BuildError!void),90 build_group: event.Group(BuildError!void),
9191
92 const BuildErrorsList = std.SegmentedList(BuildErrorDesc, 1);92 compile_errors: event.Locked(CompileErrList),
9393
94 pub const BuildErrorDesc = struct {94 const CompileErrList = std.ArrayList(*errmsg.Msg);
95 code: BuildError,
96 text: []const u8,
97 };
9895
99 // TODO handle some of these earlier and report them in a way other than error codes96 // TODO handle some of these earlier and report them in a way other than error codes
100 pub const BuildError = error{97 pub const BuildError = error{
...@@ -131,11 +128,12 @@ pub const Module = struct {...@@ -131,11 +128,12 @@ pub const Module = struct {
131 NoStdHandles,128 NoStdHandles,
132 Overflow,129 Overflow,
133 NotSupported,130 NotSupported,
131 BufferTooSmall,
134 };132 };
135133
136 pub const Event = union(enum) {134 pub const Event = union(enum) {
137 Ok,135 Ok,
138 Fail: []errmsg.Msg,136 Fail: []*errmsg.Msg,
139 Error: BuildError,137 Error: BuildError,
140 };138 };
141139
...@@ -249,6 +247,7 @@ pub const Module = struct {...@@ -249,6 +247,7 @@ pub const Module = struct {
249 .link_out_file = null,247 .link_out_file = null,
250 .exported_symbol_names = event.Locked(Decl.Table).init(loop, Decl.Table.init(loop.allocator)),248 .exported_symbol_names = event.Locked(Decl.Table).init(loop, Decl.Table.init(loop.allocator)),
251 .build_group = event.Group(BuildError!void).init(loop),249 .build_group = event.Group(BuildError!void).init(loop),
250 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),
252 });251 });
253 }252 }
254253
...@@ -288,7 +287,17 @@ pub const Module = struct {...@@ -288,7 +287,17 @@ pub const Module = struct {
288 await (async self.events.put(Event{ .Error = err }) catch unreachable);287 await (async self.events.put(Event{ .Error = err }) catch unreachable);
289 return;288 return;
290 };289 };
291 await (async self.events.put(Event.Ok) catch unreachable);290 const compile_errors = blk: {
291 const held = await (async self.compile_errors.acquire() catch unreachable);
292 defer held.release();
293 break :blk held.value.toOwnedSlice();
294 };
295
296 if (compile_errors.len == 0) {
297 await (async self.events.put(Event.Ok) catch unreachable);
298 } else {
299 await (async self.events.put(Event{ .Fail = compile_errors }) catch unreachable);
300 }
292 // for now we stop after 1301 // for now we stop after 1
293 return;302 return;
294 }303 }
...@@ -310,10 +319,13 @@ pub const Module = struct {...@@ -310,10 +319,13 @@ pub const Module = struct {
310 };319 };
311 errdefer self.a().free(source_code);320 errdefer self.a().free(source_code);
312321
313 var parsed_file = ParsedFile{322 const parsed_file = try self.a().create(ParsedFile{
314 .tree = try std.zig.parse(self.a(), source_code),323 .tree = undefined,
315 .realpath = root_src_real_path,324 .realpath = root_src_real_path,
316 };325 });
326 errdefer self.a().destroy(parsed_file);
327
328 parsed_file.tree = try std.zig.parse(self.a(), source_code);
317 errdefer parsed_file.tree.deinit();329 errdefer parsed_file.tree.deinit();
318330
319 const tree = &parsed_file.tree;331 const tree = &parsed_file.tree;
...@@ -337,7 +349,7 @@ pub const Module = struct {...@@ -337,7 +349,7 @@ pub const Module = struct {
337 const name = if (fn_proto.name_token) |name_token| tree.tokenSlice(name_token) else {349 const name = if (fn_proto.name_token) |name_token| tree.tokenSlice(name_token) else {
338 @panic("TODO add compile error");350 @panic("TODO add compile error");
339 //try self.addCompileError(351 //try self.addCompileError(
340 // &parsed_file,352 // parsed_file,
341 // fn_proto.fn_token,353 // fn_proto.fn_token,
342 // fn_proto.fn_token + 1,354 // fn_proto.fn_token + 1,
343 // "missing function name",355 // "missing function name",
...@@ -357,7 +369,7 @@ pub const Module = struct {...@@ -357,7 +369,7 @@ pub const Module = struct {
357 });369 });
358 errdefer self.a().destroy(fn_decl);370 errdefer self.a().destroy(fn_decl);
359371
360 try decl_group.call(addTopLevelDecl, self, tree, &fn_decl.base);372 try decl_group.call(addTopLevelDecl, self, parsed_file, &fn_decl.base);
361 },373 },
362 ast.Node.Id.TestDecl => @panic("TODO"),374 ast.Node.Id.TestDecl => @panic("TODO"),
363 else => unreachable,375 else => unreachable,
...@@ -367,20 +379,56 @@ pub const Module = struct {...@@ -367,20 +379,56 @@ pub const Module = struct {
367 try await (async self.build_group.wait() catch unreachable);379 try await (async self.build_group.wait() catch unreachable);
368 }380 }
369381
370 async fn addTopLevelDecl(self: *Module, tree: *ast.Tree, decl: *Decl) !void {382 async fn addTopLevelDecl(self: *Module, parsed_file: *ParsedFile, decl: *Decl) !void {
371 const is_export = decl.isExported(tree);383 const is_export = decl.isExported(&parsed_file.tree);
372384
373 if (is_export) {385 if (is_export) {
374 try self.build_group.call(verifyUniqueSymbol, self, decl);386 try self.build_group.call(verifyUniqueSymbol, self, parsed_file, decl);
375 }387 }
376 }388 }
377389
378 async fn verifyUniqueSymbol(self: *Module, decl: *Decl) !void {390 fn addCompileError(self: *Module, parsed_file: *ParsedFile, span: errmsg.Span, comptime fmt: []const u8, args: ...) !void {
391 const text = try std.fmt.allocPrint(self.loop.allocator, fmt, args);
392 errdefer self.loop.allocator.free(text);
393
394 try self.build_group.call(addCompileErrorAsync, self, parsed_file, span.first, span.last, text);
395 }
396
397 async fn addCompileErrorAsync(
398 self: *Module,
399 parsed_file: *ParsedFile,
400 first_token: ast.TokenIndex,
401 last_token: ast.TokenIndex,
402 text: []u8,
403 ) !void {
404 const msg = try self.loop.allocator.create(errmsg.Msg{
405 .path = parsed_file.realpath,
406 .text = text,
407 .span = errmsg.Span{
408 .first = first_token,
409 .last = last_token,
410 },
411 .tree = &parsed_file.tree,
412 });
413 errdefer self.loop.allocator.destroy(msg);
414
415 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);
416 defer compile_errors.release();
417
418 try compile_errors.value.append(msg);
419 }
420
421 async fn verifyUniqueSymbol(self: *Module, parsed_file: *ParsedFile, decl: *Decl) !void {
379 const exported_symbol_names = await (async self.exported_symbol_names.acquire() catch unreachable);422 const exported_symbol_names = await (async self.exported_symbol_names.acquire() catch unreachable);
380 defer exported_symbol_names.release();423 defer exported_symbol_names.release();
381424
382 if (try exported_symbol_names.value.put(decl.name, decl)) |other_decl| {425 if (try exported_symbol_names.value.put(decl.name, decl)) |other_decl| {
383 @panic("TODO report compile error");426 try self.addCompileError(
427 parsed_file,
428 decl.getSpan(),
429 "exported symbol collision: '{}'",
430 decl.name,
431 );
384 }432 }
385 }433 }
386434
...@@ -503,6 +551,22 @@ pub const Decl = struct {...@@ -503,6 +551,22 @@ pub const Decl = struct {
503 }551 }
504 }552 }
505553
554 pub fn getSpan(base: *const Decl) errmsg.Span {
555 switch (base.id) {
556 Id.Fn => {
557 const fn_decl = @fieldParentPtr(Fn, "base", base);
558 const fn_proto = fn_decl.fn_proto;
559 const start = fn_proto.fn_token;
560 const end = fn_proto.name_token orelse start;
561 return errmsg.Span{
562 .first = start,
563 .last = end + 1,
564 };
565 },
566 else => @panic("TODO"),
567 }
568 }
569
506 pub const Resolution = enum {570 pub const Resolution = enum {
507 Unresolved,571 Unresolved,
508 InProgress,572 InProgress,
src-self-hosted/test.zig created+164
...@@ -0,0 +1,164 @@
1const std = @import("std");
2const mem = std.mem;
3const builtin = @import("builtin");
4const Target = @import("target.zig").Target;
5const Module = @import("module.zig").Module;
6const introspect = @import("introspect.zig");
7const assertOrPanic = std.debug.assertOrPanic;
8const errmsg = @import("errmsg.zig");
9
10test "compile errors" {
11 var ctx: TestContext = undefined;
12 try ctx.init();
13 defer ctx.deinit();
14
15 try ctx.testCompileError(
16 \\export fn entry() void {}
17 \\export fn entry() void {}
18 , file1, 2, 8, "exported symbol collision: 'entry'");
19
20 try ctx.run();
21}
22
23const file1 = "1.zig";
24const allocator = std.heap.c_allocator;
25
26const TestContext = struct {
27 loop: std.event.Loop,
28 zig_lib_dir: []u8,
29 zig_cache_dir: []u8,
30 file_index: std.atomic.Int(usize),
31 group: std.event.Group(error!void),
32 any_err: error!void,
33
34 const tmp_dir_name = "stage2_test_tmp";
35
36 fn init(self: *TestContext) !void {
37 self.* = TestContext{
38 .any_err = {},
39 .loop = undefined,
40 .zig_lib_dir = undefined,
41 .zig_cache_dir = undefined,
42 .group = undefined,
43 .file_index = std.atomic.Int(usize).init(0),
44 };
45
46 try self.loop.initMultiThreaded(allocator);
47 errdefer self.loop.deinit();
48
49 self.group = std.event.Group(error!void).init(&self.loop);
50 errdefer self.group.cancelAll();
51
52 self.zig_lib_dir = try introspect.resolveZigLibDir(allocator);
53 errdefer allocator.free(self.zig_lib_dir);
54
55 self.zig_cache_dir = try introspect.resolveZigCacheDir(allocator);
56 errdefer allocator.free(self.zig_cache_dir);
57
58 try std.os.makePath(allocator, tmp_dir_name);
59 errdefer std.os.deleteTree(allocator, tmp_dir_name) catch {};
60 }
61
62 fn deinit(self: *TestContext) void {
63 std.os.deleteTree(allocator, tmp_dir_name) catch {};
64 allocator.free(self.zig_cache_dir);
65 allocator.free(self.zig_lib_dir);
66 self.loop.deinit();
67 }
68
69 fn run(self: *TestContext) !void {
70 const handle = try self.loop.call(waitForGroup, self);
71 defer cancel handle;
72 self.loop.run();
73 return self.any_err;
74 }
75
76 async fn waitForGroup(self: *TestContext) void {
77 self.any_err = await (async self.group.wait() catch unreachable);
78 }
79
80 fn testCompileError(
81 self: *TestContext,
82 source: []const u8,
83 path: []const u8,
84 line: usize,
85 column: usize,
86 msg: []const u8,
87 ) !void {
88 var file_index_buf: [20]u8 = undefined;
89 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.next());
90 const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
91
92 if (std.os.path.dirname(file1_path)) |dirname| {
93 try std.os.makePath(allocator, dirname);
94 }
95
96 // TODO async I/O
97 try std.io.writeFile(allocator, file1_path, source);
98
99 var module = try Module.create(
100 &self.loop,
101 "test",
102 file1_path,
103 Target.Native,
104 Module.Kind.Obj,
105 builtin.Mode.Debug,
106 self.zig_lib_dir,
107 self.zig_cache_dir,
108 );
109 errdefer module.destroy();
110
111 try module.build();
112
113 try self.group.call(getModuleEvent, module, source, path, line, column, msg);
114 }
115
116 async fn getModuleEvent(
117 module: *Module,
118 source: []const u8,
119 path: []const u8,
120 line: usize,
121 column: usize,
122 text: []const u8,
123 ) !void {
124 defer module.destroy();
125 const build_event = await (async module.events.get() catch unreachable);
126
127 switch (build_event) {
128 Module.Event.Ok => {
129 @panic("build incorrectly succeeded");
130 },
131 Module.Event.Error => |err| {
132 @panic("build incorrectly failed");
133 },
134 Module.Event.Fail => |msgs| {
135 assertOrPanic(msgs.len != 0);
136 for (msgs) |msg| {
137 if (mem.endsWith(u8, msg.path, path) and mem.eql(u8, msg.text, text)) {
138 const first_token = msg.tree.tokens.at(msg.span.first);
139 const last_token = msg.tree.tokens.at(msg.span.first);
140 const start_loc = msg.tree.tokenLocationPtr(0, first_token);
141 if (start_loc.line + 1 == line and start_loc.column + 1 == column) {
142 return;
143 }
144 }
145 }
146 std.debug.warn(
147 "\n=====source:=======\n{}\n====expected:========\n{}:{}:{}: error: {}\n",
148 source,
149 path,
150 line,
151 column,
152 text,
153 );
154 std.debug.warn("\n====found:========\n");
155 var stderr = try std.io.getStdErr();
156 for (msgs) |msg| {
157 try errmsg.printToFile(&stderr, msg, errmsg.Color.Auto);
158 }
159 std.debug.warn("============\n");
160 return error.TestFailed;
161 },
162 }
163 }
164};
src/main.cpp+7-3
...@@ -891,15 +891,19 @@ int main(int argc, char **argv) {...@@ -891,15 +891,19 @@ int main(int argc, char **argv) {
891891
892 add_package(g, cur_pkg, g->root_package);892 add_package(g, cur_pkg, g->root_package);
893893
894 if (cmd == CmdBuild || cmd == CmdRun) {894 if (cmd == CmdBuild || cmd == CmdRun || cmd == CmdTest) {
895 codegen_set_emit_file_type(g, emit_file_type);
896
897 for (size_t i = 0; i < objects.length; i += 1) {895 for (size_t i = 0; i < objects.length; i += 1) {
898 codegen_add_object(g, buf_create_from_str(objects.at(i)));896 codegen_add_object(g, buf_create_from_str(objects.at(i)));
899 }897 }
900 for (size_t i = 0; i < asm_files.length; i += 1) {898 for (size_t i = 0; i < asm_files.length; i += 1) {
901 codegen_add_assembly(g, buf_create_from_str(asm_files.at(i)));899 codegen_add_assembly(g, buf_create_from_str(asm_files.at(i)));
902 }900 }
901 }
902
903
904 if (cmd == CmdBuild || cmd == CmdRun) {
905 codegen_set_emit_file_type(g, emit_file_type);
906
903 codegen_build(g);907 codegen_build(g);
904 codegen_link(g, out_file);908 codegen_link(g, out_file);
905 if (timing_info)909 if (timing_info)
std/atomic/index.zig+2
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1pub const Stack = @import("stack.zig").Stack;1pub const Stack = @import("stack.zig").Stack;
2pub const QueueMpsc = @import("queue_mpsc.zig").QueueMpsc;2pub const QueueMpsc = @import("queue_mpsc.zig").QueueMpsc;
3pub const QueueMpmc = @import("queue_mpmc.zig").QueueMpmc;3pub const QueueMpmc = @import("queue_mpmc.zig").QueueMpmc;
4pub const Int = @import("int.zig").Int;
45
5test "std.atomic" {6test "std.atomic" {
6 _ = @import("stack.zig");7 _ = @import("stack.zig");
7 _ = @import("queue_mpsc.zig");8 _ = @import("queue_mpsc.zig");
8 _ = @import("queue_mpmc.zig");9 _ = @import("queue_mpmc.zig");
10 _ = @import("int.zig");
9}11}
std/atomic/int.zig created+19
...@@ -0,0 +1,19 @@
1const builtin = @import("builtin");
2const AtomicOrder = builtin.AtomicOrder;
3
4/// Thread-safe, lock-free integer
5pub fn Int(comptime T: type) type {
6 return struct {
7 value: T,
8
9 pub const Self = this;
10
11 pub fn init(init_val: T) Self {
12 return Self{ .value = init_val };
13 }
14
15 pub fn next(self: *Self) T {
16 return @atomicRmw(T, &self.value, builtin.AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
17 }
18 };
19}
std/build.zig+22
...@@ -1596,6 +1596,8 @@ pub const TestStep = struct {...@@ -1596,6 +1596,8 @@ pub const TestStep = struct {
1596 target: Target,1596 target: Target,
1597 exec_cmd_args: ?[]const ?[]const u8,1597 exec_cmd_args: ?[]const ?[]const u8,
1598 include_dirs: ArrayList([]const u8),1598 include_dirs: ArrayList([]const u8),
1599 lib_paths: ArrayList([]const u8),
1600 object_files: ArrayList([]const u8),
15991601
1600 pub fn init(builder: *Builder, root_src: []const u8) TestStep {1602 pub fn init(builder: *Builder, root_src: []const u8) TestStep {
1601 const step_name = builder.fmt("test {}", root_src);1603 const step_name = builder.fmt("test {}", root_src);
...@@ -1611,9 +1613,15 @@ pub const TestStep = struct {...@@ -1611,9 +1613,15 @@ pub const TestStep = struct {
1611 .target = Target{ .Native = {} },1613 .target = Target{ .Native = {} },
1612 .exec_cmd_args = null,1614 .exec_cmd_args = null,
1613 .include_dirs = ArrayList([]const u8).init(builder.allocator),1615 .include_dirs = ArrayList([]const u8).init(builder.allocator),
1616 .lib_paths = ArrayList([]const u8).init(builder.allocator),
1617 .object_files = ArrayList([]const u8).init(builder.allocator),
1614 };1618 };
1615 }1619 }
16161620
1621 pub fn addLibPath(self: *TestStep, path: []const u8) void {
1622 self.lib_paths.append(path) catch unreachable;
1623 }
1624
1617 pub fn setVerbose(self: *TestStep, value: bool) void {1625 pub fn setVerbose(self: *TestStep, value: bool) void {
1618 self.verbose = value;1626 self.verbose = value;
1619 }1627 }
...@@ -1638,6 +1646,10 @@ pub const TestStep = struct {...@@ -1638,6 +1646,10 @@ pub const TestStep = struct {
1638 self.filter = text;1646 self.filter = text;
1639 }1647 }
16401648
1649 pub fn addObjectFile(self: *TestStep, path: []const u8) void {
1650 self.object_files.append(path) catch unreachable;
1651 }
1652
1641 pub fn setTarget(self: *TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {1653 pub fn setTarget(self: *TestStep, target_arch: builtin.Arch, target_os: builtin.Os, target_environ: builtin.Environ) void {
1642 self.target = Target{1654 self.target = Target{
1643 .Cross = CrossTarget{1655 .Cross = CrossTarget{
...@@ -1699,6 +1711,11 @@ pub const TestStep = struct {...@@ -1699,6 +1711,11 @@ pub const TestStep = struct {
1699 try zig_args.append(self.name_prefix);1711 try zig_args.append(self.name_prefix);
1700 }1712 }
17011713
1714 for (self.object_files.toSliceConst()) |object_file| {
1715 try zig_args.append("--object");
1716 try zig_args.append(builder.pathFromRoot(object_file));
1717 }
1718
1702 {1719 {
1703 var it = self.link_libs.iterator();1720 var it = self.link_libs.iterator();
1704 while (true) {1721 while (true) {
...@@ -1734,6 +1751,11 @@ pub const TestStep = struct {...@@ -1734,6 +1751,11 @@ pub const TestStep = struct {
1734 try zig_args.append(rpath);1751 try zig_args.append(rpath);
1735 }1752 }
17361753
1754 for (self.lib_paths.toSliceConst()) |lib_path| {
1755 try zig_args.append("--library-path");
1756 try zig_args.append(lib_path);
1757 }
1758
1737 for (builder.lib_paths.toSliceConst()) |lib_path| {1759 for (builder.lib_paths.toSliceConst()) |lib_path| {
1738 try zig_args.append("--library-path");1760 try zig_args.append("--library-path");
1739 try zig_args.append(lib_path);1761 try zig_args.append(lib_path);