# HG changeset patch # User Paul Boddie # Date 1479509293 -3600 # Node ID 7e1a6b2d69b816d3652fc1c736f54cb18c2905af # Parent c0775a0f068c80dfad141db0dd21246120de1220 Make sure that return operations restore all previous exception contexts. diff -r c0775a0f068c -r 7e1a6b2d69b8 templates/cexcept.h --- a/templates/cexcept.h Fri Nov 18 17:25:24 2016 +0100 +++ b/templates/cexcept.h Fri Nov 18 23:48:13 2016 +0100 @@ -9,8 +9,8 @@ An interface for exception-handling in ANSI C (C89 and subsequent ISO standards), developed jointly with Cosmin Truta. + Copyright (c) 2016 Paul Boddie (modified for Lichen). Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta. - Copyright (c) 2016 Paul Boddie (modified for Lichen). This software may be modified only if its author and version information is updated accurately, and may be redistributed only if accompanied by this unaltered notice. Subject to those diff -r c0775a0f068c -r 7e1a6b2d69b8 translator.py --- a/translator.py Fri Nov 18 17:25:24 2016 +0100 +++ b/translator.py Fri Nov 18 23:48:13 2016 +0100 @@ -234,6 +234,7 @@ # Exception raising adjustments. self.in_try_finally = False + self.in_try_except = False # Attribute access counting. @@ -1107,7 +1108,7 @@ "Process the given return node 'n'." expr = self.process_structure_node(n.value) or PredefinedConstantRef("None") - if self.in_try_finally: + if self.in_try_finally or self.in_try_except: self.writestmt("__Return(%s);" % expr) else: self.writestmt("return %s;" % expr) @@ -1120,6 +1121,9 @@ Process the given "try...except" node 'n'. """ + in_try_except = self.in_try_except + self.in_try_except = True + # Use macros to implement exception handling. self.writestmt("__Try") @@ -1153,27 +1157,23 @@ self.indent -= 1 self.writeline("}") + self.in_try_except = in_try_except + # Handlers are tests within a common handler block. self.writeline("__Catch (__tmp_exc)") self.writeline("{") self.indent += 1 + # Introduce an if statement to handle the completion of a try block. + + self.process_try_completion() + # Handle exceptions in else blocks converted to __RaiseElse, converting # them back to normal exceptions. - else_str = "" - if n.else_: - self.writeline("if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") - else_str = "else " - - # Handle the completion of try blocks or the execution of return - # statements where finally blocks apply. - - if self.in_try_finally: - self.writeline("%sif (__tmp_exc.completing) __Throw(__tmp_exc);" % else_str) - else_str = "else " + self.writeline("else if (__tmp_exc.raising_else) __Raise(__tmp_exc.arg);") # Exception handling. @@ -1183,10 +1183,9 @@ if name is not None: name_ref = self.process_structure_node(name) - self.writeline("%sif (__BOOL(__fn_native__isinstance((__attr[]) {__tmp_exc.arg, %s})))" % (else_str, name_ref)) + self.writeline("else if (__BOOL(__fn_native__isinstance((__attr[]) {__tmp_exc.arg, %s})))" % name_ref) else: - self.writeline("%sif (1)" % else_str) - else_str = "else " + self.writeline("else if (1)") self.writeline("{") self.indent += 1 @@ -1204,7 +1203,7 @@ # Re-raise unhandled exceptions. - self.writeline("%s__Throw(__tmp_exc);" % else_str) + self.writeline("else __Throw(__tmp_exc);") # End the handler block. @@ -1238,15 +1237,29 @@ self.indent += 1 self.process_structure_node(n.final) - # Test for the completion of a try block. + # Introduce an if statement to handle the completion of a try block. + + self.process_try_completion() + self.writeline("else __Throw(__tmp_exc);") + + self.indent -= 1 + self.writeline("}") + + def process_try_completion(self): + + "Generate a test for the completion of a try block." self.writestmt("if (__tmp_exc.completing)") self.writeline("{") self.indent += 1 - self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") - self.indent -= 1 - self.writeline("}") - self.writeline("else __Throw(__tmp_exc);") + + # Only use the normal return statement if no surrounding try blocks + # apply. + + if not self.in_try_finally and not self.in_try_except: + self.writeline("if (!__ISNULL(__tmp_exc.arg)) return __tmp_exc.arg;") + else: + self.writeline("if (!__ISNULL(__tmp_exc.arg)) __Throw(__tmp_exc);") self.indent -= 1 self.writeline("}")