authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-04-28 19:18:39+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-04-30 08:57:50+01:00
logd764716cb5cdcf3dec07d66ce87be915327f564e
treef38773a68062f1bb792405eb7e5a479777c2704b
parente67c344fc0ec62748cbfb645e14b9f99ad3655cd
signaturelock-open Commit is signed but in an unrecognized format.

compiler: remove capturing errdefer from the language

Resolves: https://github.com/ziglang/zig/issues/23734

13 files changed, 31 insertions(+), 267 deletions(-)

doc/langref.html.in+1-1
...@@ -7774,7 +7774,7 @@ ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_f...@@ -7774,7 +7774,7 @@ ContainerField <- doc_comment? (KEYWORD_comptime / !KEYWORD_comptime) !KEYWORD_f
7774BlockStatement7774BlockStatement
7775 <- Statement7775 <- Statement
7776 / KEYWORD_defer BlockExprStatement7776 / KEYWORD_defer BlockExprStatement
7777 / KEYWORD_errdefer Payload? BlockExprStatement7777 / KEYWORD_errdefer BlockExprStatement
7778 / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement7778 / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
77797779
7780Statement7780Statement
lib/compiler/reduce/Walk.zig+1-5
...@@ -223,12 +223,8 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {...@@ -223,12 +223,8 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void {
223 return walkBlock(w, node, statements);223 return walkBlock(w, node, statements);
224 },224 },
225225
226 .@"errdefer" => {
227 const expr = ast.nodeData(node).opt_token_and_node[1];
228 return walkExpression(w, expr);
229 },
230
231 .@"defer",226 .@"defer",
227 .@"errdefer",
232 .@"comptime",228 .@"comptime",
233 .@"nosuspend",229 .@"nosuspend",
234 .@"suspend",230 .@"suspend",
lib/docs/wasm/Walk.zig+1-2
...@@ -1014,8 +1014,7 @@ fn block(...@@ -1014,8 +1014,7 @@ fn block(
10141014
1015 .grouped_expression => try expr(w, scope, parent_decl, ast.nodeData(node).node_and_token[0]),1015 .grouped_expression => try expr(w, scope, parent_decl, ast.nodeData(node).node_and_token[0]),
10161016
1017 .@"defer" => try expr(w, scope, parent_decl, ast.nodeData(node).node),1017 .@"defer", .@"errdefer" => try expr(w, scope, parent_decl, ast.nodeData(node).node),
1018 .@"errdefer" => try expr(w, scope, parent_decl, ast.nodeData(node).opt_token_and_node[1]),
10191018
1020 else => try expr(w, scope, parent_decl, node),1019 else => try expr(w, scope, parent_decl, node),
1021 }1020 }
lib/std/zig/Ast.zig+4-7
...@@ -952,8 +952,8 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {...@@ -952,8 +952,8 @@ pub fn lastToken(tree: Ast, node: Node.Index) TokenIndex {
952 .switch_range,952 .switch_range,
953 => n = tree.nodeData(n).node_and_node[1],953 => n = tree.nodeData(n).node_and_node[1],
954954
955 .test_decl, .@"errdefer" => n = tree.nodeData(n).opt_token_and_node[1],955 .test_decl => n = tree.nodeData(n).opt_token_and_node[1],
956 .@"defer" => n = tree.nodeData(n).node,956 .@"defer", .@"errdefer" => n = tree.nodeData(n).node,
957 .anyframe_type => n = tree.nodeData(n).token_and_node[1],957 .anyframe_type => n = tree.nodeData(n).token_and_node[1],
958958
959 .switch_case_one,959 .switch_case_one,
...@@ -3059,11 +3059,8 @@ pub const Node = struct {...@@ -3059,11 +3059,8 @@ pub const Node = struct {
3059 /// a `assign_destructure` node or a parsing error occured.3059 /// a `assign_destructure` node or a parsing error occured.
3060 aligned_var_decl,3060 aligned_var_decl,
3061 /// `errdefer expr`,3061 /// `errdefer expr`,
3062 /// `errdefer |payload| expr`.
3063 ///3062 ///
3064 /// The `data` field is a `.opt_token_and_node`:3063 /// The `data` field is a `.node` to the deferred expression.
3065 /// 1. a `OptionalTokenIndex` to the payload identifier, if any.
3066 /// 2. a `Node.Index` to the deferred expression.
3067 ///3064 ///
3068 /// The `main_token` field is the `errdefer` token.3065 /// The `main_token` field is the `errdefer` token.
3069 @"errdefer",3066 @"errdefer",
...@@ -3071,7 +3068,7 @@ pub const Node = struct {...@@ -3071,7 +3068,7 @@ pub const Node = struct {
3071 ///3068 ///
3072 /// The `data` field is a `.node` to the deferred expression.3069 /// The `data` field is a `.node` to the deferred expression.
3073 ///3070 ///
3074 /// The `main_token` field is the `defer`.3071 /// The `main_token` field is the `defer` token.
3075 @"defer",3072 @"defer",
3076 /// `lhs catch rhs`,3073 /// `lhs catch rhs`,
3077 /// `lhs catch |err| rhs`.3074 /// `lhs catch |err| rhs`.
lib/std/zig/Ast/Render.zig+1-13
...@@ -394,20 +394,8 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {...@@ -394,20 +394,8 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void {
394 return renderBlock(r, node, statements, space);394 return renderBlock(r, node, statements, space);
395 },395 },
396396
397 .@"errdefer" => {
398 const defer_token = tree.nodeMainToken(node);
399 const maybe_payload_token, const expr = tree.nodeData(node).opt_token_and_node;
400
401 try renderToken(r, defer_token, .maybe_space);
402 if (maybe_payload_token.unwrap()) |payload_token| {
403 try renderToken(r, payload_token - 1, .none); // |
404 try renderIdentifier(r, payload_token, .none, .preserve_when_shadowing); // identifier
405 try renderToken(r, payload_token + 1, .maybe_space); // |
406 }
407 return renderExpression(r, expr, space);
408 },
409
410 .@"defer",397 .@"defer",
398 .@"errdefer",
411 .@"comptime",399 .@"comptime",
412 .@"nosuspend",400 .@"nosuspend",
413 .@"suspend",401 .@"suspend",
lib/std/zig/AstGen.zig+19-120
...@@ -2875,7 +2875,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2875,7 +2875,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2875 .max,2875 .max,
2876 .min,2876 .min,
2877 .@"resume",2877 .@"resume",
2878 .ret_err_value_code,
2879 .ret_ptr,2878 .ret_ptr,
2880 .ret_type,2879 .ret_type,
2881 .for_len,2880 .for_len,
...@@ -2964,7 +2963,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2964,7 +2963,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2964 => break :b true,2963 => break :b true,
29652964
2966 .@"defer" => unreachable,2965 .@"defer" => unreachable,
2967 .defer_err_code => unreachable,
2968 }2966 }
2969 } else switch (maybe_unused_result) {2967 } else switch (maybe_unused_result) {
2970 .none => unreachable,2968 .none => unreachable,
...@@ -2984,60 +2982,28 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As...@@ -2984,60 +2982,28 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
2984 return noreturn_src_node;2982 return noreturn_src_node;
2985}2983}
29862984
2987fn countDefers(outer_scope: *Scope, inner_scope: *Scope) struct {2985fn anyErrdefers(outer_scope: *Scope, inner_scope: *Scope) bool {
2988 have_any: bool,
2989 have_normal: bool,
2990 have_err: bool,
2991 need_err_code: bool,
2992} {
2993 var have_normal = false;
2994 var have_err = false;
2995 var need_err_code = false;
2996 var scope = inner_scope;2986 var scope = inner_scope;
2997 while (scope != outer_scope) {2987 while (scope != outer_scope) {
2998 switch (scope.unwrap()) {2988 switch (scope.unwrap()) {
2999 .gen_zir => |gen_zir| scope = gen_zir.parent,2989 .gen_zir => |gen_zir| scope = gen_zir.parent,
3000 .local_val => |local_val| scope = local_val.parent,2990 .local_val => |local_val| scope = local_val.parent,
3001 .local_ptr => |local_ptr| scope = local_ptr.parent,2991 .local_ptr => |local_ptr| scope = local_ptr.parent,
3002 .defer_normal => |defer_scope| {2992 .defer_normal => |defer_normal| scope = defer_normal.parent,
3003 scope = defer_scope.parent;2993 .defer_error => return true,
3004
3005 have_normal = true;
3006 },
3007 .defer_error => |defer_scope| {
3008 scope = defer_scope.parent;
3009
3010 have_err = true;
3011
3012 const have_err_payload = defer_scope.remapped_err_code != .none;
3013 need_err_code = need_err_code or have_err_payload;
3014 },
3015 .namespace => unreachable,2994 .namespace => unreachable,
3016 .top => unreachable,2995 .top => unreachable,
3017 }2996 }
3018 }2997 }
3019 return .{2998 return false;
3020 .have_any = have_normal or have_err,
3021 .have_normal = have_normal,
3022 .have_err = have_err,
3023 .need_err_code = need_err_code,
3024 };
3025}2999}
30263000
3027const DefersToEmit = union(enum) {
3028 both: Zir.Inst.Ref, // err code
3029 both_sans_err,
3030 normal_only,
3031};
3032
3033fn genDefers(3001fn genDefers(
3034 gz: *GenZir,3002 gz: *GenZir,
3035 outer_scope: *Scope,3003 outer_scope: *Scope,
3036 inner_scope: *Scope,3004 inner_scope: *Scope,
3037 which_ones: DefersToEmit,3005 which_ones: enum { normal_only, normal_and_error },
3038) InnerError!void {3006) InnerError!void {
3039 const gpa = gz.astgen.gpa;
3040
3041 var scope = inner_scope;3007 var scope = inner_scope;
3042 while (scope != outer_scope) {3008 while (scope != outer_scope) {
3043 switch (scope.unwrap()) {3009 switch (scope.unwrap()) {
...@@ -3051,33 +3017,10 @@ fn genDefers(...@@ -3051,33 +3017,10 @@ fn genDefers(
3051 .defer_error => |defer_scope| {3017 .defer_error => |defer_scope| {
3052 scope = defer_scope.parent;3018 scope = defer_scope.parent;
3053 switch (which_ones) {3019 switch (which_ones) {
3054 .both_sans_err => {3020 .normal_only => continue,
3021 .normal_and_error => {
3055 try gz.addDefer(defer_scope.index, defer_scope.len);3022 try gz.addDefer(defer_scope.index, defer_scope.len);
3056 },3023 },
3057 .both => |err_code| {
3058 if (defer_scope.remapped_err_code.unwrap()) |remapped_err_code| {
3059 try gz.instructions.ensureUnusedCapacity(gpa, 1);
3060 try gz.astgen.instructions.ensureUnusedCapacity(gpa, 1);
3061
3062 const payload_index = try gz.astgen.addExtra(Zir.Inst.DeferErrCode{
3063 .remapped_err_code = remapped_err_code,
3064 .index = defer_scope.index,
3065 .len = defer_scope.len,
3066 });
3067 const new_index: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
3068 gz.astgen.instructions.appendAssumeCapacity(.{
3069 .tag = .defer_err_code,
3070 .data = .{ .defer_err_code = .{
3071 .err_code = err_code,
3072 .payload_index = payload_index,
3073 } },
3074 });
3075 gz.instructions.appendAssumeCapacity(new_index);
3076 } else {
3077 try gz.addDefer(defer_scope.index, defer_scope.len);
3078 }
3079 },
3080 .normal_only => continue,
3081 }3024 }
3082 },3025 },
3083 .namespace => unreachable,3026 .namespace => unreachable,
...@@ -3140,46 +3083,17 @@ fn deferStmt(...@@ -3140,46 +3083,17 @@ fn deferStmt(
3140 defer defer_gen.unstack();3083 defer defer_gen.unstack();
31413084
3142 const tree = gz.astgen.tree;3085 const tree = gz.astgen.tree;
3143 var local_val_scope: Scope.LocalVal = undefined;3086 const expr_node = tree.nodeData(node).node;
3144 var opt_remapped_err_code: Zir.Inst.OptionalIndex = .none;3087 _ = try unusedResultExpr(&defer_gen, &defer_gen.base, expr_node);
3145 const sub_scope = if (scope_tag != .defer_error) &defer_gen.base else blk: {3088 try checkUsed(gz, scope, &defer_gen.base);
3146 const payload_token = tree.nodeData(node).opt_token_and_node[0].unwrap() orelse break :blk &defer_gen.base;
3147 const ident_name = try gz.astgen.identAsString(payload_token);
3148 if (std.mem.eql(u8, tree.tokenSlice(payload_token), "_")) {
3149 try gz.astgen.appendErrorTok(payload_token, "discard of error capture; omit it instead", .{});
3150 break :blk &defer_gen.base;
3151 }
3152 const remapped_err_code: Zir.Inst.Index = @enumFromInt(gz.astgen.instructions.len);
3153 opt_remapped_err_code = remapped_err_code.toOptional();
3154 _ = try gz.astgen.appendPlaceholder();
3155 const remapped_err_code_ref = remapped_err_code.toRef();
3156 local_val_scope = .{
3157 .parent = &defer_gen.base,
3158 .gen_zir = gz,
3159 .name = ident_name,
3160 .inst = remapped_err_code_ref,
3161 .token_src = payload_token,
3162 .id_cat = .capture,
3163 };
3164 try gz.addDbgVar(.dbg_var_val, ident_name, remapped_err_code_ref);
3165 break :blk &local_val_scope.base;
3166 };
3167 const expr_node = switch (scope_tag) {
3168 .defer_normal => tree.nodeData(node).node,
3169 .defer_error => tree.nodeData(node).opt_token_and_node[1],
3170 else => unreachable,
3171 };
3172 _ = try unusedResultExpr(&defer_gen, sub_scope, expr_node);
3173 try checkUsed(gz, scope, sub_scope);
3174 _ = try defer_gen.addBreak(.break_inline, @enumFromInt(0), .void_value);3089 _ = try defer_gen.addBreak(.break_inline, @enumFromInt(0), .void_value);
31753090
3176 const body = defer_gen.instructionsSlice();3091 const body = defer_gen.instructionsSlice();
3177 const extra_insts: []const Zir.Inst.Index = if (opt_remapped_err_code.unwrap()) |ec| &.{ec} else &.{};3092 const body_len = gz.astgen.countBodyLenAfterFixupsExtraRefs(body, &.{});
3178 const body_len = gz.astgen.countBodyLenAfterFixupsExtraRefs(body, extra_insts);
31793093
3180 const index: u32 = @intCast(gz.astgen.extra.items.len);3094 const index: u32 = @intCast(gz.astgen.extra.items.len);
3181 try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_len);3095 try gz.astgen.extra.ensureUnusedCapacity(gz.astgen.gpa, body_len);
3182 gz.astgen.appendBodyWithFixupsExtraRefsArrayList(&gz.astgen.extra, body, extra_insts);3096 gz.astgen.appendBodyWithFixupsExtraRefsArrayList(&gz.astgen.extra, body, &.{});
31833097
3184 const defer_scope = try block_arena.create(Scope.Defer);3098 const defer_scope = try block_arena.create(Scope.Defer);
31853099
...@@ -3188,7 +3102,6 @@ fn deferStmt(...@@ -3188,7 +3102,6 @@ fn deferStmt(
3188 .parent = scope,3102 .parent = scope,
3189 .index = index,3103 .index = index,
3190 .len = body_len,3104 .len = body_len,
3191 .remapped_err_code = opt_remapped_err_code,
3192 };3105 };
3193 return &defer_scope.base;3106 return &defer_scope.base;
3194}3107}
...@@ -5882,7 +5795,7 @@ fn tryExpr(...@@ -5882,7 +5795,7 @@ fn tryExpr(
5882 else => Zir.Inst.Tag.err_union_code,5795 else => Zir.Inst.Tag.err_union_code,
5883 };5796 };
5884 const err_code = try else_scope.addUnNode(err_tag, operand, node);5797 const err_code = try else_scope.addUnNode(err_tag, operand, node);
5885 try genDefers(&else_scope, &fn_block.base, scope, .{ .both = err_code });5798 try genDefers(&else_scope, &fn_block.base, scope, .normal_and_error);
5886 try emitDbgStmt(&else_scope, try_lc);5799 try emitDbgStmt(&else_scope, try_lc);
5887 _ = try else_scope.addUnNode(.ret_node, err_code, node);5800 _ = try else_scope.addUnNode(.ret_node, err_code, node);
58885801
...@@ -8033,18 +7946,10 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -8033,18 +7946,10 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
8033 // for detecting whether to add something to the function's inferred error set.7946 // for detecting whether to add something to the function's inferred error set.
8034 const ident_token = tree.nodeMainToken(operand_node) + 2;7947 const ident_token = tree.nodeMainToken(operand_node) + 2;
8035 const err_name_str_index = try astgen.identAsString(ident_token);7948 const err_name_str_index = try astgen.identAsString(ident_token);
8036 const defer_counts = countDefers(defer_outer, scope);7949 try genDefers(gz, defer_outer, scope, .normal_and_error);
8037 if (!defer_counts.need_err_code) {
8038 try genDefers(gz, defer_outer, scope, .both_sans_err);
8039 try emitDbgStmt(gz, ret_lc);
8040 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
8041 return Zir.Inst.Ref.unreachable_value;
8042 }
8043 const err_code = try gz.addStrTok(.ret_err_value_code, err_name_str_index, ident_token);
8044 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
8045 try emitDbgStmt(gz, ret_lc);7950 try emitDbgStmt(gz, ret_lc);
8046 _ = try gz.addUnNode(.ret_node, err_code, node);7951 _ = try gz.addStrTok(.ret_err_value, err_name_str_index, ident_token);
8047 return Zir.Inst.Ref.unreachable_value;7952 return .unreachable_value;
8048 }7953 }
80497954
8050 const ri: ResultInfo = if (astgen.nodes_need_rl.contains(node)) .{7955 const ri: ResultInfo = if (astgen.nodes_need_rl.contains(node)) .{
...@@ -8071,15 +7976,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -8071,15 +7976,13 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
8071 },7976 },
8072 .always => {7977 .always => {
8073 // Value is always an error. Emit both error defers and regular defers.7978 // Value is always an error. Emit both error defers and regular defers.
8074 const err_code = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand;7979 try genDefers(gz, defer_outer, scope, .normal_and_error);
8075 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
8076 try emitDbgStmt(gz, ret_lc);7980 try emitDbgStmt(gz, ret_lc);
8077 try gz.addRet(ri, operand, node);7981 try gz.addRet(ri, operand, node);
8078 return Zir.Inst.Ref.unreachable_value;7982 return Zir.Inst.Ref.unreachable_value;
8079 },7983 },
8080 .maybe => {7984 .maybe => {
8081 const defer_counts = countDefers(defer_outer, scope);7985 if (!anyErrdefers(defer_outer, scope)) {
8082 if (!defer_counts.have_err) {
8083 // Only regular defers; no branch needed.7986 // Only regular defers; no branch needed.
8084 try genDefers(gz, defer_outer, scope, .normal_only);7987 try genDefers(gz, defer_outer, scope, .normal_only);
8085 try emitDbgStmt(gz, ret_lc);7988 try emitDbgStmt(gz, ret_lc);
...@@ -8111,10 +8014,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -8111,10 +8014,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
8111 var else_scope = gz.makeSubBlock(scope);8014 var else_scope = gz.makeSubBlock(scope);
8112 defer else_scope.unstack();8015 defer else_scope.unstack();
81138016
8114 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{8017 try genDefers(&else_scope, defer_outer, scope, .normal_and_error);
8115 .both = try else_scope.addUnNode(.err_union_code, result, node),
8116 };
8117 try genDefers(&else_scope, defer_outer, scope, which_ones);
8118 try emitDbgStmt(&else_scope, ret_lc);8018 try emitDbgStmt(&else_scope, ret_lc);
8119 try else_scope.addRet(ri, operand, node);8019 try else_scope.addRet(ri, operand, node);
81208020
...@@ -11239,7 +11139,6 @@ const Scope = struct {...@@ -11239,7 +11139,6 @@ const Scope = struct {
11239 parent: *Scope,11139 parent: *Scope,
11240 index: u32,11140 index: u32,
11241 len: u32,11141 len: u32,
11242 remapped_err_code: Zir.Inst.OptionalIndex = .none,
11243 };11142 };
1124411143
11245 /// Represents a global scope that has any number of declarations in it.11144 /// Represents a global scope that has any number of declarations in it.
lib/std/zig/AstRlAnnotate.zig+1-5
...@@ -141,11 +141,7 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI...@@ -141,11 +141,7 @@ fn expr(astrl: *AstRlAnnotate, node: Ast.Node.Index, block: ?*Block, ri: ResultI
141 .asm_input,141 .asm_input,
142 => unreachable,142 => unreachable,
143143
144 .@"errdefer" => {144 .@"defer", .@"errdefer" => {
145 _ = try astrl.expr(tree.nodeData(node).opt_token_and_node[1], block, ResultInfo.none);
146 return false;
147 },
148 .@"defer" => {
149 _ = try astrl.expr(tree.nodeData(node).node, block, ResultInfo.none);145 _ = try astrl.expr(tree.nodeData(node).node, block, ResultInfo.none);
150 return false;146 return false;
151 },147 },
lib/std/zig/AstSmith.zig+1-1
...@@ -486,7 +486,7 @@ fn pegContainerField(a: *AstSmith) SourceError!void {...@@ -486,7 +486,7 @@ fn pegContainerField(a: *AstSmith) SourceError!void {
486/// BlockStatement486/// BlockStatement
487/// <- Statement487/// <- Statement
488/// / KEYWORD_defer BlockExprStatement488/// / KEYWORD_defer BlockExprStatement
489/// / KEYWORD_errdefer Payload? BlockExprStatement489/// / KEYWORD_errdefer BlockExprStatement
490/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement490/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
491fn pegBlockStatement(a: *AstSmith) SourceError!void {491fn pegBlockStatement(a: *AstSmith) SourceError!void {
492 const Kind = enum {492 const Kind = enum {
lib/std/zig/Parse.zig+2-5
...@@ -909,7 +909,7 @@ fn expectContainerField(p: *Parse) !Node.Index {...@@ -909,7 +909,7 @@ fn expectContainerField(p: *Parse) !Node.Index {
909/// BlockStatement909/// BlockStatement
910/// <- Statement910/// <- Statement
911/// / KEYWORD_defer BlockExprStatement911/// / KEYWORD_defer BlockExprStatement
912/// / KEYWORD_errdefer Payload? BlockExprStatement912/// / KEYWORD_errdefer BlockExprStatement
913/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement913/// / !ExprStatement (KEYWORD_comptime !BlockExpr)? VarAssignStatement
914///914///
915/// Statement915/// Statement
...@@ -975,10 +975,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {...@@ -975,10 +975,7 @@ fn expectStatement(p: *Parse, is_block_level: bool) Error!Node.Index {
975 .keyword_errdefer => if (is_block_level) return p.addNode(.{975 .keyword_errdefer => if (is_block_level) return p.addNode(.{
976 .tag = .@"errdefer",976 .tag = .@"errdefer",
977 .main_token = p.nextToken(),977 .main_token = p.nextToken(),
978 .data = .{ .opt_token_and_node = .{978 .data = .{ .node = try p.expectBlockExprStatement() },
979 try p.parsePayload(),
980 try p.expectBlockExprStatement(),
981 } },
982 }),979 }),
983 .keyword_if => return p.expectIfStatement(),980 .keyword_if => return p.expectIfStatement(),
984 .keyword_enum, .keyword_struct, .keyword_union => {981 .keyword_enum, .keyword_struct, .keyword_union => {
lib/std/zig/Zir.zig-37
...@@ -597,13 +597,6 @@ pub const Inst = struct {...@@ -597,13 +597,6 @@ pub const Inst = struct {
597 /// name is added to it.597 /// name is added to it.
598 /// Uses the `str_tok` union field.598 /// Uses the `str_tok` union field.
599 ret_err_value,599 ret_err_value,
600 /// A string name is provided which is an anonymous error set value.
601 /// If the current function has an inferred error set, the error given by the
602 /// name is added to it.
603 /// Results in the error code. Note that control flow is not diverted with
604 /// this instruction; a following 'ret' instruction will do the diversion.
605 /// Uses the `str_tok` union field.
606 ret_err_value_code,
607 /// Obtains a pointer to the return value.600 /// Obtains a pointer to the return value.
608 /// Uses the `node` union field.601 /// Uses the `node` union field.
609 ret_ptr,602 ret_ptr,
...@@ -1066,9 +1059,6 @@ pub const Inst = struct {...@@ -1066,9 +1059,6 @@ pub const Inst = struct {
1066 /// A defer statement.1059 /// A defer statement.
1067 /// Uses the `defer` union field.1060 /// Uses the `defer` union field.
1068 @"defer",1061 @"defer",
1069 /// An errdefer statement with a code.
1070 /// Uses the `err_defer_code` union field.
1071 defer_err_code,
10721062
1073 /// Requests that Sema update the saved error return trace index for the enclosing1063 /// Requests that Sema update the saved error return trace index for the enclosing
1074 /// block, if the operand is .none or of an error/error-union type.1064 /// block, if the operand is .none or of an error/error-union type.
...@@ -1295,14 +1285,12 @@ pub const Inst = struct {...@@ -1295,14 +1285,12 @@ pub const Inst = struct {
1295 .memmove,1285 .memmove,
1296 .min,1286 .min,
1297 .@"resume",1287 .@"resume",
1298 .ret_err_value_code,
1299 .extended,1288 .extended,
1300 .ret_ptr,1289 .ret_ptr,
1301 .ret_type,1290 .ret_type,
1302 .@"try",1291 .@"try",
1303 .try_ptr,1292 .try_ptr,
1304 .@"defer",1293 .@"defer",
1305 .defer_err_code,
1306 .save_err_ret_index,1294 .save_err_ret_index,
1307 .for_len,1295 .for_len,
1308 .opt_eu_base_ptr_init,1296 .opt_eu_base_ptr_init,
...@@ -1377,7 +1365,6 @@ pub const Inst = struct {...@@ -1377,7 +1365,6 @@ pub const Inst = struct {
1377 .memmove,1365 .memmove,
1378 .check_comptime_control_flow,1366 .check_comptime_control_flow,
1379 .@"defer",1367 .@"defer",
1380 .defer_err_code,
1381 .save_err_ret_index,1368 .save_err_ret_index,
1382 .restore_err_ret_index_unconditional,1369 .restore_err_ret_index_unconditional,
1383 .restore_err_ret_index_fn_entry,1370 .restore_err_ret_index_fn_entry,
...@@ -1574,7 +1561,6 @@ pub const Inst = struct {...@@ -1574,7 +1561,6 @@ pub const Inst = struct {
1574 .max,1561 .max,
1575 .min,1562 .min,
1576 .@"resume",1563 .@"resume",
1577 .ret_err_value_code,
1578 .@"break",1564 .@"break",
1579 .break_inline,1565 .break_inline,
1580 .condbr,1566 .condbr,
...@@ -1732,7 +1718,6 @@ pub const Inst = struct {...@@ -1732,7 +1718,6 @@ pub const Inst = struct {
1732 .ret_load = .un_node,1718 .ret_load = .un_node,
1733 .ret_implicit = .un_tok,1719 .ret_implicit = .un_tok,
1734 .ret_err_value = .str_tok,1720 .ret_err_value = .str_tok,
1735 .ret_err_value_code = .str_tok,
1736 .ret_ptr = .node,1721 .ret_ptr = .node,
1737 .ret_type = .node,1722 .ret_type = .node,
1738 .ptr_type = .ptr_type,1723 .ptr_type = .ptr_type,
...@@ -1866,7 +1851,6 @@ pub const Inst = struct {...@@ -1866,7 +1851,6 @@ pub const Inst = struct {
1866 .@"resume" = .un_node,1851 .@"resume" = .un_node,
18671852
1868 .@"defer" = .@"defer",1853 .@"defer" = .@"defer",
1869 .defer_err_code = .defer_err_code,
18701854
1871 .save_err_ret_index = .save_err_ret_index,1855 .save_err_ret_index = .save_err_ret_index,
1872 .restore_err_ret_index_unconditional = .un_node,1856 .restore_err_ret_index_unconditional = .un_node,
...@@ -2484,10 +2468,6 @@ pub const Inst = struct {...@@ -2484,10 +2468,6 @@ pub const Inst = struct {
2484 index: u32,2468 index: u32,
2485 len: u32,2469 len: u32,
2486 },2470 },
2487 defer_err_code: struct {
2488 err_code: Ref,
2489 payload_index: u32,
2490 },
2491 save_err_ret_index: struct {2471 save_err_ret_index: struct {
2492 operand: Ref, // If error type (or .none), save new trace index2472 operand: Ref, // If error type (or .none), save new trace index
2493 },2473 },
...@@ -2538,7 +2518,6 @@ pub const Inst = struct {...@@ -2538,7 +2518,6 @@ pub const Inst = struct {
2538 inst_node,2518 inst_node,
2539 str_op,2519 str_op,
2540 @"defer",2520 @"defer",
2541 defer_err_code,
2542 save_err_ret_index,2521 save_err_ret_index,
2543 elem_val_imm,2522 elem_val_imm,
2544 declaration,2523 declaration,
...@@ -3974,12 +3953,6 @@ pub const Inst = struct {...@@ -3974,12 +3953,6 @@ pub const Inst = struct {
3974 column: u32,3953 column: u32,
3975 };3954 };
39763955
3977 pub const DeferErrCode = struct {
3978 remapped_err_code: Index,
3979 index: u32,
3980 len: u32,
3981 };
3982
3983 pub const ValidateDestructure = struct {3956 pub const ValidateDestructure = struct {
3984 /// The value being destructured.3957 /// The value being destructured.
3985 operand: Ref,3958 operand: Ref,
...@@ -4222,7 +4195,6 @@ fn findTrackableInner(...@@ -4222,7 +4195,6 @@ fn findTrackableInner(
4222 .ret_load,4195 .ret_load,
4223 .ret_implicit,4196 .ret_implicit,
4224 .ret_err_value,4197 .ret_err_value,
4225 .ret_err_value_code,
4226 .ret_ptr,4198 .ret_ptr,
4227 .ret_type,4199 .ret_type,
4228 .ptr_type,4200 .ptr_type,
...@@ -4621,15 +4593,6 @@ fn findTrackableInner(...@@ -4621,15 +4593,6 @@ fn findTrackableInner(
4621 try zir.findTrackableBody(gpa, contents, defers, body);4593 try zir.findTrackableBody(gpa, contents, defers, body);
4622 }4594 }
4623 },4595 },
4624 .defer_err_code => {
4625 const inst_data = datas[@intFromEnum(inst)].defer_err_code;
4626 const extra = zir.extraData(Inst.DeferErrCode, inst_data.payload_index).data;
4627 const gop = try defers.getOrPut(gpa, extra.index);
4628 if (!gop.found_existing) {
4629 const body = zir.bodySlice(extra.index, extra.len);
4630 try zir.findTrackableBody(gpa, contents, defers, body);
4631 }
4632 },
4633 }4596 }
4634}4597}
46354598
lib/std/zig/parser_test.zig-13
...@@ -298,19 +298,6 @@ test "zig fmt: decl between fields" {...@@ -298,19 +298,6 @@ test "zig fmt: decl between fields" {
298 });298 });
299}299}
300300
301test "zig fmt: errdefer with payload" {
302 try testCanonical(
303 \\pub fn main() anyerror!void {
304 \\ errdefer |a| x += 1;
305 \\ errdefer |a| {}
306 \\ errdefer |a| {
307 \\ x += 1;
308 \\ }
309 \\}
310 \\
311 );
312}
313
314test "zig fmt: nosuspend block" {301test "zig fmt: nosuspend block" {
315 try testCanonical(302 try testCanonical(
316 \\pub fn main() anyerror!void {303 \\pub fn main() anyerror!void {
src/Sema.zig-43
...@@ -1245,7 +1245,6 @@ fn analyzeBodyInner(...@@ -1245,7 +1245,6 @@ fn analyzeBodyInner(
1245 .optional_type => try sema.zirOptionalType(block, inst),1245 .optional_type => try sema.zirOptionalType(block, inst),
1246 .ptr_type => try sema.zirPtrType(block, inst),1246 .ptr_type => try sema.zirPtrType(block, inst),
1247 .ref => try sema.zirRef(block, inst),1247 .ref => try sema.zirRef(block, inst),
1248 .ret_err_value_code => try sema.zirRetErrValueCode(inst),
1249 .shr => try sema.zirShr(block, inst, .shr),1248 .shr => try sema.zirShr(block, inst, .shr),
1250 .shr_exact => try sema.zirShr(block, inst, .shr_exact),1249 .shr_exact => try sema.zirShr(block, inst, .shr_exact),
1251 .slice_end => try sema.zirSliceEnd(block, inst),1250 .slice_end => try sema.zirSliceEnd(block, inst),
...@@ -1969,25 +1968,6 @@ fn analyzeBodyInner(...@@ -1969,25 +1968,6 @@ fn analyzeBodyInner(
1969 }1968 }
1970 break :blk .void_value;1969 break :blk .void_value;
1971 },1970 },
1972 .defer_err_code => blk: {
1973 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].defer_err_code;
1974 const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
1975 const defer_body = sema.code.bodySlice(extra.index, extra.len);
1976 const err_code = sema.resolveInst(inst_data.err_code);
1977 try map.ensureSpaceForInstructions(sema.gpa, defer_body);
1978 map.putAssumeCapacity(extra.remapped_err_code, err_code);
1979 if (sema.analyzeBodyInner(block, defer_body)) {
1980 // The defer terminated noreturn - no more analysis needed.
1981 break;
1982 } else |err| switch (err) {
1983 error.ComptimeBreak => {},
1984 else => |e| return e,
1985 }
1986 if (sema.comptime_break_inst != defer_body[defer_body.len - 1]) {
1987 return error.ComptimeBreak;
1988 }
1989 break :blk .void_value;
1990 },
1991 };1971 };
19921972
1993 const is_inferred_alloc = if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) {1973 const is_inferred_alloc = if (air_ref.toIndex()) |air_inst| switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst)]) {
...@@ -12938,29 +12918,6 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -12938,29 +12918,6 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
12938 return Air.internedToRef(result.val);12918 return Air.internedToRef(result.val);
12939}12919}
1294012920
12941fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
12942 const pt = sema.pt;
12943 const zcu = pt.zcu;
12944 const comp = zcu.comp;
12945 const gpa = comp.gpa;
12946 const io = comp.io;
12947
12948 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
12949 const name = try zcu.intern_pool.getOrPutString(
12950 gpa,
12951 io,
12952 pt.tid,
12953 inst_data.get(sema.code),
12954 .no_embedded_nulls,
12955 );
12956 _ = try pt.getErrorValue(name);
12957 const error_set_type = try pt.singleErrorSetType(name);
12958 return Air.internedToRef((try pt.intern(.{ .err = .{
12959 .ty = error_set_type.toIntern(),
12960 .name = name,
12961 } })));
12962}
12963
12964fn zirShl(12921fn zirShl(
12965 sema: *Sema,12922 sema: *Sema,
12966 block: *Block,12923 block: *Block,
src/print_zir.zig-15
...@@ -477,7 +477,6 @@ const Writer = struct {...@@ -477,7 +477,6 @@ const Writer = struct {
477 .decl_ref,477 .decl_ref,
478 .decl_val,478 .decl_val,
479 .ret_err_value,479 .ret_err_value,
480 .ret_err_value_code,
481 .param_anytype,480 .param_anytype,
482 .param_anytype_comptime,481 .param_anytype_comptime,
483 => try self.writeStrTok(stream, inst),482 => try self.writeStrTok(stream, inst),
...@@ -497,7 +496,6 @@ const Writer = struct {...@@ -497,7 +496,6 @@ const Writer = struct {
497 .dbg_stmt => try self.writeDbgStmt(stream, inst),496 .dbg_stmt => try self.writeDbgStmt(stream, inst),
498497
499 .@"defer" => try self.writeDefer(stream, inst),498 .@"defer" => try self.writeDefer(stream, inst),
500 .defer_err_code => try self.writeDeferErrCode(stream, inst),
501499
502 .declaration => try self.writeDeclaration(stream, inst),500 .declaration => try self.writeDeclaration(stream, inst),
503501
...@@ -2186,19 +2184,6 @@ const Writer = struct {...@@ -2186,19 +2184,6 @@ const Writer = struct {
2186 try stream.writeByte(')');2184 try stream.writeByte(')');
2187 }2185 }
21882186
2189 fn writeDeferErrCode(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
2190 const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].defer_err_code;
2191 const extra = self.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
2192
2193 try self.writeInstRef(stream, extra.remapped_err_code.toRef());
2194 try stream.writeAll(" = ");
2195 try self.writeInstRef(stream, inst_data.err_code);
2196 try stream.writeAll(", ");
2197 const body = self.code.bodySlice(extra.index, extra.len);
2198 try self.writeBracedBody(stream, body);
2199 try stream.writeByte(')');
2200 }
2201
2202 fn writeDeclaration(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {2187 fn writeDeclaration(self: *Writer, stream: *std.Io.Writer, inst: Zir.Inst.Index) !void {
2203 const decl = self.code.getDeclaration(inst);2188 const decl = self.code.getDeclaration(inst);
22042189