aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-29 19:44:51 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-29 19:44:51 -0700
commit86d564eed8b9eacd0447598dd364ab04c5b1b04d (patch)
treed4fff51821459dd9ae181a31c667cac1bd2b3bbc /src
parentba9b9cb38dbd66c7a600606c5599c80b115e0f85 (diff)
downloadzig-86d564eed8b9eacd0447598dd364ab04c5b1b04d.tar.gz
zig-86d564eed8b9eacd0447598dd364ab04c5b1b04d.zip
AstGen: implement extern variables
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig20
-rw-r--r--src/Module.zig51
-rw-r--r--src/Sema.zig12
-rw-r--r--src/Zir.zig72
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);
}