| ... | ... | @@ -4427,6 +4427,15 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator { |
| 4427 | 4427 | }; |
| 4428 | 4428 | }, |
| 4429 | 4429 | |
| 4430 | // Functions are allowed and yield no iterations. |
| 4431 | .func, |
| 4432 | .func_inferred, |
| 4433 | .extended, // assume also a function |
| 4434 | => .{ |
| 4435 | .extra_index = 0, |
| 4436 | .decls_len = 0, |
| 4437 | }, |
| 4438 | |
| 4430 | 4439 | else => unreachable, |
| 4431 | 4440 | }; |
| 4432 | 4441 | |
| ... | ... | @@ -4441,3 +4450,110 @@ pub fn declIterator(zir: Zir, decl_inst: u32) DeclIterator { |
| 4441 | 4450 | .decls_len = decl_info.decls_len, |
| 4442 | 4451 | }; |
| 4443 | 4452 | } |
| 4453 | |
| 4454 | /// The iterator would have to allocate memory anyway to iterate. So here we populate |
| 4455 | /// an ArrayList as the result. |
| 4456 | pub fn findDecls(zir: Zir, list: *std.ArrayList(Zir.Inst.Index), decl_sub_index: u32) !void { |
| 4457 | const block_inst = zir.extra[decl_sub_index + 6]; |
| 4458 | list.clearRetainingCapacity(); |
| 4459 | |
| 4460 | return zir.findDeclsInner(list, block_inst); |
| 4461 | } |
| 4462 | |
| 4463 | fn findDeclsInner( |
| 4464 | zir: Zir, |
| 4465 | list: *std.ArrayList(Zir.Inst.Index), |
| 4466 | inst: Zir.Inst.Index, |
| 4467 | ) Allocator.Error!void { |
| 4468 | const tags = zir.instructions.items(.tag); |
| 4469 | const datas = zir.instructions.items(.data); |
| 4470 | |
| 4471 | switch (tags[inst]) { |
| 4472 | // Decl instructions are interesting but have no body. |
| 4473 | .struct_decl, |
| 4474 | .struct_decl_packed, |
| 4475 | .struct_decl_extern, |
| 4476 | .union_decl, |
| 4477 | .union_decl_packed, |
| 4478 | .union_decl_extern, |
| 4479 | .enum_decl, |
| 4480 | .enum_decl_nonexhaustive, |
| 4481 | .opaque_decl, |
| 4482 | => return list.append(inst), |
| 4483 | |
| 4484 | // Functions instructions are interesting and have a body. |
| 4485 | .func, |
| 4486 | .func_inferred, |
| 4487 | => { |
| 4488 | try list.append(inst); |
| 4489 | |
| 4490 | const inst_data = datas[inst].pl_node; |
| 4491 | const extra = zir.extraData(Inst.Func, inst_data.payload_index); |
| 4492 | const param_types_len = extra.data.param_types_len; |
| 4493 | const body = zir.extra[extra.end + param_types_len ..][0..extra.data.body_len]; |
| 4494 | return zir.findDeclsBody(list, body); |
| 4495 | }, |
| 4496 | .extended => { |
| 4497 | const extended = datas[inst].extended; |
| 4498 | if (extended.opcode != .func) return; |
| 4499 | |
| 4500 | try list.append(inst); |
| 4501 | |
| 4502 | const extra = zir.extraData(Inst.ExtendedFunc, extended.operand); |
| 4503 | const small = @bitCast(Inst.ExtendedFunc.Small, extended.small); |
| 4504 | var extra_index: usize = extra.end; |
| 4505 | extra_index += @boolToInt(small.has_lib_name); |
| 4506 | extra_index += @boolToInt(small.has_cc); |
| 4507 | extra_index += @boolToInt(small.has_align); |
| 4508 | extra_index += extra.data.param_types_len; |
| 4509 | const body = zir.extra[extra_index..][0..extra.data.body_len]; |
| 4510 | return zir.findDeclsBody(list, body); |
| 4511 | }, |
| 4512 | |
| 4513 | // Block instructions, recurse over the bodies. |
| 4514 | |
| 4515 | .block, .block_inline => { |
| 4516 | const inst_data = datas[inst].pl_node; |
| 4517 | const extra = zir.extraData(Inst.Block, inst_data.payload_index); |
| 4518 | const body = zir.extra[extra.end..][0..extra.data.body_len]; |
| 4519 | return zir.findDeclsBody(list, body); |
| 4520 | }, |
| 4521 | .condbr, .condbr_inline => { |
| 4522 | const inst_data = datas[inst].pl_node; |
| 4523 | const extra = zir.extraData(Inst.CondBr, inst_data.payload_index); |
| 4524 | const then_body = zir.extra[extra.end..][0..extra.data.then_body_len]; |
| 4525 | const else_body = zir.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]; |
| 4526 | try zir.findDeclsBody(list, then_body); |
| 4527 | try zir.findDeclsBody(list, else_body); |
| 4528 | }, |
| 4529 | .switch_block, |
| 4530 | .switch_block_else, |
| 4531 | .switch_block_under, |
| 4532 | .switch_block_ref, |
| 4533 | .switch_block_ref_else, |
| 4534 | .switch_block_ref_under, |
| 4535 | => @panic("TODO iterate switch block"), |
| 4536 | |
| 4537 | .switch_block_multi, |
| 4538 | .switch_block_else_multi, |
| 4539 | .switch_block_under_multi, |
| 4540 | .switch_block_ref_multi, |
| 4541 | .switch_block_ref_else_multi, |
| 4542 | .switch_block_ref_under_multi, |
| 4543 | => @panic("TODO iterate switch block multi"), |
| 4544 | |
| 4545 | .suspend_block => @panic("TODO iterate suspend block"), |
| 4546 | |
| 4547 | else => return, // Regular instruction, not interesting. |
| 4548 | } |
| 4549 | } |
| 4550 | |
| 4551 | fn findDeclsBody( |
| 4552 | zir: Zir, |
| 4553 | list: *std.ArrayList(Zir.Inst.Index), |
| 4554 | body: []const Zir.Inst.Index, |
| 4555 | ) Allocator.Error!void { |
| 4556 | for (body) |member| { |
| 4557 | try zir.findDeclsInner(list, member); |
| 4558 | } |
| 4559 | } |