From 7c453b91b85bab6800d24feb57c4f35b8ce48d57 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 22 Apr 2021 16:31:51 -0700 Subject: [PATCH] AstGen: implement `@extern` builtin --- src/AstGen.zig | 13 +++++++++++++ src/BuiltinFn.zig | 8 ++++++++ src/Sema.zig | 11 +++++++++++ src/Zir.zig | 9 +++++++++ src/type.zig | 18 ++++++++++++++++++ src/value.zig | 7 +++++++ 6 files changed, 66 insertions(+) diff --git a/src/AstGen.zig b/src/AstGen.zig index e9b3946116..1080506192 100644 --- a/src/AstGen.zig +++ b/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), diff --git a/src/BuiltinFn.zig b/src/BuiltinFn.zig index b4d52bdc9d..ad5e15424b 100644 --- a/src/BuiltinFn.zig +++ b/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", .{ diff --git a/src/Sema.zig b/src/Sema.zig index 49610506d9..ccbd724bdb 100644 --- a/src/Sema.zig +++ b/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", .{}); diff --git a/src/Zir.zig b/src/Zir.zig index b44050fdfe..485d72992e 100644 --- a/src/Zir.zig +++ b/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, diff --git a/src/type.zig b/src/type.zig index 44d635f64a..5bcf06cb5d 100644 --- a/src/type.zig +++ b/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, diff --git a/src/value.zig b/src/value.zig index 4776cb5a76..e1ca79332c 100644 --- a/src/value.zig +++ b/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,