Commit 89f02d1c10
lib/std/zig/Zir.zig
@@ -603,7 +603,7 @@ pub const Inst = struct {
/// Uses the `un_node` field.
typeof,
/// Implements `@TypeOf` for one operand.
- /// Uses the `pl_node` field.
+ /// Uses the `pl_node` field. Payload is `Block`.
typeof_builtin,
/// Given a value, look at the type of it, which must be an integer type.
/// Returns the integer type for the RHS of a shift operation.
@@ -2727,6 +2727,9 @@ pub const Inst = struct {
field_name_start: NullTerminatedString,
};
+ /// There is a body of instructions at `extra[body_index..][0..body_len]`.
+ /// Trailing:
+ /// 0. operand: Ref // for each `operands_len`
pub const TypeOfPeer = struct {
src_node: i32,
body_len: u32,
@@ -2844,6 +2847,40 @@ pub const Inst = struct {
src_line: u32,
};
+ /// Trailing:
+ /// 0. multi_cases_len: u32 // if `has_multi_cases`
+ /// 1. err_capture_inst: u32 // if `any_uses_err_capture`
+ /// 2. non_err_body {
+ /// info: ProngInfo,
+ /// inst: Index // for every `info.body_len`
+ /// }
+ /// 3. else_body { // if `has_else`
+ /// info: ProngInfo,
+ /// inst: Index // for every `info.body_len`
+ /// }
+ /// 4. scalar_cases: { // for every `scalar_cases_len`
+ /// item: Ref,
+ /// info: ProngInfo,
+ /// inst: Index // for every `info.body_len`
+ /// }
+ /// 5. multi_cases: { // for every `multi_cases_len`
+ /// items_len: u32,
+ /// ranges_len: u32,
+ /// info: ProngInfo,
+ /// item: Ref // for every `items_len`
+ /// ranges: { // for every `ranges_len`
+ /// item_first: Ref,
+ /// item_last: Ref,
+ /// }
+ /// inst: Index // for every `info.body_len`
+ /// }
+ ///
+ /// When analyzing a case body, the switch instruction itself refers to the
+ /// captured error, or to the success value in `non_err_body`. Whether this
+ /// is captured by reference or by value depends on whether the `byref` bit
+ /// is set for the corresponding body. `err_capture_inst` refers to the error
+ /// capture outside of the `switch`, i.e. `err` in
+ /// `x catch |err| switch (err) { ... }`.
pub const SwitchBlockErrUnion = struct {
operand: Ref,
bits: Bits,
@@ -3153,7 +3190,7 @@ pub const Inst = struct {
/// 1. captures_len: u32 // if has_captures_len
/// 2. body_len: u32, // if has_body_len
/// 3. fields_len: u32, // if has_fields_len
- /// 4. decls_len: u37, // if has_decls_len
+ /// 4. decls_len: u32, // if has_decls_len
/// 5. capture: Capture // for every captures_len
/// 6. decl: Index, // for every decls_len; points to a `declaration` instruction
/// 7. inst: Index // for every body_len
@@ -3624,33 +3661,492 @@ pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
}
}
-/// The iterator would have to allocate memory anyway to iterate. So here we populate
-/// an ArrayList as the result.
-pub fn findDecls(zir: Zir, list: *std.ArrayList(Inst.Index), decl_inst: Zir.Inst.Index) !void {
+/// Find all type declarations, recursively, within a `declaration` instruction. Does not recurse through
+/// said type declarations' declarations; to find all declarations, call this function on the declarations
+/// of the discovered types recursively.
+/// The iterator would have to allocate memory anyway to iterate, so an `ArrayList` is populated as the result.
+pub fn findDecls(zir: Zir, gpa: Allocator, list: *std.ArrayListUnmanaged(Inst.Index), decl_inst: Zir.Inst.Index) !void {
list.clearRetainingCapacity();
const declaration, const extra_end = zir.getDeclaration(decl_inst);
const bodies = declaration.getBodies(extra_end, zir);
- try zir.findDeclsBody(list, bodies.value_body);
- if (bodies.align_body) |b| try zir.findDeclsBody(list, b);
- if (bodies.linksection_body) |b| try zir.findDeclsBody(list, b);
- if (bodies.addrspace_body) |b| try zir.findDeclsBody(list, b);
+ // `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) = .{};
+ defer found_defers.deinit(gpa);
+
+ try zir.findDeclsBody(gpa, list, &found_defers, bodies.value_body);
+ if (bodies.align_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
+ if (bodies.linksection_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
+ if (bodies.addrspace_body) |b| try zir.findDeclsBody(gpa, list, &found_defers, b);
}
fn findDeclsInner(
zir: Zir,
- list: *std.ArrayList(Inst.Index),
+ gpa: Allocator,
+ list: *std.ArrayListUnmanaged(Inst.Index),
+ defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index,
) Allocator.Error!void {
const tags = zir.instructions.items(.tag);
const datas = zir.instructions.items(.data);
switch (tags[@intFromEnum(inst)]) {
+ .declaration => unreachable,
+
+ // Boring instruction tags first. These have no body and are not declarations or type declarations.
+ .add,
+ .addwrap,
+ .add_sat,
+ .add_unsafe,
+ .sub,
+ .subwrap,
+ .sub_sat,
+ .mul,
+ .mulwrap,
+ .mul_sat,
+ .div_exact,
+ .div_floor,
+ .div_trunc,
+ .mod,
+ .rem,
+ .mod_rem,
+ .shl,
+ .shl_exact,
+ .shl_sat,
+ .shr,
+ .shr_exact,
+ .param_anytype,
+ .param_anytype_comptime,
+ .array_cat,
+ .array_mul,
+ .array_type,
+ .array_type_sentinel,
+ .vector_type,
+ .elem_type,
+ .indexable_ptr_elem_type,
+ .vector_elem_type,
+ .indexable_ptr_len,
+ .anyframe_type,
+ .as_node,
+ .as_shift_operand,
+ .bit_and,
+ .bitcast,
+ .bit_not,
+ .bit_or,
+ .bool_not,
+ .bool_br_and,
+ .bool_br_or,
+ .@"break",
+ .break_inline,
+ .check_comptime_control_flow,
+ .builtin_call,
+ .cmp_lt,
+ .cmp_lte,
+ .cmp_eq,
+ .cmp_gte,
+ .cmp_gt,
+ .cmp_neq,
+ .error_set_decl,
+ .dbg_stmt,
+ .dbg_var_ptr,
+ .dbg_var_val,
+ .decl_ref,
+ .decl_val,
+ .load,
+ .div,
+ .elem_ptr_node,
+ .elem_ptr,
+ .elem_val_node,
+ .elem_val,
+ .elem_val_imm,
+ .ensure_result_used,
+ .ensure_result_non_error,
+ .ensure_err_union_payload_void,
+ .error_union_type,
+ .error_value,
+ .@"export",
+ .export_value,
+ .field_ptr,
+ .field_val,
+ .field_ptr_named,
+ .field_val_named,
+ .import,
+ .int,
+ .int_big,
+ .float,
+ .float128,
+ .int_type,
+ .is_non_null,
+ .is_non_null_ptr,
+ .is_non_err,
+ .is_non_err_ptr,
+ .ret_is_non_err,
+ .repeat,
+ .repeat_inline,
+ .for_len,
+ .merge_error_sets,
+ .ref,
+ .ret_node,
+ .ret_load,
+ .ret_implicit,
+ .ret_err_value,
+ .ret_err_value_code,
+ .ret_ptr,
+ .ret_type,
+ .ptr_type,
+ .slice_start,
+ .slice_end,
+ .slice_sentinel,
+ .slice_length,
+ .store_node,
+ .store_to_inferred_ptr,
+ .str,
+ .negate,
+ .negate_wrap,
+ .typeof,
+ .typeof_log2_int_type,
+ .@"unreachable",
+ .xor,
+ .optional_type,
+ .optional_payload_safe,
+ .optional_payload_unsafe,
+ .optional_payload_safe_ptr,
+ .optional_payload_unsafe_ptr,
+ .err_union_payload_unsafe,
+ .err_union_payload_unsafe_ptr,
+ .err_union_code,
+ .err_union_code_ptr,
+ .enum_literal,
+ .validate_deref,
+ .validate_destructure,
+ .field_type_ref,
+ .opt_eu_base_ptr_init,
+ .coerce_ptr_elem_ty,
+ .validate_ref_ty,
+ .struct_init_empty,
+ .struct_init_empty_result,
+ .struct_init_empty_ref_result,
+ .struct_init_anon,
+ .struct_init,
+ .struct_init_ref,
+ .validate_struct_init_ty,
+ .validate_struct_init_result_ty,
+ .validate_ptr_struct_init,
+ .struct_init_field_type,
+ .struct_init_field_ptr,
+ .array_init_anon,
+ .array_init,
+ .array_init_ref,
+ .validate_array_init_ty,
+ .validate_array_init_result_ty,
+ .validate_array_init_ref_ty,
+ .validate_ptr_array_init,
+ .array_init_elem_type,
+ .array_init_elem_ptr,
+ .union_init,
+ .type_info,
+ .size_of,
+ .bit_size_of,
+ .int_from_ptr,
+ .compile_error,
+ .set_eval_branch_quota,
+ .int_from_enum,
+ .align_of,
+ .int_from_bool,
+ .embed_file,
+ .error_name,
+ .panic,
+ .trap,
+ .set_runtime_safety,
+ .sqrt,
+ .sin,
+ .cos,
+ .tan,
+ .exp,
+ .exp2,
+ .log,
+ .log2,
+ .log10,
+ .abs,
+ .floor,
+ .ceil,
+ .trunc,
+ .round,
+ .tag_name,
+ .type_name,
+ .frame_type,
+ .frame_size,
+ .int_from_float,
+ .float_from_int,
+ .ptr_from_int,
+ .enum_from_int,
+ .float_cast,
+ .int_cast,
+ .ptr_cast,
+ .truncate,
+ .has_decl,
+ .has_field,
+ .clz,
+ .ctz,
+ .pop_count,
+ .byte_swap,
+ .bit_reverse,
+ .bit_offset_of,
+ .offset_of,
+ .splat,
+ .reduce,
+ .shuffle,
+ .atomic_load,
+ .atomic_rmw,
+ .atomic_store,
+ .mul_add,
+ .memcpy,
+ .memset,
+ .min,
+ .max,
+ .alloc,
+ .alloc_mut,
+ .alloc_comptime_mut,
+ .alloc_inferred,
+ .alloc_inferred_mut,
+ .alloc_inferred_comptime,
+ .alloc_inferred_comptime_mut,
+ .resolve_inferred_alloc,
+ .make_ptr_const,
+ .@"resume",
+ .@"await",
+ .save_err_ret_index,
+ .restore_err_ret_index_unconditional,
+ .restore_err_ret_index_fn_entry,
+ => return,
+
+ .extended => {
+ const extended = datas[@intFromEnum(inst)].extended;
+ switch (extended.opcode) {
+ .value_placeholder => unreachable,
+
+ // Once again, we start with the boring tags.
+ .variable,
+ .this,
+ .ret_addr,
+ .builtin_src,
+ .error_return_trace,
+ .frame,
+ .frame_address,
+ .alloc,
+ .builtin_extern,
+ .@"asm",
+ .asm_expr,
+ .compile_log,
+ .min_multi,
+ .max_multi,
+ .add_with_overflow,
+ .sub_with_overflow,
+ .mul_with_overflow,
+ .shl_with_overflow,
+ .c_undef,
+ .c_include,
+ .c_define,
+ .wasm_memory_size,
+ .wasm_memory_grow,
+ .prefetch,
+ .fence,
+ .set_float_mode,
+ .set_align_stack,
+ .set_cold,
+ .error_cast,
+ .await_nosuspend,
+ .breakpoint,
+ .disable_instrumentation,
+ .select,
+ .int_from_error,
+ .error_from_int,
+ .builtin_async_call,
+ .cmpxchg,
+ .c_va_arg,
+ .c_va_copy,
+ .c_va_end,
+ .c_va_start,
+ .ptr_cast_full,
+ .ptr_cast_no_dest,
+ .work_item_id,
+ .work_group_size,
+ .work_group_id,
+ .in_comptime,
+ .restore_err_ret_index,
+ .closure_get,
+ .field_parent_ptr,
+ => return,
+
+ // `@TypeOf` has a body.
+ .typeof_peer => {
+ const extra = zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
+ const body = zir.bodySlice(extra.data.body_index, extra.data.body_len);
+ try zir.findDeclsBody(gpa, list, defers, body);
+ },
+
+ // Reifications and opaque declarations need tracking, but have no body.
+ .reify, .opaque_decl => return list.append(gpa, inst),
+
+ // Struct declarations need tracking and have bodies.
+ .struct_decl => {
+ try list.append(gpa, inst);
+
+ const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
+ const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
+ var extra_index = extra.end;
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+ const fields_len = if (small.has_fields_len) blk: {
+ const fields_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk fields_len;
+ } else 0;
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+ extra_index += captures_len;
+ if (small.has_backing_int) {
+ const backing_int_body_len = zir.extra[extra_index];
+ extra_index += 1;
+ if (backing_int_body_len == 0) {
+ extra_index += 1; // backing_int_ref
+ } else {
+ const body = zir.bodySlice(extra_index, backing_int_body_len);
+ extra_index += backing_int_body_len;
+ try zir.findDeclsBody(gpa, list, defers, body);
+ }
+ }
+ extra_index += decls_len;
+
+ // This ZIR is structured in a slightly awkward way, so we have to split up the iteration.
+ // `extra_index` iterates `flags` (bags of bits).
+ // `fields_extra_index` iterates `fields`.
+ // We accumulate the total length of bodies into `total_bodies_len`. This is sufficient because
+ // the bodies are packed together in `extra` and we only need to traverse their instructions (we
+ // don't really care about the structure).
+
+ const bits_per_field = 4;
+ const fields_per_u32 = 32 / bits_per_field;
+ const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
+ var cur_bit_bag: u32 = undefined;
+
+ var fields_extra_index = extra_index + bit_bags_count;
+ var total_bodies_len: u32 = 0;
+
+ for (0..fields_len) |field_i| {
+ if (field_i % fields_per_u32 == 0) {
+ cur_bit_bag = zir.extra[extra_index];
+ extra_index += 1;
+ }
+
+ const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
+ cur_bit_bag >>= 1;
+ const has_init = @as(u1, @truncate(cur_bit_bag)) != 0;
+ cur_bit_bag >>= 2; // also skip `is_comptime`; we don't care
+ const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
+ cur_bit_bag >>= 1;
+
+ fields_extra_index += @intFromBool(!small.is_tuple); // field_name
+ fields_extra_index += 1; // doc_comment
+
+ if (has_type_body) {
+ const field_type_body_len = zir.extra[fields_extra_index];
+ total_bodies_len += field_type_body_len;
+ }
+ fields_extra_index += 1; // field_type or field_type_body_len
+
+ if (has_align) {
+ const align_body_len = zir.extra[fields_extra_index];
+ fields_extra_index += 1;
+ total_bodies_len += align_body_len;
+ }
+
+ if (has_init) {
+ const init_body_len = zir.extra[fields_extra_index];
+ fields_extra_index += 1;
+ total_bodies_len += init_body_len;
+ }
+ }
+
+ // Now, `fields_extra_index` points to `bodies`. Let's treat this as one big body.
+ const merged_bodies = zir.bodySlice(fields_extra_index, total_bodies_len);
+ try zir.findDeclsBody(gpa, list, defers, merged_bodies);
+ },
+
+ // Union declarations need tracking and have a body.
+ .union_decl => {
+ try list.append(gpa, inst);
+
+ const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
+ const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
+ var extra_index = extra.end;
+ extra_index += @intFromBool(small.has_tag_type);
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+ extra_index += @intFromBool(small.has_fields_len);
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+ extra_index += captures_len;
+ extra_index += decls_len;
+ const body = zir.bodySlice(extra_index, body_len);
+ try zir.findDeclsBody(gpa, list, defers, body);
+ },
+
+ // Enum declarations need tracking and have a body.
+ .enum_decl => {
+ try list.append(gpa, inst);
+
+ const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
+ const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
+ var extra_index = extra.end;
+ extra_index += @intFromBool(small.has_tag_type);
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+ const body_len = if (small.has_body_len) blk: {
+ const body_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk body_len;
+ } else 0;
+ extra_index += @intFromBool(small.has_fields_len);
+ const decls_len = if (small.has_decls_len) blk: {
+ const decls_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk decls_len;
+ } else 0;
+ extra_index += captures_len;
+ extra_index += decls_len;
+ const body = zir.bodySlice(extra_index, body_len);
+ try zir.findDeclsBody(gpa, list, defers, body);
+ },
+ }
+ },
+
// Functions instructions are interesting and have a body.
.func,
.func_inferred,
=> {
- try list.append(inst);
+ try list.append(gpa, inst);
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.Func, inst_data.payload_index);
@@ -3661,14 +4157,14 @@ fn findDeclsInner(
else => {
const body = zir.bodySlice(extra_index, extra.data.ret_body_len);
extra_index += body.len;
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
},
}
const body = zir.bodySlice(extra_index, extra.data.body_len);
- return zir.findDeclsBody(list, body);
+ return zir.findDeclsBody(gpa, list, defers, body);
},
.func_fancy => {
- try list.append(inst);
+ try list.append(gpa, inst);
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.FuncFancy, inst_data.payload_index);
@@ -3679,7 +4175,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_align_ref) {
extra_index += 1;
@@ -3689,7 +4185,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_addrspace_ref) {
extra_index += 1;
@@ -3699,7 +4195,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_section_ref) {
extra_index += 1;
@@ -3709,7 +4205,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_cc_ref) {
extra_index += 1;
@@ -3719,7 +4215,7 @@ fn findDeclsInner(
const body_len = zir.extra[extra_index];
extra_index += 1;
const body = zir.bodySlice(extra_index, body_len);
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
extra_index += body.len;
} else if (extra.data.bits.has_ret_ty_ref) {
extra_index += 1;
@@ -3728,62 +4224,99 @@ fn findDeclsInner(
extra_index += @intFromBool(extra.data.bits.has_any_noalias);
const body = zir.bodySlice(extra_index, extra.data.body_len);
- return zir.findDeclsBody(list, body);
- },
- .extended => {
- const extended = datas[@intFromEnum(inst)].extended;
- switch (extended.opcode) {
-
- // Decl instructions are interesting but have no body.
- // TODO yes they do have a body actually. recurse over them just like block instructions.
- .struct_decl,
- .union_decl,
- .enum_decl,
- .opaque_decl,
- .reify,
- => return list.append(inst),
-
- else => return,
- }
+ return zir.findDeclsBody(gpa, list, defers, body);
},
// Block instructions, recurse over the bodies.
- .block, .block_comptime, .block_inline => {
+ .block,
+ .block_comptime,
+ .block_inline,
+ .c_import,
+ .typeof_builtin,
+ .loop,
+ => {
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.Block, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.body_len);
- return zir.findDeclsBody(list, body);
+ return zir.findDeclsBody(gpa, list, defers, body);
},
.condbr, .condbr_inline => {
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.CondBr, inst_data.payload_index);
const then_body = zir.bodySlice(extra.end, extra.data.then_body_len);
const else_body = zir.bodySlice(extra.end + then_body.len, extra.data.else_body_len);
- try zir.findDeclsBody(list, then_body);
- try zir.findDeclsBody(list, else_body);
+ try zir.findDeclsBody(gpa, list, defers, then_body);
+ try zir.findDeclsBody(gpa, list, defers, else_body);
},
.@"try", .try_ptr => {
const inst_data = datas[@intFromEnum(inst)].pl_node;
const extra = zir.extraData(Inst.Try, inst_data.payload_index);
const body = zir.bodySlice(extra.end, extra.data.body_len);
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
},
- .switch_block => return findDeclsSwitch(zir, list, inst),
+ .switch_block, .switch_block_ref => return zir.findDeclsSwitch(gpa, list, defers, inst, .normal),
+ .switch_block_err_union => return zir.findDeclsSwitch(gpa, list, defers, inst, .err_union),
.suspend_block => @panic("TODO iterate suspend block"),
- else => return, // Regular instruction, not interesting.
+ .param, .param_comptime => {
+ const inst_data = datas[@intFromEnum(inst)].pl_tok;
+ const extra = zir.extraData(Inst.Param, inst_data.payload_index);
+ const body = zir.bodySlice(extra.end, extra.data.body_len);
+ try zir.findDeclsBody(gpa, list, defers, body);
+ },
+
+ inline .call, .field_call => |tag| {
+ const inst_data = datas[@intFromEnum(inst)].pl_node;
+ const extra = zir.extraData(switch (tag) {
+ .call => Inst.Call,
+ .field_call => Inst.FieldCall,
+ else => unreachable,
+ }, inst_data.payload_index);
+ // It's easiest to just combine all the arg bodies into one body, like we do above for `struct_decl`.
+ const args_len = extra.data.flags.args_len;
+ if (args_len > 0) {
+ const first_arg_start_off = args_len;
+ const final_arg_end_off = zir.extra[extra.end + args_len - 1];
+ const args_body = zir.bodySlice(extra.end + first_arg_start_off, final_arg_end_off - first_arg_start_off);
+ try zir.findDeclsBody(gpa, list, defers, args_body);
+ }
+ },
+ .@"defer" => {
+ const inst_data = datas[@intFromEnum(inst)].@"defer";
+ const gop = try defers.getOrPut(gpa, inst_data.index);
+ if (!gop.found_existing) {
+ const body = zir.bodySlice(inst_data.index, inst_data.len);
+ try zir.findDeclsBody(gpa, list, defers, body);
+ }
+ },
+ .defer_err_code => {
+ const inst_data = datas[@intFromEnum(inst)].defer_err_code;
+ const extra = zir.extraData(Inst.DeferErrCode, inst_data.payload_index).data;
+ const gop = try defers.getOrPut(gpa, extra.index);
+ if (!gop.found_existing) {
+ const body = zir.bodySlice(extra.index, extra.len);
+ try zir.findDeclsBody(gpa, list, defers, body);
+ }
+ },
}
}
fn findDeclsSwitch(
zir: Zir,
- list: *std.ArrayList(Inst.Index),
+ gpa: Allocator,
+ list: *std.ArrayListUnmanaged(Inst.Index),
+ defers: *std.AutoHashMapUnmanaged(u32, void),
inst: Inst.Index,
+ /// Distinguishes between `switch_block[_ref]` and `switch_block_err_union`.
+ comptime kind: enum { normal, err_union },
) Allocator.Error!void {
const inst_data = zir.instructions.items(.data)[@intFromEnum(inst)].pl_node;
- const extra = zir.extraData(Inst.SwitchBlock, inst_data.payload_index);
+ const extra = zir.extraData(switch (kind) {
+ .normal => Inst.SwitchBlock,
+ .err_union => Inst.SwitchBlockErrUnion,
+ }, inst_data.payload_index);
var extra_index: usize = extra.end;
@@ -3793,18 +4326,35 @@ fn findDeclsSwitch(
break :blk multi_cases_len;
} else 0;
- if (extra.data.bits.any_has_tag_capture) {
+ if (switch (kind) {
+ .normal => extra.data.bits.any_has_tag_capture,
+ .err_union => extra.data.bits.any_uses_err_capture,
+ }) {
extra_index += 1;
}
- const special_prong = extra.data.bits.specialProng();
- if (special_prong != .none) {
+ const has_special = switch (kind) {
+ .normal => extra.data.bits.specialProng() != .none,
+ .err_union => has_special: {
+ // Handle `non_err_body` first.
+ const prong_info: Inst.SwitchBlock.ProngInfo = @bitCast(zir.extra[extra_index]);
+ extra_index += 1;
+ const body = zir.bodySlice(extra_index, prong_info.body_len);
+ extra_index += body.len;
+
+ try zir.findDeclsBody(gpa, list, defers, body);
+
+ break :has_special extra.data.bits.has_else;
+ },
+ };
+
+ if (has_special) {
const prong_info: Inst.SwitchBlock.ProngInfo = @bitCast(zir.extra[extra_index]);
extra_index += 1;
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
}
{
@@ -3816,7 +4366,7 @@ fn findDeclsSwitch(
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
}
}
{
@@ -3833,18 +4383,20 @@ fn findDeclsSwitch(
const body = zir.bodySlice(extra_index, prong_info.body_len);
extra_index += body.len;
- try zir.findDeclsBody(list, body);
+ try zir.findDeclsBody(gpa, list, defers, body);
}
}
}
fn findDeclsBody(
zir: Zir,
- list: *std.ArrayList(Inst.Index),
+ gpa: Allocator,
+ list: *std.ArrayListUnmanaged(Inst.Index),
+ defers: *std.AutoHashMapUnmanaged(u32, void),
body: []const Inst.Index,
) Allocator.Error!void {
for (body) |member| {
- try zir.findDeclsInner(list, member);
+ try zir.findDeclsInner(gpa, list, defers, member);
}
}
@@ -4042,7 +4594,7 @@ pub fn getAssociatedSrcHash(zir: Zir, inst: Zir.Inst.Index) ?std.zig.SrcHash {
return null;
}
const extra_index = extra.end +
- 1 +
+ extra.data.ret_body_len +
extra.data.body_len +
@typeInfo(Inst.Func.SrcLocs).Struct.fields.len;
return @bitCast([4]u32{
src/Zcu.zig
@@ -2557,10 +2557,10 @@ pub fn mapOldZirToNew(
});
// 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();
+ var old_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
+ defer old_decls.deinit(gpa);
+ var new_decls: std.ArrayListUnmanaged(Zir.Inst.Index) = .{};
+ defer new_decls.deinit(gpa);
while (match_stack.popOrNull()) |match_item| {
// Match the namespace declaration itself
@@ -2647,11 +2647,11 @@ pub fn mapOldZirToNew(
// 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);
+ // Find container type declarations within this declaration
+ try old_zir.findDecls(gpa, &old_decls, old_decl_inst);
+ try new_zir.findDecls(gpa, &new_decls, new_decl_inst);
- // We don't have any smart way of matching up these namespace declarations, so we always
+ // We don't have any smart way of matching up these type 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);