diff --git a/src/Sema.zig b/src/Sema.zig index 99564fd1ea..7a73b52e83 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -25675,6 +25675,7 @@ fn zirBuiltinExtern( extended: Zir.Inst.Extended.InstData, ) CompileError!Air.Inst.Ref { const mod = sema.mod; + const ip = &mod.intern_pool; const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data; const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node }; @@ -25714,34 +25715,38 @@ fn zirBuiltinExtern( const new_decl = mod.declPtr(new_decl_index); new_decl.name = options.name; - { - const new_var = try mod.intern(.{ .variable = .{ - .ty = ptr_info.child, - .init = .none, - .decl = sema.owner_decl_index, - .lib_name = options.library_name, - .is_extern = true, - .is_const = ptr_info.flags.is_const, - .is_threadlocal = options.is_thread_local, - .is_weak_linkage = options.linkage == .Weak, - } }); - - new_decl.src_line = sema.owner_decl.src_line; - // We only access this decl through the decl_ref with the correct type created - // below, so this type doesn't matter - new_decl.ty = Type.fromInterned(ptr_info.child); - new_decl.val = Value.fromInterned(new_var); - new_decl.alignment = .none; - new_decl.@"linksection" = .none; - new_decl.has_tv = true; - new_decl.analysis = .complete; - new_decl.generation = mod.generation; - } + new_decl.src_line = sema.owner_decl.src_line; + new_decl.ty = Type.fromInterned(ptr_info.child); + new_decl.val = Value.fromInterned( + if (Type.fromInterned(ptr_info.child).zigTypeTag(mod) == .Fn) + try ip.getExternFunc(sema.gpa, .{ + .ty = ptr_info.child, + .decl = new_decl_index, + .lib_name = options.library_name, + }) + else + try mod.intern(.{ .variable = .{ + .ty = ptr_info.child, + .init = .none, + .decl = new_decl_index, + .lib_name = options.library_name, + .is_extern = true, + .is_const = ptr_info.flags.is_const, + .is_threadlocal = options.is_thread_local, + .is_weak_linkage = options.linkage == .Weak, + } }), + ); + new_decl.alignment = .none; + new_decl.@"linksection" = .none; + new_decl.has_tv = true; + new_decl.owns_tv = true; + new_decl.analysis = .complete; + new_decl.generation = mod.generation; try sema.ensureDeclAnalyzed(new_decl_index); return Air.internedToRef((try mod.getCoerced(Value.fromInterned((try mod.intern(.{ .ptr = .{ - .ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) { + .ty = switch (ip.indexToKey(ty.toIntern())) { .ptr_type => ty.toIntern(), .opt_type => |child_type| child_type, else => unreachable, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 01da7ba9a2..8f2a27c514 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -2941,9 +2941,13 @@ pub const Object = struct { const target = owner_mod.resolved_target.result; const sret = firstParamSRet(fn_info, zcu); + const is_extern = decl.isExtern(zcu); const function_index = try o.builder.addFunction( try o.lowerType(zig_fn_type), - try o.builder.string(ip.stringToSlice(try decl.getFullyQualifiedName(zcu))), + try o.builder.string(ip.stringToSlice(if (is_extern) + decl.name + else + try decl.getFullyQualifiedName(zcu))), toLlvmAddressSpace(decl.@"addrspace", target), ); gop.value_ptr.* = function_index.ptrConst(&o.builder).global; @@ -2951,7 +2955,6 @@ pub const Object = struct { var attributes: Builder.FunctionAttributes.Wip = .{}; defer attributes.deinit(&o.builder); - const is_extern = decl.isExtern(zcu); if (!is_extern) { function_index.setLinkage(.internal, &o.builder); function_index.setUnnamedAddr(.unnamed_addr, &o.builder); diff --git a/test/behavior/extern.zig b/test/behavior/extern.zig index 87a93624d0..af9c86e3be 100644 --- a/test/behavior/extern.zig +++ b/test/behavior/extern.zig @@ -12,3 +12,16 @@ test "anyopaque extern symbol" { } export var a_mystery_symbol: i32 = 1234; + +test "function extern symbol" { + 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 and builtin.target.ofmt != .elf) return error.SkipZigTest; + + const a = @extern(*const fn () callconv(.C) i32, .{ .name = "a_mystery_function" }); + try expect(a() == 4567); +} + +export fn a_mystery_function() i32 { + return 4567; +}