Commit 482b995a49
Changed files (10)
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,
lib/std/start2.zig
@@ -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;
-}
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;
}
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;
}
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);
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();
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);
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;
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);
+}
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) {