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 @@...@@ -7,7 +7,7 @@
77
8const root = @import("root");8const root = @import("root");
9const std = @import("std.zig");9const std = @import("std.zig");
10const builtin = std.builtin;10const builtin = @import("builtin");
11const assert = std.debug.assert;11const assert = std.debug.assert;
12const uefi = std.os.uefi;12const uefi = std.os.uefi;
13const tlcsprng = @import("crypto/tlcsprng.zig");13const tlcsprng = @import("crypto/tlcsprng.zig");
...@@ -17,39 +17,101 @@ var argc_argv_ptr: [*]usize = undefined;...@@ -17,39 +17,101 @@ var argc_argv_ptr: [*]usize = undefined;
17const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";17const start_sym_name = if (builtin.arch.isMIPS()) "__start" else "_start";
1818
19comptime {19comptime {
20 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {20 // The self-hosted compiler is not fully capable of handling all of this start.zig file.
21 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {21 // Until then, we have simplified logic here for self-hosted. TODO remove this once
22 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });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 }
23 }34 }
24 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {35 } else {
25 if (builtin.link_libc and @hasDecl(root, "main")) {36 if (builtin.output_mode == .Lib and builtin.link_mode == .Dynamic) {
26 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {37 if (builtin.os.tag == .windows and !@hasDecl(root, "_DllMainCRTStartup")) {
27 @export(main, .{ .name = "main", .linkage = .Weak });38 @export(_DllMainCRTStartup, .{ .name = "_DllMainCRTStartup" });
28 }39 }
29 } else if (builtin.os.tag == .windows) {40 } else if (builtin.output_mode == .Exe or @hasDecl(root, "main")) {
30 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and41 if (builtin.link_libc and @hasDecl(root, "main")) {
31 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))42 if (@typeInfo(@TypeOf(root.main)).Fn.calling_convention != .C) {
32 {43 @export(main, .{ .name = "main", .linkage = .Weak });
33 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });44 }
34 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and45 } else if (builtin.os.tag == .windows) {
35 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))46 if (!@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
36 {47 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
37 @compileError("WinMain not supported; declare wWinMain or main instead");48 {
38 } else if (@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup") and49 @export(WinStartup, .{ .name = "wWinMainCRTStartup" });
39 !@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup"))50 } else if (@hasDecl(root, "WinMain") and !@hasDecl(root, "WinMainCRTStartup") and
40 {51 !@hasDecl(root, "wWinMain") and !@hasDecl(root, "wWinMainCRTStartup"))
41 @export(wWinMainCRTStartup, .{ .name = "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 });
42 }65 }
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 });
49 }66 }
50 }67 }
51}68}
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
53fn _DllMainCRTStartup(115fn _DllMainCRTStartup(
54 hinstDLL: std.os.windows.HINSTANCE,116 hinstDLL: std.os.windows.HINSTANCE,
55 fdwReason: std.os.windows.DWORD,117 fdwReason: std.os.windows.DWORD,
lib/std/std.zig+1-1
...@@ -92,7 +92,7 @@ pub const zig = @import("zig.zig");...@@ -92,7 +92,7 @@ pub const zig = @import("zig.zig");
92pub const start = @import("start.zig");92pub const start = @import("start.zig");
9393
94// This forces the start.zig file to be imported, and the comptime logic inside that94// 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.
96comptime {96comptime {
97 _ = start;97 _ = start;
98}98}
lib/std/zig.zig+11-8
...@@ -18,16 +18,19 @@ pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;...@@ -18,16 +18,19 @@ pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
1818
19pub const SrcHash = [16]u8;19pub 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.
23pub fn hashSrc(src: []const u8) SrcHash {21pub fn hashSrc(src: []const u8) SrcHash {
24 var out: SrcHash = undefined;22 var out: SrcHash = undefined;
25 if (src.len <= @typeInfo(SrcHash).Array.len) {23 std.crypto.hash.Blake3.hash(src, &out, .{});
26 std.mem.copy(u8, &out, src);24 return out;
27 std.mem.set(u8, out[src.len..], 0);25}
28 } else {26
29 std.crypto.hash.Blake3.hash(src, &out, .{});27pub fn hashName(parent_hash: SrcHash, sep: []const u8, name: []const u8) SrcHash {
30 }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);
31 return out;34 return out;
32}35}
3336
src/AstGen.zig+61-5
...@@ -823,7 +823,31 @@ pub fn structInitExpr(...@@ -823,7 +823,31 @@ pub fn structInitExpr(
823 .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),823 .none, .none_or_ref => return mod.failNode(scope, node, "TODO implement structInitExpr none", .{}),
824 .ref => unreachable, // struct literal not valid as l-value824 .ref => unreachable, // struct literal not valid as l-value
825 .ty => |ty_inst| {825 .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);
827 },851 },
828 .ptr => |ptr_inst| {852 .ptr => |ptr_inst| {
829 const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len);853 const field_ptr_list = try gpa.alloc(zir.Inst.Index, struct_init.ast.fields.len);
...@@ -1245,6 +1269,7 @@ fn blockExprStmts(...@@ -1245,6 +1269,7 @@ fn blockExprStmts(
1245 .fn_type_var_args,1269 .fn_type_var_args,
1246 .fn_type_cc,1270 .fn_type_cc,
1247 .fn_type_cc_var_args,1271 .fn_type_cc_var_args,
1272 .has_decl,
1248 .int,1273 .int,
1249 .float,1274 .float,
1250 .float128,1275 .float128,
...@@ -1320,6 +1345,8 @@ fn blockExprStmts(...@@ -1320,6 +1345,8 @@ fn blockExprStmts(
1320 .switch_capture_else,1345 .switch_capture_else,
1321 .switch_capture_else_ref,1346 .switch_capture_else_ref,
1322 .struct_init_empty,1347 .struct_init_empty,
1348 .struct_init,
1349 .field_type,
1323 .struct_decl,1350 .struct_decl,
1324 .struct_decl_packed,1351 .struct_decl_packed,
1325 .struct_decl_extern,1352 .struct_decl_extern,
...@@ -1329,6 +1356,7 @@ fn blockExprStmts(...@@ -1329,6 +1356,7 @@ fn blockExprStmts(
1329 .opaque_decl,1356 .opaque_decl,
1330 .int_to_enum,1357 .int_to_enum,
1331 .enum_to_int,1358 .enum_to_int,
1359 .type_info,
1332 => break :b false,1360 => break :b false,
13331361
1334 // ZIR instructions that are always either `noreturn` or `void`.1362 // ZIR instructions that are always either `noreturn` or `void`.
...@@ -1336,6 +1364,7 @@ fn blockExprStmts(...@@ -1336,6 +1364,7 @@ fn blockExprStmts(
1336 .dbg_stmt_node,1364 .dbg_stmt_node,
1337 .ensure_result_used,1365 .ensure_result_used,
1338 .ensure_result_non_error,1366 .ensure_result_non_error,
1367 .@"export",
1339 .set_eval_branch_quota,1368 .set_eval_branch_quota,
1340 .compile_log,1369 .compile_log,
1341 .ensure_err_payload_void,1370 .ensure_err_payload_void,
...@@ -2347,7 +2376,7 @@ fn arrayAccess(...@@ -2347,7 +2376,7 @@ fn arrayAccess(
2347 ),2376 ),
2348 else => return rvalue(gz, scope, rl, try gz.addBin(2377 else => return rvalue(gz, scope, rl, try gz.addBin(
2349 .elem_val,2378 .elem_val,
2350 try expr(gz, scope, .none, node_datas[node].lhs),2379 try expr(gz, scope, .none_or_ref, node_datas[node].lhs),
2351 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),2380 try expr(gz, scope, .{ .ty = .usize_type }, node_datas[node].rhs),
2352 ), node),2381 ), node),
2353 }2382 }
...@@ -4146,6 +4175,36 @@ fn builtinCall(...@@ -4146,6 +4175,36 @@ fn builtinCall(
4146 return rvalue(gz, scope, rl, result, node);4175 return rvalue(gz, scope, rl, result, node);
4147 },4176 },
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
4149 .add_with_overflow,4208 .add_with_overflow,
4150 .align_cast,4209 .align_cast,
4151 .align_of,4210 .align_of,
...@@ -4175,11 +4234,9 @@ fn builtinCall(...@@ -4175,11 +4234,9 @@ fn builtinCall(
4175 .error_name,4234 .error_name,
4176 .error_return_trace,4235 .error_return_trace,
4177 .err_set_cast,4236 .err_set_cast,
4178 .@"export",
4179 .fence,4237 .fence,
4180 .field_parent_ptr,4238 .field_parent_ptr,
4181 .float_to_int,4239 .float_to_int,
4182 .has_decl,
4183 .has_field,4240 .has_field,
4184 .int_to_float,4241 .int_to_float,
4185 .int_to_ptr,4242 .int_to_ptr,
...@@ -4224,7 +4281,6 @@ fn builtinCall(...@@ -4224,7 +4281,6 @@ fn builtinCall(
4224 .This,4281 .This,
4225 .truncate,4282 .truncate,
4226 .Type,4283 .Type,
4227 .type_info,
4228 .type_name,4284 .type_name,
4229 .union_init,4285 .union_init,
4230 => return mod.failNode(scope, node, "TODO: implement builtin function {s}", .{4286 => 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 {...@@ -932,38 +932,56 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
932 artifact_sub_dir,932 artifact_sub_dir,
933 };933 };
934934
935 // TODO when we implement serialization and deserialization of incremental compilation metadata,935 // If we rely on stage1, we must not redundantly add these packages.
936 // this is where we would load it. We have open a handle to the directory where936 const use_stage1 = build_options.is_stage1 and use_llvm;
937 // the output either already is, or will be.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.
938 // However we currently do not have serialization of such metadata, so for now965 // However we currently do not have serialization of such metadata, so for now
939 // we set up an empty Module that does the entire compilation fresh.966 // we set up an empty Module that does the entire compilation fresh.
940967
941 const root_scope = rs: {968 const root_scope = try gpa.create(Module.Scope.File);
942 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {969 errdefer gpa.destroy(root_scope);
943 const root_scope = try gpa.create(Module.Scope.File);970
944 const struct_ty = try Type.Tag.empty_struct.create(971 const struct_ty = try Type.Tag.empty_struct.create(gpa, &root_scope.root_container);
945 gpa,972 root_scope.* = .{
946 &root_scope.root_container,973 // TODO this is duped so it can be freed in Container.deinit
947 );974 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),
948 root_scope.* = .{975 .source = .{ .unloaded = {} },
949 // TODO this is duped so it can be freed in Container.deinit976 .tree = undefined,
950 .sub_file_path = try gpa.dupe(u8, root_pkg.root_src_path),977 .status = .never_loaded,
951 .source = .{ .unloaded = {} },978 .pkg = root_pkg,
952 .tree = undefined,979 .root_container = .{
953 .status = .never_loaded,980 .file_scope = root_scope,
954 .pkg = root_pkg,981 .decls = .{},
955 .root_container = .{982 .ty = struct_ty,
956 .file_scope = root_scope,983 .parent_name_hash = root_pkg.namespace_hash,
957 .decls = .{},984 },
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 }
967 };985 };
968986
969 const module = try arena.create(Module);987 const module = try arena.create(Module);
...@@ -1365,7 +1383,8 @@ pub fn update(self: *Compilation) !void {...@@ -1365,7 +1383,8 @@ pub fn update(self: *Compilation) !void {
1365 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);1383 self.c_object_work_queue.writeItemAssumeCapacity(entry.key);
1366 }1384 }
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);
1369 if (!use_stage1) {1388 if (!use_stage1) {
1370 if (self.bin_file.options.module) |module| {1389 if (self.bin_file.options.module) |module| {
1371 module.compile_log_text.shrinkAndFree(module.gpa, 0);1390 module.compile_log_text.shrinkAndFree(module.gpa, 0);
...@@ -2490,7 +2509,7 @@ pub fn addCCArgs(...@@ -2490,7 +2509,7 @@ pub fn addCCArgs(
2490 try argv.append("-fPIC");2509 try argv.append("-fPIC");
2491 }2510 }
2492 },2511 },
2493 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig, .zir => {},2512 .shared_library, .assembly, .ll, .bc, .unknown, .static_library, .object, .zig => {},
2494 }2513 }
2495 if (out_dep_path) |p| {2514 if (out_dep_path) |p| {
2496 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });2515 try argv.appendSlice(&[_][]const u8{ "-MD", "-MV", "-MF", p });
...@@ -2564,7 +2583,6 @@ pub const FileExt = enum {...@@ -2564,7 +2583,6 @@ pub const FileExt = enum {
2564 object,2583 object,
2565 static_library,2584 static_library,
2566 zig,2585 zig,
2567 zir,
2568 unknown,2586 unknown,
25692587
2570 pub fn clangSupportsDepFile(ext: FileExt) bool {2588 pub fn clangSupportsDepFile(ext: FileExt) bool {
...@@ -2578,7 +2596,6 @@ pub const FileExt = enum {...@@ -2578,7 +2596,6 @@ pub const FileExt = enum {
2578 .object,2596 .object,
2579 .static_library,2597 .static_library,
2580 .zig,2598 .zig,
2581 .zir,
2582 .unknown,2599 .unknown,
2583 => false,2600 => false,
2584 };2601 };
...@@ -2650,8 +2667,6 @@ pub fn classifyFileExt(filename: []const u8) FileExt {...@@ -2650,8 +2667,6 @@ pub fn classifyFileExt(filename: []const u8) FileExt {
2650 return .h;2667 return .h;
2651 } else if (mem.endsWith(u8, filename, ".zig")) {2668 } else if (mem.endsWith(u8, filename, ".zig")) {
2652 return .zig;2669 return .zig;
2653 } else if (mem.endsWith(u8, filename, ".zir")) {
2654 return .zir;
2655 } else if (hasSharedLibraryExt(filename)) {2670 } else if (hasSharedLibraryExt(filename)) {
2656 return .shared_library;2671 return .shared_library;
2657 } else if (hasStaticLibraryExt(filename)) {2672 } else if (hasStaticLibraryExt(filename)) {
...@@ -2672,7 +2687,6 @@ test "classifyFileExt" {...@@ -2672,7 +2687,6 @@ test "classifyFileExt" {
2672 std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3"));2687 std.testing.expectEqual(FileExt.shared_library, classifyFileExt("foo.so.1.2.3"));
2673 std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));2688 std.testing.expectEqual(FileExt.unknown, classifyFileExt("foo.so.1.2.3~"));
2674 std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));2689 std.testing.expectEqual(FileExt.zig, classifyFileExt("foo.zig"));
2675 std.testing.expectEqual(FileExt.zir, classifyFileExt("foo.zir"));
2676}2690}
26772691
2678fn haveFramePointer(comp: *const Compilation) bool {2692fn haveFramePointer(comp: *const Compilation) bool {
...@@ -2867,6 +2881,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8...@@ -2867,6 +2881,8 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
28672881
2868 const target = comp.getTarget();2882 const target = comp.getTarget();
2869 const generic_arch_name = target.cpu.arch.genericName();2883 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
2871 @setEvalBranchQuota(4000);2887 @setEvalBranchQuota(4000);
2872 try buffer.writer().print(2888 try buffer.writer().print(
...@@ -2879,6 +2895,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8...@@ -2879,6 +2895,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
2879 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer2895 \\/// Zig version. When writing code that supports multiple versions of Zig, prefer
2880 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.2896 \\/// feature detection (i.e. with `@hasDecl` or `@hasField`) over version checks.
2881 \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}");2897 \\pub const zig_version = try @import("std").SemanticVersion.parse("{s}");
2898 \\pub const zig_is_stage2 = {};
2882 \\2899 \\
2883 \\pub const output_mode = OutputMode.{};2900 \\pub const output_mode = OutputMode.{};
2884 \\pub const link_mode = LinkMode.{};2901 \\pub const link_mode = LinkMode.{};
...@@ -2892,6 +2909,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8...@@ -2892,6 +2909,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
2892 \\2909 \\
2893 , .{2910 , .{
2894 build_options.version,2911 build_options.version,
2912 !use_stage1,
2895 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),2913 std.zig.fmtId(@tagName(comp.bin_file.options.output_mode)),
2896 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),2914 std.zig.fmtId(@tagName(comp.bin_file.options.link_mode)),
2897 comp.bin_file.options.is_test,2915 comp.bin_file.options.is_test,
...@@ -3101,6 +3119,7 @@ fn buildOutputFromZig(...@@ -3101,6 +3119,7 @@ fn buildOutputFromZig(
3101 .handle = special_dir,3119 .handle = special_dir,
3102 },3120 },
3103 .root_src_path = src_basename,3121 .root_src_path = src_basename,
3122 .namespace_hash = Package.root_namespace_hash,
3104 };3123 };
3105 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];3124 const root_name = src_basename[0 .. src_basename.len - std.fs.path.extension(src_basename).len];
3106 const target = comp.getTarget();3125 const target = comp.getTarget();
src/Module.zig+68-90
...@@ -150,9 +150,15 @@ pub const Decl = struct {...@@ -150,9 +150,15 @@ pub const Decl = struct {
150 /// The direct parent container of the Decl.150 /// The direct parent container of the Decl.
151 /// Reference to externally owned memory.151 /// Reference to externally owned memory.
152 container: *Scope.Container,152 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.
154 /// Must be recomputed when the corresponding source file is modified.159 /// Must be recomputed when the corresponding source file is modified.
155 src_index: usize,160 src_node: ast.Node.Index,
161
156 /// The most recent value of the Decl after a successful semantic analysis.162 /// The most recent value of the Decl after a successful semantic analysis.
157 typed_value: union(enum) {163 typed_value: union(enum) {
158 never_succeeded: void,164 never_succeeded: void,
...@@ -198,11 +204,6 @@ pub const Decl = struct {...@@ -198,11 +204,6 @@ pub const Decl = struct {
198 /// Whether the corresponding AST decl has a `pub` keyword.204 /// Whether the corresponding AST decl has a `pub` keyword.
199 is_pub: bool,205 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
206 /// Represents the position of the code in the output file.207 /// Represents the position of the code in the output file.
207 /// This is populated regardless of semantic analysis and code generation.208 /// This is populated regardless of semantic analysis and code generation.
208 link: link.File.LinkBlock,209 link: link.File.LinkBlock,
...@@ -249,11 +250,11 @@ pub const Decl = struct {...@@ -249,11 +250,11 @@ pub const Decl = struct {
249 }250 }
250251
251 pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index {252 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));
253 }254 }
254255
255 pub fn nodeIndexToRelative(decl: Decl, node_index: ast.Node.Index) i32 {256 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);
257 }258 }
258259
259 pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc {260 pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc {
...@@ -271,14 +272,9 @@ pub const Decl = struct {...@@ -271,14 +272,9 @@ pub const Decl = struct {
271 };272 };
272 }273 }
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
279 pub fn srcToken(decl: Decl) u32 {275 pub fn srcToken(decl: Decl) u32 {
280 const tree = &decl.container.file_scope.tree;276 const tree = &decl.container.file_scope.tree;
281 return tree.firstToken(decl.srcNode());277 return tree.firstToken(decl.src_node);
282 }278 }
283279
284 pub fn srcByteOffset(decl: Decl) u32 {280 pub fn srcByteOffset(decl: Decl) u32 {
...@@ -678,6 +674,7 @@ pub const Scope = struct {...@@ -678,6 +674,7 @@ pub const Scope = struct {
678 base: Scope = Scope{ .tag = base_tag },674 base: Scope = Scope{ .tag = base_tag },
679675
680 file_scope: *Scope.File,676 file_scope: *Scope.File,
677 parent_name_hash: NameHash,
681678
682 /// Direct children of the file.679 /// Direct children of the file.
683 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},680 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
...@@ -696,8 +693,7 @@ pub const Scope = struct {...@@ -696,8 +693,7 @@ pub const Scope = struct {
696 }693 }
697694
698 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {695 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {
699 // TODO container scope qualified names.696 return std.zig.hashName(cont.parent_name_hash, ".", name);
700 return std.zig.hashSrc(name);
701 }697 }
702698
703 pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void {699 pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void {
...@@ -2296,6 +2292,20 @@ pub const InnerError = error{ OutOfMemory, AnalysisFail };...@@ -2296,6 +2292,20 @@ pub const InnerError = error{ OutOfMemory, AnalysisFail };
2296pub fn deinit(mod: *Module) void {2292pub fn deinit(mod: *Module) void {
2297 const gpa = mod.gpa;2293 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
2299 mod.compile_log_text.deinit(gpa);2309 mod.compile_log_text.deinit(gpa);
23002310
2301 mod.zig_cache_artifact_directory.handle.close();2311 mod.zig_cache_artifact_directory.handle.close();
...@@ -2458,7 +2468,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2458,7 +2468,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
2458 const tree = try mod.getAstTree(decl.container.file_scope);2468 const tree = try mod.getAstTree(decl.container.file_scope);
2459 const node_tags = tree.nodes.items(.tag);2469 const node_tags = tree.nodes.items(.tag);
2460 const node_datas = tree.nodes.items(.data);2470 const node_datas = tree.nodes.items(.data);
2461 const decl_node = tree.rootDecls()[decl.src_index];2471 const decl_node = decl.src_node;
2462 switch (node_tags[decl_node]) {2472 switch (node_tags[decl_node]) {
2463 .fn_decl => {2473 .fn_decl => {
2464 const fn_proto = node_datas[decl_node].lhs;2474 const fn_proto = node_datas[decl_node].lhs;
...@@ -2513,6 +2523,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -2513,6 +2523,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
25132523
2514 const block_expr = node_datas[decl_node].lhs;2524 const block_expr = node_datas[decl_node].lhs;
2515 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);2525 _ = try AstGen.comptimeExpr(&gen_scope, &gen_scope.base, .none, block_expr);
2526 _ = try gen_scope.addBreak(.break_inline, 0, .void_value);
25162527
2517 const code = try gen_scope.finish();2528 const code = try gen_scope.finish();
2518 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {2529 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
...@@ -3294,7 +3305,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3294,7 +3305,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3294 var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa);3305 var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa);
3295 defer outdated_decls.deinit();3306 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]) {
3298 .fn_decl => {3309 .fn_decl => {
3299 const fn_proto = node_datas[decl_node].lhs;3310 const fn_proto = node_datas[decl_node].lhs;
3300 const body = node_datas[decl_node].rhs;3311 const body = node_datas[decl_node].rhs;
...@@ -3306,7 +3317,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3306,7 +3317,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3306 &deleted_decls,3317 &deleted_decls,
3307 &outdated_decls,3318 &outdated_decls,
3308 decl_node,3319 decl_node,
3309 decl_i,
3310 tree.*,3320 tree.*,
3311 body,3321 body,
3312 tree.fnProtoSimple(&params, fn_proto),3322 tree.fnProtoSimple(&params, fn_proto),
...@@ -3317,7 +3327,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3317,7 +3327,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3317 &deleted_decls,3327 &deleted_decls,
3318 &outdated_decls,3328 &outdated_decls,
3319 decl_node,3329 decl_node,
3320 decl_i,
3321 tree.*,3330 tree.*,
3322 body,3331 body,
3323 tree.fnProtoMulti(fn_proto),3332 tree.fnProtoMulti(fn_proto),
...@@ -3329,7 +3338,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3329,7 +3338,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3329 &deleted_decls,3338 &deleted_decls,
3330 &outdated_decls,3339 &outdated_decls,
3331 decl_node,3340 decl_node,
3332 decl_i,
3333 tree.*,3341 tree.*,
3334 body,3342 body,
3335 tree.fnProtoOne(&params, fn_proto),3343 tree.fnProtoOne(&params, fn_proto),
...@@ -3340,7 +3348,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3340,7 +3348,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3340 &deleted_decls,3348 &deleted_decls,
3341 &outdated_decls,3349 &outdated_decls,
3342 decl_node,3350 decl_node,
3343 decl_i,
3344 tree.*,3351 tree.*,
3345 body,3352 body,
3346 tree.fnProto(fn_proto),3353 tree.fnProto(fn_proto),
...@@ -3355,7 +3362,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3355,7 +3362,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3355 &deleted_decls,3362 &deleted_decls,
3356 &outdated_decls,3363 &outdated_decls,
3357 decl_node,3364 decl_node,
3358 decl_i,
3359 tree.*,3365 tree.*,
3360 0,3366 0,
3361 tree.fnProtoSimple(&params, decl_node),3367 tree.fnProtoSimple(&params, decl_node),
...@@ -3366,7 +3372,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3366,7 +3372,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3366 &deleted_decls,3372 &deleted_decls,
3367 &outdated_decls,3373 &outdated_decls,
3368 decl_node,3374 decl_node,
3369 decl_i,
3370 tree.*,3375 tree.*,
3371 0,3376 0,
3372 tree.fnProtoMulti(decl_node),3377 tree.fnProtoMulti(decl_node),
...@@ -3378,7 +3383,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3378,7 +3383,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3378 &deleted_decls,3383 &deleted_decls,
3379 &outdated_decls,3384 &outdated_decls,
3380 decl_node,3385 decl_node,
3381 decl_i,
3382 tree.*,3386 tree.*,
3383 0,3387 0,
3384 tree.fnProtoOne(&params, decl_node),3388 tree.fnProtoOne(&params, decl_node),
...@@ -3389,7 +3393,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3389,7 +3393,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3389 &deleted_decls,3393 &deleted_decls,
3390 &outdated_decls,3394 &outdated_decls,
3391 decl_node,3395 decl_node,
3392 decl_i,
3393 tree.*,3396 tree.*,
3394 0,3397 0,
3395 tree.fnProto(decl_node),3398 tree.fnProto(decl_node),
...@@ -3400,7 +3403,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3400,7 +3403,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3400 &deleted_decls,3403 &deleted_decls,
3401 &outdated_decls,3404 &outdated_decls,
3402 decl_node,3405 decl_node,
3403 decl_i,
3404 tree.*,3406 tree.*,
3405 tree.globalVarDecl(decl_node),3407 tree.globalVarDecl(decl_node),
3406 ),3408 ),
...@@ -3409,7 +3411,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3409,7 +3411,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3409 &deleted_decls,3411 &deleted_decls,
3410 &outdated_decls,3412 &outdated_decls,
3411 decl_node,3413 decl_node,
3412 decl_i,
3413 tree.*,3414 tree.*,
3414 tree.localVarDecl(decl_node),3415 tree.localVarDecl(decl_node),
3415 ),3416 ),
...@@ -3418,7 +3419,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3418,7 +3419,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3418 &deleted_decls,3419 &deleted_decls,
3419 &outdated_decls,3420 &outdated_decls,
3420 decl_node,3421 decl_node,
3421 decl_i,
3422 tree.*,3422 tree.*,
3423 tree.simpleVarDecl(decl_node),3423 tree.simpleVarDecl(decl_node),
3424 ),3424 ),
...@@ -3427,7 +3427,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3427,7 +3427,6 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3427 &deleted_decls,3427 &deleted_decls,
3428 &outdated_decls,3428 &outdated_decls,
3429 decl_node,3429 decl_node,
3430 decl_i,
3431 tree.*,3430 tree.*,
3432 tree.alignedVarDecl(decl_node),3431 tree.alignedVarDecl(decl_node),
3433 ),3432 ),
...@@ -3440,38 +3439,21 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {...@@ -3440,38 +3439,21 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void {
3440 const name_hash = container_scope.fullyQualifiedNameHash(name);3439 const name_hash = container_scope.fullyQualifiedNameHash(name);
3441 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));3440 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);
3444 container_scope.decls.putAssumeCapacity(new_decl, {});3443 container_scope.decls.putAssumeCapacity(new_decl, {});
3445 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });3444 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
3446 },3445 },
34473446
3448 .container_field_init => try mod.semaContainerField(3447 // Container fields are handled in AstGen.
3449 container_scope,3448 .container_field_init,
3450 &deleted_decls,3449 .container_field_align,
3451 decl_node,3450 .container_field,
3452 decl_i,3451 => continue,
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 ),
34723452
3473 .test_decl => {3453 .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 }
3475 },3457 },
3476 .@"usingnamespace" => {3458 .@"usingnamespace" => {
3477 log.err("TODO: analyze usingnamespace decl", .{});3459 log.err("TODO: analyze usingnamespace decl", .{});
...@@ -3508,7 +3490,6 @@ fn semaContainerFn(...@@ -3508,7 +3490,6 @@ fn semaContainerFn(
3508 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3490 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3509 outdated_decls: *std.AutoArrayHashMap(*Decl, void),3491 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
3510 decl_node: ast.Node.Index,3492 decl_node: ast.Node.Index,
3511 decl_i: usize,
3512 tree: ast.Tree,3493 tree: ast.Tree,
3513 body_node: ast.Node.Index,3494 body_node: ast.Node.Index,
3514 fn_proto: ast.full.FnProto,3495 fn_proto: ast.full.FnProto,
...@@ -3517,24 +3498,30 @@ fn semaContainerFn(...@@ -3517,24 +3498,30 @@ fn semaContainerFn(
3517 defer tracy.end();3498 defer tracy.end();
35183499
3519 // We will create a Decl for it regardless of analysis status.3500 // 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 {
3521 // This problem will go away with #1717.3502 // This problem will go away with #1717.
3522 @panic("TODO missing function name");3503 @panic("TODO missing function name");
3523 };3504 };
3524 const name = tree.tokenSlice(name_tok); // TODO use identifierTokenString3505 const name = tree.tokenSlice(name_token); // TODO use identifierTokenString
3525 const name_hash = container_scope.fullyQualifiedNameHash(name);3506 const name_hash = container_scope.fullyQualifiedNameHash(name);
3526 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));3507 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
3527 if (mod.decl_table.get(name_hash)) |decl| {3508 if (mod.decl_table.get(name_hash)) |decl| {
3528 // Update the AST Node index of the decl, even if its contents are unchanged, it may3509 // Update the AST Node index of the decl, even if its contents are unchanged, it may
3529 // have been re-ordered.3510 // have been re-ordered.
3530 decl.src_index = decl_i;3511 const prev_src_node = decl.src_node;
3512 decl.src_node = decl_node;
3531 if (deleted_decls.swapRemove(decl) == null) {3513 if (deleted_decls.swapRemove(decl) == null) {
3532 decl.analysis = .sema_failure;3514 decl.analysis = .sema_failure;
3533 const msg = try ErrorMsg.create(mod.gpa, .{3515 const msg = try ErrorMsg.create(mod.gpa, .{
3534 .container = .{ .file_scope = container_scope.file_scope },3516 .container = .{ .file_scope = container_scope.file_scope },
3535 .lazy = .{ .token_abs = name_tok },3517 .lazy = .{ .token_abs = name_token },
3536 }, "redefinition of '{s}'", .{decl.name});3518 }, "redefinition of '{s}'", .{decl.name});
3537 errdefer msg.destroy(mod.gpa);3519 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", .{});
3538 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);3525 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
3539 } else {3526 } else {
3540 if (!srcHashEql(decl.contents_hash, contents_hash)) {3527 if (!srcHashEql(decl.contents_hash, contents_hash)) {
...@@ -3558,7 +3545,7 @@ fn semaContainerFn(...@@ -3558,7 +3545,7 @@ fn semaContainerFn(
3558 }3545 }
3559 }3546 }
3560 } else {3547 } 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);
3562 container_scope.decls.putAssumeCapacity(new_decl, {});3549 container_scope.decls.putAssumeCapacity(new_decl, {});
3563 if (fn_proto.extern_export_token) |maybe_export_token| {3550 if (fn_proto.extern_export_token) |maybe_export_token| {
3564 const token_tags = tree.tokens.items(.tag);3551 const token_tags = tree.tokens.items(.tag);
...@@ -3566,6 +3553,7 @@ fn semaContainerFn(...@@ -3566,6 +3553,7 @@ fn semaContainerFn(
3566 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });3553 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
3567 }3554 }
3568 }3555 }
3556 new_decl.is_pub = fn_proto.visib_token != null;
3569 }3557 }
3570}3558}
35713559
...@@ -3575,7 +3563,6 @@ fn semaContainerVar(...@@ -3575,7 +3563,6 @@ fn semaContainerVar(
3575 deleted_decls: *std.AutoArrayHashMap(*Decl, void),3563 deleted_decls: *std.AutoArrayHashMap(*Decl, void),
3576 outdated_decls: *std.AutoArrayHashMap(*Decl, void),3564 outdated_decls: *std.AutoArrayHashMap(*Decl, void),
3577 decl_node: ast.Node.Index,3565 decl_node: ast.Node.Index,
3578 decl_i: usize,
3579 tree: ast.Tree,3566 tree: ast.Tree,
3580 var_decl: ast.full.VarDecl,3567 var_decl: ast.full.VarDecl,
3581) !void {3568) !void {
...@@ -3589,21 +3576,27 @@ fn semaContainerVar(...@@ -3589,21 +3576,27 @@ fn semaContainerVar(
3589 if (mod.decl_table.get(name_hash)) |decl| {3576 if (mod.decl_table.get(name_hash)) |decl| {
3590 // Update the AST Node index of the decl, even if its contents are unchanged, it may3577 // Update the AST Node index of the decl, even if its contents are unchanged, it may
3591 // have been re-ordered.3578 // have been re-ordered.
3592 decl.src_index = decl_i;3579 const prev_src_node = decl.src_node;
3580 decl.src_node = decl_node;
3593 if (deleted_decls.swapRemove(decl) == null) {3581 if (deleted_decls.swapRemove(decl) == null) {
3594 decl.analysis = .sema_failure;3582 decl.analysis = .sema_failure;
3595 const err_msg = try ErrorMsg.create(mod.gpa, .{3583 const msg = try ErrorMsg.create(mod.gpa, .{
3596 .container = .{ .file_scope = container_scope.file_scope },3584 .container = .{ .file_scope = container_scope.file_scope },
3597 .lazy = .{ .token_abs = name_token },3585 .lazy = .{ .token_abs = name_token },
3598 }, "redefinition of '{s}'", .{decl.name});3586 }, "redefinition of '{s}'", .{decl.name});
3599 errdefer err_msg.destroy(mod.gpa);3587 errdefer msg.destroy(mod.gpa);
3600 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);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);
3601 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {3594 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
3602 try outdated_decls.put(decl, {});3595 try outdated_decls.put(decl, {});
3603 decl.contents_hash = contents_hash;3596 decl.contents_hash = contents_hash;
3604 }3597 }
3605 } else {3598 } 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);
3607 container_scope.decls.putAssumeCapacity(new_decl, {});3600 container_scope.decls.putAssumeCapacity(new_decl, {});
3608 if (var_decl.extern_export_token) |maybe_export_token| {3601 if (var_decl.extern_export_token) |maybe_export_token| {
3609 const token_tags = tree.tokens.items(.tag);3602 const token_tags = tree.tokens.items(.tag);
...@@ -3614,21 +3607,6 @@ fn semaContainerVar(...@@ -3614,21 +3607,6 @@ fn semaContainerVar(
3614 }3607 }
3615}3608}
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
3632pub fn deleteDecl(3610pub fn deleteDecl(
3633 mod: *Module,3611 mod: *Module,
3634 decl: *Decl,3612 decl: *Decl,
...@@ -3811,7 +3789,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {...@@ -3811,7 +3789,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
3811fn allocateNewDecl(3789fn allocateNewDecl(
3812 mod: *Module,3790 mod: *Module,
3813 scope: *Scope,3791 scope: *Scope,
3814 src_index: usize,3792 src_node: ast.Node.Index,
3815 contents_hash: std.zig.SrcHash,3793 contents_hash: std.zig.SrcHash,
3816) !*Decl {3794) !*Decl {
3817 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.3795 // If we have emit-h then we must allocate a bigger structure to store the emit-h state.
...@@ -3827,7 +3805,7 @@ fn allocateNewDecl(...@@ -3827,7 +3805,7 @@ fn allocateNewDecl(
3827 new_decl.* = .{3805 new_decl.* = .{
3828 .name = "",3806 .name = "",
3829 .container = scope.namespace(),3807 .container = scope.namespace(),
3830 .src_index = src_index,3808 .src_node = src_node,
3831 .typed_value = .{ .never_succeeded = {} },3809 .typed_value = .{ .never_succeeded = {} },
3832 .analysis = .unreferenced,3810 .analysis = .unreferenced,
3833 .deletion_flag = false,3811 .deletion_flag = false,
...@@ -3858,12 +3836,12 @@ fn createNewDecl(...@@ -3858,12 +3836,12 @@ fn createNewDecl(
3858 mod: *Module,3836 mod: *Module,
3859 scope: *Scope,3837 scope: *Scope,
3860 decl_name: []const u8,3838 decl_name: []const u8,
3861 src_index: usize,3839 src_node: ast.Node.Index,
3862 name_hash: Scope.NameHash,3840 name_hash: Scope.NameHash,
3863 contents_hash: std.zig.SrcHash,3841 contents_hash: std.zig.SrcHash,
3864) !*Decl {3842) !*Decl {
3865 try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1);3843 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);
3867 errdefer mod.gpa.destroy(new_decl);3845 errdefer mod.gpa.destroy(new_decl);
3868 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);3846 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);
3869 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);3847 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
...@@ -4076,7 +4054,7 @@ pub fn createAnonymousDecl(...@@ -4076,7 +4054,7 @@ pub fn createAnonymousDecl(
4076 defer mod.gpa.free(name);4054 defer mod.gpa.free(name);
4077 const name_hash = scope.namespace().fullyQualifiedNameHash(name);4055 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
4078 const src_hash: std.zig.SrcHash = undefined;4056 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);
4080 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);4058 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
40814059
4082 decl_arena_state.* = decl_arena.state;4060 decl_arena_state.* = decl_arena.state;
...@@ -4112,7 +4090,7 @@ pub fn createContainerDecl(...@@ -4112,7 +4090,7 @@ pub fn createContainerDecl(
4112 defer mod.gpa.free(name);4090 defer mod.gpa.free(name);
4113 const name_hash = scope.namespace().fullyQualifiedNameHash(name);4091 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
4114 const src_hash: std.zig.SrcHash = undefined;4092 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);
4116 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);4094 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
41174095
4118 decl_arena_state.* = decl_arena.state;4096 decl_arena_state.* = decl_arena.state;
src/Package.zig+68-8
...@@ -4,18 +4,29 @@ const std = @import("std");...@@ -4,18 +4,29 @@ const std = @import("std");
4const fs = std.fs;4const fs = std.fs;
5const mem = std.mem;5const mem = std.mem;
6const Allocator = mem.Allocator;6const Allocator = mem.Allocator;
7const assert = std.debug.assert;
78
8const Compilation = @import("Compilation.zig");9const Compilation = @import("Compilation.zig");
10const Module = @import("Module.zig");
911
10pub const Table = std.StringHashMapUnmanaged(*Package);12pub 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
12root_src_directory: Compilation.Directory,19root_src_directory: Compilation.Directory,
13/// Relative to `root_src_directory`. May contain path separators.20/// Relative to `root_src_directory`. May contain path separators.
14root_src_path: []const u8,21root_src_path: []const u8,
15table: Table = .{},22table: Table = .{},
16parent: ?*Package = null,23parent: ?*Package = null,
24namespace_hash: Module.Scope.NameHash,
25/// Whether to free `root_src_directory` on `destroy`.
26root_src_directory_owned: bool = false,
1727
18/// Allocate a Package. No references to the slices passed are kept.28/// Allocate a Package. No references to the slices passed are kept.
29/// Don't forget to set `namespace_hash` later.
19pub fn create(30pub fn create(
20 gpa: *Allocator,31 gpa: *Allocator,
21 /// Null indicates the current working directory32 /// Null indicates the current working directory
...@@ -38,27 +49,69 @@ pub fn create(...@@ -38,27 +49,69 @@ pub fn create(
38 .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(),49 .handle = if (owned_dir_path) |p| try fs.cwd().openDir(p, .{}) else fs.cwd(),
39 },50 },
40 .root_src_path = owned_src_path,51 .root_src_path = owned_src_path,
52 .root_src_directory_owned = true,
53 .namespace_hash = undefined,
41 };54 };
4255
43 return ptr;56 return ptr;
44}57}
4558
46/// Free all memory associated with this package and recursively call destroy59pub fn createWithDir(
47/// on all packages in its table60 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.
48pub fn destroy(pkg: *Package, gpa: *Allocator) void {100pub fn destroy(pkg: *Package, gpa: *Allocator) void {
49 gpa.free(pkg.root_src_path);101 gpa.free(pkg.root_src_path);
50102
51 // If root_src_directory.path is null then the handle is the cwd()103 if (pkg.root_src_directory_owned) {
52 // which shouldn't be closed.104 // If root_src_directory.path is null then the handle is the cwd()
53 if (pkg.root_src_directory.path) |p| {105 // which shouldn't be closed.
54 gpa.free(p);106 if (pkg.root_src_directory.path) |p| {
55 pkg.root_src_directory.handle.close();107 gpa.free(p);
108 pkg.root_src_directory.handle.close();
109 }
56 }110 }
57111
58 {112 {
59 var it = pkg.table.iterator();113 var it = pkg.table.iterator();
60 while (it.next()) |kv| {114 while (it.next()) |kv| {
61 kv.value.destroy(gpa);
62 gpa.free(kv.key);115 gpa.free(kv.key);
63 }116 }
64 }117 }
...@@ -72,3 +125,10 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package)...@@ -72,3 +125,10 @@ pub fn add(pkg: *Package, gpa: *Allocator, name: []const u8, package: *Package)
72 const name_dupe = try mem.dupe(gpa, u8, name);125 const name_dupe = try mem.dupe(gpa, u8, name);
73 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);126 pkg.table.putAssumeCapacityNoClobber(name_dupe, package);
74}127}
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(...@@ -199,6 +199,7 @@ pub fn analyzeBody(
199 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),199 .fn_type_cc => try sema.zirFnTypeCc(block, inst, false),
200 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),200 .fn_type_cc_var_args => try sema.zirFnTypeCc(block, inst, true),
201 .fn_type_var_args => try sema.zirFnType(block, inst, true),201 .fn_type_var_args => try sema.zirFnType(block, inst, true),
202 .has_decl => try sema.zirHasDecl(block, inst),
202 .import => try sema.zirImport(block, inst),203 .import => try sema.zirImport(block, inst),
203 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),204 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, inst),
204 .int => try sema.zirInt(block, inst),205 .int => try sema.zirInt(block, inst),
...@@ -258,11 +259,14 @@ pub fn analyzeBody(...@@ -258,11 +259,14 @@ pub fn analyzeBody(
258 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),259 .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
259 .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),260 .switch_capture_else => try sema.zirSwitchCaptureElse(block, inst, false),
260 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),261 .switch_capture_else_ref => try sema.zirSwitchCaptureElse(block, inst, true),
262 .type_info => try sema.zirTypeInfo(block, inst),
261 .typeof => try sema.zirTypeof(block, inst),263 .typeof => try sema.zirTypeof(block, inst),
262 .typeof_elem => try sema.zirTypeofElem(block, inst),264 .typeof_elem => try sema.zirTypeofElem(block, inst),
263 .typeof_peer => try sema.zirTypeofPeer(block, inst),265 .typeof_peer => try sema.zirTypeofPeer(block, inst),
264 .xor => try sema.zirBitwise(block, inst, .xor),266 .xor => try sema.zirBitwise(block, inst, .xor),
265 .struct_init_empty => try sema.zirStructInitEmpty(block, inst),267 .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
267 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),271 .struct_decl => try sema.zirStructDecl(block, inst, .Auto),
268 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),272 .struct_decl_packed => try sema.zirStructDecl(block, inst, .Packed),
...@@ -342,6 +346,10 @@ pub fn analyzeBody(...@@ -342,6 +346,10 @@ pub fn analyzeBody(
342 try sema.zirValidateStructInitPtr(block, inst);346 try sema.zirValidateStructInitPtr(block, inst);
343 continue;347 continue;
344 },348 },
349 .@"export" => {
350 try sema.zirExport(block, inst);
351 continue;
352 },
345353
346 // Special case instructions to handle comptime control flow.354 // Special case instructions to handle comptime control flow.
347 .repeat_inline => {355 .repeat_inline => {
...@@ -593,6 +601,10 @@ fn zirStructDecl(...@@ -593,6 +601,10 @@ fn zirStructDecl(
593 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);601 const struct_obj = try new_decl_arena.allocator.create(Module.Struct);
594 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);602 const struct_ty = try Type.Tag.@"struct".create(&new_decl_arena.allocator, struct_obj);
595 const struct_val = try Value.Tag.ty.create(&new_decl_arena.allocator, struct_ty);603 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 });
596 struct_obj.* = .{608 struct_obj.* = .{
597 .owner_decl = sema.owner_decl,609 .owner_decl = sema.owner_decl,
598 .fields = fields_map,610 .fields = fields_map,
...@@ -600,12 +612,9 @@ fn zirStructDecl(...@@ -600,12 +612,9 @@ fn zirStructDecl(
600 .container = .{612 .container = .{
601 .ty = struct_ty,613 .ty = struct_ty,
602 .file_scope = block.getFileScope(),614 .file_scope = block.getFileScope(),
615 .parent_name_hash = new_decl.fullyQualifiedNameHash(),
603 },616 },
604 };617 };
605 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
606 .ty = Type.initTag(.type),
607 .val = struct_val,
608 });
609 return sema.analyzeDeclVal(block, src, new_decl);618 return sema.analyzeDeclVal(block, src, new_decl);
610}619}
611620
...@@ -1333,6 +1342,28 @@ fn analyzeBlockBody(...@@ -1333,6 +1342,28 @@ fn analyzeBlockBody(
1333 return &merges.block_inst.base;1342 return &merges.block_inst.base;
1334}1343}
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
1336fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {1367fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!void {
1337 const tracy = trace(@src());1368 const tracy = trace(@src());
1338 defer tracy.end();1369 defer tracy.end();
...@@ -1402,9 +1433,6 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE...@@ -1402,9 +1433,6 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
1402}1433}
14031434
1404fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1435fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1405 const tracy = trace(@src());
1406 defer tracy.end();
1407
1408 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1436 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1409 const src = inst_data.src();1437 const src = inst_data.src();
1410 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;1438 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...@@ -1412,9 +1440,6 @@ fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
1412}1440}
14131441
1414fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {1442fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1415 const tracy = trace(@src());
1416 defer tracy.end();
1417
1418 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;1443 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1419 const src = inst_data.src();1444 const src = inst_data.src();
1420 const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key;1445 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...@@ -2543,7 +2568,10 @@ fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError
25432568
2544 const bin_inst = sema.code.instructions.items(.data)[inst].bin;2569 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2545 const array = try sema.resolveInst(bin_inst.lhs);2570 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);
2547 const elem_index = try sema.resolveInst(bin_inst.rhs);2575 const elem_index = try sema.resolveInst(bin_inst.rhs);
2548 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);2576 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
2549 return sema.analyzeLoad(block, sema.src, result_ptr, sema.src);2577 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...@@ -2558,7 +2586,10 @@ fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerE
2558 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };2586 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
2559 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;2587 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
2560 const array = try sema.resolveInst(extra.lhs);2588 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);
2562 const elem_index = try sema.resolveInst(extra.rhs);2593 const elem_index = try sema.resolveInst(extra.rhs);
2563 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);2594 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
2564 return sema.analyzeLoad(block, src, result_ptr, src);2595 return sema.analyzeLoad(block, src, result_ptr, src);
...@@ -3595,6 +3626,34 @@ fn validateSwitchNoRange(...@@ -3595,6 +3626,34 @@ fn validateSwitchNoRange(
3595 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);3626 return sema.mod.failWithOwnedErrorMsg(&block.base, msg);
3596}3627}
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
3598fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {3657fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
3599 const tracy = trace(@src());3658 const tracy = trace(@src());
3600 defer tracy.end();3659 defer tracy.end();
...@@ -4021,6 +4080,12 @@ fn zirCmp(...@@ -4021,6 +4080,12 @@ fn zirCmp(
4021 return block.addBinOp(src, bool_type, tag, casted_lhs, casted_rhs);4080 return block.addBinOp(src, bool_type, tag, casted_lhs, casted_rhs);
4022}4081}
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
4024fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {4089fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
4025 const inst_data = sema.code.instructions.items(.data)[inst].un_node;4090 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
4026 const src = inst_data.src();4091 const src = inst_data.src();
...@@ -4438,6 +4503,18 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In...@@ -4438,6 +4503,18 @@ fn zirStructInitEmpty(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) In
4438 });4503 });
4439}4504}
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
4441fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {4518fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
4442 if (sema.func == null) {4519 if (sema.func == null) {
4443 return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});4520 return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
...@@ -4632,7 +4709,8 @@ fn namedFieldPtr(...@@ -4632,7 +4709,8 @@ fn namedFieldPtr(
4632 .Struct, .Opaque, .Union => {4709 .Struct, .Opaque, .Union => {
4633 if (child_type.getContainerScope()) |container_scope| {4710 if (child_type.getContainerScope()) |container_scope| {
4634 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {4711 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});
4636 return sema.analyzeDeclRef(block, src, decl);4714 return sema.analyzeDeclRef(block, src, decl);
4637 }4715 }
46384716
...@@ -4660,7 +4738,8 @@ fn namedFieldPtr(...@@ -4660,7 +4738,8 @@ fn namedFieldPtr(
4660 .Enum => {4738 .Enum => {
4661 if (child_type.getContainerScope()) |container_scope| {4739 if (child_type.getContainerScope()) |container_scope| {
4662 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {4740 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});
4664 return sema.analyzeDeclRef(block, src, decl);4743 return sema.analyzeDeclRef(block, src, decl);
4665 }4744 }
4666 }4745 }
...@@ -4731,37 +4810,51 @@ fn elemPtr(...@@ -4731,37 +4810,51 @@ fn elemPtr(
4731 elem_index: *Inst,4810 elem_index: *Inst,
4732 elem_index_src: LazySrcLoc,4811 elem_index_src: LazySrcLoc,
4733) InnerError!*Inst {4812) InnerError!*Inst {
4734 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {4813 const array_ty = switch (array_ptr.ty.zigTypeTag()) {
4735 .Pointer => array_ptr.ty.elemType(),4814 .Pointer => array_ptr.ty.elemType(),
4736 else => return sema.mod.fail(&block.base, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),4815 else => return sema.mod.fail(&block.base, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
4737 };4816 };
4738 if (!elem_ty.isIndexable()) {4817 if (!array_ty.isIndexable()) {
4739 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{elem_ty});4818 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{array_ty});
4740 }4819 }
47414820 if (array_ty.isSinglePointer() and array_ty.elemType().zigTypeTag() == .Array) {
4742 if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
4743 // we have to deref the ptr operand to get the actual array pointer4821 // we have to deref the ptr operand to get the actual array pointer
4744 const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr.src);4822 const array_ptr_deref = try sema.analyzeLoad(block, src, array_ptr, array_ptr.src);
4745 if (array_ptr_deref.value()) |array_ptr_val| {4823 return sema.elemPtrArray(block, src, array_ptr_deref, elem_index, elem_index_src);
4746 if (elem_index.value()) |index_val| {4824 }
4747 // Both array pointer and index are compile-time known.4825 if (array_ty.zigTypeTag() == .Array) {
4748 const index_u64 = index_val.toUnsignedInt();4826 return sema.elemPtrArray(block, src, array_ptr, elem_index, elem_index_src);
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 }
4760 }4827 }
47614828
4762 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});4829 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});
4763}4830}
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
4765fn coerce(4858fn coerce(
4766 sema: *Sema,4859 sema: *Sema,
4767 block: *Scope.Block,4860 block: *Scope.Block,
...@@ -5244,9 +5337,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin...@@ -5244,9 +5337,9 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
5244 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });5337 try std.fs.path.resolve(sema.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
5245 errdefer sema.gpa.free(resolved_path);5338 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| {
5248 sema.gpa.free(resolved_path);5341 sema.gpa.free(resolved_path);
5249 return some;5342 return cached_import;
5250 }5343 }
52515344
5252 if (found_pkg == null) {5345 if (found_pkg == null) {
...@@ -5264,6 +5357,11 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin...@@ -5264,6 +5357,11 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
5264 const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);5357 const struct_ty = try Type.Tag.empty_struct.create(sema.gpa, &file_scope.root_container);
5265 errdefer sema.gpa.destroy(struct_ty.castTag(.empty_struct).?);5358 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
5267 file_scope.* = .{5365 file_scope.* = .{
5268 .sub_file_path = resolved_path,5366 .sub_file_path = resolved_path,
5269 .source = .{ .unloaded = {} },5367 .source = .{ .unloaded = {} },
...@@ -5274,6 +5372,7 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin...@@ -5274,6 +5372,7 @@ fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_strin
5274 .file_scope = file_scope,5372 .file_scope = file_scope,
5275 .decls = .{},5373 .decls = .{},
5276 .ty = struct_ty,5374 .ty = struct_ty,
5375 .parent_name_hash = container_name_hash,
5277 },5376 },
5278 };5377 };
5279 sema.mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {5378 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 {...@@ -417,7 +417,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
417 const node_datas = tree.nodes.items(.data);417 const node_datas = tree.nodes.items(.data);
418 const token_starts = tree.tokens.items(.start);418 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;
421 assert(node_tags[fn_decl] == .fn_decl);421 assert(node_tags[fn_decl] == .fn_decl);
422 const block = node_datas[fn_decl].rhs;422 const block = node_datas[fn_decl].rhs;
423 const lbrace_src = token_starts[tree.firstToken(block)];423 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 {...@@ -2228,10 +2228,9 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2228 const node_datas = tree.nodes.items(.data);2228 const node_datas = tree.nodes.items(.data);
2229 const token_starts = tree.tokens.items(.start);2229 const token_starts = tree.tokens.items(.start);
22302230
2231 const file_ast_decls = tree.rootDecls();
2232 // TODO Look into improving the performance here by adding a token-index-to-line2231 // TODO Look into improving the performance here by adding a token-index-to-line
2233 // lookup table. Currently this involves scanning over the source code for newlines.2232 // 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;
2235 assert(node_tags[fn_decl] == .fn_decl);2234 assert(node_tags[fn_decl] == .fn_decl);
2236 const block = node_datas[fn_decl].rhs;2235 const block = node_datas[fn_decl].rhs;
2237 const lbrace = tree.firstToken(block);2236 const lbrace = tree.firstToken(block);
...@@ -2755,10 +2754,9 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec...@@ -2755,10 +2754,9 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
2755 const node_datas = tree.nodes.items(.data);2754 const node_datas = tree.nodes.items(.data);
2756 const token_starts = tree.tokens.items(.start);2755 const token_starts = tree.tokens.items(.start);
27572756
2758 const file_ast_decls = tree.rootDecls();
2759 // TODO Look into improving the performance here by adding a token-index-to-line2757 // TODO Look into improving the performance here by adding a token-index-to-line
2760 // lookup table. Currently this involves scanning over the source code for newlines.2758 // 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;
2762 assert(node_tags[fn_decl] == .fn_decl);2760 assert(node_tags[fn_decl] == .fn_decl);
2763 const block = node_datas[fn_decl].rhs;2761 const block = node_datas[fn_decl].rhs;
2764 const lbrace = tree.firstToken(block);2762 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...@@ -909,10 +909,9 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
909 const node_datas = tree.nodes.items(.data);909 const node_datas = tree.nodes.items(.data);
910 const token_starts = tree.tokens.items(.start);910 const token_starts = tree.tokens.items(.start);
911911
912 const file_ast_decls = tree.rootDecls();
913 // TODO Look into improving the performance here by adding a token-index-to-line912 // TODO Look into improving the performance here by adding a token-index-to-line
914 // lookup table. Currently this involves scanning over the source code for newlines.913 // 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;
916 assert(node_tags[fn_decl] == .fn_decl);915 assert(node_tags[fn_decl] == .fn_decl);
917 const block = node_datas[fn_decl].rhs;916 const block = node_datas[fn_decl].rhs;
918 const lbrace = tree.firstToken(block);917 const lbrace = tree.firstToken(block);
...@@ -959,10 +958,9 @@ pub fn initDeclDebugBuffers(...@@ -959,10 +958,9 @@ pub fn initDeclDebugBuffers(
959 const node_datas = tree.nodes.items(.data);958 const node_datas = tree.nodes.items(.data);
960 const token_starts = tree.tokens.items(.start);959 const token_starts = tree.tokens.items(.start);
961960
962 const file_ast_decls = tree.rootDecls();
963 // TODO Look into improving the performance here by adding a token-index-to-line961 // TODO Look into improving the performance here by adding a token-index-to-line
964 // lookup table. Currently this involves scanning over the source code for newlines.962 // 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;
966 assert(node_tags[fn_decl] == .fn_decl);964 assert(node_tags[fn_decl] == .fn_decl);
967 const block = node_datas[fn_decl].rhs;965 const block = node_datas[fn_decl].rhs;
968 const lbrace = tree.firstToken(block);966 const lbrace = tree.firstToken(block);
src/main.zig+23-23
...@@ -505,7 +505,6 @@ fn buildOutputType(...@@ -505,7 +505,6 @@ fn buildOutputType(
505 var emit_bin: EmitBin = .yes_default_path;505 var emit_bin: EmitBin = .yes_default_path;
506 var emit_asm: Emit = .no;506 var emit_asm: Emit = .no;
507 var emit_llvm_ir: Emit = .no;507 var emit_llvm_ir: Emit = .no;
508 var emit_zir: Emit = .no;
509 var emit_docs: Emit = .no;508 var emit_docs: Emit = .no;
510 var emit_analysis: Emit = .no;509 var emit_analysis: Emit = .no;
511 var target_arch_os_abi: []const u8 = "native";510 var target_arch_os_abi: []const u8 = "native";
...@@ -599,15 +598,15 @@ fn buildOutputType(...@@ -599,15 +598,15 @@ fn buildOutputType(
599 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);598 var test_exec_args = std.ArrayList(?[]const u8).init(gpa);
600 defer test_exec_args.deinit();599 defer test_exec_args.deinit();
601600
602 const pkg_tree_root = try gpa.create(Package);
603 // This package only exists to clean up the code parsing --pkg-begin and601 // This package only exists to clean up the code parsing --pkg-begin and
604 // --pkg-end flags. Use dummy values that are safe for the destroy call.602 // --pkg-end flags. Use dummy values that are safe for the destroy call.
605 pkg_tree_root.* = .{603 var pkg_tree_root: Package = .{
606 .root_src_directory = .{ .path = null, .handle = fs.cwd() },604 .root_src_directory = .{ .path = null, .handle = fs.cwd() },
607 .root_src_path = &[0]u8{},605 .root_src_path = &[0]u8{},
606 .namespace_hash = Package.root_namespace_hash,
608 };607 };
609 defer pkg_tree_root.destroy(gpa);608 defer freePkgTree(gpa, &pkg_tree_root, false);
610 var cur_pkg: *Package = pkg_tree_root;609 var cur_pkg: *Package = &pkg_tree_root;
611610
612 switch (arg_mode) {611 switch (arg_mode) {
613 .build, .translate_c, .zig_test, .run => {612 .build, .translate_c, .zig_test, .run => {
...@@ -658,8 +657,7 @@ fn buildOutputType(...@@ -658,8 +657,7 @@ fn buildOutputType(
658 ) catch |err| {657 ) catch |err| {
659 fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) });658 fatal("Failed to add package at path {s}: {s}", .{ pkg_path, @errorName(err) });
660 };659 };
661 new_cur_pkg.parent = cur_pkg;660 try cur_pkg.addAndAdopt(gpa, pkg_name, new_cur_pkg);
662 try cur_pkg.add(gpa, pkg_name, new_cur_pkg);
663 cur_pkg = new_cur_pkg;661 cur_pkg = new_cur_pkg;
664 } else if (mem.eql(u8, arg, "--pkg-end")) {662 } else if (mem.eql(u8, arg, "--pkg-end")) {
665 cur_pkg = cur_pkg.parent orelse663 cur_pkg = cur_pkg.parent orelse
...@@ -924,12 +922,6 @@ fn buildOutputType(...@@ -924,12 +922,6 @@ fn buildOutputType(
924 emit_bin = .{ .yes = arg["-femit-bin=".len..] };922 emit_bin = .{ .yes = arg["-femit-bin=".len..] };
925 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {923 } else if (mem.eql(u8, arg, "-fno-emit-bin")) {
926 emit_bin = .no;924 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;
933 } else if (mem.eql(u8, arg, "-femit-h")) {925 } else if (mem.eql(u8, arg, "-femit-h")) {
934 emit_h = .yes_default_path;926 emit_h = .yes_default_path;
935 } else if (mem.startsWith(u8, arg, "-femit-h=")) {927 } else if (mem.startsWith(u8, arg, "-femit-h=")) {
...@@ -1026,7 +1018,7 @@ fn buildOutputType(...@@ -1026,7 +1018,7 @@ fn buildOutputType(
1026 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),1018 .extra_flags = try arena.dupe([]const u8, extra_cflags.items),
1027 });1019 });
1028 },1020 },
1029 .zig, .zir => {1021 .zig => {
1030 if (root_src_file) |other| {1022 if (root_src_file) |other| {
1031 fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });1023 fatal("found another zig file '{s}' after root source file '{s}'", .{ arg, other });
1032 } else {1024 } else {
...@@ -1087,7 +1079,7 @@ fn buildOutputType(...@@ -1087,7 +1079,7 @@ fn buildOutputType(
1087 .unknown, .shared_library, .object, .static_library => {1079 .unknown, .shared_library, .object, .static_library => {
1088 try link_objects.append(it.only_arg);1080 try link_objects.append(it.only_arg);
1089 },1081 },
1090 .zig, .zir => {1082 .zig => {
1091 if (root_src_file) |other| {1083 if (root_src_file) |other| {
1092 fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });1084 fatal("found another zig file '{s}' after root source file '{s}'", .{ it.only_arg, other });
1093 } else {1085 } else {
...@@ -1725,13 +1717,6 @@ fn buildOutputType(...@@ -1725,13 +1717,6 @@ fn buildOutputType(
1725 var emit_docs_resolved = try emit_docs.resolve("docs");1717 var emit_docs_resolved = try emit_docs.resolve("docs");
1726 defer emit_docs_resolved.deinit();1718 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
1735 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {1720 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
1736 if (main_pkg_path) |p| {1721 if (main_pkg_path) |p| {
1737 const rel_src_path = try fs.path.relative(gpa, p, src_path);1722 const rel_src_path = try fs.path.relative(gpa, p, src_path);
...@@ -1747,6 +1732,7 @@ fn buildOutputType(...@@ -1747,6 +1732,7 @@ fn buildOutputType(
1747 if (root_pkg) |pkg| {1732 if (root_pkg) |pkg| {
1748 pkg.table = pkg_tree_root.table;1733 pkg.table = pkg_tree_root.table;
1749 pkg_tree_root.table = .{};1734 pkg_tree_root.table = .{};
1735 pkg.namespace_hash = pkg_tree_root.namespace_hash;
1750 }1736 }
17511737
1752 const self_exe_path = try fs.selfExePathAlloc(arena);1738 const self_exe_path = try fs.selfExePathAlloc(arena);
...@@ -2155,6 +2141,18 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi...@@ -2155,6 +2141,18 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !voi
2155 }2141 }
2156}2142}
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
2158fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {2156fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {
2159 if (!build_options.have_llvm)2157 if (!build_options.have_llvm)
2160 fatal("cannot translate-c: compiler built without LLVM extensions", .{});2158 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...@@ -2509,6 +2507,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2509 .handle = try zig_lib_directory.handle.openDir(std_special, .{}),2507 .handle = try zig_lib_directory.handle.openDir(std_special, .{}),
2510 },2508 },
2511 .root_src_path = "build_runner.zig",2509 .root_src_path = "build_runner.zig",
2510 .namespace_hash = Package.root_namespace_hash,
2512 };2511 };
2513 defer root_pkg.root_src_directory.handle.close();2512 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...@@ -2554,8 +2553,9 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2554 var build_pkg: Package = .{2553 var build_pkg: Package = .{
2555 .root_src_directory = build_directory,2554 .root_src_directory = build_directory,
2556 .root_src_path = build_zig_basename,2555 .root_src_path = build_zig_basename,
2556 .namespace_hash = undefined,
2557 };2557 };
2558 try root_pkg.table.put(arena, "@build", &build_pkg);2558 try root_pkg.addAndAdopt(arena, "@build", &build_pkg);
25592559
2560 var global_cache_directory: Compilation.Directory = l: {2560 var global_cache_directory: Compilation.Directory = l: {
2561 const p = override_global_cache_dir orelse try introspect.resolveGlobalCacheDir(arena);2561 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) {...@@ -9137,6 +9137,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
9137 buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));9137 buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));
9138 buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));9138 buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));
9139 buf_appendf(contents, "pub const code_model = CodeModel.default;\n");9139 buf_appendf(contents, "pub const code_model = CodeModel.default;\n");
9140 buf_appendf(contents, "pub const zig_is_stage2 = false;\n");
91409141
9141 {9142 {
9142 TargetSubsystem detected_subsystem = detect_subsystem(g);9143 TargetSubsystem detected_subsystem = detect_subsystem(g);
src/test.zig+21-42
...@@ -122,11 +122,6 @@ pub const TestContext = struct {...@@ -122,11 +122,6 @@ pub const TestContext = struct {
122 path: []const u8,122 path: []const u8,
123 };123 };
124124
125 pub const Extension = enum {
126 Zig,
127 ZIR,
128 };
129
130 /// A `Case` consists of a list of `Update`. The same `Compilation` is used for each125 /// A `Case` consists of a list of `Update`. The same `Compilation` is used for each
131 /// update, so each update's source is treated as a single file being126 /// update, so each update's source is treated as a single file being
132 /// updated by the test harness and incrementally compiled.127 /// updated by the test harness and incrementally compiled.
...@@ -141,7 +136,6 @@ pub const TestContext = struct {...@@ -141,7 +136,6 @@ pub const TestContext = struct {
141 /// to Executable.136 /// to Executable.
142 output_mode: std.builtin.OutputMode,137 output_mode: std.builtin.OutputMode,
143 updates: std.ArrayList(Update),138 updates: std.ArrayList(Update),
144 extension: Extension,
145 object_format: ?std.builtin.ObjectFormat = null,139 object_format: ?std.builtin.ObjectFormat = null,
146 emit_h: bool = false,140 emit_h: bool = false,
147 llvm_backend: bool = false,141 llvm_backend: bool = false,
...@@ -238,14 +232,12 @@ pub const TestContext = struct {...@@ -238,14 +232,12 @@ pub const TestContext = struct {
238 ctx: *TestContext,232 ctx: *TestContext,
239 name: []const u8,233 name: []const u8,
240 target: CrossTarget,234 target: CrossTarget,
241 extension: Extension,
242 ) *Case {235 ) *Case {
243 ctx.cases.append(Case{236 ctx.cases.append(Case{
244 .name = name,237 .name = name,
245 .target = target,238 .target = target,
246 .updates = std.ArrayList(Update).init(ctx.cases.allocator),239 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
247 .output_mode = .Exe,240 .output_mode = .Exe,
248 .extension = extension,
249 .files = std.ArrayList(File).init(ctx.cases.allocator),241 .files = std.ArrayList(File).init(ctx.cases.allocator),
250 }) catch @panic("out of memory");242 }) catch @panic("out of memory");
251 return &ctx.cases.items[ctx.cases.items.len - 1];243 return &ctx.cases.items[ctx.cases.items.len - 1];
...@@ -253,7 +245,7 @@ pub const TestContext = struct {...@@ -253,7 +245,7 @@ pub const TestContext = struct {
253245
254 /// Adds a test case for Zig input, producing an executable246 /// Adds a test case for Zig input, producing an executable
255 pub fn exe(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {247 pub fn exe(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
256 return ctx.addExe(name, target, .Zig);248 return ctx.addExe(name, target);
257 }249 }
258250
259 /// Adds a test case for ZIR input, producing an executable251 /// Adds a test case for ZIR input, producing an executable
...@@ -269,7 +261,6 @@ pub const TestContext = struct {...@@ -269,7 +261,6 @@ pub const TestContext = struct {
269 .target = target,261 .target = target,
270 .updates = std.ArrayList(Update).init(ctx.cases.allocator),262 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
271 .output_mode = .Exe,263 .output_mode = .Exe,
272 .extension = .Zig,
273 .object_format = .c,264 .object_format = .c,
274 .files = std.ArrayList(File).init(ctx.cases.allocator),265 .files = std.ArrayList(File).init(ctx.cases.allocator),
275 }) catch @panic("out of memory");266 }) catch @panic("out of memory");
...@@ -284,7 +275,6 @@ pub const TestContext = struct {...@@ -284,7 +275,6 @@ pub const TestContext = struct {
284 .target = target,275 .target = target,
285 .updates = std.ArrayList(Update).init(ctx.cases.allocator),276 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
286 .output_mode = .Exe,277 .output_mode = .Exe,
287 .extension = .Zig,
288 .files = std.ArrayList(File).init(ctx.cases.allocator),278 .files = std.ArrayList(File).init(ctx.cases.allocator),
289 .llvm_backend = true,279 .llvm_backend = true,
290 }) catch @panic("out of memory");280 }) catch @panic("out of memory");
...@@ -295,14 +285,12 @@ pub const TestContext = struct {...@@ -295,14 +285,12 @@ pub const TestContext = struct {
295 ctx: *TestContext,285 ctx: *TestContext,
296 name: []const u8,286 name: []const u8,
297 target: CrossTarget,287 target: CrossTarget,
298 extension: Extension,
299 ) *Case {288 ) *Case {
300 ctx.cases.append(Case{289 ctx.cases.append(Case{
301 .name = name,290 .name = name,
302 .target = target,291 .target = target,
303 .updates = std.ArrayList(Update).init(ctx.cases.allocator),292 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
304 .output_mode = .Obj,293 .output_mode = .Obj,
305 .extension = extension,
306 .files = std.ArrayList(File).init(ctx.cases.allocator),294 .files = std.ArrayList(File).init(ctx.cases.allocator),
307 }) catch @panic("out of memory");295 }) catch @panic("out of memory");
308 return &ctx.cases.items[ctx.cases.items.len - 1];296 return &ctx.cases.items[ctx.cases.items.len - 1];
...@@ -310,7 +298,7 @@ pub const TestContext = struct {...@@ -310,7 +298,7 @@ pub const TestContext = struct {
310298
311 /// Adds a test case for Zig input, producing an object file.299 /// Adds a test case for Zig input, producing an object file.
312 pub fn obj(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {300 pub fn obj(ctx: *TestContext, name: []const u8, target: CrossTarget) *Case {
313 return ctx.addObj(name, target, .Zig);301 return ctx.addObj(name, target);
314 }302 }
315303
316 /// Adds a test case for ZIR input, producing an object file.304 /// Adds a test case for ZIR input, producing an object file.
...@@ -319,13 +307,12 @@ pub const TestContext = struct {...@@ -319,13 +307,12 @@ pub const TestContext = struct {
319 }307 }
320308
321 /// Adds a test case for Zig or ZIR input, producing C code.309 /// 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 {
323 ctx.cases.append(Case{311 ctx.cases.append(Case{
324 .name = name,312 .name = name,
325 .target = target,313 .target = target,
326 .updates = std.ArrayList(Update).init(ctx.cases.allocator),314 .updates = std.ArrayList(Update).init(ctx.cases.allocator),
327 .output_mode = .Obj,315 .output_mode = .Obj,
328 .extension = ext,
329 .object_format = .c,316 .object_format = .c,
330 .files = std.ArrayList(File).init(ctx.cases.allocator),317 .files = std.ArrayList(File).init(ctx.cases.allocator),
331 }) catch @panic("out of memory");318 }) catch @panic("out of memory");
...@@ -333,21 +320,20 @@ pub const TestContext = struct {...@@ -333,21 +320,20 @@ pub const TestContext = struct {
333 }320 }
334321
335 pub fn c(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {322 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);
337 }324 }
338325
339 pub fn h(ctx: *TestContext, name: []const u8, target: CrossTarget, src: [:0]const u8, comptime out: [:0]const u8) void {326 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);
341 }328 }
342329
343 pub fn addCompareOutput(330 pub fn addCompareOutput(
344 ctx: *TestContext,331 ctx: *TestContext,
345 name: []const u8,332 name: []const u8,
346 extension: Extension,
347 src: [:0]const u8,333 src: [:0]const u8,
348 expected_stdout: []const u8,334 expected_stdout: []const u8,
349 ) void {335 ) void {
350 ctx.addExe(name, .{}, extension).addCompareOutput(src, expected_stdout);336 ctx.addExe(name, .{}).addCompareOutput(src, expected_stdout);
351 }337 }
352338
353 /// Adds a test case that compiles the Zig source given in `src`, executes339 /// Adds a test case that compiles the Zig source given in `src`, executes
...@@ -358,7 +344,7 @@ pub const TestContext = struct {...@@ -358,7 +344,7 @@ pub const TestContext = struct {
358 src: [:0]const u8,344 src: [:0]const u8,
359 expected_stdout: []const u8,345 expected_stdout: []const u8,
360 ) void {346 ) void {
361 return ctx.addCompareOutput(name, .Zig, src, expected_stdout);347 return ctx.addCompareOutput(name, src, expected_stdout);
362 }348 }
363349
364 /// Adds a test case that compiles the ZIR source given in `src`, executes350 /// Adds a test case that compiles the ZIR source given in `src`, executes
...@@ -376,11 +362,10 @@ pub const TestContext = struct {...@@ -376,11 +362,10 @@ pub const TestContext = struct {
376 ctx: *TestContext,362 ctx: *TestContext,
377 name: []const u8,363 name: []const u8,
378 target: CrossTarget,364 target: CrossTarget,
379 extension: Extension,
380 src: [:0]const u8,365 src: [:0]const u8,
381 result: [:0]const u8,366 result: [:0]const u8,
382 ) void {367 ) void {
383 ctx.addObj(name, target, extension).addTransform(src, result);368 ctx.addObj(name, target).addTransform(src, result);
384 }369 }
385370
386 /// Adds a test case that compiles the Zig given in `src` to ZIR and tests371 /// Adds a test case that compiles the Zig given in `src` to ZIR and tests
...@@ -392,7 +377,7 @@ pub const TestContext = struct {...@@ -392,7 +377,7 @@ pub const TestContext = struct {
392 src: [:0]const u8,377 src: [:0]const u8,
393 result: [:0]const u8,378 result: [:0]const u8,
394 ) void {379 ) void {
395 ctx.addTransform(name, target, .Zig, src, result);380 ctx.addTransform(name, target, src, result);
396 }381 }
397382
398 /// Adds a test case that cleans up the ZIR source given in `src`, and383 /// Adds a test case that cleans up the ZIR source given in `src`, and
...@@ -411,11 +396,10 @@ pub const TestContext = struct {...@@ -411,11 +396,10 @@ pub const TestContext = struct {
411 ctx: *TestContext,396 ctx: *TestContext,
412 name: []const u8,397 name: []const u8,
413 target: CrossTarget,398 target: CrossTarget,
414 extension: Extension,
415 src: [:0]const u8,399 src: [:0]const u8,
416 expected_errors: []const []const u8,400 expected_errors: []const []const u8,
417 ) void {401 ) void {
418 ctx.addObj(name, target, extension).addError(src, expected_errors);402 ctx.addObj(name, target).addError(src, expected_errors);
419 }403 }
420404
421 /// Adds a test case that ensures that the Zig given in `src` fails to405 /// Adds a test case that ensures that the Zig given in `src` fails to
...@@ -428,7 +412,7 @@ pub const TestContext = struct {...@@ -428,7 +412,7 @@ pub const TestContext = struct {
428 src: [:0]const u8,412 src: [:0]const u8,
429 expected_errors: []const []const u8,413 expected_errors: []const []const u8,
430 ) void {414 ) void {
431 ctx.addError(name, target, .Zig, src, expected_errors);415 ctx.addError(name, target, src, expected_errors);
432 }416 }
433417
434 /// Adds a test case that ensures that the ZIR given in `src` fails to418 /// Adds a test case that ensures that the ZIR given in `src` fails to
...@@ -448,10 +432,9 @@ pub const TestContext = struct {...@@ -448,10 +432,9 @@ pub const TestContext = struct {
448 ctx: *TestContext,432 ctx: *TestContext,
449 name: []const u8,433 name: []const u8,
450 target: CrossTarget,434 target: CrossTarget,
451 extension: Extension,
452 src: [:0]const u8,435 src: [:0]const u8,
453 ) void {436 ) void {
454 ctx.addObj(name, target, extension).compiles(src);437 ctx.addObj(name, target).compiles(src);
455 }438 }
456439
457 /// Adds a test case that asserts that the Zig given in `src` compiles440 /// Adds a test case that asserts that the Zig given in `src` compiles
...@@ -462,7 +445,7 @@ pub const TestContext = struct {...@@ -462,7 +445,7 @@ pub const TestContext = struct {
462 target: CrossTarget,445 target: CrossTarget,
463 src: [:0]const u8,446 src: [:0]const u8,
464 ) void {447 ) void {
465 ctx.addCompiles(name, target, .Zig, src);448 ctx.addCompiles(name, target, src);
466 }449 }
467450
468 /// Adds a test case that asserts that the ZIR given in `src` compiles451 /// Adds a test case that asserts that the ZIR given in `src` compiles
...@@ -489,7 +472,7 @@ pub const TestContext = struct {...@@ -489,7 +472,7 @@ pub const TestContext = struct {
489 expected_errors: []const []const u8,472 expected_errors: []const []const u8,
490 fixed_src: [:0]const u8,473 fixed_src: [:0]const u8,
491 ) void {474 ) void {
492 var case = ctx.addObj(name, target, .Zig);475 var case = ctx.addObj(name, target);
493 case.addError(src, expected_errors);476 case.addError(src, expected_errors);
494 case.compiles(fixed_src);477 case.compiles(fixed_src);
495 }478 }
...@@ -614,15 +597,14 @@ pub const TestContext = struct {...@@ -614,15 +597,14 @@ pub const TestContext = struct {
614 .path = try std.fs.path.join(arena, &[_][]const u8{ tmp_dir_path, "zig-cache" }),597 .path = try std.fs.path.join(arena, &[_][]const u8{ tmp_dir_path, "zig-cache" }),
615 };598 };
616599
617 const tmp_src_path = switch (case.extension) {600 const tmp_src_path = "test_case.zig";
618 .Zig => "test_case.zig",
619 .ZIR => "test_case.zir",
620 };
621601
622 var root_pkg: Package = .{602 var root_pkg: Package = .{
623 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },603 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
624 .root_src_path = tmp_src_path,604 .root_src_path = tmp_src_path,
605 .namespace_hash = Package.root_namespace_hash,
625 };606 };
607 defer root_pkg.table.deinit(allocator);
626608
627 const bin_name = try std.zig.binNameAlloc(arena, .{609 const bin_name = try std.zig.binNameAlloc(arena, .{
628 .root_name = "test_case",610 .root_name = "test_case",
...@@ -639,13 +621,10 @@ pub const TestContext = struct {...@@ -639,13 +621,10 @@ pub const TestContext = struct {
639 .directory = emit_directory,621 .directory = emit_directory,
640 .basename = bin_name,622 .basename = bin_name,
641 };623 };
642 const emit_h: ?Compilation.EmitLoc = if (case.emit_h)624 const emit_h: ?Compilation.EmitLoc = if (case.emit_h) .{
643 .{625 .directory = emit_directory,
644 .directory = emit_directory,626 .basename = "test_case.h",
645 .basename = "test_case.h",627 } else null;
646 }
647 else
648 null;
649 const comp = try Compilation.create(allocator, .{628 const comp = try Compilation.create(allocator, .{
650 .local_cache_directory = zig_cache_directory,629 .local_cache_directory = zig_cache_directory,
651 .global_cache_directory = global_cache_directory,630 .global_cache_directory = global_cache_directory,
src/zir.zig+43
...@@ -328,6 +328,9 @@ pub const Inst = struct {...@@ -328,6 +328,9 @@ pub const Inst = struct {
328 error_union_type,328 error_union_type,
329 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.329 /// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
330 error_value,330 error_value,
331 /// Implements the `@export` builtin function.
332 /// Uses the `pl_node` union field. Payload is `Bin`.
333 @"export",
331 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer334 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
332 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.335 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
333 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.336 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
...@@ -360,6 +363,9 @@ pub const Inst = struct {...@@ -360,6 +363,9 @@ pub const Inst = struct {
360 fn_type_cc,363 fn_type_cc,
361 /// Same as `fn_type_cc` but the function is variadic.364 /// Same as `fn_type_cc` but the function is variadic.
362 fn_type_cc_var_args,365 fn_type_cc_var_args,
366 /// Implements the `@hasDecl` builtin.
367 /// Uses the `pl_node` union field. Payload is `Bin`.
368 has_decl,
363 /// `@import(operand)`.369 /// `@import(operand)`.
364 /// Uses the `un_node` field.370 /// Uses the `un_node` field.
365 import,371 import,
...@@ -668,12 +674,21 @@ pub const Inst = struct {...@@ -668,12 +674,21 @@ pub const Inst = struct {
668 /// A struct literal with a specified type, with no fields.674 /// A struct literal with a specified type, with no fields.
669 /// Uses the `un_node` field.675 /// Uses the `un_node` field.
670 struct_init_empty,676 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,
671 /// Converts an integer into an enum value.684 /// Converts an integer into an enum value.
672 /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.685 /// Uses `pl_node` with payload `Bin`. `lhs` is enum type, `rhs` is operand.
673 int_to_enum,686 int_to_enum,
674 /// Converts an enum value into an integer. Resulting type will be the tag type687 /// Converts an enum value into an integer. Resulting type will be the tag type
675 /// of the enum. Uses `un_node`.688 /// of the enum. Uses `un_node`.
676 enum_to_int,689 enum_to_int,
690 /// Implements the `@typeInfo` builtin. Uses `un_node`.
691 type_info,
677692
678 /// Returns whether the instruction is one of the control flow "noreturn" types.693 /// Returns whether the instruction is one of the control flow "noreturn" types.
679 /// Function calls do not count.694 /// Function calls do not count.
...@@ -737,6 +752,7 @@ pub const Inst = struct {...@@ -737,6 +752,7 @@ pub const Inst = struct {
737 .elem_val_node,752 .elem_val_node,
738 .ensure_result_used,753 .ensure_result_used,
739 .ensure_result_non_error,754 .ensure_result_non_error,
755 .@"export",
740 .floatcast,756 .floatcast,
741 .field_ptr,757 .field_ptr,
742 .field_val,758 .field_val,
...@@ -746,6 +762,7 @@ pub const Inst = struct {...@@ -746,6 +762,7 @@ pub const Inst = struct {
746 .fn_type_var_args,762 .fn_type_var_args,
747 .fn_type_cc,763 .fn_type_cc,
748 .fn_type_cc_var_args,764 .fn_type_cc_var_args,
765 .has_decl,
749 .int,766 .int,
750 .float,767 .float,
751 .float128,768 .float128,
...@@ -831,8 +848,11 @@ pub const Inst = struct {...@@ -831,8 +848,11 @@ pub const Inst = struct {
831 .switch_block_ref_under_multi,848 .switch_block_ref_under_multi,
832 .validate_struct_init_ptr,849 .validate_struct_init_ptr,
833 .struct_init_empty,850 .struct_init_empty,
851 .struct_init,
852 .field_type,
834 .int_to_enum,853 .int_to_enum,
835 .enum_to_int,854 .enum_to_int,
855 .type_info,
836 => false,856 => false,
837857
838 .@"break",858 .@"break",
...@@ -1543,6 +1563,24 @@ pub const Inst = struct {...@@ -1543,6 +1563,24 @@ pub const Inst = struct {
1543 return @bitCast(f128, int_bits);1563 return @bitCast(f128, int_bits);
1544 }1564 }
1545 };1565 };
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 };
1546};1584};
15471585
1548pub const SpecialProng = enum { none, @"else", under };1586pub const SpecialProng = enum { none, @"else", under };
...@@ -1617,6 +1655,7 @@ const Writer = struct {...@@ -1617,6 +1655,7 @@ const Writer = struct {
1617 .typeof_elem,1655 .typeof_elem,
1618 .struct_init_empty,1656 .struct_init_empty,
1619 .enum_to_int,1657 .enum_to_int,
1658 .type_info,
1620 => try self.writeUnNode(stream, inst),1659 => try self.writeUnNode(stream, inst),
16211660
1622 .ref,1661 .ref,
...@@ -1657,6 +1696,8 @@ const Writer = struct {...@@ -1657,6 +1696,8 @@ const Writer = struct {
1657 .union_decl,1696 .union_decl,
1658 .enum_decl,1697 .enum_decl,
1659 .enum_decl_nonexhaustive,1698 .enum_decl_nonexhaustive,
1699 .struct_init,
1700 .field_type,
1660 => try self.writePlNode(stream, inst),1701 => try self.writePlNode(stream, inst),
16611702
1662 .add,1703 .add,
...@@ -1676,12 +1717,14 @@ const Writer = struct {...@@ -1676,12 +1717,14 @@ const Writer = struct {
1676 .cmp_gt,1717 .cmp_gt,
1677 .cmp_neq,1718 .cmp_neq,
1678 .div,1719 .div,
1720 .has_decl,
1679 .mod_rem,1721 .mod_rem,
1680 .shl,1722 .shl,
1681 .shr,1723 .shr,
1682 .xor,1724 .xor,
1683 .store_node,1725 .store_node,
1684 .error_union_type,1726 .error_union_type,
1727 .@"export",
1685 .merge_error_sets,1728 .merge_error_sets,
1686 .bit_and,1729 .bit_and,
1687 .bit_or,1730 .bit_or,
test/stack_traces.zig+3-3
...@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -282,10 +282,10 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
282 \\source.zig:10:8: [address] in main (test)282 \\source.zig:10:8: [address] in main (test)
283 \\ foo();283 \\ foo();
284 \\ ^284 \\ ^
285 \\start.zig:342:29: [address] in std.start.posixCallMainAndExit (test)285 \\start.zig:404:29: [address] in std.start.posixCallMainAndExit (test)
286 \\ return root.main();286 \\ return root.main();
287 \\ ^287 \\ ^
288 \\start.zig:163:5: [address] in std.start._start (test)288 \\start.zig:225:5: [address] in std.start._start (test)
289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});289 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
290 \\ ^290 \\ ^
291 \\291 \\
...@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {...@@ -294,7 +294,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void {
294 switch (std.Target.current.cpu.arch) {294 switch (std.Target.current.cpu.arch) {
295 .aarch64 => "", // TODO disabled; results in segfault295 .aarch64 => "", // TODO disabled; results in segfault
296 else => 296 else =>
297 \\start.zig:163:5: [address] in std.start._start (test)297 \\start.zig:225:5: [address] in std.start._start (test)
298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});298 \\ @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
299 \\ ^299 \\ ^
300 \\300 \\
test/stage2/test.zig+78-2
...@@ -941,6 +941,32 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -941,6 +941,32 @@ pub fn addCases(ctx: *TestContext) !void {
941 "",941 "",
942 );942 );
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
944 // 64bit set stack970 // 64bit set stack
945 case.addCompareOutput(971 case.addCompareOutput(
946 \\export fn _start() noreturn {972 \\export fn _start() noreturn {
...@@ -1022,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1022,7 +1048,7 @@ pub fn addCases(ctx: *TestContext) !void {
1022 "Hello, World!\n",1048 "Hello, World!\n",
1023 );1049 );
1024 try case.files.append(.{1050 try case.files.append(.{
1025 .src = 1051 .src =
1026 \\pub fn print() void {1052 \\pub fn print() void {
1027 \\ asm volatile ("syscall"1053 \\ asm volatile ("syscall"
1028 \\ :1054 \\ :
...@@ -1038,11 +1064,61 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1038,11 +1064,61 @@ pub fn addCases(ctx: *TestContext) !void {
1038 .path = "print.zig",1064 .path = "print.zig",
1039 });1065 });
1040 }1066 }
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
1042 ctx.compileError("function redefinition", linux_x64,1105 ctx.compileError("function redefinition", linux_x64,
1106 \\// dummy comment
1043 \\fn entry() void {}1107 \\fn entry() void {}
1044 \\fn entry() void {}1108 \\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
1047 ctx.compileError("compileError", linux_x64,1123 ctx.compileError("compileError", linux_x64,
1048 \\export fn _start() noreturn {1124 \\export fn _start() noreturn {