aboutsummaryrefslogtreecommitdiff
path: root/src/Module.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/Module.zig')
-rw-r--r--src/Module.zig476
1 files changed, 216 insertions, 260 deletions
diff --git a/src/Module.zig b/src/Module.zig
index 7637e40798..02df2dac67 100644
--- a/src/Module.zig
+++ b/src/Module.zig
@@ -386,11 +386,9 @@ pub const Decl = struct {
/// do not need to be loaded into memory in order to compute debug line numbers.
/// This value is absolute.
src_line: u32,
- /// Index to ZIR `extra` array to the entry in the parent's decl structure
- /// (the part that says "for every decls_len"). The first item at this index is
- /// the contents hash, followed by line, name, etc.
- /// For anonymous decls and also the root Decl for a File, this is `none`.
- zir_decl_index: Zir.OptionalExtraIndex,
+ /// Index of the ZIR `declaration` instruction from which this `Decl` was created.
+ /// For the root `Decl` of a `File` and legacy anonymous decls, this is `.none`.
+ zir_decl_index: Zir.Inst.OptionalIndex,
/// Represents the "shallow" analysis status. For example, for decls that are functions,
/// the function type is analyzed with this set to `in_progress`, however, the semantic
@@ -442,10 +440,6 @@ pub const Decl = struct {
is_pub: bool,
/// Whether the corresponding AST decl has a `export` keyword.
is_exported: bool,
- /// Whether the ZIR code provides an align instruction.
- has_align: bool,
- /// Whether the ZIR code provides a linksection and address space instruction.
- has_linksection_or_addrspace: bool,
/// Flag used by garbage collection to mark and sweep.
/// Decls which correspond to an AST node always have this field set to `true`.
/// Anonymous Decls are initialized with this field set to `false` and then it
@@ -471,81 +465,19 @@ pub const Decl = struct {
const Index = InternPool.DeclIndex;
const OptionalIndex = InternPool.OptionalDeclIndex;
- pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, DepType);
-
- /// Later types take priority; e.g. if a dependent decl has both `normal`
- /// and `function_body` dependencies on another decl, it will be marked as
- /// having a `function_body` dependency.
- pub const DepType = enum {
- /// The dependent references or uses the dependency's value, so must be
- /// updated whenever it is changed. However, if the dependency is a
- /// function and its type is unchanged, the dependent does not need to
- /// be updated.
- normal,
- /// The dependent performs an inline or comptime call to the dependency,
- /// or is a generic instantiation of it. It must therefore be updated
- /// whenever the dependency is updated, even if the function type
- /// remained the same.
- function_body,
- };
-
- /// This name is relative to the containing namespace of the decl.
- /// The memory is owned by the containing File ZIR.
- pub fn getName(decl: Decl, mod: *Module) ?[:0]const u8 {
- const zir = decl.getFileScope(mod).zir;
- return decl.getNameZir(zir);
+ /// Asserts that `zir_decl_index` is not `.none`.
+ fn getDeclaration(decl: Decl, zir: Zir) Zir.Inst.Declaration {
+ const zir_index = decl.zir_decl_index.unwrap().?;
+ const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
+ return zir.extraData(Zir.Inst.Declaration, pl_node.payload_index).data;
}
- pub fn getNameZir(decl: Decl, zir: Zir) ?[:0]const u8 {
- assert(decl.zir_decl_index != .none);
- const name_index = zir.extra[@intFromEnum(decl.zir_decl_index) + 5];
- if (name_index <= 1) return null;
- return zir.nullTerminatedString(name_index);
- }
-
- pub fn contentsHash(decl: Decl, mod: *Module) std.zig.SrcHash {
- const zir = decl.getFileScope(mod).zir;
- return decl.contentsHashZir(zir);
- }
-
- pub fn contentsHashZir(decl: Decl, zir: Zir) std.zig.SrcHash {
- assert(decl.zir_decl_index != .none);
- const hash_u32s = zir.extra[@intFromEnum(decl.zir_decl_index)..][0..4];
- const contents_hash = @as(std.zig.SrcHash, @bitCast(hash_u32s.*));
- return contents_hash;
- }
-
- pub fn zirBlockIndex(decl: *const Decl, mod: *Module) Zir.Inst.Index {
- assert(decl.zir_decl_index != .none);
- const zir = decl.getFileScope(mod).zir;
- return @enumFromInt(zir.extra[@intFromEnum(decl.zir_decl_index) + 6]);
- }
-
- pub fn zirAlignRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
- if (!decl.has_align) return .none;
- assert(decl.zir_decl_index != .none);
- const zir = decl.getFileScope(mod).zir;
- return @enumFromInt(zir.extra[@intFromEnum(decl.zir_decl_index) + 8]);
- }
-
- pub fn zirLinksectionRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
- if (!decl.has_linksection_or_addrspace) return .none;
- assert(decl.zir_decl_index != .none);
- const zir = decl.getFileScope(mod).zir;
- const extra_index = @intFromEnum(decl.zir_decl_index) + 8 + @intFromBool(decl.has_align);
- return @enumFromInt(zir.extra[extra_index]);
- }
-
- pub fn zirAddrspaceRef(decl: Decl, mod: *Module) Zir.Inst.Ref {
- if (!decl.has_linksection_or_addrspace) return .none;
- assert(decl.zir_decl_index != .none);
- const zir = decl.getFileScope(mod).zir;
- const extra_index = @intFromEnum(decl.zir_decl_index) + 8 + @intFromBool(decl.has_align) + 1;
- return @enumFromInt(zir.extra[extra_index]);
- }
-
- pub fn relativeToLine(decl: Decl, offset: u32) u32 {
- return decl.src_line + offset;
+ pub fn zirBodies(decl: Decl, zcu: *Zcu) Zir.Inst.Declaration.Bodies {
+ const zir = decl.getFileScope(zcu).zir;
+ const zir_index = decl.zir_decl_index.unwrap().?;
+ const pl_node = zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
+ const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
+ return extra.data.getBodies(@intCast(extra.end), zir);
}
pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index {
@@ -3015,16 +2947,12 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
// The root decl will be null if the previous ZIR had AST errors.
const root_decl = file.root_decl.unwrap() orelse return;
- // Maps from old ZIR to new ZIR, struct_decl, enum_decl, etc. Any instruction which
- // creates a namespace, gets mapped from old to new here.
+ // Maps from old ZIR to new ZIR, declaration, struct_decl, enum_decl, etc. Any instruction which
+ // creates a namespace, and any `declaration` instruction, gets mapped from old to new here.
var inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index) = .{};
defer inst_map.deinit(gpa);
- // Maps from old ZIR to new ZIR, the extra data index for the sub-decl item.
- // e.g. the thing that Decl.zir_decl_index points to.
- var extra_map: std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex) = .{};
- defer extra_map.deinit(gpa);
- try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map, &extra_map);
+ try mapOldZirToNew(gpa, old_zir, new_zir, &inst_map);
// Walk the Decl graph, updating ZIR indexes, strings, and populating
// the deleted and outdated lists.
@@ -3050,7 +2978,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void {
// Anonymous decls should not be marked outdated. They will be re-generated
// if their owner decl is marked outdated.
if (decl.zir_decl_index.unwrap()) |old_zir_decl_index| {
- const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse {
+ const new_zir_decl_index = inst_map.get(old_zir_decl_index) orelse {
try file.deleted_decls.append(gpa, decl_index);
continue;
};
@@ -3098,9 +3026,9 @@ pub fn mapOldZirToNew(
old_zir: Zir,
new_zir: Zir,
inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
- extra_map: *std.AutoHashMapUnmanaged(Zir.ExtraIndex, Zir.ExtraIndex),
) Allocator.Error!void {
- // Contain ZIR indexes of declaration instructions.
+ // Contain ZIR indexes of namespace declaration instructions, e.g. struct_decl, union_decl, etc.
+ // Not `declaration`, as this does not create a namespace.
const MatchedZirDecl = struct {
old_inst: Zir.Inst.Index,
new_inst: Zir.Inst.Index,
@@ -3108,47 +3036,113 @@ pub fn mapOldZirToNew(
var match_stack: ArrayListUnmanaged(MatchedZirDecl) = .{};
defer match_stack.deinit(gpa);
- // Main struct inst is always the same
+ // Main struct inst is always matched
try match_stack.append(gpa, .{
.old_inst = .main_struct_inst,
.new_inst = .main_struct_inst,
});
+ // Used as temporary buffers for namespace declaration instructions
var old_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
defer old_decls.deinit();
var new_decls = std.ArrayList(Zir.Inst.Index).init(gpa);
defer new_decls.deinit();
while (match_stack.popOrNull()) |match_item| {
+ // Match the namespace declaration itself
try inst_map.put(gpa, match_item.old_inst, match_item.new_inst);
- // Maps name to extra index of decl sub item.
- var decl_map: std.StringHashMapUnmanaged(Zir.ExtraIndex) = .{};
- defer decl_map.deinit(gpa);
+ // Maps decl name to `declaration` instruction.
+ var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
+ defer named_decls.deinit(gpa);
+ // Maps test name to `declaration` instruction.
+ var named_tests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .{};
+ defer named_tests.deinit(gpa);
+ // All unnamed tests, in order, for a best-effort match.
+ var unnamed_tests: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
+ defer unnamed_tests.deinit(gpa);
+ // All comptime declarations, in order, for a best-effort match.
+ var comptime_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
+ defer comptime_decls.deinit(gpa);
+ // All usingnamespace declarations, in order, for a best-effort match.
+ var usingnamespace_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
+ defer usingnamespace_decls.deinit(gpa);
{
var old_decl_it = old_zir.declIterator(match_item.old_inst);
- while (old_decl_it.next()) |old_decl| {
- try decl_map.put(gpa, old_decl.name, old_decl.sub_index);
+ while (old_decl_it.next()) |old_decl_inst| {
+ const old_decl, _ = old_zir.getDeclaration(old_decl_inst);
+ switch (old_decl.name) {
+ .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
+ .@"usingnamespace" => try usingnamespace_decls.append(gpa, old_decl_inst),
+ .unnamed_test, .decltest => try unnamed_tests.append(gpa, old_decl_inst),
+ _ => {
+ const name_nts = old_decl.name.toString(old_zir).?;
+ const name = old_zir.nullTerminatedString(name_nts);
+ if (old_decl.name.isNamedTest(old_zir)) {
+ try named_tests.put(gpa, name, old_decl_inst);
+ } else {
+ try named_decls.put(gpa, name, old_decl_inst);
+ }
+ },
+ }
}
}
+ var unnamed_test_idx: u32 = 0;
+ var comptime_decl_idx: u32 = 0;
+ var usingnamespace_decl_idx: u32 = 0;
+
var new_decl_it = new_zir.declIterator(match_item.new_inst);
- while (new_decl_it.next()) |new_decl| {
- const old_extra_index = decl_map.get(new_decl.name) orelse continue;
- const new_extra_index = new_decl.sub_index;
- try extra_map.put(gpa, old_extra_index, new_extra_index);
-
- try old_zir.findDecls(&old_decls, old_extra_index);
- try new_zir.findDecls(&new_decls, new_extra_index);
- var i: usize = 0;
- while (true) : (i += 1) {
- if (i >= old_decls.items.len) break;
- if (i >= new_decls.items.len) break;
- try match_stack.append(gpa, .{
- .old_inst = old_decls.items[i],
- .new_inst = new_decls.items[i],
- });
+ while (new_decl_it.next()) |new_decl_inst| {
+ const new_decl, _ = new_zir.getDeclaration(new_decl_inst);
+ // Attempt to match this to a declaration in the old ZIR:
+ // * For named declarations (`const`/`var`/`fn`), we match based on name.
+ // * For named tests (`test "foo"`), we also match based on name.
+ // * For unnamed tests and decltests, we match based on order.
+ // * For comptime blocks, we match based on order.
+ // * For usingnamespace decls, we match based on order.
+ // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`.
+ const old_decl_inst = switch (new_decl.name) {
+ .@"comptime" => inst: {
+ if (comptime_decl_idx == comptime_decls.items.len) continue;
+ defer comptime_decl_idx += 1;
+ break :inst comptime_decls.items[comptime_decl_idx];
+ },
+ .@"usingnamespace" => inst: {
+ if (usingnamespace_decl_idx == usingnamespace_decls.items.len) continue;
+ defer usingnamespace_decl_idx += 1;
+ break :inst usingnamespace_decls.items[usingnamespace_decl_idx];
+ },
+ .unnamed_test, .decltest => inst: {
+ if (unnamed_test_idx == unnamed_tests.items.len) continue;
+ defer unnamed_test_idx += 1;
+ break :inst unnamed_tests.items[unnamed_test_idx];
+ },
+ _ => inst: {
+ const name_nts = new_decl.name.toString(old_zir).?;
+ const name = new_zir.nullTerminatedString(name_nts);
+ if (new_decl.name.isNamedTest(new_zir)) {
+ break :inst named_tests.get(name) orelse continue;
+ } else {
+ break :inst named_decls.get(name) orelse continue;
+ }
+ },
+ };
+
+ // Match the `declaration` instruction
+ try inst_map.put(gpa, old_decl_inst, new_decl_inst);
+
+ // Find namespace declarations within this declaration
+ try old_zir.findDecls(&old_decls, old_decl_inst);
+ try new_zir.findDecls(&new_decls, new_decl_inst);
+
+ // We don't have any smart way of matching up these namespace declarations, so we always
+ // correlate them based on source order.
+ const n = @min(old_decls.items.len, new_decls.items.len);
+ try match_stack.ensureUnusedCapacity(gpa, n);
+ for (old_decls.items[0..n], new_decls.items[0..n]) |old_inst, new_inst| {
+ match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst });
}
}
}
@@ -3457,8 +3451,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
new_decl.src_line = 0;
new_decl.is_pub = true;
new_decl.is_exported = false;
- new_decl.has_align = false;
- new_decl.has_linksection_or_addrspace = false;
new_decl.ty = Type.type;
new_decl.alignment = .none;
new_decl.@"linksection" = .none;
@@ -3561,7 +3553,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
const gpa = mod.gpa;
const zir = decl.getFileScope(mod).zir;
- const zir_datas = zir.instructions.items(.data);
const builtin_type_target_index: InternPool.Index = blk: {
const std_mod = mod.std_mod;
@@ -3639,11 +3630,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
};
defer block_scope.instructions.deinit(gpa);
- const zir_block_index = decl.zirBlockIndex(mod);
- const inst_data = zir_datas[@intFromEnum(zir_block_index)].pl_node;
- const extra = zir.extraData(Zir.Inst.Block, inst_data.payload_index);
- const body = zir.extra[extra.end..][0..extra.data.body_len];
- const result_ref = (try sema.analyzeBodyBreak(&block_scope, @ptrCast(body))).?.operand;
+ const decl_bodies = decl.zirBodies(mod);
+
+ const result_ref = (try sema.analyzeBodyBreak(&block_scope, decl_bodies.value_body)).?.operand;
// We'll do some other bits with the Sema. Clear the type target index just
// in case they analyze any type.
sema.builtin_type_target_index = .none;
@@ -3760,13 +3749,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
decl.ty = decl_tv.ty;
decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod)));
decl.alignment = blk: {
- const align_ref = decl.zirAlignRef(mod);
- if (align_ref == .none) break :blk .none;
+ const align_body = decl_bodies.align_body orelse break :blk .none;
+ const align_ref = (try sema.analyzeBodyBreak(&block_scope, align_body)).?.operand;
break :blk try sema.resolveAlign(&block_scope, align_src, align_ref);
};
decl.@"linksection" = blk: {
- const linksection_ref = decl.zirLinksectionRef(mod);
- if (linksection_ref == .none) break :blk .none;
+ const linksection_body = decl_bodies.linksection_body orelse break :blk .none;
+ const linksection_ref = (try sema.analyzeBodyBreak(&block_scope, linksection_body)).?.operand;
const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, .{
.needed_comptime_reason = "linksection must be comptime-known",
});
@@ -3786,15 +3775,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
};
const target = sema.mod.getTarget();
- break :blk switch (decl.zirAddrspaceRef(mod)) {
- .none => switch (addrspace_ctx) {
- .function => target_util.defaultAddressSpace(target, .function),
- .variable => target_util.defaultAddressSpace(target, .global_mutable),
- .constant => target_util.defaultAddressSpace(target, .global_constant),
- else => unreachable,
- },
- else => |addrspace_ref| try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx),
+
+ const addrspace_body = decl_bodies.addrspace_body orelse break :blk switch (addrspace_ctx) {
+ .function => target_util.defaultAddressSpace(target, .function),
+ .variable => target_util.defaultAddressSpace(target, .global_mutable),
+ .constant => target_util.defaultAddressSpace(target, .global_constant),
+ else => unreachable,
};
+ const addrspace_ref = (try sema.analyzeBodyBreak(&block_scope, addrspace_body)).?.operand;
+ break :blk try sema.analyzeAddressSpace(&block_scope, address_space_src, addrspace_ref, addrspace_ctx);
};
decl.has_tv = true;
decl.analysis = .complete;
@@ -4133,52 +4122,32 @@ fn newEmbedFile(
}
pub fn scanNamespace(
- mod: *Module,
+ zcu: *Zcu,
namespace_index: Namespace.Index,
- extra_start: usize,
- decls_len: u32,
+ decls: []const Zir.Inst.Index,
parent_decl: *Decl,
-) Allocator.Error!usize {
+) Allocator.Error!void {
const tracy = trace(@src());
defer tracy.end();
- const gpa = mod.gpa;
- const namespace = mod.namespacePtr(namespace_index);
- const zir = namespace.file_scope.zir;
+ const gpa = zcu.gpa;
+ const namespace = zcu.namespacePtr(namespace_index);
- try mod.comp.work_queue.ensureUnusedCapacity(decls_len);
- try namespace.decls.ensureTotalCapacity(gpa, decls_len);
+ try zcu.comp.work_queue.ensureUnusedCapacity(decls.len);
+ try namespace.decls.ensureTotalCapacity(gpa, decls.len);
- const bit_bags_count = std.math.divCeil(usize, decls_len, 8) catch unreachable;
- var extra_index = extra_start + bit_bags_count;
- var bit_bag_index: usize = extra_start;
- var cur_bit_bag: u32 = undefined;
- var decl_i: u32 = 0;
var scan_decl_iter: ScanDeclIter = .{
- .module = mod,
+ .zcu = zcu,
.namespace_index = namespace_index,
.parent_decl = parent_decl,
};
- while (decl_i < decls_len) : (decl_i += 1) {
- if (decl_i % 8 == 0) {
- cur_bit_bag = zir.extra[bit_bag_index];
- bit_bag_index += 1;
- }
- const flags = @as(u4, @truncate(cur_bit_bag));
- cur_bit_bag >>= 4;
-
- const decl_sub_index = extra_index;
- extra_index += 8; // src_hash(4) + line(1) + name(1) + value(1) + doc_comment(1)
- extra_index += @as(u1, @truncate(flags >> 2)); // Align
- extra_index += @as(u2, @as(u1, @truncate(flags >> 3))) * 2; // Link section or address space, consists of 2 Refs
-
- try scanDecl(&scan_decl_iter, decl_sub_index, flags);
+ for (decls) |decl_inst| {
+ try scanDecl(&scan_decl_iter, decl_inst);
}
- return extra_index;
}
const ScanDeclIter = struct {
- module: *Module,
+ zcu: *Zcu,
namespace_index: Namespace.Index,
parent_decl: *Decl,
usingnamespace_index: usize = 0,
@@ -4186,119 +4155,112 @@ const ScanDeclIter = struct {
unnamed_test_index: usize = 0,
};
-fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Error!void {
+fn scanDecl(iter: *ScanDeclIter, decl_inst: Zir.Inst.Index) Allocator.Error!void {
const tracy = trace(@src());
defer tracy.end();
- const mod = iter.module;
+ const zcu = iter.zcu;
const namespace_index = iter.namespace_index;
- const namespace = mod.namespacePtr(namespace_index);
- const gpa = mod.gpa;
+ const namespace = zcu.namespacePtr(namespace_index);
+ const gpa = zcu.gpa;
const zir = namespace.file_scope.zir;
- const ip = &mod.intern_pool;
+ const ip = &zcu.intern_pool;
+
+ const pl_node = zir.instructions.items(.data)[@intFromEnum(decl_inst)].pl_node;
+ const extra = zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
+ const declaration = extra.data;
- // zig fmt: off
- const is_pub = (flags & 0b0001) != 0;
- const export_bit = (flags & 0b0010) != 0;
- const has_align = (flags & 0b0100) != 0;
- const has_linksection_or_addrspace = (flags & 0b1000) != 0;
- // zig fmt: on
-
- const line_off = zir.extra[decl_sub_index + 4];
- const line = iter.parent_decl.relativeToLine(line_off);
- const decl_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[decl_sub_index + 5]);
- const decl_doccomment_index = zir.extra[decl_sub_index + 7];
- const decl_zir_index = zir.extra[decl_sub_index + 6];
- const decl_block_inst_data = zir.instructions.items(.data)[decl_zir_index].pl_node;
- const decl_node = iter.parent_decl.relativeToNodeIndex(decl_block_inst_data.src_node);
+ const line = iter.parent_decl.src_line + declaration.line_offset;
+ const decl_node = iter.parent_decl.relativeToNodeIndex(pl_node.src_node);
// Every Decl needs a name.
- var is_named_test = false;
- var kind: Decl.Kind = .named;
- const decl_name: InternPool.NullTerminatedString = switch (decl_name_index) {
- .empty => name: {
- if (export_bit) {
- const i = iter.usingnamespace_index;
- iter.usingnamespace_index += 1;
- kind = .@"usingnamespace";
- break :name try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i});
- } else {
- const i = iter.comptime_index;
- iter.comptime_index += 1;
- kind = .@"comptime";
- break :name try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i});
- }
+ const decl_name: InternPool.NullTerminatedString, const kind: Decl.Kind, const is_named_test: bool = switch (declaration.name) {
+ .@"comptime" => info: {
+ const i = iter.comptime_index;
+ iter.comptime_index += 1;
+ break :info .{
+ try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}),
+ .@"comptime",
+ false,
+ };
+ },
+ .@"usingnamespace" => info: {
+ const i = iter.usingnamespace_index;
+ iter.usingnamespace_index += 1;
+ break :info .{
+ try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}),
+ .@"usingnamespace",
+ false,
+ };
},
- .unnamed_test_decl => name: {
+ .unnamed_test => info: {
const i = iter.unnamed_test_index;
iter.unnamed_test_index += 1;
- kind = .@"test";
- break :name try ip.getOrPutStringFmt(gpa, "test_{d}", .{i});
+ break :info .{
+ try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}),
+ .@"test",
+ false,
+ };
},
- .decltest => name: {
- is_named_test = true;
- const test_name = zir.nullTerminatedString(@enumFromInt(decl_doccomment_index));
- kind = .@"test";
- break :name try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{test_name});
+ .decltest => info: {
+ assert(declaration.flags.has_doc_comment);
+ const name = zir.nullTerminatedString(@enumFromInt(zir.extra[extra.end]));
+ break :info .{
+ try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{name}),
+ .@"test",
+ true,
+ };
},
- _ => name: {
- const raw_name = zir.nullTerminatedString(decl_name_index);
- if (raw_name.len == 0) {
- is_named_test = true;
- const test_name = zir.nullTerminatedString(@enumFromInt(@intFromEnum(decl_name_index) + 1));
- kind = .@"test";
- break :name try ip.getOrPutStringFmt(gpa, "test.{s}", .{test_name});
- } else {
- break :name try ip.getOrPutString(gpa, raw_name);
- }
+ _ => if (declaration.name.isNamedTest(zir)) .{
+ try ip.getOrPutStringFmt(gpa, "test.{s}", .{zir.nullTerminatedString(declaration.name.toString(zir).?)}),
+ .@"test",
+ true,
+ } else .{
+ try ip.getOrPutString(gpa, zir.nullTerminatedString(declaration.name.toString(zir).?)),
+ .named,
+ false,
},
};
- const is_exported = export_bit and decl_name_index != .empty;
if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1);
// We create a Decl for it regardless of analysis status.
const gop = try namespace.decls.getOrPutContextAdapted(
gpa,
decl_name,
- DeclAdapter{ .mod = mod },
- Namespace.DeclContext{ .module = mod },
+ DeclAdapter{ .mod = zcu },
+ Namespace.DeclContext{ .module = zcu },
);
- const comp = mod.comp;
+ const comp = zcu.comp;
if (!gop.found_existing) {
- const new_decl_index = try mod.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
- const new_decl = mod.declPtr(new_decl_index);
+ const new_decl_index = try zcu.allocateNewDecl(namespace_index, decl_node, iter.parent_decl.src_scope);
+ const new_decl = zcu.declPtr(new_decl_index);
new_decl.kind = kind;
new_decl.name = decl_name;
if (kind == .@"usingnamespace") {
- namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub);
+ namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, declaration.flags.is_pub);
}
new_decl.src_line = line;
gop.key_ptr.* = new_decl_index;
// Exported decls, comptime decls, usingnamespace decls, and
// test decls if in test mode, get analyzed.
const decl_mod = namespace.file_scope.mod;
- const want_analysis = is_exported or switch (decl_name_index) {
- .empty => true, // comptime or usingnamespace decl
- .unnamed_test_decl => blk: {
- // test decl with no name. Skip the part where we check against
- // the test name filter.
- if (!comp.config.is_test) break :blk false;
- if (decl_mod != mod.main_mod) break :blk false;
- try mod.test_functions.put(gpa, new_decl_index, {});
- break :blk true;
- },
- else => blk: {
- if (!is_named_test) break :blk false;
- if (!comp.config.is_test) break :blk false;
- if (decl_mod != mod.main_mod) break :blk false;
- if (comp.test_filter) |test_filter| {
- if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
- break :blk false;
+ const want_analysis = declaration.flags.is_export or switch (kind) {
+ .anon => unreachable,
+ .@"comptime", .@"usingnamespace" => true,
+ .named => false,
+ .@"test" => a: {
+ if (!comp.config.is_test) break :a false;
+ if (decl_mod != zcu.main_mod) break :a false;
+ if (is_named_test) {
+ if (comp.test_filter) |test_filter| {
+ if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) {
+ break :a false;
+ }
}
}
- try mod.test_functions.put(gpa, new_decl_index, {});
- break :blk true;
+ try zcu.test_functions.put(gpa, new_decl_index, {});
+ break :a true;
},
};
if (want_analysis) {
@@ -4307,46 +4269,42 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err
});
comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl_index });
}
- new_decl.is_pub = is_pub;
- new_decl.is_exported = is_exported;
- new_decl.has_align = has_align;
- new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
- new_decl.zir_decl_index = @enumFromInt(decl_sub_index);
+ new_decl.is_pub = declaration.flags.is_pub;
+ new_decl.is_exported = declaration.flags.is_export;
+ new_decl.zir_decl_index = decl_inst.toOptional();
new_decl.alive = true; // This Decl corresponds to an AST node and therefore always alive.
return;
}
const decl_index = gop.key_ptr.*;
- const decl = mod.declPtr(decl_index);
+ const decl = zcu.declPtr(decl_index);
if (kind == .@"test") {
const src_loc = SrcLoc{
- .file_scope = decl.getFileScope(mod),
+ .file_scope = decl.getFileScope(zcu),
.parent_decl_node = decl.src_node,
.lazy = .{ .token_offset = 1 },
};
const msg = try ErrorMsg.create(gpa, src_loc, "duplicate test name: {}", .{
- decl_name.fmt(&mod.intern_pool),
+ decl_name.fmt(ip),
});
errdefer msg.destroy(gpa);
- try mod.failed_decls.putNoClobber(gpa, decl_index, msg);
+ try zcu.failed_decls.putNoClobber(gpa, decl_index, msg);
const other_src_loc = SrcLoc{
.file_scope = namespace.file_scope,
.parent_decl_node = decl_node,
.lazy = .{ .token_offset = 1 },
};
- try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
+ try zcu.errNoteNonLazy(other_src_loc, msg, "other test here", .{});
}
// Update the AST node of the decl; even if its contents are unchanged, it may
// have been re-ordered.
decl.src_node = decl_node;
decl.src_line = line;
- decl.is_pub = is_pub;
- decl.is_exported = is_exported;
+ decl.is_pub = declaration.flags.is_pub;
+ decl.is_exported = declaration.flags.is_export;
decl.kind = kind;
- decl.has_align = has_align;
- decl.has_linksection_or_addrspace = has_linksection_or_addrspace;
- decl.zir_decl_index = @enumFromInt(decl_sub_index);
- if (decl.getOwnedFunction(mod) != null) {
+ decl.zir_decl_index = decl_inst.toOptional();
+ if (decl.getOwnedFunction(zcu) != null) {
// TODO Look into detecting when this would be unnecessary by storing enough state
// in `Decl` to notice that the line number did not change.
comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl_index });
@@ -4730,8 +4688,6 @@ pub fn allocateNewDecl(
.generation = 0,
.is_pub = false,
.is_exported = false,
- .has_linksection_or_addrspace = false,
- .has_align = false,
.alive = false,
.kind = .anon,
});