authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-09 10:15:46-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-04-09 10:15:46-07:00
logf75cdd1acd0929792c33766bd1d093d897c65113
tree4f67752f34d4d3d8b78631b48d48fb971000c7a1
parent952032b40cd6e3dbffc5642d17a7a05fa7c83895
parentafe5862111034ea4100b0eea5971e181d70ffc39
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #8470 from ziglang/stage2-start

stage2: blaze the trail for std lib integration

17 files changed, 662 insertions(+), 290 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/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/AstGen.zig+61-5
......@@ -823,7 +823,31 @@ pub fn structInitExpr(
823823 .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
824824 .ref => unreachable, // struct literal not valid as l-value
825825 .ty => |ty_inst| {
826 return mod.failNode(scope, node, "TODO implement structInitExpr ty", .{});
826 const fields_list = try gpa.alloc(zir.Inst.StructInit.Item, struct_init.ast.fields.len);
827 defer gpa.free(fields_list);
828
829 for (struct_init.ast.fields) |field_init, i| {
830 const name_token = tree.firstToken(field_init) - 2;
831 const str_index = try gz.identAsString(name_token);
832
833 const field_ty_inst = try gz.addPlNode(.field_type, field_init, zir.Inst.FieldType{
834 .container_type = ty_inst,
835 .name_start = str_index,
836 });
837 fields_list[i] = .{
838 .field_type = astgen.refToIndex(field_ty_inst).?,
839 .init = try expr(gz, scope, .{ .ty = field_ty_inst }, field_init),
840 };
841 }
842 const init_inst = try gz.addPlNode(.struct_init, node, zir.Inst.StructInit{
843 .fields_len = @intCast(u32, fields_list.len),
844 });
845 try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len +
846 fields_list.len * @typeInfo(zir.Inst.StructInit.Item).Struct.fields.len);
847 for (fields_list) |field| {
848 _ = gz.astgen.addExtraAssumeCapacity(field);
849 }
850 return rvalue(gz, scope, rl, init_inst, node);
827851 },
828852 .ptr => |ptr_inst| {
829853 const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len);
......@@ -1245,6 +1269,7 @@ fn blockExprStmts(
12451269 .fn_type_var_args,
12461270 .fn_type_cc,
12471271 .fn_type_cc_var_args,
1272 .has_decl,
12481273 .int,
12491274 .float,
12501275 .float128,
......@@ -1320,6 +1345,8 @@ fn blockExprStmts(
13201345 .switch_capture_else,
13211346 .switch_capture_else_ref,
13221347 .struct_init_empty,
1348 .struct_init,
1349 .field_type,
13231350 .struct_decl,
13241351 .struct_decl_packed,
13251352 .struct_decl_extern,
......@@ -1329,6 +1356,7 @@ fn blockExprStmts(
13291356 .opaque_decl,
13301357 .int_to_enum,
13311358 .enum_to_int,
1359 .type_info,
13321360 => break :b false,
13331361
13341362 // ZIR instructions that are always either `noreturn` or `void`.
......@@ -1336,6 +1364,7 @@ fn blockExprStmts(
13361364 .dbg_stmt_node,
13371365 .ensure_result_used,
13381366 .ensure_result_non_error,
1367 .@"export",
13391368 .set_eval_branch_quota,
13401369 .compile_log,
13411370 .ensure_err_payload_void,
......@@ -2347,7 +2376,7 @@ fn arrayAccess(
23472376 ),
23482377 else => return rvalue(gz, scope, rl, try gz.addBin(
23492378 .elem_val,
2350 try expr(gz, scope, .none, node_datas[node].lhs),
2379 try expr(gz, scope, .none_or_ref, node_datas[node].lhs),
23512380 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
23522381 ), node),
23532382 }
......@@ -4146,6 +4175,36 @@ fn builtinCall(
41464175 return rvalue(gz, scope, rl, result, node);
41474176 },
41484177
4178 .@"export" => {
4179 // TODO: @export is supposed to be able to export things other than functions.
4180 // Instead of `comptimeExpr` here we need `decl_ref`.
4181 const fn_to_export = try comptimeExpr(gz, scope, .none, params[0]);
4182 // TODO: the second parameter here is supposed to be
4183 // `std.builtin.ExportOptions`, not a string.
4184 const export_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
4185 _ = try gz.addPlNode(.@"export", node, zir.Inst.Bin{
4186 .lhs = fn_to_export,
4187 .rhs = export_name,
4188 });
4189 return rvalue(gz, scope, rl, .void_value, node);
4190 },
4191
4192 .has_decl => {
4193 const container_type = try typeExpr(gz, scope, params[0]);
4194 const name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]);
4195 const result = try gz.addPlNode(.has_decl, node, zir.Inst.Bin{
4196 .lhs = container_type,
4197 .rhs = name,
4198 });
4199 return rvalue(gz, scope, rl, result, node);
4200 },
4201
4202 .type_info => {
4203 const operand = try typeExpr(gz, scope, params[0]);
4204 const result = try gz.addUnNode(.type_info, operand, node);
4205 return rvalue(gz, scope, rl, result, node);
4206 },
4207
41494208 .add_with_overflow,
41504209 .align_cast,
41514210 .align_of,
......@@ -4175,11 +4234,9 @@ fn builtinCall(
41754234 .error_name,
41764235 .error_return_trace,
41774236 .err_set_cast,
4178 .@"export",
41794237 .fence,
41804238 .field_parent_ptr,
41814239 .float_to_int,
4182 .has_decl,
41834240 .has_field,
41844241 .int_to_float,
41854242 .int_to_ptr,
......@@ -4224,7 +4281,6 @@ fn builtinCall(
42244281 .This,
42254282 .truncate,
42264283 .Type,
4227 .type_info,
42284284 .type_name,
42294285 .union_init,
42304286 => return mod.failNode(scope, node, "TODO: implement builtin function {s}", .{
src/Compilation.zig+55-36
......@@ -932,38 +932,56 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
932932 artifact_sub_dir,
933933 };
934934
935 // TODO when we implement serialization and deserialization of incremental compilation metadata,
936 // this is where we would load it. We have open a handle to the directory where
937 // the output either already is, or will be.
935 // If we rely on stage1, we must not redundantly add these packages.
936 const use_stage1 = build_options.is_stage1 and use_llvm;
937 if (!use_stage1) {
938 const builtin_pkg = try Package.createWithDir(
939 gpa,
940 zig_cache_artifact_directory,
941 null,
942 "builtin.zig",
943 );
944 errdefer builtin_pkg.destroy(gpa);
945
946 const std_pkg = try Package.createWithDir(
947 gpa,
948 options.zig_lib_directory,
949 "std",
950 "std.zig",
951 );
952 errdefer std_pkg.destroy(gpa);
953
954 try root_pkg.addAndAdopt(gpa, "builtin", builtin_pkg);
955 try root_pkg.add(gpa, "root", root_pkg);
956 try root_pkg.addAndAdopt(gpa, "std", std_pkg);
957
958 try std_pkg.add(gpa, "builtin", builtin_pkg);
959 try std_pkg.add(gpa, "root", root_pkg);
960 }
961
962 // TODO when we implement serialization and deserialization of incremental
963 // compilation metadata, this is where we would load it. We have open a handle
964 // to the directory where the output either already is, or will be.
938965 // However we currently do not have serialization of such metadata, so for now
939966 // we set up an empty Module that does the entire compilation fresh.
940967
941 const root_scope = rs: {
942 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
943 const root_scope = try gpa.create(Module.Scope.File);
944 const struct_ty = try Type.Tag.empty_struct.create(
945 gpa,
946 &root_scope.root_container,
947 );
948 root_scope.* = .{
949 // TODO this is duped so it can be freed in Container.deinit
950 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
951 .source = .{ .unloaded = {} },
952 .tree = undefined,
953 .status = .never_loaded,
954 .pkg = root_pkg,
955 .root_container = .{
956 .file_scope = root_scope,
957 .decls = .{},
958 .ty = struct_ty,
959 },
960 };
961 break :rs root_scope;
962 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
963 return error.ZirFilesUnsupported;
964 } else {
965 unreachable;
966 }
968 const root_scope = try gpa.create(Module.Scope.File);
969 errdefer gpa.destroy(root_scope);
970
971 const struct_ty = try Type.Tag.empty_struct.create(gpa, &root_scope.root_container);
972 root_scope.* = .{
973 // TODO this is duped so it can be freed in Container.deinit
974 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
975 .source = .{ .unloaded = {} },
976 .tree = undefined,
977 .status = .never_loaded,
978 .pkg = root_pkg,
979 .root_container = .{
980 .file_scope = root_scope,
981 .decls = .{},
982 .ty = struct_ty,
983 .parent_name_hash = root_pkg.namespace_hash,
984 },
967985 };
968986
969987 const module = try arena.create(Module);
......@@ -1365,7 +1383,8 @@ pub fn update(self: *Compilation) !void {
13651383 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);
13661384 }
13671385
1368 const use_stage1 = build_options.omit_stage2 or build_options.is_stage1 and self.bin_file.options.use_llvm;
1386 const use_stage1 = build_options.omit_stage2 or
1387 (build_options.is_stage1 and self.bin_file.options.use_llvm);
13691388 if (!use_stage1) {
13701389 if (self.bin_file.options.module) |module| {
13711390 module.compile_log_text.shrinkAndFree(module.gpa, 0);
......@@ -2490,7 +2509,7 @@ pub fn addCCArgs(
24902509 try argv.append("-fPIC");
24912510 }
24922511 },
2493 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig, .zir => {},
2512 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig => {},
24942513 }
24952514 if (out_dep_path) |p| {
24962515 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
......@@ -2564,7 +2583,6 @@ pub const FileExt = enum {
25642583 object,
25652584 static_library,
25662585 zig,
2567 zir,
25682586 unknown,
25692587
25702588 pub fn clangSupportsDepFile(ext: FileExt) bool {
......@@ -2578,7 +2596,6 @@ pub const FileExt = enum {
25782596 .object,
25792597 .static_library,
25802598 .zig,
2581 .zir,
25822599 .unknown,
25832600 => false,
25842601 };
......@@ -2650,8 +2667,6 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
26502667 return .h;
26512668 } else if (mem.endsWith(u8, filename, ".zig")) {
26522669 return .zig;
2653 } else if (mem.endsWith(u8, filename, ".zir")) {
2654 return .zir;
26552670 } else if (hasSharedLibraryExt(filename)) {
26562671 return .shared_library;
26572672 } else if (hasStaticLibraryExt(filename)) {
......@@ -2672,7 +2687,6 @@ test "classifyFileExt" {
26722687 std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3"));
26732688 std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));
26742689 std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
2675 std.testing.expectEqual(FileExt.zir, classifyFileExt("foo.zir"));
26762690}
26772691
26782692fn haveFramePointer(comp: *const Compilation) bool {
......@@ -2867,6 +2881,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28672881
28682882 const target = comp.getTarget();
28692883 const generic_arch_name = target.cpu.arch.genericName();
2884 const use_stage1 = build_options.omit_stage2 or
2885 (build_options.is_stage1 and comp.bin_file.options.use_llvm);
28702886
28712887 @setEvalBranchQuota(4000);
28722888 try buffer.writer().print(
......@@ -2879,6 +2895,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28792895 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
28802896 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
28812897 \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}");
2898 \\pub const zig_is_stage2 = {};
28822899 \\
28832900 \\pub const output_mode = OutputMode.{};
28842901 \\pub const link_mode = LinkMode.{};
......@@ -2892,6 +2909,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28922909 \\
28932910 , .{
28942911 build_options.version,
2912 !use_stage1,
28952913 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
28962914 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
28972915 comp.bin_file.options.is_test,
......@@ -3101,6 +3119,7 @@ fn buildOutputFromZig(
31013119 .handle = special_dir,
31023120 },
31033121 .root_src_path = src_basename,
3122 .namespace_hash = Package.root_namespace_hash,
31043123 };
31053124 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
31063125 const target = comp.getTarget();
src/Module.zig+68-90
......@@ -150,9 +150,15 @@ pub const Decl = struct {
150150 /// The direct parent container of the Decl.
151151 /// Reference to externally owned memory.
152152 container: *Scope.Container,
153 /// The AST Node decl index or ZIR Inst index that contains this declaration.
153
154 /// An integer that can be checked against the corresponding incrementing
155 /// generation field of Module. This is used to determine whether `complete` status
156 /// represents pre- or post- re-analysis.
157 generation: u32,
158 /// The AST Node index or ZIR Inst index that contains this declaration.
154159 /// Must be recomputed when the corresponding source file is modified.
155 src_index: usize,
160 src_node: ast.Node.Index,
161
156162 /// The most recent value of the Decl after a successful semantic analysis.
157163 typed_value: union(enum) {
158164 never_succeeded: void,
......@@ -198,11 +204,6 @@ pub const Decl = struct {
198204 /// Whether the corresponding AST decl has a `pub` keyword.
199205 is_pub: bool,
200206
201 /// An integer that can be checked against the corresponding incrementing
202 /// generation field of Module. This is used to determine whether `complete` status
203 /// represents pre- or post- re-analysis.
204 generation: u32,
205
206207 /// Represents the position of the code in the output file.
207208 /// This is populated regardless of semantic analysis and code generation.
208209 link: link.File.LinkBlock,
......@@ -249,11 +250,11 @@ pub const Decl = struct {
249250 }
250251
251252 pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index {
252 return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.srcNode()));
253 return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.src_node));
253254 }
254255
255256 pub fn nodeIndexToRelative(decl: Decl, node_index: ast.Node.Index) i32 {
256 return @bitCast(i32, node_index) - @bitCast(i32, decl.srcNode());
257 return @bitCast(i32, node_index) - @bitCast(i32, decl.src_node);
257258 }
258259
259260 pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc {
......@@ -271,14 +272,9 @@ pub const Decl = struct {
271272 };
272273 }
273274
274 pub fn srcNode(decl: Decl) u32 {
275 const tree = &decl.container.file_scope.tree;
276 return tree.rootDecls()[decl.src_index];
277 }
278
279275 pub fn srcToken(decl: Decl) u32 {
280276 const tree = &decl.container.file_scope.tree;
281 return tree.firstToken(decl.srcNode());
277 return tree.firstToken(decl.src_node);
282278 }
283279
284280 pub fn srcByteOffset(decl: Decl) u32 {
......@@ -678,6 +674,7 @@ pub const Scope = struct {
678674 base: Scope = Scope{ .tag = base_tag },
679675
680676 file_scope: *Scope.File,
677 parent_name_hash: NameHash,
681678
682679 /// Direct children of the file.
683680 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
......@@ -696,8 +693,7 @@ pub const Scope = struct {
696693 }
697694
698695 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {
699 // TODO container scope qualified names.
700 return std.zig.hashSrc(name);
696 return std.zig.hashName(cont.parent_name_hash, ".", name);
701697 }
702698
703699 pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void {
......@@ -2296,6 +2292,20 @@ pub const InnerError = error{ OutOfMemory, AnalysisFail };
22962292pub fn deinit(mod: *Module) void {
22972293 const gpa = mod.gpa;
22982294
2295 // The callsite of `Compilation.create` owns the `root_pkg`, however
2296 // Module owns the builtin and std packages that it adds.
2297 if (mod.root_pkg.table.remove("builtin")) |entry| {
2298 gpa.free(entry.key);
2299 entry.value.destroy(gpa);
2300 }
2301 if (mod.root_pkg.table.remove("std")) |entry| {
2302 gpa.free(entry.key);
2303 entry.value.destroy(gpa);
2304 }
2305 if (mod.root_pkg.table.remove("root")) |entry| {
2306 gpa.free(entry.key);
2307 }
2308
22992309 mod.compile_log_text.deinit(gpa);
23002310
23012311 mod.zig_cache_artifact_directory.handle.close();
......@@ -2458,7 +2468,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
24582468 const tree = try mod.getAstTree(decl.container.file_scope);
24592469 const node_tags = tree.nodes.items(.tag);
24602470 const node_datas = tree.nodes.items(.data);
2461 const decl_node = tree.rootDecls()[decl.src_index];
2471 const decl_node = decl.src_node;
24622472 switch (node_tags[decl_node]) {
24632473 .fn_decl => {
24642474 const fn_proto = node_datas[decl_node].lhs;
......@@ -2513,6 +2523,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
25132523
25142524 const block_expr = node_datas[decl_node].lhs;
25152525 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
2526 _ = try gen_scope.addBreak(.break_inline, 0, .void_value);
25162527
25172528 const code = try gen_scope.finish();
25182529 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
......@@ -3294,7 +3305,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
32943305 var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa);
32953306 defer outdated_decls.deinit();
32963307
3297 for (decls) |decl_node, decl_i| switch (node_tags[decl_node]) {
3308 for (decls) |decl_node| switch (node_tags[decl_node]) {
32983309 .fn_decl => {
32993310 const fn_proto = node_datas[decl_node].lhs;
33003311 const body = node_datas[decl_node].rhs;
......@@ -3306,7 +3317,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33063317 &deleted_decls,
33073318 &outdated_decls,
33083319 decl_node,
3309 decl_i,
33103320 tree.*,
33113321 body,
33123322 tree.fnProtoSimple(&params, fn_proto),
......@@ -3317,7 +3327,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33173327 &deleted_decls,
33183328 &outdated_decls,
33193329 decl_node,
3320 decl_i,
33213330 tree.*,
33223331 body,
33233332 tree.fnProtoMulti(fn_proto),
......@@ -3329,7 +3338,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33293338 &deleted_decls,
33303339 &outdated_decls,
33313340 decl_node,
3332 decl_i,
33333341 tree.*,
33343342 body,
33353343 tree.fnProtoOne(&params, fn_proto),
......@@ -3340,7 +3348,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33403348 &deleted_decls,
33413349 &outdated_decls,
33423350 decl_node,
3343 decl_i,
33443351 tree.*,
33453352 body,
33463353 tree.fnProto(fn_proto),
......@@ -3355,7 +3362,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33553362 &deleted_decls,
33563363 &outdated_decls,
33573364 decl_node,
3358 decl_i,
33593365 tree.*,
33603366 0,
33613367 tree.fnProtoSimple(&params, decl_node),
......@@ -3366,7 +3372,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33663372 &deleted_decls,
33673373 &outdated_decls,
33683374 decl_node,
3369 decl_i,
33703375 tree.*,
33713376 0,
33723377 tree.fnProtoMulti(decl_node),
......@@ -3378,7 +3383,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33783383 &deleted_decls,
33793384 &outdated_decls,
33803385 decl_node,
3381 decl_i,
33823386 tree.*,
33833387 0,
33843388 tree.fnProtoOne(&params, decl_node),
......@@ -3389,7 +3393,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
33893393 &deleted_decls,
33903394 &outdated_decls,
33913395 decl_node,
3392 decl_i,
33933396 tree.*,
33943397 0,
33953398 tree.fnProto(decl_node),
......@@ -3400,7 +3403,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34003403 &deleted_decls,
34013404 &outdated_decls,
34023405 decl_node,
3403 decl_i,
34043406 tree.*,
34053407 tree.globalVarDecl(decl_node),
34063408 ),
......@@ -3409,7 +3411,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34093411 &deleted_decls,
34103412 &outdated_decls,
34113413 decl_node,
3412 decl_i,
34133414 tree.*,
34143415 tree.localVarDecl(decl_node),
34153416 ),
......@@ -3418,7 +3419,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34183419 &deleted_decls,
34193420 &outdated_decls,
34203421 decl_node,
3421 decl_i,
34223422 tree.*,
34233423 tree.simpleVarDecl(decl_node),
34243424 ),
......@@ -3427,7 +3427,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34273427 &deleted_decls,
34283428 &outdated_decls,
34293429 decl_node,
3430 decl_i,
34313430 tree.*,
34323431 tree.alignedVarDecl(decl_node),
34333432 ),
......@@ -3440,38 +3439,21 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
34403439 const name_hash = container_scope.fullyQualifiedNameHash(name);
34413440 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
34423441
3443 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
3442 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
34443443 container_scope.decls.putAssumeCapacity(new_decl, {});
34453444 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
34463445 },
34473446
3448 .container_field_init => try mod.semaContainerField(
3449 container_scope,
3450 &deleted_decls,
3451 decl_node,
3452 decl_i,
3453 tree.*,
3454 tree.containerFieldInit(decl_node),
3455 ),
3456 .container_field_align => try mod.semaContainerField(
3457 container_scope,
3458 &deleted_decls,
3459 decl_node,
3460 decl_i,
3461 tree.*,
3462 tree.containerFieldAlign(decl_node),
3463 ),
3464 .container_field => try mod.semaContainerField(
3465 container_scope,
3466 &deleted_decls,
3467 decl_node,
3468 decl_i,
3469 tree.*,
3470 tree.containerField(decl_node),
3471 ),
3447 // Container fields are handled in AstGen.
3448 .container_field_init,
3449 .container_field_align,
3450 .container_field,
3451 => continue,
34723452
34733453 .test_decl => {
3474 log.err("TODO: analyze test decl", .{});
3454 if (mod.comp.bin_file.options.is_test) {
3455 log.err("TODO: analyze test decl", .{});
3456 }
34753457 },
34763458 .@"usingnamespace" => {
34773459 log.err("TODO: analyze usingnamespace decl", .{});
......@@ -3508,7 +3490,6 @@ fn semaContainerFn(
35083490 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
35093491 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
35103492 decl_node: ast.Node.Index,
3511 decl_i: usize,
35123493 tree: ast.Tree,
35133494 body_node: ast.Node.Index,
35143495 fn_proto: ast.full.FnProto,
......@@ -3517,24 +3498,30 @@ fn semaContainerFn(
35173498 defer tracy.end();
35183499
35193500 // We will create a Decl for it regardless of analysis status.
3520 const name_tok = fn_proto.name_token orelse {
3501 const name_token = fn_proto.name_token orelse {
35213502 // This problem will go away with #1717.
35223503 @panic("TODO missing function name");
35233504 };
3524 const name = tree.tokenSlice(name_tok); // TODO use identifierTokenString
3505 const name = tree.tokenSlice(name_token); // TODO use identifierTokenString
35253506 const name_hash = container_scope.fullyQualifiedNameHash(name);
35263507 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
35273508 if (mod.decl_table.get(name_hash)) |decl| {
35283509 // Update the AST Node index of the decl, even if its contents are unchanged, it may
35293510 // have been re-ordered.
3530 decl.src_index = decl_i;
3511 const prev_src_node = decl.src_node;
3512 decl.src_node = decl_node;
35313513 if (deleted_decls.swapRemove(decl) == null) {
35323514 decl.analysis = .sema_failure;
35333515 const msg = try ErrorMsg.create(mod.gpa, .{
35343516 .container = .{ .file_scope = container_scope.file_scope },
3535 .lazy = .{ .token_abs = name_tok },
3517 .lazy = .{ .token_abs = name_token },
35363518 }, "redefinition of '{s}'", .{decl.name});
35373519 errdefer msg.destroy(mod.gpa);
3520 const other_src_loc: SrcLoc = .{
3521 .container = .{ .file_scope = decl.container.file_scope },
3522 .lazy = .{ .node_abs = prev_src_node },
3523 };
3524 try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{});
35383525 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
35393526 } else {
35403527 if (!srcHashEql(decl.contents_hash, contents_hash)) {
......@@ -3558,7 +3545,7 @@ fn semaContainerFn(
35583545 }
35593546 }
35603547 } else {
3561 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
3548 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
35623549 container_scope.decls.putAssumeCapacity(new_decl, {});
35633550 if (fn_proto.extern_export_token) |maybe_export_token| {
35643551 const token_tags = tree.tokens.items(.tag);
......@@ -3566,6 +3553,7 @@ fn semaContainerFn(
35663553 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
35673554 }
35683555 }
3556 new_decl.is_pub = fn_proto.visib_token != null;
35693557 }
35703558}
35713559
......@@ -3575,7 +3563,6 @@ fn semaContainerVar(
35753563 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
35763564 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
35773565 decl_node: ast.Node.Index,
3578 decl_i: usize,
35793566 tree: ast.Tree,
35803567 var_decl: ast.full.VarDecl,
35813568) !void {
......@@ -3589,21 +3576,27 @@ fn semaContainerVar(
35893576 if (mod.decl_table.get(name_hash)) |decl| {
35903577 // Update the AST Node index of the decl, even if its contents are unchanged, it may
35913578 // have been re-ordered.
3592 decl.src_index = decl_i;
3579 const prev_src_node = decl.src_node;
3580 decl.src_node = decl_node;
35933581 if (deleted_decls.swapRemove(decl) == null) {
35943582 decl.analysis = .sema_failure;
3595 const err_msg = try ErrorMsg.create(mod.gpa, .{
3583 const msg = try ErrorMsg.create(mod.gpa, .{
35963584 .container = .{ .file_scope = container_scope.file_scope },
35973585 .lazy = .{ .token_abs = name_token },
35983586 }, "redefinition of '{s}'", .{decl.name});
3599 errdefer err_msg.destroy(mod.gpa);
3600 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);
3587 errdefer msg.destroy(mod.gpa);
3588 const other_src_loc: SrcLoc = .{
3589 .container = .{ .file_scope = decl.container.file_scope },
3590 .lazy = .{ .node_abs = prev_src_node },
3591 };
3592 try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{});
3593 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
36013594 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
36023595 try outdated_decls.put(decl, {});
36033596 decl.contents_hash = contents_hash;
36043597 }
36053598 } else {
3606 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
3599 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash);
36073600 container_scope.decls.putAssumeCapacity(new_decl, {});
36083601 if (var_decl.extern_export_token) |maybe_export_token| {
36093602 const token_tags = tree.tokens.items(.tag);
......@@ -3614,21 +3607,6 @@ fn semaContainerVar(
36143607 }
36153608}
36163609
3617fn semaContainerField(
3618 mod: *Module,
3619 container_scope: *Scope.Container,
3620 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3621 decl_node: ast.Node.Index,
3622 decl_i: usize,
3623 tree: ast.Tree,
3624 field: ast.full.ContainerField,
3625) !void {
3626 const tracy = trace(@src());
3627 defer tracy.end();
3628
3629 log.err("TODO: analyze container field", .{});
3630}
3631
36323610pub fn deleteDecl(
36333611 mod: *Module,
36343612 decl: *Decl,
......@@ -3811,7 +3789,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
38113789fn allocateNewDecl(
38123790 mod: *Module,
38133791 scope: *Scope,
3814 src_index: usize,
3792 src_node: ast.Node.Index,
38153793 contents_hash: std.zig.SrcHash,
38163794) !*Decl {
38173795 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.
......@@ -3827,7 +3805,7 @@ fn allocateNewDecl(
38273805 new_decl.* = .{
38283806 .name = "",
38293807 .container = scope.namespace(),
3830 .src_index = src_index,
3808 .src_node = src_node,
38313809 .typed_value = .{ .never_succeeded = {} },
38323810 .analysis = .unreferenced,
38333811 .deletion_flag = false,
......@@ -3858,12 +3836,12 @@ fn createNewDecl(
38583836 mod: *Module,
38593837 scope: *Scope,
38603838 decl_name: []const u8,
3861 src_index: usize,
3839 src_node: ast.Node.Index,
38623840 name_hash: Scope.NameHash,
38633841 contents_hash: std.zig.SrcHash,
38643842) !*Decl {
38653843 try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1);
3866 const new_decl = try mod.allocateNewDecl(scope, src_index, contents_hash);
3844 const new_decl = try mod.allocateNewDecl(scope, src_node, contents_hash);
38673845 errdefer mod.gpa.destroy(new_decl);
38683846 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);
38693847 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
......@@ -4076,7 +4054,7 @@ pub fn createAnonymousDecl(
40764054 defer mod.gpa.free(name);
40774055 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
40784056 const src_hash: std.zig.SrcHash = undefined;
4079 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
4057 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash);
40804058 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
40814059
40824060 decl_arena_state.* = decl_arena.state;
......@@ -4112,7 +4090,7 @@ pub fn createContainerDecl(
41124090 defer mod.gpa.free(name);
41134091 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
41144092 const src_hash: std.zig.SrcHash = undefined;
4115 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
4093 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash);
41164094 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
41174095
41184096 decl_arena_state.* = decl_arena.state;
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+135-36
......@@ -199,6 +199,7 @@ pub fn analyzeBody(
199199 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),
200200 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),
201201 .fn_type_var_args => try sema.zirFnType(block, inst, true),
202 .has_decl => try sema.zirHasDecl(block, inst),
202203 .import => try sema.zirImport(block, inst),
203204 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
204205 .int => try sema.zirInt(block, inst),
......@@ -258,11 +259,14 @@ pub fn analyzeBody(
258259 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
259260 .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
260261 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
262 .type_info => try sema.zirTypeInfo(block, inst),
261263 .typeof => try sema.zirTypeof(block, inst),
262264 .typeof_elem => try sema.zirTypeofElem(block, inst),
263265 .typeof_peer => try sema.zirTypeofPeer(block, inst),
264266 .xor => try sema.zirBitwise(block, inst, .xor),
265267 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),
268 .struct_init => try sema.zirStructInit(block, inst),
269 .field_type => try sema.zirFieldType(block, inst),
266270
267271 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),
268272 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
......@@ -342,6 +346,10 @@ pub fn analyzeBody(
342346 try sema.zirValidateStructInitPtr(block, inst);
343347 continue;
344348 },
349 .@"export" => {
350 try sema.zirExport(block, inst);
351 continue;
352 },
345353
346354 // Special case instructions to handle comptime control flow.
347355 .repeat_inline => {
......@@ -593,6 +601,10 @@ fn zirStructDecl(
593601 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
594602 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
595603 const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);
604 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
605 .ty = Type.initTag(.type),
606 .val = struct_val,
607 });
596608 struct_obj.* = .{
597609 .owner_decl = sema.owner_decl,
598610 .fields = fields_map,
......@@ -600,12 +612,9 @@ fn zirStructDecl(
600612 .container = .{
601613 .ty = struct_ty,
602614 .file_scope = block.getFileScope(),
615 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
603616 },
604617 };
605 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
606 .ty = Type.initTag(.type),
607 .val = struct_val,
608 });
609618 return sema.analyzeDeclVal(block, src, new_decl);
610619}
611620
......@@ -1333,6 +1342,28 @@ fn analyzeBlockBody(
13331342 return &merges.block_inst.base;
13341343}
13351344
1345fn zirExport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
1346 const tracy = trace(@src());
1347 defer tracy.end();
1348
1349 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1350 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
1351 const src = inst_data.src();
1352 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1353 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1354
1355 // TODO (see corresponding TODO in AstGen) this is supposed to be a `decl_ref`
1356 // instruction, which could reference any decl, which is then supposed to get
1357 // exported, regardless of whether or not it is a function.
1358 const target_fn = try sema.resolveInstConst(block, lhs_src, extra.lhs);
1359 // TODO (see corresponding TODO in AstGen) this is supposed to be
1360 // `std.builtin.ExportOptions`, not a string.
1361 const export_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
1362
1363 const actual_fn = target_fn.val.castTag(.function).?.data;
1364 try sema.mod.analyzeExport(&block.base, src, export_name, actual_fn.owner_decl);
1365}
1366
13361367fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
13371368 const tracy = trace(@src());
13381369 defer tracy.end();
......@@ -1402,9 +1433,6 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
14021433}
14031434
14041435fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1405 const tracy = trace(@src());
1406 defer tracy.end();
1407
14081436 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
14091437 const src = inst_data.src();
14101438 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
......@@ -1412,9 +1440,6 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
14121440}
14131441
14141442fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1415 const tracy = trace(@src());
1416 defer tracy.end();
1417
14181443 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
14191444 const src = inst_data.src();
14201445 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;
......@@ -2543,7 +2568,10 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
25432568
25442569 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
25452570 const array = try sema.resolveInst(bin_inst.lhs);
2546 const array_ptr = try sema.analyzeRef(block, sema.src, array);
2571 const array_ptr = if (array.ty.zigTypeTag() == .Pointer)
2572 array
2573 else
2574 try sema.analyzeRef(block, sema.src, array);
25472575 const elem_index = try sema.resolveInst(bin_inst.rhs);
25482576 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
25492577 return sema.analyzeLoad(block, sema.src, result_ptr, sema.src);
......@@ -2558,7 +2586,10 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
25582586 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
25592587 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
25602588 const array = try sema.resolveInst(extra.lhs);
2561 const array_ptr = try sema.analyzeRef(block, src, array);
2589 const array_ptr = if (array.ty.zigTypeTag() == .Pointer)
2590 array
2591 else
2592 try sema.analyzeRef(block, src, array);
25622593 const elem_index = try sema.resolveInst(extra.rhs);
25632594 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
25642595 return sema.analyzeLoad(block, src, result_ptr, src);
......@@ -3595,6 +3626,34 @@ fn validateSwitchNoRange(
35953626 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
35963627}
35973628
3629fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
3630 const tracy = trace(@src());
3631 defer tracy.end();
3632
3633 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
3634 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
3635 const src = inst_data.src();
3636 const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
3637 const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
3638 const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
3639 const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs);
3640 const mod = sema.mod;
3641 const arena = sema.arena;
3642
3643 const container_scope = container_type.getContainerScope() orelse return mod.fail(
3644 &block.base,
3645 lhs_src,
3646 "expected struct, enum, union, or opaque, found '{}'",
3647 .{container_type},
3648 );
3649 if (mod.lookupDeclName(&container_scope.base, decl_name)) |decl| {
3650 // TODO if !decl.is_pub and inDifferentFiles() return false
3651 return mod.constBool(arena, src, true);
3652 } else {
3653 return mod.constBool(arena, src, false);
3654 }
3655}
3656
35983657fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
35993658 const tracy = trace(@src());
36003659 defer tracy.end();
......@@ -4021,6 +4080,12 @@ fn zirCmp(
40214080 return block.addBinOp(src, bool_type, tag, casted_lhs, casted_rhs);
40224081}
40234082
4083fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4084 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4085 const src = inst_data.src();
4086 return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirTypeInfo", .{});
4087}
4088
40244089fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
40254090 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
40264091 const src = inst_data.src();
......@@ -4438,6 +4503,18 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In
44384503 });
44394504}
44404505
4506fn zirStructInit(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4507 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
4508 const src = inst_data.src();
4509 return sema.mod.fail(&block.base, src, "TODO: Sema.zirStructInit", .{});
4510}
4511
4512fn zirFieldType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4513 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
4514 const src = inst_data.src();
4515 return sema.mod.fail(&block.base, src, "TODO: Sema.zirFieldType", .{});
4516}
4517
44414518fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
44424519 if (sema.func == null) {
44434520 return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
......@@ -4632,7 +4709,8 @@ fn namedFieldPtr(
46324709 .Struct, .Opaque, .Union => {
46334710 if (child_type.getContainerScope()) |container_scope| {
46344711 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4635 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4712 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))
4713 return mod.fail(&block.base, src, "'{s}' is private", .{field_name});
46364714 return sema.analyzeDeclRef(block, src, decl);
46374715 }
46384716
......@@ -4660,7 +4738,8 @@ fn namedFieldPtr(
46604738 .Enum => {
46614739 if (child_type.getContainerScope()) |container_scope| {
46624740 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4663 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4741 if (!decl.is_pub and !(decl.container.file_scope == block.base.namespace().file_scope))
4742 return mod.fail(&block.base, src, "'{s}' is private", .{field_name});
46644743 return sema.analyzeDeclRef(block, src, decl);
46654744 }
46664745 }
......@@ -4731,37 +4810,51 @@ fn elemPtr(
47314810 elem_index: *Inst,
47324811 elem_index_src: LazySrcLoc,
47334812) InnerError!*Inst {
4734 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
4813 const array_ty = switch (array_ptr.ty.zigTypeTag()) {
47354814 .Pointer => array_ptr.ty.elemType(),
47364815 else => return sema.mod.fail(&block.base, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
47374816 };
4738 if (!elem_ty.isIndexable()) {
4739 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{elem_ty});
4817 if (!array_ty.isIndexable()) {
4818 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{array_ty});
47404819 }
4741
4742 if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
4820 if (array_ty.isSinglePointer() and array_ty.elemType().zigTypeTag() == .Array) {
47434821 // we have to deref the ptr operand to get the actual array pointer
47444822 const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr.src);
4745 if (array_ptr_deref.value()) |array_ptr_val| {
4746 if (elem_index.value()) |index_val| {
4747 // Both array pointer and index are compile-time known.
4748 const index_u64 = index_val.toUnsignedInt();
4749 // @intCast here because it would have been impossible to construct a value that
4750 // required a larger index.
4751 const elem_ptr = try array_ptr_val.elemPtr(sema.arena, @intCast(usize, index_u64));
4752 const pointee_type = elem_ty.elemType().elemType();
4753
4754 return sema.mod.constInst(sema.arena, src, .{
4755 .ty = try Type.Tag.single_const_pointer.create(sema.arena, pointee_type),
4756 .val = elem_ptr,
4757 });
4758 }
4759 }
4823 return sema.elemPtrArray(block, src, array_ptr_deref, elem_index, elem_index_src);
4824 }
4825 if (array_ty.zigTypeTag() == .Array) {
4826 return sema.elemPtrArray(block, src, array_ptr, elem_index, elem_index_src);
47604827 }
47614828
47624829 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});
47634830}
47644831
4832fn elemPtrArray(
4833 sema: *Sema,
4834 block: *Scope.Block,
4835 src: LazySrcLoc,
4836 array_ptr: *Inst,
4837 elem_index: *Inst,
4838 elem_index_src: LazySrcLoc,
4839) InnerError!*Inst {
4840 if (array_ptr.value()) |array_ptr_val| {
4841 if (elem_index.value()) |index_val| {
4842 // Both array pointer and index are compile-time known.
4843 const index_u64 = index_val.toUnsignedInt();
4844 // @intCast here because it would have been impossible to construct a value that
4845 // required a larger index.
4846 const elem_ptr = try array_ptr_val.elemPtr(sema.arena, @intCast(usize, index_u64));
4847 const pointee_type = array_ptr.ty.elemType().elemType();
4848
4849 return sema.mod.constInst(sema.arena, src, .{
4850 .ty = try Type.Tag.single_const_pointer.create(sema.arena, pointee_type),
4851 .val = elem_ptr,
4852 });
4853 }
4854 }
4855 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr for arrays", .{});
4856}
4857
47654858fn coerce(
47664859 sema: *Sema,
47674860 block: *Scope.Block,
......@@ -5244,9 +5337,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
52445337 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
52455338 errdefer sema.gpa.free(resolved_path);
52465339
5247 if (sema.mod.import_table.get(resolved_path)) |some| {
5340 if (sema.mod.import_table.get(resolved_path)) |cached_import| {
52485341 sema.gpa.free(resolved_path);
5249 return some;
5342 return cached_import;
52505343 }
52515344
52525345 if (found_pkg == null) {
......@@ -5264,6 +5357,11 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
52645357 const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);
52655358 errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?);
52665359
5360 const container_name_hash: Scope.NameHash = if (found_pkg) |pkg|
5361 pkg.namespace_hash
5362 else
5363 std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path);
5364
52675365 file_scope.* = .{
52685366 .sub_file_path = resolved_path,
52695367 .source = .{ .unloaded = {} },
......@@ -5274,6 +5372,7 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
52745372 .file_scope = file_scope,
52755373 .decls = .{},
52765374 .ty = struct_ty,
5375 .parent_name_hash = container_name_hash,
52775376 },
52785377 };
52795378 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
src/codegen.zig+1-1
......@@ -417,7 +417,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
417417 const node_datas = tree.nodes.items(.data);
418418 const token_starts = tree.tokens.items(.start);
419419
420 const fn_decl = tree.rootDecls()[module_fn.owner_decl.src_index];
420 const fn_decl = module_fn.owner_decl.src_node;
421421 assert(node_tags[fn_decl] == .fn_decl);
422422 const block = node_datas[fn_decl].rhs;
423423 const lbrace_src = token_starts[tree.firstToken(block)];
src/link/Elf.zig+2-4
......@@ -2228,10 +2228,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
22282228 const node_datas = tree.nodes.items(.data);
22292229 const token_starts = tree.tokens.items(.start);
22302230
2231 const file_ast_decls = tree.rootDecls();
22322231 // TODO Look into improving the performance here by adding a token-index-to-line
22332232 // lookup table. Currently this involves scanning over the source code for newlines.
2234 const fn_decl = file_ast_decls[decl.src_index];
2233 const fn_decl = decl.src_node;
22352234 assert(node_tags[fn_decl] == .fn_decl);
22362235 const block = node_datas[fn_decl].rhs;
22372236 const lbrace = tree.firstToken(block);
......@@ -2755,10 +2754,9 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
27552754 const node_datas = tree.nodes.items(.data);
27562755 const token_starts = tree.tokens.items(.start);
27572756
2758 const file_ast_decls = tree.rootDecls();
27592757 // TODO Look into improving the performance here by adding a token-index-to-line
27602758 // lookup table. Currently this involves scanning over the source code for newlines.
2761 const fn_decl = file_ast_decls[decl.src_index];
2759 const fn_decl = decl.src_node;
27622760 assert(node_tags[fn_decl] == .fn_decl);
27632761 const block = node_datas[fn_decl].rhs;
27642762 const lbrace = tree.firstToken(block);
src/link/MachO/DebugSymbols.zig+2-4
......@@ -909,10 +909,9 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
909909 const node_datas = tree.nodes.items(.data);
910910 const token_starts = tree.tokens.items(.start);
911911
912 const file_ast_decls = tree.rootDecls();
913912 // TODO Look into improving the performance here by adding a token-index-to-line
914913 // lookup table. Currently this involves scanning over the source code for newlines.
915 const fn_decl = file_ast_decls[decl.src_index];
914 const fn_decl = decl.src_node;
916915 assert(node_tags[fn_decl] == .fn_decl);
917916 const block = node_datas[fn_decl].rhs;
918917 const lbrace = tree.firstToken(block);
......@@ -959,10 +958,9 @@ pub fn initDeclDebugBuffers(
959958 const node_datas = tree.nodes.items(.data);
960959 const token_starts = tree.tokens.items(.start);
961960
962 const file_ast_decls = tree.rootDecls();
963961 // TODO Look into improving the performance here by adding a token-index-to-line
964962 // lookup table. Currently this involves scanning over the source code for newlines.
965 const fn_decl = file_ast_decls[decl.src_index];
963 const fn_decl = decl.src_node;
966964 assert(node_tags[fn_decl] == .fn_decl);
967965 const block = node_datas[fn_decl].rhs;
968966 const lbrace = tree.firstToken(block);
src/main.zig+23-23
......@@ -505,7 +505,6 @@ fn buildOutputType(
505505 var emit_bin: EmitBin = .yes_default_path;
506506 var emit_asm: Emit = .no;
507507 var emit_llvm_ir: Emit = .no;
508 var emit_zir: Emit = .no;
509508 var emit_docs: Emit = .no;
510509 var emit_analysis: Emit = .no;
511510 var target_arch_os_abi: []const u8 = "native";
......@@ -599,15 +598,15 @@ fn buildOutputType(
599598 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);
600599 defer test_exec_args.deinit();
601600
602 const pkg_tree_root = try gpa.create(Package);
603601 // This package only exists to clean up the code parsing --pkg-begin and
604602 // --pkg-end flags. Use dummy values that are safe for the destroy call.
605 pkg_tree_root.* = .{
603 var pkg_tree_root: Package = .{
606604 .root_src_directory = .{ .path = null, .handle = fs.cwd() },
607605 .root_src_path = &[0]u8{},
606 .namespace_hash = Package.root_namespace_hash,
608607 };
609 defer pkg_tree_root.destroy(gpa);
610 var cur_pkg: *Package = pkg_tree_root;
608 defer freePkgTree(gpa, &pkg_tree_root, false);
609 var cur_pkg: *Package = &pkg_tree_root;
611610
612611 switch (arg_mode) {
613612 .build, .translate_c, .zig_test, .run => {
......@@ -658,8 +657,7 @@ fn buildOutputType(
658657 ) catch |err| {
659658 fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) });
660659 };
661 new_cur_pkg.parent = cur_pkg;
662 try cur_pkg.add(gpa, pkg_name, new_cur_pkg);
660 try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg);
663661 cur_pkg = new_cur_pkg;
664662 } else if (mem.eql(u8, arg, "--pkg-end")) {
665663 cur_pkg = cur_pkg.parent orelse
......@@ -924,12 +922,6 @@ fn buildOutputType(
924922 emit_bin = .{ .yes = arg["-femit-bin=".len..] };
925923 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {
926924 emit_bin = .no;
927 } else if (mem.eql(u8, arg, "-femit-zir")) {
928 emit_zir = .yes_default_path;
929 } else if (mem.startsWith(u8, arg, "-femit-zir=")) {
930 emit_zir = .{ .yes = arg["-femit-zir=".len..] };
931 } else if (mem.eql(u8, arg, "-fno-emit-zir")) {
932 emit_zir = .no;
933925 } else if (mem.eql(u8, arg, "-femit-h")) {
934926 emit_h = .yes_default_path;
935927 } else if (mem.startsWith(u8, arg, "-femit-h=")) {
......@@ -1026,7 +1018,7 @@ fn buildOutputType(
10261018 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
10271019 });
10281020 },
1029 .zig, .zir => {
1021 .zig => {
10301022 if (root_src_file) |other| {
10311023 fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });
10321024 } else {
......@@ -1087,7 +1079,7 @@ fn buildOutputType(
10871079 .unknown, .shared_library, .object, .static_library => {
10881080 try link_objects.append(it.only_arg);
10891081 },
1090 .zig, .zir => {
1082 .zig => {
10911083 if (root_src_file) |other| {
10921084 fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
10931085 } else {
......@@ -1725,13 +1717,6 @@ fn buildOutputType(
17251717 var emit_docs_resolved = try emit_docs.resolve("docs");
17261718 defer emit_docs_resolved.deinit();
17271719
1728 switch (emit_zir) {
1729 .no => {},
1730 .yes_default_path, .yes => {
1731 fatal("The -femit-zir implementation has been intentionally deleted so that it can be rewritten as a proper backend.", .{});
1732 },
1733 }
1734
17351720 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
17361721 if (main_pkg_path) |p| {
17371722 const rel_src_path = try fs.path.relative(gpa, p, src_path);
......@@ -1747,6 +1732,7 @@ fn buildOutputType(
17471732 if (root_pkg) |pkg| {
17481733 pkg.table = pkg_tree_root.table;
17491734 pkg_tree_root.table = .{};
1735 pkg.namespace_hash = pkg_tree_root.namespace_hash;
17501736 }
17511737
17521738 const self_exe_path = try fs.selfExePathAlloc(arena);
......@@ -2155,6 +2141,18 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
21552141 }
21562142}
21572143
2144fn freePkgTree(gpa: *Allocator, pkg: *Package, free_parent: bool) void {
2145 {
2146 var it = pkg.table.iterator();
2147 while (it.next()) |kv| {
2148 freePkgTree(gpa, kv.value, true);
2149 }
2150 }
2151 if (free_parent) {
2152 pkg.destroy(gpa);
2153 }
2154}
2155
21582156fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {
21592157 if (!build_options.have_llvm)
21602158 fatal("cannot translate-c: compiler built without LLVM extensions", .{});
......@@ -2509,6 +2507,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
25092507 .handle = try zig_lib_directory.handle.openDir(std_special, .{}),
25102508 },
25112509 .root_src_path = "build_runner.zig",
2510 .namespace_hash = Package.root_namespace_hash,
25122511 };
25132512 defer root_pkg.root_src_directory.handle.close();
25142513
......@@ -2554,8 +2553,9 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
25542553 var build_pkg: Package = .{
25552554 .root_src_directory = build_directory,
25562555 .root_src_path = build_zig_basename,
2556 .namespace_hash = undefined,
25572557 };
2558 try root_pkg.table.put(arena, "@build", &build_pkg);
2558 try root_pkg.addAndAdopt(arena, "@build", &build_pkg);
25592559
25602560 var global_cache_directory: Compilation.Directory = l: {
25612561 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);
src/test.zig+21-42
......@@ -122,11 +122,6 @@ pub const TestContext = struct {
122122 path: []const u8,
123123 };
124124
125 pub const Extension = enum {
126 Zig,
127 ZIR,
128 };
129
130125 /// A `Case` consists of a list of `Update`. The same `Compilation` is used for each
131126 /// update, so each update's source is treated as a single file being
132127 /// updated by the test harness and incrementally compiled.
......@@ -141,7 +136,6 @@ pub const TestContext = struct {
141136 /// to Executable.
142137 output_mode: std.builtin.OutputMode,
143138 updates: std.ArrayList(Update),
144 extension: Extension,
145139 object_format: ?std.builtin.ObjectFormat = null,
146140 emit_h: bool = false,
147141 llvm_backend: bool = false,
......@@ -238,14 +232,12 @@ pub const TestContext = struct {
238232 ctx: *TestContext,
239233 name: []const u8,
240234 target: CrossTarget,
241 extension: Extension,
242235 ) *Case {
243236 ctx.cases.append(Case{
244237 .name = name,
245238 .target = target,
246239 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
247240 .output_mode = .Exe,
248 .extension = extension,
249241 .files = std.ArrayList(File).init(ctx.cases.allocator),
250242 }) catch @panic("out of memory");
251243 return &ctx.cases.items[ctx.cases.items.len - 1];
......@@ -253,7 +245,7 @@ pub const TestContext = struct {
253245
254246 /// Adds a test case for Zig input, producing an executable
255247 pub fn exe(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
256 return ctx.addExe(name, target, .Zig);
248 return ctx.addExe(name, target);
257249 }
258250
259251 /// Adds a test case for ZIR input, producing an executable
......@@ -269,7 +261,6 @@ pub const TestContext = struct {
269261 .target = target,
270262 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
271263 .output_mode = .Exe,
272 .extension = .Zig,
273264 .object_format = .c,
274265 .files = std.ArrayList(File).init(ctx.cases.allocator),
275266 }) catch @panic("out of memory");
......@@ -284,7 +275,6 @@ pub const TestContext = struct {
284275 .target = target,
285276 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
286277 .output_mode = .Exe,
287 .extension = .Zig,
288278 .files = std.ArrayList(File).init(ctx.cases.allocator),
289279 .llvm_backend = true,
290280 }) catch @panic("out of memory");
......@@ -295,14 +285,12 @@ pub const TestContext = struct {
295285 ctx: *TestContext,
296286 name: []const u8,
297287 target: CrossTarget,
298 extension: Extension,
299288 ) *Case {
300289 ctx.cases.append(Case{
301290 .name = name,
302291 .target = target,
303292 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
304293 .output_mode = .Obj,
305 .extension = extension,
306294 .files = std.ArrayList(File).init(ctx.cases.allocator),
307295 }) catch @panic("out of memory");
308296 return &ctx.cases.items[ctx.cases.items.len - 1];
......@@ -310,7 +298,7 @@ pub const TestContext = struct {
310298
311299 /// Adds a test case for Zig input, producing an object file.
312300 pub fn obj(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
313 return ctx.addObj(name, target, .Zig);
301 return ctx.addObj(name, target);
314302 }
315303
316304 /// Adds a test case for ZIR input, producing an object file.
......@@ -319,13 +307,12 @@ pub const TestContext = struct {
319307 }
320308
321309 /// Adds a test case for Zig or ZIR input, producing C code.
322 pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget, ext: Extension) *Case {
310 pub fn addC(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
323311 ctx.cases.append(Case{
324312 .name = name,
325313 .target = target,
326314 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
327315 .output_mode = .Obj,
328 .extension = ext,
329316 .object_format = .c,
330317 .files = std.ArrayList(File).init(ctx.cases.allocator),
331318 }) catch @panic("out of memory");
......@@ -333,21 +320,20 @@ pub const TestContext = struct {
333320 }
334321
335322 pub fn c(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
336 ctx.addC(name, target, .Zig).addCompareObjectFile(src, zig_h ++ out);
323 ctx.addC(name, target).addCompareObjectFile(src, zig_h ++ out);
337324 }
338325
339326 pub fn h(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {
340 ctx.addC(name, target, .Zig).addHeader(src, zig_h ++ out);
327 ctx.addC(name, target).addHeader(src, zig_h ++ out);
341328 }
342329
343330 pub fn addCompareOutput(
344331 ctx: *TestContext,
345332 name: []const u8,
346 extension: Extension,
347333 src: [:0]const u8,
348334 expected_stdout: []const u8,
349335 ) void {
350 ctx.addExe(name, .{}, extension).addCompareOutput(src, expected_stdout);
336 ctx.addExe(name, .{}).addCompareOutput(src, expected_stdout);
351337 }
352338
353339 /// Adds a test case that compiles the Zig source given in `src`, executes
......@@ -358,7 +344,7 @@ pub const TestContext = struct {
358344 src: [:0]const u8,
359345 expected_stdout: []const u8,
360346 ) void {
361 return ctx.addCompareOutput(name, .Zig, src, expected_stdout);
347 return ctx.addCompareOutput(name, src, expected_stdout);
362348 }
363349
364350 /// Adds a test case that compiles the ZIR source given in `src`, executes
......@@ -376,11 +362,10 @@ pub const TestContext = struct {
376362 ctx: *TestContext,
377363 name: []const u8,
378364 target: CrossTarget,
379 extension: Extension,
380365 src: [:0]const u8,
381366 result: [:0]const u8,
382367 ) void {
383 ctx.addObj(name, target, extension).addTransform(src, result);
368 ctx.addObj(name, target).addTransform(src, result);
384369 }
385370
386371 /// Adds a test case that compiles the Zig given in `src` to ZIR and tests
......@@ -392,7 +377,7 @@ pub const TestContext = struct {
392377 src: [:0]const u8,
393378 result: [:0]const u8,
394379 ) void {
395 ctx.addTransform(name, target, .Zig, src, result);
380 ctx.addTransform(name, target, src, result);
396381 }
397382
398383 /// Adds a test case that cleans up the ZIR source given in `src`, and
......@@ -411,11 +396,10 @@ pub const TestContext = struct {
411396 ctx: *TestContext,
412397 name: []const u8,
413398 target: CrossTarget,
414 extension: Extension,
415399 src: [:0]const u8,
416400 expected_errors: []const []const u8,
417401 ) void {
418 ctx.addObj(name, target, extension).addError(src, expected_errors);
402 ctx.addObj(name, target).addError(src, expected_errors);
419403 }
420404
421405 /// Adds a test case that ensures that the Zig given in `src` fails to
......@@ -428,7 +412,7 @@ pub const TestContext = struct {
428412 src: [:0]const u8,
429413 expected_errors: []const []const u8,
430414 ) void {
431 ctx.addError(name, target, .Zig, src, expected_errors);
415 ctx.addError(name, target, src, expected_errors);
432416 }
433417
434418 /// Adds a test case that ensures that the ZIR given in `src` fails to
......@@ -448,10 +432,9 @@ pub const TestContext = struct {
448432 ctx: *TestContext,
449433 name: []const u8,
450434 target: CrossTarget,
451 extension: Extension,
452435 src: [:0]const u8,
453436 ) void {
454 ctx.addObj(name, target, extension).compiles(src);
437 ctx.addObj(name, target).compiles(src);
455438 }
456439
457440 /// Adds a test case that asserts that the Zig given in `src` compiles
......@@ -462,7 +445,7 @@ pub const TestContext = struct {
462445 target: CrossTarget,
463446 src: [:0]const u8,
464447 ) void {
465 ctx.addCompiles(name, target, .Zig, src);
448 ctx.addCompiles(name, target, src);
466449 }
467450
468451 /// Adds a test case that asserts that the ZIR given in `src` compiles
......@@ -489,7 +472,7 @@ pub const TestContext = struct {
489472 expected_errors: []const []const u8,
490473 fixed_src: [:0]const u8,
491474 ) void {
492 var case = ctx.addObj(name, target, .Zig);
475 var case = ctx.addObj(name, target);
493476 case.addError(src, expected_errors);
494477 case.compiles(fixed_src);
495478 }
......@@ -614,15 +597,14 @@ pub const TestContext = struct {
614597 .path = try std.fs.path.join(arena, &[_][]const u8{ tmp_dir_path, "zig-cache" }),
615598 };
616599
617 const tmp_src_path = switch (case.extension) {
618 .Zig => "test_case.zig",
619 .ZIR => "test_case.zir",
620 };
600 const tmp_src_path = "test_case.zig";
621601
622602 var root_pkg: Package = .{
623603 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
624604 .root_src_path = tmp_src_path,
605 .namespace_hash = Package.root_namespace_hash,
625606 };
607 defer root_pkg.table.deinit(allocator);
626608
627609 const bin_name = try std.zig.binNameAlloc(arena, .{
628610 .root_name = "test_case",
......@@ -639,13 +621,10 @@ pub const TestContext = struct {
639621 .directory = emit_directory,
640622 .basename = bin_name,
641623 };
642 const emit_h: ?Compilation.EmitLoc = if (case.emit_h)
643 .{
644 .directory = emit_directory,
645 .basename = "test_case.h",
646 }
647 else
648 null;
624 const emit_h: ?Compilation.EmitLoc = if (case.emit_h) .{
625 .directory = emit_directory,
626 .basename = "test_case.h",
627 } else null;
649628 const comp = try Compilation.create(allocator, .{
650629 .local_cache_directory = zig_cache_directory,
651630 .global_cache_directory = global_cache_directory,
src/zir.zig+43
......@@ -328,6 +328,9 @@ pub const Inst = struct {
328328 error_union_type,
329329 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
330330 error_value,
331 /// Implements the `@export` builtin function.
332 /// Uses the `pl_node` union field. Payload is `Bin`.
333 @"export",
331334 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
332335 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
333336 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
......@@ -360,6 +363,9 @@ pub const Inst = struct {
360363 fn_type_cc,
361364 /// Same as `fn_type_cc` but the function is variadic.
362365 fn_type_cc_var_args,
366 /// Implements the `@hasDecl` builtin.
367 /// Uses the `pl_node` union field. Payload is `Bin`.
368 has_decl,
363369 /// `@import(operand)`.
364370 /// Uses the `un_node` field.
365371 import,
......@@ -668,12 +674,21 @@ pub const Inst = struct {
668674 /// A struct literal with a specified type, with no fields.
669675 /// Uses the `un_node` field.
670676 struct_init_empty,
677 /// Given a struct, union, enum, or opaque and a field name, returns the field type.
678 /// Uses the `pl_node` field. Payload is `FieldType`.
679 field_type,
680 /// Finalizes a typed struct initialization, performs validation, and returns the
681 /// struct value.
682 /// Uses the `pl_node` field. Payload is `StructInit`.
683 struct_init,
671684 /// Converts an integer into an enum value.
672685 /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.
673686 int_to_enum,
674687 /// Converts an enum value into an integer. Resulting type will be the tag type
675688 /// of the enum. Uses `un_node`.
676689 enum_to_int,
690 /// Implements the `@typeInfo` builtin. Uses `un_node`.
691 type_info,
677692
678693 /// Returns whether the instruction is one of the control flow "noreturn" types.
679694 /// Function calls do not count.
......@@ -737,6 +752,7 @@ pub const Inst = struct {
737752 .elem_val_node,
738753 .ensure_result_used,
739754 .ensure_result_non_error,
755 .@"export",
740756 .floatcast,
741757 .field_ptr,
742758 .field_val,
......@@ -746,6 +762,7 @@ pub const Inst = struct {
746762 .fn_type_var_args,
747763 .fn_type_cc,
748764 .fn_type_cc_var_args,
765 .has_decl,
749766 .int,
750767 .float,
751768 .float128,
......@@ -831,8 +848,11 @@ pub const Inst = struct {
831848 .switch_block_ref_under_multi,
832849 .validate_struct_init_ptr,
833850 .struct_init_empty,
851 .struct_init,
852 .field_type,
834853 .int_to_enum,
835854 .enum_to_int,
855 .type_info,
836856 => false,
837857
838858 .@"break",
......@@ -1543,6 +1563,24 @@ pub const Inst = struct {
15431563 return @bitCast(f128, int_bits);
15441564 }
15451565 };
1566
1567 /// Trailing is an item per field.
1568 pub const StructInit = struct {
1569 fields_len: u32,
1570
1571 pub const Item = struct {
1572 /// The `field_type` ZIR instruction for this field init.
1573 field_type: Index,
1574 /// The field init expression to be used as the field value.
1575 init: Ref,
1576 };
1577 };
1578
1579 pub const FieldType = struct {
1580 container_type: Ref,
1581 /// Offset into `string_bytes`, null terminated.
1582 name_start: u32,
1583 };
15461584};
15471585
15481586pub const SpecialProng = enum { none, @"else", under };
......@@ -1617,6 +1655,7 @@ const Writer = struct {
16171655 .typeof_elem,
16181656 .struct_init_empty,
16191657 .enum_to_int,
1658 .type_info,
16201659 => try self.writeUnNode(stream, inst),
16211660
16221661 .ref,
......@@ -1657,6 +1696,8 @@ const Writer = struct {
16571696 .union_decl,
16581697 .enum_decl,
16591698 .enum_decl_nonexhaustive,
1699 .struct_init,
1700 .field_type,
16601701 => try self.writePlNode(stream, inst),
16611702
16621703 .add,
......@@ -1676,12 +1717,14 @@ const Writer = struct {
16761717 .cmp_gt,
16771718 .cmp_neq,
16781719 .div,
1720 .has_decl,
16791721 .mod_rem,
16801722 .shl,
16811723 .shr,
16821724 .xor,
16831725 .store_node,
16841726 .error_union_type,
1727 .@"export",
16851728 .merge_error_sets,
16861729 .bit_and,
16871730 .bit_or,
test/stack_traces.zig+3-3
......@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
282282 \\source.zig:10:8: [address] in main (test)
283283 \\ foo();
284284 \\ ^
285 \\start.zig:342:29: [address] in std.start.posixCallMainAndExit (test)
285 \\start.zig:404:29: [address] in std.start.posixCallMainAndExit (test)
286286 \\ return root.main();
287287 \\ ^
288 \\start.zig:163:5: [address] in std.start._start (test)
288 \\start.zig:225:5: [address] in std.start._start (test)
289289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
290290 \\ ^
291291 \\
......@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
294294 switch (std.Target.current.cpu.arch) {
295295 .aarch64 => "", // TODO disabled; results in segfault
296296 else =>
297 \\start.zig:163:5: [address] in std.start._start (test)
297 \\start.zig:225:5: [address] in std.start._start (test)
298298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
299299 \\ ^
300300 \\
test/stage2/test.zig+78-2
......@@ -941,6 +941,32 @@ pub fn addCases(ctx: *TestContext) !void {
941941 "",
942942 );
943943
944 // Array access to a global array.
945 case.addCompareOutput(
946 \\const hello = "hello".*;
947 \\export fn _start() noreturn {
948 \\ assert(hello[1] == 'e');
949 \\
950 \\ exit();
951 \\}
952 \\
953 \\pub fn assert(ok: bool) void {
954 \\ if (!ok) unreachable; // assertion failure
955 \\}
956 \\
957 \\fn exit() noreturn {
958 \\ asm volatile ("syscall"
959 \\ :
960 \\ : [number] "{rax}" (231),
961 \\ [arg1] "{rdi}" (0)
962 \\ : "rcx", "r11", "memory"
963 \\ );
964 \\ unreachable;
965 \\}
966 ,
967 "",
968 );
969
944970 // 64bit set stack
945971 case.addCompareOutput(
946972 \\export fn _start() noreturn {
......@@ -1022,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {
10221048 "Hello, World!\n",
10231049 );
10241050 try case.files.append(.{
1025 .src =
1051 .src =
10261052 \\pub fn print() void {
10271053 \\ asm volatile ("syscall"
10281054 \\ :
......@@ -1038,11 +1064,61 @@ pub fn addCases(ctx: *TestContext) !void {
10381064 .path = "print.zig",
10391065 });
10401066 }
1067 {
1068 var case = ctx.exe("import private", linux_x64);
1069 case.addError(
1070 \\export fn _start() noreturn {
1071 \\ @import("print.zig").print();
1072 \\ exit();
1073 \\}
1074 \\
1075 \\fn exit() noreturn {
1076 \\ asm volatile ("syscall"
1077 \\ :
1078 \\ : [number] "{rax}" (231),
1079 \\ [arg1] "{rdi}" (@as(usize, 0))
1080 \\ : "rcx", "r11", "memory"
1081 \\ );
1082 \\ unreachable;
1083 \\}
1084 ,
1085 &.{":2:25: error: 'print' is private"},
1086 );
1087 try case.files.append(.{
1088 .src =
1089 \\fn print() void {
1090 \\ asm volatile ("syscall"
1091 \\ :
1092 \\ : [number] "{rax}" (@as(usize, 1)),
1093 \\ [arg1] "{rdi}" (@as(usize, 1)),
1094 \\ [arg2] "{rsi}" (@ptrToInt("Hello, World!\n")),
1095 \\ [arg3] "{rdx}" (@as(usize, 14))
1096 \\ : "rcx", "r11", "memory"
1097 \\ );
1098 \\ return;
1099 \\}
1100 ,
1101 .path = "print.zig",
1102 });
1103 }
10411104
10421105 ctx.compileError("function redefinition", linux_x64,
1106 \\// dummy comment
10431107 \\fn entry() void {}
10441108 \\fn entry() void {}
1045 , &[_][]const u8{":2:4: error: redefinition of 'entry'"});
1109 , &[_][]const u8{
1110 ":3:4: error: redefinition of 'entry'",
1111 ":2:1: note: previous definition here",
1112 });
1113
1114 ctx.compileError("global variable redefinition", linux_x64,
1115 \\// dummy comment
1116 \\var foo = false;
1117 \\var foo = true;
1118 , &[_][]const u8{
1119 ":3:5: error: redefinition of 'foo'",
1120 ":2:1: note: previous definition here",
1121 });
10461122
10471123 ctx.compileError("compileError", linux_x64,
10481124 \\export fn _start() noreturn {