From e4ca1f441bf0c54e3fd447a2db6567a936175002 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 14 Dec 2019 01:43:55 +0200 Subject: [PATCH 1/3] translate-c-2 record type --- lib/std/zig/render.zig | 4 +- src-self-hosted/clang.zig | 26 +++- src-self-hosted/translate_c.zig | 230 +++++++++++++++++++++++++++++--- test/translate_c.zig | 68 +++++++++- 4 files changed, 304 insertions(+), 24 deletions(-) diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index 9add521c00..fa8388b711 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -193,6 +193,7 @@ fn renderRoot( fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Child.Error!void { const first_token = node.firstToken(); var prev_token = first_token; + if (prev_token == 0) return; while (tree.tokens.at(prev_token - 1).id == .DocComment) { prev_token -= 1; } @@ -2174,8 +2175,7 @@ fn renderTokenOffset( } while (true) { - assert(loc.line != 0); - const newline_count = if (loc.line == 1) @as(u8, 1) else @as(u8, 2); + const newline_count = if (loc.line < 2) @as(u8, 1) else @as(u8, 2); try stream.writeByteNTimes('\n', newline_count); try stream.writeByteNTimes(' ', indent); try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ")); diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index eebedd0be9..4764a475c1 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -709,6 +709,20 @@ pub const ZigClangStringLiteral_StringKind = extern enum { UTF32, }; +pub const ZigClangRecordDecl_field_iterator = extern struct { + opaque: *c_void, +}; + +pub const ZigClangElaboratedTypeKeyword = extern enum { + Struct, + Interface, + Union, + Class, + Enum, + Typename, + None, +}; + pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; @@ -718,7 +732,7 @@ pub extern fn ZigClangASTContext_getPointerType(self: ?*const struct_ZigClangAST pub extern fn ZigClangASTUnit_getASTContext(self: ?*struct_ZigClangASTUnit) ?*struct_ZigClangASTContext; pub extern fn ZigClangASTUnit_getSourceManager(self: *struct_ZigClangASTUnit) *struct_ZigClangSourceManager; pub extern fn ZigClangASTUnit_visitLocalTopLevelDecls(self: *struct_ZigClangASTUnit, context: ?*c_void, Fn: ?extern fn (?*c_void, *const struct_ZigClangDecl) bool) bool; -pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) ?*const struct_ZigClangRecordDecl; +pub extern fn ZigClangRecordType_getDecl(record_ty: ?*const struct_ZigClangRecordType) *const struct_ZigClangRecordDecl; pub extern fn ZigClangEnumType_getDecl(record_ty: ?*const struct_ZigClangEnumType) ?*const struct_ZigClangEnumDecl; pub extern fn ZigClangRecordDecl_getCanonicalDecl(record_decl: ?*const struct_ZigClangRecordDecl) ?*const struct_ZigClangTagDecl; pub extern fn ZigClangEnumDecl_getCanonicalDecl(self: ?*const struct_ZigClangEnumDecl) ?*const struct_ZigClangTagDecl; @@ -732,6 +746,11 @@ pub extern fn ZigClangDecl_getLocation(self: *const ZigClangDecl) ZigClangSource pub extern fn ZigClangRecordDecl_isUnion(record_decl: ?*const struct_ZigClangRecordDecl) bool; pub extern fn ZigClangRecordDecl_isStruct(record_decl: ?*const struct_ZigClangRecordDecl) bool; pub extern fn ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl: ?*const struct_ZigClangRecordDecl) bool; +pub extern fn ZigClangRecordDecl_field_begin(*const struct_ZigClangRecordDecl) ZigClangRecordDecl_field_iterator; +pub extern fn ZigClangRecordDecl_field_end(*const struct_ZigClangRecordDecl) ZigClangRecordDecl_field_iterator; +pub extern fn ZigClangRecordDecl_field_iterator_next(ZigClangRecordDecl_field_iterator) ZigClangRecordDecl_field_iterator; +pub extern fn ZigClangRecordDecl_field_iterator_deref(ZigClangRecordDecl_field_iterator) *const struct_ZigClangFieldDecl; +pub extern fn ZigClangRecordDecl_field_iterator_neq(ZigClangRecordDecl_field_iterator, ZigClangRecordDecl_field_iterator) bool; 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; @@ -948,6 +967,7 @@ pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const Zig pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType; +pub extern fn ZigClangElaboratedType_getKeyword(*const struct_ZigClangElaboratedType) ZigClangElaboratedTypeKeyword; pub extern fn ZigClangElaboratedType_getNamedType(*const ZigClangElaboratedType) ZigClangQualType; pub extern fn ZigClangAttributedType_getEquivalentType(*const ZigClangAttributedType) ZigClangQualType; @@ -987,3 +1007,7 @@ pub extern fn ZigClangStringLiteral_getKind(*const ZigClangStringLiteral) ZigCla pub extern fn ZigClangStringLiteral_getString_bytes_begin_size(*const ZigClangStringLiteral, *usize) [*c]const u8; pub extern fn ZigClangParenExpr_getSubExpr(*const ZigClangParenExpr) *const ZigClangExpr; + +pub extern fn ZigClangFieldDecl_isBitField(*const struct_ZigClangFieldDecl) bool; +pub extern fn ZigClangFieldDecl_getType(*const struct_ZigClangFieldDecl) struct_ZigClangQualType; +pub extern fn ZigClangFieldDecl_getLocation(*const struct_ZigClangFieldDecl) struct_ZigClangSourceLocation; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index b3770d1ab7..42f5b87f23 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -15,7 +15,7 @@ pub const Error = error{OutOfMemory}; const TypeError = Error || error{UnsupportedType}; const TransError = TypeError || error{UnsupportedTranslation}; -const DeclTable = std.HashMap(usize, void, addrHash, addrEql); +const DeclTable = std.HashMap(usize, []const u8, addrHash, addrEql); fn addrHash(x: usize) u32 { switch (@typeInfo(usize).Int.bits) { @@ -194,6 +194,7 @@ pub fn translate( tree.root_node.eof_token = try appendToken(&context, .Eof, ""); tree.source = source_buffer.toOwnedSlice(); + if (false) { std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source); var i: usize = 0; @@ -220,13 +221,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); }, .Typedef => { - try resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); + return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); }, .Enum => { try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for enums", .{}); }, .Record => { - try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for structs", .{}); + return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); }, .Var => { return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); @@ -239,9 +240,10 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { } fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { - if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice + if (c.decl_table.contains(@ptrToInt(fn_decl))) return; // Avoid processing this decl twice const rp = makeRestorePoint(c); const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); + _ = try c.decl_table.put(@ptrToInt(fn_decl), fn_name); const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); const fn_qt = ZigClangFunctionDecl_getType(fn_decl); const fn_type = ZigClangQualType_getTypePtr(fn_qt); @@ -303,7 +305,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { } fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { - if (try c.decl_table.put(@ptrToInt(var_decl), {})) |_| return; // Avoid processing this decl twice + if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice const rp = makeRestorePoint(c); const visib_tok = try appendToken(c, .Keyword_pub, "pub"); @@ -314,6 +316,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { var scope = &c.global_scope.base; const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); + _ = try c.decl_table.put(@ptrToInt(var_decl), var_name); const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); @@ -385,12 +388,13 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { } 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 + if (c.decl_table.contains(@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))); + _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); const name_tok = try appendToken(c, .Identifier, typedef_name); const eq_tok = try appendToken(c, .Equal, "="); @@ -398,9 +402,7 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err 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; + return failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); }, error.OutOfMemory => |e| return e, }; @@ -426,6 +428,60 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err try addTopLevelDecl(c, typedef_name, &node.base); } +fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void { + if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_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 bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); + + const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) + "union" + else if (ZigClangRecordDecl_isStruct(record_decl)) + "struct" + else + return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), bare_name, "record {} is not a struct or union", .{bare_name}); + + if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) + return; + + const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); + _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); + const name_tok = try appendToken(c, .Identifier, name); + + const eq_tok = try appendToken(c, .Equal, "="); + const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { + error.UnsupportedType => { + return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{}); + }, + error.OutOfMemory => |e| return e, + }; + const semicolon_token = try appendToken(c, .Semicolon, ";"); + + 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 = init_node, + .semicolon_token = semicolon_token, + }; + + try addTopLevelDecl(c, name, &node.base); +} + const ResultUsed = enum { used, unused, @@ -1148,22 +1204,113 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); } +fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeError!*ast.Node { + const rp = makeRestorePoint(c); + + const record_loc = ZigClangRecordDecl_getLocation(record_decl); + + var container_kind_name: []const u8 = undefined; + var container_kind: std.zig.Token.Id = undefined; + + if (ZigClangRecordDecl_isUnion(record_decl)) { + container_kind_name = "union"; + container_kind = .Keyword_union; + } else if (ZigClangRecordDecl_isStruct(record_decl)) { + container_kind_name = "struct"; + container_kind = .Keyword_struct; + } else { + return revertAndWarn( + rp, + error.UnsupportedType, + record_loc, + "unsupported record type", + .{}, + ); + } + + const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { + return transCreateNodeOpaqueType(c); + }; + + const extern_tok = try appendToken(c, .Keyword_extern, "extern"); + const container_tok = try appendToken(c, container_kind, container_kind_name); + const lbrace_token = try appendToken(c, .LBrace, "{"); + + const container_node = try c.a().create(ast.Node.ContainerDecl); + container_node.* = .{ + .base = ast.Node{ .id = .ContainerDecl }, + .layout_token = extern_tok, + .kind_token = container_tok, + .init_arg_expr = .None, + .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), + .lbrace_token = lbrace_token, + .rbrace_token = undefined, // TODO + }; + + var it = ZigClangRecordDecl_field_begin(record_def); + const end_it = ZigClangRecordDecl_field_end(record_def); + while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { + const field_decl = ZigClangRecordDecl_field_iterator_deref(it); + const field_loc = ZigClangFieldDecl_getLocation(field_decl); + + if (ZigClangFieldDecl_isBitField(field_decl)) { + rp.activate(); + const node = try transCreateNodeOpaqueType(c); + try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); + return node; + } + + const field_name = try appendToken(c, .Identifier, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); + _ = try appendToken(c, .Colon, ":"); + const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc); + + const field_node = try c.a().create(ast.Node.ContainerField); + field_node.* = .{ + .doc_comments = null, + .comptime_token = null, + .name_token = field_name, + .type_expr = field_type, + .value_expr = null, + .align_expr = null, + }; + + try container_node.fields_and_decls.push(&field_node.base); + _ = try appendToken(c, .Comma, ","); + } + + container_node.rbrace_token = try appendToken(c, .RBrace, "}"); + return &container_node.base; +} + fn qualTypeIsPtr(qt: ZigClangQualType) bool { return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; } fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { const ty = ZigClangQualType_getTypePtr(qt); - if (ZigClangType_getTypeClass(ty) == .Paren) { - const paren_type = @ptrCast(*const ZigClangParenType, ty); - const inner_type = ZigClangParenType_getInnerType(paren_type); - return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto; + + switch (ZigClangType_getTypeClass(ty)) { + .FunctionProto, .FunctionNoProto => return true, + .Elaborated => { + const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); + return qualTypeChildIsFnProto(ZigClangElaboratedType_getNamedType(elaborated_ty)); + }, + .Typedef => { + const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); + const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + return qualTypeChildIsFnProto(ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl)); + }, + .Paren => { + const paren_type = @ptrCast(*const ZigClangParenType, ty); + const inner_type = ZigClangParenType_getInnerType(paren_type); + return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto; + }, + .Attributed => { + const attr_type = @ptrCast(*const ZigClangAttributedType, ty); + return qualTypeChildIsFnProto(ZigClangAttributedType_getEquivalentType(attr_type)); + }, + else => return false, } - if (ZigClangType_getTypeClass(ty) == .Attributed) { - const attr_type = @ptrCast(*const ZigClangAttributedType, ty); - return qualTypeChildIsFnProto(ZigClangAttributedType_getEquivalentType(attr_type)); - } - return false; } fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType { @@ -1197,7 +1344,18 @@ fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocatio .Record => { const record_ty = @ptrCast(*const ZigClangRecordType, ty); const record_decl = ZigClangRecordType_getDecl(record_ty); - return (ZigClangRecordDecl_getDefinition(record_decl) == null); + const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse + return true; + var it = ZigClangRecordDecl_field_begin(record_def); + const end_it = ZigClangRecordDecl_field_end(record_def); + while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { + const field_decl = ZigClangRecordDecl_field_iterator_deref(it); + + if (ZigClangFieldDecl_isBitField(field_decl)) { + return true; + } + } + return false; }, .Elaborated => { const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); @@ -1450,7 +1608,7 @@ fn transCreateNodeArrayInitializer(c: *Context, type_node: *ast.Node) !*ast.Node } fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { - const token = try appendToken(c, .IntegerLiteral, try std.fmt.allocPrint(c.a(), "{}", .{int})); + const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); const node = try c.a().create(ast.Node.IntegerLiteral); node.* = ast.Node.IntegerLiteral{ .base = ast.Node{ .id = .IntegerLiteral }, @@ -1459,6 +1617,21 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { return &node.base; } +fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { + const builtin_tok = try appendToken(c, .Builtin, "@OpaqueType"); + _ = try appendToken(c, .LParen, "("); + const rparen_tok = try appendToken(c, .RParen, ")"); + + const call_node = try c.a().create(ast.Node.BuiltinCall); + call_node.* = ast.Node.BuiltinCall{ + .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, + .builtin_token = builtin_tok, + .params = ast.Node.BuiltinCall.ParamList.init(c.a()), + .rparen_token = rparen_tok, + }; + return &call_node.base; +} + const RestorePoint = struct { c: *Context, token_index: ast.TokenIndex, @@ -1580,9 +1753,26 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + // const typedef_name = rp.c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl))).?.value; const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); return appendIdentifier(rp.c, typedef_name); }, + .Record => { + const record_ty = @ptrCast(*const ZigClangRecordType, ty); + + const record_decl = ZigClangRecordType_getDecl(record_ty); + if (rp.c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv| + return appendIdentifier(rp.c, kv.value) + else + return transRecordDecl(rp.c, record_decl); + }, + .Elaborated => { + const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); + switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) { + .Struct, .Enum, .Union => return try transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc), + else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported elaborated type", .{}), + } + }, else => { const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); diff --git a/test/translate_c.zig b/test/translate_c.zig index 86f7c85e92..b8f085c458 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -186,9 +186,75 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export var arr2: [*c]u8 = "hello"; }); + cases.add_2("pointer to struct demoted to opaque due to bit fields", + \\struct Foo { + \\ unsigned int: 1; + \\}; + \\struct Bar { + \\ struct Foo *foo; + \\}; + , &[_][]const u8{ // TODO that semicolon is hideous + \\pub const struct_Foo = @OpaqueType() // /home/vexu/Documents/zig/zig/zig-cache/source.h:2:5: warning: struct demoted to opaque type - has bitfield + \\ ; + \\pub const struct_Bar = extern struct { + \\ foo: ?*struct_Foo, + \\}; + }); + + cases.add_2("double define struct", + \\typedef struct Bar Bar; + \\typedef struct Foo Foo; + \\ + \\struct Foo { + \\ Foo *a; + \\}; + \\ + \\struct Bar { + \\ Foo *a; + \\}; + , &[_][]const u8{ + \\pub const struct_Bar = extern struct { + \\ a: [*c]Foo, + \\}; + \\pub const Bar = struct_Bar; + \\pub const struct_Foo = extern struct { + \\ a: [*c]Foo, + \\}; + \\pub const Foo = struct_Foo; + }); + + cases.add_2("simple struct", + \\struct Foo { + \\ int x; + \\ char *y; + \\}; + , &[_][]const u8{ + \\const struct_Foo = extern struct { + \\ x: c_int, + \\ y: [*c]u8, + \\}; + }); + + cases.add_2("self referential struct with function pointer", + \\struct Foo { + \\ void (*derp)(struct Foo *foo); + \\}; + , &[_][]const u8{ + \\pub const struct_Foo = extern struct { + \\ derp: ?extern fn ([*c]struct_Foo) void, + \\}; + }); + cases.add_2("struct prototype used in func", + \\struct Foo; + \\struct Foo *some_func(struct Foo *foo, int x); + , &[_][]const u8{ + \\pub const struct_Foo = @OpaqueType(); + \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// - cases.add("typedef of function in struct field", + cases.add_both("typedef of function in struct field", \\typedef void lws_callback_function(void); \\struct Foo { \\ void (*func)(void); From a4ac6d15c42a4a06eb5e2bfe73224384d3613bf6 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 14 Dec 2019 10:41:00 +0200 Subject: [PATCH 2/3] translate-c-2 array initializer expr --- src-self-hosted/translate_c.zig | 114 +++++++++++++++++++++++++++++--- test/translate_c.zig | 16 +++++ 2 files changed, 120 insertions(+), 10 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index 42f5b87f23..ac930efd2b 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -498,7 +498,7 @@ fn transStmt( stmt: *const ZigClangStmt, result_used: ResultUsed, lrvalue: LRValue, -) !TransResult { +) TransError!TransResult { const sc = ZigClangStmt_getStmtClass(stmt); switch (sc) { .BinaryOperatorClass => return transBinaryOperator(rp, scope, @ptrCast(*const ZigClangBinaryOperator, stmt), result_used), @@ -512,6 +512,7 @@ fn transStmt( .StringLiteralClass => return transStringLiteral(rp, scope, @ptrCast(*const ZigClangStringLiteral, stmt), result_used), .ParenExprClass => return transExpr(rp, scope, ZigClangParenExpr_getSubExpr(@ptrCast(*const ZigClangParenExpr, stmt)), result_used, lrvalue), .InitListExprClass => return transInitListExpr(rp, scope, @ptrCast(*const ZigClangInitListExpr, stmt), result_used), + .ImplicitValueInitExprClass => return transImplicitValueInitExpr(rp, scope, @ptrCast(*const ZigClangExpr, stmt), result_used), else => { return revertAndWarn( rp, @@ -856,6 +857,13 @@ fn transImplicitCastExpr( .LValueToRValue, .NoOp => { return transExpr(rp, scope, sub_expr, .used, .r_value); }, + .NullToPointer => { + return TransResult{ + .node = try transCreateNodeNullLiteral(rp.c), + .node_scope = scope, + .child_scope = scope, + }; + }, else => |kind| return revertAndWarn( rp, error.UnsupportedTranslation, @@ -1040,21 +1048,33 @@ fn transInitListExpr( expr: *const ZigClangInitListExpr, used: ResultUsed, ) TransError!TransResult { - // TODO use anon literals once they work properly const qt = getExprQualType(rp.c, @ptrCast(*const ZigClangExpr, expr)); const qual_type = ZigClangQualType_getTypePtr(qt); const source_loc = ZigClangExpr_getBeginLoc(@ptrCast(*const ZigClangExpr, expr)); + switch (ZigClangType_getTypeClass(qual_type)) { + .ConstantArray => {}, + .Record, .Elaborated => { + return revertAndWarn(rp, error.UnsupportedType, source_loc, "TODO initListExpr for structs", .{}); + }, + else => { + const type_name = rp.c.str(ZigClangType_getTypeClassName(qual_type)); + return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported initlist type: '{}'", .{type_name}); + }, + } + const arr_type = ZigClangType_getAsArrayTypeUnsafe(qual_type); + const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type); const child_qt = ZigClangArrayType_getElementType(arr_type); const init_count = ZigClangInitListExpr_getNumInits(expr); - const all_count = 200; //ZigClangArrayType_getSize(arr_type); + const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty); + const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize)); const leftover_count = all_count - init_count; var init_node: *ast.Node.SuffixOp = undefined; var cat_tok: ast.TokenIndex = undefined; if (init_count != 0) { - var type_node = try transQualType(rp, qt, source_loc); - init_node = try transCreateNodeArrayInitializer(rp.c, type_node); + const dot_tok = try appendToken(rp.c, .Period, "."); + init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok); var i: c_uint = 0; while (i < init_count) : (i += 1) { const elem_expr = ZigClangInitListExpr_getInit(expr, i); @@ -1072,8 +1092,8 @@ fn transInitListExpr( cat_tok = try appendToken(rp.c, .PlusPlus, "++"); } - var filler_type_node = try transQualType(rp, qt, source_loc); - var filler_init_node = try transCreateNodeArrayInitializer(rp.c, filler_type_node); + const dot_tok = try appendToken(rp.c, .Period, "."); + var filler_init_node = try transCreateNodeArrayInitializer(rp.c, dot_tok); const filler_val_expr = ZigClangInitListExpr_getArrayFiller(expr); try filler_init_node.op.ArrayInitializer.push((try transExpr(rp, scope, filler_val_expr, .used, .r_value)).node); filler_init_node.rtoken = try appendToken(rp.c, .RBrace, "}"); @@ -1116,6 +1136,58 @@ fn transInitListExpr( }; } +fn transImplicitValueInitExpr( + rp: RestorePoint, + scope: *Scope, + expr: *const ZigClangExpr, + used: ResultUsed, +) TransError!TransResult { + const source_loc = ZigClangExpr_getBeginLoc(expr); + const qt = getExprQualType(rp.c, expr); + const ty = ZigClangQualType_getTypePtr(qt); + const node = switch (ZigClangType_getTypeClass(ty)) { + .Builtin => blk: { + const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty); + switch (ZigClangBuiltinType_getKind(builtin_ty)) { + .Bool => { + break :blk try transCreateNodeBoolLiteral(rp.c, false); + }, + .Char_U, + .UChar, + .Char_S, + .Char8, + .SChar, + .UShort, + .UInt, + .ULong, + .ULongLong, + .Short, + .Int, + .Long, + .LongLong, + .UInt128, + .Int128, + .Float, + .Double, + .Float128, + .Float16, + .LongDouble, + => { + break :blk try transCreateNodeInt(rp.c, 0); + }, + else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), + } + }, + .Pointer => try transCreateNodeNullLiteral(rp.c), + else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "type does not have an implicit init value", .{}), + }; + return TransResult{ + .node = node, + .child_scope = scope, + .node_scope = scope, + }; +} + fn findBlockScope(inner: *Scope) *Scope.Block { var scope = inner; while (true) : (scope = scope.parent orelse unreachable) { @@ -1593,12 +1665,35 @@ fn transCreateNodeUndefinedLiteral(c: *Context) !*ast.Node { return &node.base; } -fn transCreateNodeArrayInitializer(c: *Context, type_node: *ast.Node) !*ast.Node.SuffixOp { +fn transCreateNodeNullLiteral(c: *Context) !*ast.Node { + const token = try appendToken(c, .Keyword_null, "null"); + const node = try c.a().create(ast.Node.NullLiteral); + node.* = ast.Node.NullLiteral{ + .base = ast.Node{ .id = .NullLiteral }, + .token = token, + }; + return &node.base; +} + +fn transCreateNodeBoolLiteral(c: *Context, value: bool) !*ast.Node { + const token = if (value) + try appendToken(c, .Keyword_true, "true") + else + try appendToken(c, .Keyword_false, "false"); + const node = try c.a().create(ast.Node.BoolLiteral); + node.* = ast.Node.BoolLiteral{ + .base = ast.Node{ .id = .BoolLiteral }, + .token = token, + }; + return &node.base; +} + +fn transCreateNodeArrayInitializer(c: *Context, dot_tok: ast.TokenIndex) !*ast.Node.SuffixOp { _ = try appendToken(c, .LBrace, "{"); const node = try c.a().create(ast.Node.SuffixOp); node.* = ast.Node.SuffixOp{ .base = ast.Node{ .id = .SuffixOp }, - .lhs = .{ .node = type_node }, + .lhs = .{ .dot = dot_tok }, .op = .{ .ArrayInitializer = ast.Node.SuffixOp.Op.InitList.init(c.a()), }, @@ -1753,7 +1848,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); - // const typedef_name = rp.c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl))).?.value; const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); return appendIdentifier(rp.c, typedef_name); }, diff --git a/test/translate_c.zig b/test/translate_c.zig index b8f085c458..eab53498de 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -252,6 +252,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; }); + cases.add_2("array initializer expr", + \\static void foo(void){ + \\ char arr[10] ={1}; + \\ char *arr1[10] ={0}; + \\} + , &[_][]const u8{ + \\pub fn foo() void { + \\ var arr: [10]u8 = .{ + \\ @as(u8, 1), + \\ } ++ .{0} ** 9; + \\ var arr1: [10][*c]u8 = .{ + \\ null, + \\ } ++ .{null} ** 9; + \\} + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.add_both("typedef of function in struct field", From 4dae70e702f10c385be1dea552f3d6e815dc93c9 Mon Sep 17 00:00:00 2001 From: Vexu Date: Sat, 14 Dec 2019 13:09:35 +0200 Subject: [PATCH 3/3] translate-c-2 container aliases --- lib/std/zig/render.zig | 4 +- src-self-hosted/clang.zig | 11 ---- src-self-hosted/translate_c.zig | 99 ++++++++++++++++++++++++------- test/translate_c.zig | 100 +++++++++----------------------- 4 files changed, 107 insertions(+), 107 deletions(-) diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index fa8388b711..9add521c00 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -193,7 +193,6 @@ fn renderRoot( fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *ast.Node) @TypeOf(stream).Child.Error!void { const first_token = node.firstToken(); var prev_token = first_token; - if (prev_token == 0) return; while (tree.tokens.at(prev_token - 1).id == .DocComment) { prev_token -= 1; } @@ -2175,7 +2174,8 @@ fn renderTokenOffset( } while (true) { - const newline_count = if (loc.line < 2) @as(u8, 1) else @as(u8, 2); + assert(loc.line != 0); + const newline_count = if (loc.line == 1) @as(u8, 1) else @as(u8, 2); try stream.writeByteNTimes('\n', newline_count); try stream.writeByteNTimes(' ', indent); try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ")); diff --git a/src-self-hosted/clang.zig b/src-self-hosted/clang.zig index 4764a475c1..0313d6e918 100644 --- a/src-self-hosted/clang.zig +++ b/src-self-hosted/clang.zig @@ -713,16 +713,6 @@ pub const ZigClangRecordDecl_field_iterator = extern struct { opaque: *c_void, }; -pub const ZigClangElaboratedTypeKeyword = extern enum { - Struct, - Interface, - Union, - Class, - Enum, - Typename, - None, -}; - pub extern fn ZigClangSourceManager_getSpellingLoc(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) struct_ZigClangSourceLocation; pub extern fn ZigClangSourceManager_getFilename(self: *const struct_ZigClangSourceManager, SpellingLoc: struct_ZigClangSourceLocation) ?[*:0]const u8; pub extern fn ZigClangSourceManager_getSpellingLineNumber(self: ?*const struct_ZigClangSourceManager, Loc: struct_ZigClangSourceLocation) c_uint; @@ -967,7 +957,6 @@ pub extern fn ZigClangDeclRefExpr_getDecl(*const ZigClangDeclRefExpr) *const Zig pub extern fn ZigClangParenType_getInnerType(*const ZigClangParenType) ZigClangQualType; -pub extern fn ZigClangElaboratedType_getKeyword(*const struct_ZigClangElaboratedType) ZigClangElaboratedTypeKeyword; pub extern fn ZigClangElaboratedType_getNamedType(*const ZigClangElaboratedType) ZigClangQualType; pub extern fn ZigClangAttributedType_getEquivalentType(*const ZigClangAttributedType) ZigClangQualType; diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index ac930efd2b..4478233270 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -15,7 +15,7 @@ pub const Error = error{OutOfMemory}; const TypeError = Error || error{UnsupportedType}; const TransError = TypeError || error{UnsupportedTranslation}; -const DeclTable = std.HashMap(usize, []const u8, addrHash, addrEql); +const DeclTable = std.HashMap(usize, void, addrHash, addrEql); fn addrHash(x: usize) u32 { switch (@typeInfo(usize).Int.bits) { @@ -31,6 +31,12 @@ fn addrEql(a: usize, b: usize) bool { return a == b; } +const SymbolTable = std.StringHashMap(void); +const AliasList = std.SegmentedList(struct { + alias: []const u8, + name: []const u8, +}, 4); + const Scope = struct { id: Id, parent: ?*Scope, @@ -98,6 +104,8 @@ const Context = struct { err: Error, source_manager: *ZigClangSourceManager, decl_table: DeclTable, + alias_list: AliasList, + sym_table: SymbolTable, global_scope: *Scope.Root, ptr_params: std.BufSet, clang_context: *ZigClangASTContext, @@ -177,6 +185,8 @@ pub fn translate( .source_manager = ZigClangASTUnit_getSourceManager(ast_unit), .err = undefined, .decl_table = DeclTable.init(arena), + .alias_list = AliasList.init(arena), + .sym_table = SymbolTable.init(arena), .global_scope = try arena.create(Scope.Root), .ptr_params = std.BufSet.init(arena), .clang_context = ZigClangASTUnit_getASTContext(ast_unit).?, @@ -191,10 +201,15 @@ pub fn translate( if (!ZigClangASTUnit_visitLocalTopLevelDecls(ast_unit, &context, declVisitorC)) { return context.err; } + var it = context.alias_list.iterator(0); + while (it.next()) |alias| { + if (!context.sym_table.contains(alias.alias)) { + try createAlias(&context, alias); + } + } tree.root_node.eof_token = try appendToken(&context, .Eof, ""); tree.source = source_buffer.toOwnedSlice(); - if (false) { std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source); var i: usize = 0; @@ -240,10 +255,9 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { } fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { - if (c.decl_table.contains(@ptrToInt(fn_decl))) return; // Avoid processing this decl twice + if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice const rp = makeRestorePoint(c); const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); - _ = try c.decl_table.put(@ptrToInt(fn_decl), fn_name); const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); const fn_qt = ZigClangFunctionDecl_getType(fn_decl); const fn_type = ZigClangQualType_getTypePtr(fn_qt); @@ -305,7 +319,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { } fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { - if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice + if (try c.decl_table.put(@ptrToInt(var_decl), {})) |_| return; // Avoid processing this decl twice const rp = makeRestorePoint(c); const visib_tok = try appendToken(c, .Keyword_pub, "pub"); @@ -316,7 +330,6 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { var scope = &c.global_scope.base; const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); - _ = try c.decl_table.put(@ptrToInt(var_decl), var_name); const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); @@ -388,13 +401,12 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { } fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void { - if (c.decl_table.contains(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) return; // Avoid processing this decl twice + 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))); - _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); const name_tok = try appendToken(c, .Identifier, typedef_name); const eq_tok = try appendToken(c, .Equal, "="); @@ -429,12 +441,9 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err } fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void { - if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice + if (try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_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 bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) @@ -447,8 +456,10 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) return; + const visib_tok = try appendToken(c, .Keyword_pub, "pub"); + const const_tok = try appendToken(c, .Keyword_const, "const"); + const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); - _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); const name_tok = try appendToken(c, .Identifier, name); const eq_tok = try appendToken(c, .Equal, "="); @@ -480,6 +491,36 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! }; try addTopLevelDecl(c, name, &node.base); + try c.alias_list.push(.{ .alias = bare_name, .name = name }); +} + +fn createAlias(c: *Context, alias: var) !void { + const visib_tok = try appendToken(c, .Keyword_pub, "pub"); + const mut_tok = try appendToken(c, .Keyword_const, "const"); + const name_tok = try appendToken(c, .Identifier, alias.alias); + + const eq_tok = try appendToken(c, .Equal, "="); + const init_node = try appendIdentifier(c, alias.name); + + 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 = mut_tok, + .comptime_token = null, + .extern_export_token = null, + .lib_name = null, + .type_node = null, + .align_node = null, + .section_node = null, + .init_node = init_node, + .semicolon_token = try appendToken(c, .Semicolon, ";"), + }; + return addTopLevelDecl(c, alias.alias, &node.base); } const ResultUsed = enum { @@ -1063,9 +1104,9 @@ fn transInitListExpr( } const arr_type = ZigClangType_getAsArrayTypeUnsafe(qual_type); - const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type); const child_qt = ZigClangArrayType_getElementType(arr_type); const init_count = ZigClangInitListExpr_getNumInits(expr); + const const_arr_ty = @ptrCast(*const ZigClangConstantArrayType, qual_type); const size_ap_int = ZigClangConstantArrayType_getSize(const_arr_ty); const all_count = ZigClangAPInt_getLimitedValue(size_ap_int, std.math.maxInt(usize)); const leftover_count = all_count - init_count; @@ -1270,6 +1311,7 @@ fn maybeSuppressResult( fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: *ast.Node) !void { try c.tree.root_node.decls.push(decl_node); + _ = try c.sym_table.put(name, {}); } fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) TypeError!*ast.Node { @@ -1316,7 +1358,7 @@ fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeErro .init_arg_expr = .None, .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), .lbrace_token = lbrace_token, - .rbrace_token = undefined, // TODO + .rbrace_token = undefined, }; var it = ZigClangRecordDecl_field_begin(record_def); @@ -1855,17 +1897,14 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour const record_ty = @ptrCast(*const ZigClangRecordType, ty); const record_decl = ZigClangRecordType_getDecl(record_ty); - if (rp.c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv| - return appendIdentifier(rp.c, kv.value) + if (try getContainerName(rp.c, record_decl)) |name| + return appendIdentifier(rp.c, name) else return transRecordDecl(rp.c, record_decl); }, .Elaborated => { const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); - switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) { - .Struct, .Enum, .Union => return try transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc), - else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported elaborated type", .{}), - } + return transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc); }, else => { const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); @@ -1874,6 +1913,24 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour } } +fn getContainerName(c: *Context, record_decl: *const ZigClangRecordDecl) !?[]const u8 { + const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); + + const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) + "union" + else if (ZigClangRecordDecl_isStruct(record_decl)) + "struct" + else { + try emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); + return null; + }; + + if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) + return null; + + return try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); +} + fn isCVoid(qt: ZigClangQualType) bool { const ty = ZigClangQualType_getTypePtr(qt); if (ZigClangType_getTypeClass(ty) == .Builtin) { diff --git a/test/translate_c.zig b/test/translate_c.zig index eab53498de..92ebdb9d26 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -186,72 +186,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub export var arr2: [*c]u8 = "hello"; }); - cases.add_2("pointer to struct demoted to opaque due to bit fields", - \\struct Foo { - \\ unsigned int: 1; - \\}; - \\struct Bar { - \\ struct Foo *foo; - \\}; - , &[_][]const u8{ // TODO that semicolon is hideous - \\pub const struct_Foo = @OpaqueType() // /home/vexu/Documents/zig/zig/zig-cache/source.h:2:5: warning: struct demoted to opaque type - has bitfield - \\ ; - \\pub const struct_Bar = extern struct { - \\ foo: ?*struct_Foo, - \\}; - }); - - cases.add_2("double define struct", - \\typedef struct Bar Bar; - \\typedef struct Foo Foo; - \\ - \\struct Foo { - \\ Foo *a; - \\}; - \\ - \\struct Bar { - \\ Foo *a; - \\}; - , &[_][]const u8{ - \\pub const struct_Bar = extern struct { - \\ a: [*c]Foo, - \\}; - \\pub const Bar = struct_Bar; - \\pub const struct_Foo = extern struct { - \\ a: [*c]Foo, - \\}; - \\pub const Foo = struct_Foo; - }); - - cases.add_2("simple struct", - \\struct Foo { - \\ int x; - \\ char *y; - \\}; - , &[_][]const u8{ - \\const struct_Foo = extern struct { - \\ x: c_int, - \\ y: [*c]u8, - \\}; - }); - - cases.add_2("self referential struct with function pointer", - \\struct Foo { - \\ void (*derp)(struct Foo *foo); - \\}; - , &[_][]const u8{ - \\pub const struct_Foo = extern struct { - \\ derp: ?extern fn ([*c]struct_Foo) void, - \\}; - }); - cases.add_2("struct prototype used in func", - \\struct Foo; - \\struct Foo *some_func(struct Foo *foo, int x); - , &[_][]const u8{ - \\pub const struct_Foo = @OpaqueType(); - \\pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo; - }); - cases.add_2("array initializer expr", \\static void foo(void){ \\ char arr[10] ={1}; @@ -268,6 +202,21 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_2("field struct", + \\union OpenGLProcs { + \\ struct { + \\ int Clear; + \\ } gl; + \\}; + , &[_][]const u8{ + \\pub const union_OpenGLProcs = extern union { + \\ gl: extern struct { + \\ Clear: c_int, + \\ }, + \\}; + \\pub const OpenGLProcs = union_OpenGLProcs; + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// cases.add_both("typedef of function in struct field", @@ -284,7 +233,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\}; }); - cases.add("pointer to struct demoted to opaque due to bit fields", + cases.add_both("pointer to struct demoted to opaque due to bit fields", \\struct Foo { \\ unsigned int: 1; \\}; @@ -292,7 +241,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\ struct Foo *foo; \\}; , &[_][]const u8{ - \\pub const struct_Foo = @OpaqueType(); + \\pub const struct_Foo = @OpaqueType() + , \\pub const struct_Bar = extern struct { \\ foo: ?*struct_Foo, \\}; @@ -441,7 +391,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); - cases.add("double define struct", + cases.add_both("double define struct", \\typedef struct Bar Bar; \\typedef struct Foo Foo; \\ @@ -456,10 +406,14 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const struct_Foo = extern struct { \\ a: [*c]Foo, \\}; + , \\pub const Foo = struct_Foo; + , \\pub const struct_Bar = extern struct { \\ a: [*c]Foo, \\}; + , + \\pub const Bar = struct_Bar; }); cases.addAllowWarnings("simple data types", @@ -536,7 +490,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn foo(noalias bar: ?*c_void, noalias arg1: ?*c_void) void; }); - cases.add("simple struct", + cases.add_both("simple struct", \\struct Foo { \\ int x; \\ char *y; @@ -588,7 +542,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub extern fn func(array: [*c]c_int) void; }); - cases.add("self referential struct with function pointer", + cases.add_both("self referential struct with function pointer", \\struct Foo { \\ void (*derp)(struct Foo *foo); \\}; @@ -600,7 +554,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const Foo = struct_Foo; }); - cases.add("struct prototype used in func", + cases.add_both("struct prototype used in func", \\struct Foo; \\struct Foo *some_func(struct Foo *foo, int x); , &[_][]const u8{ @@ -632,7 +586,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\pub const THING2 = THING1; }); - cases.add("circular struct definitions", + cases.add_both("circular struct definitions", \\struct Bar; \\ \\struct Foo {