Skip to content

Commit e2cbbd0

Browse files
committed
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!
1 parent 9cf28d1 commit e2cbbd0

File tree

2 files changed

+43
-31
lines changed

2 files changed

+43
-31
lines changed

src/Sema.zig

Lines changed: 25 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -25989,41 +25989,35 @@ fn zirBuiltinExtern(
2598925989
}
2599025990
const ptr_info = ty.ptrInfo(mod);
2599125991

25992-
// TODO check duplicate extern
25993-
2599425992
const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node);
2599525993
errdefer mod.destroyDecl(new_decl_index);
2599625994
const new_decl = mod.declPtr(new_decl_index);
25997-
new_decl.name = options.name;
25998-
25999-
new_decl.src_line = sema.owner_decl.src_line;
26000-
new_decl.ty = Type.fromInterned(ptr_info.child);
26001-
new_decl.val = Value.fromInterned(
26002-
if (Type.fromInterned(ptr_info.child).zigTypeTag(mod) == .Fn)
26003-
try ip.getExternFunc(sema.gpa, .{
26004-
.ty = ptr_info.child,
26005-
.decl = new_decl_index,
26006-
.lib_name = options.library_name,
26007-
})
26008-
else
26009-
try mod.intern(.{ .variable = .{
26010-
.ty = ptr_info.child,
26011-
.init = .none,
26012-
.decl = new_decl_index,
26013-
.lib_name = options.library_name,
26014-
.is_extern = true,
26015-
.is_const = ptr_info.flags.is_const,
26016-
.is_threadlocal = options.is_thread_local,
26017-
.is_weak_linkage = options.linkage == .Weak,
26018-
} }),
26019-
);
26020-
new_decl.alignment = .none;
26021-
new_decl.@"linksection" = .none;
26022-
new_decl.has_tv = true;
25995+
try mod.initNewAnonDecl(new_decl_index, sema.owner_decl.src_line, .{
25996+
.ty = Type.fromInterned(ptr_info.child),
25997+
.val = Value.fromInterned(
25998+
if (Type.fromInterned(ptr_info.child).zigTypeTag(mod) == .Fn)
25999+
try ip.getExternFunc(sema.gpa, .{
26000+
.ty = ptr_info.child,
26001+
.decl = new_decl_index,
26002+
.lib_name = options.library_name,
26003+
})
26004+
else
26005+
try mod.intern(.{ .variable = .{
26006+
.ty = ptr_info.child,
26007+
.init = .none,
26008+
.decl = new_decl_index,
26009+
.lib_name = options.library_name,
26010+
.is_extern = true,
26011+
.is_const = ptr_info.flags.is_const,
26012+
.is_threadlocal = options.is_thread_local,
26013+
.is_weak_linkage = options.linkage == .Weak,
26014+
} }),
26015+
),
26016+
}, options.name);
2602326017
new_decl.owns_tv = true;
26024-
new_decl.analysis = .complete;
26025-
26026-
try sema.ensureDeclAnalyzed(new_decl_index);
26018+
// Note that this will queue the anon decl for codegen, so that the backend can
26019+
// correctly handle the extern, including duplicate detection.
26020+
try mod.finalizeAnonDecl(new_decl_index);
2602726021

2602826022
return Air.internedToRef((try mod.getCoerced(Value.fromInterned((try mod.intern(.{ .ptr = .{
2602926023
.ty = switch (ip.indexToKey(ty.toIntern())) {

test/behavior/extern.zig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,21 @@ test "function extern symbol" {
2727
export fn a_mystery_function() i32 {
2828
return 4567;
2929
}
30+
31+
test "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+
45+
export fn another_mystery_function() u32 {
46+
return 12345;
47+
}

0 commit comments

Comments
 (0)