From b21becb2a6a82b4ac65e98fa0094a7786cbbfdc3 Mon Sep 17 00:00:00 2001 From: mlugg Date: Wed, 5 Feb 2025 21:58:32 +0000 Subject: [PATCH] incremental: fix crash when introducing syntax error Clearing the analysis roots was very clever and all, but not actually valid. We need to avoid *any* reference to the analysis errors if there were any fatal files, and that includes sorting the errors! Resolves: #22774 --- src/Compilation.zig | 10 +++-- src/Zcu.zig | 2 + .../analysis_error_and_syntax_error | 42 +++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 test/incremental/analysis_error_and_syntax_error diff --git a/src/Compilation.zig b/src/Compilation.zig index 14c216854e..0062465ae4 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2195,6 +2195,8 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void { zcu.compile_log_text.shrinkAndFree(gpa, 0); + zcu.skip_analysis_errors = false; + // Make sure std.zig is inside the import_table. We unconditionally need // it for start.zig. const std_mod = zcu.std_mod; @@ -3207,7 +3209,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { }); } - if (comp.zcu) |zcu| { + if (comp.zcu) |zcu| zcu_errors: { for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| { if (error_msg) |msg| { try addModuleErrorMsg(zcu, &bundle, msg.*); @@ -3224,6 +3226,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { } } } + if (zcu.skip_analysis_errors) break :zcu_errors; var sorted_failed_analysis: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: { const SortOrder = struct { zcu: *Zcu, @@ -3359,7 +3362,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { try comp.link_diags.addMessagesToBundle(&bundle, comp.bin_file); if (comp.zcu) |zcu| { - if (bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) { + if (!zcu.skip_analysis_errors and bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) { const values = zcu.compile_log_sources.values(); // First one will be the error; subsequent ones will be notes. const src_loc = values[0].src(); @@ -3860,10 +3863,9 @@ fn performAllTheWorkInner( // We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents // us from invalidating lots of incremental dependencies due to files with e.g. parse errors. // However, this means our analysis data is invalid, so we want to omit all analysis errors. - // To do that, let's just clear the analysis roots! assert(zcu.failed_files.count() > 0); // we will get an error - zcu.analysis_roots.clear(); // no analysis happened + zcu.skip_analysis_errors = true; return; } diff --git a/src/Zcu.zig b/src/Zcu.zig index 9b292ad783..c870a04adf 100644 --- a/src/Zcu.zig +++ b/src/Zcu.zig @@ -181,6 +181,8 @@ analysis_roots: std.BoundedArray(*Package.Module, 3) = .{}, /// Allocated into `gpa`. resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null, +skip_analysis_errors: bool = false, + stage1_flags: packed struct { have_winmain: bool = false, have_wwinmain: bool = false, diff --git a/test/incremental/analysis_error_and_syntax_error b/test/incremental/analysis_error_and_syntax_error new file mode 100644 index 0000000000..05d899a225 --- /dev/null +++ b/test/incremental/analysis_error_and_syntax_error @@ -0,0 +1,42 @@ +#target=x86_64-linux-selfhosted +#target=x86_64-linux-cbe +#target=x86_64-windows-cbe +#target=wasm32-wasi-selfhosted +#update=initial version +#file=main.zig +pub fn main() !void { + @compileError("uh oh"); +} +#expect_error=main.zig:2:5: error: uh oh + +#update=add parse error +#file=main.zig +pub fn main() !void { + @compileError("uh oh"); +#expect_error=main.zig:3:1: error: expected statement, found 'EOF' + +#update=fix parse error +#file=main.zig +pub fn main() !void { + @compileError("uh oh"); +} +#expect_error=main.zig:2:5: error: uh oh + +#update=add parse error again +#file=main.zig +pub fn main() !void { + @compileError("uh oh"); +#expect_error=main.zig:3:1: error: expected statement, found 'EOF' + +#update=comment @compileError call +#file=main.zig +pub fn main() !void { + //@compileError("uh oh"); +#expect_error=main.zig:3:1: error: expected statement, found 'EOF' + +#update=fix parse error again +#file=main.zig +pub fn main() !void { + //@compileError("uh oh"); +} +#expect_stdout=""