authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-12 16:11:18-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-12 16:11:18-07:00
log011663eea590dddff79b73c72bfeda5dd7f947cc
treec51299eb6d22d3762674540de062d7e4723c9a92
parent01e89fec71c781113f4be6f65af8e1702c8dde7c
parente323cf1264f390911dcc2efea71d46be1d631d92

Merge remote-tracking branch 'origin/master' into llvm15


9 files changed, 261 insertions(+), 148 deletions(-)

doc/langref.html.in-5
......@@ -5700,7 +5700,6 @@ fn bar() !void {
57005700 try quux();
57015701 } else |err| switch (err) {
57025702 error.FileNotFound => try hello(),
5703 else => try another(),
57045703 }
57055704}
57065705
......@@ -5716,10 +5715,6 @@ fn hello() !void {
57165715 try bang2();
57175716}
57185717
5719fn another() !void {
5720 try bang1();
5721}
5722
57235718fn bang1() !void {
57245719 return error.FileNotFound;
57255720}
src/AstGen.zig+134-138
......@@ -135,7 +135,6 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
135135 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
136136 var gen_scope: GenZir = .{
137137 .force_comptime = true,
138 .in_defer = false,
139138 .parent = &top_scope.base,
140139 .anon_name_strategy = .parent,
141140 .decl_node_index = 0,
......@@ -1856,6 +1855,16 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
18561855 .gen_zir => {
18571856 const block_gz = scope.cast(GenZir).?;
18581857
1858 if (block_gz.cur_defer_node != 0) {
1859 return astgen.failNodeNotes(node, "cannot break out of defer expression", .{}, &.{
1860 try astgen.errNoteNode(
1861 block_gz.cur_defer_node,
1862 "defer expression here",
1863 .{},
1864 ),
1865 });
1866 }
1867
18591868 const block_inst = blk: {
18601869 if (break_label != 0) {
18611870 if (block_gz.label) |*label| {
......@@ -1919,17 +1928,6 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
19191928 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
19201929 .namespace => break,
19211930 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
1922 .defer_gen => {
1923 const defer_gen = scope.cast(Scope.DeferGen).?;
1924
1925 return astgen.failNodeNotes(node, "cannot break out of defer expression", .{}, &.{
1926 try astgen.errNoteNode(
1927 defer_gen.defer_node,
1928 "defer expression here",
1929 .{},
1930 ),
1931 });
1932 },
19331931 .top => unreachable,
19341932 }
19351933 }
......@@ -1953,6 +1951,16 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
19531951 switch (scope.tag) {
19541952 .gen_zir => {
19551953 const gen_zir = scope.cast(GenZir).?;
1954
1955 if (gen_zir.cur_defer_node != 0) {
1956 return astgen.failNodeNotes(node, "cannot continue out of defer expression", .{}, &.{
1957 try astgen.errNoteNode(
1958 gen_zir.cur_defer_node,
1959 "defer expression here",
1960 .{},
1961 ),
1962 });
1963 }
19561964 const continue_block = gen_zir.continue_block;
19571965 if (continue_block == 0) {
19581966 scope = gen_zir.parent;
......@@ -1985,21 +1993,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
19851993 .defer_normal => {
19861994 const defer_scope = scope.cast(Scope.Defer).?;
19871995 scope = defer_scope.parent;
1988 const expr_node = node_datas[defer_scope.defer_node].rhs;
1989 try unusedResultDeferExpr(parent_gz, defer_scope, defer_scope.parent, expr_node);
1996 try parent_gz.addDefer(defer_scope.index, defer_scope.len);
19901997 },
19911998 .defer_error => scope = scope.cast(Scope.Defer).?.parent,
1992 .defer_gen => {
1993 const defer_gen = scope.cast(Scope.DeferGen).?;
1994
1995 return astgen.failNodeNotes(node, "cannot continue out of defer expression", .{}, &.{
1996 try astgen.errNoteNode(
1997 defer_gen.defer_node,
1998 "defer expression here",
1999 .{},
2000 ),
2001 });
2002 },
20031999 .namespace => break,
20042000 .top => unreachable,
20052001 }
......@@ -2064,7 +2060,6 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke
20642060 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
20652061 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
20662062 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2067 .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent,
20682063 .namespace => break,
20692064 .top => unreachable,
20702065 }
......@@ -2208,8 +2203,8 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
22082203 .simple_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.simpleVarDecl(statement)),
22092204 .aligned_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.alignedVarDecl(statement)),
22102205
2211 .@"defer" => scope = try makeDeferScope(gz.astgen, scope, statement, block_arena_allocator, .defer_normal),
2212 .@"errdefer" => scope = try makeDeferScope(gz.astgen, scope, statement, block_arena_allocator, .defer_error),
2206 .@"defer" => scope = try deferStmt(gz, scope, statement, block_arena_allocator, .defer_normal),
2207 .@"errdefer" => scope = try deferStmt(gz, scope, statement, block_arena_allocator, .defer_error),
22132208
22142209 .assign => try assign(gz, scope, statement),
22152210
......@@ -2253,28 +2248,6 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
22532248 try checkUsed(gz, parent_scope, scope);
22542249}
22552250
2256fn unusedResultDeferExpr(gz: *GenZir, defer_scope: *Scope.Defer, expr_scope: *Scope, expr_node: Ast.Node.Index) InnerError!void {
2257 const astgen = gz.astgen;
2258 const prev_offset = astgen.source_offset;
2259 const prev_line = astgen.source_line;
2260 const prev_column = astgen.source_column;
2261 defer {
2262 astgen.source_offset = prev_offset;
2263 astgen.source_line = prev_line;
2264 astgen.source_column = prev_column;
2265 }
2266 astgen.source_offset = defer_scope.source_offset;
2267 astgen.source_line = defer_scope.source_line;
2268 astgen.source_column = defer_scope.source_column;
2269
2270 var defer_gen: Scope.DeferGen = .{
2271 .parent = expr_scope,
2272 .defer_node = defer_scope.defer_node,
2273 };
2274
2275 _ = try unusedResultExpr(gz, &defer_gen.base, expr_node);
2276}
2277
22782251/// Returns AST source node of the thing that is noreturn if the statement is
22792252/// definitely `noreturn`. Otherwise returns 0.
22802253fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index {
......@@ -2584,6 +2557,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
25842557 .validate_struct_init_ty,
25852558 .validate_deref,
25862559 => break :b true,
2560
2561 .@"defer" => unreachable,
2562 .defer_err_code => unreachable,
25872563 }
25882564 } else switch (maybe_unused_result) {
25892565 .none => unreachable,
......@@ -2603,15 +2579,12 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
26032579 return noreturn_src_node;
26042580}
26052581
2606fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct {
2582fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {
26072583 have_any: bool,
26082584 have_normal: bool,
26092585 have_err: bool,
26102586 need_err_code: bool,
26112587} {
2612 const tree = astgen.tree;
2613 const node_datas = tree.nodes.items(.data);
2614
26152588 var have_normal = false;
26162589 var have_err = false;
26172590 var need_err_code = false;
......@@ -2621,7 +2594,6 @@ fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct
26212594 .gen_zir => scope = scope.cast(GenZir).?.parent,
26222595 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
26232596 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2624 .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent,
26252597 .defer_normal => {
26262598 const defer_scope = scope.cast(Scope.Defer).?;
26272599 scope = defer_scope.parent;
......@@ -2634,7 +2606,7 @@ fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct
26342606
26352607 have_err = true;
26362608
2637 const have_err_payload = node_datas[defer_scope.defer_node].lhs != 0;
2609 const have_err_payload = defer_scope.remapped_err_code != 0;
26382610 need_err_code = need_err_code or have_err_payload;
26392611 },
26402612 .namespace => unreachable,
......@@ -2661,9 +2633,7 @@ fn genDefers(
26612633 inner_scope: *Scope,
26622634 which_ones: DefersToEmit,
26632635) InnerError!void {
2664 const astgen = gz.astgen;
2665 const tree = astgen.tree;
2666 const node_datas = tree.nodes.items(.data);
2636 const gpa = gz.astgen.gpa;
26672637
26682638 var scope = inner_scope;
26692639 while (scope != outer_scope) {
......@@ -2671,51 +2641,40 @@ fn genDefers(
26712641 .gen_zir => scope = scope.cast(GenZir).?.parent,
26722642 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
26732643 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2674 .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent,
26752644 .defer_normal => {
26762645 const defer_scope = scope.cast(Scope.Defer).?;
26772646 scope = defer_scope.parent;
2678 const expr_node = node_datas[defer_scope.defer_node].rhs;
2679 const prev_in_defer = gz.in_defer;
2680 gz.in_defer = true;
2681 defer gz.in_defer = prev_in_defer;
2682 try unusedResultDeferExpr(gz, defer_scope, defer_scope.parent, expr_node);
2647 try gz.addDefer(defer_scope.index, defer_scope.len);
26832648 },
26842649 .defer_error => {
26852650 const defer_scope = scope.cast(Scope.Defer).?;
26862651 scope = defer_scope.parent;
26872652 switch (which_ones) {
26882653 .both_sans_err => {
2689 const expr_node = node_datas[defer_scope.defer_node].rhs;
2690 const prev_in_defer = gz.in_defer;
2691 gz.in_defer = true;
2692 defer gz.in_defer = prev_in_defer;
2693 try unusedResultDeferExpr(gz, defer_scope, defer_scope.parent, expr_node);
2654 try gz.addDefer(defer_scope.index, defer_scope.len);
26942655 },
26952656 .both => |err_code| {
2696 const expr_node = node_datas[defer_scope.defer_node].rhs;
2697 const payload_token = node_datas[defer_scope.defer_node].lhs;
2698 const prev_in_defer = gz.in_defer;
2699 gz.in_defer = true;
2700 defer gz.in_defer = prev_in_defer;
2701 var local_val_scope: Scope.LocalVal = undefined;
2702 try gz.addDbgBlockBegin();
2703 const sub_scope = if (payload_token == 0) defer_scope.parent else blk: {
2704 const ident_name = try astgen.identAsString(payload_token);
2705 local_val_scope = .{
2706 .parent = defer_scope.parent,
2707 .gen_zir = gz,
2708 .name = ident_name,
2709 .inst = err_code,
2710 .token_src = payload_token,
2711 .id_cat = .@"capture",
2712 };
2713 try gz.addDbgVar(.dbg_var_val, ident_name, err_code);
2714 break :blk &local_val_scope.base;
2715 };
2716 try unusedResultDeferExpr(gz, defer_scope, sub_scope, expr_node);
2717 try checkUsed(gz, scope, sub_scope);
2718 try gz.addDbgBlockEnd();
2657 if (defer_scope.remapped_err_code == 0) {
2658 try gz.addDefer(defer_scope.index, defer_scope.len);
2659 } else {
2660 try gz.instructions.ensureUnusedCapacity(gpa, 1);
2661 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
2662
2663 const payload_index = try gz.astgen.addExtra(Zir.Inst.DeferErrCode{
2664 .remapped_err_code = defer_scope.remapped_err_code,
2665 .index = defer_scope.index,
2666 .len = defer_scope.len,
2667 });
2668 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
2669 gz.astgen.instructions.appendAssumeCapacity(.{
2670 .tag = .defer_err_code,
2671 .data = .{ .defer_err_code = .{
2672 .err_code = err_code,
2673 .payload_index = payload_index,
2674 } },
2675 });
2676 gz.instructions.appendAssumeCapacity(new_index);
2677 }
27192678 },
27202679 .normal_only => continue,
27212680 }
......@@ -2752,35 +2711,68 @@ fn checkUsed(
27522711 scope = s.parent;
27532712 },
27542713 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2755 .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent,
27562714 .namespace => unreachable,
27572715 .top => unreachable,
27582716 }
27592717 }
27602718}
27612719
2762fn makeDeferScope(
2763 astgen: *AstGen,
2720fn deferStmt(
2721 gz: *GenZir,
27642722 scope: *Scope,
27652723 node: Ast.Node.Index,
27662724 block_arena: Allocator,
27672725 scope_tag: Scope.Tag,
27682726) InnerError!*Scope {
2769 const tree = astgen.tree;
2727 var defer_gen = gz.makeSubBlock(scope);
2728 defer_gen.cur_defer_node = node;
2729 defer_gen.any_defer_node = node;
2730 defer defer_gen.unstack();
2731
2732 const tree = gz.astgen.tree;
27702733 const node_datas = tree.nodes.items(.data);
27712734 const expr_node = node_datas[node].rhs;
2772 const token_starts = tree.tokens.items(.start);
2773 const node_start = token_starts[tree.firstToken(expr_node)];
2735
2736 const payload_token = node_datas[node].lhs;
2737 var local_val_scope: Scope.LocalVal = undefined;
2738 var remapped_err_code: Zir.Inst.Index = 0;
2739 const have_err_code = scope_tag == .defer_error and payload_token != 0;
2740 const sub_scope = if (!have_err_code) &defer_gen.base else blk: {
2741 try gz.addDbgBlockBegin();
2742 const ident_name = try gz.astgen.identAsString(payload_token);
2743 remapped_err_code = @intCast(u32, try gz.astgen.instructions.addOne(gz.astgen.gpa));
2744 const remapped_err_code_ref = Zir.indexToRef(remapped_err_code);
2745 local_val_scope = .{
2746 .parent = &defer_gen.base,
2747 .gen_zir = gz,
2748 .name = ident_name,
2749 .inst = remapped_err_code_ref,
2750 .token_src = payload_token,
2751 .id_cat = .@"capture",
2752 };
2753 try gz.addDbgVar(.dbg_var_val, ident_name, remapped_err_code_ref);
2754 break :blk &local_val_scope.base;
2755 };
2756 _ = try unusedResultExpr(&defer_gen, sub_scope, expr_node);
2757 try checkUsed(gz, scope, sub_scope);
2758 if (have_err_code) try gz.addDbgBlockEnd();
2759 _ = try defer_gen.addBreak(.break_inline, 0, .void_value);
2760
2761 const body = defer_gen.instructionsSlice();
2762 const body_len = gz.astgen.countBodyLenAfterFixups(body);
2763
2764 const index = @intCast(u32, gz.astgen.extra.items.len);
2765 try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_len);
2766 gz.astgen.appendBodyWithFixups(body);
2767
27742768 const defer_scope = try block_arena.create(Scope.Defer);
2775 astgen.advanceSourceCursor(node_start);
27762769
27772770 defer_scope.* = .{
27782771 .base = .{ .tag = scope_tag },
27792772 .parent = scope,
2780 .defer_node = node,
2781 .source_offset = astgen.source_offset,
2782 .source_line = astgen.source_line,
2783 .source_column = astgen.source_column,
2773 .index = index,
2774 .len = body_len,
2775 .remapped_err_code = remapped_err_code,
27842776 };
27852777 return &defer_scope.base;
27862778}
......@@ -3461,7 +3453,6 @@ fn fnDecl(
34613453
34623454 var decl_gz: GenZir = .{
34633455 .force_comptime = true,
3464 .in_defer = false,
34653456 .decl_node_index = fn_proto.ast.proto_node,
34663457 .decl_line = astgen.source_line,
34673458 .parent = scope,
......@@ -3473,7 +3464,6 @@ fn fnDecl(
34733464
34743465 var fn_gz: GenZir = .{
34753466 .force_comptime = false,
3476 .in_defer = false,
34773467 .decl_node_index = fn_proto.ast.proto_node,
34783468 .decl_line = decl_gz.decl_line,
34793469 .parent = &decl_gz.base,
......@@ -3812,7 +3802,6 @@ fn globalVarDecl(
38123802 .decl_line = astgen.source_line,
38133803 .astgen = astgen,
38143804 .force_comptime = true,
3815 .in_defer = false,
38163805 .anon_name_strategy = .parent,
38173806 .instructions = gz.instructions,
38183807 .instructions_top = gz.instructions.items.len,
......@@ -3964,7 +3953,6 @@ fn comptimeDecl(
39643953
39653954 var decl_block: GenZir = .{
39663955 .force_comptime = true,
3967 .in_defer = false,
39683956 .decl_node_index = node,
39693957 .decl_line = astgen.source_line,
39703958 .parent = scope,
......@@ -4019,7 +4007,6 @@ fn usingnamespaceDecl(
40194007
40204008 var decl_block: GenZir = .{
40214009 .force_comptime = true,
4022 .in_defer = false,
40234010 .decl_node_index = node,
40244011 .decl_line = astgen.source_line,
40254012 .parent = scope,
......@@ -4067,7 +4054,6 @@ fn testDecl(
40674054
40684055 var decl_block: GenZir = .{
40694056 .force_comptime = true,
4070 .in_defer = false,
40714057 .decl_node_index = node,
40724058 .decl_line = astgen.source_line,
40734059 .parent = scope,
......@@ -4132,7 +4118,6 @@ fn testDecl(
41324118 .local_val, .local_ptr => unreachable, // a test cannot be in a local scope
41334119 .gen_zir => s = s.cast(GenZir).?.parent,
41344120 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
4135 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
41364121 .namespace => {
41374122 const ns = s.cast(Scope.Namespace).?;
41384123 if (ns.decls.get(name_str_index)) |i| {
......@@ -4164,7 +4149,6 @@ fn testDecl(
41644149
41654150 var fn_block: GenZir = .{
41664151 .force_comptime = false,
4167 .in_defer = false,
41684152 .decl_node_index = node,
41694153 .decl_line = decl_block.decl_line,
41704154 .parent = &decl_block.base,
......@@ -4288,7 +4272,6 @@ fn structDeclInner(
42884272 .decl_line = decl_line,
42894273 .astgen = astgen,
42904274 .force_comptime = true,
4291 .in_defer = false,
42924275 .instructions = gz.instructions,
42934276 .instructions_top = gz.instructions.items.len,
42944277 };
......@@ -4489,7 +4472,6 @@ fn unionDeclInner(
44894472 .decl_line = astgen.source_line,
44904473 .astgen = astgen,
44914474 .force_comptime = true,
4492 .in_defer = false,
44934475 .instructions = gz.instructions,
44944476 .instructions_top = gz.instructions.items.len,
44954477 };
......@@ -4773,7 +4755,6 @@ fn containerDecl(
47734755 .decl_line = astgen.source_line,
47744756 .astgen = astgen,
47754757 .force_comptime = true,
4776 .in_defer = false,
47774758 .instructions = gz.instructions,
47784759 .instructions_top = gz.instructions.items.len,
47794760 };
......@@ -4879,7 +4860,6 @@ fn containerDecl(
48794860 .decl_line = astgen.source_line,
48804861 .astgen = astgen,
48814862 .force_comptime = true,
4882 .in_defer = false,
48834863 .instructions = gz.instructions,
48844864 .instructions_top = gz.instructions.items.len,
48854865 };
......@@ -5110,7 +5090,15 @@ fn tryExpr(
51105090 return astgen.failNode(node, "'try' outside function scope", .{});
51115091 };
51125092
5113 if (parent_gz.in_defer) return astgen.failNode(node, "'try' not allowed inside defer expression", .{});
5093 if (parent_gz.any_defer_node != 0) {
5094 return astgen.failNodeNotes(node, "'try' not allowed inside defer expression", .{}, &.{
5095 try astgen.errNoteNode(
5096 parent_gz.any_defer_node,
5097 "defer expression here",
5098 .{},
5099 ),
5100 });
5101 }
51145102
51155103 // Ensure debug line/column information is emitted for this try expression.
51165104 // Then we will save the line/column so that we can emit another one that goes
......@@ -6656,7 +6644,15 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66566644 return astgen.failNode(node, "'return' outside function scope", .{});
66576645 }
66586646
6659 if (gz.in_defer) return astgen.failNode(node, "cannot return from defer expression", .{});
6647 if (gz.any_defer_node != 0) {
6648 return astgen.failNodeNotes(node, "cannot return from defer expression", .{}, &.{
6649 try astgen.errNoteNode(
6650 gz.any_defer_node,
6651 "defer expression here",
6652 .{},
6653 ),
6654 });
6655 }
66606656
66616657 // Ensure debug line/column information is emitted for this return expression.
66626658 // Then we will save the line/column so that we can emit another one that goes
......@@ -6683,7 +6679,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
66836679 // for detecting whether to add something to the function's inferred error set.
66846680 const ident_token = node_datas[operand_node].rhs;
66856681 const err_name_str_index = try astgen.identAsString(ident_token);
6686 const defer_counts = countDefers(astgen, defer_outer, scope);
6682 const defer_counts = countDefers(defer_outer, scope);
66876683 if (!defer_counts.need_err_code) {
66886684 try genDefers(gz, defer_outer, scope, .both_sans_err);
66896685 try emitDbgStmt(gz, ret_line, ret_column);
......@@ -6724,7 +6720,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
67246720 return Zir.Inst.Ref.unreachable_value;
67256721 },
67266722 .maybe => {
6727 const defer_counts = countDefers(astgen, defer_outer, scope);
6723 const defer_counts = countDefers(defer_outer, scope);
67286724 if (!defer_counts.have_err) {
67296725 // Only regular defers; no branch needed.
67306726 try genDefers(gz, defer_outer, scope, .normal_only);
......@@ -6921,7 +6917,6 @@ fn localVarRef(
69216917 },
69226918 .gen_zir => s = s.cast(GenZir).?.parent,
69236919 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
6924 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
69256920 .namespace => {
69266921 const ns = s.cast(Scope.Namespace).?;
69276922 if (ns.decls.get(name_str_index)) |i| {
......@@ -7550,7 +7545,6 @@ fn builtinCall(
75507545 },
75517546 .gen_zir => s = s.cast(GenZir).?.parent,
75527547 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
7553 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
75547548 .namespace => {
75557549 const ns = s.cast(Scope.Namespace).?;
75567550 if (ns.decls.get(decl_name)) |i| {
......@@ -10046,7 +10040,6 @@ const Scope = struct {
1004610040 local_ptr,
1004710041 defer_normal,
1004810042 defer_error,
10049 defer_gen,
1005010043 namespace,
1005110044 top,
1005210045 };
......@@ -10105,10 +10098,9 @@ const Scope = struct {
1010510098 base: Scope,
1010610099 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
1010710100 parent: *Scope,
10108 defer_node: Ast.Node.Index,
10109 source_offset: u32,
10110 source_line: u32,
10111 source_column: u32,
10101 index: u32,
10102 len: u32,
10103 remapped_err_code: Zir.Inst.Index = 0,
1011210104 };
1011310105
1011410106 /// Represents a global scope that has any number of declarations in it.
......@@ -10144,13 +10136,6 @@ const Scope = struct {
1014410136 const base_tag: Scope.Tag = .top;
1014510137 base: Scope = Scope{ .tag = base_tag },
1014610138 };
10147
10148 const DeferGen = struct {
10149 const base_tag: Scope.Tag = .defer_gen;
10150 base: Scope = Scope{ .tag = base_tag },
10151 parent: *Scope,
10152 defer_node: Ast.Node.Index,
10153 };
1015410139};
1015510140
1015610141/// This is a temporary structure; references to it are valid only
......@@ -10161,7 +10146,6 @@ const GenZir = struct {
1016110146 force_comptime: bool,
1016210147 /// This is set to true for inline loops; false otherwise.
1016310148 is_inline: bool = false,
10164 in_defer: bool,
1016510149 c_import: bool = false,
1016610150 /// How decls created in this scope should be named.
1016710151 anon_name_strategy: Zir.Inst.NameStrategy = .anon,
......@@ -10204,6 +10188,10 @@ const GenZir = struct {
1020410188
1020510189 suspend_node: Ast.Node.Index = 0,
1020610190 nosuspend_node: Ast.Node.Index = 0,
10191 /// Set if this GenZir is a defer.
10192 cur_defer_node: Ast.Node.Index = 0,
10193 // Set if this GenZir is a defer or it is inside a defer.
10194 any_defer_node: Ast.Node.Index = 0,
1020710195
1020810196 /// Namespace members are lazy. When executing a decl within a namespace,
1020910197 /// any references to external instructions need to be treated specially.
......@@ -10244,7 +10232,6 @@ const GenZir = struct {
1024410232 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {
1024510233 return .{
1024610234 .force_comptime = gz.force_comptime,
10247 .in_defer = gz.in_defer,
1024810235 .c_import = gz.c_import,
1024910236 .decl_node_index = gz.decl_node_index,
1025010237 .decl_line = gz.decl_line,
......@@ -10253,6 +10240,7 @@ const GenZir = struct {
1025310240 .astgen = gz.astgen,
1025410241 .suspend_node = gz.suspend_node,
1025510242 .nosuspend_node = gz.nosuspend_node,
10243 .any_defer_node = gz.any_defer_node,
1025610244 .instructions = gz.instructions,
1025710245 .instructions_top = gz.instructions.items.len,
1025810246 };
......@@ -11107,6 +11095,16 @@ const GenZir = struct {
1110711095 });
1110811096 }
1110911097
11098 fn addDefer(gz: *GenZir, index: u32, len: u32) !void {
11099 _ = try gz.add(.{
11100 .tag = .@"defer",
11101 .data = .{ .@"defer" = .{
11102 .index = index,
11103 .len = len,
11104 } },
11105 });
11106 }
11107
1111011108 fn addDecl(
1111111109 gz: *GenZir,
1111211110 tag: Zir.Inst.Tag,
......@@ -11670,7 +11668,6 @@ fn detectLocalShadowing(
1167011668 },
1167111669 .gen_zir => s = s.cast(GenZir).?.parent,
1167211670 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
11673 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
1167411671 .top => break,
1167511672 };
1167611673}
......@@ -11809,7 +11806,6 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
1180911806 .namespace => s = s.cast(Scope.Namespace).?.parent,
1181011807 .gen_zir => s = s.cast(GenZir).?.parent,
1181111808 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
11812 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
1181311809 .top => break,
1181411810 };
1181511811 gop.value_ptr.* = member_node;
src/Sema.zig+29-5
......@@ -1461,6 +1461,29 @@ fn analyzeBodyInner(
14611461 // break break_data.inst;
14621462 // }
14631463 //},
1464 .@"defer" => blk: {
1465 const inst_data = sema.code.instructions.items(.data)[inst].@"defer";
1466 const defer_body = sema.code.extra[inst_data.index..][0..inst_data.len];
1467 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) {
1468 error.ComptimeBreak => sema.comptime_break_inst,
1469 else => |e| return e,
1470 };
1471 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn;
1472 break :blk Air.Inst.Ref.void_value;
1473 },
1474 .defer_err_code => blk: {
1475 const inst_data = sema.code.instructions.items(.data)[inst].defer_err_code;
1476 const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
1477 const defer_body = sema.code.extra[extra.index..][0..extra.len];
1478 const err_code = try sema.resolveInst(inst_data.err_code);
1479 try sema.inst_map.put(sema.gpa, extra.remapped_err_code, err_code);
1480 const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) {
1481 error.ComptimeBreak => sema.comptime_break_inst,
1482 else => |e| return e,
1483 };
1484 if (break_inst != defer_body[defer_body.len - 1]) break always_noreturn;
1485 break :blk Air.Inst.Ref.void_value;
1486 },
14641487 };
14651488 if (sema.typeOf(air_inst).isNoReturn())
14661489 break always_noreturn;
......@@ -9394,11 +9417,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
93949417 }
93959418
93969419 if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) {
9397
9398 // TODO re-enable if defer implementation is improved
9399 // https://github.com/ziglang/zig/issues/11798
9400 if (true) break :else_validation;
9401
94029420 // In order to enable common patterns for generic code allow simple else bodies
94039421 // else => unreachable,
94049422 // else => return,
......@@ -9415,6 +9433,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
94159433 .as_node,
94169434 .ret_node,
94179435 .@"unreachable",
9436 .@"defer",
9437 .defer_err_code,
9438 .err_union_code,
9439 .ret_err_value_code,
9440 .is_non_err,
9441 .condbr,
94189442 => {},
94199443 else => break,
94209444 } else break :else_validation;
src/Zir.zig+30
......@@ -995,6 +995,13 @@ pub const Inst = struct {
995995 /// closure_capture instruction ref.
996996 closure_get,
997997
998 /// A defer statement.
999 /// Uses the `defer` union field.
1000 @"defer",
1001 /// An errdefer statement with a code.
1002 /// Uses the `err_defer_code` union field.
1003 defer_err_code,
1004
9981005 /// The ZIR instruction tag is one of the `Extended` ones.
9991006 /// Uses the `extended` union field.
10001007 extended,
......@@ -1244,6 +1251,8 @@ pub const Inst = struct {
12441251 .try_ptr,
12451252 //.try_inline,
12461253 //.try_ptr_inline,
1254 .@"defer",
1255 .defer_err_code,
12471256 => false,
12481257
12491258 .@"break",
......@@ -1311,6 +1320,8 @@ pub const Inst = struct {
13111320 .memcpy,
13121321 .memset,
13131322 .check_comptime_control_flow,
1323 .@"defer",
1324 .defer_err_code,
13141325 => true,
13151326
13161327 .param,
......@@ -1819,6 +1830,9 @@ pub const Inst = struct {
18191830 .closure_capture = .un_tok,
18201831 .closure_get = .inst_node,
18211832
1833 .@"defer" = .@"defer",
1834 .defer_err_code = .defer_err_code,
1835
18221836 .extended = .extended,
18231837 });
18241838 };
......@@ -2575,6 +2589,14 @@ pub const Inst = struct {
25752589 return zir.nullTerminatedString(self.str);
25762590 }
25772591 },
2592 @"defer": struct {
2593 index: u32,
2594 len: u32,
2595 },
2596 defer_err_code: struct {
2597 err_code: Ref,
2598 payload_index: u32,
2599 },
25782600
25792601 // Make sure we don't accidentally add a field to make this union
25802602 // bigger than expected. Note that in Debug builds, Zig is allowed
......@@ -2611,6 +2633,8 @@ pub const Inst = struct {
26112633 dbg_stmt,
26122634 inst_node,
26132635 str_op,
2636 @"defer",
2637 defer_err_code,
26142638 };
26152639 };
26162640
......@@ -3550,6 +3574,12 @@ pub const Inst = struct {
35503574 line: u32,
35513575 column: u32,
35523576 };
3577
3578 pub const DeferErrCode = struct {
3579 remapped_err_code: Index,
3580 index: u32,
3581 len: u32,
3582 };
35533583};
35543584
35553585pub const SpecialProng = enum { none, @"else", under };
src/print_zir.zig+23
......@@ -446,6 +446,9 @@ const Writer = struct {
446446
447447 .closure_get => try self.writeInstNode(stream, inst),
448448
449 .@"defer" => try self.writeDefer(stream, inst),
450 .defer_err_code => try self.writeDeferErrCode(stream, inst),
451
449452 .extended => try self.writeExtended(stream, inst),
450453 }
451454 }
......@@ -2364,6 +2367,26 @@ const Writer = struct {
23642367 try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });
23652368 }
23662369
2370 fn writeDefer(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2371 const inst_data = self.code.instructions.items(.data)[inst].@"defer";
2372 const body = self.code.extra[inst_data.index..][0..inst_data.len];
2373 try self.writeBracedBody(stream, body);
2374 try stream.writeByte(')');
2375 }
2376
2377 fn writeDeferErrCode(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
2378 const inst_data = self.code.instructions.items(.data)[inst].defer_err_code;
2379 const extra = self.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
2380
2381 try self.writeInstRef(stream, Zir.indexToRef(extra.remapped_err_code));
2382 try stream.writeAll(" = ");
2383 try self.writeInstRef(stream, inst_data.err_code);
2384 try stream.writeAll(", ");
2385 const body = self.code.extra[extra.index..][0..extra.len];
2386 try self.writeBracedBody(stream, body);
2387 try stream.writeByte(')');
2388 }
2389
23672390 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
23682391 var i: usize = @enumToInt(ref);
23692392
test/behavior/defer.zig+17
......@@ -127,3 +127,20 @@ test "errdefer with payload" {
127127 try S.doTheTest();
128128 comptime try S.doTheTest();
129129}
130
131test "simple else prong doesn't emit an error for unreachable else prong" {
132 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
133
134 const S = struct {
135 fn foo() error{Foo}!void {
136 return error.Foo;
137 }
138 };
139 var a: u32 = 0;
140 defer a += 1;
141 S.foo() catch |err| switch (err) {
142 error.Foo => a += 1,
143 else => |e| return e,
144 };
145 try expect(a == 1);
146}
test/cases/compile_errors/return_from_defer_expression.zig+1
......@@ -19,3 +19,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(testTrickyDefer)); }
1919// target=native
2020//
2121// :4:11: error: 'try' not allowed inside defer expression
22// :4:5: note: defer expression here
test/cases/compile_errors/uncreachable_else_prong_err_set.zig created+25
......@@ -0,0 +1,25 @@
1pub export fn complex() void {
2 var a: error{ Foo, Bar } = error.Foo;
3 switch (a) {
4 error.Foo => unreachable,
5 error.Bar => unreachable,
6 else => {
7 @compileError("<something complex here>");
8 },
9 }
10}
11
12pub export fn simple() void {
13 var a: error{ Foo, Bar } = error.Foo;
14 switch (a) {
15 error.Foo => unreachable,
16 error.Bar => unreachable,
17 else => |e| return e,
18 }
19}
20
21// error
22// backend=llvm
23// target=native
24//
25// :6:14: error: unreachable else prong; all cases already handled
test/cases/returns_in_try.zig+2
......@@ -13,4 +13,6 @@ pub fn b() !void {
1313// error
1414//
1515// :7:11: error: 'try' not allowed inside defer expression
16// :7:5: note: defer expression here
1617// :10:11: error: cannot return from defer expression
18// :10:5: note: defer expression here