Skip to content
This repository was archived by the owner on Nov 26, 2025. It is now read-only.

Commit 6e2131b

Browse files
dotcarmenVexu
authored andcommitted
Scope: don't mangle member function names
1 parent 75c8c6d commit 6e2131b

9 files changed

+85
-29
lines changed

src/Scope.zig

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ pub const Root = struct {
252252
const gpa = root.translator.gpa;
253253
const arena = root.translator.arena;
254254

255-
var member_names: std.StringArrayHashMapUnmanaged(u32) = .empty;
255+
var member_names: std.StringArrayHashMapUnmanaged(void) = .empty;
256256
defer member_names.deinit(gpa);
257257
for (root.container_member_fns_map.values()) |members| {
258258
member_names.clearRetainingCapacity();
@@ -261,7 +261,7 @@ pub const Root = struct {
261261
const payload: *ast.Payload.Container = @alignCast(@fieldParentPtr("base", members.container_decl_ptr.ptr_otherwise));
262262
// Avoid duplication with field names
263263
for (payload.data.fields) |field| {
264-
try member_names.put(gpa, field.name, 0);
264+
try member_names.put(gpa, field.name, {});
265265
}
266266
break :blk_record &payload.data.decls;
267267
},
@@ -278,34 +278,39 @@ pub const Root = struct {
278278
};
279279

280280
const old_decls = decls_ptr.*;
281-
const new_decls = try arena.alloc(ast.Node, old_decls.len + members.member_fns.items.len);
281+
const new_decls = try arena.alloc(ast.Node, old_decls.len + members.member_fns.items.len * 2);
282282
@memcpy(new_decls[0..old_decls.len], old_decls);
283283
// Assume the allocator of payload.data.decls is arena,
284284
// so don't add arena.free(old_variables).
285285
const func_ref_vars = new_decls[old_decls.len..];
286286
var count: u32 = 0;
287+
288+
// Add members without mangling them - only fields may cause name conflicts
287289
for (members.member_fns.items) |func| {
288290
const func_name = func.data.name.?;
291+
const member_name_slot = try member_names.getOrPutValue(gpa, func_name, {});
292+
if (member_name_slot.found_existing) continue;
293+
func_ref_vars[count] = try ast.Node.Tag.pub_var_simple.create(arena, .{
294+
.name = func_name,
295+
.init = try ast.Node.Tag.root_ref.create(arena, func_name),
296+
});
297+
count += 1;
298+
}
289299

290-
const last_index = std.mem.lastIndexOf(u8, func_name, "_");
291-
const last_name = if (last_index) |index| func_name[index + 1 ..] else continue;
292-
var same_count: u32 = 0;
293-
const gop = try member_names.getOrPutValue(gpa, last_name, same_count);
294-
if (gop.found_existing) {
295-
gop.value_ptr.* += 1;
296-
same_count = gop.value_ptr.*;
297-
}
298-
const var_name = if (same_count == 0)
299-
last_name
300-
else
301-
try std.fmt.allocPrint(arena, "{s}{d}", .{ last_name, same_count });
302-
300+
for (members.member_fns.items) |func| {
301+
const func_name = func.data.name.?;
302+
const func_name_trimmed = std.mem.trimEnd(u8, func_name, "_");
303+
const last_idx = std.mem.lastIndexOf(u8, func_name_trimmed, "_") orelse continue;
304+
const func_name_alias = func_name[last_idx + 1 ..];
305+
const member_name_slot = try member_names.getOrPutValue(gpa, func_name_alias, {});
306+
if (member_name_slot.found_existing) continue;
303307
func_ref_vars[count] = try ast.Node.Tag.pub_var_simple.create(arena, .{
304-
.name = var_name,
305-
.init = try ast.Node.Tag.identifier.create(arena, func_name),
308+
.name = func_name_alias,
309+
.init = try ast.Node.Tag.root_ref.create(arena, func_name),
306310
});
307311
count += 1;
308312
}
313+
309314
decls_ptr.* = new_decls[0 .. old_decls.len + count];
310315
}
311316
}

src/Translator.zig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@ pub fn translate(options: Options) mem.Allocator.Error![]u8 {
223223
var allocating: std.Io.Writer.Allocating = .init(gpa);
224224
defer allocating.deinit();
225225

226+
allocating.writer.writeAll(
227+
\\const __root = @This();
228+
\\
229+
) catch return error.OutOfMemory;
230+
226231
if (options.module_libs) {
227232
allocating.writer.writeAll(
228233
\\pub const __builtin = @import("c_builtins");

src/ast.zig

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,9 @@ pub const Node = extern union {
247247
/// comptime { if (!(lhs)) @compileError(rhs); }
248248
static_assert,
249249

250+
/// __root.<name>
251+
root_ref,
252+
250253
pub const last_no_payload_tag = Tag.@"break";
251254
pub const no_payload_count = @intFromEnum(last_no_payload_tag) + 1;
252255

@@ -406,6 +409,7 @@ pub const Node = extern union {
406409
.builtin_extern => Payload.Extern,
407410
.helper_call => Payload.HelperCall,
408411
.helper_ref => Payload.HelperRef,
412+
.root_ref => Payload.RootRef,
409413
};
410414
}
411415

@@ -801,6 +805,11 @@ pub const Payload = struct {
801805
base: Payload,
802806
data: []const u8,
803807
};
808+
809+
pub const RootRef = struct {
810+
base: Payload,
811+
data: []const u8,
812+
};
804813
};
805814

806815
/// Converts the nodes into a Zig Ast.
@@ -2190,6 +2199,15 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
21902199
});
21912200
},
21922201
.@"anytype" => unreachable, // Handled in renderParams
2202+
.root_ref => {
2203+
const payload = node.castTag(.root_ref).?.data;
2204+
const root_tok = try c.addNode(.{
2205+
.tag = .identifier,
2206+
.main_token = try c.addIdentifier("__root"),
2207+
.data = undefined,
2208+
});
2209+
return renderFieldAccess(c, root_tok, payload);
2210+
},
21932211
}
21942212
}
21952213

@@ -2512,6 +2530,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
25122530
.sqrt,
25132531
.trunc,
25142532
.floor,
2533+
.root_ref,
25152534
=> {
25162535
// no grouping needed
25172536
return renderNode(c, node);

test/cases/translate/anonymous_struct_&_unions.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ void foo(outer *x) { x->y = x->x; }
1717
// };
1818
// pub const outer = extern struct {
1919
// unnamed_0: union_unnamed_1 = @import("std").mem.zeroes(union_unnamed_1),
20+
// pub const foo = __root.foo;
2021
// };
2122
// pub export fn foo(arg_x: [*c]outer) void {
2223
// var x = arg_x;

test/cases/translate/detect_member_func.c

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,22 @@ int opa_foo_init(OpaFoo *foo);
2424
int opa_foo1_bar(OpaFoo foo);
2525
int opa_foo2_bar(OpaFoo *foo);
2626

27+
typedef struct foo_quux FooQuux;
28+
29+
int foo_quux_bar1(FooQuux *foo);
30+
int foo_quux_bar2_(FooQuux *foo);
31+
2732
// translate
2833
//
2934
// pub const Foo = extern struct {
3035
// foo: c_int = 0,
3136
// bar: [*c]u8 = null,
32-
// pub const bar1 = Foo_bar;
33-
// pub const quux = libsomething_quux;
34-
// pub const bar2 = foo1_bar;
35-
// pub const bar3 = foo2_bar;
37+
// pub const Foo_bar = __root.Foo_bar;
38+
// pub const baz = __root.baz;
39+
// pub const libsomething_quux = __root.libsomething_quux;
40+
// pub const foo1_bar = __root.foo1_bar;
41+
// pub const foo2_bar = __root.foo2_bar;
42+
// pub const quux = __root.libsomething_quux;
3643
// };
3744
// pub extern fn Foo_bar(foo: Foo) c_int;
3845
// pub extern fn baz(foo: [*c]Foo) c_int;
@@ -42,18 +49,32 @@ int opa_foo2_bar(OpaFoo *foo);
4249
// pub const UFoo = extern union {
4350
// foo: c_int,
4451
// numb: f32,
45-
// pub const bar = UFoo_bar;
46-
// pub const quux = libsomething_union_quux;
52+
// pub const UFoo_bar = __root.UFoo_bar;
53+
// pub const ubaz = __root.ubaz;
54+
// pub const libsomething_union_quux = __root.libsomething_union_quux;
55+
// pub const bar = __root.UFoo_bar;
56+
// pub const quux = __root.libsomething_union_quux;
4757
// };
4858
// pub extern fn UFoo_bar(ufoo: UFoo) c_int;
4959
// pub extern fn ubaz(ufoo: [*c]UFoo) c_int;
5060
// pub extern fn libsomething_union_quux(ufoo: [*c]UFoo) c_int;
5161
// pub const struct_opa_foo = opaque {
52-
// pub const init = opa_foo_init;
53-
// pub const bar = opa_foo1_bar;
54-
// pub const bar1 = opa_foo2_bar;
62+
// pub const opa_foo_init = __root.opa_foo_init;
63+
// pub const opa_foo1_bar = __root.opa_foo1_bar;
64+
// pub const opa_foo2_bar = __root.opa_foo2_bar;
65+
// pub const init = __root.opa_foo_init;
66+
// pub const bar = __root.opa_foo1_bar;
5567
// };
5668
// pub const OpaFoo = struct_opa_foo;
5769
// pub extern fn opa_foo_init(foo: ?*OpaFoo) c_int;
5870
// pub extern fn opa_foo1_bar(foo: OpaFoo) c_int;
5971
// pub extern fn opa_foo2_bar(foo: ?*OpaFoo) c_int;
72+
// pub const struct_foo_quux = opaque {
73+
// pub const foo_quux_bar1 = __root.foo_quux_bar1;
74+
// pub const foo_quux_bar2_ = __root.foo_quux_bar2_;
75+
// pub const bar1 = __root.foo_quux_bar1;
76+
// pub const bar2_ = __root.foo_quux_bar2_;
77+
// };
78+
// pub const FooQuux = struct_foo_quux;
79+
// pub extern fn foo_quux_bar1(foo: ?*FooQuux) c_int;
80+
// pub extern fn foo_quux_bar2_(foo: ?*FooQuux) c_int;

test/cases/translate/qualified_struct_and_enum.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void func(struct Foo *a, enum Bar **b);
1414
// pub const struct_Foo = extern struct {
1515
// x: c_int = 0,
1616
// y: c_int = 0,
17+
// pub const func = __root.func;
1718
// };
1819
// pub const BarA: c_int = 0;
1920
// pub const BarB: c_int = 1;

test/cases/translate/qualified_struct_and_enum_msvc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ void func(struct Foo *a, enum Bar **b);
1414
// pub const struct_Foo = extern struct {
1515
// x: c_int = 0,
1616
// y: c_int = 0,
17+
// pub const func = __root.func;
1718
// };
1819
// pub const BarA: c_int = 0;
1920
// pub const BarB: c_int = 1;

test/cases/translate/simple_ptrCast_for_casts_between_opaque_types.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ void function(struct opaque *opaque) {
66

77
// translate
88
//
9-
// pub const struct_opaque = opaque {};
9+
// pub const struct_opaque = opaque {
10+
// pub const function = __root.function;
11+
// };
1012
// pub const struct_opaque_2 = opaque {};
1113
// pub export fn function(arg_opaque_1: ?*struct_opaque) void {
1214
// var opaque_1 = arg_opaque_1;

test/cases/translate/struct prototype used in func.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ struct Foo *some_func(struct Foo *foo, int x);
44
// translate
55
//
66
// pub const struct_Foo = opaque {
7-
// pub const func = some_func;
7+
// pub const some_func = __root.some_func;
8+
// pub const func = __root.some_func;
89
// };
910
// pub extern fn some_func(foo: ?*struct_Foo, x: c_int) ?*struct_Foo;

0 commit comments

Comments
 (0)