authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-16 02:42:06-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-01-16 02:42:06-08:00
logfe870418b1d83ad4e08a8fba9785289735d29f4f
treeb7fe04fb408e99e5799433447381e0f741ce5f54
parent7116b02210bcae7bafac9017a7e47a14b52eafc2
parent06410f58bd5378d5544f34dc3e87e3309cbdd332
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #18584 from Techatrix/fix-switch-on-err

fix ast gen failure to catch incorrect by ref error captures

5 files changed, 88 insertions(+), 19 deletions(-)

src/AstGen.zig+26-16
...@@ -841,13 +841,16 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -841,13 +841,16 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
841 .@"if",841 .@"if",
842 => {842 => {
843 const if_full = tree.fullIf(node).?;843 const if_full = tree.fullIf(node).?;
844 if (if_full.error_token) |error_token| {844 no_switch_on_err: {
845 const tag = node_tags[if_full.ast.else_expr];845 const error_token = if_full.error_token orelse break :no_switch_on_err;
846 if ((tag == .@"switch" or tag == .switch_comma) and846 switch (node_tags[if_full.ast.else_expr]) {
847 std.mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(error_token + 4)))847 .@"switch", .switch_comma => {},
848 {848 else => break :no_switch_on_err,
849 return switchExprErrUnion(gz, scope, ri.br(), node, .@"if");
850 }849 }
850 const switch_operand = node_datas[if_full.ast.else_expr].lhs;
851 if (node_tags[switch_operand] != .identifier) break :no_switch_on_err;
852 if (!mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(main_tokens[switch_operand]))) break :no_switch_on_err;
853 return switchExprErrUnion(gz, scope, ri.br(), node, .@"if");
851 }854 }
852 return ifExpr(gz, scope, ri.br(), node, if_full);855 return ifExpr(gz, scope, ri.br(), node, if_full);
853 },856 },
...@@ -1026,16 +1029,21 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE...@@ -1026,16 +1029,21 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
1026 },1029 },
1027 .@"catch" => {1030 .@"catch" => {
1028 const catch_token = main_tokens[node];1031 const catch_token = main_tokens[node];
1029 const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) blk: {1032 const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)
1030 if (token_tags.len > catch_token + 6 and1033 catch_token + 2
1031 token_tags[catch_token + 4] == .keyword_switch)1034 else
1032 {1035 null;
1033 if (std.mem.eql(u8, tree.tokenSlice(catch_token + 2), tree.tokenSlice(catch_token + 6))) {1036 no_switch_on_err: {
1034 return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");1037 const capture_token = payload_token orelse break :no_switch_on_err;
1035 }1038 switch (node_tags[node_datas[node].rhs]) {
1039 .@"switch", .switch_comma => {},
1040 else => break :no_switch_on_err,
1036 }1041 }
1037 break :blk catch_token + 2;1042 const switch_operand = node_datas[node_datas[node].rhs].lhs;
1038 } else null;1043 if (node_tags[switch_operand] != .identifier) break :no_switch_on_err;
1044 if (!mem.eql(u8, tree.tokenSlice(capture_token), tree.tokenSlice(main_tokens[switch_operand]))) break :no_switch_on_err;
1045 return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");
1046 }
1039 switch (ri.rl) {1047 switch (ri.rl) {
1040 .ref, .ref_coerced_ty => return orelseCatchExpr(1048 .ref, .ref_coerced_ty => return orelseCatchExpr(
1041 gz,1049 gz,
...@@ -7219,7 +7227,9 @@ fn switchExprErrUnion(...@@ -7219,7 +7227,9 @@ fn switchExprErrUnion(
7219 };7227 };
72207228
7221 const capture_token = case.payload_token orelse break :blk &err_scope.base;7229 const capture_token = case.payload_token orelse break :blk &err_scope.base;
7222 assert(token_tags[capture_token] == .identifier);7230 if (token_tags[capture_token] != .identifier) {
7231 return astgen.failTok(capture_token + 1, "error set cannot be captured by reference", .{});
7232 }
72237233
7224 const capture_slice = tree.tokenSlice(capture_token);7234 const capture_slice = tree.tokenSlice(capture_token);
7225 if (mem.eql(u8, capture_slice, "_")) {7235 if (mem.eql(u8, capture_slice, "_")) {
test/cases/compile_errors/error_set_cannot_capture_by_reference.zig created+15
...@@ -0,0 +1,15 @@
1export fn entry() void {
2 const err: error{Foo} = error.Foo;
3
4 switch (err) {
5 error.Foo => |*foo| {
6 foo catch {};
7 },
8 }
9}
10
11// error
12// backend=stage2
13// target=native
14//
15// :5:23: error: error set cannot be captured by reference
test/cases/compile_errors/switch_on_error_union_discard.zig+1-3
...@@ -1,10 +1,8 @@...@@ -1,10 +1,8 @@
1export fn entry() void {1export fn entry() void {
2 const x: error{}!u32 = 0;2 const x: error{}!u32 = 0;
3 if (x) |v| v else |_| switch (_) {3 if (x) |v| v else |_| switch (_) {}
4 }
5}4}
65
7
8// error6// error
9// backend=stage27// backend=stage2
10// target=native8// target=native
test/cases/compile_errors/switch_on_error_with_capture_by_reference.zig created+24
...@@ -0,0 +1,24 @@
1comptime {
2 const e: error{Foo}!u32 = error.Foo;
3 e catch |err| switch (err) {
4 error.Foo => |*foo| {
5 foo catch {};
6 },
7 };
8}
9
10comptime {
11 const e: error{Foo}!u32 = error.Foo;
12 if (e) {} else |err| switch (err) {
13 error.Foo => |*foo| {
14 foo catch {};
15 },
16 }
17}
18
19// error
20// backend=stage2
21// target=native
22//
23// :4:24: error: error set cannot be captured by reference
24// :13:24: error: error set cannot be captured by reference
test/cases/compile_errors/switch_on_error_with_non_trivial_switch_operand.zig created+22
...@@ -0,0 +1,22 @@
1export fn entry1() void {
2 var x: error{Foo}!u32 = 0;
3 _ = &x;
4 if (x) |_| {} else |err| switch (err + 1) {
5 else => {},
6 }
7}
8
9export fn entry2() void {
10 var x: error{Foo}!u32 = 0;
11 _ = &x;
12 _ = x catch |err| switch (err + 1) {
13 else => {},
14 };
15}
16
17// error
18// backend=stage2
19// target=native
20//
21// :4:42: error: invalid operands to binary expression: 'ErrorSet' and 'ComptimeInt'
22// :12:35: error: invalid operands to binary expression: 'ErrorSet' and 'ComptimeInt'