From a6960b89ed9b1a5951d08b1f7d8e215c86bb9e7e Mon Sep 17 00:00:00 2001 From: Vexu Date: Tue, 17 Dec 2019 22:05:07 +0200 Subject: [PATCH] translate-c-2 fix container type resolution --- src-self-hosted/translate_c.zig | 518 +++++++++++++++----------------- test/translate_c.zig | 29 +- 2 files changed, 263 insertions(+), 284 deletions(-) diff --git a/src-self-hosted/translate_c.zig b/src-self-hosted/translate_c.zig index a3ed6a9999..0f7f1b99bc 100644 --- a/src-self-hosted/translate_c.zig +++ b/src-self-hosted/translate_c.zig @@ -371,13 +371,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); }, .Typedef => { - return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); + _ = try transTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); }, .Enum => { _ = try transEnumDecl(c, @ptrCast(*const ZigClangEnumDecl, decl)); }, .Record => { - return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); + _ = try transRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); }, .Var => { return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); @@ -541,10 +541,9 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { return addTopLevelDecl(c, checked_name, &node.base); } -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 +fn transTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!?*ast.Node { + if (c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) |kv| + return try transCreateNodeIdentifier(c, kv.value); // 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"); @@ -558,29 +557,40 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); node.init_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { error.UnsupportedType => { - return failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); + try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); + return null; }, error.OutOfMemory => |e| return e, }; node.semicolon_token = try appendToken(c, .Semicolon, ";"); try addTopLevelDecl(c, typedef_name, &node.base); + return transCreateNodeIdentifier(c, typedef_name); } -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); +fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!?*ast.Node { + if (c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv| + return try transCreateNodeIdentifier(c, kv.value); // Avoid processing this decl twice + const record_loc = ZigClangRecordDecl_getLocation(record_decl); - const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); + var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); + var is_unnamed = false; + if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) { + bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); + is_unnamed = true; + } - const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) - "union" - else if (ZigClangRecordDecl_isStruct(record_decl)) - "struct" - else - return emitWarning(c, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); - - if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) - return; + 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 { + try emitWarning(c, record_loc, "record {} is not a struct or union", .{bare_name}); + return null; + } const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); @@ -588,16 +598,211 @@ fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error! const node = try transCreateNodeVarDecl(c, true, true, name); node.eq_token = try appendToken(c, .Equal, "="); - node.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, + + var semicolon: ast.TokenIndex = undefined; + node.init_node = blk: { + const rp = makeRestorePoint(c); + const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { + const opaque = try transCreateNodeOpaqueType(c); + semicolon = try appendToken(c, .Semicolon, ";"); + break :blk opaque; + }; + + 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.* = .{ + .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, + }; + + 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)) { + const opaque = try transCreateNodeOpaqueType(c); + semicolon = try appendToken(c, .Semicolon, ";"); + try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); + break :blk opaque; + } + + const field_name = try appendIdentifier(c, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); + _ = try appendToken(c, .Colon, ":"); + const field_type = transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc) catch |err| switch (err) { + error.UnsupportedType => { + try failDecl(c, record_loc, name, "unable to translate {} member type", .{container_kind_name}); + return null; + }, + else => |e| return e, + }; + + 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, "}"); + semicolon = try appendToken(c, .Semicolon, ";"); + break :blk &container_node.base; }; + node.semicolon_token = semicolon; + + try addTopLevelDecl(c, name, &node.base); + if (!is_unnamed) + try c.alias_list.push(.{ .alias = bare_name, .name = name }); + return transCreateNodeIdentifier(c, name); +} + +fn transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { + if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| + return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice + const rp = makeRestorePoint(c); + const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); + + var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); + var is_unnamed = false; + if (bare_name.len == 0) { + bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); + is_unnamed = true; + } + + const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); + _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); + const node = try transCreateNodeVarDecl(c, true, true, name); + node.eq_token = try appendToken(c, .Equal, "="); + + node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { + var pure_enum = true; + var it = ZigClangEnumDecl_enumerator_begin(enum_def); + var end_it = ZigClangEnumDecl_enumerator_end(enum_def); + while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { + const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); + if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { + pure_enum = false; + break; + } + } + + const extern_tok = try appendToken(c, .Keyword_extern, "extern"); + const container_tok = try appendToken(c, .Keyword_enum, "enum"); + + const container_node = try c.a().create(ast.Node.ContainerDecl); + container_node.* = .{ + .layout_token = extern_tok, + .kind_token = container_tok, + .init_arg_expr = .None, + .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), + .lbrace_token = undefined, + .rbrace_token = undefined, + }; + + const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); + + // TODO only emit this tag type if the enum tag type is not the default. + // I don't know what the default is, need to figure out how clang is deciding. + // it appears to at least be different across gcc/msvc + if (!isCBuiltinType(int_type, .UInt) and + !isCBuiltinType(int_type, .Int)) + { + _ = try appendToken(c, .LParen, "("); + container_node.init_arg_expr = .{ + .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { + error.UnsupportedType => { + try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); + return null; + }, + else => |e| return e, + }, + }; + _ = try appendToken(c, .RParen, ")"); + } + + container_node.lbrace_token = try appendToken(c, .LBrace, "{"); + + it = ZigClangEnumDecl_enumerator_begin(enum_def); + end_it = ZigClangEnumDecl_enumerator_end(enum_def); + while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { + const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); + + const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const))); + + const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name)) + enum_val_name[bare_name.len..] + else + enum_val_name; + + const field_name_tok = try appendIdentifier(c, field_name); + + const int_node = if (!pure_enum) blk: { + _ = try appendToken(c, .Colon, "="); + break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); + } else + null; + + const field_node = try c.a().create(ast.Node.ContainerField); + field_node.* = .{ + .doc_comments = null, + .comptime_token = null, + .name_token = field_name_tok, + .type_expr = null, + .value_expr = int_node, + .align_expr = null, + }; + + try container_node.fields_and_decls.push(&field_node.base); + _ = try appendToken(c, .Comma, ","); + // In C each enum value is in the global namespace. So we put them there too. + // At this point we can rely on the enum emitting successfully. + try addEnumTopLevel(c, name, field_name, enum_val_name); + } + container_node.rbrace_token = try appendToken(c, .RBrace, "}"); + + break :blk &container_node.base; + } else + try transCreateNodeOpaqueType(c); + node.semicolon_token = try appendToken(c, .Semicolon, ";"); try addTopLevelDecl(c, name, &node.base); - try c.alias_list.push(.{ .alias = bare_name, .name = name }); + if (!is_unnamed) + try c.alias_list.push(.{ .alias = bare_name, .name = name }); + return transCreateNodeIdentifier(c, name); +} + +fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { + const node = try transCreateNodeVarDecl(c, true, true, enum_val_name); + node.eq_token = try appendToken(c, .Equal, "="); + const enum_ident = try transCreateNodeIdentifier(c, enum_name); + const period_tok = try appendToken(c, .Period, "."); + const field_ident = try transCreateNodeIdentifier(c, field_name); + node.semicolon_token = try appendToken(c, .Semicolon, ";"); + + const field_access_node = try c.a().create(ast.Node.InfixOp); + field_access_node.* = .{ + .op_token = period_tok, + .lhs = enum_ident, + .op = .Period, + .rhs = field_ident, + }; + node.init_node = &field_access_node.base; + try addTopLevelDecl(c, field_name, &node.base); } fn createAlias(c: *Context, alias: var) !void { @@ -1452,7 +1657,6 @@ fn transSwitch( switch_scope.pending_block.rbrace = try appendToken(rp.c, .RBrace, "}"); return &switch_scope.pending_block.base; } - fn transCase( rp: RestorePoint, @@ -1675,222 +1879,6 @@ 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.* = .{ - .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, - }; - - 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 appendIdentifier(c, 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 transEnumDecl(c: *Context, enum_decl: *const ZigClangEnumDecl) Error!?*ast.Node { - if (c.decl_table.get(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)))) |name| - return try transCreateNodeIdentifier(c, name.value); // Avoid processing this decl twice - const rp = makeRestorePoint(c); - const enum_loc = ZigClangEnumDecl_getLocation(enum_decl); - - var bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_decl))); - var is_unnamed = false; - if (bare_name.len == 0) { - bare_name = try std.fmt.allocPrint(c.a(), "unnamed_{}", .{c.getMangle()}); - is_unnamed = true; - } - - const name = try std.fmt.allocPrint(c.a(), "enum_{}", .{bare_name}); - _ = try c.decl_table.put(@ptrToInt(ZigClangEnumDecl_getCanonicalDecl(enum_decl)), name); - const node = try transCreateNodeVarDecl(c, true, true, name); - node.eq_token = try appendToken(c, .Equal, "="); - - node.init_node = if (ZigClangEnumDecl_getDefinition(enum_decl)) |enum_def| blk: { - var pure_enum = true; - var it = ZigClangEnumDecl_enumerator_begin(enum_def); - var end_it = ZigClangEnumDecl_enumerator_end(enum_def); - while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { - const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); - if (ZigClangEnumConstantDecl_getInitExpr(enum_const)) |_| { - pure_enum = false; - break; - } - } - - const extern_tok = try appendToken(c, .Keyword_extern, "extern"); - const container_tok = try appendToken(c, .Keyword_enum, "enum"); - - const container_node = try c.a().create(ast.Node.ContainerDecl); - container_node.* = .{ - .layout_token = extern_tok, - .kind_token = container_tok, - .init_arg_expr = .None, - .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), - .lbrace_token = undefined, - .rbrace_token = undefined, - }; - - const int_type = ZigClangEnumDecl_getIntegerType(enum_decl); - - // TODO only emit this tag type if the enum tag type is not the default. - // I don't know what the default is, need to figure out how clang is deciding. - // it appears to at least be different across gcc/msvc - if (!isCBuiltinType(int_type, .UInt) and - !isCBuiltinType(int_type, .Int)) - { - _ = try appendToken(c, .LParen, "("); - container_node.init_arg_expr = .{ - .Type = transQualType(rp, int_type, enum_loc) catch |err| switch (err) { - error.UnsupportedType => { - if (is_unnamed) { - try emitWarning(c, enum_loc, "unable to translate enum tag type", .{}); - } else { - try failDecl(c, enum_loc, name, "unable to translate enum tag type", .{}); - } - return null; - }, - else => |e| return e, - }, - }; - _ = try appendToken(c, .RParen, ")"); - } - - container_node.lbrace_token = try appendToken(c, .LBrace, "{"); - - it = ZigClangEnumDecl_enumerator_begin(enum_def); - end_it = ZigClangEnumDecl_enumerator_end(enum_def); - while (ZigClangEnumDecl_enumerator_iterator_neq(it, end_it)) : (it = ZigClangEnumDecl_enumerator_iterator_next(it)) { - const enum_const = ZigClangEnumDecl_enumerator_iterator_deref(it); - - const enum_val_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, enum_const))); - - const field_name = if (!is_unnamed and std.mem.startsWith(u8, enum_val_name, bare_name)) - enum_val_name[bare_name.len..] - else - enum_val_name; - - const field_name_tok = try appendIdentifier(c, field_name); - - const int_node = if (!pure_enum) blk: { - _ = try appendToken(c, .Colon, "="); - break :blk try transCreateNodeAPInt(c, ZigClangEnumConstantDecl_getInitVal(enum_const)); - } else - null; - - const field_node = try c.a().create(ast.Node.ContainerField); - field_node.* = .{ - .doc_comments = null, - .comptime_token = null, - .name_token = field_name_tok, - .type_expr = null, - .value_expr = int_node, - .align_expr = null, - }; - - try container_node.fields_and_decls.push(&field_node.base); - _ = try appendToken(c, .Comma, ","); - // In C each enum value is in the global namespace. So we put them there too. - // At this point we can rely on the enum emitting successfully. - try addEnumTopLevel(c, name, field_name, enum_val_name); - } - container_node.rbrace_token = try appendToken(c, .RBrace, "}"); - - break :blk &container_node.base; - } else - try transCreateNodeOpaqueType(c); - - node.semicolon_token = try appendToken(c, .Semicolon, ";"); - - try addTopLevelDecl(c, name, &node.base); - if (!is_unnamed) - try c.alias_list.push(.{ .alias = bare_name, .name = name }); - return transCreateNodeIdentifier(c, name); -} - -fn addEnumTopLevel(c: *Context, enum_name: []const u8, field_name: []const u8, enum_val_name: []const u8) !void { - const node = try transCreateNodeVarDecl(c, true, true, enum_val_name); - node.eq_token = try appendToken(c, .Equal, "="); - const enum_ident = try transCreateNodeIdentifier(c, enum_name); - const period_tok = try appendToken(c, .Period, "."); - const field_ident = try transCreateNodeIdentifier(c, field_name); - node.semicolon_token = try appendToken(c, .Semicolon, ";"); - - const field_access_node = try c.a().create(ast.Node.InfixOp); - field_access_node.* = .{ - .op_token = period_tok, - .lhs = enum_ident, - .op = .Period, - .rhs = field_ident, - }; - node.init_node = &field_access_node.base; - try addTopLevelDecl(c, field_name, &node.base); -} - fn isCBuiltinType(qt: ZigClangQualType, kind: ZigClangBuiltinTypeKind) bool { const c_type = qualTypeCanon(qt); if (ZigClangType_getTypeClass(c_type) != .Builtin) @@ -2591,7 +2579,7 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), }); }, - .FunctionProto => { + .FunctionProto, .FunctionNoProto => { const fn_proto_ty = @ptrCast(*const ZigClangFunctionProtoType, ty); const fn_proto = try transFnProto(rp, null, fn_proto_ty, source_loc, null, false); return &fn_proto.base; @@ -2666,24 +2654,15 @@ 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 = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); - return transCreateNodeIdentifier(rp.c, typedef_name); + return (try transTypeDef(rp.c, typedef_decl)) orelse + revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to translate typedef declaration", .{}); }, .Record => { const record_ty = @ptrCast(*const ZigClangRecordType, ty); - // TODO this sould get the name from decl_table - // struct Foo { - // struct Bar{ - // int b; - // }; - // struct Bar c; - // }; const record_decl = ZigClangRecordType_getDecl(record_ty); - if (try getContainerName(rp, record_decl)) |name| - return transCreateNodeIdentifier(rp.c, name) - else - return transRecordDecl(rp.c, record_decl); + return (try transRecordDecl(rp.c, record_decl)) orelse + revertAndWarn(rp, error.UnsupportedType, source_loc, "unable to resolve record declaration", .{}); }, .Enum => { const enum_ty = @ptrCast(*const ZigClangEnumType, ty); @@ -2704,6 +2683,10 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour const attributed_ty = @ptrCast(*const ZigClangAttributedType, ty); return transQualType(rp, ZigClangAttributedType_getEquivalentType(attributed_ty), source_loc); }, + .MacroQualified => { + const macroqualified_ty = @ptrCast(*const ZigClangMacroQualifiedType, ty); + return transQualType(rp, ZigClangMacroQualifiedType_getModifiedType(macroqualified_ty), source_loc); + }, else => { const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); @@ -2711,22 +2694,6 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour } } -fn getContainerName(rp: RestorePoint, record_decl: *const ZigClangRecordDecl) !?[]const u8 { - const bare_name = try rp.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 revertAndWarn(rp, error.UnsupportedType, ZigClangRecordDecl_getLocation(record_decl), "record {} is not a struct or union", .{bare_name}); - - if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) - return null; - - return try std.fmt.allocPrint(rp.c.a(), "{}_{}", .{ container_kind_name, bare_name }); -} - fn isCVoid(qt: ZigClangQualType) bool { const ty = ZigClangQualType_getTypePtr(qt); if (ZigClangType_getTypeClass(ty) == .Builtin) { @@ -2909,14 +2876,13 @@ fn finishTransFnProto( }; const fn_proto = try rp.c.a().create(ast.Node.FnProto); - fn_proto.* = ast.Node.FnProto{ - .base = ast.Node{ .id = ast.Node.Id.FnProto }, + fn_proto.* = .{ .doc_comments = null, .visib_token = pub_tok, .fn_token = fn_tok, .name_token = name_tok, .params = fn_params, - .return_type = ast.Node.FnProto.ReturnType{ .Explicit = return_type_node }, + .return_type = .{ .Explicit = return_type_node }, .var_args_token = null, // TODO this field is broken in the AST data model .extern_export_inline_token = extern_export_inline_tok, .cc_token = cc_tok, diff --git a/test/translate_c.zig b/test/translate_c.zig index 0935f2cf65..be31ee3cbb 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -228,7 +228,7 @@ 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, @@ -622,18 +622,15 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\#define glClearPFN PFNGLCLEARPROC , &[_][]const u8{ \\pub const GLbitfield = c_uint; - , \\pub const PFNGLCLEARPROC = ?extern fn (GLbitfield) void; - , \\pub const OpenGLProc = ?extern fn () void; - , + \\pub const struct_unnamed_1 = extern struct { + \\ Clear: PFNGLCLEARPROC, + \\}; \\pub const union_OpenGLProcs = extern union { \\ ptr: [1]OpenGLProc, - \\ gl: extern struct { - \\ Clear: PFNGLCLEARPROC, - \\ }, + \\ gl: struct_unnamed_1, \\}; - , \\pub extern var glProcs: union_OpenGLProcs; , \\pub const glClearPFN = PFNGLCLEARPROC; @@ -891,6 +888,22 @@ pub fn addCases(cases: *tests.TranslateCContext) void { \\} }); + cases.add_2("type referenced struct", + \\struct Foo { + \\ struct Bar{ + \\ int b; + \\ }; + \\ struct Bar c; + \\}; + , &[_][]const u8{ + \\pub const struct_Bar = extern struct { + \\ b: c_int, + \\}; + \\pub const struct_Foo = extern struct { + \\ c: struct_Bar, + \\}; + }); + /////////////// Cases for only stage1 which are TODO items for stage2 //////////////// if (builtin.os != builtin.Os.windows) {