forked from M-Labs/artiq
1
0
Fork 0

Fix try/finally:while:try compilation

When we have a trys inside a loop then we want to make sure any
finallys are executed by break and continue inside this try. But
this shouldn't pull finallys defined outside the loop in to the
loop. This change resets the `outer_final` attribute when
visiting for and while loops so that this doesn't happen.

Signed-off-by: Michael Birtwell <michael.birtwell@oxionics.com>
This commit is contained in:
Michael Birtwell 2022-02-22 10:47:29 +00:00 committed by Sébastien Bourdeauducq
parent c000af9985
commit 2d6215158f
1 changed files with 14 additions and 0 deletions

View File

@ -468,6 +468,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
self.append(ir.BranchIf(cond, if_true, tail), block=head) self.append(ir.BranchIf(cond, if_true, tail), block=head)
def visit_While(self, node): def visit_While(self, node):
old_outer_final, self.outer_final = self.outer_final, None
try: try:
head = self.add_block("while.head") head = self.add_block("while.head")
self.append(ir.Branch(head)) self.append(ir.Branch(head))
@ -487,6 +488,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
finally: finally:
self.break_target = old_break self.break_target = old_break
self.continue_target = old_continue self.continue_target = old_continue
self.outer_final = old_outer_final
if any(node.orelse): if any(node.orelse):
else_tail = self.add_block("while.else") else_tail = self.add_block("while.else")
@ -561,6 +563,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
assert False assert False
def visit_ForT(self, node): def visit_ForT(self, node):
old_outer_final, self.outer_final = self.outer_final, None
try: try:
iterable = self.visit(node.iter) iterable = self.visit(node.iter)
length = self.iterable_len(iterable) length = self.iterable_len(iterable)
@ -598,6 +601,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
finally: finally:
self.break_target = old_break self.break_target = old_break
self.continue_target = old_continue self.continue_target = old_continue
self.outer_final = old_outer_final
if any(node.orelse): if any(node.orelse):
else_tail = self.add_block("for.else") else_tail = self.add_block("for.else")
@ -783,8 +787,18 @@ class ARTIQIRGenerator(algorithm.Visitor):
old_unwind, self.unwind_target = self.unwind_target, final_dispatcher old_unwind, self.unwind_target = self.unwind_target, final_dispatcher
if any(node.finalbody): if any(node.finalbody):
# if we have a while:try/finally continue must execute finally
# before continuing the while
redirect = final_branch redirect = final_branch
elif self.outer_final is not None: elif self.outer_final is not None:
# If we have while:try/finally:try then we need to execute that finally
# before the continuing the while
# If we have try/finally:while:try then we should just continue the
# while without having to execute the finally until later
# If we have try/finally:while:try/finally:try we should execute
# one but not the other
# This is achieved by reseting self.outer_final in while and for
# loops
redirect = self.outer_final redirect = self.outer_final
else: else:
redirect = lambda dest, proxy: proxy.append(ir.Branch(dest)) redirect = lambda dest, proxy: proxy.append(ir.Branch(dest))