| author | |
| committer | |
| log | 556f0ce5bfb962764bb68d9d9c16765cf9e1b9ba |
| tree | e3ddbc2240c99a089906a10c4c40dcc83a883f17 |
| parent | 04f379dd414184a42412f4497b0573d7612d6730 |
`ExternFn` will contain a maybe-lib-name if it was defined with
the `extern` keyword like so
```zig
extern "c" fn write(usize, usize, usize) usize;
```
`lib_name` will live as long as `ExternFn` decl does.8 files changed, 90 insertions(+), 27 deletions(-)
src/Module.zig+32-4| ... | ... | @@ -501,6 +501,10 @@ pub const Decl = struct { |
| 501 | 501 | } |
| 502 | 502 | |
| 503 | 503 | pub fn clearValues(decl: *Decl, gpa: Allocator) void { |
| 504 | if (decl.getExternFn()) |extern_fn| { | |
| 505 | extern_fn.deinit(gpa); | |
| 506 | gpa.destroy(extern_fn); | |
| 507 | } | |
| 504 | 508 | if (decl.getFunction()) |func| { |
| 505 | 509 | func.deinit(gpa); |
| 506 | 510 | gpa.destroy(func); |
| ... | ... | @@ -690,6 +694,13 @@ pub const Decl = struct { |
| 690 | 694 | return func; |
| 691 | 695 | } |
| 692 | 696 | |
| 697 | pub fn getExternFn(decl: *const Decl) ?*ExternFn { | |
| 698 | if (!decl.owns_tv) return null; | |
| 699 | const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data; | |
| 700 | assert(extern_fn.owner_decl == decl); | |
| 701 | return extern_fn; | |
| 702 | } | |
| 703 | ||
| 693 | 704 | pub fn getVariable(decl: *Decl) ?*Var { |
| 694 | 705 | if (!decl.owns_tv) return null; |
| 695 | 706 | const variable = (decl.val.castTag(.variable) orelse return null).data; |
| ... | ... | @@ -1320,9 +1331,26 @@ pub const Opaque = struct { |
| 1320 | 1331 | } |
| 1321 | 1332 | }; |
| 1322 | 1333 | |
| 1334 | /// Some extern function struct memory is owned by the Decl's TypedValue.Managed | |
| 1335 | /// arena allocator. | |
| 1336 | pub const ExternFn = struct { | |
| 1337 | /// The Decl that corresponds to the function itself. | |
| 1338 | owner_decl: *Decl, | |
| 1339 | /// Library name if specified. | |
| 1340 | /// For example `extern "c" fn write(...) usize` would have 'c' as library name. | |
| 1341 | /// Allocated with Module's allocator; outlives the ZIR code. | |
| 1342 | lib_name: ?[*:0]const u8, | |
| 1343 | ||
| 1344 | pub fn deinit(extern_fn: *ExternFn, gpa: Allocator) void { | |
| 1345 | if (extern_fn.lib_name) |lib_name| { | |
| 1346 | gpa.free(mem.sliceTo(lib_name, 0)); | |
| 1347 | } | |
| 1348 | } | |
| 1349 | }; | |
| 1350 | ||
| 1323 | 1351 | /// Some Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator. |
| 1324 | /// Extern functions do not have this data structure; they are represented by | |
| 1325 | /// the `Decl` only, with a `Value` tag of `extern_fn`. | |
| 1352 | /// Extern functions do not have this data structure; they are represented by `ExternFn` | |
| 1353 | /// instead. | |
| 1326 | 1354 | pub const Fn = struct { |
| 1327 | 1355 | /// The Decl that corresponds to the function itself. |
| 1328 | 1356 | owner_decl: *Decl, |
| ... | ... | @@ -3768,8 +3796,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { |
| 3768 | 3796 | } |
| 3769 | 3797 | }, |
| 3770 | 3798 | .extern_fn => { |
| 3771 | const owner_decl = decl_tv.val.castTag(.extern_fn).?.data; | |
| 3772 | if (decl == owner_decl) { | |
| 3799 | const extern_fn = decl_tv.val.castTag(.extern_fn).?.data; | |
| 3800 | if (extern_fn.owner_decl == decl) { | |
| 3773 | 3801 | decl.owns_tv = true; |
| 3774 | 3802 | queue_linker_work = true; |
| 3775 | 3803 | is_extern = true; |
src/Sema.zig+18-4| ... | ... | @@ -5614,10 +5614,24 @@ fn funcCommon( |
| 5614 | 5614 | } |
| 5615 | 5615 | |
| 5616 | 5616 | if (is_extern) { |
| 5617 | return sema.addConstant( | |
| 5618 | fn_ty, | |
| 5619 | try Value.Tag.extern_fn.create(sema.arena, sema.owner_decl), | |
| 5620 | ); | |
| 5617 | const new_extern_fn = try sema.gpa.create(Module.ExternFn); | |
| 5618 | errdefer sema.gpa.destroy(new_extern_fn); | |
| 5619 | ||
| 5620 | const lib_name: ?[*:0]const u8 = if (opt_lib_name) |lib_name| blk: { | |
| 5621 | break :blk try sema.gpa.dupeZ(u8, lib_name); | |
| 5622 | } else null; | |
| 5623 | ||
| 5624 | new_extern_fn.* = Module.ExternFn{ | |
| 5625 | .owner_decl = sema.owner_decl, | |
| 5626 | .lib_name = lib_name, | |
| 5627 | }; | |
| 5628 | ||
| 5629 | const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn); | |
| 5630 | extern_fn_payload.* = .{ | |
| 5631 | .base = .{ .tag = .extern_fn }, | |
| 5632 | .data = new_extern_fn, | |
| 5633 | }; | |
| 5634 | return sema.addConstant(fn_ty, Value.initPayload(&extern_fn_payload.base)); | |
| 5621 | 5635 | } |
| 5622 | 5636 | |
| 5623 | 5637 | if (!has_body) { |
src/arch/aarch64/CodeGen.zig+9-2| ... | ... | @@ -1574,8 +1574,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 1574 | 1574 | .data = .{ .reg = .x30 }, |
| 1575 | 1575 | }); |
| 1576 | 1576 | } else if (func_value.castTag(.extern_fn)) |func_payload| { |
| 1577 | const decl = func_payload.data; | |
| 1578 | const n_strx = try macho_file.addExternFn(mem.sliceTo(decl.name, 0)); | |
| 1577 | const extern_fn = func_payload.data; | |
| 1578 | const decl_name = extern_fn.owner_decl.name; | |
| 1579 | if (extern_fn.lib_name) |lib_name| { | |
| 1580 | log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ | |
| 1581 | decl_name, | |
| 1582 | lib_name, | |
| 1583 | }); | |
| 1584 | } | |
| 1585 | const n_strx = try macho_file.addExternFn(mem.sliceTo(decl_name, 0)); | |
| 1579 | 1586 | |
| 1580 | 1587 | _ = try self.addInst(.{ |
| 1581 | 1588 | .tag = .call_extern, |
src/arch/wasm/CodeGen.zig+3-3| ... | ... | @@ -952,7 +952,7 @@ pub const DeclGen = struct { |
| 952 | 952 | _ = func_payload; |
| 953 | 953 | return self.fail("TODO wasm backend genDecl function pointer", .{}); |
| 954 | 954 | } else if (decl.val.castTag(.extern_fn)) |extern_fn| { |
| 955 | const ext_decl = extern_fn.data; | |
| 955 | const ext_decl = extern_fn.data.owner_decl; | |
| 956 | 956 | var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target()); |
| 957 | 957 | func_type.deinit(self.gpa); |
| 958 | 958 | ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type); |
| ... | ... | @@ -978,7 +978,7 @@ pub const DeclGen = struct { |
| 978 | 978 | switch (ty.zigTypeTag()) { |
| 979 | 979 | .Fn => { |
| 980 | 980 | const fn_decl = switch (val.tag()) { |
| 981 | .extern_fn => val.castTag(.extern_fn).?.data, | |
| 981 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, | |
| 982 | 982 | .function => val.castTag(.function).?.data.owner_decl, |
| 983 | 983 | else => unreachable, |
| 984 | 984 | }; |
| ... | ... | @@ -1776,7 +1776,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue { |
| 1776 | 1776 | if (func_val.castTag(.function)) |func| { |
| 1777 | 1777 | break :blk func.data.owner_decl; |
| 1778 | 1778 | } else if (func_val.castTag(.extern_fn)) |ext_fn| { |
| 1779 | break :blk ext_fn.data; | |
| 1779 | break :blk ext_fn.data.owner_decl; | |
| 1780 | 1780 | } else if (func_val.castTag(.decl_ref)) |decl_ref| { |
| 1781 | 1781 | break :blk decl_ref.data; |
| 1782 | 1782 | } |
src/arch/x86_64/CodeGen.zig+9-2| ... | ... | @@ -2516,8 +2516,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void { |
| 2516 | 2516 | .data = undefined, |
| 2517 | 2517 | }); |
| 2518 | 2518 | } else if (func_value.castTag(.extern_fn)) |func_payload| { |
| 2519 | const decl = func_payload.data; | |
| 2520 | const n_strx = try macho_file.addExternFn(mem.sliceTo(decl.name, 0)); | |
| 2519 | const extern_fn = func_payload.data; | |
| 2520 | const decl_name = extern_fn.owner_decl.name; | |
| 2521 | if (extern_fn.lib_name) |lib_name| { | |
| 2522 | log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{ | |
| 2523 | decl_name, | |
| 2524 | lib_name, | |
| 2525 | }); | |
| 2526 | } | |
| 2527 | const n_strx = try macho_file.addExternFn(mem.sliceTo(decl_name, 0)); | |
| 2521 | 2528 | _ = try self.addInst(.{ |
| 2522 | 2529 | .tag = .call_extern, |
| 2523 | 2530 | .ops = undefined, |
src/codegen/c.zig+4-4| ... | ... | @@ -542,8 +542,8 @@ pub const DeclGen = struct { |
| 542 | 542 | try dg.renderDeclName(func.owner_decl, writer); |
| 543 | 543 | }, |
| 544 | 544 | .extern_fn => { |
| 545 | const decl = val.castTag(.extern_fn).?.data; | |
| 546 | try dg.renderDeclName(decl, writer); | |
| 545 | const extern_fn = val.castTag(.extern_fn).?.data; | |
| 546 | try dg.renderDeclName(extern_fn.owner_decl, writer); | |
| 547 | 547 | }, |
| 548 | 548 | .int_u64, .one => { |
| 549 | 549 | try writer.writeAll("(("); |
| ... | ... | @@ -681,7 +681,7 @@ pub const DeclGen = struct { |
| 681 | 681 | return dg.renderDeclValue(writer, ty, val, decl); |
| 682 | 682 | }, |
| 683 | 683 | .extern_fn => { |
| 684 | const decl = val.castTag(.extern_fn).?.data; | |
| 684 | const decl = val.castTag(.extern_fn).?.data.owner_decl; | |
| 685 | 685 | return dg.renderDeclValue(writer, ty, val, decl); |
| 686 | 686 | }, |
| 687 | 687 | else => unreachable, |
| ... | ... | @@ -2442,7 +2442,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue { |
| 2442 | 2442 | const fn_decl = fn_decl: { |
| 2443 | 2443 | const callee_val = f.air.value(pl_op.operand) orelse break :known; |
| 2444 | 2444 | break :fn_decl switch (callee_val.tag()) { |
| 2445 | .extern_fn => callee_val.castTag(.extern_fn).?.data, | |
| 2445 | .extern_fn => callee_val.castTag(.extern_fn).?.data.owner_decl, | |
| 2446 | 2446 | .function => callee_val.castTag(.function).?.data.owner_decl, |
| 2447 | 2447 | .decl_ref => callee_val.castTag(.decl_ref).?.data, |
| 2448 | 2448 | else => break :known, |
src/codegen/llvm.zig+2-2| ... | ... | @@ -622,7 +622,7 @@ pub const DeclGen = struct { |
| 622 | 622 | _ = func_payload; |
| 623 | 623 | @panic("TODO llvm backend genDecl function pointer"); |
| 624 | 624 | } else if (decl.val.castTag(.extern_fn)) |extern_fn| { |
| 625 | _ = try dg.resolveLlvmFunction(extern_fn.data); | |
| 625 | _ = try dg.resolveLlvmFunction(extern_fn.data.owner_decl); | |
| 626 | 626 | } else { |
| 627 | 627 | const target = dg.module.getTarget(); |
| 628 | 628 | const global = try dg.resolveGlobalDecl(decl); |
| ... | ... | @@ -1410,7 +1410,7 @@ pub const DeclGen = struct { |
| 1410 | 1410 | }, |
| 1411 | 1411 | .Fn => { |
| 1412 | 1412 | const fn_decl = switch (tv.val.tag()) { |
| 1413 | .extern_fn => tv.val.castTag(.extern_fn).?.data, | |
| 1413 | .extern_fn => tv.val.castTag(.extern_fn).?.data.owner_decl, | |
| 1414 | 1414 | .function => tv.val.castTag(.function).?.data.owner_decl, |
| 1415 | 1415 | else => unreachable, |
| 1416 | 1416 | }; |
src/value.zig+13-6| ... | ... | @@ -262,9 +262,9 @@ pub const Value = extern union { |
| 262 | 262 | .int_big_negative, |
| 263 | 263 | => Payload.BigInt, |
| 264 | 264 | |
| 265 | .extern_fn, | |
| 266 | .decl_ref, | |
| 267 | => Payload.Decl, | |
| 265 | .extern_fn => Payload.ExternFn, | |
| 266 | ||
| 267 | .decl_ref => Payload.Decl, | |
| 268 | 268 | |
| 269 | 269 | .repeated, |
| 270 | 270 | .eu_payload, |
| ... | ... | @@ -475,7 +475,7 @@ pub const Value = extern union { |
| 475 | 475 | return Value{ .ptr_otherwise = &new_payload.base }; |
| 476 | 476 | }, |
| 477 | 477 | .function => return self.copyPayloadShallow(arena, Payload.Function), |
| 478 | .extern_fn => return self.copyPayloadShallow(arena, Payload.Decl), | |
| 478 | .extern_fn => return self.copyPayloadShallow(arena, Payload.ExternFn), | |
| 479 | 479 | .variable => return self.copyPayloadShallow(arena, Payload.Variable), |
| 480 | 480 | .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl), |
| 481 | 481 | .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut), |
| ... | ... | @@ -1803,9 +1803,10 @@ pub const Value = extern union { |
| 1803 | 1803 | pub fn pointerDecl(val: Value) ?*Module.Decl { |
| 1804 | 1804 | return switch (val.tag()) { |
| 1805 | 1805 | .decl_ref_mut => val.castTag(.decl_ref_mut).?.data.decl, |
| 1806 | .extern_fn, .decl_ref => val.cast(Payload.Decl).?.data, | |
| 1806 | .extern_fn => val.castTag(.extern_fn).?.data.owner_decl, | |
| 1807 | 1807 | .function => val.castTag(.function).?.data.owner_decl, |
| 1808 | 1808 | .variable => val.castTag(.variable).?.data.owner_decl, |
| 1809 | .decl_ref => val.cast(Payload.Decl).?.data, | |
| 1809 | 1810 | else => null, |
| 1810 | 1811 | }; |
| 1811 | 1812 | } |
| ... | ... | @@ -1872,9 +1873,10 @@ pub const Value = extern union { |
| 1872 | 1873 | pub fn markReferencedDeclsAlive(val: Value) void { |
| 1873 | 1874 | switch (val.tag()) { |
| 1874 | 1875 | .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.markAlive(), |
| 1875 | .extern_fn, .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(), | |
| 1876 | .extern_fn => return val.castTag(.extern_fn).?.data.owner_decl.markAlive(), | |
| 1876 | 1877 | .function => return val.castTag(.function).?.data.owner_decl.markAlive(), |
| 1877 | 1878 | .variable => return val.castTag(.variable).?.data.owner_decl.markAlive(), |
| 1879 | .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(), | |
| 1878 | 1880 | |
| 1879 | 1881 | .repeated, |
| 1880 | 1882 | .eu_payload, |
| ... | ... | @@ -3148,6 +3150,11 @@ pub const Value = extern union { |
| 3148 | 3150 | data: *Module.Fn, |
| 3149 | 3151 | }; |
| 3150 | 3152 | |
| 3153 | pub const ExternFn = struct { | |
| 3154 | base: Payload, | |
| 3155 | data: *Module.ExternFn, | |
| 3156 | }; | |
| 3157 | ||
| 3151 | 3158 | pub const Decl = struct { |
| 3152 | 3159 | base: Payload, |
| 3153 | 3160 | data: *Module.Decl, |