translate-c-2 typedef

This commit is contained in:
Vexu 2019-12-13 17:36:18 +02:00
parent eb057ef41c
commit 41a67126a5
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
3 changed files with 139 additions and 80 deletions

View File

@ -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;

View File

@ -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 {

View File

@ -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;