authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-16 22:51:01-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-16 22:51:01-07:00
log8c9ac4db978c80246b4872c899b1618b1b195ec2
treee6bddfb9df54fc6d60518978506e6869c1b2be80
parent8436134499c623485aeb20374a9928685db4211e

stage2: implement error notes and regress -femit-zir

* Implement error notes - note: other symbol exported here - note: previous else prong is here - note: previous '_' prong is here * Add Compilation.CObject.ErrorMsg. This object properly converts to AllErrors.Message when the time comes. * Add Compilation.CObject.failure_retryable. Properly handles out-of-memory and other transient failures. * Introduce Module.SrcLoc which has not only a byte offset but also references the file which the byte offset applies to. * Scope.Block now contains both a pointer to the "owner" Decl and the "source" Decl. As an example, during inline function call, the "owner" will be the Decl of the caller and the "source" will be the Decl of the callee. * Module.ErrorMsg now sports a `file_scope` field so that notes can refer to source locations in a file other than the parent error message. * Some instances where a `*Scope` was stored, now store a `*Scope.Container`. * Some methods in the `Scope` namespace were moved to the more specific type, since there was only an implementation for one particular tag. - `removeDecl` moved to `Scope.Container` - `destroy` moved to `Scope.File` * Two kinds of Scope deleted: - zir_module - decl * astgen: properly use DeclVal / DeclRef. DeclVal was incorrectly changed to be a reference; this commit fixes it. Fewer ZIR instructions processed as a result. - declval_in_module is renamed to declval - previous declval ZIR instruction is deleted; it was only for .zir files. * Test harness: friendlier diagnostics when an unexpected set of errors is encountered. * zir_sema: fix analyzeInstBlockFlat by properly calling resolvingInst on the last zir instruction in the block. Compile log implementation: * Write to a buffer rather than directly to stderr. * Only keep track of 1 callsite per Decl. * No longer mutate the ZIR Inst struct data. * "Compile log statement found" errors are only emitted when there are no other compile errors. -femit-zir and support for .zir source files is regressed. If we wanted to support this again, outputting .zir would need to be done as yet another backend rather than in the haphazard way it was previously implemented. For parsing .zir, it was implemented previously in a way that was not helpful for debugging. We need tighter integration with the test harness for it to be useful; so clearly a rewrite is needed. Given that a rewrite is needed, and it was getting in the way of progress and organization of the rest of stage2, I regressed the feature.

18 files changed, 904 insertions(+), 2618 deletions(-)

src/Compilation.zig+179-126
...@@ -51,7 +51,7 @@ c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),...@@ -51,7 +51,7 @@ c_object_work_queue: std.fifo.LinearFifo(*CObject, .Dynamic),
5151
52/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.52/// The ErrorMsg memory is owned by the `CObject`, using Compilation's general purpose allocator.
53/// This data is accessed by multiple threads and is protected by `mutex`.53/// This data is accessed by multiple threads and is protected by `mutex`.
54failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *ErrorMsg) = .{},54failed_c_objects: std.AutoArrayHashMapUnmanaged(*CObject, *CObject.ErrorMsg) = .{},
5555
56keep_source_files_loaded: bool,56keep_source_files_loaded: bool,
57use_clang: bool,57use_clang: bool,
...@@ -215,13 +215,29 @@ pub const CObject = struct {...@@ -215,13 +215,29 @@ pub const CObject = struct {
215 },215 },
216 /// There will be a corresponding ErrorMsg in Compilation.failed_c_objects.216 /// There will be a corresponding ErrorMsg in Compilation.failed_c_objects.
217 failure,217 failure,
218 /// A transient failure happened when trying to compile the C Object; it may
219 /// succeed if we try again. There may be a corresponding ErrorMsg in
220 /// Compilation.failed_c_objects. If there is not, the failure is out of memory.
221 failure_retryable,
218 },222 },
219223
224 pub const ErrorMsg = struct {
225 msg: []const u8,
226 line: u32,
227 column: u32,
228
229 pub fn destroy(em: *ErrorMsg, gpa: *Allocator) void {
230 gpa.free(em.msg);
231 gpa.destroy(em);
232 em.* = undefined;
233 }
234 };
235
220 /// Returns if there was failure.236 /// Returns if there was failure.
221 pub fn clearStatus(self: *CObject, gpa: *Allocator) bool {237 pub fn clearStatus(self: *CObject, gpa: *Allocator) bool {
222 switch (self.status) {238 switch (self.status) {
223 .new => return false,239 .new => return false,
224 .failure => {240 .failure, .failure_retryable => {
225 self.status = .new;241 self.status = .new;
226 return true;242 return true;
227 },243 },
...@@ -240,6 +256,11 @@ pub const CObject = struct {...@@ -240,6 +256,11 @@ pub const CObject = struct {
240 }256 }
241};257};
242258
259/// To support incremental compilation, errors are stored in various places
260/// so that they can be created and destroyed appropriately. This structure
261/// is used to collect all the errors from the various places into one
262/// convenient place for API users to consume. It is allocated into 1 heap
263/// and freed all at once.
243pub const AllErrors = struct {264pub const AllErrors = struct {
244 arena: std.heap.ArenaAllocator.State,265 arena: std.heap.ArenaAllocator.State,
245 list: []const Message,266 list: []const Message,
...@@ -251,23 +272,32 @@ pub const AllErrors = struct {...@@ -251,23 +272,32 @@ pub const AllErrors = struct {
251 column: usize,272 column: usize,
252 byte_offset: usize,273 byte_offset: usize,
253 msg: []const u8,274 msg: []const u8,
275 notes: []Message = &.{},
254 },276 },
255 plain: struct {277 plain: struct {
256 msg: []const u8,278 msg: []const u8,
257 },279 },
258280
259 pub fn renderToStdErr(self: Message) void {281 pub fn renderToStdErr(msg: Message) void {
260 switch (self) {282 return msg.renderToStdErrInner("error");
283 }
284
285 fn renderToStdErrInner(msg: Message, kind: []const u8) void {
286 switch (msg) {
261 .src => |src| {287 .src => |src| {
262 std.debug.print("{s}:{d}:{d}: error: {s}\n", .{288 std.debug.print("{s}:{d}:{d}: {s}: {s}\n", .{
263 src.src_path,289 src.src_path,
264 src.line + 1,290 src.line + 1,
265 src.column + 1,291 src.column + 1,
292 kind,
266 src.msg,293 src.msg,
267 });294 });
295 for (src.notes) |note| {
296 note.renderToStdErrInner("note");
297 }
268 },298 },
269 .plain => |plain| {299 .plain => |plain| {
270 std.debug.print("error: {s}\n", .{plain.msg});300 std.debug.print("{s}: {s}\n", .{ kind, plain.msg });
271 },301 },
272 }302 }
273 }303 }
...@@ -278,20 +308,38 @@ pub const AllErrors = struct {...@@ -278,20 +308,38 @@ pub const AllErrors = struct {
278 }308 }
279309
280 fn add(310 fn add(
311 module: *Module,
281 arena: *std.heap.ArenaAllocator,312 arena: *std.heap.ArenaAllocator,
282 errors: *std.ArrayList(Message),313 errors: *std.ArrayList(Message),
283 sub_file_path: []const u8,314 module_err_msg: Module.ErrorMsg,
284 source: []const u8,
285 simple_err_msg: ErrorMsg,
286 ) !void {315 ) !void {
287 const loc = std.zig.findLineColumn(source, simple_err_msg.byte_offset);316 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);
317 for (notes) |*note, i| {
318 const module_note = module_err_msg.notes[i];
319 const source = try module_note.src_loc.file_scope.getSource(module);
320 const loc = std.zig.findLineColumn(source, module_note.src_loc.byte_offset);
321 const sub_file_path = module_note.src_loc.file_scope.sub_file_path;
322 note.* = .{
323 .src = .{
324 .src_path = try arena.allocator.dupe(u8, sub_file_path),
325 .msg = try arena.allocator.dupe(u8, module_note.msg),
326 .byte_offset = module_note.src_loc.byte_offset,
327 .line = loc.line,
328 .column = loc.column,
329 },
330 };
331 }
332 const source = try module_err_msg.src_loc.file_scope.getSource(module);
333 const loc = std.zig.findLineColumn(source, module_err_msg.src_loc.byte_offset);
334 const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path;
288 try errors.append(.{335 try errors.append(.{
289 .src = .{336 .src = .{
290 .src_path = try arena.allocator.dupe(u8, sub_file_path),337 .src_path = try arena.allocator.dupe(u8, sub_file_path),
291 .msg = try arena.allocator.dupe(u8, simple_err_msg.msg),338 .msg = try arena.allocator.dupe(u8, module_err_msg.msg),
292 .byte_offset = simple_err_msg.byte_offset,339 .byte_offset = module_err_msg.src_loc.byte_offset,
293 .line = loc.line,340 .line = loc.line,
294 .column = loc.column,341 .column = loc.column,
342 .notes = notes,
295 },343 },
296 });344 });
297 }345 }
...@@ -849,17 +897,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -849,17 +897,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
849 .ty = struct_ty,897 .ty = struct_ty,
850 },898 },
851 };899 };
852 break :rs &root_scope.base;900 break :rs root_scope;
853 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {901 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
854 const root_scope = try gpa.create(Module.Scope.ZIRModule);902 return error.ZirFilesUnsupported;
855 root_scope.* = .{
856 .sub_file_path = root_pkg.root_src_path,
857 .source = .{ .unloaded = {} },
858 .contents = .{ .not_available = {} },
859 .status = .never_loaded,
860 .decls = .{},
861 };
862 break :rs &root_scope.base;
863 } else {903 } else {
864 unreachable;904 unreachable;
865 }905 }
...@@ -1258,32 +1298,23 @@ pub fn update(self: *Compilation) !void {...@@ -1258,32 +1298,23 @@ pub fn update(self: *Compilation) !void {
1258 const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_llvm;1298 const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_llvm;
1259 if (!use_stage1) {1299 if (!use_stage1) {
1260 if (self.bin_file.options.module) |module| {1300 if (self.bin_file.options.module) |module| {
1301 module.compile_log_text.shrinkAndFree(module.gpa, 0);
1261 module.generation += 1;1302 module.generation += 1;
12621303
1263 // TODO Detect which source files changed.1304 // TODO Detect which source files changed.
1264 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;1305 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
1265 // to force a refresh we unload now.1306 // to force a refresh we unload now.
1266 if (module.root_scope.cast(Module.Scope.File)) |zig_file| {1307 module.root_scope.unload(module.gpa);
1267 zig_file.unload(module.gpa);1308 module.failed_root_src_file = null;
1268 module.failed_root_src_file = null;1309 module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {
1269 module.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {1310 error.AnalysisFail => {
1270 error.AnalysisFail => {1311 assert(self.totalErrorCount() != 0);
1271 assert(self.totalErrorCount() != 0);1312 },
1272 },1313 error.OutOfMemory => return error.OutOfMemory,
1273 error.OutOfMemory => return error.OutOfMemory,1314 else => |e| {
1274 else => |e| {1315 module.failed_root_src_file = e;
1275 module.failed_root_src_file = e;1316 },
1276 },1317 };
1277 };
1278 } else if (module.root_scope.cast(Module.Scope.ZIRModule)) |zir_module| {
1279 zir_module.unload(module.gpa);
1280 module.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
1281 error.AnalysisFail => {
1282 assert(self.totalErrorCount() != 0);
1283 },
1284 else => |e| return e,
1285 };
1286 }
12871318
1288 // TODO only analyze imports if they are still referenced1319 // TODO only analyze imports if they are still referenced
1289 for (module.import_table.items()) |entry| {1320 for (module.import_table.items()) |entry| {
...@@ -1359,14 +1390,18 @@ pub fn totalErrorCount(self: *Compilation) usize {...@@ -1359,14 +1390,18 @@ pub fn totalErrorCount(self: *Compilation) usize {
1359 module.failed_exports.items().len +1390 module.failed_exports.items().len +
1360 module.failed_files.items().len +1391 module.failed_files.items().len +
1361 @boolToInt(module.failed_root_src_file != null);1392 @boolToInt(module.failed_root_src_file != null);
1362 for (module.compile_log_decls.items()) |entry| {
1363 total += entry.value.items.len;
1364 }
1365 }1393 }
13661394
1367 // The "no entry point found" error only counts if there are no other errors.1395 // The "no entry point found" error only counts if there are no other errors.
1368 if (total == 0) {1396 if (total == 0) {
1369 return @boolToInt(self.link_error_flags.no_entry_point_found);1397 total += @boolToInt(self.link_error_flags.no_entry_point_found);
1398 }
1399
1400 // Compile log errors only count if there are no other errors.
1401 if (total == 0) {
1402 if (self.bin_file.options.module) |module| {
1403 total += @boolToInt(module.compile_log_decls.items().len != 0);
1404 }
1370 }1405 }
13711406
1372 return total;1407 return total;
...@@ -1382,32 +1417,32 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1382,32 +1417,32 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1382 for (self.failed_c_objects.items()) |entry| {1417 for (self.failed_c_objects.items()) |entry| {
1383 const c_object = entry.key;1418 const c_object = entry.key;
1384 const err_msg = entry.value;1419 const err_msg = entry.value;
1385 try AllErrors.add(&arena, &errors, c_object.src.src_path, "", err_msg.*);1420 // TODO these fields will need to be adjusted when we have proper
1421 // C error reporting bubbling up.
1422 try errors.append(.{
1423 .src = .{
1424 .src_path = try arena.allocator.dupe(u8, c_object.src.src_path),
1425 .msg = try std.fmt.allocPrint(&arena.allocator, "unable to build C object: {s}", .{
1426 err_msg.msg,
1427 }),
1428 .byte_offset = 0,
1429 .line = err_msg.line,
1430 .column = err_msg.column,
1431 },
1432 });
1386 }1433 }
1387 if (self.bin_file.options.module) |module| {1434 if (self.bin_file.options.module) |module| {
1388 for (module.failed_files.items()) |entry| {1435 for (module.failed_files.items()) |entry| {
1389 const scope = entry.key;1436 try AllErrors.add(module, &arena, &errors, entry.value.*);
1390 const err_msg = entry.value;
1391 const source = try scope.getSource(module);
1392 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
1393 }1437 }
1394 for (module.failed_decls.items()) |entry| {1438 for (module.failed_decls.items()) |entry| {
1395 const decl = entry.key;1439 try AllErrors.add(module, &arena, &errors, entry.value.*);
1396 const err_msg = entry.value;
1397 const source = try decl.scope.getSource(module);
1398 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
1399 }1440 }
1400 for (module.emit_h_failed_decls.items()) |entry| {1441 for (module.emit_h_failed_decls.items()) |entry| {
1401 const decl = entry.key;1442 try AllErrors.add(module, &arena, &errors, entry.value.*);
1402 const err_msg = entry.value;
1403 const source = try decl.scope.getSource(module);
1404 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
1405 }1443 }
1406 for (module.failed_exports.items()) |entry| {1444 for (module.failed_exports.items()) |entry| {
1407 const decl = entry.key.owner_decl;1445 try AllErrors.add(module, &arena, &errors, entry.value.*);
1408 const err_msg = entry.value;
1409 const source = try decl.scope.getSource(module);
1410 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
1411 }1446 }
1412 if (module.failed_root_src_file) |err| {1447 if (module.failed_root_src_file) |err| {
1413 const file_path = try module.root_pkg.root_src_directory.join(&arena.allocator, &[_][]const u8{1448 const file_path = try module.root_pkg.root_src_directory.join(&arena.allocator, &[_][]const u8{
...@@ -1418,15 +1453,6 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1418,15 +1453,6 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1418 });1453 });
1419 try AllErrors.addPlain(&arena, &errors, msg);1454 try AllErrors.addPlain(&arena, &errors, msg);
1420 }1455 }
1421 for (module.compile_log_decls.items()) |entry| {
1422 const decl = entry.key;
1423 const path = decl.scope.subFilePath();
1424 const source = try decl.scope.getSource(module);
1425 for (entry.value.items) |src_loc| {
1426 const err_msg = ErrorMsg{ .byte_offset = src_loc, .msg = "found compile log statement" };
1427 try AllErrors.add(&arena, &errors, path, source, err_msg);
1428 }
1429 }
1430 }1456 }
14311457
1432 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {1458 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
...@@ -1437,6 +1463,28 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1437,6 +1463,28 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1437 });1463 });
1438 }1464 }
14391465
1466 if (self.bin_file.options.module) |module| {
1467 const compile_log_items = module.compile_log_decls.items();
1468 if (errors.items.len == 0 and compile_log_items.len != 0) {
1469 // First one will be the error; subsequent ones will be notes.
1470 const err_msg = Module.ErrorMsg{
1471 .src_loc = compile_log_items[0].value,
1472 .msg = "found compile log statement",
1473 .notes = try self.gpa.alloc(Module.ErrorMsg, compile_log_items.len - 1),
1474 };
1475 defer self.gpa.free(err_msg.notes);
1476
1477 for (compile_log_items[1..]) |entry, i| {
1478 err_msg.notes[i] = .{
1479 .src_loc = entry.value,
1480 .msg = "also here",
1481 };
1482 }
1483
1484 try AllErrors.add(module, &arena, &errors, err_msg);
1485 }
1486 }
1487
1440 assert(errors.items.len == self.totalErrorCount());1488 assert(errors.items.len == self.totalErrorCount());
14411489
1442 return AllErrors{1490 return AllErrors{
...@@ -1445,6 +1493,11 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {...@@ -1445,6 +1493,11 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
1445 };1493 };
1446}1494}
14471495
1496pub fn getCompileLogOutput(self: *Compilation) []const u8 {
1497 const module = self.bin_file.options.module orelse return &[0]u8{};
1498 return module.compile_log_text.items;
1499}
1500
1448pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void {1501pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemory }!void {
1449 var progress: std.Progress = .{};1502 var progress: std.Progress = .{};
1450 var main_progress_node = try progress.start("", 0);1503 var main_progress_node = try progress.start("", 0);
...@@ -1517,9 +1570,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -1517,9 +1570,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
1517 },1570 },
1518 else => {1571 else => {
1519 try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);1572 try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
1520 module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(1573 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
1521 module.gpa,1574 module.gpa,
1522 decl.src(),1575 decl.srcLoc(),
1523 "unable to codegen: {s}",1576 "unable to codegen: {s}",
1524 .{@errorName(err)},1577 .{@errorName(err)},
1525 ));1578 ));
...@@ -1586,9 +1639,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor...@@ -1586,9 +1639,9 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
1586 const module = self.bin_file.options.module.?;1639 const module = self.bin_file.options.module.?;
1587 self.bin_file.updateDeclLineNumber(module, decl) catch |err| {1640 self.bin_file.updateDeclLineNumber(module, decl) catch |err| {
1588 try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);1641 try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
1589 module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(1642 module.failed_decls.putAssumeCapacityNoClobber(decl, try Module.ErrorMsg.create(
1590 module.gpa,1643 module.gpa,
1591 decl.src(),1644 decl.srcLoc(),
1592 "unable to update line number: {s}",1645 "unable to update line number: {s}",
1593 .{@errorName(err)},1646 .{@errorName(err)},
1594 ));1647 ));
...@@ -1858,26 +1911,38 @@ fn workerUpdateCObject(...@@ -1858,26 +1911,38 @@ fn workerUpdateCObject(
1858 comp.updateCObject(c_object, progress_node) catch |err| switch (err) {1911 comp.updateCObject(c_object, progress_node) catch |err| switch (err) {
1859 error.AnalysisFail => return,1912 error.AnalysisFail => return,
1860 else => {1913 else => {
1861 {1914 comp.reportRetryableCObjectError(c_object, err) catch |oom| switch (oom) {
1862 const lock = comp.mutex.acquire();1915 // Swallowing this error is OK because it's implied to be OOM when
1863 defer lock.release();1916 // there is a missing failed_c_objects error message.
1864 comp.failed_c_objects.ensureCapacity(comp.gpa, comp.failed_c_objects.items().len + 1) catch {1917 error.OutOfMemory => {},
1865 fatal("TODO handle this by setting c_object.status = oom failure", .{});1918 };
1866 };
1867 comp.failed_c_objects.putAssumeCapacityNoClobber(c_object, ErrorMsg.create(
1868 comp.gpa,
1869 0,
1870 "unable to build C object: {s}",
1871 .{@errorName(err)},
1872 ) catch {
1873 fatal("TODO handle this by setting c_object.status = oom failure", .{});
1874 });
1875 }
1876 c_object.status = .{ .failure = {} };
1877 },1919 },
1878 };1920 };
1879}1921}
18801922
1923fn reportRetryableCObjectError(
1924 comp: *Compilation,
1925 c_object: *CObject,
1926 err: anyerror,
1927) error{OutOfMemory}!void {
1928 c_object.status = .failure_retryable;
1929
1930 const c_obj_err_msg = try comp.gpa.create(CObject.ErrorMsg);
1931 errdefer comp.gpa.destroy(c_obj_err_msg);
1932 const msg = try std.fmt.allocPrint(comp.gpa, "unable to build C object: {s}", .{@errorName(err)});
1933 errdefer comp.gpa.free(msg);
1934 c_obj_err_msg.* = .{
1935 .msg = msg,
1936 .line = 0,
1937 .column = 0,
1938 };
1939 {
1940 const lock = comp.mutex.acquire();
1941 defer lock.release();
1942 try comp.failed_c_objects.putNoClobber(comp.gpa, c_object, c_obj_err_msg);
1943 }
1944}
1945
1881fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *std.Progress.Node) !void {1946fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *std.Progress.Node) !void {
1882 if (!build_options.have_llvm) {1947 if (!build_options.have_llvm) {
1883 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});1948 return comp.failCObj(c_object, "clang not available: compiler built without LLVM extensions", .{});
...@@ -1892,7 +1957,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *...@@ -1892,7 +1957,9 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_comp_progress_node: *
1892 // There was previous failure.1957 // There was previous failure.
1893 const lock = comp.mutex.acquire();1958 const lock = comp.mutex.acquire();
1894 defer lock.release();1959 defer lock.release();
1895 comp.failed_c_objects.removeAssertDiscard(c_object);1960 // If the failure was OOM, there will not be an entry here, so we do
1961 // not assert discard.
1962 _ = comp.failed_c_objects.swapRemove(c_object);
1896 }1963 }
18971964
1898 var man = comp.obtainCObjectCacheManifest();1965 var man = comp.obtainCObjectCacheManifest();
...@@ -2343,11 +2410,27 @@ pub fn addCCArgs(...@@ -2343,11 +2410,27 @@ pub fn addCCArgs(
23432410
2344fn failCObj(comp: *Compilation, c_object: *CObject, comptime format: []const u8, args: anytype) InnerError {2411fn failCObj(comp: *Compilation, c_object: *CObject, comptime format: []const u8, args: anytype) InnerError {
2345 @setCold(true);2412 @setCold(true);
2346 const err_msg = try ErrorMsg.create(comp.gpa, 0, "unable to build C object: " ++ format, args);2413 const err_msg = blk: {
2414 const msg = try std.fmt.allocPrint(comp.gpa, format, args);
2415 errdefer comp.gpa.free(msg);
2416 const err_msg = try comp.gpa.create(CObject.ErrorMsg);
2417 errdefer comp.gpa.destroy(err_msg);
2418 err_msg.* = .{
2419 .msg = msg,
2420 .line = 0,
2421 .column = 0,
2422 };
2423 break :blk err_msg;
2424 };
2347 return comp.failCObjWithOwnedErrorMsg(c_object, err_msg);2425 return comp.failCObjWithOwnedErrorMsg(c_object, err_msg);
2348}2426}
23492427
2350fn failCObjWithOwnedErrorMsg(comp: *Compilation, c_object: *CObject, err_msg: *ErrorMsg) InnerError {2428fn failCObjWithOwnedErrorMsg(
2429 comp: *Compilation,
2430 c_object: *CObject,
2431 err_msg: *CObject.ErrorMsg,
2432) InnerError {
2433 @setCold(true);
2351 {2434 {
2352 const lock = comp.mutex.acquire();2435 const lock = comp.mutex.acquire();
2353 defer lock.release();2436 defer lock.release();
...@@ -2361,36 +2444,6 @@ fn failCObjWithOwnedErrorMsg(comp: *Compilation, c_object: *CObject, err_msg: *E...@@ -2361,36 +2444,6 @@ fn failCObjWithOwnedErrorMsg(comp: *Compilation, c_object: *CObject, err_msg: *E
2361 return error.AnalysisFail;2444 return error.AnalysisFail;
2362}2445}
23632446
2364pub const ErrorMsg = struct {
2365 byte_offset: usize,
2366 msg: []const u8,
2367
2368 pub fn create(gpa: *Allocator, byte_offset: usize, comptime format: []const u8, args: anytype) !*ErrorMsg {
2369 const self = try gpa.create(ErrorMsg);
2370 errdefer gpa.destroy(self);
2371 self.* = try init(gpa, byte_offset, format, args);
2372 return self;
2373 }
2374
2375 /// Assumes the ErrorMsg struct and msg were both allocated with allocator.
2376 pub fn destroy(self: *ErrorMsg, gpa: *Allocator) void {
2377 self.deinit(gpa);
2378 gpa.destroy(self);
2379 }
2380
2381 pub fn init(gpa: *Allocator, byte_offset: usize, comptime format: []const u8, args: anytype) !ErrorMsg {
2382 return ErrorMsg{
2383 .byte_offset = byte_offset,
2384 .msg = try std.fmt.allocPrint(gpa, format, args),
2385 };
2386 }
2387
2388 pub fn deinit(self: *ErrorMsg, gpa: *Allocator) void {
2389 gpa.free(self.msg);
2390 self.* = undefined;
2391 }
2392};
2393
2394pub const FileExt = enum {2447pub const FileExt = enum {
2395 c,2448 c,
2396 cpp,2449 cpp,
src/Module.zig+281-483
...@@ -35,8 +35,7 @@ zig_cache_artifact_directory: Compilation.Directory,...@@ -35,8 +35,7 @@ zig_cache_artifact_directory: Compilation.Directory,
35/// Pointer to externally managed resource. `null` if there is no zig file being compiled.35/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
36root_pkg: *Package,36root_pkg: *Package,
37/// Module owns this resource.37/// Module owns this resource.
38/// The `Scope` is either a `Scope.ZIRModule` or `Scope.File`.38root_scope: *Scope.File,
39root_scope: *Scope,
40/// It's rare for a decl to be exported, so we save memory by having a sparse map of39/// It's rare for a decl to be exported, so we save memory by having a sparse map of
41/// Decl pointers to details about them being exported.40/// Decl pointers to details about them being exported.
42/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.41/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
...@@ -57,19 +56,19 @@ decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_has...@@ -57,19 +56,19 @@ decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_has
57/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.56/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
58/// Note that a Decl can succeed but the Fn it represents can fail. In this case,57/// Note that a Decl can succeed but the Fn it represents can fail. In this case,
59/// a Decl can have a failed_decls entry but have analysis status of success.58/// a Decl can have a failed_decls entry but have analysis status of success.
60failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *Compilation.ErrorMsg) = .{},59failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},
61/// When emit_h is non-null, each Decl gets one more compile error slot for60/// When emit_h is non-null, each Decl gets one more compile error slot for
62/// emit-h failing for that Decl. This table is also how we tell if a Decl has61/// emit-h failing for that Decl. This table is also how we tell if a Decl has
63/// failed emit-h or succeeded.62/// failed emit-h or succeeded.
64emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *Compilation.ErrorMsg) = .{},63emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{},
65/// A Decl can have multiple compileLogs, but only one error, so we map a Decl to a the src locs of all the compileLogs64/// Keep track of one `@compileLog` callsite per owner Decl.
66compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, ArrayListUnmanaged(usize)) = .{},65compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{},
67/// Using a map here for consistency with the other fields here.66/// Using a map here for consistency with the other fields here.
68/// The ErrorMsg memory is owned by the `Scope`, using Module's general purpose allocator.67/// The ErrorMsg memory is owned by the `Scope`, using Module's general purpose allocator.
69failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *Compilation.ErrorMsg) = .{},68failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *ErrorMsg) = .{},
70/// Using a map here for consistency with the other fields here.69/// Using a map here for consistency with the other fields here.
71/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.70/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
72failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *Compilation.ErrorMsg) = .{},71failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
7372
74next_anon_name_index: usize = 0,73next_anon_name_index: usize = 0,
7574
...@@ -103,6 +102,8 @@ stage1_flags: packed struct {...@@ -103,6 +102,8 @@ stage1_flags: packed struct {
103102
104emit_h: ?Compilation.EmitLoc,103emit_h: ?Compilation.EmitLoc,
105104
105compile_log_text: std.ArrayListUnmanaged(u8) = .{},
106
106pub const Export = struct {107pub const Export = struct {
107 options: std.builtin.ExportOptions,108 options: std.builtin.ExportOptions,
108 /// Byte offset into the file that contains the export directive.109 /// Byte offset into the file that contains the export directive.
...@@ -138,9 +139,9 @@ pub const Decl = struct {...@@ -138,9 +139,9 @@ pub const Decl = struct {
138 /// mapping them to an address in the output file.139 /// mapping them to an address in the output file.
139 /// Memory owned by this decl, using Module's allocator.140 /// Memory owned by this decl, using Module's allocator.
140 name: [*:0]const u8,141 name: [*:0]const u8,
141 /// The direct parent container of the Decl. This is either a `Scope.Container` or `Scope.ZIRModule`.142 /// The direct parent container of the Decl.
142 /// Reference to externally owned memory.143 /// Reference to externally owned memory.
143 scope: *Scope,144 container: *Scope.Container,
144 /// The AST Node decl index or ZIR Inst index that contains this declaration.145 /// The AST Node decl index or ZIR Inst index that contains this declaration.
145 /// Must be recomputed when the corresponding source file is modified.146 /// Must be recomputed when the corresponding source file is modified.
146 src_index: usize,147 src_index: usize,
...@@ -235,31 +236,21 @@ pub const Decl = struct {...@@ -235,31 +236,21 @@ pub const Decl = struct {
235 }236 }
236 }237 }
237238
239 pub fn srcLoc(self: Decl) SrcLoc {
240 return .{
241 .byte_offset = self.src(),
242 .file_scope = self.getFileScope(),
243 };
244 }
245
238 pub fn src(self: Decl) usize {246 pub fn src(self: Decl) usize {
239 switch (self.scope.tag) {247 const tree = self.container.file_scope.contents.tree;
240 .container => {248 const decl_node = tree.root_node.decls()[self.src_index];
241 const container = @fieldParentPtr(Scope.Container, "base", self.scope);249 return tree.token_locs[decl_node.firstToken()].start;
242 const tree = container.file_scope.contents.tree;
243 // TODO Container should have its own decls()
244 const decl_node = tree.root_node.decls()[self.src_index];
245 return tree.token_locs[decl_node.firstToken()].start;
246 },
247 .zir_module => {
248 const zir_module = @fieldParentPtr(Scope.ZIRModule, "base", self.scope);
249 const module = zir_module.contents.module;
250 const src_decl = module.decls[self.src_index];
251 return src_decl.inst.src;
252 },
253 .file, .block => unreachable,
254 .gen_zir => unreachable,
255 .local_val => unreachable,
256 .local_ptr => unreachable,
257 .decl => unreachable,
258 }
259 }250 }
260251
261 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {252 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {
262 return self.scope.fullyQualifiedNameHash(mem.spanZ(self.name));253 return self.container.fullyQualifiedNameHash(mem.spanZ(self.name));
263 }254 }
264255
265 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {256 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {
...@@ -293,9 +284,8 @@ pub const Decl = struct {...@@ -293,9 +284,8 @@ pub const Decl = struct {
293 }284 }
294 }285 }
295286
296 /// Asserts that the `Decl` is part of AST and not ZIRModule.287 pub fn getFileScope(self: Decl) *Scope.File {
297 pub fn getFileScope(self: *Decl) *Scope.File {288 return self.container.file_scope;
298 return self.scope.cast(Scope.Container).?.file_scope;
299 }289 }
300290
301 pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {291 pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {
...@@ -326,7 +316,7 @@ pub const Fn = struct {...@@ -326,7 +316,7 @@ pub const Fn = struct {
326 /// Contains un-analyzed ZIR instructions generated from Zig source AST.316 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
327 /// Even after we finish analysis, the ZIR is kept in memory, so that317 /// Even after we finish analysis, the ZIR is kept in memory, so that
328 /// comptime and inline function calls can happen.318 /// comptime and inline function calls can happen.
329 zir: zir.Module.Body,319 zir: zir.Body,
330 /// undefined unless analysis state is `success`.320 /// undefined unless analysis state is `success`.
331 body: Body,321 body: Body,
332 state: Analysis,322 state: Analysis,
...@@ -373,47 +363,49 @@ pub const Scope = struct {...@@ -373,47 +363,49 @@ pub const Scope = struct {
373 return @fieldParentPtr(T, "base", base);363 return @fieldParentPtr(T, "base", base);
374 }364 }
375365
376 /// Asserts the scope has a parent which is a DeclAnalysis and366 /// Returns the arena Allocator associated with the Decl of the Scope.
377 /// returns the arena Allocator.
378 pub fn arena(self: *Scope) *Allocator {367 pub fn arena(self: *Scope) *Allocator {
379 switch (self.tag) {368 switch (self.tag) {
380 .block => return self.cast(Block).?.arena,369 .block => return self.cast(Block).?.arena,
381 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
382 .gen_zir => return self.cast(GenZIR).?.arena,370 .gen_zir => return self.cast(GenZIR).?.arena,
383 .local_val => return self.cast(LocalVal).?.gen_zir.arena,371 .local_val => return self.cast(LocalVal).?.gen_zir.arena,
384 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,372 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
385 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
386 .file => unreachable,373 .file => unreachable,
387 .container => unreachable,374 .container => unreachable,
388 }375 }
389 }376 }
390377
391 /// If the scope has a parent which is a `DeclAnalysis`,378 pub fn ownerDecl(self: *Scope) ?*Decl {
392 /// returns the `Decl`, otherwise returns `null`.379 return switch (self.tag) {
393 pub fn decl(self: *Scope) ?*Decl {380 .block => self.cast(Block).?.owner_decl,
381 .gen_zir => self.cast(GenZIR).?.decl,
382 .local_val => self.cast(LocalVal).?.gen_zir.decl,
383 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
384 .file => null,
385 .container => null,
386 };
387 }
388
389 pub fn srcDecl(self: *Scope) ?*Decl {
394 return switch (self.tag) {390 return switch (self.tag) {
395 .block => self.cast(Block).?.decl,391 .block => self.cast(Block).?.src_decl,
396 .gen_zir => self.cast(GenZIR).?.decl,392 .gen_zir => self.cast(GenZIR).?.decl,
397 .local_val => self.cast(LocalVal).?.gen_zir.decl,393 .local_val => self.cast(LocalVal).?.gen_zir.decl,
398 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,394 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
399 .decl => self.cast(DeclAnalysis).?.decl,
400 .zir_module => null,
401 .file => null,395 .file => null,
402 .container => null,396 .container => null,
403 };397 };
404 }398 }
405399
406 /// Asserts the scope has a parent which is a ZIRModule or Container and400 /// Asserts the scope has a parent which is a Container and returns it.
407 /// returns it.401 pub fn namespace(self: *Scope) *Container {
408 pub fn namespace(self: *Scope) *Scope {
409 switch (self.tag) {402 switch (self.tag) {
410 .block => return self.cast(Block).?.decl.scope,403 .block => return self.cast(Block).?.owner_decl.container,
411 .gen_zir => return self.cast(GenZIR).?.decl.scope,404 .gen_zir => return self.cast(GenZIR).?.decl.container,
412 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,405 .local_val => return self.cast(LocalVal).?.gen_zir.decl.container,
413 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,406 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container,
414 .decl => return self.cast(DeclAnalysis).?.decl.scope,407 .file => return &self.cast(File).?.root_container,
415 .file => return &self.cast(File).?.root_container.base,408 .container => return self.cast(Container).?,
416 .zir_module, .container => return self,
417 }409 }
418 }410 }
419411
...@@ -426,9 +418,7 @@ pub const Scope = struct {...@@ -426,9 +418,7 @@ pub const Scope = struct {
426 .gen_zir => unreachable,418 .gen_zir => unreachable,
427 .local_val => unreachable,419 .local_val => unreachable,
428 .local_ptr => unreachable,420 .local_ptr => unreachable,
429 .decl => unreachable,
430 .file => unreachable,421 .file => unreachable,
431 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
432 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),422 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),
433 }423 }
434 }424 }
...@@ -437,12 +427,10 @@ pub const Scope = struct {...@@ -437,12 +427,10 @@ pub const Scope = struct {
437 pub fn tree(self: *Scope) *ast.Tree {427 pub fn tree(self: *Scope) *ast.Tree {
438 switch (self.tag) {428 switch (self.tag) {
439 .file => return self.cast(File).?.contents.tree,429 .file => return self.cast(File).?.contents.tree,
440 .zir_module => unreachable,430 .block => return self.cast(Block).?.src_decl.container.file_scope.contents.tree,
441 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(Container).?.file_scope.contents.tree,431 .gen_zir => return self.cast(GenZIR).?.decl.container.file_scope.contents.tree,
442 .block => return self.cast(Block).?.decl.scope.cast(Container).?.file_scope.contents.tree,432 .local_val => return self.cast(LocalVal).?.gen_zir.decl.container.file_scope.contents.tree,
443 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(Container).?.file_scope.contents.tree,433 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.contents.tree,
444 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
445 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
446 .container => return self.cast(Container).?.file_scope.contents.tree,434 .container => return self.cast(Container).?.file_scope.contents.tree,
447 }435 }
448 }436 }
...@@ -454,38 +442,21 @@ pub const Scope = struct {...@@ -454,38 +442,21 @@ pub const Scope = struct {
454 .gen_zir => self.cast(GenZIR).?,442 .gen_zir => self.cast(GenZIR).?,
455 .local_val => return self.cast(LocalVal).?.gen_zir,443 .local_val => return self.cast(LocalVal).?.gen_zir,
456 .local_ptr => return self.cast(LocalPtr).?.gen_zir,444 .local_ptr => return self.cast(LocalPtr).?.gen_zir,
457 .decl => unreachable,
458 .zir_module => unreachable,
459 .file => unreachable,445 .file => unreachable,
460 .container => unreachable,446 .container => unreachable,
461 };447 };
462 }448 }
463449
464 /// Asserts the scope has a parent which is a ZIRModule, Container or File and450 /// Asserts the scope has a parent which is a Container or File and
465 /// returns the sub_file_path field.451 /// returns the sub_file_path field.
466 pub fn subFilePath(base: *Scope) []const u8 {452 pub fn subFilePath(base: *Scope) []const u8 {
467 switch (base.tag) {453 switch (base.tag) {
468 .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path,454 .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path,
469 .file => return @fieldParentPtr(File, "base", base).sub_file_path,455 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
470 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
471 .block => unreachable,456 .block => unreachable,
472 .gen_zir => unreachable,457 .gen_zir => unreachable,
473 .local_val => unreachable,458 .local_val => unreachable,
474 .local_ptr => unreachable,459 .local_ptr => unreachable,
475 .decl => unreachable,
476 }
477 }
478
479 pub fn unload(base: *Scope, gpa: *Allocator) void {
480 switch (base.tag) {
481 .file => return @fieldParentPtr(File, "base", base).unload(gpa),
482 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),
483 .block => unreachable,
484 .gen_zir => unreachable,
485 .local_val => unreachable,
486 .local_ptr => unreachable,
487 .decl => unreachable,
488 .container => unreachable,
489 }460 }
490 }461 }
491462
...@@ -493,67 +464,28 @@ pub const Scope = struct {...@@ -493,67 +464,28 @@ pub const Scope = struct {
493 switch (base.tag) {464 switch (base.tag) {
494 .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module),465 .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module),
495 .file => return @fieldParentPtr(File, "base", base).getSource(module),466 .file => return @fieldParentPtr(File, "base", base).getSource(module),
496 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
497 .gen_zir => unreachable,467 .gen_zir => unreachable,
498 .local_val => unreachable,468 .local_val => unreachable,
499 .local_ptr => unreachable,469 .local_ptr => unreachable,
500 .block => unreachable,470 .block => unreachable,
501 .decl => unreachable,
502 }471 }
503 }472 }
504473
474 /// When called from inside a Block Scope, chases the src_decl, not the owner_decl.
505 pub fn getFileScope(base: *Scope) *Scope.File {475 pub fn getFileScope(base: *Scope) *Scope.File {
506 var cur = base;476 var cur = base;
507 while (true) {477 while (true) {
508 cur = switch (cur.tag) {478 cur = switch (cur.tag) {
509 .container => return @fieldParentPtr(Container, "base", cur).file_scope,479 .container => return @fieldParentPtr(Container, "base", cur).file_scope,
510 .file => return @fieldParentPtr(File, "base", cur),480 .file => return @fieldParentPtr(File, "base", cur),
511 .zir_module => unreachable, // TODO are zir modules allowed to import packages?
512 .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,481 .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,
513 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,482 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
514 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,483 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
515 .block => @fieldParentPtr(Block, "base", cur).decl.scope,484 .block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope,
516 .decl => @fieldParentPtr(DeclAnalysis, "base", cur).decl.scope,
517 };485 };
518 }486 }
519 }487 }
520488
521 /// Asserts the scope is a namespace Scope and removes the Decl from the namespace.
522 pub fn removeDecl(base: *Scope, child: *Decl) void {
523 switch (base.tag) {
524 .container => return @fieldParentPtr(Container, "base", base).removeDecl(child),
525 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
526 .file => unreachable,
527 .block => unreachable,
528 .gen_zir => unreachable,
529 .local_val => unreachable,
530 .local_ptr => unreachable,
531 .decl => unreachable,
532 }
533 }
534
535 /// Asserts the scope is a File or ZIRModule and deinitializes it, then deallocates it.
536 pub fn destroy(base: *Scope, gpa: *Allocator) void {
537 switch (base.tag) {
538 .file => {
539 const scope_file = @fieldParentPtr(File, "base", base);
540 scope_file.deinit(gpa);
541 gpa.destroy(scope_file);
542 },
543 .zir_module => {
544 const scope_zir_module = @fieldParentPtr(ZIRModule, "base", base);
545 scope_zir_module.deinit(gpa);
546 gpa.destroy(scope_zir_module);
547 },
548 .block => unreachable,
549 .gen_zir => unreachable,
550 .local_val => unreachable,
551 .local_ptr => unreachable,
552 .decl => unreachable,
553 .container => unreachable,
554 }
555 }
556
557 fn name_hash_hash(x: NameHash) u32 {489 fn name_hash_hash(x: NameHash) u32 {
558 return @truncate(u32, @bitCast(u128, x));490 return @truncate(u32, @bitCast(u128, x));
559 }491 }
...@@ -563,14 +495,11 @@ pub const Scope = struct {...@@ -563,14 +495,11 @@ pub const Scope = struct {
563 }495 }
564496
565 pub const Tag = enum {497 pub const Tag = enum {
566 /// .zir source code.
567 zir_module,
568 /// .zig source code.498 /// .zig source code.
569 file,499 file,
570 /// struct, enum or union, every .file contains one of these.500 /// struct, enum or union, every .file contains one of these.
571 container,501 container,
572 block,502 block,
573 decl,
574 gen_zir,503 gen_zir,
575 local_val,504 local_val,
576 local_ptr,505 local_ptr,
...@@ -657,6 +586,11 @@ pub const Scope = struct {...@@ -657,6 +586,11 @@ pub const Scope = struct {
657 self.* = undefined;586 self.* = undefined;
658 }587 }
659588
589 pub fn destroy(self: *File, gpa: *Allocator) void {
590 self.deinit(gpa);
591 gpa.destroy(self);
592 }
593
660 pub fn dumpSrc(self: *File, src: usize) void {594 pub fn dumpSrc(self: *File, src: usize) void {
661 const loc = std.zig.findLineColumn(self.source.bytes, src);595 const loc = std.zig.findLineColumn(self.source.bytes, src);
662 std.debug.print("{s}:{d}:{d}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });596 std.debug.print("{s}:{d}:{d}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
...@@ -681,109 +615,6 @@ pub const Scope = struct {...@@ -681,109 +615,6 @@ pub const Scope = struct {
681 }615 }
682 };616 };
683617
684 pub const ZIRModule = struct {
685 pub const base_tag: Tag = .zir_module;
686 base: Scope = Scope{ .tag = base_tag },
687 /// Relative to the owning package's root_src_dir.
688 /// Reference to external memory, not owned by ZIRModule.
689 sub_file_path: []const u8,
690 source: union(enum) {
691 unloaded: void,
692 bytes: [:0]const u8,
693 },
694 contents: union {
695 not_available: void,
696 module: *zir.Module,
697 },
698 status: enum {
699 never_loaded,
700 unloaded_success,
701 unloaded_parse_failure,
702 unloaded_sema_failure,
703
704 loaded_sema_failure,
705 loaded_success,
706 },
707
708 /// Even though .zir files only have 1 module, this set is still needed
709 /// because of anonymous Decls, which can exist in the global set, but
710 /// not this one.
711 decls: ArrayListUnmanaged(*Decl),
712
713 pub fn unload(self: *ZIRModule, gpa: *Allocator) void {
714 switch (self.status) {
715 .never_loaded,
716 .unloaded_parse_failure,
717 .unloaded_sema_failure,
718 .unloaded_success,
719 => {},
720
721 .loaded_success => {
722 self.contents.module.deinit(gpa);
723 gpa.destroy(self.contents.module);
724 self.contents = .{ .not_available = {} };
725 self.status = .unloaded_success;
726 },
727 .loaded_sema_failure => {
728 self.contents.module.deinit(gpa);
729 gpa.destroy(self.contents.module);
730 self.contents = .{ .not_available = {} };
731 self.status = .unloaded_sema_failure;
732 },
733 }
734 switch (self.source) {
735 .bytes => |bytes| {
736 gpa.free(bytes);
737 self.source = .{ .unloaded = {} };
738 },
739 .unloaded => {},
740 }
741 }
742
743 pub fn deinit(self: *ZIRModule, gpa: *Allocator) void {
744 self.decls.deinit(gpa);
745 self.unload(gpa);
746 self.* = undefined;
747 }
748
749 pub fn removeDecl(self: *ZIRModule, child: *Decl) void {
750 for (self.decls.items) |item, i| {
751 if (item == child) {
752 _ = self.decls.swapRemove(i);
753 return;
754 }
755 }
756 }
757
758 pub fn dumpSrc(self: *ZIRModule, src: usize) void {
759 const loc = std.zig.findLineColumn(self.source.bytes, src);
760 std.debug.print("{s}:{d}:{d}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
761 }
762
763 pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 {
764 switch (self.source) {
765 .unloaded => {
766 const source = try module.root_pkg.root_src_directory.handle.readFileAllocOptions(
767 module.gpa,
768 self.sub_file_path,
769 std.math.maxInt(u32),
770 null,
771 1,
772 0,
773 );
774 self.source = .{ .bytes = source };
775 return source;
776 },
777 .bytes => |bytes| return bytes,
778 }
779 }
780
781 pub fn fullyQualifiedNameHash(self: *ZIRModule, name: []const u8) NameHash {
782 // ZIR modules only have 1 file with all decls global in the same namespace.
783 return std.zig.hashSrc(name);
784 }
785 };
786
787 /// This is a temporary structure, references to it are valid only618 /// This is a temporary structure, references to it are valid only
788 /// during semantic analysis of the block.619 /// during semantic analysis of the block.
789 pub const Block = struct {620 pub const Block = struct {
...@@ -794,9 +625,14 @@ pub const Scope = struct {...@@ -794,9 +625,14 @@ pub const Scope = struct {
794 /// Maps ZIR to TZIR. Shared to sub-blocks.625 /// Maps ZIR to TZIR. Shared to sub-blocks.
795 inst_table: *InstTable,626 inst_table: *InstTable,
796 func: ?*Fn,627 func: ?*Fn,
797 decl: *Decl,628 /// When analyzing an inline function call, owner_decl is the Decl of the caller
629 /// and src_decl is the Decl of the callee.
630 /// This Decl owns the arena memory of this Block.
631 owner_decl: *Decl,
632 /// This Decl is the Decl according to the Zig source code corresponding to this Block.
633 src_decl: *Decl,
798 instructions: ArrayListUnmanaged(*Inst),634 instructions: ArrayListUnmanaged(*Inst),
799 /// Points to the arena allocator of DeclAnalysis635 /// Points to the arena allocator of the Decl.
800 arena: *Allocator,636 arena: *Allocator,
801 label: ?Label = null,637 label: ?Label = null,
802 inlining: ?*Inlining,638 inlining: ?*Inlining,
...@@ -845,21 +681,12 @@ pub const Scope = struct {...@@ -845,21 +681,12 @@ pub const Scope = struct {
845 }681 }
846 };682 };
847683
848 /// This is a temporary structure, references to it are valid only
849 /// during semantic analysis of the decl.
850 pub const DeclAnalysis = struct {
851 pub const base_tag: Tag = .decl;
852 base: Scope = Scope{ .tag = base_tag },
853 decl: *Decl,
854 arena: std.heap.ArenaAllocator,
855 };
856
857 /// This is a temporary structure, references to it are valid only684 /// This is a temporary structure, references to it are valid only
858 /// during semantic analysis of the decl.685 /// during semantic analysis of the decl.
859 pub const GenZIR = struct {686 pub const GenZIR = struct {
860 pub const base_tag: Tag = .gen_zir;687 pub const base_tag: Tag = .gen_zir;
861 base: Scope = Scope{ .tag = base_tag },688 base: Scope = Scope{ .tag = base_tag },
862 /// Parents can be: `GenZIR`, `ZIRModule`, `File`689 /// Parents can be: `GenZIR`, `File`
863 parent: *Scope,690 parent: *Scope,
864 decl: *Decl,691 decl: *Decl,
865 arena: *Allocator,692 arena: *Allocator,
...@@ -905,11 +732,73 @@ pub const Scope = struct {...@@ -905,11 +732,73 @@ pub const Scope = struct {
905 };732 };
906};733};
907734
735/// This struct holds data necessary to construct API-facing `AllErrors.Message`.
736/// Its memory is managed with the general purpose allocator so that they
737/// can be created and destroyed in response to incremental updates.
738/// In some cases, the Scope.File could have been inferred from where the ErrorMsg
739/// is stored. For example, if it is stored in Module.failed_decls, then the Scope.File
740/// would be determined by the Decl Scope. However, the data structure contains the field
741/// anyway so that `ErrorMsg` can be reused for error notes, which may be in a different
742/// file than the parent error message. It also simplifies processing of error messages.
743pub const ErrorMsg = struct {
744 src_loc: SrcLoc,
745 msg: []const u8,
746 notes: []ErrorMsg = &.{},
747
748 pub fn create(
749 gpa: *Allocator,
750 src_loc: SrcLoc,
751 comptime format: []const u8,
752 args: anytype,
753 ) !*ErrorMsg {
754 const self = try gpa.create(ErrorMsg);
755 errdefer gpa.destroy(self);
756 self.* = try init(gpa, src_loc, format, args);
757 return self;
758 }
759
760 /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`,
761 /// as well as all notes.
762 pub fn destroy(self: *ErrorMsg, gpa: *Allocator) void {
763 self.deinit(gpa);
764 gpa.destroy(self);
765 }
766
767 pub fn init(
768 gpa: *Allocator,
769 src_loc: SrcLoc,
770 comptime format: []const u8,
771 args: anytype,
772 ) !ErrorMsg {
773 return ErrorMsg{
774 .src_loc = src_loc,
775 .msg = try std.fmt.allocPrint(gpa, format, args),
776 };
777 }
778
779 pub fn deinit(self: *ErrorMsg, gpa: *Allocator) void {
780 for (self.notes) |*note| {
781 note.deinit(gpa);
782 }
783 gpa.free(self.notes);
784 gpa.free(self.msg);
785 self.* = undefined;
786 }
787};
788
789/// Canonical reference to a position within a source file.
790pub const SrcLoc = struct {
791 file_scope: *Scope.File,
792 byte_offset: usize,
793};
794
908pub const InnerError = error{ OutOfMemory, AnalysisFail };795pub const InnerError = error{ OutOfMemory, AnalysisFail };
909796
910pub fn deinit(self: *Module) void {797pub fn deinit(self: *Module) void {
911 const gpa = self.gpa;798 const gpa = self.gpa;
912799
800 self.compile_log_text.deinit(gpa);
801
913 self.zig_cache_artifact_directory.handle.close();802 self.zig_cache_artifact_directory.handle.close();
914803
915 self.deletion_set.deinit(gpa);804 self.deletion_set.deinit(gpa);
...@@ -939,9 +828,6 @@ pub fn deinit(self: *Module) void {...@@ -939,9 +828,6 @@ pub fn deinit(self: *Module) void {
939 }828 }
940 self.failed_exports.deinit(gpa);829 self.failed_exports.deinit(gpa);
941830
942 for (self.compile_log_decls.items()) |*entry| {
943 entry.value.deinit(gpa);
944 }
945 self.compile_log_decls.deinit(gpa);831 self.compile_log_decls.deinit(gpa);
946832
947 for (self.decl_exports.items()) |entry| {833 for (self.decl_exports.items()) |entry| {
...@@ -965,7 +851,7 @@ pub fn deinit(self: *Module) void {...@@ -965,7 +851,7 @@ pub fn deinit(self: *Module) void {
965 self.global_error_set.deinit(gpa);851 self.global_error_set.deinit(gpa);
966852
967 for (self.import_table.items()) |entry| {853 for (self.import_table.items()) |entry| {
968 entry.value.base.destroy(gpa);854 entry.value.destroy(gpa);
969 }855 }
970 self.import_table.deinit(gpa);856 self.import_table.deinit(gpa);
971}857}
...@@ -978,7 +864,7 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {...@@ -978,7 +864,7 @@ fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
978 gpa.free(export_list);864 gpa.free(export_list);
979}865}
980866
981pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {867pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void {
982 const tracy = trace(@src());868 const tracy = trace(@src());
983 defer tracy.end();869 defer tracy.end();
984870
...@@ -999,7 +885,7 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {...@@ -999,7 +885,7 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
999885
1000 // The exports this Decl performs will be re-discovered, so we remove them here886 // The exports this Decl performs will be re-discovered, so we remove them here
1001 // prior to re-analysis.887 // prior to re-analysis.
1002 self.deleteDeclExports(decl);888 mod.deleteDeclExports(decl);
1003 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.889 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
1004 for (decl.dependencies.items()) |entry| {890 for (decl.dependencies.items()) |entry| {
1005 const dep = entry.key;891 const dep = entry.key;
...@@ -1008,7 +894,7 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {...@@ -1008,7 +894,7 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
1008 // We don't perform a deletion here, because this Decl or another one894 // We don't perform a deletion here, because this Decl or another one
1009 // may end up referencing it before the update is complete.895 // may end up referencing it before the update is complete.
1010 dep.deletion_flag = true;896 dep.deletion_flag = true;
1011 try self.deletion_set.append(self.gpa, dep);897 try mod.deletion_set.append(mod.gpa, dep);
1012 }898 }
1013 }899 }
1014 decl.dependencies.clearRetainingCapacity();900 decl.dependencies.clearRetainingCapacity();
...@@ -1019,24 +905,21 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {...@@ -1019,24 +905,21 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
1019 .unreferenced => false,905 .unreferenced => false,
1020 };906 };
1021907
1022 const type_changed = if (self.root_scope.cast(Scope.ZIRModule)) |zir_module|908 const type_changed = mod.astGenAndAnalyzeDecl(decl) catch |err| switch (err) {
1023 try zir_sema.analyzeZirDecl(self, decl, zir_module.contents.module.decls[decl.src_index])909 error.OutOfMemory => return error.OutOfMemory,
1024 else910 error.AnalysisFail => return error.AnalysisFail,
1025 self.astGenAndAnalyzeDecl(decl) catch |err| switch (err) {911 else => {
1026 error.OutOfMemory => return error.OutOfMemory,912 decl.analysis = .sema_failure_retryable;
1027 error.AnalysisFail => return error.AnalysisFail,913 try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1);
1028 else => {914 mod.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
1029 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);915 mod.gpa,
1030 self.failed_decls.putAssumeCapacityNoClobber(decl, try Compilation.ErrorMsg.create(916 decl.srcLoc(),
1031 self.gpa,917 "unable to analyze: {s}",
1032 decl.src(),918 .{@errorName(err)},
1033 "unable to analyze: {s}",919 ));
1034 .{@errorName(err)},920 return error.AnalysisFail;
1035 ));921 },
1036 decl.analysis = .sema_failure_retryable;922 };
1037 return error.AnalysisFail;
1038 },
1039 };
1040923
1041 if (subsequent_analysis) {924 if (subsequent_analysis) {
1042 // We may need to chase the dependants and re-analyze them.925 // We may need to chase the dependants and re-analyze them.
...@@ -1055,8 +938,8 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {...@@ -1055,8 +938,8 @@ pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
1055 .codegen_failure,938 .codegen_failure,
1056 .codegen_failure_retryable,939 .codegen_failure_retryable,
1057 .complete,940 .complete,
1058 => if (dep.generation != self.generation) {941 => if (dep.generation != mod.generation) {
1059 try self.markOutdatedDecl(dep);942 try mod.markOutdatedDecl(dep);
1060 },943 },
1061 }944 }
1062 }945 }
...@@ -1068,8 +951,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1068,8 +951,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1068 const tracy = trace(@src());951 const tracy = trace(@src());
1069 defer tracy.end();952 defer tracy.end();
1070953
1071 const container_scope = decl.scope.cast(Scope.Container).?;954 const tree = try self.getAstTree(decl.container.file_scope);
1072 const tree = try self.getAstTree(container_scope.file_scope);
1073 const ast_node = tree.root_node.decls()[decl.src_index];955 const ast_node = tree.root_node.decls()[decl.src_index];
1074 switch (ast_node.tag) {956 switch (ast_node.tag) {
1075 .FnProto => {957 .FnProto => {
...@@ -1085,7 +967,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1085,7 +967,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1085 var fn_type_scope: Scope.GenZIR = .{967 var fn_type_scope: Scope.GenZIR = .{
1086 .decl = decl,968 .decl = decl,
1087 .arena = &fn_type_scope_arena.allocator,969 .arena = &fn_type_scope_arena.allocator,
1088 .parent = decl.scope,970 .parent = &decl.container.base,
1089 };971 };
1090 defer fn_type_scope.instructions.deinit(self.gpa);972 defer fn_type_scope.instructions.deinit(self.gpa);
1091973
...@@ -1197,7 +1079,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1197,7 +1079,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1197 .parent = null,1079 .parent = null,
1198 .inst_table = &inst_table,1080 .inst_table = &inst_table,
1199 .func = null,1081 .func = null,
1200 .decl = decl,1082 .owner_decl = decl,
1083 .src_decl = decl,
1201 .instructions = .{},1084 .instructions = .{},
1202 .arena = &decl_arena.allocator,1085 .arena = &decl_arena.allocator,
1203 .inlining = null,1086 .inlining = null,
...@@ -1242,12 +1125,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1242,12 +1125,12 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1242 const new_func = try decl_arena.allocator.create(Fn);1125 const new_func = try decl_arena.allocator.create(Fn);
1243 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);1126 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
12441127
1245 const fn_zir: zir.Module.Body = blk: {1128 const fn_zir: zir.Body = blk: {
1246 // We put the ZIR inside the Decl arena.1129 // We put the ZIR inside the Decl arena.
1247 var gen_scope: Scope.GenZIR = .{1130 var gen_scope: Scope.GenZIR = .{
1248 .decl = decl,1131 .decl = decl,
1249 .arena = &decl_arena.allocator,1132 .arena = &decl_arena.allocator,
1250 .parent = decl.scope,1133 .parent = &decl.container.base,
1251 };1134 };
1252 defer gen_scope.instructions.deinit(self.gpa);1135 defer gen_scope.instructions.deinit(self.gpa);
12531136
...@@ -1400,7 +1283,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1400,7 +1283,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1400 .parent = null,1283 .parent = null,
1401 .inst_table = &decl_inst_table,1284 .inst_table = &decl_inst_table,
1402 .func = null,1285 .func = null,
1403 .decl = decl,1286 .owner_decl = decl,
1287 .src_decl = decl,
1404 .instructions = .{},1288 .instructions = .{},
1405 .arena = &decl_arena.allocator,1289 .arena = &decl_arena.allocator,
1406 .inlining = null,1290 .inlining = null,
...@@ -1444,7 +1328,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1444,7 +1328,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1444 var gen_scope: Scope.GenZIR = .{1328 var gen_scope: Scope.GenZIR = .{
1445 .decl = decl,1329 .decl = decl,
1446 .arena = &gen_scope_arena.allocator,1330 .arena = &gen_scope_arena.allocator,
1447 .parent = decl.scope,1331 .parent = &decl.container.base,
1448 };1332 };
1449 defer gen_scope.instructions.deinit(self.gpa);1333 defer gen_scope.instructions.deinit(self.gpa);
14501334
...@@ -1472,7 +1356,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1472,7 +1356,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1472 .parent = null,1356 .parent = null,
1473 .inst_table = &var_inst_table,1357 .inst_table = &var_inst_table,
1474 .func = null,1358 .func = null,
1475 .decl = decl,1359 .owner_decl = decl,
1360 .src_decl = decl,
1476 .instructions = .{},1361 .instructions = .{},
1477 .arena = &gen_scope_arena.allocator,1362 .arena = &gen_scope_arena.allocator,
1478 .inlining = null,1363 .inlining = null,
...@@ -1503,7 +1388,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1503,7 +1388,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1503 var type_scope: Scope.GenZIR = .{1388 var type_scope: Scope.GenZIR = .{
1504 .decl = decl,1389 .decl = decl,
1505 .arena = &type_scope_arena.allocator,1390 .arena = &type_scope_arena.allocator,
1506 .parent = decl.scope,1391 .parent = &decl.container.base,
1507 };1392 };
1508 defer type_scope.instructions.deinit(self.gpa);1393 defer type_scope.instructions.deinit(self.gpa);
15091394
...@@ -1584,7 +1469,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1584,7 +1469,7 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1584 var gen_scope: Scope.GenZIR = .{1469 var gen_scope: Scope.GenZIR = .{
1585 .decl = decl,1470 .decl = decl,
1586 .arena = &analysis_arena.allocator,1471 .arena = &analysis_arena.allocator,
1587 .parent = decl.scope,1472 .parent = &decl.container.base,
1588 };1473 };
1589 defer gen_scope.instructions.deinit(self.gpa);1474 defer gen_scope.instructions.deinit(self.gpa);
15901475
...@@ -1602,7 +1487,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {...@@ -1602,7 +1487,8 @@ fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
1602 .parent = null,1487 .parent = null,
1603 .inst_table = &inst_table,1488 .inst_table = &inst_table,
1604 .func = null,1489 .func = null,
1605 .decl = decl,1490 .owner_decl = decl,
1491 .src_decl = decl,
1606 .instructions = .{},1492 .instructions = .{},
1607 .arena = &analysis_arena.allocator,1493 .arena = &analysis_arena.allocator,
1608 .inlining = null,1494 .inlining = null,
...@@ -1632,44 +1518,6 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void...@@ -1632,44 +1518,6 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void
1632 dependee.dependants.putAssumeCapacity(depender, {});1518 dependee.dependants.putAssumeCapacity(depender, {});
1633}1519}
16341520
1635fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
1636 switch (root_scope.status) {
1637 .never_loaded, .unloaded_success => {
1638 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
1639
1640 const source = try root_scope.getSource(self);
1641
1642 var keep_zir_module = false;
1643 const zir_module = try self.gpa.create(zir.Module);
1644 defer if (!keep_zir_module) self.gpa.destroy(zir_module);
1645
1646 zir_module.* = try zir.parse(self.gpa, source);
1647 defer if (!keep_zir_module) zir_module.deinit(self.gpa);
1648
1649 if (zir_module.error_msg) |src_err_msg| {
1650 self.failed_files.putAssumeCapacityNoClobber(
1651 &root_scope.base,
1652 try Compilation.ErrorMsg.create(self.gpa, src_err_msg.byte_offset, "{s}", .{src_err_msg.msg}),
1653 );
1654 root_scope.status = .unloaded_parse_failure;
1655 return error.AnalysisFail;
1656 }
1657
1658 root_scope.status = .loaded_success;
1659 root_scope.contents = .{ .module = zir_module };
1660 keep_zir_module = true;
1661
1662 return zir_module;
1663 },
1664
1665 .unloaded_parse_failure,
1666 .unloaded_sema_failure,
1667 => return error.AnalysisFail,
1668
1669 .loaded_success, .loaded_sema_failure => return root_scope.contents.module,
1670 }
1671}
1672
1673pub fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {1521pub fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
1674 const tracy = trace(@src());1522 const tracy = trace(@src());
1675 defer tracy.end();1523 defer tracy.end();
...@@ -1691,10 +1539,13 @@ pub fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {...@@ -1691,10 +1539,13 @@ pub fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree {
1691 defer msg.deinit();1539 defer msg.deinit();
16921540
1693 try parse_err.render(tree.token_ids, msg.writer());1541 try parse_err.render(tree.token_ids, msg.writer());
1694 const err_msg = try self.gpa.create(Compilation.ErrorMsg);1542 const err_msg = try self.gpa.create(ErrorMsg);
1695 err_msg.* = .{1543 err_msg.* = .{
1544 .src_loc = .{
1545 .file_scope = root_scope,
1546 .byte_offset = tree.token_locs[parse_err.loc()].start,
1547 },
1696 .msg = msg.toOwnedSlice(),1548 .msg = msg.toOwnedSlice(),
1697 .byte_offset = tree.token_locs[parse_err.loc()].start,
1698 };1549 };
16991550
1700 self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);1551 self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
...@@ -1753,9 +1604,12 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void...@@ -1753,9 +1604,12 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void
1753 decl.src_index = decl_i;1604 decl.src_index = decl_i;
1754 if (deleted_decls.swapRemove(decl) == null) {1605 if (deleted_decls.swapRemove(decl) == null) {
1755 decl.analysis = .sema_failure;1606 decl.analysis = .sema_failure;
1756 const err_msg = try Compilation.ErrorMsg.create(self.gpa, tree.token_locs[name_tok].start, "redefinition of '{s}'", .{decl.name});1607 const msg = try ErrorMsg.create(self.gpa, .{
1757 errdefer err_msg.destroy(self.gpa);1608 .file_scope = container_scope.file_scope,
1758 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);1609 .byte_offset = tree.token_locs[name_tok].start,
1610 }, "redefinition of '{s}'", .{decl.name});
1611 errdefer msg.destroy(self.gpa);
1612 try self.failed_decls.putNoClobber(self.gpa, decl, msg);
1759 } else {1613 } else {
1760 if (!srcHashEql(decl.contents_hash, contents_hash)) {1614 if (!srcHashEql(decl.contents_hash, contents_hash)) {
1761 try self.markOutdatedDecl(decl);1615 try self.markOutdatedDecl(decl);
...@@ -1795,7 +1649,10 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void...@@ -1795,7 +1649,10 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void
1795 decl.src_index = decl_i;1649 decl.src_index = decl_i;
1796 if (deleted_decls.swapRemove(decl) == null) {1650 if (deleted_decls.swapRemove(decl) == null) {
1797 decl.analysis = .sema_failure;1651 decl.analysis = .sema_failure;
1798 const err_msg = try Compilation.ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{s}'", .{decl.name});1652 const err_msg = try ErrorMsg.create(self.gpa, .{
1653 .file_scope = container_scope.file_scope,
1654 .byte_offset = name_loc.start,
1655 }, "redefinition of '{s}'", .{decl.name});
1799 errdefer err_msg.destroy(self.gpa);1656 errdefer err_msg.destroy(self.gpa);
1800 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);1657 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
1801 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {1658 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
...@@ -1840,65 +1697,12 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void...@@ -1840,65 +1697,12 @@ pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void
1840 }1697 }
1841}1698}
18421699
1843pub fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
1844 // We may be analyzing it for the first time, or this may be
1845 // an incremental update. This code handles both cases.
1846 const src_module = try self.getSrcModule(root_scope);
1847
1848 try self.comp.work_queue.ensureUnusedCapacity(src_module.decls.len);
1849 try root_scope.decls.ensureCapacity(self.gpa, src_module.decls.len);
1850
1851 var exports_to_resolve = std.ArrayList(*zir.Decl).init(self.gpa);
1852 defer exports_to_resolve.deinit();
1853
1854 // Keep track of the decls that we expect to see in this file so that
1855 // we know which ones have been deleted.
1856 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);
1857 defer deleted_decls.deinit();
1858 try deleted_decls.ensureCapacity(self.decl_table.items().len);
1859 for (self.decl_table.items()) |entry| {
1860 deleted_decls.putAssumeCapacityNoClobber(entry.value, {});
1861 }
1862
1863 for (src_module.decls) |src_decl, decl_i| {
1864 const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name);
1865 if (self.decl_table.get(name_hash)) |decl| {
1866 deleted_decls.removeAssertDiscard(decl);
1867 if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) {
1868 try self.markOutdatedDecl(decl);
1869 decl.contents_hash = src_decl.contents_hash;
1870 }
1871 } else {
1872 const new_decl = try self.createNewDecl(
1873 &root_scope.base,
1874 src_decl.name,
1875 decl_i,
1876 name_hash,
1877 src_decl.contents_hash,
1878 );
1879 root_scope.decls.appendAssumeCapacity(new_decl);
1880 if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| {
1881 try exports_to_resolve.append(src_decl);
1882 }
1883 }
1884 }
1885 for (exports_to_resolve.items) |export_decl| {
1886 _ = try zir_sema.resolveZirDecl(self, &root_scope.base, export_decl);
1887 }
1888 // Handle explicitly deleted decls from the source code. Not to be confused
1889 // with when we delete decls because they are no longer referenced.
1890 for (deleted_decls.items()) |entry| {
1891 log.debug("noticed '{s}' deleted from source\n", .{entry.key.name});
1892 try self.deleteDecl(entry.key);
1893 }
1894}
1895
1896pub fn deleteDecl(self: *Module, decl: *Decl) !void {1700pub fn deleteDecl(self: *Module, decl: *Decl) !void {
1897 try self.deletion_set.ensureCapacity(self.gpa, self.deletion_set.items.len + decl.dependencies.items().len);1701 try self.deletion_set.ensureCapacity(self.gpa, self.deletion_set.items.len + decl.dependencies.items().len);
18981702
1899 // Remove from the namespace it resides in. In the case of an anonymous Decl it will1703 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
1900 // not be present in the set, and this does nothing.1704 // not be present in the set, and this does nothing.
1901 decl.scope.removeDecl(decl);1705 decl.container.removeDecl(decl);
19021706
1903 log.debug("deleting decl '{s}'\n", .{decl.name});1707 log.debug("deleting decl '{s}'\n", .{decl.name});
1904 const name_hash = decl.fullyQualifiedNameHash();1708 const name_hash = decl.fullyQualifiedNameHash();
...@@ -1929,9 +1733,7 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {...@@ -1929,9 +1733,7 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {
1929 if (self.emit_h_failed_decls.swapRemove(decl)) |entry| {1733 if (self.emit_h_failed_decls.swapRemove(decl)) |entry| {
1930 entry.value.destroy(self.gpa);1734 entry.value.destroy(self.gpa);
1931 }1735 }
1932 if (self.compile_log_decls.swapRemove(decl)) |*entry| {1736 _ = self.compile_log_decls.swapRemove(decl);
1933 entry.value.deinit(self.gpa);
1934 }
1935 self.deleteDeclExports(decl);1737 self.deleteDeclExports(decl);
1936 self.comp.bin_file.freeDecl(decl);1738 self.comp.bin_file.freeDecl(decl);
19371739
...@@ -1993,7 +1795,8 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {...@@ -1993,7 +1795,8 @@ pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
1993 .parent = null,1795 .parent = null,
1994 .inst_table = &inst_table,1796 .inst_table = &inst_table,
1995 .func = func,1797 .func = func,
1996 .decl = decl,1798 .owner_decl = decl,
1799 .src_decl = decl,
1997 .instructions = .{},1800 .instructions = .{},
1998 .arena = &arena.allocator,1801 .arena = &arena.allocator,
1999 .inlining = null,1802 .inlining = null,
...@@ -2022,9 +1825,7 @@ fn markOutdatedDecl(self: *Module, decl: *Decl) !void {...@@ -2022,9 +1825,7 @@ fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
2022 if (self.emit_h_failed_decls.swapRemove(decl)) |entry| {1825 if (self.emit_h_failed_decls.swapRemove(decl)) |entry| {
2023 entry.value.destroy(self.gpa);1826 entry.value.destroy(self.gpa);
2024 }1827 }
2025 if (self.compile_log_decls.swapRemove(decl)) |*entry| {1828 _ = self.compile_log_decls.swapRemove(decl);
2026 entry.value.deinit(self.gpa);
2027 }
2028 decl.analysis = .outdated;1829 decl.analysis = .outdated;
2029}1830}
20301831
...@@ -2046,7 +1847,7 @@ fn allocateNewDecl(...@@ -2046,7 +1847,7 @@ fn allocateNewDecl(
20461847
2047 new_decl.* = .{1848 new_decl.* = .{
2048 .name = "",1849 .name = "",
2049 .scope = scope.namespace(),1850 .container = scope.namespace(),
2050 .src_index = src_index,1851 .src_index = src_index,
2051 .typed_value = .{ .never_succeeded = {} },1852 .typed_value = .{ .never_succeeded = {} },
2052 .analysis = .unreferenced,1853 .analysis = .unreferenced,
...@@ -2129,34 +1930,34 @@ pub fn resolveDefinedValue(self: *Module, scope: *Scope, base: *Inst) !?Value {...@@ -2129,34 +1930,34 @@ pub fn resolveDefinedValue(self: *Module, scope: *Scope, base: *Inst) !?Value {
2129}1930}
21301931
2131pub fn analyzeExport(1932pub fn analyzeExport(
2132 self: *Module,1933 mod: *Module,
2133 scope: *Scope,1934 scope: *Scope,
2134 src: usize,1935 src: usize,
2135 borrowed_symbol_name: []const u8,1936 borrowed_symbol_name: []const u8,
2136 exported_decl: *Decl,1937 exported_decl: *Decl,
2137) !void {1938) !void {
2138 try self.ensureDeclAnalyzed(exported_decl);1939 try mod.ensureDeclAnalyzed(exported_decl);
2139 const typed_value = exported_decl.typed_value.most_recent.typed_value;1940 const typed_value = exported_decl.typed_value.most_recent.typed_value;
2140 switch (typed_value.ty.zigTypeTag()) {1941 switch (typed_value.ty.zigTypeTag()) {
2141 .Fn => {},1942 .Fn => {},
2142 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),1943 else => return mod.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
2143 }1944 }
21441945
2145 try self.decl_exports.ensureCapacity(self.gpa, self.decl_exports.items().len + 1);1946 try mod.decl_exports.ensureCapacity(mod.gpa, mod.decl_exports.items().len + 1);
2146 try self.export_owners.ensureCapacity(self.gpa, self.export_owners.items().len + 1);1947 try mod.export_owners.ensureCapacity(mod.gpa, mod.export_owners.items().len + 1);
21471948
2148 const new_export = try self.gpa.create(Export);1949 const new_export = try mod.gpa.create(Export);
2149 errdefer self.gpa.destroy(new_export);1950 errdefer mod.gpa.destroy(new_export);
21501951
2151 const symbol_name = try self.gpa.dupe(u8, borrowed_symbol_name);1952 const symbol_name = try mod.gpa.dupe(u8, borrowed_symbol_name);
2152 errdefer self.gpa.free(symbol_name);1953 errdefer mod.gpa.free(symbol_name);
21531954
2154 const owner_decl = scope.decl().?;1955 const owner_decl = scope.ownerDecl().?;
21551956
2156 new_export.* = .{1957 new_export.* = .{
2157 .options = .{ .name = symbol_name },1958 .options = .{ .name = symbol_name },
2158 .src = src,1959 .src = src,
2159 .link = switch (self.comp.bin_file.tag) {1960 .link = switch (mod.comp.bin_file.tag) {
2160 .coff => .{ .coff = {} },1961 .coff => .{ .coff = {} },
2161 .elf => .{ .elf = link.File.Elf.Export{} },1962 .elf => .{ .elf = link.File.Elf.Export{} },
2162 .macho => .{ .macho = link.File.MachO.Export{} },1963 .macho => .{ .macho = link.File.MachO.Export{} },
...@@ -2169,48 +1970,53 @@ pub fn analyzeExport(...@@ -2169,48 +1970,53 @@ pub fn analyzeExport(
2169 };1970 };
21701971
2171 // Add to export_owners table.1972 // Add to export_owners table.
2172 const eo_gop = self.export_owners.getOrPutAssumeCapacity(owner_decl);1973 const eo_gop = mod.export_owners.getOrPutAssumeCapacity(owner_decl);
2173 if (!eo_gop.found_existing) {1974 if (!eo_gop.found_existing) {
2174 eo_gop.entry.value = &[0]*Export{};1975 eo_gop.entry.value = &[0]*Export{};
2175 }1976 }
2176 eo_gop.entry.value = try self.gpa.realloc(eo_gop.entry.value, eo_gop.entry.value.len + 1);1977 eo_gop.entry.value = try mod.gpa.realloc(eo_gop.entry.value, eo_gop.entry.value.len + 1);
2177 eo_gop.entry.value[eo_gop.entry.value.len - 1] = new_export;1978 eo_gop.entry.value[eo_gop.entry.value.len - 1] = new_export;
2178 errdefer eo_gop.entry.value = self.gpa.shrink(eo_gop.entry.value, eo_gop.entry.value.len - 1);1979 errdefer eo_gop.entry.value = mod.gpa.shrink(eo_gop.entry.value, eo_gop.entry.value.len - 1);
21791980
2180 // Add to exported_decl table.1981 // Add to exported_decl table.
2181 const de_gop = self.decl_exports.getOrPutAssumeCapacity(exported_decl);1982 const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl);
2182 if (!de_gop.found_existing) {1983 if (!de_gop.found_existing) {
2183 de_gop.entry.value = &[0]*Export{};1984 de_gop.entry.value = &[0]*Export{};
2184 }1985 }
2185 de_gop.entry.value = try self.gpa.realloc(de_gop.entry.value, de_gop.entry.value.len + 1);1986 de_gop.entry.value = try mod.gpa.realloc(de_gop.entry.value, de_gop.entry.value.len + 1);
2186 de_gop.entry.value[de_gop.entry.value.len - 1] = new_export;1987 de_gop.entry.value[de_gop.entry.value.len - 1] = new_export;
2187 errdefer de_gop.entry.value = self.gpa.shrink(de_gop.entry.value, de_gop.entry.value.len - 1);1988 errdefer de_gop.entry.value = mod.gpa.shrink(de_gop.entry.value, de_gop.entry.value.len - 1);
21881989
2189 if (self.symbol_exports.get(symbol_name)) |_| {1990 if (mod.symbol_exports.get(symbol_name)) |other_export| {
2190 try self.failed_exports.ensureCapacity(self.gpa, self.failed_exports.items().len + 1);1991 new_export.status = .failed_retryable;
2191 self.failed_exports.putAssumeCapacityNoClobber(new_export, try Compilation.ErrorMsg.create(1992 try mod.failed_exports.ensureCapacity(mod.gpa, mod.failed_exports.items().len + 1);
2192 self.gpa,1993 const msg = try mod.errMsg(
1994 scope,
2193 src,1995 src,
2194 "exported symbol collision: {s}",1996 "exported symbol collision: {s}",
2195 .{symbol_name},1997 .{symbol_name},
2196 ));1998 );
2197 // TODO: add a note1999 errdefer msg.destroy(mod.gpa);
2000 try mod.errNote(
2001 &other_export.owner_decl.container.base,
2002 other_export.src,
2003 msg,
2004 "other symbol here",
2005 .{},
2006 );
2007 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
2198 new_export.status = .failed;2008 new_export.status = .failed;
2199 return;2009 return;
2200 }2010 }
22012011
2202 try self.symbol_exports.putNoClobber(self.gpa, symbol_name, new_export);2012 try mod.symbol_exports.putNoClobber(mod.gpa, symbol_name, new_export);
2203 self.comp.bin_file.updateDeclExports(self, exported_decl, de_gop.entry.value) catch |err| switch (err) {2013 mod.comp.bin_file.updateDeclExports(mod, exported_decl, de_gop.entry.value) catch |err| switch (err) {
2204 error.OutOfMemory => return error.OutOfMemory,2014 error.OutOfMemory => return error.OutOfMemory,
2205 else => {2015 else => {
2206 try self.failed_exports.ensureCapacity(self.gpa, self.failed_exports.items().len + 1);
2207 self.failed_exports.putAssumeCapacityNoClobber(new_export, try Compilation.ErrorMsg.create(
2208 self.gpa,
2209 src,
2210 "unable to export: {s}",
2211 .{@errorName(err)},
2212 ));
2213 new_export.status = .failed_retryable;2016 new_export.status = .failed_retryable;
2017 try mod.failed_exports.ensureCapacity(mod.gpa, mod.failed_exports.items().len + 1);
2018 const msg = try mod.errMsg(scope, src, "unable to export: {s}", .{@errorName(err)});
2019 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
2214 },2020 },
2215 };2021 };
2216}2022}
...@@ -2476,7 +2282,7 @@ pub fn createAnonymousDecl(...@@ -2476,7 +2282,7 @@ pub fn createAnonymousDecl(
2476 typed_value: TypedValue,2282 typed_value: TypedValue,
2477) !*Decl {2283) !*Decl {
2478 const name_index = self.getNextAnonNameIndex();2284 const name_index = self.getNextAnonNameIndex();
2479 const scope_decl = scope.decl().?;2285 const scope_decl = scope.ownerDecl().?;
2480 const name = try std.fmt.allocPrint(self.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });2286 const name = try std.fmt.allocPrint(self.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });
2481 defer self.gpa.free(name);2287 defer self.gpa.free(name);
2482 const name_hash = scope.namespace().fullyQualifiedNameHash(name);2288 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
...@@ -2512,7 +2318,7 @@ pub fn createContainerDecl(...@@ -2512,7 +2318,7 @@ pub fn createContainerDecl(
2512 decl_arena: *std.heap.ArenaAllocator,2318 decl_arena: *std.heap.ArenaAllocator,
2513 typed_value: TypedValue,2319 typed_value: TypedValue,
2514) !*Decl {2320) !*Decl {
2515 const scope_decl = scope.decl().?;2321 const scope_decl = scope.ownerDecl().?;
2516 const name = try self.getAnonTypeName(scope, base_token);2322 const name = try self.getAnonTypeName(scope, base_token);
2517 defer self.gpa.free(name);2323 defer self.gpa.free(name);
2518 const name_hash = scope.namespace().fullyQualifiedNameHash(name);2324 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
...@@ -2558,14 +2364,14 @@ pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*De...@@ -2558,14 +2364,14 @@ pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*De
2558}2364}
25592365
2560pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {2366pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
2561 const scope_decl = scope.decl().?;2367 const scope_decl = scope.ownerDecl().?;
2562 try self.declareDeclDependency(scope_decl, decl);2368 try self.declareDeclDependency(scope_decl, decl);
2563 self.ensureDeclAnalyzed(decl) catch |err| {2369 self.ensureDeclAnalyzed(decl) catch |err| {
2564 if (scope.cast(Scope.Block)) |block| {2370 if (scope.cast(Scope.Block)) |block| {
2565 if (block.func) |func| {2371 if (block.func) |func| {
2566 func.state = .dependency_failure;2372 func.state = .dependency_failure;
2567 } else {2373 } else {
2568 block.decl.analysis = .dependency_failure;2374 block.owner_decl.analysis = .dependency_failure;
2569 }2375 }
2570 } else {2376 } else {
2571 scope_decl.analysis = .dependency_failure;2377 scope_decl.analysis = .dependency_failure;
...@@ -3217,10 +3023,51 @@ fn coerceArrayPtrToMany(self: *Module, scope: *Scope, dest_type: Type, inst: *In...@@ -3217,10 +3023,51 @@ fn coerceArrayPtrToMany(self: *Module, scope: *Scope, dest_type: Type, inst: *In
3217 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToMany runtime instruction", .{});3023 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToMany runtime instruction", .{});
3218}3024}
32193025
3220pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {3026/// We don't return a pointer to the new error note because the pointer
3221 @setCold(true);3027/// becomes invalid when you add another one.
3222 const err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args);3028pub fn errNote(
3223 return self.failWithOwnedErrorMsg(scope, src, err_msg);3029 mod: *Module,
3030 scope: *Scope,
3031 src: usize,
3032 parent: *ErrorMsg,
3033 comptime format: []const u8,
3034 args: anytype,
3035) error{OutOfMemory}!void {
3036 const msg = try std.fmt.allocPrint(mod.gpa, format, args);
3037 errdefer mod.gpa.free(msg);
3038
3039 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
3040 parent.notes[parent.notes.len - 1] = .{
3041 .src_loc = .{
3042 .file_scope = scope.getFileScope(),
3043 .byte_offset = src,
3044 },
3045 .msg = msg,
3046 };
3047}
3048
3049pub fn errMsg(
3050 mod: *Module,
3051 scope: *Scope,
3052 src_byte_offset: usize,
3053 comptime format: []const u8,
3054 args: anytype,
3055) error{OutOfMemory}!*ErrorMsg {
3056 return ErrorMsg.create(mod.gpa, .{
3057 .file_scope = scope.getFileScope(),
3058 .byte_offset = src_byte_offset,
3059 }, format, args);
3060}
3061
3062pub fn fail(
3063 mod: *Module,
3064 scope: *Scope,
3065 src_byte_offset: usize,
3066 comptime format: []const u8,
3067 args: anytype,
3068) InnerError {
3069 const err_msg = try mod.errMsg(scope, src_byte_offset, format, args);
3070 return mod.failWithOwnedErrorMsg(scope, err_msg);
3224}3071}
32253072
3226pub fn failTok(3073pub fn failTok(
...@@ -3230,7 +3077,6 @@ pub fn failTok(...@@ -3230,7 +3077,6 @@ pub fn failTok(
3230 comptime format: []const u8,3077 comptime format: []const u8,
3231 args: anytype,3078 args: anytype,
3232) InnerError {3079) InnerError {
3233 @setCold(true);
3234 const src = scope.tree().token_locs[token_index].start;3080 const src = scope.tree().token_locs[token_index].start;
3235 return self.fail(scope, src, format, args);3081 return self.fail(scope, src, format, args);
3236}3082}
...@@ -3242,80 +3088,36 @@ pub fn failNode(...@@ -3242,80 +3088,36 @@ pub fn failNode(
3242 comptime format: []const u8,3088 comptime format: []const u8,
3243 args: anytype,3089 args: anytype,
3244) InnerError {3090) InnerError {
3245 @setCold(true);
3246 const src = scope.tree().token_locs[ast_node.firstToken()].start;3091 const src = scope.tree().token_locs[ast_node.firstToken()].start;
3247 return self.fail(scope, src, format, args);3092 return self.fail(scope, src, format, args);
3248}3093}
32493094
3250fn addCompileLog(self: *Module, decl: *Decl, src: usize) error{OutOfMemory}!void {3095pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {
3251 const entry = try self.compile_log_decls.getOrPutValue(self.gpa, decl, .{});3096 @setCold(true);
3252 try entry.value.append(self.gpa, src);
3253}
3254
3255pub fn failCompileLog(
3256 self: *Module,
3257 scope: *Scope,
3258 src: usize,
3259) InnerError!void {
3260 switch (scope.tag) {
3261 .decl => {
3262 const decl = scope.cast(Scope.DeclAnalysis).?.decl;
3263 try self.addCompileLog(decl, src);
3264 },
3265 .block => {
3266 const block = scope.cast(Scope.Block).?;
3267 try self.addCompileLog(block.decl, src);
3268 },
3269 .gen_zir => {
3270 const gen_zir = scope.cast(Scope.GenZIR).?;
3271 try self.addCompileLog(gen_zir.decl, src);
3272 },
3273 .local_val => {
3274 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
3275 try self.addCompileLog(gen_zir.decl, src);
3276 },
3277 .local_ptr => {
3278 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
3279 try self.addCompileLog(gen_zir.decl, src);
3280 },
3281 .zir_module,
3282 .file,
3283 .container,
3284 => unreachable,
3285 }
3286}
3287
3288fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Compilation.ErrorMsg) InnerError {
3289 {3097 {
3290 errdefer err_msg.destroy(self.gpa);3098 errdefer err_msg.destroy(self.gpa);
3291 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);3099 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
3292 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);3100 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
3293 }3101 }
3294 switch (scope.tag) {3102 switch (scope.tag) {
3295 .decl => {
3296 const decl = scope.cast(Scope.DeclAnalysis).?.decl;
3297 decl.analysis = .sema_failure;
3298 decl.generation = self.generation;
3299 self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg);
3300 },
3301 .block => {3103 .block => {
3302 const block = scope.cast(Scope.Block).?;3104 const block = scope.cast(Scope.Block).?;
3303 if (block.inlining) |inlining| {3105 if (block.inlining) |inlining| {
3304 if (inlining.shared.caller) |func| {3106 if (inlining.shared.caller) |func| {
3305 func.state = .sema_failure;3107 func.state = .sema_failure;
3306 } else {3108 } else {
3307 block.decl.analysis = .sema_failure;3109 block.owner_decl.analysis = .sema_failure;
3308 block.decl.generation = self.generation;3110 block.owner_decl.generation = self.generation;
3309 }3111 }
3310 } else {3112 } else {
3311 if (block.func) |func| {3113 if (block.func) |func| {
3312 func.state = .sema_failure;3114 func.state = .sema_failure;
3313 } else {3115 } else {
3314 block.decl.analysis = .sema_failure;3116 block.owner_decl.analysis = .sema_failure;
3315 block.decl.generation = self.generation;3117 block.owner_decl.generation = self.generation;
3316 }3118 }
3317 }3119 }
3318 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);3120 self.failed_decls.putAssumeCapacityNoClobber(block.owner_decl, err_msg);
3319 },3121 },
3320 .gen_zir => {3122 .gen_zir => {
3321 const gen_zir = scope.cast(Scope.GenZIR).?;3123 const gen_zir = scope.cast(Scope.GenZIR).?;
...@@ -3335,11 +3137,6 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Com...@@ -3335,11 +3137,6 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Com
3335 gen_zir.decl.generation = self.generation;3137 gen_zir.decl.generation = self.generation;
3336 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);3138 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3337 },3139 },
3338 .zir_module => {
3339 const zir_module = scope.cast(Scope.ZIRModule).?;
3340 zir_module.status = .loaded_sema_failure;
3341 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
3342 },
3343 .file => unreachable,3140 .file => unreachable,
3344 .container => unreachable,3141 .container => unreachable,
3345 }3142 }
...@@ -3671,7 +3468,8 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic...@@ -3671,7 +3468,8 @@ pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic
3671 .parent = parent_block,3468 .parent = parent_block,
3672 .inst_table = parent_block.inst_table,3469 .inst_table = parent_block.inst_table,
3673 .func = parent_block.func,3470 .func = parent_block.func,
3674 .decl = parent_block.decl,3471 .owner_decl = parent_block.owner_decl,
3472 .src_decl = parent_block.src_decl,
3675 .instructions = .{},3473 .instructions = .{},
3676 .arena = parent_block.arena,3474 .arena = parent_block.arena,
3677 .inlining = parent_block.inlining,3475 .inlining = parent_block.inlining,
src/astgen.zig+56-21
...@@ -318,7 +318,7 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as...@@ -318,7 +318,7 @@ pub fn comptimeExpr(mod: *Module, parent_scope: *Scope, rl: ResultLoc, node: *as
318 // Make a scope to collect generated instructions in the sub-expression.318 // Make a scope to collect generated instructions in the sub-expression.
319 var block_scope: Scope.GenZIR = .{319 var block_scope: Scope.GenZIR = .{
320 .parent = parent_scope,320 .parent = parent_scope,
321 .decl = parent_scope.decl().?,321 .decl = parent_scope.ownerDecl().?,
322 .arena = parent_scope.arena(),322 .arena = parent_scope.arena(),
323 .instructions = .{},323 .instructions = .{},
324 };324 };
...@@ -474,7 +474,7 @@ fn labeledBlockExpr(...@@ -474,7 +474,7 @@ fn labeledBlockExpr(
474474
475 var block_scope: Scope.GenZIR = .{475 var block_scope: Scope.GenZIR = .{
476 .parent = parent_scope,476 .parent = parent_scope,
477 .decl = parent_scope.decl().?,477 .decl = parent_scope.ownerDecl().?,
478 .arena = gen_zir.arena,478 .arena = gen_zir.arena,
479 .instructions = .{},479 .instructions = .{},
480 .break_result_loc = rl,480 .break_result_loc = rl,
...@@ -899,7 +899,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con...@@ -899,7 +899,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
899899
900 var gen_scope: Scope.GenZIR = .{900 var gen_scope: Scope.GenZIR = .{
901 .parent = scope,901 .parent = scope,
902 .decl = scope.decl().?,902 .decl = scope.ownerDecl().?,
903 .arena = scope.arena(),903 .arena = scope.arena(),
904 .instructions = .{},904 .instructions = .{},
905 };905 };
...@@ -1028,7 +1028,13 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con...@@ -1028,7 +1028,13 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con
1028 .ty = Type.initTag(.type),1028 .ty = Type.initTag(.type),
1029 .val = val,1029 .val = val,
1030 });1030 });
1031 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}));1031 if (rl == .ref) {
1032 return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{});
1033 } else {
1034 return rlWrap(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{
1035 .decl = decl,
1036 }, .{}));
1037 }
1032}1038}
10331039
1034fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {1040fn errorSetDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst {
...@@ -1084,7 +1090,7 @@ fn orelseCatchExpr(...@@ -1084,7 +1090,7 @@ fn orelseCatchExpr(
10841090
1085 var block_scope: Scope.GenZIR = .{1091 var block_scope: Scope.GenZIR = .{
1086 .parent = scope,1092 .parent = scope,
1087 .decl = scope.decl().?,1093 .decl = scope.ownerDecl().?,
1088 .arena = scope.arena(),1094 .arena = scope.arena(),
1089 .instructions = .{},1095 .instructions = .{},
1090 };1096 };
...@@ -1266,7 +1272,7 @@ fn boolBinOp(...@@ -1266,7 +1272,7 @@ fn boolBinOp(
12661272
1267 var block_scope: Scope.GenZIR = .{1273 var block_scope: Scope.GenZIR = .{
1268 .parent = scope,1274 .parent = scope,
1269 .decl = scope.decl().?,1275 .decl = scope.ownerDecl().?,
1270 .arena = scope.arena(),1276 .arena = scope.arena(),
1271 .instructions = .{},1277 .instructions = .{},
1272 };1278 };
...@@ -1412,7 +1418,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -1412,7 +1418,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
1412 }1418 }
1413 var block_scope: Scope.GenZIR = .{1419 var block_scope: Scope.GenZIR = .{
1414 .parent = scope,1420 .parent = scope,
1415 .decl = scope.decl().?,1421 .decl = scope.ownerDecl().?,
1416 .arena = scope.arena(),1422 .arena = scope.arena(),
1417 .instructions = .{},1423 .instructions = .{},
1418 };1424 };
...@@ -1513,7 +1519,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -1513,7 +1519,7 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
15131519
1514 var expr_scope: Scope.GenZIR = .{1520 var expr_scope: Scope.GenZIR = .{
1515 .parent = scope,1521 .parent = scope,
1516 .decl = scope.decl().?,1522 .decl = scope.ownerDecl().?,
1517 .arena = scope.arena(),1523 .arena = scope.arena(),
1518 .instructions = .{},1524 .instructions = .{},
1519 };1525 };
...@@ -1649,7 +1655,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)...@@ -1649,7 +1655,7 @@ fn forExpr(mod: *Module, scope: *Scope, rl: ResultLoc, for_node: *ast.Node.For)
16491655
1650 var for_scope: Scope.GenZIR = .{1656 var for_scope: Scope.GenZIR = .{
1651 .parent = scope,1657 .parent = scope,
1652 .decl = scope.decl().?,1658 .decl = scope.ownerDecl().?,
1653 .arena = scope.arena(),1659 .arena = scope.arena(),
1654 .instructions = .{},1660 .instructions = .{},
1655 };1661 };
...@@ -1843,7 +1849,7 @@ fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp {...@@ -1843,7 +1849,7 @@ fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp {
1843fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.Switch) InnerError!*zir.Inst {1849fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.Switch) InnerError!*zir.Inst {
1844 var block_scope: Scope.GenZIR = .{1850 var block_scope: Scope.GenZIR = .{
1845 .parent = scope,1851 .parent = scope,
1846 .decl = scope.decl().?,1852 .decl = scope.ownerDecl().?,
1847 .arena = scope.arena(),1853 .arena = scope.arena(),
1848 .instructions = .{},1854 .instructions = .{},
1849 };1855 };
...@@ -1885,7 +1891,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -1885,7 +1891,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
18851891
1886 var item_scope: Scope.GenZIR = .{1892 var item_scope: Scope.GenZIR = .{
1887 .parent = scope,1893 .parent = scope,
1888 .decl = scope.decl().?,1894 .decl = scope.ownerDecl().?,
1889 .arena = scope.arena(),1895 .arena = scope.arena(),
1890 .instructions = .{},1896 .instructions = .{},
1891 };1897 };
...@@ -1922,8 +1928,15 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -1922,8 +1928,15 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
1922 // Check for else/_ prong, those are handled last.1928 // Check for else/_ prong, those are handled last.
1923 if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) {1929 if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) {
1924 if (else_src) |src| {1930 if (else_src) |src| {
1925 return mod.fail(scope, case_src, "multiple else prongs in switch expression", .{});1931 const msg = try mod.errMsg(
1926 // TODO notes "previous else prong is here"1932 scope,
1933 case_src,
1934 "multiple else prongs in switch expression",
1935 .{},
1936 );
1937 errdefer msg.destroy(mod.gpa);
1938 try mod.errNote(scope, src, msg, "previous else prong is here", .{});
1939 return mod.failWithOwnedErrorMsg(scope, msg);
1927 }1940 }
1928 else_src = case_src;1941 else_src = case_src;
1929 special_case = case;1942 special_case = case;
...@@ -1932,8 +1945,15 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -1932,8 +1945,15 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
1932 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))1945 mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_"))
1933 {1946 {
1934 if (underscore_src) |src| {1947 if (underscore_src) |src| {
1935 return mod.fail(scope, case_src, "multiple '_' prongs in switch expression", .{});1948 const msg = try mod.errMsg(
1936 // TODO notes "previous '_' prong is here"1949 scope,
1950 case_src,
1951 "multiple '_' prongs in switch expression",
1952 .{},
1953 );
1954 errdefer msg.destroy(mod.gpa);
1955 try mod.errNote(scope, src, msg, "previous '_' prong is here", .{});
1956 return mod.failWithOwnedErrorMsg(scope, msg);
1937 }1957 }
1938 underscore_src = case_src;1958 underscore_src = case_src;
1939 special_case = case;1959 special_case = case;
...@@ -1942,9 +1962,16 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node...@@ -1942,9 +1962,16 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node
19421962
1943 if (else_src) |some_else| {1963 if (else_src) |some_else| {
1944 if (underscore_src) |some_underscore| {1964 if (underscore_src) |some_underscore| {
1945 return mod.fail(scope, switch_src, "else and '_' prong in switch expression", .{});1965 const msg = try mod.errMsg(
1946 // TODO notes "else prong is here"1966 scope,
1947 // TODO notes "'_' prong is here"1967 switch_src,
1968 "else and '_' prong in switch expression",
1969 .{},
1970 );
1971 errdefer msg.destroy(mod.gpa);
1972 try mod.errNote(scope, some_else, msg, "else prong is here", .{});
1973 try mod.errNote(scope, some_underscore, msg, "'_' prong is here", .{});
1974 return mod.failWithOwnedErrorMsg(scope, msg);
1948 }1975 }
1949 }1976 }
19501977
...@@ -2162,7 +2189,13 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo...@@ -2162,7 +2189,13 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
2162 }2189 }
21632190
2164 if (mod.lookupDeclName(scope, ident_name)) |decl| {2191 if (mod.lookupDeclName(scope, ident_name)) |decl| {
2165 return rlWrapPtr(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclValInModule, .{ .decl = decl }, .{}));2192 if (rl == .ref) {
2193 return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{});
2194 } else {
2195 return rlWrap(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{
2196 .decl = decl,
2197 }, .{}));
2198 }
2166 }2199 }
21672200
2168 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{s}'", .{ident_name});2201 return mod.failNode(scope, &ident.base, "use of undeclared identifier '{s}'", .{ident_name});
...@@ -2927,6 +2960,8 @@ fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, resul...@@ -2927,6 +2960,8 @@ fn rlWrapVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, resul
2927 return rlWrap(mod, scope, rl, void_inst);2960 return rlWrap(mod, scope, rl, void_inst);
2928}2961}
29292962
2963/// TODO go over all the callsites and see where we can introduce "by-value" ZIR instructions
2964/// to save ZIR memory. For example, see DeclVal vs DeclRef.
2930fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst {2965fn rlWrapPtr(mod: *Module, scope: *Scope, rl: ResultLoc, ptr: *zir.Inst) InnerError!*zir.Inst {
2931 if (rl == .ref) return ptr;2966 if (rl == .ref) return ptr;
29322967
...@@ -3032,7 +3067,7 @@ pub fn addZIRInstBlock(...@@ -3032,7 +3067,7 @@ pub fn addZIRInstBlock(
3032 scope: *Scope,3067 scope: *Scope,
3033 src: usize,3068 src: usize,
3034 tag: zir.Inst.Tag,3069 tag: zir.Inst.Tag,
3035 body: zir.Module.Body,3070 body: zir.Body,
3036) !*zir.Inst.Block {3071) !*zir.Inst.Block {
3037 const gen_zir = scope.getGenZIR();3072 const gen_zir = scope.getGenZIR();
3038 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);3073 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
...@@ -3070,7 +3105,7 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ...@@ -3070,7 +3105,7 @@ pub fn addZIRInstConst(mod: *Module, scope: *Scope, src: usize, typed_value: Typ
3070}3105}
30713106
3072/// TODO The existence of this function is a workaround for a bug in stage1.3107/// TODO The existence of this function is a workaround for a bug in stage1.
3073pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Module.Body) !*zir.Inst.Loop {3108pub fn addZIRInstLoop(mod: *Module, scope: *Scope, src: usize, body: zir.Body) !*zir.Inst.Loop {
3074 const P = std.meta.fieldInfo(zir.Inst.Loop, .positionals).field_type;3109 const P = std.meta.fieldInfo(zir.Inst.Loop, .positionals).field_type;
3075 return addZIRInstSpecial(mod, scope, src, zir.Inst.Loop, P{ .body = body }, .{});3110 return addZIRInstSpecial(mod, scope, src, zir.Inst.Loop, P{ .body = body }, .{});
3076}3111}
src/codegen.zig+87-79
...@@ -9,7 +9,7 @@ const TypedValue = @import("TypedValue.zig");...@@ -9,7 +9,7 @@ const TypedValue = @import("TypedValue.zig");
9const link = @import("link.zig");9const link = @import("link.zig");
10const Module = @import("Module.zig");10const Module = @import("Module.zig");
11const Compilation = @import("Compilation.zig");11const Compilation = @import("Compilation.zig");
12const ErrorMsg = Compilation.ErrorMsg;12const ErrorMsg = Module.ErrorMsg;
13const Target = std.Target;13const Target = std.Target;
14const Allocator = mem.Allocator;14const Allocator = mem.Allocator;
15const trace = @import("tracy.zig").trace;15const trace = @import("tracy.zig").trace;
...@@ -74,7 +74,7 @@ pub const DebugInfoOutput = union(enum) {...@@ -74,7 +74,7 @@ pub const DebugInfoOutput = union(enum) {
7474
75pub fn generateSymbol(75pub fn generateSymbol(
76 bin_file: *link.File,76 bin_file: *link.File,
77 src: usize,77 src_loc: Module.SrcLoc,
78 typed_value: TypedValue,78 typed_value: TypedValue,
79 code: *std.ArrayList(u8),79 code: *std.ArrayList(u8),
80 debug_output: DebugInfoOutput,80 debug_output: DebugInfoOutput,
...@@ -87,56 +87,56 @@ pub fn generateSymbol(...@@ -87,56 +87,56 @@ pub fn generateSymbol(
87 switch (bin_file.options.target.cpu.arch) {87 switch (bin_file.options.target.cpu.arch) {
88 .wasm32 => unreachable, // has its own code path88 .wasm32 => unreachable, // has its own code path
89 .wasm64 => unreachable, // has its own code path89 .wasm64 => unreachable, // has its own code path
90 .arm => return Function(.arm).generateSymbol(bin_file, src, typed_value, code, debug_output),90 .arm => return Function(.arm).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
91 .armeb => return Function(.armeb).generateSymbol(bin_file, src, typed_value, code, debug_output),91 .armeb => return Function(.armeb).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
92 .aarch64 => return Function(.aarch64).generateSymbol(bin_file, src, typed_value, code, debug_output),92 .aarch64 => return Function(.aarch64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
93 .aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src, typed_value, code, debug_output),93 .aarch64_be => return Function(.aarch64_be).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
94 .aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src, typed_value, code, debug_output),94 .aarch64_32 => return Function(.aarch64_32).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
95 //.arc => return Function(.arc).generateSymbol(bin_file, src, typed_value, code, debug_output),95 //.arc => return Function(.arc).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
96 //.avr => return Function(.avr).generateSymbol(bin_file, src, typed_value, code, debug_output),96 //.avr => return Function(.avr).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
97 //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src, typed_value, code, debug_output),97 //.bpfel => return Function(.bpfel).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
98 //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src, typed_value, code, debug_output),98 //.bpfeb => return Function(.bpfeb).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
99 //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src, typed_value, code, debug_output),99 //.hexagon => return Function(.hexagon).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
100 //.mips => return Function(.mips).generateSymbol(bin_file, src, typed_value, code, debug_output),100 //.mips => return Function(.mips).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
101 //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src, typed_value, code, debug_output),101 //.mipsel => return Function(.mipsel).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
102 //.mips64 => return Function(.mips64).generateSymbol(bin_file, src, typed_value, code, debug_output),102 //.mips64 => return Function(.mips64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
103 //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src, typed_value, code, debug_output),103 //.mips64el => return Function(.mips64el).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
104 //.msp430 => return Function(.msp430).generateSymbol(bin_file, src, typed_value, code, debug_output),104 //.msp430 => return Function(.msp430).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
105 //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src, typed_value, code, debug_output),105 //.powerpc => return Function(.powerpc).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
106 //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src, typed_value, code, debug_output),106 //.powerpc64 => return Function(.powerpc64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
107 //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src, typed_value, code, debug_output),107 //.powerpc64le => return Function(.powerpc64le).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
108 //.r600 => return Function(.r600).generateSymbol(bin_file, src, typed_value, code, debug_output),108 //.r600 => return Function(.r600).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
109 //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src, typed_value, code, debug_output),109 //.amdgcn => return Function(.amdgcn).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
110 //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src, typed_value, code, debug_output),110 //.riscv32 => return Function(.riscv32).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
111 .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src, typed_value, code, debug_output),111 .riscv64 => return Function(.riscv64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
112 //.sparc => return Function(.sparc).generateSymbol(bin_file, src, typed_value, code, debug_output),112 //.sparc => return Function(.sparc).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
113 //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src, typed_value, code, debug_output),113 //.sparcv9 => return Function(.sparcv9).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
114 //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src, typed_value, code, debug_output),114 //.sparcel => return Function(.sparcel).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
115 //.s390x => return Function(.s390x).generateSymbol(bin_file, src, typed_value, code, debug_output),115 //.s390x => return Function(.s390x).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
116 .spu_2 => return Function(.spu_2).generateSymbol(bin_file, src, typed_value, code, debug_output),116 .spu_2 => return Function(.spu_2).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
117 //.tce => return Function(.tce).generateSymbol(bin_file, src, typed_value, code, debug_output),117 //.tce => return Function(.tce).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
118 //.tcele => return Function(.tcele).generateSymbol(bin_file, src, typed_value, code, debug_output),118 //.tcele => return Function(.tcele).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
119 //.thumb => return Function(.thumb).generateSymbol(bin_file, src, typed_value, code, debug_output),119 //.thumb => return Function(.thumb).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
120 //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src, typed_value, code, debug_output),120 //.thumbeb => return Function(.thumbeb).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
121 //.i386 => return Function(.i386).generateSymbol(bin_file, src, typed_value, code, debug_output),121 //.i386 => return Function(.i386).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
122 .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src, typed_value, code, debug_output),122 .x86_64 => return Function(.x86_64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
123 //.xcore => return Function(.xcore).generateSymbol(bin_file, src, typed_value, code, debug_output),123 //.xcore => return Function(.xcore).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
124 //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src, typed_value, code, debug_output),124 //.nvptx => return Function(.nvptx).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
125 //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src, typed_value, code, debug_output),125 //.nvptx64 => return Function(.nvptx64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
126 //.le32 => return Function(.le32).generateSymbol(bin_file, src, typed_value, code, debug_output),126 //.le32 => return Function(.le32).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
127 //.le64 => return Function(.le64).generateSymbol(bin_file, src, typed_value, code, debug_output),127 //.le64 => return Function(.le64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
128 //.amdil => return Function(.amdil).generateSymbol(bin_file, src, typed_value, code, debug_output),128 //.amdil => return Function(.amdil).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
129 //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src, typed_value, code, debug_output),129 //.amdil64 => return Function(.amdil64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
130 //.hsail => return Function(.hsail).generateSymbol(bin_file, src, typed_value, code, debug_output),130 //.hsail => return Function(.hsail).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
131 //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src, typed_value, code, debug_output),131 //.hsail64 => return Function(.hsail64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
132 //.spir => return Function(.spir).generateSymbol(bin_file, src, typed_value, code, debug_output),132 //.spir => return Function(.spir).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
133 //.spir64 => return Function(.spir64).generateSymbol(bin_file, src, typed_value, code, debug_output),133 //.spir64 => return Function(.spir64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
134 //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src, typed_value, code, debug_output),134 //.kalimba => return Function(.kalimba).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
135 //.shave => return Function(.shave).generateSymbol(bin_file, src, typed_value, code, debug_output),135 //.shave => return Function(.shave).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
136 //.lanai => return Function(.lanai).generateSymbol(bin_file, src, typed_value, code, debug_output),136 //.lanai => return Function(.lanai).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
137 //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src, typed_value, code, debug_output),137 //.renderscript32 => return Function(.renderscript32).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
138 //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src, typed_value, code, debug_output),138 //.renderscript64 => return Function(.renderscript64).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
139 //.ve => return Function(.ve).generateSymbol(bin_file, src, typed_value, code, debug_output),139 //.ve => return Function(.ve).generateSymbol(bin_file, src_loc, typed_value, code, debug_output),
140 else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),140 else => @panic("Backend architectures that don't have good support yet are commented out, to improve compilation performance. If you are interested in one of these other backends feel free to uncomment them. Eventually these will be completed, but stage1 is slow and a memory hog."),
141 }141 }
142 },142 },
...@@ -147,7 +147,7 @@ pub fn generateSymbol(...@@ -147,7 +147,7 @@ pub fn generateSymbol(
147 try code.ensureCapacity(code.items.len + payload.data.len + 1);147 try code.ensureCapacity(code.items.len + payload.data.len + 1);
148 code.appendSliceAssumeCapacity(payload.data);148 code.appendSliceAssumeCapacity(payload.data);
149 const prev_len = code.items.len;149 const prev_len = code.items.len;
150 switch (try generateSymbol(bin_file, src, .{150 switch (try generateSymbol(bin_file, src_loc, .{
151 .ty = typed_value.ty.elemType(),151 .ty = typed_value.ty.elemType(),
152 .val = sentinel,152 .val = sentinel,
153 }, code, debug_output)) {153 }, code, debug_output)) {
...@@ -165,7 +165,7 @@ pub fn generateSymbol(...@@ -165,7 +165,7 @@ pub fn generateSymbol(
165 return Result{165 return Result{
166 .fail = try ErrorMsg.create(166 .fail = try ErrorMsg.create(
167 bin_file.allocator,167 bin_file.allocator,
168 src,168 src_loc,
169 "TODO implement generateSymbol for more kinds of arrays",169 "TODO implement generateSymbol for more kinds of arrays",
170 .{},170 .{},
171 ),171 ),
...@@ -200,7 +200,7 @@ pub fn generateSymbol(...@@ -200,7 +200,7 @@ pub fn generateSymbol(
200 return Result{200 return Result{
201 .fail = try ErrorMsg.create(201 .fail = try ErrorMsg.create(
202 bin_file.allocator,202 bin_file.allocator,
203 src,203 src_loc,
204 "TODO implement generateSymbol for pointer {}",204 "TODO implement generateSymbol for pointer {}",
205 .{typed_value.val},205 .{typed_value.val},
206 ),206 ),
...@@ -217,7 +217,7 @@ pub fn generateSymbol(...@@ -217,7 +217,7 @@ pub fn generateSymbol(
217 return Result{217 return Result{
218 .fail = try ErrorMsg.create(218 .fail = try ErrorMsg.create(
219 bin_file.allocator,219 bin_file.allocator,
220 src,220 src_loc,
221 "TODO implement generateSymbol for int type '{}'",221 "TODO implement generateSymbol for int type '{}'",
222 .{typed_value.ty},222 .{typed_value.ty},
223 ),223 ),
...@@ -227,7 +227,7 @@ pub fn generateSymbol(...@@ -227,7 +227,7 @@ pub fn generateSymbol(
227 return Result{227 return Result{
228 .fail = try ErrorMsg.create(228 .fail = try ErrorMsg.create(
229 bin_file.allocator,229 bin_file.allocator,
230 src,230 src_loc,
231 "TODO implement generateSymbol for type '{s}'",231 "TODO implement generateSymbol for type '{s}'",
232 .{@tagName(t)},232 .{@tagName(t)},
233 ),233 ),
...@@ -259,7 +259,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -259,7 +259,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
259 ret_mcv: MCValue,259 ret_mcv: MCValue,
260 fn_type: Type,260 fn_type: Type,
261 arg_index: usize,261 arg_index: usize,
262 src: usize,262 src_loc: Module.SrcLoc,
263 stack_align: u32,263 stack_align: u32,
264264
265 /// Byte offset within the source file.265 /// Byte offset within the source file.
...@@ -428,7 +428,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -428,7 +428,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
428428
429 fn generateSymbol(429 fn generateSymbol(
430 bin_file: *link.File,430 bin_file: *link.File,
431 src: usize,431 src_loc: Module.SrcLoc,
432 typed_value: TypedValue,432 typed_value: TypedValue,
433 code: *std.ArrayList(u8),433 code: *std.ArrayList(u8),
434 debug_output: DebugInfoOutput,434 debug_output: DebugInfoOutput,
...@@ -450,19 +450,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -450,19 +450,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
450 try branch_stack.append(.{});450 try branch_stack.append(.{});
451451
452 const src_data: struct { lbrace_src: usize, rbrace_src: usize, source: []const u8 } = blk: {452 const src_data: struct { lbrace_src: usize, rbrace_src: usize, source: []const u8 } = blk: {
453 if (module_fn.owner_decl.scope.cast(Module.Scope.Container)) |container_scope| {453 const container_scope = module_fn.owner_decl.container;
454 const tree = container_scope.file_scope.contents.tree;454 const tree = container_scope.file_scope.contents.tree;
455 const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?;455 const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?;
456 const block = fn_proto.getBodyNode().?.castTag(.Block).?;456 const block = fn_proto.getBodyNode().?.castTag(.Block).?;
457 const lbrace_src = tree.token_locs[block.lbrace].start;457 const lbrace_src = tree.token_locs[block.lbrace].start;
458 const rbrace_src = tree.token_locs[block.rbrace].start;458 const rbrace_src = tree.token_locs[block.rbrace].start;
459 break :blk .{ .lbrace_src = lbrace_src, .rbrace_src = rbrace_src, .source = tree.source };459 break :blk .{
460 } else if (module_fn.owner_decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| {460 .lbrace_src = lbrace_src,
461 const byte_off = zir_module.contents.module.decls[module_fn.owner_decl.src_index].inst.src;461 .rbrace_src = rbrace_src,
462 break :blk .{ .lbrace_src = byte_off, .rbrace_src = byte_off, .source = zir_module.source.bytes };462 .source = tree.source,
463 } else {463 };
464 unreachable;
465 }
466 };464 };
467465
468 var function = Self{466 var function = Self{
...@@ -478,7 +476,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -478,7 +476,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
478 .fn_type = fn_type,476 .fn_type = fn_type,
479 .arg_index = 0,477 .arg_index = 0,
480 .branch_stack = &branch_stack,478 .branch_stack = &branch_stack,
481 .src = src,479 .src_loc = src_loc,
482 .stack_align = undefined,480 .stack_align = undefined,
483 .prev_di_pc = 0,481 .prev_di_pc = 0,
484 .prev_di_src = src_data.lbrace_src,482 .prev_di_src = src_data.lbrace_src,
...@@ -489,7 +487,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -489,7 +487,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
489 defer function.stack.deinit(bin_file.allocator);487 defer function.stack.deinit(bin_file.allocator);
490 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);488 defer function.exitlude_jump_relocs.deinit(bin_file.allocator);
491489
492 var call_info = function.resolveCallingConventionValues(src, fn_type) catch |err| switch (err) {490 var call_info = function.resolveCallingConventionValues(src_loc.byte_offset, fn_type) catch |err| switch (err) {
493 error.CodegenFail => return Result{ .fail = function.err_msg.? },491 error.CodegenFail => return Result{ .fail = function.err_msg.? },
494 else => |e| return e,492 else => |e| return e,
495 };493 };
...@@ -536,12 +534,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -536,12 +534,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
536534
537 const stack_end = self.max_end_stack;535 const stack_end = self.max_end_stack;
538 if (stack_end > math.maxInt(i32))536 if (stack_end > math.maxInt(i32))
539 return self.fail(self.src, "too much stack used in call parameters", .{});537 return self.failSymbol("too much stack used in call parameters", .{});
540 const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);538 const aligned_stack_end = mem.alignForward(stack_end, self.stack_align);
541 mem.writeIntLittle(u32, self.code.items[reloc_index..][0..4], @intCast(u32, aligned_stack_end));539 mem.writeIntLittle(u32, self.code.items[reloc_index..][0..4], @intCast(u32, aligned_stack_end));
542540
543 if (self.code.items.len >= math.maxInt(i32)) {541 if (self.code.items.len >= math.maxInt(i32)) {
544 return self.fail(self.src, "unable to perform relocation: jump too far", .{});542 return self.failSymbol("unable to perform relocation: jump too far", .{});
545 }543 }
546 if (self.exitlude_jump_relocs.items.len == 1) {544 if (self.exitlude_jump_relocs.items.len == 1) {
547 self.code.items.len -= 5;545 self.code.items.len -= 5;
...@@ -598,7 +596,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -598,7 +596,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
598 if (Instruction.Operand.fromU32(@intCast(u32, aligned_stack_end))) |op| {596 if (Instruction.Operand.fromU32(@intCast(u32, aligned_stack_end))) |op| {
599 writeInt(u32, self.code.items[backpatch_reloc..][0..4], Instruction.sub(.al, .sp, .sp, op).toU32());597 writeInt(u32, self.code.items[backpatch_reloc..][0..4], Instruction.sub(.al, .sp, .sp, op).toU32());
600 } else {598 } else {
601 return self.fail(self.src, "TODO ARM: allow larger stacks", .{});599 return self.failSymbol("TODO ARM: allow larger stacks", .{});
602 }600 }
603601
604 try self.dbgSetEpilogueBegin();602 try self.dbgSetEpilogueBegin();
...@@ -624,7 +622,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -624,7 +622,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
624 if (math.cast(i26, amt)) |offset| {622 if (math.cast(i26, amt)) |offset| {
625 writeInt(u32, self.code.items[jmp_reloc..][0..4], Instruction.b(.al, offset).toU32());623 writeInt(u32, self.code.items[jmp_reloc..][0..4], Instruction.b(.al, offset).toU32());
626 } else |err| {624 } else |err| {
627 return self.fail(self.src, "exitlude jump is too large", .{});625 return self.failSymbol("exitlude jump is too large", .{});
628 }626 }
629 }627 }
630 }628 }
...@@ -3678,7 +3676,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3678,7 +3676,17 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3678 fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError {3676 fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError {
3679 @setCold(true);3677 @setCold(true);
3680 assert(self.err_msg == null);3678 assert(self.err_msg == null);
3681 self.err_msg = try ErrorMsg.create(self.bin_file.allocator, src, format, args);3679 self.err_msg = try ErrorMsg.create(self.bin_file.allocator, .{
3680 .file_scope = self.src_loc.file_scope,
3681 .byte_offset = src,
3682 }, format, args);
3683 return error.CodegenFail;
3684 }
3685
3686 fn failSymbol(self: *Self, comptime format: []const u8, args: anytype) InnerError {
3687 @setCold(true);
3688 assert(self.err_msg == null);
3689 self.err_msg = try ErrorMsg.create(self.bin_file.allocator, self.src_loc, format, args);
3682 return error.CodegenFail;3690 return error.CodegenFail;
3683 }3691 }
36843692
src/codegen/c.zig+5-2
...@@ -114,10 +114,13 @@ pub const DeclGen = struct {...@@ -114,10 +114,13 @@ pub const DeclGen = struct {
114 module: *Module,114 module: *Module,
115 decl: *Decl,115 decl: *Decl,
116 fwd_decl: std.ArrayList(u8),116 fwd_decl: std.ArrayList(u8),
117 error_msg: ?*Compilation.ErrorMsg,117 error_msg: ?*Module.ErrorMsg,
118118
119 fn fail(dg: *DeclGen, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {119 fn fail(dg: *DeclGen, src: usize, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
120 dg.error_msg = try Compilation.ErrorMsg.create(dg.module.gpa, src, format, args);120 dg.error_msg = try Module.ErrorMsg.create(dg.module.gpa, .{
121 .file_scope = dg.decl.getFileScope(),
122 .byte_offset = src,
123 }, format, args);
121 return error.AnalysisFail;124 return error.AnalysisFail;
122 }125 }
123126
src/codegen/llvm.zig+11-2
...@@ -148,7 +148,7 @@ pub const LLVMIRModule = struct {...@@ -148,7 +148,7 @@ pub const LLVMIRModule = struct {
148 object_path: []const u8,148 object_path: []const u8,
149149
150 gpa: *Allocator,150 gpa: *Allocator,
151 err_msg: ?*Compilation.ErrorMsg = null,151 err_msg: ?*Module.ErrorMsg = null,
152152
153 // TODO: The fields below should really move into a different struct,153 // TODO: The fields below should really move into a different struct,
154 // because they are only valid when generating a function154 // because they are only valid when generating a function
...@@ -177,6 +177,8 @@ pub const LLVMIRModule = struct {...@@ -177,6 +177,8 @@ pub const LLVMIRModule = struct {
177 break_vals: *BreakValues,177 break_vals: *BreakValues,
178 }) = .{},178 }) = .{},
179179
180 src_loc: Module.SrcLoc,
181
180 const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock);182 const BreakBasicBlocks = std.ArrayListUnmanaged(*const llvm.BasicBlock);
181 const BreakValues = std.ArrayListUnmanaged(*const llvm.Value);183 const BreakValues = std.ArrayListUnmanaged(*const llvm.Value);
182184
...@@ -254,6 +256,8 @@ pub const LLVMIRModule = struct {...@@ -254,6 +256,8 @@ pub const LLVMIRModule = struct {
254 .builder = builder,256 .builder = builder,
255 .object_path = object_path,257 .object_path = object_path,
256 .gpa = gpa,258 .gpa = gpa,
259 // TODO move this field into a struct that is only instantiated per gen() call
260 .src_loc = undefined,
257 };261 };
258 return self;262 return self;
259 }263 }
...@@ -335,6 +339,8 @@ pub const LLVMIRModule = struct {...@@ -335,6 +339,8 @@ pub const LLVMIRModule = struct {
335 const typed_value = decl.typed_value.most_recent.typed_value;339 const typed_value = decl.typed_value.most_recent.typed_value;
336 const src = decl.src();340 const src = decl.src();
337341
342 self.src_loc = decl.srcLoc();
343
338 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, typed_value.ty, typed_value.val });344 log.debug("gen: {s} type: {}, value: {}", .{ decl.name, typed_value.ty, typed_value.val });
339345
340 if (typed_value.val.castTag(.function)) |func_payload| {346 if (typed_value.val.castTag(.function)) |func_payload| {
...@@ -853,7 +859,10 @@ pub const LLVMIRModule = struct {...@@ -853,7 +859,10 @@ pub const LLVMIRModule = struct {
853 pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {859 pub fn fail(self: *LLVMIRModule, src: usize, comptime format: []const u8, args: anytype) error{ OutOfMemory, CodegenFail } {
854 @setCold(true);860 @setCold(true);
855 assert(self.err_msg == null);861 assert(self.err_msg == null);
856 self.err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args);862 self.err_msg = try Module.ErrorMsg.create(self.gpa, .{
863 .file_scope = self.src_loc.file_scope,
864 .byte_offset = src,
865 }, format, args);
857 return error.CodegenFail;866 return error.CodegenFail;
858 }867 }
859};868};
src/link/Coff.zig+3-3
...@@ -670,7 +670,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {...@@ -670,7 +670,7 @@ pub fn updateDecl(self: *Coff, module: *Module, decl: *Module.Decl) !void {
670 var code_buffer = std.ArrayList(u8).init(self.base.allocator);670 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
671 defer code_buffer.deinit();671 defer code_buffer.deinit();
672672
673 const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .none);673 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none);
674 const code = switch (res) {674 const code = switch (res) {
675 .externally_managed => |x| x,675 .externally_managed => |x| x,
676 .appended => code_buffer.items,676 .appended => code_buffer.items,
...@@ -732,7 +732,7 @@ pub fn updateDeclExports(self: *Coff, module: *Module, decl: *const Module.Decl,...@@ -732,7 +732,7 @@ pub fn updateDeclExports(self: *Coff, module: *Module, decl: *const Module.Decl,
732 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);732 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
733 module.failed_exports.putAssumeCapacityNoClobber(733 module.failed_exports.putAssumeCapacityNoClobber(
734 exp,734 exp,
735 try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),735 try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: ExportOptions.section", .{}),
736 );736 );
737 continue;737 continue;
738 }738 }
...@@ -743,7 +743,7 @@ pub fn updateDeclExports(self: *Coff, module: *Module, decl: *const Module.Decl,...@@ -743,7 +743,7 @@ pub fn updateDeclExports(self: *Coff, module: *Module, decl: *const Module.Decl,
743 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);743 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
744 module.failed_exports.putAssumeCapacityNoClobber(744 module.failed_exports.putAssumeCapacityNoClobber(
745 exp,745 exp,
746 try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: Exports other than '_start'", .{}),746 try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: Exports other than '_start'", .{}),
747 );747 );
748 continue;748 continue;
749 }749 }
src/link/Elf.zig+12-21
...@@ -2189,22 +2189,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2189,22 +2189,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2189 try dbg_line_buffer.ensureCapacity(26);2189 try dbg_line_buffer.ensureCapacity(26);
21902190
2191 const line_off: u28 = blk: {2191 const line_off: u28 = blk: {
2192 if (decl.scope.cast(Module.Scope.Container)) |container_scope| {2192 const tree = decl.container.file_scope.contents.tree;
2193 const tree = container_scope.file_scope.contents.tree;2193 const file_ast_decls = tree.root_node.decls();
2194 const file_ast_decls = tree.root_node.decls();2194 // TODO Look into improving the performance here by adding a token-index-to-line
2195 // TODO Look into improving the performance here by adding a token-index-to-line2195 // lookup table. Currently this involves scanning over the source code for newlines.
2196 // lookup table. Currently this involves scanning over the source code for newlines.2196 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;
2197 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;2197 const block = fn_proto.getBodyNode().?.castTag(.Block).?;
2198 const block = fn_proto.getBodyNode().?.castTag(.Block).?;2198 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);
2199 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);2199 break :blk @intCast(u28, line_delta);
2200 break :blk @intCast(u28, line_delta);
2201 } else if (decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| {
2202 const byte_off = zir_module.contents.module.decls[decl.src_index].inst.src;
2203 const line_delta = std.zig.lineDelta(zir_module.source.bytes, 0, byte_off);
2204 break :blk @intCast(u28, line_delta);
2205 } else {
2206 unreachable;
2207 }
2208 };2200 };
22092201
2210 const ptr_width_bytes = self.ptrWidthBytes();2202 const ptr_width_bytes = self.ptrWidthBytes();
...@@ -2268,7 +2260,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2268,7 +2260,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2268 } else {2260 } else {
2269 // TODO implement .debug_info for global variables2261 // TODO implement .debug_info for global variables
2270 }2262 }
2271 const res = try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .{2263 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
2272 .dwarf = .{2264 .dwarf = .{
2273 .dbg_line = &dbg_line_buffer,2265 .dbg_line = &dbg_line_buffer,
2274 .dbg_info = &dbg_info_buffer,2266 .dbg_info = &dbg_info_buffer,
...@@ -2642,7 +2634,7 @@ pub fn updateDeclExports(...@@ -2642,7 +2634,7 @@ pub fn updateDeclExports(
2642 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);2634 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
2643 module.failed_exports.putAssumeCapacityNoClobber(2635 module.failed_exports.putAssumeCapacityNoClobber(
2644 exp,2636 exp,
2645 try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),2637 try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: ExportOptions.section", .{}),
2646 );2638 );
2647 continue;2639 continue;
2648 }2640 }
...@@ -2660,7 +2652,7 @@ pub fn updateDeclExports(...@@ -2660,7 +2652,7 @@ pub fn updateDeclExports(
2660 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);2652 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
2661 module.failed_exports.putAssumeCapacityNoClobber(2653 module.failed_exports.putAssumeCapacityNoClobber(
2662 exp,2654 exp,
2663 try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),2655 try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: GlobalLinkage.LinkOnce", .{}),
2664 );2656 );
2665 continue;2657 continue;
2666 },2658 },
...@@ -2703,8 +2695,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec...@@ -2703,8 +2695,7 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec
27032695
2704 if (self.llvm_ir_module) |_| return;2696 if (self.llvm_ir_module) |_| return;
27052697
2706 const container_scope = decl.scope.cast(Module.Scope.Container).?;2698 const tree = decl.container.file_scope.contents.tree;
2707 const tree = container_scope.file_scope.contents.tree;
2708 const file_ast_decls = tree.root_node.decls();2699 const file_ast_decls = tree.root_node.decls();
2709 // TODO Look into improving the performance here by adding a token-index-to-line2700 // TODO Look into improving the performance here by adding a token-index-to-line
2710 // lookup table. Currently this involves scanning over the source code for newlines.2701 // lookup table. Currently this involves scanning over the source code for newlines.
src/link/MachO.zig+4-4
...@@ -1148,7 +1148,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1148,7 +1148,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1148 }1148 }
11491149
1150 const res = if (debug_buffers) |*dbg|1150 const res = if (debug_buffers) |*dbg|
1151 try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .{1151 try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .{
1152 .dwarf = .{1152 .dwarf = .{
1153 .dbg_line = &dbg.dbg_line_buffer,1153 .dbg_line = &dbg.dbg_line_buffer,
1154 .dbg_info = &dbg.dbg_info_buffer,1154 .dbg_info = &dbg.dbg_info_buffer,
...@@ -1156,7 +1156,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -1156,7 +1156,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
1156 },1156 },
1157 })1157 })
1158 else1158 else
1159 try codegen.generateSymbol(&self.base, decl.src(), typed_value, &code_buffer, .none);1159 try codegen.generateSymbol(&self.base, decl.srcLoc(), typed_value, &code_buffer, .none);
11601160
1161 const code = switch (res) {1161 const code = switch (res) {
1162 .externally_managed => |x| x,1162 .externally_managed => |x| x,
...@@ -1316,7 +1316,7 @@ pub fn updateDeclExports(...@@ -1316,7 +1316,7 @@ pub fn updateDeclExports(
1316 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);1316 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
1317 module.failed_exports.putAssumeCapacityNoClobber(1317 module.failed_exports.putAssumeCapacityNoClobber(
1318 exp,1318 exp,
1319 try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: ExportOptions.section", .{}),1319 try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: ExportOptions.section", .{}),
1320 );1320 );
1321 continue;1321 continue;
1322 }1322 }
...@@ -1334,7 +1334,7 @@ pub fn updateDeclExports(...@@ -1334,7 +1334,7 @@ pub fn updateDeclExports(
1334 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);1334 try module.failed_exports.ensureCapacity(module.gpa, module.failed_exports.items().len + 1);
1335 module.failed_exports.putAssumeCapacityNoClobber(1335 module.failed_exports.putAssumeCapacityNoClobber(
1336 exp,1336 exp,
1337 try Compilation.ErrorMsg.create(self.base.allocator, 0, "Unimplemented: GlobalLinkage.LinkOnce", .{}),1337 try Module.ErrorMsg.create(self.base.allocator, decl.srcLoc(), "Unimplemented: GlobalLinkage.LinkOnce", .{}),
1338 );1338 );
1339 continue;1339 continue;
1340 },1340 },
src/link/MachO/DebugSymbols.zig+9-18
...@@ -906,8 +906,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M...@@ -906,8 +906,7 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M
906 const tracy = trace(@src());906 const tracy = trace(@src());
907 defer tracy.end();907 defer tracy.end();
908908
909 const container_scope = decl.scope.cast(Module.Scope.Container).?;909 const tree = decl.container.file_scope.contents.tree;
910 const tree = container_scope.file_scope.contents.tree;
911 const file_ast_decls = tree.root_node.decls();910 const file_ast_decls = tree.root_node.decls();
912 // TODO Look into improving the performance here by adding a token-index-to-line911 // TODO Look into improving the performance here by adding a token-index-to-line
913 // lookup table. Currently this involves scanning over the source code for newlines.912 // lookup table. Currently this involves scanning over the source code for newlines.
...@@ -951,22 +950,14 @@ pub fn initDeclDebugBuffers(...@@ -951,22 +950,14 @@ pub fn initDeclDebugBuffers(
951 try dbg_line_buffer.ensureCapacity(26);950 try dbg_line_buffer.ensureCapacity(26);
952951
953 const line_off: u28 = blk: {952 const line_off: u28 = blk: {
954 if (decl.scope.cast(Module.Scope.Container)) |container_scope| {953 const tree = decl.container.file_scope.contents.tree;
955 const tree = container_scope.file_scope.contents.tree;954 const file_ast_decls = tree.root_node.decls();
956 const file_ast_decls = tree.root_node.decls();955 // TODO Look into improving the performance here by adding a token-index-to-line
957 // TODO Look into improving the performance here by adding a token-index-to-line956 // lookup table. Currently this involves scanning over the source code for newlines.
958 // lookup table. Currently this involves scanning over the source code for newlines.957 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;
959 const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?;958 const block = fn_proto.getBodyNode().?.castTag(.Block).?;
960 const block = fn_proto.getBodyNode().?.castTag(.Block).?;959 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);
961 const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start);960 break :blk @intCast(u28, line_delta);
962 break :blk @intCast(u28, line_delta);
963 } else if (decl.scope.cast(Module.Scope.ZIRModule)) |zir_module| {
964 const byte_off = zir_module.contents.module.decls[decl.src_index].inst.src;
965 const line_delta = std.zig.lineDelta(zir_module.source.bytes, 0, byte_off);
966 break :blk @intCast(u28, line_delta);
967 } else {
968 unreachable;
969 }
970 };961 };
971962
972 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{963 dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{
src/main.zig+14-33
...@@ -221,7 +221,6 @@ const usage_build_generic =...@@ -221,7 +221,6 @@ const usage_build_generic =
221 \\221 \\
222 \\Supported file types:222 \\Supported file types:
223 \\ .zig Zig source code223 \\ .zig Zig source code
224 \\ .zir Zig Intermediate Representation code
225 \\ .o ELF object file224 \\ .o ELF object file
226 \\ .o MACH-O (macOS) object file225 \\ .o MACH-O (macOS) object file
227 \\ .obj COFF (Windows) object file226 \\ .obj COFF (Windows) object file
...@@ -245,8 +244,6 @@ const usage_build_generic =...@@ -245,8 +244,6 @@ const usage_build_generic =
245 \\ -fno-emit-bin Do not output machine code244 \\ -fno-emit-bin Do not output machine code
246 \\ -femit-asm[=path] Output .s (assembly code)245 \\ -femit-asm[=path] Output .s (assembly code)
247 \\ -fno-emit-asm (default) Do not output .s (assembly code)246 \\ -fno-emit-asm (default) Do not output .s (assembly code)
248 \\ -femit-zir[=path] Produce a .zir file with Zig IR
249 \\ -fno-emit-zir (default) Do not produce a .zir file with Zig IR
250 \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)247 \\ -femit-llvm-ir[=path] Produce a .ll file with LLVM IR (requires LLVM extensions)
251 \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR248 \\ -fno-emit-llvm-ir (default) Do not produce a .ll file with LLVM IR
252 \\ -femit-h[=path] Generate a C header file (.h)249 \\ -femit-h[=path] Generate a C header file (.h)
...@@ -1631,18 +1628,12 @@ fn buildOutputType(...@@ -1631,18 +1628,12 @@ fn buildOutputType(
1631 var emit_docs_resolved = try emit_docs.resolve("docs");1628 var emit_docs_resolved = try emit_docs.resolve("docs");
1632 defer emit_docs_resolved.deinit();1629 defer emit_docs_resolved.deinit();
16331630
1634 const zir_out_path: ?[]const u8 = switch (emit_zir) {1631 switch (emit_zir) {
1635 .no => null,1632 .no => {},
1636 .yes_default_path => blk: {1633 .yes_default_path, .yes => {
1637 if (root_src_file) |rsf| {1634 fatal("The -femit-zir implementation has been intentionally deleted so that it can be rewritten as a proper backend.", .{});
1638 if (mem.endsWith(u8, rsf, ".zir")) {
1639 break :blk try std.fmt.allocPrint(arena, "{s}.out.zir", .{root_name});
1640 }
1641 }
1642 break :blk try std.fmt.allocPrint(arena, "{s}.zir", .{root_name});
1643 },1635 },
1644 .yes => |p| p,1636 }
1645 };
16461637
1647 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {1638 const root_pkg: ?*Package = if (root_src_file) |src_path| blk: {
1648 if (main_pkg_path) |p| {1639 if (main_pkg_path) |p| {
...@@ -1753,7 +1744,7 @@ fn buildOutputType(...@@ -1753,7 +1744,7 @@ fn buildOutputType(
1753 .dll_export_fns = dll_export_fns,1744 .dll_export_fns = dll_export_fns,
1754 .object_format = object_format,1745 .object_format = object_format,
1755 .optimize_mode = optimize_mode,1746 .optimize_mode = optimize_mode,
1756 .keep_source_files_loaded = zir_out_path != null,1747 .keep_source_files_loaded = false,
1757 .clang_argv = clang_argv.items,1748 .clang_argv = clang_argv.items,
1758 .lld_argv = lld_argv.items,1749 .lld_argv = lld_argv.items,
1759 .lib_dirs = lib_dirs.items,1750 .lib_dirs = lib_dirs.items,
...@@ -1845,7 +1836,7 @@ fn buildOutputType(...@@ -1845,7 +1836,7 @@ fn buildOutputType(
1845 }1836 }
1846 };1837 };
18471838
1848 updateModule(gpa, comp, zir_out_path, hook) catch |err| switch (err) {1839 updateModule(gpa, comp, hook) catch |err| switch (err) {
1849 error.SemanticAnalyzeFail => if (!watch) process.exit(1),1840 error.SemanticAnalyzeFail => if (!watch) process.exit(1),
1850 else => |e| return e,1841 else => |e| return e,
1851 };1842 };
...@@ -1980,7 +1971,7 @@ fn buildOutputType(...@@ -1980,7 +1971,7 @@ fn buildOutputType(
1980 if (output_mode == .Exe) {1971 if (output_mode == .Exe) {
1981 try comp.makeBinFileWritable();1972 try comp.makeBinFileWritable();
1982 }1973 }
1983 updateModule(gpa, comp, zir_out_path, hook) catch |err| switch (err) {1974 updateModule(gpa, comp, hook) catch |err| switch (err) {
1984 error.SemanticAnalyzeFail => continue,1975 error.SemanticAnalyzeFail => continue,
1985 else => |e| return e,1976 else => |e| return e,
1986 };1977 };
...@@ -2003,7 +1994,7 @@ const AfterUpdateHook = union(enum) {...@@ -2003,7 +1994,7 @@ const AfterUpdateHook = union(enum) {
2003 update: []const u8,1994 update: []const u8,
2004};1995};
20051996
2006fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8, hook: AfterUpdateHook) !void {1997fn updateModule(gpa: *Allocator, comp: *Compilation, hook: AfterUpdateHook) !void {
2007 try comp.update();1998 try comp.update();
20081999
2009 var errors = try comp.getAllErrorsAlloc();2000 var errors = try comp.getAllErrorsAlloc();
...@@ -2013,6 +2004,10 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8,...@@ -2013,6 +2004,10 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8,
2013 for (errors.list) |full_err_msg| {2004 for (errors.list) |full_err_msg| {
2014 full_err_msg.renderToStdErr();2005 full_err_msg.renderToStdErr();
2015 }2006 }
2007 const log_text = comp.getCompileLogOutput();
2008 if (log_text.len != 0) {
2009 std.debug.print("\nCompile Log Output:\n{s}", .{log_text});
2010 }
2016 return error.SemanticAnalyzeFail;2011 return error.SemanticAnalyzeFail;
2017 } else switch (hook) {2012 } else switch (hook) {
2018 .none => {},2013 .none => {},
...@@ -2024,20 +2019,6 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8,...@@ -2024,20 +2019,6 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8,
2024 .{},2019 .{},
2025 ),2020 ),
2026 }2021 }
2027
2028 if (zir_out_path) |zop| {
2029 const module = comp.bin_file.options.module orelse
2030 fatal("-femit-zir with no zig source code", .{});
2031 var new_zir_module = try zir.emit(gpa, module);
2032 defer new_zir_module.deinit(gpa);
2033
2034 const baf = try io.BufferedAtomicFile.create(gpa, fs.cwd(), zop, .{});
2035 defer baf.destroy();
2036
2037 try new_zir_module.writeToStream(gpa, baf.writer());
2038
2039 try baf.finish();
2040 }
2041}2022}
20422023
2043fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {2024fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !void {
...@@ -2506,7 +2487,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v...@@ -2506,7 +2487,7 @@ pub fn cmdBuild(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v
2506 };2487 };
2507 defer comp.destroy();2488 defer comp.destroy();
25082489
2509 try updateModule(gpa, comp, null, .none);2490 try updateModule(gpa, comp, .none);
2510 try comp.makeBinFileExecutable();2491 try comp.makeBinFileExecutable();
25112492
2512 child_argv.items[argv_index_exe] = try comp.bin_file.options.emit.?.directory.join(2493 child_argv.items[argv_index_exe] = try comp.bin_file.options.emit.?.directory.join(
src/test.zig+124-88
...@@ -15,6 +15,8 @@ const CrossTarget = std.zig.CrossTarget;...@@ -15,6 +15,8 @@ const CrossTarget = std.zig.CrossTarget;
1515
16const zig_h = link.File.C.zig_h;16const zig_h = link.File.C.zig_h;
1717
18const hr = "=" ** 40;
19
18test "self-hosted" {20test "self-hosted" {
19 var ctx = TestContext.init();21 var ctx = TestContext.init();
20 defer ctx.deinit();22 defer ctx.deinit();
...@@ -29,23 +31,32 @@ const ErrorMsg = union(enum) {...@@ -29,23 +31,32 @@ const ErrorMsg = union(enum) {
29 msg: []const u8,31 msg: []const u8,
30 line: u32,32 line: u32,
31 column: u32,33 column: u32,
34 kind: Kind,
32 },35 },
33 plain: struct {36 plain: struct {
34 msg: []const u8,37 msg: []const u8,
38 kind: Kind,
35 },39 },
3640
37 fn init(other: Compilation.AllErrors.Message) ErrorMsg {41 const Kind = enum {
42 @"error",
43 note,
44 };
45
46 fn init(other: Compilation.AllErrors.Message, kind: Kind) ErrorMsg {
38 switch (other) {47 switch (other) {
39 .src => |src| return .{48 .src => |src| return .{
40 .src = .{49 .src = .{
41 .msg = src.msg,50 .msg = src.msg,
42 .line = @intCast(u32, src.line),51 .line = @intCast(u32, src.line),
43 .column = @intCast(u32, src.column),52 .column = @intCast(u32, src.column),
53 .kind = kind,
44 },54 },
45 },55 },
46 .plain => |plain| return .{56 .plain => |plain| return .{
47 .plain = .{57 .plain = .{
48 .msg = plain.msg,58 .msg = plain.msg,
59 .kind = kind,
49 },60 },
50 },61 },
51 }62 }
...@@ -59,14 +70,15 @@ const ErrorMsg = union(enum) {...@@ -59,14 +70,15 @@ const ErrorMsg = union(enum) {
59 ) !void {70 ) !void {
60 switch (self) {71 switch (self) {
61 .src => |src| {72 .src => |src| {
62 return writer.print(":{d}:{d}: error: {s}", .{73 return writer.print(":{d}:{d}: {s}: {s}", .{
63 src.line + 1,74 src.line + 1,
64 src.column + 1,75 src.column + 1,
76 @tagName(src.kind),
65 src.msg,77 src.msg,
66 });78 });
67 },79 },
68 .plain => |plain| {80 .plain => |plain| {
69 return writer.print("error: {s}", .{plain.msg});81 return writer.print("{s}: {s}", .{ plain.msg, @tagName(plain.kind) });
70 },82 },
71 }83 }
72 }84 }
...@@ -86,9 +98,6 @@ pub const TestContext = struct {...@@ -86,9 +98,6 @@ pub const TestContext = struct {
86 /// effects of the incremental compilation.98 /// effects of the incremental compilation.
87 src: [:0]const u8,99 src: [:0]const u8,
88 case: union(enum) {100 case: union(enum) {
89 /// A transformation update transforms the input and tests against
90 /// the expected output ZIR.
91 Transformation: [:0]const u8,
92 /// Check the main binary output file against an expected set of bytes.101 /// Check the main binary output file against an expected set of bytes.
93 /// This is most useful with, for example, `-ofmt=c`.102 /// This is most useful with, for example, `-ofmt=c`.
94 CompareObjectFile: []const u8,103 CompareObjectFile: []const u8,
...@@ -139,15 +148,6 @@ pub const TestContext = struct {...@@ -139,15 +148,6 @@ pub const TestContext = struct {
139148
140 files: std.ArrayList(File),149 files: std.ArrayList(File),
141150
142 /// Adds a subcase in which the module is updated with `src`, and the
143 /// resulting ZIR is validated against `result`.
144 pub fn addTransform(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
145 self.updates.append(.{
146 .src = src,
147 .case = .{ .Transformation = result },
148 }) catch unreachable;
149 }
150
151 /// Adds a subcase in which the module is updated with `src`, and a C151 /// Adds a subcase in which the module is updated with `src`, and a C
152 /// header is generated.152 /// header is generated.
153 pub fn addHeader(self: *Case, src: [:0]const u8, result: [:0]const u8) void {153 pub fn addHeader(self: *Case, src: [:0]const u8, result: [:0]const u8) void {
...@@ -182,31 +182,37 @@ pub const TestContext = struct {...@@ -182,31 +182,37 @@ pub const TestContext = struct {
182 /// the form `:line:column: error: message`.182 /// the form `:line:column: error: message`.
183 pub fn addError(self: *Case, src: [:0]const u8, errors: []const []const u8) void {183 pub fn addError(self: *Case, src: [:0]const u8, errors: []const []const u8) void {
184 var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;184 var array = self.updates.allocator.alloc(ErrorMsg, errors.len) catch unreachable;
185 for (errors) |e, i| {185 for (errors) |err_msg_line, i| {
186 if (e[0] != ':') {186 if (std.mem.startsWith(u8, err_msg_line, "error: ")) {
187 array[i] = .{ .plain = .{ .msg = e } };187 array[i] = .{
188 .plain = .{ .msg = err_msg_line["error: ".len..], .kind = .@"error" },
189 };
190 continue;
191 } else if (std.mem.startsWith(u8, err_msg_line, "note: ")) {
192 array[i] = .{
193 .plain = .{ .msg = err_msg_line["note: ".len..], .kind = .note },
194 };
188 continue;195 continue;
189 }196 }
190 var cur = e[1..];197 // example: ":1:2: error: bad thing happened"
191 var line_index = std.mem.indexOf(u8, cur, ":");198 var it = std.mem.split(err_msg_line, ":");
192 if (line_index == null) {199 _ = it.next() orelse @panic("missing colon");
193 @panic("Invalid test: error must be specified as follows:\n:line:column: error: message\n=========\n");200 const line_text = it.next() orelse @panic("missing line");
194 }201 const col_text = it.next() orelse @panic("missing column");
195 const line = std.fmt.parseInt(u32, cur[0..line_index.?], 10) catch @panic("Unable to parse line number");202 const kind_text = it.next() orelse @panic("missing 'error'/'note'");
196 cur = cur[line_index.? + 1 ..];203 const msg = it.rest()[1..]; // skip over the space at end of "error: "
197 const column_index = std.mem.indexOf(u8, cur, ":");204
198 if (column_index == null) {205 const line = std.fmt.parseInt(u32, line_text, 10) catch @panic("bad line number");
199 @panic("Invalid test: error must be specified as follows:\n:line:column: error: message\n=========\n");206 const column = std.fmt.parseInt(u32, col_text, 10) catch @panic("bad column number");
200 }207 const kind: ErrorMsg.Kind = if (std.mem.eql(u8, kind_text, " error"))
201 const column = std.fmt.parseInt(u32, cur[0..column_index.?], 10) catch @panic("Unable to parse column number");208 .@"error"
202 cur = cur[column_index.? + 2 ..];209 else if (std.mem.eql(u8, kind_text, " note"))
203 if (!std.mem.eql(u8, cur[0..7], "error: ")) {210 .note
204 @panic("Invalid test: error must be specified as follows:\n:line:column: error: message\n=========\n");211 else
205 }212 @panic("expected 'error'/'note'");
206 const msg = cur[7..];
207213
208 if (line == 0 or column == 0) {214 if (line == 0 or column == 0) {
209 @panic("Invalid test: error line and column must be specified starting at one!");215 @panic("line and column must be specified starting at one");
210 }216 }
211217
212 array[i] = .{218 array[i] = .{
...@@ -214,6 +220,7 @@ pub const TestContext = struct {...@@ -214,6 +220,7 @@ pub const TestContext = struct {
214 .msg = msg,220 .msg = msg,
215 .line = line - 1,221 .line = line - 1,
216 .column = column - 1,222 .column = column - 1,
223 .kind = kind,
217 },224 },
218 };225 };
219 }226 }
...@@ -689,25 +696,20 @@ pub const TestContext = struct {...@@ -689,25 +696,20 @@ pub const TestContext = struct {
689 var all_errors = try comp.getAllErrorsAlloc();696 var all_errors = try comp.getAllErrorsAlloc();
690 defer all_errors.deinit(allocator);697 defer all_errors.deinit(allocator);
691 if (all_errors.list.len != 0) {698 if (all_errors.list.len != 0) {
692 std.debug.print("\nErrors occurred updating the compilation:\n================\n", .{});699 std.debug.print("\nErrors occurred updating the compilation:\n{s}\n", .{hr});
693 for (all_errors.list) |err_msg| {700 for (all_errors.list) |err_msg| {
694 switch (err_msg) {701 switch (err_msg) {
695 .src => |src| {702 .src => |src| {
696 std.debug.print(":{d}:{d}: error: {s}\n================\n", .{703 std.debug.print(":{d}:{d}: error: {s}\n{s}\n", .{
697 src.line + 1, src.column + 1, src.msg,704 src.line + 1, src.column + 1, src.msg, hr,
698 });705 });
699 },706 },
700 .plain => |plain| {707 .plain => |plain| {
701 std.debug.print("error: {s}\n================\n", .{plain.msg});708 std.debug.print("error: {s}\n{s}\n", .{ plain.msg, hr });
702 },709 },
703 }710 }
704 }711 }
705 // TODO print generated C code712 // TODO print generated C code
706 //if (comp.bin_file.cast(link.File.C)) |c_file| {
707 // std.debug.print("Generated C: \n===============\n{s}\n\n===========\n\n", .{
708 // c_file.main.items,
709 // });
710 //}
711 std.debug.print("Test failed.\n", .{});713 std.debug.print("Test failed.\n", .{});
712 std.process.exit(1);714 std.process.exit(1);
713 }715 }
...@@ -728,48 +730,74 @@ pub const TestContext = struct {...@@ -728,48 +730,74 @@ pub const TestContext = struct {
728730
729 std.testing.expectEqualStrings(expected_output, out);731 std.testing.expectEqualStrings(expected_output, out);
730 },732 },
731 .Transformation => |expected_output| {733 .Error => |case_error_list| {
732 update_node.setEstimatedTotalItems(5);
733 var emit_node = update_node.start("emit", 0);
734 emit_node.activate();
735 var new_zir_module = try zir.emit(allocator, comp.bin_file.options.module.?);
736 defer new_zir_module.deinit(allocator);
737 emit_node.end();
738
739 var write_node = update_node.start("write", 0);
740 write_node.activate();
741 var out_zir = std.ArrayList(u8).init(allocator);
742 defer out_zir.deinit();
743 try new_zir_module.writeToStream(allocator, out_zir.writer());
744 write_node.end();
745
746 var test_node = update_node.start("assert", 0);734 var test_node = update_node.start("assert", 0);
747 test_node.activate();735 test_node.activate();
748 defer test_node.end();736 defer test_node.end();
749737
750 std.testing.expectEqualStrings(expected_output, out_zir.items);738 const handled_errors = try arena.alloc(bool, case_error_list.len);
751 },739 std.mem.set(bool, handled_errors, false);
752 .Error => |e| {740
753 var test_node = update_node.start("assert", 0);741 var actual_errors = try comp.getAllErrorsAlloc();
754 test_node.activate();742 defer actual_errors.deinit(allocator);
755 defer test_node.end();743
756 var handled_errors = try arena.alloc(bool, e.len);744 var any_failed = false;
757 for (handled_errors) |*handled| {745 var notes_to_check = std.ArrayList(*const Compilation.AllErrors.Message).init(allocator);
758 handled.* = false;746 defer notes_to_check.deinit();
747
748 for (actual_errors.list) |actual_error| {
749 for (case_error_list) |case_msg, i| {
750 const ex_tag: @TagType(@TypeOf(case_msg)) = case_msg;
751 switch (actual_error) {
752 .src => |actual_msg| {
753 for (actual_msg.notes) |*note| {
754 try notes_to_check.append(note);
755 }
756
757 if (ex_tag != .src) continue;
758
759 if (actual_msg.line == case_msg.src.line and
760 actual_msg.column == case_msg.src.column and
761 std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
762 case_msg.src.kind == .@"error")
763 {
764 handled_errors[i] = true;
765 break;
766 }
767 },
768 .plain => |plain| {
769 if (ex_tag != .plain) continue;
770
771 if (std.mem.eql(u8, case_msg.plain.msg, plain.msg) and
772 case_msg.plain.kind == .@"error")
773 {
774 handled_errors[i] = true;
775 break;
776 }
777 },
778 }
779 } else {
780 std.debug.print(
781 "\nUnexpected error:\n{s}\n{}\n{s}",
782 .{ hr, ErrorMsg.init(actual_error, .@"error"), hr },
783 );
784 any_failed = true;
785 }
759 }786 }
760 var all_errors = try comp.getAllErrorsAlloc();787 while (notes_to_check.popOrNull()) |note| {
761 defer all_errors.deinit(allocator);788 for (case_error_list) |case_msg, i| {
762 for (all_errors.list) |a| {789 const ex_tag: @TagType(@TypeOf(case_msg)) = case_msg;
763 for (e) |ex, i| {790 switch (note.*) {
764 const a_tag: @TagType(@TypeOf(a)) = a;791 .src => |actual_msg| {
765 const ex_tag: @TagType(@TypeOf(ex)) = ex;792 for (actual_msg.notes) |*sub_note| {
766 switch (a) {793 try notes_to_check.append(sub_note);
767 .src => |src| {794 }
768 if (ex_tag != .src) continue;795 if (ex_tag != .src) continue;
769796
770 if (src.line == ex.src.line and797 if (actual_msg.line == case_msg.src.line and
771 src.column == ex.src.column and798 actual_msg.column == case_msg.src.column and
772 std.mem.eql(u8, ex.src.msg, src.msg))799 std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
800 case_msg.src.kind == .note)
773 {801 {
774 handled_errors[i] = true;802 handled_errors[i] = true;
775 break;803 break;
...@@ -778,7 +806,9 @@ pub const TestContext = struct {...@@ -778,7 +806,9 @@ pub const TestContext = struct {
778 .plain => |plain| {806 .plain => |plain| {
779 if (ex_tag != .plain) continue;807 if (ex_tag != .plain) continue;
780808
781 if (std.mem.eql(u8, ex.plain.msg, plain.msg)) {809 if (std.mem.eql(u8, case_msg.plain.msg, plain.msg) and
810 case_msg.plain.kind == .note)
811 {
782 handled_errors[i] = true;812 handled_errors[i] = true;
783 break;813 break;
784 }814 }
...@@ -786,23 +816,29 @@ pub const TestContext = struct {...@@ -786,23 +816,29 @@ pub const TestContext = struct {
786 }816 }
787 } else {817 } else {
788 std.debug.print(818 std.debug.print(
789 "{s}\nUnexpected error:\n================\n{}\n================\nTest failed.\n",819 "\nUnexpected note:\n{s}\n{}\n{s}",
790 .{ case.name, ErrorMsg.init(a) },820 .{ hr, ErrorMsg.init(note.*, .note), hr },
791 );821 );
792 std.process.exit(1);822 any_failed = true;
793 }823 }
794 }824 }
795825
796 for (handled_errors) |handled, i| {826 for (handled_errors) |handled, i| {
797 if (!handled) {827 if (!handled) {
798 const er = e[i];
799 std.debug.print(828 std.debug.print(
800 "{s}\nDid not receive error:\n================\n{}\n================\nTest failed.\n",829 "\nExpected error not found:\n{s}\n{}\n{s}",
801 .{ case.name, er },830 .{ hr, case_error_list[i], hr },
802 );831 );
803 std.process.exit(1);832 any_failed = true;
804 }833 }
805 }834 }
835
836 if (any_failed) {
837 std.debug.print("\nTest case '{s}' failed, update_index={d}.\n", .{
838 case.name, update_index,
839 });
840 std.process.exit(1);
841 }
806 },842 },
807 .Execution => |expected_stdout| {843 .Execution => |expected_stdout| {
808 update_node.setEstimatedTotalItems(4);844 update_node.setEstimatedTotalItems(4);
src/type/Enum.zig+1-1
...@@ -21,7 +21,7 @@ pub const Field = struct {...@@ -21,7 +21,7 @@ pub const Field = struct {
21};21};
2222
23pub const Zir = struct {23pub const Zir = struct {
24 body: zir.Module.Body,24 body: zir.Body,
25 inst: *zir.Inst,25 inst: *zir.Inst,
26};26};
2727
src/type/Struct.zig+1-1
...@@ -24,7 +24,7 @@ pub const Field = struct {...@@ -24,7 +24,7 @@ pub const Field = struct {
24};24};
2525
26pub const Zir = struct {26pub const Zir = struct {
27 body: zir.Module.Body,27 body: zir.Body,
28 inst: *zir.Inst,28 inst: *zir.Inst,
29};29};
3030
src/type/Union.zig+1-1
...@@ -24,7 +24,7 @@ pub const Field = struct {...@@ -24,7 +24,7 @@ pub const Field = struct {
24};24};
2525
26pub const Zir = struct {26pub const Zir = struct {
27 body: zir.Module.Body,27 body: zir.Body,
28 inst: *zir.Inst,28 inst: *zir.Inst,
29};29};
3030
src/zir.zig+27-1583
...@@ -12,17 +12,6 @@ const TypedValue = @import("TypedValue.zig");...@@ -12,17 +12,6 @@ const TypedValue = @import("TypedValue.zig");
12const ir = @import("ir.zig");12const ir = @import("ir.zig");
13const IrModule = @import("Module.zig");13const IrModule = @import("Module.zig");
1414
15/// This struct is relevent only for the ZIR Module text format. It is not used for
16/// semantic analysis of Zig source code.
17pub const Decl = struct {
18 name: []const u8,
19
20 /// Hash of slice into the source of the part after the = and before the next instruction.
21 contents_hash: std.zig.SrcHash,
22
23 inst: *Inst,
24};
25
26/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for15/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
27/// in-memory, analyzed instructions with types and values.16/// in-memory, analyzed instructions with types and values.
28/// We use a table to map these instruction to their respective semantically analyzed17/// We use a table to map these instruction to their respective semantically analyzed
...@@ -141,15 +130,12 @@ pub const Inst = struct {...@@ -141,15 +130,12 @@ pub const Inst = struct {
141 container_field,130 container_field,
142 /// Declares the beginning of a statement. Used for debug info.131 /// Declares the beginning of a statement. Used for debug info.
143 dbg_stmt,132 dbg_stmt,
144 /// Represents a pointer to a global decl by name.133 /// Represents a pointer to a global decl.
145 declref,134 declref,
146 /// Represents a pointer to a global decl by string name.135 /// Represents a pointer to a global decl by string name.
147 declref_str,136 declref_str,
148 /// The syntax `@foo` is equivalent to `declval("foo")`.137 /// Equivalent to a declref followed by deref.
149 /// declval is equivalent to declref followed by deref.
150 declval,138 declval,
151 /// Same as declval but the parameter is a `*Module.Decl` rather than a name.
152 declval_in_module,
153 /// Load the value from a pointer.139 /// Load the value from a pointer.
154 deref,140 deref,
155 /// Arithmetic division. Asserts no integer overflow.141 /// Arithmetic division. Asserts no integer overflow.
...@@ -419,7 +405,6 @@ pub const Inst = struct {...@@ -419,7 +405,6 @@ pub const Inst = struct {
419 .declref => DeclRef,405 .declref => DeclRef,
420 .declref_str => DeclRefStr,406 .declref_str => DeclRefStr,
421 .declval => DeclVal,407 .declval => DeclVal,
422 .declval_in_module => DeclValInModule,
423 .coerce_result_block_ptr => CoerceResultBlockPtr,408 .coerce_result_block_ptr => CoerceResultBlockPtr,
424 .compilelog => CompileLog,409 .compilelog => CompileLog,
425 .loop => Loop,410 .loop => Loop,
...@@ -496,7 +481,6 @@ pub const Inst = struct {...@@ -496,7 +481,6 @@ pub const Inst = struct {
496 .declref,481 .declref,
497 .declref_str,482 .declref_str,
498 .declval,483 .declval,
499 .declval_in_module,
500 .deref,484 .deref,
501 .div,485 .div,
502 .elemptr,486 .elemptr,
...@@ -650,7 +634,7 @@ pub const Inst = struct {...@@ -650,7 +634,7 @@ pub const Inst = struct {
650 base: Inst,634 base: Inst,
651635
652 positionals: struct {636 positionals: struct {
653 body: Module.Body,637 body: Body,
654 },638 },
655 kw_args: struct {},639 kw_args: struct {},
656 };640 };
...@@ -705,7 +689,7 @@ pub const Inst = struct {...@@ -705,7 +689,7 @@ pub const Inst = struct {
705 base: Inst,689 base: Inst,
706690
707 positionals: struct {691 positionals: struct {
708 name: []const u8,692 decl: *IrModule.Decl,
709 },693 },
710 kw_args: struct {},694 kw_args: struct {},
711 };695 };
...@@ -724,16 +708,6 @@ pub const Inst = struct {...@@ -724,16 +708,6 @@ pub const Inst = struct {
724 pub const base_tag = Tag.declval;708 pub const base_tag = Tag.declval;
725 base: Inst,709 base: Inst,
726710
727 positionals: struct {
728 name: []const u8,
729 },
730 kw_args: struct {},
731 };
732
733 pub const DeclValInModule = struct {
734 pub const base_tag = Tag.declval_in_module;
735 base: Inst,
736
737 positionals: struct {711 positionals: struct {
738 decl: *IrModule.Decl,712 decl: *IrModule.Decl,
739 },713 },
...@@ -758,10 +732,7 @@ pub const Inst = struct {...@@ -758,10 +732,7 @@ pub const Inst = struct {
758 positionals: struct {732 positionals: struct {
759 to_log: []*Inst,733 to_log: []*Inst,
760 },734 },
761 kw_args: struct {735 kw_args: struct {},
762 /// If we have seen it already so don't make another error
763 seen: bool = false,
764 },
765 };736 };
766737
767 pub const Const = struct {738 pub const Const = struct {
...@@ -799,7 +770,7 @@ pub const Inst = struct {...@@ -799,7 +770,7 @@ pub const Inst = struct {
799 base: Inst,770 base: Inst,
800771
801 positionals: struct {772 positionals: struct {
802 body: Module.Body,773 body: Body,
803 },774 },
804 kw_args: struct {},775 kw_args: struct {},
805 };776 };
...@@ -838,7 +809,7 @@ pub const Inst = struct {...@@ -838,7 +809,7 @@ pub const Inst = struct {
838809
839 positionals: struct {810 positionals: struct {
840 fn_type: *Inst,811 fn_type: *Inst,
841 body: Module.Body,812 body: Body,
842 },813 },
843 kw_args: struct {814 kw_args: struct {
844 is_inline: bool = false,815 is_inline: bool = false,
...@@ -998,8 +969,8 @@ pub const Inst = struct {...@@ -998,8 +969,8 @@ pub const Inst = struct {
998969
999 positionals: struct {970 positionals: struct {
1000 condition: *Inst,971 condition: *Inst,
1001 then_body: Module.Body,972 then_body: Body,
1002 else_body: Module.Body,973 else_body: Body,
1003 },974 },
1004 kw_args: struct {},975 kw_args: struct {},
1005 };976 };
...@@ -1078,7 +1049,7 @@ pub const Inst = struct {...@@ -1078,7 +1049,7 @@ pub const Inst = struct {
1078 /// List of all individual items and ranges1049 /// List of all individual items and ranges
1079 items: []*Inst,1050 items: []*Inst,
1080 cases: []Case,1051 cases: []Case,
1081 else_body: Module.Body,1052 else_body: Body,
1082 },1053 },
1083 kw_args: struct {1054 kw_args: struct {
1084 /// Pointer to first range if such exists.1055 /// Pointer to first range if such exists.
...@@ -1092,7 +1063,7 @@ pub const Inst = struct {...@@ -1092,7 +1063,7 @@ pub const Inst = struct {
10921063
1093 pub const Case = struct {1064 pub const Case = struct {
1094 item: *Inst,1065 item: *Inst,
1095 body: Module.Body,1066 body: Body,
1096 };1067 };
1097 };1068 };
1098 pub const TypeOfPeer = struct {1069 pub const TypeOfPeer = struct {
...@@ -1192,6 +1163,10 @@ pub const ErrorMsg = struct {...@@ -1192,6 +1163,10 @@ pub const ErrorMsg = struct {
1192 msg: []const u8,1163 msg: []const u8,
1193};1164};
11941165
1166pub const Body = struct {
1167 instructions: []*Inst,
1168};
1169
1195pub const Module = struct {1170pub const Module = struct {
1196 decls: []*Decl,1171 decls: []*Decl,
1197 arena: std.heap.ArenaAllocator,1172 arena: std.heap.ArenaAllocator,
...@@ -1199,6 +1174,15 @@ pub const Module = struct {...@@ -1199,6 +1174,15 @@ pub const Module = struct {
1199 metadata: std.AutoHashMap(*Inst, MetaData),1174 metadata: std.AutoHashMap(*Inst, MetaData),
1200 body_metadata: std.AutoHashMap(*Body, BodyMetaData),1175 body_metadata: std.AutoHashMap(*Body, BodyMetaData),
12011176
1177 pub const Decl = struct {
1178 name: []const u8,
1179
1180 /// Hash of slice into the source of the part after the = and before the next instruction.
1181 contents_hash: std.zig.SrcHash,
1182
1183 inst: *Inst,
1184 };
1185
1202 pub const MetaData = struct {1186 pub const MetaData = struct {
1203 deaths: ir.Inst.DeathsInt,1187 deaths: ir.Inst.DeathsInt,
1204 addr: usize,1188 addr: usize,
...@@ -1208,10 +1192,6 @@ pub const Module = struct {...@@ -1208,10 +1192,6 @@ pub const Module = struct {
1208 deaths: []*Inst,1192 deaths: []*Inst,
1209 };1193 };
12101194
1211 pub const Body = struct {
1212 instructions: []*Inst,
1213 };
1214
1215 pub fn deinit(self: *Module, allocator: *Allocator) void {1195 pub fn deinit(self: *Module, allocator: *Allocator) void {
1216 self.metadata.deinit();1196 self.metadata.deinit();
1217 self.body_metadata.deinit();1197 self.body_metadata.deinit();
...@@ -1369,7 +1349,7 @@ const Writer = struct {...@@ -1369,7 +1349,7 @@ const Writer = struct {
1369 }1349 }
1370 try stream.writeByte(']');1350 try stream.writeByte(']');
1371 },1351 },
1372 Module.Body => {1352 Body => {
1373 try stream.writeAll("{\n");1353 try stream.writeAll("{\n");
1374 if (self.module.body_metadata.get(param_ptr)) |metadata| {1354 if (self.module.body_metadata.get(param_ptr)) |metadata| {
1375 if (metadata.deaths.len > 0) {1355 if (metadata.deaths.len > 0) {
...@@ -1468,8 +1448,6 @@ const Writer = struct {...@@ -1468,8 +1448,6 @@ const Writer = struct {
1468 try stream.print("@{s}", .{info.name});1448 try stream.print("@{s}", .{info.name});
1469 }1449 }
1470 } else if (inst.cast(Inst.DeclVal)) |decl_val| {1450 } else if (inst.cast(Inst.DeclVal)) |decl_val| {
1471 try stream.print("@{s}", .{decl_val.positionals.name});
1472 } else if (inst.cast(Inst.DeclValInModule)) |decl_val| {
1473 try stream.print("@{s}", .{decl_val.positionals.decl.name});1451 try stream.print("@{s}", .{decl_val.positionals.decl.name});
1474 } else {1452 } else {
1475 // This should be unreachable in theory, but since ZIR is used for debugging the compiler1453 // This should be unreachable in theory, but since ZIR is used for debugging the compiler
...@@ -1479,502 +1457,6 @@ const Writer = struct {...@@ -1479,502 +1457,6 @@ const Writer = struct {
1479 }1457 }
1480};1458};
14811459
1482pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module {
1483 var global_name_map = std.StringHashMap(*Inst).init(allocator);
1484 defer global_name_map.deinit();
1485
1486 var parser: Parser = .{
1487 .allocator = allocator,
1488 .arena = std.heap.ArenaAllocator.init(allocator),
1489 .i = 0,
1490 .source = source,
1491 .global_name_map = &global_name_map,
1492 .decls = .{},
1493 .unnamed_index = 0,
1494 .block_table = std.StringHashMap(*Inst.Block).init(allocator),
1495 .loop_table = std.StringHashMap(*Inst.Loop).init(allocator),
1496 };
1497 defer parser.block_table.deinit();
1498 defer parser.loop_table.deinit();
1499 errdefer parser.arena.deinit();
1500
1501 parser.parseRoot() catch |err| switch (err) {
1502 error.ParseFailure => {
1503 assert(parser.error_msg != null);
1504 },
1505 else => |e| return e,
1506 };
1507
1508 return Module{
1509 .decls = parser.decls.toOwnedSlice(allocator),
1510 .arena = parser.arena,
1511 .error_msg = parser.error_msg,
1512 .metadata = std.AutoHashMap(*Inst, Module.MetaData).init(allocator),
1513 .body_metadata = std.AutoHashMap(*Module.Body, Module.BodyMetaData).init(allocator),
1514 };
1515}
1516
1517const Parser = struct {
1518 allocator: *Allocator,
1519 arena: std.heap.ArenaAllocator,
1520 i: usize,
1521 source: [:0]const u8,
1522 decls: std.ArrayListUnmanaged(*Decl),
1523 global_name_map: *std.StringHashMap(*Inst),
1524 error_msg: ?ErrorMsg = null,
1525 unnamed_index: usize,
1526 block_table: std.StringHashMap(*Inst.Block),
1527 loop_table: std.StringHashMap(*Inst.Loop),
1528
1529 const Body = struct {
1530 instructions: std.ArrayList(*Inst),
1531 name_map: *std.StringHashMap(*Inst),
1532 };
1533
1534 fn parseBody(self: *Parser, body_ctx: ?*Body) !Module.Body {
1535 var name_map = std.StringHashMap(*Inst).init(self.allocator);
1536 defer name_map.deinit();
1537
1538 var body_context = Body{
1539 .instructions = std.ArrayList(*Inst).init(self.allocator),
1540 .name_map = if (body_ctx) |bctx| bctx.name_map else &name_map,
1541 };
1542 defer body_context.instructions.deinit();
1543
1544 try requireEatBytes(self, "{");
1545 skipSpace(self);
1546
1547 while (true) : (self.i += 1) switch (self.source[self.i]) {
1548 ';' => _ = try skipToAndOver(self, '\n'),
1549 '%' => {
1550 self.i += 1;
1551 const ident = try skipToAndOver(self, ' ');
1552 skipSpace(self);
1553 try requireEatBytes(self, "=");
1554 skipSpace(self);
1555 const decl = try parseInstruction(self, &body_context, ident);
1556 const ident_index = body_context.instructions.items.len;
1557 if (try body_context.name_map.fetchPut(ident, decl.inst)) |_| {
1558 return self.fail("redefinition of identifier '{s}'", .{ident});
1559 }
1560 try body_context.instructions.append(decl.inst);
1561 continue;
1562 },
1563 ' ', '\n' => continue,
1564 '}' => {
1565 self.i += 1;
1566 break;
1567 },
1568 else => |byte| return self.failByte(byte),
1569 };
1570
1571 // Move the instructions to the arena
1572 const instrs = try self.arena.allocator.alloc(*Inst, body_context.instructions.items.len);
1573 mem.copy(*Inst, instrs, body_context.instructions.items);
1574 return Module.Body{ .instructions = instrs };
1575 }
1576
1577 fn parseStringLiteral(self: *Parser) ![]u8 {
1578 const start = self.i;
1579 try self.requireEatBytes("\"");
1580
1581 while (true) : (self.i += 1) switch (self.source[self.i]) {
1582 '"' => {
1583 self.i += 1;
1584 const span = self.source[start..self.i];
1585 var bad_index: usize = undefined;
1586 const parsed = std.zig.parseStringLiteral(&self.arena.allocator, span, &bad_index) catch |err| switch (err) {
1587 error.InvalidCharacter => {
1588 self.i = start + bad_index;
1589 const bad_byte = self.source[self.i];
1590 return self.fail("invalid string literal character: '{c}'\n", .{bad_byte});
1591 },
1592 else => |e| return e,
1593 };
1594 return parsed;
1595 },
1596 '\\' => {
1597 self.i += 1;
1598 continue;
1599 },
1600 0 => return self.failByte(0),
1601 else => continue,
1602 };
1603 }
1604
1605 fn parseIntegerLiteral(self: *Parser) !BigIntConst {
1606 const start = self.i;
1607 if (self.source[self.i] == '-') self.i += 1;
1608 while (true) : (self.i += 1) switch (self.source[self.i]) {
1609 '0'...'9' => continue,
1610 else => break,
1611 };
1612 const number_text = self.source[start..self.i];
1613 const base = 10;
1614 // TODO reuse the same array list for this
1615 const limbs_buffer_len = std.math.big.int.calcSetStringLimbsBufferLen(base, number_text.len);
1616 const limbs_buffer = try self.allocator.alloc(std.math.big.Limb, limbs_buffer_len);
1617 defer self.allocator.free(limbs_buffer);
1618 const limb_len = std.math.big.int.calcSetStringLimbCount(base, number_text.len);
1619 const limbs = try self.arena.allocator.alloc(std.math.big.Limb, limb_len);
1620 var result = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
1621 result.setString(base, number_text, limbs_buffer, self.allocator) catch |err| switch (err) {
1622 error.InvalidCharacter => {
1623 self.i = start;
1624 return self.fail("invalid digit in integer literal", .{});
1625 },
1626 };
1627 return result.toConst();
1628 }
1629
1630 fn parseRoot(self: *Parser) !void {
1631 // The IR format is designed so that it can be tokenized and parsed at the same time.
1632 while (true) {
1633 switch (self.source[self.i]) {
1634 ';' => _ = try skipToAndOver(self, '\n'),
1635 '@' => {
1636 self.i += 1;
1637 const ident = try skipToAndOver(self, ' ');
1638 skipSpace(self);
1639 try requireEatBytes(self, "=");
1640 skipSpace(self);
1641 const decl = try parseInstruction(self, null, ident);
1642 const ident_index = self.decls.items.len;
1643 if (try self.global_name_map.fetchPut(ident, decl.inst)) |_| {
1644 return self.fail("redefinition of identifier '{s}'", .{ident});
1645 }
1646 try self.decls.append(self.allocator, decl);
1647 },
1648 ' ', '\n' => self.i += 1,
1649 0 => break,
1650 else => |byte| return self.fail("unexpected byte: '{c}'", .{byte}),
1651 }
1652 }
1653 }
1654
1655 fn eatByte(self: *Parser, byte: u8) bool {
1656 if (self.source[self.i] != byte) return false;
1657 self.i += 1;
1658 return true;
1659 }
1660
1661 fn skipSpace(self: *Parser) void {
1662 while (self.source[self.i] == ' ' or self.source[self.i] == '\n') {
1663 self.i += 1;
1664 }
1665 }
1666
1667 fn requireEatBytes(self: *Parser, bytes: []const u8) !void {
1668 const start = self.i;
1669 for (bytes) |byte| {
1670 if (self.source[self.i] != byte) {
1671 self.i = start;
1672 return self.fail("expected '{s}'", .{bytes});
1673 }
1674 self.i += 1;
1675 }
1676 }
1677
1678 fn skipToAndOver(self: *Parser, byte: u8) ![]const u8 {
1679 const start_i = self.i;
1680 while (self.source[self.i] != 0) : (self.i += 1) {
1681 if (self.source[self.i] == byte) {
1682 const result = self.source[start_i..self.i];
1683 self.i += 1;
1684 return result;
1685 }
1686 }
1687 return self.fail("unexpected EOF", .{});
1688 }
1689
1690 /// ParseFailure is an internal error code; handled in `parse`.
1691 const InnerError = error{ ParseFailure, OutOfMemory };
1692
1693 fn failByte(self: *Parser, byte: u8) InnerError {
1694 if (byte == 0) {
1695 return self.fail("unexpected EOF", .{});
1696 } else {
1697 return self.fail("unexpected byte: '{c}'", .{byte});
1698 }
1699 }
1700
1701 fn fail(self: *Parser, comptime format: []const u8, args: anytype) InnerError {
1702 @setCold(true);
1703 self.error_msg = ErrorMsg{
1704 .byte_offset = self.i,
1705 .msg = try std.fmt.allocPrint(&self.arena.allocator, format, args),
1706 };
1707 return error.ParseFailure;
1708 }
1709
1710 fn parseInstruction(self: *Parser, body_ctx: ?*Body, name: []const u8) InnerError!*Decl {
1711 const contents_start = self.i;
1712 const fn_name = try skipToAndOver(self, '(');
1713 inline for (@typeInfo(Inst.Tag).Enum.fields) |field| {
1714 if (mem.eql(u8, field.name, fn_name)) {
1715 const tag = @field(Inst.Tag, field.name);
1716 return parseInstructionGeneric(self, field.name, tag.Type(), tag, body_ctx, name, contents_start);
1717 }
1718 }
1719 return self.fail("unknown instruction '{s}'", .{fn_name});
1720 }
1721
1722 fn parseInstructionGeneric(
1723 self: *Parser,
1724 comptime fn_name: []const u8,
1725 comptime InstType: type,
1726 tag: Inst.Tag,
1727 body_ctx: ?*Body,
1728 inst_name: []const u8,
1729 contents_start: usize,
1730 ) InnerError!*Decl {
1731 const inst_specific = try self.arena.allocator.create(InstType);
1732 inst_specific.base = .{
1733 .src = self.i,
1734 .tag = tag,
1735 };
1736
1737 if (InstType == Inst.Block) {
1738 try self.block_table.put(inst_name, inst_specific);
1739 } else if (InstType == Inst.Loop) {
1740 try self.loop_table.put(inst_name, inst_specific);
1741 }
1742
1743 if (@hasField(InstType, "ty")) {
1744 inst_specific.ty = opt_type orelse {
1745 return self.fail("instruction '" ++ fn_name ++ "' requires type", .{});
1746 };
1747 }
1748
1749 const Positionals = @TypeOf(inst_specific.positionals);
1750 inline for (@typeInfo(Positionals).Struct.fields) |arg_field| {
1751 if (self.source[self.i] == ',') {
1752 self.i += 1;
1753 skipSpace(self);
1754 } else if (self.source[self.i] == ')') {
1755 return self.fail("expected positional parameter '{s}'", .{arg_field.name});
1756 }
1757 @field(inst_specific.positionals, arg_field.name) = try parseParameterGeneric(
1758 self,
1759 arg_field.field_type,
1760 body_ctx,
1761 );
1762 skipSpace(self);
1763 }
1764
1765 const KW_Args = @TypeOf(inst_specific.kw_args);
1766 inst_specific.kw_args = .{}; // assign defaults
1767 skipSpace(self);
1768 while (eatByte(self, ',')) {
1769 skipSpace(self);
1770 const name = try skipToAndOver(self, '=');
1771 inline for (@typeInfo(KW_Args).Struct.fields) |arg_field| {
1772 const field_name = arg_field.name;
1773 if (mem.eql(u8, name, field_name)) {
1774 const NonOptional = switch (@typeInfo(arg_field.field_type)) {
1775 .Optional => |info| info.child,
1776 else => arg_field.field_type,
1777 };
1778 @field(inst_specific.kw_args, field_name) = try parseParameterGeneric(self, NonOptional, body_ctx);
1779 break;
1780 }
1781 } else {
1782 return self.fail("unrecognized keyword parameter: '{s}'", .{name});
1783 }
1784 skipSpace(self);
1785 }
1786 try requireEatBytes(self, ")");
1787
1788 const decl = try self.arena.allocator.create(Decl);
1789 decl.* = .{
1790 .name = inst_name,
1791 .contents_hash = std.zig.hashSrc(self.source[contents_start..self.i]),
1792 .inst = &inst_specific.base,
1793 };
1794
1795 return decl;
1796 }
1797
1798 fn parseParameterGeneric(self: *Parser, comptime T: type, body_ctx: ?*Body) !T {
1799 if (@typeInfo(T) == .Enum) {
1800 const start = self.i;
1801 while (true) : (self.i += 1) switch (self.source[self.i]) {
1802 ' ', '\n', ',', ')' => {
1803 const enum_name = self.source[start..self.i];
1804 return std.meta.stringToEnum(T, enum_name) orelse {
1805 return self.fail("tag '{s}' not a member of enum '{s}'", .{ enum_name, @typeName(T) });
1806 };
1807 },
1808 0 => return self.failByte(0),
1809 else => continue,
1810 };
1811 }
1812 switch (T) {
1813 Module.Body => return parseBody(self, body_ctx),
1814 bool => {
1815 const bool_value = switch (self.source[self.i]) {
1816 '0' => false,
1817 '1' => true,
1818 else => |byte| return self.fail("expected '0' or '1' for boolean value, found {c}", .{byte}),
1819 };
1820 self.i += 1;
1821 return bool_value;
1822 },
1823 []*Inst => {
1824 try requireEatBytes(self, "[");
1825 skipSpace(self);
1826 if (eatByte(self, ']')) return &[0]*Inst{};
1827
1828 var instructions = std.ArrayList(*Inst).init(&self.arena.allocator);
1829 while (true) {
1830 skipSpace(self);
1831 try instructions.append(try parseParameterInst(self, body_ctx));
1832 skipSpace(self);
1833 if (!eatByte(self, ',')) break;
1834 }
1835 try requireEatBytes(self, "]");
1836 return instructions.toOwnedSlice();
1837 },
1838 *Inst => return parseParameterInst(self, body_ctx),
1839 []u8, []const u8 => return self.parseStringLiteral(),
1840 BigIntConst => return self.parseIntegerLiteral(),
1841 usize => {
1842 const big_int = try self.parseIntegerLiteral();
1843 return big_int.to(usize) catch |err| return self.fail("integer literal: {s}", .{@errorName(err)});
1844 },
1845 TypedValue => return self.fail("'const' is a special instruction; not legal in ZIR text", .{}),
1846 *IrModule.Decl => return self.fail("'declval_in_module' is a special instruction; not legal in ZIR text", .{}),
1847 *Inst.Block => {
1848 const name = try self.parseStringLiteral();
1849 return self.block_table.get(name).?;
1850 },
1851 *Inst.Loop => {
1852 const name = try self.parseStringLiteral();
1853 return self.loop_table.get(name).?;
1854 },
1855 [][]const u8 => {
1856 try requireEatBytes(self, "[");
1857 skipSpace(self);
1858 if (eatByte(self, ']')) return &[0][]const u8{};
1859
1860 var strings = std.ArrayList([]const u8).init(&self.arena.allocator);
1861 while (true) {
1862 skipSpace(self);
1863 try strings.append(try self.parseStringLiteral());
1864 skipSpace(self);
1865 if (!eatByte(self, ',')) break;
1866 }
1867 try requireEatBytes(self, "]");
1868 return strings.toOwnedSlice();
1869 },
1870 []Inst.SwitchBr.Case => {
1871 try requireEatBytes(self, "{");
1872 skipSpace(self);
1873 if (eatByte(self, '}')) return &[0]Inst.SwitchBr.Case{};
1874
1875 var cases = std.ArrayList(Inst.SwitchBr.Case).init(&self.arena.allocator);
1876 while (true) {
1877 const cur = try cases.addOne();
1878 skipSpace(self);
1879 cur.item = try self.parseParameterGeneric(*Inst, body_ctx);
1880 skipSpace(self);
1881 try requireEatBytes(self, "=>");
1882 cur.body = try self.parseBody(body_ctx);
1883 skipSpace(self);
1884 if (!eatByte(self, ',')) break;
1885 }
1886 skipSpace(self);
1887 try requireEatBytes(self, "}");
1888 return cases.toOwnedSlice();
1889 },
1890 else => @compileError("Unimplemented: ir parseParameterGeneric for type " ++ @typeName(T)),
1891 }
1892 return self.fail("TODO parse parameter {s}", .{@typeName(T)});
1893 }
1894
1895 fn parseParameterInst(self: *Parser, body_ctx: ?*Body) !*Inst {
1896 const local_ref = switch (self.source[self.i]) {
1897 '@' => false,
1898 '%' => true,
1899 else => |byte| return self.fail("unexpected byte: '{c}'", .{byte}),
1900 };
1901 const map = if (local_ref)
1902 if (body_ctx) |bc|
1903 bc.name_map
1904 else
1905 return self.fail("referencing a % instruction in global scope", .{})
1906 else
1907 self.global_name_map;
1908
1909 self.i += 1;
1910 const name_start = self.i;
1911 while (true) : (self.i += 1) switch (self.source[self.i]) {
1912 0, ' ', '\n', ',', ')', ']' => break,
1913 else => continue,
1914 };
1915 const ident = self.source[name_start..self.i];
1916 return map.get(ident) orelse {
1917 const bad_name = self.source[name_start - 1 .. self.i];
1918 const src = name_start - 1;
1919 if (local_ref) {
1920 self.i = src;
1921 return self.fail("unrecognized identifier: {s}", .{bad_name});
1922 } else {
1923 const declval = try self.arena.allocator.create(Inst.DeclVal);
1924 declval.* = .{
1925 .base = .{
1926 .src = src,
1927 .tag = Inst.DeclVal.base_tag,
1928 },
1929 .positionals = .{ .name = ident },
1930 .kw_args = .{},
1931 };
1932 return &declval.base;
1933 }
1934 };
1935 }
1936
1937 fn generateName(self: *Parser) ![]u8 {
1938 const result = try std.fmt.allocPrint(&self.arena.allocator, "unnamed${d}", .{self.unnamed_index});
1939 self.unnamed_index += 1;
1940 return result;
1941 }
1942};
1943
1944pub fn emit(allocator: *Allocator, old_module: *IrModule) !Module {
1945 var ctx: EmitZIR = .{
1946 .allocator = allocator,
1947 .decls = .{},
1948 .arena = std.heap.ArenaAllocator.init(allocator),
1949 .old_module = old_module,
1950 .next_auto_name = 0,
1951 .names = std.StringArrayHashMap(void).init(allocator),
1952 .primitive_table = std.AutoHashMap(Inst.Primitive.Builtin, *Decl).init(allocator),
1953 .indent = 0,
1954 .block_table = std.AutoHashMap(*ir.Inst.Block, *Inst.Block).init(allocator),
1955 .loop_table = std.AutoHashMap(*ir.Inst.Loop, *Inst.Loop).init(allocator),
1956 .metadata = std.AutoHashMap(*Inst, Module.MetaData).init(allocator),
1957 .body_metadata = std.AutoHashMap(*Module.Body, Module.BodyMetaData).init(allocator),
1958 };
1959 errdefer ctx.metadata.deinit();
1960 errdefer ctx.body_metadata.deinit();
1961 defer ctx.block_table.deinit();
1962 defer ctx.loop_table.deinit();
1963 defer ctx.decls.deinit(allocator);
1964 defer ctx.names.deinit();
1965 defer ctx.primitive_table.deinit();
1966 errdefer ctx.arena.deinit();
1967
1968 try ctx.emit();
1969
1970 return Module{
1971 .decls = ctx.decls.toOwnedSlice(allocator),
1972 .arena = ctx.arena,
1973 .metadata = ctx.metadata,
1974 .body_metadata = ctx.body_metadata,
1975 };
1976}
1977
1978/// For debugging purposes, prints a function representation to stderr.1460/// For debugging purposes, prints a function representation to stderr.
1979pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {1461pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {
1980 const allocator = old_module.gpa;1462 const allocator = old_module.gpa;
...@@ -2374,1052 +1856,14 @@ const DumpTzir = struct {...@@ -2374,1052 +1856,14 @@ const DumpTzir = struct {
2374 }1856 }
2375};1857};
23761858
2377const EmitZIR = struct {
2378 allocator: *Allocator,
2379 arena: std.heap.ArenaAllocator,
2380 old_module: *const IrModule,
2381 decls: std.ArrayListUnmanaged(*Decl),
2382 names: std.StringArrayHashMap(void),
2383 next_auto_name: usize,
2384 primitive_table: std.AutoHashMap(Inst.Primitive.Builtin, *Decl),
2385 indent: usize,
2386 block_table: std.AutoHashMap(*ir.Inst.Block, *Inst.Block),
2387 loop_table: std.AutoHashMap(*ir.Inst.Loop, *Inst.Loop),
2388 metadata: std.AutoHashMap(*Inst, Module.MetaData),
2389 body_metadata: std.AutoHashMap(*Module.Body, Module.BodyMetaData),
2390
2391 fn emit(self: *EmitZIR) !void {
2392 // Put all the Decls in a list and sort them by name to avoid nondeterminism introduced
2393 // by the hash table.
2394 var src_decls = std.ArrayList(*IrModule.Decl).init(self.allocator);
2395 defer src_decls.deinit();
2396 try src_decls.ensureCapacity(self.old_module.decl_table.items().len);
2397 try self.decls.ensureCapacity(self.allocator, self.old_module.decl_table.items().len);
2398 try self.names.ensureCapacity(self.old_module.decl_table.items().len);
2399
2400 for (self.old_module.decl_table.items()) |entry| {
2401 const decl = entry.value;
2402 src_decls.appendAssumeCapacity(decl);
2403 self.names.putAssumeCapacityNoClobber(mem.spanZ(decl.name), {});
2404 }
2405 std.sort.sort(*IrModule.Decl, src_decls.items, {}, (struct {
2406 fn lessThan(context: void, a: *IrModule.Decl, b: *IrModule.Decl) bool {
2407 return a.src_index < b.src_index;
2408 }
2409 }).lessThan);
2410
2411 // Emit all the decls.
2412 for (src_decls.items) |ir_decl| {
2413 switch (ir_decl.analysis) {
2414 .unreferenced => continue,
2415
2416 .complete => {},
2417 .codegen_failure => {}, // We still can emit the ZIR.
2418 .codegen_failure_retryable => {}, // We still can emit the ZIR.
2419
2420 .in_progress => unreachable,
2421 .outdated => unreachable,
2422
2423 .sema_failure,
2424 .sema_failure_retryable,
2425 .dependency_failure,
2426 => if (self.old_module.failed_decls.get(ir_decl)) |err_msg| {
2427 const fail_inst = try self.arena.allocator.create(Inst.UnOp);
2428 fail_inst.* = .{
2429 .base = .{
2430 .src = ir_decl.src(),
2431 .tag = .compileerror,
2432 },
2433 .positionals = .{
2434 .operand = blk: {
2435 const msg_str = try self.arena.allocator.dupe(u8, err_msg.msg);
2436
2437 const str_inst = try self.arena.allocator.create(Inst.Str);
2438 str_inst.* = .{
2439 .base = .{
2440 .src = ir_decl.src(),
2441 .tag = Inst.Str.base_tag,
2442 },
2443 .positionals = .{
2444 .bytes = err_msg.msg,
2445 },
2446 .kw_args = .{},
2447 };
2448 break :blk &str_inst.base;
2449 },
2450 },
2451 .kw_args = .{},
2452 };
2453 const decl = try self.arena.allocator.create(Decl);
2454 decl.* = .{
2455 .name = mem.spanZ(ir_decl.name),
2456 .contents_hash = undefined,
2457 .inst = &fail_inst.base,
2458 };
2459 try self.decls.append(self.allocator, decl);
2460 continue;
2461 },
2462 }
2463 if (self.old_module.export_owners.get(ir_decl)) |exports| {
2464 for (exports) |module_export| {
2465 const symbol_name = try self.emitStringLiteral(module_export.src, module_export.options.name);
2466 const export_inst = try self.arena.allocator.create(Inst.Export);
2467 export_inst.* = .{
2468 .base = .{
2469 .src = module_export.src,
2470 .tag = Inst.Export.base_tag,
2471 },
2472 .positionals = .{
2473 .symbol_name = symbol_name.inst,
2474 .decl_name = mem.spanZ(module_export.exported_decl.name),
2475 },
2476 .kw_args = .{},
2477 };
2478 _ = try self.emitUnnamedDecl(&export_inst.base);
2479 }
2480 }
2481 const new_decl = try self.emitTypedValue(ir_decl.src(), ir_decl.typed_value.most_recent.typed_value);
2482 new_decl.name = try self.arena.allocator.dupe(u8, mem.spanZ(ir_decl.name));
2483 }
2484 }
2485
2486 const ZirBody = struct {
2487 inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
2488 instructions: *std.ArrayList(*Inst),
2489 };
2490
2491 fn resolveInst(self: *EmitZIR, new_body: ZirBody, inst: *ir.Inst) !*Inst {
2492 if (inst.cast(ir.Inst.Constant)) |const_inst| {
2493 const new_inst = if (const_inst.val.castTag(.function)) |func_pl| blk: {
2494 const owner_decl = func_pl.data.owner_decl;
2495 break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
2496 } else if (const_inst.val.castTag(.decl_ref)) |declref| blk: {
2497 const decl_ref = try self.emitDeclRef(inst.src, declref.data);
2498 try new_body.instructions.append(decl_ref);
2499 break :blk decl_ref;
2500 } else if (const_inst.val.castTag(.variable)) |var_pl| blk: {
2501 const owner_decl = var_pl.data.owner_decl;
2502 break :blk try self.emitDeclVal(inst.src, mem.spanZ(owner_decl.name));
2503 } else blk: {
2504 break :blk (try self.emitTypedValue(inst.src, .{ .ty = inst.ty, .val = const_inst.val })).inst;
2505 };
2506 _ = try new_body.inst_table.put(inst, new_inst);
2507 return new_inst;
2508 } else {
2509 return new_body.inst_table.get(inst).?;
2510 }
2511 }
2512
2513 fn emitDeclVal(self: *EmitZIR, src: usize, decl_name: []const u8) !*Inst {
2514 const declval = try self.arena.allocator.create(Inst.DeclVal);
2515 declval.* = .{
2516 .base = .{
2517 .src = src,
2518 .tag = Inst.DeclVal.base_tag,
2519 },
2520 .positionals = .{ .name = try self.arena.allocator.dupe(u8, decl_name) },
2521 .kw_args = .{},
2522 };
2523 return &declval.base;
2524 }
2525
2526 fn emitComptimeIntVal(self: *EmitZIR, src: usize, val: Value) !*Decl {
2527 const big_int_space = try self.arena.allocator.create(Value.BigIntSpace);
2528 const int_inst = try self.arena.allocator.create(Inst.Int);
2529 int_inst.* = .{
2530 .base = .{
2531 .src = src,
2532 .tag = Inst.Int.base_tag,
2533 },
2534 .positionals = .{
2535 .int = val.toBigInt(big_int_space),
2536 },
2537 .kw_args = .{},
2538 };
2539 return self.emitUnnamedDecl(&int_inst.base);
2540 }
2541
2542 fn emitDeclRef(self: *EmitZIR, src: usize, module_decl: *IrModule.Decl) !*Inst {
2543 const declref_inst = try self.arena.allocator.create(Inst.DeclRef);
2544 declref_inst.* = .{
2545 .base = .{
2546 .src = src,
2547 .tag = Inst.DeclRef.base_tag,
2548 },
2549 .positionals = .{
2550 .name = mem.spanZ(module_decl.name),
2551 },
2552 .kw_args = .{},
2553 };
2554 return &declref_inst.base;
2555 }
2556
2557 fn emitFn(self: *EmitZIR, module_fn: *IrModule.Fn, src: usize, ty: Type) Allocator.Error!*Decl {
2558 var inst_table = std.AutoHashMap(*ir.Inst, *Inst).init(self.allocator);
2559 defer inst_table.deinit();
2560
2561 var instructions = std.ArrayList(*Inst).init(self.allocator);
2562 defer instructions.deinit();
2563
2564 switch (module_fn.state) {
2565 .queued => unreachable,
2566 .in_progress => unreachable,
2567 .inline_only => unreachable,
2568 .success => {
2569 try self.emitBody(module_fn.body, &inst_table, &instructions);
2570 },
2571 .sema_failure => {
2572 const err_msg = self.old_module.failed_decls.get(module_fn.owner_decl).?;
2573 const fail_inst = try self.arena.allocator.create(Inst.UnOp);
2574 fail_inst.* = .{
2575 .base = .{
2576 .src = src,
2577 .tag = .compileerror,
2578 },
2579 .positionals = .{
2580 .operand = blk: {
2581 const msg_str = try self.arena.allocator.dupe(u8, err_msg.msg);
2582
2583 const str_inst = try self.arena.allocator.create(Inst.Str);
2584 str_inst.* = .{
2585 .base = .{
2586 .src = src,
2587 .tag = Inst.Str.base_tag,
2588 },
2589 .positionals = .{
2590 .bytes = msg_str,
2591 },
2592 .kw_args = .{},
2593 };
2594 break :blk &str_inst.base;
2595 },
2596 },
2597 .kw_args = .{},
2598 };
2599 try instructions.append(&fail_inst.base);
2600 },
2601 .dependency_failure => {
2602 const fail_inst = try self.arena.allocator.create(Inst.UnOp);
2603 fail_inst.* = .{
2604 .base = .{
2605 .src = src,
2606 .tag = .compileerror,
2607 },
2608 .positionals = .{
2609 .operand = blk: {
2610 const msg_str = try self.arena.allocator.dupe(u8, "depends on another failed Decl");
2611
2612 const str_inst = try self.arena.allocator.create(Inst.Str);
2613 str_inst.* = .{
2614 .base = .{
2615 .src = src,
2616 .tag = Inst.Str.base_tag,
2617 },
2618 .positionals = .{
2619 .bytes = msg_str,
2620 },
2621 .kw_args = .{},
2622 };
2623 break :blk &str_inst.base;
2624 },
2625 },
2626 .kw_args = .{},
2627 };
2628 try instructions.append(&fail_inst.base);
2629 },
2630 }
2631
2632 const fn_type = try self.emitType(src, ty);
2633
2634 const arena_instrs = try self.arena.allocator.alloc(*Inst, instructions.items.len);
2635 mem.copy(*Inst, arena_instrs, instructions.items);
2636
2637 const fn_inst = try self.arena.allocator.create(Inst.Fn);
2638 fn_inst.* = .{
2639 .base = .{
2640 .src = src,
2641 .tag = Inst.Fn.base_tag,
2642 },
2643 .positionals = .{
2644 .fn_type = fn_type.inst,
2645 .body = .{ .instructions = arena_instrs },
2646 },
2647 .kw_args = .{
2648 .is_inline = module_fn.state == .inline_only,
2649 },
2650 };
2651 return self.emitUnnamedDecl(&fn_inst.base);
2652 }
2653
2654 fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Decl {
2655 const allocator = &self.arena.allocator;
2656 if (typed_value.val.castTag(.decl_ref)) |decl_ref| {
2657 const decl = decl_ref.data;
2658 return try self.emitUnnamedDecl(try self.emitDeclRef(src, decl));
2659 } else if (typed_value.val.castTag(.variable)) |variable| {
2660 return self.emitTypedValue(src, .{
2661 .ty = typed_value.ty,
2662 .val = variable.data.init,
2663 });
2664 }
2665 if (typed_value.val.isUndef()) {
2666 const as_inst = try self.arena.allocator.create(Inst.BinOp);
2667 as_inst.* = .{
2668 .base = .{
2669 .tag = .as,
2670 .src = src,
2671 },
2672 .positionals = .{
2673 .lhs = (try self.emitType(src, typed_value.ty)).inst,
2674 .rhs = (try self.emitPrimitive(src, .@"undefined")).inst,
2675 },
2676 .kw_args = .{},
2677 };
2678 return self.emitUnnamedDecl(&as_inst.base);
2679 }
2680 switch (typed_value.ty.zigTypeTag()) {
2681 .Pointer => {
2682 const ptr_elem_type = typed_value.ty.elemType();
2683 switch (ptr_elem_type.zigTypeTag()) {
2684 .Array => {
2685 // TODO more checks to make sure this can be emitted as a string literal
2686 //const array_elem_type = ptr_elem_type.elemType();
2687 //if (array_elem_type.eql(Type.initTag(.u8)) and
2688 // ptr_elem_type.hasSentinel(Value.initTag(.zero)))
2689 //{
2690 //}
2691 const bytes = typed_value.val.toAllocatedBytes(allocator) catch |err| switch (err) {
2692 error.AnalysisFail => unreachable,
2693 else => |e| return e,
2694 };
2695 return self.emitStringLiteral(src, bytes);
2696 },
2697 else => |t| std.debug.panic("TODO implement emitTypedValue for pointer to {s}", .{@tagName(t)}),
2698 }
2699 },
2700 .ComptimeInt => return self.emitComptimeIntVal(src, typed_value.val),
2701 .Int => {
2702 const as_inst = try self.arena.allocator.create(Inst.BinOp);
2703 as_inst.* = .{
2704 .base = .{
2705 .tag = .as,
2706 .src = src,
2707 },
2708 .positionals = .{
2709 .lhs = (try self.emitType(src, typed_value.ty)).inst,
2710 .rhs = (try self.emitComptimeIntVal(src, typed_value.val)).inst,
2711 },
2712 .kw_args = .{},
2713 };
2714 return self.emitUnnamedDecl(&as_inst.base);
2715 },
2716 .Type => {
2717 const ty = try typed_value.val.toType(&self.arena.allocator);
2718 return self.emitType(src, ty);
2719 },
2720 .Fn => {
2721 const module_fn = typed_value.val.castTag(.function).?.data;
2722 return self.emitFn(module_fn, src, typed_value.ty);
2723 },
2724 .Array => {
2725 // TODO more checks to make sure this can be emitted as a string literal
2726 //const array_elem_type = ptr_elem_type.elemType();
2727 //if (array_elem_type.eql(Type.initTag(.u8)) and
2728 // ptr_elem_type.hasSentinel(Value.initTag(.zero)))
2729 //{
2730 //}
2731 const bytes = typed_value.val.toAllocatedBytes(allocator) catch |err| switch (err) {
2732 error.AnalysisFail => unreachable,
2733 else => |e| return e,
2734 };
2735 const str_inst = try self.arena.allocator.create(Inst.Str);
2736 str_inst.* = .{
2737 .base = .{
2738 .src = src,
2739 .tag = Inst.Str.base_tag,
2740 },
2741 .positionals = .{
2742 .bytes = bytes,
2743 },
2744 .kw_args = .{},
2745 };
2746 return self.emitUnnamedDecl(&str_inst.base);
2747 },
2748 .Void => return self.emitPrimitive(src, .void_value),
2749 .Bool => if (typed_value.val.toBool())
2750 return self.emitPrimitive(src, .@"true")
2751 else
2752 return self.emitPrimitive(src, .@"false"),
2753 .EnumLiteral => {
2754 const enum_literal = typed_value.val.castTag(.enum_literal).?;
2755 const inst = try self.arena.allocator.create(Inst.Str);
2756 inst.* = .{
2757 .base = .{
2758 .src = src,
2759 .tag = .enum_literal,
2760 },
2761 .positionals = .{
2762 .bytes = enum_literal.data,
2763 },
2764 .kw_args = .{},
2765 };
2766 return self.emitUnnamedDecl(&inst.base);
2767 },
2768 else => |t| std.debug.panic("TODO implement emitTypedValue for {s}", .{@tagName(t)}),
2769 }
2770 }
2771
2772 fn emitNoOp(self: *EmitZIR, src: usize, old_inst: *ir.Inst.NoOp, tag: Inst.Tag) Allocator.Error!*Inst {
2773 const new_inst = try self.arena.allocator.create(Inst.NoOp);
2774 new_inst.* = .{
2775 .base = .{
2776 .src = src,
2777 .tag = tag,
2778 },
2779 .positionals = .{},
2780 .kw_args = .{},
2781 };
2782 return &new_inst.base;
2783 }
2784
2785 fn emitUnOp(
2786 self: *EmitZIR,
2787 src: usize,
2788 new_body: ZirBody,
2789 old_inst: *ir.Inst.UnOp,
2790 tag: Inst.Tag,
2791 ) Allocator.Error!*Inst {
2792 const new_inst = try self.arena.allocator.create(Inst.UnOp);
2793 new_inst.* = .{
2794 .base = .{
2795 .src = src,
2796 .tag = tag,
2797 },
2798 .positionals = .{
2799 .operand = try self.resolveInst(new_body, old_inst.operand),
2800 },
2801 .kw_args = .{},
2802 };
2803 return &new_inst.base;
2804 }
2805
2806 fn emitBinOp(
2807 self: *EmitZIR,
2808 src: usize,
2809 new_body: ZirBody,
2810 old_inst: *ir.Inst.BinOp,
2811 tag: Inst.Tag,
2812 ) Allocator.Error!*Inst {
2813 const new_inst = try self.arena.allocator.create(Inst.BinOp);
2814 new_inst.* = .{
2815 .base = .{
2816 .src = src,
2817 .tag = tag,
2818 },
2819 .positionals = .{
2820 .lhs = try self.resolveInst(new_body, old_inst.lhs),
2821 .rhs = try self.resolveInst(new_body, old_inst.rhs),
2822 },
2823 .kw_args = .{},
2824 };
2825 return &new_inst.base;
2826 }
2827
2828 fn emitCast(
2829 self: *EmitZIR,
2830 src: usize,
2831 new_body: ZirBody,
2832 old_inst: *ir.Inst.UnOp,
2833 tag: Inst.Tag,
2834 ) Allocator.Error!*Inst {
2835 const new_inst = try self.arena.allocator.create(Inst.BinOp);
2836 new_inst.* = .{
2837 .base = .{
2838 .src = src,
2839 .tag = tag,
2840 },
2841 .positionals = .{
2842 .lhs = (try self.emitType(old_inst.base.src, old_inst.base.ty)).inst,
2843 .rhs = try self.resolveInst(new_body, old_inst.operand),
2844 },
2845 .kw_args = .{},
2846 };
2847 return &new_inst.base;
2848 }
2849
2850 fn emitBody(
2851 self: *EmitZIR,
2852 body: ir.Body,
2853 inst_table: *std.AutoHashMap(*ir.Inst, *Inst),
2854 instructions: *std.ArrayList(*Inst),
2855 ) Allocator.Error!void {
2856 const new_body = ZirBody{
2857 .inst_table = inst_table,
2858 .instructions = instructions,
2859 };
2860 for (body.instructions) |inst| {
2861 const new_inst = switch (inst.tag) {
2862 .constant => unreachable, // excluded from function bodies
2863
2864 .breakpoint => try self.emitNoOp(inst.src, inst.castTag(.breakpoint).?, .breakpoint),
2865 .unreach => try self.emitNoOp(inst.src, inst.castTag(.unreach).?, .unreach_nocheck),
2866 .retvoid => try self.emitNoOp(inst.src, inst.castTag(.retvoid).?, .returnvoid),
2867 .dbg_stmt => try self.emitNoOp(inst.src, inst.castTag(.dbg_stmt).?, .dbg_stmt),
2868
2869 .not => try self.emitUnOp(inst.src, new_body, inst.castTag(.not).?, .boolnot),
2870 .ret => try self.emitUnOp(inst.src, new_body, inst.castTag(.ret).?, .@"return"),
2871 .ptrtoint => try self.emitUnOp(inst.src, new_body, inst.castTag(.ptrtoint).?, .ptrtoint),
2872 .isnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnull).?, .isnull),
2873 .isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull),
2874 .iserr => try self.emitUnOp(inst.src, new_body, inst.castTag(.iserr).?, .iserr),
2875 .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref),
2876 .ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref),
2877 .unwrap_optional => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional).?, .unwrap_optional_unsafe),
2878 .wrap_optional => try self.emitCast(inst.src, new_body, inst.castTag(.wrap_optional).?, .as),
2879
2880 .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),
2881 .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),
2882 .store => try self.emitBinOp(inst.src, new_body, inst.castTag(.store).?, .store),
2883 .cmp_lt => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_lt).?, .cmp_lt),
2884 .cmp_lte => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_lte).?, .cmp_lte),
2885 .cmp_eq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_eq).?, .cmp_eq),
2886 .cmp_gte => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_gte).?, .cmp_gte),
2887 .cmp_gt => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_gt).?, .cmp_gt),
2888 .cmp_neq => try self.emitBinOp(inst.src, new_body, inst.castTag(.cmp_neq).?, .cmp_neq),
2889 .booland => try self.emitBinOp(inst.src, new_body, inst.castTag(.booland).?, .booland),
2890 .boolor => try self.emitBinOp(inst.src, new_body, inst.castTag(.boolor).?, .boolor),
2891 .bitand => try self.emitBinOp(inst.src, new_body, inst.castTag(.bitand).?, .bitand),
2892 .bitor => try self.emitBinOp(inst.src, new_body, inst.castTag(.bitor).?, .bitor),
2893 .xor => try self.emitBinOp(inst.src, new_body, inst.castTag(.xor).?, .xor),
2894
2895 .bitcast => try self.emitCast(inst.src, new_body, inst.castTag(.bitcast).?, .bitcast),
2896 .intcast => try self.emitCast(inst.src, new_body, inst.castTag(.intcast).?, .intcast),
2897 .floatcast => try self.emitCast(inst.src, new_body, inst.castTag(.floatcast).?, .floatcast),
2898
2899 .alloc => blk: {
2900 const new_inst = try self.arena.allocator.create(Inst.UnOp);
2901 new_inst.* = .{
2902 .base = .{
2903 .src = inst.src,
2904 .tag = .alloc,
2905 },
2906 .positionals = .{
2907 .operand = (try self.emitType(inst.src, inst.ty)).inst,
2908 },
2909 .kw_args = .{},
2910 };
2911 break :blk &new_inst.base;
2912 },
2913
2914 .arg => blk: {
2915 const old_inst = inst.castTag(.arg).?;
2916 const new_inst = try self.arena.allocator.create(Inst.Arg);
2917 new_inst.* = .{
2918 .base = .{
2919 .src = inst.src,
2920 .tag = .arg,
2921 },
2922 .positionals = .{
2923 .name = try self.arena.allocator.dupe(u8, mem.spanZ(old_inst.name)),
2924 },
2925 .kw_args = .{},
2926 };
2927 break :blk &new_inst.base;
2928 },
2929
2930 .block => blk: {
2931 const old_inst = inst.castTag(.block).?;
2932 const new_inst = try self.arena.allocator.create(Inst.Block);
2933
2934 try self.block_table.put(old_inst, new_inst);
2935
2936 var block_body = std.ArrayList(*Inst).init(self.allocator);
2937 defer block_body.deinit();
2938
2939 try self.emitBody(old_inst.body, inst_table, &block_body);
2940
2941 new_inst.* = .{
2942 .base = .{
2943 .src = inst.src,
2944 .tag = Inst.Block.base_tag,
2945 },
2946 .positionals = .{
2947 .body = .{ .instructions = block_body.toOwnedSlice() },
2948 },
2949 .kw_args = .{},
2950 };
2951
2952 break :blk &new_inst.base;
2953 },
2954
2955 .loop => blk: {
2956 const old_inst = inst.castTag(.loop).?;
2957 const new_inst = try self.arena.allocator.create(Inst.Loop);
2958
2959 try self.loop_table.put(old_inst, new_inst);
2960
2961 var loop_body = std.ArrayList(*Inst).init(self.allocator);
2962 defer loop_body.deinit();
2963
2964 try self.emitBody(old_inst.body, inst_table, &loop_body);
2965
2966 new_inst.* = .{
2967 .base = .{
2968 .src = inst.src,
2969 .tag = Inst.Loop.base_tag,
2970 },
2971 .positionals = .{
2972 .body = .{ .instructions = loop_body.toOwnedSlice() },
2973 },
2974 .kw_args = .{},
2975 };
2976
2977 break :blk &new_inst.base;
2978 },
2979
2980 .brvoid => blk: {
2981 const old_inst = inst.cast(ir.Inst.BrVoid).?;
2982 const new_block = self.block_table.get(old_inst.block).?;
2983 const new_inst = try self.arena.allocator.create(Inst.BreakVoid);
2984 new_inst.* = .{
2985 .base = .{
2986 .src = inst.src,
2987 .tag = Inst.BreakVoid.base_tag,
2988 },
2989 .positionals = .{
2990 .block = new_block,
2991 },
2992 .kw_args = .{},
2993 };
2994 break :blk &new_inst.base;
2995 },
2996
2997 .br => blk: {
2998 const old_inst = inst.castTag(.br).?;
2999 const new_block = self.block_table.get(old_inst.block).?;
3000 const new_inst = try self.arena.allocator.create(Inst.Break);
3001 new_inst.* = .{
3002 .base = .{
3003 .src = inst.src,
3004 .tag = Inst.Break.base_tag,
3005 },
3006 .positionals = .{
3007 .block = new_block,
3008 .operand = try self.resolveInst(new_body, old_inst.operand),
3009 },
3010 .kw_args = .{},
3011 };
3012 break :blk &new_inst.base;
3013 },
3014
3015 .call => blk: {
3016 const old_inst = inst.castTag(.call).?;
3017 const new_inst = try self.arena.allocator.create(Inst.Call);
3018
3019 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.len);
3020 for (args) |*elem, i| {
3021 elem.* = try self.resolveInst(new_body, old_inst.args[i]);
3022 }
3023 new_inst.* = .{
3024 .base = .{
3025 .src = inst.src,
3026 .tag = Inst.Call.base_tag,
3027 },
3028 .positionals = .{
3029 .func = try self.resolveInst(new_body, old_inst.func),
3030 .args = args,
3031 },
3032 .kw_args = .{},
3033 };
3034 break :blk &new_inst.base;
3035 },
3036
3037 .assembly => blk: {
3038 const old_inst = inst.castTag(.assembly).?;
3039 const new_inst = try self.arena.allocator.create(Inst.Asm);
3040
3041 const inputs = try self.arena.allocator.alloc(*Inst, old_inst.inputs.len);
3042 for (inputs) |*elem, i| {
3043 elem.* = (try self.emitStringLiteral(inst.src, old_inst.inputs[i])).inst;
3044 }
3045
3046 const clobbers = try self.arena.allocator.alloc(*Inst, old_inst.clobbers.len);
3047 for (clobbers) |*elem, i| {
3048 elem.* = (try self.emitStringLiteral(inst.src, old_inst.clobbers[i])).inst;
3049 }
3050
3051 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.len);
3052 for (args) |*elem, i| {
3053 elem.* = try self.resolveInst(new_body, old_inst.args[i]);
3054 }
3055
3056 new_inst.* = .{
3057 .base = .{
3058 .src = inst.src,
3059 .tag = Inst.Asm.base_tag,
3060 },
3061 .positionals = .{
3062 .asm_source = (try self.emitStringLiteral(inst.src, old_inst.asm_source)).inst,
3063 .return_type = (try self.emitType(inst.src, inst.ty)).inst,
3064 },
3065 .kw_args = .{
3066 .@"volatile" = old_inst.is_volatile,
3067 .output = if (old_inst.output) |o|
3068 (try self.emitStringLiteral(inst.src, o)).inst
3069 else
3070 null,
3071 .inputs = inputs,
3072 .clobbers = clobbers,
3073 .args = args,
3074 },
3075 };
3076 break :blk &new_inst.base;
3077 },
3078
3079 .condbr => blk: {
3080 const old_inst = inst.castTag(.condbr).?;
3081
3082 var then_body = std.ArrayList(*Inst).init(self.allocator);
3083 var else_body = std.ArrayList(*Inst).init(self.allocator);
3084
3085 defer then_body.deinit();
3086 defer else_body.deinit();
3087
3088 const then_deaths = try self.arena.allocator.alloc(*Inst, old_inst.thenDeaths().len);
3089 const else_deaths = try self.arena.allocator.alloc(*Inst, old_inst.elseDeaths().len);
3090
3091 for (old_inst.thenDeaths()) |death, i| {
3092 then_deaths[i] = try self.resolveInst(new_body, death);
3093 }
3094 for (old_inst.elseDeaths()) |death, i| {
3095 else_deaths[i] = try self.resolveInst(new_body, death);
3096 }
3097
3098 try self.emitBody(old_inst.then_body, inst_table, &then_body);
3099 try self.emitBody(old_inst.else_body, inst_table, &else_body);
3100
3101 const new_inst = try self.arena.allocator.create(Inst.CondBr);
3102
3103 try self.body_metadata.put(&new_inst.positionals.then_body, .{ .deaths = then_deaths });
3104 try self.body_metadata.put(&new_inst.positionals.else_body, .{ .deaths = else_deaths });
3105
3106 new_inst.* = .{
3107 .base = .{
3108 .src = inst.src,
3109 .tag = Inst.CondBr.base_tag,
3110 },
3111 .positionals = .{
3112 .condition = try self.resolveInst(new_body, old_inst.condition),
3113 .then_body = .{ .instructions = then_body.toOwnedSlice() },
3114 .else_body = .{ .instructions = else_body.toOwnedSlice() },
3115 },
3116 .kw_args = .{},
3117 };
3118 break :blk &new_inst.base;
3119 },
3120 .switchbr => blk: {
3121 const old_inst = inst.castTag(.switchbr).?;
3122 const cases = try self.arena.allocator.alloc(Inst.SwitchBr.Case, old_inst.cases.len);
3123 const new_inst = try self.arena.allocator.create(Inst.SwitchBr);
3124 new_inst.* = .{
3125 .base = .{
3126 .src = inst.src,
3127 .tag = Inst.SwitchBr.base_tag,
3128 },
3129 .positionals = .{
3130 .target_ptr = try self.resolveInst(new_body, old_inst.target_ptr),
3131 .cases = cases,
3132 .items = &[_]*Inst{}, // TODO this should actually be populated
3133 .else_body = undefined, // populated below
3134 },
3135 .kw_args = .{},
3136 };
3137
3138 var body_tmp = std.ArrayList(*Inst).init(self.allocator);
3139 defer body_tmp.deinit();
3140
3141 for (old_inst.cases) |*case, i| {
3142 body_tmp.items.len = 0;
3143
3144 const case_deaths = try self.arena.allocator.alloc(*Inst, old_inst.caseDeaths(i).len);
3145 for (old_inst.caseDeaths(i)) |death, j| {
3146 case_deaths[j] = try self.resolveInst(new_body, death);
3147 }
3148 try self.body_metadata.put(&cases[i].body, .{ .deaths = case_deaths });
3149
3150 try self.emitBody(case.body, inst_table, &body_tmp);
3151 const item = (try self.emitTypedValue(inst.src, .{
3152 .ty = old_inst.target_ptr.ty.elemType(),
3153 .val = case.item,
3154 })).inst;
3155
3156 cases[i] = .{
3157 .item = item,
3158 .body = .{ .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items) },
3159 };
3160 }
3161 { // else
3162 const else_deaths = try self.arena.allocator.alloc(*Inst, old_inst.elseDeaths().len);
3163 for (old_inst.elseDeaths()) |death, j| {
3164 else_deaths[j] = try self.resolveInst(new_body, death);
3165 }
3166 try self.body_metadata.put(&new_inst.positionals.else_body, .{ .deaths = else_deaths });
3167
3168 body_tmp.items.len = 0;
3169 try self.emitBody(old_inst.else_body, inst_table, &body_tmp);
3170 new_inst.positionals.else_body = .{
3171 .instructions = try self.arena.allocator.dupe(*Inst, body_tmp.items),
3172 };
3173 }
3174
3175 break :blk &new_inst.base;
3176 },
3177 .varptr => @panic("TODO"),
3178 };
3179 try self.metadata.put(new_inst, .{
3180 .deaths = inst.deaths,
3181 .addr = @ptrToInt(inst),
3182 });
3183 try instructions.append(new_inst);
3184 try inst_table.put(inst, new_inst);
3185 }
3186 }
3187
3188 fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Decl {
3189 switch (ty.tag()) {
3190 .i8 => return self.emitPrimitive(src, .i8),
3191 .u8 => return self.emitPrimitive(src, .u8),
3192 .i16 => return self.emitPrimitive(src, .i16),
3193 .u16 => return self.emitPrimitive(src, .u16),
3194 .i32 => return self.emitPrimitive(src, .i32),
3195 .u32 => return self.emitPrimitive(src, .u32),
3196 .i64 => return self.emitPrimitive(src, .i64),
3197 .u64 => return self.emitPrimitive(src, .u64),
3198 .isize => return self.emitPrimitive(src, .isize),
3199 .usize => return self.emitPrimitive(src, .usize),
3200 .c_short => return self.emitPrimitive(src, .c_short),
3201 .c_ushort => return self.emitPrimitive(src, .c_ushort),
3202 .c_int => return self.emitPrimitive(src, .c_int),
3203 .c_uint => return self.emitPrimitive(src, .c_uint),
3204 .c_long => return self.emitPrimitive(src, .c_long),
3205 .c_ulong => return self.emitPrimitive(src, .c_ulong),
3206 .c_longlong => return self.emitPrimitive(src, .c_longlong),
3207 .c_ulonglong => return self.emitPrimitive(src, .c_ulonglong),
3208 .c_longdouble => return self.emitPrimitive(src, .c_longdouble),
3209 .c_void => return self.emitPrimitive(src, .c_void),
3210 .f16 => return self.emitPrimitive(src, .f16),
3211 .f32 => return self.emitPrimitive(src, .f32),
3212 .f64 => return self.emitPrimitive(src, .f64),
3213 .f128 => return self.emitPrimitive(src, .f128),
3214 .anyerror => return self.emitPrimitive(src, .anyerror),
3215 else => switch (ty.zigTypeTag()) {
3216 .Bool => return self.emitPrimitive(src, .bool),
3217 .Void => return self.emitPrimitive(src, .void),
3218 .NoReturn => return self.emitPrimitive(src, .noreturn),
3219 .Type => return self.emitPrimitive(src, .type),
3220 .ComptimeInt => return self.emitPrimitive(src, .comptime_int),
3221 .ComptimeFloat => return self.emitPrimitive(src, .comptime_float),
3222 .Fn => {
3223 const param_types = try self.allocator.alloc(Type, ty.fnParamLen());
3224 defer self.allocator.free(param_types);
3225
3226 ty.fnParamTypes(param_types);
3227 const emitted_params = try self.arena.allocator.alloc(*Inst, param_types.len);
3228 for (param_types) |param_type, i| {
3229 emitted_params[i] = (try self.emitType(src, param_type)).inst;
3230 }
3231
3232 const fntype_inst = try self.arena.allocator.create(Inst.FnType);
3233 fntype_inst.* = .{
3234 .base = .{
3235 .src = src,
3236 .tag = Inst.FnType.base_tag,
3237 },
3238 .positionals = .{
3239 .param_types = emitted_params,
3240 .return_type = (try self.emitType(src, ty.fnReturnType())).inst,
3241 },
3242 .kw_args = .{
3243 .cc = ty.fnCallingConvention(),
3244 },
3245 };
3246 return self.emitUnnamedDecl(&fntype_inst.base);
3247 },
3248 .Int => {
3249 const info = ty.intInfo(self.old_module.getTarget());
3250 const signed = try self.emitPrimitive(src, switch (info.signedness) {
3251 .signed => .@"true",
3252 .unsigned => .@"false",
3253 });
3254 const bits_val = try Value.Tag.int_u64.create(&self.arena.allocator, info.bits);
3255 const bits = try self.emitComptimeIntVal(src, bits_val);
3256 const inttype_inst = try self.arena.allocator.create(Inst.IntType);
3257 inttype_inst.* = .{
3258 .base = .{
3259 .src = src,
3260 .tag = Inst.IntType.base_tag,
3261 },
3262 .positionals = .{
3263 .signed = signed.inst,
3264 .bits = bits.inst,
3265 },
3266 .kw_args = .{},
3267 };
3268 return self.emitUnnamedDecl(&inttype_inst.base);
3269 },
3270 .Pointer => {
3271 if (ty.isSinglePointer()) {
3272 const inst = try self.arena.allocator.create(Inst.UnOp);
3273 const tag: Inst.Tag = if (ty.isConstPtr()) .single_const_ptr_type else .single_mut_ptr_type;
3274 inst.* = .{
3275 .base = .{
3276 .src = src,
3277 .tag = tag,
3278 },
3279 .positionals = .{
3280 .operand = (try self.emitType(src, ty.elemType())).inst,
3281 },
3282 .kw_args = .{},
3283 };
3284 return self.emitUnnamedDecl(&inst.base);
3285 } else {
3286 std.debug.panic("TODO implement emitType for {}", .{ty});
3287 }
3288 },
3289 .Optional => {
3290 var buf: Type.Payload.ElemType = undefined;
3291 const inst = try self.arena.allocator.create(Inst.UnOp);
3292 inst.* = .{
3293 .base = .{
3294 .src = src,
3295 .tag = .optional_type,
3296 },
3297 .positionals = .{
3298 .operand = (try self.emitType(src, ty.optionalChild(&buf))).inst,
3299 },
3300 .kw_args = .{},
3301 };
3302 return self.emitUnnamedDecl(&inst.base);
3303 },
3304 .Array => {
3305 var len_pl = Value.Payload.U64{
3306 .base = .{ .tag = .int_u64 },
3307 .data = ty.arrayLen(),
3308 };
3309 const len = Value.initPayload(&len_pl.base);
3310
3311 const inst = if (ty.sentinel()) |sentinel| blk: {
3312 const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel);
3313 inst.* = .{
3314 .base = .{
3315 .src = src,
3316 .tag = .array_type,
3317 },
3318 .positionals = .{
3319 .len = (try self.emitTypedValue(src, .{
3320 .ty = Type.initTag(.usize),
3321 .val = len,
3322 })).inst,
3323 .sentinel = (try self.emitTypedValue(src, .{
3324 .ty = ty.elemType(),
3325 .val = sentinel,
3326 })).inst,
3327 .elem_type = (try self.emitType(src, ty.elemType())).inst,
3328 },
3329 .kw_args = .{},
3330 };
3331 break :blk &inst.base;
3332 } else blk: {
3333 const inst = try self.arena.allocator.create(Inst.BinOp);
3334 inst.* = .{
3335 .base = .{
3336 .src = src,
3337 .tag = .array_type,
3338 },
3339 .positionals = .{
3340 .lhs = (try self.emitTypedValue(src, .{
3341 .ty = Type.initTag(.usize),
3342 .val = len,
3343 })).inst,
3344 .rhs = (try self.emitType(src, ty.elemType())).inst,
3345 },
3346 .kw_args = .{},
3347 };
3348 break :blk &inst.base;
3349 };
3350 return self.emitUnnamedDecl(inst);
3351 },
3352 else => std.debug.panic("TODO implement emitType for {}", .{ty}),
3353 },
3354 }
3355 }
3356
3357 fn autoName(self: *EmitZIR) ![]u8 {
3358 while (true) {
3359 const proposed_name = try std.fmt.allocPrint(&self.arena.allocator, "unnamed${d}", .{self.next_auto_name});
3360 self.next_auto_name += 1;
3361 const gop = try self.names.getOrPut(proposed_name);
3362 if (!gop.found_existing) {
3363 gop.entry.value = {};
3364 return proposed_name;
3365 }
3366 }
3367 }
3368
3369 fn emitPrimitive(self: *EmitZIR, src: usize, tag: Inst.Primitive.Builtin) !*Decl {
3370 const gop = try self.primitive_table.getOrPut(tag);
3371 if (!gop.found_existing) {
3372 const primitive_inst = try self.arena.allocator.create(Inst.Primitive);
3373 primitive_inst.* = .{
3374 .base = .{
3375 .src = src,
3376 .tag = Inst.Primitive.base_tag,
3377 },
3378 .positionals = .{
3379 .tag = tag,
3380 },
3381 .kw_args = .{},
3382 };
3383 gop.entry.value = try self.emitUnnamedDecl(&primitive_inst.base);
3384 }
3385 return gop.entry.value;
3386 }
3387
3388 fn emitStringLiteral(self: *EmitZIR, src: usize, str: []const u8) !*Decl {
3389 const str_inst = try self.arena.allocator.create(Inst.Str);
3390 str_inst.* = .{
3391 .base = .{
3392 .src = src,
3393 .tag = Inst.Str.base_tag,
3394 },
3395 .positionals = .{
3396 .bytes = str,
3397 },
3398 .kw_args = .{},
3399 };
3400 return self.emitUnnamedDecl(&str_inst.base);
3401 }
3402
3403 fn emitUnnamedDecl(self: *EmitZIR, inst: *Inst) !*Decl {
3404 const decl = try self.arena.allocator.create(Decl);
3405 decl.* = .{
3406 .name = try self.autoName(),
3407 .contents_hash = undefined,
3408 .inst = inst,
3409 };
3410 try self.decls.append(self.allocator, decl);
3411 return decl;
3412 }
3413};
3414
3415/// For debugging purposes, like dumpFn but for unanalyzed zir blocks1859/// For debugging purposes, like dumpFn but for unanalyzed zir blocks
3416pub fn dumpZir(allocator: *Allocator, kind: []const u8, decl_name: [*:0]const u8, instructions: []*Inst) !void {1860pub fn dumpZir(allocator: *Allocator, kind: []const u8, decl_name: [*:0]const u8, instructions: []*Inst) !void {
3417 var fib = std.heap.FixedBufferAllocator.init(&[_]u8{});1861 var fib = std.heap.FixedBufferAllocator.init(&[_]u8{});
3418 var module = Module{1862 var module = Module{
3419 .decls = &[_]*Decl{},1863 .decls = &[_]*Module.Decl{},
3420 .arena = std.heap.ArenaAllocator.init(&fib.allocator),1864 .arena = std.heap.ArenaAllocator.init(&fib.allocator),
3421 .metadata = std.AutoHashMap(*Inst, Module.MetaData).init(&fib.allocator),1865 .metadata = std.AutoHashMap(*Inst, Module.MetaData).init(&fib.allocator),
3422 .body_metadata = std.AutoHashMap(*Module.Body, Module.BodyMetaData).init(&fib.allocator),1866 .body_metadata = std.AutoHashMap(*Body, Module.BodyMetaData).init(&fib.allocator),
3423 };1867 };
3424 var write = Writer{1868 var write = Writer{
3425 .module = &module,1869 .module = &module,
src/zir_sema.zig+47-132
...@@ -63,7 +63,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -63,7 +63,6 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
63 .declref => return analyzeInstDeclRef(mod, scope, old_inst.castTag(.declref).?),63 .declref => return analyzeInstDeclRef(mod, scope, old_inst.castTag(.declref).?),
64 .declref_str => return analyzeInstDeclRefStr(mod, scope, old_inst.castTag(.declref_str).?),64 .declref_str => return analyzeInstDeclRefStr(mod, scope, old_inst.castTag(.declref_str).?),
65 .declval => return analyzeInstDeclVal(mod, scope, old_inst.castTag(.declval).?),65 .declval => return analyzeInstDeclVal(mod, scope, old_inst.castTag(.declval).?),
66 .declval_in_module => return analyzeInstDeclValInModule(mod, scope, old_inst.castTag(.declval_in_module).?),
67 .ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?),66 .ensure_result_used => return analyzeInstEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?),
68 .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),67 .ensure_result_non_error => return analyzeInstEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),
69 .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),68 .ensure_indexable => return analyzeInstEnsureIndexable(mod, scope, old_inst.castTag(.ensure_indexable).?),
...@@ -166,7 +165,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -166,7 +165,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
166 }165 }
167}166}
168167
169pub fn analyzeBody(mod: *Module, block: *Scope.Block, body: zir.Module.Body) !void {168pub fn analyzeBody(mod: *Module, block: *Scope.Block, body: zir.Body) !void {
170 const tracy = trace(@src());169 const tracy = trace(@src());
171 defer tracy.end();170 defer tracy.end();
172171
...@@ -183,7 +182,7 @@ pub fn analyzeBodyValueAsType(...@@ -183,7 +182,7 @@ pub fn analyzeBodyValueAsType(
183 mod: *Module,182 mod: *Module,
184 block_scope: *Scope.Block,183 block_scope: *Scope.Block,
185 zir_result_inst: *zir.Inst,184 zir_result_inst: *zir.Inst,
186 body: zir.Module.Body,185 body: zir.Body,
187) !Type {186) !Type {
188 try analyzeBody(mod, block_scope, body);187 try analyzeBody(mod, block_scope, body);
189 const result_inst = block_scope.inst_table.get(zir_result_inst).?;188 const result_inst = block_scope.inst_table.get(zir_result_inst).?;
...@@ -191,84 +190,6 @@ pub fn analyzeBodyValueAsType(...@@ -191,84 +190,6 @@ pub fn analyzeBodyValueAsType(
191 return val.toType(block_scope.base.arena());190 return val.toType(block_scope.base.arena());
192}191}
193192
194pub fn analyzeZirDecl(mod: *Module, decl: *Decl, src_decl: *zir.Decl) InnerError!bool {
195 var decl_scope: Scope.DeclAnalysis = .{
196 .decl = decl,
197 .arena = std.heap.ArenaAllocator.init(mod.gpa),
198 };
199 errdefer decl_scope.arena.deinit();
200
201 decl.analysis = .in_progress;
202
203 const typed_value = try analyzeConstInst(mod, &decl_scope.base, src_decl.inst);
204 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
205
206 var prev_type_has_bits = false;
207 var type_changed = true;
208
209 if (decl.typedValueManaged()) |tvm| {
210 prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits();
211 type_changed = !tvm.typed_value.ty.eql(typed_value.ty);
212
213 tvm.deinit(mod.gpa);
214 }
215
216 arena_state.* = decl_scope.arena.state;
217 decl.typed_value = .{
218 .most_recent = .{
219 .typed_value = typed_value,
220 .arena = arena_state,
221 },
222 };
223 decl.analysis = .complete;
224 decl.generation = mod.generation;
225 if (typed_value.ty.hasCodeGenBits()) {
226 // We don't fully codegen the decl until later, but we do need to reserve a global
227 // offset table index for it. This allows us to codegen decls out of dependency order,
228 // increasing how many computations can be done in parallel.
229 try mod.comp.bin_file.allocateDeclIndexes(decl);
230 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl });
231 } else if (prev_type_has_bits) {
232 mod.comp.bin_file.freeDecl(decl);
233 }
234
235 return type_changed;
236}
237
238pub fn resolveZirDecl(mod: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl {
239 const zir_module = mod.root_scope.cast(Scope.ZIRModule).?;
240 const entry = zir_module.contents.module.findDecl(src_decl.name).?;
241 return resolveZirDeclHavingIndex(mod, scope, src_decl, entry.index);
242}
243
244fn resolveZirDeclHavingIndex(mod: *Module, scope: *Scope, src_decl: *zir.Decl, src_index: usize) InnerError!*Decl {
245 const name_hash = scope.namespace().fullyQualifiedNameHash(src_decl.name);
246 const decl = mod.decl_table.get(name_hash).?;
247 decl.src_index = src_index;
248 try mod.ensureDeclAnalyzed(decl);
249 return decl;
250}
251
252/// Declares a dependency on the decl.
253fn resolveCompleteZirDecl(mod: *Module, scope: *Scope, src_decl: *zir.Decl) InnerError!*Decl {
254 const decl = try resolveZirDecl(mod, scope, src_decl);
255 switch (decl.analysis) {
256 .unreferenced => unreachable,
257 .in_progress => unreachable,
258 .outdated => unreachable,
259
260 .dependency_failure,
261 .sema_failure,
262 .sema_failure_retryable,
263 .codegen_failure,
264 .codegen_failure_retryable,
265 => return error.AnalysisFail,
266
267 .complete => {},
268 }
269 return decl;
270}
271
272pub fn resolveInst(mod: *Module, scope: *Scope, zir_inst: *zir.Inst) InnerError!*Inst {193pub fn resolveInst(mod: *Module, scope: *Scope, zir_inst: *zir.Inst) InnerError!*Inst {
273 const block = scope.cast(Scope.Block).?;194 const block = scope.cast(Scope.Block).?;
274 return block.inst_table.get(zir_inst).?; // Instruction does not dominate all uses!195 return block.inst_table.get(zir_inst).?; // Instruction does not dominate all uses!
...@@ -640,22 +561,28 @@ fn analyzeInstCompileError(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In...@@ -640,22 +561,28 @@ fn analyzeInstCompileError(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) In
640}561}
641562
642fn analyzeInstCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerError!*Inst {563fn analyzeInstCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerError!*Inst {
643 std.debug.print("| ", .{});564 var managed = mod.compile_log_text.toManaged(mod.gpa);
644 for (inst.positionals.to_log) |item, i| {565 defer mod.compile_log_text = managed.moveToUnmanaged();
645 const to_log = try resolveInst(mod, scope, item);566 const writer = managed.writer();
646 if (to_log.value()) |val| {567
647 std.debug.print("{}", .{val});568 for (inst.positionals.to_log) |arg_inst, i| {
569 if (i != 0) try writer.print(", ", .{});
570
571 const arg = try resolveInst(mod, scope, arg_inst);
572 if (arg.value()) |val| {
573 try writer.print("@as({}, {})", .{ arg.ty, val });
648 } else {574 } else {
649 std.debug.print("(runtime value)", .{});575 try writer.print("@as({}, [runtime value])", .{arg.ty});
650 }576 }
651 if (i != inst.positionals.to_log.len - 1) std.debug.print(", ", .{});
652 }577 }
653 std.debug.print("\n", .{});578 try writer.print("\n", .{});
654 if (!inst.kw_args.seen) {
655579
656 // so that we do not give multiple compile errors if it gets evaled twice580 const gop = try mod.compile_log_decls.getOrPut(mod.gpa, scope.ownerDecl().?);
657 inst.kw_args.seen = true;581 if (!gop.found_existing) {
658 try mod.failCompileLog(scope, inst.base.src);582 gop.entry.value = .{
583 .file_scope = scope.getFileScope(),
584 .byte_offset = inst.base.src,
585 };
659 }586 }
660 return mod.constVoid(scope, inst.base.src);587 return mod.constVoid(scope, inst.base.src);
661}588}
...@@ -705,7 +632,8 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError...@@ -705,7 +632,8 @@ fn analyzeInstLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError
705 .parent = parent_block,632 .parent = parent_block,
706 .inst_table = parent_block.inst_table,633 .inst_table = parent_block.inst_table,
707 .func = parent_block.func,634 .func = parent_block.func,
708 .decl = parent_block.decl,635 .owner_decl = parent_block.owner_decl,
636 .src_decl = parent_block.src_decl,
709 .instructions = .{},637 .instructions = .{},
710 .arena = parent_block.arena,638 .arena = parent_block.arena,
711 .inlining = parent_block.inlining,639 .inlining = parent_block.inlining,
...@@ -732,7 +660,8 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c...@@ -732,7 +660,8 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c
732 .parent = parent_block,660 .parent = parent_block,
733 .inst_table = parent_block.inst_table,661 .inst_table = parent_block.inst_table,
734 .func = parent_block.func,662 .func = parent_block.func,
735 .decl = parent_block.decl,663 .owner_decl = parent_block.owner_decl,
664 .src_decl = parent_block.src_decl,
736 .instructions = .{},665 .instructions = .{},
737 .arena = parent_block.arena,666 .arena = parent_block.arena,
738 .label = null,667 .label = null,
...@@ -744,13 +673,14 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c...@@ -744,13 +673,14 @@ fn analyzeInstBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_c
744673
745 try analyzeBody(mod, &child_block, inst.positionals.body);674 try analyzeBody(mod, &child_block, inst.positionals.body);
746675
747 try parent_block.instructions.appendSlice(mod.gpa, child_block.instructions.items);676 // Move the analyzed instructions into the parent block arena.
748677 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items);
749 // comptime blocks won't generate any runtime values678 try parent_block.instructions.appendSlice(mod.gpa, copied_instructions);
750 if (child_block.instructions.items.len == 0)
751 return mod.constVoid(scope, inst.base.src);
752679
753 return parent_block.instructions.items[parent_block.instructions.items.len - 1];680 // The result of a flat block is the last instruction.
681 const zir_inst_list = inst.positionals.body.instructions;
682 const last_zir_inst = zir_inst_list[zir_inst_list.len - 1];
683 return resolveInst(mod, scope, last_zir_inst);
754}684}
755685
756fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst {686fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst {
...@@ -775,7 +705,8 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt...@@ -775,7 +705,8 @@ fn analyzeInstBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_compt
775 .parent = parent_block,705 .parent = parent_block,
776 .inst_table = parent_block.inst_table,706 .inst_table = parent_block.inst_table,
777 .func = parent_block.func,707 .func = parent_block.func,
778 .decl = parent_block.decl,708 .owner_decl = parent_block.owner_decl,
709 .src_decl = parent_block.src_decl,
779 .instructions = .{},710 .instructions = .{},
780 .arena = parent_block.arena,711 .arena = parent_block.arena,
781 // TODO @as here is working around a stage1 miscompilation bug :(712 // TODO @as here is working around a stage1 miscompilation bug :(
...@@ -890,22 +821,15 @@ fn analyzeInstDeclRefStr(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr...@@ -890,22 +821,15 @@ fn analyzeInstDeclRefStr(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr
890fn analyzeInstDeclRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {821fn analyzeInstDeclRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
891 const tracy = trace(@src());822 const tracy = trace(@src());
892 defer tracy.end();823 defer tracy.end();
893 return mod.analyzeDeclRefByName(scope, inst.base.src, inst.positionals.name);824 return mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl);
894}825}
895826
896fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst {827fn analyzeInstDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst {
897 const tracy = trace(@src());828 const tracy = trace(@src());
898 defer tracy.end();829 defer tracy.end();
899 const decl = try analyzeDeclVal(mod, scope, inst);830 const decl_ref = try mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl);
900 const ptr = try mod.analyzeDeclRef(scope, inst.base.src, decl);831 // TODO look into avoiding the call to analyzeDeref here
901 return mod.analyzeDeref(scope, inst.base.src, ptr, inst.base.src);832 return mod.analyzeDeref(scope, inst.base.src, decl_ref, inst.base.src);
902}
903
904fn analyzeInstDeclValInModule(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclValInModule) InnerError!*Inst {
905 const tracy = trace(@src());
906 defer tracy.end();
907 const decl = inst.positionals.decl;
908 return mod.analyzeDeclRef(scope, inst.base.src, decl);
909}833}
910834
911fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {835fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
...@@ -1032,9 +956,8 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError...@@ -1032,9 +956,8 @@ fn analyzeInstCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError
1032 .parent = null,956 .parent = null,
1033 .inst_table = &inst_table,957 .inst_table = &inst_table,
1034 .func = module_fn,958 .func = module_fn,
1035 // Note that we pass the caller's Decl, not the callee. This causes959 .owner_decl = scope.ownerDecl().?,
1036 // compile errors to be attached (correctly) to the caller's Decl.960 .src_decl = module_fn.owner_decl,
1037 .decl = scope.decl().?,
1038 .instructions = .{},961 .instructions = .{},
1039 .arena = scope.arena(),962 .arena = scope.arena(),
1040 .label = null,963 .label = null,
...@@ -1069,7 +992,7 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!...@@ -1069,7 +992,7 @@ fn analyzeInstFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!
1069 .state = if (fn_inst.kw_args.is_inline) .inline_only else .queued,992 .state = if (fn_inst.kw_args.is_inline) .inline_only else .queued,
1070 .zir = fn_inst.positionals.body,993 .zir = fn_inst.positionals.body,
1071 .body = undefined,994 .body = undefined,
1072 .owner_decl = scope.decl().?,995 .owner_decl = scope.ownerDecl().?,
1073 };996 };
1074 return mod.constInst(scope, fn_inst.base.src, .{997 return mod.constInst(scope, fn_inst.base.src, .{
1075 .ty = fn_type,998 .ty = fn_type,
...@@ -1391,7 +1314,7 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr...@@ -1391,7 +1314,7 @@ fn analyzeInstFieldPtr(mod: *Module, scope: *Scope, fieldptr: *zir.Inst.FieldPtr
1391 return mod.analyzeDeclRef(scope, fieldptr.base.src, decl);1314 return mod.analyzeDeclRef(scope, fieldptr.base.src, decl);
1392 }1315 }
13931316
1394 if (&container_scope.file_scope.base == mod.root_scope) {1317 if (container_scope.file_scope == mod.root_scope) {
1395 return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{s}'", .{field_name});1318 return mod.fail(scope, fieldptr.base.src, "root source file has no member called '{s}'", .{field_name});
1396 } else {1319 } else {
1397 return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{s}'", .{ child_type, field_name });1320 return mod.fail(scope, fieldptr.base.src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
...@@ -1606,7 +1529,8 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In...@@ -1606,7 +1529,8 @@ fn analyzeInstSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr) In
1606 .parent = parent_block,1529 .parent = parent_block,
1607 .inst_table = parent_block.inst_table,1530 .inst_table = parent_block.inst_table,
1608 .func = parent_block.func,1531 .func = parent_block.func,
1609 .decl = parent_block.decl,1532 .owner_decl = parent_block.owner_decl,
1533 .src_decl = parent_block.src_decl,
1610 .instructions = .{},1534 .instructions = .{},
1611 .arena = parent_block.arena,1535 .arena = parent_block.arena,
1612 .inlining = parent_block.inlining,1536 .inlining = parent_block.inlining,
...@@ -2182,7 +2106,8 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE...@@ -2182,7 +2106,8 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE
2182 .parent = parent_block,2106 .parent = parent_block,
2183 .inst_table = parent_block.inst_table,2107 .inst_table = parent_block.inst_table,
2184 .func = parent_block.func,2108 .func = parent_block.func,
2185 .decl = parent_block.decl,2109 .owner_decl = parent_block.owner_decl,
2110 .src_decl = parent_block.src_decl,
2186 .instructions = .{},2111 .instructions = .{},
2187 .arena = parent_block.arena,2112 .arena = parent_block.arena,
2188 .inlining = parent_block.inlining,2113 .inlining = parent_block.inlining,
...@@ -2196,7 +2121,8 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE...@@ -2196,7 +2121,8 @@ fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerE
2196 .parent = parent_block,2121 .parent = parent_block,
2197 .inst_table = parent_block.inst_table,2122 .inst_table = parent_block.inst_table,
2198 .func = parent_block.func,2123 .func = parent_block.func,
2199 .decl = parent_block.decl,2124 .owner_decl = parent_block.owner_decl,
2125 .src_decl = parent_block.src_decl,
2200 .instructions = .{},2126 .instructions = .{},
2201 .arena = parent_block.arena,2127 .arena = parent_block.arena,
2202 .inlining = parent_block.inlining,2128 .inlining = parent_block.inlining,
...@@ -2294,17 +2220,6 @@ fn analyzeBreak(...@@ -2294,17 +2220,6 @@ fn analyzeBreak(
2294 } else unreachable;2220 } else unreachable;
2295}2221}
22962222
2297fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl {
2298 const decl_name = inst.positionals.name;
2299 const zir_module = scope.namespace().cast(Scope.ZIRModule).?;
2300 const src_decl = zir_module.contents.module.findDecl(decl_name) orelse
2301 return mod.fail(scope, inst.base.src, "use of undeclared identifier '{s}'", .{decl_name});
2302
2303 const decl = try resolveCompleteZirDecl(mod, scope, src_decl.decl);
2304
2305 return decl;
2306}
2307
2308fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst {2223fn analyzeInstSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst {
2309 const tracy = trace(@src());2224 const tracy = trace(@src());
2310 defer tracy.end();2225 defer tracy.end();
test/stage2/test.zig+42-20
...@@ -36,7 +36,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -36,7 +36,7 @@ pub fn addCases(ctx: *TestContext) !void {
36 {36 {
37 var case = ctx.exe("hello world with updates", linux_x64);37 var case = ctx.exe("hello world with updates", linux_x64);
3838
39 case.addError("", &[_][]const u8{"no entry point found"});39 case.addError("", &[_][]const u8{"error: no entry point found"});
4040
41 // Incorrect return type41 // Incorrect return type
42 case.addError(42 case.addError(
...@@ -147,7 +147,7 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -147,7 +147,7 @@ pub fn addCases(ctx: *TestContext) !void {
147147
148 {148 {
149 var case = ctx.exe("hello world with updates", macosx_x64);149 var case = ctx.exe("hello world with updates", macosx_x64);
150 case.addError("", &[_][]const u8{"no entry point found"});150 case.addError("", &[_][]const u8{"error: no entry point found"});
151151
152 // Incorrect return type152 // Incorrect return type
153 case.addError(153 case.addError(
...@@ -1243,24 +1243,46 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -1243,24 +1243,46 @@ pub fn addCases(ctx: *TestContext) !void {
1243 \\}1243 \\}
1244 , &[_][]const u8{":3:9: error: redefinition of 'testing'"});1244 , &[_][]const u8{":3:9: error: redefinition of 'testing'"});
1245 }1245 }
1246 ctx.compileError("compileLog", linux_x64,1246
1247 \\export fn _start() noreturn {1247 {
1248 \\ const b = true;1248 // TODO make the test harness support checking the compile log output too
1249 \\ var f: u32 = 1;1249 var case = ctx.obj("@compileLog", linux_x64);
1250 \\ @compileLog(b, 20, f, x);1250 // The other compile error prevents emission of a "found compile log" statement.
1251 \\ @compileLog(1000);1251 case.addError(
1252 \\ var bruh: usize = true;1252 \\export fn _start() noreturn {
1253 \\ unreachable;1253 \\ const b = true;
1254 \\}1254 \\ var f: u32 = 1;
1255 \\fn x() void {}1255 \\ @compileLog(b, 20, f, x);
1256 , &[_][]const u8{1256 \\ @compileLog(1000);
1257 ":4:3: error: found compile log statement",1257 \\ var bruh: usize = true;
1258 ":5:3: error: found compile log statement",1258 \\ unreachable;
1259 ":6:21: error: expected usize, found bool",1259 \\}
1260 });1260 \\export fn other() void {
1261 // TODO if this is here it invalidates the compile error checker:1261 \\ @compileLog(1234);
1262 // "| true, 20, (runtime value), (function)"1262 \\}
1263 // "| 1000"1263 \\fn x() void {}
1264 , &[_][]const u8{
1265 ":6:23: error: expected usize, found bool",
1266 });
1267
1268 // Now only compile log statements remain. One per Decl.
1269 case.addError(
1270 \\export fn _start() noreturn {
1271 \\ const b = true;
1272 \\ var f: u32 = 1;
1273 \\ @compileLog(b, 20, f, x);
1274 \\ @compileLog(1000);
1275 \\ unreachable;
1276 \\}
1277 \\export fn other() void {
1278 \\ @compileLog(1234);
1279 \\}
1280 \\fn x() void {}
1281 , &[_][]const u8{
1282 ":11:8: error: found compile log statement",
1283 ":4:5: note: also here",
1284 });
1285 }
12641286
1265 {1287 {
1266 var case = ctx.obj("extern variable has no type", linux_x64);1288 var case = ctx.obj("extern variable has no type", linux_x64);