zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 41a67126a50e3cfab67c749bfc52ac242694774b (tree)
parent eb057ef41c8a5482586fc39bab11c280e261ea94
Author: Vexu <git@vexu.eu>
Date:   Fri, 13 Dec 2019 17:36:18 +0200

translate-c-2 typedef

Diffstat:
Msrc-self-hosted/clang.zig | 2+-
Msrc-self-hosted/translate_c.zig | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mtest/translate_c.zig | 152++++++++++++++++++++++++++++++++++++++++----------------------------------------
3 files changed, 139 insertions(+), 80 deletions(-)

diff --git a/src-self-hosted/clang.zig b/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; diff --git a/src-self-hosted/translate_c.zig b/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 { diff --git a/test/translate_c.zig b/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;