diff --git a/lib/std/start.zig b/lib/std/start.zig index 0fb96c768f..5454cc58c6 100644 --- a/lib/std/start.zig +++ b/lib/std/start.zig @@ -7,7 +7,7 @@ const root = @import("root"); const std = @import("std.zig"); -const builtin = std.builtin; +const builtin = @import("builtin"); const assert = std.debug.assert; const uefi = std.os.uefi; const tlcsprng = @import("crypto/tlcsprng.zig"); @@ -17,39 +17,101 @@ var argc_argv_ptr: [*]usize = undefined; const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start"; comptime { - if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { - if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) { - @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" }); + // The self-hosted compiler is not fully capable of handling all of this start.zig file. + // Until then, we have simplified logic here for self-hosted. TODO remove this once + // self-hosted is capable enough to handle all of the real start.zig logic. + if (builtin.zig_is_stage2) { + if (builtin.output_mode == .Exe) { + if (builtin.link_libc or builtin.object_format == .c) { + if (!@hasDecl(root, "main")) { + @export(main2, "main"); + } + } else { + if (!@hasDecl(root, "_start")) { + @export(_start2, "_start"); + } + } } - } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { - if (builtin.link_libc and @hasDecl(root, "main")) { - if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { - @export(main, .{ .name = "main", .linkage = .Weak }); + } else { + if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) { + if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) { + @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" }); } - } else if (builtin.os.tag == .windows) { - if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and - !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) - { - @export(WinStartup, .{ .name = "wWinMainCRTStartup" }); - } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and - !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) - { - @compileError("WinMain not supported; declare wWinMain or main instead"); - } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and - !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) - { - @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" }); + } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) { + if (builtin.link_libc and @hasDecl(root, "main")) { + if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) { + @export(main, .{ .name = "main", .linkage = .Weak }); + } + } else if (builtin.os.tag == .windows) { + if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and + !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) + { + @export(WinStartup, .{ .name = "wWinMainCRTStartup" }); + } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and + !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup")) + { + @compileError("WinMain not supported; declare wWinMain or main instead"); + } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and + !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup")) + { + @export(wWinMainCRTStartup, .{ .name = "wWinMainCRTStartup" }); + } + } else if (builtin.os.tag == .uefi) { + if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); + } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) { + if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); + } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) { + if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); } - } else if (builtin.os.tag == .uefi) { - if (!@hasDecl(root, "EfiMain")) @export(EfiMain, .{ .name = "EfiMain" }); - } else if (builtin.arch.isWasm() and builtin.os.tag == .freestanding) { - if (!@hasDecl(root, start_sym_name)) @export(wasm_freestanding_start, .{ .name = start_sym_name }); - } else if (builtin.os.tag != .other and builtin.os.tag != .freestanding) { - if (!@hasDecl(root, start_sym_name)) @export(_start, .{ .name = start_sym_name }); } } } +// Simplified start code for stage2 until it supports more language features /// + +fn main2() callconv(.C) c_int { + root.main(); + return 0; +} + +fn _start2() callconv(.Naked) noreturn { + root.main(); + exit2(0); +} + +fn exit2(code: u8) noreturn { + switch (builtin.arch) { + .x86_64 => { + asm volatile ("syscall" + : + : [number] "{rax}" (231), + [arg1] "{rdi}" (code) + : "rcx", "r11", "memory" + ); + }, + .arm => { + asm volatile ("svc #0" + : + : [number] "{r7}" (1), + [arg1] "{r0}" (code) + : "memory" + ); + }, + .aarch64 => { + asm volatile ("svc #0" + : + : [number] "{x8}" (93), + [arg1] "{x0}" (code) + : "memory", "cc" + ); + }, + else => @compileError("TODO"), + } + unreachable; +} + +//////////////////////////////////////////////////////////////////////////////// + fn _DllMainCRTStartup( hinstDLL: std.os.windows.HINSTANCE, fdwReason: std.os.windows.DWORD, diff --git a/lib/std/start2.zig b/lib/std/start2.zig deleted file mode 100644 index 22f3578d98..0000000000 --- a/lib/std/start2.zig +++ /dev/null @@ -1,58 +0,0 @@ -const root = @import("root"); -const builtin = @import("builtin"); - -comptime { - if (builtin.output_mode == 0) { // OutputMode.Exe - if (builtin.link_libc or builtin.object_format == 5) { // ObjectFormat.c - if (!@hasDecl(root, "main")) { - @export(otherMain, "main"); - } - } else { - if (!@hasDecl(root, "_start")) { - @export(otherStart, "_start"); - } - } - } -} - -// FIXME: Cannot call this function `main`, because `fully qualified names` -// have not been implemented yet. -fn otherMain() callconv(.C) c_int { - root.zigMain(); - return 0; -} - -// FIXME: Cannot call this function `_start`, because `fully qualified names` -// have not been implemented yet. -fn otherStart() callconv(.Naked) noreturn { - root.zigMain(); - otherExit(); -} - -// FIXME: Cannot call this function `exit`, because `fully qualified names` -// have not been implemented yet. -fn otherExit() noreturn { - if (builtin.arch == 31) { // x86_64 - asm volatile ("syscall" - : - : [number] "{rax}" (231), - [arg1] "{rdi}" (0) - : "rcx", "r11", "memory" - ); - } else if (builtin.arch == 0) { // arm - asm volatile ("svc #0" - : - : [number] "{r7}" (1), - [arg1] "{r0}" (0) - : "memory" - ); - } else if (builtin.arch == 2) { // aarch64 - asm volatile ("svc #0" - : - : [number] "{x8}" (93), - [arg1] "{x0}" (0) - : "memory", "cc" - ); - } else @compileError("not yet supported!"); - unreachable; -} diff --git a/lib/std/std.zig b/lib/std/std.zig index f8bc477068..5f10def72e 100644 --- a/lib/std/std.zig +++ b/lib/std/std.zig @@ -92,7 +92,7 @@ pub const zig = @import("zig.zig"); pub const start = @import("start.zig"); // This forces the start.zig file to be imported, and the comptime logic inside that -// file decides whether to export any appropriate start symbols. +// file decides whether to export any appropriate start symbols, and call main. comptime { _ = start; } diff --git a/lib/std/zig.zig b/lib/std/zig.zig index cff07a2bd2..714235523e 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -18,16 +18,19 @@ pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget; pub const SrcHash = [16]u8; -/// If the source is small enough, it is used directly as the hash. -/// If it is long, blake3 hash is computed. pub fn hashSrc(src: []const u8) SrcHash { var out: SrcHash = undefined; - if (src.len <= @typeInfo(SrcHash).Array.len) { - std.mem.copy(u8, &out, src); - std.mem.set(u8, out[src.len..], 0); - } else { - std.crypto.hash.Blake3.hash(src, &out, .{}); - } + std.crypto.hash.Blake3.hash(src, &out, .{}); + return out; +} + +pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash { + var out: SrcHash = undefined; + var hasher = std.crypto.hash.Blake3.init(.{}); + hasher.update(&parent_hash); + hasher.update(sep); + hasher.update(name); + hasher.final(&out); return out; } diff --git a/src/Compilation.zig b/src/Compilation.zig index 080d4bddaa..73fafa0976 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -906,38 +906,61 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { artifact_sub_dir, }; - // TODO when we implement serialization and deserialization of incremental compilation metadata, - // this is where we would load it. We have open a handle to the directory where - // the output either already is, or will be. + // If we rely on stage1, we must not redundantly add these packages. + const use_stage1 = build_options.is_stage1 and use_llvm; + if (!use_stage1) { + const builtin_pkg = try Package.createWithDir( + gpa, + zig_cache_artifact_directory, + null, + "builtin.zig", + ); + errdefer builtin_pkg.destroy(gpa); + + const std_pkg = try Package.createWithDir( + gpa, + options.zig_lib_directory, + "std", + "std.zig", + ); + errdefer std_pkg.destroy(gpa); + + try root_pkg.addAndAdopt(gpa, "builtin", builtin_pkg); + try root_pkg.add(gpa, "root", root_pkg); + try root_pkg.addAndAdopt(gpa, "std", std_pkg); + + try std_pkg.add(gpa, "builtin", builtin_pkg); + try std_pkg.add(gpa, "root", root_pkg); + } + + // TODO when we implement serialization and deserialization of incremental + // compilation metadata, this is where we would load it. We have open a handle + // to the directory where the output either already is, or will be. // However we currently do not have serialization of such metadata, so for now // we set up an empty Module that does the entire compilation fresh. - const root_scope = rs: { - if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) { - const root_scope = try gpa.create(Module.Scope.File); - const struct_ty = try Type.Tag.empty_struct.create( - gpa, - &root_scope.root_container, - ); - root_scope.* = .{ - // TODO this is duped so it can be freed in Container.deinit - .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path), - .source = .{ .unloaded = {} }, - .tree = undefined, - .status = .never_loaded, - .pkg = root_pkg, - .root_container = .{ - .file_scope = root_scope, - .decls = .{}, - .ty = struct_ty, - }, - }; - break :rs root_scope; - } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) { - return error.ZirFilesUnsupported; - } else { - unreachable; - } + // TODO remove CLI support for .zir files and then we can remove this error + // handling and assertion. + if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) return error.ZirFilesUnsupported; + assert(mem.endsWith(u8, root_pkg.root_src_path, ".zig")); + + const root_scope = try gpa.create(Module.Scope.File); + errdefer gpa.destroy(root_scope); + + const struct_ty = try Type.Tag.empty_struct.create(gpa, &root_scope.root_container); + root_scope.* = .{ + // TODO this is duped so it can be freed in Container.deinit + .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path), + .source = .{ .unloaded = {} }, + .tree = undefined, + .status = .never_loaded, + .pkg = root_pkg, + .root_container = .{ + .file_scope = root_scope, + .decls = .{}, + .ty = struct_ty, + .parent_name_hash = root_pkg.namespace_hash, + }, }; const module = try arena.create(Module); @@ -1339,7 +1362,8 @@ pub fn update(self: *Compilation) !void { self.c_object_work_queue.writeItemAssumeCapacity(entry.key); } - const use_stage1 = build_options.omit_stage2 or build_options.is_stage1 and self.bin_file.options.use_llvm; + const use_stage1 = build_options.omit_stage2 or + (build_options.is_stage1 and self.bin_file.options.use_llvm); if (!use_stage1) { if (self.bin_file.options.module) |module| { module.compile_log_text.shrinkAndFree(module.gpa, 0); @@ -2840,6 +2864,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 const target = comp.getTarget(); const generic_arch_name = target.cpu.arch.genericName(); + const use_stage1 = build_options.omit_stage2 or + (build_options.is_stage1 and comp.bin_file.options.use_llvm); @setEvalBranchQuota(4000); try buffer.writer().print( @@ -2852,6 +2878,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks. \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}"); + \\pub const zig_is_stage2 = {}; \\ \\pub const output_mode = OutputMode.{}; \\pub const link_mode = LinkMode.{}; @@ -2865,6 +2892,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 \\ , .{ build_options.version, + !use_stage1, std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)), std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)), comp.bin_file.options.is_test, @@ -3074,6 +3102,7 @@ fn buildOutputFromZig( .handle = special_dir, }, .root_src_path = src_basename, + .namespace_hash = Package.root_namespace_hash, }; const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len]; const target = comp.getTarget(); diff --git a/src/Module.zig b/src/Module.zig index 933917d948..5883109852 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -678,6 +678,7 @@ pub const Scope = struct { base: Scope = Scope{ .tag = base_tag }, file_scope: *Scope.File, + parent_name_hash: NameHash, /// Direct children of the file. decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, @@ -696,8 +697,7 @@ pub const Scope = struct { } pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash { - // TODO container scope qualified names. - return std.zig.hashSrc(name); + return std.zig.hashName(cont.parent_name_hash, ".", name); } pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void { @@ -2513,6 +2513,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { const block_expr = node_datas[decl_node].lhs; _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr); + _ = try gen_scope.addBreak(.break_inline, 0, .void_value); const code = try gen_scope.finish(); if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { @@ -3468,7 +3469,9 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { ), .test_decl => { - log.err("TODO: analyze test decl", .{}); + if (mod.comp.bin_file.options.is_test) { + log.err("TODO: analyze test decl", .{}); + } }, .@"usingnamespace" => { log.err("TODO: analyze usingnamespace decl", .{}); @@ -3532,6 +3535,7 @@ fn semaContainerFn( .lazy = .{ .token_abs = name_tok }, }, "redefinition of '{s}'", .{decl.name}); errdefer msg.destroy(mod.gpa); + try mod.errNoteNonLazy(decl.srcLoc(), msg, "previous definition here", .{}); try mod.failed_decls.putNoClobber(mod.gpa, decl, msg); } else { if (!srcHashEql(decl.contents_hash, contents_hash)) { @@ -3589,12 +3593,13 @@ fn semaContainerVar( decl.src_index = decl_i; if (deleted_decls.swapRemove(decl) == null) { decl.analysis = .sema_failure; - const err_msg = try ErrorMsg.create(mod.gpa, .{ + const msg = try ErrorMsg.create(mod.gpa, .{ .container = .{ .file_scope = container_scope.file_scope }, .lazy = .{ .token_abs = name_token }, }, "redefinition of '{s}'", .{decl.name}); - errdefer err_msg.destroy(mod.gpa); - try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg); + errdefer msg.destroy(mod.gpa); + try mod.errNoteNonLazy(decl.srcLoc(), msg, "previous definition here", .{}); + try mod.failed_decls.putNoClobber(mod.gpa, decl, msg); } else if (!srcHashEql(decl.contents_hash, contents_hash)) { try outdated_decls.put(decl, {}); decl.contents_hash = contents_hash; diff --git a/src/Package.zig b/src/Package.zig index 33ff4766ca..25a9f55d63 100644 --- a/src/Package.zig +++ b/src/Package.zig @@ -4,18 +4,29 @@ const std = @import("std"); const fs = std.fs; const mem = std.mem; const Allocator = mem.Allocator; +const assert = std.debug.assert; const Compilation = @import("Compilation.zig"); +const Module = @import("Module.zig"); pub const Table = std.StringHashMapUnmanaged(*Package); +pub const root_namespace_hash: Module.Scope.NameHash = .{ + 0, 0, 6, 6, 6, 0, 0, 0, + 6, 9, 0, 0, 0, 4, 2, 0, +}; + root_src_directory: Compilation.Directory, /// Relative to `root_src_directory`. May contain path separators. root_src_path: []const u8, table: Table = .{}, parent: ?*Package = null, +namespace_hash: Module.Scope.NameHash, +/// Whether to free `root_src_directory` on `destroy`. +root_src_directory_owned: bool = false, /// Allocate a Package. No references to the slices passed are kept. +/// Don't forget to set `namespace_hash` later. pub fn create( gpa: *Allocator, /// Null indicates the current working directory @@ -38,27 +49,69 @@ pub fn create( .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(), }, .root_src_path = owned_src_path, + .root_src_directory_owned = true, + .namespace_hash = undefined, }; return ptr; } -/// Free all memory associated with this package and recursively call destroy -/// on all packages in its table +pub fn createWithDir( + gpa: *Allocator, + directory: Compilation.Directory, + /// Relative to `directory`. If null, means `directory` is the root src dir + /// and is owned externally. + root_src_dir_path: ?[]const u8, + /// Relative to root_src_dir_path + root_src_path: []const u8, +) !*Package { + const ptr = try gpa.create(Package); + errdefer gpa.destroy(ptr); + + const owned_src_path = try gpa.dupe(u8, root_src_path); + errdefer gpa.free(owned_src_path); + + if (root_src_dir_path) |p| { + const owned_dir_path = try directory.join(gpa, &[1][]const u8{p}); + errdefer gpa.free(owned_dir_path); + + ptr.* = .{ + .root_src_directory = .{ + .path = owned_dir_path, + .handle = try directory.handle.openDir(p, .{}), + }, + .root_src_directory_owned = true, + .root_src_path = owned_src_path, + .namespace_hash = undefined, + }; + } else { + ptr.* = .{ + .root_src_directory = directory, + .root_src_directory_owned = false, + .root_src_path = owned_src_path, + .namespace_hash = undefined, + }; + } + return ptr; +} + +/// Free all memory associated with this package. It does not destroy any packages +/// inside its table; the caller is responsible for calling destroy() on them. pub fn destroy(pkg: *Package, gpa: *Allocator) void { gpa.free(pkg.root_src_path); - // If root_src_directory.path is null then the handle is the cwd() - // which shouldn't be closed. - if (pkg.root_src_directory.path) |p| { - gpa.free(p); - pkg.root_src_directory.handle.close(); + if (pkg.root_src_directory_owned) { + // If root_src_directory.path is null then the handle is the cwd() + // which shouldn't be closed. + if (pkg.root_src_directory.path) |p| { + gpa.free(p); + pkg.root_src_directory.handle.close(); + } } { var it = pkg.table.iterator(); while (it.next()) |kv| { - kv.value.destroy(gpa); gpa.free(kv.key); } } @@ -72,3 +125,10 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package) const name_dupe = try mem.dupe(gpa, u8, name); pkg.table.putAssumeCapacityNoClobber(name_dupe, package); } + +pub fn addAndAdopt(parent: *Package, gpa: *Allocator, name: []const u8, child: *Package) !void { + assert(child.parent == null); // make up your mind, who is the parent?? + child.parent = parent; + child.namespace_hash = std.zig.hashName(parent.namespace_hash, ":", name); + return parent.add(gpa, name, child); +} diff --git a/src/Sema.zig b/src/Sema.zig index 51d350ea7c..161c4b0539 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -598,6 +598,10 @@ fn zirStructDecl( const struct_obj = try new_decl_arena.allocator.create(Module.Struct); const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj); const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty); + const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{ + .ty = Type.initTag(.type), + .val = struct_val, + }); struct_obj.* = .{ .owner_decl = sema.owner_decl, .fields = fields_map, @@ -605,12 +609,9 @@ fn zirStructDecl( .container = .{ .ty = struct_ty, .file_scope = block.getFileScope(), + .parent_name_hash = new_decl.fullyQualifiedNameHash(), }, }; - const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{ - .ty = Type.initTag(.type), - .val = struct_val, - }); return sema.analyzeDeclVal(block, src, new_decl); } @@ -5298,9 +5299,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string }); errdefer sema.gpa.free(resolved_path); - if (sema.mod.import_table.get(resolved_path)) |some| { + if (sema.mod.import_table.get(resolved_path)) |cached_import| { sema.gpa.free(resolved_path); - return some; + return cached_import; } if (found_pkg == null) { @@ -5318,6 +5319,11 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container); errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?); + const container_name_hash: Scope.NameHash = if (found_pkg) |pkg| + pkg.namespace_hash + else + std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path); + file_scope.* = .{ .sub_file_path = resolved_path, .source = .{ .unloaded = {} }, @@ -5328,6 +5334,7 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin .file_scope = file_scope, .decls = .{}, .ty = struct_ty, + .parent_name_hash = container_name_hash, }, }; sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) { diff --git a/src/main.zig b/src/main.zig index 5fb74db61f..6136c964ce 100644 --- a/src/main.zig +++ b/src/main.zig @@ -599,15 +599,15 @@ fn buildOutputType( var test_exec_args = std.ArrayList(?[]const u8).init(gpa); defer test_exec_args.deinit(); - const pkg_tree_root = try gpa.create(Package); // This package only exists to clean up the code parsing --pkg-begin and // --pkg-end flags. Use dummy values that are safe for the destroy call. - pkg_tree_root.* = .{ + var pkg_tree_root: Package = .{ .root_src_directory = .{ .path = null, .handle = fs.cwd() }, .root_src_path = &[0]u8{}, + .namespace_hash = Package.root_namespace_hash, }; - defer pkg_tree_root.destroy(gpa); - var cur_pkg: *Package = pkg_tree_root; + defer freePkgTree(gpa, &pkg_tree_root, false); + var cur_pkg: *Package = &pkg_tree_root; switch (arg_mode) { .build, .translate_c, .zig_test, .run => { @@ -658,8 +658,7 @@ fn buildOutputType( ) catch |err| { fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) }); }; - new_cur_pkg.parent = cur_pkg; - try cur_pkg.add(gpa, pkg_name, new_cur_pkg); + try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg); cur_pkg = new_cur_pkg; } else if (mem.eql(u8, arg, "--pkg-end")) { cur_pkg = cur_pkg.parent orelse @@ -1747,6 +1746,7 @@ fn buildOutputType( if (root_pkg) |pkg| { pkg.table = pkg_tree_root.table; pkg_tree_root.table = .{}; + pkg.namespace_hash = pkg_tree_root.namespace_hash; } const self_exe_path = try fs.selfExePathAlloc(arena); @@ -2151,6 +2151,18 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi } } +fn freePkgTree(gpa: *Allocator, pkg: *Package, free_parent: bool) void { + { + var it = pkg.table.iterator(); + while (it.next()) |kv| { + freePkgTree(gpa, kv.value, true); + } + } + if (free_parent) { + pkg.destroy(gpa); + } +} + fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void { if (!build_options.have_llvm) 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 .handle = try zig_lib_directory.handle.openDir(std_special, .{}), }, .root_src_path = "build_runner.zig", + .namespace_hash = Package.root_namespace_hash, }; defer root_pkg.root_src_directory.handle.close(); @@ -2550,8 +2563,9 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v var build_pkg: Package = .{ .root_src_directory = build_directory, .root_src_path = build_zig_basename, + .namespace_hash = undefined, }; - try root_pkg.table.put(arena, "@build", &build_pkg); + try root_pkg.addAndAdopt(arena, "@build", &build_pkg); var global_cache_directory: Compilation.Directory = l: { const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena); diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 5c37a1247b..6e966fe75d 100644 --- a/src/stage1/codegen.cpp +++ b/src/stage1/codegen.cpp @@ -9137,6 +9137,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie)); buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols)); buf_appendf(contents, "pub const code_model = CodeModel.default;\n"); + buf_appendf(contents, "pub const zig_is_stage2 = false;\n"); { TargetSubsystem detected_subsystem = detect_subsystem(g);