diff --git a/Cython/Compiler/FlowControl.py b/Cython/Compiler/FlowControl.py
new file mode 100644
index 0000000000000000000000000000000000000000..9358cde579c6fe23837094fd96b724cfe17ba9d0
--- /dev/null
+++ b/Cython/Compiler/FlowControl.py
@@ -0,0 +1,928 @@
+import cython
+cython.declare(PyrexTypes=object, Naming=object, ExprNodes=object, Nodes=object,
+               Options=object, UtilNodes=object, ModuleNode=object,
+               LetNode=object, LetRefNode=object, TreeFragment=object,
+               TemplateTransform=object, EncodedString=object,
+               error=object, warning=object, copy=object)
+
+import Builtin
+import ExprNodes
+import Nodes
+from PyrexTypes import py_object_type, unspecified_type
+
+from Visitor import TreeVisitor, CythonTransform
+from Errors import error, warning, CompileError, InternalError
+
+from cython import set
+
+class TypedExprNode(ExprNodes.ExprNode):
+    # Used for declaring assignments of a specified type whithout a known entry.
+    def __init__(self, type):
+        self.type = type
+
+object_expr = TypedExprNode(py_object_type)
+
+class ControlBlock(object):
+    """Control flow graph node. Sequence of assignments and name references.
+
+       children  set of children nodes
+       parents   set of parent nodes
+       positions set of position markers
+
+       stats     list of block statements
+       gen       dict of assignments generated by this block
+       bounded   set  of entries that are definitely bounded in this block
+
+       Example:
+
+        a = 1
+        b = a + c # 'c' is already bounded or exception here
+
+        stats = [Assignment(a), NameReference(a), NameReference(c),
+                     Assignment(b)]
+        gen = {Entry(a): Assignment(a), Entry(b): Assignment(b)}
+        bounded = set([Entry(a), Entry(c)])
+
+    """
+
+    def __init__(self):
+        self.children = set()
+        self.parents = set()
+        self.positions = set()
+
+        self.stats = []
+        self.gen = {}
+        self.bounded = set()
+
+    def empty(self):
+        return (not self.stats and not self.positions)
+
+    def detach(self):
+        """Detach block from parents and children."""
+        for child in self.children:
+            child.parents.remove(self)
+        for parent in self.parents:
+            parent.children.remove(self)
+        self.parents.clear()
+        self.children.clear()
+
+    def add_child(self, block):
+        self.children.add(block)
+        block.parents.add(self)
+
+
+class ExitBlock(ControlBlock):
+    """Non-empty exit point block."""
+
+    def empty(self):
+        return False
+
+
+class ControlFlow(object):
+    """Control-flow graph.
+
+       entry_point ControlBlock entry point for this graph
+       exit_point  ControlBlock normal exit point
+       block       ControlBlock current block
+       blocks      set    children nodes
+       entries     set    tracked entries
+       loops       list   stack for loop descriptors
+       exceptions  list   stack for exception descriptors
+
+    """
+
+    def __init__(self):
+        self.blocks = set()
+        self.entries = set()
+        self.loops = []
+        self.exceptions = []
+
+        self.entry_point = ControlBlock()
+        self.exit_point = ExitBlock()
+        self.blocks.add(self.exit_point)
+        self.block = self.entry_point
+
+    def newblock(self, parent=None):
+        """Create floating block linked to `parent` if given.
+
+           NOTE: Block is NOT added to self.blocks
+        """
+        block = ControlBlock()
+        self.blocks.add(block)
+        if parent:
+            parent.add_child(block)
+        return block
+
+    def nextblock(self, parent=None):
+        """Create block children block linked to current or `parent` if given.
+
+           NOTE: Block is added to self.blocks
+        """
+        block = ControlBlock()
+        self.blocks.add(block)
+        if parent:
+            parent.add_child(block)
+        elif self.block:
+            self.block.add_child(block)
+        self.block = block
+        return self.block
+
+    def is_tracked(self, entry):
+        if entry.is_anonymous:
+            return False
+        return entry.is_local or entry.is_pyclass_attr or entry.is_arg
+
+    def mark_position(self, node):
+        """Mark position, will be used to draw graph nodes."""
+        if self.block:
+            self.block.positions.add(node.pos[:2])
+
+    def mark_assignment(self, lhs, rhs, entry=None):
+        if self.block:
+            if entry is None:
+                entry = lhs.entry
+            if not self.is_tracked(entry):
+                return
+            assignment = NameAssignment(lhs, rhs, entry)
+            self.block.stats.append(assignment)
+            self.block.gen[entry] = assignment
+            self.entries.add(entry)
+
+    def mark_argument(self, lhs, rhs, entry):
+        if self.block and self.is_tracked(entry):
+            assignment = Argument(lhs, rhs, entry)
+            self.block.stats.append(assignment)
+            self.block.gen[entry] = assignment
+            self.entries.add(entry)
+
+    def mark_deletion(self, node, entry):
+        if self.block and self.is_tracked(entry):
+            assignment = NameAssignment(node, None, entry)
+            self.block.stats.append(assignment)
+            self.block.gen[entry] = Uninitialized
+            self.entries.add(entry)
+
+    def mark_reference(self, node, entry):
+        if self.block and self.is_tracked(entry):
+            self.block.stats.append(NameReference(node, entry))
+            # Local variable is definitely bound after this reference
+            self.block.bounded.add(entry)
+            self.entries.add(entry)
+
+    def normalize(self):
+        """Delete unreachable and orphan blocks."""
+        queue = set([self.entry_point])
+        visited = set()
+        while queue:
+            root = queue.pop()
+            visited.add(root)
+            for child in root.children:
+                if child not in visited:
+                    queue.add(child)
+        unreachable = self.blocks - visited
+        for block in unreachable:
+            block.detach()
+        visited.remove(self.entry_point)
+        for block in visited:
+            if block.empty():
+                for parent in block.parents: # Re-parent
+                    for child in block.children:
+                        parent.add_child(child)
+                block.detach()
+                unreachable.add(block)
+        self.blocks -= unreachable
+
+
+class LoopDescr(object):
+    def __init__(self, next_block, loop_block):
+        self.next_block = next_block
+        self.loop_block = loop_block
+
+class ExceptionDescr(object):
+    """Exception handling helper.
+
+    entry_point   ControlBlock Exception handling entry point
+    finally_enter ControlBlock Normal finally clause entry point
+    finally_exit  ControlBlock Normal finally clause exit point
+    """
+
+    def __init__(self, entry_point, finally_enter=None, finally_exit=None):
+        self.entry_point = entry_point
+        self.finally_enter = finally_enter
+        self.finally_exit = finally_exit
+
+class NameAssignment(object):
+    is_arg = False
+
+    def __init__(self, lhs, rhs, entry):
+        self.lhs = lhs
+        self.rhs = rhs
+        self.entry = entry
+        self.pos = lhs.pos
+        self.refs = set()
+
+    def __repr__(self):
+        return '%s(entry=%r)' % (self.__class__.__name__, self.entry)
+
+class Argument(NameAssignment):
+    is_arg = True
+
+class Uninitialized(object):
+    pass
+
+class NameReference(object):
+    def __init__(self, node, entry):
+        self.node = node
+        self.entry = entry
+        self.pos = node.pos
+
+    def __repr__(self):
+        return '%s(entry=%r)' % (self.__class__.__name__, self.entry)
+
+
+class GVContext(object):
+    """Graphviz subgraph object."""
+
+    def __init__(self):
+        self.blockids = {}
+        self.nextid = 0
+        self.children = []
+        self.sources = {}
+
+    def add(self, child):
+        self.children.append(child)
+
+    def nodeid(self, block):
+        if block not in self.blockids:
+            self.blockids[block] = 'block%d' % self.nextid
+            self.nextid += 1
+        return self.blockids[block]
+
+    def extract_sources(self, block):
+        if not block.positions:
+            return ''
+        start = min(block.positions)
+        stop = max(block.positions)
+        srcdescr = start[0]
+        if not srcdescr in self.sources:
+            self.sources[srcdescr] = list(srcdescr.get_lines())
+        lines = self.sources[srcdescr]
+        return '\\n'.join([l.strip() for l in lines[start[1] - 1:stop[1]]])
+
+    def render(self, fp, name, annotate_defs=False):
+        """Render graphviz dot graph"""
+        fp.write('digraph %s {\n' % name)
+        fp.write(' node [shape=box];\n')
+        for child in self.children:
+            child.render(fp, self, annotate_defs)
+        fp.write('}\n')
+
+    def escape(self, text):
+        return text.replace('"', '\\"').replace('\n', '\\n')
+
+class GV(object):
+    """Graphviz DOT renderer."""
+
+    def __init__(self, name, flow):
+        self.name = name
+        self.flow = flow
+
+    def render(self, fp, ctx, annotate_defs=False):
+        fp.write(' subgraph %s {\n' % self.name)
+        for block in self.flow.blocks:
+            label = ctx.extract_sources(block)
+            if annotate_defs:
+                for stat in block.stats:
+                    if isinstance(stat, NameAssignment):
+                        label += '\n %s [definition]' % stat.entry.name
+                    elif isinstance(stat, NameReference):
+                        if stat.entry:
+                            label += '\n %s [reference]' % stat.entry.name
+            if not label:
+                label = 'empty'
+            pid = ctx.nodeid(block)
+            fp.write('  %s [label="%s"];\n' % (pid, ctx.escape(label)))
+        for block in self.flow.blocks:
+            pid = ctx.nodeid(block)
+            for child in block.children:
+                fp.write('  %s -> %s;\n' % (pid, ctx.nodeid(child)))
+        fp.write(' }\n')
+
+class MessageCollection(list):
+    """Collect error/warnings messages first then sort"""
+
+    def error(self, pos, message):
+        self.append((pos, True, message))
+
+    def warning(self, pos, message):
+        self.append((pos, False, message))
+
+    def _key(self, item):
+        return item[0]
+
+    def sort(self):
+        list.sort(self, key=self._key)
+
+
+def check_definitions(flow, compiler_directives):
+    """Based on algo 9.11 from Dragon Book."""
+    # Initialize
+    for block in flow.blocks:
+        block.input = {}
+        block.output = {}
+        for entry, item in block.gen.items():
+            block.output[entry] = set([item])
+
+    entry_point = flow.entry_point
+    entry_point.input = {}
+    entry_point.output = {}
+    for entry in flow.entries:
+        entry_point.gen[entry] = Uninitialized
+        entry_point.output[entry] = set([Uninitialized])
+
+    # Per-block reaching definitons
+    dirty = True
+    while dirty:
+        dirty = False
+        for block in flow.blocks:
+            input = {}
+            for parent in block.parents:
+                for entry, items in parent.output.iteritems():
+                    if entry in input:
+                        input[entry].update(items)
+                    else:
+                        input[entry] = set(items)
+            output = {}
+            for entry, items in input.iteritems():
+                if entry in block.gen:
+                    continue
+                output[entry] = set(items)
+                if entry in block.bounded:
+                    output[entry].discard(Uninitialized)
+            for entry, item in block.gen.iteritems():
+                output[entry] = set([item])
+            if not dirty:
+                if output != block.output:
+                    dirty = True
+            block.input = input
+            block.output = output
+
+    # Track down state
+    messages = MessageCollection()
+    assignments = set()
+    for block in flow.blocks:
+        state = {}
+        for entry, items in block.input.iteritems():
+            state[entry] = items.copy()
+        for stat in block.stats:
+            if isinstance(stat, NameAssignment):
+                if stat.rhs:
+                    state[stat.entry] = set([stat])
+                else:
+                    state[stat.entry] = set([Uninitialized])
+                assignments.add(stat)
+                stat.entry._assignments.append(stat)
+            elif isinstance(stat, NameReference):
+                stat.entry.references.append(stat)
+                if Uninitialized in state[stat.entry]:
+                    if stat.entry.from_closure:
+                        pass # Can be uninitialized here
+                    elif len(state[stat.entry]) == 1:
+                        messages.error(stat.pos, "local variable '%s' referenced before assignment" % stat.entry.name)
+                    else:
+                        if compiler_directives['warn.maybe_uninitialized']:
+                            messages.warning(stat.pos, "local variable '%s' might be referenced before assignment" % stat.entry.name)
+                    state[stat.entry] -= set([Uninitialized])
+                for assmt in state[stat.entry]:
+                    assmt.refs.add(stat)
+
+    # Check variable usage
+    warn_unused_result = compiler_directives['warn.unused_result']
+    warn_unused = compiler_directives['warn.unused']
+    warn_unused_arg = compiler_directives['warn.unused_arg']
+
+    for assmt in assignments:
+        if not assmt.refs and not assmt.entry.is_pyclass_attr \
+               and not assmt.entry.in_closure:
+            if assmt.entry.references and warn_unused_result:
+                if assmt.is_arg:
+                    messages.warning(assmt.pos, "Unused argument value '%s'" % assmt.entry.name)
+                else:
+                    messages.warning(assmt.pos, "Unused result in '%s'" % assmt.entry.name)
+            assmt.lhs.used = False
+
+    for entry in flow.entries:
+        if not entry.references and not entry.is_pyclass_attr and not entry.in_closure:
+            # TODO: handle unused buffers
+            if entry.type.is_buffer:
+                entry.used = True
+                continue
+            # TODO: starred args entries are not marked with is_arg flag
+            for assmt in entry._assignments:
+                if assmt.is_arg:
+                    is_arg = True
+                    break
+            else:
+                is_arg = False
+            if is_arg:
+                if warn_unused_arg:
+                    messages.warning(entry.pos, "Unused argument '%s'" % entry.name)
+                # TODO: handle unused arguments
+                entry.used = True
+            else:
+                if warn_unused:
+                    messages.warning(entry.pos, "Unused entry '%s'" % entry.name)
+                entry.used = False
+
+    # Sort warnings by position
+    messages.sort()
+    for pos, is_error, message in messages:
+        if is_error:
+            error(pos, message)
+        else:
+            warning(pos, message, 2)
+
+
+class AssignmentCollector(TreeVisitor):
+    def __init__(self):
+        super(AssignmentCollector, self).__init__()
+        self.assignments = []
+
+    def visit_Node(self):
+        self.visitchildren(self)
+
+    def visit_SingleAssignmentNode(self, node):
+        self.assignments.append((node.lhs, node.rhs))
+
+    def visit_CascadedAssignmentNode(self, node):
+        for lhs in node.lhs_list:
+            self.assignments.append((lhs, node.rhs))
+
+
+class CreateControlFlowGraph(CythonTransform):
+    """Create NameNode use and assignment graph."""
+
+    def visit_ModuleNode(self, node):
+        self.gv_ctx = GVContext()
+
+        self.env_stack = []
+        self.env = node.scope
+        self.stack = []
+        self.flow = ControlFlow()
+        self.visitchildren(node)
+
+        dot_output = self.current_directives['control_flow.dot_output']
+        if dot_output:
+            annotate_defs = self.current_directives['control_flow.dot_annotate_defs']
+            fp = open(dot_output, 'wt')
+            try:
+                self.gv_ctx.render(fp, 'module', annotate_defs=annotate_defs)
+            finally:
+                fp.close()
+        return node
+
+    def visit_FuncDefNode(self, node):
+        self.env_stack.append(self.env)
+        self.env = node.local_scope
+        self.stack.append(self.flow)
+        self.flow = ControlFlow()
+
+        self.mark_position(node)
+        # Function body block
+        self.flow.nextblock()
+
+        if node.star_arg:
+            self.flow.mark_argument(node.star_arg,
+                                    TypedExprNode(Builtin.tuple_type),
+                                    node.star_arg.entry)
+        if node.starstar_arg:
+            self.flow.mark_argument(node.starstar_arg,
+                                    TypedExprNode(Builtin.dict_type),
+                                    node.starstar_arg.entry)
+        self.visitchildren(node)
+
+        # Exit point
+        if self.flow.block:
+            self.flow.block.add_child(self.flow.exit_point)
+
+        # Cleanup graph
+        self.flow.normalize()
+        check_definitions(self.flow, self.current_directives)
+        self.flow.blocks.add(self.flow.entry_point)
+
+        self.gv_ctx.add(GV(node.local_scope.name, self.flow))
+
+        self.flow = self.stack.pop()
+        self.env = self.env_stack.pop()
+        return node
+
+    def visit_DefNode(self, node):
+        ## XXX: no target name node here
+        node.used = True
+        self.flow.mark_assignment(node, object_expr, self.env.lookup(node.name))
+        return self.visit_FuncDefNode(node)
+
+    def visit_CTypeDefNode(self, node):
+        return node
+
+    def mark_assignment(self, lhs, rhs=None):
+        if not self.flow.block:
+            return
+        if self.flow.exceptions:
+            exc_descr = self.flow.exceptions[-1]
+            self.flow.block.add_child(exc_descr.entry_point)
+            self.flow.nextblock()
+
+        if isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode)):
+            self.visit(lhs)
+            return
+
+        if not rhs:
+            rhs = object_expr
+        if lhs.is_name:
+            if lhs.entry is None:
+                # TODO: This shouldn't happen...
+                return
+            self.flow.mark_assignment(lhs, rhs)
+        elif isinstance(lhs, ExprNodes.SequenceNode):
+            for arg in lhs.args:
+                self.mark_assignment(arg)
+        else:
+            # Could use this info to infer cdef class attributes...
+            pass
+
+        if self.flow.exceptions:
+            exc_descr = self.flow.exceptions[-1]
+            self.flow.block.add_child(exc_descr.entry_point)
+            self.flow.nextblock()
+
+    def mark_position(self, node):
+        """Mark position if DOT output is enabled."""
+        if self.current_directives['control_flow.dot_output']:
+            self.flow.mark_position(node)
+
+    def visit_FromImportStatNode(self, node):
+        for name, target in node.items:
+            if name != "*":
+                self.mark_assignment(target)
+        self.visitchildren(node)
+        return node
+
+    def visit_SingleAssignmentNode(self, node):
+        self.visit(node.rhs)
+        self.mark_assignment(node.lhs)
+        return node
+
+    def visit_CascadedAssignmentNode(self, node):
+        self.visit(node.rhs)
+        for lhs in node.lhs_list:
+            self.mark_assignment(lhs, node.rhs)
+        return node
+
+    def visit_ParallelAssignmentNode(self, node):
+        collector = AssignmentCollector()
+        collector.visitchildren(node)
+        for lhs, rhs in collector.assignments:
+            self.visit(rhs)
+        for lhs, rhs in collector.assignments:
+            self.mark_assignment(lhs, rhs)
+        return node
+
+    def visit_InPlaceAssignmentNode(self, node):
+        self.visitchildren(node)
+        self.mark_assignment(node.lhs, node.create_binop_node())
+        return node
+
+    def _delete_name_node(self, node):
+        entry = node.entry or self.env.lookup(node.name)
+        if entry.in_closure or entry.from_closure:
+            error(node.pos, "can not delete variable '%s' referenced in nested scope" % entry.name)
+        # Mark reference
+        self.visit(node)
+        self.flow.mark_deletion(node, entry)
+
+    def visit_DelStatNode(self, node):
+        for arg in node.args:
+            if arg.is_name:
+                self._delete_name_node(arg)
+            elif arg.is_sequence_constructor:
+                self.visit_DelStatNode(arg)
+            else:
+                self.visit(arg)
+        return node
+
+    def visit_CArgDeclNode(self, node):
+        entry = self.env.lookup(node.name)
+        self.flow.mark_argument(node, TypedExprNode(entry.type), entry)
+        return node
+
+    def visit_NameNode(self, node):
+        if self.flow.block:
+            entry = node.entry or self.env.lookup(node.name)
+            if entry:
+                self.flow.mark_reference(node, entry)
+        return node
+
+    def visit_StatListNode(self, node):
+        for stat in node.stats:
+            if not self.flow.block:
+                break
+            self.visit(stat)
+        return node
+
+    def visit_Node(self, node):
+        self.visitchildren(node)
+        self.mark_position(node)
+        return node
+
+    def visit_IfStatNode(self, node):
+        next_block = self.flow.newblock()
+        parent = self.flow.block
+        # If clauses
+        for clause in node.if_clauses:
+            parent = self.flow.nextblock(parent)
+            self.visit(clause.condition)
+            self.flow.nextblock()
+            self.visit(clause.body)
+            if self.flow.block:
+                self.flow.block.add_child(next_block)
+        # Else clause
+        if node.else_clause:
+            self.flow.nextblock(parent=parent)
+            self.visit(node.else_clause)
+            if self.flow.block:
+                self.flow.block.add_child(next_block)
+        else:
+            parent.add_child(next_block)
+
+        if next_block.parents:
+            self.flow.block = next_block
+        else:
+            self.flow.block = None
+        return node
+
+    def visit_WhileStatNode(self, node):
+        condition_block = self.flow.nextblock()
+        next_block = self.flow.newblock()
+        # Condition block
+        self.flow.loops.append(LoopDescr(next_block, condition_block))
+        self.visit(node.condition)
+        # Body block
+        self.flow.nextblock()
+        self.visit(node.body)
+        # Loop it
+        if self.flow.block:
+            self.flow.block.add_child(condition_block)
+            self.flow.block.add_child(next_block)
+        # Else clause
+        if node.else_clause:
+            self.flow.nextblock(parent=condition_block)
+            self.visit(node.else_clause)
+            if self.flow.block:
+                self.flow.block.add_child(next_block)
+        else:
+            condition_block.add_child(next_block)
+        self.flow.loops.pop()
+        self.flow.block = next_block
+        return node
+
+    def visit_ForInStatNode(self, node):
+        condition_block = self.flow.nextblock()
+        next_block = self.flow.newblock()
+        # Condition with iterator
+        self.flow.loops.append(LoopDescr(next_block, condition_block))
+        self.visit(node.iterator)
+        # Target assignment
+        self.flow.nextblock()
+        self.mark_assignment(node.target)
+        # Body block
+        self.flow.nextblock()
+        self.visit(node.body)
+        # Loop it
+        if self.flow.block:
+            self.flow.block.add_child(condition_block)
+        # Else clause
+        if node.else_clause:
+            self.flow.nextblock(parent=condition_block)
+            self.visit(node.else_clause)
+            if self.flow.block:
+                self.flow.block.add_child(next_block)
+        else:
+            condition_block.add_child(next_block)
+        self.flow.loops.pop()
+        self.flow.block = next_block
+        return node
+
+    def visit_ForFromStatNode(self, node):
+        condition_block = self.flow.nextblock()
+        next_block = self.flow.newblock()
+        # Condition with iterator
+        self.flow.loops.append(LoopDescr(next_block, condition_block))
+        self.visit(node.bound1)
+        self.visit(node.bound2)
+        if node.step:
+            self.visit(node.step)
+        # Target assignment
+        self.flow.nextblock()
+        self.mark_assignment(node.target)
+
+        # TODO: force target use, should ForFromStatNode should allocate temp var instead
+        self.visit(node.target)
+        # Body block
+        self.flow.nextblock()
+        self.visit(node.body)
+        # Loop it
+        if self.flow.block:
+            self.flow.block.add_child(condition_block)
+        # Else clause
+        if node.else_clause:
+            self.flow.nextblock(parent=condition_block)
+            self.visit(node.else_clause)
+            if self.flow.block:
+                self.flow.block.add_child(next_block)
+        else:
+            condition_block.add_child(next_block)
+        self.flow.loops.pop()
+        self.flow.block = next_block
+        return node
+
+    def visit_LoopNode(self, node):
+        raise InternalError, "Generic loops are not supported"
+
+    def visit_WithStatNode(self, node):
+        # never be here: WithStatNode is replaced with try except finally
+        raise InternalError, "with statement is not supported"
+
+    def visit_TryExceptStatNode(self, node):
+        # After exception handling
+        next_block = self.flow.newblock()
+        # Body block
+        self.flow.newblock()
+        # Exception entry point
+        entry_point = self.flow.newblock()
+        self.flow.exceptions.append(ExceptionDescr(entry_point))
+        self.flow.nextblock()
+        ## XXX: links to exception handling point should be added by
+        ## XXX: children nodes
+        self.flow.block.add_child(entry_point)
+        self.visit(node.body)
+        self.flow.exceptions.pop()
+
+        # After exception
+        if self.flow.block:
+            if node.else_clause:
+                self.flow.nextblock()
+                self.visit(node.else_clause)
+            if self.flow.block:
+                self.flow.block.add_child(next_block)
+
+        for clause in node.except_clauses:
+            self.flow.block = entry_point
+            if clause.pattern:
+                for pattern in clause.pattern:
+                    self.visit(pattern)
+            else:
+                # TODO: handle * pattern
+                pass
+            if clause.target:
+                self.mark_assignment(clause.target)
+            entry_point = self.flow.newblock(parent=self.flow.block)
+            self.flow.nextblock()
+            self.visit(clause.body)
+            if self.flow.block:
+                self.flow.block.add_child(next_block)
+
+        if self.flow.exceptions:
+            entry_point.add_child(self.flow.exceptions[-1].entry_point)
+
+        if next_block.parents:
+            self.flow.block = next_block
+        else:
+            self.flow.block = None
+        return node
+
+    def visit_TryFinallyStatNode(self, node):
+        body_block = self.flow.nextblock()
+
+        # Exception entry point
+        entry_point = self.flow.newblock()
+        self.flow.block = entry_point
+        self.visit(node.finally_clause)
+
+        # Normal execution
+        finally_enter = self.flow.newblock()
+        self.flow.block = finally_enter
+        self.visit(node.finally_clause)
+        finally_exit = self.flow.block
+
+        self.flow.exceptions.append(ExceptionDescr(entry_point, finally_enter, finally_exit))
+        self.flow.block = body_block
+        ## XXX: Is it still required
+        body_block.add_child(entry_point)
+        self.visit(node.body)
+        self.flow.exceptions.pop()
+
+        if self.flow.block:
+            self.flow.block.add_child(finally_enter)
+            if finally_exit:
+                self.flow.block = self.flow.nextblock(parent=finally_exit)
+            else:
+                self.flow.block = None
+        return node
+
+    def visit_RaiseStatNode(self, node):
+        self.mark_position(node)
+        if self.flow.exceptions:
+            self.flow.block.add_child(self.flow.exceptions[-1].entry_point)
+        self.flow.block = None
+        return node
+
+    def visit_ReraiseStatNode(self, node):
+        self.mark_position(node)
+        if self.flow.exceptions:
+            self.flow.block.add_child(self.flow.exceptions[-1].entry_point)
+        self.flow.block = None
+        return node
+
+    def visit_ReturnStatNode(self, node):
+        self.mark_position(node)
+        self.visitchildren(node)
+
+        for exception in self.flow.exceptions[::-1]:
+            if exception.finally_enter:
+                self.flow.block.add_child(exception.finally_enter)
+                if exception.finally_exit:
+                    exception.finally_exit.add_child(self.flow.exit_point)
+                break
+        else:
+            if self.flow.block:
+                self.flow.block.add_child(self.flow.exit_point)
+        self.flow.block = None
+        return node
+
+    def visit_BreakStatNode(self, node):
+        if not self.flow.loops:
+            #error(node.pos, "break statement not inside loop")
+            return node
+        loop = self.flow.loops[-1]
+        self.mark_position(node)
+        for exception in self.flow.exceptions[::-1]:
+            if exception.finally_enter:
+                self.flow.block.add_child(exception.finally_enter)
+                if exception.finally_exit:
+                    exception.finally_exit.add_child(loop.next_block)
+                break
+        else:
+            self.flow.block.add_child(loop.next_block)
+        self.flow.block = None
+        return node
+
+    def visit_ContinueStatNode(self, node):
+        if not self.flow.loops:
+            #error(node.pos, "continue statement not inside loop")
+            return node
+        loop = self.flow.loops[-1]
+        self.mark_position(node)
+        for exception in self.flow.exceptions[::-1]:
+            if exception.finally_enter:
+                self.flow.block.add_child(exception.finally_enter)
+                if exception.finally_exit:
+                    exception.finally_exit.add_child(loop.loop_block)
+                break
+        else:
+            self.flow.block.add_child(loop.loop_block)
+        self.flow.block = None
+        return node
+
+    def visit_ComprehensionNode(self, node):
+        if node.expr_scope:
+            self.env_stack.append(self.env)
+            self.env = node.expr_scope
+        # Skip append node here
+        self.visit(node.target)
+        self.visit(node.loop)
+        if node.expr_scope:
+            self.env = self.env_stack.pop()
+        return node
+
+    def visit_ScopedExprNode(self, node):
+        if node.expr_scope:
+            self.env_stack.append(self.env)
+            self.env = node.expr_scope
+        self.visitchildren(node)
+        if node.expr_scope:
+            self.env = self.env_stack.pop()
+        return node
+
+    def visit_PyClassDefNode(self, node):
+        self.flow.mark_assignment(node.target,
+                                  object_expr, self.env.lookup(node.name))
+        # TODO: add negative attribute list to "visitchildren"?
+        self.visitchildren(node, attrs=['dict', 'metaclass', 'mkw', 'bases', 'classobj'])
+        self.env_stack.append(self.env)
+        self.env = node.scope
+        self.flow.nextblock()
+        self.visitchildren(node, attrs=['body'])
+        self.flow.nextblock()
+        self.env = self.env_stack.pop()
+        return node