Commit fd634f3db3
Changed files (4)
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");
+ }
}
//////////////////////////////////////////////////////////////////////////////