Commit fd634f3db3

Andrew Kelley <superjoe30@gmail.com>
2017-03-23 23:28:10
don't mangle symbols with underscores
closes #275
1 parent d685685
src/all_types.hpp
@@ -1293,6 +1293,7 @@ struct CodeGen {
     HashMap<Scope *, IrInstruction *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
     HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
     HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> compile_vars;
+    HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_symbol_names;
 
     ZigList<ImportTableEntry *> import_queue;
     size_t import_queue_index;
src/analyze.cpp
@@ -1904,6 +1904,16 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
         g->resolve_queue.append(tld);
     }
 
+    if (tld->visib_mod == VisibModExport) {
+        auto entry = g->external_symbol_names.put_unique(tld->name, tld);
+        if (entry) {
+            Tld *other_tld = entry->value;
+            ErrorMsg *msg = add_node_error(g, tld->source_node,
+                    buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name)));
+            add_error_note(g, msg, other_tld->source_node, buf_sprintf("other symbol is here"));
+        }
+    }
+
     auto entry = decls_scope->decl_table.put_unique(tld->name, tld);
     if (entry) {
         Tld *other_tld = entry->value;
src/codegen.cpp
@@ -67,6 +67,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
     g->llvm_fn_table.init(16);
     g->memoized_fn_eval_table.init(16);
     g->compile_vars.init(16);
+    g->external_symbol_names.init(8);
     g->is_release_build = false;
     g->is_test_build = false;
     g->want_h_file = true;
@@ -260,16 +261,25 @@ static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const cha
     return addLLVMAttr(arg_val, param_index + 1, attr_name);
 }
 
+static Buf *get_mangled_name(CodeGen *g, Buf *original_name, bool external_linkage) {
+    if (external_linkage || g->external_symbol_names.maybe_get(original_name) == nullptr) {
+        return original_name;
+    }
+
+    int n = 0;
+    for (;; n += 1) {
+        Buf *new_name = buf_sprintf("%s.%d", buf_ptr(original_name), n);
+        if (g->external_symbol_names.maybe_get(new_name) == nullptr) {
+            return new_name;
+        }
+    }
+}
+
 static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
     if (fn_table_entry->llvm_value)
         return fn_table_entry->llvm_value;
 
-    Buf *symbol_name;
-    if (!fn_table_entry->internal_linkage) {
-        symbol_name = &fn_table_entry->symbol_name;
-    } else {
-        symbol_name = buf_sprintf("_%s", buf_ptr(&fn_table_entry->symbol_name));
-    }
+    Buf *symbol_name = get_mangled_name(g, &fn_table_entry->symbol_name, !fn_table_entry->internal_linkage);
 
     TypeTableEntry *fn_type = fn_table_entry->type_entry;
     LLVMTypeRef fn_llvm_type = fn_type->data.fn.raw_type_ref;
@@ -3288,7 +3298,7 @@ static void do_code_gen(CodeGen *g) {
             LLVMSetLinkage(global_value, LLVMExternalLinkage);
         } else {
             render_const_val(g, var->value);
-            render_const_val_global(g, var->value, buf_ptr(&var->name));
+            render_const_val_global(g, var->value, buf_ptr(get_mangled_name(g, &var->name, false)));
             global_value = var->value->llvm_global;
 
             if (var->linkage == VarLinkageExport) {
test/run_tests.cpp
@@ -1631,7 +1631,7 @@ const foo = @import("foo.zig");
 export fn callPrivFunction() {
     foo.privateFunction();
 }
-        )SOURCE", 2, 
+        )SOURCE", 2,
             ".tmp_source.zig:5:8: error: 'privateFunction' is private",
             "foo.zig:2:1: note: declared here");
 
@@ -1828,6 +1828,23 @@ fn ptrEql(a: &[]const u8, b: &[]const u8) -> bool {
 
 export fn entry() -> usize { @sizeOf(@typeOf(foo)) }
     )SOURCE", 1, ".tmp_source.zig:5:19: error: expected type '&[]const u8', found '&const []const u8'");
+
+    {
+        TestCase *tc = add_compile_fail_case("export collision", R"SOURCE(
+const foo = @import("foo.zig");
+
+export fn bar() -> usize {
+    return foo.baz;
+}
+        )SOURCE", 2,
+            "foo.zig:2:8: error: exported symbol collision: 'bar'",
+            ".tmp_source.zig:4:8: note: other symbol is here");
+
+        add_source_file(tc, "foo.zig", R"SOURCE(
+export fn bar() {}
+pub const baz = 1234;
+        )SOURCE");
+    }
 }
 
 //////////////////////////////////////////////////////////////////////////////