authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-12 22:02:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-12 22:02:44-07:00
log344dc0cc0ffcd32ffb07c43ca7123b8564f2a506
treebbe151e35981f21e26030494422e1958a43afac7
parent417b5b1daae800ef423f65154c40a513a73485e8

stage2: fix handling of "prev successful ZIR"

Before this change, the attempt to save the most recent successful ZIR code only worked in some cases; this reworks the code to be more robust, thereby fixing a crash when running the stage2 "enums" CBE test cases.

1 files changed, 52 insertions(+), 50 deletions(-)

src/Module.zig+52-50
...@@ -2428,13 +2428,21 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2428,13 +2428,21 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
24282428
2429 mod.lockAndClearFileCompileError(file);2429 mod.lockAndClearFileCompileError(file);
24302430
2431 // Move previous ZIR to a local variable so we can compare it with the new one.2431 // If the previous ZIR does not have compile errors, keep it around
2432 var prev_zir = file.zir;2432 // in case parsing or new ZIR fails. In case of successful ZIR update
2433 var prev_zir_loaded = file.zir_loaded;2433 // at the end of this function we will free it.
2434 file.zir_loaded = false;2434 // We keep the previous ZIR loaded so that we can use it
2435 file.zir = undefined;2435 // for the update next time it does not have any compile errors. This avoids
2436 defer if (prev_zir_loaded) prev_zir.deinit(gpa);2436 // needlessly tossing out semantic analysis work when an error is
24372437 // temporarily introduced.
2438 if (file.zir_loaded and !file.zir.hasCompileErrors()) {
2439 assert(file.prev_zir == null);
2440 const prev_zir_ptr = try gpa.create(Zir);
2441 file.prev_zir = prev_zir_ptr;
2442 prev_zir_ptr.* = file.zir;
2443 file.zir = undefined;
2444 file.zir_loaded = false;
2445 }
2438 file.unload(gpa);2446 file.unload(gpa);
24392447
2440 if (stat.size > std.math.maxInt(u32))2448 if (stat.size > std.math.maxInt(u32))
...@@ -2546,7 +2554,17 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2546,7 +2554,17 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2546 });2554 });
2547 };2555 };
25482556
2549 if (prev_zir_loaded) {2557 if (file.zir.hasCompileErrors()) {
2558 {
2559 const lock = comp.mutex.acquire();
2560 defer lock.release();
2561 try mod.failed_files.putNoClobber(gpa, file, null);
2562 }
2563 file.status = .astgen_failure;
2564 return error.AnalysisFail;
2565 }
2566
2567 if (file.prev_zir) |prev_zir| {
2550 // Iterate over all Namespace objects contained within this File, looking at the2568 // Iterate over all Namespace objects contained within this File, looking at the
2551 // previous and new ZIR together and update the references to point2569 // previous and new ZIR together and update the references to point
2552 // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace2570 // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace
...@@ -2555,47 +2573,19 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node...@@ -2555,47 +2573,19 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node
2555 // We do not need to hold any locks at this time because all the Decl and Namespace2573 // We do not need to hold any locks at this time because all the Decl and Namespace
2556 // objects being touched are specific to this File, and the only other concurrent2574 // objects being touched are specific to this File, and the only other concurrent
2557 // tasks are touching other File objects.2575 // tasks are touching other File objects.
2558 if (file.zir.hasCompileErrors()) {2576 try updateZirRefs(gpa, file, prev_zir.*);
2559 // In this case, we keep the previous ZIR loaded so that we can use it
2560 // for the update next time it does not have any compile errors. This avoids
2561 // needlessly tossing out semantic analysis work when a ZIR error is
2562 // temporarily introduced.
2563 if (!prev_zir.hasCompileErrors()) {
2564 assert(file.prev_zir == null);
2565 const prev_zir_ptr = try gpa.create(Zir);
2566 file.prev_zir = prev_zir_ptr;
2567 prev_zir_ptr.* = prev_zir;
2568 prev_zir_loaded = false;
2569 }
2570 } else if (prev_zir.hasCompileErrors()) {
2571 if (file.prev_zir) |file_prev_zir| {
2572 prev_zir.deinit(gpa);
2573 prev_zir = file_prev_zir.*;
2574 gpa.destroy(file_prev_zir);
2575 file.prev_zir = null;
2576 try updateZirRefs(gpa, file, prev_zir);
2577 } else if (file.root_decl) |root_decl| {
2578 // First time the File has succeeded ZIR. We must mark it outdated since
2579 // we have already tried to semantically analyze it.
2580 try file.outdated_decls.resize(gpa, 1);
2581 file.outdated_decls.items[0] = root_decl;
2582 }
2583 } else {
2584 try updateZirRefs(gpa, file, prev_zir);
2585 }
2586 // At this point, `file.outdated_decls` and `file.deleted_decls` are populated,2577 // At this point, `file.outdated_decls` and `file.deleted_decls` are populated,
2587 // and semantic analysis will deal with them properly.2578 // and semantic analysis will deal with them properly.
2588 }2579 // No need to keep previous ZIR.
25892580 prev_zir.deinit(gpa);
2590 // TODO don't report compile errors until Sema @importFile2581 gpa.destroy(prev_zir);
2591 if (file.zir.hasCompileErrors()) {2582 file.prev_zir = null;
2592 {2583 } else if (file.root_decl) |root_decl| {
2593 const lock = comp.mutex.acquire();2584 // This is an update, but it is the first time the File has succeeded
2594 defer lock.release();2585 // ZIR. We must mark it outdated since we have already tried to
2595 try mod.failed_files.putNoClobber(gpa, file, null);2586 // semantically analyze it.
2596 }2587 try file.outdated_decls.resize(gpa, 1);
2597 file.status = .astgen_failure;2588 file.outdated_decls.items[0] = root_decl;
2598 return error.AnalysisFail;
2599 }2589 }
2600}2590}
26012591
...@@ -2640,14 +2630,26 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {...@@ -2640,14 +2630,26 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void {
2640 // Anonymous decls should not be marked outdated. They will be re-generated2630 // Anonymous decls should not be marked outdated. They will be re-generated
2641 // if their owner decl is marked outdated.2631 // if their owner decl is marked outdated.
2642 if (decl.zir_decl_index != 0) {2632 if (decl.zir_decl_index != 0) {
2643 const old_hash = decl.contentsHashZir(old_zir);2633 const old_zir_decl_index = decl.zir_decl_index;
2644 decl.zir_decl_index = extra_map.get(decl.zir_decl_index) orelse {2634 const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse {
2635 log.debug("updateZirRefs {s}: delete {*} ({s})", .{
2636 file.sub_file_path, decl, decl.name,
2637 });
2645 try file.deleted_decls.append(gpa, decl);2638 try file.deleted_decls.append(gpa, decl);
2646 continue;2639 continue;
2647 };2640 };
2641 const old_hash = decl.contentsHashZir(old_zir);
2642 decl.zir_decl_index = new_zir_decl_index;
2648 const new_hash = decl.contentsHashZir(new_zir);2643 const new_hash = decl.contentsHashZir(new_zir);
2649 if (!std.zig.srcHashEql(old_hash, new_hash)) {2644 if (!std.zig.srcHashEql(old_hash, new_hash)) {
2645 log.debug("updateZirRefs {s}: outdated {*} ({s}) {d} => {d}", .{
2646 file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index,
2647 });
2650 try file.outdated_decls.append(gpa, decl);2648 try file.outdated_decls.append(gpa, decl);
2649 } else {
2650 log.debug("updateZirRefs {s}: unchanged {*} ({s}) {d} => {d}", .{
2651 file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index,
2652 });
2651 }2653 }
2652 }2654 }
26532655
...@@ -3376,7 +3378,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo...@@ -3376,7 +3378,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo
3376 }3378 }
3377 gpa.free(decl_name);3379 gpa.free(decl_name);
3378 const decl = gop.entry.value;3380 const decl = gop.entry.value;
3379 log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl_name, namespace });3381 log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl.name, namespace });
3380 // Update the AST node of the decl; even if its contents are unchanged, it may3382 // Update the AST node of the decl; even if its contents are unchanged, it may
3381 // have been re-ordered.3383 // have been re-ordered.
3382 const prev_src_node = decl.src_node;3384 const prev_src_node = decl.src_node;