Commit 3d637e6dd2

Andrew Kelley <andrew@ziglang.org>
2021-04-23 01:07:58
AstGen: fix `@export`
Make it properly use `std.builtin.ExportOptions`.
1 parent 130ad08
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);
         },
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 {
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,
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,
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);