mirror of
https://github.com/ziglang/zig.git
synced 2025-12-26 08:03:08 +00:00
Merge pull request #18584 from Techatrix/fix-switch-on-err
fix ast gen failure to catch incorrect by ref error captures
This commit is contained in:
commit
fe870418b1
@ -841,13 +841,16 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
||||
.@"if",
|
||||
=> {
|
||||
const if_full = tree.fullIf(node).?;
|
||||
if (if_full.error_token) |error_token| {
|
||||
const tag = node_tags[if_full.ast.else_expr];
|
||||
if ((tag == .@"switch" or tag == .switch_comma) and
|
||||
std.mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(error_token + 4)))
|
||||
{
|
||||
return switchExprErrUnion(gz, scope, ri.br(), node, .@"if");
|
||||
no_switch_on_err: {
|
||||
const error_token = if_full.error_token orelse break :no_switch_on_err;
|
||||
switch (node_tags[if_full.ast.else_expr]) {
|
||||
.@"switch", .switch_comma => {},
|
||||
else => break :no_switch_on_err,
|
||||
}
|
||||
const switch_operand = node_datas[if_full.ast.else_expr].lhs;
|
||||
if (node_tags[switch_operand] != .identifier) break :no_switch_on_err;
|
||||
if (!mem.eql(u8, tree.tokenSlice(error_token), tree.tokenSlice(main_tokens[switch_operand]))) break :no_switch_on_err;
|
||||
return switchExprErrUnion(gz, scope, ri.br(), node, .@"if");
|
||||
}
|
||||
return ifExpr(gz, scope, ri.br(), node, if_full);
|
||||
},
|
||||
@ -1026,16 +1029,21 @@ fn expr(gz: *GenZir, scope: *Scope, ri: ResultInfo, node: Ast.Node.Index) InnerE
|
||||
},
|
||||
.@"catch" => {
|
||||
const catch_token = main_tokens[node];
|
||||
const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) blk: {
|
||||
if (token_tags.len > catch_token + 6 and
|
||||
token_tags[catch_token + 4] == .keyword_switch)
|
||||
{
|
||||
if (std.mem.eql(u8, tree.tokenSlice(catch_token + 2), tree.tokenSlice(catch_token + 6))) {
|
||||
return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");
|
||||
}
|
||||
const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe)
|
||||
catch_token + 2
|
||||
else
|
||||
null;
|
||||
no_switch_on_err: {
|
||||
const capture_token = payload_token orelse break :no_switch_on_err;
|
||||
switch (node_tags[node_datas[node].rhs]) {
|
||||
.@"switch", .switch_comma => {},
|
||||
else => break :no_switch_on_err,
|
||||
}
|
||||
break :blk catch_token + 2;
|
||||
} else null;
|
||||
const switch_operand = node_datas[node_datas[node].rhs].lhs;
|
||||
if (node_tags[switch_operand] != .identifier) break :no_switch_on_err;
|
||||
if (!mem.eql(u8, tree.tokenSlice(capture_token), tree.tokenSlice(main_tokens[switch_operand]))) break :no_switch_on_err;
|
||||
return switchExprErrUnion(gz, scope, ri.br(), node, .@"catch");
|
||||
}
|
||||
switch (ri.rl) {
|
||||
.ref, .ref_coerced_ty => return orelseCatchExpr(
|
||||
gz,
|
||||
@ -7219,7 +7227,9 @@ fn switchExprErrUnion(
|
||||
};
|
||||
|
||||
const capture_token = case.payload_token orelse break :blk &err_scope.base;
|
||||
assert(token_tags[capture_token] == .identifier);
|
||||
if (token_tags[capture_token] != .identifier) {
|
||||
return astgen.failTok(capture_token + 1, "error set cannot be captured by reference", .{});
|
||||
}
|
||||
|
||||
const capture_slice = tree.tokenSlice(capture_token);
|
||||
if (mem.eql(u8, capture_slice, "_")) {
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
export fn entry() void {
|
||||
const err: error{Foo} = error.Foo;
|
||||
|
||||
switch (err) {
|
||||
error.Foo => |*foo| {
|
||||
foo catch {};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :5:23: error: error set cannot be captured by reference
|
||||
@ -1,10 +1,8 @@
|
||||
export fn entry() void {
|
||||
const x: error{}!u32 = 0;
|
||||
if (x) |v| v else |_| switch (_) {
|
||||
}
|
||||
if (x) |v| v else |_| switch (_) {}
|
||||
}
|
||||
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
comptime {
|
||||
const e: error{Foo}!u32 = error.Foo;
|
||||
e catch |err| switch (err) {
|
||||
error.Foo => |*foo| {
|
||||
foo catch {};
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
comptime {
|
||||
const e: error{Foo}!u32 = error.Foo;
|
||||
if (e) {} else |err| switch (err) {
|
||||
error.Foo => |*foo| {
|
||||
foo catch {};
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :4:24: error: error set cannot be captured by reference
|
||||
// :13:24: error: error set cannot be captured by reference
|
||||
@ -0,0 +1,22 @@
|
||||
export fn entry1() void {
|
||||
var x: error{Foo}!u32 = 0;
|
||||
_ = &x;
|
||||
if (x) |_| {} else |err| switch (err + 1) {
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
export fn entry2() void {
|
||||
var x: error{Foo}!u32 = 0;
|
||||
_ = &x;
|
||||
_ = x catch |err| switch (err + 1) {
|
||||
else => {},
|
||||
};
|
||||
}
|
||||
|
||||
// error
|
||||
// backend=stage2
|
||||
// target=native
|
||||
//
|
||||
// :4:42: error: invalid operands to binary expression: 'ErrorSet' and 'ComptimeInt'
|
||||
// :12:35: error: invalid operands to binary expression: 'ErrorSet' and 'ComptimeInt'
|
||||
Loading…
x
Reference in New Issue
Block a user