authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-26 19:42:39-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-02-26 19:43:12-05:00
log557983e5020d0a28dba1f63ee9e515c6b779bfd4
tree2fd2b3b2715d99eba024e0c6d27fe5cf29c9be38
parent763357c9c3e8feba34a932c60b55f2224989f2d4
signaturelock-open Commit is signed but in an unrecognized format.

fix handling when there are multiple externs and

an export in the same object closes #529

8 files changed, 55 insertions(+), 7 deletions(-)

src/all_types.hpp+1-1
......@@ -1679,7 +1679,7 @@ struct CodeGen {
16791679 HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table;
16801680 HashMap<Scope *, ConstExprValue *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table;
16811681 HashMap<ZigLLVMFnKey, LLVMValueRef, zig_llvm_fn_key_hash, zig_llvm_fn_key_eql> llvm_fn_table;
1682 HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> exported_symbol_names;
1682 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> exported_symbol_names;
16831683 HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes;
16841684 HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table;
16851685 HashMap<const ZigType *, ConstExprValue *, type_ptr_hash, type_ptr_eql> type_info_cache;
src/analyze.cpp+2-2
......@@ -3439,9 +3439,9 @@ static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) {
34393439 if (is_export) {
34403440 g->resolve_queue.append(tld);
34413441
3442 auto entry = g->exported_symbol_names.put_unique(tld->name, tld->source_node);
3442 auto entry = g->exported_symbol_names.put_unique(tld->name, tld);
34433443 if (entry) {
3444 AstNode *other_source_node = entry->value;
3444 AstNode *other_source_node = entry->value->source_node;
34453445 ErrorMsg *msg = add_node_error(g, tld->source_node,
34463446 buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name)));
34473447 add_error_note(g, msg, other_source_node, buf_sprintf("other symbol here"));
src/codegen.cpp+15-2
......@@ -478,10 +478,23 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, ZigFn *fn_table_entry) {
478478 fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0));
479479 return fn_table_entry->llvm_value;
480480 } else {
481 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
481 auto entry = g->exported_symbol_names.maybe_get(symbol_name);
482 if (entry == nullptr) {
483 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
484 } else {
485 assert(entry->value->id == TldIdFn);
486 TldFn *tld_fn = reinterpret_cast<TldFn *>(entry->value);
487 tld_fn->fn_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name),
488 tld_fn->fn_entry->type_entry->data.fn.raw_type_ref);
489 fn_table_entry->llvm_value = LLVMConstBitCast(tld_fn->fn_entry->llvm_value,
490 LLVMPointerType(fn_llvm_type, 0));
491 return fn_table_entry->llvm_value;
492 }
482493 }
483494 } else {
484 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
495 if (fn_table_entry->llvm_value == nullptr) {
496 fn_table_entry->llvm_value = LLVMAddFunction(g->module, buf_ptr(symbol_name), fn_llvm_type);
497 }
485498
486499 for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) {
487500 FnExport *fn_export = &fn_table_entry->export_list.items[i];
src/ir.cpp+12-2
......@@ -13279,12 +13279,21 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1327913279 }
1328013280 }
1328113281
13282 auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, instruction->base.source_node);
13282 // TODO: This function needs to be audited.
13283 // It's not clear how all the different types are supposed to be handled.
13284 // Need comprehensive tests for exporting one thing in one file and declaring an extern var
13285 // in another file.
13286 TldFn *tld_fn = allocate<TldFn>(1);
13287 tld_fn->base.id = TldIdFn;
13288 tld_fn->base.source_node = instruction->base.source_node;
13289
13290 auto entry = ira->codegen->exported_symbol_names.put_unique(symbol_name, &tld_fn->base);
1328313291 if (entry) {
13284 AstNode *other_export_node = entry->value;
13292 AstNode *other_export_node = entry->value->source_node;
1328513293 ErrorMsg *msg = ir_add_error(ira, &instruction->base,
1328613294 buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name)));
1328713295 add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here"));
13296 return ira->codegen->invalid_instruction;
1328813297 }
1328913298
1329013299 bool want_var_export = false;
......@@ -13295,6 +13304,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio
1329513304 case ZigTypeIdFn: {
1329613305 assert(target->value.data.x_ptr.special == ConstPtrSpecialFunction);
1329713306 ZigFn *fn_entry = target->value.data.x_ptr.data.fn.fn_entry;
13307 tld_fn->fn_entry = fn_entry;
1329813308 CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc;
1329913309 switch (cc) {
1330013310 case CallingConventionUnspecified: {
test/stage1/behavior.zig+1
......@@ -22,6 +22,7 @@ comptime {
2222 _ = @import("behavior/bugs/2006.zig");
2323 _ = @import("behavior/bugs/394.zig");
2424 _ = @import("behavior/bugs/421.zig");
25 _ = @import("behavior/bugs/529.zig");
2526 _ = @import("behavior/bugs/655.zig");
2627 _ = @import("behavior/bugs/656.zig");
2728 _ = @import("behavior/bugs/704.zig");
test/stage1/behavior/bugs/529.zig created+15
......@@ -0,0 +1,15 @@
1const A = extern struct {
2 field: c_int,
3};
4
5extern fn issue529(?*A) void;
6
7comptime {
8 _ = @import("529_other_file_2.zig");
9}
10
11test "issue 529 fixed" {
12 @import("529_other_file.zig").issue529(null);
13 issue529(null);
14}
15
test/stage1/behavior/bugs/529_other_file.zig created+5
......@@ -0,0 +1,5 @@
1pub const A = extern struct {
2 field: c_int,
3};
4
5pub extern fn issue529(?*A) void;
test/stage1/behavior/bugs/529_other_file_2.zig created+4
......@@ -0,0 +1,4 @@
1pub const A = extern struct {
2 field: c_int,
3};
4export fn issue529(a: ?*A) void {}