mirror of
https://github.com/ziglang/zig.git
synced 2026-01-07 05:55:36 +00:00
translate-c: stop creating unnamed decls for typedefs child types
This commit is contained in:
parent
5c28b8cd11
commit
df0f7f4692
@ -270,7 +270,10 @@ pub const Context = struct {
|
||||
global_scope: *Scope.Root,
|
||||
clang_context: *clang.ASTContext,
|
||||
mangle_count: u32 = 0,
|
||||
/// Table of record decls that have been demoted to opaques.
|
||||
opaque_demotes: std.AutoHashMapUnmanaged(usize, void) = .{},
|
||||
/// Table of unnamed enums and records that are child types of typedefs.
|
||||
unnamed_typedefs: std.AutoHashMapUnmanaged(usize, []const u8) = .{},
|
||||
|
||||
/// This one is different than the root scope's name table. This contains
|
||||
/// a list of names that we found by visiting all the top level decls without
|
||||
@ -338,6 +341,7 @@ pub fn translate(
|
||||
context.alias_list.deinit();
|
||||
context.global_names.deinit(gpa);
|
||||
context.opaque_demotes.deinit(gpa);
|
||||
context.unnamed_typedefs.deinit(gpa);
|
||||
context.global_scope.deinit();
|
||||
}
|
||||
|
||||
@ -401,6 +405,51 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
|
||||
if (decl.castToNamedDecl()) |named_decl| {
|
||||
const decl_name = try c.str(named_decl.getName_bytes_begin());
|
||||
try c.global_names.put(c.gpa, decl_name, {});
|
||||
|
||||
// Check for typedefs with unnamed enum/record child types.
|
||||
if (decl.getKind() == .Typedef) {
|
||||
const typedef_decl = @ptrCast(*const clang.TypedefNameDecl, decl);
|
||||
var child_ty = typedef_decl.getUnderlyingType().getTypePtr();
|
||||
const addr: usize = while (true) switch (child_ty.getTypeClass()) {
|
||||
.Enum => {
|
||||
const enum_ty = @ptrCast(*const clang.EnumType, child_ty);
|
||||
const enum_decl = enum_ty.getDecl();
|
||||
// check if this decl is unnamed
|
||||
if (@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin()[0] != 0) return;
|
||||
break @ptrToInt(enum_decl.getCanonicalDecl());
|
||||
},
|
||||
.Record => {
|
||||
const record_ty = @ptrCast(*const clang.RecordType, child_ty);
|
||||
const record_decl = record_ty.getDecl();
|
||||
// check if this decl is unnamed
|
||||
if (@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin()[0] != 0) return;
|
||||
break @ptrToInt(record_decl.getCanonicalDecl());
|
||||
},
|
||||
.Elaborated => {
|
||||
const elaborated_ty = @ptrCast(*const clang.ElaboratedType, child_ty);
|
||||
child_ty = elaborated_ty.getNamedType().getTypePtr();
|
||||
},
|
||||
.Decayed => {
|
||||
const decayed_ty = @ptrCast(*const clang.DecayedType, child_ty);
|
||||
child_ty = decayed_ty.getDecayedType().getTypePtr();
|
||||
},
|
||||
.Attributed => {
|
||||
const attributed_ty = @ptrCast(*const clang.AttributedType, child_ty);
|
||||
child_ty = attributed_ty.getEquivalentType().getTypePtr();
|
||||
},
|
||||
.MacroQualified => {
|
||||
const macroqualified_ty = @ptrCast(*const clang.MacroQualifiedType, child_ty);
|
||||
child_ty = macroqualified_ty.getModifiedType().getTypePtr();
|
||||
},
|
||||
else => return,
|
||||
} else unreachable;
|
||||
// TODO https://github.com/ziglang/zig/issues/3756
|
||||
// TODO https://github.com/ziglang/zig/issues/1802
|
||||
const name = if (isZigPrimitiveType(decl_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ decl_name, c.getMangle() }) else decl_name;
|
||||
try c.unnamed_typedefs.putNoClobber(c.gpa, addr, name);
|
||||
// Put this typedef in the decl_table to avoid redefinitions.
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -752,17 +801,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
const toplevel = scope.id == .root;
|
||||
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
|
||||
|
||||
var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin());
|
||||
var is_unnamed = false;
|
||||
// Record declarations such as `struct {...} x` have no name but they're not
|
||||
// anonymous hence here isAnonymousStructOrUnion is not needed
|
||||
if (bare_name.len == 0) {
|
||||
bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
|
||||
is_unnamed = true;
|
||||
}
|
||||
|
||||
var container_kind_name: []const u8 = undefined;
|
||||
var is_union = false;
|
||||
var container_kind_name: []const u8 = undefined;
|
||||
var bare_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, record_decl).getName_bytes_begin());
|
||||
|
||||
if (record_decl.isUnion()) {
|
||||
container_kind_name = "union";
|
||||
is_union = true;
|
||||
@ -773,7 +815,20 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD
|
||||
return failDecl(c, record_loc, bare_name, "record {s} is not a struct or union", .{bare_name});
|
||||
}
|
||||
|
||||
var name: []const u8 = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
|
||||
var is_unnamed = false;
|
||||
var name = bare_name;
|
||||
if (c.unnamed_typedefs.get(@ptrToInt(record_decl.getCanonicalDecl()))) |typedef_name| {
|
||||
bare_name = typedef_name;
|
||||
name = typedef_name;
|
||||
} else {
|
||||
// Record declarations such as `struct {...} x` have no name but they're not
|
||||
// anonymous hence here isAnonymousStructOrUnion is not needed
|
||||
if (bare_name.len == 0) {
|
||||
bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
|
||||
is_unnamed = true;
|
||||
}
|
||||
name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name });
|
||||
}
|
||||
if (!toplevel) name = try bs.makeMangledName(c, name);
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(record_decl.getCanonicalDecl()), name);
|
||||
|
||||
@ -874,14 +929,19 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E
|
||||
const toplevel = scope.id == .root;
|
||||
const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined;
|
||||
|
||||
var bare_name = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());
|
||||
var is_unnamed = false;
|
||||
if (bare_name.len == 0) {
|
||||
bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
|
||||
is_unnamed = true;
|
||||
var bare_name: []const u8 = try c.str(@ptrCast(*const clang.NamedDecl, enum_decl).getName_bytes_begin());
|
||||
var name = bare_name;
|
||||
if (c.unnamed_typedefs.get(@ptrToInt(enum_decl.getCanonicalDecl()))) |typedef_name| {
|
||||
bare_name = typedef_name;
|
||||
name = typedef_name;
|
||||
} else {
|
||||
if (bare_name.len == 0) {
|
||||
bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()});
|
||||
is_unnamed = true;
|
||||
}
|
||||
name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
|
||||
}
|
||||
|
||||
var name: []const u8 = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name});
|
||||
if (!toplevel) _ = try bs.makeMangledName(c, name);
|
||||
try c.decl_table.putNoClobber(c.gpa, @ptrToInt(enum_decl.getCanonicalDecl()), name);
|
||||
|
||||
|
||||
@ -3,6 +3,28 @@ const std = @import("std");
|
||||
const CrossTarget = std.zig.CrossTarget;
|
||||
|
||||
pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
cases.add("unnamed child types of typedef receive typedef's name",
|
||||
\\typedef enum {
|
||||
\\ FooA,
|
||||
\\ FooB,
|
||||
\\} Foo;
|
||||
\\typedef struct {
|
||||
\\ int a, b;
|
||||
\\} Bar;
|
||||
, &[_][]const u8{
|
||||
\\pub const Foo = extern enum(c_int) {
|
||||
\\ A,
|
||||
\\ B,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const FooA = @enumToInt(Foo.A);
|
||||
\\pub const FooB = @enumToInt(Foo.B);
|
||||
\\pub const Bar = extern struct {
|
||||
\\ a: c_int,
|
||||
\\ b: c_int,
|
||||
\\};
|
||||
});
|
||||
|
||||
cases.add("if as while stmt has semicolon",
|
||||
\\void foo() {
|
||||
\\ while (1) if (1) {
|
||||
@ -218,9 +240,8 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\} Bar;
|
||||
, &[_][]const u8{
|
||||
\\source.h:1:9: warning: struct demoted to opaque type - unable to translate type of field foo
|
||||
\\const struct_unnamed_1 = opaque {};
|
||||
\\pub const Foo = struct_unnamed_1;
|
||||
\\const struct_unnamed_2 = extern struct {
|
||||
\\pub const Foo = opaque {};
|
||||
\\pub const Bar = extern struct {
|
||||
\\ bar: ?*Foo,
|
||||
\\};
|
||||
});
|
||||
@ -519,17 +540,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\} outer;
|
||||
\\void foo(outer *x) { x->y = x->x; }
|
||||
, &[_][]const u8{
|
||||
\\const struct_unnamed_3 = extern struct {
|
||||
\\const struct_unnamed_2 = extern struct {
|
||||
\\ y: c_int,
|
||||
\\};
|
||||
\\const union_unnamed_2 = extern union {
|
||||
\\const union_unnamed_1 = extern union {
|
||||
\\ x: u8,
|
||||
\\ unnamed_0: struct_unnamed_3,
|
||||
\\ unnamed_0: struct_unnamed_2,
|
||||
\\};
|
||||
\\const struct_unnamed_1 = extern struct {
|
||||
\\ unnamed_0: union_unnamed_2,
|
||||
\\pub const outer = extern struct {
|
||||
\\ unnamed_0: union_unnamed_1,
|
||||
\\};
|
||||
\\pub const outer = struct_unnamed_1;
|
||||
\\pub export fn foo(arg_x: [*c]outer) void {
|
||||
\\ var x = arg_x;
|
||||
\\ 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 {
|
||||
\\struct {int x,y;} s2 = {.y = 2, .x=1};
|
||||
\\foo s3 = { 123 };
|
||||
, &[_][]const u8{
|
||||
\\const struct_unnamed_1 = extern struct {
|
||||
\\pub const foo = extern struct {
|
||||
\\ x: c_int,
|
||||
\\};
|
||||
\\pub const foo = struct_unnamed_1;
|
||||
\\const struct_unnamed_2 = extern struct {
|
||||
\\const struct_unnamed_1 = extern struct {
|
||||
\\ x: f64,
|
||||
\\ y: f64,
|
||||
\\ z: f64,
|
||||
\\};
|
||||
\\pub export var s0: struct_unnamed_2 = struct_unnamed_2{
|
||||
\\pub export var s0: struct_unnamed_1 = struct_unnamed_1{
|
||||
\\ .x = 1.2,
|
||||
\\ .y = 1.3,
|
||||
\\ .z = 0,
|
||||
\\};
|
||||
\\const struct_unnamed_3 = extern struct {
|
||||
\\const struct_unnamed_2 = extern struct {
|
||||
\\ sec: c_int,
|
||||
\\ min: c_int,
|
||||
\\ hour: c_int,
|
||||
@ -587,7 +606,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ mon: c_int,
|
||||
\\ year: c_int,
|
||||
\\};
|
||||
\\pub export var s1: struct_unnamed_3 = struct_unnamed_3{
|
||||
\\pub export var s1: struct_unnamed_2 = struct_unnamed_2{
|
||||
\\ .sec = @as(c_int, 30),
|
||||
\\ .min = @as(c_int, 15),
|
||||
\\ .hour = @as(c_int, 17),
|
||||
@ -595,11 +614,11 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ .mon = @as(c_int, 12),
|
||||
\\ .year = @as(c_int, 2014),
|
||||
\\};
|
||||
\\const struct_unnamed_4 = extern struct {
|
||||
\\const struct_unnamed_3 = extern struct {
|
||||
\\ x: c_int,
|
||||
\\ y: c_int,
|
||||
\\};
|
||||
\\pub export var s2: struct_unnamed_4 = struct_unnamed_4{
|
||||
\\pub export var s2: struct_unnamed_3 = struct_unnamed_3{
|
||||
\\ .x = @as(c_int, 1),
|
||||
\\ .y = @as(c_int, 2),
|
||||
\\};
|
||||
@ -1639,37 +1658,36 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
|
||||
\\ p,
|
||||
\\};
|
||||
, &[_][]const u8{
|
||||
\\const enum_unnamed_1 = extern enum(c_int) {
|
||||
\\pub const d = extern enum(c_int) {
|
||||
\\ a,
|
||||
\\ b,
|
||||
\\ c,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const a = @enumToInt(enum_unnamed_1.a);
|
||||
\\pub const b = @enumToInt(enum_unnamed_1.b);
|
||||
\\pub const c = @enumToInt(enum_unnamed_1.c);
|
||||
\\pub const d = enum_unnamed_1;
|
||||
\\const enum_unnamed_2 = extern enum(c_int) {
|
||||
\\pub const a = @enumToInt(d.a);
|
||||
\\pub const b = @enumToInt(d.b);
|
||||
\\pub const c = @enumToInt(d.c);
|
||||
\\const enum_unnamed_1 = extern enum(c_int) {
|
||||
\\ e = 0,
|
||||
\\ f = 4,
|
||||
\\ g = 5,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const e = @enumToInt(enum_unnamed_2.e);
|
||||
\\pub const f = @enumToInt(enum_unnamed_2.f);
|
||||
\\pub const g = @enumToInt(enum_unnamed_2.g);
|
||||
\\pub export var h: enum_unnamed_2 = @intToEnum(enum_unnamed_2, e);
|
||||
\\const enum_unnamed_3 = extern enum(c_int) {
|
||||
\\pub const e = @enumToInt(enum_unnamed_1.e);
|
||||
\\pub const f = @enumToInt(enum_unnamed_1.f);
|
||||
\\pub const g = @enumToInt(enum_unnamed_1.g);
|
||||
\\pub export var h: enum_unnamed_1 = @intToEnum(enum_unnamed_1, e);
|
||||
\\const enum_unnamed_2 = extern enum(c_int) {
|
||||
\\ i,
|
||||
\\ j,
|
||||
\\ k,
|
||||
\\ _,
|
||||
\\};
|
||||
\\pub const i = @enumToInt(enum_unnamed_3.i);
|
||||
\\pub const j = @enumToInt(enum_unnamed_3.j);
|
||||
\\pub const k = @enumToInt(enum_unnamed_3.k);
|
||||
\\pub const i = @enumToInt(enum_unnamed_2.i);
|
||||
\\pub const j = @enumToInt(enum_unnamed_2.j);
|
||||
\\pub const k = @enumToInt(enum_unnamed_2.k);
|
||||
\\pub const struct_Baz = extern struct {
|
||||
\\ l: enum_unnamed_3,
|
||||
\\ l: enum_unnamed_2,
|
||||
\\ m: d,
|
||||
\\};
|
||||
\\pub const enum_i = extern enum(c_int) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user