diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 004d152e1f..3da66acc18 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -287,6 +287,15 @@ pub fn supportsTailCall(target: std.Target) bool { } } +/// TODO can this be done with simpler logic / different API binding? +fn deleteLlvmGlobal(llvm_global: *const llvm.Value) void { + if (llvm_global.globalGetValueType().getTypeKind() == .Function) { + llvm_global.deleteFunction(); + return; + } + return llvm_global.deleteGlobal(); +} + pub const Object = struct { gpa: Allocator, module: *Module, @@ -640,7 +649,7 @@ pub const Object = struct { const new_global_ptr = other_global.constBitCast(llvm_global.typeOf()); llvm_global.replaceAllUsesWith(new_global_ptr); - object.deleteLlvmGlobal(llvm_global); + deleteLlvmGlobal(llvm_global); entry.value_ptr.* = new_global_ptr; } object.extern_collisions.clearRetainingCapacity(); @@ -666,7 +675,7 @@ pub const Object = struct { const new_global_ptr = llvm_global.constBitCast(other_global.typeOf()); other_global.replaceAllUsesWith(new_global_ptr); llvm_global.takeName(other_global); - other_global.deleteGlobal(); + deleteLlvmGlobal(other_global); // Problem: now we need to replace in the decl_map that // the extern decl index points to this new global. However we don't // know the decl index. @@ -1184,15 +1193,6 @@ pub const Object = struct { return null; } - /// TODO can this be done with simpler logic / different API binding? - fn deleteLlvmGlobal(o: Object, llvm_global: *const llvm.Value) void { - if (o.llvm_module.getNamedFunction(llvm_global.getValueName()) != null) { - llvm_global.deleteFunction(); - return; - } - return llvm_global.deleteGlobal(); - } - pub fn updateDeclExports( self: *Object, module: *Module, @@ -1287,7 +1287,7 @@ pub const Object = struct { alias.setAliasee(llvm_global); } else { _ = self.llvm_module.addAlias( - llvm_global.typeOf(), + llvm_global.globalGetValueType(), 0, llvm_global, exp_name_z, diff --git a/test/behavior.zig b/test/behavior.zig index 8f581f372e..4b55913af5 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -85,6 +85,7 @@ test { _ = @import("behavior/bugs/12033.zig"); _ = @import("behavior/bugs/12430.zig"); _ = @import("behavior/bugs/12486.zig"); + _ = @import("behavior/bugs/12680.zig"); _ = @import("behavior/byteswap.zig"); _ = @import("behavior/byval_arg_var.zig"); _ = @import("behavior/call.zig"); diff --git a/test/behavior/bugs/12680.zig b/test/behavior/bugs/12680.zig new file mode 100644 index 0000000000..c7bd8f63aa --- /dev/null +++ b/test/behavior/bugs/12680.zig @@ -0,0 +1,17 @@ +const std = @import("std"); +const expectEqual = std.testing.expectEqual; +const other_file = @import("12680_other_file.zig"); +const builtin = @import("builtin"); + +extern fn test_func() callconv(.C) usize; + +test "export a function twice" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; + + // If it exports the function correctly, `test_func` and `testFunc` will points to the same address. + try expectEqual(test_func(), other_file.testFunc()); +} diff --git a/test/behavior/bugs/12680_other_file.zig b/test/behavior/bugs/12680_other_file.zig new file mode 100644 index 0000000000..32b9dc1b27 --- /dev/null +++ b/test/behavior/bugs/12680_other_file.zig @@ -0,0 +1,8 @@ +// export this function twice +pub export fn testFunc() callconv(.C) usize { + return @ptrToInt(&testFunc); +} + +comptime { + @export(testFunc, .{ .name = "test_func", .linkage = .Strong }); +}