authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-10-25 13:40:03-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-10-25 13:40:03-04:00
logd4bf44024a005fcd6931fd0975d78c890dedb4e6
tree35931469836f03190a72f3b3a277279a766a4138
parent3f6eef22e4f50c1fb80557f7e48e85d8224b6281
parent9c5b852f9bb47e25c878cbccdaa175517ae48fc6
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10019 from mattbork/ret-fixes

astgen.zig: fixes for error propagation `ret` and return types in `fnDecl` and `fnProtoExpr`

2 files changed, 50 insertions(+), 25 deletions(-)

src/AstGen.zig+34-25
...@@ -1156,16 +1156,6 @@ fn fnProtoExpr(...@@ -1156,16 +1156,6 @@ fn fnProtoExpr(
1156 return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});1156 return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});
1157 }1157 }
11581158
1159 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
1160 const is_inferred_error = token_tags[maybe_bang] == .bang;
1161 if (is_inferred_error) {
1162 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
1163 }
1164 var ret_gz = gz.makeSubBlock(scope);
1165 defer ret_gz.instructions.deinit(gpa);
1166 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
1167 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
1168
1169 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)1159 const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
1170 try expr(1160 try expr(
1171 gz,1161 gz,
...@@ -1176,6 +1166,16 @@ fn fnProtoExpr(...@@ -1176,6 +1166,16 @@ fn fnProtoExpr(
1176 else1166 else
1177 Zir.Inst.Ref.none;1167 Zir.Inst.Ref.none;
11781168
1169 const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
1170 const is_inferred_error = token_tags[maybe_bang] == .bang;
1171 if (is_inferred_error) {
1172 return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
1173 }
1174 var ret_gz = gz.makeSubBlock(scope);
1175 defer ret_gz.instructions.deinit(gpa);
1176 const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
1177 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
1178
1179 const result = try gz.addFunc(.{1179 const result = try gz.addFunc(.{
1180 .src_node = fn_proto.ast.proto_node,1180 .src_node = fn_proto.ast.proto_node,
1181 .param_block = 0,1181 .param_block = 0,
...@@ -3182,11 +3182,6 @@ fn fnDecl(...@@ -3182,11 +3182,6 @@ fn fnDecl(
3182 break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);3182 break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
3183 };3183 };
31843184
3185 var ret_gz = decl_gz.makeSubBlock(params_scope);
3186 defer ret_gz.instructions.deinit(gpa);
3187 const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
3188 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
3189
3190 const cc: Zir.Inst.Ref = blk: {3185 const cc: Zir.Inst.Ref = blk: {
3191 if (fn_proto.ast.callconv_expr != 0) {3186 if (fn_proto.ast.callconv_expr != 0) {
3192 if (has_inline_keyword) {3187 if (has_inline_keyword) {
...@@ -3212,6 +3207,11 @@ fn fnDecl(...@@ -3212,6 +3207,11 @@ fn fnDecl(
3212 }3207 }
3213 };3208 };
32143209
3210 var ret_gz = decl_gz.makeSubBlock(params_scope);
3211 defer ret_gz.instructions.deinit(gpa);
3212 const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
3213 const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
3214
3215 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {3215 const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
3216 if (!is_extern) {3216 if (!is_extern) {
3217 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});3217 return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
...@@ -6500,7 +6500,8 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6500,7 +6500,8 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6500 },6500 },
6501 .always => {6501 .always => {
6502 // Value is always an error. Emit both error defers and regular defers.6502 // Value is always an error. Emit both error defers and regular defers.
6503 const err_code = try gz.addUnNode(.err_union_code, operand, node);6503 const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
6504 const err_code = try gz.addUnNode(.err_union_code, result, node);
6504 try genDefers(gz, defer_outer, scope, .{ .both = err_code });6505 try genDefers(gz, defer_outer, scope, .{ .both = err_code });
6505 try gz.addRet(rl, operand, node);6506 try gz.addRet(rl, operand, node);
6506 return Zir.Inst.Ref.unreachable_value;6507 return Zir.Inst.Ref.unreachable_value;
...@@ -6515,7 +6516,8 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6515,7 +6516,8 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6515 }6516 }
65166517
6517 // Emit conditional branch for generating errdefers.6518 // Emit conditional branch for generating errdefers.
6518 const is_non_err = try gz.addUnNode(.is_non_err, operand, node);6519 const result = if (rl == .ptr) try gz.addUnNode(.load, rl.ptr, node) else operand;
6520 const is_non_err = try gz.addUnNode(.is_non_err, result, node);
6519 const condbr = try gz.addCondBr(.condbr, node);6521 const condbr = try gz.addCondBr(.condbr, node);
65206522
6521 var then_scope = gz.makeSubBlock(scope);6523 var then_scope = gz.makeSubBlock(scope);
...@@ -6528,7 +6530,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref...@@ -6528,7 +6530,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref
6528 defer else_scope.instructions.deinit(astgen.gpa);6530 defer else_scope.instructions.deinit(astgen.gpa);
65296531
6530 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{6532 const which_ones: DefersToEmit = if (!defer_counts.need_err_code) .both_sans_err else .{
6531 .both = try else_scope.addUnNode(.err_union_code, operand, node),6533 .both = try else_scope.addUnNode(.err_union_code, result, node),
6532 };6534 };
6533 try genDefers(&else_scope, defer_outer, scope, which_ones);6535 try genDefers(&else_scope, defer_outer, scope, which_ones);
6534 try else_scope.addRet(rl, operand, node);6536 try else_scope.addRet(rl, operand, node);
...@@ -8514,10 +8516,10 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never...@@ -8514,10 +8516,10 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never
8514 .unwrap_optional,8516 .unwrap_optional,
8515 => node = node_datas[node].lhs,8517 => node = node_datas[node].lhs,
85168518
8517 // Forward the question to the RHS sub-expression.8519 // LHS sub-expression may still be an error under the outer optional or error union
8518 .@"catch",8520 .@"catch",
8519 .@"orelse",8521 .@"orelse",
8520 => node = node_datas[node].rhs,8522 => return .maybe,
85218523
8522 .block_two,8524 .block_two,
8523 .block_two_semicolon,8525 .block_two_semicolon,
...@@ -8544,11 +8546,18 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never...@@ -8544,11 +8546,18 @@ fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never
8544 // If the builtin is an invalid name, we don't cause an error here; instead8546 // If the builtin is an invalid name, we don't cause an error here; instead
8545 // let it pass, and the error will be "invalid builtin function" later.8547 // let it pass, and the error will be "invalid builtin function" later.
8546 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return .maybe;8548 const builtin_info = BuiltinFn.list.get(builtin_name) orelse return .maybe;
8547 if (builtin_info.tag == .err_set_cast) {8549 return switch (builtin_info.tag) {
8548 return .always;8550 .as,
8549 } else {8551 .call,
8550 return .never;8552 .field,
8551 }8553 => .maybe,
8554
8555 .err_set_cast,
8556 .int_to_error,
8557 => .always,
8558
8559 else => .never,
8560 };
8552 },8561 },
8553 }8562 }
8554 }8563 }
test/behavior/fn_stage1.zig+16
...@@ -204,3 +204,19 @@ test "function with inferred error set but returning no error" {...@@ -204,3 +204,19 @@ test "function with inferred error set but returning no error" {
204 const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?;204 const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?;
205 try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len);205 try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len);
206}206}
207
208const nComplexCallconv = 100;
209fn fComplexCallconvRet(x: u32) callconv(blk: {
210 const s: struct { n: u32 } = .{ .n = nComplexCallconv };
211 break :blk switch (s.n) {
212 0 => .C,
213 1 => .Inline,
214 else => .Unspecified,
215 };
216}) struct { x: u32 } {
217 return .{ .x = x * x };
218}
219
220test "function with complex callconv and return type expressions" {
221 try expect(fComplexCallconvRet(3).x == 9);
222}