| author | |
| committer | |
| log | 557983e5020d0a28dba1f63ee9e515c6b779bfd4 |
| tree | 2fd2b3b2715d99eba024e0c6d27fe5cf29c9be38 |
| parent | 763357c9c3e8feba34a932c60b55f2224989f2d4 |
| signature |
an export in the same object
closes #5298 files changed, 55 insertions(+), 7 deletions(-)
src/all_types.hpp+1-1| ... | ... | @@ -1679,7 +1679,7 @@ struct CodeGen { |
| 1679 | 1679 | HashMap<GenericFnTypeId *, ZigFn *, generic_fn_type_id_hash, generic_fn_type_id_eql> generic_table; |
| 1680 | 1680 | HashMap<Scope *, ConstExprValue *, fn_eval_hash, fn_eval_eql> memoized_fn_eval_table; |
| 1681 | 1681 | 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; | |
| 1683 | 1683 | HashMap<Buf *, Tld *, buf_hash, buf_eql_buf> external_prototypes; |
| 1684 | 1684 | HashMap<Buf *, ConstExprValue *, buf_hash, buf_eql_buf> string_literals_table; |
| 1685 | 1685 | 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) { |
| 3439 | 3439 | if (is_export) { |
| 3440 | 3440 | g->resolve_queue.append(tld); |
| 3441 | 3441 | |
| 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); | |
| 3443 | 3443 | if (entry) { |
| 3444 | AstNode *other_source_node = entry->value; | |
| 3444 | AstNode *other_source_node = entry->value->source_node; | |
| 3445 | 3445 | ErrorMsg *msg = add_node_error(g, tld->source_node, |
| 3446 | 3446 | buf_sprintf("exported symbol collision: '%s'", buf_ptr(tld->name))); |
| 3447 | 3447 | 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) { |
| 478 | 478 | fn_table_entry->llvm_value = LLVMConstBitCast(existing_llvm_fn, LLVMPointerType(fn_llvm_type, 0)); |
| 479 | 479 | return fn_table_entry->llvm_value; |
| 480 | 480 | } 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 | } | |
| 482 | 493 | } |
| 483 | 494 | } 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 | } | |
| 485 | 498 | |
| 486 | 499 | for (size_t i = 1; i < fn_table_entry->export_list.length; i += 1) { |
| 487 | 500 | 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 |
| 13279 | 13279 | } |
| 13280 | 13280 | } |
| 13281 | 13281 | |
| 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); | |
| 13283 | 13291 | if (entry) { |
| 13284 | AstNode *other_export_node = entry->value; | |
| 13292 | AstNode *other_export_node = entry->value->source_node; | |
| 13285 | 13293 | ErrorMsg *msg = ir_add_error(ira, &instruction->base, |
| 13286 | 13294 | buf_sprintf("exported symbol collision: '%s'", buf_ptr(symbol_name))); |
| 13287 | 13295 | add_error_note(ira->codegen, msg, other_export_node, buf_sprintf("other symbol is here")); |
| 13296 | return ira->codegen->invalid_instruction; | |
| 13288 | 13297 | } |
| 13289 | 13298 | |
| 13290 | 13299 | bool want_var_export = false; |
| ... | ... | @@ -13295,6 +13304,7 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio |
| 13295 | 13304 | case ZigTypeIdFn: { |
| 13296 | 13305 | assert(target->value.data.x_ptr.special == ConstPtrSpecialFunction); |
| 13297 | 13306 | ZigFn *fn_entry = target->value.data.x_ptr.data.fn.fn_entry; |
| 13307 | tld_fn->fn_entry = fn_entry; | |
| 13298 | 13308 | CallingConvention cc = fn_entry->type_entry->data.fn.fn_type_id.cc; |
| 13299 | 13309 | switch (cc) { |
| 13300 | 13310 | case CallingConventionUnspecified: { |
test/stage1/behavior.zig+1| ... | ... | @@ -22,6 +22,7 @@ comptime { |
| 22 | 22 | _ = @import("behavior/bugs/2006.zig"); |
| 23 | 23 | _ = @import("behavior/bugs/394.zig"); |
| 24 | 24 | _ = @import("behavior/bugs/421.zig"); |
| 25 | _ = @import("behavior/bugs/529.zig"); | |
| 25 | 26 | _ = @import("behavior/bugs/655.zig"); |
| 26 | 27 | _ = @import("behavior/bugs/656.zig"); |
| 27 | 28 | _ = @import("behavior/bugs/704.zig"); |
test/stage1/behavior/bugs/529.zig created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | const A = extern struct { | |
| 2 | field: c_int, | |
| 3 | }; | |
| 4 | ||
| 5 | extern fn issue529(?*A) void; | |
| 6 | ||
| 7 | comptime { | |
| 8 | _ = @import("529_other_file_2.zig"); | |
| 9 | } | |
| 10 | ||
| 11 | test "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 @@ |
| 1 | pub const A = extern struct { | |
| 2 | field: c_int, | |
| 3 | }; | |
| 4 | ||
| 5 | pub extern fn issue529(?*A) void; |
test/stage1/behavior/bugs/529_other_file_2.zig created+4| ... | ... | @@ -0,0 +1,4 @@ |
| 1 | pub const A = extern struct { | |
| 2 | field: c_int, | |
| 3 | }; | |
| 4 | export fn issue529(a: ?*A) void {} |