From 4a17e008daa90d5dbb0fc917d53e52c1ec990f2d Mon Sep 17 00:00:00 2001 From: Noam Preil Date: Fri, 26 Jun 2020 03:17:13 -0400 Subject: [PATCH] Stage2: exported symbol collision detection --- src-self-hosted/Module.zig | 50 +++++++++++++++++++++++++--------- test/stage2/compile_errors.zig | 32 +++++++++++++++++++--- 2 files changed, 65 insertions(+), 17 deletions(-) diff --git a/src-self-hosted/Module.zig b/src-self-hosted/Module.zig index 63cca38973..600da10d93 100644 --- a/src-self-hosted/Module.zig +++ b/src-self-hosted/Module.zig @@ -2120,6 +2120,20 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}), } + var already_exported = false; + { + var it = self.decl_exports.iterator(); + while (it.next()) |kv| { + const export_list = kv.value; + for (export_list) |e| { + if (std.mem.eql(u8, e.options.name, symbol_name)) { + already_exported = true; + break; + } + } + } + } + try self.decl_exports.ensureCapacity(self.decl_exports.size + 1); try self.export_owners.ensureCapacity(self.export_owners.size + 1); @@ -2155,19 +2169,29 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const de_gop.kv.value[de_gop.kv.value.len - 1] = new_export; errdefer de_gop.kv.value = self.allocator.shrink(de_gop.kv.value, de_gop.kv.value.len - 1); - self.bin_file.updateDeclExports(self, exported_decl, de_gop.kv.value) catch |err| switch (err) { - error.OutOfMemory => return error.OutOfMemory, - else => { - try self.failed_exports.ensureCapacity(self.failed_exports.size + 1); - self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create( - self.allocator, - src, - "unable to export: {}", - .{@errorName(err)}, - )); - new_export.status = .failed_retryable; - }, - }; + if (already_exported) { + try self.failed_exports.ensureCapacity(self.failed_exports.size + 1); + self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create( + self.allocator, + src, + "exported symbol collision: {}", + .{symbol_name}, + )); + } else { + self.bin_file.updateDeclExports(self, exported_decl, de_gop.kv.value) catch |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + else => { + try self.failed_exports.ensureCapacity(self.failed_exports.size + 1); + self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create( + self.allocator, + src, + "unable to export: {}", + .{@errorName(err)}, + )); + new_export.status = .failed_retryable; + }, + }; + } } fn addNewInstArgs( diff --git a/test/stage2/compile_errors.zig b/test/stage2/compile_errors.zig index 905f106f94..79b67da2c2 100644 --- a/test/stage2/compile_errors.zig +++ b/test/stage2/compile_errors.zig @@ -43,13 +43,37 @@ pub fn addCases(ctx: *TestContext) !void { \\@1 = export(@0, "start") , &[_][]const u8{":4:9: error: unable to call function with naked calling convention"}); + { + var case = ctx.objZIR("exported symbol collision", linux_x64); + // First, ensure we receive the error correctly + case.addError( + \\@noreturn = primitive(noreturn) + \\ + \\@start_fnty = fntype([], @noreturn) + \\@start = fn(@start_fnty, {}) + \\ + \\@0 = str("_start") + \\@1 = export(@0, "start") + \\@2 = export(@0, "start") + , &[_][]const u8{":8:13: error: exported symbol collision: _start"}); + // Next, ensure everything works properly on the next compilation with the problem fixed + case.compiles( + \\@noreturn = primitive(noreturn) + \\ + \\@start_fnty = fntype([], @noreturn) + \\@start = fn(@start_fnty, {}) + \\ + \\@0 = str("_start") + \\@1 = export(@0, "start") + ); + } // TODO: re-enable these tests. // https://github.com/ziglang/zig/issues/1364 - // ctx.addError("Export same symbol twice", linux_x64, .Zig, - // \\export fn entry() void {} - // \\export fn entry() void {} - // , &[_][]const u8{":2:1: error: exported symbol collision"}); + // ctx.compileError("Export same symbol twice", linux_x64, + // \\export fn entry() void {} + // \\export fn entry() void {} + // , &[_][]const u8{":2:1: error: exported symbol collision"}); // ctx.addError("Missing function name", linux_x64, .Zig, // \\fn() void {}