Unwind the fblock stack, emitting cleanup code for each block preserve_tos: if true, preserve the top of stack (e.g., return value) stop_at_loop: if true, stop when encountering a loop (for break/continue)
(&mut self, preserve_tos: bool, stop_at_loop: bool)
| 1606 | /// preserve_tos: if true, preserve the top of stack (e.g., return value) |
| 1607 | /// stop_at_loop: if true, stop when encountering a loop (for break/continue) |
| 1608 | fn unwind_fblock_stack(&mut self, preserve_tos: bool, stop_at_loop: bool) -> CompileResult<()> { |
| 1609 | // Collect the info we need, with indices for FinallyTry blocks |
| 1610 | #[derive(Clone)] |
| 1611 | enum UnwindInfo { |
| 1612 | Normal(FBlockInfo), |
| 1613 | FinallyTry { |
| 1614 | body: Vec<ruff_python_ast::Stmt>, |
| 1615 | fblock_idx: usize, |
| 1616 | }, |
| 1617 | } |
| 1618 | let mut unwind_infos = Vec::new(); |
| 1619 | |
| 1620 | { |
| 1621 | let code = self.current_code_info(); |
| 1622 | for i in (0..code.fblock.len()).rev() { |
| 1623 | // Check for exception group handler (forbidden) |
| 1624 | if matches!(code.fblock[i].fb_type, FBlockType::ExceptionGroupHandler) { |
| 1625 | return Err(self.error(CodegenErrorType::BreakContinueReturnInExceptStar)); |
| 1626 | } |
| 1627 | |
| 1628 | // Stop at loop if requested |
| 1629 | if stop_at_loop |
| 1630 | && matches!( |
| 1631 | code.fblock[i].fb_type, |
| 1632 | FBlockType::WhileLoop | FBlockType::ForLoop |
| 1633 | ) |
| 1634 | { |
| 1635 | break; |
| 1636 | } |
| 1637 | |
| 1638 | if matches!(code.fblock[i].fb_type, FBlockType::FinallyTry) { |
| 1639 | if let FBlockDatum::FinallyBody(ref body) = code.fblock[i].fb_datum { |
| 1640 | unwind_infos.push(UnwindInfo::FinallyTry { |
| 1641 | body: body.clone(), |
| 1642 | fblock_idx: i, |
| 1643 | }); |
| 1644 | } |
| 1645 | } else { |
| 1646 | unwind_infos.push(UnwindInfo::Normal(code.fblock[i].clone())); |
| 1647 | } |
| 1648 | } |
| 1649 | } |
| 1650 | |
| 1651 | // Process each fblock |
| 1652 | for info in unwind_infos { |
| 1653 | match info { |
| 1654 | UnwindInfo::Normal(fblock_info) => { |
| 1655 | self.unwind_fblock(&fblock_info, preserve_tos)?; |
| 1656 | } |
| 1657 | UnwindInfo::FinallyTry { body, fblock_idx } => { |
| 1658 | // codegen_unwind_fblock(FINALLY_TRY) |
| 1659 | emit!(self, PseudoInstruction::PopBlock); |
| 1660 | |
| 1661 | // Temporarily remove the FinallyTry fblock so nested return/break/continue |
| 1662 | // in the finally body won't see it again |
| 1663 | let code = self.current_code_info(); |
| 1664 | let saved_fblock = code.fblock.remove(fblock_idx); |
| 1665 |
no test coverage detected