Commit 41a67126a5

Vexu <git@vexu.eu>
2019-12-13 16:36:18
translate-c-2 typedef
1 parent eb057ef
Changed files (3)
src-self-hosted/clang.zig
@@ -735,7 +735,7 @@ pub extern fn ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl: ?*const s
 pub extern fn ZigClangEnumDecl_getIntegerType(self: ?*const struct_ZigClangEnumDecl) struct_ZigClangQualType;
 pub extern fn ZigClangDecl_getName_bytes_begin(decl: ?*const struct_ZigClangDecl) [*c]const u8;
 pub extern fn ZigClangSourceLocation_eq(a: struct_ZigClangSourceLocation, b: struct_ZigClangSourceLocation) bool;
-pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) ?*const struct_ZigClangTypedefNameDecl;
+pub extern fn ZigClangTypedefType_getDecl(self: ?*const struct_ZigClangTypedefType) *const struct_ZigClangTypedefNameDecl;
 pub extern fn ZigClangTypedefNameDecl_getUnderlyingType(self: ?*const struct_ZigClangTypedefNameDecl) struct_ZigClangQualType;
 pub extern fn ZigClangQualType_getCanonicalType(self: struct_ZigClangQualType) struct_ZigClangQualType;
 pub extern fn ZigClangQualType_getTypeClass(self: struct_ZigClangQualType) ZigClangTypeClass;
src-self-hosted/translate_c.zig
@@ -220,7 +220,7 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void {
             return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl));
         },
         .Typedef => {
-            try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for typedefs", .{});
+            try resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl));
         },
         .Enum => {
             try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for enums", .{});
@@ -384,6 +384,48 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void {
     return addTopLevelDecl(c, var_name, &node.base);
 }
 
+fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void {
+    if (try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), {})) |_| return; // Avoid processing this decl twice
+    const rp = makeRestorePoint(c);
+    const visib_tok = try appendToken(c, .Keyword_pub, "pub");
+    const const_tok = try appendToken(c, .Keyword_const, "const");
+
+    const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
+    const name_tok = try appendToken(c, .Identifier, typedef_name);
+    const eq_tok = try appendToken(c, .Equal, "=");
+
+    const child_qt = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
+    const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl);
+    const type_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) {
+        error.UnsupportedType => {
+            const node = try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{});
+            _ = try c.decl_table.put(@ptrToInt(typedef_decl), node);
+            return node;
+        },
+        error.OutOfMemory => |e| return e,
+    };
+
+    const node = try c.a().create(ast.Node.VarDecl);
+    node.* = ast.Node.VarDecl{
+        .base = ast.Node{ .id = .VarDecl },
+        .doc_comments = null,
+        .visib_token = visib_tok,
+        .thread_local_token = null,
+        .name_token = name_tok,
+        .eq_token = eq_tok,
+        .mut_token = const_tok,
+        .comptime_token = null,
+        .extern_export_token = null,
+        .lib_name = null,
+        .type_node = null,
+        .align_node = null,
+        .section_node = null,
+        .init_node = type_node,
+        .semicolon_token = try appendToken(c, .Semicolon, ";"),
+    };
+    try addTopLevelDecl(c, typedef_name, &node.base);
+}
+
 const ResultUsed = enum {
     used,
     unused,
@@ -1534,6 +1576,13 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
             node.rhs = try transQualType(rp, child_qt, source_loc);
             return &node.base;
         },
+        .Typedef => {
+            const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
+
+            const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
+            const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
+            return appendIdentifier(rp.c, typedef_name);
+        },
         else => {
             const type_name = rp.c.str(ZigClangType_getTypeClassName(ty));
             return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name});
@@ -1541,6 +1590,15 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour
     }
 }
 
+fn isCVoid(qt: ZigClangQualType) bool {
+    const ty = ZigClangQualType_getTypePtr(qt);
+    if (ZigClangType_getTypeClass(ty) == .Builtin) {
+        const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
+        return ZigClangBuiltinType_getKind(builtin_ty) == .Void;
+    }
+    return false;
+}
+
 const FnDeclContext = struct {
     fn_name: []const u8,
     has_body: bool,
@@ -1691,7 +1749,8 @@ fn finishTransFnProto(
             break :blk try appendIdentifier(rp.c, "noreturn");
         } else {
             const return_qt = ZigClangFunctionType_getReturnType(fn_ty);
-            if (ZigClangType_isVoidType(qualTypeCanon(return_qt))) {
+            if (isCVoid(return_qt)) {
+                // convert primitive c_void to actual void (only for return type)
                 break :blk try appendIdentifier(rp.c, "void");
             } else {
                 break :blk transQualType(rp, return_qt, source_loc) catch |err| switch (err) {
@@ -1786,7 +1845,7 @@ fn failDecl(c: *Context, loc: ZigClangSourceLocation, name: []const u8, comptime
         .init_node = &call_node.base,
         .semicolon_token = semi_tok,
     };
-    try c.tree.root_node.decls.push(&var_decl_node.base);
+    try addTopLevelDecl(c, name, &var_decl_node.base);
 }
 
 fn appendToken(c: *Context, token_id: Token.Id, bytes: []const u8) !ast.TokenIndex {
test/translate_c.zig
@@ -84,6 +84,82 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub fn bar() void {}
     });
 
+    cases.add_both("typedef void",
+        \\typedef void Foo;
+        \\Foo fun(Foo *a);
+    , &[_][]const u8{
+        \\pub const Foo = c_void;
+    ,
+        \\pub extern fn fun(a: ?*Foo) Foo;
+    });
+
+    cases.add_both("duplicate typedef",
+        \\typedef long foo;
+        \\typedef int bar;
+        \\typedef long foo;
+        \\typedef int baz;
+    , &[_][]const u8{
+        \\pub const foo = c_long;
+        \\pub const bar = c_int;
+        \\pub const baz = c_int;
+    });
+
+    cases.add_both("casting pointers to ints and ints to pointers",
+        \\void foo(void);
+        \\void bar(void) {
+        \\    void *func_ptr = foo;
+        \\    void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr;
+        \\}
+    , &[_][]const u8{
+        \\pub extern fn foo() void;
+        \\pub export fn bar() void {
+        \\    var func_ptr: ?*c_void = @ptrCast(?*c_void, foo);
+        \\    var typed_func_ptr: ?extern fn () void = @intToPtr(?extern fn () void, @as(c_ulong, @ptrToInt(func_ptr)));
+        \\}
+    });
+
+    cases.add_both("noreturn attribute",
+        \\void foo(void) __attribute__((noreturn));
+    , &[_][]const u8{
+        \\pub extern fn foo() noreturn;
+    });
+
+    cases.add_both("add, sub, mul, div, rem",
+        \\int s(int a, int b) {
+        \\    int c;
+        \\    c = a + b;
+        \\    c = a - b;
+        \\    c = a * b;
+        \\    c = a / b;
+        \\    c = a % b;
+        \\}
+        \\unsigned u(unsigned a, unsigned b) {
+        \\    unsigned c;
+        \\    c = a + b;
+        \\    c = a - b;
+        \\    c = a * b;
+        \\    c = a / b;
+        \\    c = a % b;
+        \\}
+    , &[_][]const u8{
+        \\pub export fn s(a: c_int, b: c_int) c_int {
+        \\    var c: c_int = undefined;
+        \\    c = (a + b);
+        \\    c = (a - b);
+        \\    c = (a * b);
+        \\    c = @divTrunc(a, b);
+        \\    c = @rem(a, b);
+        \\}
+        \\pub export fn u(a: c_uint, b: c_uint) c_uint {
+        \\    var c: c_uint = undefined;
+        \\    c = (a +% b);
+        \\    c = (a -% b);
+        \\    c = (a *% b);
+        \\    c = (a / b);
+        \\    c = (a % b);
+        \\}
+    });
+
     /////////////// Cases that pass for only stage2 ////////////////
 
     cases.add_2("Parameterless function prototypes",
@@ -144,20 +220,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub const REDISMODULE_READ = 1 << 0;
     });
 
-    cases.add_both("casting pointers to ints and ints to pointers",
-        \\void foo(void);
-        \\void bar(void) {
-        \\    void *func_ptr = foo;
-        \\    void (*typed_func_ptr)(void) = (void (*)(void)) (unsigned long) func_ptr;
-        \\}
-    , &[_][]const u8{
-        \\pub extern fn foo() void;
-        \\pub export fn bar() void {
-        \\    var func_ptr: ?*c_void = @ptrCast(?*c_void, foo);
-        \\    var typed_func_ptr: ?extern fn () void = @intToPtr(?extern fn () void, @as(c_ulong, @ptrToInt(func_ptr)));
-        \\}
-    });
-
     if (builtin.os != builtin.Os.windows) {
         // Windows treats this as an enum with type c_int
         cases.add("big negative enum init values when C ABI supports long long enums",
@@ -330,12 +392,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\pub extern fn baz(a: i8, b: i16, c: i32, d: i64) void;
     });
 
-    cases.add_both("noreturn attribute",
-        \\void foo(void) __attribute__((noreturn));
-    , &[_][]const u8{
-        \\pub extern fn foo() noreturn;
-    });
-
     cases.add("simple function",
         \\int abs(int a) {
         \\    return a < 0 ? -a : a;
@@ -512,15 +568,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\};
     });
 
-    cases.add("typedef void",
-        \\typedef void Foo;
-        \\Foo fun(Foo *a);
-    , &[_][]const u8{
-        \\pub const Foo = c_void;
-    ,
-        \\pub extern fn fun(a: ?*Foo) Foo;
-    });
-
     cases.add("generate inline func for #define global extern fn",
         \\extern void (*fn_ptr)(void);
         \\#define foo fn_ptr
@@ -720,42 +767,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add_both("add, sub, mul, div, rem",
-        \\int s(int a, int b) {
-        \\    int c;
-        \\    c = a + b;
-        \\    c = a - b;
-        \\    c = a * b;
-        \\    c = a / b;
-        \\    c = a % b;
-        \\}
-        \\unsigned u(unsigned a, unsigned b) {
-        \\    unsigned c;
-        \\    c = a + b;
-        \\    c = a - b;
-        \\    c = a * b;
-        \\    c = a / b;
-        \\    c = a % b;
-        \\}
-    , &[_][]const u8{
-        \\pub export fn s(a: c_int, b: c_int) c_int {
-        \\    var c: c_int = undefined;
-        \\    c = (a + b);
-        \\    c = (a - b);
-        \\    c = (a * b);
-        \\    c = @divTrunc(a, b);
-        \\    c = @rem(a, b);
-        \\}
-        \\pub export fn u(a: c_uint, b: c_uint) c_uint {
-        \\    var c: c_uint = undefined;
-        \\    c = (a +% b);
-        \\    c = (a -% b);
-        \\    c = (a *% b);
-        \\    c = (a / b);
-        \\    c = (a % b);
-        \\}
-    });
-
     cases.add("bitwise binary operators",
         \\int max(int a, int b) {
         \\    return (a & b) ^ (a | b);
@@ -1148,17 +1159,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
         \\}
     });
 
-    cases.add("duplicate typedef",
-        \\typedef long foo;
-        \\typedef int bar;
-        \\typedef long foo;
-        \\typedef int baz;
-    , &[_][]const u8{
-        \\pub const foo = c_long;
-        \\pub const bar = c_int;
-        \\pub const baz = c_int;
-    });
-
     cases.add("post increment/decrement",
         \\void foo(void) {
         \\    int i = 0;