diff --git a/src/AstGen.zig b/src/AstGen.zig index d2906a6838..e9b3946116 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -6127,15 +6127,18 @@ fn builtinCall( .c_import => return cImport( gz, scope, rl, node, params[0]), .@"export" => { - // TODO: @export is supposed to be able to export things other than functions. - // Instead of `comptimeExpr` here we need `decl_ref`. - const fn_to_export = try comptimeExpr(gz, scope, .none, params[0]); - // TODO: the second parameter here is supposed to be - // `std.builtin.ExportOptions`, not a string. - const export_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); - _ = try gz.addPlNode(.@"export", node, Zir.Inst.Bin{ - .lhs = fn_to_export, - .rhs = export_name, + const node_tags = tree.nodes.items(.tag); + // This function causes a Decl to be exported. The first parameter is not an expression, + // but an identifier of the Decl to be exported. + if (node_tags[params[0]] != .identifier) { + return astgen.failNode(params[0], "the first @export parameter must be an identifier", .{}); + } + const ident_token = main_tokens[params[0]]; + const decl_name = try gz.identAsString(ident_token); + const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]); + _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{ + .decl_name = decl_name, + .options = options, }); return rvalue(gz, scope, rl, .void_value, node); }, diff --git a/src/Sema.zig b/src/Sema.zig index 00ec5222ec..49610506d9 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1766,21 +1766,20 @@ fn zirExport(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError! defer tracy.end(); const inst_data = sema.code.instructions.items(.data)[inst].pl_node; - const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; + const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; const src = inst_data.src(); const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; + const decl_name = sema.code.nullTerminatedString(extra.decl_name); + const decl = try sema.lookupIdentifier(block, lhs_src, decl_name); + const options = try sema.resolveInstConst(block, rhs_src, extra.options); - // TODO (see corresponding TODO in AstGen) this is supposed to be a `decl_ref` - // instruction, which could reference any decl, which is then supposed to get - // exported, regardless of whether or not it is a function. - const target_fn = try sema.resolveInstConst(block, lhs_src, extra.lhs); - // TODO (see corresponding TODO in AstGen) this is supposed to be - // `std.builtin.ExportOptions`, not a string. - const export_name = try sema.resolveConstString(block, rhs_src, extra.rhs); + // TODO respect the name, linkage, and section options. Until then we export + // as the decl name. + _ = options; + const export_name = mem.spanZ(decl.name); - const actual_fn = target_fn.val.castTag(.function).?.data; - try sema.mod.analyzeExport(&block.base, src, export_name, actual_fn.owner_decl); + try sema.mod.analyzeExport(&block.base, src, export_name, decl); } fn zirSetAlignStack(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!void { diff --git a/src/Zir.zig b/src/Zir.zig index 3da2c6aff8..b44050fdfe 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -1352,6 +1352,7 @@ pub const Inst = struct { float_mode_type, reduce_op_type, call_options_type, + export_options_type, /// `undefined` (untyped) undef, @@ -1575,6 +1576,10 @@ pub const Inst = struct { .ty = Type.initTag(.type), .val = Value.initTag(.call_options_type), }, + .export_options_type = .{ + .ty = Type.initTag(.type), + .val = Value.initTag(.export_options_type), + }, .undef = .{ .ty = Type.initTag(.@"undefined"), @@ -2214,6 +2219,12 @@ pub const Inst = struct { src_node: i32, }; + pub const Export = struct { + /// Null-terminated string index. + decl_name: u32, + options: Ref, + }; + /// Trailing: `CompileErrors.Item` for each `items_len`. pub const CompileErrors = struct { items_len: u32, @@ -2451,7 +2462,6 @@ const Writer = struct { .xor, .store_node, .error_union_type, - .@"export", .merge_error_sets, .bit_and, .bit_or, @@ -2479,6 +2489,8 @@ const Writer = struct { .bitcast_result_ptr, => try self.writePlNodeBin(stream, inst), + .@"export" => try self.writePlNodeExport(stream, inst), + .call, .call_chkused, .call_compile_time, @@ -2729,6 +2741,17 @@ const Writer = struct { try self.writeSrc(stream, inst_data.src()); } + fn writePlNodeExport(self: *Writer, stream: anytype, inst: Inst.Index) !void { + const inst_data = self.code.instructions.items(.data)[inst].pl_node; + const extra = self.code.extraData(Inst.Export, inst_data.payload_index).data; + const decl_name = self.code.nullTerminatedString(extra.decl_name); + + try stream.print("{}, ", .{std.zig.fmtId(decl_name)}); + try self.writeInstRef(stream, extra.options); + try stream.writeAll(") "); + try self.writeSrc(stream, inst_data.src()); + } + fn writePlNodeErrorSetDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[inst].pl_node; const extra = self.code.extraData(Inst.ErrorSetDecl, inst_data.payload_index); diff --git a/src/type.zig b/src/type.zig index 63c1616506..44d635f64a 100644 --- a/src/type.zig +++ b/src/type.zig @@ -99,6 +99,7 @@ pub const Type = extern union { .empty_struct_literal, .@"struct", .call_options, + .export_options, => return .Struct, .enum_full, @@ -616,6 +617,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => unreachable, .array_u8, @@ -794,6 +796,7 @@ pub const Type = extern union { .float_mode => return writer.writeAll("std.builtin.FloatMode"), .reduce_op => return writer.writeAll("std.builtin.ReduceOp"), .call_options => return writer.writeAll("std.builtin.CallOptions"), + .export_options => return writer.writeAll("std.builtin.ExportOptions"), .function => { const payload = ty.castTag(.function).?.data; try writer.writeAll("fn("); @@ -1008,6 +1011,7 @@ pub const Type = extern union { .float_mode => return Value.initTag(.float_mode_type), .reduce_op => return Value.initTag(.reduce_op_type), .call_options => return Value.initTag(.call_options_type), + .export_options => return Value.initTag(.export_options_type), .inferred_alloc_const => unreachable, .inferred_alloc_mut => unreachable, else => return Value.Tag.ty.create(allocator, self), @@ -1065,6 +1069,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => true, .@"struct" => { @@ -1175,6 +1180,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => return 1, .fn_noreturn_no_args, // represents machine code; not a pointer @@ -1352,6 +1358,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => return 1, .array_u8 => self.castTag(.array_u8).?.data, @@ -1615,6 +1622,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @panic("TODO at some point we gotta resolve builtin types"), }; } @@ -2238,6 +2246,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => return null, .@"struct" => { @@ -2403,6 +2412,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @panic("TODO resolve std.builtin types"), else => unreachable, @@ -2425,6 +2435,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @panic("TODO resolve std.builtin types"), else => unreachable, } @@ -2446,6 +2457,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @panic("TODO resolve std.builtin types"), else => unreachable, } @@ -2489,6 +2501,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @panic("TODO resolve std.builtin types"), else => unreachable, } @@ -2518,6 +2531,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @panic("TODO resolve std.builtin types"), else => unreachable, } @@ -2548,6 +2562,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @panic("TODO resolve std.builtin types"), else => unreachable, } @@ -2587,6 +2602,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @panic("TODO resolve std.builtin types"), else => unreachable, @@ -2643,6 +2659,7 @@ pub const Type = extern union { float_mode, reduce_op, call_options, + export_options, @"null", @"undefined", fn_noreturn_no_args, @@ -2754,6 +2771,7 @@ pub const Type = extern union { .float_mode, .reduce_op, .call_options, + .export_options, => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"), .array_u8, diff --git a/src/value.zig b/src/value.zig index 80b21f0713..4776cb5a76 100644 --- a/src/value.zig +++ b/src/value.zig @@ -72,6 +72,7 @@ pub const Value = extern union { float_mode_type, reduce_op_type, call_options_type, + export_options_type, undef, zero, @@ -185,6 +186,7 @@ pub const Value = extern union { .float_mode_type, .reduce_op_type, .call_options_type, + .export_options_type, => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"), .int_big_positive, @@ -351,6 +353,7 @@ pub const Value = extern union { .float_mode_type, .reduce_op_type, .call_options_type, + .export_options_type, => unreachable, .ty => { @@ -506,6 +509,7 @@ pub const Value = extern union { .float_mode_type => return out_stream.writeAll("std.builtin.FloatMode"), .reduce_op_type => return out_stream.writeAll("std.builtin.ReduceOp"), .call_options_type => return out_stream.writeAll("std.builtin.CallOptions"), + .export_options_type => return out_stream.writeAll("std.builtin.ExportOptions"), .abi_align_default => return out_stream.writeAll("(default ABI alignment)"), .empty_struct_value => return out_stream.writeAll("struct {}{}"), @@ -635,6 +639,7 @@ pub const Value = extern union { .float_mode_type => Type.initTag(.float_mode), .reduce_op_type => Type.initTag(.reduce_op), .call_options_type => Type.initTag(.call_options), + .export_options_type => Type.initTag(.export_options), .int_type => { const payload = self.castTag(.int_type).?.data; @@ -1181,6 +1186,7 @@ pub const Value = extern union { .float_mode_type, .reduce_op_type, .call_options_type, + .export_options_type, => @panic("TODO this hash function looks pretty broken. audit it"), } return hasher.final(); @@ -1336,6 +1342,7 @@ pub const Value = extern union { .float_mode_type, .reduce_op_type, .call_options_type, + .export_options_type, => true, .zero,