| ... | @@ -218,7 +218,7 @@ const Scope = struct { | ... | @@ -218,7 +218,7 @@ const Scope = struct { |
| 218 | | 218 | |
| 219 | /// Check if the global scope contains the name, includes all decls that haven't been translated yet. | 219 | /// Check if the global scope contains the name, includes all decls that haven't been translated yet. |
| 220 | fn contains(scope: *Root, name: []const u8) bool { | 220 | fn contains(scope: *Root, name: []const u8) bool { |
| 221 | return scope.containsNow(name) or scope.context.global_names.contains(name); | 221 | return scope.containsNow(name) or scope.context.global_names.contains(name) or scope.context.weak_global_names.contains(name); |
| 222 | } | 222 | } |
| 223 | }; | 223 | }; |
| 224 | | 224 | |
| ... | @@ -335,6 +335,15 @@ pub const Context = struct { | ... | @@ -335,6 +335,15 @@ pub const Context = struct { |
| 335 | /// up front in a pre-processing step. | 335 | /// up front in a pre-processing step. |
| 336 | global_names: std.StringArrayHashMapUnmanaged(void) = .{}, | 336 | global_names: std.StringArrayHashMapUnmanaged(void) = .{}, |
| 337 | | 337 | |
| | 338 | /// This is similar to `global_names`, but contains names which we would |
| | 339 | /// *like* to use, but do not strictly *have* to if they are unavailable. |
| | 340 | /// These are relevant to types, which ideally we would name like |
| | 341 | /// 'struct_foo' with an alias 'foo', but if either of those names is taken, |
| | 342 | /// may be mangled. |
| | 343 | /// This is distinct from `global_names` so we can detect at a type |
| | 344 | /// declaration whether or not the name is available. |
| | 345 | weak_global_names: std.StringArrayHashMapUnmanaged(void) = .{}, |
| | 346 | |
| 338 | pattern_list: PatternList, | 347 | pattern_list: PatternList, |
| 339 | | 348 | |
| 340 | fn getMangle(c: *Context) u32 { | 349 | fn getMangle(c: *Context) u32 { |
| ... | @@ -425,10 +434,8 @@ pub fn translate( | ... | @@ -425,10 +434,8 @@ pub fn translate( |
| 425 | | 434 | |
| 426 | try addMacros(&context); | 435 | try addMacros(&context); |
| 427 | for (context.alias_list.items) |alias| { | 436 | for (context.alias_list.items) |alias| { |
| 428 | if (!context.global_scope.sym_table.contains(alias.alias)) { | 437 | const node = try Tag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name }); |
| 429 | const node = try Tag.alias.create(arena, .{ .actual = alias.alias, .mangled = alias.name }); | 438 | try addTopLevelDecl(&context, alias.alias, node); |
| 430 | try addTopLevelDecl(&context, alias.alias, node); | | |
| 431 | } | | |
| 432 | } | 439 | } |
| 433 | | 440 | |
| 434 | return ast.render(gpa, context.global_scope.nodes.items); | 441 | return ast.render(gpa, context.global_scope.nodes.items); |
| ... | @@ -493,7 +500,29 @@ fn declVisitorC(context: ?*anyopaque, decl: *const clang.Decl) callconv(.C) bool | ... | @@ -493,7 +500,29 @@ fn declVisitorC(context: ?*anyopaque, decl: *const clang.Decl) callconv(.C) bool |
| 493 | fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void { | 500 | fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void { |
| 494 | if (decl.castToNamedDecl()) |named_decl| { | 501 | if (decl.castToNamedDecl()) |named_decl| { |
| 495 | const decl_name = try c.str(named_decl.getName_bytes_begin()); | 502 | const decl_name = try c.str(named_decl.getName_bytes_begin()); |
| 496 | try c.global_names.put(c.gpa, decl_name, {}); | 503 | |
| | 504 | switch (decl.getKind()) { |
| | 505 | .Record, .Enum => { |
| | 506 | // These types are prefixed with the container kind. |
| | 507 | const container_prefix = if (decl.getKind() == .Record) prefix: { |
| | 508 | const record_decl: *const clang.RecordDecl = @ptrCast(decl); |
| | 509 | if (record_decl.isUnion()) { |
| | 510 | break :prefix "union"; |
| | 511 | } else { |
| | 512 | break :prefix "struct"; |
| | 513 | } |
| | 514 | } else "enum"; |
| | 515 | const prefixed_name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_prefix, decl_name }); |
| | 516 | // `decl_name` and `prefixed_name` are the preferred names for this type. |
| | 517 | // However, we can name it anything else if necessary, so these are "weak names". |
| | 518 | try c.weak_global_names.ensureUnusedCapacity(c.gpa, 2); |
| | 519 | c.weak_global_names.putAssumeCapacity(decl_name, {}); |
| | 520 | c.weak_global_names.putAssumeCapacity(prefixed_name, {}); |
| | 521 | }, |
| | 522 | else => { |
| | 523 | try c.global_names.put(c.gpa, decl_name, {}); |
| | 524 | }, |
| | 525 | } |
| 497 | | 526 | |
| 498 | // Check for typedefs with unnamed enum/record child types. | 527 | // Check for typedefs with unnamed enum/record child types. |
| 499 | if (decl.getKind() == .Typedef) { | 528 | if (decl.getKind() == .Typedef) { |
| ... | @@ -1079,6 +1108,21 @@ fn flexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) ?*const | ... | @@ -1079,6 +1108,21 @@ fn flexibleArrayField(c: *Context, record_def: *const clang.RecordDecl) ?*const |
| 1079 | return flexible_field; | 1108 | return flexible_field; |
| 1080 | } | 1109 | } |
| 1081 | | 1110 | |
| | 1111 | fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { |
| | 1112 | var cur_name = want_name; |
| | 1113 | |
| | 1114 | if (!c.weak_global_names.contains(want_name)) { |
| | 1115 | // This type wasn't noticed by the name detection pass, so nothing has been treating this as |
| | 1116 | // a weak global name. We must mangle it to avoid conflicts with locals. |
| | 1117 | cur_name = try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ want_name, c.getMangle() }); |
| | 1118 | } |
| | 1119 | |
| | 1120 | while (c.global_names.contains(cur_name)) { |
| | 1121 | cur_name = try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ want_name, c.getMangle() }); |
| | 1122 | } |
| | 1123 | return cur_name; |
| | 1124 | } |
| | 1125 | |
| 1082 | fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void { | 1126 | fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordDecl) Error!void { |
| 1083 | if (c.decl_table.get(@intFromPtr(record_decl.getCanonicalDecl()))) |_| | 1127 | if (c.decl_table.get(@intFromPtr(record_decl.getCanonicalDecl()))) |_| |
| 1084 | return; // Avoid processing this decl twice | 1128 | return; // Avoid processing this decl twice |
| ... | @@ -1113,6 +1157,9 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD | ... | @@ -1113,6 +1157,9 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 1113 | is_unnamed = true; | 1157 | is_unnamed = true; |
| 1114 | } | 1158 | } |
| 1115 | name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name }); | 1159 | name = try std.fmt.allocPrint(c.arena, "{s}_{s}", .{ container_kind_name, bare_name }); |
| | 1160 | if (toplevel and !is_unnamed) { |
| | 1161 | name = try mangleWeakGlobalName(c, name); |
| | 1162 | } |
| 1116 | } | 1163 | } |
| 1117 | if (!toplevel) name = try bs.makeMangledName(c, name); | 1164 | if (!toplevel) name = try bs.makeMangledName(c, name); |
| 1118 | try c.decl_table.putNoClobber(c.gpa, @intFromPtr(record_decl.getCanonicalDecl()), name); | 1165 | try c.decl_table.putNoClobber(c.gpa, @intFromPtr(record_decl.getCanonicalDecl()), name); |
| ... | @@ -1217,7 +1264,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD | ... | @@ -1217,7 +1264,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_decl: *const clang.RecordD |
| 1217 | const node = Node.initPayload(&payload.base); | 1264 | const node = Node.initPayload(&payload.base); |
| 1218 | if (toplevel) { | 1265 | if (toplevel) { |
| 1219 | try addTopLevelDecl(c, name, node); | 1266 | try addTopLevelDecl(c, name, node); |
| 1220 | if (!is_unnamed) | 1267 | // Only add the alias if the name is available *and* it was caught by |
| | 1268 | // name detection. Don't bother performing a weak mangle, since a |
| | 1269 | // mangled name is of no real use here. |
| | 1270 | if (!is_unnamed and !c.global_names.contains(bare_name) and c.weak_global_names.contains(bare_name)) |
| 1221 | try c.alias_list.append(.{ .alias = bare_name, .name = name }); | 1271 | try c.alias_list.append(.{ .alias = bare_name, .name = name }); |
| 1222 | } else { | 1272 | } else { |
| 1223 | try scope.appendNode(node); | 1273 | try scope.appendNode(node); |
| ... | @@ -1246,6 +1296,9 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E | ... | @@ -1246,6 +1296,9 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E |
| 1246 | is_unnamed = true; | 1296 | is_unnamed = true; |
| 1247 | } | 1297 | } |
| 1248 | name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name}); | 1298 | name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name}); |
| | 1299 | if (toplevel and !is_unnamed) { |
| | 1300 | name = try mangleWeakGlobalName(c, name); |
| | 1301 | } |
| 1249 | } | 1302 | } |
| 1250 | if (!toplevel) name = try bs.makeMangledName(c, name); | 1303 | if (!toplevel) name = try bs.makeMangledName(c, name); |
| 1251 | try c.decl_table.putNoClobber(c.gpa, @intFromPtr(enum_decl.getCanonicalDecl()), name); | 1304 | try c.decl_table.putNoClobber(c.gpa, @intFromPtr(enum_decl.getCanonicalDecl()), name); |
| ... | @@ -1313,7 +1366,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E | ... | @@ -1313,7 +1366,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const clang.EnumDecl) E |
| 1313 | const node = Node.initPayload(&payload.base); | 1366 | const node = Node.initPayload(&payload.base); |
| 1314 | if (toplevel) { | 1367 | if (toplevel) { |
| 1315 | try addTopLevelDecl(c, name, node); | 1368 | try addTopLevelDecl(c, name, node); |
| 1316 | if (!is_unnamed) | 1369 | // Only add the alias if the name is available *and* it was caught by |
| | 1370 | // name detection. Don't bother performing a weak mangle, since a |
| | 1371 | // mangled name is of no real use here. |
| | 1372 | if (!is_unnamed and !c.global_names.contains(bare_name) and c.weak_global_names.contains(bare_name)) |
| 1317 | try c.alias_list.append(.{ .alias = bare_name, .name = name }); | 1373 | try c.alias_list.append(.{ .alias = bare_name, .name = name }); |
| 1318 | } else { | 1374 | } else { |
| 1319 | try scope.appendNode(node); | 1375 | try scope.appendNode(node); |
| ... | @@ -4881,7 +4937,7 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan | ... | @@ -4881,7 +4937,7 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan |
| 4881 | var trans_scope = scope; | 4937 | var trans_scope = scope; |
| 4882 | if (@as(*const clang.Decl, @ptrCast(record_decl)).castToNamedDecl()) |named_decl| { | 4938 | if (@as(*const clang.Decl, @ptrCast(record_decl)).castToNamedDecl()) |named_decl| { |
| 4883 | const decl_name = try c.str(named_decl.getName_bytes_begin()); | 4939 | const decl_name = try c.str(named_decl.getName_bytes_begin()); |
| 4884 | if (c.global_names.get(decl_name)) |_| trans_scope = &c.global_scope.base; | 4940 | if (c.weak_global_names.contains(decl_name)) trans_scope = &c.global_scope.base; |
| 4885 | } | 4941 | } |
| 4886 | try transRecordDecl(c, trans_scope, record_decl); | 4942 | try transRecordDecl(c, trans_scope, record_decl); |
| 4887 | const name = c.decl_table.get(@intFromPtr(record_decl.getCanonicalDecl())).?; | 4943 | const name = c.decl_table.get(@intFromPtr(record_decl.getCanonicalDecl())).?; |
| ... | @@ -4894,7 +4950,7 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan | ... | @@ -4894,7 +4950,7 @@ fn transType(c: *Context, scope: *Scope, ty: *const clang.Type, source_loc: clan |
| 4894 | var trans_scope = scope; | 4950 | var trans_scope = scope; |
| 4895 | if (@as(*const clang.Decl, @ptrCast(enum_decl)).castToNamedDecl()) |named_decl| { | 4951 | if (@as(*const clang.Decl, @ptrCast(enum_decl)).castToNamedDecl()) |named_decl| { |
| 4896 | const decl_name = try c.str(named_decl.getName_bytes_begin()); | 4952 | const decl_name = try c.str(named_decl.getName_bytes_begin()); |
| 4897 | if (c.global_names.get(decl_name)) |_| trans_scope = &c.global_scope.base; | 4953 | if (c.weak_global_names.contains(decl_name)) trans_scope = &c.global_scope.base; |
| 4898 | } | 4954 | } |
| 4899 | try transEnumDecl(c, trans_scope, enum_decl); | 4955 | try transEnumDecl(c, trans_scope, enum_decl); |
| 4900 | const name = c.decl_table.get(@intFromPtr(enum_decl.getCanonicalDecl())).?; | 4956 | const name = c.decl_table.get(@intFromPtr(enum_decl.getCanonicalDecl())).?; |