Commit 7c453b91b8

Andrew Kelley <andrew@ziglang.org>
2021-04-23 01:31:51
AstGen: implement `@extern` builtin
1 parent 3d637e6
src/AstGen.zig
@@ -6135,6 +6135,9 @@ fn builtinCall(
             }
             const ident_token = main_tokens[params[0]];
             const decl_name = try gz.identAsString(ident_token);
+            // TODO look for local variables in scope matching `decl_name` and emit a compile
+            // error. Only top-level declarations can be exported. Until this is done, the
+            // compile error will end up being "use of undeclared identifier" in Sema.
             const options = try comptimeExpr(gz, scope, .{ .ty = .export_options_type }, params[1]);
             _ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{
                 .decl_name = decl_name,
@@ -6142,6 +6145,16 @@ fn builtinCall(
             });
             return rvalue(gz, scope, rl, .void_value, node);
         },
+        .@"extern" => {
+            const type_inst = try typeExpr(gz, scope, params[0]);
+            const options = try comptimeExpr(gz, scope, .{ .ty = .extern_options_type }, params[1]);
+            const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{
+                .node = gz.nodeIndexToRelative(node),
+                .lhs = type_inst,
+                .rhs = options,
+            });
+            return rvalue(gz, scope, rl, result, node);
+        },
 
         .breakpoint => return simpleNoOpVoid(gz, scope, rl, node, .breakpoint),
         .fence      => return simpleNoOpVoid(gz, scope, rl, node, .fence),
src/BuiltinFn.zig
@@ -39,6 +39,7 @@ pub const Tag = enum {
     error_to_int,
     err_set_cast,
     @"export",
+    @"extern",
     fence,
     field,
     field_parent_ptr,
@@ -387,6 +388,13 @@ pub const list = list: {
                 .param_count = 2,
             },
         },
+        .{
+            "@extern",
+            .{
+                .tag = .@"extern",
+                .param_count = 2,
+            },
+        },
         .{
             "@fence",
             .{
src/Sema.zig
@@ -517,6 +517,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
         .frame              => return sema.zirFrame(           block, extended),
         .frame_address      => return sema.zirFrameAddress(    block, extended),
         .alloc              => return sema.zirAllocExtended(   block, extended),
+        .builtin_extern     => return sema.zirBuiltinExtern(   block, extended),
         .c_undef            => return sema.zirCUndef(          block, extended),
         .c_include          => return sema.zirCInclude(        block, extended),
         .c_define           => return sema.zirCDefine(         block, extended),
@@ -5488,6 +5489,16 @@ fn zirWasmMemoryGrow(
     return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirWasmMemoryGrow", .{});
 }
 
+fn zirBuiltinExtern(
+    sema: *Sema,
+    block: *Scope.Block,
+    extended: Zir.Inst.Extended.InstData,
+) InnerError!*Inst {
+    const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
+    const src: LazySrcLoc = .{ .node_offset = extra.node };
+    return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirBuiltinExtern", .{});
+}
+
 fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
     if (sema.func == null) {
         return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
src/type.zig
@@ -100,6 +100,7 @@ pub const Type = extern union {
             .@"struct",
             .call_options,
             .export_options,
+            .extern_options,
             => return .Struct,
 
             .enum_full,
@@ -618,6 +619,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => unreachable,
 
             .array_u8,
@@ -797,6 +799,7 @@ pub const Type = extern union {
                 .reduce_op => return writer.writeAll("std.builtin.ReduceOp"),
                 .call_options => return writer.writeAll("std.builtin.CallOptions"),
                 .export_options => return writer.writeAll("std.builtin.ExportOptions"),
+                .extern_options => return writer.writeAll("std.builtin.ExternOptions"),
                 .function => {
                     const payload = ty.castTag(.function).?.data;
                     try writer.writeAll("fn(");
@@ -1012,6 +1015,7 @@ pub const Type = extern union {
             .reduce_op => return Value.initTag(.reduce_op_type),
             .call_options => return Value.initTag(.call_options_type),
             .export_options => return Value.initTag(.export_options_type),
+            .extern_options => return Value.initTag(.extern_options_type),
             .inferred_alloc_const => unreachable,
             .inferred_alloc_mut => unreachable,
             else => return Value.Tag.ty.create(allocator, self),
@@ -1070,6 +1074,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => true,
 
             .@"struct" => {
@@ -1181,6 +1186,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => return 1,
 
             .fn_noreturn_no_args, // represents machine code; not a pointer
@@ -1359,6 +1365,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => return 1,
 
             .array_u8 => self.castTag(.array_u8).?.data,
@@ -1623,6 +1630,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => @panic("TODO at some point we gotta resolve builtin types"),
         };
     }
@@ -2247,6 +2255,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => return null,
 
             .@"struct" => {
@@ -2413,6 +2422,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => @panic("TODO resolve std.builtin types"),
 
             else => unreachable,
@@ -2436,6 +2446,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
@@ -2458,6 +2469,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
@@ -2502,6 +2514,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
@@ -2532,6 +2545,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
@@ -2563,6 +2577,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => @panic("TODO resolve std.builtin types"),
             else => unreachable,
         }
@@ -2603,6 +2618,7 @@ pub const Type = extern union {
             .reduce_op,
             .call_options,
             .export_options,
+            .extern_options,
             => @panic("TODO resolve std.builtin types"),
 
             else => unreachable,
@@ -2660,6 +2676,7 @@ pub const Type = extern union {
         reduce_op,
         call_options,
         export_options,
+        extern_options,
         @"null",
         @"undefined",
         fn_noreturn_no_args,
@@ -2772,6 +2789,7 @@ pub const Type = extern union {
                 .reduce_op,
                 .call_options,
                 .export_options,
+                .extern_options,
                 => @compileError("Type Tag " ++ @tagName(t) ++ " has no payload"),
 
                 .array_u8,
src/value.zig
@@ -73,6 +73,7 @@ pub const Value = extern union {
         reduce_op_type,
         call_options_type,
         export_options_type,
+        extern_options_type,
 
         undef,
         zero,
@@ -187,6 +188,7 @@ pub const Value = extern union {
                 .reduce_op_type,
                 .call_options_type,
                 .export_options_type,
+                .extern_options_type,
                 => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
 
                 .int_big_positive,
@@ -354,6 +356,7 @@ pub const Value = extern union {
             .reduce_op_type,
             .call_options_type,
             .export_options_type,
+            .extern_options_type,
             => unreachable,
 
             .ty => {
@@ -510,6 +513,7 @@ pub const Value = extern union {
             .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"),
+            .extern_options_type => return out_stream.writeAll("std.builtin.ExternOptions"),
             .abi_align_default => return out_stream.writeAll("(default ABI alignment)"),
 
             .empty_struct_value => return out_stream.writeAll("struct {}{}"),
@@ -640,6 +644,7 @@ pub const Value = extern union {
             .reduce_op_type => Type.initTag(.reduce_op),
             .call_options_type => Type.initTag(.call_options),
             .export_options_type => Type.initTag(.export_options),
+            .extern_options_type => Type.initTag(.extern_options),
 
             .int_type => {
                 const payload = self.castTag(.int_type).?.data;
@@ -1187,6 +1192,7 @@ pub const Value = extern union {
             .reduce_op_type,
             .call_options_type,
             .export_options_type,
+            .extern_options_type,
             => @panic("TODO this hash function looks pretty broken. audit it"),
         }
         return hasher.final();
@@ -1343,6 +1349,7 @@ pub const Value = extern union {
             .reduce_op_type,
             .call_options_type,
             .export_options_type,
+            .extern_options_type,
             => true,
 
             .zero,
src/Zir.zig
@@ -1258,6 +1258,9 @@ pub const Inst = struct {
         ///  * 0b0X00 - 1=const, 0=var
         ///  * 0bX000 - is comptime
         alloc,
+        /// The `@extern` builtin.
+        /// `operand` is payload index to `BinNode`.
+        builtin_extern,
         /// `operand` is payload index to `UnNode`.
         c_undef,
         /// `operand` is payload index to `UnNode`.
@@ -1353,6 +1356,7 @@ pub const Inst = struct {
         reduce_op_type,
         call_options_type,
         export_options_type,
+        extern_options_type,
 
         /// `undefined` (untyped)
         undef,
@@ -1580,6 +1584,10 @@ pub const Inst = struct {
                 .ty = Type.initTag(.type),
                 .val = Value.initTag(.export_options_type),
             },
+            .extern_options_type = .{
+                .ty = Type.initTag(.type),
+                .val = Value.initTag(.extern_options_type),
+            },
 
             .undef = .{
                 .ty = Type.initTag(.@"undefined"),
@@ -2598,6 +2606,7 @@ const Writer = struct {
 
             .func,
             .alloc,
+            .builtin_extern,
             .c_undef,
             .c_include,
             .c_define,