mirror of
https://github.com/ziglang/zig.git
synced 2024-11-15 08:33:06 +00:00
Merge pull request #17735 from ziglang/export-anon
link: support exporting constant values without a Decl
This commit is contained in:
commit
1c85b0acbb
179
src/Module.zig
179
src/Module.zig
@ -70,6 +70,8 @@ local_zir_cache: Compilation.Directory,
|
||||
/// The Export memory is owned by the `export_owners` table; the slice itself
|
||||
/// is owned by this table. The slice is guaranteed to not be empty.
|
||||
decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
|
||||
/// Same as `decl_exports` but for exported constant values.
|
||||
value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(*Export)) = .{},
|
||||
/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
|
||||
/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
|
||||
/// is performing the export of another Decl.
|
||||
@ -244,6 +246,13 @@ pub const GlobalEmitH = struct {
|
||||
|
||||
pub const ErrorInt = u32;
|
||||
|
||||
pub const Exported = union(enum) {
|
||||
/// The Decl being exported. Note this is *not* the Decl performing the export.
|
||||
decl_index: Decl.Index,
|
||||
/// Constant value being exported.
|
||||
value: InternPool.Index,
|
||||
};
|
||||
|
||||
pub const Export = struct {
|
||||
opts: Options,
|
||||
src: LazySrcLoc,
|
||||
@ -252,8 +261,7 @@ pub const Export = struct {
|
||||
/// The Decl containing the export statement. Inline function calls
|
||||
/// may cause this to be different from the owner_decl.
|
||||
src_decl: Decl.Index,
|
||||
/// The Decl being exported. Note this is *not* the Decl performing the export.
|
||||
exported_decl: Decl.Index,
|
||||
exported: Exported,
|
||||
status: enum {
|
||||
in_progress,
|
||||
failed,
|
||||
@ -2575,6 +2583,11 @@ pub fn deinit(mod: *Module) void {
|
||||
}
|
||||
mod.decl_exports.deinit(gpa);
|
||||
|
||||
for (mod.value_exports.values()) |*export_list| {
|
||||
export_list.deinit(gpa);
|
||||
}
|
||||
mod.value_exports.deinit(gpa);
|
||||
|
||||
for (mod.export_owners.values()) |*value| {
|
||||
freeExportList(gpa, value);
|
||||
}
|
||||
@ -4620,36 +4633,49 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void
|
||||
var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
|
||||
|
||||
for (export_owners.items) |exp| {
|
||||
if (mod.decl_exports.getPtr(exp.exported_decl)) |value_ptr| {
|
||||
// Remove exports with owner_decl matching the regenerating decl.
|
||||
const list = value_ptr.items;
|
||||
var i: usize = 0;
|
||||
var new_len = list.len;
|
||||
while (i < new_len) {
|
||||
if (list[i].owner_decl == decl_index) {
|
||||
mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
|
||||
new_len -= 1;
|
||||
} else {
|
||||
i += 1;
|
||||
switch (exp.exported) {
|
||||
.decl_index => |exported_decl_index| {
|
||||
if (mod.decl_exports.getPtr(exported_decl_index)) |export_list| {
|
||||
// Remove exports with owner_decl matching the regenerating decl.
|
||||
const list = export_list.items;
|
||||
var i: usize = 0;
|
||||
var new_len = list.len;
|
||||
while (i < new_len) {
|
||||
if (list[i].owner_decl == decl_index) {
|
||||
mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
|
||||
new_len -= 1;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
export_list.shrinkAndFree(mod.gpa, new_len);
|
||||
if (new_len == 0) {
|
||||
assert(mod.decl_exports.swapRemove(exported_decl_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
value_ptr.shrinkAndFree(mod.gpa, new_len);
|
||||
if (new_len == 0) {
|
||||
assert(mod.decl_exports.swapRemove(exp.exported_decl));
|
||||
}
|
||||
}
|
||||
if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
|
||||
elf.deleteDeclExport(decl_index, exp.opts.name);
|
||||
}
|
||||
if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {
|
||||
try macho.deleteDeclExport(decl_index, exp.opts.name);
|
||||
}
|
||||
if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| {
|
||||
wasm.deleteDeclExport(decl_index);
|
||||
}
|
||||
if (mod.comp.bin_file.cast(link.File.Coff)) |coff| {
|
||||
coff.deleteDeclExport(decl_index, exp.opts.name);
|
||||
},
|
||||
.value => |value| {
|
||||
if (mod.value_exports.getPtr(value)) |export_list| {
|
||||
// Remove exports with owner_decl matching the regenerating decl.
|
||||
const list = export_list.items;
|
||||
var i: usize = 0;
|
||||
var new_len = list.len;
|
||||
while (i < new_len) {
|
||||
if (list[i].owner_decl == decl_index) {
|
||||
mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
|
||||
new_len -= 1;
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
export_list.shrinkAndFree(mod.gpa, new_len);
|
||||
if (new_len == 0) {
|
||||
assert(mod.value_exports.swapRemove(value));
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
try mod.comp.bin_file.deleteDeclExport(decl_index, exp.opts.name);
|
||||
if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
|
||||
failed_kv.value.destroy(mod.gpa);
|
||||
}
|
||||
@ -5503,48 +5529,63 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void {
|
||||
/// reporting compile errors. In this function we emit exported symbol collision
|
||||
/// errors and communicate exported symbols to the linker backend.
|
||||
pub fn processExports(mod: *Module) !void {
|
||||
const gpa = mod.gpa;
|
||||
// Map symbol names to `Export` for name collision detection.
|
||||
var symbol_exports: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export) = .{};
|
||||
defer symbol_exports.deinit(gpa);
|
||||
var symbol_exports: SymbolExports = .{};
|
||||
defer symbol_exports.deinit(mod.gpa);
|
||||
|
||||
var it = mod.decl_exports.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const exported_decl = entry.key_ptr.*;
|
||||
const exports = entry.value_ptr.items;
|
||||
for (exports) |new_export| {
|
||||
const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
|
||||
if (gop.found_existing) {
|
||||
new_export.status = .failed_retryable;
|
||||
try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const src_loc = new_export.getSrcLoc(mod);
|
||||
const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{
|
||||
new_export.opts.name.fmt(&mod.intern_pool),
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
const other_export = gop.value_ptr.*;
|
||||
const other_src_loc = other_export.getSrcLoc(mod);
|
||||
try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
|
||||
new_export.status = .failed;
|
||||
} else {
|
||||
gop.value_ptr.* = new_export;
|
||||
}
|
||||
}
|
||||
mod.comp.bin_file.updateDeclExports(mod, exported_decl, exports) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => {
|
||||
const new_export = exports[0];
|
||||
new_export.status = .failed_retryable;
|
||||
try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const src_loc = new_export.getSrcLoc(mod);
|
||||
const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
|
||||
@errorName(err),
|
||||
});
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
|
||||
},
|
||||
};
|
||||
for (mod.decl_exports.keys(), mod.decl_exports.values()) |exported_decl, exports_list| {
|
||||
const exported: Exported = .{ .decl_index = exported_decl };
|
||||
try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
|
||||
}
|
||||
|
||||
for (mod.value_exports.keys(), mod.value_exports.values()) |exported_value, exports_list| {
|
||||
const exported: Exported = .{ .value = exported_value };
|
||||
try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
|
||||
}
|
||||
}
|
||||
|
||||
const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export);
|
||||
|
||||
fn processExportsInner(
|
||||
mod: *Module,
|
||||
symbol_exports: *SymbolExports,
|
||||
exported: Exported,
|
||||
exports: []const *Export,
|
||||
) error{OutOfMemory}!void {
|
||||
const gpa = mod.gpa;
|
||||
|
||||
for (exports) |new_export| {
|
||||
const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
|
||||
if (gop.found_existing) {
|
||||
new_export.status = .failed_retryable;
|
||||
try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const src_loc = new_export.getSrcLoc(mod);
|
||||
const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{
|
||||
new_export.opts.name.fmt(&mod.intern_pool),
|
||||
});
|
||||
errdefer msg.destroy(gpa);
|
||||
const other_export = gop.value_ptr.*;
|
||||
const other_src_loc = other_export.getSrcLoc(mod);
|
||||
try mod.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
|
||||
new_export.status = .failed;
|
||||
} else {
|
||||
gop.value_ptr.* = new_export;
|
||||
}
|
||||
}
|
||||
mod.comp.bin_file.updateExports(mod, exported, exports) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
else => {
|
||||
const new_export = exports[0];
|
||||
new_export.status = .failed_retryable;
|
||||
try mod.failed_exports.ensureUnusedCapacity(gpa, 1);
|
||||
const src_loc = new_export.getSrcLoc(mod);
|
||||
const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
|
||||
@errorName(err),
|
||||
});
|
||||
mod.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
pub fn populateTestFunctions(
|
||||
|
88
src/Sema.zig
88
src/Sema.zig
@ -6026,6 +6026,7 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const mod = sema.mod;
|
||||
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
|
||||
const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
|
||||
const src = inst_data.src();
|
||||
@ -6034,19 +6035,22 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
|
||||
const operand = try sema.resolveInstConst(block, operand_src, extra.operand, .{
|
||||
.needed_comptime_reason = "export target must be comptime-known",
|
||||
});
|
||||
const options = sema.resolveExportOptions(block, .unneeded, extra.options) catch |err| switch (err) {
|
||||
error.NeededSourceLocation => {
|
||||
_ = try sema.resolveExportOptions(block, options_src, extra.options);
|
||||
unreachable;
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
const decl_index = if (operand.val.getFunction(sema.mod)) |function| function.owner_decl else blk: {
|
||||
var anon_decl = try block.startAnonDecl(); // TODO: export value without Decl
|
||||
defer anon_decl.deinit();
|
||||
break :blk try anon_decl.finish(operand.ty, operand.val, .none);
|
||||
};
|
||||
try sema.analyzeExport(block, src, options, decl_index);
|
||||
const options = try sema.resolveExportOptions(block, options_src, extra.options);
|
||||
if (options.linkage == .Internal)
|
||||
return;
|
||||
if (operand.val.getFunction(mod)) |function| {
|
||||
const decl_index = function.owner_decl;
|
||||
return sema.analyzeExport(block, src, options, decl_index);
|
||||
}
|
||||
|
||||
try addExport(mod, .{
|
||||
.opts = options,
|
||||
.src = src,
|
||||
.owner_decl = sema.owner_decl_index,
|
||||
.src_decl = block.src_decl,
|
||||
.exported = .{ .value = operand.val.toIntern() },
|
||||
.status = .in_progress,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn analyzeExport(
|
||||
@ -6056,12 +6060,11 @@ pub fn analyzeExport(
|
||||
options: Module.Export.Options,
|
||||
exported_decl_index: Decl.Index,
|
||||
) !void {
|
||||
const Export = Module.Export;
|
||||
const gpa = sema.gpa;
|
||||
const mod = sema.mod;
|
||||
|
||||
if (options.linkage == .Internal) {
|
||||
if (options.linkage == .Internal)
|
||||
return;
|
||||
}
|
||||
|
||||
try mod.ensureDeclAnalyzed(exported_decl_index);
|
||||
const exported_decl = mod.declPtr(exported_decl_index);
|
||||
@ -6069,7 +6072,7 @@ pub fn analyzeExport(
|
||||
if (!try sema.validateExternType(exported_decl.ty, .other)) {
|
||||
const msg = msg: {
|
||||
const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(mod)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
errdefer msg.destroy(gpa);
|
||||
|
||||
const src_decl = mod.declPtr(block.src_decl);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other);
|
||||
@ -6089,38 +6092,45 @@ pub fn analyzeExport(
|
||||
try mod.markDeclAlive(exported_decl);
|
||||
try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
|
||||
|
||||
const gpa = sema.gpa;
|
||||
|
||||
try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
|
||||
try mod.export_owners.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const new_export = try gpa.create(Export);
|
||||
errdefer gpa.destroy(new_export);
|
||||
|
||||
new_export.* = .{
|
||||
try addExport(mod, .{
|
||||
.opts = options,
|
||||
.src = src,
|
||||
.owner_decl = sema.owner_decl_index,
|
||||
.src_decl = block.src_decl,
|
||||
.exported_decl = exported_decl_index,
|
||||
.exported = .{ .decl_index = exported_decl_index },
|
||||
.status = .in_progress,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
// Add to export_owners table.
|
||||
const eo_gop = mod.export_owners.getOrPutAssumeCapacity(sema.owner_decl_index);
|
||||
if (!eo_gop.found_existing) {
|
||||
eo_gop.value_ptr.* = .{};
|
||||
}
|
||||
fn addExport(mod: *Module, export_init: Module.Export) error{OutOfMemory}!void {
|
||||
const gpa = mod.gpa;
|
||||
|
||||
try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
|
||||
try mod.value_exports.ensureUnusedCapacity(gpa, 1);
|
||||
try mod.export_owners.ensureUnusedCapacity(gpa, 1);
|
||||
|
||||
const new_export = try gpa.create(Module.Export);
|
||||
errdefer gpa.destroy(new_export);
|
||||
|
||||
new_export.* = export_init;
|
||||
|
||||
const eo_gop = mod.export_owners.getOrPutAssumeCapacity(export_init.owner_decl);
|
||||
if (!eo_gop.found_existing) eo_gop.value_ptr.* = .{};
|
||||
try eo_gop.value_ptr.append(gpa, new_export);
|
||||
errdefer _ = eo_gop.value_ptr.pop();
|
||||
|
||||
// Add to exported_decl table.
|
||||
const de_gop = mod.decl_exports.getOrPutAssumeCapacity(exported_decl_index);
|
||||
if (!de_gop.found_existing) {
|
||||
de_gop.value_ptr.* = .{};
|
||||
switch (export_init.exported) {
|
||||
.decl_index => |decl_index| {
|
||||
const de_gop = mod.decl_exports.getOrPutAssumeCapacity(decl_index);
|
||||
if (!de_gop.found_existing) de_gop.value_ptr.* = .{};
|
||||
try de_gop.value_ptr.append(gpa, new_export);
|
||||
},
|
||||
.value => |value| {
|
||||
const ve_gop = mod.value_exports.getOrPutAssumeCapacity(value);
|
||||
if (!ve_gop.found_existing) ve_gop.value_ptr.* = .{};
|
||||
try ve_gop.value_ptr.append(gpa, new_export);
|
||||
},
|
||||
}
|
||||
try de_gop.value_ptr.append(gpa, new_export);
|
||||
errdefer _ = de_gop.value_ptr.pop();
|
||||
}
|
||||
|
||||
fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
|
||||
|
@ -1144,26 +1144,40 @@ pub const Object = struct {
|
||||
|
||||
for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
|
||||
const global = object.decl_map.get(decl_index) orelse continue;
|
||||
const global_base = global.toConst().getBase(&object.builder);
|
||||
for (export_list.items) |exp| {
|
||||
// Detect if the LLVM global has already been created as an extern. In such
|
||||
// case, we need to replace all uses of it with this exported global.
|
||||
const exp_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(exp.opts.name)) orelse continue;
|
||||
try resolveGlobalCollisions(object, global, export_list.items);
|
||||
}
|
||||
|
||||
const other_global = object.builder.getGlobal(exp_name) orelse continue;
|
||||
if (other_global.toConst().getBase(&object.builder) == global_base) continue;
|
||||
for (mod.value_exports.keys(), mod.value_exports.values()) |val, export_list| {
|
||||
const global = object.anon_decl_map.get(val) orelse continue;
|
||||
try resolveGlobalCollisions(object, global, export_list.items);
|
||||
}
|
||||
}
|
||||
|
||||
try global.takeName(other_global, &object.builder);
|
||||
try other_global.replace(global, &object.builder);
|
||||
// Problem: now we need to replace in the decl_map that
|
||||
// the extern decl index points to this new global. However we don't
|
||||
// know the decl index.
|
||||
// Even if we did, a future incremental update to the extern would then
|
||||
// treat the LLVM global as an extern rather than an export, so it would
|
||||
// need a way to check that.
|
||||
// This is a TODO that needs to be solved when making
|
||||
// the LLVM backend support incremental compilation.
|
||||
}
|
||||
fn resolveGlobalCollisions(
|
||||
object: *Object,
|
||||
global: Builder.Global.Index,
|
||||
export_list: []const *Module.Export,
|
||||
) !void {
|
||||
const mod = object.module;
|
||||
const global_base = global.toConst().getBase(&object.builder);
|
||||
for (export_list) |exp| {
|
||||
// Detect if the LLVM global has already been created as an extern. In such
|
||||
// case, we need to replace all uses of it with this exported global.
|
||||
const exp_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(exp.opts.name)) orelse continue;
|
||||
|
||||
const other_global = object.builder.getGlobal(exp_name) orelse continue;
|
||||
if (other_global.toConst().getBase(&object.builder) == global_base) continue;
|
||||
|
||||
try global.takeName(other_global, &object.builder);
|
||||
try other_global.replace(global, &object.builder);
|
||||
// Problem: now we need to replace in the decl_map that
|
||||
// the extern decl index points to this new global. However we don't
|
||||
// know the decl index.
|
||||
// Even if we did, a future incremental update to the extern would then
|
||||
// treat the LLVM global as an extern rather than an export, so it would
|
||||
// need a way to check that.
|
||||
// This is a TODO that needs to be solved when making
|
||||
// the LLVM backend support incremental compilation.
|
||||
}
|
||||
}
|
||||
|
||||
@ -1642,7 +1656,7 @@ pub const Object = struct {
|
||||
|
||||
try fg.wip.finish();
|
||||
|
||||
try o.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
||||
try o.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
pub fn updateDecl(self: *Object, module: *Module, decl_index: Module.Decl.Index) !void {
|
||||
@ -1662,18 +1676,22 @@ pub const Object = struct {
|
||||
},
|
||||
else => |e| return e,
|
||||
};
|
||||
try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
|
||||
try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
self: *Object,
|
||||
mod: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) !void {
|
||||
) link.File.UpdateExportsError!void {
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| return updateExportedValue(self, mod, val, exports),
|
||||
};
|
||||
const gpa = mod.gpa;
|
||||
// If the module does not already have the function, we ignore this function call
|
||||
// because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
|
||||
// because we call `updateExports` at the end of `updateFunc` and `updateDecl`.
|
||||
const global_index = self.decl_map.get(decl_index) orelse return;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
if (decl.isExtern(mod)) {
|
||||
@ -1733,8 +1751,7 @@ pub const Object = struct {
|
||||
mod.intern_pool.stringToSlice(exports[0].opts.name),
|
||||
);
|
||||
try global_index.rename(main_exp_name, &self.builder);
|
||||
global_index.setUnnamedAddr(.default, &self.builder);
|
||||
if (mod.wantDllExports()) global_index.setDllStorageClass(.dllexport, &self.builder);
|
||||
|
||||
if (self.di_map.get(decl)) |di_node| {
|
||||
const main_exp_name_slice = main_exp_name.slice(&self.builder).?;
|
||||
if (try decl.isFunction(mod)) {
|
||||
@ -1755,55 +1772,12 @@ pub const Object = struct {
|
||||
di_global.replaceLinkageName(linkage_name);
|
||||
}
|
||||
}
|
||||
global_index.setLinkage(switch (exports[0].opts.linkage) {
|
||||
.Internal => unreachable,
|
||||
.Strong => .external,
|
||||
.Weak => .weak_odr,
|
||||
.LinkOnce => .linkonce_odr,
|
||||
}, &self.builder);
|
||||
global_index.setVisibility(switch (exports[0].opts.visibility) {
|
||||
.default => .default,
|
||||
.hidden => .hidden,
|
||||
.protected => .protected,
|
||||
}, &self.builder);
|
||||
if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section|
|
||||
switch (global_index.ptrConst(&self.builder).kind) {
|
||||
inline .variable, .function => |impl_index| impl_index.setSection(
|
||||
try self.builder.string(section),
|
||||
&self.builder,
|
||||
),
|
||||
.alias, .replaced => unreachable,
|
||||
};
|
||||
|
||||
if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal)
|
||||
global_index.ptrConst(&self.builder).kind
|
||||
.variable.setThreadLocal(.generaldynamic, &self.builder);
|
||||
|
||||
// If a Decl is exported more than one time (which is rare),
|
||||
// we add aliases for all but the first export.
|
||||
// TODO LLVM C API does not support deleting aliases.
|
||||
// The planned solution to this is https://github.com/ziglang/zig/issues/13265
|
||||
// Until then we iterate over existing aliases and make them point
|
||||
// to the correct decl, or otherwise add a new alias. Old aliases are leaked.
|
||||
for (exports[1..]) |exp| {
|
||||
const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exp.opts.name));
|
||||
if (self.builder.getGlobal(exp_name)) |global| {
|
||||
switch (global.ptrConst(&self.builder).kind) {
|
||||
.alias => |alias| {
|
||||
alias.setAliasee(global_index.toConst(), &self.builder);
|
||||
continue;
|
||||
},
|
||||
.variable, .function => {},
|
||||
.replaced => unreachable,
|
||||
}
|
||||
}
|
||||
const alias_index = try self.builder.addAlias(
|
||||
.empty,
|
||||
global_index.typeOf(&self.builder),
|
||||
.default,
|
||||
global_index.toConst(),
|
||||
);
|
||||
try alias_index.rename(exp_name, &self.builder);
|
||||
}
|
||||
return updateExportedGlobal(self, mod, global_index, exports);
|
||||
} else {
|
||||
const fqn = try self.builder.string(
|
||||
mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)),
|
||||
@ -1824,6 +1798,100 @@ pub const Object = struct {
|
||||
}
|
||||
}
|
||||
|
||||
fn updateExportedValue(
|
||||
o: *Object,
|
||||
mod: *Module,
|
||||
exported_value: InternPool.Index,
|
||||
exports: []const *Module.Export,
|
||||
) link.File.UpdateExportsError!void {
|
||||
const gpa = mod.gpa;
|
||||
const main_exp_name = try o.builder.string(
|
||||
mod.intern_pool.stringToSlice(exports[0].opts.name),
|
||||
);
|
||||
const global_index = i: {
|
||||
const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);
|
||||
if (gop.found_existing) {
|
||||
const global_index = gop.value_ptr.*;
|
||||
try global_index.rename(main_exp_name, &o.builder);
|
||||
break :i global_index;
|
||||
}
|
||||
const llvm_addr_space = toLlvmAddressSpace(.generic, o.target);
|
||||
const variable_index = try o.builder.addVariable(
|
||||
main_exp_name,
|
||||
try o.lowerType(mod.intern_pool.typeOf(exported_value).toType()),
|
||||
llvm_addr_space,
|
||||
);
|
||||
const global_index = variable_index.ptrConst(&o.builder).global;
|
||||
gop.value_ptr.* = global_index;
|
||||
// This line invalidates `gop`.
|
||||
const init_val = o.lowerValue(exported_value) catch |err| switch (err) {
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
error.CodegenFail => return error.AnalysisFail,
|
||||
};
|
||||
try variable_index.setInitializer(init_val, &o.builder);
|
||||
break :i global_index;
|
||||
};
|
||||
return updateExportedGlobal(o, mod, global_index, exports);
|
||||
}
|
||||
|
||||
fn updateExportedGlobal(
|
||||
o: *Object,
|
||||
mod: *Module,
|
||||
global_index: Builder.Global.Index,
|
||||
exports: []const *Module.Export,
|
||||
) link.File.UpdateExportsError!void {
|
||||
global_index.setUnnamedAddr(.default, &o.builder);
|
||||
if (mod.wantDllExports()) global_index.setDllStorageClass(.dllexport, &o.builder);
|
||||
global_index.setLinkage(switch (exports[0].opts.linkage) {
|
||||
.Internal => unreachable,
|
||||
.Strong => .external,
|
||||
.Weak => .weak_odr,
|
||||
.LinkOnce => .linkonce_odr,
|
||||
}, &o.builder);
|
||||
global_index.setVisibility(switch (exports[0].opts.visibility) {
|
||||
.default => .default,
|
||||
.hidden => .hidden,
|
||||
.protected => .protected,
|
||||
}, &o.builder);
|
||||
if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section|
|
||||
switch (global_index.ptrConst(&o.builder).kind) {
|
||||
.variable => |impl_index| impl_index.setSection(
|
||||
try o.builder.string(section),
|
||||
&o.builder,
|
||||
),
|
||||
.function => unreachable,
|
||||
.alias => unreachable,
|
||||
.replaced => unreachable,
|
||||
};
|
||||
|
||||
// If a Decl is exported more than one time (which is rare),
|
||||
// we add aliases for all but the first export.
|
||||
// TODO LLVM C API does not support deleting aliases.
|
||||
// The planned solution to this is https://github.com/ziglang/zig/issues/13265
|
||||
// Until then we iterate over existing aliases and make them point
|
||||
// to the correct decl, or otherwise add a new alias. Old aliases are leaked.
|
||||
for (exports[1..]) |exp| {
|
||||
const exp_name = try o.builder.string(mod.intern_pool.stringToSlice(exp.opts.name));
|
||||
if (o.builder.getGlobal(exp_name)) |global| {
|
||||
switch (global.ptrConst(&o.builder).kind) {
|
||||
.alias => |alias| {
|
||||
alias.setAliasee(global_index.toConst(), &o.builder);
|
||||
continue;
|
||||
},
|
||||
.variable, .function => {},
|
||||
.replaced => unreachable,
|
||||
}
|
||||
}
|
||||
const alias_index = try o.builder.addAlias(
|
||||
.empty,
|
||||
global_index.typeOf(&o.builder),
|
||||
.default,
|
||||
global_index.toConst(),
|
||||
);
|
||||
try alias_index.rename(exp_name, &o.builder);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn freeDecl(self: *Object, decl_index: Module.Decl.Index) void {
|
||||
const global = self.decl_map.get(decl_index) orelse return;
|
||||
global.delete(&self.builder);
|
||||
|
49
src/link.zig
49
src/link.zig
@ -587,7 +587,7 @@ pub const File = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// May be called before or after updateDeclExports for any given Decl.
|
||||
/// May be called before or after updateExports for any given Decl.
|
||||
pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
|
||||
const decl = module.declPtr(decl_index);
|
||||
assert(decl.has_tv);
|
||||
@ -609,7 +609,7 @@ pub const File = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// May be called before or after updateDeclExports for any given Decl.
|
||||
/// May be called before or after updateExports for any given Decl.
|
||||
pub fn updateFunc(base: *File, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) UpdateDeclError!void {
|
||||
if (build_options.only_c) {
|
||||
assert(base.tag == .c);
|
||||
@ -882,33 +882,34 @@ pub const File = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub const UpdateDeclExportsError = error{
|
||||
pub const UpdateExportsError = error{
|
||||
OutOfMemory,
|
||||
AnalysisFail,
|
||||
};
|
||||
|
||||
/// This is called for every exported thing. `exports` is almost always
|
||||
/// a list of size 1, meaning that `exported` is exported once. However, it is possible
|
||||
/// to export the same thing with multiple different symbol names (aliases).
|
||||
/// May be called before or after updateDecl for any given Decl.
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
base: *File,
|
||||
module: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) UpdateDeclExportsError!void {
|
||||
const decl = module.declPtr(decl_index);
|
||||
assert(decl.has_tv);
|
||||
) UpdateExportsError!void {
|
||||
if (build_options.only_c) {
|
||||
assert(base.tag == .c);
|
||||
return @fieldParentPtr(C, "base", base).updateDeclExports(module, decl_index, exports);
|
||||
return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports);
|
||||
}
|
||||
switch (base.tag) {
|
||||
.coff => return @fieldParentPtr(Coff, "base", base).updateDeclExports(module, decl_index, exports),
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).updateDeclExports(module, decl_index, exports),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).updateDeclExports(module, decl_index, exports),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateDeclExports(module, decl_index, exports),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateDeclExports(module, decl_index, exports),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).updateDeclExports(module, decl_index, exports),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).updateDeclExports(module, decl_index, exports),
|
||||
.nvptx => return @fieldParentPtr(NvPtx, "base", base).updateDeclExports(module, decl_index, exports),
|
||||
.coff => return @fieldParentPtr(Coff, "base", base).updateExports(module, exported, exports),
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).updateExports(module, exported, exports),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).updateExports(module, exported, exports),
|
||||
.c => return @fieldParentPtr(C, "base", base).updateExports(module, exported, exports),
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).updateExports(module, exported, exports),
|
||||
.spirv => return @fieldParentPtr(SpirV, "base", base).updateExports(module, exported, exports),
|
||||
.plan9 => return @fieldParentPtr(Plan9, "base", base).updateExports(module, exported, exports),
|
||||
.nvptx => return @fieldParentPtr(NvPtx, "base", base).updateExports(module, exported, exports),
|
||||
}
|
||||
}
|
||||
|
||||
@ -968,6 +969,20 @@ pub const File = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deleteDeclExport(base: *File, decl_index: Module.Decl.Index, name: InternPool.NullTerminatedString) !void {
|
||||
if (build_options.only_c) unreachable;
|
||||
switch (base.tag) {
|
||||
.coff => return @fieldParentPtr(Coff, "base", base).deleteDeclExport(decl_index, name),
|
||||
.elf => return @fieldParentPtr(Elf, "base", base).deleteDeclExport(decl_index, name),
|
||||
.macho => return @fieldParentPtr(MachO, "base", base).deleteDeclExport(decl_index, name),
|
||||
.plan9 => {},
|
||||
.c => {},
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).deleteDeclExport(decl_index),
|
||||
.spirv => {},
|
||||
.nvptx => {},
|
||||
}
|
||||
}
|
||||
|
||||
/// This function is called by the frontend before flush(). It communicates that
|
||||
/// `options.bin_file.emit` directory needs to be renamed from
|
||||
/// `[zig-cache]/tmp/[random]` to `[zig-cache]/o/[digest]`.
|
||||
|
@ -753,14 +753,14 @@ pub fn flushEmitH(module: *Module) !void {
|
||||
try file.pwritevAll(all_buffers.items, 0);
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
self: *C,
|
||||
module: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) !void {
|
||||
_ = exports;
|
||||
_ = decl_index;
|
||||
_ = exported;
|
||||
_ = module;
|
||||
_ = self;
|
||||
}
|
||||
|
@ -1075,7 +1075,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
||||
return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {
|
||||
@ -1195,7 +1195,7 @@ pub fn updateDecl(
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
||||
return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
fn updateLazySymbolAtom(
|
||||
@ -1409,12 +1409,12 @@ pub fn freeDecl(self: *Coff, decl_index: Module.Decl.Index) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
self: *Coff,
|
||||
mod: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) link.File.UpdateDeclExportsError!void {
|
||||
) link.File.UpdateExportsError!void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .coff) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
@ -1425,7 +1425,11 @@ pub fn updateDeclExports(
|
||||
// Even in the case of LLVM, we need to notice certain exported symbols in order to
|
||||
// detect the default subsystem.
|
||||
for (exports) |exp| {
|
||||
const exported_decl = mod.declPtr(exp.exported_decl);
|
||||
const exported_decl_index = switch (exp.exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => continue,
|
||||
};
|
||||
const exported_decl = mod.declPtr(exported_decl_index);
|
||||
if (exported_decl.getOwnedFunction(mod) == null) continue;
|
||||
const winapi_cc = switch (self.base.options.target.cpu.arch) {
|
||||
.x86 => std.builtin.CallingConvention.Stdcall,
|
||||
@ -1452,12 +1456,19 @@ pub fn updateDeclExports(
|
||||
}
|
||||
}
|
||||
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
|
||||
|
||||
if (self.base.options.emit == null) return;
|
||||
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| {
|
||||
_ = val;
|
||||
@panic("TODO: implement COFF linker code for exporting a constant value");
|
||||
},
|
||||
};
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const atom_index = try self.getOrCreateAtomForDecl(decl_index);
|
||||
const atom = self.getAtom(atom_index);
|
||||
|
@ -3306,7 +3306,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
||||
return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
pub fn updateDecl(
|
||||
@ -3388,7 +3388,7 @@ pub fn updateDecl(
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export
|
||||
// symbol also needs to be updated.
|
||||
return self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
||||
return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.Index) !void {
|
||||
@ -3555,16 +3555,16 @@ fn lowerConst(
|
||||
return .{ .ok = sym_index };
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
self: *Elf,
|
||||
mod: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) link.File.UpdateDeclExportsError!void {
|
||||
) link.File.UpdateExportsError!void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .elf) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
|
||||
if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
|
||||
|
||||
if (self.base.options.emit == null) return;
|
||||
|
||||
@ -3573,6 +3573,13 @@ pub fn updateDeclExports(
|
||||
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| {
|
||||
_ = val;
|
||||
@panic("TODO: implement ELF linker code for exporting a constant value");
|
||||
},
|
||||
};
|
||||
const zig_module = self.file(self.zig_module_index.?).?.zig_module;
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index);
|
||||
|
@ -1670,7 +1670,7 @@ fn resolveGlobalSymbol(self: *MachO, current: SymbolWithLoc) !void {
|
||||
const global_is_weak = global_sym.sect() and (global_sym.weakDef() or global_sym.pext());
|
||||
|
||||
if (sym_is_strong and global_is_strong) {
|
||||
// TODO redo this logic with corresponding logic in updateDeclExports to avoid this
|
||||
// TODO redo this logic with corresponding logic in updateExports to avoid this
|
||||
// ugly check.
|
||||
if (self.mode == .zld) {
|
||||
try self.reportSymbolCollision(global, current);
|
||||
@ -2180,7 +2180,7 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air:
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export symbol also
|
||||
// needs to be updated.
|
||||
try self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
||||
try self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
pub 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
|
||||
|
||||
// Since we updated the vaddr and the size, each corresponding export symbol also
|
||||
// needs to be updated.
|
||||
try self.updateDeclExports(mod, decl_index, mod.getDeclExports(decl_index));
|
||||
try self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
|
||||
}
|
||||
|
||||
fn updateLazySymbolAtom(
|
||||
@ -2529,7 +2529,7 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D
|
||||
);
|
||||
}
|
||||
|
||||
try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
|
||||
try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
|
||||
|
||||
// 2. Create a TLV descriptor.
|
||||
const init_atom_sym_loc = init_atom.getSymbolWithLoc();
|
||||
@ -2670,17 +2670,17 @@ pub fn updateDeclLineNumber(self: *MachO, module: *Module, decl_index: Module.De
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
self: *MachO,
|
||||
mod: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) File.UpdateDeclExportsError!void {
|
||||
) File.UpdateExportsError!void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .macho) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (self.llvm_object) |llvm_object|
|
||||
return llvm_object.updateDeclExports(mod, decl_index, exports);
|
||||
return llvm_object.updateExports(mod, exported, exports);
|
||||
|
||||
if (self.base.options.emit == null) return;
|
||||
|
||||
@ -2689,6 +2689,13 @@ pub fn updateDeclExports(
|
||||
|
||||
const gpa = self.base.allocator;
|
||||
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| {
|
||||
_ = val;
|
||||
@panic("TODO: implement MachO linker code for exporting a constant value");
|
||||
},
|
||||
};
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const atom_index = try self.getOrCreateAtomForDecl(decl_index);
|
||||
const atom = self.getAtom(atom_index);
|
||||
|
@ -74,16 +74,16 @@ pub fn updateDecl(self: *NvPtx, module: *Module, decl_index: Module.Decl.Index)
|
||||
return self.llvm_object.updateDecl(module, decl_index);
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
self: *NvPtx,
|
||||
module: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .nvptx) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
return self.llvm_object.updateDeclExports(module, decl_index, exports);
|
||||
return self.llvm_object.updateExports(module, exported, exports);
|
||||
}
|
||||
|
||||
pub fn freeDecl(self: *NvPtx, decl_index: Module.Decl.Index) void {
|
||||
|
@ -1116,13 +1116,16 @@ pub fn seeDecl(self: *Plan9, decl_index: Module.Decl.Index) !Atom.Index {
|
||||
return atom_idx;
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
self: *Plan9,
|
||||
module: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) !void {
|
||||
_ = try self.seeDecl(decl_index);
|
||||
switch (exported) {
|
||||
.value => @panic("TODO: plan9 updateExports handling values"),
|
||||
.decl_index => |decl_index| _ = try self.seeDecl(decl_index),
|
||||
}
|
||||
// we do all the things in flush
|
||||
_ = module;
|
||||
_ = exports;
|
||||
|
@ -120,12 +120,19 @@ pub fn updateDecl(self: *SpirV, module: *Module, decl_index: Module.Decl.Index)
|
||||
try self.object.updateDecl(module, decl_index);
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
self: *SpirV,
|
||||
mod: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) !void {
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| {
|
||||
_ = val;
|
||||
@panic("TODO: implement SpirV linker code for exporting a constant value");
|
||||
},
|
||||
};
|
||||
const decl = mod.declPtr(decl_index);
|
||||
if (decl.val.isFuncBody(mod) and decl.ty.fnCallingConvention(mod) == .Kernel) {
|
||||
const spv_decl_index = try self.object.resolveDecl(mod, decl_index);
|
||||
|
@ -1786,19 +1786,26 @@ pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn updateDeclExports(
|
||||
pub fn updateExports(
|
||||
wasm: *Wasm,
|
||||
mod: *Module,
|
||||
decl_index: Module.Decl.Index,
|
||||
exported: Module.Exported,
|
||||
exports: []const *Module.Export,
|
||||
) !void {
|
||||
if (build_options.skip_non_native and builtin.object_format != .wasm) {
|
||||
@panic("Attempted to compile for object format that was disabled by build configuration");
|
||||
}
|
||||
if (wasm.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports);
|
||||
if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
|
||||
|
||||
if (wasm.base.options.emit == null) return;
|
||||
|
||||
const decl_index = switch (exported) {
|
||||
.decl_index => |i| i,
|
||||
.value => |val| {
|
||||
_ = val;
|
||||
@panic("TODO: implement Wasm linker code for exporting a constant value");
|
||||
},
|
||||
};
|
||||
const decl = mod.declPtr(decl_index);
|
||||
const atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
|
||||
const atom = wasm.getAtom(atom_index);
|
||||
@ -1816,7 +1823,19 @@ pub fn updateDeclExports(
|
||||
continue;
|
||||
}
|
||||
|
||||
const exported_atom_index = try wasm.getOrCreateAtomForDecl(exp.exported_decl);
|
||||
const exported_decl_index = switch (exp.exported) {
|
||||
.value => {
|
||||
try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
|
||||
gpa,
|
||||
decl.srcLoc(mod),
|
||||
"Unimplemented: exporting a named constant value",
|
||||
.{},
|
||||
));
|
||||
continue;
|
||||
},
|
||||
.decl_index => |i| i,
|
||||
};
|
||||
const exported_atom_index = try wasm.getOrCreateAtomForDecl(exported_decl_index);
|
||||
const exported_atom = wasm.getAtom(exported_atom_index);
|
||||
const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.opts.name));
|
||||
const sym_loc = exported_atom.symbolLoc();
|
||||
|
@ -72,6 +72,8 @@ test "exporting using field access" {
|
||||
}
|
||||
|
||||
test "exporting comptime-known value" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
|
||||
const x: u32 = 10;
|
||||
@export(x, .{ .name = "exporting_comptime_known_value_foo" });
|
||||
const S = struct {
|
||||
@ -81,6 +83,8 @@ test "exporting comptime-known value" {
|
||||
}
|
||||
|
||||
test "exporting comptime var" {
|
||||
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
|
||||
|
||||
comptime var x: u32 = 5;
|
||||
@export(x, .{ .name = "exporting_comptime_var_foo" });
|
||||
x = 7; // modifying this now shouldn't change anything
|
||||
|
Loading…
Reference in New Issue
Block a user