diff --git a/lib/std/testing.zig b/lib/std/testing.zig index 03e1d06c1894c3a01ae60b21d1c007ce41b0fa9d..24287f65aae647f217a5726c3d52c223e83889b2 100644 --- a/lib/std/testing.zig +++ b/lib/std/testing.zig @@ -813,7 +813,7 @@ fn expectEqualDeepInner(comptime T: type, expected: T, actual: T) error{TestExpe } }, - .array => |_| { + .array => { if (expected.len != actual.len) { print("Array len not the same, expected {d}, found {d}\n", .{ expected.len, actual.len }); return error.TestExpectedEqual; diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index 2a6423a60d1ce2455eba0b3933400ca107e87522..38fa5f84d71f8810620f899ba34674b9639475c2 100644 --- a/lib/std/zig/AstGen.zig +++ b/lib/std/zig/AstGen.zig @@ -7882,8 +7882,10 @@ fn switchExpr( var payload_sub_scope: *Scope = undefined; if (mem.eql(u8, ident_slice, "_")) { if (capture_is_ref) { + // |*_, tag| is invalid, so we can fail early return astgen.failTok(payload_token, "pointer modifier invalid on discard", .{}); } + capture = .none; payload_sub_scope = &case_scope.base; } else { const capture_name = try astgen.identAsString(ident); @@ -7903,11 +7905,15 @@ fn switchExpr( const tag_token = if (tree.tokenTag(ident + 1) == .comma) ident + 2 - else - break :blk payload_sub_scope; + else if (capture == .none) { + // discarding the capture is only valid iff the tag is captured + // whether the tag capture is discarded is handled below + return astgen.failTok(payload_token, "discard of capture; omit it instead", .{}); + } else break :blk payload_sub_scope; + const tag_slice = tree.tokenSlice(tag_token); if (mem.eql(u8, tag_slice, "_")) { - try astgen.appendErrorTok(tag_token, "discard of tag capture; omit it instead", .{}); + return astgen.failTok(tag_token, "discard of tag capture; omit it instead", .{}); } else if (case.inline_token == null) { return astgen.failTok(tag_token, "tag capture on non-inline prong", .{}); } diff --git a/src/Sema.zig b/src/Sema.zig index 63e923ad19f5de4ff9109842cbe0b000c32b8c56..88e70ff8892e8cd9ce1f274b73836e15c6e5ac92 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -11546,7 +11546,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r }); } try sema.validateRuntimeValue(block, operand_src, maybe_ptr); - const operand_alloc = if (extra.data.bits.any_non_inline_capture) a: { + const operand_alloc = if (extra.data.bits.any_non_inline_capture or + extra.data.bits.any_has_tag_capture) + a: { const operand_ptr_ty = try pt.singleMutPtrType(sema.typeOf(maybe_ptr)); const operand_alloc = try block.addTy(.alloc, operand_ptr_ty); _ = try block.addBinOp(.store, operand_alloc, maybe_ptr); diff --git a/test/behavior/switch_loop.zig b/test/behavior/switch_loop.zig index 8dfbf9775c27c8b92193a9436dead75c6ea660fa..0df338334234c9f0cf48d80485950c587f323df9 100644 --- a/test/behavior/switch_loop.zig +++ b/test/behavior/switch_loop.zig @@ -270,3 +270,30 @@ test "switch loop on non-exhaustive enum" { try S.doTheTest(); try comptime S.doTheTest(); } + +test "switch loop with discarded tag capture" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; + + const S = struct { + const U = union(enum) { + a: u32, + b: u32, + c: u32, + }; + + fn doTheTest() void { + const a: U = .{ .a = 10 }; + blk: switch (a) { + inline .b => |_, tag| { + _ = tag; + continue :blk .{ .c = 20 }; + }, + else => {}, + } + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} diff --git a/test/cases/compile_errors/switch_loop_discarded_capture.zig b/test/cases/compile_errors/switch_loop_discarded_capture.zig new file mode 100644 index 0000000000000000000000000000000000000000..bca1d9e85c3b5a49dfb50168a608458071780141 --- /dev/null +++ b/test/cases/compile_errors/switch_loop_discarded_capture.zig @@ -0,0 +1,16 @@ +export fn foo() void { + const S = struct { + fn doTheTest() void { + blk: switch (@as(u8, 'a')) { + '1' => |_| continue :blk '1', + else => {}, + } + } + }; + S.doTheTest(); + comptime S.doTheTest(); +} + +// error +// +// :5:25: error: discard of capture; omit it instead