summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2015-12-24 12:47:39 +0000
committerDamien George <damien.p.george@gmail.com>2015-12-24 12:47:39 +0000
commit8047340d7532ec32bc9f2d603bffc0bc9544297f (patch)
tree2a1eced095349199a049e82f0c9a080de13fb9b3
parent117158fcd560a84318a0b9cb5332c5599acdb84b (diff)
downloadmicropython-8047340d7532ec32bc9f2d603bffc0bc9544297f.tar.gz
micropython-8047340d7532ec32bc9f2d603bffc0bc9544297f.zip
py: Handle case of return within the finally block of try-finally.
Addresses issue #1636.
-rw-r--r--py/vm.c8
-rw-r--r--tests/basics/try_finally_return2.py104
2 files changed, 112 insertions, 0 deletions
diff --git a/py/vm.c b/py/vm.c
index 8bf59f1e05..8c7c2265e4 100644
--- a/py/vm.c
+++ b/py/vm.c
@@ -1032,6 +1032,14 @@ unwind_jump:;
ENTRY(MP_BC_RETURN_VALUE):
MARK_EXC_IP_SELECTIVE();
+ // These next 3 lines pop a try-finally exception handler, if one
+ // is there on the exception stack. Without this the finally block
+ // is executed a second time when the return is executed, because
+ // the try-finally exception handler is still on the stack.
+ // TODO Possibly find a better way to handle this case.
+ if (currently_in_except_block) {
+ POP_EXC_BLOCK();
+ }
unwind_return:
while (exc_sp >= exc_stack) {
if (MP_TAGPTR_TAG1(exc_sp->val_sp)) {
diff --git a/tests/basics/try_finally_return2.py b/tests/basics/try_finally_return2.py
new file mode 100644
index 0000000000..e3ea5f1eb8
--- /dev/null
+++ b/tests/basics/try_finally_return2.py
@@ -0,0 +1,104 @@
+# test 'return' within the finally block
+# it should swallow the exception
+
+# simple case
+def f():
+ try:
+ raise ValueError()
+ finally:
+ print('finally')
+ return 0
+ print('got here')
+print(f())
+
+# nested, return in outer
+def f():
+ try:
+ try:
+ raise ValueError
+ finally:
+ print('finally 1')
+ print('got here')
+ finally:
+ print('finally 2')
+ return 2
+ print('got here')
+print(f())
+
+# nested, return in inner
+def f():
+ try:
+ try:
+ raise ValueError
+ finally:
+ print('finally 1')
+ return 1
+ print('got here')
+ finally:
+ print('finally 2')
+ print('got here')
+print(f())
+
+# nested, return in inner and outer
+def f():
+ try:
+ try:
+ raise ValueError
+ finally:
+ print('finally 1')
+ return 1
+ print('got here')
+ finally:
+ print('finally 2')
+ return 2
+ print('got here')
+print(f())
+
+# nested with reraise
+def f():
+ try:
+ try:
+ raise ValueError
+ except:
+ raise
+ print('got here')
+ finally:
+ print('finally')
+ return 0
+ print('got here')
+print(f())
+
+# triple nesting with reraise
+def f():
+ try:
+ try:
+ try:
+ raise ValueError
+ except:
+ raise
+ except:
+ raise
+ finally:
+ print('finally')
+ return 0
+print(f())
+
+# exception when matching exception
+def f():
+ try:
+ raise ValueError
+ except NonExistingError:
+ pass
+ finally:
+ print('finally')
+ return 0
+print(f())
+
+# raising exception class, not instance
+def f():
+ try:
+ raise ValueError
+ finally:
+ print('finally')
+ return 0
+print(f())