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 {...@@ -5700,7 +5700,6 @@ fn bar() !void {
5700 try quux();5700 try quux();
5701 } else |err| switch (err) {5701 } else |err| switch (err) {
5702 error.FileNotFound => try hello(),5702 error.FileNotFound => try hello(),
5703 else => try another(),
5704 }5703 }
5705}5704}
57065705
...@@ -5716,10 +5715,6 @@ fn hello() !void {...@@ -5716,10 +5715,6 @@ fn hello() !void {
5716 try bang2();5715 try bang2();
5717}5716}
57185717
5719fn another() !void {
5720 try bang1();
5721}
5722
5723fn bang1() !void {5718fn bang1() !void {
5724 return error.FileNotFound;5719 return error.FileNotFound;
5725}5720}
src/AstGen.zig+134-138
...@@ -135,7 +135,6 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {...@@ -135,7 +135,6 @@ pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zir {
135 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};135 var gz_instructions: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
136 var gen_scope: GenZir = .{136 var gen_scope: GenZir = .{
137 .force_comptime = true,137 .force_comptime = true,
138 .in_defer = false,
139 .parent = &top_scope.base,138 .parent = &top_scope.base,
140 .anon_name_strategy = .parent,139 .anon_name_strategy = .parent,
141 .decl_node_index = 0,140 .decl_node_index = 0,
...@@ -1856,6 +1855,16 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn...@@ -1856,6 +1855,16 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
1856 .gen_zir => {1855 .gen_zir => {
1857 const block_gz = scope.cast(GenZir).?;1856 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
1859 const block_inst = blk: {1868 const block_inst = blk: {
1860 if (break_label != 0) {1869 if (break_label != 0) {
1861 if (block_gz.label) |*label| {1870 if (block_gz.label) |*label| {
...@@ -1919,17 +1928,6 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn...@@ -1919,17 +1928,6 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) Inn
1919 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,1928 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
1920 .namespace => break,1929 .namespace => break,
1921 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,1930 .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 },
1933 .top => unreachable,1931 .top => unreachable,
1934 }1932 }
1935 }1933 }
...@@ -1953,6 +1951,16 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)...@@ -1953,6 +1951,16 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
1953 switch (scope.tag) {1951 switch (scope.tag) {
1954 .gen_zir => {1952 .gen_zir => {
1955 const gen_zir = scope.cast(GenZir).?;1953 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 }
1956 const continue_block = gen_zir.continue_block;1964 const continue_block = gen_zir.continue_block;
1957 if (continue_block == 0) {1965 if (continue_block == 0) {
1958 scope = gen_zir.parent;1966 scope = gen_zir.parent;
...@@ -1985,21 +1993,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)...@@ -1985,21 +1993,9 @@ fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index)
1985 .defer_normal => {1993 .defer_normal => {
1986 const defer_scope = scope.cast(Scope.Defer).?;1994 const defer_scope = scope.cast(Scope.Defer).?;
1987 scope = defer_scope.parent;1995 scope = defer_scope.parent;
1988 const expr_node = node_datas[defer_scope.defer_node].rhs;1996 try parent_gz.addDefer(defer_scope.index, defer_scope.len);
1989 try unusedResultDeferExpr(parent_gz, defer_scope, defer_scope.parent, expr_node);
1990 },1997 },
1991 .defer_error => scope = scope.cast(Scope.Defer).?.parent,1998 .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 },
2003 .namespace => break,1999 .namespace => break,
2004 .top => unreachable,2000 .top => unreachable,
2005 }2001 }
...@@ -2064,7 +2060,6 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke...@@ -2064,7 +2060,6 @@ fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.Toke
2064 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,2060 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2065 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,2061 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2066 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,2062 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2067 .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent,
2068 .namespace => break,2063 .namespace => break,
2069 .top => unreachable,2064 .top => unreachable,
2070 }2065 }
...@@ -2208,8 +2203,8 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod...@@ -2208,8 +2203,8 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
2208 .simple_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.simpleVarDecl(statement)),2203 .simple_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.simpleVarDecl(statement)),
2209 .aligned_var_decl => scope = try varDecl(gz, scope, statement, block_arena_allocator, tree.alignedVarDecl(statement)),2204 .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),2206 .@"defer" => scope = try deferStmt(gz, scope, statement, block_arena_allocator, .defer_normal),
2212 .@"errdefer" => scope = try makeDeferScope(gz.astgen, scope, statement, block_arena_allocator, .defer_error),2207 .@"errdefer" => scope = try deferStmt(gz, scope, statement, block_arena_allocator, .defer_error),
22132208
2214 .assign => try assign(gz, scope, statement),2209 .assign => try assign(gz, scope, statement),
22152210
...@@ -2253,28 +2248,6 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod...@@ -2253,28 +2248,6 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Nod
2253 try checkUsed(gz, parent_scope, scope);2248 try checkUsed(gz, parent_scope, scope);
2254}2249}
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
2278/// Returns AST source node of the thing that is noreturn if the statement is2251/// Returns AST source node of the thing that is noreturn if the statement is
2279/// definitely `noreturn`. Otherwise returns 0.2252/// definitely `noreturn`. Otherwise returns 0.
2280fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index {2253fn 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...@@ -2584,6 +2557,9 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2584 .validate_struct_init_ty,2557 .validate_struct_init_ty,
2585 .validate_deref,2558 .validate_deref,
2586 => break :b true,2559 => break :b true,
2560
2561 .@"defer" => unreachable,
2562 .defer_err_code => unreachable,
2587 }2563 }
2588 } else switch (maybe_unused_result) {2564 } else switch (maybe_unused_result) {
2589 .none => unreachable,2565 .none => unreachable,
...@@ -2603,15 +2579,12 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2603,15 +2579,12 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2603 return noreturn_src_node;2579 return noreturn_src_node;
2604}2580}
26052581
2606fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct {2582fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {
2607 have_any: bool,2583 have_any: bool,
2608 have_normal: bool,2584 have_normal: bool,
2609 have_err: bool,2585 have_err: bool,
2610 need_err_code: bool,2586 need_err_code: bool,
2611} {2587} {
2612 const tree = astgen.tree;
2613 const node_datas = tree.nodes.items(.data);
2614
2615 var have_normal = false;2588 var have_normal = false;
2616 var have_err = false;2589 var have_err = false;
2617 var need_err_code = false;2590 var need_err_code = false;
...@@ -2621,7 +2594,6 @@ fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct...@@ -2621,7 +2594,6 @@ fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct
2621 .gen_zir => scope = scope.cast(GenZir).?.parent,2594 .gen_zir => scope = scope.cast(GenZir).?.parent,
2622 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,2595 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2623 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,2596 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2624 .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent,
2625 .defer_normal => {2597 .defer_normal => {
2626 const defer_scope = scope.cast(Scope.Defer).?;2598 const defer_scope = scope.cast(Scope.Defer).?;
2627 scope = defer_scope.parent;2599 scope = defer_scope.parent;
...@@ -2634,7 +2606,7 @@ fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct...@@ -2634,7 +2606,7 @@ fn countDefers(astgen: *AstGen, outer_scope: *Scope, inner_scope: *Scope) struct
26342606
2635 have_err = true;2607 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;
2638 need_err_code = need_err_code or have_err_payload;2610 need_err_code = need_err_code or have_err_payload;
2639 },2611 },
2640 .namespace => unreachable,2612 .namespace => unreachable,
...@@ -2661,9 +2633,7 @@ fn genDefers(...@@ -2661,9 +2633,7 @@ fn genDefers(
2661 inner_scope: *Scope,2633 inner_scope: *Scope,
2662 which_ones: DefersToEmit,2634 which_ones: DefersToEmit,
2663) InnerError!void {2635) InnerError!void {
2664 const astgen = gz.astgen;2636 const gpa = gz.astgen.gpa;
2665 const tree = astgen.tree;
2666 const node_datas = tree.nodes.items(.data);
26672637
2668 var scope = inner_scope;2638 var scope = inner_scope;
2669 while (scope != outer_scope) {2639 while (scope != outer_scope) {
...@@ -2671,51 +2641,40 @@ fn genDefers(...@@ -2671,51 +2641,40 @@ fn genDefers(
2671 .gen_zir => scope = scope.cast(GenZir).?.parent,2641 .gen_zir => scope = scope.cast(GenZir).?.parent,
2672 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,2642 .local_val => scope = scope.cast(Scope.LocalVal).?.parent,
2673 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,2643 .local_ptr => scope = scope.cast(Scope.LocalPtr).?.parent,
2674 .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent,
2675 .defer_normal => {2644 .defer_normal => {
2676 const defer_scope = scope.cast(Scope.Defer).?;2645 const defer_scope = scope.cast(Scope.Defer).?;
2677 scope = defer_scope.parent;2646 scope = defer_scope.parent;
2678 const expr_node = node_datas[defer_scope.defer_node].rhs;2647 try gz.addDefer(defer_scope.index, defer_scope.len);
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);
2683 },2648 },
2684 .defer_error => {2649 .defer_error => {
2685 const defer_scope = scope.cast(Scope.Defer).?;2650 const defer_scope = scope.cast(Scope.Defer).?;
2686 scope = defer_scope.parent;2651 scope = defer_scope.parent;
2687 switch (which_ones) {2652 switch (which_ones) {
2688 .both_sans_err => {2653 .both_sans_err => {
2689 const expr_node = node_datas[defer_scope.defer_node].rhs;2654 try gz.addDefer(defer_scope.index, defer_scope.len);
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);
2694 },2655 },
2695 .both => |err_code| {2656 .both => |err_code| {
2696 const expr_node = node_datas[defer_scope.defer_node].rhs;2657 if (defer_scope.remapped_err_code == 0) {
2697 const payload_token = node_datas[defer_scope.defer_node].lhs;2658 try gz.addDefer(defer_scope.index, defer_scope.len);
2698 const prev_in_defer = gz.in_defer;2659 } else {
2699 gz.in_defer = true;2660 try gz.instructions.ensureUnusedCapacity(gpa, 1);
2700 defer gz.in_defer = prev_in_defer;2661 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
2701 var local_val_scope: Scope.LocalVal = undefined;2662
2702 try gz.addDbgBlockBegin();2663 const payload_index = try gz.astgen.addExtra(Zir.Inst.DeferErrCode{
2703 const sub_scope = if (payload_token == 0) defer_scope.parent else blk: {2664 .remapped_err_code = defer_scope.remapped_err_code,
2704 const ident_name = try astgen.identAsString(payload_token);2665 .index = defer_scope.index,
2705 local_val_scope = .{2666 .len = defer_scope.len,
2706 .parent = defer_scope.parent,2667 });
2707 .gen_zir = gz,2668 const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len);
2708 .name = ident_name,2669 gz.astgen.instructions.appendAssumeCapacity(.{
2709 .inst = err_code,2670 .tag = .defer_err_code,
2710 .token_src = payload_token,2671 .data = .{ .defer_err_code = .{
2711 .id_cat = .@"capture",2672 .err_code = err_code,
2712 };2673 .payload_index = payload_index,
2713 try gz.addDbgVar(.dbg_var_val, ident_name, err_code);2674 } },
2714 break :blk &local_val_scope.base;2675 });
2715 };2676 gz.instructions.appendAssumeCapacity(new_index);
2716 try unusedResultDeferExpr(gz, defer_scope, sub_scope, expr_node);2677 }
2717 try checkUsed(gz, scope, sub_scope);
2718 try gz.addDbgBlockEnd();
2719 },2678 },
2720 .normal_only => continue,2679 .normal_only => continue,
2721 }2680 }
...@@ -2752,35 +2711,68 @@ fn checkUsed(...@@ -2752,35 +2711,68 @@ fn checkUsed(
2752 scope = s.parent;2711 scope = s.parent;
2753 },2712 },
2754 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,2713 .defer_normal, .defer_error => scope = scope.cast(Scope.Defer).?.parent,
2755 .defer_gen => scope = scope.cast(Scope.DeferGen).?.parent,
2756 .namespace => unreachable,2714 .namespace => unreachable,
2757 .top => unreachable,2715 .top => unreachable,
2758 }2716 }
2759 }2717 }
2760}2718}
27612719
2762fn makeDeferScope(2720fn deferStmt(
2763 astgen: *AstGen,2721 gz: *GenZir,
2764 scope: *Scope,2722 scope: *Scope,
2765 node: Ast.Node.Index,2723 node: Ast.Node.Index,
2766 block_arena: Allocator,2724 block_arena: Allocator,
2767 scope_tag: Scope.Tag,2725 scope_tag: Scope.Tag,
2768) InnerError!*Scope {2726) 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;
2770 const node_datas = tree.nodes.items(.data);2733 const node_datas = tree.nodes.items(.data);
2771 const expr_node = node_datas[node].rhs;2734 const expr_node = node_datas[node].rhs;
2772 const token_starts = tree.tokens.items(.start);2735
2773 const node_start = token_starts[tree.firstToken(expr_node)];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
2774 const defer_scope = try block_arena.create(Scope.Defer);2768 const defer_scope = try block_arena.create(Scope.Defer);
2775 astgen.advanceSourceCursor(node_start);
27762769
2777 defer_scope.* = .{2770 defer_scope.* = .{
2778 .base = .{ .tag = scope_tag },2771 .base = .{ .tag = scope_tag },
2779 .parent = scope,2772 .parent = scope,
2780 .defer_node = node,2773 .index = index,
2781 .source_offset = astgen.source_offset,2774 .len = body_len,
2782 .source_line = astgen.source_line,2775 .remapped_err_code = remapped_err_code,
2783 .source_column = astgen.source_column,
2784 };2776 };
2785 return &defer_scope.base;2777 return &defer_scope.base;
2786}2778}
...@@ -3461,7 +3453,6 @@ fn fnDecl(...@@ -3461,7 +3453,6 @@ fn fnDecl(
34613453
3462 var decl_gz: GenZir = .{3454 var decl_gz: GenZir = .{
3463 .force_comptime = true,3455 .force_comptime = true,
3464 .in_defer = false,
3465 .decl_node_index = fn_proto.ast.proto_node,3456 .decl_node_index = fn_proto.ast.proto_node,
3466 .decl_line = astgen.source_line,3457 .decl_line = astgen.source_line,
3467 .parent = scope,3458 .parent = scope,
...@@ -3473,7 +3464,6 @@ fn fnDecl(...@@ -3473,7 +3464,6 @@ fn fnDecl(
34733464
3474 var fn_gz: GenZir = .{3465 var fn_gz: GenZir = .{
3475 .force_comptime = false,3466 .force_comptime = false,
3476 .in_defer = false,
3477 .decl_node_index = fn_proto.ast.proto_node,3467 .decl_node_index = fn_proto.ast.proto_node,
3478 .decl_line = decl_gz.decl_line,3468 .decl_line = decl_gz.decl_line,
3479 .parent = &decl_gz.base,3469 .parent = &decl_gz.base,
...@@ -3812,7 +3802,6 @@ fn globalVarDecl(...@@ -3812,7 +3802,6 @@ fn globalVarDecl(
3812 .decl_line = astgen.source_line,3802 .decl_line = astgen.source_line,
3813 .astgen = astgen,3803 .astgen = astgen,
3814 .force_comptime = true,3804 .force_comptime = true,
3815 .in_defer = false,
3816 .anon_name_strategy = .parent,3805 .anon_name_strategy = .parent,
3817 .instructions = gz.instructions,3806 .instructions = gz.instructions,
3818 .instructions_top = gz.instructions.items.len,3807 .instructions_top = gz.instructions.items.len,
...@@ -3964,7 +3953,6 @@ fn comptimeDecl(...@@ -3964,7 +3953,6 @@ fn comptimeDecl(
39643953
3965 var decl_block: GenZir = .{3954 var decl_block: GenZir = .{
3966 .force_comptime = true,3955 .force_comptime = true,
3967 .in_defer = false,
3968 .decl_node_index = node,3956 .decl_node_index = node,
3969 .decl_line = astgen.source_line,3957 .decl_line = astgen.source_line,
3970 .parent = scope,3958 .parent = scope,
...@@ -4019,7 +4007,6 @@ fn usingnamespaceDecl(...@@ -4019,7 +4007,6 @@ fn usingnamespaceDecl(
40194007
4020 var decl_block: GenZir = .{4008 var decl_block: GenZir = .{
4021 .force_comptime = true,4009 .force_comptime = true,
4022 .in_defer = false,
4023 .decl_node_index = node,4010 .decl_node_index = node,
4024 .decl_line = astgen.source_line,4011 .decl_line = astgen.source_line,
4025 .parent = scope,4012 .parent = scope,
...@@ -4067,7 +4054,6 @@ fn testDecl(...@@ -4067,7 +4054,6 @@ fn testDecl(
40674054
4068 var decl_block: GenZir = .{4055 var decl_block: GenZir = .{
4069 .force_comptime = true,4056 .force_comptime = true,
4070 .in_defer = false,
4071 .decl_node_index = node,4057 .decl_node_index = node,
4072 .decl_line = astgen.source_line,4058 .decl_line = astgen.source_line,
4073 .parent = scope,4059 .parent = scope,
...@@ -4132,7 +4118,6 @@ fn testDecl(...@@ -4132,7 +4118,6 @@ fn testDecl(
4132 .local_val, .local_ptr => unreachable, // a test cannot be in a local scope4118 .local_val, .local_ptr => unreachable, // a test cannot be in a local scope
4133 .gen_zir => s = s.cast(GenZir).?.parent,4119 .gen_zir => s = s.cast(GenZir).?.parent,
4134 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,4120 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
4135 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
4136 .namespace => {4121 .namespace => {
4137 const ns = s.cast(Scope.Namespace).?;4122 const ns = s.cast(Scope.Namespace).?;
4138 if (ns.decls.get(name_str_index)) |i| {4123 if (ns.decls.get(name_str_index)) |i| {
...@@ -4164,7 +4149,6 @@ fn testDecl(...@@ -4164,7 +4149,6 @@ fn testDecl(
41644149
4165 var fn_block: GenZir = .{4150 var fn_block: GenZir = .{
4166 .force_comptime = false,4151 .force_comptime = false,
4167 .in_defer = false,
4168 .decl_node_index = node,4152 .decl_node_index = node,
4169 .decl_line = decl_block.decl_line,4153 .decl_line = decl_block.decl_line,
4170 .parent = &decl_block.base,4154 .parent = &decl_block.base,
...@@ -4288,7 +4272,6 @@ fn structDeclInner(...@@ -4288,7 +4272,6 @@ fn structDeclInner(
4288 .decl_line = decl_line,4272 .decl_line = decl_line,
4289 .astgen = astgen,4273 .astgen = astgen,
4290 .force_comptime = true,4274 .force_comptime = true,
4291 .in_defer = false,
4292 .instructions = gz.instructions,4275 .instructions = gz.instructions,
4293 .instructions_top = gz.instructions.items.len,4276 .instructions_top = gz.instructions.items.len,
4294 };4277 };
...@@ -4489,7 +4472,6 @@ fn unionDeclInner(...@@ -4489,7 +4472,6 @@ fn unionDeclInner(
4489 .decl_line = astgen.source_line,4472 .decl_line = astgen.source_line,
4490 .astgen = astgen,4473 .astgen = astgen,
4491 .force_comptime = true,4474 .force_comptime = true,
4492 .in_defer = false,
4493 .instructions = gz.instructions,4475 .instructions = gz.instructions,
4494 .instructions_top = gz.instructions.items.len,4476 .instructions_top = gz.instructions.items.len,
4495 };4477 };
...@@ -4773,7 +4755,6 @@ fn containerDecl(...@@ -4773,7 +4755,6 @@ fn containerDecl(
4773 .decl_line = astgen.source_line,4755 .decl_line = astgen.source_line,
4774 .astgen = astgen,4756 .astgen = astgen,
4775 .force_comptime = true,4757 .force_comptime = true,
4776 .in_defer = false,
4777 .instructions = gz.instructions,4758 .instructions = gz.instructions,
4778 .instructions_top = gz.instructions.items.len,4759 .instructions_top = gz.instructions.items.len,
4779 };4760 };
...@@ -4879,7 +4860,6 @@ fn containerDecl(...@@ -4879,7 +4860,6 @@ fn containerDecl(
4879 .decl_line = astgen.source_line,4860 .decl_line = astgen.source_line,
4880 .astgen = astgen,4861 .astgen = astgen,
4881 .force_comptime = true,4862 .force_comptime = true,
4882 .in_defer = false,
4883 .instructions = gz.instructions,4863 .instructions = gz.instructions,
4884 .instructions_top = gz.instructions.items.len,4864 .instructions_top = gz.instructions.items.len,
4885 };4865 };
...@@ -5110,7 +5090,15 @@ fn tryExpr(...@@ -5110,7 +5090,15 @@ fn tryExpr(
5110 return astgen.failNode(node, "'try' outside function scope", .{});5090 return astgen.failNode(node, "'try' outside function scope", .{});
5111 };5091 };
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
5115 // Ensure debug line/column information is emitted for this try expression.5103 // Ensure debug line/column information is emitted for this try expression.
5116 // Then we will save the line/column so that we can emit another one that goes5104 // 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...@@ -6656,7 +6644,15 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6656 return astgen.failNode(node, "'return' outside function scope", .{});6644 return astgen.failNode(node, "'return' outside function scope", .{});
6657 }6645 }
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
6661 // Ensure debug line/column information is emitted for this return expression.6657 // Ensure debug line/column information is emitted for this return expression.
6662 // Then we will save the line/column so that we can emit another one that goes6658 // 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...@@ -6683,7 +6679,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6683 // for detecting whether to add something to the function's inferred error set.6679 // for detecting whether to add something to the function's inferred error set.
6684 const ident_token = node_datas[operand_node].rhs;6680 const ident_token = node_datas[operand_node].rhs;
6685 const err_name_str_index = try astgen.identAsString(ident_token);6681 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);
6687 if (!defer_counts.need_err_code) {6683 if (!defer_counts.need_err_code) {
6688 try genDefers(gz, defer_outer, scope, .both_sans_err);6684 try genDefers(gz, defer_outer, scope, .both_sans_err);
6689 try emitDbgStmt(gz, ret_line, ret_column);6685 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...@@ -6724,7 +6720,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6724 return Zir.Inst.Ref.unreachable_value;6720 return Zir.Inst.Ref.unreachable_value;
6725 },6721 },
6726 .maybe => {6722 .maybe => {
6727 const defer_counts = countDefers(astgen, defer_outer, scope);6723 const defer_counts = countDefers(defer_outer, scope);
6728 if (!defer_counts.have_err) {6724 if (!defer_counts.have_err) {
6729 // Only regular defers; no branch needed.6725 // Only regular defers; no branch needed.
6730 try genDefers(gz, defer_outer, scope, .normal_only);6726 try genDefers(gz, defer_outer, scope, .normal_only);
...@@ -6921,7 +6917,6 @@ fn localVarRef(...@@ -6921,7 +6917,6 @@ fn localVarRef(
6921 },6917 },
6922 .gen_zir => s = s.cast(GenZir).?.parent,6918 .gen_zir => s = s.cast(GenZir).?.parent,
6923 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,6919 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
6924 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
6925 .namespace => {6920 .namespace => {
6926 const ns = s.cast(Scope.Namespace).?;6921 const ns = s.cast(Scope.Namespace).?;
6927 if (ns.decls.get(name_str_index)) |i| {6922 if (ns.decls.get(name_str_index)) |i| {
...@@ -7550,7 +7545,6 @@ fn builtinCall(...@@ -7550,7 +7545,6 @@ fn builtinCall(
7550 },7545 },
7551 .gen_zir => s = s.cast(GenZir).?.parent,7546 .gen_zir => s = s.cast(GenZir).?.parent,
7552 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,7547 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
7553 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
7554 .namespace => {7548 .namespace => {
7555 const ns = s.cast(Scope.Namespace).?;7549 const ns = s.cast(Scope.Namespace).?;
7556 if (ns.decls.get(decl_name)) |i| {7550 if (ns.decls.get(decl_name)) |i| {
...@@ -10046,7 +10040,6 @@ const Scope = struct {...@@ -10046,7 +10040,6 @@ const Scope = struct {
10046 local_ptr,10040 local_ptr,
10047 defer_normal,10041 defer_normal,
10048 defer_error,10042 defer_error,
10049 defer_gen,
10050 namespace,10043 namespace,
10051 top,10044 top,
10052 };10045 };
...@@ -10105,10 +10098,9 @@ const Scope = struct {...@@ -10105,10 +10098,9 @@ const Scope = struct {
10105 base: Scope,10098 base: Scope,
10106 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.10099 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`, `Namespace`.
10107 parent: *Scope,10100 parent: *Scope,
10108 defer_node: Ast.Node.Index,10101 index: u32,
10109 source_offset: u32,10102 len: u32,
10110 source_line: u32,10103 remapped_err_code: Zir.Inst.Index = 0,
10111 source_column: u32,
10112 };10104 };
1011310105
10114 /// Represents a global scope that has any number of declarations in it.10106 /// Represents a global scope that has any number of declarations in it.
...@@ -10144,13 +10136,6 @@ const Scope = struct {...@@ -10144,13 +10136,6 @@ const Scope = struct {
10144 const base_tag: Scope.Tag = .top;10136 const base_tag: Scope.Tag = .top;
10145 base: Scope = Scope{ .tag = base_tag },10137 base: Scope = Scope{ .tag = base_tag },
10146 };10138 };
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 };
10154};10139};
1015510140
10156/// This is a temporary structure; references to it are valid only10141/// This is a temporary structure; references to it are valid only
...@@ -10161,7 +10146,6 @@ const GenZir = struct {...@@ -10161,7 +10146,6 @@ const GenZir = struct {
10161 force_comptime: bool,10146 force_comptime: bool,
10162 /// This is set to true for inline loops; false otherwise.10147 /// This is set to true for inline loops; false otherwise.
10163 is_inline: bool = false,10148 is_inline: bool = false,
10164 in_defer: bool,
10165 c_import: bool = false,10149 c_import: bool = false,
10166 /// How decls created in this scope should be named.10150 /// How decls created in this scope should be named.
10167 anon_name_strategy: Zir.Inst.NameStrategy = .anon,10151 anon_name_strategy: Zir.Inst.NameStrategy = .anon,
...@@ -10204,6 +10188,10 @@ const GenZir = struct {...@@ -10204,6 +10188,10 @@ const GenZir = struct {
1020410188
10205 suspend_node: Ast.Node.Index = 0,10189 suspend_node: Ast.Node.Index = 0,
10206 nosuspend_node: Ast.Node.Index = 0,10190 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
10208 /// Namespace members are lazy. When executing a decl within a namespace,10196 /// Namespace members are lazy. When executing a decl within a namespace,
10209 /// any references to external instructions need to be treated specially.10197 /// any references to external instructions need to be treated specially.
...@@ -10244,7 +10232,6 @@ const GenZir = struct {...@@ -10244,7 +10232,6 @@ const GenZir = struct {
10244 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {10232 fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir {
10245 return .{10233 return .{
10246 .force_comptime = gz.force_comptime,10234 .force_comptime = gz.force_comptime,
10247 .in_defer = gz.in_defer,
10248 .c_import = gz.c_import,10235 .c_import = gz.c_import,
10249 .decl_node_index = gz.decl_node_index,10236 .decl_node_index = gz.decl_node_index,
10250 .decl_line = gz.decl_line,10237 .decl_line = gz.decl_line,
...@@ -10253,6 +10240,7 @@ const GenZir = struct {...@@ -10253,6 +10240,7 @@ const GenZir = struct {
10253 .astgen = gz.astgen,10240 .astgen = gz.astgen,
10254 .suspend_node = gz.suspend_node,10241 .suspend_node = gz.suspend_node,
10255 .nosuspend_node = gz.nosuspend_node,10242 .nosuspend_node = gz.nosuspend_node,
10243 .any_defer_node = gz.any_defer_node,
10256 .instructions = gz.instructions,10244 .instructions = gz.instructions,
10257 .instructions_top = gz.instructions.items.len,10245 .instructions_top = gz.instructions.items.len,
10258 };10246 };
...@@ -11107,6 +11095,16 @@ const GenZir = struct {...@@ -11107,6 +11095,16 @@ const GenZir = struct {
11107 });11095 });
11108 }11096 }
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
11110 fn addDecl(11108 fn addDecl(
11111 gz: *GenZir,11109 gz: *GenZir,
11112 tag: Zir.Inst.Tag,11110 tag: Zir.Inst.Tag,
...@@ -11670,7 +11668,6 @@ fn detectLocalShadowing(...@@ -11670,7 +11668,6 @@ fn detectLocalShadowing(
11670 },11668 },
11671 .gen_zir => s = s.cast(GenZir).?.parent,11669 .gen_zir => s = s.cast(GenZir).?.parent,
11672 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,11670 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
11673 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
11674 .top => break,11671 .top => break,
11675 };11672 };
11676}11673}
...@@ -11809,7 +11806,6 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast....@@ -11809,7 +11806,6 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.
11809 .namespace => s = s.cast(Scope.Namespace).?.parent,11806 .namespace => s = s.cast(Scope.Namespace).?.parent,
11810 .gen_zir => s = s.cast(GenZir).?.parent,11807 .gen_zir => s = s.cast(GenZir).?.parent,
11811 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,11808 .defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
11812 .defer_gen => s = s.cast(Scope.DeferGen).?.parent,
11813 .top => break,11809 .top => break,
11814 };11810 };
11815 gop.value_ptr.* = member_node;11811 gop.value_ptr.* = member_node;
src/Sema.zig+29-5
...@@ -1461,6 +1461,29 @@ fn analyzeBodyInner(...@@ -1461,6 +1461,29 @@ fn analyzeBodyInner(
1461 // break break_data.inst;1461 // break break_data.inst;
1462 // }1462 // }
1463 //},1463 //},
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 },
1464 };1487 };
1465 if (sema.typeOf(air_inst).isNoReturn())1488 if (sema.typeOf(air_inst).isNoReturn())
1466 break always_noreturn;1489 break always_noreturn;
...@@ -9394,11 +9417,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9394,11 +9417,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9394 }9417 }
93959418
9396 if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) {9419 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
9402 // In order to enable common patterns for generic code allow simple else bodies9420 // In order to enable common patterns for generic code allow simple else bodies
9403 // else => unreachable,9421 // else => unreachable,
9404 // else => return,9422 // else => return,
...@@ -9415,6 +9433,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -9415,6 +9433,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
9415 .as_node,9433 .as_node,
9416 .ret_node,9434 .ret_node,
9417 .@"unreachable",9435 .@"unreachable",
9436 .@"defer",
9437 .defer_err_code,
9438 .err_union_code,
9439 .ret_err_value_code,
9440 .is_non_err,
9441 .condbr,
9418 => {},9442 => {},
9419 else => break,9443 else => break,
9420 } else break :else_validation;9444 } else break :else_validation;
src/Zir.zig+30
...@@ -995,6 +995,13 @@ pub const Inst = struct {...@@ -995,6 +995,13 @@ pub const Inst = struct {
995 /// closure_capture instruction ref.995 /// closure_capture instruction ref.
996 closure_get,996 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
998 /// The ZIR instruction tag is one of the `Extended` ones.1005 /// The ZIR instruction tag is one of the `Extended` ones.
999 /// Uses the `extended` union field.1006 /// Uses the `extended` union field.
1000 extended,1007 extended,
...@@ -1244,6 +1251,8 @@ pub const Inst = struct {...@@ -1244,6 +1251,8 @@ pub const Inst = struct {
1244 .try_ptr,1251 .try_ptr,
1245 //.try_inline,1252 //.try_inline,
1246 //.try_ptr_inline,1253 //.try_ptr_inline,
1254 .@"defer",
1255 .defer_err_code,
1247 => false,1256 => false,
12481257
1249 .@"break",1258 .@"break",
...@@ -1311,6 +1320,8 @@ pub const Inst = struct {...@@ -1311,6 +1320,8 @@ pub const Inst = struct {
1311 .memcpy,1320 .memcpy,
1312 .memset,1321 .memset,
1313 .check_comptime_control_flow,1322 .check_comptime_control_flow,
1323 .@"defer",
1324 .defer_err_code,
1314 => true,1325 => true,
13151326
1316 .param,1327 .param,
...@@ -1819,6 +1830,9 @@ pub const Inst = struct {...@@ -1819,6 +1830,9 @@ pub const Inst = struct {
1819 .closure_capture = .un_tok,1830 .closure_capture = .un_tok,
1820 .closure_get = .inst_node,1831 .closure_get = .inst_node,
18211832
1833 .@"defer" = .@"defer",
1834 .defer_err_code = .defer_err_code,
1835
1822 .extended = .extended,1836 .extended = .extended,
1823 });1837 });
1824 };1838 };
...@@ -2575,6 +2589,14 @@ pub const Inst = struct {...@@ -2575,6 +2589,14 @@ pub const Inst = struct {
2575 return zir.nullTerminatedString(self.str);2589 return zir.nullTerminatedString(self.str);
2576 }2590 }
2577 },2591 },
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
2579 // Make sure we don't accidentally add a field to make this union2601 // Make sure we don't accidentally add a field to make this union
2580 // bigger than expected. Note that in Debug builds, Zig is allowed2602 // bigger than expected. Note that in Debug builds, Zig is allowed
...@@ -2611,6 +2633,8 @@ pub const Inst = struct {...@@ -2611,6 +2633,8 @@ pub const Inst = struct {
2611 dbg_stmt,2633 dbg_stmt,
2612 inst_node,2634 inst_node,
2613 str_op,2635 str_op,
2636 @"defer",
2637 defer_err_code,
2614 };2638 };
2615 };2639 };
26162640
...@@ -3550,6 +3574,12 @@ pub const Inst = struct {...@@ -3550,6 +3574,12 @@ pub const Inst = struct {
3550 line: u32,3574 line: u32,
3551 column: u32,3575 column: u32,
3552 };3576 };
3577
3578 pub const DeferErrCode = struct {
3579 remapped_err_code: Index,
3580 index: u32,
3581 len: u32,
3582 };
3553};3583};
35543584
3555pub const SpecialProng = enum { none, @"else", under };3585pub const SpecialProng = enum { none, @"else", under };
src/print_zir.zig+23
...@@ -446,6 +446,9 @@ const Writer = struct {...@@ -446,6 +446,9 @@ const Writer = struct {
446446
447 .closure_get => try self.writeInstNode(stream, inst),447 .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
449 .extended => try self.writeExtended(stream, inst),452 .extended => try self.writeExtended(stream, inst),
450 }453 }
451 }454 }
...@@ -2364,6 +2367,26 @@ const Writer = struct {...@@ -2364,6 +2367,26 @@ const Writer = struct {
2364 try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });2367 try stream.print("{d}, {d})", .{ inst_data.line + 1, inst_data.column + 1 });
2365 }2368 }
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
2367 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {2390 fn writeInstRef(self: *Writer, stream: anytype, ref: Zir.Inst.Ref) !void {
2368 var i: usize = @enumToInt(ref);2391 var i: usize = @enumToInt(ref);
23692392
test/behavior/defer.zig+17
...@@ -127,3 +127,20 @@ test "errdefer with payload" {...@@ -127,3 +127,20 @@ test "errdefer with payload" {
127 try S.doTheTest();127 try S.doTheTest();
128 comptime try S.doTheTest();128 comptime try S.doTheTest();
129}129}
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)); }...@@ -19,3 +19,4 @@ export fn entry() usize { return @sizeOf(@TypeOf(testTrickyDefer)); }
19// target=native19// target=native
20//20//
21// :4:11: error: 'try' not allowed inside defer expression21// :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 {...@@ -13,4 +13,6 @@ pub fn b() !void {
13// error13// error
14//14//
15// :7:11: error: 'try' not allowed inside defer expression15// :7:11: error: 'try' not allowed inside defer expression
16// :7:5: note: defer expression here
16// :10:11: error: cannot return from defer expression17// :10:11: error: cannot return from defer expression
18// :10:5: note: defer expression here