fix ticket #644: infer type of C-API optimised methods of builtin types as Python...
[cython.git] / Cython / Compiler / ExprNodes.py
index 5f463f9bf11bbdb1d329d8b11fe246f05aa169a9..93eba7cc2eb07e4583e5926cfdeccfaba01e35c8 100755 (executable)
@@ -2,9 +2,19 @@
 #   Pyrex - Parse tree nodes for expressions
 #
 
+import cython
+from cython import set
+cython.declare(error=object, warning=object, warn_once=object, InternalError=object,
+               CompileError=object, UtilityCode=object, StringEncoding=object, operator=object,
+               Naming=object, Nodes=object, PyrexTypes=object, py_object_type=object,
+               list_type=object, tuple_type=object, set_type=object, dict_type=object, \
+               unicode_type=object, str_type=object, bytes_type=object, type_type=object,
+               Builtin=object, Symtab=object, Utils=object, find_coercion_error=object,
+               debug_disposal_code=object, debug_temp_alloc=object, debug_coercion=object)
+
 import operator
 
-from Errors import error, warning, warn_once, InternalError
+from Errors import error, warning, warn_once, InternalError, CompileError
 from Errors import hold_errors, release_errors, held_errors, report_error
 from Code import UtilityCode
 import StringEncoding
@@ -21,16 +31,15 @@ import Symtab
 import Options
 from Cython import Utils
 from Annotate import AnnotationItem
-from Cython import Utils
 
 from Cython.Debugging import print_call_chain
 from DebugFlags import debug_disposal_code, debug_temp_alloc, \
     debug_coercion
 
 try:
-    set
-except NameError:
-    from sets import Set as set
+    from __builtin__ import basestring
+except ImportError:
+    basestring = str # Python 3
 
 class NotConstant(object):
     def __repr__(self):
@@ -61,14 +70,14 @@ class ExprNode(Node):
     #  result_code  string       Code fragment
     #  result_ctype string       C type of result_code if different from type
     #  is_temp      boolean      Result is in a temporary variable
-    #  is_sequence_constructor  
+    #  is_sequence_constructor
     #               boolean      Is a list or tuple constructor expression
     #  is_starred   boolean      Is a starred expression (e.g. '*a')
     #  saved_subexpr_nodes
     #               [ExprNode or [ExprNode or None] or None]
     #                            Cached result of subexpr_nodes()
     #  use_managed_ref boolean   use ref-counted temps/assignments/etc.
-    
+
     result_ctype = None
     type = None
     temp_code = None
@@ -101,8 +110,8 @@ class ExprNode(Node):
     #  'subexprs' class attribute of ExprNodes, which should
     #  contain a list of the names of attributes which can
     #  hold sub-nodes or sequences of sub-nodes.
-    #  
-    #  The framework makes use of a number of abstract methods. 
+    #
+    #  The framework makes use of a number of abstract methods.
     #  Their responsibilities are as follows.
     #
     #    Declaration Analysis phase
@@ -125,7 +134,7 @@ class ExprNode(Node):
     #
     #      analyse_target_types
     #        Called during the Analyse Types phase to analyse
-    #        the LHS of an assignment or argument of a del 
+    #        the LHS of an assignment or argument of a del
     #        statement. Similar responsibilities to analyse_types.
     #
     #      target_code
@@ -136,9 +145,9 @@ class ExprNode(Node):
     #      check_const
     #        - Check that this node and its subnodes form a
     #          legal constant expression. If so, do nothing,
-    #          otherwise call not_const. 
+    #          otherwise call not_const.
     #
-    #        The default implementation of check_const 
+    #        The default implementation of check_const
     #        assumes that the expression is not constant.
     #
     #      check_const_addr
@@ -147,7 +156,7 @@ class ExprNode(Node):
     #          constant. Otherwise, call addr_not_const.
     #
     #        The default implementation of calc_const_addr
-    #        assumes that the expression is not a constant 
+    #        assumes that the expression is not a constant
     #        lvalue.
     #
     #   Code Generation phase
@@ -168,8 +177,8 @@ class ExprNode(Node):
     #              sub-expressions.
     #
     #          calculate_result_code
-    #            - Should return a C code fragment evaluating to the 
-    #              result. This is only called when the result is not 
+    #            - Should return a C code fragment evaluating to the
+    #              result. This is only called when the result is not
     #              a temporary.
     #
     #      generate_assignment_code
@@ -187,10 +196,10 @@ class ExprNode(Node):
     #        - Call generate_disposal_code on all sub-expressions.
     #
     #
-    
+
     is_sequence_constructor = 0
     is_attribute = 0
-    
+
     saved_subexpr_nodes = None
     is_temp = 0
     is_target = 0
@@ -202,19 +211,20 @@ class ExprNode(Node):
         _get_child_attrs = operator.attrgetter('subexprs')
     except AttributeError:
         # Python 2.3
-        def _get_child_attrs(self):
+        def __get_child_attrs(self):
             return self.subexprs
+        _get_child_attrs = __get_child_attrs
     child_attrs = property(fget=_get_child_attrs)
-        
+
     def not_implemented(self, method_name):
         print_call_chain(method_name, "not implemented") ###
         raise InternalError(
             "%s.%s not implemented" %
                 (self.__class__.__name__, method_name))
-                
+
     def is_lvalue(self):
         return 0
-    
+
     def is_ephemeral(self):
         #  An ephemeral node is one whose result is in
         #  a Python temporary and we suspect there are no
@@ -235,21 +245,21 @@ class ExprNode(Node):
                 else:
                     nodes.append(item)
         return nodes
-        
+
     def result(self):
         if self.is_temp:
             return self.temp_code
         else:
             return self.calculate_result_code()
-    
+
     def result_as(self, type = None):
         #  Return the result code cast to the specified C type.
         return typecast(type, self.ctype(), self.result())
-    
+
     def py_result(self):
         #  Return the result code cast to PyObject *.
         return self.result_as(py_object_type)
-    
+
     def ctype(self):
         #  Return the native C type of the result (i.e. the
         #  C type of the result_code expression).
@@ -285,18 +295,18 @@ class ExprNode(Node):
     def compile_time_value(self, denv):
         #  Return value of compile-time expression, or report error.
         error(self.pos, "Invalid compile-time expression")
-    
+
     def compile_time_value_error(self, e):
         error(self.pos, "Error in compile-time expression: %s: %s" % (
             e.__class__.__name__, e))
-    
+
     # ------------- Declaration Analysis ----------------
-    
+
     def analyse_target_declaration(self, env):
         error(self.pos, "Cannot assign to or delete this")
-    
+
     # ------------- Expression Analysis ----------------
-    
+
     def analyse_const_expression(self, env):
         #  Called during the analyse_declarations phase of a
         #  constant expression. Analyses the expression's type,
@@ -304,25 +314,25 @@ class ExprNode(Node):
         #  and determines its value.
         self.analyse_types(env)
         return self.check_const()
-    
+
     def analyse_expressions(self, env):
         #  Convenience routine performing both the Type
-        #  Analysis and Temp Allocation phases for a whole 
+        #  Analysis and Temp Allocation phases for a whole
         #  expression.
         self.analyse_types(env)
-    
+
     def analyse_target_expression(self, env, rhs):
         #  Convenience routine performing both the Type
         #  Analysis and Temp Allocation phases for the LHS of
         #  an assignment.
         self.analyse_target_types(env)
-    
+
     def analyse_boolean_expression(self, env):
         #  Analyse expression and coerce to a boolean.
         self.analyse_types(env)
         bool = self.coerce_to_boolean(env)
         return bool
-    
+
     def analyse_temp_boolean_expression(self, env):
         #  Analyse boolean expression and coerce result into
         #  a temporary. This is used when a branch is to be
@@ -335,17 +345,17 @@ class ExprNode(Node):
         return self.coerce_to_boolean(env).coerce_to_simple(env)
 
     # --------------- Type Inference -----------------
-    
+
     def type_dependencies(self, env):
         # Returns the list of entries whose types must be determined
         # before the type of self can be infered.
         if hasattr(self, 'type') and self.type is not None:
             return ()
         return sum([node.type_dependencies(env) for node in self.subexpr_nodes()], ())
-    
+
     def infer_type(self, env):
-        # Attempt to deduce the type of self. 
-        # Differs from analyse_types as it avoids unnecessary 
+        # Attempt to deduce the type of self.
+        # Differs from analyse_types as it avoids unnecessary
         # analysis of subexpressions, but can assume everything
         # in self.type_dependencies() has been resolved.
         if hasattr(self, 'type') and self.type is not None:
@@ -354,27 +364,27 @@ class ExprNode(Node):
             return self.entry.type
         else:
             self.not_implemented("infer_type")
-    
+
     # --------------- Type Analysis ------------------
-    
+
     def analyse_as_module(self, env):
         # If this node can be interpreted as a reference to a
         # cimported module, return its scope, else None.
         return None
-        
+
     def analyse_as_type(self, env):
         # If this node can be interpreted as a reference to a
         # type, return that type, else None.
         return None
-    
+
     def analyse_as_extension_type(self, env):
         # If this node can be interpreted as a reference to an
         # extension type, return its type, else None.
         return None
-    
+
     def analyse_types(self, env):
         self.not_implemented("analyse_types")
-    
+
     def analyse_target_types(self, env):
         self.analyse_types(env)
 
@@ -392,33 +402,33 @@ class ExprNode(Node):
     def check_const(self):
         self.not_const()
         return False
-    
+
     def not_const(self):
         error(self.pos, "Not allowed in a constant expression")
-    
+
     def check_const_addr(self):
         self.addr_not_const()
         return False
-    
+
     def addr_not_const(self):
         error(self.pos, "Address is not constant")
 
     # ----------------- Result Allocation -----------------
-    
+
     def result_in_temp(self):
         #  Return true if result is in a temporary owned by
         #  this node or one of its subexpressions. Overridden
         #  by certain nodes which can share the result of
         #  a subnode.
         return self.is_temp
-            
+
     def target_code(self):
         #  Return code fragment for use as LHS of a C assignment.
         return self.calculate_result_code()
-    
+
     def calculate_result_code(self):
         self.not_implemented("calculate_result_code")
-    
+
 #    def release_target_temp(self, env):
 #        #  Release temporaries used by LHS of an assignment.
 #        self.release_subexpr_temps(env)
@@ -448,16 +458,16 @@ class ExprNode(Node):
         self.temp_code = None
 
     # ---------------- Code Generation -----------------
-    
+
     def make_owned_reference(self, code):
         #  If result is a pyobject, make sure we own
         #  a reference to it.
         if self.type.is_pyobject and not self.result_in_temp():
             code.put_incref(self.result(), self.ctype())
-    
+
     def generate_evaluation_code(self, code):
         code.mark_pos(self.pos)
-        
+
         #  Generate code to evaluate this node and
         #  its sub-expressions, and dispose of any
         #  temporary results of its sub-expressions.
@@ -476,10 +486,10 @@ class ExprNode(Node):
     def generate_subexpr_evaluation_code(self, code):
         for node in self.subexpr_nodes():
             node.generate_evaluation_code(code)
-    
+
     def generate_result_code(self, code):
         self.not_implemented("generate_result_code")
-    
+
     def generate_disposal_code(self, code):
         if self.is_temp:
             if self.type.is_pyobject:
@@ -493,7 +503,7 @@ class ExprNode(Node):
         #  of all sub-expressions.
         for node in self.subexpr_nodes():
             node.generate_disposal_code(code)
-    
+
     def generate_post_assignment_code(self, code):
         if self.is_temp:
             if self.type.is_pyobject:
@@ -503,10 +513,10 @@ class ExprNode(Node):
 
     def generate_assignment_code(self, rhs, code):
         #  Stub method for nodes which are not legal as
-        #  the LHS of an assignment. An error will have 
+        #  the LHS of an assignment. An error will have
         #  been reported earlier.
         pass
-    
+
     def generate_deletion_code(self, code):
         #  Stub method for nodes that are not legal as
         #  the argument of a del statement. An error
@@ -519,7 +529,7 @@ class ExprNode(Node):
                 self.release_temp_result(code)
         else:
             self.free_subexpr_temps(code)
-    
+
     def free_subexpr_temps(self, code):
         for sub in self.subexpr_nodes():
             sub.free_temps(code)
@@ -528,13 +538,13 @@ class ExprNode(Node):
         pass
 
     # ---------------- Annotation ---------------------
-    
+
     def annotate(self, code):
         for node in self.subexpr_nodes():
             node.annotate(code)
-    
+
     # ----------------- Coercion ----------------------
-    
+
     def coerce_to(self, dst_type, env):
         #   Coerce the result so that it can be assigned to
         #   something of type dst_type. If processing is necessary,
@@ -561,7 +571,7 @@ class ExprNode(Node):
 
         if dst_type.is_reference:
             dst_type = dst_type.ref_base_type
-        
+
         if dst_type.is_pyobject:
             if not src.type.is_pyobject:
                 if dst_type is bytes_type and src.type.is_int:
@@ -573,7 +583,7 @@ class ExprNode(Node):
                     src = PyTypeTestNode(src, dst_type, env)
         elif src.type.is_pyobject:
             src = CoerceFromPyTypeNode(dst_type, src, env)
-        elif (dst_type.is_complex 
+        elif (dst_type.is_complex
               and src_type != dst_type
               and dst_type.assignable_from(src_type)):
             src = CoerceToComplexNode(src, dst_type, env)
@@ -618,31 +628,31 @@ class ExprNode(Node):
             return CoerceToBooleanNode(self, env)
         else:
             if not (type.is_int or type.is_enum or type.is_error):
-                error(self.pos, 
+                error(self.pos,
                     "Type '%s' not acceptable as a boolean" % type)
             return self
-    
+
     def coerce_to_integer(self, env):
         # If not already some C integer type, coerce to longint.
         if self.type.is_int:
             return self
         else:
             return self.coerce_to(PyrexTypes.c_long_type, env)
-    
+
     def coerce_to_temp(self, env):
         #  Ensure that the result is in a temporary.
         if self.result_in_temp():
             return self
         else:
             return CoerceToTempNode(self, env)
-    
+
     def coerce_to_simple(self, env):
         #  Ensure that the result is simple (see is_simple).
         if self.is_simple():
             return self
         else:
             return self.coerce_to_temp(env)
-    
+
     def is_simple(self):
         #  A node is simple if its result is something that can
         #  be referred to without performing any operations, e.g.
@@ -672,7 +682,7 @@ class ExprNode(Node):
 class AtomicExprNode(ExprNode):
     #  Abstract base class for expression nodes which have
     #  no sub-expressions.
-    
+
     subexprs = []
 
     # Override to optimize -- we know we have no children
@@ -683,10 +693,10 @@ class AtomicExprNode(ExprNode):
 
 class PyConstNode(AtomicExprNode):
     #  Abstract base class for constant Python values.
-    
+
     is_literal = 1
     type = py_object_type
-    
+
     def is_simple(self):
         return 1
 
@@ -695,7 +705,7 @@ class PyConstNode(AtomicExprNode):
 
     def analyse_types(self, env):
         pass
-    
+
     def calculate_result_code(self):
         return self.value
 
@@ -705,11 +715,11 @@ class PyConstNode(AtomicExprNode):
 
 class NoneNode(PyConstNode):
     #  The constant value None
-    
+
     value = "Py_None"
 
     constant_result = None
-    
+
     nogil_check = None
 
     def compile_time_value(self, denv):
@@ -721,7 +731,7 @@ class NoneNode(PyConstNode):
 
 class EllipsisNode(PyConstNode):
     #  '...' in a subscript list.
-    
+
     value = "Py_Ellipsis"
 
     constant_result = Ellipsis
@@ -734,7 +744,7 @@ class ConstNode(AtomicExprNode):
     # Abstract base type for literal constant nodes.
     #
     # value     string      C code fragment
-    
+
     is_literal = 1
     nogil_check = None
 
@@ -746,10 +756,10 @@ class ConstNode(AtomicExprNode):
 
     def analyse_types(self, env):
         pass # Types are held in class variables
-    
+
     def check_const(self):
         return True
-    
+
     def get_constant_c_result_code(self):
         return self.calculate_result_code()
 
@@ -769,7 +779,7 @@ class BoolNode(ConstNode):
 
     def compile_time_value(self, denv):
         return self.value
-    
+
     def calculate_result_code(self):
         return str(int(self.value))
 
@@ -788,10 +798,10 @@ class CharNode(ConstNode):
 
     def calculate_constant_result(self):
         self.constant_result = ord(self.value)
-    
+
     def compile_time_value(self, denv):
         return ord(self.value)
-    
+
     def calculate_result_code(self):
         return "'%s'" % StringEncoding.escape_char(self.value)
 
@@ -881,7 +891,7 @@ class IntNode(ConstNode):
             self.result_code = code.get_py_num(plain_integer_string, self.longness)
         else:
             self.result_code = self.get_constant_c_result_code()
-    
+
     def get_constant_c_result_code(self):
         return self.value_as_c_integer_string() + self.unsigned + self.longness
 
@@ -918,7 +928,7 @@ class FloatNode(ConstNode):
 
     def compile_time_value(self, denv):
         return float(self.value)
-    
+
     def calculate_result_code(self):
         strval = self.value
         assert isinstance(strval, (str, unicode))
@@ -938,14 +948,15 @@ class BytesNode(ConstNode):
     #
     # value      BytesLiteral
 
-    type = PyrexTypes.c_char_ptr_type
+    # start off as Python 'bytes' to support len() in O(1)
+    type = bytes_type
 
     def compile_time_value(self, denv):
         return self.value
 
     def analyse_as_type(self, env):
         type = PyrexTypes.parse_basic_type(self.value)
-        if type is not None:    
+        if type is not None:
             return type
         from TreeFragment import TreeFragment
         pos = (self.pos[0], self.pos[1], self.pos[2]-7)
@@ -959,11 +970,13 @@ class BytesNode(ConstNode):
         return len(self.value) == 1
 
     def coerce_to_boolean(self, env):
-        # This is special because we start off as a C char*.  Testing
-        # that for truth directly would yield the wrong result.
+        # This is special because testing a C char* for truth directly
+        # would yield the wrong result.
         return BoolNode(self.pos, value=bool(self.value))
 
     def coerce_to(self, dst_type, env):
+        if self.type == dst_type:
+            return self
         if dst_type.is_int:
             if not self.can_coerce_to_char_literal():
                 error(self.pos, "Only single-character string literals can be coerced into ints.")
@@ -974,21 +987,20 @@ class BytesNode(ConstNode):
             return CharNode(self.pos, value=self.value)
 
         node = BytesNode(self.pos, value=self.value)
-        if dst_type == PyrexTypes.c_char_ptr_type:
-            node.type = PyrexTypes.c_char_ptr_type
+        if dst_type.is_pyobject:
+            if dst_type in (py_object_type, Builtin.bytes_type):
+                node.type = Builtin.bytes_type
+            else:
+                self.check_for_coercion_error(dst_type, fail=True)
+                return node
+        elif dst_type == PyrexTypes.c_char_ptr_type:
+            node.type = dst_type
             return node
         elif dst_type == PyrexTypes.c_uchar_ptr_type:
             node.type = PyrexTypes.c_char_ptr_type
             return CastNode(node, PyrexTypes.c_uchar_ptr_type)
-
-        if not self.type.is_pyobject:
-            if dst_type in (py_object_type, Builtin.bytes_type):
-                node.type = Builtin.bytes_type
-            elif dst_type.is_pyobject:
-                self.fail_assignment(dst_type)
-                return self
-        elif dst_type.is_pyobject and dst_type is not py_object_type:
-            self.check_for_coercion_error(dst_type, fail=True)
+        elif dst_type.assignable_from(PyrexTypes.c_char_ptr_type):
+            node.type = dst_type
             return node
 
         # We still need to perform normal coerce_to processing on the
@@ -996,11 +1008,6 @@ class BytesNode(ConstNode):
         # in which case a type test node will be needed.
         return ConstNode.coerce_to(node, dst_type, env)
 
-    def as_py_string_node(self, env):
-        # Return a new BytesNode with the same value as this node
-        # but whose type is a Python type instead of a C type.
-        return BytesNode(self.pos, value = self.value, type = Builtin.bytes_type)
-
     def generate_evaluation_code(self, code):
         if self.type.is_pyobject:
             self.result_code = code.get_py_string_const(self.value)
@@ -1009,7 +1016,7 @@ class BytesNode(ConstNode):
 
     def get_constant_c_result_code(self):
         return None # FIXME
-    
+
     def calculate_result_code(self):
         return self.result_code
 
@@ -1067,7 +1074,7 @@ class UnicodeNode(PyConstNode):
 
     def calculate_result_code(self):
         return self.result_code
-        
+
     def compile_time_value(self, env):
         return self.value
 
@@ -1076,8 +1083,8 @@ class StringNode(PyConstNode):
     # A Python str object, i.e. a byte string in Python 2.x and a
     # unicode string in Python 3.x
     #
-    # value          BytesLiteral
-    # unicode_value  EncodedString
+    # value          BytesLiteral (or EncodedString with ASCII content)
+    # unicode_value  EncodedString or None
     # is_identifier  boolean
 
     type = str_type
@@ -1094,12 +1101,13 @@ class StringNode(PyConstNode):
             self.check_for_coercion_error(dst_type, fail=True)
 
         # this will be a unicode string in Py3, so make sure we can decode it
-        if self.value.encoding:
-            encoding = self.value.encoding
+        if self.value.encoding and isinstance(self.value, StringEncoding.BytesLiteral):
             try:
-                self.value.decode(encoding)
+                self.value.decode(self.value.encoding)
             except UnicodeDecodeError:
-                error(self.pos, "String decoding as '%s' failed. Consider using a byte string or unicode string explicitly, or adjust the source code encoding." % encoding)
+                error(self.pos, ("Decoding unprefixed string literal from '%s' failed. Consider using"
+                                 "a byte string or unicode string explicitly, "
+                                 "or adjust the source code encoding.") % self.value.encoding)
 
         return self
 
@@ -1115,7 +1123,7 @@ class StringNode(PyConstNode):
 
     def calculate_result_code(self):
         return self.result_code
-        
+
     def compile_time_value(self, env):
         return self.value
 
@@ -1135,10 +1143,10 @@ class LongNode(AtomicExprNode):
 
     def calculate_constant_result(self):
         self.constant_result = Utils.str_to_number(self.value)
-    
+
     def compile_time_value(self, denv):
         return Utils.str_to_number(self.value)
-    
+
     def analyse_types(self, env):
         self.is_temp = 1
 
@@ -1160,15 +1168,15 @@ class ImagNode(AtomicExprNode):
     #  Imaginary number literal
     #
     #  value   float    imaginary part
-    
+
     type = PyrexTypes.c_double_complex_type
 
     def calculate_constant_result(self):
         self.constant_result = complex(0.0, self.value)
-    
+
     def compile_time_value(self, denv):
         return complex(0.0, self.value)
-    
+
     def analyse_types(self, env):
         self.type.create_declaration_utility_code(env)
 
@@ -1203,16 +1211,16 @@ class ImagNode(AtomicExprNode):
                     float(self.value),
                     code.error_goto_if_null(self.result(), self.pos)))
             code.put_gotref(self.py_result())
-        
+
 
 class NewExprNode(AtomicExprNode):
 
     # C++ new statement
     #
     # cppclass              node                 c++ class to create
-    
+
     type = None
-    
+
     def infer_type(self, env):
         type = self.cppclass.analyse_as_type(env)
         if type is None or not type.is_cpp_class:
@@ -1230,7 +1238,7 @@ class NewExprNode(AtomicExprNode):
         self.entry = constructor
         self.type = constructor.type
         return self.type
-    
+
     def analyse_types(self, env):
         if self.type is None:
             self.infer_type(env)
@@ -1240,7 +1248,7 @@ class NewExprNode(AtomicExprNode):
 
     def generate_result_code(self, code):
         pass
-   
+
     def calculate_result_code(self):
         return "new " + self.class_type.declaration_code("")
 
@@ -1251,7 +1259,7 @@ class NameNode(AtomicExprNode):
     #  name            string    Python name of the variable
     #  entry           Entry     Symbol table entry
     #  type_entry      Entry     For extension type names, the original type entry
-    
+
     is_name = True
     is_cython_module = False
     cython_attribute = None
@@ -1264,12 +1272,12 @@ class NameNode(AtomicExprNode):
         node = NameNode(pos)
         node.analyse_types(env, entry=entry)
         return node
-        
+
     def as_cython_attribute(self):
         return self.cython_attribute
-    
+
     create_analysed_rvalue = staticmethod(create_analysed_rvalue)
-    
+
     def type_dependencies(self, env):
         if self.entry is None:
             self.entry = env.lookup(self.name)
@@ -1277,7 +1285,7 @@ class NameNode(AtomicExprNode):
             return (self.entry,)
         else:
             return ()
-    
+
     def infer_type(self, env):
         if self.entry is None:
             self.entry = env.lookup(self.name)
@@ -1288,9 +1296,12 @@ class NameNode(AtomicExprNode):
             # Unfortunately the type attribute of type objects
             # is used for the pointer to the type they represent.
             return type_type
+        elif self.entry.type.is_cfunction:
+            # special case: referring to a C function must return its pointer
+            return PyrexTypes.CPtrType(self.entry.type)
         else:
             return self.entry.type
-    
+
     def compile_time_value(self, denv):
         try:
             return denv.lookup(self.name)
@@ -1301,7 +1312,7 @@ class NameNode(AtomicExprNode):
         if not self.entry or self.entry.type.is_pyobject:
             return None
         return self.entry.cname
-    
+
     def coerce_to(self, dst_type, env):
         #  If coercing to a generic pyobject and this is a builtin
         #  C function with a Python equivalent, manufacture a NameNode
@@ -1319,7 +1330,7 @@ class NameNode(AtomicExprNode):
                     node.analyse_rvalue_entry(env)
                     return node
         return super(NameNode, self).coerce_to(dst_type, env)
-    
+
     def analyse_as_module(self, env):
         # Try to interpret this as a reference to a cimported module.
         # Returns the module scope, or None.
@@ -1329,7 +1340,7 @@ class NameNode(AtomicExprNode):
         if entry and entry.as_module:
             return entry.as_module
         return None
-        
+
     def analyse_as_type(self, env):
         if self.cython_attribute:
             type = PyrexTypes.parse_basic_type(self.cython_attribute)
@@ -1344,7 +1355,7 @@ class NameNode(AtomicExprNode):
             return entry.type
         else:
             return None
-    
+
     def analyse_as_extension_type(self, env):
         # Try to interpret this as a reference to an extension type.
         # Returns the extension type, or None.
@@ -1355,7 +1366,7 @@ class NameNode(AtomicExprNode):
             return entry.type
         else:
             return None
-    
+
     def analyse_target_declaration(self, env):
         if not self.entry:
             self.entry = env.lookup_here(self.name)
@@ -1371,7 +1382,7 @@ class NameNode(AtomicExprNode):
         env.control_flow.set_state(self.pos, (self.name, 'source'), 'assignment')
         if self.entry.is_declared_generic:
             self.result_ctype = py_object_type
-    
+
     def analyse_types(self, env):
         if self.entry is None:
             self.entry = env.lookup(self.name)
@@ -1389,7 +1400,7 @@ class NameNode(AtomicExprNode):
             if entry.utility_code:
                 env.use_utility_code(entry.utility_code)
         self.analyse_rvalue_entry(env)
-        
+
     def analyse_target_types(self, env):
         self.analyse_entry(env)
         if not self.is_lvalue():
@@ -1400,7 +1411,7 @@ class NameNode(AtomicExprNode):
         if self.entry.type.is_buffer:
             import Buffer
             Buffer.used_buffer_aux_vars(self.entry)
-                
+
     def analyse_rvalue_entry(self, env):
         #print "NameNode.analyse_rvalue_entry:", self.name ###
         #print "Entry:", self.entry.__dict__ ###
@@ -1420,8 +1431,8 @@ class NameNode(AtomicExprNode):
         if self.is_used_as_rvalue:
             entry = self.entry
             if entry.is_builtin:
-                if not Options.cache_builtins: # cached builtins are ok
-                self.gil_error()
+                if not Options.cache_builtins: # cached builtins are ok
+                    self.gil_error()
             elif entry.is_pyglobal:
                 self.gil_error()
 
@@ -1441,29 +1452,29 @@ class NameNode(AtomicExprNode):
         entry = self.entry
         if entry.is_type and entry.type.is_extension_type:
             self.type_entry = entry
-        if not (entry.is_const or entry.is_variable 
+        if not (entry.is_const or entry.is_variable
             or entry.is_builtin or entry.is_cfunction
             or entry.is_cpp_class):
                 if self.entry.as_variable:
                     self.entry = self.entry.as_variable
                 else:
-                    error(self.pos, 
+                    error(self.pos,
                           "'%s' is not a constant, variable or function identifier" % self.name)
 
     def is_simple(self):
         #  If it's not a C variable, it'll be in a temp.
         return 1
-    
+
     def calculate_target_results(self, env):
         pass
-    
+
     def check_const(self):
         entry = self.entry
         if entry is not None and not (entry.is_const or entry.is_cfunction or entry.is_builtin):
             self.not_const()
             return False
         return True
-    
+
     def check_const_addr(self):
         entry = self.entry
         if not (entry.is_cglobal or entry.is_cfunction or entry.is_builtin):
@@ -1475,18 +1486,18 @@ class NameNode(AtomicExprNode):
         return self.entry.is_variable and \
             not self.entry.type.is_array and \
             not self.entry.is_readonly
-    
+
     def is_ephemeral(self):
         #  Name nodes are never ephemeral, even if the
         #  result is in a temporary.
         return 0
-    
+
     def calculate_result_code(self):
         entry = self.entry
         if not entry:
             return "<error>" # There was an error earlier
         return entry.cname
-    
+
     def generate_result_code(self, code):
         assert hasattr(self, 'entry')
         entry = self.entry
@@ -1501,7 +1512,6 @@ class NameNode(AtomicExprNode):
                 namespace = Naming.builtins_cname
             else: # entry.is_pyglobal
                 namespace = entry.scope.namespace_cname
-            code.globalstate.use_utility_code(getitem_dict_utility_code)
             code.putln(
                 '%s = PyObject_GetItem(%s, %s); %s' % (
                 self.result(),
@@ -1509,7 +1519,7 @@ class NameNode(AtomicExprNode):
                 interned_cname,
                 code.error_goto_if_null(self.result(), self.pos)))
             code.put_gotref(self.py_result())
-            
+
         elif entry.is_pyglobal or entry.is_builtin:
             assert entry.type.is_pyobject, "Python global or builtin not a Python object"
             interned_cname = code.intern_identifier(self.entry.name)
@@ -1521,11 +1531,11 @@ class NameNode(AtomicExprNode):
             code.putln(
                 '%s = __Pyx_GetName(%s, %s); %s' % (
                 self.result(),
-                namespace, 
+                namespace,
                 interned_cname,
                 code.error_goto_if_null(self.result(), self.pos)))
             code.put_gotref(self.py_result())
-            
+
         elif entry.is_local and False:
             # control flow not good enough yet
             assigned = entry.scope.control_flow.get_state((entry.name, 'initialized'), self.pos)
@@ -1545,7 +1555,7 @@ class NameNode(AtomicExprNode):
         if (self.entry.type.is_ptr and isinstance(rhs, ListNode)
             and not self.lhs_of_first_assignment):
             error(self.pos, "Literal list must be assigned to pointer at time of declaration")
-        
+
         # is_pyglobal seems to be True for module level-globals only.
         # We use this to access class->tp_dict if necessary.
         if entry.is_pyglobal:
@@ -1641,11 +1651,11 @@ class NameNode(AtomicExprNode):
         Buffer.put_assign_to_buffer(self.result(), rhstmp, buffer_aux, self.entry.type,
                                     is_initialized=not self.lhs_of_first_assignment,
                                     pos=self.pos, code=code)
-        
+
         if not pretty_rhs:
             code.putln("%s = 0;" % rhstmp)
             code.funcstate.release_temp(rhstmp)
-    
+
     def generate_deletion_code(self, code):
         if self.entry is None:
             return # There was an error earlier
@@ -1659,11 +1669,11 @@ class NameNode(AtomicExprNode):
                     namespace,
                     self.entry.name))
         else:
-            code.put_error_if_neg(self.pos, 
+            code.put_error_if_neg(self.pos,
                 '__Pyx_DelAttrString(%s, "%s")' % (
                     Naming.module_cname,
                     self.entry.name))
-                
+
     def annotate(self, code):
         if hasattr(self, 'is_called') and self.is_called:
             pos = (self.pos[0], self.pos[1], self.pos[2] - len(self.name) - 1)
@@ -1671,16 +1681,16 @@ class NameNode(AtomicExprNode):
                 code.annotate(pos, AnnotationItem('py_call', 'python function', size=len(self.name)))
             else:
                 code.annotate(pos, AnnotationItem('c_call', 'c function', size=len(self.name)))
-            
+
 class BackquoteNode(ExprNode):
     #  `expr`
     #
     #  arg    ExprNode
-    
+
     type = py_object_type
-    
+
     subexprs = ['arg']
-    
+
     def analyse_types(self, env):
         self.arg.analyse_types(env)
         self.arg = self.arg.coerce_to_pyobject(env)
@@ -1698,21 +1708,21 @@ class BackquoteNode(ExprNode):
                 self.arg.py_result(),
                 code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
-        
+
 
 
 class ImportNode(ExprNode):
     #  Used as part of import statement implementation.
-    #  Implements result = 
+    #  Implements result =
     #    __import__(module_name, globals(), None, name_list)
     #
     #  module_name   StringNode            dotted name of module
     #  name_list     ListNode or None      list of names to be imported
-    
+
     type = py_object_type
-    
+
     subexprs = ['module_name', 'name_list']
-    
+
     def analyse_types(self, env):
         self.module_name.analyse_types(env)
         self.module_name = self.module_name.coerce_to_pyobject(env)
@@ -1747,11 +1757,11 @@ class IteratorNode(ExprNode):
     #  Implements result = iter(sequence)
     #
     #  sequence   ExprNode
-    
+
     type = py_object_type
-    
+
     subexprs = ['sequence']
-    
+
     def analyse_types(self, env):
         self.sequence.analyse_types(env)
         if (self.sequence.type.is_array or self.sequence.type.is_ptr) and \
@@ -1760,6 +1770,9 @@ class IteratorNode(ExprNode):
             self.type = self.sequence.type
         else:
             self.sequence = self.sequence.coerce_to_pyobject(env)
+            if self.sequence.type is list_type or \
+                   self.sequence.type is tuple_type:
+                self.sequence = self.sequence.as_none_safe_node("'NoneType' object is not iterable")
         self.is_temp = 1
 
     gil_message = "Iterating over Python object"
@@ -1776,36 +1789,30 @@ class IteratorNode(ExprNode):
             raise InternalError("for in carray slice not transformed")
         is_builtin_sequence = self.sequence.type is list_type or \
                               self.sequence.type is tuple_type
-        may_be_a_sequence = is_builtin_sequence or not self.sequence.type.is_builtin_type
-        if is_builtin_sequence:
-            code.putln(
-                "if (likely(%s != Py_None)) {" % self.sequence.py_result())
-        elif may_be_a_sequence:
+        may_be_a_sequence = not self.sequence.type.is_builtin_type
+        if may_be_a_sequence:
             code.putln(
                 "if (PyList_CheckExact(%s) || PyTuple_CheckExact(%s)) {" % (
                     self.sequence.py_result(),
                     self.sequence.py_result()))
-        if may_be_a_sequence:
+        if is_builtin_sequence or may_be_a_sequence:
             code.putln(
                 "%s = 0; %s = %s; __Pyx_INCREF(%s);" % (
                     self.counter_cname,
                     self.result(),
                     self.sequence.py_result(),
                     self.result()))
-            code.putln("} else {")
-        if is_builtin_sequence:
-            code.putln(
-                'PyErr_SetString(PyExc_TypeError, "\'NoneType\' object is not iterable"); %s' %
-                code.error_goto(self.pos))
-        else:
+        if not is_builtin_sequence:
+            if may_be_a_sequence:
+                code.putln("} else {")
             code.putln("%s = -1; %s = PyObject_GetIter(%s); %s" % (
                     self.counter_cname,
                     self.result(),
                     self.sequence.py_result(),
                     code.error_goto_if_null(self.result(), self.pos)))
             code.put_gotref(self.py_result())
-        if may_be_a_sequence:
-            code.putln("}")
+            if may_be_a_sequence:
+                code.putln("}")
 
 
 class NextNode(AtomicExprNode):
@@ -1815,16 +1822,16 @@ class NextNode(AtomicExprNode):
     #  The iterator is not owned by this node.
     #
     #  iterator   ExprNode
-    
+
     type = py_object_type
-    
+
     def __init__(self, iterator, env):
         self.pos = iterator.pos
         self.iterator = iterator
         if iterator.type.is_ptr or iterator.type.is_array:
             self.type = iterator.type.base_type
         self.is_temp = 1
-    
+
     def generate_result_code(self, code):
         sequence_type = self.iterator.sequence.type
         if sequence_type is list_type:
@@ -1877,15 +1884,15 @@ class ExcValueNode(AtomicExprNode):
     #  Node created during analyse_types phase
     #  of an ExceptClauseNode to fetch the current
     #  exception value.
-    
+
     type = py_object_type
-    
+
     def __init__(self, pos, env):
         ExprNode.__init__(self, pos)
 
     def set_var(self, var):
         self.var = var
-    
+
     def calculate_result_code(self):
         return self.var
 
@@ -1906,17 +1913,17 @@ class TempNode(ExprNode):
     # the regular cycle.
 
     subexprs = []
-    
+
     def __init__(self, pos, type, env):
         ExprNode.__init__(self, pos)
         self.type = type
         if type.is_pyobject:
             self.result_ctype = py_object_type
         self.is_temp = 1
-        
+
     def analyse_types(self, env):
         return self.type
-    
+
     def generate_result_code(self, code):
         pass
 
@@ -1937,19 +1944,19 @@ class TempNode(ExprNode):
     # Do not participate in normal temp alloc/dealloc:
     def allocate_temp_result(self, code):
         pass
-    
+
     def release_temp_result(self, code):
         pass
 
 class PyTempNode(TempNode):
     #  TempNode holding a Python value.
-    
+
     def __init__(self, pos, env):
         TempNode.__init__(self, pos, PyrexTypes.py_object_type, env)
 
 class RawCNameExprNode(ExprNode):
     subexprs = []
-    
+
     def __init__(self, pos, type=None):
         self.pos = pos
         self.type = type
@@ -1984,7 +1991,7 @@ class IndexNode(ExprNode):
     #  indices is used on buffer access, index on non-buffer access.
     #  The former contains a clean list of index parameters, the
     #  latter whatever Python object is needed for index access.
-    
+
     subexprs = ['base', 'index', 'indices']
     indices = None
 
@@ -2003,13 +2010,13 @@ class IndexNode(ExprNode):
             return base[index]
         except Exception, e:
             self.compile_time_value_error(e)
-    
+
     def is_ephemeral(self):
         return self.base.is_ephemeral()
-    
+
     def analyse_target_declaration(self, env):
         pass
-        
+
     def analyse_as_type(self, env):
         base_type = self.base.analyse_as_type(env)
         if base_type and not base_type.is_pyobject:
@@ -2020,23 +2027,23 @@ class IndexNode(ExprNode):
                     template_values = [self.index]
                 import Nodes
                 type_node = Nodes.TemplatedTypeNode(
-                    pos = self.pos, 
-                    positional_args = template_values, 
+                    pos = self.pos,
+                    positional_args = template_values,
                     keyword_args = None)
                 return type_node.analyse(env, base_type = base_type)
             else:
                 return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env)))
         return None
-    
+
     def type_dependencies(self, env):
-        return self.base.type_dependencies(env)
-    
+        return self.base.type_dependencies(env) + self.index.type_dependencies(env)
+
     def infer_type(self, env):
         base_type = self.base.infer_type(env)
         if isinstance(self.index, SliceNode):
             # slicing!
             if base_type.is_string:
-                # sliced C strings must coerce to Python 
+                # sliced C strings must coerce to Python
                 return bytes_type
             elif base_type in (unicode_type, bytes_type, str_type, list_type, tuple_type):
                 # slicing these returns the same type
@@ -2073,10 +2080,10 @@ class IndexNode(ExprNode):
         else:
             # TODO: Handle buffers (hopefully without too much redundancy).
             return py_object_type
-    
+
     def analyse_types(self, env):
         self.analyse_base_and_index_types(env, getting = 1)
-    
+
     def analyse_target_types(self, env):
         self.analyse_base_and_index_types(env, setting = 1)
 
@@ -2096,7 +2103,7 @@ class IndexNode(ExprNode):
             # error messages
             self.type = PyrexTypes.error_type
             return
-        
+
         is_slice = isinstance(self.index, SliceNode)
         # Potentially overflowing index value.
         if not is_slice and isinstance(self.index, IntNode) and Utils.long_literal(self.index.value):
@@ -2228,7 +2235,7 @@ class IndexNode(ExprNode):
 
     def check_const_addr(self):
         return self.base.check_const_addr() and self.index.check_const()
-    
+
     def is_lvalue(self):
         return 1
 
@@ -2246,7 +2253,7 @@ class IndexNode(ExprNode):
         else:
             return "(%s[%s])" % (
                 self.base.result(), self.index.result())
-            
+
     def extra_index_params(self):
         if self.index.type.is_int:
             if self.original_index_type.signed:
@@ -2264,7 +2271,7 @@ class IndexNode(ExprNode):
         else:
             for i in self.indices:
                 i.generate_evaluation_code(code)
-        
+
     def generate_subexpr_disposal_code(self, code):
         self.base.generate_disposal_code(code)
         if not self.indices:
@@ -2332,7 +2339,7 @@ class IndexNode(ExprNode):
                         self.extra_index_params(),
                         self.result(),
                         code.error_goto(self.pos)))
-            
+
     def generate_setitem_code(self, value_code, code):
         if self.index.type.is_int:
             function = "__Pyx_SetItemInt"
@@ -2343,12 +2350,12 @@ class IndexNode(ExprNode):
             if self.base.type is dict_type:
                 function = "PyDict_SetItem"
             # It would seem that we could specialized lists/tuples, but that
-            # shouldn't happen here. 
-            # Both PyList_SetItem PyTuple_SetItem and a Py_ssize_t as input, 
-            # not a PyObject*, and bad conversion here would give the wrong 
-            # exception. Also, tuples are supposed to be immutable, and raise 
-            # TypeErrors when trying to set their entries (PyTuple_SetItem 
-            # is for creating new tuples from). 
+            # shouldn't happen here.
+            # Both PyList_SetItem PyTuple_SetItem and a Py_ssize_t as input,
+            # not a PyObject*, and bad conversion here would give the wrong
+            # exception. Also, tuples are supposed to be immutable, and raise
+            # TypeErrors when trying to set their entries (PyTuple_SetItem
+            # is for creating new tuples from).
             else:
                 function = "PyObject_SetItem"
         code.putln(
@@ -2378,7 +2385,7 @@ class IndexNode(ExprNode):
             code.putln("*%s %s= %s;" % (ptr, op, rhs_code))
             code.put_giveref("*%s" % ptr)
             code.funcstate.release_temp(ptr)
-        else: 
+        else:
             # Simple case
             code.putln("*%s %s= %s;" % (ptrexpr, op, rhs.result()))
 
@@ -2396,7 +2403,7 @@ class IndexNode(ExprNode):
         self.free_subexpr_temps(code)
         rhs.generate_disposal_code(code)
         rhs.free_temps(code)
-    
+
     def generate_deletion_code(self, code):
         self.generate_subexpr_evaluation_code(code)
         #if self.type.is_pyobject:
@@ -2448,7 +2455,7 @@ class SliceIndexNode(ExprNode):
     #  base      ExprNode
     #  start     ExprNode or None
     #  stop      ExprNode or None
-    
+
     subexprs = ['base', 'start', 'stop']
 
     def infer_type(self, env):
@@ -2478,10 +2485,10 @@ class SliceIndexNode(ExprNode):
             return base[start:stop]
         except Exception, e:
             self.compile_time_value_error(e)
-    
+
     def analyse_target_declaration(self, env):
         pass
-    
+
     def analyse_target_types(self, env):
         self.analyse_types(env)
         # when assigning, we must accept any Python type
@@ -2551,11 +2558,11 @@ class SliceIndexNode(ExprNode):
                     self.stop_code(),
                     code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
-    
+
     def generate_assignment_code(self, rhs, code):
         self.generate_subexpr_evaluation_code(code)
         if self.type.is_pyobject:
-            code.put_error_if_neg(self.pos, 
+            code.put_error_if_neg(self.pos,
                 "__Pyx_PySequence_SetSlice(%s, %s, %s, %s)" % (
                     self.base.py_result(),
                     self.start_code(),
@@ -2598,6 +2605,7 @@ class SliceIndexNode(ExprNode):
                 self.start_code(),
                 self.stop_code()))
         self.generate_subexpr_disposal_code(code)
+        self.free_subexpr_temps(code)
 
     def generate_slice_guard_code(self, code, target_size):
         if not self.base.type.is_array:
@@ -2646,13 +2654,13 @@ class SliceIndexNode(ExprNode):
                         target_size, check))
             code.putln(code.error_goto(self.pos))
             code.putln("}")
-    
+
     def start_code(self):
         if self.start:
             return self.start.result()
         else:
             return "0"
-    
+
     def stop_code(self):
         if self.stop:
             return self.stop.result()
@@ -2660,11 +2668,11 @@ class SliceIndexNode(ExprNode):
             return self.base.type.size
         else:
             return "PY_SSIZE_T_MAX"
-    
+
     def calculate_result_code(self):
         # self.result() is not used, but this method must exist
         return "<unused>"
-    
+
 
 class SliceNode(ExprNode):
     #  start:stop:step in subscript list
@@ -2672,7 +2680,7 @@ class SliceNode(ExprNode):
     #  start     ExprNode
     #  stop      ExprNode
     #  step      ExprNode
-    
+
     type = py_object_type
     is_temp = 1
 
@@ -2698,7 +2706,7 @@ class SliceNode(ExprNode):
             self.compile_time_value_error(e)
 
     subexprs = ['start', 'stop', 'step']
-    
+
     def analyse_types(self, env):
         self.start.analyse_types(env)
         self.stop.analyse_types(env)
@@ -2713,8 +2721,8 @@ class SliceNode(ExprNode):
         code.putln(
             "%s = PySlice_New(%s, %s, %s); %s" % (
                 self.result(),
-                self.start.py_result(), 
-                self.stop.py_result(), 
+                self.start.py_result(),
+                self.stop.py_result(),
                 self.step.py_result(),
                 code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
@@ -2753,7 +2761,7 @@ class CallNode(ExprNode):
             self.function.set_cname(type.declaration_code(""))
             self.analyse_c_function_call(env)
             return True
-    
+
     def is_lvalue(self):
         return self.type.is_reference
 
@@ -2778,9 +2786,9 @@ class SimpleCallNode(CallNode):
     #  wrapper_call   bool                 used internally
     #  has_optional_args   bool            used internally
     #  nogil          bool                 used internally
-    
+
     subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']
-    
+
     self = None
     coerced_self = None
     arg_tuple = None
@@ -2788,7 +2796,7 @@ class SimpleCallNode(CallNode):
     has_optional_args = False
     nogil = False
     analysed = False
-    
+
     def compile_time_value(self, denv):
         function = self.function.compile_time_value(denv)
         args = [arg.compile_time_value(denv) for arg in self.args]
@@ -2796,12 +2804,12 @@ class SimpleCallNode(CallNode):
             return function(*args)
         except Exception, e:
             self.compile_time_value_error(e)
-            
+
     def type_dependencies(self, env):
         # TODO: Update when Danilo's C++ code merged in to handle the
         # the case of function overloading.
         return self.function.type_dependencies(env)
-    
+
     def infer_type(self, env):
         function = self.function
         func_type = function.infer_type(env)
@@ -2896,7 +2904,7 @@ class SimpleCallNode(CallNode):
                 # Insert coerced 'self' argument into argument list.
                 self.args.insert(0, self.coerced_self)
             self.analyse_c_function_call(env)
-    
+
     def function_type(self):
         # Return the type of the function being called, coercing a function
         # pointer to a function if necessary.
@@ -2904,7 +2912,7 @@ class SimpleCallNode(CallNode):
         if func_type.is_ptr:
             func_type = func_type.base_type
         return func_type
-    
+
     def analyse_c_function_call(self, env):
         if self.function.type is error_type:
             self.type = error_type
@@ -2945,11 +2953,23 @@ class SimpleCallNode(CallNode):
         # Coerce arguments
         for i in range(min(max_nargs, actual_nargs)):
             formal_type = func_type.args[i].type
-            self.args[i] = self.args[i].coerce_to(formal_type, env)
+            arg = self.args[i].coerce_to(formal_type, env)
+            if arg.type.is_pyobject and not env.nogil and (arg.is_attribute or not arg.is_simple):
+                # we do not own the argument's reference, but we must
+                # make sure it cannot be collected before we return
+                # from the function, so we create an owned temp
+                # reference to it
+                arg = arg.coerce_to_temp(env)
+            self.args[i] = arg
         for i in range(max_nargs, actual_nargs):
-            if self.args[i].type.is_pyobject:
-                error(self.args[i].pos, 
-                    "Python object cannot be passed as a varargs parameter")
+            arg = self.args[i]
+            if arg.type.is_pyobject:
+                arg_ctype = arg.type.default_coerced_ctype()
+                if arg_ctype is None:
+                    error(self.args[i].pos,
+                          "Python object cannot be passed as a varargs parameter")
+                else:
+                    self.args[i] = arg.coerce_to(arg_ctype, env)
         # Calc result type and code fragment
         if isinstance(self.function, NewExprNode):
             self.type = PyrexTypes.CPtrType(self.function.class_type)
@@ -2974,37 +2994,37 @@ class SimpleCallNode(CallNode):
 
     def calculate_result_code(self):
         return self.c_call_code()
-    
+
     def c_call_code(self):
         func_type = self.function_type()
         if self.type is PyrexTypes.error_type or not func_type.is_cfunction:
             return "<error>"
         formal_args = func_type.args
         arg_list_code = []
-        args = zip(formal_args, self.args)
+        args = list(zip(formal_args, self.args))
         max_nargs = len(func_type.args)
         expected_nargs = max_nargs - func_type.optional_arg_count
         actual_nargs = len(self.args)
         for formal_arg, actual_arg in args[:expected_nargs]:
                 arg_code = actual_arg.result_as(formal_arg.type)
                 arg_list_code.append(arg_code)
-                
+
         if func_type.is_overridable:
             arg_list_code.append(str(int(self.wrapper_call or self.function.entry.is_unbound_cmethod)))
-                
+
         if func_type.optional_arg_count:
             if expected_nargs == actual_nargs:
                 optional_args = 'NULL'
             else:
                 optional_args = "&%s" % self.opt_arg_struct
             arg_list_code.append(optional_args)
-            
+
         for actual_arg in self.args[len(formal_args):]:
             arg_list_code.append(actual_arg.result())
         result = "%s(%s)" % (self.function.result(),
             ', '.join(arg_list_code))
         return result
-    
+
     def generate_result_code(self, code):
         func_type = self.function_type()
         if func_type.is_pyobject:
@@ -3026,7 +3046,7 @@ class SimpleCallNode(CallNode):
                         self.opt_arg_struct,
                         Naming.pyrex_prefix + "n",
                         len(self.args) - expected_nargs))
-                args = zip(func_type.args, self.args)
+                args = list(zip(func_type.args, self.args))
                 for formal_arg, actual_arg in args[expected_nargs:actual_nargs]:
                     code.putln("%s.%s = %s;" % (
                             self.opt_arg_struct,
@@ -3043,7 +3063,7 @@ class SimpleCallNode(CallNode):
                 if exc_check:
                     if self.nogil:
                         exc_checks.append("__Pyx_ErrOccurredWithGIL()")
-                    else:    
+                    else:
                         exc_checks.append("PyErr_Occurred()")
             if self.is_temp or exc_checks:
                 rhs = self.c_call_code()
@@ -3133,9 +3153,9 @@ class GeneralCallNode(CallNode):
     #  positional_args  ExprNode          Tuple of positional arguments
     #  keyword_args     ExprNode or None  Dict of keyword arguments
     #  starstar_arg     ExprNode or None  Dict of extra keyword args
-    
+
     type = py_object_type
-    
+
     subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg']
 
     nogil_check = Node.gil_error
@@ -3150,10 +3170,10 @@ class GeneralCallNode(CallNode):
             return function(*positional_args, **keyword_args)
         except Exception, e:
             self.compile_time_value_error(e)
-            
+
     def explicit_args_kwds(self):
         if self.starstar_arg or not isinstance(self.positional_args, TupleNode):
-            raise PostParseError(self.pos,
+            raise CompileError(self.pos,
                 'Compile-time keyword arguments must be explicit.')
         return self.positional_args.args, self.keyword_args
 
@@ -3189,14 +3209,14 @@ class GeneralCallNode(CallNode):
         else:
             self.type = py_object_type
         self.is_temp = 1
-        
+
     def generate_result_code(self, code):
         if self.type.is_error: return
         kwargs_call_function = "PyEval_CallObjectWithKeywords"
         if self.keyword_args and self.starstar_arg:
-            code.put_error_if_neg(self.pos, 
+            code.put_error_if_neg(self.pos,
                 "PyDict_Update(%s, %s)" % (
-                    self.keyword_args.py_result(), 
+                    self.keyword_args.py_result(),
                     self.starstar_arg.py_result()))
             keyword_code = self.keyword_args.py_result()
         elif self.keyword_args:
@@ -3232,12 +3252,12 @@ class AsTupleNode(ExprNode):
     #  the * argument of a function call.
     #
     #  arg    ExprNode
-    
+
     subexprs = ['arg']
 
     def calculate_constant_result(self):
         self.constant_result = tuple(self.base.constant_result)
-    
+
     def compile_time_value(self, denv):
         arg = self.arg.compile_time_value(denv)
         try:
@@ -3264,7 +3284,7 @@ class AsTupleNode(ExprNode):
                 self.arg.py_result(),
                 code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
-    
+
 
 class AttributeNode(ExprNode):
     #  obj.attribute
@@ -3280,10 +3300,10 @@ class AttributeNode(ExprNode):
     #  member               string    C name of struct member
     #  is_called            boolean   Function call is being done on result
     #  entry                Entry     Symbol table entry of attribute
-    
+
     is_attribute = 1
     subexprs = ['obj']
-    
+
     type = PyrexTypes.error_type
     entry = None
     is_called = 0
@@ -3305,7 +3325,7 @@ class AttributeNode(ExprNode):
                 # must be a cpdef function
                 self.is_temp = 1
                 self.entry = entry.as_variable
-                self.analyse_as_python_attribute(env) 
+                self.analyse_as_python_attribute(env)
                 return self
         return ExprNode.coerce_to(self, dst_type, env)
 
@@ -3326,32 +3346,39 @@ class AttributeNode(ExprNode):
             return getattr(obj, attr)
         except Exception, e:
             self.compile_time_value_error(e)
-    
+
     def type_dependencies(self, env):
         return self.obj.type_dependencies(env)
-    
+
     def infer_type(self, env):
         if self.analyse_as_cimported_attribute(env, 0):
             return self.entry.type
         elif self.analyse_as_unbound_cmethod(env):
             return self.entry.type
         else:
-            self.analyse_attribute(env, obj_type = self.obj.infer_type(env))
+            obj_type = self.obj.infer_type(env)
+            self.analyse_attribute(env, obj_type = obj_type)
+            if obj_type.is_builtin_type and self.type.is_cfunction:
+                # special case: C-API replacements for C methods of
+                # builtin types cannot be inferred as C functions as
+                # that would prevent their use as bound methods
+                self.type = py_object_type
+                return py_object_type
             return self.type
 
     def analyse_target_declaration(self, env):
         pass
-    
+
     def analyse_target_types(self, env):
         self.analyse_types(env, target = 1)
-    
+
     def analyse_types(self, env, target = 0):
         if self.analyse_as_cimported_attribute(env, target):
             return
         if not target and self.analyse_as_unbound_cmethod(env):
             return
         self.analyse_as_ordinary_attribute(env, target)
-    
+
     def analyse_as_cimported_attribute(self, env, target):
         # Try to interpret this as a reference to an imported
         # C const, type, var or function. If successful, mutates
@@ -3366,7 +3393,7 @@ class AttributeNode(ExprNode):
                     self.mutate_into_name_node(env, entry, target)
                     return 1
         return 0
-    
+
     def analyse_as_unbound_cmethod(self, env):
         # Try to interpret this as a reference to an unbound
         # C method of an extension type. If successful, mutates
@@ -3387,17 +3414,17 @@ class AttributeNode(ExprNode):
                 self.mutate_into_name_node(env, ubcm_entry, None)
                 return 1
         return 0
-        
+
     def analyse_as_type(self, env):
         module_scope = self.obj.analyse_as_module(env)
         if module_scope:
             return module_scope.lookup_type(self.attribute)
         if not isinstance(self.obj, (UnicodeNode, StringNode, BytesNode)):
             base_type = self.obj.analyse_as_type(env)
-            if base_type and hasattr(base_type, 'scope'):
+            if base_type and hasattr(base_type, 'scope') and base_type.scope is not None:
                 return base_type.scope.lookup_type(self.attribute)
         return None
-    
+
     def analyse_as_extension_type(self, env):
         # Try to interpret this as a reference to an extension type
         # in a cimported module. Returns the extension type, or None.
@@ -3407,7 +3434,7 @@ class AttributeNode(ExprNode):
             if entry and entry.is_type and entry.type.is_extension_type:
                 return entry.type
         return None
-    
+
     def analyse_as_module(self, env):
         # Try to interpret this as a reference to a cimported module
         # in another cimported module. Returns the module scope, or None.
@@ -3417,7 +3444,7 @@ class AttributeNode(ExprNode):
             if entry and entry.as_module:
                 return entry.as_module
         return None
-                
+
     def mutate_into_name_node(self, env, entry, target):
         # Mutate this node into a NameNode and complete the
         # analyse_types phase.
@@ -3430,7 +3457,7 @@ class AttributeNode(ExprNode):
             NameNode.analyse_target_types(self, env)
         else:
             NameNode.analyse_rvalue_entry(self, env)
-    
+
     def analyse_as_ordinary_attribute(self, env, target):
         self.obj.analyse_types(env)
         self.analyse_attribute(env)
@@ -3444,7 +3471,9 @@ class AttributeNode(ExprNode):
             if not target:
                 self.is_temp = 1
                 self.result_ctype = py_object_type
-    
+        elif target and self.obj.type.is_builtin_type:
+            error(self.pos, "Assignment to an immutable object field")
+
     def analyse_attribute(self, env, obj_type = None):
         # Look up attribute and set self.type and self.member.
         self.is_py_attr = 0
@@ -3459,7 +3488,7 @@ class AttributeNode(ExprNode):
         if obj_type.is_ptr or obj_type.is_array:
             obj_type = obj_type.base_type
             self.op = "->"
-        elif obj_type.is_extension_type:
+        elif obj_type.is_extension_type or obj_type.is_builtin_type:
             self.op = "->"
         else:
             self.op = "."
@@ -3470,8 +3499,8 @@ class AttributeNode(ExprNode):
                 if entry and entry.is_member:
                     entry = None
             else:
-                error(self.pos, 
-                    "Cannot select attribute of incomplete type '%s'" 
+                error(self.pos,
+                    "Cannot select attribute of incomplete type '%s'"
                     % obj_type)
                 self.type = PyrexTypes.error_type
                 return
@@ -3490,7 +3519,7 @@ class AttributeNode(ExprNode):
                     # method of an extension type, so we treat it like a Python
                     # attribute.
                     pass
-        # If we get here, the base object is not a struct/union/extension 
+        # If we get here, the base object is not a struct/union/extension
         # type, or it is an extension type and the attribute is either not
         # declared or is declared as a Python method. Treat it as a Python
         # attribute reference.
@@ -3527,13 +3556,13 @@ class AttributeNode(ExprNode):
             return 1
         else:
             return NameNode.is_lvalue(self)
-    
+
     def is_ephemeral(self):
         if self.obj:
             return self.obj.is_ephemeral()
         else:
             return NameNode.is_ephemeral(self)
-    
+
     def calculate_result_code(self):
         #print "AttributeNode.calculate_result_code:", self.member ###
         #print "...obj node =", self.obj, "code", self.obj.result() ###
@@ -3544,15 +3573,18 @@ class AttributeNode(ExprNode):
         if self.entry and self.entry.is_cmethod:
             if obj.type.is_extension_type:
                 return "((struct %s *)%s%s%s)->%s" % (
-                    obj.type.vtabstruct_cname, obj_code, self.op, 
+                    obj.type.vtabstruct_cname, obj_code, self.op,
                     obj.type.vtabslot_cname, self.member)
             else:
                 return self.member
         elif obj.type.is_complex:
             return "__Pyx_C%s(%s)" % (self.member.upper(), obj_code)
         else:
+            if obj.type.is_builtin_type and self.entry and self.entry.is_variable:
+                # accessing a field of a builtin type, need to cast better than result_as() does
+                obj_code = obj.type.cast_code(obj.result(), to_object_struct = True)
             return "%s%s%s" % (obj_code, self.op, self.member)
-    
+
     def generate_result_code(self, code):
         interned_attr_cname = code.intern_identifier(self.attribute)
         if self.is_py_attr:
@@ -3570,12 +3602,12 @@ class AttributeNode(ExprNode):
                   and self.needs_none_check
                   and code.globalstate.directives['nonecheck']):
                 self.put_nonecheck(code)
-    
+
     def generate_assignment_code(self, rhs, code):
         interned_attr_cname = code.intern_identifier(self.attribute)
         self.obj.generate_evaluation_code(code)
         if self.is_py_attr:
-            code.put_error_if_neg(self.pos, 
+            code.put_error_if_neg(self.pos,
                 'PyObject_SetAttr(%s, %s, %s)' % (
                     self.obj.py_result(),
                     interned_attr_cname,
@@ -3608,12 +3640,12 @@ class AttributeNode(ExprNode):
             rhs.free_temps(code)
         self.obj.generate_disposal_code(code)
         self.obj.free_temps(code)
-    
+
     def generate_deletion_code(self, code):
         interned_attr_cname = code.intern_identifier(self.attribute)
         self.obj.generate_evaluation_code(code)
         if self.is_py_attr or (isinstance(self.entry.scope, Symtab.PropertyScope)
-                               and self.entry.scope.entries.has_key(u'__del__')):
+                               and u'__del__' in self.entry.scope.entries):
             code.put_error_if_neg(self.pos,
                 'PyObject_DelAttr(%s, %s)' % (
                     self.obj.py_result(),
@@ -3622,7 +3654,7 @@ class AttributeNode(ExprNode):
             error(self.pos, "Cannot delete C attribute of extension type")
         self.obj.generate_disposal_code(code)
         self.obj.free_temps(code)
-        
+
     def annotate(self, code):
         if self.is_py_attr:
             code.annotate(self.pos, AnnotationItem('py_attr', 'python attribute', size=len(self.attribute)))
@@ -3695,9 +3727,9 @@ class SequenceNode(ExprNode):
     #  iterator                ExprNode
     #  unpacked_items          [ExprNode] or None
     #  coerced_unpacked_items  [ExprNode] or None
-    
+
     subexprs = ['args']
-    
+
     is_sequence_constructor = 1
     unpacked_items = None
 
@@ -3754,7 +3786,7 @@ class SequenceNode(ExprNode):
 
     def generate_result_code(self, code):
         self.generate_operation_code(code)
-    
+
     def generate_assignment_code(self, rhs, code):
         if self.starred_assignment:
             self.generate_starred_assignment_code(rhs, code)
@@ -3776,8 +3808,8 @@ class SequenceNode(ExprNode):
             tuple_check = "PyTuple_CheckExact(%s)"
         code.putln(
             "if (%s && likely(PyTuple_GET_SIZE(%s) == %s)) {" % (
-                tuple_check % rhs.py_result(), 
-                rhs.py_result(), 
+                tuple_check % rhs.py_result(),
+                rhs.py_result(),
                 len(self.args)))
         code.putln("PyObject* tuple = %s;" % rhs.py_result())
         for item in self.unpacked_items:
@@ -3796,7 +3828,7 @@ class SequenceNode(ExprNode):
         for i in range(len(self.args)):
             self.args[i].generate_assignment_code(
                 self.coerced_unpacked_items[i], code)
-                 
+
         code.putln("} else {")
 
         if rhs.type is tuple_type:
@@ -3922,7 +3954,7 @@ class SequenceNode(ExprNode):
 
 class TupleNode(SequenceNode):
     #  Tuple constructor.
-    
+
     type = tuple_type
 
     gil_message = "Constructing Python tuple"
@@ -3933,10 +3965,16 @@ class TupleNode(SequenceNode):
             self.is_literal = 1
         else:
             SequenceNode.analyse_types(self, env, skip_children)
+            for child in self.args:
+                if not child.is_literal:
+                    break
+            else:
+                self.is_temp = 0
+                self.is_literal = 1
 
     def calculate_result_code(self):
         if len(self.args) > 0:
-            error(self.pos, "Positive length tuples must be constructed.")
+            return self.result_code
         else:
             return Naming.empty_tuple
 
@@ -3950,11 +3988,18 @@ class TupleNode(SequenceNode):
             return tuple(values)
         except Exception, e:
             self.compile_time_value_error(e)
-    
+
     def generate_operation_code(self, code):
         if len(self.args) == 0:
             # result_code is Naming.empty_tuple
             return
+        if self.is_literal:
+            # non-empty cached tuple => result is global constant,
+            # creation code goes into separate code writer
+            self.result_code = code.get_py_const(py_object_type, 'tuple_', cleanup_level=2)
+            code = code.get_cached_constants_writer()
+            code.mark_pos(self.pos)
+
         code.putln(
             "%s = PyTuple_New(%s); %s" % (
                 self.result(),
@@ -3971,7 +4016,9 @@ class TupleNode(SequenceNode):
                     i,
                     arg.py_result()))
             code.put_giveref(arg.py_result())
-    
+        if self.is_literal:
+            code.put_giveref(self.py_result())
+
     def generate_subexpr_disposal_code(self, code):
         # We call generate_post_assignment_code here instead
         # of generate_disposal_code, because values were stored
@@ -3984,7 +4031,7 @@ class TupleNode(SequenceNode):
 
 class ListNode(SequenceNode):
     #  List constructor.
-    
+
     # obj_conversion_errors    [PyrexError]   used internally
     # orignial_args            [ExprNode]     used internally
 
@@ -3992,10 +4039,10 @@ class ListNode(SequenceNode):
     type = list_type
 
     gil_message = "Constructing Python list"
-    
+
     def type_dependencies(self, env):
         return ()
-    
+
     def infer_type(self, env):
         # TOOD: Infer non-object list arrays.
         return list_type
@@ -4010,7 +4057,7 @@ class ListNode(SequenceNode):
         SequenceNode.analyse_types(self, env)
         self.obj_conversion_errors = held_errors()
         release_errors(ignore=True)
-        
+
     def coerce_to(self, dst_type, env):
         if dst_type.is_pyobject:
             for err in self.obj_conversion_errors:
@@ -4018,7 +4065,7 @@ class ListNode(SequenceNode):
             self.obj_conversion_errors = []
             if not self.type.subtype_of(dst_type):
                 error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
-        elif dst_type.is_ptr:
+        elif dst_type.is_ptr and dst_type.base_type is not PyrexTypes.c_void_type:
             base_type = dst_type.base_type
             self.type = PyrexTypes.CArrayType(base_type, len(self.args))
             for i in range(len(self.original_args)):
@@ -4041,11 +4088,11 @@ class ListNode(SequenceNode):
             self.type = error_type
             error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
         return self
-        
+
     def release_temp(self, env):
         if self.type.is_array:
-            # To be valid C++, we must allocate the memory on the stack 
-            # manually and be sure not to reuse it for something else. 
+            # To be valid C++, we must allocate the memory on the stack
+            # manually and be sure not to reuse it for something else.
             pass
         else:
             SequenceNode.release_temp(self, env)
@@ -4110,49 +4157,98 @@ class ScopedExprNode(ExprNode):
     subexprs = []
     expr_scope = None
 
-    def analyse_types(self, env):
-        # nothing to do here, the children will be analysed separately
-        pass
-
-    def analyse_expressions(self, env):
-        # nothing to do here, the children will be analysed separately
-        pass
+    # does this node really have a local scope, e.g. does it leak loop
+    # variables or not?  non-leaking Py3 behaviour is default, except
+    # for list comprehensions where the behaviour differs in Py2 and
+    # Py3 (set in Parsing.py based on parser context)
+    has_local_scope = True
 
-    def analyse_scoped_expressions(self, env):
+    def init_scope(self, outer_scope, expr_scope=None):
+        if expr_scope is not None:
+            self.expr_scope = expr_scope
+        elif self.has_local_scope:
+            self.expr_scope = Symtab.GeneratorExpressionScope(outer_scope)
+        else:
+            self.expr_scope = None
+
+    def analyse_declarations(self, env):
+        self.init_scope(env)
+
+    def analyse_scoped_declarations(self, env):
         # this is called with the expr_scope as env
         pass
 
-    def init_scope(self, outer_scope, expr_scope=None):
-        self.expr_scope = expr_scope
+    def analyse_types(self, env):
+        # no recursion here, the children will be analysed separately below
+        pass
+
+    def analyse_scoped_expressions(self, env):
+        # 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)
+        if not py_entries:
+            # no local Python references => no cleanup required
+            generate_inner_evaluation_code(code)
+            code.putln('} /* exit inner scope */')
+            return
+        for entry in py_entries:
+            code.put_init_var_to_py_none(entry)
+
+        # 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"]
     child_attrs = ["loop", "append"]
 
-    # leak loop variables or not?  non-leaking Py3 behaviour is
-    # default, except for list comprehensions where the behaviour
-    # differs in Py2 and Py3 (see Parsing.py)
-    has_local_scope = True
-
     def infer_type(self, env):
         return self.target.infer_type(env)
 
     def analyse_declarations(self, env):
         self.append.target = self # this is used in the PyList_Append of the inner loop
         self.init_scope(env)
-        if self.expr_scope is not None:
-            self.loop.analyse_declarations(self.expr_scope)
-        else:
-            self.loop.analyse_declarations(env)
 
-    def init_scope(self, outer_scope, expr_scope=None):
-        if expr_scope is not None:
-            self.expr_scope = expr_scope
-        elif self.has_local_scope:
-            self.expr_scope = Symtab.GeneratorExpressionScope(outer_scope)
-        else:
-            self.expr_scope = None
+    def analyse_scoped_declarations(self, env):
+        self.loop.analyse_declarations(env)
 
     def analyse_types(self, env):
         self.target.analyse_expressions(env)
@@ -4160,9 +4256,6 @@ class ComprehensionNode(ScopedExprNode):
         if not self.has_local_scope:
             self.loop.analyse_expressions(env)
 
-    def analyse_expressions(self, env):
-        self.analyse_types(env)
-
     def analyse_scoped_expressions(self, env):
         if self.has_local_scope:
             self.loop.analyse_expressions(env)
@@ -4172,7 +4265,7 @@ class ComprehensionNode(ScopedExprNode):
 
     def calculate_result_code(self):
         return self.target.result()
-    
+
     def generate_result_code(self, code):
         self.generate_operation_code(code)
 
@@ -4190,7 +4283,7 @@ class ComprehensionAppendNode(Node):
     child_attrs = ['expr']
 
     type = PyrexTypes.c_int_type
-    
+
     def analyse_expressions(self, env):
         self.expr.analyse_expressions(env)
         if not self.expr.type.is_pyobject:
@@ -4264,21 +4357,17 @@ class GeneratorExpressionNode(ScopedExprNode):
 
     type = py_object_type
 
-    def analyse_declarations(self, env):
-        self.init_scope(env)
-        self.loop.analyse_declarations(self.expr_scope)
-
-    def init_scope(self, outer_scope, expr_scope=None):
-        if expr_scope is not None:
-            self.expr_scope = expr_scope
-        else:
-            self.expr_scope = Symtab.GeneratorExpressionScope(outer_scope)
+    def analyse_scoped_declarations(self, env):
+        self.loop.analyse_declarations(env)
 
     def analyse_types(self, env):
+        if not self.has_local_scope:
+            self.loop.analyse_expressions(env)
         self.is_temp = True
 
     def analyse_scoped_expressions(self, env):
-        self.loop.analyse_expressions(env)
+        if self.has_local_scope:
+            self.loop.analyse_expressions(env)
 
     def may_be_none(self):
         return False
@@ -4298,14 +4387,29 @@ class InlinedGeneratorExpressionNode(GeneratorExpressionNode):
     # orig_func      String           the name of the builtin function this node replaces
 
     child_attrs = ["loop"]
+    loop_analysed = False
+
+    def infer_type(self, env):
+        return self.result_node.infer_type(env)
 
     def analyse_types(self, env):
+        if not self.has_local_scope:
+            self.loop_analysed = True
+            self.loop.analyse_expressions(env)
         self.type = self.result_node.type
         self.is_temp = True
 
+    def analyse_scoped_expressions(self, env):
+        self.loop_analysed = True
+        GeneratorExpressionNode.analyse_scoped_expressions(self, env)
+
     def coerce_to(self, dst_type, env):
-        if self.orig_func == 'sum' and dst_type.is_numeric:
-            # we can optimise by dropping the aggregation variable into C
+        if self.orig_func == 'sum' and dst_type.is_numeric and not self.loop_analysed:
+            # We can optimise by dropping the aggregation variable and
+            # the add operations into C.  This can only be done safely
+            # before analysing the loop body, after that, the result
+            # reference type will have infected expressions and
+            # assignments.
             self.result_node.type = self.type = dst_type
             return self
         return GeneratorExpressionNode.coerce_to(self, dst_type, env)
@@ -4323,7 +4427,7 @@ class SetNode(ExprNode):
     subexprs = ['args']
 
     gil_message = "Constructing Python set"
-    
+
     def analyse_types(self, env):
         for i in range(len(self.args)):
             arg = self.args[i]
@@ -4370,7 +4474,7 @@ class DictNode(ExprNode):
     #  key_value_pairs  [DictItemNode]
     #
     # obj_conversion_errors    [PyrexError]   used internally
-    
+
     subexprs = ['key_value_pairs']
     is_temp = 1
     type = dict_type
@@ -4380,7 +4484,7 @@ class DictNode(ExprNode):
     def calculate_constant_result(self):
         self.constant_result = dict([
                 item.constant_result for item in self.key_value_pairs])
-    
+
     def compile_time_value(self, denv):
         pairs = [(item.key.compile_time_value(denv), item.value.compile_time_value(denv))
             for item in self.key_value_pairs]
@@ -4388,10 +4492,10 @@ class DictNode(ExprNode):
             return dict(pairs)
         except Exception, e:
             self.compile_time_value_error(e)
-    
+
     def type_dependencies(self, env):
         return ()
-    
+
     def infer_type(self, env):
         # TOOD: Infer struct constructors.
         return dict_type
@@ -4405,7 +4509,7 @@ class DictNode(ExprNode):
 
     def may_be_none(self):
         return False
-        
+
     def coerce_to(self, dst_type, env):
         if dst_type.is_pyobject:
             self.release_errors()
@@ -4437,7 +4541,7 @@ class DictNode(ExprNode):
             self.type = error_type
             error(self.pos, "Cannot interpret dict as type '%s'" % dst_type)
         return self
-    
+
     def release_errors(self):
         for err in self.obj_conversion_errors:
             report_error(err)
@@ -4460,7 +4564,7 @@ class DictNode(ExprNode):
         for item in self.key_value_pairs:
             item.generate_evaluation_code(code)
             if self.type.is_pyobject:
-                code.put_error_if_neg(self.pos, 
+                code.put_error_if_neg(self.pos,
                     "PyDict_SetItem(%s, %s, %s)" % (
                         self.result(),
                         item.key.py_result(),
@@ -4472,11 +4576,11 @@ class DictNode(ExprNode):
                         item.value.result()))
             item.generate_disposal_code(code)
             item.free_temps(code)
-            
+
     def annotate(self, code):
         for item in self.key_value_pairs:
             item.annotate(code)
-            
+
 class DictItemNode(ExprNode):
     # Represents a single item in a DictNode
     #
@@ -4489,13 +4593,13 @@ class DictItemNode(ExprNode):
     def calculate_constant_result(self):
         self.constant_result = (
             self.key.constant_result, self.value.constant_result)
-            
+
     def analyse_types(self, env):
         self.key.analyse_types(env)
         self.value.analyse_types(env)
         self.key = self.key.coerce_to_pyobject(env)
         self.value = self.value.coerce_to_pyobject(env)
-        
+
     def generate_evaluation_code(self, code):
         self.key.generate_evaluation_code(code)
         self.value.generate_evaluation_code(code)
@@ -4507,7 +4611,7 @@ class DictItemNode(ExprNode):
     def free_temps(self, code):
         self.key.free_temps(code)
         self.value.free_temps(code)
-        
+
     def __iter__(self):
         return iter([self.key, self.value])
 
@@ -4529,23 +4633,14 @@ class ClassNode(ExprNode, ModuleNameMixin):
     #  dict         ExprNode           Class dict (not owned by this node)
     #  doc          ExprNode or None   Doc string
     #  module_name  EncodedString      Name of defining module
-    #  keyword_args ExprNode or None   Py3 Dict of keyword arguments, passed to __new__
-    #  starstar_arg ExprNode or None   Py3 Dict of extra keyword args, same here
-    
-    subexprs = ['bases', 'keyword_args', 'starstar_arg', 'doc']
+
+    subexprs = ['bases', 'doc']
 
     def analyse_types(self, env):
         self.bases.analyse_types(env)
         if self.doc:
             self.doc.analyse_types(env)
             self.doc = self.doc.coerce_to_pyobject(env)
-        if self.keyword_args:
-            self.keyword_args.analyse_types(env)
-        if self.starstar_arg:
-            self.starstar_arg.analyse_types(env)
-            # make sure we have a Python object as **kwargs mapping
-            self.starstar_arg = \
-                self.starstar_arg.coerce_to_pyobject(env)
         self.type = py_object_type
         self.is_temp = 1
         env.use_utility_code(create_class_utility_code);
@@ -4559,37 +4654,169 @@ class ClassNode(ExprNode, ModuleNameMixin):
 
     def generate_result_code(self, code):
         cname = code.intern_identifier(self.name)
+
+        if self.doc:
+            code.put_error_if_neg(self.pos,
+                'PyDict_SetItemString(%s, "__doc__", %s)' % (
+                    self.dict.py_result(),
+                    self.doc.py_result()))
+        py_mod_name = self.get_py_mod_name(code)
+        code.putln(
+            '%s = __Pyx_CreateClass(%s, %s, %s, %s); %s' % (
+                self.result(),
+                self.bases.py_result(),
+                self.dict.py_result(),
+                cname,
+                py_mod_name,
+                code.error_goto_if_null(self.result(), self.pos)))
+        code.put_gotref(self.py_result())
+
+
+class Py3ClassNode(ExprNode):
+    #  Helper class used in the implementation of Python3+
+    #  class definitions. Constructs a class object given
+    #  a name, tuple of bases and class dictionary.
+    #
+    #  name         EncodedString      Name of the class
+    #  dict         ExprNode           Class dict (not owned by this node)
+    #  module_name  EncodedString      Name of defining module
+
+    subexprs = []
+
+    def analyse_types(self, env):
+        self.type = py_object_type
+        self.is_temp = 1
+
+    def may_be_none(self):
+        return True
+
+    gil_message = "Constructing Python class"
+
+    def generate_result_code(self, code):
+        code.globalstate.use_utility_code(create_py3class_utility_code)
+        cname = code.intern_identifier(self.name)
+        code.putln(
+            '%s = __Pyx_Py3ClassCreate(%s, %s, %s, %s, %s); %s' % (
+                self.result(),
+                self.metaclass.result(),
+                cname,
+                self.bases.py_result(),
+                self.dict.py_result(),
+                self.mkw.py_result(),
+                code.error_goto_if_null(self.result(), self.pos)))
+        code.put_gotref(self.py_result())
+
+class KeywordArgsNode(ExprNode):
+    # Helper class for keyword arguments
+    #
+    # keyword_args ExprNode or None     Keyword arguments
+    # starstar_arg ExprNode or None     Extra arguments
+
+    subexprs = ['keyword_args', 'starstar_arg']
+
+    def analyse_types(self, env):
+        if self.keyword_args:
+            self.keyword_args.analyse_types(env)
+        if self.starstar_arg:
+            self.starstar_arg.analyse_types(env)
+            # make sure we have a Python object as **kwargs mapping
+            self.starstar_arg = \
+                self.starstar_arg.coerce_to_pyobject(env)
+        self.type = py_object_type
+        self.is_temp = 1
+
+    gil_message = "Constructing Keyword Args"
+
+    def generate_result_code(self, code):
         if self.keyword_args and self.starstar_arg:
             code.put_error_if_neg(self.pos,
                 "PyDict_Update(%s, %s)" % (
                     self.keyword_args.py_result(),
                     self.starstar_arg.py_result()))
-            keyword_code = self.keyword_args.py_result()
-        elif self.keyword_args:
-            keyword_code = self.keyword_args.py_result()
+        if self.keyword_args:
+            code.putln("%s = %s;" % (self.result(), self.keyword_args.result()))
+            code.put_incref(self.keyword_args.result(), self.keyword_args.ctype())
         elif self.starstar_arg:
-            keyword_code = self.starstar_arg.py_result()
+            code.putln(
+                "%s = PyDict_Copy(%s); %s" % (
+                    self.result(),
+                    self.starstar_arg.py_result(),
+                    code.error_goto_if_null(self.result(), self.pos)))
+            code.put_gotref(self.py_result())
         else:
-            keyword_code = 'NULL'
+            code.putln(
+                "%s = PyDict_New(); %s" % (
+                    self.result(),
+                    code.error_goto_if_null(self.result(), self.pos)))
+            code.put_gotref(self.py_result())
+
+class PyClassMetaclassNode(ExprNode):
+    # Helper class holds Python3 metaclass object
+    #
+    #  bases        ExprNode           Base class tuple (not owned by this node)
+    #  mkw          ExprNode           Class keyword arguments (not owned by this node)
 
+    subexprs = []
+
+    def analyse_types(self, env):
+        self.type = py_object_type
+        self.is_temp = True
+
+    def may_be_none(self):
+        return True
+
+    def generate_result_code(self, code):
+        code.putln(
+            "%s = __Pyx_Py3MetaclassGet(%s, %s); %s" % (
+                self.result(),
+                self.bases.result(),
+                self.mkw.result(),
+                code.error_goto_if_null(self.result(), self.pos)))
+        code.put_gotref(self.py_result())
+
+class PyClassNamespaceNode(ExprNode, ModuleNameMixin):
+    # Helper class holds Python3 namespace object
+    #
+    # All this are not owned by this node
+    #  metaclass    ExprNode           Metaclass object
+    #  bases        ExprNode           Base class tuple
+    #  mkw          ExprNode           Class keyword arguments
+    #  doc          ExprNode or None   Doc string (owned)
+
+    subexprs = ['doc']
+
+    def analyse_types(self, env):
+        self.bases.analyse_types(env)
         if self.doc:
-            code.put_error_if_neg(self.pos, 
-                'PyDict_SetItemString(%s, "__doc__", %s)' % (
-                    self.dict.py_result(),
-                    self.doc.py_result()))
+            self.doc.analyse_types(env)
+            self.doc = self.doc.coerce_to_pyobject(env)
+        self.type = py_object_type
+        self.is_temp = 1
+        #TODO(craig,haoyu) This should be moved to a better place
+        self.set_mod_name(env)
+
+    def may_be_none(self):
+        return True
+
+    def generate_result_code(self, code):
+        cname = code.intern_identifier(self.name)
         py_mod_name = self.get_py_mod_name(code)
+        if self.doc:
+            doc_code = self.doc.result()
+        else:
+            doc_code = '(PyObject *) NULL'
         code.putln(
-            '%s = __Pyx_CreateClass(%s, %s, %s, %s, %s); %s' % (
+            "%s = __Pyx_Py3MetaclassPrepare(%s, %s, %s, %s, %s, %s); %s" % (
                 self.result(),
-                self.bases.py_result(),
-                self.dict.py_result(),
+                self.metaclass.result(),
+                self.bases.result(),
                 cname,
+                self.mkw.result(),
                 py_mod_name,
-                keyword_code,
+                doc_code,
                 code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
 
-
 class BoundMethodNode(ExprNode):
     #  Helper class used in the implementation of Python
     #  class definitions. Constructs an bound method
@@ -4597,9 +4824,9 @@ class BoundMethodNode(ExprNode):
     #
     #  function      ExprNode   Function object
     #  self_object   ExprNode   self object
-    
+
     subexprs = ['function']
-    
+
     def analyse_types(self, env):
         self.function.analyse_types(env)
         self.type = py_object_type
@@ -4623,12 +4850,12 @@ class UnboundMethodNode(ExprNode):
     #  object from a class and a function.
     #
     #  function      ExprNode   Function object
-    
+
     type = py_object_type
     is_temp = 1
-    
+
     subexprs = ['function']
-    
+
     def analyse_types(self, env):
         self.function.analyse_types(env)
 
@@ -4661,10 +4888,10 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
     subexprs = []
     self_object = None
     binding = False
-    
+
     type = py_object_type
     is_temp = 1
-    
+
     def analyse_types(self, env):
         if self.binding:
             env.use_utility_code(binding_cfunc_utility_code)
@@ -4674,7 +4901,7 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
 
     def may_be_none(self):
         return False
-    
+
     gil_message = "Constructing Python function"
 
     def self_result_code(self):
@@ -4703,10 +4930,14 @@ class PyCFunctionNode(ExprNode, ModuleNameMixin):
 class InnerFunctionNode(PyCFunctionNode):
     # Special PyCFunctionNode that depends on a closure class
     #
+
     binding = True
-    
+    needs_self_code = True
+
     def self_result_code(self):
-        return "((PyObject*)%s)" % Naming.cur_scope_cname
+        if self.needs_self_code:
+            return "((PyObject*)%s)" % (Naming.cur_scope_cname)
+        return "NULL"
 
 class LambdaNode(InnerFunctionNode):
     # Lambda expression node (only used as a function reference)
@@ -4724,7 +4955,6 @@ class LambdaNode(InnerFunctionNode):
     name = StringEncoding.EncodedString('<lambda>')
 
     def analyse_declarations(self, env):
-        #self.def_node.needs_closure = self.needs_closure
         self.def_node.analyse_declarations(env)
         self.pymethdef_cname = self.def_node.entry.pymethdef_cname
         env.add_lambda_def(self.def_node)
@@ -4780,14 +5010,14 @@ class UnopNode(ExprNode):
     #      - Check operand type and coerce if needed.
     #      - Determine result type and result code fragment.
     #      - Allocate temporary for result if needed.
-    
+
     subexprs = ['operand']
     infix = True
 
     def calculate_constant_result(self):
         func = compile_time_unary_operators[self.operator]
         self.constant_result = func(self.operand.constant_result)
-    
+
     def compile_time_value(self, denv):
         func = compile_time_unary_operators.get(self.operator)
         if not func:
@@ -4799,7 +5029,7 @@ class UnopNode(ExprNode):
             return func(operand)
         except Exception, e:
             self.compile_time_value_error(e)
-    
+
     def infer_type(self, env):
         operand_type = self.operand.infer_type(env)
         if operand_type.is_pyobject:
@@ -4817,10 +5047,10 @@ class UnopNode(ExprNode):
             self.analyse_cpp_operation(env)
         else:
             self.analyse_c_operation(env)
-    
+
     def check_const(self):
         return self.operand.check_const()
-    
+
     def is_py_operation(self):
         return self.operand.type.is_pyobject
 
@@ -4831,24 +5061,24 @@ class UnopNode(ExprNode):
     def is_cpp_operation(self):
         type = self.operand.type
         return type.is_cpp_class
-    
+
     def coerce_operand_to_pyobject(self, env):
         self.operand = self.operand.coerce_to_pyobject(env)
-    
+
     def generate_result_code(self, code):
         if self.operand.type.is_pyobject:
             self.generate_py_operation_code(code)
-    
+
     def generate_py_operation_code(self, code):
         function = self.py_operation_function()
         code.putln(
             "%s = %s(%s); %s" % (
-                self.result(), 
-                function, 
+                self.result(),
+                function,
                 self.operand.py_result(),
                 code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
-        
+
     def type_error(self):
         if not self.operand.type.is_error:
             error(self.pos, "Invalid operand type for '%s' (%s)" %
@@ -4875,11 +5105,11 @@ class NotNode(ExprNode):
     #  'not' operator
     #
     #  operand   ExprNode
-    
+
     type = PyrexTypes.c_bint_type
 
     subexprs = ['operand']
-    
+
     def calculate_constant_result(self):
         self.constant_result = not self.operand.constant_result
 
@@ -4892,29 +5122,29 @@ class NotNode(ExprNode):
 
     def infer_type(self, env):
         return PyrexTypes.c_bint_type
-    
+
     def analyse_types(self, env):
         self.operand.analyse_types(env)
         self.operand = self.operand.coerce_to_boolean(env)
-    
+
     def calculate_result_code(self):
         return "(!%s)" % self.operand.result()
-    
+
     def generate_result_code(self, code):
         pass
 
 
 class UnaryPlusNode(UnopNode):
     #  unary '+' operator
-    
+
     operator = '+'
-    
+
     def analyse_c_operation(self, env):
         self.type = self.operand.type
-    
+
     def py_operation_function(self):
         return "PyNumber_Positive"
-    
+
     def calculate_result_code(self):
         if self.is_cpp_operation():
             return "(+%s)" % self.operand.result()
@@ -4924,9 +5154,9 @@ class UnaryPlusNode(UnopNode):
 
 class UnaryMinusNode(UnopNode):
     #  unary '-' operator
-    
+
     operator = '-'
-    
+
     def analyse_c_operation(self, env):
         if self.operand.type.is_numeric:
             self.type = self.operand.type
@@ -4934,10 +5164,10 @@ class UnaryMinusNode(UnopNode):
             self.type_error()
         if self.type.is_complex:
             self.infix = False
-    
+
     def py_operation_function(self):
         return "PyNumber_Negative"
-    
+
     def calculate_result_code(self):
         if self.infix:
             return "(-%s)" % self.operand.result()
@@ -4960,7 +5190,7 @@ class TildeNode(UnopNode):
 
     def py_operation_function(self):
         return "PyNumber_Invert"
-    
+
     def calculate_result_code(self):
         return "(~%s)" % self.operand.result()
 
@@ -4974,7 +5204,7 @@ class DereferenceNode(CUnopNode):
     #  unary * operator
 
     operator = '*'
-    
+
     def analyse_c_operation(self, env):
         if self.operand.type.is_ptr:
             self.type = self.operand.type.base_type
@@ -4987,7 +5217,7 @@ class DereferenceNode(CUnopNode):
 
 class DecrementIncrementNode(CUnopNode):
     #  unary ++/-- operator
-    
+
     def analyse_c_operation(self, env):
         if self.operand.type.is_ptr or self.operand.type.is_numeric:
             self.type = self.operand.type
@@ -5008,9 +5238,9 @@ class AmpersandNode(ExprNode):
     #  The C address-of operator.
     #
     #  operand  ExprNode
-    
+
     subexprs = ['operand']
-    
+
     def infer_type(self, env):
         return PyrexTypes.c_ptr_type(self.operand.infer_type(env))
 
@@ -5024,21 +5254,21 @@ class AmpersandNode(ExprNode):
             self.error("Cannot take address of Python variable")
             return
         self.type = PyrexTypes.c_ptr_type(argtype)
-    
+
     def check_const(self):
         return self.operand.check_const_addr()
-    
+
     def error(self, mess):
         error(self.pos, mess)
         self.type = PyrexTypes.error_type
         self.result_code = "<error>"
-    
+
     def calculate_result_code(self):
         return "(&%s)" % self.operand.result()
 
     def generate_result_code(self, code):
         pass
-    
+
 
 unop_node_classes = {
     "+":  UnaryPlusNode,
@@ -5047,14 +5277,14 @@ unop_node_classes = {
 }
 
 def unop_node(pos, operator, operand):
-    # Construct unnop node of appropriate class for 
+    # Construct unnop node of appropriate class for
     # given operator.
     if isinstance(operand, IntNode) and operator == '-':
         return IntNode(pos = operand.pos, value = str(-Utils.str_to_number(operand.value)))
     elif isinstance(operand, UnopNode) and operand.operator == operator:
         warning(pos, "Python has no increment/decrement operator: %s%sx = %s(%sx) = x" % ((operator,)*4), 5)
-    return unop_node_classes[operator](pos, 
-        operator = operator, 
+    return unop_node_classes[operator](pos,
+        operator = operator,
         operand = operand)
 
 
@@ -5067,19 +5297,19 @@ class TypecastNode(ExprNode):
     #
     #  If used from a transform, one can if wanted specify the attribute
     #  "type" directly and leave base_type and declarator to None
-    
+
     subexprs = ['operand']
     base_type = declarator = type = None
-    
+
     def type_dependencies(self, env):
         return ()
-    
+
     def infer_type(self, env):
         if self.type is None:
             base_type = self.base_type.analyse(env)
             _, self.type = self.declarator.analyse(base_type, env)
         return self.type
-    
+
     def analyse_types(self, env):
         if self.type is None:
             base_type = self.base_type.analyse(env)
@@ -5107,7 +5337,7 @@ class TypecastNode(ExprNode):
                     if not (self.operand.type.base_type.is_void or self.operand.type.base_type.is_struct):
                         error(self.pos, "Python objects cannot be cast from pointers of primitive types")
                 else:
-                    # Should this be an error? 
+                    # Should this be an error?
                     warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type))
                 self.operand = self.operand.coerce_to_simple(env)
         elif from_py and not to_py:
@@ -5135,7 +5365,7 @@ class TypecastNode(ExprNode):
         # we usually do not know the result of a type cast at code
         # generation time
         pass
-    
+
     def calculate_result_code(self):
         if self.type.is_complex:
             operand_result = self.operand.result()
@@ -5148,15 +5378,15 @@ class TypecastNode(ExprNode):
             return "%s(%s, %s)" % (
                     self.type.from_parts,
                     real_part,
-                    imag_part)    
+                    imag_part)
         else:
             return self.type.cast_code(self.operand.result())
-    
+
     def get_constant_c_result_code(self):
         operand_result = self.operand.get_constant_c_result_code()
         if operand_result:
             return self.type.cast_code(operand_result)
-    
+
     def result_as(self, type):
         if self.type.is_pyobject and not self.is_temp:
             #  Optimise away some unnecessary casting
@@ -5175,7 +5405,7 @@ class TypecastNode(ExprNode):
 
 class SizeofNode(ExprNode):
     #  Abstract base class for sizeof(x) expression nodes.
-    
+
     type = PyrexTypes.c_size_t_type
 
     def check_const(self):
@@ -5190,10 +5420,10 @@ class SizeofTypeNode(SizeofNode):
     #
     #  base_type   CBaseTypeNode
     #  declarator  CDeclaratorNode
-    
+
     subexprs = []
     arg_type = None
-    
+
     def analyse_types(self, env):
         # we may have incorrectly interpreted a dotted name as a type rather than an attribute
         # this could be better handled by more uniformly treating types as runtime-available objects
@@ -5214,7 +5444,7 @@ class SizeofTypeNode(SizeofNode):
             _, arg_type = self.declarator.analyse(base_type, env)
             self.arg_type = arg_type
         self.check_type()
-        
+
     def check_type(self):
         arg_type = self.arg_type
         if arg_type.is_pyobject and not arg_type.is_extension_type:
@@ -5223,7 +5453,7 @@ class SizeofTypeNode(SizeofNode):
             error(self.pos, "Cannot take sizeof void")
         elif not arg_type.is_complete():
             error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type)
-        
+
     def calculate_result_code(self):
         if self.arg_type.is_extension_type:
             # the size of the pointer is boring
@@ -5232,15 +5462,15 @@ class SizeofTypeNode(SizeofNode):
         else:
             arg_code = self.arg_type.declaration_code("")
         return "(sizeof(%s))" % arg_code
-    
+
 
 class SizeofVarNode(SizeofNode):
     #  C sizeof function applied to a variable
     #
     #  operand   ExprNode
-    
+
     subexprs = ['operand']
-    
+
     def analyse_types(self, env):
         # We may actually be looking at a type rather than a variable...
         # If we are, traditional analysis would fail...
@@ -5251,10 +5481,10 @@ class SizeofVarNode(SizeofNode):
             self.check_type()
         else:
             self.operand.analyse_types(env)
-    
+
     def calculate_result_code(self):
         return "(sizeof(%s))" % self.operand.result()
-    
+
     def generate_result_code(self, code):
         pass
 
@@ -5263,12 +5493,12 @@ class TypeofNode(ExprNode):
     #
     #  operand   ExprNode
     #  literal   StringNode # internal
-    
+
     literal = None
     type = py_object_type
-    
+
     subexprs = ['literal'] # 'operand' will be ignored after type analysis!
-    
+
     def analyse_types(self, env):
         self.operand.analyse_types(env)
         self.literal = StringNode(
@@ -5281,7 +5511,7 @@ class TypeofNode(ExprNode):
 
     def generate_evaluation_code(self, code):
         self.literal.generate_evaluation_code(code)
-    
+
     def calculate_result_code(self):
         return self.literal.calculate_result_code()
 
@@ -5339,7 +5569,7 @@ class BinopNode(ExprNode):
     #      - Check operand types and coerce if needed.
     #      - Determine result type and result code fragment.
     #      - Allocate temporary for result if needed.
-    
+
     subexprs = ['operand1', 'operand2']
     inplace = False
 
@@ -5357,16 +5587,16 @@ class BinopNode(ExprNode):
             return func(operand1, operand2)
         except Exception, e:
             self.compile_time_value_error(e)
-    
+
     def infer_type(self, env):
         return self.result_type(self.operand1.infer_type(env),
                                 self.operand2.infer_type(env))
-    
+
     def analyse_types(self, env):
         self.operand1.analyse_types(env)
         self.operand2.analyse_types(env)
         self.analyse_operation(env)
-    
+
     def analyse_operation(self, env):
         if self.is_py_operation():
             self.coerce_operands_to_pyobjects(env)
@@ -5378,17 +5608,17 @@ class BinopNode(ExprNode):
             self.analyse_cpp_operation(env)
         else:
             self.analyse_c_operation(env)
-    
+
     def is_py_operation(self):
         return self.is_py_operation_types(self.operand1.type, self.operand2.type)
-    
+
     def is_py_operation_types(self, type1, type2):
         return type1.is_pyobject or type2.is_pyobject
 
     def is_cpp_operation(self):
         return (self.operand1.type.is_cpp_class
             or self.operand2.type.is_cpp_class)
-    
+
     def analyse_cpp_operation(self, env):
         type1 = self.operand1.type
         type2 = self.operand2.type
@@ -5405,7 +5635,7 @@ class BinopNode(ExprNode):
             self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env)
             self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env)
         self.type = func_type.return_type
-    
+
     def result_type(self, type1, type2):
         if self.is_py_operation_types(type1, type2):
             if type2.is_string:
@@ -5439,14 +5669,14 @@ class BinopNode(ExprNode):
     def nogil_check(self, env):
         if self.is_py_operation():
             self.gil_error()
-        
+
     def coerce_operands_to_pyobjects(self, env):
         self.operand1 = self.operand1.coerce_to_pyobject(env)
         self.operand2 = self.operand2.coerce_to_pyobject(env)
-    
+
     def check_const(self):
         return self.operand1.check_const() and self.operand2.check_const()
-    
+
     def generate_result_code(self, code):
         #print "BinopNode.generate_result_code:", self.operand1, self.operand2 ###
         if self.operand1.type.is_pyobject:
@@ -5457,37 +5687,37 @@ class BinopNode(ExprNode):
                 extra_args = ""
             code.putln(
                 "%s = %s(%s, %s%s); %s" % (
-                    self.result(), 
-                    function, 
+                    self.result(),
+                    function,
                     self.operand1.py_result(),
                     self.operand2.py_result(),
                     extra_args,
                     code.error_goto_if_null(self.result(), self.pos)))
             code.put_gotref(self.py_result())
-    
+
     def type_error(self):
         if not (self.operand1.type.is_error
                 or self.operand2.type.is_error):
             error(self.pos, "Invalid operand types for '%s' (%s; %s)" %
-                (self.operator, self.operand1.type, 
+                (self.operator, self.operand1.type,
                     self.operand2.type))
         self.type = PyrexTypes.error_type
 
 
 class CBinopNode(BinopNode):
-    
+
     def analyse_types(self, env):
         BinopNode.analyse_types(self, env)
         if self.is_py_operation():
             self.type = PyrexTypes.error_type
-    
+
     def py_operation_function():
         return ""
-        
+
     def calculate_result_code(self):
         return "(%s %s %s)" % (
-            self.operand1.result(), 
-            self.operator, 
+            self.operand1.result(),
+            self.operator,
             self.operand2.result())
 
 
@@ -5498,9 +5728,9 @@ def c_binop_constructor(operator):
 
 class NumBinopNode(BinopNode):
     #  Binary operation taking numeric arguments.
-    
+
     infix = True
-    
+
     def analyse_c_operation(self, env):
         type1 = self.operand1.type
         type2 = self.operand2.type
@@ -5513,10 +5743,15 @@ class NumBinopNode(BinopNode):
         if not self.infix or (type1.is_numeric and type2.is_numeric):
             self.operand1 = self.operand1.coerce_to(self.type, env)
             self.operand2 = self.operand2.coerce_to(self.type, env)
-    
+
     def compute_c_result_type(self, type1, type2):
         if self.c_types_okay(type1, type2):
-            return PyrexTypes.widest_numeric_type(type1, type2)
+            widest_type = PyrexTypes.widest_numeric_type(type1, type2)
+            if widest_type is PyrexTypes.c_bint_type:
+                if self.operator not in '|^&':
+                    # False + False == 0 # not False!
+                    widest_type = PyrexTypes.c_int_type
+            return widest_type
         else:
             return None
 
@@ -5527,7 +5762,7 @@ class NumBinopNode(BinopNode):
             return "(%s %s %s)" % (value1, self.operator, value2)
         else:
             return None
-    
+
     def c_types_okay(self, type1, type2):
         #print "NumBinopNode.c_types_okay:", type1, type2 ###
         return (type1.is_numeric  or type1.is_enum) \
@@ -5536,8 +5771,8 @@ class NumBinopNode(BinopNode):
     def calculate_result_code(self):
         if self.infix:
             return "(%s %s %s)" % (
-                self.operand1.result(), 
-                self.operator, 
+                self.operand1.result(),
+                self.operator,
                 self.operand2.result())
         else:
             func = self.type.binary_op(self.operator)
@@ -5547,12 +5782,12 @@ class NumBinopNode(BinopNode):
                 func,
                 self.operand1.result(),
                 self.operand2.result())
-    
+
     def is_py_operation_types(self, type1, type2):
         return (type1 is PyrexTypes.c_py_unicode_type or
                 type2 is PyrexTypes.c_py_unicode_type or
                 BinopNode.is_py_operation_types(self, type1, type2))
-    
+
     def py_operation_function(self):
         fuction = self.py_functions[self.operator]
         if self.inplace:
@@ -5576,16 +5811,16 @@ class NumBinopNode(BinopNode):
 
 class IntBinopNode(NumBinopNode):
     #  Binary operation taking integer arguments.
-    
+
     def c_types_okay(self, type1, type2):
         #print "IntBinopNode.c_types_okay:", type1, type2 ###
         return (type1.is_int or type1.is_enum) \
             and (type2.is_int or type2.is_enum)
 
-    
+
 class AddNode(NumBinopNode):
     #  '+' operator.
-    
+
     def is_py_operation_types(self, type1, type2):
         if type1.is_string and type2.is_string:
             return 1
@@ -5605,7 +5840,7 @@ class AddNode(NumBinopNode):
 
 class SubNode(NumBinopNode):
     #  '-' operator.
-    
+
     def compute_c_result_type(self, type1, type2):
         if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
             return type1
@@ -5618,7 +5853,7 @@ class SubNode(NumBinopNode):
 
 class MulNode(NumBinopNode):
     #  '*' operator.
-    
+
     def is_py_operation_types(self, type1, type2):
         if (type1.is_string and type2.is_int) \
             or (type2.is_string and type1.is_int):
@@ -5629,7 +5864,7 @@ class MulNode(NumBinopNode):
 
 class DivNode(NumBinopNode):
     #  '/' or '//' operator.
-    
+
     cdivision = None
     truedivision = None   # == "unknown" if operator == '/'
     ctruedivision = False
@@ -5699,14 +5934,14 @@ class DivNode(NumBinopNode):
     def generate_evaluation_code(self, code):
         if not self.type.is_pyobject and not self.type.is_complex:
             if self.cdivision is None:
-                self.cdivision = (code.globalstate.directives['cdivision'] 
+                self.cdivision = (code.globalstate.directives['cdivision']
                                     or not self.type.signed
                                     or self.type.is_float)
             if not self.cdivision:
                 code.globalstate.use_utility_code(div_int_utility_code.specialize(self.type))
         NumBinopNode.generate_evaluation_code(self, code)
         self.generate_div_warning_code(code)
-    
+
     def generate_div_warning_code(self, code):
         if not self.type.is_pyobject:
             if self.zerodivision_check:
@@ -5721,7 +5956,7 @@ class DivNode(NumBinopNode):
                 if self.type.is_int and self.type.signed and self.operator != '%':
                     code.globalstate.use_utility_code(division_overflow_test_code)
                     code.putln("else if (sizeof(%s) == sizeof(long) && unlikely(%s == -1) && unlikely(UNARY_NEG_WOULD_OVERFLOW(%s))) {" % (
-                                    self.type.declaration_code(''), 
+                                    self.type.declaration_code(''),
                                     self.operand2.result(),
                                     self.operand1.result()))
                     code.putln('PyErr_Format(PyExc_OverflowError, "value too large to perform division");')
@@ -5736,7 +5971,7 @@ class DivNode(NumBinopNode):
                 code.put("if (__Pyx_cdivision_warning()) ")
                 code.put_goto(code.error_label)
                 code.putln("}")
-    
+
     def calculate_result_code(self):
         if self.type.is_complex:
             return NumBinopNode.calculate_result_code(self)
@@ -5756,7 +5991,7 @@ class DivNode(NumBinopNode):
         else:
             return "__Pyx_div_%s(%s, %s)" % (
                     self.type.specialization_name(),
-                    self.operand1.result(), 
+                    self.operand1.result(),
                     self.operand2.result())
 
 
@@ -5773,7 +6008,7 @@ class ModNode(DivNode):
             return "integer division or modulo by zero"
         else:
             return "float divmod()"
-    
+
     def generate_evaluation_code(self, code):
         if not self.type.is_pyobject:
             if self.cdivision is None:
@@ -5786,27 +6021,27 @@ class ModNode(DivNode):
                         mod_float_utility_code.specialize(self.type, math_h_modifier=self.type.math_h_modifier))
         NumBinopNode.generate_evaluation_code(self, code)
         self.generate_div_warning_code(code)
-    
+
     def calculate_result_code(self):
         if self.cdivision:
             if self.type.is_float:
                 return "fmod%s(%s, %s)" % (
                     self.type.math_h_modifier,
-                    self.operand1.result(), 
+                    self.operand1.result(),
                     self.operand2.result())
             else:
                 return "(%s %% %s)" % (
-                    self.operand1.result(), 
+                    self.operand1.result(),
                     self.operand2.result())
         else:
             return "__Pyx_mod_%s(%s, %s)" % (
                     self.type.specialization_name(),
-                    self.operand1.result(), 
+                    self.operand1.result(),
                     self.operand2.result())
 
 class PowNode(NumBinopNode):
     #  '**' operator.
-    
+
     def analyse_c_operation(self, env):
         NumBinopNode.analyse_c_operation(self, env)
         if self.type.is_complex:
@@ -5822,7 +6057,7 @@ class PowNode(NumBinopNode):
         else:
             self.pow_func = "__Pyx_pow_%s" % self.type.declaration_code('').replace(' ', '_')
             env.use_utility_code(
-                    int_pow_utility_code.specialize(func_name=self.pow_func, 
+                    int_pow_utility_code.specialize(func_name=self.pow_func,
                                                 type=self.type.declaration_code('')))
 
     def calculate_result_code(self):
@@ -5833,8 +6068,8 @@ class PowNode(NumBinopNode):
             else:
                 return self.type.cast_code(operand.result())
         return "%s(%s, %s)" % (
-            self.pow_func, 
-            typecast(self.operand1), 
+            self.pow_func,
+            typecast(self.operand1),
             typecast(self.operand2))
 
 
@@ -5850,9 +6085,9 @@ class BoolBinopNode(ExprNode):
     #  operator     string
     #  operand1     ExprNode
     #  operand2     ExprNode
-    
+
     subexprs = ['operand1', 'operand2']
-    
+
     def infer_type(self, env):
         type1 = self.operand1.infer_type(env)
         type2 = self.operand2.infer_type(env)
@@ -5873,7 +6108,7 @@ class BoolBinopNode(ExprNode):
             self.constant_result = \
                 self.operand1.constant_result or \
                 self.operand2.constant_result
-    
+
     def compile_time_value(self, denv):
         if self.operator == 'and':
             return self.operand1.compile_time_value(denv) \
@@ -5881,7 +6116,7 @@ class BoolBinopNode(ExprNode):
         else:
             return self.operand1.compile_time_value(denv) \
                 or self.operand2.compile_time_value(denv)
-    
+
     def coerce_to_boolean(self, env):
         return BoolBinopNode(
             self.pos,
@@ -5897,7 +6132,7 @@ class BoolBinopNode(ExprNode):
         self.type = PyrexTypes.independent_spanning_type(self.operand1.type, self.operand2.type)
         self.operand1 = self.operand1.coerce_to(self.type, env)
         self.operand2 = self.operand2.coerce_to(self.type, env)
-        
+
         # For what we're about to do, it's vital that
         # both operands be temp nodes.
         self.operand1 = self.operand1.coerce_to_simple(env)
@@ -5908,7 +6143,7 @@ class BoolBinopNode(ExprNode):
 
     def check_const(self):
         return self.operand1.check_const() and self.operand2.check_const()
-    
+
     def generate_evaluation_code(self, code):
         code.mark_pos(self.pos)
         self.operand1.generate_evaluation_code(code)
@@ -5936,7 +6171,7 @@ class BoolBinopNode(ExprNode):
         self.operand1.generate_post_assignment_code(code)
         self.operand1.free_temps(code)
         code.putln("}")
-    
+
     def generate_operand1_test(self, code):
         #  Generate code to test the truth of the first operand.
         if self.type.is_pyobject:
@@ -5958,15 +6193,15 @@ class CondExprNode(ExprNode):
     #  test        ExprNode
     #  true_val    ExprNode
     #  false_val   ExprNode
-    
+
     true_val = None
     false_val = None
-    
+
     subexprs = ['test', 'true_val', 'false_val']
-    
+
     def type_dependencies(self, env):
         return self.true_val.type_dependencies(env) + self.false_val.type_dependencies(env)
-    
+
     def infer_type(self, env):
         return PyrexTypes.independent_spanning_type(self.true_val.infer_type(env),
                                                     self.false_val.infer_type(env))
@@ -5989,22 +6224,22 @@ class CondExprNode(ExprNode):
         self.is_temp = 1
         if self.type == PyrexTypes.error_type:
             self.type_error()
-        
+
     def type_error(self):
         if not (self.true_val.type.is_error or self.false_val.type.is_error):
             error(self.pos, "Incompatable types in conditional expression (%s; %s)" %
                 (self.true_val.type, self.false_val.type))
         self.type = PyrexTypes.error_type
-    
+
     def check_const(self):
-        return (self.test.check_const() 
+        return (self.test.check_const()
             and self.true_val.check_const()
             and self.false_val.check_const())
-    
+
     def generate_evaluation_code(self, code):
         # Because subexprs may not be evaluated we can use a more optimal
         # subexpr allocation strategy than the default, so override evaluation_code.
-        
+
         code.mark_pos(self.pos)
         self.allocate_temp_result(code)
         self.test.generate_evaluation_code(code)
@@ -6209,7 +6444,7 @@ class CmpNode(object):
                  and (self.operand2.type.is_string or self.operand2.type is bytes_type)) or
                 (self.operand1.type is PyrexTypes.c_py_unicode_type
                  and self.operand2.type is unicode_type))
-    
+
     def is_ptr_contains(self):
         if self.operator in ('in', 'not_in'):
             container_type = self.operand2.type
@@ -6226,15 +6461,15 @@ class CmpNode(object):
                     return True
         return False
 
-    def generate_operation_code(self, code, result_code, 
+    def generate_operation_code(self, code, result_code,
             operand1, op , operand2):
         if self.type.is_pyobject:
             coerce_result = "__Pyx_PyBool_FromLong"
         else:
             coerce_result = ""
-        if 'not' in op: 
+        if 'not' in op:
             negation = "!"
-        else: 
+        else:
             negation = ""
         if self.special_bool_cmp_function:
             if operand1.type.is_pyobject:
@@ -6274,30 +6509,30 @@ class CmpNode(object):
                     coerce_result,
                     negation,
                     method,
-                    operand2.py_result(), 
-                    operand1.py_result(), 
+                    operand2.py_result(),
+                    operand1.py_result(),
                     got_ref,
                     error_clause(result_code, self.pos)))
         elif (operand1.type.is_pyobject
             and op not in ('is', 'is_not')):
                 code.putln("%s = PyObject_RichCompare(%s, %s, %s); %s" % (
-                        result_code, 
-                        operand1.py_result(), 
-                        operand2.py_result(), 
+                        result_code,
+                        operand1.py_result(),
+                        operand2.py_result(),
                         richcmp_constants[op],
                         code.error_goto_if_null(result_code, self.pos)))
                 code.put_gotref(result_code)
         elif operand1.type.is_complex:
-            if op == "!=": 
+            if op == "!=":
                 negation = "!"
-            else: 
+            else:
                 negation = ""
             code.putln("%s = %s(%s%s(%s, %s));" % (
-                result_code, 
+                result_code,
                 coerce_result,
                 negation,
-                operand1.type.unary_op('eq'), 
-                operand1.result(), 
+                operand1.type.unary_op('eq'),
+                operand1.result(),
                 operand2.result()))
         else:
             type1 = operand1.type
@@ -6312,10 +6547,10 @@ class CmpNode(object):
             code1 = operand1.result_as(common_type)
             code2 = operand2.result_as(common_type)
             code.putln("%s = %s(%s %s %s);" % (
-                result_code, 
-                coerce_result, 
-                code1, 
-                self.c_operator(op), 
+                result_code,
+                coerce_result,
+                code1,
+                self.c_operator(op),
                 code2))
 
     def c_operator(self, op):
@@ -6325,7 +6560,7 @@ class CmpNode(object):
             return "!="
         else:
             return op
-    
+
 contains_utility_code = UtilityCode(
 proto="""
 static CYTHON_INLINE long __Pyx_NegateNonNeg(long b) { return unlikely(b < 0) ? b : !b; }
@@ -6415,14 +6650,14 @@ class PrimaryCmpNode(ExprNode, CmpNode):
     #  operand1      ExprNode
     #  operand2      ExprNode
     #  cascade       CascadedCmpNode
-    
+
     #  We don't use the subexprs mechanism, because
     #  things here are too complicated for it to handle.
     #  Instead, we override all the framework methods
     #  which use it.
-    
+
     child_attrs = ['operand1', 'operand2', 'cascade']
-    
+
     cascade = None
 
     def infer_type(self, env):
@@ -6434,7 +6669,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
 
     def calculate_constant_result(self):
         self.calculate_cascaded_constant_result(self.operand1.constant_result)
-    
+
     def compile_time_value(self, denv):
         operand1 = self.operand1.compile_time_value(denv)
         return self.cascaded_compile_time_value(operand1, denv)
@@ -6504,7 +6739,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
             cdr = cdr.cascade
         if self.is_pycmp or self.cascade:
             self.is_temp = 1
-    
+
     def analyse_cpp_comparison(self, env):
         type1 = self.operand1.type
         type2 = self.operand2.type
@@ -6524,11 +6759,11 @@ class PrimaryCmpNode(ExprNode, CmpNode):
             self.operand1 = self.operand1.coerce_to(func_type.args[0].type, env)
             self.operand2 = self.operand2.coerce_to(func_type.args[1].type, env)
         self.type = func_type.return_type
-    
+
     def has_python_operands(self):
         return (self.operand1.type.is_pyobject
             or self.operand2.type.is_pyobject)
-    
+
     def check_const(self):
         if self.cascade:
             self.not_const()
@@ -6544,8 +6779,8 @@ class PrimaryCmpNode(ExprNode, CmpNode):
                 negation = ""
             return "(%s%s(%s, %s))" % (
                 negation,
-                self.operand1.type.binary_op('=='), 
-                self.operand1.result(), 
+                self.operand1.type.binary_op('=='),
+                self.operand1.result(),
                 self.operand2.result())
         elif self.is_c_string_contains():
             if self.operand2.type is bytes_type:
@@ -6559,7 +6794,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
             return "(%s%s(%s, %s))" % (
                 negation,
                 method,
-                self.operand2.result(), 
+                self.operand2.result(),
                 self.operand1.result())
         else:
             return "(%s %s %s)" % (
@@ -6572,7 +6807,7 @@ class PrimaryCmpNode(ExprNode, CmpNode):
         self.operand2.generate_evaluation_code(code)
         if self.is_temp:
             self.allocate_temp_result(code)
-            self.generate_operation_code(code, self.result(), 
+            self.generate_operation_code(code, self.result(),
                 self.operand1, self.operator, self.operand2)
             if self.cascade:
                 self.cascade.generate_evaluation_code(code,
@@ -6587,13 +6822,13 @@ class PrimaryCmpNode(ExprNode, CmpNode):
         #  so only need to dispose of the two main operands.
         self.operand1.generate_disposal_code(code)
         self.operand2.generate_disposal_code(code)
-        
+
     def free_subexpr_temps(self, code):
         #  If this is called, it is a non-cascaded cmp,
         #  so only need to dispose of the two main operands.
         self.operand1.free_temps(code)
         self.operand2.free_temps(code)
-        
+
     def annotate(self, code):
         self.operand1.annotate(code)
         self.operand2.annotate(code)
@@ -6602,9 +6837,9 @@ class PrimaryCmpNode(ExprNode, CmpNode):
 
 
 class CascadedCmpNode(Node, CmpNode):
-    #  A CascadedCmpNode is not a complete expression node. It 
-    #  hangs off the side of another comparison node, shares 
-    #  its left operand with that node, and shares its result 
+    #  A CascadedCmpNode is not a complete expression node. It
+    #  hangs off the side of another comparison node, shares
+    #  its left operand with that node, and shares its result
     #  with the PrimaryCmpNode at the head of the chain.
     #
     #  operator      string
@@ -6634,7 +6869,7 @@ class CascadedCmpNode(Node, CmpNode):
 
     def has_python_operands(self):
         return self.operand2.type.is_pyobject
-        
+
     def coerce_operands_to_pyobjects(self, env):
         self.operand2 = self.operand2.coerce_to_pyobject(env)
         if self.operand2.type is dict_type and self.operator in ('in', 'not_in'):
@@ -6647,7 +6882,7 @@ class CascadedCmpNode(Node, CmpNode):
             #self.operand2 = self.operand2.coerce_to_temp(env) #CTT
             self.operand2 = self.operand2.coerce_to_simple(env)
             self.cascade.coerce_cascaded_operands_to_temp(env)
-    
+
     def generate_evaluation_code(self, code, result, operand1):
         if self.type.is_pyobject:
             code.putln("if (__Pyx_PyObject_IsTrue(%s)) {" % result)
@@ -6655,7 +6890,7 @@ class CascadedCmpNode(Node, CmpNode):
         else:
             code.putln("if (%s) {" % result)
         self.operand2.generate_evaluation_code(code)
-        self.generate_operation_code(code, result, 
+        self.generate_operation_code(code, result,
             operand1, self.operator, self.operand2)
         if self.cascade:
             self.cascade.generate_evaluation_code(
@@ -6689,11 +6924,11 @@ binop_node_classes = {
 }
 
 def binop_node(pos, operator, operand1, operand2, inplace=False):
-    # Construct binop node of appropriate class for 
+    # Construct binop node of appropriate class for
     # given operator.
-    return binop_node_classes[operator](pos, 
-        operator = operator, 
-        operand1 = operand1, 
+    return binop_node_classes[operator](pos,
+        operator = operator,
+        operand1 = operand1,
         operand2 = operand2,
         inplace = inplace)
 
@@ -6712,10 +6947,10 @@ class CoercionNode(ExprNode):
     #  Abstract base class for coercion nodes.
     #
     #  arg       ExprNode       node being coerced
-    
+
     subexprs = ['arg']
     constant_result = not_a_constant
-    
+
     def __init__(self, arg):
         self.pos = arg.pos
         self.arg = arg
@@ -6725,7 +6960,7 @@ class CoercionNode(ExprNode):
     def calculate_constant_result(self):
         # constant folding can break type coercion, so this is disabled
         pass
-            
+
     def annotate(self, code):
         self.arg.annotate(code)
         if self.arg.type != self.type:
@@ -6735,14 +6970,14 @@ class CoercionNode(ExprNode):
 
 class CastNode(CoercionNode):
     #  Wrap a node in a C type cast.
-    
+
     def __init__(self, arg, new_type):
         CoercionNode.__init__(self, arg)
         self.type = new_type
 
     def may_be_none(self):
         return self.arg.may_be_none()
-    
+
     def calculate_result_code(self):
         return self.arg.result_as(self.type)
 
@@ -6766,7 +7001,7 @@ class PyTypeTestNode(CoercionNode):
 
     nogil_check = Node.gil_error
     gil_message = "Python type test"
-    
+
     def analyse_types(self, env):
         pass
 
@@ -6774,10 +7009,10 @@ class PyTypeTestNode(CoercionNode):
         if self.notnone:
             return False
         return self.arg.may_be_none()
-    
+
     def result_in_temp(self):
         return self.arg.result_in_temp()
-    
+
     def is_ephemeral(self):
         return self.arg.is_ephemeral()
 
@@ -6787,7 +7022,7 @@ class PyTypeTestNode(CoercionNode):
 
     def calculate_result_code(self):
         return self.arg.result()
-    
+
     def generate_result_code(self, code):
         if self.type.typeobj_is_available():
             if not self.type.is_builtin_type:
@@ -6799,7 +7034,7 @@ class PyTypeTestNode(CoercionNode):
         else:
             error(self.pos, "Cannot test type of extern C class "
                 "without type object name specification")
-                
+
     def generate_post_assignment_code(self, code):
         self.arg.generate_post_assignment_code(code)
 
@@ -6830,7 +7065,7 @@ class NoneCheckNode(CoercionNode):
 
     def calculate_result_code(self):
         return self.arg.result()
-    
+
     def generate_result_code(self, code):
         code.putln(
             "if (unlikely(%s == Py_None)) {" % self.arg.result())
@@ -6851,7 +7086,7 @@ class NoneCheckNode(CoercionNode):
 class CoerceToPyTypeNode(CoercionNode):
     #  This node is used to convert a C data type
     #  to a Python object.
-    
+
     type = py_object_type
     is_temp = 1
 
@@ -6860,12 +7095,17 @@ class CoerceToPyTypeNode(CoercionNode):
         if not arg.type.create_to_py_utility_code(env):
             error(arg.pos,
                   "Cannot convert '%s' to Python object" % arg.type)
-        if type is not py_object_type:
-            self.type = py_object_type
-        elif arg.type.is_string:
-            self.type = bytes_type
-        elif arg.type is PyrexTypes.c_py_unicode_type:
-            self.type = unicode_type
+        if type is py_object_type:
+            # be specific about some known types
+            if arg.type.is_string:
+                self.type = bytes_type
+            elif arg.type is PyrexTypes.c_py_unicode_type:
+                self.type = unicode_type
+            elif arg.type.is_complex:
+                self.type = Builtin.complex_type
+        else:
+            # FIXME: check that the target type and the resulting type are compatible
+            pass
 
     gil_message = "Converting to Python object"
 
@@ -6880,7 +7120,7 @@ class CoerceToPyTypeNode(CoercionNode):
             return self.arg.coerce_to_temp(env)
         else:
             return CoerceToBooleanNode(self, env)
-    
+
     def coerce_to_integer(self, env):
         # If not already some C integer type, coerce to longint.
         if self.arg.type.is_int:
@@ -6895,9 +7135,9 @@ class CoerceToPyTypeNode(CoercionNode):
     def generate_result_code(self, code):
         function = self.arg.type.to_py_function
         code.putln('%s = %s(%s); %s' % (
-            self.result(), 
-            function, 
-            self.arg.result(), 
+            self.result(),
+            function,
+            self.arg.result(),
             code.error_goto_if_null(self.result(), self.pos)))
         code.put_gotref(self.py_result())
 
@@ -6956,7 +7196,7 @@ class CoerceFromPyTypeNode(CoercionNode):
         if self.type.is_string and self.arg.is_ephemeral():
             error(arg.pos,
                   "Obtaining char * from temporary Python value")
-    
+
     def analyse_types(self, env):
         # The arg is always already analysed
         pass
@@ -6968,7 +7208,7 @@ class CoerceFromPyTypeNode(CoercionNode):
         if self.type.is_enum:
             rhs = typecast(self.type, c_long_type, rhs)
         code.putln('%s = %s; %s' % (
-            self.result(), 
+            self.result(),
             rhs,
             code.error_goto_if(self.type.error_condition(self.result()), self.pos)))
         if self.type.is_pyobject:
@@ -6978,7 +7218,7 @@ class CoerceFromPyTypeNode(CoercionNode):
 class CoerceToBooleanNode(CoercionNode):
     #  This node is used when a result needs to be used
     #  in a boolean context.
-    
+
     type = PyrexTypes.c_bint_type
 
     _special_builtins = {
@@ -6998,13 +7238,13 @@ class CoerceToBooleanNode(CoercionNode):
             self.gil_error()
 
     gil_message = "Truth-testing Python object"
-    
+
     def check_const(self):
         if self.is_temp:
             self.not_const()
             return False
         return self.arg.check_const()
-    
+
     def calculate_result_code(self):
         return "(%s != 0)" % self.arg.result()
 
@@ -7021,8 +7261,8 @@ class CoerceToBooleanNode(CoercionNode):
         else:
             code.putln(
                 "%s = __Pyx_PyObject_IsTrue(%s); %s" % (
-                    self.result(), 
-                    self.arg.py_result(), 
+                    self.result(),
+                    self.arg.py_result(),
                     code.error_goto_if_neg(self.result(), self.pos)))
 
 class CoerceToComplexNode(CoercionNode):
@@ -7045,7 +7285,7 @@ class CoerceToComplexNode(CoercionNode):
                 self.type.from_parts,
                 real_part,
                 imag_part)
-    
+
     def generate_result_code(self, code):
         pass
 
@@ -7067,7 +7307,7 @@ class CoerceToTempNode(CoercionNode):
     def analyse_types(self, env):
         # The arg is always already analysed
         pass
-        
+
     def coerce_to_boolean(self, env):
         self.arg = self.arg.coerce_to_boolean(env)
         if self.arg.is_simple():
@@ -7090,12 +7330,12 @@ class CloneNode(CoercionNode):
     #  to be used multiple times. The argument node's result must
     #  be in a temporary. This node "borrows" the result from the
     #  argument node, and does not generate any evaluation or
-    #  disposal code for it. The original owner of the argument 
+    #  disposal code for it. The original owner of the argument
     #  node is responsible for doing those things.
-    
+
     subexprs = [] # Arg is not considered a subexpr
     nogil_check = None
-    
+
     def __init__(self, arg):
         CoercionNode.__init__(self, arg)
         if hasattr(arg, 'type'):
@@ -7103,13 +7343,13 @@ class CloneNode(CoercionNode):
             self.result_ctype = arg.result_ctype
         if hasattr(arg, 'entry'):
             self.entry = arg.entry
-            
+
     def result(self):
         return self.arg.result()
-    
+
     def type_dependencies(self, env):
         return self.arg.type_dependencies(env)
-    
+
     def infer_type(self, env):
         return self.arg.infer_type(env)
 
@@ -7119,27 +7359,27 @@ class CloneNode(CoercionNode):
         self.is_temp = 1
         if hasattr(self.arg, 'entry'):
             self.entry = self.arg.entry
-    
+
     def generate_evaluation_code(self, code):
         pass
 
     def generate_result_code(self, code):
         pass
-        
+
     def generate_disposal_code(self, code):
         pass
-                
+
     def free_temps(self, code):
         pass
 
 
 class ModuleRefNode(ExprNode):
     # Simple returns the module object
-    
+
     type = py_object_type
     is_temp = False
     subexprs = []
-    
+
     def analyse_types(self, env):
         pass
 
@@ -7154,11 +7394,11 @@ class ModuleRefNode(ExprNode):
 
 class DocstringRefNode(ExprNode):
     # Extracts the docstring of the body element
-    
+
     subexprs = ['body']
     type = py_object_type
     is_temp = True
-    
+
     def __init__(self, pos, body):
         ExprNode.__init__(self, pos)
         assert body.type.is_pyobject
@@ -7305,120 +7545,176 @@ static CYTHON_INLINE int __Pyx_TypeTest(PyObject *obj, PyTypeObject *type) {
 
 #------------------------------------------------------------------------------------
 
+find_py2_metaclass_utility_code = UtilityCode(
+proto = '''
+static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases); /*proto*/
+''',
+impl = '''
+static PyObject *__Pyx_FindPy2Metaclass(PyObject *bases) {
+    PyObject *metaclass;
+    /* Default metaclass */
+#if PY_MAJOR_VERSION < 3
+    if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
+        PyObject *base = PyTuple_GET_ITEM(bases, 0);
+        metaclass = PyObject_GetAttrString(base, "__class__");
+        if (!metaclass) {
+            PyErr_Clear();
+            metaclass = (PyObject*) Py_TYPE(base);
+        }
+    } else {
+        metaclass = (PyObject *) &PyClass_Type;
+    }
+#else
+    if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
+        PyObject *base = PyTuple_GET_ITEM(bases, 0);
+        metaclass = (PyObject*) Py_TYPE(base);
+    } else {
+        metaclass = (PyObject *) &PyType_Type;
+    }
+#endif
+    Py_INCREF(metaclass);
+    return metaclass;
+}
+''')
+
 create_class_utility_code = UtilityCode(
 proto = """
 static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
-                                   PyObject *modname, PyObject *kwargs); /*proto*/
-static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name,
-                              PyObject *mkw, PyObject *dict); /*proto*/
+                                   PyObject *modname); /*proto*/
+""",
+impl = """
+static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
+                                   PyObject *modname) {
+    PyObject *result;
+    PyObject *metaclass;
+
+    if (PyDict_SetItemString(dict, "__module__", modname) < 0)
+        return NULL;
+
+    /* Python2 __metaclass__ */
+    metaclass = PyDict_GetItemString(dict, "__metaclass__");
+    if (metaclass) {
+        Py_INCREF(metaclass);
+    } else {
+        metaclass = __Pyx_FindPy2Metaclass(bases);
+    }
+    result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL);
+    Py_DECREF(metaclass);
+    return result;
+}
+""",
+requires = [find_py2_metaclass_utility_code])
+
+#------------------------------------------------------------------------------------
+
+create_py3class_utility_code = UtilityCode(
+proto = """
+static PyObject *__Pyx_Py3MetaclassGet(PyObject *bases, PyObject *mkw); /*proto*/
+static PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *mkw, PyObject *modname, PyObject *doc); /*proto*/
+static PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, PyObject *mkw); /*proto*/
 """,
 impl = """
-static int __Pyx_PrepareClass(PyObject *metaclass, PyObject *bases, PyObject *name,
-                              PyObject *mkw, PyObject *dict) {
+PyObject *__Pyx_Py3MetaclassGet(PyObject *bases, PyObject *mkw) {
+    PyObject *metaclass = PyDict_GetItemString(mkw, "metaclass");
+    if (metaclass) {
+        Py_INCREF(metaclass);
+        if (PyDict_DelItemString(mkw, "metaclass") < 0) {
+            Py_DECREF(metaclass);
+            return NULL;
+        }
+        return metaclass;
+    }
+    return __Pyx_FindPy2Metaclass(bases);
+}
+
+PyObject *__Pyx_Py3MetaclassPrepare(PyObject *metaclass, PyObject *bases, PyObject *name, PyObject *mkw,
+                                    PyObject *modname, PyObject *doc) {
     PyObject *prep;
     PyObject *pargs;
     PyObject *ns;
+    PyObject *str;
 
     prep = PyObject_GetAttrString(metaclass, "__prepare__");
-    if (prep == NULL) {
+    if (!prep) {
         if (!PyErr_ExceptionMatches(PyExc_AttributeError))
-            return -1;
+            return NULL;
         PyErr_Clear();
-        return 0;
+        return PyDict_New();
     }
     pargs = PyTuple_New(2);
     if (!pargs) {
         Py_DECREF(prep);
-        return -1;
+        return NULL;
     }
+
     Py_INCREF(name);
     Py_INCREF(bases);
     PyTuple_SET_ITEM(pargs, 0, name);
     PyTuple_SET_ITEM(pargs, 1, bases);
-    ns = PyEval_CallObjectWithKeywords(prep, pargs, mkw);
-    Py_DECREF(pargs);
+
+    ns = PyObject_Call(prep, pargs, mkw);
+
     Py_DECREF(prep);
+    Py_DECREF(pargs);
+
     if (ns == NULL)
-        return -1;
-    /* XXX: This is hack, merge namespace back to dict,
-       __prepare__ should be ran before dict initialization */
-    if (PyDict_Merge(dict, ns, 0)) {
+        return NULL;
+
+    /* Required here to emulate assignment order */
+    /* XXX: use consts here */
+    #if PY_MAJOR_VERSION >= 3
+    str = PyUnicode_FromString("__module__");
+    #else
+    str = PyString_FromString("__module__");
+    #endif
+    if (!str) {
         Py_DECREF(ns);
-        return -1;
+        return NULL;
     }
-    Py_DECREF(ns);
-    return 0;
-}
-
-static PyObject *__Pyx_CreateClass(PyObject *bases, PyObject *dict, PyObject *name,
-                                   PyObject *modname, PyObject *kwargs) {
-    PyObject *result = NULL;
-    PyObject *metaclass = NULL;
-    PyObject *mkw = NULL;
 
-    if (PyDict_SetItemString(dict, "__module__", modname) < 0)
+    if (PyObject_SetItem(ns, str, modname) < 0) {
+        Py_DECREF(ns);
+        Py_DECREF(str);
         return NULL;
-
-    /* Python3 metaclasses */
-    if (kwargs) {
-        mkw = PyDict_Copy(kwargs); /* Don't modify kwargs passed in! */
-        if (!mkw)
+    }
+    Py_DECREF(str);
+    if (doc) {
+        #if PY_MAJOR_VERSION >= 3
+        str = PyUnicode_FromString("__doc__");
+        #else
+        str = PyString_FromString("__doc__");
+        #endif
+        if (!str) {
+            Py_DECREF(ns);
             return NULL;
-        metaclass = PyDict_GetItemString(mkw, "metaclass");
-        if (metaclass) {
-            Py_INCREF(metaclass);
-            if (PyDict_DelItemString(mkw, "metaclass") < 0)
-                goto bad;
-            if (__Pyx_PrepareClass(metaclass, bases, name, mkw, dict))
-                goto bad;
         }
-    }
-    if (!metaclass) {
-        /* Python2 __metaclass__ */
-        metaclass = PyDict_GetItemString(dict, "__metaclass__");
-        if (!metaclass) {
-            /* Default metaclass */
-#if PY_MAJOR_VERSION < 3
-            if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
-                PyObject *base = PyTuple_GET_ITEM(bases, 0);
-                metaclass = PyObject_GetAttrString(base, "__class__");
-                if (!metaclass) {
-                    PyErr_Clear();
-                    metaclass = (PyObject *)base->ob_type;
-                }
-            } else
-                metaclass = (PyObject *) &PyClass_Type;
-#else
-            if (PyTuple_Check(bases) && PyTuple_GET_SIZE(bases) > 0) {
-                PyObject *base = PyTuple_GET_ITEM(bases, 0);
-                metaclass = (PyObject *)base->ob_type;
-            } else
-                metaclass = (PyObject *) &PyType_Type;
-#endif
+        if (PyObject_SetItem(ns, str, doc) < 0) {
+            Py_DECREF(ns);
+            Py_DECREF(str);
+            return NULL;
         }
-        Py_INCREF(metaclass);
+        Py_DECREF(str);
     }
-    if (mkw && PyDict_Size(mkw) > 0) {
-        PyObject *margs = PyTuple_New(3);
-        if (!margs)
-            goto bad;
-        Py_INCREF(name);
-        Py_INCREF(bases);
-        Py_INCREF(dict);
-        PyTuple_SET_ITEM(margs, 0, name);
-        PyTuple_SET_ITEM(margs, 1, bases);
-        PyTuple_SET_ITEM(margs, 2, dict);
-        result = PyEval_CallObjectWithKeywords(metaclass, margs, mkw);
-        Py_DECREF(margs);
-    } else {
-        result = PyObject_CallFunctionObjArgs(metaclass, name, bases, dict, NULL);
-    }
-bad:
-    Py_DECREF(metaclass);
-    Py_XDECREF(mkw);
+    return ns;
+}
+
+PyObject *__Pyx_Py3ClassCreate(PyObject *metaclass, PyObject *name, PyObject *bases, PyObject *dict, PyObject *mkw) {
+    PyObject *result;
+    PyObject *margs = PyTuple_New(3);
+    if (!margs)
+        return NULL;
+    Py_INCREF(name);
+    Py_INCREF(bases);
+    Py_INCREF(dict);
+    PyTuple_SET_ITEM(margs, 0, name);
+    PyTuple_SET_ITEM(margs, 1, bases);
+    PyTuple_SET_ITEM(margs, 2, dict);
+    result = PyObject_Call(metaclass, margs, mkw);
+    Py_DECREF(margs);
     return result;
 }
-""")
+""",
+requires = [find_py2_metaclass_utility_code])
 
 #------------------------------------------------------------------------------------
 
@@ -7507,7 +7803,6 @@ static CYTHON_INLINE void __Pyx_RaiseNoneNotIterableError(void) {
 
 getitem_dict_utility_code = UtilityCode(
 proto = """
-
 #if PY_MAJOR_VERSION >= 3
 static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
     PyObject *value;
@@ -7527,7 +7822,7 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
 #else
     #define __Pyx_PyDict_GetItem(d, key) PyObject_GetItem(d, key)
 #endif
-""", 
+""",
 requires = [raise_noneindex_error_utility_code])
 
 #------------------------------------------------------------------------------------
@@ -7726,7 +8021,7 @@ static CYTHON_INLINE void __Pyx_RaiseNeedMoreValuesError(Py_ssize_t index) {
 tuple_unpacking_error_code = UtilityCode(
 proto = """
 static void __Pyx_UnpackTupleError(PyObject *, Py_ssize_t index); /*proto*/
-""", 
+""",
 impl = """
 static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) {
     if (t == Py_None) {
@@ -7737,7 +8032,7 @@ static void __Pyx_UnpackTupleError(PyObject *t, Py_ssize_t index) {
       __Pyx_RaiseTooManyValuesError(index);
     }
 }
-""", 
+""",
 requires = [raise_none_iter_error_utility_code,
             raise_need_more_values_to_unpack,
             raise_too_many_values_to_unpack]
@@ -7800,7 +8095,7 @@ static PyObject* __Pyx_PyEval_CallObjectWithKeywords(PyObject *callable, PyObjec
         return result; /* may be NULL */
     }
 }
-""", 
+""",
 )
 
 
@@ -7879,9 +8174,9 @@ static int __Pyx_cdivision_warning(void); /* proto */
 """,
 impl="""
 static int __Pyx_cdivision_warning(void) {
-    return PyErr_WarnExplicit(PyExc_RuntimeWarning, 
+    return PyErr_WarnExplicit(PyExc_RuntimeWarning,
                               "division with oppositely signed operands, C and Python semantics differ",
-                              %(FILENAME)s, 
+                              %(FILENAME)s,
                               %(LINENO)s,
                               __Pyx_MODULE_NAME,
                               NULL);
@@ -7907,17 +8202,17 @@ typedef struct {
     PyCFunctionObject func;
 } %(binding_cfunc)s_object;
 
-PyTypeObject %(binding_cfunc)s_type;
-PyTypeObject *%(binding_cfunc)s = NULL;
+static PyTypeObject %(binding_cfunc)s_type;
+static PyTypeObject *%(binding_cfunc)s = NULL;
 
-PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module); /* proto */
+static PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module); /* proto */
 #define %(binding_cfunc)s_New(ml, self) %(binding_cfunc)s_NewEx(ml, self, NULL)
 
-int %(binding_cfunc)s_init(void); /* proto */
+static int %(binding_cfunc)s_init(void); /* proto */
 """ % Naming.__dict__,
 impl="""
 
-PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
+static PyObject *%(binding_cfunc)s_NewEx(PyMethodDef *ml, PyObject *self, PyObject *module) {
        %(binding_cfunc)s_object *op = PyObject_GC_New(%(binding_cfunc)s_object, %(binding_cfunc)s);
     if (op == NULL)
         return NULL;
@@ -7943,7 +8238,7 @@ static PyObject *%(binding_cfunc)s_descr_get(PyObject *func, PyObject *obj, PyOb
        return PyMethod_New(func, obj, type);
 }
 
-int %(binding_cfunc)s_init(void) {
+static int %(binding_cfunc)s_init(void) {
     %(binding_cfunc)s_type = PyCFunction_Type;
     %(binding_cfunc)s_type.tp_name = __Pyx_NAMESTR("cython_binding_builtin_function_or_method");
     %(binding_cfunc)s_type.tp_dealloc = (destructor)%(binding_cfunc)s_dealloc;