summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2017-06-22 13:50:33 +1000
committerDamien George <damien.p.george@gmail.com>2017-06-22 13:50:33 +1000
commit4c5f108321a8fd3f67f597ca918427eda813c12e (patch)
tree4da9c137766f24d6a5b47fc9d5b8dac2ebc2b304
parent458cbacb8f62ad0f33024360af61fb797530c65b (diff)
downloadmicropython-4c5f108321a8fd3f67f597ca918427eda813c12e.tar.gz
micropython-4c5f108321a8fd3f67f597ca918427eda813c12e.zip
py/compile: Fix bug with break/continue in else of optimised for-range.
This patch fixes a bug whereby the Python stack was not correctly reset if there was a break/continue statement in the else black of an optimised for-range loop. For example, in the following code the "j" variable from the inner for loop was not being popped off the Python stack: for i in range(4): for j in range(4): pass else: continue This is now fixed with this patch.
-rw-r--r--py/compile.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/py/compile.c b/py/compile.c
index 86ec4d3a3c..1511786ae9 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -1406,7 +1406,20 @@ STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t p
// break/continue apply to outer loop (if any) in the else block
END_BREAK_CONTINUE_BLOCK
- compile_node(comp, pn_else);
+ // Compile the else block. We must pop the iterator variables before
+ // executing the else code because it may contain break/continue statements.
+ uint end_label = 0;
+ if (!MP_PARSE_NODE_IS_NULL(pn_else)) {
+ // discard final value of "var", and possible "end" value
+ EMIT(pop_top);
+ if (end_on_stack) {
+ EMIT(pop_top);
+ }
+ compile_node(comp, pn_else);
+ end_label = comp_next_label(comp);
+ EMIT_ARG(jump, end_label);
+ EMIT_ARG(adjust_stack_size, 1 + end_on_stack);
+ }
EMIT_ARG(label_assign, break_label);
@@ -1417,6 +1430,10 @@ STATIC void compile_for_stmt_optimised_range(compiler_t *comp, mp_parse_node_t p
if (end_on_stack) {
EMIT(pop_top);
}
+
+ if (!MP_PARSE_NODE_IS_NULL(pn_else)) {
+ EMIT_ARG(label_assign, end_label);
+ }
}
STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
@@ -1496,7 +1513,7 @@ STATIC void compile_for_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
// break/continue apply to outer loop (if any) in the else block
END_BREAK_CONTINUE_BLOCK
- compile_node(comp, pns->nodes[3]); // else (not tested)
+ compile_node(comp, pns->nodes[3]); // else (may be empty)
EMIT_ARG(label_assign, break_label);
}