From: Stefan Behnel Date: Tue, 30 Nov 2010 22:52:57 +0000 (+0100) Subject: fix ticket #606: move scoped local variables back into ScopedExprNode/GeneratorExpres... X-Git-Tag: 0.14.alpha0~38 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=94fd3ab9c284ce2228a4d5aca794742988ef7367;p=cython.git fix ticket #606: move scoped local variables back into ScopedExprNode/GeneratorExpressionScope to make sure they are cleaned up timely --- diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index 80ba4c7e..5c00a1dd 100755 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -4161,6 +4161,54 @@ class ScopedExprNode(ExprNode): # this is called with the expr_scope as env pass + def generate_evaluation_code(self, code): + # set up local variables and free their references on exit + generate_inner_evaluation_code = super(ScopedExprNode, self).generate_evaluation_code + if not self.has_local_scope or not self.expr_scope.var_entries: + # no local variables => delegate, done + generate_inner_evaluation_code(code) + return + + code.putln('{ /* enter inner scope */') + py_entries = [] + for entry in self.expr_scope.var_entries: + if not entry.in_closure: + code.put_var_declaration(entry) + if entry.type.is_pyobject and entry.used: + py_entries.append(entry) + code.put_init_var_to_py_none(entry) + if not py_entries: + # no local Python references => no cleanup required + generate_inner_evaluation_code(code) + code.putln('} /* exit inner scope */') + return + + # must free all local Python references at each exit point + old_loop_labels = tuple(code.new_loop_labels()) + old_error_label = code.new_error_label() + + generate_inner_evaluation_code(code) + + # normal (non-error) exit + for entry in py_entries: + code.put_var_decref(entry) + + # error/loop body exit points + exit_scope = code.new_label('exit_scope') + code.put_goto(exit_scope) + for label, old_label in ([(code.error_label, old_error_label)] + + list(zip(code.get_loop_labels(), old_loop_labels))): + if code.label_used(label): + code.put_label(label) + for entry in py_entries: + code.put_var_decref(entry) + code.put_goto(old_label) + code.put_label(exit_scope) + code.putln('} /* exit inner scope */') + + code.set_loop_labels(old_loop_labels) + code.error_label = old_error_label + class ComprehensionNode(ScopedExprNode): subexprs = ["target"] diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 1dec2321..5ee19ae7 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -1313,7 +1313,9 @@ class GeneratorExpressionScope(Scope): # the parent scope needs to generate code for the variable, but # this scope must hold its name exclusively cname = '%s%s' % (self.genexp_prefix, self.parent_scope.mangle(Naming.var_prefix, name)) - entry = self.parent_scope.declare_var(None, type, pos, cname, visibility, is_cdef = True) + entry = self.declare(name, cname, type, pos, visibility) + entry.is_variable = 1 + self.var_entries.append(entry) self.entries[name] = entry return entry