Commit 13e472aa2a

Vexu <git@vexu.eu>
2020-08-13 15:06:42
translate-c: add return if one is needed
1 parent c5368ba
Changed files (5)
lib/std/hash/auto_hash.zig
@@ -129,7 +129,7 @@ pub fn hash(hasher: anytype, key: anytype, comptime strat: HashStrategy) void {
             }
         },
 
-        .Union => |info| blk: {
+        .Union => |info| {
             if (info.tag_type) |tag_type| {
                 const tag = meta.activeTag(key);
                 const s = hash(hasher, tag, strat);
src-self-hosted/Module.zig
@@ -2798,7 +2798,7 @@ pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
             val_payload.* = .{ .val = lhs_val + rhs_val };
             break :blk &val_payload.base;
         },
-        128 => blk: {
+        128 => {
             return self.fail(scope, src, "TODO Implement addition for big floats", .{});
         },
         else => unreachable,
@@ -2832,7 +2832,7 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
             val_payload.* = .{ .val = lhs_val - rhs_val };
             break :blk &val_payload.base;
         },
-        128 => blk: {
+        128 => {
             return self.fail(scope, src, "TODO Implement substraction for big floats", .{});
         },
         else => unreachable,
src-self-hosted/translate_c.zig
@@ -628,6 +628,46 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void {
         error.UnsupportedType,
         => return failDecl(c, fn_decl_loc, fn_name, "unable to translate function", .{}),
     };
+    // add return statement if the function didn't have one
+    blk: {
+        const fn_ty = @ptrCast(*const ZigClangFunctionType, fn_type);
+
+        if (ZigClangFunctionType_getNoReturnAttr(fn_ty)) break :blk;
+        const return_qt = ZigClangFunctionType_getReturnType(fn_ty);
+        if (isCVoid(return_qt)) break :blk;
+
+        if (block_scope.statements.items.len > 0) {
+            var last = block_scope.statements.items[block_scope.statements.items.len - 1];
+            while (true) {
+                switch (last.tag) {
+                    .Block => {
+                        const stmts = last.castTag(.Block).?.statements();
+                        if (stmts.len == 0) break;
+
+                        last = stmts[stmts.len - 1];
+                    },
+                    // no extra return needed
+                    .Return => break :blk,
+                    else => break,
+                }
+            }
+        }
+
+        const return_expr = try ast.Node.ControlFlowExpression.create(rp.c.arena, .{
+            .ltoken = try appendToken(rp.c, .Keyword_return, "return"),
+            .tag = .Return,
+        }, .{
+            .rhs = transZeroInitExpr(rp, scope, fn_decl_loc, ZigClangQualType_getTypePtr(return_qt)) catch |err| switch (err) {
+                error.OutOfMemory => |e| return e,
+                error.UnsupportedTranslation,
+                error.UnsupportedType,
+                => return failDecl(c, fn_decl_loc, fn_name, "unable to create a return value for function", .{}),
+            },
+        });
+        _ = try appendToken(rp.c, .Semicolon, ";");
+        try block_scope.statements.append(&return_expr.base);
+    }
+
     const body_node = try block_scope.complete(rp.c);
     proto_node.setTrailer("body_node", &body_node.base);
     return addTopLevelDecl(c, fn_name, &proto_node.base);
test/run_translated_c.zig
@@ -15,7 +15,6 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
         \\    }
         \\    if (s0 != 1) abort();
         \\    if (s1 != 10) abort();
-        \\    return 0;
         \\}
     , "");
 
test/translate_c.zig
@@ -3,12 +3,33 @@ const std = @import("std");
 const CrossTarget = std.zig.CrossTarget;
 
 pub fn addCases(cases: *tests.TranslateCContext) void {
+    cases.add("missing return stmt",
+        \\int foo() {}
+        \\int bar() {
+        \\    int a = 2;
+        \\}
+        \\int baz() {
+        \\    return 0;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn foo() c_int {
+        \\    return 0;
+        \\}
+        \\pub export fn bar() c_int {
+        \\    var a: c_int = 2;
+        \\    return 0;
+        \\}
+        \\pub export fn baz() c_int {
+        \\    return 0;
+        \\}
+    });
+
     cases.add("alignof",
-        \\int main() {
+        \\void main() {
         \\    int a = _Alignof(int);
         \\}
     , &[_][]const u8{
-        \\pub export fn main() c_int {
+        \\pub export fn main() void {
         \\    var a: c_int = @bitCast(c_int, @truncate(c_uint, @alignOf(c_int)));
         \\}
     });
@@ -539,6 +560,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    c = (a * b);
         \\    c = @divTrunc(a, b);
         \\    c = @rem(a, b);
+        \\    return 0;
         \\}
         \\pub export fn u() c_uint {
         \\    var a: c_uint = undefined;
@@ -549,6 +571,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    c = (a *% b);
         \\    c = (a / b);
         \\    c = (a % b);
+        \\    return 0;
         \\}
     });
 
@@ -1596,13 +1619,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     });
 
     cases.add("worst-case assign",
-        \\int foo() {
+        \\void foo() {
         \\    int a;
         \\    int b;
         \\    a = b = 2;
         \\}
     , &[_][]const u8{
-        \\pub export fn foo() c_int {
+        \\pub export fn foo() void {
         \\    var a: c_int = undefined;
         \\    var b: c_int = undefined;
         \\    a = blk: {
@@ -1650,11 +1673,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\        a = 7;
         \\        if (!true) break;
         \\    }
+        \\    return 0;
         \\}
     });
 
     cases.add("for loops",
-        \\int foo() {
+        \\void foo() {
         \\    for (int i = 2, b = 4; i + 2; i = 2) {
         \\        int a = 2;
         \\        a = 6, 5, 7;
@@ -1662,7 +1686,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    char i = 2;
         \\}
     , &[_][]const u8{
-        \\pub export fn foo() c_int {
+        \\pub export fn foo() void {
         \\    {
         \\        var i: c_int = 2;
         \\        var b: c_int = 4;
@@ -1712,7 +1736,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     });
 
     cases.add("switch on int",
-        \\int switch_fn(int i) {
+        \\void switch_fn(int i) {
         \\    int res = 0;
         \\    switch (i) {
         \\        case 0:
@@ -1727,7 +1751,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    }
         \\}
     , &[_][]const u8{
-        \\pub export fn switch_fn(arg_i: c_int) c_int {
+        \\pub export fn switch_fn(arg_i: c_int) void {
         \\    var i = arg_i;
         \\    var res: c_int = 0;
         \\    @"switch": {
@@ -1787,13 +1811,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     });
 
     cases.add("assign",
-        \\int max(int a) {
+        \\void max(int a) {
         \\    int tmp;
         \\    tmp = a;
         \\    a = tmp;
         \\}
     , &[_][]const u8{
-        \\pub export fn max(arg_a: c_int) c_int {
+        \\pub export fn max(arg_a: c_int) void {
         \\    var a = arg_a;
         \\    var tmp: c_int = undefined;
         \\    tmp = a;
@@ -2082,7 +2106,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    int b;
         \\}a;
         \\float b = 2.0f;
-        \\int foo(void) {
+        \\void foo(void) {
         \\    struct Foo *c;
         \\    a.b;
         \\    c->b;
@@ -2093,7 +2117,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
         \\pub extern var a: struct_Foo;
         \\pub export var b: f32 = 2;
-        \\pub export fn foo() c_int {
+        \\pub export fn foo() void {
         \\    var c: [*c]struct_Foo = undefined;
         \\    _ = a.b;
         \\    _ = c.*.b;
@@ -2204,11 +2228,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    if (a < b) return b;
         \\    if (a < b) return b else return a;
         \\    if (a < b) {} else {}
+        \\    return 0;
         \\}
     });
 
     cases.add("if statements",
-        \\int foo() {
+        \\void foo() {
         \\    if (2) {
         \\        int a = 2;
         \\    }
@@ -2217,7 +2242,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\    }
         \\}
     , &[_][]const u8{
-        \\pub export fn foo() c_int {
+        \\pub export fn foo() void {
         \\    if (true) {
         \\        var a: c_int = 2;
         \\    }
@@ -2811,12 +2836,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     });
 
     cases.add("arg name aliasing decl which comes after",
-        \\int foo(int bar) {
+        \\void foo(int bar) {
         \\    bar = 2;
         \\}
         \\int bar = 4;
     , &[_][]const u8{
-        \\pub export fn foo(arg_bar_1: c_int) c_int {
+        \\pub export fn foo(arg_bar_1: c_int) void {
         \\    var bar_1 = arg_bar_1;
         \\    bar_1 = 2;
         \\}
@@ -2824,12 +2849,12 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
     });
 
     cases.add("arg name aliasing macro which comes after",
-        \\int foo(int bar) {
+        \\void foo(int bar) {
         \\    bar = 2;
         \\}
         \\#define bar 4
     , &[_][]const u8{
-        \\pub export fn foo(arg_bar_1: c_int) c_int {
+        \\pub export fn foo(arg_bar_1: c_int) void {
         \\    var bar_1 = arg_bar_1;
         \\    bar_1 = 2;
         \\}