mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 22:35:24 +00:00
parent
492cc2ef8d
commit
f2d7096bb9
@ -2861,7 +2861,6 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As
|
||||
.ensure_result_non_error,
|
||||
.ensure_err_union_payload_void,
|
||||
.@"export",
|
||||
.export_value,
|
||||
.set_eval_branch_quota,
|
||||
.atomic_store,
|
||||
.store_node,
|
||||
@ -9249,87 +9248,11 @@ fn builtinCall(
|
||||
// zig fmt: on
|
||||
|
||||
.@"export" => {
|
||||
const exported = try expr(gz, scope, .{ .rl = .none }, params[0]);
|
||||
const export_options_ty = try gz.addBuiltinValue(node, .export_options);
|
||||
const node_tags = tree.nodes.items(.tag);
|
||||
const node_datas = tree.nodes.items(.data);
|
||||
// This function causes a Decl to be exported. The first parameter is not an expression,
|
||||
// but an identifier of the Decl to be exported.
|
||||
var namespace: Zir.Inst.Ref = .none;
|
||||
var decl_name: Zir.NullTerminatedString = .empty;
|
||||
switch (node_tags[params[0]]) {
|
||||
.identifier => {
|
||||
const ident_token = main_tokens[params[0]];
|
||||
if (isPrimitive(tree.tokenSlice(ident_token))) {
|
||||
return astgen.failTok(ident_token, "unable to export primitive value", .{});
|
||||
}
|
||||
decl_name = try astgen.identAsString(ident_token);
|
||||
|
||||
var s = scope;
|
||||
var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already
|
||||
while (true) switch (s.tag) {
|
||||
.local_val => {
|
||||
const local_val = s.cast(Scope.LocalVal).?;
|
||||
if (local_val.name == decl_name) {
|
||||
local_val.used = ident_token;
|
||||
_ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{
|
||||
.operand = local_val.inst,
|
||||
.options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = export_options_ty } }, params[1]),
|
||||
});
|
||||
return rvalue(gz, ri, .void_value, node);
|
||||
}
|
||||
s = local_val.parent;
|
||||
},
|
||||
.local_ptr => {
|
||||
const local_ptr = s.cast(Scope.LocalPtr).?;
|
||||
if (local_ptr.name == decl_name) {
|
||||
if (!local_ptr.maybe_comptime)
|
||||
return astgen.failNode(params[0], "unable to export runtime-known value", .{});
|
||||
local_ptr.used = ident_token;
|
||||
const loaded = try gz.addUnNode(.load, local_ptr.ptr, node);
|
||||
_ = try gz.addPlNode(.export_value, node, Zir.Inst.ExportValue{
|
||||
.operand = loaded,
|
||||
.options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = export_options_ty } }, params[1]),
|
||||
});
|
||||
return rvalue(gz, ri, .void_value, node);
|
||||
}
|
||||
s = local_ptr.parent;
|
||||
},
|
||||
.gen_zir => s = s.cast(GenZir).?.parent,
|
||||
.defer_normal, .defer_error => s = s.cast(Scope.Defer).?.parent,
|
||||
.namespace => {
|
||||
const ns = s.cast(Scope.Namespace).?;
|
||||
if (ns.decls.get(decl_name)) |i| {
|
||||
if (found_already) |f| {
|
||||
return astgen.failNodeNotes(node, "ambiguous reference", .{}, &.{
|
||||
try astgen.errNoteNode(f, "declared here", .{}),
|
||||
try astgen.errNoteNode(i, "also declared here", .{}),
|
||||
});
|
||||
}
|
||||
// We found a match but must continue looking for ambiguous references to decls.
|
||||
found_already = i;
|
||||
}
|
||||
s = ns.parent;
|
||||
},
|
||||
.top => break,
|
||||
};
|
||||
if (found_already == null) {
|
||||
const ident_name = try astgen.identifierTokenString(ident_token);
|
||||
return astgen.failNode(params[0], "use of undeclared identifier '{s}'", .{ident_name});
|
||||
}
|
||||
},
|
||||
.field_access => {
|
||||
const namespace_node = node_datas[params[0]].lhs;
|
||||
namespace = try typeExpr(gz, scope, namespace_node);
|
||||
const dot_token = main_tokens[params[0]];
|
||||
const field_ident = dot_token + 1;
|
||||
decl_name = try astgen.identAsString(field_ident);
|
||||
},
|
||||
else => return astgen.failNode(params[0], "symbol to export must identify a declaration", .{}),
|
||||
}
|
||||
const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = export_options_ty } }, params[1]);
|
||||
_ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{
|
||||
.namespace = namespace,
|
||||
.decl_name = decl_name,
|
||||
.exported = exported,
|
||||
.options = options,
|
||||
});
|
||||
return rvalue(gz, ri, .void_value, node);
|
||||
|
||||
@ -431,14 +431,9 @@ pub const Inst = struct {
|
||||
error_union_type,
|
||||
/// `error.Foo` syntax. Uses the `str_tok` field of the Data union.
|
||||
error_value,
|
||||
/// Implements the `@export` builtin function, based on either an identifier to a Decl,
|
||||
/// or field access of a Decl. The thing being exported is the Decl.
|
||||
/// Implements the `@export` builtin function.
|
||||
/// Uses the `pl_node` union field. Payload is `Export`.
|
||||
@"export",
|
||||
/// Implements the `@export` builtin function, based on a comptime-known value.
|
||||
/// The thing being exported is the comptime-known value which is the operand.
|
||||
/// Uses the `pl_node` union field. Payload is `ExportValue`.
|
||||
export_value,
|
||||
/// Given a pointer to a struct or object that contains virtual fields, returns a pointer
|
||||
/// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
|
||||
/// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
|
||||
@ -1093,7 +1088,6 @@ pub const Inst = struct {
|
||||
.ensure_result_non_error,
|
||||
.ensure_err_union_payload_void,
|
||||
.@"export",
|
||||
.export_value,
|
||||
.field_ptr,
|
||||
.field_val,
|
||||
.field_ptr_named,
|
||||
@ -1314,7 +1308,6 @@ pub const Inst = struct {
|
||||
.validate_deref,
|
||||
.validate_destructure,
|
||||
.@"export",
|
||||
.export_value,
|
||||
.set_runtime_safety,
|
||||
.memcpy,
|
||||
.memset,
|
||||
@ -1637,7 +1630,6 @@ pub const Inst = struct {
|
||||
.error_union_type = .pl_node,
|
||||
.error_value = .str_tok,
|
||||
.@"export" = .pl_node,
|
||||
.export_value = .pl_node,
|
||||
.field_ptr = .pl_node,
|
||||
.field_val = .pl_node,
|
||||
.field_ptr_named = .pl_node,
|
||||
@ -3425,17 +3417,7 @@ pub const Inst = struct {
|
||||
};
|
||||
|
||||
pub const Export = struct {
|
||||
/// If present, this is referring to a Decl via field access, e.g. `a.b`.
|
||||
/// If omitted, this is referring to a Decl via identifier, e.g. `a`.
|
||||
namespace: Ref,
|
||||
/// Null-terminated string index.
|
||||
decl_name: NullTerminatedString,
|
||||
options: Ref,
|
||||
};
|
||||
|
||||
pub const ExportValue = struct {
|
||||
/// The comptime value to export.
|
||||
operand: Ref,
|
||||
exported: Ref,
|
||||
options: Ref,
|
||||
};
|
||||
|
||||
@ -3793,7 +3775,6 @@ fn findDeclsInner(
|
||||
.error_union_type,
|
||||
.error_value,
|
||||
.@"export",
|
||||
.export_value,
|
||||
.field_ptr,
|
||||
.field_val,
|
||||
.field_ptr_named,
|
||||
|
||||
126
src/Sema.zig
126
src/Sema.zig
@ -1442,11 +1442,6 @@ fn analyzeBodyInner(
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.export_value => {
|
||||
try sema.zirExportValue(block, inst);
|
||||
i += 1;
|
||||
continue;
|
||||
},
|
||||
.set_runtime_safety => {
|
||||
try sema.zirSetRuntimeSafety(block, inst);
|
||||
i += 1;
|
||||
@ -6279,73 +6274,72 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
|
||||
const ip = &zcu.intern_pool;
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
|
||||
const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
|
||||
|
||||
const src = block.nodeOffset(inst_data.src_node);
|
||||
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
|
||||
const ptr_src = block.builtinCallArgSrc(inst_data.src_node, 0);
|
||||
const options_src = block.builtinCallArgSrc(inst_data.src_node, 1);
|
||||
const decl_name = try ip.getOrPutString(
|
||||
zcu.gpa,
|
||||
pt.tid,
|
||||
sema.code.nullTerminatedString(extra.decl_name),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
const nav_index = if (extra.namespace != .none) index_blk: {
|
||||
const container_ty = try sema.resolveType(block, operand_src, extra.namespace);
|
||||
const container_namespace = container_ty.getNamespaceIndex(zcu);
|
||||
|
||||
const lookup = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false) orelse
|
||||
return sema.failWithBadMemberAccess(block, container_ty, operand_src, decl_name);
|
||||
|
||||
break :index_blk lookup.nav;
|
||||
} else try sema.lookupIdentifier(block, operand_src, decl_name);
|
||||
const options = try sema.resolveExportOptions(block, options_src, extra.options);
|
||||
|
||||
try sema.ensureNavResolved(src, nav_index);
|
||||
|
||||
// Make sure to export the owner Nav if applicable.
|
||||
const exported_nav = switch (ip.indexToKey(ip.getNav(nav_index).status.resolved.val)) {
|
||||
.variable => |v| v.owner_nav,
|
||||
.@"extern" => |e| e.owner_nav,
|
||||
.func => |f| f.owner_nav,
|
||||
else => nav_index,
|
||||
};
|
||||
try sema.analyzeExport(block, src, options, exported_nav);
|
||||
}
|
||||
|
||||
fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
|
||||
const tracy = trace(@src());
|
||||
defer tracy.end();
|
||||
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
|
||||
const extra = sema.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
|
||||
const src = block.nodeOffset(inst_data.src_node);
|
||||
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
|
||||
const options_src = block.builtinCallArgSrc(inst_data.src_node, 1);
|
||||
const operand = try sema.resolveInstConst(block, operand_src, extra.operand, .{
|
||||
const ptr = try sema.resolveInst(extra.exported);
|
||||
const ptr_val = try sema.resolveConstDefinedValue(block, ptr_src, ptr, .{
|
||||
.needed_comptime_reason = "export target must be comptime-known",
|
||||
});
|
||||
const options = try sema.resolveExportOptions(block, options_src, extra.options);
|
||||
if (options.linkage == .internal)
|
||||
return;
|
||||
const ptr_ty = ptr_val.typeOf(zcu);
|
||||
|
||||
// If the value has an owner Nav, export that instead.
|
||||
const maybe_owner_nav = switch (ip.indexToKey(operand.toIntern())) {
|
||||
.variable => |v| v.owner_nav,
|
||||
.@"extern" => |e| e.owner_nav,
|
||||
.func => |f| f.owner_nav,
|
||||
else => null,
|
||||
};
|
||||
if (maybe_owner_nav) |owner_nav| {
|
||||
return sema.analyzeExport(block, src, options, owner_nav);
|
||||
} else {
|
||||
try sema.exports.append(zcu.gpa, .{
|
||||
.opts = options,
|
||||
.src = src,
|
||||
.exported = .{ .uav = operand.toIntern() },
|
||||
.status = .in_progress,
|
||||
});
|
||||
const options = try sema.resolveExportOptions(block, options_src, extra.options);
|
||||
|
||||
{
|
||||
if (ptr_ty.zigTypeTag(zcu) != .Pointer) {
|
||||
return sema.fail(block, ptr_src, "expected pointer type, found '{}'", .{ptr_ty.fmt(pt)});
|
||||
}
|
||||
const ptr_ty_info = ptr_ty.ptrInfo(zcu);
|
||||
if (ptr_ty_info.flags.size == .Slice) {
|
||||
return sema.fail(block, ptr_src, "export target cannot be slice", .{});
|
||||
}
|
||||
if (ptr_ty_info.packed_offset.host_size != 0) {
|
||||
return sema.fail(block, ptr_src, "export target cannot be bit-pointer", .{});
|
||||
}
|
||||
}
|
||||
|
||||
const ptr_info = ip.indexToKey(ptr_val.toIntern()).ptr;
|
||||
switch (ptr_info.base_addr) {
|
||||
.comptime_alloc, .int, .comptime_field => return sema.fail(block, ptr_src, "export target must be a global variable or a comptime-known constant", .{}),
|
||||
.eu_payload, .opt_payload, .field, .arr_elem => return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}),
|
||||
.uav => |uav| {
|
||||
if (ptr_info.byte_offset != 0) {
|
||||
return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
|
||||
}
|
||||
if (options.linkage == .internal) return;
|
||||
const export_ty = Value.fromInterned(uav.val).typeOf(zcu);
|
||||
if (!try sema.validateExternType(export_ty, .other)) {
|
||||
return sema.failWithOwnedErrorMsg(block, msg: {
|
||||
const msg = try sema.errMsg(src, "unable to export type '{}'", .{export_ty.fmt(pt)});
|
||||
errdefer msg.destroy(sema.gpa);
|
||||
try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other);
|
||||
try sema.addDeclaredHereNote(msg, export_ty);
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
try sema.exports.append(zcu.gpa, .{
|
||||
.opts = options,
|
||||
.src = src,
|
||||
.exported = .{ .uav = uav.val },
|
||||
.status = .in_progress,
|
||||
});
|
||||
},
|
||||
.nav => |nav| {
|
||||
if (ptr_info.byte_offset != 0) {
|
||||
return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{});
|
||||
}
|
||||
try sema.ensureNavResolved(src, nav);
|
||||
// Make sure to export the owner Nav if applicable.
|
||||
const exported_nav = switch (ip.indexToKey(ip.getNav(nav).status.resolved.val)) {
|
||||
.variable => |v| v.owner_nav,
|
||||
.@"extern" => |e| e.owner_nav,
|
||||
.func => |f| f.owner_nav,
|
||||
else => nav,
|
||||
};
|
||||
try sema.analyzeExport(block, src, options, exported_nav);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -429,7 +429,6 @@ const Writer = struct {
|
||||
.elem_val_imm => try self.writeElemValImm(stream, inst),
|
||||
|
||||
.@"export" => try self.writePlNodeExport(stream, inst),
|
||||
.export_value => try self.writePlNodeExportValue(stream, inst),
|
||||
|
||||
.call => try self.writeCall(stream, inst, .direct),
|
||||
.field_call => try self.writeCall(stream, inst, .field),
|
||||
@ -1007,20 +1006,8 @@ const Writer = struct {
|
||||
fn writePlNodeExport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
|
||||
const extra = self.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
|
||||
const decl_name = self.code.nullTerminatedString(extra.decl_name);
|
||||
|
||||
try self.writeInstRef(stream, extra.namespace);
|
||||
try stream.print(", {p}, ", .{std.zig.fmtId(decl_name)});
|
||||
try self.writeInstRef(stream, extra.options);
|
||||
try stream.writeAll(") ");
|
||||
try self.writeSrcNode(stream, inst_data.src_node);
|
||||
}
|
||||
|
||||
fn writePlNodeExportValue(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_node;
|
||||
const extra = self.code.extraData(Zir.Inst.ExportValue, inst_data.payload_index).data;
|
||||
|
||||
try self.writeInstRef(stream, extra.operand);
|
||||
try self.writeInstRef(stream, extra.exported);
|
||||
try stream.writeAll(", ");
|
||||
try self.writeInstRef(stream, extra.options);
|
||||
try stream.writeAll(") ");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user