diff --git a/src/AstGen.zig b/src/AstGen.zig index 9ed6be87ba..f8bb24c14d 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2982,11 +2982,27 @@ fn deferStmt( if (have_err_code) try gz.addDbgBlockEnd(); _ = try defer_gen.addBreak(.break_inline, 0, .void_value); + // We must handle ref_table for remapped_err_code manually. const body = defer_gen.instructionsSlice(); - const body_len = gz.astgen.countBodyLenAfterFixups(body); + const body_len = blk: { + var refs: u32 = 0; + if (have_err_code) { + var cur_inst = remapped_err_code; + while (gz.astgen.ref_table.get(cur_inst)) |ref_inst| { + refs += 1; + cur_inst = ref_inst; + } + } + break :blk gz.astgen.countBodyLenAfterFixups(body) + refs; + }; const index = @intCast(u32, gz.astgen.extra.items.len); try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_len); + if (have_err_code) { + if (gz.astgen.ref_table.fetchRemove(remapped_err_code)) |kv| { + gz.astgen.appendPossiblyRefdBodyInst(&gz.astgen.extra, kv.value); + } + } gz.astgen.appendBodyWithFixups(body); const defer_scope = try block_arena.create(Scope.Defer); diff --git a/test/behavior/defer.zig b/test/behavior/defer.zig index c97350cd75..8e97425c5e 100644 --- a/test/behavior/defer.zig +++ b/test/behavior/defer.zig @@ -134,6 +134,32 @@ test "errdefer with payload" { comptime try S.doTheTest(); } +test "reference to errdefer payload" { + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO + + const S = struct { + fn foo() !i32 { + errdefer |a| { + const ptr = &a; + const ptr2 = &ptr; + expectEqual(error.One, ptr2.*.*) catch @panic("test failure"); + expectEqual(error.One, ptr.*) catch @panic("test failure"); + } + return error.One; + } + fn doTheTest() !void { + try expectError(error.One, foo()); + } + }; + try S.doTheTest(); + comptime try S.doTheTest(); +} + test "simple else prong doesn't emit an error for unreachable else prong" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO