authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-08 21:42:45+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-03-09 04:52:06+00:00
loge2cbbd0c264b323a422ef6dc8c586c287aec845a
treee77ffd706104730d8e50d60cfebb60fdf0e7941a
parent9cf28d1e9bc940b13cd47efb778fd42a4b3b88de

Sema: perform codegen for anon decl created by `@extern`

This fixes a bug where, at least with the LLVM backend, `@extern` calls which had the same name as a normal `extern` in the same Zcu would result in the `@extern` incorrectly suffixing the identifier `.2`. Usually, the LLVM backend has a system to change the generated globals to "collapse" them all together, but it only works if `updateDecl` is called!

2 files changed, 43 insertions(+), 31 deletions(-)

src/Sema.zig+25-31
...@@ -25989,41 +25989,35 @@ fn zirBuiltinExtern(...@@ -25989,41 +25989,35 @@ fn zirBuiltinExtern(
25989 }25989 }
25990 const ptr_info = ty.ptrInfo(mod);25990 const ptr_info = ty.ptrInfo(mod);
2599125991
25992 // TODO check duplicate extern
25993
25994 const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node);25992 const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node);
25995 errdefer mod.destroyDecl(new_decl_index);25993 errdefer mod.destroyDecl(new_decl_index);
25996 const new_decl = mod.declPtr(new_decl_index);25994 const new_decl = mod.declPtr(new_decl_index);
25997 new_decl.name = options.name;25995 try mod.initNewAnonDecl(new_decl_index, sema.owner_decl.src_line, .{
2599825996 .ty = Type.fromInterned(ptr_info.child),
25999 new_decl.src_line = sema.owner_decl.src_line;25997 .val = Value.fromInterned(
26000 new_decl.ty = Type.fromInterned(ptr_info.child);25998 if (Type.fromInterned(ptr_info.child).zigTypeTag(mod) == .Fn)
26001 new_decl.val = Value.fromInterned(25999 try ip.getExternFunc(sema.gpa, .{
26002 if (Type.fromInterned(ptr_info.child).zigTypeTag(mod) == .Fn)26000 .ty = ptr_info.child,
26003 try ip.getExternFunc(sema.gpa, .{26001 .decl = new_decl_index,
26004 .ty = ptr_info.child,26002 .lib_name = options.library_name,
26005 .decl = new_decl_index,26003 })
26006 .lib_name = options.library_name,26004 else
26007 })26005 try mod.intern(.{ .variable = .{
26008 else26006 .ty = ptr_info.child,
26009 try mod.intern(.{ .variable = .{26007 .init = .none,
26010 .ty = ptr_info.child,26008 .decl = new_decl_index,
26011 .init = .none,26009 .lib_name = options.library_name,
26012 .decl = new_decl_index,26010 .is_extern = true,
26013 .lib_name = options.library_name,26011 .is_const = ptr_info.flags.is_const,
26014 .is_extern = true,26012 .is_threadlocal = options.is_thread_local,
26015 .is_const = ptr_info.flags.is_const,26013 .is_weak_linkage = options.linkage == .Weak,
26016 .is_threadlocal = options.is_thread_local,26014 } }),
26017 .is_weak_linkage = options.linkage == .Weak,26015 ),
26018 } }),26016 }, options.name);
26019 );
26020 new_decl.alignment = .none;
26021 new_decl.@"linksection" = .none;
26022 new_decl.has_tv = true;
26023 new_decl.owns_tv = true;26017 new_decl.owns_tv = true;
26024 new_decl.analysis = .complete;26018 // Note that this will queue the anon decl for codegen, so that the backend can
2602526019 // correctly handle the extern, including duplicate detection.
26026 try sema.ensureDeclAnalyzed(new_decl_index);26020 try mod.finalizeAnonDecl(new_decl_index);
2602726021
26028 return Air.internedToRef((try mod.getCoerced(Value.fromInterned((try mod.intern(.{ .ptr = .{26022 return Air.internedToRef((try mod.getCoerced(Value.fromInterned((try mod.intern(.{ .ptr = .{
26029 .ty = switch (ip.indexToKey(ty.toIntern())) {26023 .ty = switch (ip.indexToKey(ty.toIntern())) {
test/behavior/extern.zig+18
...@@ -27,3 +27,21 @@ test "function extern symbol" {...@@ -27,3 +27,21 @@ test "function extern symbol" {
27export fn a_mystery_function() i32 {27export fn a_mystery_function() i32 {
28 return 4567;28 return 4567;
29}29}
30
31test "function extern symbol matches extern decl" {
32 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
33 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
34 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf and builtin.target.ofmt != .macho) return error.SkipZigTest;
35 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
36
37 const S = struct {
38 extern fn another_mystery_function() u32;
39 const same_thing = @extern(*const fn () callconv(.C) u32, .{ .name = "another_mystery_function" });
40 };
41 try expect(S.another_mystery_function() == 12345);
42 try expect(S.same_thing() == 12345);
43}
44
45export fn another_mystery_function() u32 {
46 return 12345;
47}