authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-03-10 08:38:12+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-04-22 00:17:52+02:00
log36faf76fe1eeb3aafcc4de94fc83fd8ca3b18b25
tree2d733976d1e99f1add9d20bd4a2c2619effc550b
parentd4cac43d308ffa930cd7174567be7c1fe18e29fb

AstGen: add missing addRestoreErrRetIndex calls when handling for/while expr

Fixes #30912

2 files changed, 142 insertions(+), 0 deletions(-)

lib/std/zig/AstGen.zig+16
...@@ -6656,9 +6656,16 @@ fn whileExpr(...@@ -6656,9 +6656,16 @@ fn whileExpr(
6656 .operand = undefined,6656 .operand = undefined,
6657 } },6657 } },
6658 });6658 });
6659 if (!continue_scope.is_comptime) {
6660 _ = try continue_scope.addRestoreErrRetIndex(.{ .block = continue_block }, .always, then_node);
6661 }
6659 _ = try continue_scope.addBreak(break_tag, continue_block, .void_value);6662 _ = try continue_scope.addBreak(break_tag, continue_block, .void_value);
6660 }6663 }
6661 try continue_scope.setBlockBody(continue_block);6664 try continue_scope.setBlockBody(continue_block);
6665 if (!then_scope.is_comptime) {
6666 const cont_node = while_full.ast.cont_expr.unwrap() orelse then_node;
6667 _ = try then_scope.addRestoreErrRetIndex(.{ .block = cond_block }, .always, cont_node);
6668 }
6662 _ = try then_scope.addBreak(break_tag, cond_block, .void_value);6669 _ = try then_scope.addBreak(break_tag, cond_block, .void_value);
66636670
6664 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);6671 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
...@@ -6703,6 +6710,9 @@ fn whileExpr(...@@ -6703,6 +6710,9 @@ fn whileExpr(
67036710
6704 try checkUsed(parent_gz, &else_scope.base, sub_scope);6711 try checkUsed(parent_gz, &else_scope.base, sub_scope);
6705 if (!else_scope.endsWithNoReturn()) {6712 if (!else_scope.endsWithNoReturn()) {
6713 if (!else_scope.is_comptime) {
6714 _ = try else_scope.addRestoreErrRetIndex(.{ .block = loop_block }, .always, else_node);
6715 }
6706 _ = try else_scope.addBreakWithSrcNode(break_tag, loop_block, else_result, else_node);6716 _ = try else_scope.addBreakWithSrcNode(break_tag, loop_block, else_result, else_node);
6707 }6717 }
6708 } else {6718 } else {
...@@ -6973,6 +6983,9 @@ fn forExpr(...@@ -6973,6 +6983,9 @@ fn forExpr(
6973 });6983 });
69746984
6975 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";6985 const break_tag: Zir.Inst.Tag = if (is_inline) .break_inline else .@"break";
6986 if (!then_scope.is_comptime) {
6987 _ = try then_scope.addRestoreErrRetIndex(.{ .block = cond_block }, .always, then_node);
6988 }
6976 _ = try then_scope.addBreak(break_tag, cond_block, .void_value);6989 _ = try then_scope.addBreak(break_tag, cond_block, .void_value);
69776990
6978 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);6991 var else_scope = parent_gz.makeSubBlock(&cond_scope.base);
...@@ -6990,6 +7003,9 @@ fn forExpr(...@@ -6990,6 +7003,9 @@ fn forExpr(
6990 _ = try addEnsureResult(&else_scope, else_result, else_node);7003 _ = try addEnsureResult(&else_scope, else_result, else_node);
6991 }7004 }
6992 if (!else_scope.endsWithNoReturn()) {7005 if (!else_scope.endsWithNoReturn()) {
7006 if (!else_scope.is_comptime) {
7007 _ = try else_scope.addRestoreErrRetIndex(.{ .block = loop_block }, .always, else_node);
7008 }
6993 _ = try else_scope.addBreakWithSrcNode(break_tag, loop_block, else_result, else_node);7009 _ = try else_scope.addBreakWithSrcNode(break_tag, loop_block, else_result, else_node);
6994 }7010 }
6995 } else {7011 } else {
test/error_traces.zig+126
...@@ -92,6 +92,132 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target....@@ -92,6 +92,132 @@ pub fn addCases(cases: *@import("tests.zig").ErrorTracesContext, os: std.Target.
92 ,92 ,
93 });93 });
9494
95 cases.addCase(.{
96 .name = "for loop pops error return trace",
97 .source =
98 \\fn foo() !void { return error.FooError; }
99 \\
100 \\pub fn main() !void {
101 \\ for (0..2) |_| {
102 \\ const f = foo();
103 \\ f catch {};
104 \\ } else {
105 \\ const f = foo();
106 \\ f catch {};
107 \\ }
108 \\ return error.Stop;
109 \\}
110 ,
111 .expect_error = "Stop",
112 .expect_trace =
113 \\source.zig:11:5: [address] in main
114 \\ return error.Stop;
115 \\ ^
116 ,
117 .disable_trace_optimized = &.{
118 .{ .x86_64, .windows },
119 .{ .x86, .windows },
120 .{ .x86_64, .macos },
121 .{ .aarch64, .macos },
122 },
123 });
124
125 cases.addCase(.{
126 .name = "implicit continue in for loop pops stale error return trace",
127 .source =
128 \\fn foo() !void { return error.FooError; }
129 \\
130 \\pub fn main() !void {
131 \\ for (0..2) |i| {
132 \\ const f = foo();
133 \\ f catch {};
134 \\
135 \\ if (i == 1) return error.Stop;
136 \\ }
137 \\}
138 ,
139 .expect_error = "Stop",
140 .expect_trace =
141 \\source.zig:1:18: [address] in foo
142 \\fn foo() !void { return error.FooError; }
143 \\ ^
144 \\source.zig:8:21: [address] in main
145 \\ if (i == 1) return error.Stop;
146 \\ ^
147 ,
148 .disable_trace_optimized = &.{
149 .{ .x86_64, .windows },
150 .{ .x86, .windows },
151 .{ .x86_64, .macos },
152 .{ .aarch64, .macos },
153 },
154 });
155
156 cases.addCase(.{
157 .name = "while loop pops error return trace",
158 .source =
159 \\fn foo() !void { return error.FooError; }
160 \\
161 \\pub fn main() !void {
162 \\ var i: usize = 0;
163 \\ while (i < 2) {
164 \\ const f = foo();
165 \\ f catch {};
166 \\ i += 1;
167 \\ } else {
168 \\ const f = foo();
169 \\ f catch {};
170 \\ }
171 \\ return error.Stop;
172 \\}
173 ,
174 .expect_error = "Stop",
175 .expect_trace =
176 \\source.zig:13:5: [address] in main
177 \\ return error.Stop;
178 \\ ^
179 ,
180 .disable_trace_optimized = &.{
181 .{ .x86_64, .windows },
182 .{ .x86, .windows },
183 .{ .x86_64, .macos },
184 .{ .aarch64, .macos },
185 },
186 });
187
188 cases.addCase(.{
189 .name = "implicit continue in while loop pops stale error return trace",
190 .source =
191 \\fn foo() !void { return error.FooError; }
192 \\
193 \\pub fn main() !void {
194 \\ var i: usize = 0;
195 \\ while (i < 2) {
196 \\ const f = foo();
197 \\ f catch {};
198 \\
199 \\ if (i == 1) return error.Stop;
200 \\ i += 1;
201 \\ }
202 \\}
203 ,
204 .expect_error = "Stop",
205 .expect_trace =
206 \\source.zig:1:18: [address] in foo
207 \\fn foo() !void { return error.FooError; }
208 \\ ^
209 \\source.zig:9:21: [address] in main
210 \\ if (i == 1) return error.Stop;
211 \\ ^
212 ,
213 .disable_trace_optimized = &.{
214 .{ .x86_64, .windows },
215 .{ .x86, .windows },
216 .{ .x86_64, .macos },
217 .{ .aarch64, .macos },
218 },
219 });
220
95 cases.addCase(.{221 cases.addCase(.{
96 .name = "try return + handled catch/if-else",222 .name = "try return + handled catch/if-else",
97 .source =223 .source =