diff --git a/src/all_types.hpp b/src/all_types.hpp index e1ebf50e69..c1b1542467 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1293,6 +1293,7 @@ struct CodeGen { HashMap memoized_fn_eval_table; HashMap llvm_fn_table; HashMap compile_vars; + HashMap external_symbol_names; ZigList import_queue; size_t import_queue_index; diff --git a/src/analyze.cpp b/src/analyze.cpp index 631707c978..d3617ad9c8 100644 --- a/src/analyze.cpp +++ b/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; diff --git a/src/codegen.cpp b/src/codegen.cpp index 03629b2da1..a336beb11f 100644 --- a/src/codegen.cpp +++ b/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) { diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 0029699d74..187ace42c7 100644 --- a/test/run_tests.cpp +++ b/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"); + } } //////////////////////////////////////////////////////////////////////////////