authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-02-07 13:30:59-05:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-02-07 13:30:59-05:00
log9acf06d28ac77a52028697dc01f42fd96c230ca9
tree6c90921e6437293e84f137adce8364550f43ebb4
parent3db130ff3d8175adce610f7805a149810cf7989d
parentdb9500a31401c65327a4fd556f50d74ce75fb858
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #10803 from ziglang/decl-has-lib-name

stage2: store externs lib name as part of decl

8 files changed, 177 insertions(+), 78 deletions(-)

src/Module.zig+48-4
......@@ -501,11 +501,16 @@ pub const Decl = struct {
501501 }
502502
503503 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 }
504508 if (decl.getFunction()) |func| {
505509 func.deinit(gpa);
506510 gpa.destroy(func);
507511 }
508512 if (decl.getVariable()) |variable| {
513 variable.deinit(gpa);
509514 gpa.destroy(variable);
510515 }
511516 if (decl.value_arena) |arena_state| {
......@@ -690,6 +695,17 @@ pub const Decl = struct {
690695 return func;
691696 }
692697
698 /// If the Decl has a value and it is an extern function, returns it,
699 /// otherwise null.
700 pub fn getExternFn(decl: *const Decl) ?*ExternFn {
701 if (!decl.owns_tv) return null;
702 const extern_fn = (decl.val.castTag(.extern_fn) orelse return null).data;
703 assert(extern_fn.owner_decl == decl);
704 return extern_fn;
705 }
706
707 /// If the Decl has a value and it is a variable, returns it,
708 /// otherwise null.
693709 pub fn getVariable(decl: *Decl) ?*Var {
694710 if (!decl.owns_tv) return null;
695711 const variable = (decl.val.castTag(.variable) orelse return null).data;
......@@ -1320,9 +1336,26 @@ pub const Opaque = struct {
13201336 }
13211337};
13221338
1339/// Some extern function struct memory is owned by the Decl's TypedValue.Managed
1340/// arena allocator.
1341pub const ExternFn = struct {
1342 /// The Decl that corresponds to the function itself.
1343 owner_decl: *Decl,
1344 /// Library name if specified.
1345 /// For example `extern "c" fn write(...) usize` would have 'c' as library name.
1346 /// Allocated with Module's allocator; outlives the ZIR code.
1347 lib_name: ?[*:0]const u8,
1348
1349 pub fn deinit(extern_fn: *ExternFn, gpa: Allocator) void {
1350 if (extern_fn.lib_name) |lib_name| {
1351 gpa.free(mem.sliceTo(lib_name, 0));
1352 }
1353 }
1354};
1355
13231356/// 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`.
1357/// Extern functions do not have this data structure; they are represented by `ExternFn`
1358/// instead.
13261359pub const Fn = struct {
13271360 /// The Decl that corresponds to the function itself.
13281361 owner_decl: *Decl,
......@@ -1441,9 +1474,20 @@ pub const Var = struct {
14411474 init: Value,
14421475 owner_decl: *Decl,
14431476
1477 /// Library name if specified.
1478 /// For example `extern "c" var stderrp = ...` would have 'c' as library name.
1479 /// Allocated with Module's allocator; outlives the ZIR code.
1480 lib_name: ?[*:0]const u8,
1481
14441482 is_extern: bool,
14451483 is_mutable: bool,
14461484 is_threadlocal: bool,
1485
1486 pub fn deinit(variable: *Var, gpa: Allocator) void {
1487 if (variable.lib_name) |lib_name| {
1488 gpa.free(mem.sliceTo(lib_name, 0));
1489 }
1490 }
14471491};
14481492
14491493/// The container that structs, enums, unions, and opaques have.
......@@ -3768,8 +3812,8 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool {
37683812 }
37693813 },
37703814 .extern_fn => {
3771 const owner_decl = decl_tv.val.castTag(.extern_fn).?.data;
3772 if (decl == owner_decl) {
3815 const extern_fn = decl_tv.val.castTag(.extern_fn).?.data;
3816 if (extern_fn.owner_decl == decl) {
37733817 decl.owns_tv = true;
37743818 queue_linker_work = true;
37753819 is_extern = true;
src/Sema.zig+89-55
......@@ -5431,6 +5431,69 @@ fn zirFunc(
54315431 );
54325432}
54335433
5434/// Given a library name, examines if the library name should end up in
5435/// `link.File.Options.system_libs` table (for example, libc is always
5436/// specified via dedicated flag `link.File.Options.link_libc` instead),
5437/// and puts it there if it doesn't exist.
5438/// It also dupes the library name which can then be saved as part of the
5439/// respective `Decl` (either `ExternFn` or `Var`).
5440/// The liveness of the duped library name is tied to liveness of `Module`.
5441/// To deallocate, call `deinit` on the respective `Decl` (`ExternFn` or `Var`).
5442fn handleExternLibName(
5443 sema: *Sema,
5444 block: *Block,
5445 src_loc: LazySrcLoc,
5446 lib_name: []const u8,
5447) CompileError![:0]u8 {
5448 blk: {
5449 const mod = sema.mod;
5450 const target = mod.getTarget();
5451 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
5452 if (target_util.is_libc_lib_name(target, lib_name)) {
5453 if (!mod.comp.bin_file.options.link_libc) {
5454 return sema.fail(
5455 block,
5456 src_loc,
5457 "dependency on libc must be explicitly specified in the build command",
5458 .{},
5459 );
5460 }
5461 mod.comp.bin_file.options.link_libc = true;
5462 break :blk;
5463 }
5464 if (target_util.is_libcpp_lib_name(target, lib_name)) {
5465 if (!mod.comp.bin_file.options.link_libcpp) {
5466 return sema.fail(
5467 block,
5468 src_loc,
5469 "dependency on libc++ must be explicitly specified in the build command",
5470 .{},
5471 );
5472 }
5473 mod.comp.bin_file.options.link_libcpp = true;
5474 break :blk;
5475 }
5476 if (mem.eql(u8, lib_name, "unwind")) {
5477 mod.comp.bin_file.options.link_libunwind = true;
5478 break :blk;
5479 }
5480 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
5481 return sema.fail(
5482 block,
5483 src_loc,
5484 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
5485 .{ lib_name, lib_name },
5486 );
5487 }
5488 mod.comp.stage1AddLinkLib(lib_name) catch |err| {
5489 return sema.fail(block, src_loc, "unable to add link lib '{s}': {s}", .{
5490 lib_name, @errorName(err),
5491 });
5492 };
5493 }
5494 return sema.gpa.dupeZ(u8, lib_name);
5495}
5496
54345497fn funcCommon(
54355498 sema: *Sema,
54365499 block: *Block,
......@@ -5568,57 +5631,27 @@ fn funcCommon(
55685631 });
55695632 };
55705633
5571 if (opt_lib_name) |lib_name| blk: {
5572 const lib_name_src: LazySrcLoc = .{ .node_offset_lib_name = src_node_offset };
5573 log.debug("extern fn symbol expected in lib '{s}'", .{lib_name});
5574 if (target_util.is_libc_lib_name(target, lib_name)) {
5575 if (!mod.comp.bin_file.options.link_libc) {
5576 return sema.fail(
5577 block,
5578 lib_name_src,
5579 "dependency on libc must be explicitly specified in the build command",
5580 .{},
5581 );
5582 }
5583 mod.comp.bin_file.options.link_libc = true;
5584 break :blk;
5585 }
5586 if (target_util.is_libcpp_lib_name(target, lib_name)) {
5587 if (!mod.comp.bin_file.options.link_libcpp) {
5588 return sema.fail(
5589 block,
5590 lib_name_src,
5591 "dependency on libc++ must be explicitly specified in the build command",
5592 .{},
5593 );
5594 }
5595 mod.comp.bin_file.options.link_libcpp = true;
5596 break :blk;
5597 }
5598 if (mem.eql(u8, lib_name, "unwind")) {
5599 mod.comp.bin_file.options.link_libunwind = true;
5600 break :blk;
5601 }
5602 if (!target.isWasm() and !mod.comp.bin_file.options.pic) {
5603 return sema.fail(
5604 block,
5605 lib_name_src,
5606 "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.",
5607 .{ lib_name, lib_name },
5608 );
5609 }
5610 mod.comp.stage1AddLinkLib(lib_name) catch |err| {
5611 return sema.fail(block, lib_name_src, "unable to add link lib '{s}': {s}", .{
5612 lib_name, @errorName(err),
5613 });
5634 if (is_extern) {
5635 const new_extern_fn = try sema.gpa.create(Module.ExternFn);
5636 errdefer sema.gpa.destroy(new_extern_fn);
5637
5638 new_extern_fn.* = Module.ExternFn{
5639 .owner_decl = sema.owner_decl,
5640 .lib_name = null,
56145641 };
5615 }
56165642
5617 if (is_extern) {
5618 return sema.addConstant(
5619 fn_ty,
5620 try Value.Tag.extern_fn.create(sema.arena, sema.owner_decl),
5621 );
5643 if (opt_lib_name) |lib_name| {
5644 new_extern_fn.lib_name = try sema.handleExternLibName(block, .{
5645 .node_offset_lib_name = src_node_offset,
5646 }, lib_name);
5647 }
5648
5649 const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn);
5650 extern_fn_payload.* = .{
5651 .base = .{ .tag = .extern_fn },
5652 .data = new_extern_fn,
5653 };
5654 return sema.addConstant(fn_ty, Value.initPayload(&extern_fn_payload.base));
56225655 }
56235656
56245657 if (!has_body) {
......@@ -12444,13 +12477,8 @@ fn zirVarExtended(
1244412477
1244512478 try sema.validateVarType(block, mut_src, var_ty, small.is_extern);
1244612479
12447 if (lib_name != null) {
12448 // Look at the sema code for functions which has this logic, it just needs to
12449 // be extracted and shared by both var and func
12450 return sema.fail(block, src, "TODO: handle var with lib_name in Sema", .{});
12451 }
12452
1245312480 const new_var = try sema.gpa.create(Module.Var);
12481 errdefer sema.gpa.destroy(new_var);
1245412482
1245512483 log.debug("created variable {*} owner_decl: {*} ({s})", .{
1245612484 new_var, sema.owner_decl, sema.owner_decl.name,
......@@ -12462,7 +12490,13 @@ fn zirVarExtended(
1246212490 .is_extern = small.is_extern,
1246312491 .is_mutable = true, // TODO get rid of this unused field
1246412492 .is_threadlocal = small.is_threadlocal,
12493 .lib_name = null,
1246512494 };
12495
12496 if (lib_name) |lname| {
12497 new_var.lib_name = try sema.handleExternLibName(block, ty_src, lname);
12498 }
12499
1246612500 const result = try sema.addConstant(
1246712501 var_ty,
1246812502 try Value.Tag.variable.create(sema.arena, new_var),
src/arch/aarch64/CodeGen.zig+9-2
......@@ -1581,8 +1581,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
15811581 .data = .{ .reg = .x30 },
15821582 });
15831583 } else if (func_value.castTag(.extern_fn)) |func_payload| {
1584 const decl = func_payload.data;
1585 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl.name, 0));
1584 const extern_fn = func_payload.data;
1585 const decl_name = extern_fn.owner_decl.name;
1586 if (extern_fn.lib_name) |lib_name| {
1587 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
1588 decl_name,
1589 lib_name,
1590 });
1591 }
1592 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl_name, 0));
15861593
15871594 _ = try self.addInst(.{
15881595 .tag = .call_extern,
src/arch/wasm/CodeGen.zig+3-3
......@@ -952,7 +952,7 @@ pub const DeclGen = struct {
952952 _ = func_payload;
953953 return self.fail("TODO wasm backend genDecl function pointer", .{});
954954 } 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;
956956 var func_type = try genFunctype(self.gpa, ext_decl.ty, self.target());
957957 func_type.deinit(self.gpa);
958958 ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
......@@ -978,7 +978,7 @@ pub const DeclGen = struct {
978978 switch (ty.zigTypeTag()) {
979979 .Fn => {
980980 const fn_decl = switch (val.tag()) {
981 .extern_fn => val.castTag(.extern_fn).?.data,
981 .extern_fn => val.castTag(.extern_fn).?.data.owner_decl,
982982 .function => val.castTag(.function).?.data.owner_decl,
983983 else => unreachable,
984984 };
......@@ -1776,7 +1776,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index) InnerError!WValue {
17761776 if (func_val.castTag(.function)) |func| {
17771777 break :blk func.data.owner_decl;
17781778 } else if (func_val.castTag(.extern_fn)) |ext_fn| {
1779 break :blk ext_fn.data;
1779 break :blk ext_fn.data.owner_decl;
17801780 } else if (func_val.castTag(.decl_ref)) |decl_ref| {
17811781 break :blk decl_ref.data;
17821782 }
src/arch/x86_64/CodeGen.zig+9-2
......@@ -2566,8 +2566,15 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
25662566 .data = undefined,
25672567 });
25682568 } else if (func_value.castTag(.extern_fn)) |func_payload| {
2569 const decl = func_payload.data;
2570 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl.name, 0));
2569 const extern_fn = func_payload.data;
2570 const decl_name = extern_fn.owner_decl.name;
2571 if (extern_fn.lib_name) |lib_name| {
2572 log.debug("TODO enforce that '{s}' is expected in '{s}' library", .{
2573 decl_name,
2574 lib_name,
2575 });
2576 }
2577 const n_strx = try macho_file.addExternFn(mem.sliceTo(decl_name, 0));
25712578 _ = try self.addInst(.{
25722579 .tag = .call_extern,
25732580 .ops = undefined,
src/codegen/c.zig+4-4
......@@ -542,8 +542,8 @@ pub const DeclGen = struct {
542542 try dg.renderDeclName(func.owner_decl, writer);
543543 },
544544 .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);
547547 },
548548 .int_u64, .one => {
549549 try writer.writeAll("((");
......@@ -681,7 +681,7 @@ pub const DeclGen = struct {
681681 return dg.renderDeclValue(writer, ty, val, decl);
682682 },
683683 .extern_fn => {
684 const decl = val.castTag(.extern_fn).?.data;
684 const decl = val.castTag(.extern_fn).?.data.owner_decl;
685685 return dg.renderDeclValue(writer, ty, val, decl);
686686 },
687687 else => unreachable,
......@@ -2442,7 +2442,7 @@ fn airCall(f: *Function, inst: Air.Inst.Index) !CValue {
24422442 const fn_decl = fn_decl: {
24432443 const callee_val = f.air.value(pl_op.operand) orelse break :known;
24442444 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,
24462446 .function => callee_val.castTag(.function).?.data.owner_decl,
24472447 .decl_ref => callee_val.castTag(.decl_ref).?.data,
24482448 else => break :known,
src/codegen/llvm.zig+2-2
......@@ -622,7 +622,7 @@ pub const DeclGen = struct {
622622 _ = func_payload;
623623 @panic("TODO llvm backend genDecl function pointer");
624624 } 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);
626626 } else {
627627 const target = dg.module.getTarget();
628628 const global = try dg.resolveGlobalDecl(decl);
......@@ -1410,7 +1410,7 @@ pub const DeclGen = struct {
14101410 },
14111411 .Fn => {
14121412 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,
14141414 .function => tv.val.castTag(.function).?.data.owner_decl,
14151415 else => unreachable,
14161416 };
src/value.zig+13-6
......@@ -263,9 +263,9 @@ pub const Value = extern union {
263263 .int_big_negative,
264264 => Payload.BigInt,
265265
266 .extern_fn,
267 .decl_ref,
268 => Payload.Decl,
266 .extern_fn => Payload.ExternFn,
267
268 .decl_ref => Payload.Decl,
269269
270270 .repeated,
271271 .eu_payload,
......@@ -477,7 +477,7 @@ pub const Value = extern union {
477477 return Value{ .ptr_otherwise = &new_payload.base };
478478 },
479479 .function => return self.copyPayloadShallow(arena, Payload.Function),
480 .extern_fn => return self.copyPayloadShallow(arena, Payload.Decl),
480 .extern_fn => return self.copyPayloadShallow(arena, Payload.ExternFn),
481481 .variable => return self.copyPayloadShallow(arena, Payload.Variable),
482482 .decl_ref => return self.copyPayloadShallow(arena, Payload.Decl),
483483 .decl_ref_mut => return self.copyPayloadShallow(arena, Payload.DeclRefMut),
......@@ -1842,9 +1842,10 @@ pub const Value = extern union {
18421842 pub fn pointerDecl(val: Value) ?*Module.Decl {
18431843 return switch (val.tag()) {
18441844 .decl_ref_mut => val.castTag(.decl_ref_mut).?.data.decl,
1845 .extern_fn, .decl_ref => val.cast(Payload.Decl).?.data,
1845 .extern_fn => val.castTag(.extern_fn).?.data.owner_decl,
18461846 .function => val.castTag(.function).?.data.owner_decl,
18471847 .variable => val.castTag(.variable).?.data.owner_decl,
1848 .decl_ref => val.cast(Payload.Decl).?.data,
18481849 else => null,
18491850 };
18501851 }
......@@ -1911,9 +1912,10 @@ pub const Value = extern union {
19111912 pub fn markReferencedDeclsAlive(val: Value) void {
19121913 switch (val.tag()) {
19131914 .decl_ref_mut => return val.castTag(.decl_ref_mut).?.data.decl.markAlive(),
1914 .extern_fn, .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(),
1915 .extern_fn => return val.castTag(.extern_fn).?.data.owner_decl.markAlive(),
19151916 .function => return val.castTag(.function).?.data.owner_decl.markAlive(),
19161917 .variable => return val.castTag(.variable).?.data.owner_decl.markAlive(),
1918 .decl_ref => return val.cast(Payload.Decl).?.data.markAlive(),
19171919
19181920 .repeated,
19191921 .eu_payload,
......@@ -3301,6 +3303,11 @@ pub const Value = extern union {
33013303 data: *Module.Fn,
33023304 };
33033305
3306 pub const ExternFn = struct {
3307 base: Payload,
3308 data: *Module.ExternFn,
3309 };
3310
33043311 pub const Decl = struct {
33053312 base: Payload,
33063313 data: *Module.Decl,