diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig index 3450e39cc6..f11143e9cd 100644 --- a/lib/std/zig/AstGen.zig +++ b/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); diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig index 26f4c4780f..e73fc5fd2d 100644 --- a/lib/std/zig/Zir.zig +++ b/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, diff --git a/src/Sema.zig b/src/Sema.zig index 2a43439616..024ec8961d 100644 --- a/src/Sema.zig +++ b/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); + }, } } diff --git a/src/print_zir.zig b/src/print_zir.zig index 774b222626..71e051af5a 100644 --- a/src/print_zir.zig +++ b/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(") ");