Commit f2d7096bb9
Changed files (4)
lib
std
lib/std/zig/AstGen.zig
@@ -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);
lib/std/zig/Zir.zig
@@ -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,
src/print_zir.zig
@@ -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(") ");
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 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 ptr_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 ptr_ty = ptr_val.typeOf(zcu);
+
const options = try sema.resolveExportOptions(block, options_src, extra.options);
- if (options.linkage == .internal)
- return;
- // 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,
- });
+ {
+ 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);
+ },
}
}