diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-04-29 19:44:51 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-04-29 19:44:51 -0700 |
| commit | 86d564eed8b9eacd0447598dd364ab04c5b1b04d (patch) | |
| tree | d4fff51821459dd9ae181a31c667cac1bd2b3bbc /src | |
| parent | ba9b9cb38dbd66c7a600606c5599c80b115e0f85 (diff) | |
| download | zig-86d564eed8b9eacd0447598dd364ab04c5b1b04d.tar.gz zig-86d564eed8b9eacd0447598dd364ab04c5b1b04d.zip | |
AstGen: implement extern variables
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 20 | ||||
| -rw-r--r-- | src/Module.zig | 51 | ||||
| -rw-r--r-- | src/Sema.zig | 12 | ||||
| -rw-r--r-- | src/Zir.zig | 72 |
4 files changed, 139 insertions, 16 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index c7706a1dd0..c5611eeb88 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2961,7 +2961,7 @@ fn globalVarDecl( assert(var_decl.comptime_token == null); // handled by parser - const var_inst: Zir.Inst.Index = if (var_decl.ast.init_node != 0) vi: { + if (var_decl.ast.init_node != 0) { if (is_extern) { return astgen.failNode( var_decl.ast.init_node, @@ -2989,19 +2989,25 @@ fn globalVarDecl( // We do this at the end so that the instruction index marks the end // range of a top level declaration. _ = try block_scope.addBreak(.break_inline, block_inst, init_inst); - try block_scope.setBlockBody(block_inst); - break :vi block_inst; } else if (!is_extern) { return astgen.failNode(node, "variables must be initialized", .{}); } else if (var_decl.ast.type_node != 0) { // Extern variable which has an explicit type. - const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node); - return astgen.failNode(node, "TODO AstGen extern global variable", .{}); + const var_inst = try block_scope.addVar(.{ + .var_type = type_inst, + .lib_name = lib_name, + .align_inst = .none, // passed in the decls data + .init = .none, + .is_extern = true, + }); + + _ = try block_scope.addBreak(.break_inline, block_inst, var_inst); } else { return astgen.failNode(node, "unable to infer variable type", .{}); - }; + } + try block_scope.setBlockBody(block_inst); const name_token = var_decl.ast.mut_token + 1; const name_str_index = try gz.identAsString(name_token); @@ -3013,7 +3019,7 @@ fn globalVarDecl( wip_decls.payload.appendSliceAssumeCapacity(&casted); } wip_decls.payload.appendAssumeCapacity(name_str_index); - wip_decls.payload.appendAssumeCapacity(var_inst); + wip_decls.payload.appendAssumeCapacity(block_inst); if (align_inst != .none) { wip_decls.payload.appendAssumeCapacity(@enumToInt(align_inst)); } diff --git a/src/Module.zig b/src/Module.zig index 2bbc5383c8..94a0dd5c54 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1462,6 +1462,57 @@ pub const Scope = struct { } } + pub fn addVar(gz: *GenZir, args: struct { + align_inst: Zir.Inst.Ref, + lib_name: u32, + var_type: Zir.Inst.Ref, + init: Zir.Inst.Ref, + is_extern: bool, + }) !Zir.Inst.Ref { + const astgen = gz.astgen; + const gpa = astgen.gpa; + + try gz.instructions.ensureUnusedCapacity(gpa, 1); + try astgen.instructions.ensureUnusedCapacity(gpa, 1); + + try astgen.extra.ensureUnusedCapacity( + gpa, + @typeInfo(Zir.Inst.ExtendedVar).Struct.fields.len + + @boolToInt(args.lib_name != 0) + + @boolToInt(args.align_inst != .none) + + @boolToInt(args.init != .none), + ); + const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{ + .var_type = args.var_type, + }); + if (args.lib_name != 0) { + astgen.extra.appendAssumeCapacity(args.lib_name); + } + if (args.align_inst != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst)); + } + if (args.init != .none) { + astgen.extra.appendAssumeCapacity(@enumToInt(args.init)); + } + + const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len); + astgen.instructions.appendAssumeCapacity(.{ + .tag = .extended, + .data = .{ .extended = .{ + .opcode = .variable, + .small = @bitCast(u16, Zir.Inst.ExtendedVar.Small{ + .has_lib_name = args.lib_name != 0, + .has_align = args.align_inst != .none, + .has_init = args.init != .none, + .is_extern = args.is_extern, + }), + .operand = payload_index, + } }, + }); + gz.instructions.appendAssumeCapacity(new_index); + return gz.indexToRef(new_index); + } + pub fn addCall( gz: *GenZir, tag: Zir.Inst.Tag, diff --git a/src/Sema.zig b/src/Sema.zig index ba7b87e251..949789470e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -479,6 +479,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro switch (extended.opcode) { // zig fmt: off .func => return sema.zirFuncExtended( block, extended), + .variable => return sema.zirVarExtended( block, extended), .ret_ptr => return sema.zirRetPtr( block, extended), .ret_type => return sema.zirRetType( block, extended), .this => return sema.zirThis( block, extended), @@ -5427,6 +5428,17 @@ fn zirAwait( return sema.mod.fail(&block.base, src, "TODO: Sema.zirAwait", .{}); } +fn zirVarExtended( + sema: *Sema, + block: *Scope.Block, + extended: Zir.Inst.Extended.InstData, +) InnerError!*Inst { + const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand); + const src = sema.src; + + return sema.mod.fail(&block.base, src, "TODO implement Sema.zirVarExtended", .{}); +} + fn zirFuncExtended( sema: *Sema, block: *Scope.Block, diff --git a/src/Zir.zig b/src/Zir.zig index 065649c118..565dfdc6a4 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -1496,6 +1496,10 @@ pub const Inst = struct { /// `operand` is payload index to `ExtendedFunc`. /// `small` is `ExtendedFunc.Small`. func, + /// Declares a global variable. + /// `operand` is payload index to `ExtendedVar`. + /// `small` is `ExtendedVar.Small`. + variable, /// Obtains a pointer to the return value. /// `operand` is `src_node: i32`. ret_ptr, @@ -2210,6 +2214,23 @@ pub const Inst = struct { }; /// Trailing: + /// 0. lib_name: u32, // null terminated string index, if has_lib_name is set + /// 1. align: Ref, // if has_align is set + /// 2. init: Ref // if has_init is set + /// The source node is obtained from the containing `block_inline`. + pub const ExtendedVar = struct { + var_type: Ref, + + pub const Small = packed struct { + has_lib_name: bool, + has_align: bool, + has_init: bool, + is_extern: bool, + _: u12 = undefined, + }; + }; + + /// Trailing: /// 0. param_type: Ref // for each param_types_len /// - `none` indicates that the param type is `anytype`. /// 1. body: Index // for each body_len @@ -3010,6 +3031,7 @@ const Writer = struct { .@"asm" => try self.writeAsm(stream, extended), .func => try self.writeFuncExtended(stream, extended), + .variable => try self.writeVarExtended(stream, extended), .compile_log, .typeof_peer, @@ -4015,6 +4037,34 @@ const Writer = struct { ); } + fn writeVarExtended(self: *Writer, stream: anytype, extended: Inst.Extended.InstData) !void { + const extra = self.code.extraData(Inst.ExtendedVar, extended.operand); + const small = @bitCast(Inst.ExtendedVar.Small, extended.small); + + try self.writeInstRef(stream, extra.data.var_type); + + var extra_index: usize = extra.end; + if (small.has_lib_name) { + const lib_name = self.code.nullTerminatedString(self.code.extra[extra_index]); + extra_index += 1; + try stream.print(", lib_name=\"{}\"", .{std.zig.fmtEscapes(lib_name)}); + } + const align_inst: Inst.Ref = if (!small.has_align) .none else blk: { + const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk align_inst; + }; + const init_inst: Inst.Ref = if (!small.has_init) .none else blk: { + const init_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + break :blk init_inst; + }; + try self.writeFlag(stream, ", is_extern", small.is_extern); + try self.writeOptionalInstRef(stream, ", align=", align_inst); + try self.writeOptionalInstRef(stream, ", init=", init_inst); + try stream.writeAll("))"); + } + fn writeBoolBr(self: *Writer, stream: anytype, inst: Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[inst].bool_br; const extra = self.code.extraData(Inst.Block, inst_data.payload_index); @@ -4078,15 +4128,19 @@ const Writer = struct { try self.writeFlag(stream, ", vargs", var_args); try self.writeFlag(stream, ", inferror", inferred_error_set); - try stream.writeAll(", {\n"); - self.indent += 2; - const prev_param_count = self.param_count; - self.param_count = param_types.len; - try self.writeBody(stream, body); - self.param_count = prev_param_count; - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); + if (body.len == 0) { + try stream.writeAll(", {}) "); + } else { + try stream.writeAll(", {\n"); + self.indent += 2; + const prev_param_count = self.param_count; + self.param_count = param_types.len; + try self.writeBody(stream, body); + self.param_count = prev_param_count; + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + } try self.writeSrc(stream, src); } |
