authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-27 15:20:13-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-27 15:20:13-04:00
log1c85b0acbb5148dec7ff671e767354f3df5c6b83
tree29edfb52b0885c647ad4f72a12e13683d513e81b
parent772636ed0d4a2051955197999c9ddf2906384806
parent4bc88dd11641a664d80b00ad784bafc6da776697
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17735 from ziglang/export-anon

link: support exporting constant values without a Decl

13 files changed, 425 insertions(+), 233 deletions(-)

src/Module.zig+110-69
......@@ -70,6 +70,8 @@ local_zir_cache: Compilation.Directory,
7070/// The Export memory is owned by the `export_owners` table; the slice itself
7171/// is owned by this table. The slice is guaranteed to not be empty.
7272decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
73/// Same as `decl_exports` but for exported constant values.
74value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(*Export)) = .{},
7375/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
7476/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
7577/// is performing the export of another Decl.
......@@ -244,6 +246,13 @@ pub const GlobalEmitH = struct {
244246
245247pub const ErrorInt = u32;
246248
249pub const Exported = union(enum) {
250 /// The Decl being exported. Note this is *not* the Decl performing the export.
251 decl_index: Decl.Index,
252 /// Constant value being exported.
253 value: InternPool.Index,
254};
255
247256pub const Export = struct {
248257 opts: Options,
249258 src: LazySrcLoc,
......@@ -252,8 +261,7 @@ pub const Export = struct {
252261 /// The Decl containing the export statement. Inline function calls
253262 /// may cause this to be different from the owner_decl.
254263 src_decl: Decl.Index,
255 /// The Decl being exported. Note this is *not* the Decl performing the export.
256 exported_decl: Decl.Index,
264 exported: Exported,
257265 status: enum {
258266 in_progress,
259267 failed,
......@@ -2575,6 +2583,11 @@ pub fn deinit(mod: *Module) void {
25752583 }
25762584 mod.decl_exports.deinit(gpa);
25772585
2586 for (mod.value_exports.values()) |*export_list| {
2587 export_list.deinit(gpa);
2588 }
2589 mod.value_exports.deinit(gpa);
2590
25782591 for (mod.export_owners.values()) |*value| {
25792592 freeExportList(gpa, value);
25802593 }
......@@ -4620,36 +4633,49 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void
46204633 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
46214634
46224635 for (export_owners.items) |exp| {
4623 if (mod.decl_exports.getPtr(exp.exported_decl)) |value_ptr| {
4624 // Remove exports with owner_decl matching the regenerating decl.
4625 const list = value_ptr.items;
4626 var i: usize = 0;
4627 var new_len = list.len;
4628 while (i < new_len) {
4629 if (list[i].owner_decl == decl_index) {
4630 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
4631 new_len -= 1;
4632 } else {
4633 i += 1;
4636 switch (exp.exported) {
4637 .decl_index => |exported_decl_index| {
4638 if (mod.decl_exports.getPtr(exported_decl_index)) |export_list| {
4639 // Remove exports with owner_decl matching the regenerating decl.
4640 const list = export_list.items;
4641 var i: usize = 0;
4642 var new_len = list.len;
4643 while (i < new_len) {
4644 if (list[i].owner_decl == decl_index) {
4645 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
4646 new_len -= 1;
4647 } else {
4648 i += 1;
4649 }
4650 }
4651 export_list.shrinkAndFree(mod.gpa, new_len);
4652 if (new_len == 0) {
4653 assert(mod.decl_exports.swapRemove(exported_decl_index));
4654 }
46344655 }
4635 }
4636 value_ptr.shrinkAndFree(mod.gpa, new_len);
4637 if (new_len == 0) {
4638 assert(mod.decl_exports.swapRemove(exp.exported_decl));
4639 }
4640 }
4641 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
4642 elf.deleteDeclExport(decl_index, exp.opts.name);
4643 }
4644 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {
4645 try macho.deleteDeclExport(decl_index, exp.opts.name);
4646 }
4647 if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {
4648 wasm.deleteDeclExport(decl_index);
4649 }
4650 if (mod.comp.bin_file.cast(link.File.Coff)) |coff| {
4651 coff.deleteDeclExport(decl_index, exp.opts.name);
4656 },
4657 .value => |value| {
4658 if (mod.value_exports.getPtr(value)) |export_list| {
4659 // Remove exports with owner_decl matching the regenerating decl.
4660 const list = export_list.items;
4661 var i: usize = 0;
4662 var new_len = list.len;
4663 while (i < new_len) {
4664 if (list[i].owner_decl == decl_index) {
4665 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
4666 new_len -= 1;
4667 } else {
4668 i += 1;
4669 }
4670 }
4671 export_list.shrinkAndFree(mod.gpa, new_len);
4672 if (new_len == 0) {
4673 assert(mod.value_exports.swapRemove(value));
4674 }
4675 }
4676 },
46524677 }
4678 try mod.comp.bin_file.deleteDeclExport(decl_index, exp.opts.name);
46534679 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
46544680 failed_kv.value.destroy(mod.gpa);
46554681 }
......@@ -5503,48 +5529,63 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
55035529/// reporting compile errors. In this function we emit exported symbol collision
55045530/// errors and communicate exported symbols to the linker backend.
55055531pub fn processExports(mod: *Module) !void {
5506 const gpa = mod.gpa;
55075532 // Map symbol names to `Export` for name collision detection.
5508 var symbol_exports: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export) = .{};
5509 defer symbol_exports.deinit(gpa);
5510
5511 var it = mod.decl_exports.iterator();
5512 while (it.next()) |entry| {
5513 const exported_decl = entry.key_ptr.*;
5514 const exports = entry.value_ptr.items;
5515 for (exports) |new_export| {
5516 const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
5517 if (gop.found_existing) {
5518 new_export.status = .failed_retryable;
5519 try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
5520 const src_loc = new_export.getSrcLoc(mod);
5521 const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{
5522 new_export.opts.name.fmt(&mod.intern_pool),
5523 });
5524 errdefer msg.destroy(gpa);
5525 const other_export = gop.value_ptr.*;
5526 const other_src_loc = other_export.getSrcLoc(mod);
5527 try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
5528 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
5529 new_export.status = .failed;
5530 } else {
5531 gop.value_ptr.* = new_export;
5532 }
5533 var symbol_exports: SymbolExports = .{};
5534 defer symbol_exports.deinit(mod.gpa);
5535
5536 for (mod.decl_exports.keys(), mod.decl_exports.values()) |exported_decl, exports_list| {
5537 const exported: Exported = .{ .decl_index = exported_decl };
5538 try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
5539 }
5540
5541 for (mod.value_exports.keys(), mod.value_exports.values()) |exported_value, exports_list| {
5542 const exported: Exported = .{ .value = exported_value };
5543 try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
5544 }
5545}
5546
5547const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export);
5548
5549fn processExportsInner(
5550 mod: *Module,
5551 symbol_exports: *SymbolExports,
5552 exported: Exported,
5553 exports: []const *Export,
5554) error{OutOfMemory}!void {
5555 const gpa = mod.gpa;
5556
5557 for (exports) |new_export| {
5558 const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
5559 if (gop.found_existing) {
5560 new_export.status = .failed_retryable;
5561 try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
5562 const src_loc = new_export.getSrcLoc(mod);
5563 const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{
5564 new_export.opts.name.fmt(&mod.intern_pool),
5565 });
5566 errdefer msg.destroy(gpa);
5567 const other_export = gop.value_ptr.*;
5568 const other_src_loc = other_export.getSrcLoc(mod);
5569 try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
5570 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
5571 new_export.status = .failed;
5572 } else {
5573 gop.value_ptr.* = new_export;
55335574 }
5534 mod.comp.bin_file.updateDeclExports(mod, exported_decl, exports) catch |err| switch (err) {
5535 error.OutOfMemory => return error.OutOfMemory,
5536 else => {
5537 const new_export = exports[0];
5538 new_export.status = .failed_retryable;
5539 try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
5540 const src_loc = new_export.getSrcLoc(mod);
5541 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
5542 @errorName(err),
5543 });
5544 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
5545 },
5546 };
55475575 }
5576 mod.comp.bin_file.updateExports(mod, exported, exports) catch |err| switch (err) {
5577 error.OutOfMemory => return error.OutOfMemory,
5578 else => {
5579 const new_export = exports[0];
5580 new_export.status = .failed_retryable;
5581 try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
5582 const src_loc = new_export.getSrcLoc(mod);
5583 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
5584 @errorName(err),
5585 });
5586 mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
5587 },
5588 };
55485589}
55495590
55505591pub fn populateTestFunctions(
src/Sema.zig+48-38
......@@ -6026,6 +6026,7 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
60266026 const tracy = trace(@src());
60276027 defer tracy.end();
60286028
6029 const mod = sema.mod;
60296030 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
60306031 const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
60316032 const src = inst_data.src();
......@@ -6034,19 +6035,22 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
60346035 const operand = try sema.resolveInstConst(block, operand_src, extra.operand, .{
60356036 .needed_comptime_reason = "export target must be comptime-known",
60366037 });
6037 const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) {
6038 error.NeededSourceLocation => {
6039 _ = try sema.resolveExportOptions(block, options_src, extra.options);
6040 unreachable;
6041 },
6042 else => |e| return e,
6043 };
6044 const decl_index = if (operand.val.getFunction(sema.mod)) |function| function.owner_decl else blk: {
6045 var anon_decl = try block.startAnonDecl(); // TODO: export value without Decl
6046 defer anon_decl.deinit();
6047 break :blk try anon_decl.finish(operand.ty, operand.val, .none);
6048 };
6049 try sema.analyzeExport(block, src, options, decl_index);
6038 const options = try sema.resolveExportOptions(block, options_src, extra.options);
6039 if (options.linkage == .Internal)
6040 return;
6041 if (operand.val.getFunction(mod)) |function| {
6042 const decl_index = function.owner_decl;
6043 return sema.analyzeExport(block, src, options, decl_index);
6044 }
6045
6046 try addExport(mod, .{
6047 .opts = options,
6048 .src = src,
6049 .owner_decl = sema.owner_decl_index,
6050 .src_decl = block.src_decl,
6051 .exported = .{ .value = operand.val.toIntern() },
6052 .status = .in_progress,
6053 });
60506054}
60516055
60526056pub fn analyzeExport(
......@@ -6056,12 +6060,11 @@ pub fn analyzeExport(
60566060 options: Module.Export.Options,
60576061 exported_decl_index: Decl.Index,
60586062) !void {
6059 const Export = Module.Export;
6063 const gpa = sema.gpa;
60606064 const mod = sema.mod;
60616065
6062 if (options.linkage == .Internal) {
6066 if (options.linkage == .Internal)
60636067 return;
6064 }
60656068
60666069 try mod.ensureDeclAnalyzed(exported_decl_index);
60676070 const exported_decl = mod.declPtr(exported_decl_index);
......@@ -6069,7 +6072,7 @@ pub fn analyzeExport(
60696072 if (!try sema.validateExternType(exported_decl.ty, .other)) {
60706073 const msg = msg: {
60716074 const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(mod)});
6072 errdefer msg.destroy(sema.gpa);
6075 errdefer msg.destroy(gpa);
60736076
60746077 const src_decl = mod.declPtr(block.src_decl);
60756078 try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other);
......@@ -6089,38 +6092,45 @@ pub fn analyzeExport(
60896092 try mod.markDeclAlive(exported_decl);
60906093 try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
60916094
6092 const gpa = sema.gpa;
6095 try addExport(mod, .{
6096 .opts = options,
6097 .src = src,
6098 .owner_decl = sema.owner_decl_index,
6099 .src_decl = block.src_decl,
6100 .exported = .{ .decl_index = exported_decl_index },
6101 .status = .in_progress,
6102 });
6103}
6104
6105fn addExport(mod: *Module, export_init: Module.Export) error{OutOfMemory}!void {
6106 const gpa = mod.gpa;
60936107
60946108 try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
6109 try mod.value_exports.ensureUnusedCapacity(gpa, 1);
60956110 try mod.export_owners.ensureUnusedCapacity(gpa, 1);
60966111
6097 const new_export = try gpa.create(Export);
6112 const new_export = try gpa.create(Module.Export);
60986113 errdefer gpa.destroy(new_export);
60996114
6100 new_export.* = .{
6101 .opts = options,
6102 .src = src,
6103 .owner_decl = sema.owner_decl_index,
6104 .src_decl = block.src_decl,
6105 .exported_decl = exported_decl_index,
6106 .status = .in_progress,
6107 };
6115 new_export.* = export_init;
61086116
6109 // Add to export_owners table.
6110 const eo_gop = mod.export_owners.getOrPutAssumeCapacity(sema.owner_decl_index);
6111 if (!eo_gop.found_existing) {
6112 eo_gop.value_ptr.* = .{};
6113 }
6117 const eo_gop = mod.export_owners.getOrPutAssumeCapacity(export_init.owner_decl);
6118 if (!eo_gop.found_existing) eo_gop.value_ptr.* = .{};
61146119 try eo_gop.value_ptr.append(gpa, new_export);
61156120 errdefer _ = eo_gop.value_ptr.pop();
61166121
6117 // Add to exported_decl table.
6118 const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl_index);
6119 if (!de_gop.found_existing) {
6120 de_gop.value_ptr.* = .{};
6122 switch (export_init.exported) {
6123 .decl_index => |decl_index| {
6124 const de_gop = mod.decl_exports.getOrPutAssumeCapacity(decl_index);
6125 if (!de_gop.found_existing) de_gop.value_ptr.* = .{};
6126 try de_gop.value_ptr.append(gpa, new_export);
6127 },
6128 .value => |value| {
6129 const ve_gop = mod.value_exports.getOrPutAssumeCapacity(value);
6130 if (!ve_gop.found_existing) ve_gop.value_ptr.* = .{};
6131 try ve_gop.value_ptr.append(gpa, new_export);
6132 },
61216133 }
6122 try de_gop.value_ptr.append(gpa, new_export);
6123 errdefer _ = de_gop.value_ptr.pop();
61246134}
61256135
61266136fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
src/codegen/llvm.zig+141-73
......@@ -1144,26 +1144,40 @@ pub const Object = struct {
11441144
11451145 for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
11461146 const global = object.decl_map.get(decl_index) orelse continue;
1147 const global_base = global.toConst().getBase(&object.builder);
1148 for (export_list.items) |exp| {
1149 // Detect if the LLVM global has already been created as an extern. In such
1150 // case, we need to replace all uses of it with this exported global.
1151 const exp_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(exp.opts.name)) orelse continue;
1152
1153 const other_global = object.builder.getGlobal(exp_name) orelse continue;
1154 if (other_global.toConst().getBase(&object.builder) == global_base) continue;
1155
1156 try global.takeName(other_global, &object.builder);
1157 try other_global.replace(global, &object.builder);
1158 // Problem: now we need to replace in the decl_map that
1159 // the extern decl index points to this new global. However we don't
1160 // know the decl index.
1161 // Even if we did, a future incremental update to the extern would then
1162 // treat the LLVM global as an extern rather than an export, so it would
1163 // need a way to check that.
1164 // This is a TODO that needs to be solved when making
1165 // the LLVM backend support incremental compilation.
1166 }
1147 try resolveGlobalCollisions(object, global, export_list.items);
1148 }
1149
1150 for (mod.value_exports.keys(), mod.value_exports.values()) |val, export_list| {
1151 const global = object.anon_decl_map.get(val) orelse continue;
1152 try resolveGlobalCollisions(object, global, export_list.items);
1153 }
1154 }
1155
1156 fn resolveGlobalCollisions(
1157 object: *Object,
1158 global: Builder.Global.Index,
1159 export_list: []const *Module.Export,
1160 ) !void {
1161 const mod = object.module;
1162 const global_base = global.toConst().getBase(&object.builder);
1163 for (export_list) |exp| {
1164 // Detect if the LLVM global has already been created as an extern. In such
1165 // case, we need to replace all uses of it with this exported global.
1166 const exp_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(exp.opts.name)) orelse continue;
1167
1168 const other_global = object.builder.getGlobal(exp_name) orelse continue;
1169 if (other_global.toConst().getBase(&object.builder) == global_base) continue;
1170
1171 try global.takeName(other_global, &object.builder);
1172 try other_global.replace(global, &object.builder);
1173 // Problem: now we need to replace in the decl_map that
1174 // the extern decl index points to this new global. However we don't
1175 // know the decl index.
1176 // Even if we did, a future incremental update to the extern would then
1177 // treat the LLVM global as an extern rather than an export, so it would
1178 // need a way to check that.
1179 // This is a TODO that needs to be solved when making
1180 // the LLVM backend support incremental compilation.
11671181 }
11681182 }
11691183
......@@ -1642,7 +1656,7 @@ pub const Object = struct {
16421656
16431657 try fg.wip.finish();
16441658
1645 try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
1659 try o.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
16461660 }
16471661
16481662 pub fn updateDecl(self: *Object, module: *Module, decl_index: Module.Decl.Index) !void {
......@@ -1662,18 +1676,22 @@ pub const Object = struct {
16621676 },
16631677 else => |e| return e,
16641678 };
1665 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
1679 try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
16661680 }
16671681
1668 pub fn updateDeclExports(
1682 pub fn updateExports(
16691683 self: *Object,
16701684 mod: *Module,
1671 decl_index: Module.Decl.Index,
1685 exported: Module.Exported,
16721686 exports: []const *Module.Export,
1673 ) !void {
1687 ) link.File.UpdateExportsError!void {
1688 const decl_index = switch (exported) {
1689 .decl_index => |i| i,
1690 .value => |val| return updateExportedValue(self, mod, val, exports),
1691 };
16741692 const gpa = mod.gpa;
16751693 // If the module does not already have the function, we ignore this function call
1676 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
1694 // because we call `updateExports` at the end of `updateFunc` and `updateDecl`.
16771695 const global_index = self.decl_map.get(decl_index) orelse return;
16781696 const decl = mod.declPtr(decl_index);
16791697 if (decl.isExtern(mod)) {
......@@ -1733,8 +1751,7 @@ pub const Object = struct {
17331751 mod.intern_pool.stringToSlice(exports[0].opts.name),
17341752 );
17351753 try global_index.rename(main_exp_name, &self.builder);
1736 global_index.setUnnamedAddr(.default, &self.builder);
1737 if (mod.wantDllExports()) global_index.setDllStorageClass(.dllexport, &self.builder);
1754
17381755 if (self.di_map.get(decl)) |di_node| {
17391756 const main_exp_name_slice = main_exp_name.slice(&self.builder).?;
17401757 if (try decl.isFunction(mod)) {
......@@ -1755,55 +1772,12 @@ pub const Object = struct {
17551772 di_global.replaceLinkageName(linkage_name);
17561773 }
17571774 }
1758 global_index.setLinkage(switch (exports[0].opts.linkage) {
1759 .Internal => unreachable,
1760 .Strong => .external,
1761 .Weak => .weak_odr,
1762 .LinkOnce => .linkonce_odr,
1763 }, &self.builder);
1764 global_index.setVisibility(switch (exports[0].opts.visibility) {
1765 .default => .default,
1766 .hidden => .hidden,
1767 .protected => .protected,
1768 }, &self.builder);
1769 if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section|
1770 switch (global_index.ptrConst(&self.builder).kind) {
1771 inline .variable, .function => |impl_index| impl_index.setSection(
1772 try self.builder.string(section),
1773 &self.builder,
1774 ),
1775 .alias, .replaced => unreachable,
1776 };
1775
17771776 if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal)
17781777 global_index.ptrConst(&self.builder).kind
17791778 .variable.setThreadLocal(.generaldynamic, &self.builder);
17801779
1781 // If a Decl is exported more than one time (which is rare),
1782 // we add aliases for all but the first export.
1783 // TODO LLVM C API does not support deleting aliases.
1784 // The planned solution to this is https://github.com/ziglang/zig/issues/13265
1785 // Until then we iterate over existing aliases and make them point
1786 // to the correct decl, or otherwise add a new alias. Old aliases are leaked.
1787 for (exports[1..]) |exp| {
1788 const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exp.opts.name));
1789 if (self.builder.getGlobal(exp_name)) |global| {
1790 switch (global.ptrConst(&self.builder).kind) {
1791 .alias => |alias| {
1792 alias.setAliasee(global_index.toConst(), &self.builder);
1793 continue;
1794 },
1795 .variable, .function => {},
1796 .replaced => unreachable,
1797 }
1798 }
1799 const alias_index = try self.builder.addAlias(
1800 .empty,
1801 global_index.typeOf(&self.builder),
1802 .default,
1803 global_index.toConst(),
1804 );
1805 try alias_index.rename(exp_name, &self.builder);
1806 }
1780 return updateExportedGlobal(self, mod, global_index, exports);
18071781 } else {
18081782 const fqn = try self.builder.string(
18091783 mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)),
......@@ -1824,6 +1798,100 @@ pub const Object = struct {
18241798 }
18251799 }
18261800
1801 fn updateExportedValue(
1802 o: *Object,
1803 mod: *Module,
1804 exported_value: InternPool.Index,
1805 exports: []const *Module.Export,
1806 ) link.File.UpdateExportsError!void {
1807 const gpa = mod.gpa;
1808 const main_exp_name = try o.builder.string(
1809 mod.intern_pool.stringToSlice(exports[0].opts.name),
1810 );
1811 const global_index = i: {
1812 const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);
1813 if (gop.found_existing) {
1814 const global_index = gop.value_ptr.*;
1815 try global_index.rename(main_exp_name, &o.builder);
1816 break :i global_index;
1817 }
1818 const llvm_addr_space = toLlvmAddressSpace(.generic, o.target);
1819 const variable_index = try o.builder.addVariable(
1820 main_exp_name,
1821 try o.lowerType(mod.intern_pool.typeOf(exported_value).toType()),
1822 llvm_addr_space,
1823 );
1824 const global_index = variable_index.ptrConst(&o.builder).global;
1825 gop.value_ptr.* = global_index;
1826 // This line invalidates `gop`.
1827 const init_val = o.lowerValue(exported_value) catch |err| switch (err) {
1828 error.OutOfMemory => return error.OutOfMemory,
1829 error.CodegenFail => return error.AnalysisFail,
1830 };
1831 try variable_index.setInitializer(init_val, &o.builder);
1832 break :i global_index;
1833 };
1834 return updateExportedGlobal(o, mod, global_index, exports);
1835 }
1836
1837 fn updateExportedGlobal(
1838 o: *Object,
1839 mod: *Module,
1840 global_index: Builder.Global.Index,
1841 exports: []const *Module.Export,
1842 ) link.File.UpdateExportsError!void {
1843 global_index.setUnnamedAddr(.default, &o.builder);
1844 if (mod.wantDllExports()) global_index.setDllStorageClass(.dllexport, &o.builder);
1845 global_index.setLinkage(switch (exports[0].opts.linkage) {
1846 .Internal => unreachable,
1847 .Strong => .external,
1848 .Weak => .weak_odr,
1849 .LinkOnce => .linkonce_odr,
1850 }, &o.builder);
1851 global_index.setVisibility(switch (exports[0].opts.visibility) {
1852 .default => .default,
1853 .hidden => .hidden,
1854 .protected => .protected,
1855 }, &o.builder);
1856 if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section|
1857 switch (global_index.ptrConst(&o.builder).kind) {
1858 .variable => |impl_index| impl_index.setSection(
1859 try o.builder.string(section),
1860 &o.builder,
1861 ),
1862 .function => unreachable,
1863 .alias => unreachable,
1864 .replaced => unreachable,
1865 };
1866
1867 // If a Decl is exported more than one time (which is rare),
1868 // we add aliases for all but the first export.
1869 // TODO LLVM C API does not support deleting aliases.
1870 // The planned solution to this is https://github.com/ziglang/zig/issues/13265
1871 // Until then we iterate over existing aliases and make them point
1872 // to the correct decl, or otherwise add a new alias. Old aliases are leaked.
1873 for (exports[1..]) |exp| {
1874 const exp_name = try o.builder.string(mod.intern_pool.stringToSlice(exp.opts.name));
1875 if (o.builder.getGlobal(exp_name)) |global| {
1876 switch (global.ptrConst(&o.builder).kind) {
1877 .alias => |alias| {
1878 alias.setAliasee(global_index.toConst(), &o.builder);
1879 continue;
1880 },
1881 .variable, .function => {},
1882 .replaced => unreachable,
1883 }
1884 }
1885 const alias_index = try o.builder.addAlias(
1886 .empty,
1887 global_index.typeOf(&o.builder),
1888 .default,
1889 global_index.toConst(),
1890 );
1891 try alias_index.rename(exp_name, &o.builder);
1892 }
1893 }
1894
18271895 pub fn freeDecl(self: *Object, decl_index: Module.Decl.Index) void {
18281896 const global = self.decl_map.get(decl_index) orelse return;
18291897 global.delete(&self.builder);
src/link.zig+32-17
......@@ -587,7 +587,7 @@ pub const File = struct {
587587 }
588588 }
589589
590 /// May be called before or after updateDeclExports for any given Decl.
590 /// May be called before or after updateExports for any given Decl.
591591 pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
592592 const decl = module.declPtr(decl_index);
593593 assert(decl.has_tv);
......@@ -609,7 +609,7 @@ pub const File = struct {
609609 }
610610 }
611611
612 /// May be called before or after updateDeclExports for any given Decl.
612 /// May be called before or after updateExports for any given Decl.
613613 pub fn updateFunc(base: *File, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) UpdateDeclError!void {
614614 if (build_options.only_c) {
615615 assert(base.tag == .c);
......@@ -882,33 +882,34 @@ pub const File = struct {
882882 }
883883 }
884884
885 pub const UpdateDeclExportsError = error{
885 pub const UpdateExportsError = error{
886886 OutOfMemory,
887887 AnalysisFail,
888888 };
889889
890 /// This is called for every exported thing. `exports` is almost always
891 /// a list of size 1, meaning that `exported` is exported once. However, it is possible
892 /// to export the same thing with multiple different symbol names (aliases).
890893 /// May be called before or after updateDecl for any given Decl.
891 pub fn updateDeclExports(
894 pub fn updateExports(
892895 base: *File,
893896 module: *Module,
894 decl_index: Module.Decl.Index,
897 exported: Module.Exported,
895898 exports: []const *Module.Export,
896 ) UpdateDeclExportsError!void {
897 const decl = module.declPtr(decl_index);
898 assert(decl.has_tv);
899 ) UpdateExportsError!void {
899900 if (build_options.only_c) {
900901 assert(base.tag == .c);
901 return @fieldParentPtr(C, "base", base).updateDeclExports(module, decl_index, exports);
902 return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports);
902903 }
903904 switch (base.tag) {
904 .coff => return @fieldParentPtr(Coff, "base", base).updateDeclExports(module, decl_index, exports),
905 .elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl_index, exports),
906 .macho => return @fieldParentPtr(MachO, "base", base).updateDeclExports(module, decl_index, exports),
907 .c => return @fieldParentPtr(C, "base", base).updateDeclExports(module, decl_index, exports),
908 .wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclExports(module, decl_index, exports),
909 .spirv => return @fieldParentPtr(SpirV, "base", base).updateDeclExports(module, decl_index, exports),
910 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclExports(module, decl_index, exports),
911 .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateDeclExports(module, decl_index, exports),
905 .coff => return @fieldParentPtr(Coff, "base", base).updateExports(module, exported, exports),
906 .elf => return @fieldParentPtr(Elf, "base", base).updateExports(module, exported, exports),
907 .macho => return @fieldParentPtr(MachO, "base", base).updateExports(module, exported, exports),
908 .c => return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports),
909 .wasm => return @fieldParentPtr(Wasm, "base", base).updateExports(module, exported, exports),
910 .spirv => return @fieldParentPtr(SpirV, "base", base).updateExports(module, exported, exports),
911 .plan9 => return @fieldParentPtr(Plan9, "base", base).updateExports(module, exported, exports),
912 .nvptx => return @fieldParentPtr(NvPtx, "base", base).updateExports(module, exported, exports),
912913 }
913914 }
914915
......@@ -968,6 +969,20 @@ pub const File = struct {
968969 }
969970 }
970971
972 pub fn deleteDeclExport(base: *File, decl_index: Module.Decl.Index, name: InternPool.NullTerminatedString) !void {
973 if (build_options.only_c) unreachable;
974 switch (base.tag) {
975 .coff => return @fieldParentPtr(Coff, "base", base).deleteDeclExport(decl_index, name),
976 .elf => return @fieldParentPtr(Elf, "base", base).deleteDeclExport(decl_index, name),
977 .macho => return @fieldParentPtr(MachO, "base", base).deleteDeclExport(decl_index, name),
978 .plan9 => {},
979 .c => {},
980 .wasm => return @fieldParentPtr(Wasm, "base", base).deleteDeclExport(decl_index),
981 .spirv => {},
982 .nvptx => {},
983 }
984 }
985
971986 /// This function is called by the frontend before flush(). It communicates that
972987 /// `options.bin_file.emit` directory needs to be renamed from
973988 /// `[zig-cache]/tmp/[random]` to `[zig-cache]/o/[digest]`.
src/link/C.zig+3-3
......@@ -753,14 +753,14 @@ pub fn flushEmitH(module: *Module) !void {
753753 try file.pwritevAll(all_buffers.items, 0);
754754}
755755
756pub fn updateDeclExports(
756pub fn updateExports(
757757 self: *C,
758758 module: *Module,
759 decl_index: Module.Decl.Index,
759 exported: Module.Exported,
760760 exports: []const *Module.Export,
761761) !void {
762762 _ = exports;
763 _ = decl_index;
763 _ = exported;
764764 _ = module;
765765 _ = self;
766766}
src/link/Coff.zig+18-7
......@@ -1075,7 +1075,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
10751075
10761076 // Since we updated the vaddr and the size, each corresponding export
10771077 // symbol also needs to be updated.
1078 return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
1078 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
10791079}
10801080
10811081pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {
......@@ -1195,7 +1195,7 @@ pub fn updateDecl(
11951195
11961196 // Since we updated the vaddr and the size, each corresponding export
11971197 // symbol also needs to be updated.
1198 return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
1198 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
11991199}
12001200
12011201fn updateLazySymbolAtom(
......@@ -1409,12 +1409,12 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
14091409 }
14101410}
14111411
1412pub fn updateDeclExports(
1412pub fn updateExports(
14131413 self: *Coff,
14141414 mod: *Module,
1415 decl_index: Module.Decl.Index,
1415 exported: Module.Exported,
14161416 exports: []const *Module.Export,
1417) link.File.UpdateDeclExportsError!void {
1417) link.File.UpdateExportsError!void {
14181418 if (build_options.skip_non_native and builtin.object_format != .coff) {
14191419 @panic("Attempted to compile for object format that was disabled by build configuration");
14201420 }
......@@ -1425,7 +1425,11 @@ pub fn updateDeclExports(
14251425 // Even in the case of LLVM, we need to notice certain exported symbols in order to
14261426 // detect the default subsystem.
14271427 for (exports) |exp| {
1428 const exported_decl = mod.declPtr(exp.exported_decl);
1428 const exported_decl_index = switch (exp.exported) {
1429 .decl_index => |i| i,
1430 .value => continue,
1431 };
1432 const exported_decl = mod.declPtr(exported_decl_index);
14291433 if (exported_decl.getOwnedFunction(mod) == null) continue;
14301434 const winapi_cc = switch (self.base.options.target.cpu.arch) {
14311435 .x86 => std.builtin.CallingConvention.Stdcall,
......@@ -1452,12 +1456,19 @@ pub fn updateDeclExports(
14521456 }
14531457 }
14541458
1455 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
1459 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
14561460
14571461 if (self.base.options.emit == null) return;
14581462
14591463 const gpa = self.base.allocator;
14601464
1465 const decl_index = switch (exported) {
1466 .decl_index => |i| i,
1467 .value => |val| {
1468 _ = val;
1469 @panic("TODO: implement COFF linker code for exporting a constant value");
1470 },
1471 };
14611472 const decl = mod.declPtr(decl_index);
14621473 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
14631474 const atom = self.getAtom(atom_index);
src/link/Elf.zig+13-6
......@@ -3306,7 +3306,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A
33063306
33073307 // Since we updated the vaddr and the size, each corresponding export
33083308 // symbol also needs to be updated.
3309 return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
3309 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
33103310}
33113311
33123312pub fn updateDecl(
......@@ -3388,7 +3388,7 @@ pub fn updateDecl(
33883388
33893389 // Since we updated the vaddr and the size, each corresponding export
33903390 // symbol also needs to be updated.
3391 return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
3391 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
33923392}
33933393
33943394fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.Index) !void {
......@@ -3555,16 +3555,16 @@ fn lowerConst(
35553555 return .{ .ok = sym_index };
35563556}
35573557
3558pub fn updateDeclExports(
3558pub fn updateExports(
35593559 self: *Elf,
35603560 mod: *Module,
3561 decl_index: Module.Decl.Index,
3561 exported: Module.Exported,
35623562 exports: []const *Module.Export,
3563) link.File.UpdateDeclExportsError!void {
3563) link.File.UpdateExportsError!void {
35643564 if (build_options.skip_non_native and builtin.object_format != .elf) {
35653565 @panic("Attempted to compile for object format that was disabled by build configuration");
35663566 }
3567 if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
3567 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
35683568
35693569 if (self.base.options.emit == null) return;
35703570
......@@ -3573,6 +3573,13 @@ pub fn updateDeclExports(
35733573
35743574 const gpa = self.base.allocator;
35753575
3576 const decl_index = switch (exported) {
3577 .decl_index => |i| i,
3578 .value => |val| {
3579 _ = val;
3580 @panic("TODO: implement ELF linker code for exporting a constant value");
3581 },
3582 };
35763583 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
35773584 const decl = mod.declPtr(decl_index);
35783585 const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index);
src/link/MachO.zig+15-8
......@@ -1670,7 +1670,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
16701670 const global_is_weak = global_sym.sect() and (global_sym.weakDef() or global_sym.pext());
16711671
16721672 if (sym_is_strong and global_is_strong) {
1673 // TODO redo this logic with corresponding logic in updateDeclExports to avoid this
1673 // TODO redo this logic with corresponding logic in updateExports to avoid this
16741674 // ugly check.
16751675 if (self.mode == .zld) {
16761676 try self.reportSymbolCollision(global, current);
......@@ -2180,7 +2180,7 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air:
21802180
21812181 // Since we updated the vaddr and the size, each corresponding export symbol also
21822182 // needs to be updated.
2183 try self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
2183 try self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
21842184}
21852185
21862186pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
......@@ -2340,7 +2340,7 @@ pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !vo
23402340
23412341 // Since we updated the vaddr and the size, each corresponding export symbol also
23422342 // needs to be updated.
2343 try self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
2343 try self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
23442344}
23452345
23462346fn updateLazySymbolAtom(
......@@ -2529,7 +2529,7 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D
25292529 );
25302530 }
25312531
2532 try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
2532 try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
25332533
25342534 // 2. Create a TLV descriptor.
25352535 const init_atom_sym_loc = init_atom.getSymbolWithLoc();
......@@ -2670,17 +2670,17 @@ pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.De
26702670 }
26712671}
26722672
2673pub fn updateDeclExports(
2673pub fn updateExports(
26742674 self: *MachO,
26752675 mod: *Module,
2676 decl_index: Module.Decl.Index,
2676 exported: Module.Exported,
26772677 exports: []const *Module.Export,
2678) File.UpdateDeclExportsError!void {
2678) File.UpdateExportsError!void {
26792679 if (build_options.skip_non_native and builtin.object_format != .macho) {
26802680 @panic("Attempted to compile for object format that was disabled by build configuration");
26812681 }
26822682 if (self.llvm_object) |llvm_object|
2683 return llvm_object.updateDeclExports(mod, decl_index, exports);
2683 return llvm_object.updateExports(mod, exported, exports);
26842684
26852685 if (self.base.options.emit == null) return;
26862686
......@@ -2689,6 +2689,13 @@ pub fn updateDeclExports(
26892689
26902690 const gpa = self.base.allocator;
26912691
2692 const decl_index = switch (exported) {
2693 .decl_index => |i| i,
2694 .value => |val| {
2695 _ = val;
2696 @panic("TODO: implement MachO linker code for exporting a constant value");
2697 },
2698 };
26922699 const decl = mod.declPtr(decl_index);
26932700 const atom_index = try self.getOrCreateAtomForDecl(decl_index);
26942701 const atom = self.getAtom(atom_index);
src/link/NvPtx.zig+3-3
......@@ -74,16 +74,16 @@ pub fn updateDecl(self: *NvPtx, module: *Module, decl_index: Module.Decl.Index)
7474 return self.llvm_object.updateDecl(module, decl_index);
7575}
7676
77pub fn updateDeclExports(
77pub fn updateExports(
7878 self: *NvPtx,
7979 module: *Module,
80 decl_index: Module.Decl.Index,
80 exported: Module.Exported,
8181 exports: []const *Module.Export,
8282) !void {
8383 if (build_options.skip_non_native and builtin.object_format != .nvptx) {
8484 @panic("Attempted to compile for object format that was disabled by build configuration");
8585 }
86 return self.llvm_object.updateDeclExports(module, decl_index, exports);
86 return self.llvm_object.updateExports(module, exported, exports);
8787}
8888
8989pub fn freeDecl(self: *NvPtx, decl_index: Module.Decl.Index) void {
src/link/Plan9.zig+6-3
......@@ -1116,13 +1116,16 @@ pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !Atom.Index {
11161116 return atom_idx;
11171117}
11181118
1119pub fn updateDeclExports(
1119pub fn updateExports(
11201120 self: *Plan9,
11211121 module: *Module,
1122 decl_index: Module.Decl.Index,
1122 exported: Module.Exported,
11231123 exports: []const *Module.Export,
11241124) !void {
1125 _ = try self.seeDecl(decl_index);
1125 switch (exported) {
1126 .value => @panic("TODO: plan9 updateExports handling values"),
1127 .decl_index => |decl_index| _ = try self.seeDecl(decl_index),
1128 }
11261129 // we do all the things in flush
11271130 _ = module;
11281131 _ = exports;
src/link/SpirV.zig+9-2
......@@ -120,12 +120,19 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index)
120120 try self.object.updateDecl(module, decl_index);
121121}
122122
123pub fn updateDeclExports(
123pub fn updateExports(
124124 self: *SpirV,
125125 mod: *Module,
126 decl_index: Module.Decl.Index,
126 exported: Module.Exported,
127127 exports: []const *Module.Export,
128128) !void {
129 const decl_index = switch (exported) {
130 .decl_index => |i| i,
131 .value => |val| {
132 _ = val;
133 @panic("TODO: implement SpirV linker code for exporting a constant value");
134 },
135 };
129136 const decl = mod.declPtr(decl_index);
130137 if (decl.val.isFuncBody(mod) and decl.ty.fnCallingConvention(mod) == .Kernel) {
131138 const spv_decl_index = try self.object.resolveDecl(mod, decl_index);
src/link/Wasm.zig+23-4
......@@ -1786,19 +1786,26 @@ pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {
17861786 }
17871787}
17881788
1789pub fn updateDeclExports(
1789pub fn updateExports(
17901790 wasm: *Wasm,
17911791 mod: *Module,
1792 decl_index: Module.Decl.Index,
1792 exported: Module.Exported,
17931793 exports: []const *Module.Export,
17941794) !void {
17951795 if (build_options.skip_non_native and builtin.object_format != .wasm) {
17961796 @panic("Attempted to compile for object format that was disabled by build configuration");
17971797 }
1798 if (wasm.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
1798 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
17991799
18001800 if (wasm.base.options.emit == null) return;
18011801
1802 const decl_index = switch (exported) {
1803 .decl_index => |i| i,
1804 .value => |val| {
1805 _ = val;
1806 @panic("TODO: implement Wasm linker code for exporting a constant value");
1807 },
1808 };
18021809 const decl = mod.declPtr(decl_index);
18031810 const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
18041811 const atom = wasm.getAtom(atom_index);
......@@ -1816,7 +1823,19 @@ pub fn updateDeclExports(
18161823 continue;
18171824 }
18181825
1819 const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl);
1826 const exported_decl_index = switch (exp.exported) {
1827 .value => {
1828 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1829 gpa,
1830 decl.srcLoc(mod),
1831 "Unimplemented: exporting a named constant value",
1832 .{},
1833 ));
1834 continue;
1835 },
1836 .decl_index => |i| i,
1837 };
1838 const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index);
18201839 const exported_atom = wasm.getAtom(exported_atom_index);
18211840 const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name));
18221841 const sym_loc = exported_atom.symbolLoc();
test/behavior/export.zig+4
......@@ -72,6 +72,8 @@ test "exporting using field access" {
7272}
7373
7474test "exporting comptime-known value" {
75 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
76
7577 const x: u32 = 10;
7678 @export(x, .{ .name = "exporting_comptime_known_value_foo" });
7779 const S = struct {
......@@ -81,6 +83,8 @@ test "exporting comptime-known value" {
8183}
8284
8385test "exporting comptime var" {
86 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
87
8488 comptime var x: u32 = 5;
8589 @export(x, .{ .name = "exporting_comptime_var_foo" });
8690 x = 7; // modifying this now shouldn't change anything