diff --git a/src/Sema.zig b/src/Sema.zig index ac73c24911..1ac6d28bf0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -25989,41 +25989,35 @@ fn zirBuiltinExtern( } const ptr_info = ty.ptrInfo(mod); - // TODO check duplicate extern - const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node); errdefer mod.destroyDecl(new_decl_index); const new_decl = mod.declPtr(new_decl_index); - new_decl.name = options.name; - - 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; + try mod.initNewAnonDecl(new_decl_index, sema.owner_decl.src_line, .{ + .ty = Type.fromInterned(ptr_info.child), + .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, + } }), + ), + }, options.name); new_decl.owns_tv = true; - new_decl.analysis = .complete; - - try sema.ensureDeclAnalyzed(new_decl_index); + // Note that this will queue the anon decl for codegen, so that the backend can + // correctly handle the extern, including duplicate detection. + try mod.finalizeAnonDecl(new_decl_index); return Air.internedToRef((try mod.getCoerced(Value.fromInterned((try mod.intern(.{ .ptr = .{ .ty = switch (ip.indexToKey(ty.toIntern())) { diff --git a/test/behavior/extern.zig b/test/behavior/extern.zig index 4beb738008..93ac494b88 100644 --- a/test/behavior/extern.zig +++ b/test/behavior/extern.zig @@ -27,3 +27,21 @@ test "function extern symbol" { export fn a_mystery_function() i32 { return 4567; } + +test "function extern symbol matches extern decl" { + 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 and builtin.target.ofmt != .macho) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; + + const S = struct { + extern fn another_mystery_function() u32; + const same_thing = @extern(*const fn () callconv(.C) u32, .{ .name = "another_mystery_function" }); + }; + try expect(S.another_mystery_function() == 12345); + try expect(S.same_thing() == 12345); +} + +export fn another_mystery_function() u32 { + return 12345; +}