Python: Handle loop constructs outside of loops

Observed on some test files in Nuitka/Nuitka, having `break` and
`continue` outside of loops in Python is (to Python) a syntax error, but
our parser happily accepted this broken syntax.

This then caused issues further downstream in the control-flow
construction, as it broke some invariants.

To fix this we now skip the code that would previously fail when the
invariants are broken.

Co-authored-by: yoff <yoff@github.com>
This commit is contained in:
Taus
2025-02-06 14:28:06 +00:00
parent 40851aeaef
commit 131ec8d22f
3 changed files with 25 additions and 2 deletions

View File

@@ -909,14 +909,22 @@ class FlowPass(Pass):
def _walk_break(self, node, predecessors):
#A break statement counts as an exit to the enclosing loop statement
predecessors = self.add_successor(predecessors, node)
self.scope.breaking_stack.add(predecessors)
# In well formed code, there should always be an element in the breaking stack, but because
# our parser accepts code where `break` appears outside of a loop, we must check for this
# case.
if self.scope.breaking_stack:
self.scope.breaking_stack.add(predecessors)
#Provide no predecessors to following statement
return EMPTY
def _walk_continue(self, node, predecessors):
#A continue statement counts as an exit to the following orelse
predecessors = self.add_successor(predecessors, node)
self.scope.continuing_stack.add(predecessors)
# In well formed code, there should always be an element in the continuing stack, but
# because our parser accepts code where `continue` appears outside of a loop, we must check
# for this case.
if self.scope.continuing_stack:
self.scope.continuing_stack.add(predecessors)
#Provide no predecessors to following statement
return EMPTY