cython-devel

changeset 3338:879bb33c11c9

fix ticket #533: 'continue' in the 'else' block of a for-in-loop leaks a reference
author Stefan Behnel <scoder@users.berlios.de>
date Sun May 09 13:14:09 2010 +0200 (3 years ago)
parents e14fe9894ca9
children 57f8fb925531
files Cython/Compiler/Nodes.py tests/run/for_in_break_continue_T533.pyx
line diff
1.1 --- a/Cython/Compiler/Nodes.py Sat May 08 19:24:53 2010 -0300 1.2 +++ b/Cython/Compiler/Nodes.py Sun May 09 13:14:09 2010 +0200 1.3 @@ -4095,11 +4095,28 @@ 1.4 "}") 1.5 break_label = code.break_label 1.6 code.set_loop_labels(old_loop_labels) 1.7 - if self.else_clause: 1.8 + 1.9 + if self.else_clause: 1.10 + # in nested loops, the 'else' block can contain a 1.11 + # 'continue' statement for the outer loop, but we may need 1.12 + # to generate cleanup code before taking that path, so we 1.13 + # intercept it here 1.14 + orig_continue_label = code.continue_label 1.15 + code.continue_label = code.new_label('outer_continue') 1.16 + 1.17 code.putln("/*else*/ {") 1.18 self.else_clause.generate_execution_code(code) 1.19 code.putln("}") 1.20 - code.put_label(break_label) 1.21 + 1.22 + if code.label_used(code.continue_label): 1.23 + code.put_goto(break_label) 1.24 + code.put_label(code.continue_label) 1.25 + self.iterator.generate_disposal_code(code) 1.26 + code.put_goto(orig_continue_label) 1.27 + code.set_loop_labels(old_loop_labels) 1.28 + 1.29 + if code.label_used(break_label): 1.30 + code.put_label(break_label) 1.31 self.iterator.release_counter_temp(code) 1.32 self.iterator.generate_disposal_code(code) 1.33 self.iterator.free_temps(code)
2.1 --- a/tests/run/for_in_break_continue_T533.pyx Sat May 08 19:24:53 2010 -0300 2.2 +++ b/tests/run/for_in_break_continue_T533.pyx Sun May 09 13:14:09 2010 +0200 2.3 @@ -2,6 +2,9 @@ 2.4 def for_in(): 2.5 """ 2.6 >>> for_in() 2.7 + CONTINUE -1 2.8 + CONTINUE 4 2.9 + BREAK 6 2.10 6 2.11 """ 2.12 i = -1 2.13 @@ -10,6 +13,28 @@ 2.14 if i > 5: 2.15 break 2.16 else: 2.17 + print "CONTINUE", i 2.18 continue 2.19 + print "BREAK", i 2.20 break 2.21 return i 2.22 + 2.23 +def for_from(): 2.24 + """ 2.25 + >>> for_from() 2.26 + CONTINUE 0 2.27 + CONTINUE 5 2.28 + BREAK 6 2.29 + 6 2.30 + """ 2.31 + i = -1 2.32 + for L in [[], range(5), range(10)]: 2.33 + for i from 0 <= i < len(L): 2.34 + if i > 5: 2.35 + break 2.36 + else: 2.37 + print "CONTINUE", i 2.38 + continue 2.39 + print "BREAK", i 2.40 + break 2.41 + return i