diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index fa8388b71..9add521c0 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 4764a475c..0313d6e91 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 ac930efd2..447823327 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 eab53498d..92ebdb9d2 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 {