fix ticket #533: 'continue' in the 'else' block of a for-in-loop leaks a reference
authorStefan Behnel <scoder@users.berlios.de>
Sun, 9 May 2010 11:14:09 +0000 (13:14 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Sun, 9 May 2010 11:14:09 +0000 (13:14 +0200)
Cython/Compiler/Nodes.py
tests/run/for_in_break_continue_T533.pyx

index d4d3a556a00cbc3b09c67fdb009b5819db124bb3..f1ee64a5da8ab2e345b9b4982dc661c954d5bf1e 100644 (file)
@@ -4095,11 +4095,28 @@ class ForInStatNode(LoopNode, StatNode):
             "}")
         break_label = code.break_label
         code.set_loop_labels(old_loop_labels)
+
         if self.else_clause:
+            # in nested loops, the 'else' block can contain a
+            # 'continue' statement for the outer loop, but we may need
+            # to generate cleanup code before taking that path, so we
+            # intercept it here
+            orig_continue_label = code.continue_label
+            code.continue_label = code.new_label('outer_continue')
+
             code.putln("/*else*/ {")
             self.else_clause.generate_execution_code(code)
             code.putln("}")
-        code.put_label(break_label)
+
+            if code.label_used(code.continue_label):
+                code.put_goto(break_label)
+                code.put_label(code.continue_label)
+                self.iterator.generate_disposal_code(code)
+                code.put_goto(orig_continue_label)
+            code.set_loop_labels(old_loop_labels)
+
+        if code.label_used(break_label):
+            code.put_label(break_label)
         self.iterator.release_counter_temp(code)
         self.iterator.generate_disposal_code(code)
         self.iterator.free_temps(code)
index 0608258ac68febf3547c9ef82cb4689bf414c844..23c27246bc56358af626de55d84d1f67e89ba53c 100644 (file)
@@ -2,6 +2,9 @@
 def for_in():
     """
     >>> for_in()
+    CONTINUE -1
+    CONTINUE 4
+    BREAK 6
     6
     """
     i = -1
@@ -10,6 +13,28 @@ def for_in():
             if i > 5:
                 break
         else:
+            print "CONTINUE", i
             continue
+        print "BREAK", i
+        break
+    return i
+
+def for_from():
+    """
+    >>> for_from()
+    CONTINUE 0
+    CONTINUE 5
+    BREAK 6
+    6
+    """
+    i = -1
+    for L in [[], range(5), range(10)]:
+        for i from 0 <= i < len(L):
+            if i > 5:
+                break
+        else:
+            print "CONTINUE", i
+            continue
+        print "BREAK", i
         break
     return i