authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-03-21 18:42:30+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2021-03-25 16:59:26+02:00
logdf0f7f46923da9927df18809ad1d744102e78ebd
tree3b780c2a5b2ebc92328a58effe4b1b0e0ca28afe
parent5c28b8cd119979bb4b7d32edd1f4542165fc1f98

translate-c: stop creating unnamed decls for typedefs child types


2 files changed, 127 insertions(+), 49 deletions(-)

src/translate_c.zig+77-17
...@@ -270,7 +270,10 @@ pub const Context = struct {...@@ -270,7 +270,10 @@ pub const Context = struct {
270 global_scope: *Scope.Root,270 global_scope: *Scope.Root,
271 clang_context: *clang.ASTContext,271 clang_context: *clang.ASTContext,
272 mangle_count: u32 = 0,272 mangle_count: u32 = 0,
273 /// Table of record decls that have been demoted to opaques.
273 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},274 opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
275 /// Table of unnamed enums and records that are child types of typedefs.
276 unnamed_typedefs: std.AutoHashMapUnmanaged(usize, []const u8) = .{},
274277
275 /// This one is different than the root scope's name table. This contains278 /// This one is different than the root scope's name table. This contains
276 /// a list of names that we found by visiting all the top level decls without279 /// a list of names that we found by visiting all the top level decls without
...@@ -338,6 +341,7 @@ pub fn translate(...@@ -338,6 +341,7 @@ pub fn translate(
338 context.alias_list.deinit();341 context.alias_list.deinit();
339 context.global_names.deinit(gpa);342 context.global_names.deinit(gpa);
340 context.opaque_demotes.deinit(gpa);343 context.opaque_demotes.deinit(gpa);
344 context.unnamed_typedefs.deinit(gpa);
341 context.global_scope.deinit();345 context.global_scope.deinit();
342 }346 }
343347
...@@ -401,6 +405,51 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {...@@ -401,6 +405,51 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
401 if (decl.castToNamedDecl()) |named_decl| {405 if (decl.castToNamedDecl()) |named_decl| {
402 const decl_name = try c.str(named_decl.getName_bytes_begin());406 const decl_name = try c.str(named_decl.getName_bytes_begin());
403 try c.global_names.put(c.gpa, decl_name, {});407 try c.global_names.put(c.gpa, decl_name, {});
408
409 // Check for typedefs with unnamed enum/record child types.
410 if (decl.getKind() == .Typedef) {
411 const typedef_decl = @ptrCast(*const clang.TypedefNameDecl, decl);
412 var child_ty = typedef_decl.getUnderlyingType().getTypePtr();
413 const addr: usize = while (true) switch (child_ty.getTypeClass()) {
414 .Enum => {
415 const enum_ty = @ptrCast(*const clang.EnumType, child_ty);
416 const enum_decl = enum_ty.getDecl();
417 // check if this decl is unnamed
418 if (@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin()[0] != 0) return;
419 break @ptrToInt(enum_decl.getCanonicalDecl());
420 },
421 .Record => {
422 const record_ty = @ptrCast(*const clang.RecordType, child_ty);
423 const record_decl = record_ty.getDecl();
424 // check if this decl is unnamed
425 if (@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin()[0] != 0) return;
426 break @ptrToInt(record_decl.getCanonicalDecl());
427 },
428 .Elaborated => {
429 const elaborated_ty = @ptrCast(*const clang.ElaboratedType, child_ty);
430 child_ty = elaborated_ty.getNamedType().getTypePtr();
431 },
432 .Decayed => {
433 const decayed_ty = @ptrCast(*const clang.DecayedType, child_ty);
434 child_ty = decayed_ty.getDecayedType().getTypePtr();
435 },
436 .Attributed => {
437 const attributed_ty = @ptrCast(*const clang.AttributedType, child_ty);
438 child_ty = attributed_ty.getEquivalentType().getTypePtr();
439 },
440 .MacroQualified => {
441 const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, child_ty);
442 child_ty = macroqualified_ty.getModifiedType().getTypePtr();
443 },
444 else => return,
445 } else unreachable;
446 // TODO https://github.com/ziglang/zig/issues/3756
447 // TODO https://github.com/ziglang/zig/issues/1802
448 const name = if (isZigPrimitiveType(decl_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ decl_name, c.getMangle() }) else decl_name;
449 try c.unnamed_typedefs.putNoClobber(c.gpa, addr, name);
450 // Put this typedef in the decl_table to avoid redefinitions.
451 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
452 }
404 }453 }
405}454}
406455
...@@ -752,17 +801,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -752,17 +801,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
752 const toplevel = scope.id == .root;801 const toplevel = scope.id == .root;
753 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;802 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
754803
755 var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin());
756 var is_unnamed = false;
757 // Record declarations such as `struct {...} x` have no name but they're not
758 // anonymous hence here isAnonymousStructOrUnion is not needed
759 if (bare_name.len == 0) {
760 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
761 is_unnamed = true;
762 }
763
764 var container_kind_name: []const u8 = undefined;
765 var is_union = false;804 var is_union = false;
805 var container_kind_name: []const u8 = undefined;
806 var bare_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin());
807
766 if (record_decl.isUnion()) {808 if (record_decl.isUnion()) {
767 container_kind_name = "union";809 container_kind_name = "union";
768 is_union = true;810 is_union = true;
...@@ -773,7 +815,20 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD...@@ -773,7 +815,20 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
773 return failDecl(c, record_loc, bare_name, "record {s} is not a struct or union", .{bare_name});815 return failDecl(c, record_loc, bare_name, "record {s} is not a struct or union", .{bare_name});
774 }816 }
775817
776 var name: []const u8 = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });818 var is_unnamed = false;
819 var name = bare_name;
820 if (c.unnamed_typedefs.get(@ptrToInt(record_decl.getCanonicalDecl()))) |typedef_name| {
821 bare_name = typedef_name;
822 name = typedef_name;
823 } else {
824 // Record declarations such as `struct {...} x` have no name but they're not
825 // anonymous hence here isAnonymousStructOrUnion is not needed
826 if (bare_name.len == 0) {
827 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
828 is_unnamed = true;
829 }
830 name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
831 }
777 if (!toplevel) name = try bs.makeMangledName(c, name);832 if (!toplevel) name = try bs.makeMangledName(c, name);
778 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);833 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);
779834
...@@ -874,14 +929,19 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E...@@ -874,14 +929,19 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
874 const toplevel = scope.id == .root;929 const toplevel = scope.id == .root;
875 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;930 const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
876931
877 var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());
878 var is_unnamed = false;932 var is_unnamed = false;
879 if (bare_name.len == 0) {933 var bare_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());
880 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});934 var name = bare_name;
881 is_unnamed = true;935 if (c.unnamed_typedefs.get(@ptrToInt(enum_decl.getCanonicalDecl()))) |typedef_name| {
936 bare_name = typedef_name;
937 name = typedef_name;
938 } else {
939 if (bare_name.len == 0) {
940 bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
941 is_unnamed = true;
942 }
943 name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
882 }944 }
883
884 var name: []const u8 = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
885 if (!toplevel) _ = try bs.makeMangledName(c, name);945 if (!toplevel) _ = try bs.makeMangledName(c, name);
886 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);946 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);
887947
test/translate_c.zig+50-32
...@@ -3,6 +3,28 @@ const std = @import("std");...@@ -3,6 +3,28 @@ const std = @import("std");
3const CrossTarget = std.zig.CrossTarget;3const CrossTarget = std.zig.CrossTarget;
44
5pub fn addCases(cases: *tests.TranslateCContext) void {5pub fn addCases(cases: *tests.TranslateCContext) void {
6 cases.add("unnamed child types of typedef receive typedef's name",
7 \\typedef enum {
8 \\ FooA,
9 \\ FooB,
10 \\} Foo;
11 \\typedef struct {
12 \\ int a, b;
13 \\} Bar;
14 , &[_][]const u8{
15 \\pub const Foo = extern enum(c_int) {
16 \\ A,
17 \\ B,
18 \\ _,
19 \\};
20 \\pub const FooA = @enumToInt(Foo.A);
21 \\pub const FooB = @enumToInt(Foo.B);
22 \\pub const Bar = extern struct {
23 \\ a: c_int,
24 \\ b: c_int,
25 \\};
26 });
27
6 cases.add("if as while stmt has semicolon",28 cases.add("if as while stmt has semicolon",
7 \\void foo() {29 \\void foo() {
8 \\ while (1) if (1) {30 \\ while (1) if (1) {
...@@ -218,9 +240,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -218,9 +240,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
218 \\} Bar;240 \\} Bar;
219 , &[_][]const u8{241 , &[_][]const u8{
220 \\source.h:1:9: warning: struct demoted to opaque type - unable to translate type of field foo242 \\source.h:1:9: warning: struct demoted to opaque type - unable to translate type of field foo
221 \\const struct_unnamed_1 = opaque {};243 \\pub const Foo = opaque {};
222 \\pub const Foo = struct_unnamed_1;244 \\pub const Bar = extern struct {
223 \\const struct_unnamed_2 = extern struct {
224 \\ bar: ?*Foo,245 \\ bar: ?*Foo,
225 \\};246 \\};
226 });247 });
...@@ -519,17 +540,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -519,17 +540,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
519 \\} outer;540 \\} outer;
520 \\void foo(outer *x) { x->y = x->x; }541 \\void foo(outer *x) { x->y = x->x; }
521 , &[_][]const u8{542 , &[_][]const u8{
522 \\const struct_unnamed_3 = extern struct {543 \\const struct_unnamed_2 = extern struct {
523 \\ y: c_int,544 \\ y: c_int,
524 \\};545 \\};
525 \\const union_unnamed_2 = extern union {546 \\const union_unnamed_1 = extern union {
526 \\ x: u8,547 \\ x: u8,
527 \\ unnamed_0: struct_unnamed_3,548 \\ unnamed_0: struct_unnamed_2,
528 \\};549 \\};
529 \\const struct_unnamed_1 = extern struct {550 \\pub const outer = extern struct {
530 \\ unnamed_0: union_unnamed_2,551 \\ unnamed_0: union_unnamed_1,
531 \\};552 \\};
532 \\pub const outer = struct_unnamed_1;
533 \\pub export fn foo(arg_x: [*c]outer) void {553 \\pub export fn foo(arg_x: [*c]outer) void {
534 \\ var x = arg_x;554 \\ var x = arg_x;
535 \\ x.*.unnamed_0.unnamed_0.y = @bitCast(c_int, @as(c_uint, x.*.unnamed_0.x));555 \\ x.*.unnamed_0.unnamed_0.y = @bitCast(c_int, @as(c_uint, x.*.unnamed_0.x));
...@@ -565,21 +585,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -565,21 +585,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
565 \\struct {int x,y;} s2 = {.y = 2, .x=1};585 \\struct {int x,y;} s2 = {.y = 2, .x=1};
566 \\foo s3 = { 123 };586 \\foo s3 = { 123 };
567 , &[_][]const u8{587 , &[_][]const u8{
568 \\const struct_unnamed_1 = extern struct {588 \\pub const foo = extern struct {
569 \\ x: c_int,589 \\ x: c_int,
570 \\};590 \\};
571 \\pub const foo = struct_unnamed_1;591 \\const struct_unnamed_1 = extern struct {
572 \\const struct_unnamed_2 = extern struct {
573 \\ x: f64,592 \\ x: f64,
574 \\ y: f64,593 \\ y: f64,
575 \\ z: f64,594 \\ z: f64,
576 \\};595 \\};
577 \\pub export var s0: struct_unnamed_2 = struct_unnamed_2{596 \\pub export var s0: struct_unnamed_1 = struct_unnamed_1{
578 \\ .x = 1.2,597 \\ .x = 1.2,
579 \\ .y = 1.3,598 \\ .y = 1.3,
580 \\ .z = 0,599 \\ .z = 0,
581 \\};600 \\};
582 \\const struct_unnamed_3 = extern struct {601 \\const struct_unnamed_2 = extern struct {
583 \\ sec: c_int,602 \\ sec: c_int,
584 \\ min: c_int,603 \\ min: c_int,
585 \\ hour: c_int,604 \\ hour: c_int,
...@@ -587,7 +606,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -587,7 +606,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
587 \\ mon: c_int,606 \\ mon: c_int,
588 \\ year: c_int,607 \\ year: c_int,
589 \\};608 \\};
590 \\pub export var s1: struct_unnamed_3 = struct_unnamed_3{609 \\pub export var s1: struct_unnamed_2 = struct_unnamed_2{
591 \\ .sec = @as(c_int, 30),610 \\ .sec = @as(c_int, 30),
592 \\ .min = @as(c_int, 15),611 \\ .min = @as(c_int, 15),
593 \\ .hour = @as(c_int, 17),612 \\ .hour = @as(c_int, 17),
...@@ -595,11 +614,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -595,11 +614,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
595 \\ .mon = @as(c_int, 12),614 \\ .mon = @as(c_int, 12),
596 \\ .year = @as(c_int, 2014),615 \\ .year = @as(c_int, 2014),
597 \\};616 \\};
598 \\const struct_unnamed_4 = extern struct {617 \\const struct_unnamed_3 = extern struct {
599 \\ x: c_int,618 \\ x: c_int,
600 \\ y: c_int,619 \\ y: c_int,
601 \\};620 \\};
602 \\pub export var s2: struct_unnamed_4 = struct_unnamed_4{621 \\pub export var s2: struct_unnamed_3 = struct_unnamed_3{
603 \\ .x = @as(c_int, 1),622 \\ .x = @as(c_int, 1),
604 \\ .y = @as(c_int, 2),623 \\ .y = @as(c_int, 2),
605 \\};624 \\};
...@@ -1639,37 +1658,36 @@ pub fn addCases(cases: *tests.TranslateCContext) void {...@@ -1639,37 +1658,36 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
1639 \\ p,1658 \\ p,
1640 \\};1659 \\};
1641 , &[_][]const u8{1660 , &[_][]const u8{
1642 \\const enum_unnamed_1 = extern enum(c_int) {1661 \\pub const d = extern enum(c_int) {
1643 \\ a,1662 \\ a,
1644 \\ b,1663 \\ b,
1645 \\ c,1664 \\ c,
1646 \\ _,1665 \\ _,
1647 \\};1666 \\};
1648 \\pub const a = @enumToInt(enum_unnamed_1.a);1667 \\pub const a = @enumToInt(d.a);
1649 \\pub const b = @enumToInt(enum_unnamed_1.b);1668 \\pub const b = @enumToInt(d.b);
1650 \\pub const c = @enumToInt(enum_unnamed_1.c);1669 \\pub const c = @enumToInt(d.c);
1651 \\pub const d = enum_unnamed_1;1670 \\const enum_unnamed_1 = extern enum(c_int) {
1652 \\const enum_unnamed_2 = extern enum(c_int) {
1653 \\ e = 0,1671 \\ e = 0,
1654 \\ f = 4,1672 \\ f = 4,
1655 \\ g = 5,1673 \\ g = 5,
1656 \\ _,1674 \\ _,
1657 \\};1675 \\};
1658 \\pub const e = @enumToInt(enum_unnamed_2.e);1676 \\pub const e = @enumToInt(enum_unnamed_1.e);
1659 \\pub const f = @enumToInt(enum_unnamed_2.f);1677 \\pub const f = @enumToInt(enum_unnamed_1.f);
1660 \\pub const g = @enumToInt(enum_unnamed_2.g);1678 \\pub const g = @enumToInt(enum_unnamed_1.g);
1661 \\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);1679 \\pub export var h: enum_unnamed_1 = @intToEnum(enum_unnamed_1, e);
1662 \\const enum_unnamed_3 = extern enum(c_int) {1680 \\const enum_unnamed_2 = extern enum(c_int) {
1663 \\ i,1681 \\ i,
1664 \\ j,1682 \\ j,
1665 \\ k,1683 \\ k,
1666 \\ _,1684 \\ _,
1667 \\};1685 \\};
1668 \\pub const i = @enumToInt(enum_unnamed_3.i);1686 \\pub const i = @enumToInt(enum_unnamed_2.i);
1669 \\pub const j = @enumToInt(enum_unnamed_3.j);1687 \\pub const j = @enumToInt(enum_unnamed_2.j);
1670 \\pub const k = @enumToInt(enum_unnamed_3.k);1688 \\pub const k = @enumToInt(enum_unnamed_2.k);
1671 \\pub const struct_Baz = extern struct {1689 \\pub const struct_Baz = extern struct {
1672 \\ l: enum_unnamed_3,1690 \\ l: enum_unnamed_2,
1673 \\ m: d,1691 \\ m: d,
1674 \\};1692 \\};
1675 \\pub const enum_i = extern enum(c_int) {1693 \\pub const enum_i = extern enum(c_int) {