authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-08 19:05:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-08 19:05:05-07:00
log482b995a4963e045860c7fb1a4e11c48cf4de880
treee00079980426580bbefd547e879d890dab842511
parentb9e508c410cd077d704a73418281f6d7839df241

stage2: blaze the trail for std lib integration

This branch adds "builtin" and "std" to the import table when using the self-hosted backend. "builtin" gains one additional item: ``` pub const zig_is_stage2 = true; // false when using stage1 backend ``` This allows the std lib to do conditional compilation based on detecting which backend is being used. This will be removed from builtin as soon as self-hosted catches up to feature parity with stage1. Keep a sharp eye out - people are going to be tempted to abuse this. The general rule of thumb is do not use `builtin.zig_is_stage2`. However this commit breaks the rule so that we can gain limited start.zig support as we incrementally improve the self-hosted compiler. This commit also implements `fullyQualifiedNameHash` and related functionality, which effectively puts all Decls in their proper namespaces. `fullyQualifiedName` is not yet implemented. Stop printing "todo" log messages for test decls unless we are in test mode. Add "previous definition here" error notes for Decl name collisions. This commit does not bring us yet to a newly passing test case. Here's what I'm working towards: ```zig const std = @import("std"); export fn main() c_int { const a = std.fs.base64_alphabet[0]; return a - 'A'; } ``` Current output: ``` $ ./zig-cache/bin/zig build-exe test.zig test.zig:3:1: error: TODO implement more analyze elemptr zig-cache/lib/zig/std/start.zig:38:46: error: TODO implement structInitExpr ty ``` So the next steps are clear: * Sema: improve elemptr * AstGen: implement structInitExpr

10 files changed, 274 insertions(+), 151 deletions(-)

lib/std/start.zig+89-27
......@@ -7,7 +7,7 @@
77
88const root = @import("root");
99const std = @import("std.zig");
10const builtin = std.builtin;
10const builtin = @import("builtin");
1111const assert = std.debug.assert;
1212const uefi = std.os.uefi;
1313const tlcsprng = @import("crypto/tlcsprng.zig");
......@@ -17,39 +17,101 @@ var argc_argv_ptr: [*]usize = undefined;
1717const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
1818
1919comptime {
20 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
21 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
22 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
20 // The self-hosted compiler is not fully capable of handling all of this start.zig file.
21 // Until then, we have simplified logic here for self-hosted. TODO remove this once
22 // self-hosted is capable enough to handle all of the real start.zig logic.
23 if (builtin.zig_is_stage2) {
24 if (builtin.output_mode == .Exe) {
25 if (builtin.link_libc or builtin.object_format == .c) {
26 if (!@hasDecl(root, "main")) {
27 @export(main2, "main");
28 }
29 } else {
30 if (!@hasDecl(root, "_start")) {
31 @export(_start2, "_start");
32 }
33 }
2334 }
24 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
25 if (builtin.link_libc and @hasDecl(root, "main")) {
26 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
27 @export(main, .{ .name = "main", .linkage = .Weak });
35 } else {
36 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
37 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
38 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
2839 }
29 } else if (builtin.os.tag == .windows) {
30 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
31 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
32 {
33 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });
34 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
35 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
36 {
37 @compileError("WinMain not supported; declare wWinMain or main instead");
38 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and
39 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))
40 {
41 @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });
40 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
41 if (builtin.link_libc and @hasDecl(root, "main")) {
42 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
43 @export(main, .{ .name = "main", .linkage = .Weak });
44 }
45 } else if (builtin.os.tag == .windows) {
46 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
47 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
48 {
49 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });
50 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
51 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
52 {
53 @compileError("WinMain not supported; declare wWinMain or main instead");
54 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and
55 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))
56 {
57 @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" });
58 }
59 } else if (builtin.os.tag == .uefi) {
60 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
61 } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) {
62 if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
63 } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) {
64 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
4265 }
43 } else if (builtin.os.tag == .uefi) {
44 if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" });
45 } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) {
46 if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name });
47 } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) {
48 if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name });
4966 }
5067 }
5168}
5269
70// Simplified start code for stage2 until it supports more language features ///
71
72fn main2() callconv(.C) c_int {
73 root.main();
74 return 0;
75}
76
77fn _start2() callconv(.Naked) noreturn {
78 root.main();
79 exit2(0);
80}
81
82fn exit2(code: u8) noreturn {
83 switch (builtin.arch) {
84 .x86_64 => {
85 asm volatile ("syscall"
86 :
87 : [number] "{rax}" (231),
88 [arg1] "{rdi}" (code)
89 : "rcx", "r11", "memory"
90 );
91 },
92 .arm => {
93 asm volatile ("svc #0"
94 :
95 : [number] "{r7}" (1),
96 [arg1] "{r0}" (code)
97 : "memory"
98 );
99 },
100 .aarch64 => {
101 asm volatile ("svc #0"
102 :
103 : [number] "{x8}" (93),
104 [arg1] "{x0}" (code)
105 : "memory", "cc"
106 );
107 },
108 else => @compileError("TODO"),
109 }
110 unreachable;
111}
112
113////////////////////////////////////////////////////////////////////////////////
114
53115fn _DllMainCRTStartup(
54116 hinstDLL: std.os.windows.HINSTANCE,
55117 fdwReason: std.os.windows.DWORD,
lib/std/start2.zig deleted-58
......@@ -1,58 +0,0 @@
1const root = @import("root");
2const builtin = @import("builtin");
3
4comptime {
5 if (builtin.output_mode == 0) { // OutputMode.Exe
6 if (builtin.link_libc or builtin.object_format == 5) { // ObjectFormat.c
7 if (!@hasDecl(root, "main")) {
8 @export(otherMain, "main");
9 }
10 } else {
11 if (!@hasDecl(root, "_start")) {
12 @export(otherStart, "_start");
13 }
14 }
15 }
16}
17
18// FIXME: Cannot call this function `main`, because `fully qualified names`
19// have not been implemented yet.
20fn otherMain() callconv(.C) c_int {
21 root.zigMain();
22 return 0;
23}
24
25// FIXME: Cannot call this function `_start`, because `fully qualified names`
26// have not been implemented yet.
27fn otherStart() callconv(.Naked) noreturn {
28 root.zigMain();
29 otherExit();
30}
31
32// FIXME: Cannot call this function `exit`, because `fully qualified names`
33// have not been implemented yet.
34fn otherExit() noreturn {
35 if (builtin.arch == 31) { // x86_64
36 asm volatile ("syscall"
37 :
38 : [number] "{rax}" (231),
39 [arg1] "{rdi}" (0)
40 : "rcx", "r11", "memory"
41 );
42 } else if (builtin.arch == 0) { // arm
43 asm volatile ("svc #0"
44 :
45 : [number] "{r7}" (1),
46 [arg1] "{r0}" (0)
47 : "memory"
48 );
49 } else if (builtin.arch == 2) { // aarch64
50 asm volatile ("svc #0"
51 :
52 : [number] "{x8}" (93),
53 [arg1] "{x0}" (0)
54 : "memory", "cc"
55 );
56 } else @compileError("not yet supported!");
57 unreachable;
58}
lib/std/std.zig+1-1
......@@ -92,7 +92,7 @@ pub const zig = @import("zig.zig");
9292pub const start = @import("start.zig");
9393
9494// This forces the start.zig file to be imported, and the comptime logic inside that
95// file decides whether to export any appropriate start symbols.
95// file decides whether to export any appropriate start symbols, and call main.
9696comptime {
9797 _ = start;
9898}
lib/std/zig.zig+11-8
......@@ -18,16 +18,19 @@ pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
1818
1919pub const SrcHash = [16]u8;
2020
21/// If the source is small enough, it is used directly as the hash.
22/// If it is long, blake3 hash is computed.
2321pub fn hashSrc(src: []const u8) SrcHash {
2422 var out: SrcHash = undefined;
25 if (src.len <= @typeInfo(SrcHash).Array.len) {
26 std.mem.copy(u8, &out, src);
27 std.mem.set(u8, out[src.len..], 0);
28 } else {
29 std.crypto.hash.Blake3.hash(src, &out, .{});
30 }
23 std.crypto.hash.Blake3.hash(src, &out, .{});
24 return out;
25}
26
27pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash {
28 var out: SrcHash = undefined;
29 var hasher = std.crypto.hash.Blake3.init(.{});
30 hasher.update(&parent_hash);
31 hasher.update(sep);
32 hasher.update(name);
33 hasher.final(&out);
3134 return out;
3235}
3336
src/Compilation.zig+59-30
......@@ -906,38 +906,61 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
906906 artifact_sub_dir,
907907 };
908908
909 // TODO when we implement serialization and deserialization of incremental compilation metadata,
910 // this is where we would load it. We have open a handle to the directory where
911 // the output either already is, or will be.
909 // If we rely on stage1, we must not redundantly add these packages.
910 const use_stage1 = build_options.is_stage1 and use_llvm;
911 if (!use_stage1) {
912 const builtin_pkg = try Package.createWithDir(
913 gpa,
914 zig_cache_artifact_directory,
915 null,
916 "builtin.zig",
917 );
918 errdefer builtin_pkg.destroy(gpa);
919
920 const std_pkg = try Package.createWithDir(
921 gpa,
922 options.zig_lib_directory,
923 "std",
924 "std.zig",
925 );
926 errdefer std_pkg.destroy(gpa);
927
928 try root_pkg.addAndAdopt(gpa, "builtin", builtin_pkg);
929 try root_pkg.add(gpa, "root", root_pkg);
930 try root_pkg.addAndAdopt(gpa, "std", std_pkg);
931
932 try std_pkg.add(gpa, "builtin", builtin_pkg);
933 try std_pkg.add(gpa, "root", root_pkg);
934 }
935
936 // TODO when we implement serialization and deserialization of incremental
937 // compilation metadata, this is where we would load it. We have open a handle
938 // to the directory where the output either already is, or will be.
912939 // However we currently do not have serialization of such metadata, so for now
913940 // we set up an empty Module that does the entire compilation fresh.
914941
915 const root_scope = rs: {
916 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
917 const root_scope = try gpa.create(Module.Scope.File);
918 const struct_ty = try Type.Tag.empty_struct.create(
919 gpa,
920 &root_scope.root_container,
921 );
922 root_scope.* = .{
923 // TODO this is duped so it can be freed in Container.deinit
924 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
925 .source = .{ .unloaded = {} },
926 .tree = undefined,
927 .status = .never_loaded,
928 .pkg = root_pkg,
929 .root_container = .{
930 .file_scope = root_scope,
931 .decls = .{},
932 .ty = struct_ty,
933 },
934 };
935 break :rs root_scope;
936 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
937 return error.ZirFilesUnsupported;
938 } else {
939 unreachable;
940 }
942 // TODO remove CLI support for .zir files and then we can remove this error
943 // handling and assertion.
944 if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) return error.ZirFilesUnsupported;
945 assert(mem.endsWith(u8, root_pkg.root_src_path, ".zig"));
946
947 const root_scope = try gpa.create(Module.Scope.File);
948 errdefer gpa.destroy(root_scope);
949
950 const struct_ty = try Type.Tag.empty_struct.create(gpa, &root_scope.root_container);
951 root_scope.* = .{
952 // TODO this is duped so it can be freed in Container.deinit
953 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
954 .source = .{ .unloaded = {} },
955 .tree = undefined,
956 .status = .never_loaded,
957 .pkg = root_pkg,
958 .root_container = .{
959 .file_scope = root_scope,
960 .decls = .{},
961 .ty = struct_ty,
962 .parent_name_hash = root_pkg.namespace_hash,
963 },
941964 };
942965
943966 const module = try arena.create(Module);
......@@ -1339,7 +1362,8 @@ pub fn update(self: *Compilation) !void {
13391362 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);
13401363 }
13411364
1342 const use_stage1 = build_options.omit_stage2 or build_options.is_stage1 and self.bin_file.options.use_llvm;
1365 const use_stage1 = build_options.omit_stage2 or
1366 (build_options.is_stage1 and self.bin_file.options.use_llvm);
13431367 if (!use_stage1) {
13441368 if (self.bin_file.options.module) |module| {
13451369 module.compile_log_text.shrinkAndFree(module.gpa, 0);
......@@ -2840,6 +2864,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28402864
28412865 const target = comp.getTarget();
28422866 const generic_arch_name = target.cpu.arch.genericName();
2867 const use_stage1 = build_options.omit_stage2 or
2868 (build_options.is_stage1 and comp.bin_file.options.use_llvm);
28432869
28442870 @setEvalBranchQuota(4000);
28452871 try buffer.writer().print(
......@@ -2852,6 +2878,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28522878 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
28532879 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
28542880 \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}");
2881 \\pub const zig_is_stage2 = {};
28552882 \\
28562883 \\pub const output_mode = OutputMode.{};
28572884 \\pub const link_mode = LinkMode.{};
......@@ -2865,6 +2892,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28652892 \\
28662893 , .{
28672894 build_options.version,
2895 !use_stage1,
28682896 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
28692897 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
28702898 comp.bin_file.options.is_test,
......@@ -3074,6 +3102,7 @@ fn buildOutputFromZig(
30743102 .handle = special_dir,
30753103 },
30763104 .root_src_path = src_basename,
3105 .namespace_hash = Package.root_namespace_hash,
30773106 };
30783107 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
30793108 const target = comp.getTarget();
src/Module.zig+11-6
......@@ -678,6 +678,7 @@ pub const Scope = struct {
678678 base: Scope = Scope{ .tag = base_tag },
679679
680680 file_scope: *Scope.File,
681 parent_name_hash: NameHash,
681682
682683 /// Direct children of the file.
683684 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
......@@ -696,8 +697,7 @@ pub const Scope = struct {
696697 }
697698
698699 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {
699 // TODO container scope qualified names.
700 return std.zig.hashSrc(name);
700 return std.zig.hashName(cont.parent_name_hash, ".", name);
701701 }
702702
703703 pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void {
......@@ -2513,6 +2513,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
25132513
25142514 const block_expr = node_datas[decl_node].lhs;
25152515 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
2516 _ = try gen_scope.addBreak(.break_inline, 0, .void_value);
25162517
25172518 const code = try gen_scope.finish();
25182519 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
......@@ -3468,7 +3469,9 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34683469 ),
34693470
34703471 .test_decl => {
3471 log.err("TODO: analyze test decl", .{});
3472 if (mod.comp.bin_file.options.is_test) {
3473 log.err("TODO: analyze test decl", .{});
3474 }
34723475 },
34733476 .@"usingnamespace" => {
34743477 log.err("TODO: analyze usingnamespace decl", .{});
......@@ -3532,6 +3535,7 @@ fn semaContainerFn(
35323535 .lazy = .{ .token_abs = name_tok },
35333536 }, "redefinition of '{s}'", .{decl.name});
35343537 errdefer msg.destroy(mod.gpa);
3538 try mod.errNoteNonLazy(decl.srcLoc(), msg, "previous definition here", .{});
35353539 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
35363540 } else {
35373541 if (!srcHashEql(decl.contents_hash, contents_hash)) {
......@@ -3589,12 +3593,13 @@ fn semaContainerVar(
35893593 decl.src_index = decl_i;
35903594 if (deleted_decls.swapRemove(decl) == null) {
35913595 decl.analysis = .sema_failure;
3592 const err_msg = try ErrorMsg.create(mod.gpa, .{
3596 const msg = try ErrorMsg.create(mod.gpa, .{
35933597 .container = .{ .file_scope = container_scope.file_scope },
35943598 .lazy = .{ .token_abs = name_token },
35953599 }, "redefinition of '{s}'", .{decl.name});
3596 errdefer err_msg.destroy(mod.gpa);
3597 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);
3600 errdefer msg.destroy(mod.gpa);
3601 try mod.errNoteNonLazy(decl.srcLoc(), msg, "previous definition here", .{});
3602 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
35983603 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
35993604 try outdated_decls.put(decl, {});
36003605 decl.contents_hash = contents_hash;
src/Package.zig+68-8
......@@ -4,18 +4,29 @@ const std = @import("std");
44const fs = std.fs;
55const mem = std.mem;
66const Allocator = mem.Allocator;
7const assert = std.debug.assert;
78
89const Compilation = @import("Compilation.zig");
10const Module = @import("Module.zig");
911
1012pub const Table = std.StringHashMapUnmanaged(*Package);
1113
14pub const root_namespace_hash: Module.Scope.NameHash = .{
15 0, 0, 6, 6, 6, 0, 0, 0,
16 6, 9, 0, 0, 0, 4, 2, 0,
17};
18
1219root_src_directory: Compilation.Directory,
1320/// Relative to `root_src_directory`. May contain path separators.
1421root_src_path: []const u8,
1522table: Table = .{},
1623parent: ?*Package = null,
24namespace_hash: Module.Scope.NameHash,
25/// Whether to free `root_src_directory` on `destroy`.
26root_src_directory_owned: bool = false,
1727
1828/// Allocate a Package. No references to the slices passed are kept.
29/// Don't forget to set `namespace_hash` later.
1930pub fn create(
2031 gpa: *Allocator,
2132 /// Null indicates the current working directory
......@@ -38,27 +49,69 @@ pub fn create(
3849 .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(),
3950 },
4051 .root_src_path = owned_src_path,
52 .root_src_directory_owned = true,
53 .namespace_hash = undefined,
4154 };
4255
4356 return ptr;
4457}
4558
46/// Free all memory associated with this package and recursively call destroy
47/// on all packages in its table
59pub fn createWithDir(
60 gpa: *Allocator,
61 directory: Compilation.Directory,
62 /// Relative to `directory`. If null, means `directory` is the root src dir
63 /// and is owned externally.
64 root_src_dir_path: ?[]const u8,
65 /// Relative to root_src_dir_path
66 root_src_path: []const u8,
67) !*Package {
68 const ptr = try gpa.create(Package);
69 errdefer gpa.destroy(ptr);
70
71 const owned_src_path = try gpa.dupe(u8, root_src_path);
72 errdefer gpa.free(owned_src_path);
73
74 if (root_src_dir_path) |p| {
75 const owned_dir_path = try directory.join(gpa, &[1][]const u8{p});
76 errdefer gpa.free(owned_dir_path);
77
78 ptr.* = .{
79 .root_src_directory = .{
80 .path = owned_dir_path,
81 .handle = try directory.handle.openDir(p, .{}),
82 },
83 .root_src_directory_owned = true,
84 .root_src_path = owned_src_path,
85 .namespace_hash = undefined,
86 };
87 } else {
88 ptr.* = .{
89 .root_src_directory = directory,
90 .root_src_directory_owned = false,
91 .root_src_path = owned_src_path,
92 .namespace_hash = undefined,
93 };
94 }
95 return ptr;
96}
97
98/// Free all memory associated with this package. It does not destroy any packages
99/// inside its table; the caller is responsible for calling destroy() on them.
48100pub fn destroy(pkg: *Package, gpa: *Allocator) void {
49101 gpa.free(pkg.root_src_path);
50102
51 // If root_src_directory.path is null then the handle is the cwd()
52 // which shouldn't be closed.
53 if (pkg.root_src_directory.path) |p| {
54 gpa.free(p);
55 pkg.root_src_directory.handle.close();
103 if (pkg.root_src_directory_owned) {
104 // If root_src_directory.path is null then the handle is the cwd()
105 // which shouldn't be closed.
106 if (pkg.root_src_directory.path) |p| {
107 gpa.free(p);
108 pkg.root_src_directory.handle.close();
109 }
56110 }
57111
58112 {
59113 var it = pkg.table.iterator();
60114 while (it.next()) |kv| {
61 kv.value.destroy(gpa);
62115 gpa.free(kv.key);
63116 }
64117 }
......@@ -72,3 +125,10 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package)
72125 const name_dupe = try mem.dupe(gpa, u8, name);
73126 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
74127}
128
129pub fn addAndAdopt(parent: *Package, gpa: *Allocator, name: []const u8, child: *Package) !void {
130 assert(child.parent == null); // make up your mind, who is the parent??
131 child.parent = parent;
132 child.namespace_hash = std.zig.hashName(parent.namespace_hash, ":", name);
133 return parent.add(gpa, name, child);
134}
src/Sema.zig+13-6
......@@ -598,6 +598,10 @@ fn zirStructDecl(
598598 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
599599 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
600600 const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
601 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
602 .ty = Type.initTag(.type),
603 .val = struct_val,
604 });
601605 struct_obj.* = .{
602606 .owner_decl = sema.owner_decl,
603607 .fields = fields_map,
......@@ -605,12 +609,9 @@ fn zirStructDecl(
605609 .container = .{
606610 .ty = struct_ty,
607611 .file_scope = block.getFileScope(),
612 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
608613 },
609614 };
610 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
611 .ty = Type.initTag(.type),
612 .val = struct_val,
613 });
614615 return sema.analyzeDeclVal(block, src, new_decl);
615616}
616617
......@@ -5298,9 +5299,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
52985299 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
52995300 errdefer sema.gpa.free(resolved_path);
53005301
5301 if (sema.mod.import_table.get(resolved_path)) |some| {
5302 if (sema.mod.import_table.get(resolved_path)) |cached_import| {
53025303 sema.gpa.free(resolved_path);
5303 return some;
5304 return cached_import;
53045305 }
53055306
53065307 if (found_pkg == null) {
......@@ -5318,6 +5319,11 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
53185319 const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);
53195320 errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?);
53205321
5322 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
5323 pkg.namespace_hash
5324 else
5325 std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
5326
53215327 file_scope.* = .{
53225328 .sub_file_path = resolved_path,
53235329 .source = .{ .unloaded = {} },
......@@ -5328,6 +5334,7 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
53285334 .file_scope = file_scope,
53295335 .decls = .{},
53305336 .ty = struct_ty,
5337 .parent_name_hash = container_name_hash,
53315338 },
53325339 };
53335340 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
src/main.zig+21-7
......@@ -599,15 +599,15 @@ fn buildOutputType(
599599 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);
600600 defer test_exec_args.deinit();
601601
602 const pkg_tree_root = try gpa.create(Package);
603602 // This package only exists to clean up the code parsing --pkg-begin and
604603 // --pkg-end flags. Use dummy values that are safe for the destroy call.
605 pkg_tree_root.* = .{
604 var pkg_tree_root: Package = .{
606605 .root_src_directory = .{ .path = null, .handle = fs.cwd() },
607606 .root_src_path = &[0]u8{},
607 .namespace_hash = Package.root_namespace_hash,
608608 };
609 defer pkg_tree_root.destroy(gpa);
610 var cur_pkg: *Package = pkg_tree_root;
609 defer freePkgTree(gpa, &pkg_tree_root, false);
610 var cur_pkg: *Package = &pkg_tree_root;
611611
612612 switch (arg_mode) {
613613 .build, .translate_c, .zig_test, .run => {
......@@ -658,8 +658,7 @@ fn buildOutputType(
658658 ) catch |err| {
659659 fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) });
660660 };
661 new_cur_pkg.parent = cur_pkg;
662 try cur_pkg.add(gpa, pkg_name, new_cur_pkg);
661 try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg);
663662 cur_pkg = new_cur_pkg;
664663 } else if (mem.eql(u8, arg, "--pkg-end")) {
665664 cur_pkg = cur_pkg.parent orelse
......@@ -1747,6 +1746,7 @@ fn buildOutputType(
17471746 if (root_pkg) |pkg| {
17481747 pkg.table = pkg_tree_root.table;
17491748 pkg_tree_root.table = .{};
1749 pkg.namespace_hash = pkg_tree_root.namespace_hash;
17501750 }
17511751
17521752 const self_exe_path = try fs.selfExePathAlloc(arena);
......@@ -2151,6 +2151,18 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
21512151 }
21522152}
21532153
2154fn freePkgTree(gpa: *Allocator, pkg: *Package, free_parent: bool) void {
2155 {
2156 var it = pkg.table.iterator();
2157 while (it.next()) |kv| {
2158 freePkgTree(gpa, kv.value, true);
2159 }
2160 }
2161 if (free_parent) {
2162 pkg.destroy(gpa);
2163 }
2164}
2165
21542166fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {
21552167 if (!build_options.have_llvm)
21562168 fatal("cannot translate-c: compiler built without LLVM extensions", .{});
......@@ -2505,6 +2517,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
25052517 .handle = try zig_lib_directory.handle.openDir(std_special, .{}),
25062518 },
25072519 .root_src_path = "build_runner.zig",
2520 .namespace_hash = Package.root_namespace_hash,
25082521 };
25092522 defer root_pkg.root_src_directory.handle.close();
25102523
......@@ -2550,8 +2563,9 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
25502563 var build_pkg: Package = .{
25512564 .root_src_directory = build_directory,
25522565 .root_src_path = build_zig_basename,
2566 .namespace_hash = undefined,
25532567 };
2554 try root_pkg.table.put(arena, "@build", &build_pkg);
2568 try root_pkg.addAndAdopt(arena, "@build", &build_pkg);
25552569
25562570 var global_cache_directory: Compilation.Directory = l: {
25572571 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);
src/stage1/codegen.cpp+1
......@@ -9137,6 +9137,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
91379137 buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));
91389138 buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));
91399139 buf_appendf(contents, "pub const code_model = CodeModel.default;\n");
9140 buf_appendf(contents, "pub const zig_is_stage2 = false;\n");
91409141
91419142 {
91429143 TargetSubsystem detected_subsystem = detect_subsystem(g);