authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-18 13:25:13-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2025-08-18 13:25:13-07:00
log001ec07772f35ffee031429a558506b89d02cdca
tree2c626a0670ba522cc201e5af8d922e2c395b8ed5
parentc1483eb05c221b4f0c0c357bf75b828f722fa44d
parent52178d14b080d0bbf5e1fe8ed25ce1c26ea18566
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #24249 from antlilja/dwarf-extern-arg

Fix compiler crash when passing a comptime extern function arg to a function

8 files changed, 243 insertions(+), 65 deletions(-)

src/InternPool.zig+10-3
...@@ -2257,6 +2257,7 @@ pub const Key = union(enum) {...@@ -2257,6 +2257,7 @@ pub const Key = union(enum) {
2257 /// The `Nav` corresponding to this extern symbol.2257 /// The `Nav` corresponding to this extern symbol.
2258 /// This is ignored by hashing and equality.2258 /// This is ignored by hashing and equality.
2259 owner_nav: Nav.Index,2259 owner_nav: Nav.Index,
2260 source: Tag.Extern.Flags.Source,
2260 };2261 };
22612262
2262 pub const Func = struct {2263 pub const Func = struct {
...@@ -2859,7 +2860,7 @@ pub const Key = union(enum) {...@@ -2859,7 +2860,7 @@ pub const Key = union(enum) {
2859 asBytes(&e.is_threadlocal) ++ asBytes(&e.is_dll_import) ++2860 asBytes(&e.is_threadlocal) ++ asBytes(&e.is_dll_import) ++
2860 asBytes(&e.relocation) ++2861 asBytes(&e.relocation) ++
2861 asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++2862 asBytes(&e.is_const) ++ asBytes(&e.alignment) ++ asBytes(&e.@"addrspace") ++
2862 asBytes(&e.zir_index)),2863 asBytes(&e.zir_index) ++ &[1]u8{@intFromEnum(e.source)}),
2863 };2864 };
2864 }2865 }
28652866
...@@ -2958,7 +2959,8 @@ pub const Key = union(enum) {...@@ -2958,7 +2959,8 @@ pub const Key = union(enum) {
2958 a_info.is_const == b_info.is_const and2959 a_info.is_const == b_info.is_const and
2959 a_info.alignment == b_info.alignment and2960 a_info.alignment == b_info.alignment and
2960 a_info.@"addrspace" == b_info.@"addrspace" and2961 a_info.@"addrspace" == b_info.@"addrspace" and
2961 a_info.zir_index == b_info.zir_index;2962 a_info.zir_index == b_info.zir_index and
2963 a_info.source == b_info.source;
2962 },2964 },
2963 .func => |a_info| {2965 .func => |a_info| {
2964 const b_info = b.func;2966 const b_info = b.func;
...@@ -5967,7 +5969,10 @@ pub const Tag = enum(u8) {...@@ -5967,7 +5969,10 @@ pub const Tag = enum(u8) {
5967 is_threadlocal: bool,5969 is_threadlocal: bool,
5968 is_dll_import: bool,5970 is_dll_import: bool,
5969 relocation: std.builtin.ExternOptions.Relocation,5971 relocation: std.builtin.ExternOptions.Relocation,
5970 _: u25 = 0,5972 source: Source,
5973 _: u24 = 0,
5974
5975 pub const Source = enum(u1) { builtin, syntax };
5971 };5976 };
5972 };5977 };
59735978
...@@ -7320,6 +7325,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7320,6 +7325,7 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7320 .@"addrspace" = nav.status.fully_resolved.@"addrspace",7325 .@"addrspace" = nav.status.fully_resolved.@"addrspace",
7321 .zir_index = extra.zir_index,7326 .zir_index = extra.zir_index,
7322 .owner_nav = extra.owner_nav,7327 .owner_nav = extra.owner_nav,
7328 .source = extra.flags.source,
7323 } };7329 } };
7324 },7330 },
7325 .func_instance => .{ .func = ip.extraFuncInstance(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },7331 .func_instance => .{ .func = ip.extraFuncInstance(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
...@@ -9212,6 +9218,7 @@ pub fn getExtern(...@@ -9212,6 +9218,7 @@ pub fn getExtern(
9212 .is_threadlocal = key.is_threadlocal,9218 .is_threadlocal = key.is_threadlocal,
9213 .is_dll_import = key.is_dll_import,9219 .is_dll_import = key.is_dll_import,
9214 .relocation = key.relocation,9220 .relocation = key.relocation,
9221 .source = key.source,
9215 },9222 },
9216 .zir_index = key.zir_index,9223 .zir_index = key.zir_index,
9217 .owner_nav = owner_nav,9224 .owner_nav = owner_nav,
src/Sema.zig+1
...@@ -25768,6 +25768,7 @@ fn zirBuiltinExtern(...@@ -25768,6 +25768,7 @@ fn zirBuiltinExtern(
25768 },25768 },
25769 },25769 },
25770 .owner_nav = undefined, // ignored by `getExtern`25770 .owner_nav = undefined, // ignored by `getExtern`
25771 .source = .builtin,
25771 });25772 });
2577225773
25773 const uncasted_ptr = try sema.analyzeNavRef(block, src, ip.indexToKey(extern_val).@"extern".owner_nav);25774 const uncasted_ptr = try sema.analyzeNavRef(block, src, ip.indexToKey(extern_val).@"extern".owner_nav);
src/Zcu/PerThread.zig+2
...@@ -1249,6 +1249,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1249,6 +1249,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1249 .@"addrspace" = modifiers.@"addrspace",1249 .@"addrspace" = modifiers.@"addrspace",
1250 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction1250 .zir_index = old_nav.analysis.?.zir_index, // `declaration` instruction
1251 .owner_nav = undefined, // ignored by `getExtern`1251 .owner_nav = undefined, // ignored by `getExtern`
1252 .source = .syntax,
1252 }));1253 }));
1253 },1254 },
1254 };1255 };
...@@ -3435,6 +3436,7 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V...@@ -3435,6 +3436,7 @@ pub fn getCoerced(pt: Zcu.PerThread, val: Value, new_ty: Type) Allocator.Error!V
3435 .@"addrspace" = e.@"addrspace",3436 .@"addrspace" = e.@"addrspace",
3436 .zir_index = e.zir_index,3437 .zir_index = e.zir_index,
3437 .owner_nav = undefined, // ignored by `getExtern`.3438 .owner_nav = undefined, // ignored by `getExtern`.
3439 .source = e.source,
3438 });3440 });
3439 return Value.fromInterned(coerced);3441 return Value.fromInterned(coerced);
3440 },3442 },
src/link/Dwarf.zig+212-57
...@@ -1720,7 +1720,7 @@ pub const WipNav = struct {...@@ -1720,7 +1720,7 @@ pub const WipNav = struct {
1720 std.leb.writeUnsignedFixed(1720 std.leb.writeUnsignedFixed(
1721 block_bytes,1721 block_bytes,
1722 wip_nav.debug_info.written()[block.abbrev_code..][0..block_bytes],1722 wip_nav.debug_info.written()[block.abbrev_code..][0..block_bytes],
1723 try wip_nav.dwarf.refAbbrevCode(.empty_block),1723 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_block)),
1724 );1724 );
1725 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);1725 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);
1726 wip_nav.any_children = true;1726 wip_nav.any_children = true;
...@@ -1782,7 +1782,7 @@ pub const WipNav = struct {...@@ -1782,7 +1782,7 @@ pub const WipNav = struct {
1782 std.leb.writeUnsignedFixed(1782 std.leb.writeUnsignedFixed(
1783 inlined_func_bytes,1783 inlined_func_bytes,
1784 wip_nav.debug_info.written()[block.abbrev_code..][0..inlined_func_bytes],1784 wip_nav.debug_info.written()[block.abbrev_code..][0..inlined_func_bytes],
1785 try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func),1785 @intCast(try wip_nav.dwarf.refAbbrevCode(.empty_inlined_func)),
1786 );1786 );
1787 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);1787 std.mem.writeInt(u32, wip_nav.debug_info.written()[block.high_pc..][0..4], @intCast(code_off - block.low_pc_off), wip_nav.dwarf.endian);
1788 try wip_nav.setInlineFunc(func);1788 try wip_nav.setInlineFunc(func);
...@@ -2077,7 +2077,11 @@ pub const WipNav = struct {...@@ -2077,7 +2077,11 @@ pub const WipNav = struct {
2077 const ty = value.typeOf(zcu);2077 const ty = value.typeOf(zcu);
2078 if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu) and try ty.onePossibleValue(wip_nav.pt) == null);2078 if (std.debug.runtime_safety) assert(ty.comptimeOnly(zcu) and try ty.onePossibleValue(wip_nav.pt) == null);
2079 if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());2079 if (ty.toIntern() == .type_type) return wip_nav.getTypeEntry(value.toType());
2080 if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(zcu.funcInfo(value.toIntern()).owner_nav);2080 if (ip.isFunctionType(ty.toIntern()) and !value.isUndef(zcu)) return wip_nav.getNavEntry(switch (ip.indexToKey(value.toIntern())) {
2081 else => unreachable,
2082 .func => |func| func.owner_nav,
2083 .@"extern" => |@"extern"| @"extern".owner_nav,
2084 });
2081 const gop = try wip_nav.dwarf.values.getOrPut(wip_nav.dwarf.gpa, value.toIntern());2085 const gop = try wip_nav.dwarf.values.getOrPut(wip_nav.dwarf.gpa, value.toIntern());
2082 const unit: Unit.Index = .main;2086 const unit: Unit.Index = .main;
2083 if (gop.found_existing) return .{ unit, gop.value_ptr.* };2087 if (gop.found_existing) return .{ unit, gop.value_ptr.* };
...@@ -2250,6 +2254,8 @@ pub const WipNav = struct {...@@ -2250,6 +2254,8 @@ pub const WipNav = struct {
2250 .decl_func,2254 .decl_func,
2251 .decl_nullary_func_generic,2255 .decl_nullary_func_generic,
2252 .decl_func_generic,2256 .decl_func_generic,
2257 .decl_extern_nullary_func,
2258 .decl_extern_func,
2253 => false,2259 => false,
2254 .generic_decl_var,2260 .generic_decl_var,
2255 .generic_decl_const,2261 .generic_decl_const,
...@@ -2585,7 +2591,7 @@ pub fn initWipNav(...@@ -2585,7 +2591,7 @@ pub fn initWipNav(
2585 pt: Zcu.PerThread,2591 pt: Zcu.PerThread,
2586 nav_index: InternPool.Nav.Index,2592 nav_index: InternPool.Nav.Index,
2587 sym_index: u32,2593 sym_index: u32,
2588) error{ OutOfMemory, CodegenFail }!?WipNav {2594) error{ OutOfMemory, CodegenFail }!WipNav {
2589 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {2595 return initWipNavInner(dwarf, pt, nav_index, sym_index) catch |err| switch (err) {
2590 error.OutOfMemory => error.OutOfMemory,2596 error.OutOfMemory => error.OutOfMemory,
2591 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),2597 else => |e| pt.zcu.codegenFail(nav_index, "failed to init dwarf: {s}", .{@errorName(e)}),
...@@ -2597,7 +2603,7 @@ fn initWipNavInner(...@@ -2597,7 +2603,7 @@ fn initWipNavInner(
2597 pt: Zcu.PerThread,2603 pt: Zcu.PerThread,
2598 nav_index: InternPool.Nav.Index,2604 nav_index: InternPool.Nav.Index,
2599 sym_index: u32,2605 sym_index: u32,
2600) !?WipNav {2606) !WipNav {
2601 const zcu = pt.zcu;2607 const zcu = pt.zcu;
2602 const ip = &zcu.intern_pool;2608 const ip = &zcu.intern_pool;
26032609
...@@ -2613,15 +2619,6 @@ fn initWipNavInner(...@@ -2613,15 +2619,6 @@ fn initWipNavInner(
2613 nav.fqn.fmt(ip),2619 nav.fqn.fmt(ip),
2614 });2620 });
26152621
2616 const nav_val = zcu.navValue(nav_index);
2617 const nav_key = ip.indexToKey(nav_val.toIntern());
2618 switch (nav_key) {
2619 // Ignore @extern
2620 .@"extern" => |@"extern"| if (decl.linkage != .@"extern" or
2621 !@"extern".name.eqlSlice(file.zir.?.nullTerminatedString(decl.name), ip)) return null,
2622 else => {},
2623 }
2624
2625 const mod = file.mod.?;2622 const mod = file.mod.?;
2626 const unit = try dwarf.getUnit(mod);2623 const unit = try dwarf.getUnit(mod);
2627 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);2624 const nav_gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index);
...@@ -2654,44 +2651,63 @@ fn initWipNavInner(...@@ -2654,44 +2651,63 @@ fn initWipNavInner(
2654 };2651 };
2655 errdefer wip_nav.deinit();2652 errdefer wip_nav.deinit();
26562653
2657 switch (nav_key) {2654 const nav_val = zcu.navValue(nav_index);
2658 else => {2655 nav_val: switch (ip.indexToKey(nav_val.toIntern())) {
2659 const diw = &wip_nav.debug_info.writer;2656 .@"extern" => |@"extern"| switch (@"extern".source) {
2660 try wip_nav.declCommon(.{2657 .builtin => {
2661 .decl = .decl_var,2658 const maybe_func_type = switch (ip.indexToKey(@"extern".ty)) {
2662 .generic_decl = .generic_decl_var,2659 .func_type => |func_type| func_type,
2663 .decl_instance = .decl_instance_var,2660 else => null,
2664 }, &nav, inst_info.file, &decl);
2665 try wip_nav.strp(nav.fqn.toSlice(ip));
2666 const ty: Type = nav_val.typeOf(zcu);
2667 const addr: Loc = .{ .addr_reloc = sym_index };
2668 const loc: Loc = if (decl.is_threadlocal) loc: {
2669 const target = zcu.comp.root_mod.resolved_target.result;
2670 break :loc switch (target.cpu.arch) {
2671 .x86_64 => .{ .form_tls_address = &addr },
2672 else => .empty,
2673 };2661 };
2674 } else addr;2662 const diw = &wip_nav.debug_info.writer;
2675 switch (decl.kind) {2663 try wip_nav.abbrevCode(if (maybe_func_type) |func_type|
2676 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,2664 if (func_type.param_types.len > 0 or func_type.is_var_args) .builtin_extern_func else .builtin_extern_nullary_func
2677 .@"const" => {2665 else
2678 const const_ty_reloc_index = try wip_nav.refForward();2666 .builtin_extern_var);
2679 try wip_nav.infoExprLoc(loc);2667 try wip_nav.refType(.fromInterned(zcu.fileRootType(inst_info.file)));
2680 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse2668 try wip_nav.strp(@"extern".name.toSlice(ip));
2681 ty.abiAlignment(zcu).toByteUnits().?);2669 try wip_nav.refType(.fromInterned(if (maybe_func_type) |func_type| func_type.return_type else @"extern".ty));
2682 try diw.writeByte(@intFromBool(decl.linkage != .normal));2670 if (maybe_func_type) |func_type| {
2683 wip_nav.finishForward(const_ty_reloc_index);2671 try wip_nav.infoAddrSym(sym_index, 0);
2684 try wip_nav.abbrevCode(.is_const);2672 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2685 try wip_nav.refType(ty);2673 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2686 },2674 for (func_type.param_types.get(ip)) |param_type| {
2687 .@"var" => {2675 try wip_nav.abbrevCode(.extern_param);
2688 try wip_nav.refType(ty);2676 try wip_nav.refType(.fromInterned(param_type));
2689 try wip_nav.infoExprLoc(loc);2677 }
2690 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse2678 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2691 ty.abiAlignment(zcu).toByteUnits().?);2679 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
2692 try diw.writeByte(@intFromBool(decl.linkage != .normal));2680 }
2681 } else try wip_nav.infoExprLoc(.{ .addr_reloc = sym_index });
2682 },
2683 .syntax => switch (ip.isFunctionType(@"extern".ty)) {
2684 false => continue :nav_val .{ .variable = undefined },
2685 true => {
2686 const func_type = ip.indexToKey(@"extern".ty).func_type;
2687 const diw = &wip_nav.debug_info.writer;
2688 try wip_nav.declCommon(if (func_type.param_types.len > 0 or func_type.is_var_args) .{
2689 .decl = .decl_extern_func,
2690 .generic_decl = .generic_decl_func,
2691 .decl_instance = .decl_instance_extern_func,
2692 } else .{
2693 .decl = .decl_extern_nullary_func,
2694 .generic_decl = .generic_decl_func,
2695 .decl_instance = .decl_instance_extern_nullary_func,
2696 }, &nav, inst_info.file, &decl);
2697 try wip_nav.strp(@"extern".name.toSlice(ip));
2698 try wip_nav.refType(.fromInterned(func_type.return_type));
2699 try wip_nav.infoAddrSym(sym_index, 0);
2700 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
2701 if (func_type.param_types.len > 0 or func_type.is_var_args) {
2702 for (func_type.param_types.get(ip)) |param_type| {
2703 try wip_nav.abbrevCode(.extern_param);
2704 try wip_nav.refType(.fromInterned(param_type));
2705 }
2706 if (func_type.is_var_args) try wip_nav.abbrevCode(.is_var_args);
2707 try diw.writeUleb128(@intFromEnum(AbbrevCode.null));
2708 }
2693 },2709 },
2694 }2710 },
2695 },2711 },
2696 .func => |func| if (func.owner_nav != nav_index) {2712 .func => |func| if (func.owner_nav != nav_index) {
2697 try wip_nav.declCommon(.{2713 try wip_nav.declCommon(.{
...@@ -2752,7 +2768,10 @@ fn initWipNavInner(...@@ -2752,7 +2768,10 @@ fn initWipNavInner(
2752 .generic_decl = .generic_decl_func,2768 .generic_decl = .generic_decl_func,
2753 .decl_instance = .decl_instance_func,2769 .decl_instance = .decl_instance_func,
2754 }, &nav, inst_info.file, &decl);2770 }, &nav, inst_info.file, &decl);
2755 try wip_nav.strp(nav.fqn.toSlice(ip));2771 try wip_nav.strp(switch (decl.linkage) {
2772 .normal => nav.fqn,
2773 .@"extern", .@"export" => nav.name,
2774 }.toSlice(ip));
2756 try wip_nav.refType(.fromInterned(func_type.return_type));2775 try wip_nav.refType(.fromInterned(func_type.return_type));
2757 try wip_nav.infoAddrSym(sym_index, 0);2776 try wip_nav.infoAddrSym(sym_index, 0);
2758 wip_nav.func_high_pc = @intCast(diw.end);2777 wip_nav.func_high_pc = @intCast(diw.end);
...@@ -2763,7 +2782,7 @@ fn initWipNavInner(...@@ -2763,7 +2782,7 @@ fn initWipNavInner(
2763 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),2782 else => |a| a.maxStrict(target_info.minFunctionAlignment(target)),
2764 }.toByteUnits().?);2783 }.toByteUnits().?);
2765 try diw.writeByte(@intFromBool(decl.linkage != .normal));2784 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2766 try diw.writeByte(@intFromBool(func_type.return_type == .noreturn_type));2785 try diw.writeByte(@intFromBool(ip.isNoReturn(func_type.return_type)));
27672786
2768 const dlw = &wip_nav.debug_line.writer;2787 const dlw = &wip_nav.debug_line.writer;
2769 try dlw.writeByte(DW.LNS.extended_op);2788 try dlw.writeByte(DW.LNS.extended_op);
...@@ -2801,6 +2820,47 @@ fn initWipNavInner(...@@ -2801,6 +2820,47 @@ fn initWipNavInner(
2801 try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0);2820 try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0);
2802 }2821 }
2803 },2822 },
2823 else => {
2824 const diw = &wip_nav.debug_info.writer;
2825 try wip_nav.declCommon(.{
2826 .decl = .decl_var,
2827 .generic_decl = .generic_decl_var,
2828 .decl_instance = .decl_instance_var,
2829 }, &nav, inst_info.file, &decl);
2830 try wip_nav.strp(switch (decl.linkage) {
2831 .normal => nav.fqn,
2832 .@"extern", .@"export" => nav.name,
2833 }.toSlice(ip));
2834 const ty: Type = nav_val.typeOf(zcu);
2835 const addr: Loc = .{ .addr_reloc = sym_index };
2836 const loc: Loc = if (decl.is_threadlocal) loc: {
2837 const target = zcu.comp.root_mod.resolved_target.result;
2838 break :loc switch (target.cpu.arch) {
2839 .x86_64 => .{ .form_tls_address = &addr },
2840 else => .empty,
2841 };
2842 } else addr;
2843 switch (decl.kind) {
2844 .unnamed_test, .@"test", .decltest, .@"comptime" => unreachable,
2845 .@"const" => {
2846 const const_ty_reloc_index = try wip_nav.refForward();
2847 try wip_nav.infoExprLoc(loc);
2848 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
2849 ty.abiAlignment(zcu).toByteUnits().?);
2850 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2851 wip_nav.finishForward(const_ty_reloc_index);
2852 try wip_nav.abbrevCode(.is_const);
2853 try wip_nav.refType(ty);
2854 },
2855 .@"var" => {
2856 try wip_nav.refType(ty);
2857 try wip_nav.infoExprLoc(loc);
2858 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
2859 ty.abiAlignment(zcu).toByteUnits().?);
2860 try diw.writeByte(@intFromBool(decl.linkage != .normal));
2861 },
2862 }
2863 },
2804 }2864 }
2805 return wip_nav;2865 return wip_nav;
2806}2866}
...@@ -2891,11 +2951,11 @@ fn finishWipNavFuncWriterError(...@@ -2891,11 +2951,11 @@ fn finishWipNavFuncWriterError(
2891 std.leb.writeUnsignedFixed(2951 std.leb.writeUnsignedFixed(
2892 AbbrevCode.decl_bytes,2952 AbbrevCode.decl_bytes,
2893 abbrev_code_buf,2953 abbrev_code_buf,
2894 try dwarf.refAbbrevCode(switch (abbrev_code) {2954 @intCast(try dwarf.refAbbrevCode(switch (abbrev_code) {
2895 else => unreachable,2955 else => unreachable,
2896 .decl_func => .decl_nullary_func,2956 .decl_func => .decl_nullary_func,
2897 .decl_instance_func => .decl_instance_nullary_func,2957 .decl_instance_func => .decl_instance_nullary_func,
2898 }),2958 })),
2899 );2959 );
2900 }2960 }
2901 }2961 }
...@@ -3357,7 +3417,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3357,7 +3417,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3357 .generic_decl = .generic_decl_var,3417 .generic_decl = .generic_decl_var,
3358 .decl_instance = .decl_instance_var,3418 .decl_instance = .decl_instance_var,
3359 }, &nav, inst_info.file, &decl);3419 }, &nav, inst_info.file, &decl);
3360 try wip_nav.strp(nav.fqn.toSlice(ip));3420 try wip_nav.strp(switch (decl.linkage) {
3421 .normal => nav.fqn,
3422 .@"extern", .@"export" => nav.name,
3423 }.toSlice(ip));
3361 const nav_ty = nav_val.typeOf(zcu);3424 const nav_ty = nav_val.typeOf(zcu);
3362 try wip_nav.refType(nav_ty);3425 try wip_nav.refType(nav_ty);
3363 try wip_nav.blockValue(nav_src_loc, nav_val);3426 try wip_nav.blockValue(nav_src_loc, nav_val);
...@@ -3387,7 +3450,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo...@@ -3387,7 +3450,10 @@ fn updateComptimeNavInner(dwarf: *Dwarf, pt: Zcu.PerThread, nav_index: InternPoo
3387 .generic_decl = .generic_decl_const,3450 .generic_decl = .generic_decl_const,
3388 .decl_instance = .decl_instance_const,3451 .decl_instance = .decl_instance_const,
3389 }, &nav, inst_info.file, &decl);3452 }, &nav, inst_info.file, &decl);
3390 try wip_nav.strp(nav.fqn.toSlice(ip));3453 try wip_nav.strp(switch (decl.linkage) {
3454 .normal => nav.fqn,
3455 .@"extern", .@"export" => nav.name,
3456 }.toSlice(ip));
3391 const nav_ty_reloc_index = try wip_nav.refForward();3457 const nav_ty_reloc_index = try wip_nav.refForward();
3392 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse3458 try diw.writeUleb128(nav.status.fully_resolved.alignment.toByteUnits() orelse
3393 nav_ty.abiAlignment(zcu).toByteUnits().?);3459 nav_ty.abiAlignment(zcu).toByteUnits().?);
...@@ -5109,6 +5175,8 @@ const AbbrevCode = enum {...@@ -5109,6 +5175,8 @@ const AbbrevCode = enum {
5109 decl_func,5175 decl_func,
5110 decl_nullary_func_generic,5176 decl_nullary_func_generic,
5111 decl_func_generic,5177 decl_func_generic,
5178 decl_extern_nullary_func,
5179 decl_extern_func,
5112 generic_decl_var,5180 generic_decl_var,
5113 generic_decl_const,5181 generic_decl_const,
5114 generic_decl_func,5182 generic_decl_func,
...@@ -5128,6 +5196,8 @@ const AbbrevCode = enum {...@@ -5128,6 +5196,8 @@ const AbbrevCode = enum {
5128 decl_instance_func,5196 decl_instance_func,
5129 decl_instance_nullary_func_generic,5197 decl_instance_nullary_func_generic,
5130 decl_instance_func_generic,5198 decl_instance_func_generic,
5199 decl_instance_extern_nullary_func,
5200 decl_instance_extern_func,
5131 // the rest are unrestricted other than empty variants must not be longer5201 // the rest are unrestricted other than empty variants must not be longer
5132 // than the non-empty variant, and so should appear first5202 // than the non-empty variant, and so should appear first
5133 compile_unit,5203 compile_unit,
...@@ -5179,6 +5249,9 @@ const AbbrevCode = enum {...@@ -5179,6 +5249,9 @@ const AbbrevCode = enum {
5179 packed_struct_type,5249 packed_struct_type,
5180 empty_union_type,5250 empty_union_type,
5181 union_type,5251 union_type,
5252 builtin_extern_nullary_func,
5253 builtin_extern_func,
5254 builtin_extern_var,
5182 empty_block,5255 empty_block,
5183 block,5256 block,
5184 empty_inlined_func,5257 empty_inlined_func,
...@@ -5193,6 +5266,7 @@ const AbbrevCode = enum {...@@ -5193,6 +5266,7 @@ const AbbrevCode = enum {
5193 unnamed_comptime_arg_comptime_state,5266 unnamed_comptime_arg_comptime_state,
5194 comptime_arg_runtime_bits_comptime_state,5267 comptime_arg_runtime_bits_comptime_state,
5195 unnamed_comptime_arg_runtime_bits_comptime_state,5268 unnamed_comptime_arg_runtime_bits_comptime_state,
5269 extern_param,
5196 local_var,5270 local_var,
5197 local_const,5271 local_const,
5198 local_const_runtime_bits,5272 local_const_runtime_bits,
...@@ -5214,7 +5288,7 @@ const AbbrevCode = enum {...@@ -5214,7 +5288,7 @@ const AbbrevCode = enum {
5214 comptime_value_elem_runtime_bits,5288 comptime_value_elem_runtime_bits,
5215 comptime_value_elem_comptime_state,5289 comptime_value_elem_comptime_state,
52165290
5217 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_func_generic));5291 const decl_bytes = uleb128Bytes(@intFromEnum(AbbrevCode.decl_instance_extern_func));
5218 comptime {5292 comptime {
5219 assert(uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)) == 1);5293 assert(uleb128Bytes(@intFromEnum(AbbrevCode.pad_1)) == 1);
5220 assert(uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) == 1);5294 assert(uleb128Bytes(@intFromEnum(AbbrevCode.pad_n)) == 1);
...@@ -5389,6 +5463,27 @@ const AbbrevCode = enum {...@@ -5389,6 +5463,27 @@ const AbbrevCode = enum {
5389 .{ .type, .ref_addr },5463 .{ .type, .ref_addr },
5390 },5464 },
5391 },5465 },
5466 .decl_extern_nullary_func = .{
5467 .tag = .subprogram,
5468 .attrs = decl_abbrev_common_attrs ++ .{
5469 .{ .linkage_name, .strp },
5470 .{ .type, .ref_addr },
5471 .{ .low_pc, .addr },
5472 .{ .external, .flag_present },
5473 .{ .noreturn, .flag },
5474 },
5475 },
5476 .decl_extern_func = .{
5477 .tag = .subprogram,
5478 .children = true,
5479 .attrs = decl_abbrev_common_attrs ++ .{
5480 .{ .linkage_name, .strp },
5481 .{ .type, .ref_addr },
5482 .{ .low_pc, .addr },
5483 .{ .external, .flag_present },
5484 .{ .noreturn, .flag },
5485 },
5486 },
5392 .generic_decl_var = .{5487 .generic_decl_var = .{
5393 .tag = .variable,5488 .tag = .variable,
5394 .attrs = generic_decl_abbrev_common_attrs,5489 .attrs = generic_decl_abbrev_common_attrs,
...@@ -5537,6 +5632,27 @@ const AbbrevCode = enum {...@@ -5537,6 +5632,27 @@ const AbbrevCode = enum {
5537 .{ .type, .ref_addr },5632 .{ .type, .ref_addr },
5538 },5633 },
5539 },5634 },
5635 .decl_instance_extern_nullary_func = .{
5636 .tag = .subprogram,
5637 .attrs = decl_instance_abbrev_common_attrs ++ .{
5638 .{ .linkage_name, .strp },
5639 .{ .type, .ref_addr },
5640 .{ .low_pc, .addr },
5641 .{ .external, .flag_present },
5642 .{ .noreturn, .flag },
5643 },
5644 },
5645 .decl_instance_extern_func = .{
5646 .tag = .subprogram,
5647 .children = true,
5648 .attrs = decl_instance_abbrev_common_attrs ++ .{
5649 .{ .linkage_name, .strp },
5650 .{ .type, .ref_addr },
5651 .{ .low_pc, .addr },
5652 .{ .external, .flag_present },
5653 .{ .noreturn, .flag },
5654 },
5655 },
5540 .compile_unit = .{5656 .compile_unit = .{
5541 .tag = .compile_unit,5657 .tag = .compile_unit,
5542 .children = true,5658 .children = true,
...@@ -5934,6 +6050,39 @@ const AbbrevCode = enum {...@@ -5934,6 +6050,39 @@ const AbbrevCode = enum {
5934 .{ .alignment, .udata },6050 .{ .alignment, .udata },
5935 },6051 },
5936 },6052 },
6053 .builtin_extern_nullary_func = .{
6054 .tag = .subprogram,
6055 .attrs = &.{
6056 .{ .ZIG_parent, .ref_addr },
6057 .{ .linkage_name, .strp },
6058 .{ .type, .ref_addr },
6059 .{ .low_pc, .addr },
6060 .{ .external, .flag_present },
6061 .{ .noreturn, .flag },
6062 },
6063 },
6064 .builtin_extern_func = .{
6065 .tag = .subprogram,
6066 .children = true,
6067 .attrs = &.{
6068 .{ .ZIG_parent, .ref_addr },
6069 .{ .linkage_name, .strp },
6070 .{ .type, .ref_addr },
6071 .{ .low_pc, .addr },
6072 .{ .external, .flag_present },
6073 .{ .noreturn, .flag },
6074 },
6075 },
6076 .builtin_extern_var = .{
6077 .tag = .variable,
6078 .attrs = &.{
6079 .{ .ZIG_parent, .ref_addr },
6080 .{ .linkage_name, .strp },
6081 .{ .type, .ref_addr },
6082 .{ .location, .exprloc },
6083 .{ .external, .flag_present },
6084 },
6085 },
5937 .empty_block = .{6086 .empty_block = .{
5938 .tag = .lexical_block,6087 .tag = .lexical_block,
5939 .attrs = &.{6088 .attrs = &.{
...@@ -6053,6 +6202,12 @@ const AbbrevCode = enum {...@@ -6053,6 +6202,12 @@ const AbbrevCode = enum {
6053 .{ .ZIG_comptime_value, .ref_addr },6202 .{ .ZIG_comptime_value, .ref_addr },
6054 },6203 },
6055 },6204 },
6205 .extern_param = .{
6206 .tag = .formal_parameter,
6207 .attrs = &.{
6208 .{ .type, .ref_addr },
6209 },
6210 },
6056 .local_var = .{6211 .local_var = .{
6057 .tag = .variable,6212 .tag = .variable,
6058 .attrs = &.{6213 .attrs = &.{
src/link/Elf/ZigObject.zig+2-2
...@@ -1543,8 +1543,8 @@ pub fn updateNav(...@@ -1543,8 +1543,8 @@ pub fn updateNav(
1543 @"extern".lib_name.toSlice(ip),1543 @"extern".lib_name.toSlice(ip),
1544 );1544 );
1545 if (@"extern".is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) self.symbol(sym_index).flags.is_tls = true;1545 if (@"extern".is_threadlocal and elf_file.base.comp.config.any_non_single_threaded) self.symbol(sym_index).flags.is_tls = true;
1546 if (self.dwarf) |*dwarf| dwarf: {1546 if (self.dwarf) |*dwarf| {
1547 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf;1547 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index);
1548 defer debug_wip_nav.deinit();1548 defer debug_wip_nav.deinit();
1549 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {1549 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
1550 error.OutOfMemory => return error.OutOfMemory,1550 error.OutOfMemory => return error.OutOfMemory,
src/link/MachO/ZigObject.zig+2-2
...@@ -877,8 +877,8 @@ pub fn updateNav(...@@ -877,8 +877,8 @@ pub fn updateNav(
877 const lib_name = @"extern".lib_name.toSlice(ip);877 const lib_name = @"extern".lib_name.toSlice(ip);
878 const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);878 const sym_index = try self.getGlobalSymbol(macho_file, name, lib_name);
879 if (@"extern".is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;879 if (@"extern".is_threadlocal and macho_file.base.comp.config.any_non_single_threaded) self.symbols.items[sym_index].flags.tlv = true;
880 if (self.dwarf) |*dwarf| dwarf: {880 if (self.dwarf) |*dwarf| {
881 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index) orelse break :dwarf;881 var debug_wip_nav = try dwarf.initWipNav(pt, nav_index, sym_index);
882 defer debug_wip_nav.deinit();882 defer debug_wip_nav.deinit();
883 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {883 dwarf.finishWipNav(pt, nav_index, &debug_wip_nav) catch |err| switch (err) {
884 error.OutOfMemory => return error.OutOfMemory,884 error.OutOfMemory => return error.OutOfMemory,
test/behavior/extern.zig+13
...@@ -56,3 +56,16 @@ test "coerce extern function types" {...@@ -56,3 +56,16 @@ test "coerce extern function types" {
5656
57 _ = @as(fn () callconv(.c) ?*u32, c_extern_function);57 _ = @as(fn () callconv(.c) ?*u32, c_extern_function);
58}58}
59
60fn a_function(func: fn () callconv(.c) void) void {
61 _ = func;
62}
63
64test "pass extern function to function" {
65 a_function(struct {
66 extern fn an_extern_function() void;
67 }.an_extern_function);
68 a_function(@extern(*const fn () callconv(.c) void, .{ .name = "an_extern_function" }).*);
69}
70
71export fn an_extern_function() void {}
test/incremental/change_exports+1-1
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1#target=x86_64-linux-selfhosted1//#target=x86_64-linux-selfhosted
2#target=x86_64-linux-cbe2#target=x86_64-linux-cbe
3#target=x86_64-windows-cbe3#target=x86_64-windows-cbe
44