commit 36faf76fe1eeb3aafcc4de94fc83fd8ca3b18b25 (tree)
parent d4cac43d308ffa930cd7174567be7c1fe18e29fb
Author: Pavel Verigo <paul.verigo@gmail.com>
Date: Tue, 10 Mar 2026 08:38:12 +0100
AstGen: add missing addRestoreErrRetIndex calls when handling for/while expr
Fixes #30912
Diffstat:
2 files changed, 142 insertions(+), 0 deletions(-)
diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig
@@ -6656,9 +6656,16 @@ fn whileExpr(
.operand = undefined,
} },
});
+ if (!continue_scope.is_comptime) {
+ _ = try continue_scope.addRestoreErrRetIndex(.{ .block = continue_block }, .always, then_node);
+ }
_ = try continue_scope.addBreak(break_tag, continue_block, .void_value);
}
try continue_scope.setBlockBody(continue_block);
+ if (!then_scope.is_comptime) {
+ const cont_node = while_full.ast.cont_expr.unwrap() orelse then_node;
+ _ = try then_scope.addRestoreErrRetIndex(.{ .block = cond_block }, .always, cont_node);
+ }
_ = try then_scope.addBreak(break_tag, cond_block, .void_value);
var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
@@ -6703,6 +6710,9 @@ fn whileExpr(
try checkUsed(parent_gz, &else_scope.base, sub_scope);
if (!else_scope.endsWithNoReturn()) {
+ if (!else_scope.is_comptime) {
+ _ = try else_scope.addRestoreErrRetIndex(.{ .block = loop_block }, .always, else_node);
+ }
_ = try else_scope.addBreakWithSrcNode(break_tag, loop_block, else_result, else_node);
}
} else {
@@ -6973,6 +6983,9 @@ fn forExpr(
});
const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
+ if (!then_scope.is_comptime) {
+ _ = try then_scope.addRestoreErrRetIndex(.{ .block = cond_block }, .always, then_node);
+ }
_ = try then_scope.addBreak(break_tag, cond_block, .void_value);
var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
@@ -6990,6 +7003,9 @@ fn forExpr(
_ = try addEnsureResult(&else_scope, else_result, else_node);
}
if (!else_scope.endsWithNoReturn()) {
+ if (!else_scope.is_comptime) {
+ _ = try else_scope.addRestoreErrRetIndex(.{ .block = loop_block }, .always, else_node);
+ }
_ = try else_scope.addBreakWithSrcNode(break_tag, loop_block, else_result, else_node);
}
} else {
diff --git a/test/error_traces.zig b/test/error_traces.zig
@@ -93,6 +93,132 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
});
cases.addCase(.{
+ .name = "for loop pops error return trace",
+ .source =
+ \\fn foo() !void { return error.FooError; }
+ \\
+ \\pub fn main() !void {
+ \\ for (0..2) |_| {
+ \\ const f = foo();
+ \\ f catch {};
+ \\ } else {
+ \\ const f = foo();
+ \\ f catch {};
+ \\ }
+ \\ return error.Stop;
+ \\}
+ ,
+ .expect_error = "Stop",
+ .expect_trace =
+ \\source.zig:11:5: [address] in main
+ \\ return error.Stop;
+ \\ ^
+ ,
+ .disable_trace_optimized = &.{
+ .{ .x86_64, .windows },
+ .{ .x86, .windows },
+ .{ .x86_64, .macos },
+ .{ .aarch64, .macos },
+ },
+ });
+
+ cases.addCase(.{
+ .name = "implicit continue in for loop pops stale error return trace",
+ .source =
+ \\fn foo() !void { return error.FooError; }
+ \\
+ \\pub fn main() !void {
+ \\ for (0..2) |i| {
+ \\ const f = foo();
+ \\ f catch {};
+ \\
+ \\ if (i == 1) return error.Stop;
+ \\ }
+ \\}
+ ,
+ .expect_error = "Stop",
+ .expect_trace =
+ \\source.zig:1:18: [address] in foo
+ \\fn foo() !void { return error.FooError; }
+ \\ ^
+ \\source.zig:8:21: [address] in main
+ \\ if (i == 1) return error.Stop;
+ \\ ^
+ ,
+ .disable_trace_optimized = &.{
+ .{ .x86_64, .windows },
+ .{ .x86, .windows },
+ .{ .x86_64, .macos },
+ .{ .aarch64, .macos },
+ },
+ });
+
+ cases.addCase(.{
+ .name = "while loop pops error return trace",
+ .source =
+ \\fn foo() !void { return error.FooError; }
+ \\
+ \\pub fn main() !void {
+ \\ var i: usize = 0;
+ \\ while (i < 2) {
+ \\ const f = foo();
+ \\ f catch {};
+ \\ i += 1;
+ \\ } else {
+ \\ const f = foo();
+ \\ f catch {};
+ \\ }
+ \\ return error.Stop;
+ \\}
+ ,
+ .expect_error = "Stop",
+ .expect_trace =
+ \\source.zig:13:5: [address] in main
+ \\ return error.Stop;
+ \\ ^
+ ,
+ .disable_trace_optimized = &.{
+ .{ .x86_64, .windows },
+ .{ .x86, .windows },
+ .{ .x86_64, .macos },
+ .{ .aarch64, .macos },
+ },
+ });
+
+ cases.addCase(.{
+ .name = "implicit continue in while loop pops stale error return trace",
+ .source =
+ \\fn foo() !void { return error.FooError; }
+ \\
+ \\pub fn main() !void {
+ \\ var i: usize = 0;
+ \\ while (i < 2) {
+ \\ const f = foo();
+ \\ f catch {};
+ \\
+ \\ if (i == 1) return error.Stop;
+ \\ i += 1;
+ \\ }
+ \\}
+ ,
+ .expect_error = "Stop",
+ .expect_trace =
+ \\source.zig:1:18: [address] in foo
+ \\fn foo() !void { return error.FooError; }
+ \\ ^
+ \\source.zig:9:21: [address] in main
+ \\ if (i == 1) return error.Stop;
+ \\ ^
+ ,
+ .disable_trace_optimized = &.{
+ .{ .x86_64, .windows },
+ .{ .x86, .windows },
+ .{ .x86_64, .macos },
+ .{ .aarch64, .macos },
+ },
+ });
+
+ cases.addCase(.{
.name = "try return + handled catch/if-else",
.source =
\\fn foo() !void {