| ... | ... | @@ -32,6 +32,9 @@ bin_file_path: []const u8, |
| 32 | 32 | /// Decl pointers to details about them being exported. |
| 33 | 33 | /// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table. |
| 34 | 34 | decl_exports: std.AutoHashMap(*Decl, []*Export), |
| 35 | /// We track which export is associated with the given symbol name for quick |
| 36 | /// detection of symbol collisions. |
| 37 | symbol_exports: std.StringHashMap(*Export), |
| 35 | 38 | /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl |
| 36 | 39 | /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that |
| 37 | 40 | /// is performing the export of another Decl. |
| ... | ... | @@ -772,6 +775,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module { |
| 772 | 775 | .optimize_mode = options.optimize_mode, |
| 773 | 776 | .decl_table = DeclTable.init(gpa), |
| 774 | 777 | .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa), |
| 778 | .symbol_exports = std.StringHashMap(*Export).init(gpa), |
| 775 | 779 | .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa), |
| 776 | 780 | .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa), |
| 777 | 781 | .failed_files = std.AutoHashMap(*Scope, *ErrorMsg).init(gpa), |
| ... | ... | @@ -829,6 +833,7 @@ pub fn deinit(self: *Module) void { |
| 829 | 833 | } |
| 830 | 834 | self.export_owners.deinit(); |
| 831 | 835 | } |
| 836 | self.symbol_exports.deinit(); |
| 832 | 837 | self.root_scope.destroy(allocator); |
| 833 | 838 | self.* = undefined; |
| 834 | 839 | } |
| ... | ... | @@ -1869,6 +1874,7 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void { |
| 1869 | 1874 | if (self.failed_exports.remove(exp)) |entry| { |
| 1870 | 1875 | entry.value.destroy(self.allocator); |
| 1871 | 1876 | } |
| 1877 | _ = self.symbol_exports.remove(exp.options.name); |
| 1872 | 1878 | self.allocator.destroy(exp); |
| 1873 | 1879 | } |
| 1874 | 1880 | self.allocator.free(kv.value); |
| ... | ... | @@ -2104,20 +2110,6 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const |
| 2104 | 2110 | else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}), |
| 2105 | 2111 | } |
| 2106 | 2112 | |
| 2107 | | var already_exported = false; |
| 2108 | | { |
| 2109 | | var it = self.decl_exports.iterator(); |
| 2110 | | while (it.next()) |kv| { |
| 2111 | | const export_list = kv.value; |
| 2112 | | for (export_list) |e| { |
| 2113 | | if (std.mem.eql(u8, e.options.name, symbol_name)) { |
| 2114 | | already_exported = true; |
| 2115 | | break; |
| 2116 | | } |
| 2117 | | } |
| 2118 | | } |
| 2119 | | } |
| 2120 | | |
| 2121 | 2113 | try self.decl_exports.ensureCapacity(self.decl_exports.size + 1); |
| 2122 | 2114 | try self.export_owners.ensureCapacity(self.export_owners.size + 1); |
| 2123 | 2115 | |
| ... | ... | @@ -2153,7 +2145,7 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const |
| 2153 | 2145 | de_gop.kv.value[de_gop.kv.value.len - 1] = new_export; |
| 2154 | 2146 | errdefer de_gop.kv.value = self.allocator.shrink(de_gop.kv.value, de_gop.kv.value.len - 1); |
| 2155 | 2147 | |
| 2156 | | if (already_exported) { |
| 2148 | if (self.symbol_exports.get(symbol_name)) |_| { |
| 2157 | 2149 | try self.failed_exports.ensureCapacity(self.failed_exports.size + 1); |
| 2158 | 2150 | self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create( |
| 2159 | 2151 | self.allocator, |
| ... | ... | @@ -2161,9 +2153,12 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const |
| 2161 | 2153 | "exported symbol collision: {}", |
| 2162 | 2154 | .{symbol_name}, |
| 2163 | 2155 | )); |
| 2156 | // TODO: add a note |
| 2164 | 2157 | new_export.status = .failed; |
| 2165 | 2158 | return; |
| 2166 | 2159 | } |
| 2160 | |
| 2161 | try self.symbol_exports.putNoClobber(symbol_name, new_export); |
| 2167 | 2162 | self.bin_file.updateDeclExports(self, exported_decl, de_gop.kv.value) catch |err| switch (err) { |
| 2168 | 2163 | error.OutOfMemory => return error.OutOfMemory, |
| 2169 | 2164 | else => { |