From 5382c84ed22519a600642f5cf3b1d8c2769050d6 Mon Sep 17 00:00:00 2001 From: Matthew Lugg Date: Wed, 21 Oct 2026 16:33:39 +0100 Subject: [PATCH] AstGen: error on tag capture in `else` prong of `switch` Resolves: https://codeberg.org/ziglang/zig/issues/37325 --- lib/std/zig/AstGen.zig | 6 ++++++ test/behavior/switch.zig | 3 +-- test/behavior/switch_loop.zig | 3 +-- .../compile_errors/tag_capture_in_else_prong.zig | 15 +++++++++++++++ 4 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 test/cases/compile_errors/tag_capture_in_else_prong.zig diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index fd6e48314901787bedbf74ba8118af6b7b09de36..0ca2397a64bced3b64f6781732296f7956c7c7db 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -7731,6 +7731,12 @@ fn switchExpr( const tag_name = try astgen.identAsString(tag_token); try astgen.detectLocalShadowing(payload_sub_scope, tag_name, tag_token, tag_slice, .@"switch tag capture"); + if (case_node.toOptional() == else_case_node and case.inline_token == null) { + return astgen.failTokNotes(tag_token, "cannot capture tag of 'else' prong", .{}, &.{ + try astgen.errNoteTok(ident, "first capture in 'else' prong always captures 'switch' operand", .{}), + }); + } + assert(any_has_tag_capture); has_tag_capture = true; diff --git a/test/behavior/switch.zig b/test/behavior/switch.zig index 25eb5159357c06134f6b8e2f3fa5276528b7d4c4..8631be2150679ef66aaf6f53d4ad98eb5f9bcd9f 100644 --- a/test/behavior/switch.zig +++ b/test/behavior/switch.zig @@ -1186,8 +1186,7 @@ test "switch with tag capture" { _ = &tag; comptime unreachable; }, - else => |un, tag| { - try expect(tag == .c); + else => |un| { try expect(un == .c); try expect(un.c == 0xFF); }, diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index f45ef3ef4113b493fc434f75ba1fe5c6a0111945..6169baef0e02039e042576bae568066668a16138 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -416,8 +416,7 @@ test "switch loop with tag capture" { _ = &tag; return error.AnalyzedNoreturnProng; }, - else => |un, tag| { - try expect(tag == .c); + else => |un| { try expect(un == .c); if (un.c == 0xFF) continue :label .a; if (un.c == 0x00) break :label false; diff --git a/test/cases/compile_errors/tag_capture_in_else_prong.zig b/test/cases/compile_errors/tag_capture_in_else_prong.zig new file mode 100644 index 0000000000000000000000000000000000000000..3b32d49bc6737de25a5a8fce924f64a0dcbd938f --- /dev/null +++ b/test/cases/compile_errors/tag_capture_in_else_prong.zig @@ -0,0 +1,15 @@ +const Foo = union(enum) { a: u32, b: u32 }; +export fn entry() void { + const foo: Foo = .{ .a = 123 }; + switch (foo) { + else => |payload, tag| { + _ = payload; + _ = tag; + }, + } +} + +// error +// +// :5:27: error: cannot capture tag of 'else' prong +// :5:18: note: first capture in 'else' prong always captures 'switch' operand -- 2.54.0