Commit 4a17e008da

Noam Preil <pleasantatk@gmail.com>
2020-06-26 09:17:13
Stage2: exported symbol collision detection
1 parent e5a3cb8
Changed files (2)
src-self-hosted
test
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(
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 {}