Commit 41a67126a5
Changed files (3)
src-self-hosted
test
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;