AstGen: handle ref_table for errdefer captures

Resolves: #15861
This commit is contained in:
mlugg 2023-05-31 01:03:05 +01:00 committed by Andrew Kelley
parent 77b40d6ecb
commit 1a4b0d9790
2 changed files with 43 additions and 1 deletions

View file

@ -2982,11 +2982,27 @@ fn deferStmt(
if (have_err_code) try gz.addDbgBlockEnd(); if (have_err_code) try gz.addDbgBlockEnd();
_ = try defer_gen.addBreak(.break_inline, 0, .void_value); _ = 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 = 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); const index = @intCast(u32, gz.astgen.extra.items.len);
try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_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); gz.astgen.appendBodyWithFixups(body);
const defer_scope = try block_arena.create(Scope.Defer); const defer_scope = try block_arena.create(Scope.Defer);

View file

@ -134,6 +134,32 @@ test "errdefer with payload" {
comptime try S.doTheTest(); 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" { 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_aarch64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO