Commit 9c5b852f9b

Matthew Borkowski <matthew.h.borkowski@gmail.com>
2021-10-24 03:52:21
astgen.zig: emit ZIR for callconv before return type in fnDecl and fnProtoExpr
1 parent 8a95bac
Changed files (2)
src
test
behavior
src/AstGen.zig
@@ -1156,16 +1156,6 @@ fn fnProtoExpr(
         return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});
     }
 
-    const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
-    const is_inferred_error = token_tags[maybe_bang] == .bang;
-    if (is_inferred_error) {
-        return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
-    }
-    var ret_gz = gz.makeSubBlock(scope);
-    defer ret_gz.instructions.deinit(gpa);
-    const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
-    const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
-
     const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
         try expr(
             gz,
@@ -1176,6 +1166,16 @@ fn fnProtoExpr(
     else
         Zir.Inst.Ref.none;
 
+    const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
+    const is_inferred_error = token_tags[maybe_bang] == .bang;
+    if (is_inferred_error) {
+        return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
+    }
+    var ret_gz = gz.makeSubBlock(scope);
+    defer ret_gz.instructions.deinit(gpa);
+    const ret_ty = try expr(&ret_gz, scope, coerced_type_rl, fn_proto.ast.return_type);
+    const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
+
     const result = try gz.addFunc(.{
         .src_node = fn_proto.ast.proto_node,
         .param_block = 0,
@@ -3182,11 +3182,6 @@ fn fnDecl(
         break :inst try comptimeExpr(&decl_gz, params_scope, .{ .ty = .const_slice_u8_type }, fn_proto.ast.section_expr);
     };
 
-    var ret_gz = decl_gz.makeSubBlock(params_scope);
-    defer ret_gz.instructions.deinit(gpa);
-    const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
-    const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
-
     const cc: Zir.Inst.Ref = blk: {
         if (fn_proto.ast.callconv_expr != 0) {
             if (has_inline_keyword) {
@@ -3212,6 +3207,11 @@ fn fnDecl(
         }
     };
 
+    var ret_gz = decl_gz.makeSubBlock(params_scope);
+    defer ret_gz.instructions.deinit(gpa);
+    const ret_ty = try expr(&ret_gz, params_scope, coerced_type_rl, fn_proto.ast.return_type);
+    const ret_br = try ret_gz.addBreak(.break_inline, 0, ret_ty);
+
     const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
         if (!is_extern) {
             return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
test/behavior/fn_stage1.zig
@@ -204,3 +204,19 @@ test "function with inferred error set but returning no error" {
     const return_ty = @typeInfo(@TypeOf(S.foo)).Fn.return_type.?;
     try expectEqual(0, @typeInfo(@typeInfo(return_ty).ErrorUnion.error_set).ErrorSet.?.len);
 }
+
+const nComplexCallconv = 100;
+fn fComplexCallconvRet(x: u32) callconv(blk: {
+    const s: struct { n: u32 } = .{ .n = nComplexCallconv };
+    break :blk switch (s.n) {
+        0 => .C,
+        1 => .Inline,
+        else => .Unspecified,
+    };
+}) struct { x: u32 } {
+    return .{ .x = x * x };
+}
+
+test "function with complex callconv and return type expressions" {
+    try expect(fComplexCallconvRet(3).x == 9);
+}