aboutsummaryrefslogtreecommitdiff
path: root/lib/std
diff options
context:
space:
mode:
authorMatthew Lugg <mlugg@mlugg.co.uk>2024-12-25 02:58:27 +0000
committerGitHub <noreply@github.com>2024-12-25 02:58:27 +0000
commit497592c9b45a94fb7b6028bf45b80f183e395a9b (patch)
tree467873c408750cb4223f3ccf31775e42ec9fbd5c /lib/std
parentaf5e731729592af4a5716edd3b1e03264d66ea46 (diff)
parent3afda4322c34dedc2319701fdfac3505c8d311e9 (diff)
downloadzig-497592c9b45a94fb7b6028bf45b80f183e395a9b.tar.gz
zig-497592c9b45a94fb7b6028bf45b80f183e395a9b.zip
Merge pull request #22303 from mlugg/131-new
compiler: analyze type and value of global declarations separately
Diffstat (limited to 'lib/std')
-rw-r--r--lib/std/zig/AstGen.zig1118
-rw-r--r--lib/std/zig/Zir.zig487
2 files changed, 974 insertions, 631 deletions
diff --git a/lib/std/zig/AstGen.zig b/lib/std/zig/AstGen.zig
index fcec69ed8f..4a9b948beb 100644
--- a/lib/std/zig/AstGen.zig
+++ b/lib/std/zig/AstGen.zig
@@ -106,7 +106,6 @@ fn setExtra(astgen: *AstGen, index: usize, extra: anytype) void {
Zir.Inst.SwitchBlock.Bits,
Zir.Inst.SwitchBlockErrUnion.Bits,
Zir.Inst.FuncFancy.Bits,
- Zir.Inst.Declaration.Flags,
=> @bitCast(@field(extra, field.name)),
else => @compileError("bad field type"),
@@ -1317,12 +1316,45 @@ fn fnProtoExpr(
return astgen.failTok(some, "function type cannot have a name", .{});
}
+ if (fn_proto.ast.align_expr != 0) {
+ return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{});
+ }
+
+ if (fn_proto.ast.addrspace_expr != 0) {
+ return astgen.failNode(fn_proto.ast.addrspace_expr, "function type cannot have an addrspace", .{});
+ }
+
+ if (fn_proto.ast.section_expr != 0) {
+ return astgen.failNode(fn_proto.ast.section_expr, "function type cannot have a linksection", .{});
+ }
+
+ const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
+ const is_inferred_error = token_tags[maybe_bang] == .bang;
+ if (is_inferred_error) {
+ return astgen.failTok(maybe_bang, "function type cannot have an inferred error set", .{});
+ }
+
const is_extern = blk: {
const maybe_extern_token = fn_proto.extern_export_inline_token orelse break :blk false;
break :blk token_tags[maybe_extern_token] == .keyword_extern;
};
assert(!is_extern);
+ return fnProtoExprInner(gz, scope, ri, node, fn_proto, false);
+}
+
+fn fnProtoExprInner(
+ gz: *GenZir,
+ scope: *Scope,
+ ri: ResultInfo,
+ node: Ast.Node.Index,
+ fn_proto: Ast.full.FnProto,
+ implicit_ccc: bool,
+) InnerError!Zir.Inst.Ref {
+ const astgen = gz.astgen;
+ const tree = astgen.tree;
+ const token_tags = tree.tokens.items(.tag);
+
var block_scope = gz.makeSubBlock(scope);
defer block_scope.unstack();
@@ -1386,18 +1418,6 @@ fn fnProtoExpr(
break :is_var_args false;
};
- if (fn_proto.ast.align_expr != 0) {
- return astgen.failNode(fn_proto.ast.align_expr, "function type cannot have an alignment", .{});
- }
-
- if (fn_proto.ast.addrspace_expr != 0) {
- return astgen.failNode(fn_proto.ast.addrspace_expr, "function type cannot have an addrspace", .{});
- }
-
- if (fn_proto.ast.section_expr != 0) {
- return astgen.failNode(fn_proto.ast.section_expr, "function type cannot have a linksection", .{});
- }
-
const cc: Zir.Inst.Ref = if (fn_proto.ast.callconv_expr != 0)
try expr(
&block_scope,
@@ -1405,14 +1425,11 @@ fn fnProtoExpr(
.{ .rl = .{ .coerced_ty = try block_scope.addBuiltinValue(fn_proto.ast.callconv_expr, .calling_convention) } },
fn_proto.ast.callconv_expr,
)
+ else if (implicit_ccc)
+ try block_scope.addBuiltinValue(node, .calling_convention_c)
else
- Zir.Inst.Ref.none;
+ .none;
- const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
- const is_inferred_error = token_tags[maybe_bang] == .bang;
- if (is_inferred_error) {
- return astgen.failTok(maybe_bang, "function type cannot have an inferred error set", .{});
- }
const ret_ty = try expr(&block_scope, scope, coerced_type_ri, fn_proto.ast.return_type);
const result = try block_scope.addFunc(.{
@@ -1428,11 +1445,8 @@ fn fnProtoExpr(
.param_block = block_inst,
.body_gz = null,
- .lib_name = .empty,
.is_var_args = is_var_args,
.is_inferred_error = false,
- .is_test = false,
- .is_extern = false,
.is_noinline = false,
.noalias_bits = noalias_bits,
@@ -4121,17 +4135,6 @@ fn fnDecl(
const saved_cursor = astgen.saveSourceCursor();
- var decl_gz: GenZir = .{
- .is_comptime = true,
- .decl_node_index = fn_proto.ast.proto_node,
- .decl_line = astgen.source_line,
- .parent = scope,
- .astgen = astgen,
- .instructions = gz.instructions,
- .instructions_top = gz.instructions.items.len,
- };
- defer decl_gz.unstack();
-
const decl_column = astgen.source_column;
// Set this now, since parameter types, return type, etc may be generic.
@@ -4152,12 +4155,140 @@ fn fnDecl(
const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
break :blk token_tags[maybe_inline_token] == .keyword_inline;
};
+ const lib_name = if (fn_proto.lib_name) |lib_name_token| blk: {
+ const lib_name_str = try astgen.strLitAsString(lib_name_token);
+ const lib_name_slice = astgen.string_bytes.items[@intFromEnum(lib_name_str.index)..][0..lib_name_str.len];
+ if (mem.indexOfScalar(u8, lib_name_slice, 0) != null) {
+ return astgen.failTok(lib_name_token, "library name cannot contain null bytes", .{});
+ } else if (lib_name_str.len == 0) {
+ return astgen.failTok(lib_name_token, "library name cannot be empty", .{});
+ }
+ break :blk lib_name_str.index;
+ } else .empty;
+ if (fn_proto.ast.callconv_expr != 0 and has_inline_keyword) {
+ return astgen.failNode(
+ fn_proto.ast.callconv_expr,
+ "explicit callconv incompatible with inline keyword",
+ .{},
+ );
+ }
+ const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
+ const is_inferred_error = token_tags[maybe_bang] == .bang;
+ if (body_node == 0) {
+ if (!is_extern) {
+ return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
+ }
+ if (is_inferred_error) {
+ return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
+ }
+ } else {
+ assert(!is_extern); // validated by parser (TODO why???)
+ }
+
+ wip_members.nextDecl(decl_inst);
+
+ var type_gz: GenZir = .{
+ .is_comptime = true,
+ .decl_node_index = fn_proto.ast.proto_node,
+ .decl_line = astgen.source_line,
+ .parent = scope,
+ .astgen = astgen,
+ .instructions = gz.instructions,
+ .instructions_top = gz.instructions.items.len,
+ };
+ defer type_gz.unstack();
+
+ if (is_extern) {
+ // We include a function *type*, not a value.
+ const type_inst = try fnProtoExprInner(&type_gz, &type_gz.base, .{ .rl = .none }, decl_node, fn_proto, true);
+ _ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, decl_node);
+ }
+
+ var align_gz = type_gz.makeSubBlock(scope);
+ defer align_gz.unstack();
+
+ if (fn_proto.ast.align_expr != 0) {
+ astgen.restoreSourceCursor(saved_cursor);
+ const inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, fn_proto.ast.align_expr);
+ _ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
+ }
+
+ var linksection_gz = align_gz.makeSubBlock(scope);
+ defer linksection_gz.unstack();
+
+ if (fn_proto.ast.section_expr != 0) {
+ astgen.restoreSourceCursor(saved_cursor);
+ const inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, fn_proto.ast.section_expr);
+ _ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
+ }
+
+ var addrspace_gz = linksection_gz.makeSubBlock(scope);
+ defer addrspace_gz.unstack();
+
+ if (fn_proto.ast.addrspace_expr != 0) {
+ astgen.restoreSourceCursor(saved_cursor);
+ const addrspace_ty = try addrspace_gz.addBuiltinValue(fn_proto.ast.addrspace_expr, .address_space);
+ const inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, fn_proto.ast.section_expr);
+ _ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, inst, decl_node);
+ }
+
+ var value_gz = addrspace_gz.makeSubBlock(scope);
+ defer value_gz.unstack();
+
+ if (!is_extern) {
+ // We include a function *value*, not a type.
+ astgen.restoreSourceCursor(saved_cursor);
+ try astgen.fnDeclInner(&value_gz, &value_gz.base, saved_cursor, decl_inst, decl_node, body_node, fn_proto);
+ }
+
+ // *Now* we can incorporate the full source code into the hasher.
+ astgen.src_hasher.update(tree.getNodeSource(decl_node));
+
+ var hash: std.zig.SrcHash = undefined;
+ astgen.src_hasher.final(&hash);
+ try setDeclaration(decl_inst, .{
+ .src_hash = hash,
+ .src_line = type_gz.decl_line,
+ .src_column = decl_column,
+
+ .kind = .@"const",
+ .name = try astgen.identAsString(fn_name_token),
+ .is_pub = is_pub,
+ .is_threadlocal = false,
+ .linkage = if (is_extern) .@"extern" else if (is_export) .@"export" else .normal,
+ .lib_name = lib_name,
+
+ .type_gz = &type_gz,
+ .align_gz = &align_gz,
+ .linksection_gz = &linksection_gz,
+ .addrspace_gz = &addrspace_gz,
+ .value_gz = &value_gz,
+ });
+}
+
+fn fnDeclInner(
+ astgen: *AstGen,
+ decl_gz: *GenZir,
+ scope: *Scope,
+ saved_cursor: SourceCursor,
+ decl_inst: Zir.Inst.Index,
+ decl_node: Ast.Node.Index,
+ body_node: Ast.Node.Index,
+ fn_proto: Ast.full.FnProto,
+) InnerError!void {
+ const tree = astgen.tree;
+ const token_tags = tree.tokens.items(.tag);
+
const is_noinline = blk: {
const maybe_noinline_token = fn_proto.extern_export_inline_token orelse break :blk false;
break :blk token_tags[maybe_noinline_token] == .keyword_noinline;
};
-
- wip_members.nextDecl(decl_inst);
+ const has_inline_keyword = blk: {
+ const maybe_inline_token = fn_proto.extern_export_inline_token orelse break :blk false;
+ break :blk token_tags[maybe_inline_token] == .keyword_inline;
+ };
+ const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
+ const is_inferred_error = token_tags[maybe_bang] == .bang;
// Note that the capacity here may not be sufficient, as this does not include `anytype` parameters.
var param_insts: std.ArrayListUnmanaged(Zir.Inst.Index) = try .initCapacity(astgen.arena, fn_proto.ast.params.len);
@@ -4192,11 +4323,9 @@ fn fnDecl(
break :blk .empty;
const param_name = try astgen.identAsString(name_token);
- if (!is_extern) {
- try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes, .@"function parameter");
- }
+ try astgen.detectLocalShadowing(params_scope, param_name, name_token, name_bytes, .@"function parameter");
break :blk param_name;
- } else if (!is_extern) {
+ } else {
if (param.anytype_ellipsis3) |tok| {
return astgen.failTok(tok, "missing parameter name", .{});
} else {
@@ -4225,7 +4354,7 @@ fn fnDecl(
}
return astgen.failNode(param.type_expr, "missing parameter name", .{});
}
- } else .empty;
+ };
const param_inst = if (is_anytype) param: {
const name_token = param.name_token orelse param.anytype_ellipsis3.?;
@@ -4251,12 +4380,12 @@ fn fnDecl(
break :param param_inst.toRef();
};
- if (param_name == .empty or is_extern) continue;
+ if (param_name == .empty) continue;
const sub_scope = try astgen.arena.create(Scope.LocalVal);
sub_scope.* = .{
.parent = params_scope,
- .gen_zir = &decl_gz,
+ .gen_zir = decl_gz,
.name = param_name,
.inst = param_inst,
.token_src = param.name_token.?,
@@ -4268,23 +4397,9 @@ fn fnDecl(
break :is_var_args false;
};
- const lib_name = if (fn_proto.lib_name) |lib_name_token| blk: {
- const lib_name_str = try astgen.strLitAsString(lib_name_token);
- const lib_name_slice = astgen.string_bytes.items[@intFromEnum(lib_name_str.index)..][0..lib_name_str.len];
- if (mem.indexOfScalar(u8, lib_name_slice, 0) != null) {
- return astgen.failTok(lib_name_token, "library name cannot contain null bytes", .{});
- } else if (lib_name_str.len == 0) {
- return astgen.failTok(lib_name_token, "library name cannot be empty", .{});
- }
- break :blk lib_name_str.index;
- } else .empty;
-
- const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
- const is_inferred_error = token_tags[maybe_bang] == .bang;
-
// After creating the function ZIR instruction, it will need to update the break
- // instructions inside the expression blocks for align, addrspace, cc, and ret_ty
- // to use the function instruction as the "block" to break from.
+ // instructions inside the expression blocks for cc and ret_ty to use the function
+ // instruction as the body to break from.
var ret_gz = decl_gz.makeSubBlock(params_scope);
defer ret_gz.unstack();
@@ -4309,13 +4424,6 @@ fn fnDecl(
defer cc_gz.unstack();
const cc_ref: Zir.Inst.Ref = blk: {
if (fn_proto.ast.callconv_expr != 0) {
- if (has_inline_keyword) {
- return astgen.failNode(
- fn_proto.ast.callconv_expr,
- "explicit callconv incompatible with inline keyword",
- .{},
- );
- }
const inst = try expr(
&cc_gz,
scope,
@@ -4328,10 +4436,6 @@ fn fnDecl(
}
_ = try cc_gz.addBreak(.break_inline, @enumFromInt(0), inst);
break :blk inst;
- } else if (is_extern) {
- const inst = try cc_gz.addBuiltinValue(decl_node, .calling_convention_c);
- _ = try cc_gz.addBreak(.break_inline, @enumFromInt(0), inst);
- break :blk inst;
} else if (has_inline_keyword) {
const inst = try cc_gz.addBuiltinValue(decl_node, .calling_convention_inline);
_ = try cc_gz.addBreak(.break_inline, @enumFromInt(0), inst);
@@ -4341,167 +4445,86 @@ fn fnDecl(
}
};
- const func_inst: Zir.Inst.Ref = if (body_node == 0) func: {
- if (!is_extern) {
- return astgen.failTok(fn_proto.ast.fn_token, "non-extern function has no body", .{});
- }
- if (is_inferred_error) {
- return astgen.failTok(maybe_bang, "function prototype may not have inferred error set", .{});
- }
- break :func try decl_gz.addFunc(.{
- .src_node = decl_node,
- .cc_ref = cc_ref,
- .cc_gz = &cc_gz,
- .ret_ref = ret_ref,
- .ret_gz = &ret_gz,
- .ret_param_refs = ret_body_param_refs,
- .param_block = decl_inst,
- .param_insts = param_insts.items,
- .body_gz = null,
- .lib_name = lib_name,
- .is_var_args = is_var_args,
- .is_inferred_error = false,
- .is_test = false,
- .is_extern = true,
- .is_noinline = is_noinline,
- .noalias_bits = noalias_bits,
- .proto_hash = undefined, // ignored for `body_gz == null`
- });
- } else func: {
- var body_gz: GenZir = .{
- .is_comptime = false,
- .decl_node_index = fn_proto.ast.proto_node,
- .decl_line = decl_gz.decl_line,
- .parent = params_scope,
- .astgen = astgen,
- .instructions = gz.instructions,
- .instructions_top = gz.instructions.items.len,
- };
- defer body_gz.unstack();
-
- // We want `params_scope` to be stacked like this:
- // body_gz (top)
- // param2
- // param1
- // param0
- // decl_gz (bottom)
-
- // Construct the prototype hash.
- // Leave `astgen.src_hasher` unmodified; this will be used for hashing
- // the *whole* function declaration, including its body.
- var proto_hasher = astgen.src_hasher;
- const proto_node = tree.nodes.items(.data)[decl_node].lhs;
- proto_hasher.update(tree.getNodeSource(proto_node));
- var proto_hash: std.zig.SrcHash = undefined;
- proto_hasher.final(&proto_hash);
-
- const prev_fn_block = astgen.fn_block;
- const prev_fn_ret_ty = astgen.fn_ret_ty;
- defer {
- astgen.fn_block = prev_fn_block;
- astgen.fn_ret_ty = prev_fn_ret_ty;
- }
- astgen.fn_block = &body_gz;
- astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {
- // We're essentially guaranteed to need the return type at some point,
- // since the return type is likely not `void` or `noreturn` so there
- // will probably be an explicit return requiring RLS. Fetch this
- // return type now so the rest of the function can use it.
- break :r try body_gz.addNode(.ret_type, decl_node);
- } else ret_ref;
-
- const prev_var_args = astgen.fn_var_args;
- astgen.fn_var_args = is_var_args;
- defer astgen.fn_var_args = prev_var_args;
-
- astgen.advanceSourceCursorToNode(body_node);
- const lbrace_line = astgen.source_line - decl_gz.decl_line;
- const lbrace_column = astgen.source_column;
-
- _ = try fullBodyExpr(&body_gz, &body_gz.base, .{ .rl = .none }, body_node, .allow_branch_hint);
- try checkUsed(gz, scope, params_scope);
-
- if (!body_gz.endsWithNoReturn()) {
- // As our last action before the return, "pop" the error trace if needed
- _ = try body_gz.addRestoreErrRetIndex(.ret, .always, decl_node);
-
- // Add implicit return at end of function.
- _ = try body_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node));
- }
-
- break :func try decl_gz.addFunc(.{
- .src_node = decl_node,
- .cc_ref = cc_ref,
- .cc_gz = &cc_gz,
- .ret_ref = ret_ref,
- .ret_gz = &ret_gz,
- .ret_param_refs = ret_body_param_refs,
- .lbrace_line = lbrace_line,
- .lbrace_column = lbrace_column,
- .param_block = decl_inst,
- .param_insts = param_insts.items,
- .body_gz = &body_gz,
- .lib_name = lib_name,
- .is_var_args = is_var_args,
- .is_inferred_error = is_inferred_error,
- .is_test = false,
- .is_extern = false,
- .is_noinline = is_noinline,
- .noalias_bits = noalias_bits,
- .proto_hash = proto_hash,
- });
+ var body_gz: GenZir = .{
+ .is_comptime = false,
+ .decl_node_index = fn_proto.ast.proto_node,
+ .decl_line = decl_gz.decl_line,
+ .parent = params_scope,
+ .astgen = astgen,
+ .instructions = decl_gz.instructions,
+ .instructions_top = decl_gz.instructions.items.len,
};
+ defer body_gz.unstack();
+
+ // The scope stack looks like this:
+ // body_gz (top)
+ // param2
+ // param1
+ // param0
+ // decl_gz (bottom)
+
+ // Construct the prototype hash.
+ // Leave `astgen.src_hasher` unmodified; this will be used for hashing
+ // the *whole* function declaration, including its body.
+ var proto_hasher = astgen.src_hasher;
+ const proto_node = tree.nodes.items(.data)[decl_node].lhs;
+ proto_hasher.update(tree.getNodeSource(proto_node));
+ var proto_hash: std.zig.SrcHash = undefined;
+ proto_hasher.final(&proto_hash);
- // Before we stack more stuff onto `decl_gz`, add its final instruction.
- _ = try decl_gz.addBreak(.break_inline, decl_inst, func_inst);
+ const prev_fn_block = astgen.fn_block;
+ const prev_fn_ret_ty = astgen.fn_ret_ty;
+ defer {
+ astgen.fn_block = prev_fn_block;
+ astgen.fn_ret_ty = prev_fn_ret_ty;
+ }
+ astgen.fn_block = &body_gz;
+ astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: {
+ // We're essentially guaranteed to need the return type at some point,
+ // since the return type is likely not `void` or `noreturn` so there
+ // will probably be an explicit return requiring RLS. Fetch this
+ // return type now so the rest of the function can use it.
+ break :r try body_gz.addNode(.ret_type, decl_node);
+ } else ret_ref;
- // Now that `cc_gz,` `ret_gz`, and `body_gz` are unstacked, we evaluate align, addrspace, and linksection.
+ const prev_var_args = astgen.fn_var_args;
+ astgen.fn_var_args = is_var_args;
+ defer astgen.fn_var_args = prev_var_args;
- // We're jumping back in source, so restore the cursor.
- astgen.restoreSourceCursor(saved_cursor);
+ astgen.advanceSourceCursorToNode(body_node);
+ const lbrace_line = astgen.source_line - decl_gz.decl_line;
+ const lbrace_column = astgen.source_column;
- var align_gz = decl_gz.makeSubBlock(scope);
- defer align_gz.unstack();
- if (fn_proto.ast.align_expr != 0) {
- const inst = try expr(&decl_gz, &decl_gz.base, coerced_align_ri, fn_proto.ast.align_expr);
- _ = try align_gz.addBreak(.break_inline, decl_inst, inst);
- }
+ _ = try fullBodyExpr(&body_gz, &body_gz.base, .{ .rl = .none }, body_node, .allow_branch_hint);
+ try checkUsed(decl_gz, scope, params_scope);
- var section_gz = align_gz.makeSubBlock(scope);
- defer section_gz.unstack();
- if (fn_proto.ast.section_expr != 0) {
- const inst = try expr(&decl_gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, fn_proto.ast.section_expr);
- _ = try section_gz.addBreak(.break_inline, decl_inst, inst);
- }
+ if (!body_gz.endsWithNoReturn()) {
+ // As our last action before the return, "pop" the error trace if needed
+ _ = try body_gz.addRestoreErrRetIndex(.ret, .always, decl_node);
- var addrspace_gz = section_gz.makeSubBlock(scope);
- defer addrspace_gz.unstack();
- if (fn_proto.ast.addrspace_expr != 0) {
- const addrspace_ty = try decl_gz.addBuiltinValue(fn_proto.ast.addrspace_expr, .address_space);
- const inst = try expr(&decl_gz, scope, .{ .rl = .{ .coerced_ty = addrspace_ty } }, fn_proto.ast.addrspace_expr);
- _ = try addrspace_gz.addBreak(.break_inline, decl_inst, inst);
+ // Add implicit return at end of function.
+ _ = try body_gz.addUnTok(.ret_implicit, .void_value, tree.lastToken(body_node));
}
- // *Now* we can incorporate the full source code into the hasher.
- astgen.src_hasher.update(tree.getNodeSource(decl_node));
-
- var hash: std.zig.SrcHash = undefined;
- astgen.src_hasher.final(&hash);
- try setDeclaration(
- decl_inst,
- hash,
- .{ .named = fn_name_token },
- decl_gz.decl_line,
- decl_column,
- is_pub,
- is_export,
- &decl_gz,
- .{
- .align_gz = &align_gz,
- .linksection_gz = &section_gz,
- .addrspace_gz = &addrspace_gz,
- },
- );
+ const func_inst = try decl_gz.addFunc(.{
+ .src_node = decl_node,
+ .cc_ref = cc_ref,
+ .cc_gz = &cc_gz,
+ .ret_ref = ret_ref,
+ .ret_gz = &ret_gz,
+ .ret_param_refs = ret_body_param_refs,
+ .lbrace_line = lbrace_line,
+ .lbrace_column = lbrace_column,
+ .param_block = decl_inst,
+ .param_insts = param_insts.items,
+ .body_gz = &body_gz,
+ .is_var_args = is_var_args,
+ .is_inferred_error = is_inferred_error,
+ .is_noinline = is_noinline,
+ .noalias_bits = noalias_bits,
+ .proto_hash = proto_hash,
+ });
+ _ = try decl_gz.addBreakWithSrcNode(.break_inline, decl_inst, func_inst, decl_node);
}
fn globalVarDecl(
@@ -4522,26 +4545,7 @@ fn globalVarDecl(
astgen.src_hasher.update(std.mem.asBytes(&astgen.source_column));
const is_mutable = token_tags[var_decl.ast.mut_token] == .keyword_var;
- // We do this at the beginning so that the instruction index marks the range start
- // of the top level declaration.
- const decl_inst = try gz.makeDeclaration(node);
-
const name_token = var_decl.ast.mut_token + 1;
- astgen.advanceSourceCursorToNode(node);
-
- var block_scope: GenZir = .{
- .parent = scope,
- .decl_node_index = node,
- .decl_line = astgen.source_line,
- .astgen = astgen,
- .is_comptime = true,
- .instructions = gz.instructions,
- .instructions_top = gz.instructions.items.len,
- };
- defer block_scope.unstack();
-
- const decl_column = astgen.source_column;
-
const is_pub = var_decl.visib_token != null;
const is_export = blk: {
const maybe_export_token = var_decl.extern_export_token orelse break :blk false;
@@ -4551,15 +4555,12 @@ fn globalVarDecl(
const maybe_extern_token = var_decl.extern_export_token orelse break :blk false;
break :blk token_tags[maybe_extern_token] == .keyword_extern;
};
- wip_members.nextDecl(decl_inst);
-
const is_threadlocal = if (var_decl.threadlocal_token) |tok| blk: {
if (!is_mutable) {
return astgen.failTok(tok, "threadlocal variable cannot be constant", .{});
}
break :blk true;
} else false;
-
const lib_name = if (var_decl.lib_name) |lib_name_token| blk: {
const lib_name_str = try astgen.strLitAsString(lib_name_token);
const lib_name_slice = astgen.string_bytes.items[@intFromEnum(lib_name_str.index)..][0..lib_name_str.len];
@@ -4571,9 +4572,14 @@ fn globalVarDecl(
break :blk lib_name_str.index;
} else .empty;
- assert(var_decl.comptime_token == null); // handled by parser
+ astgen.advanceSourceCursorToNode(node);
+
+ const decl_column = astgen.source_column;
+
+ const decl_inst = try gz.makeDeclaration(node);
+ wip_members.nextDecl(decl_inst);
- const var_inst: Zir.Inst.Ref = 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,
@@ -4581,102 +4587,91 @@ fn globalVarDecl(
.{},
);
}
+ } else {
+ if (!is_extern) {
+ return astgen.failNode(node, "variables must be initialized", .{});
+ }
+ }
- const type_inst: Zir.Inst.Ref = if (var_decl.ast.type_node != 0)
- try expr(
- &block_scope,
- &block_scope.base,
- coerced_type_ri,
- var_decl.ast.type_node,
- )
- else
- .none;
-
- block_scope.anon_name_strategy = .parent;
+ if (is_extern and var_decl.ast.type_node == 0) {
+ return astgen.failNode(node, "unable to infer variable type", .{});
+ }
- const init_inst = try expr(
- &block_scope,
- &block_scope.base,
- if (type_inst != .none) .{ .rl = .{ .ty = type_inst } } else .{ .rl = .none },
- var_decl.ast.init_node,
- );
+ assert(var_decl.comptime_token == null); // handled by parser
- if (is_mutable) {
- const var_inst = try block_scope.addVar(.{
- .var_type = type_inst,
- .lib_name = .empty,
- .align_inst = .none, // passed via the decls data
- .init = init_inst,
- .is_extern = false,
- .is_const = !is_mutable,
- .is_threadlocal = is_threadlocal,
- });
- break :vi var_inst;
- } else {
- break :vi init_inst;
- }
- } else if (!is_extern) {
- return astgen.failNode(node, "variables must be initialized", .{});
- } else if (var_decl.ast.type_node != 0) vi: {
- // Extern variable which has an explicit type.
- const type_inst = try typeExpr(&block_scope, &block_scope.base, var_decl.ast.type_node);
-
- block_scope.anon_name_strategy = .parent;
-
- const var_inst = try block_scope.addVar(.{
- .var_type = type_inst,
- .lib_name = lib_name,
- .align_inst = .none, // passed via the decls data
- .init = .none,
- .is_extern = true,
- .is_const = !is_mutable,
- .is_threadlocal = is_threadlocal,
- });
- break :vi var_inst;
- } else {
- return astgen.failNode(node, "unable to infer variable type", .{});
+ var type_gz: GenZir = .{
+ .parent = scope,
+ .decl_node_index = node,
+ .decl_line = astgen.source_line,
+ .astgen = astgen,
+ .is_comptime = true,
+ .instructions = gz.instructions,
+ .instructions_top = gz.instructions.items.len,
};
+ defer type_gz.unstack();
+
+ if (var_decl.ast.type_node != 0) {
+ const type_inst = try expr(&type_gz, &type_gz.base, coerced_type_ri, var_decl.ast.type_node);
+ _ = try type_gz.addBreakWithSrcNode(.break_inline, decl_inst, type_inst, node);
+ }
- // We do this at the end so that the instruction index marks the end
- // range of a top level declaration.
- _ = try block_scope.addBreakWithSrcNode(.break_inline, decl_inst, var_inst, node);
+ var align_gz = type_gz.makeSubBlock(scope);
+ defer align_gz.unstack();
- var align_gz = block_scope.makeSubBlock(scope);
if (var_decl.ast.align_node != 0) {
- const align_inst = try fullBodyExpr(&align_gz, &align_gz.base, coerced_align_ri, var_decl.ast.align_node, .normal);
+ const align_inst = try expr(&align_gz, &align_gz.base, coerced_align_ri, var_decl.ast.align_node);
_ = try align_gz.addBreakWithSrcNode(.break_inline, decl_inst, align_inst, node);
}
- var linksection_gz = align_gz.makeSubBlock(scope);
+ var linksection_gz = type_gz.makeSubBlock(scope);
+ defer linksection_gz.unstack();
+
if (var_decl.ast.section_node != 0) {
- const linksection_inst = try fullBodyExpr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, var_decl.ast.section_node, .normal);
+ const linksection_inst = try expr(&linksection_gz, &linksection_gz.base, coerced_linksection_ri, var_decl.ast.section_node);
_ = try linksection_gz.addBreakWithSrcNode(.break_inline, decl_inst, linksection_inst, node);
}
- var addrspace_gz = linksection_gz.makeSubBlock(scope);
+ var addrspace_gz = type_gz.makeSubBlock(scope);
+ defer addrspace_gz.unstack();
+
if (var_decl.ast.addrspace_node != 0) {
const addrspace_ty = try addrspace_gz.addBuiltinValue(var_decl.ast.addrspace_node, .address_space);
- const addrspace_inst = try fullBodyExpr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, var_decl.ast.addrspace_node, .normal);
+ const addrspace_inst = try expr(&addrspace_gz, &addrspace_gz.base, .{ .rl = .{ .coerced_ty = addrspace_ty } }, var_decl.ast.addrspace_node);
_ = try addrspace_gz.addBreakWithSrcNode(.break_inline, decl_inst, addrspace_inst, node);
}
+ var init_gz = type_gz.makeSubBlock(scope);
+ defer init_gz.unstack();
+
+ if (var_decl.ast.init_node != 0) {
+ init_gz.anon_name_strategy = .parent;
+ const init_ri: ResultInfo = if (var_decl.ast.type_node != 0) .{
+ .rl = .{ .coerced_ty = decl_inst.toRef() },
+ } else .{ .rl = .none };
+ const init_inst = try expr(&init_gz, &init_gz.base, init_ri, var_decl.ast.init_node);
+ _ = try init_gz.addBreakWithSrcNode(.break_inline, decl_inst, init_inst, node);
+ }
+
var hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&hash);
- try setDeclaration(
- decl_inst,
- hash,
- .{ .named = name_token },
- block_scope.decl_line,
- decl_column,
- is_pub,
- is_export,
- &block_scope,
- .{
- .align_gz = &align_gz,
- .linksection_gz = &linksection_gz,
- .addrspace_gz = &addrspace_gz,
- },
- );
+ try setDeclaration(decl_inst, .{
+ .src_hash = hash,
+ .src_line = type_gz.decl_line,
+ .src_column = decl_column,
+
+ .kind = if (is_mutable) .@"var" else .@"const",
+ .name = try astgen.identAsString(name_token),
+ .is_pub = is_pub,
+ .is_threadlocal = is_threadlocal,
+ .linkage = if (is_extern) .@"extern" else if (is_export) .@"export" else .normal,
+ .lib_name = lib_name,
+
+ .type_gz = &type_gz,
+ .align_gz = &align_gz,
+ .linksection_gz = &linksection_gz,
+ .addrspace_gz = &addrspace_gz,
+ .value_gz = &init_gz,
+ });
}
fn comptimeDecl(
@@ -4702,37 +4697,45 @@ fn comptimeDecl(
wip_members.nextDecl(decl_inst);
astgen.advanceSourceCursorToNode(node);
- var decl_block: GenZir = .{
+ // This is just needed for the `setDeclaration` call.
+ var dummy_gz = gz.makeSubBlock(scope);
+ defer dummy_gz.unstack();
+
+ var comptime_gz: GenZir = .{
.is_comptime = true,
.decl_node_index = node,
.decl_line = astgen.source_line,
.parent = scope,
.astgen = astgen,
- .instructions = gz.instructions,
- .instructions_top = gz.instructions.items.len,
+ .instructions = dummy_gz.instructions,
+ .instructions_top = dummy_gz.instructions.items.len,
};
- defer decl_block.unstack();
+ defer comptime_gz.unstack();
const decl_column = astgen.source_column;
- const block_result = try fullBodyExpr(&decl_block, &decl_block.base, .{ .rl = .none }, body_node, .normal);
- if (decl_block.isEmpty() or !decl_block.refIsNoReturn(block_result)) {
- _ = try decl_block.addBreak(.break_inline, decl_inst, .void_value);
+ const block_result = try fullBodyExpr(&comptime_gz, &comptime_gz.base, .{ .rl = .none }, body_node, .normal);
+ if (comptime_gz.isEmpty() or !comptime_gz.refIsNoReturn(block_result)) {
+ _ = try comptime_gz.addBreak(.break_inline, decl_inst, .void_value);
}
var hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&hash);
- try setDeclaration(
- decl_inst,
- hash,
- .@"comptime",
- decl_block.decl_line,
- decl_column,
- false,
- false,
- &decl_block,
- null,
- );
+ try setDeclaration(decl_inst, .{
+ .src_hash = hash,
+ .src_line = comptime_gz.decl_line,
+ .src_column = decl_column,
+ .kind = .@"comptime",
+ .name = .empty,
+ .is_pub = false,
+ .is_threadlocal = false,
+ .linkage = .normal,
+ .type_gz = &dummy_gz,
+ .align_gz = &dummy_gz,
+ .linksection_gz = &dummy_gz,
+ .addrspace_gz = &dummy_gz,
+ .value_gz = &comptime_gz,
+ });
}
fn usingnamespaceDecl(
@@ -4764,7 +4767,11 @@ fn usingnamespaceDecl(
wip_members.nextDecl(decl_inst);
astgen.advanceSourceCursorToNode(node);
- var decl_block: GenZir = .{
+ // This is just needed for the `setDeclaration` call.
+ var dummy_gz = gz.makeSubBlock(scope);
+ defer dummy_gz.unstack();
+
+ var usingnamespace_gz: GenZir = .{
.is_comptime = true,
.decl_node_index = node,
.decl_line = astgen.source_line,
@@ -4773,26 +4780,30 @@ fn usingnamespaceDecl(
.instructions = gz.instructions,
.instructions_top = gz.instructions.items.len,
};
- defer decl_block.unstack();
+ defer usingnamespace_gz.unstack();
const decl_column = astgen.source_column;
- const namespace_inst = try typeExpr(&decl_block, &decl_block.base, type_expr);
- _ = try decl_block.addBreak(.break_inline, decl_inst, namespace_inst);
+ const namespace_inst = try typeExpr(&usingnamespace_gz, &usingnamespace_gz.base, type_expr);
+ _ = try usingnamespace_gz.addBreak(.break_inline, decl_inst, namespace_inst);
var hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&hash);
- try setDeclaration(
- decl_inst,
- hash,
- .@"usingnamespace",
- decl_block.decl_line,
- decl_column,
- is_pub,
- false,
- &decl_block,
- null,
- );
+ try setDeclaration(decl_inst, .{
+ .src_hash = hash,
+ .src_line = usingnamespace_gz.decl_line,
+ .src_column = decl_column,
+ .kind = .@"usingnamespace",
+ .name = .empty,
+ .is_pub = is_pub,
+ .is_threadlocal = false,
+ .linkage = .normal,
+ .type_gz = &dummy_gz,
+ .align_gz = &dummy_gz,
+ .linksection_gz = &dummy_gz,
+ .addrspace_gz = &dummy_gz,
+ .value_gz = &usingnamespace_gz,
+ });
}
fn testDecl(
@@ -4819,14 +4830,18 @@ fn testDecl(
wip_members.nextDecl(decl_inst);
astgen.advanceSourceCursorToNode(node);
+ // This is just needed for the `setDeclaration` call.
+ var dummy_gz: GenZir = gz.makeSubBlock(scope);
+ defer dummy_gz.unstack();
+
var decl_block: GenZir = .{
.is_comptime = true,
.decl_node_index = node,
.decl_line = astgen.source_line,
.parent = scope,
.astgen = astgen,
- .instructions = gz.instructions,
- .instructions_top = gz.instructions.items.len,
+ .instructions = dummy_gz.instructions,
+ .instructions_top = dummy_gz.instructions.items.len,
};
defer decl_block.unstack();
@@ -4835,11 +4850,21 @@ fn testDecl(
const main_tokens = tree.nodes.items(.main_token);
const token_tags = tree.tokens.items(.tag);
const test_token = main_tokens[node];
+
const test_name_token = test_token + 1;
- const test_name: DeclarationName = switch (token_tags[test_name_token]) {
- else => .unnamed_test,
- .string_literal => .{ .named_test = test_name_token },
- .identifier => blk: {
+ const test_name: Zir.NullTerminatedString = switch (token_tags[test_name_token]) {
+ else => .empty,
+ .string_literal => name: {
+ const name = try astgen.strLitAsString(test_name_token);
+ const slice = astgen.string_bytes.items[@intFromEnum(name.index)..][0..name.len];
+ if (mem.indexOfScalar(u8, slice, 0) != null) {
+ return astgen.failTok(test_name_token, "test name cannot contain null bytes", .{});
+ } else if (slice.len == 0) {
+ return astgen.failTok(test_name_token, "empty test name must be omitted", .{});
+ }
+ break :name name.index;
+ },
+ .identifier => name: {
const ident_name_raw = tree.tokenSlice(test_name_token);
if (mem.eql(u8, ident_name_raw, "_")) return astgen.failTok(test_name_token, "'_' used as an identifier without @\"_\" syntax", .{});
@@ -4909,7 +4934,7 @@ fn testDecl(
return astgen.failTok(test_name_token, "use of undeclared identifier '{s}'", .{ident_name});
}
- break :blk .{ .decltest = test_name_token };
+ break :name try astgen.identAsString(test_name_token);
},
};
@@ -4965,11 +4990,8 @@ fn testDecl(
.lbrace_column = lbrace_column,
.param_block = decl_inst,
.body_gz = &fn_block,
- .lib_name = .empty,
.is_var_args = false,
.is_inferred_error = false,
- .is_test = true,
- .is_extern = false,
.is_noinline = false,
.noalias_bits = 0,
@@ -4981,17 +5003,27 @@ fn testDecl(
var hash: std.zig.SrcHash = undefined;
astgen.src_hasher.final(&hash);
- try setDeclaration(
- decl_inst,
- hash,
- test_name,
- decl_block.decl_line,
- decl_column,
- false,
- false,
- &decl_block,
- null,
- );
+ try setDeclaration(decl_inst, .{
+ .src_hash = hash,
+ .src_line = decl_block.decl_line,
+ .src_column = decl_column,
+
+ .kind = switch (token_tags[test_name_token]) {
+ .string_literal => .@"test",
+ .identifier => .decltest,
+ else => .unnamed_test,
+ },
+ .name = test_name,
+ .is_pub = false,
+ .is_threadlocal = false,
+ .linkage = .normal,
+
+ .type_gz = &dummy_gz,
+ .align_gz = &dummy_gz,
+ .linksection_gz = &dummy_gz,
+ .addrspace_gz = &dummy_gz,
+ .value_gz = &decl_block,
+ });
}
fn structDeclInner(
@@ -5882,7 +5914,8 @@ fn containerMember(
try addFailedDeclaration(
wip_members,
gz,
- .{ .named = full.name_token.? },
+ .@"const",
+ try astgen.identAsString(full.name_token.?),
full.ast.proto_node,
full.visib_token != null,
);
@@ -5904,7 +5937,8 @@ fn containerMember(
try addFailedDeclaration(
wip_members,
gz,
- .{ .named = full.ast.mut_token + 1 },
+ .@"const", // doesn't really matter
+ try astgen.identAsString(full.ast.mut_token + 1),
member_node,
full.visib_token != null,
);
@@ -5922,6 +5956,7 @@ fn containerMember(
wip_members,
gz,
.@"comptime",
+ .empty,
member_node,
false,
);
@@ -5938,6 +5973,7 @@ fn containerMember(
wip_members,
gz,
.@"usingnamespace",
+ .empty,
member_node,
is_pub: {
const main_tokens = tree.nodes.items(.main_token);
@@ -5962,6 +5998,7 @@ fn containerMember(
wip_members,
gz,
.unnamed_test,
+ .empty,
member_node,
false,
);
@@ -11670,23 +11707,6 @@ fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice {
};
}
-fn testNameString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !Zir.NullTerminatedString {
- const gpa = astgen.gpa;
- const string_bytes = &astgen.string_bytes;
- const str_index: u32 = @intCast(string_bytes.items.len);
- const token_bytes = astgen.tree.tokenSlice(str_lit_token);
- try string_bytes.append(gpa, 0); // Indicates this is a test.
- try astgen.parseStrLit(str_lit_token, string_bytes, token_bytes, 0);
- const slice = string_bytes.items[str_index + 1 ..];
- if (mem.indexOfScalar(u8, slice, 0) != null) {
- return astgen.failTok(str_lit_token, "test name cannot contain null bytes", .{});
- } else if (slice.len == 0) {
- return astgen.failTok(str_lit_token, "empty test name must be omitted", .{});
- }
- try string_bytes.append(gpa, 0);
- return @enumFromInt(str_index);
-}
-
const Scope = struct {
tag: Tag,
@@ -12077,12 +12097,9 @@ const GenZir = struct {
cc_ref: Zir.Inst.Ref,
ret_ref: Zir.Inst.Ref,
- lib_name: Zir.NullTerminatedString,
noalias_bits: u32,
is_var_args: bool,
is_inferred_error: bool,
- is_test: bool,
- is_extern: bool,
is_noinline: bool,
/// Ignored if `body_gz == null`.
@@ -12150,9 +12167,8 @@ const GenZir = struct {
const body_len = astgen.countBodyLenAfterFixupsExtraRefs(body, args.param_insts);
- const tag: Zir.Inst.Tag, const payload_index: u32 = if (args.cc_ref != .none or args.lib_name != .empty or
- args.is_var_args or args.is_test or args.is_extern or
- args.noalias_bits != 0 or args.is_noinline)
+ const tag: Zir.Inst.Tag, const payload_index: u32 = if (args.cc_ref != .none or
+ args.is_var_args or args.noalias_bits != 0 or args.is_noinline)
inst_info: {
try astgen.extra.ensureUnusedCapacity(
gpa,
@@ -12160,7 +12176,6 @@ const GenZir = struct {
fancyFnExprExtraLen(astgen, &.{}, cc_body, args.cc_ref) +
fancyFnExprExtraLen(astgen, args.ret_param_refs, ret_body, ret_ref) +
body_len + src_locs_and_hash.len +
- @intFromBool(args.lib_name != .empty) +
@intFromBool(args.noalias_bits != 0),
);
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.FuncFancy{
@@ -12169,10 +12184,7 @@ const GenZir = struct {
.bits = .{
.is_var_args = args.is_var_args,
.is_inferred_error = args.is_inferred_error,
- .is_test = args.is_test,
- .is_extern = args.is_extern,
.is_noinline = args.is_noinline,
- .has_lib_name = args.lib_name != .empty,
.has_any_noalias = args.noalias_bits != 0,
.has_cc_ref = args.cc_ref != .none,
@@ -12182,9 +12194,6 @@ const GenZir = struct {
.has_ret_ty_body = ret_body.len != 0,
},
});
- if (args.lib_name != .empty) {
- astgen.extra.appendAssumeCapacity(@intFromEnum(args.lib_name));
- }
const zir_datas = astgen.instructions.items(.data);
if (cc_body.len != 0) {
@@ -12279,61 +12288,6 @@ const GenZir = struct {
@intFromBool(main_body.len > 0 or ref != .none);
}
- fn addVar(gz: *GenZir, args: struct {
- align_inst: Zir.Inst.Ref,
- lib_name: Zir.NullTerminatedString,
- var_type: Zir.Inst.Ref,
- init: Zir.Inst.Ref,
- is_extern: bool,
- is_const: bool,
- is_threadlocal: 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 +
- @intFromBool(args.lib_name != .empty) +
- @intFromBool(args.align_inst != .none) +
- @intFromBool(args.init != .none),
- );
- const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedVar{
- .var_type = args.var_type,
- });
- if (args.lib_name != .empty) {
- astgen.extra.appendAssumeCapacity(@intFromEnum(args.lib_name));
- }
- if (args.align_inst != .none) {
- astgen.extra.appendAssumeCapacity(@intFromEnum(args.align_inst));
- }
- if (args.init != .none) {
- astgen.extra.appendAssumeCapacity(@intFromEnum(args.init));
- }
-
- const new_index: Zir.Inst.Index = @enumFromInt(astgen.instructions.len);
- astgen.instructions.appendAssumeCapacity(.{
- .tag = .extended,
- .data = .{ .extended = .{
- .opcode = .variable,
- .small = @bitCast(Zir.Inst.ExtendedVar.Small{
- .has_lib_name = args.lib_name != .empty,
- .has_align = args.align_inst != .none,
- .has_init = args.init != .none,
- .is_extern = args.is_extern,
- .is_const = args.is_const,
- .is_threadlocal = args.is_threadlocal,
- }),
- .operand = payload_index,
- } },
- });
- gz.instructions.appendAssumeCapacity(new_index);
- return new_index.toRef();
- }
-
fn addInt(gz: *GenZir, integer: u64) !Zir.Inst.Ref {
return gz.add(.{
.tag = .int,
@@ -13909,14 +13863,18 @@ const DeclarationName = union(enum) {
fn addFailedDeclaration(
wip_members: *WipMembers,
gz: *GenZir,
- name: DeclarationName,
+ kind: Zir.Inst.Declaration.Unwrapped.Kind,
+ name: Zir.NullTerminatedString,
src_node: Ast.Node.Index,
is_pub: bool,
) !void {
const decl_inst = try gz.makeDeclaration(src_node);
wip_members.nextDecl(decl_inst);
- var decl_gz = gz.makeSubBlock(&gz.base); // scope doesn't matter here
- _ = try decl_gz.add(.{
+
+ var dummy_gz = gz.makeSubBlock(&gz.base);
+
+ var value_gz = gz.makeSubBlock(&gz.base); // scope doesn't matter here
+ _ = try value_gz.add(.{
.tag = .extended,
.data = .{ .extended = .{
.opcode = .astgen_error,
@@ -13924,110 +13882,198 @@ fn addFailedDeclaration(
.operand = undefined,
} },
});
- try setDeclaration(
- decl_inst,
- @splat(0), // use a fixed hash to represent an AstGen failure; we don't care about source changes if AstGen still failed!
- name,
- gz.astgen.source_line,
- gz.astgen.source_column,
- is_pub,
- false, // we don't care about exports since semantic analysis will fail
- &decl_gz,
- null,
- );
+
+ try setDeclaration(decl_inst, .{
+ .src_hash = @splat(0), // use a fixed hash to represent an AstGen failure; we don't care about source changes if AstGen still failed!
+ .src_line = gz.astgen.source_line,
+ .src_column = gz.astgen.source_column,
+ .kind = kind,
+ .name = name,
+ .is_pub = is_pub,
+ .is_threadlocal = false,
+ .linkage = .normal,
+ .type_gz = &dummy_gz,
+ .align_gz = &dummy_gz,
+ .linksection_gz = &dummy_gz,
+ .addrspace_gz = &dummy_gz,
+ .value_gz = &value_gz,
+ });
}
/// Sets all extra data for a `declaration` instruction.
-/// Unstacks `value_gz`, `align_gz`, `linksection_gz`, and `addrspace_gz`.
+/// Unstacks `type_gz`, `align_gz`, `linksection_gz`, `addrspace_gz`, and `value_gz`.
fn setDeclaration(
decl_inst: Zir.Inst.Index,
- src_hash: std.zig.SrcHash,
- name: DeclarationName,
- src_line: u32,
- src_column: u32,
- is_pub: bool,
- is_export: bool,
- value_gz: *GenZir,
- /// May be `null` if all these blocks would be empty.
- /// If `null`, then `value_gz` must have nothing stacked on it.
- extra_gzs: ?struct {
- /// Must be stacked on `value_gz`.
+ args: struct {
+ src_hash: std.zig.SrcHash,
+ src_line: u32,
+ src_column: u32,
+
+ kind: Zir.Inst.Declaration.Unwrapped.Kind,
+ name: Zir.NullTerminatedString,
+ is_pub: bool,
+ is_threadlocal: bool,
+ linkage: Zir.Inst.Declaration.Unwrapped.Linkage,
+ lib_name: Zir.NullTerminatedString = .empty,
+
+ type_gz: *GenZir,
+ /// Must be stacked on `type_gz`.
align_gz: *GenZir,
/// Must be stacked on `align_gz`.
linksection_gz: *GenZir,
- /// Must be stacked on `linksection_gz`, and have nothing stacked on it.
+ /// Must be stacked on `linksection_gz`.
addrspace_gz: *GenZir,
+ /// Must be stacked on `addrspace_gz` and have nothing stacked on top of it.
+ value_gz: *GenZir,
},
) !void {
- const astgen = value_gz.astgen;
+ const astgen = args.value_gz.astgen;
const gpa = astgen.gpa;
- const empty_body: []Zir.Inst.Index = &.{};
- const value_body, const align_body, const linksection_body, const addrspace_body = if (extra_gzs) |e| .{
- value_gz.instructionsSliceUpto(e.align_gz),
- e.align_gz.instructionsSliceUpto(e.linksection_gz),
- e.linksection_gz.instructionsSliceUpto(e.addrspace_gz),
- e.addrspace_gz.instructionsSlice(),
- } else .{ value_gz.instructionsSlice(), empty_body, empty_body, empty_body };
+ const type_body = args.type_gz.instructionsSliceUpto(args.align_gz);
+ const align_body = args.align_gz.instructionsSliceUpto(args.linksection_gz);
+ const linksection_body = args.linksection_gz.instructionsSliceUpto(args.addrspace_gz);
+ const addrspace_body = args.addrspace_gz.instructionsSliceUpto(args.value_gz);
+ const value_body = args.value_gz.instructionsSlice();
+
+ const has_name = args.name != .empty;
+ const has_lib_name = args.lib_name != .empty;
+ const has_type_body = type_body.len != 0;
+ const has_special_body = align_body.len != 0 or linksection_body.len != 0 or addrspace_body.len != 0;
+ const has_value_body = value_body.len != 0;
+
+ const id: Zir.Inst.Declaration.Flags.Id = switch (args.kind) {
+ .unnamed_test => .unnamed_test,
+ .@"test" => .@"test",
+ .decltest => .decltest,
+ .@"comptime" => .@"comptime",
+ .@"usingnamespace" => if (args.is_pub) .pub_usingnamespace else .@"usingnamespace",
+ .@"const" => switch (args.linkage) {
+ .normal => if (args.is_pub) id: {
+ if (has_special_body) break :id .pub_const;
+ if (has_type_body) break :id .pub_const_typed;
+ break :id .pub_const_simple;
+ } else id: {
+ if (has_special_body) break :id .@"const";
+ if (has_type_body) break :id .const_typed;
+ break :id .const_simple;
+ },
+ .@"extern" => if (args.is_pub) id: {
+ if (has_lib_name) break :id .pub_extern_const;
+ if (has_special_body) break :id .pub_extern_const;
+ break :id .pub_extern_const_simple;
+ } else id: {
+ if (has_lib_name) break :id .extern_const;
+ if (has_special_body) break :id .extern_const;
+ break :id .extern_const_simple;
+ },
+ .@"export" => if (args.is_pub) .pub_export_const else .export_const,
+ },
+ .@"var" => switch (args.linkage) {
+ .normal => if (args.is_pub) id: {
+ if (args.is_threadlocal) break :id .pub_var_threadlocal;
+ if (has_special_body) break :id .pub_var;
+ if (has_type_body) break :id .pub_var;
+ break :id .pub_var_simple;
+ } else id: {
+ if (args.is_threadlocal) break :id .var_threadlocal;
+ if (has_special_body) break :id .@"var";
+ if (has_type_body) break :id .@"var";
+ break :id .var_simple;
+ },
+ .@"extern" => if (args.is_pub) id: {
+ if (args.is_threadlocal) break :id .pub_extern_var_threadlocal;
+ break :id .pub_extern_var;
+ } else id: {
+ if (args.is_threadlocal) break :id .extern_var_threadlocal;
+ break :id .extern_var;
+ },
+ .@"export" => if (args.is_pub) id: {
+ if (args.is_threadlocal) break :id .pub_export_var_threadlocal;
+ break :id .pub_export_var;
+ } else id: {
+ if (args.is_threadlocal) break :id .export_var_threadlocal;
+ break :id .export_var;
+ },
+ },
+ };
- const value_len = astgen.countBodyLenAfterFixups(value_body);
+ assert(id.hasTypeBody() or !has_type_body);
+ assert(id.hasSpecialBodies() or !has_special_body);
+ assert(id.hasValueBody() == has_value_body);
+ assert(id.linkage() == args.linkage);
+ assert(id.hasName() == has_name);
+ assert(id.hasLibName() or !has_lib_name);
+ assert(id.isPub() == args.is_pub);
+ assert(id.isThreadlocal() == args.is_threadlocal);
+
+ const type_len = astgen.countBodyLenAfterFixups(type_body);
const align_len = astgen.countBodyLenAfterFixups(align_body);
const linksection_len = astgen.countBodyLenAfterFixups(linksection_body);
const addrspace_len = astgen.countBodyLenAfterFixups(addrspace_body);
+ const value_len = astgen.countBodyLenAfterFixups(value_body);
+
+ const src_hash_arr: [4]u32 = @bitCast(args.src_hash);
+ const flags: Zir.Inst.Declaration.Flags = .{
+ .src_line = @intCast(args.src_line),
+ .src_column = @intCast(args.src_column),
+ .id = id,
+ };
+ const flags_arr: [2]u32 = @bitCast(flags);
- const src_hash_arr: [4]u32 = @bitCast(src_hash);
+ const need_extra: usize =
+ @typeInfo(Zir.Inst.Declaration).@"struct".fields.len +
+ @as(usize, @intFromBool(id.hasName())) +
+ @as(usize, @intFromBool(id.hasLibName())) +
+ @as(usize, @intFromBool(id.hasTypeBody())) +
+ 3 * @as(usize, @intFromBool(id.hasSpecialBodies())) +
+ @as(usize, @intFromBool(id.hasValueBody())) +
+ type_len + align_len + linksection_len + addrspace_len + value_len;
+
+ try astgen.extra.ensureUnusedCapacity(gpa, need_extra);
const extra: Zir.Inst.Declaration = .{
.src_hash_0 = src_hash_arr[0],
.src_hash_1 = src_hash_arr[1],
.src_hash_2 = src_hash_arr[2],
.src_hash_3 = src_hash_arr[3],
- .name = switch (name) {
- .named => |tok| @enumFromInt(@intFromEnum(try astgen.identAsString(tok))),
- .named_test => |tok| @enumFromInt(@intFromEnum(try astgen.testNameString(tok))),
- .decltest => |tok| @enumFromInt(str_idx: {
- const idx = astgen.string_bytes.items.len;
- try astgen.string_bytes.append(gpa, 0); // indicates this is a test
- try astgen.appendIdentStr(tok, &astgen.string_bytes);
- try astgen.string_bytes.append(gpa, 0); // end of the string
- break :str_idx idx;
- }),
- .unnamed_test => .unnamed_test,
- .@"comptime" => .@"comptime",
- .@"usingnamespace" => .@"usingnamespace",
- },
- .src_line = src_line,
- .src_column = src_column,
- .flags = .{
- .value_body_len = @intCast(value_len),
- .is_pub = is_pub,
- .is_export = is_export,
- .test_is_decltest = name == .decltest,
- .has_align_linksection_addrspace = align_len != 0 or linksection_len != 0 or addrspace_len != 0,
- },
+ .flags_0 = flags_arr[0],
+ .flags_1 = flags_arr[1],
};
- astgen.instructions.items(.data)[@intFromEnum(decl_inst)].declaration.payload_index = try astgen.addExtra(extra);
- if (extra.flags.has_align_linksection_addrspace) {
- try astgen.extra.appendSlice(gpa, &.{
+ astgen.instructions.items(.data)[@intFromEnum(decl_inst)].declaration.payload_index =
+ astgen.addExtraAssumeCapacity(extra);
+
+ if (id.hasName()) {
+ astgen.extra.appendAssumeCapacity(@intFromEnum(args.name));
+ }
+ if (id.hasLibName()) {
+ astgen.extra.appendAssumeCapacity(@intFromEnum(args.lib_name));
+ }
+ if (id.hasTypeBody()) {
+ astgen.extra.appendAssumeCapacity(type_len);
+ }
+ if (id.hasSpecialBodies()) {
+ astgen.extra.appendSliceAssumeCapacity(&.{
align_len,
linksection_len,
addrspace_len,
});
}
- try astgen.extra.ensureUnusedCapacity(gpa, value_len + align_len + linksection_len + addrspace_len);
- astgen.appendBodyWithFixups(value_body);
- if (extra.flags.has_align_linksection_addrspace) {
- astgen.appendBodyWithFixups(align_body);
- astgen.appendBodyWithFixups(linksection_body);
- astgen.appendBodyWithFixups(addrspace_body);
+ if (id.hasValueBody()) {
+ astgen.extra.appendAssumeCapacity(value_len);
}
- if (extra_gzs) |e| {
- e.addrspace_gz.unstack();
- e.linksection_gz.unstack();
- e.align_gz.unstack();
- }
- value_gz.unstack();
+ astgen.appendBodyWithFixups(type_body);
+ astgen.appendBodyWithFixups(align_body);
+ astgen.appendBodyWithFixups(linksection_body);
+ astgen.appendBodyWithFixups(addrspace_body);
+ astgen.appendBodyWithFixups(value_body);
+
+ args.value_gz.unstack();
+ args.addrspace_gz.unstack();
+ args.linksection_gz.unstack();
+ args.align_gz.unstack();
+ args.type_gz.unstack();
}
/// Given a list of instructions, returns a list of all instructions which are a `ref` of one of the originals,
diff --git a/lib/std/zig/Zir.zig b/lib/std/zig/Zir.zig
index f2aceb14ae..0f9611aa30 100644
--- a/lib/std/zig/Zir.zig
+++ b/lib/std/zig/Zir.zig
@@ -1868,10 +1868,6 @@ pub const Inst = struct {
/// Rarer instructions are here; ones that do not fit in the 8-bit `Tag` enum.
/// `noreturn` instructions may not go here; they must be part of the main `Tag` enum.
pub const Extended = enum(u16) {
- /// Declares a global variable.
- /// `operand` is payload index to `ExtendedVar`.
- /// `small` is `ExtendedVar.Small`.
- variable,
/// A struct type definition. Contains references to ZIR instructions for
/// the field types, defaults, and alignments.
/// `operand` is payload index to `StructDecl`.
@@ -2493,26 +2489,25 @@ pub const Inst = struct {
};
/// Trailing:
- /// 0. lib_name: NullTerminatedString, // null terminated string index, if has_lib_name is set
/// if (has_cc_ref and !has_cc_body) {
- /// 1. cc: Ref,
+ /// 0. cc: Ref,
/// }
/// if (has_cc_body) {
- /// 2. cc_body_len: u32
- /// 3. cc_body: u32 // for each cc_body_len
+ /// 1. cc_body_len: u32
+ /// 2. cc_body: u32 // for each cc_body_len
/// }
/// if (has_ret_ty_ref and !has_ret_ty_body) {
- /// 4. ret_ty: Ref,
+ /// 3. ret_ty: Ref,
/// }
/// if (has_ret_ty_body) {
- /// 5. ret_ty_body_len: u32
- /// 6. ret_ty_body: u32 // for each ret_ty_body_len
+ /// 4. ret_ty_body_len: u32
+ /// 5. ret_ty_body: u32 // for each ret_ty_body_len
/// }
- /// 7. noalias_bits: u32 // if has_any_noalias
+ /// 6. noalias_bits: u32 // if has_any_noalias
/// - each bit starting with LSB corresponds to parameter indexes
- /// 8. body: Index // for each body_len
- /// 9. src_locs: Func.SrcLocs // if body_len != 0
- /// 10. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
+ /// 7. body: Index // for each body_len
+ /// 8. src_locs: Func.SrcLocs // if body_len != 0
+ /// 9. proto_hash: std.zig.SrcHash // if body_len != 0; hash of function prototype
pub const FuncFancy = struct {
/// Points to the block that contains the param instructions for this function.
/// If this is a `declaration`, it refers to the declaration's value body.
@@ -2522,38 +2517,16 @@ pub const Inst = struct {
/// If both has_cc_ref and has_cc_body are false, it means auto calling convention.
/// If both has_ret_ty_ref and has_ret_ty_body are false, it means void return type.
- pub const Bits = packed struct {
+ pub const Bits = packed struct(u32) {
is_var_args: bool,
is_inferred_error: bool,
- is_test: bool,
- is_extern: bool,
is_noinline: bool,
has_cc_ref: bool,
has_cc_body: bool,
has_ret_ty_ref: bool,
has_ret_ty_body: bool,
- has_lib_name: bool,
has_any_noalias: bool,
- _: u21 = undefined,
- };
- };
-
- /// Trailing:
- /// 0. lib_name: NullTerminatedString, // 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,
- is_const: bool,
- is_threadlocal: bool,
- _: u10 = undefined,
+ _: u24 = undefined,
};
};
@@ -2582,39 +2555,301 @@ pub const Inst = struct {
};
/// Trailing:
- /// 0. align_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `align`
- /// 1. linksection_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `linksection`
- /// 2. addrspace_body_len: u32 // if `has_align_linksection_addrspace`; 0 means no `addrspace`
- /// 3. value_body_inst: Zir.Inst.Index
- /// - for each `value_body_len`
+ /// 0. name: NullTerminatedString // if `flags.id.hasName()`
+ /// 1. lib_name: NullTerminatedString // if `flags.id.hasLibName()`
+ /// 2. type_body_len: u32 // if `flags.id.hasTypeBody()`
+ /// 3. align_body_len: u32 // if `flags.id.hasSpecialBodies()`
+ /// 4. linksection_body_len: u32 // if `flags.id.hasSpecialBodies()`
+ /// 5. addrspace_body_len: u32 // if `flags.id.hasSpecialBodies()`
+ /// 6. value_body_len: u32 // if `flags.id.hasValueBody()`
+ /// 7. type_body_inst: Zir.Inst.Index
+ /// - for each `type_body_len`
/// - body to be exited via `break_inline` to this `declaration` instruction
- /// 4. align_body_inst: Zir.Inst.Index
+ /// 8. align_body_inst: Zir.Inst.Index
/// - for each `align_body_len`
/// - body to be exited via `break_inline` to this `declaration` instruction
- /// 5. linksection_body_inst: Zir.Inst.Index
+ /// 9. linksection_body_inst: Zir.Inst.Index
/// - for each `linksection_body_len`
/// - body to be exited via `break_inline` to this `declaration` instruction
- /// 6. addrspace_body_inst: Zir.Inst.Index
+ /// 10. addrspace_body_inst: Zir.Inst.Index
/// - for each `addrspace_body_len`
/// - body to be exited via `break_inline` to this `declaration` instruction
+ /// 11. value_body_inst: Zir.Inst.Index
+ /// - for each `value_body_len`
+ /// - body to be exited via `break_inline` to this `declaration` instruction
+ /// - within this body, the `declaration` instruction refers to the resolved type from the type body
pub const Declaration = struct {
// These fields should be concatenated and reinterpreted as a `std.zig.SrcHash`.
src_hash_0: u32,
src_hash_1: u32,
src_hash_2: u32,
src_hash_3: u32,
- /// The name of this `Decl`. Also indicates whether it is a test, comptime block, etc.
- name: Name,
- src_line: u32,
- src_column: u32,
- flags: Flags,
+ // These fields should be concatenated and reinterpreted as a `Flags`.
+ flags_0: u32,
+ flags_1: u32,
+
+ pub const Unwrapped = struct {
+ pub const Kind = enum {
+ unnamed_test,
+ @"test",
+ decltest,
+ @"comptime",
+ @"usingnamespace",
+ @"const",
+ @"var",
+ };
- pub const Flags = packed struct(u32) {
- value_body_len: u28,
+ pub const Linkage = enum {
+ normal,
+ @"extern",
+ @"export",
+ };
+
+ src_node: Ast.Node.Index,
+
+ src_line: u32,
+ src_column: u32,
+
+ kind: Kind,
+ /// Always `.empty` for `kind` of `unnamed_test`, `.@"comptime"`, `.@"usingnamespace"`.
+ name: NullTerminatedString,
+ /// Always `false` for `kind` of `unnamed_test`, `.@"test"`, `.decltest`, `.@"comptime"`.
is_pub: bool,
- is_export: bool,
- test_is_decltest: bool,
- has_align_linksection_addrspace: bool,
+ /// Always `false` for `kind != .@"var"`.
+ is_threadlocal: bool,
+ /// Always `.normal` for `kind != .@"const" and kind != .@"var"`.
+ linkage: Linkage,
+ /// Always `.empty` for `linkage != .@"extern"`.
+ lib_name: NullTerminatedString,
+
+ /// Always populated for `linkage == .@"extern".
+ type_body: ?[]const Inst.Index,
+ align_body: ?[]const Inst.Index,
+ linksection_body: ?[]const Inst.Index,
+ addrspace_body: ?[]const Inst.Index,
+ /// Always populated for `linkage != .@"extern".
+ value_body: ?[]const Inst.Index,
+ };
+
+ pub const Flags = packed struct(u64) {
+ src_line: u30,
+ src_column: u29,
+ id: Id,
+
+ pub const Id = enum(u5) {
+ unnamed_test,
+ @"test",
+ decltest,
+ @"comptime",
+
+ @"usingnamespace",
+ pub_usingnamespace,
+
+ const_simple,
+ const_typed,
+ @"const",
+ pub_const_simple,
+ pub_const_typed,
+ pub_const,
+
+ extern_const_simple,
+ extern_const,
+ pub_extern_const_simple,
+ pub_extern_const,
+
+ export_const,
+ pub_export_const,
+
+ var_simple,
+ @"var",
+ var_threadlocal,
+ pub_var_simple,
+ pub_var,
+ pub_var_threadlocal,
+
+ extern_var,
+ extern_var_threadlocal,
+ pub_extern_var,
+ pub_extern_var_threadlocal,
+
+ export_var,
+ export_var_threadlocal,
+ pub_export_var,
+ pub_export_var_threadlocal,
+
+ pub fn hasName(id: Id) bool {
+ return switch (id) {
+ .unnamed_test,
+ .@"comptime",
+ .@"usingnamespace",
+ .pub_usingnamespace,
+ => false,
+ else => true,
+ };
+ }
+
+ pub fn hasLibName(id: Id) bool {
+ return switch (id) {
+ .extern_const,
+ .pub_extern_const,
+ .extern_var,
+ .extern_var_threadlocal,
+ .pub_extern_var,
+ .pub_extern_var_threadlocal,
+ => true,
+ else => false,
+ };
+ }
+
+ pub fn hasTypeBody(id: Id) bool {
+ return switch (id) {
+ .unnamed_test,
+ .@"test",
+ .decltest,
+ .@"comptime",
+ .@"usingnamespace",
+ .pub_usingnamespace,
+ => false, // these constructs are untyped
+ .const_simple,
+ .pub_const_simple,
+ .var_simple,
+ .pub_var_simple,
+ => false, // these reprs omit type bodies
+ else => true,
+ };
+ }
+
+ pub fn hasValueBody(id: Id) bool {
+ return switch (id) {
+ .extern_const_simple,
+ .extern_const,
+ .pub_extern_const_simple,
+ .pub_extern_const,
+ .extern_var,
+ .extern_var_threadlocal,
+ .pub_extern_var,
+ .pub_extern_var_threadlocal,
+ => false, // externs do not have values
+ else => true,
+ };
+ }
+
+ pub fn hasSpecialBodies(id: Id) bool {
+ return switch (id) {
+ .unnamed_test,
+ .@"test",
+ .decltest,
+ .@"comptime",
+ .@"usingnamespace",
+ .pub_usingnamespace,
+ => false, // these constructs are untyped
+ .const_simple,
+ .const_typed,
+ .pub_const_simple,
+ .pub_const_typed,
+ .extern_const_simple,
+ .pub_extern_const_simple,
+ .var_simple,
+ .pub_var_simple,
+ => false, // these reprs omit special bodies
+ else => true,
+ };
+ }
+
+ pub fn linkage(id: Id) Declaration.Unwrapped.Linkage {
+ return switch (id) {
+ .extern_const_simple,
+ .extern_const,
+ .pub_extern_const_simple,
+ .pub_extern_const,
+ .extern_var,
+ .extern_var_threadlocal,
+ .pub_extern_var,
+ .pub_extern_var_threadlocal,
+ => .@"extern",
+ .export_const,
+ .pub_export_const,
+ .export_var,
+ .export_var_threadlocal,
+ .pub_export_var,
+ .pub_export_var_threadlocal,
+ => .@"export",
+ else => .normal,
+ };
+ }
+
+ pub fn kind(id: Id) Declaration.Unwrapped.Kind {
+ return switch (id) {
+ .unnamed_test => .unnamed_test,
+ .@"test" => .@"test",
+ .decltest => .decltest,
+ .@"comptime" => .@"comptime",
+ .@"usingnamespace", .pub_usingnamespace => .@"usingnamespace",
+ .const_simple,
+ .const_typed,
+ .@"const",
+ .pub_const_simple,
+ .pub_const_typed,
+ .pub_const,
+ .extern_const_simple,
+ .extern_const,
+ .pub_extern_const_simple,
+ .pub_extern_const,
+ .export_const,
+ .pub_export_const,
+ => .@"const",
+ .var_simple,
+ .@"var",
+ .var_threadlocal,
+ .pub_var_simple,
+ .pub_var,
+ .pub_var_threadlocal,
+ .extern_var,
+ .extern_var_threadlocal,
+ .pub_extern_var,
+ .pub_extern_var_threadlocal,
+ .export_var,
+ .export_var_threadlocal,
+ .pub_export_var,
+ .pub_export_var_threadlocal,
+ => .@"var",
+ };
+ }
+
+ pub fn isPub(id: Id) bool {
+ return switch (id) {
+ .pub_usingnamespace,
+ .pub_const_simple,
+ .pub_const_typed,
+ .pub_const,
+ .pub_extern_const_simple,
+ .pub_extern_const,
+ .pub_export_const,
+ .pub_var_simple,
+ .pub_var,
+ .pub_var_threadlocal,
+ .pub_extern_var,
+ .pub_extern_var_threadlocal,
+ .pub_export_var,
+ .pub_export_var_threadlocal,
+ => true,
+ else => false,
+ };
+ }
+
+ pub fn isThreadlocal(id: Id) bool {
+ return switch (id) {
+ .var_threadlocal,
+ .pub_var_threadlocal,
+ .extern_var_threadlocal,
+ .pub_extern_var_threadlocal,
+ .export_var_threadlocal,
+ .pub_export_var_threadlocal,
+ => true,
+ else => false,
+ };
+ }
+ };
};
pub const Name = enum(u32) {
@@ -2647,17 +2882,24 @@ pub const Inst = struct {
};
pub const Bodies = struct {
- value_body: []const Index,
+ type_body: ?[]const Index,
align_body: ?[]const Index,
linksection_body: ?[]const Index,
addrspace_body: ?[]const Index,
+ value_body: ?[]const Index,
};
pub fn getBodies(declaration: Declaration, extra_end: u32, zir: Zir) Bodies {
var extra_index: u32 = extra_end;
- const value_body_len = declaration.flags.value_body_len;
+ const value_body_len = declaration.value_body_len;
+ const type_body_len: u32 = len: {
+ if (!declaration.flags().kind.hasTypeBody()) break :len 0;
+ const len = zir.extra[extra_index];
+ extra_index += 1;
+ break :len len;
+ };
const align_body_len, const linksection_body_len, const addrspace_body_len = lens: {
- if (!declaration.flags.has_align_linksection_addrspace) {
+ if (!declaration.flags.kind.hasSpecialBodies()) {
break :lens .{ 0, 0, 0 };
}
const lens = zir.extra[extra_index..][0..3].*;
@@ -2665,21 +2907,30 @@ pub const Inst = struct {
break :lens lens;
};
return .{
- .value_body = b: {
- defer extra_index += value_body_len;
- break :b zir.bodySlice(extra_index, value_body_len);
+ .type_body = if (type_body_len == 0) null else b: {
+ const b = zir.bodySlice(extra_index, type_body_len);
+ extra_index += type_body_len;
+ break :b b;
},
.align_body = if (align_body_len == 0) null else b: {
- defer extra_index += align_body_len;
- break :b zir.bodySlice(extra_index, align_body_len);
+ const b = zir.bodySlice(extra_index, align_body_len);
+ extra_index += align_body_len;
+ break :b b;
},
.linksection_body = if (linksection_body_len == 0) null else b: {
- defer extra_index += linksection_body_len;
- break :b zir.bodySlice(extra_index, linksection_body_len);
+ const b = zir.bodySlice(extra_index, linksection_body_len);
+ extra_index += linksection_body_len;
+ break :b b;
},
.addrspace_body = if (addrspace_body_len == 0) null else b: {
- defer extra_index += addrspace_body_len;
- break :b zir.bodySlice(extra_index, addrspace_body_len);
+ const b = zir.bodySlice(extra_index, addrspace_body_len);
+ extra_index += addrspace_body_len;
+ break :b b;
+ },
+ .value_body = if (value_body_len == 0) null else b: {
+ const b = zir.bodySlice(extra_index, value_body_len);
+ extra_index += value_body_len;
+ break :b b;
},
};
}
@@ -3711,18 +3962,18 @@ pub const DeclContents = struct {
pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void {
contents.clear();
- const declaration, const extra_end = zir.getDeclaration(decl_inst);
- const bodies = declaration.getBodies(extra_end, zir);
+ const decl = zir.getDeclaration(decl_inst);
// `defer` instructions duplicate the same body arbitrarily many times, but we only want to traverse
// their contents once per defer. So, we store the extra index of the body here to deduplicate.
var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty;
defer found_defers.deinit(gpa);
- try zir.findTrackableBody(gpa, contents, &found_defers, bodies.value_body);
- if (bodies.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
- if (bodies.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
- if (bodies.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
+ if (decl.type_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
+ if (decl.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
+ if (decl.linksection_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
+ if (decl.addrspace_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
+ if (decl.value_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b);
}
/// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than
@@ -3991,7 +4242,6 @@ fn findTrackableInner(
.value_placeholder => unreachable,
// Once again, we start with the boring tags.
- .variable,
.this,
.ret_addr,
.builtin_src,
@@ -4237,7 +4487,6 @@ fn findTrackableInner(
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
var extra_index: usize = extra.end;
- extra_index += @intFromBool(extra.data.bits.has_lib_name);
if (extra.data.bits.has_cc_body) {
const body_len = zir.extra[extra_index];
@@ -4470,8 +4719,7 @@ pub fn getParamBody(zir: Zir, fn_inst: Inst.Index) []const Zir.Inst.Index {
return zir.bodySlice(param_block.end, param_block.data.body_len);
},
.declaration => {
- const decl, const extra_end = zir.getDeclaration(param_block_index);
- return decl.getBodies(extra_end, zir).value_body;
+ return zir.getDeclaration(param_block_index).value_body.?;
},
else => unreachable,
}
@@ -4526,7 +4774,6 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
var ret_ty_ref: Inst.Ref = .void_type;
var ret_ty_body: []const Inst.Index = &.{};
- extra_index += @intFromBool(extra.data.bits.has_lib_name);
if (extra.data.bits.has_cc_body) {
extra_index += zir.extra[extra_index] + 1;
} else if (extra.data.bits.has_cc_ref) {
@@ -4555,17 +4802,7 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
},
else => unreachable,
};
- const param_body = switch (tags[@intFromEnum(info.param_block)]) {
- .block, .block_comptime, .block_inline => param_body: {
- const param_block = zir.extraData(Inst.Block, datas[@intFromEnum(info.param_block)].pl_node.payload_index);
- break :param_body zir.bodySlice(param_block.end, param_block.data.body_len);
- },
- .declaration => param_body: {
- const decl, const extra_end = zir.getDeclaration(info.param_block);
- break :param_body decl.getBodies(extra_end, zir).value_body;
- },
- else => unreachable,
- };
+ const param_body = zir.getParamBody(fn_inst);
var total_params_len: u32 = 0;
for (param_body) |inst| {
switch (tags[@intFromEnum(inst)]) {
@@ -4585,13 +4822,74 @@ pub fn getFnInfo(zir: Zir, fn_inst: Inst.Index) FnInfo {
};
}
-pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) struct { Inst.Declaration, u32 } {
+pub fn getDeclaration(zir: Zir, inst: Zir.Inst.Index) Inst.Declaration.Unwrapped {
assert(zir.instructions.items(.tag)[@intFromEnum(inst)] == .declaration);
const pl_node = zir.instructions.items(.data)[@intFromEnum(inst)].declaration;
const extra = zir.extraData(Inst.Declaration, pl_node.payload_index);
+
+ const flags_vals: [2]u32 = .{ extra.data.flags_0, extra.data.flags_1 };
+ const flags: Inst.Declaration.Flags = @bitCast(flags_vals);
+
+ var extra_index = extra.end;
+
+ const name: NullTerminatedString = if (flags.id.hasName()) name: {
+ const name = zir.extra[extra_index];
+ extra_index += 1;
+ break :name @enumFromInt(name);
+ } else .empty;
+
+ const lib_name: NullTerminatedString = if (flags.id.hasLibName()) lib_name: {
+ const lib_name = zir.extra[extra_index];
+ extra_index += 1;
+ break :lib_name @enumFromInt(lib_name);
+ } else .empty;
+
+ const type_body_len: u32 = if (flags.id.hasTypeBody()) len: {
+ const len = zir.extra[extra_index];
+ extra_index += 1;
+ break :len len;
+ } else 0;
+ const align_body_len: u32, const linksection_body_len: u32, const addrspace_body_len: u32 = lens: {
+ if (!flags.id.hasSpecialBodies()) break :lens .{ 0, 0, 0 };
+ const lens = zir.extra[extra_index..][0..3].*;
+ extra_index += 3;
+ break :lens lens;
+ };
+ const value_body_len: u32 = if (flags.id.hasValueBody()) len: {
+ const len = zir.extra[extra_index];
+ extra_index += 1;
+ break :len len;
+ } else 0;
+
+ const type_body = zir.bodySlice(extra_index, type_body_len);
+ extra_index += type_body_len;
+ const align_body = zir.bodySlice(extra_index, align_body_len);
+ extra_index += align_body_len;
+ const linksection_body = zir.bodySlice(extra_index, linksection_body_len);
+ extra_index += linksection_body_len;
+ const addrspace_body = zir.bodySlice(extra_index, addrspace_body_len);
+ extra_index += addrspace_body_len;
+ const value_body = zir.bodySlice(extra_index, value_body_len);
+ extra_index += value_body_len;
+
return .{
- extra.data,
- @intCast(extra.end),
+ .src_node = pl_node.src_node,
+
+ .src_line = flags.src_line,
+ .src_column = flags.src_column,
+
+ .kind = flags.id.kind(),
+ .name = name,
+ .is_pub = flags.id.isPub(),
+ .is_threadlocal = flags.id.isThreadlocal(),
+ .linkage = flags.id.linkage(),
+ .lib_name = lib_name,
+
+ .type_body = if (type_body_len == 0) null else type_body,
+ .align_body = if (align_body_len == 0) null else align_body,
+ .linksection_body = if (linksection_body_len == 0) null else linksection_body,
+ .addrspace_body = if (addrspace_body_len == 0) null else addrspace_body,
+ .value_body = if (value_body_len == 0) null else value_body,
};
}
@@ -4636,7 +4934,6 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {
}
const bits = extra.data.bits;
var extra_index = extra.end;
- extra_index += @intFromBool(bits.has_lib_name);
if (bits.has_cc_body) {
const body_len = zir.extra[extra_index];
extra_index += 1 + body_len;