authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-10-21 16:33:39+01:00
committergravatar for alex@alexrp.comAlex Rønne Petersen <alex@alexrp.com> 2026-10-23 02:16:33+02:00
log5382c84ed22519a600642f5cf3b1d8c2769050d6
tree2d11defb265047506e0c8a941d81a982809941fa
parent1bb9a9dafa1f7961e6bf7cf66bcf1a425eedc07e
signature Signed by SSH key SHA256:7B/LJ7bpR1eX8aCXSr4mtd5M45VMPKcx9zY8e95b5QM

AstGen: error on tag capture in `else` prong of `switch`

Resolves: https://codeberg.org/ziglang/zig/issues/37325

4 files changed, 23 insertions(+), 4 deletions(-)

lib/std/zig/AstGen.zig+6
...@@ -7731,6 +7731,12 @@ fn switchExpr(...@@ -7731,6 +7731,12 @@ fn switchExpr(
7731 const tag_name = try astgen.identAsString(tag_token);7731 const tag_name = try astgen.identAsString(tag_token);
7732 try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture");7732 try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture");
77337733
7734 if (case_node.toOptional() == else_case_node and case.inline_token == null) {
7735 return astgen.failTokNotes(tag_token, "cannot capture tag of 'else' prong", .{}, &.{
7736 try astgen.errNoteTok(ident, "first capture in 'else' prong always captures 'switch' operand", .{}),
7737 });
7738 }
7739
7734 assert(any_has_tag_capture);7740 assert(any_has_tag_capture);
7735 has_tag_capture = true;7741 has_tag_capture = true;
77367742
test/behavior/switch.zig+1-2
...@@ -1186,8 +1186,7 @@ test "switch with tag capture" {...@@ -1186,8 +1186,7 @@ test "switch with tag capture" {
1186 _ = &tag;1186 _ = &tag;
1187 comptime unreachable;1187 comptime unreachable;
1188 },1188 },
1189 else => |un, tag| {1189 else => |un| {
1190 try expect(tag == .c);
1191 try expect(un == .c);1190 try expect(un == .c);
1192 try expect(un.c == 0xFF);1191 try expect(un.c == 0xFF);
1193 },1192 },
test/behavior/switch_loop.zig+1-2
...@@ -416,8 +416,7 @@ test "switch loop with tag capture" {...@@ -416,8 +416,7 @@ test "switch loop with tag capture" {
416 _ = &tag;416 _ = &tag;
417 return error.AnalyzedNoreturnProng;417 return error.AnalyzedNoreturnProng;
418 },418 },
419 else => |un, tag| {419 else => |un| {
420 try expect(tag == .c);
421 try expect(un == .c);420 try expect(un == .c);
422 if (un.c == 0xFF) continue :label .a;421 if (un.c == 0xFF) continue :label .a;
423 if (un.c == 0x00) break :label false;422 if (un.c == 0x00) break :label false;
test/cases/compile_errors/tag_capture_in_else_prong.zig created+15
...@@ -0,0 +1,15 @@
1const Foo = union(enum) { a: u32, b: u32 };
2export fn entry() void {
3 const foo: Foo = .{ .a = 123 };
4 switch (foo) {
5 else => |payload, tag| {
6 _ = payload;
7 _ = tag;
8 },
9 }
10}
11
12// error
13//
14// :5:27: error: cannot capture tag of 'else' prong
15// :5:18: note: first capture in 'else' prong always captures 'switch' operand