-devel mergeback
[cython.git] / Cython / Compiler / Nodes.py
index 0de02d9782ceaed75478376a7cf300128de535f4..a3e78a9f7976db801363e0a294d67ad274e1d607 100644 (file)
@@ -13,7 +13,8 @@ import TypeSlots
 from PyrexTypes import py_object_type, error_type, CTypedefType, CFuncType
 from Symtab import ModuleScope, LocalScope, GeneratorLocalScope, \
     StructOrUnionScope, PyClassScope, CClassScope
-from Cython.Utils import open_new_file, replace_suffix, UtilityCode
+from Cython.Utils import open_new_file, replace_suffix
+from Code import UtilityCode
 from StringEncoding import EncodedString, escape_byte_string, split_docstring
 import Options
 import ControlFlow
@@ -132,11 +133,9 @@ class Node(object):
     
     gil_message = "Operation"
 
-    def gil_check(self, env):
-        if env.nogil:
-            self.gil_error()
+    nogil_check = None
 
-    def gil_error(self):
+    def gil_error(self, env=None):
         error(self.pos, "%s not allowed without gil" % self.gil_message)
 
     def clone_node(self):
@@ -299,38 +298,6 @@ class CompilerDirectivesNode(Node):
 class BlockNode(object):
     #  Mixin class for nodes representing a declaration block.
 
-    def generate_const_definitions(self, env, code):
-        if env.const_entries:
-            for entry in env.const_entries:
-                if not entry.is_interned:
-                    code.globalstate.add_const_definition(entry)
-
-    def generate_interned_string_decls(self, env, code):
-        entries = env.global_scope().new_interned_string_entries
-        if entries:
-            for entry in entries:
-                code.globalstate.add_interned_string_decl(entry)
-            del entries[:]
-
-    def generate_py_string_decls(self, env, code):
-        if env is None:
-            return # earlier error
-        entries = env.pystring_entries
-        if entries:
-            for entry in entries:
-                if not entry.is_interned:
-                    code.globalstate.add_py_string_decl(entry)
-
-    def generate_interned_num_decls(self, env, code):
-        #  Flush accumulated interned nums from the global scope
-        #  and generate declarations for them.
-        genv = env.global_scope()
-        entries = genv.interned_nums
-        if entries:
-            for entry in entries:
-                code.globalstate.add_interned_num_decl(entry)
-            del entries[:]
-
     def generate_cached_builtins_decls(self, env, code):
         entries = env.global_scope().undeclared_cached_builtins
         for entry in entries:
@@ -486,12 +453,13 @@ class CArrayDeclaratorNode(CDeclaratorNode):
             self.dimension.analyse_const_expression(env)
             if not self.dimension.type.is_int:
                 error(self.dimension.pos, "Array dimension not integer")
-            size = self.dimension.result()
-            try:
-                size = int(size)
-            except ValueError:
-                # runtime constant?
-                pass
+            size = self.dimension.get_constant_c_result_code()
+            if size is not None:
+                try:
+                    size = int(size)
+                except ValueError:
+                    # runtime constant?
+                    pass
         else:
             size = None
         if not base_type.is_complete():
@@ -537,9 +505,6 @@ class CFuncDeclaratorNode(CDeclaratorNode):
             # Catch attempted C-style func(void) decl
             if type.is_void:
                 error(arg_node.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
-#            if type.is_pyobject and self.nogil:
-#                error(self.pos,
-#                    "Function with Python argument cannot be declared nogil")
             func_type_args.append(
                 PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
             if arg_node.default:
@@ -550,8 +515,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
         if self.optional_arg_count:
             scope = StructOrUnionScope()
             arg_count_member = '%sn' % Naming.pyrex_prefix
-            scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos,
-                              cname = arg_count_member)
+            scope.declare_var(arg_count_member, PyrexTypes.c_int_type, self.pos)
             for arg in func_type_args[len(func_type_args)-self.optional_arg_count:]:
                 scope.declare_var(arg.name, arg.type, arg.pos, allow_pyobject = 1)
             struct_cname = env.mangle(Naming.opt_arg_prefix, self.base.name)
@@ -566,6 +530,8 @@ class CFuncDeclaratorNode(CDeclaratorNode):
         
         exc_val = None
         exc_check = 0
+        if self.exception_check == '+':
+            env.add_include_file('stdexcept')
         if return_type.is_pyobject \
             and (self.exception_value or self.exception_check) \
             and self.exception_check != '+':
@@ -574,6 +540,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
         else:
             if self.exception_value:
                 self.exception_value.analyse_const_expression(env)
+                exc_val = self.exception_value.get_constant_c_result_code()
                 if self.exception_check == '+':
                     exc_val_type = self.exception_value.type
                     if not exc_val_type.is_error and \
@@ -581,12 +548,10 @@ class CFuncDeclaratorNode(CDeclaratorNode):
                           not (exc_val_type.is_cfunction and not exc_val_type.return_type.is_pyobject and len(exc_val_type.args)==0):
                         error(self.exception_value.pos,
                             "Exception value must be a Python exception or cdef function with no arguments.")
-                    exc_val = self.exception_value
                 else:
-                    exc_val = self.exception_value.result()
                     if not return_type.assignable_from(self.exception_value.type):
                         error(self.exception_value.pos,
-                            "Exception value incompatible with function return type")
+                              "Exception value incompatible with function return type")
             exc_check = self.exception_check
         if return_type.is_array:
             error(self.pos,
@@ -602,6 +567,13 @@ class CFuncDeclaratorNode(CDeclaratorNode):
             nogil = self.nogil, with_gil = self.with_gil, is_overridable = self.overridable)
         if self.optional_arg_count:
             func_type.op_arg_struct = PyrexTypes.c_ptr_type(self.op_args_struct.type)
+        callspec = env.directives['callspec']
+        if callspec:
+            current = func_type.calling_convention
+            if current and current != callspec:
+                error(self.pos, "cannot have both '%s' and '%s' "
+                      "calling conventions" % (current, callspec))
+            func_type.calling_convention = callspec
         return self.base.analyse(func_type, env)
 
 
@@ -612,8 +584,7 @@ class CArgDeclNode(Node):
     # declarator     CDeclaratorNode
     # not_none       boolean            Tagged with 'not None'
     # default        ExprNode or None
-    # default_entry  Symtab.Entry       Entry for the variable holding the default value
-    # default_result_code string        cname or code fragment for default value
+    # default_value  PyObjectConst      constant for default value
     # is_self_arg    boolean            Is the "self" arg of an extension type method
     # is_kw_only     boolean            Is a keyword-only argument
 
@@ -623,6 +594,7 @@ class CArgDeclNode(Node):
     is_generic = 1
     type = None
     name_declarator = None
+    default_value = None
 
     def analyse(self, env, nonempty = 0):
         #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
@@ -644,6 +616,16 @@ class CArgDeclNode(Node):
         else:
             return self.name_declarator, self.type
 
+    def calculate_default_value_code(self, code):
+        if self.default_value is None:
+            if self.default:
+                if self.default.is_literal:
+                    # will not output any code, just assign the result_code
+                    self.default.generate_evaluation_code(code)
+                    return self.type.cast_code(self.default.result())
+                self.default_value = code.get_argument_default_const(self.type)
+        return self.default_value
+
     def annotate(self, code):
         if self.default:
             self.default.annotate(code)
@@ -673,6 +655,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
     # is_basic_c_type  boolean
     # signed           boolean
     # longness         integer
+    # complex          boolean
     # is_self_arg      boolean      Is self argument of C method
 
     child_attrs = []
@@ -713,6 +696,11 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
                     self.arg_name = self.name
                 else:
                     error(self.pos, "'%s' is not a type identifier" % self.name)
+        if self.complex:
+            if not type.is_numeric or type.is_complex:
+                error(self.pos, "can only complexify c numeric types")
+            type = PyrexTypes.CComplexType(type)
+            type.create_declaration_utility_code(env)
         if type:
             return type
         else:
@@ -746,7 +734,12 @@ class CBufferAccessTypeNode(CBaseTypeNode):
             self.positional_args,
             self.keyword_args,
             base_type.buffer_defaults)
-        
+
+        if sys.version_info[0] < 3:
+            # Py 2.x enforces byte strings as keyword arguments ...
+            options = dict([ (name.encode('ASCII'), value)
+                             for name, value in options.iteritems() ])
+
         self.type = PyrexTypes.BufferType(base_type, **options)
         return self.type
 
@@ -786,6 +779,10 @@ class CVarDefNode(StatNode):
             dest_scope = env
         self.dest_scope = dest_scope
         base_type = self.base_type.analyse(env)
+
+        # If the field is an external typedef, we cannot be sure about the type,
+        # so do conversion ourself rather than rely on the CPython mechanism (through
+        # a property; made in AnalyseDeclarationsTransform).
         if (dest_scope.is_c_class_scope
                 and self.visibility == 'public' 
                 and base_type.is_pyobject 
@@ -839,16 +836,19 @@ class CStructOrUnionDefNode(StatNode):
     #  in_pxd        boolean
     #  attributes    [CVarDefNode] or None
     #  entry         Entry
+    #  packed        boolean
     
     child_attrs = ["attributes"]
 
     def analyse_declarations(self, env):
         scope = None
+        if self.visibility == 'extern' and self.packed:
+            error(self.pos, "Cannot declare extern struct as 'packed'")
         if self.attributes is not None:
             scope = StructOrUnionScope(self.name)
         self.entry = env.declare_struct_or_union(
             self.name, self.kind, scope, self.typedef_flag, self.pos,
-            self.cname, visibility = self.visibility)
+            self.cname, visibility = self.visibility, packed = self.packed)
         if self.attributes is not None:
             if self.in_pxd and not env.in_cinclude:
                 self.entry.defined_in_pxd = 1
@@ -870,10 +870,13 @@ class CStructOrUnionDefNode(StatNode):
                 if need_typedef_indirection:
                     # C can't handle typedef structs that refer to themselves. 
                     struct_entry = self.entry
-                    cname = env.new_const_cname()
-                    self.entry = env.declare_typedef(self.name, struct_entry.type, self.pos, cname = self.cname, visibility='ignore')
+                    self.entry = env.declare_typedef(
+                        self.name, struct_entry.type, self.pos,
+                        cname = self.cname, visibility='ignore')
                     struct_entry.type.typedef_flag = False
-                    struct_entry.cname = struct_entry.type.cname = env.new_const_cname()
+                    # FIXME: this might be considered a hack ;-)
+                    struct_entry.cname = struct_entry.type.cname = \
+                                         '_' + self.entry.type.typedef_cname
     
     def analyse_expressions(self, env):
         pass
@@ -904,23 +907,24 @@ class CEnumDefNode(StatNode):
                 item.analyse_declarations(env, self.entry)
 
     def analyse_expressions(self, env):
-        if self.visibility == 'public':
-            self.temp = env.allocate_temp_pyobject()
-            env.release_temp(self.temp)
-    
+        pass
+
     def generate_execution_code(self, code):
         if self.visibility == 'public':
+            temp = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
             for item in self.entry.enum_values:
                 code.putln("%s = PyInt_FromLong(%s); %s" % (
-                        self.temp,
+                        temp,
                         item.cname,
-                        code.error_goto_if_null(self.temp, item.pos)))
+                        code.error_goto_if_null(temp, item.pos)))
+                code.put_gotref(temp)
                 code.putln('if (__Pyx_SetAttrString(%s, "%s", %s) < 0) %s' % (
                         Naming.module_cname, 
                         item.name, 
-                        self.temp,
+                        temp,
                         code.error_goto(item.pos)))
-                code.putln("%s = 0;" % self.temp)
+                code.put_decref_clear(temp, PyrexTypes.py_object_type)
+            code.funcstate.release_temp(temp)
 
 
 class CEnumDefItemNode(StatNode):
@@ -936,11 +940,9 @@ class CEnumDefItemNode(StatNode):
             if not self.value.type.is_int:
                 self.value = self.value.coerce_to(PyrexTypes.c_int_type, env)
                 self.value.analyse_const_expression(env)
-            value = self.value.result()
-        else:
-            value = self.name
         entry = env.declare_const(self.name, enum_entry.type, 
-            value, self.pos, cname = self.cname, visibility = enum_entry.visibility)
+            self.value, self.pos, cname = self.cname,
+            visibility = enum_entry.visibility)
         enum_entry.enum_values.append(entry)
 
 
@@ -980,32 +982,26 @@ class FuncDefNode(StatNode, BlockNode):
     py_func = None
     assmt = None
     needs_closure = False
+    modifiers = []
     
     def analyse_default_values(self, env):
         genv = env.global_scope()
+        default_seen = 0
         for arg in self.args:
             if arg.default:
+                default_seen = 1
                 if arg.is_generic:
-                    if not hasattr(arg, 'default_entry'):
-                        arg.default.analyse_types(env)
-                        arg.default = arg.default.coerce_to(arg.type, genv)
-                        if arg.default.is_literal:
-                            arg.default_entry = arg.default
-                            arg.default_result_code = arg.default.calculate_result_code()
-                            if arg.default.type != arg.type and not arg.type.is_int:
-                                arg.default_result_code = arg.type.cast_code(arg.default_result_code)
-                        else:
-                            arg.default.allocate_temps(genv)
-                            arg.default_entry = genv.add_default_value(arg.type)
-                            if arg.type.is_pyobject:
-                                arg.default_entry.init = 0
-                            arg.default_entry.used = 1
-                            arg.default_result_code = arg.default_entry.cname
+                    arg.default.analyse_types(env)
+                    arg.default = arg.default.coerce_to(arg.type, genv)
                 else:
                     error(arg.pos,
                         "This argument cannot have a default value")
                     arg.default = None
-    
+            elif arg.kw_only:
+                default_seen = 1
+            elif default_seen:
+                error(arg.pos, "Non-default argument following default argument")
+
     def need_gil_acquisition(self, lenv):
         return 0
         
@@ -1022,6 +1018,7 @@ class FuncDefNode(StatNode, BlockNode):
         if type.is_cfunction:
             lenv.nogil = type.nogil and not type.with_gil
         self.local_scope = lenv
+        lenv.directives = env.directives
         return lenv
                 
     def generate_function_definitions(self, env, code):
@@ -1031,6 +1028,12 @@ class FuncDefNode(StatNode, BlockNode):
 
         is_getbuffer_slot = (self.entry.name == "__getbuffer__" and
                              self.entry.scope.is_c_class_scope)
+        
+        profile = code.globalstate.directives['profile']
+        if profile:
+            if lenv.nogil:
+                error(self.pos, "Cannot profile nogil function.")
+            code.globalstate.use_utility_code(profile_utility_code)
 
         # Generate C code for header and body of function
         code.enter_cfunc_scope()
@@ -1038,13 +1041,7 @@ class FuncDefNode(StatNode, BlockNode):
             
         # ----- Top-level constants used by this function
         code.mark_pos(self.pos)
-        self.generate_interned_num_decls(lenv, code)
-        self.generate_interned_string_decls(lenv, code)
-        self.generate_py_string_decls(lenv, code)
         self.generate_cached_builtins_decls(lenv, code)
-        #code.putln("")
-        #code.put_var_declarations(lenv.const_entries, static = 1)
-        self.generate_const_definitions(lenv, code)
         # ----- Function header
         code.putln("")
         if self.py_func:
@@ -1073,11 +1070,13 @@ class FuncDefNode(StatNode, BlockNode):
         # ----- Extern library function declarations
         lenv.generate_library_function_declarations(code)
         # ----- GIL acquisition
-        acquire_gil = self.need_gil_acquisition(lenv)
+        acquire_gil = self.acquire_gil
         if acquire_gil:
             env.use_utility_code(force_init_threads_utility_code)
             code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
         # ----- Automatic lead-ins for certain special functions
+        if profile:
+            code.put_trace_call(self.entry.name, self.pos)
         if not lenv.nogil:
             code.put_setup_refcount_context(self.entry.name)
         if is_getbuffer_slot:
@@ -1121,9 +1120,6 @@ class FuncDefNode(StatNode, BlockNode):
         if code.error_label in code.labels_used:
             code.put_goto(code.return_label)
             code.put_label(code.error_label)
-            # cleanup temps the old way
-            code.put_var_xdecrefs(lenv.temp_entries)
-            # cleanup temps the new way
             for cname, type in code.funcstate.all_managed_temps():
                 code.put_xdecref(cname, type)
 
@@ -1142,6 +1138,9 @@ class FuncDefNode(StatNode, BlockNode):
             err_val = self.error_value()
             exc_check = self.caller_will_check_exceptions()
             if err_val is not None or exc_check:
+                # TODO: Fix exception tracing (though currently unused by cProfile). 
+                # code.globalstate.use_utility_code(get_exception_tuple_utility_code)
+                # code.put_trace_exception()
                 code.putln('__Pyx_AddTraceback("%s");' % self.entry.qualified_name)
             else:
                 warning(self.entry.pos, "Unraisable exception in function '%s'." \
@@ -1171,9 +1170,6 @@ class FuncDefNode(StatNode, BlockNode):
 
 
         # ----- Non-error return cleanup
-        # If you add anything here, remember to add a condition to the
-        # if-test above in the error block (so that it can jump past this
-        # block).
         code.put_label(code.return_label)
         for entry in lenv.buffer_entries:
             if entry.used:
@@ -1205,6 +1201,17 @@ class FuncDefNode(StatNode, BlockNode):
 
             code.put_finish_refcount_context()
 
+        if self.entry.is_special and self.entry.name == "__hash__":
+            # Returning -1 for __hash__ is supposed to signal an error
+            # We do as Python instances and coerce -1 into -2. 
+            code.putln("if (unlikely(%s == -1) && !PyErr_Occurred()) %s = -2;" % (Naming.retval_cname, Naming.retval_cname))
+
+        if profile:
+            if self.return_type.is_pyobject:
+                code.put_trace_return(Naming.retval_cname)
+            else:
+                code.put_trace_return("Py_None")
+        
         if acquire_gil:
             code.putln("PyGILState_Release(_save);")
 
@@ -1213,7 +1220,6 @@ class FuncDefNode(StatNode, BlockNode):
             
         code.putln("}")
         # ----- Go back and insert temp variable declarations
-        tempvardecl_code.put_var_declarations(lenv.temp_entries)
         tempvardecl_code.put_temp_declarations(code.funcstate)
         # ----- Python version
         code.exit_cfunc_scope()
@@ -1240,14 +1246,15 @@ class FuncDefNode(StatNode, BlockNode):
                 if not default.is_literal:
                     default.generate_evaluation_code(code)
                     default.make_owned_reference(code)
+                    result = default.result_as(arg.type)
                     code.putln(
                         "%s = %s;" % (
-                            arg.default_entry.cname,
-                            default.result_as(arg.default_entry.type)))
-                    if default.is_temp and default.type.is_pyobject:
-                        code.putln("%s = 0;" % default.result())
+                            arg.calculate_default_value_code(code),
+                            result))
+                    if arg.type.is_pyobject:
+                        code.put_giveref(default.result())
+                    default.generate_post_assignment_code(code)
                     default.free_temps(code)
-                    code.put_var_giveref(arg.default_entry)
         # For Python class methods, create and store function object
         if self.assmt:
             self.assmt.generate_execution_code(code)
@@ -1304,9 +1311,7 @@ class CFuncDefNode(FuncDefNode):
         return self.entry.name
         
     def analyse_declarations(self, env):
-        if 'locals' in env.directives and env.directives['locals']:
-            self.directive_locals = env.directives['locals']
-        directive_locals = self.directive_locals
+        self.directive_locals.update(env.directives['locals'])
         base_type = self.base_type.analyse(env)
         # The 2 here is because we need both function and argument names. 
         name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
@@ -1358,8 +1363,6 @@ class CFuncDefNode(FuncDefNode):
             self.entry.as_variable = self.py_func.entry
             # Reset scope entry the above cfunction
             env.entries[name] = self.entry
-            self.py_func.interned_attr_cname = env.intern_identifier(
-                self.py_func.entry.name)
             if not env.is_module_scope or Options.lookup_module_cpdef:
                 self.override = OverrideCheckNode(self.pos, py_func = self.py_func)
                 self.body = StatListNode(self.pos, stats=[self.override, self.body])
@@ -1384,23 +1387,29 @@ class CFuncDefNode(FuncDefNode):
             if not arg.name:
                 error(arg.pos, "Missing argument name")
             self.declare_argument(env, arg)
-            
+
     def need_gil_acquisition(self, lenv):
+        return self.type.with_gil
+
+    def nogil_check(self, env):
         type = self.type
-        with_gil = self.type.with_gil
+        with_gil = type.with_gil
         if type.nogil and not with_gil:
             if type.return_type.is_pyobject:
                 error(self.pos,
                       "Function with Python return type cannot be declared nogil")
-            for entry in lenv.var_entries + lenv.temp_entries:
+            for entry in self.local_scope.var_entries:
                 if entry.type.is_pyobject:
                     error(self.pos, "Function declared nogil has Python locals or temporaries")
-        return with_gil
 
     def analyse_expressions(self, env):
-        self.analyse_default_values(env)
+        self.local_scope.directives = env.directives
         if self.py_func is not None:
+            # this will also analyse the default values
             self.py_func.analyse_expressions(env)
+        else:
+            self.analyse_default_values(env)
+        self.acquire_gil = self.need_gil_acquisition(self.local_scope)
 
     def generate_function_header(self, code, with_pymethdef, with_opt_args = 1, with_dispatch = 1, cname = None):
         arg_decls = []
@@ -1439,7 +1448,9 @@ class CFuncDefNode(FuncDefNode):
     def generate_argument_declarations(self, env, code):
         for arg in self.args:
             if arg.default:
-                    code.putln('%s = %s;' % (arg.type.declaration_code(arg.cname), arg.default_result_code))
+                result = arg.calculate_default_value_code(code)
+                code.putln('%s = %s;' % (
+                    arg.type.declaration_code(arg.cname), result))
 
     def generate_keyword_list(self, code):
         pass
@@ -1572,6 +1583,7 @@ class DefNode(FuncDefNode):
     is_wrapper = 0
     decorators = None
     entry = None
+    acquire_gil = 0
     
 
     def __init__(self, pos, **kwds):
@@ -1645,14 +1657,10 @@ class DefNode(FuncDefNode):
                             nogil = cfunc_type.nogil,
                             visibility = 'private',
                             api = False,
-                            directive_locals = cfunc.directive_locals)
+                            directive_locals = getattr(cfunc, 'directive_locals', {}))
     
     def analyse_declarations(self, env):
-        if 'locals' in env.directives:
-            directive_locals = env.directives['locals']
-        else:
-            directive_locals = {}
-        self.directive_locals = directive_locals
+        directive_locals = self.directive_locals = env.directives['locals']
         for arg in self.args:
             if hasattr(arg, 'name'):
                 type = arg.type
@@ -1690,9 +1698,11 @@ class DefNode(FuncDefNode):
 
     def analyse_signature(self, env):
         any_type_tests_needed = 0
-        # Use the simpler calling signature for zero- and one-argument functions.
-        if not self.entry.is_special and not self.star_arg and not self.starstar_arg:
-            if self.entry.signature is TypeSlots.pyfunction_signature and Options.optimize_simple_methods:
+        if self.entry.is_special:
+            self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
+        elif not env.directives['always_allow_keywords'] and not (self.star_arg or self.starstar_arg):
+            # Use the simpler calling signature for zero- and one-argument functions.
+            if self.entry.signature is TypeSlots.pyfunction_signature:
                 if len(self.args) == 0:
                     self.entry.signature = TypeSlots.pyfunction_noargs
                 elif len(self.args) == 1:
@@ -1704,8 +1714,6 @@ class DefNode(FuncDefNode):
                 elif len(self.args) == 2:
                     if self.args[1].default is None and not self.args[1].kw_only:
                         self.entry.signature = TypeSlots.ibinaryfunc
-        elif self.entry.is_special:
-            self.entry.trivial_signature = len(self.args) == 1 and not (self.star_arg or self.starstar_arg)
         sig = self.entry.signature
         nfixed = sig.num_fixed_args()
         for i in range(nfixed):
@@ -1801,10 +1809,6 @@ class DefNode(FuncDefNode):
                 arg.entry = self.declare_argument(env, arg)
             arg.entry.used = 1
             arg.entry.is_self_arg = arg.is_self_arg
-            if not arg.is_self_arg:
-                arg.name_entry = env.get_string_const(
-                    arg.name, identifier = True)
-                env.add_py_string(arg.name_entry, identifier = True)
             if arg.hdr_type:
                 if arg.is_self_arg or \
                     (arg.type.is_extension_type and not arg.hdr_type.is_extension_type):
@@ -1824,16 +1828,16 @@ class DefNode(FuncDefNode):
             env.control_flow.set_state((), (arg.name, 'initalized'), True)
             
     def analyse_expressions(self, env):
+        self.local_scope.directives = env.directives
         self.analyse_default_values(env)
         if env.is_py_class_scope:
             self.synthesize_assignment_node(env)
-    
+
     def synthesize_assignment_node(self, env):
         import ExprNodes
         self.assmt = SingleAssignmentNode(self.pos,
             lhs = ExprNodes.NameNode(self.pos, name = self.name),
             rhs = ExprNodes.UnboundMethodNode(self.pos, 
-                class_cname = env.class_obj_cname,
                 function = ExprNodes.PyCFunctionNode(self.pos,
                     pymethdef_cname = self.entry.pymethdef_cname)))
         self.assmt.analyse_declarations(env)
@@ -1866,7 +1870,7 @@ class DefNode(FuncDefNode):
             return
         if self.entry.doc and Options.docstrings:
             docstr = self.entry.doc
-            if not isinstance(docstr, str):
+            if docstr.is_unicode:
                 docstr = docstr.utf8encode()
             code.putln(
                 'static char %s[] = "%s";' % (
@@ -1886,7 +1890,7 @@ class DefNode(FuncDefNode):
                     code.putln("PyObject *%s = 0;" % arg.hdr_cname)
                 else:
                     code.put_var_declaration(arg.entry)
-    
+
     def generate_keyword_list(self, code):
         if self.signature_has_generic_args() and \
                 self.signature_has_nongeneric_args():
@@ -1895,7 +1899,8 @@ class DefNode(FuncDefNode):
                     Naming.pykwdlist_cname)
             for arg in self.args:
                 if arg.is_generic:
-                    code.put('&%s,' % arg.name_entry.pystring_cname)
+                    pystring_cname = code.intern_identifier(arg.name)
+                    code.put('&%s,' % pystring_cname)
             code.putln("0};")
 
     def generate_argument_parsing_code(self, env, code):
@@ -1913,6 +1918,11 @@ class DefNode(FuncDefNode):
         has_star_or_kw_args = self.star_arg is not None \
             or self.starstar_arg is not None or has_kwonly_args
 
+        for arg in self.args:
+            if not arg.type.is_pyobject:
+                done = arg.type.create_from_py_utility_code(env)
+                if not done: pass # will fail later
+
         if not self.signature_has_generic_args():
             if has_star_or_kw_args:
                 error(self.pos, "This method cannot have * or keyword arguments")
@@ -1925,12 +1935,10 @@ class DefNode(FuncDefNode):
         else:
             positional_args = []
             kw_only_args = []
-            default_seen = 0
             for arg in self.args:
                 arg_entry = arg.entry
                 if arg.is_generic:
                     if arg.default:
-                        default_seen = 1
                         if not arg.is_self_arg:
                             if arg.kw_only:
                                 kw_only_args.append(arg)
@@ -1938,9 +1946,6 @@ class DefNode(FuncDefNode):
                                 positional_args.append(arg)
                     elif arg.kw_only:
                         kw_only_args.append(arg)
-                        default_seen = 1
-                    elif default_seen:
-                        error(arg.pos, "Non-default argument following default argument")
                     elif not arg.is_self_arg:
                         positional_args.append(arg)
 
@@ -1994,7 +1999,7 @@ class DefNode(FuncDefNode):
             code.putln("if (unlikely(PyTuple_GET_SIZE(%s) > 0)) {" %
                        Naming.args_cname)
             code.put('__Pyx_RaiseArgtupleInvalid("%s", 1, 0, 0, PyTuple_GET_SIZE(%s)); return %s;' % (
-                    self.name.utf8encode(), Naming.args_cname, self.error_value()))
+                    self.name, Naming.args_cname, self.error_value()))
             code.putln("}")
 
         code.globalstate.use_utility_code(keyword_string_check_utility_code)
@@ -2081,10 +2086,11 @@ class DefNode(FuncDefNode):
             code.putln('} else {')
             for i, arg in enumerate(kw_only_args):
                 if not arg.default:
+                    pystring_cname = code.intern_identifier(arg.name)
                     # required keyword-only argument missing
                     code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
-                            self.name.utf8encode(),
-                            arg.name_entry.pystring_cname))
+                            self.name,
+                            pystring_cname))
                     code.putln(code.error_goto(self.pos))
                     break
 
@@ -2133,7 +2139,7 @@ class DefNode(FuncDefNode):
             code.put_goto(success_label)
             code.put_label(argtuple_error_label)
             code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, PyTuple_GET_SIZE(%s)); ' % (
-                    self.name.utf8encode(), has_fixed_positional_count,
+                    self.name, has_fixed_positional_count,
                     min_positional_args, max_positional_args,
                     Naming.args_cname))
             code.putln(code.error_goto(self.pos))
@@ -2144,7 +2150,7 @@ class DefNode(FuncDefNode):
                 code.putln(
                     "%s = %s;" % (
                         arg.entry.cname,
-                        arg.default_result_code))
+                        arg.calculate_default_value_code(code)))
 
     def generate_stararg_init_code(self, max_positional_args, code):
         if self.starstar_arg:
@@ -2186,7 +2192,7 @@ class DefNode(FuncDefNode):
         default_args = []
         for i, arg in enumerate(all_args):
             if arg.default and arg.type.is_pyobject:
-                default_value = arg.default_result_code
+                default_value = arg.calculate_default_value_code(code)
                 if arg.type is not PyrexTypes.py_object_type:
                     default_value = "(PyObject*)"+default_value
                 default_args.append((i, default_value))
@@ -2232,19 +2238,20 @@ class DefNode(FuncDefNode):
                         code.putln('default:')
                     else:
                         code.putln('case %2d:' % i)
+                pystring_cname = code.intern_identifier(arg.name)
                 if arg.default:
                     if arg.kw_only:
                         # handled separately below
                         continue
                     code.putln('if (kw_args > %d) {' % num_required_args)
                     code.putln('PyObject* value = PyDict_GetItem(%s, %s);' % (
-                        Naming.kwds_cname, arg.name_entry.pystring_cname))
+                        Naming.kwds_cname, pystring_cname))
                     code.putln('if (unlikely(value)) { values[%d] = value; kw_args--; }' % i)
                     code.putln('}')
                 else:
                     num_required_args -= 1
                     code.putln('values[%d] = PyDict_GetItem(%s, %s);' % (
-                        i, Naming.kwds_cname, arg.name_entry.pystring_cname))
+                        i, Naming.kwds_cname, pystring_cname))
                     code.putln('if (likely(values[%d])) kw_args--;' % i);
                     if i < min_positional_args:
                         if i == 0:
@@ -2257,14 +2264,14 @@ class DefNode(FuncDefNode):
                             # arguments up to this point
                             code.putln('else {')
                             code.put('__Pyx_RaiseArgtupleInvalid("%s", %d, %d, %d, %d); ' % (
-                                    self.name.utf8encode(), has_fixed_positional_count,
+                                    self.name, has_fixed_positional_count,
                                     min_positional_args, max_positional_args, i))
                             code.putln(code.error_goto(self.pos))
                             code.putln('}')
                     elif arg.kw_only:
                         code.putln('else {')
                         code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' %(
-                                self.name.utf8encode(), arg.name_entry.pystring_cname))
+                                self.namepystring_cname))
                         code.putln(code.error_goto(self.pos))
                         code.putln('}')
             if max_positional_args > 0:
@@ -2284,9 +2291,10 @@ class DefNode(FuncDefNode):
                 code.putln('while (kw_args > 0) {')
                 code.putln('PyObject* value;')
                 for i, arg in optional_args:
+                    pystring_cname = code.intern_identifier(arg.name)
                     code.putln(
                         'value = PyDict_GetItem(%s, %s);' % (
-                        Naming.kwds_cname, arg.name_entry.pystring_cname))
+                        Naming.kwds_cname, pystring_cname))
                     code.putln(
                         'if (value) { values[%d] = value; if (!(--kw_args)) break; }' % i)
                 code.putln('break;')
@@ -2316,7 +2324,7 @@ class DefNode(FuncDefNode):
                 Naming.pykwdlist_cname,
                 self.starstar_arg and self.starstar_arg.entry.cname or '0',
                 pos_arg_count,
-                self.name.utf8encode()))
+                self.name))
         code.putln(code.error_goto(self.pos))
         code.putln('}')
 
@@ -2330,7 +2338,7 @@ class DefNode(FuncDefNode):
                 code.putln(
                     "%s = %s;" % (
                         arg.entry.cname,
-                        arg.default_result_code))
+                        arg.calculate_default_value_code(code)))
                 code.putln('}')
 
     def generate_argument_conversion_code(self, code):
@@ -2453,6 +2461,7 @@ class OverrideCheckNode(StatNode):
         self.body.analyse_expressions(env)
         
     def generate_execution_code(self, code):
+        interned_attr_cname = code.intern_identifier(self.py_func.entry.name)
         # Check to see if we are an extension type
         if self.py_func.is_module_scope:
             self_arg = "((PyObject *)%s)" % Naming.module_cname
@@ -2465,17 +2474,21 @@ class OverrideCheckNode(StatNode):
             code.putln("else {")
         else:
             code.putln("else if (unlikely(Py_TYPE(%s)->tp_dictoffset != 0)) {" % self_arg)
+        self.func_node.allocate(code)
         err = code.error_goto_if_null(self.func_node.result(), self.pos)
         # need to get attribute manually--scope would return cdef method
-        code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (self.func_node.result(), self_arg, self.py_func.interned_attr_cname, err))
+        code.putln("%s = PyObject_GetAttr(%s, %s); %s" % (
+            self.func_node.result(), self_arg, interned_attr_cname, err))
         code.put_gotref(self.func_node.py_result())
         is_builtin_function_or_method = 'PyCFunction_Check(%s)' % self.func_node.result()
-        is_overridden = '(PyCFunction_GET_FUNCTION(%s) != (void *)&%s)' % (self.func_node.result(), self.py_func.entry.func_cname)
+        is_overridden = '(PyCFunction_GET_FUNCTION(%s) != (void *)&%s)' % (
+            self.func_node.result(), self.py_func.entry.func_cname)
         code.putln('if (!%s || %s) {' % (is_builtin_function_or_method, is_overridden))
         self.body.generate_execution_code(code)
         code.putln('}')
         code.put_decref_clear(self.func_node.result(), PyrexTypes.py_object_type)
         code.putln("}")
+        self.func_node.release(code)
 
 class ClassDefNode(StatNode, BlockNode):
     pass
@@ -2488,6 +2501,7 @@ class PyClassDefNode(ClassDefNode):
     #  body     StatNode        Attribute definition code
     #  entry    Symtab.Entry
     #  scope    PyClassScope
+    #  decorators    [DecoratorNode]        list of decorators or None
     #
     #  The following subnodes are constructed internally:
     #
@@ -2496,12 +2510,14 @@ class PyClassDefNode(ClassDefNode):
     #  target   NameNode   Variable to assign class object to
 
     child_attrs = ["body", "dict", "classobj", "target"]
+    decorators = None
     
-    def __init__(self, pos, name, bases, doc, body):
+    def __init__(self, pos, name, bases, doc, body, decorators = None):
         StatNode.__init__(self, pos)
         self.name = name
         self.doc = doc
         self.body = body
+        self.decorators = decorators
         import ExprNodes
         self.dict = ExprNodes.DictNode(pos, key_value_pairs = [])
         if self.doc and Options.docstrings:
@@ -2547,6 +2563,7 @@ class PyClassDefNode(ClassDefNode):
                              class_name = self.name,
                              base_class_module = base_class_module,
                              base_class_name = base_class_name,
+                             decorators = self.decorators,
                              body = self.body,
                              in_pxd = False,
                              doc = self.doc)
@@ -2561,6 +2578,7 @@ class PyClassDefNode(ClassDefNode):
     def analyse_declarations(self, env):
         self.target.analyse_target_declaration(env)
         cenv = self.create_scope(env)
+        cenv.directives = env.directives
         cenv.class_obj_cname = self.target.entry.cname
         self.body.analyse_declarations(cenv)
     
@@ -2569,25 +2587,23 @@ class PyClassDefNode(ClassDefNode):
         self.classobj.analyse_expressions(env)
         genv = env.global_scope()
         cenv = self.scope
-        cenv.class_dict_cname = self.dict.result()
-        cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
         self.body.analyse_expressions(cenv)
         self.target.analyse_target_expression(env, self.classobj)
-        self.dict.release_temp(env)
-        #self.classobj.release_temp(env)
-        #self.target.release_target_temp(env)
     
     def generate_function_definitions(self, env, code):
-        self.generate_py_string_decls(self.scope, code)
         self.body.generate_function_definitions(self.scope, code)
     
     def generate_execution_code(self, code):
+        code.pyclass_stack.append(self)
+        cenv = self.scope
         self.dict.generate_evaluation_code(code)
         self.classobj.generate_evaluation_code(code)
+        cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
         self.body.generate_execution_code(code)
         self.target.generate_assignment_code(self.classobj, code)
         self.dict.generate_disposal_code(code)
         self.dict.free_temps(code)
+        code.pyclass_stack.pop()
 
 
 class CClassDefNode(ClassDefNode):
@@ -2604,6 +2620,7 @@ class CClassDefNode(ClassDefNode):
     #  objstruct_name     string or None    Specified C name of object struct
     #  typeobj_name       string or None    Specified C name of type object
     #  in_pxd             boolean           Is in a .pxd file
+    #  decorators         [DecoratorNode]   list of decorators or None
     #  doc                string or None
     #  body               StatNode or None
     #  entry              Symtab.Entry
@@ -2618,6 +2635,7 @@ class CClassDefNode(ClassDefNode):
     api = False
     objstruct_name = None
     typeobj_name = None
+    decorators = None
 
     def analyse_declarations(self, env):
         #print "CClassDefNode.analyse_declarations:", self.class_name
@@ -2699,6 +2717,8 @@ class CClassDefNode(ClassDefNode):
         if home_scope is not env and self.visibility == 'extern':
             env.add_imported_entry(self.class_name, self.entry, pos)
         scope = self.entry.type.scope
+        if scope is not None:
+            scope.directives = env.directives
 
         if self.doc and Options.docstrings:
             scope.doc = embed_position(self.pos, self.doc)
@@ -2717,7 +2737,6 @@ class CClassDefNode(ClassDefNode):
             self.body.analyse_expressions(scope)
     
     def generate_function_definitions(self, env, code):
-        self.generate_py_string_decls(self.entry.type.scope, code)
         if self.body:
             self.body.generate_function_definitions(
                 self.entry.type.scope, code)
@@ -2745,10 +2764,7 @@ class PropertyNode(StatNode):
     def analyse_declarations(self, env):
         entry = env.declare_property(self.name, self.doc, self.pos)
         if entry:
-            if self.doc and Options.docstrings:
-                doc_entry = env.get_string_const(
-                    self.doc, identifier = False)
-                entry.doc_cname = doc_entry.cname
+            entry.scope.directives = env.directives
             self.body.analyse_declarations(entry.scope)
 
     def analyse_expressions(self, env):
@@ -2807,7 +2823,6 @@ class ExprStatNode(StatNode):
     
     def analyse_expressions(self, env):
         self.expr.analyse_expressions(env)
-        self.expr.release_temp(env)
     
     def generate_execution_code(self, code):
         self.expr.generate_evaluation_code(code)
@@ -2831,8 +2846,6 @@ class AssignmentNode(StatNode):
 
     def analyse_expressions(self, env):
         self.analyse_types(env)
-        self.allocate_rhs_temps(env)
-        self.allocate_lhs_temps(env)
 
 #       def analyse_expressions(self, env):
 #           self.analyse_expressions_1(env)
@@ -2930,14 +2943,6 @@ class SingleAssignmentNode(AssignmentNode):
         if use_temp:
             self.rhs = self.rhs.coerce_to_temp(env)
     
-    def allocate_rhs_temps(self, env):
-        self.rhs.allocate_temps(env)
-
-    def allocate_lhs_temps(self, env):
-        self.lhs.allocate_target_temps(env, self.rhs)
-        #self.lhs.release_target_temp(env)
-        #self.rhs.release_temp(env)
-
     def generate_rhs_evaluation_code(self, code):
         self.rhs.generate_evaluation_code(code)
     
@@ -2983,17 +2988,6 @@ class CascadedAssignmentNode(AssignmentNode):
             rhs = rhs.coerce_to(lhs.type, env)
             self.coerced_rhs_list.append(rhs)
 
-    def allocate_rhs_temps(self, env):
-        self.rhs.allocate_temps(env)
-    
-    def allocate_lhs_temps(self, env):
-        for lhs, rhs in zip(self.lhs_list, self.coerced_rhs_list):
-            rhs.allocate_temps(env)
-            lhs.allocate_target_temps(env, rhs)
-            #lhs.release_target_temp(env)
-            #rhs.release_temp(env)
-        self.rhs.release_temp(env)
-    
     def generate_rhs_evaluation_code(self, code):
         self.rhs.generate_evaluation_code(code)
     
@@ -3037,9 +3031,6 @@ class ParallelAssignmentNode(AssignmentNode):
     def analyse_expressions(self, env):
         for stat in self.stats:
             stat.analyse_types(env, use_temp = 1)
-            stat.allocate_rhs_temps(env)
-        for stat in self.stats:
-            stat.allocate_lhs_temps(env)
 
 #    def analyse_expressions(self, env):
 #        for stat in self.stats:
@@ -3089,40 +3080,21 @@ class InPlaceAssignmentNode(AssignmentNode):
         self.lhs.analyse_target_types(env)
         if Options.incref_local_binop and self.dup.type.is_pyobject:
             self.dup = self.dup.coerce_to_temp(env)
-        
-    def allocate_rhs_temps(self, env):
         import ExprNodes
         if self.lhs.type.is_pyobject:
             self.rhs = self.rhs.coerce_to_pyobject(env)
         elif self.rhs.type.is_pyobject:
             self.rhs = self.rhs.coerce_to(self.lhs.type, env)
         if self.lhs.type.is_pyobject:
-             self.result_value = ExprNodes.PyTempNode(self.pos, env).coerce_to(self.lhs.type, env)
-             self.result_value.allocate_temps(env)
-#        if use_temp:
-#            self.rhs = self.rhs.coerce_to_temp(env)
-        self.rhs.allocate_temps(env)
-        self.dup.allocate_subexpr_temps(env)
-        self.dup.allocate_temp(env)
-    
-    def allocate_lhs_temps(self, env):
-        self.lhs.allocate_target_temps(env, self.rhs)
-#        self.lhs.release_target_temp(env)
-        self.dup.release_temp(env)
-        if self.dup.is_temp:
-            self.dup.release_subexpr_temps(env)
-#        self.rhs.release_temp(env)
-        if self.lhs.type.is_pyobject:
-            self.result_value.release_temp(env)
-
+            self.result_value_temp = ExprNodes.PyTempNode(self.pos, env)
+            self.result_value = self.result_value_temp.coerce_to(self.lhs.type, env)
+        
     def generate_execution_code(self, code):
         import ExprNodes
         self.rhs.generate_evaluation_code(code)
         self.dup.generate_subexpr_evaluation_code(code)
-        if isinstance(self.dup, ExprNodes.NewTempExprNode):
-            # This is because we're manually messing with subexpr nodes
-            if self.dup.is_temp:
-                self.dup.allocate_temp_result(code)
+        if self.dup.is_temp:
+            self.dup.allocate_temp_result(code)
         # self.dup.generate_result_code is run only if it is not buffer access
         if self.operator == "**":
             extra = ", Py_None"
@@ -3132,6 +3104,7 @@ class InPlaceAssignmentNode(AssignmentNode):
             if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
                 error(self.pos, "In-place operators not allowed on object buffers in this release.")
             self.dup.generate_result_code(code)
+            self.result_value_temp.allocate(code)
             code.putln(
                 "%s = %s(%s, %s%s); %s" % (
                     self.result_value.result(), 
@@ -3147,15 +3120,16 @@ class InPlaceAssignmentNode(AssignmentNode):
             self.dup.generate_disposal_code(code)
             self.dup.free_temps(code)
             self.lhs.generate_assignment_code(self.result_value, code)
+            self.result_value_temp.release(code)
         else: 
             c_op = self.operator
             if c_op == "//":
                 c_op = "/"
             elif c_op == "**":
-                if self.lhs.type.is_int and self.rhs.type.is_int:
-                    error(self.pos, "** with two C int types is ambiguous")
-                else:
-                    error(self.pos, "No C inplace power operator")
+                error(self.pos, "No C inplace power operator")
+            elif self.lhs.type.is_complex and not code.globalstate.directives['c99_complex']:
+                error(self.pos, "Inplace operators not implemented for complex types.")
+                
             # have to do assignment directly to avoid side-effects
             if isinstance(self.lhs, ExprNodes.IndexNode) and self.lhs.is_buffer_access:
                 self.lhs.generate_buffer_setitem_code(self.rhs, code, c_op)
@@ -3236,12 +3210,11 @@ class PrintStatNode(StatNode):
     def analyse_expressions(self, env):
         self.arg_tuple.analyse_expressions(env)
         self.arg_tuple = self.arg_tuple.coerce_to_pyobject(env)
-        self.arg_tuple.release_temp(env)
         env.use_utility_code(printing_utility_code)
         if len(self.arg_tuple.args) == 1 and self.append_newline:
             env.use_utility_code(printing_one_utility_code)
-        self.gil_check(env)
 
+    nogil_check = Node.gil_error
     gil_message = "Python print statement"
 
     def generate_execution_code(self, code):
@@ -3280,13 +3253,10 @@ class ExecStatNode(StatNode):
         for i, arg in enumerate(self.args):
             arg.analyse_expressions(env)
             arg = arg.coerce_to_pyobject(env)
-            arg.release_temp(env)
             self.args[i] = arg
-        self.temp_result = env.allocate_temp_pyobject()
-        env.release_temp(self.temp_result)
         env.use_utility_code(Builtin.pyexec_utility_code)
-        self.gil_check(env)
 
+    nogil_check = Node.gil_error
     gil_message = "Python exec statement"
 
     def generate_execution_code(self, code):
@@ -3295,15 +3265,17 @@ class ExecStatNode(StatNode):
             arg.generate_evaluation_code(code)
             args.append( arg.py_result() )
         args = tuple(args + ['0', '0'][:3-len(args)])
+        temp_result = code.funcstate.allocate_temp(PyrexTypes.py_object_type, manage_ref=True)
         code.putln("%s = __Pyx_PyRun(%s, %s, %s);" % (
-                (self.temp_result,) + args))
+                (temp_result,) + args))
         for arg in self.args:
             arg.generate_disposal_code(code)
             arg.free_temps(code)
         code.putln(
-            code.error_goto_if_null(self.temp_result, self.pos))
-        code.put_gotref(self.temp_result)
-        code.put_decref_clear(self.temp_result, py_object_type)
+            code.error_goto_if_null(temp_result, self.pos))
+        code.put_gotref(temp_result)
+        code.put_decref_clear(temp_result, py_object_type)
+        code.funcstate.release_temp(temp_result)
 
     def annotate(self, code):
         for arg in self.args:
@@ -3324,12 +3296,15 @@ class DelStatNode(StatNode):
     def analyse_expressions(self, env):
         for arg in self.args:
             arg.analyse_target_expression(env, None)
-            if arg.type.is_pyobject:
-                self.gil_check(env)
-            else:
+            if not arg.type.is_pyobject:
                 error(arg.pos, "Deletion of non-Python object")
             #arg.release_target_temp(env)
 
+    def nogil_check(self, env):
+        for arg in self.args:
+            if arg.type.is_pyobject:
+                self.gil_error()
+
     gil_message = "Deleting Python object"
 
     def generate_execution_code(self, code):
@@ -3390,14 +3365,12 @@ class ReturnStatNode(StatNode):
     #
     #  value         ExprNode or None
     #  return_type   PyrexType
-    #  temps_in_use  [Entry]            Temps in use at time of return
     
     child_attrs = ["value"]
 
     def analyse_expressions(self, env):
         return_type = env.return_type
         self.return_type = return_type
-        self.temps_in_use = env.temps_in_use()
         if not return_type:
             error(self.pos, "Return not inside a function body")
             return
@@ -3408,15 +3381,15 @@ class ReturnStatNode(StatNode):
                     "Return with value in void function")
             else:
                 self.value = self.value.coerce_to(env.return_type, env)
-            self.value.allocate_temps(env)
-            self.value.release_temp(env)
         else:
             if (not return_type.is_void
                 and not return_type.is_pyobject
                 and not return_type.is_returncode):
                     error(self.pos, "Return value required")
-        if return_type.is_pyobject:
-            self.gil_check(env)
+
+    def nogil_check(self, env):
+        if self.return_type.is_pyobject:
+            self.gil_error()
 
     gil_message = "Returning Python object"
 
@@ -3445,15 +3418,8 @@ class ReturnStatNode(StatNode):
                     "%s = %s;" % (
                         Naming.retval_cname,
                         self.return_type.default_value))
-        # free temps the old way
-        for entry in self.temps_in_use:
-            code.put_var_decref_clear(entry)
-        # free temps the new way
         for cname, type in code.funcstate.temps_holding_reference():
             code.put_decref_clear(cname, type)
-        #code.putln(
-        #    "goto %s;" %
-        #        code.return_label)
         code.put_goto(code.return_label)
         
     def annotate(self, code):
@@ -3474,25 +3440,16 @@ class RaiseStatNode(StatNode):
         if self.exc_type:
             self.exc_type.analyse_types(env)
             self.exc_type = self.exc_type.coerce_to_pyobject(env)
-            self.exc_type.allocate_temps(env)
         if self.exc_value:
             self.exc_value.analyse_types(env)
             self.exc_value = self.exc_value.coerce_to_pyobject(env)
-            self.exc_value.allocate_temps(env)
         if self.exc_tb:
             self.exc_tb.analyse_types(env)
             self.exc_tb = self.exc_tb.coerce_to_pyobject(env)
-            self.exc_tb.allocate_temps(env)
-        if self.exc_type:
-            self.exc_type.release_temp(env)
-        if self.exc_value:
-            self.exc_value.release_temp(env)
-        if self.exc_tb:
-            self.exc_tb.release_temp(env)
         env.use_utility_code(raise_utility_code)
         env.use_utility_code(restore_exception_utility_code)
-        self.gil_check(env)
 
+    nogil_check = Node.gil_error
     gil_message = "Raising exception"
 
     def generate_execution_code(self, code):
@@ -3541,10 +3498,10 @@ class ReraiseStatNode(StatNode):
     child_attrs = []
 
     def analyse_expressions(self, env):
-        self.gil_check(env)
         env.use_utility_code(raise_utility_code)
         env.use_utility_code(restore_exception_utility_code)
 
+    nogil_check = Node.gil_error
     gil_message = "Raising exception"
 
     def generate_execution_code(self, code):
@@ -3569,13 +3526,8 @@ class AssertStatNode(StatNode):
         if self.value:
             self.value.analyse_types(env)
             self.value = self.value.coerce_to_pyobject(env)
-            self.value.allocate_temps(env)
-        self.cond.release_temp(env)
-        if self.value:
-            self.value.release_temp(env)
-        self.gil_check(env)
-        #env.recycle_pending_temps() # TEMPORARY
 
+    nogil_check = Node.gil_error
     gil_message = "Raising exception"
     
     def generate_execution_code(self, code):
@@ -3673,7 +3625,6 @@ class IfClauseNode(Node):
     def analyse_expressions(self, env):
         self.condition = \
             self.condition.analyse_temp_boolean_expression(env)
-        self.condition.release_temp(env)
         self.body.analyse_expressions(env)
     
     def generate_execution_code(self, code, end_label):
@@ -3702,11 +3653,12 @@ class SwitchCaseNode(StatNode):
     # body          StatNode
     
     child_attrs = ['conditions', 'body']
-    
+
     def generate_execution_code(self, code):
         for cond in self.conditions:
             code.mark_pos(cond.pos)
-            code.putln("case %s:" % cond.calculate_result_code())
+            cond.generate_evaluation_code(code)
+            code.putln("case %s:" % cond.result())
         self.body.generate_execution_code(code)
         code.putln("break;")
         
@@ -3725,7 +3677,7 @@ class SwitchStatNode(StatNode):
     child_attrs = ['test', 'cases', 'else_clause']
     
     def generate_execution_code(self, code):
-        code.putln("switch (%s) {" % self.test.calculate_result_code())
+        code.putln("switch (%s) {" % self.test.result())
         for case in self.cases:
             case.generate_execution_code(code)
         if self.else_clause is not None:
@@ -3769,8 +3721,6 @@ class WhileStatNode(LoopNode, StatNode):
     def analyse_expressions(self, env):
         self.condition = \
             self.condition.analyse_temp_boolean_expression(env)
-        self.condition.release_temp(env)
-        #env.recycle_pending_temps() # TEMPORARY
         self.body.analyse_expressions(env)
         if self.else_clause:
             self.else_clause.analyse_expressions(env)
@@ -3833,14 +3783,9 @@ class ForInStatNode(LoopNode, StatNode):
         self.iterator.analyse_expressions(env)
         self.item = ExprNodes.NextNode(self.iterator, env)
         self.item = self.item.coerce_to(self.target.type, env)
-        self.item.allocate_temps(env)
-        self.target.allocate_target_temps(env, self.item)
-        #self.item.release_temp(env)
-        #self.target.release_target_temp(env)
         self.body.analyse_expressions(env)
         if self.else_clause:
             self.else_clause.analyse_expressions(env)
-        self.iterator.release_temp(env)
 
     def generate_execution_code(self, code):
         old_loop_labels = code.new_loop_labels()
@@ -3888,6 +3833,7 @@ class ForFromStatNode(LoopNode, StatNode):
     #
     #  Used internally:
     #
+    #  from_range         bool
     #  is_py_target       bool
     #  loopvar_node       ExprNode (usually a NameNode or temp node)
     #  py_loopvar_node    PyTempNode or None
@@ -3896,6 +3842,14 @@ class ForFromStatNode(LoopNode, StatNode):
     is_py_target = False
     loopvar_node = None
     py_loopvar_node = None
+    from_range = False
+
+    gil_message = "For-loop using object bounds or target"
+
+    def nogil_check(self, env):
+        for x in (self.target, self.bound1, self.bound2):
+            if x.type.is_pyobject:
+                self.gil_error()
 
     def analyse_declarations(self, env):
         self.target.analyse_target_declaration(env)
@@ -3908,105 +3862,115 @@ class ForFromStatNode(LoopNode, StatNode):
         self.target.analyse_target_types(env)
         self.bound1.analyse_types(env)
         self.bound2.analyse_types(env)
-        if self.target.type.is_numeric:
-            self.bound1 = self.bound1.coerce_to(self.target.type, env)
-            self.bound2 = self.bound2.coerce_to(self.target.type, env)
-        else:
-            self.bound1 = self.bound1.coerce_to_integer(env)
-            self.bound2 = self.bound2.coerce_to_integer(env)
         if self.step is not None:
             if isinstance(self.step, ExprNodes.UnaryMinusNode):
                 warning(self.step.pos, "Probable infinite loop in for-from-by statment. Consider switching the directions of the relations.", 2)
             self.step.analyse_types(env)
-            self.step = self.step.coerce_to_integer(env)
-        if not (self.bound2.is_name or self.bound2.is_literal):
+        
+        target_type = self.target.type
+        if self.target.type.is_numeric:
+            loop_type = self.target.type
+        else:
+            loop_type = PyrexTypes.c_int_type
+            if not self.bound1.type.is_pyobject:
+                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound1.type)
+            if not self.bound2.type.is_pyobject:
+                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.bound2.type)
+            if self.step is not None and not self.step.type.is_pyobject:
+                loop_type = PyrexTypes.widest_numeric_type(loop_type, self.step.type)
+        self.bound1 = self.bound1.coerce_to(loop_type, env)
+        self.bound2 = self.bound2.coerce_to(loop_type, env)
+        if not self.bound2.is_literal:
             self.bound2 = self.bound2.coerce_to_temp(env)
+        if self.step is not None:
+            self.step = self.step.coerce_to(loop_type, env)            
+            if not self.step.is_literal:
+                self.step = self.step.coerce_to_temp(env)
+
         target_type = self.target.type
         if not (target_type.is_pyobject or target_type.is_numeric):
             error(self.target.pos,
-                "Integer for-loop variable must be of type int or Python object")
-        #if not (target_type.is_pyobject
-        #    or target_type.assignable_from(PyrexTypes.c_int_type)):
-        #        error(self.target.pos,
-        #            "Cannot assign integer to variable of type '%s'" % target_type)
+                "for-from loop variable must be c numeric type or Python object")
         if target_type.is_numeric:
-            self.is_py_target = 0
+            self.is_py_target = False
             if isinstance(self.target, ExprNodes.IndexNode) and self.target.is_buffer_access:
                 raise error(self.pos, "Buffer indexing not allowed as for loop target.")
             self.loopvar_node = self.target
             self.py_loopvar_node = None
         else:
-            self.is_py_target = 1
-            c_loopvar_node = ExprNodes.TempNode(self.pos, 
-                PyrexTypes.c_long_type, env)
-            c_loopvar_node.allocate_temps(env)
+            self.is_py_target = True
+            c_loopvar_node = ExprNodes.TempNode(self.pos, loop_type, env)
             self.loopvar_node = c_loopvar_node
             self.py_loopvar_node = \
                 ExprNodes.CloneNode(c_loopvar_node).coerce_to_pyobject(env)
-        self.bound1.allocate_temps(env)
-        self.bound2.allocate_temps(env)
-        if self.step is not None:
-            self.step.allocate_temps(env)
-        if self.is_py_target:
-            self.py_loopvar_node.allocate_temps(env)
-            self.target.allocate_target_temps(env, self.py_loopvar_node)
-            #self.target.release_target_temp(env)
-            #self.py_loopvar_node.release_temp(env)
         self.body.analyse_expressions(env)
-        if self.is_py_target:
-            c_loopvar_node.release_temp(env)
         if self.else_clause:
             self.else_clause.analyse_expressions(env)
-        self.bound1.release_temp(env)
-        self.bound2.release_temp(env)
-        if self.step is not None:
-            self.step.release_temp(env)
             
     def generate_execution_code(self, code):
         old_loop_labels = code.new_loop_labels()
-        from_range = getattr(self, "from_range", False)
+        from_range = self.from_range
         self.bound1.generate_evaluation_code(code)
         self.bound2.generate_evaluation_code(code)
         offset, incop = self.relation_table[self.relation1]
-        if incop == "++":
-            decop = "--"
-        else:
-            decop = "++"
         if self.step is not None:
             self.step.generate_evaluation_code(code)
             step = self.step.result()
             incop = "%s=%s" % (incop[0], step)
-            decop = "%s=%s" % (decop[0], step)
-        loopvar_name = self.loopvar_node.result()
+        import ExprNodes
+        if isinstance(self.loopvar_node, ExprNodes.TempNode):
+            self.loopvar_node.allocate(code)
+        if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
+            self.py_loopvar_node.allocate(code)
         if from_range:
-            range_bound = code.funcstate.allocate_temp(self.bound2.type, manage_ref=False)
-            code.putln("%s = %s;" % (range_bound, self.bound2.result()))
-            # Skip the loop entirely (and avoid assigning to the loopvar) if
-            # the loop is empty:
-            code.putln("if (%s%s %s %s) {" % (
-                self.bound1.result(), offset, self.relation2, range_bound
-                ))
+            loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
         else:
-            range_bound = self.bound2.result()
+            loopvar_name = self.loopvar_node.result()
         code.putln(
             "for (%s = %s%s; %s %s %s; %s%s) {" % (
                 loopvar_name,
                 self.bound1.result(), offset,
-                loopvar_name, self.relation2, range_bound,
+                loopvar_name, self.relation2, self.bound2.result(),
                 loopvar_name, incop))
         if self.py_loopvar_node:
             self.py_loopvar_node.generate_evaluation_code(code)
             self.target.generate_assignment_code(self.py_loopvar_node, code)
+        elif from_range:
+            code.putln("%s = %s;" % (
+                            self.target.result(), loopvar_name))
         self.body.generate_execution_code(code)
         code.put_label(code.continue_label)
-        if from_range:
-            # Undo last increment to maintain Python semantics:
-            code.putln("} %s%s;" % (loopvar_name, decop))
-            # End the outer if statement:
-            code.putln("} /* end if */")
-            code.funcstate.release_temp(range_bound)
-        else:
-            code.putln("}")
+        if self.py_loopvar_node:
+            # This mess is to make for..from loops with python targets behave 
+            # exactly like those with C targets with regards to re-assignment 
+            # of the loop variable. 
+            import ExprNodes
+            if self.target.entry.is_pyglobal:
+                # We know target is a NameNode, this is the only ugly case. 
+                target_node = ExprNodes.PyTempNode(self.target.pos, None)
+                target_node.allocate(code)
+                interned_cname = code.intern_identifier(self.target.entry.name)
+                code.putln("/*here*/")
+                code.putln("%s = __Pyx_GetName(%s, %s); %s" % (
+                                target_node.result(),
+                                Naming.module_cname, 
+                                interned_cname,
+                                code.error_goto_if_null(target_node.result(), self.target.pos)))
+                code.put_gotref(target_node.result())
+            else:
+                target_node = self.target
+            from_py_node = ExprNodes.CoerceFromPyTypeNode(self.loopvar_node.type, target_node, None)
+            from_py_node.temp_code = loopvar_name
+            from_py_node.generate_result_code(code)
+            if self.target.entry.is_pyglobal:
+                code.put_decref(target_node.result(), target_node.type)
+                target_node.release(code)
+        code.putln("}")
+        if self.py_loopvar_node:
+            # This is potentially wasteful, but we don't want the semantics to 
+            # depend on whether or not the loop is a python type. 
+            self.py_loopvar_node.generate_evaluation_code(code)
+            self.target.generate_assignment_code(self.py_loopvar_node, code)
         break_label = code.break_label
         code.set_loop_labels(old_loop_labels)
         if self.else_clause:
@@ -4018,6 +3982,10 @@ class ForFromStatNode(LoopNode, StatNode):
         self.bound1.free_temps(code)
         self.bound2.generate_disposal_code(code)
         self.bound2.free_temps(code)
+        if isinstance(self.loopvar_node, ExprNodes.TempNode):
+            self.loopvar_node.release(code)
+        if isinstance(self.py_loopvar_node, ExprNodes.TempNode):
+            self.py_loopvar_node.release(code)
         if self.step is not None:
             self.step.generate_disposal_code(code)
             self.step.free_temps(code)
@@ -4059,7 +4027,6 @@ class TryExceptStatNode(StatNode):
     #  body             StatNode
     #  except_clauses   [ExceptClauseNode]
     #  else_clause      StatNode or None
-    #  cleanup_list     [Entry]            old style temps to clean up on error
 
     child_attrs = ["body", "except_clauses", "else_clause"]
     
@@ -4087,12 +4054,10 @@ class TryExceptStatNode(StatNode):
             except_clause.analyse_declarations(env)
         if self.else_clause:
             self.else_clause.analyse_declarations(env)
-        self.gil_check(env)
         env.use_utility_code(reset_exception_utility_code)
-    
+
     def analyse_expressions(self, env):
         self.body.analyse_expressions(env)
-        self.cleanup_list = env.free_temp_entries[:]
         default_clause_seen = 0
         for except_clause in self.except_clauses:
             except_clause.analyse_expressions(env)
@@ -4103,8 +4068,8 @@ class TryExceptStatNode(StatNode):
         self.has_default_clause = default_clause_seen
         if self.else_clause:
             self.else_clause.analyse_expressions(env)
-        self.gil_check(env)
 
+    nogil_check = Node.gil_error
     gil_message = "Try-except statement"
 
     def generate_execution_code(self, code):
@@ -4154,7 +4119,6 @@ class TryExceptStatNode(StatNode):
                 code.put_xdecref_clear(var, py_object_type)
             code.put_goto(old_return_label)
         code.put_label(our_error_label)
-        code.put_var_xdecrefs_clear(self.cleanup_list)
         for temp_name, type in temps_to_clean_up:
             code.put_xdecref_clear(temp_name, type)
         for except_clause in self.except_clauses:
@@ -4245,68 +4209,49 @@ class ExceptClauseNode(Node):
         if self.pattern:
             self.pattern.analyse_expressions(env)
             self.pattern = self.pattern.coerce_to_pyobject(env)
-            self.match_flag = env.allocate_temp(PyrexTypes.c_int_type)
-            self.pattern.release_temp(env)
-            env.release_temp(self.match_flag)
-
-        if self.target or self.excinfo_target:
-            self.exc_vars = [env.allocate_temp(py_object_type) for i in xrange(3)]
-        else:
-            self.exc_vars = None
 
         if self.target:
-            self.exc_value = ExprNodes.ExcValueNode(self.pos, env, self.exc_vars[1])
-            self.exc_value.allocate_temps(env)
+            self.exc_value = ExprNodes.ExcValueNode(self.pos, env)
             self.target.analyse_target_expression(env, self.exc_value)
         if self.excinfo_target is not None:
             import ExprNodes
             self.excinfo_tuple = ExprNodes.TupleNode(pos=self.pos, args=[
-                ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[0]),
-                ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[1]),
-                ExprNodes.ExcValueNode(pos=self.pos, env=env, var=self.exc_vars[2])
-            ])
+                ExprNodes.ExcValueNode(pos=self.pos, env=env) for x in range(3)])
             self.excinfo_tuple.analyse_expressions(env)
-            self.excinfo_tuple.allocate_temps(env)
             self.excinfo_target.analyse_target_expression(env, self.excinfo_tuple)
 
         self.body.analyse_expressions(env)
 
-        if self.exc_vars:
-            for var in self.exc_vars:
-                env.release_temp(var)
-    
     def generate_handling_code(self, code, end_label):
         code.mark_pos(self.pos)
         if self.pattern:
             self.pattern.generate_evaluation_code(code)
+            
+            match_flag = code.funcstate.allocate_temp(PyrexTypes.c_int_type, False)
             code.putln(
                 "%s = PyErr_ExceptionMatches(%s);" % (
-                    self.match_flag,
+                    match_flag,
                     self.pattern.py_result()))
             self.pattern.generate_disposal_code(code)
             self.pattern.free_temps(code)
             code.putln(
                 "if (%s) {" %
-                    self.match_flag)
+                    match_flag)
+            code.funcstate.release_temp(match_flag)
         else:
             code.putln("/*except:*/ {")
 
-        if self.exc_vars:
-            exc_vars = self.exc_vars
-        elif not getattr(self.body, 'stats', True):
+        if not getattr(self.body, 'stats', True):
             # most simple case: no exception variable, empty body (pass)
             # => reset the exception state, done
             code.putln("PyErr_Restore(0,0,0);")
             code.put_goto(end_label)
             code.putln("}")
             return
-        else:
-            # during type analysis, we didn't know if we need the
-            # exception value, but apparently, we do
-            exc_vars = [code.funcstate.allocate_temp(py_object_type,
-                                                     manage_ref=True)
-                        for i in xrange(3)]
-
+        
+        exc_vars = [code.funcstate.allocate_temp(py_object_type,
+                                                 manage_ref=True)
+                    for i in xrange(3)]
         code.putln('__Pyx_AddTraceback("%s");' % self.function_name)
         # We always have to fetch the exception value even if
         # there is no target, because this also normalises the 
@@ -4318,13 +4263,15 @@ class ExceptClauseNode(Node):
         for x in exc_vars:
             code.put_gotref(x)
         if self.target:
+            self.exc_value.set_var(exc_vars[1])
             self.exc_value.generate_evaluation_code(code)
             self.target.generate_assignment_code(self.exc_value, code)
         if self.excinfo_target is not None:
+            for tempvar, node in zip(exc_vars, self.excinfo_tuple.args):
+                node.set_var(tempvar)
             self.excinfo_tuple.generate_evaluation_code(code)
             self.excinfo_target.generate_assignment_code(self.excinfo_tuple, code)
 
-
         old_break_label, old_continue_label = code.break_label, code.continue_label
         code.break_label = code.new_label('except_break')
         code.continue_label = code.new_label('except_continue')
@@ -4351,10 +4298,8 @@ class ExceptClauseNode(Node):
             code.put_goto(old_continue_label)
         code.continue_label = old_continue_label
 
-        if not self.exc_vars:
-            # clean up locally allocated temps
-            for temp in exc_vars:
-                code.funcstate.release_temp(temp)
+        for temp in exc_vars:
+            code.funcstate.release_temp(temp)
 
         code.putln(
             "}")
@@ -4373,8 +4318,6 @@ class TryFinallyStatNode(StatNode):
     #  body             StatNode
     #  finally_clause   StatNode
     #
-    #  cleanup_list     [Entry]     old_style temps to clean up on error
-    #
     #  The plan is that we funnel all continue, break
     #  return and error gotos into the beginning of the
     #  finally block, setting a variable to remember which
@@ -4395,7 +4338,6 @@ class TryFinallyStatNode(StatNode):
 
     def create_analysed(pos, env, body, finally_clause):
         node = TryFinallyStatNode(pos, body=body, finally_clause=finally_clause)
-        node.cleanup_list = []
         return node
     create_analysed = staticmethod(create_analysed)
     
@@ -4412,10 +4354,9 @@ class TryFinallyStatNode(StatNode):
     
     def analyse_expressions(self, env):
         self.body.analyse_expressions(env)
-        self.cleanup_list = env.free_temp_entries[:]
         self.finally_clause.analyse_expressions(env)
-        self.gil_check(env)
 
+    nogil_check = Node.gil_error
     gil_message = "Try-finally statement"
 
     def generate_execution_code(self, code):
@@ -4518,7 +4459,6 @@ class TryFinallyStatNode(StatNode):
         code.putln(
                 "__pyx_why = %s;" %
                     i)
-        code.put_var_xdecrefs_clear(self.cleanup_list)
         for temp_name, type in temps_to_clean_up:
             code.put_xdecref_clear(temp_name, type)
         code.putln(
@@ -4562,8 +4502,8 @@ class GILStatNode(TryFinallyStatNode):
     #  'with gil' or 'with nogil' statement
     #
     #   state   string   'gil' or 'nogil'
-        
-    child_attrs = []
+
+#    child_attrs = []
     
     preserve_exception = 0
 
@@ -4580,8 +4520,7 @@ class GILStatNode(TryFinallyStatNode):
         TryFinallyStatNode.analyse_expressions(self, env)
         env.nogil = was_nogil
 
-    def gil_check(self, env):
-        pass
+    nogil_check = None
 
     def generate_execution_code(self, code):
         code.mark_pos(self.pos)
@@ -4679,8 +4618,12 @@ class FromCImportStatNode(StatNode):
                         entry = module_scope.declare_c_class(name, pos = pos,
                             module_name = self.module_name)
                     else:
-                        error(pos, "Name '%s' not declared in module '%s'"
-                            % (name, self.module_name))
+                        submodule_scope = env.context.find_module(name, relative_to = module_scope, pos = self.pos)
+                        if submodule_scope.parent_module is module_scope:
+                            env.declare_module(as_name or name, submodule_scope, self.pos)
+                        else:
+                            error(pos, "Name '%s' not declared in module '%s'"
+                                % (name, self.module_name))
                         
                 if entry:
                     local_name = as_name or name
@@ -4734,7 +4677,6 @@ class FromImportStatNode(StatNode):
         import ExprNodes
         self.module.analyse_expressions(env)
         self.item = ExprNodes.PyTempNode(self.pos, env)
-        self.item.allocate_temp(env)
         self.interned_items = []
         for name, target in self.items:
             if name == '*':
@@ -4752,10 +4694,7 @@ class FromImportStatNode(StatNode):
                 else:
                     coerced_item = self.item.coerce_to(target.type, env)
                 self.interned_items.append(
-                    (env.intern_identifier(name), target, coerced_item))
-                #target.release_target_temp(env) # was release_temp ?!?
-        self.module.release_temp(env)
-        self.item.release_temp(env)
+                    (name, target, coerced_item))
     
     def generate_execution_code(self, code):
         self.module.generate_evaluation_code(code)
@@ -4765,7 +4704,9 @@ class FromImportStatNode(StatNode):
                     Naming.import_star,
                     self.module.py_result(),
                     code.error_goto(self.pos)))
-        for cname, target, coerced_item in self.interned_items:
+        self.item.allocate(code)
+        for name, target, coerced_item in self.interned_items:
+            cname = code.intern_identifier(name)
             code.putln(
                 '%s = PyObject_GetAttr(%s, %s); %s' % (
                     self.item.result(), 
@@ -4781,6 +4722,7 @@ class FromImportStatNode(StatNode):
                 target.generate_assignment_code(coerced_item, code)
                 if self.item.result() != coerced_item.result():
                     code.put_decref_clear(self.item.result(), self.item.type)
+        self.item.release(code)
         self.module.generate_disposal_code(code)
         self.module.free_temps(code)
 
@@ -4974,7 +4916,8 @@ static int __Pyx_PrintOne(PyObject *o) {
 }
 
 #endif
-""")
+""",
+requires=[printing_utility_code])
 
 
 
@@ -5339,32 +5282,6 @@ bad:
 
 #------------------------------------------------------------------------------------
 
-unraisable_exception_utility_code = UtilityCode(
-proto = """
-static void __Pyx_WriteUnraisable(const char *name); /*proto*/
-""",
-impl = """
-static void __Pyx_WriteUnraisable(const char *name) {
-    PyObject *old_exc, *old_val, *old_tb;
-    PyObject *ctx;
-    __Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
-    #if PY_MAJOR_VERSION < 3
-    ctx = PyString_FromString(name);
-    #else
-    ctx = PyUnicode_FromString(name);
-    #endif
-    __Pyx_ErrRestore(old_exc, old_val, old_tb);
-    if (!ctx) {
-        PyErr_WriteUnraisable(Py_None);
-    } else {
-        PyErr_WriteUnraisable(ctx);
-        Py_DECREF(ctx);
-    }
-}
-""")
-
-#------------------------------------------------------------------------------------
-
 traceback_utility_code = UtilityCode(
 proto = """
 static void __Pyx_AddTraceback(const char *funcname); /*proto*/
@@ -5378,7 +5295,6 @@ static void __Pyx_AddTraceback(const char *funcname) {
     PyObject *py_srcfile = 0;
     PyObject *py_funcname = 0;
     PyObject *py_globals = 0;
-    PyObject *empty_string = 0;
     PyCodeObject *py_code = 0;
     PyFrameObject *py_frame = 0;
 
@@ -5405,12 +5321,6 @@ static void __Pyx_AddTraceback(const char *funcname) {
     if (!py_funcname) goto bad;
     py_globals = PyModule_GetDict(%(GLOBALS)s);
     if (!py_globals) goto bad;
-    #if PY_MAJOR_VERSION < 3
-    empty_string = PyString_FromStringAndSize("", 0);
-    #else
-    empty_string = PyBytes_FromStringAndSize("", 0);
-    #endif
-    if (!empty_string) goto bad;
     py_code = PyCode_New(
         0,            /*int argcount,*/
         #if PY_MAJOR_VERSION >= 3
@@ -5419,7 +5329,7 @@ static void __Pyx_AddTraceback(const char *funcname) {
         0,            /*int nlocals,*/
         0,            /*int stacksize,*/
         0,            /*int flags,*/
-        empty_string, /*PyObject *code,*/
+        %(EMPTY_BYTES)s, /*PyObject *code,*/
         %(EMPTY_TUPLE)s,  /*PyObject *consts,*/
         %(EMPTY_TUPLE)s,  /*PyObject *names,*/
         %(EMPTY_TUPLE)s,  /*PyObject *varnames,*/
@@ -5428,7 +5338,7 @@ static void __Pyx_AddTraceback(const char *funcname) {
         py_srcfile,   /*PyObject *filename,*/
         py_funcname,  /*PyObject *name,*/
         %(LINENO)s,   /*int firstlineno,*/
-        empty_string  /*PyObject *lnotab*/
+        %(EMPTY_BYTES)s  /*PyObject *lnotab*/
     );
     if (!py_code) goto bad;
     py_frame = PyFrame_New(
@@ -5443,7 +5353,6 @@ static void __Pyx_AddTraceback(const char *funcname) {
 bad:
     Py_XDECREF(py_srcfile);
     Py_XDECREF(py_funcname);
-    Py_XDECREF(empty_string);
     Py_XDECREF(py_code);
     Py_XDECREF(py_frame);
 }
@@ -5454,6 +5363,7 @@ bad:
     'CLINENO':  Naming.clineno_cname,
     'GLOBALS': Naming.module_cname,
     'EMPTY_TUPLE' : Naming.empty_tuple,
+    'EMPTY_BYTES' : Naming.empty_bytes,
 })
 
 restore_exception_utility_code = UtilityCode(
@@ -5509,6 +5419,33 @@ static INLINE void __Pyx_ErrFetch(PyObject **type, PyObject **value, PyObject **
 
 #------------------------------------------------------------------------------------
 
+unraisable_exception_utility_code = UtilityCode(
+proto = """
+static void __Pyx_WriteUnraisable(const char *name); /*proto*/
+""",
+impl = """
+static void __Pyx_WriteUnraisable(const char *name) {
+    PyObject *old_exc, *old_val, *old_tb;
+    PyObject *ctx;
+    __Pyx_ErrFetch(&old_exc, &old_val, &old_tb);
+    #if PY_MAJOR_VERSION < 3
+    ctx = PyString_FromString(name);
+    #else
+    ctx = PyUnicode_FromString(name);
+    #endif
+    __Pyx_ErrRestore(old_exc, old_val, old_tb);
+    if (!ctx) {
+        PyErr_WriteUnraisable(Py_None);
+    } else {
+        PyErr_WriteUnraisable(ctx);
+        Py_DECREF(ctx);
+    }
+}
+""",
+requires=[restore_exception_utility_code])
+
+#------------------------------------------------------------------------------------
+
 set_vtable_utility_code = UtilityCode(
 proto = """
 static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
@@ -5641,6 +5578,31 @@ bad:
 
 #------------------------------------------------------------------------------------
 
+get_exception_tuple_utility_code = UtilityCode(proto="""
+static PyObject *__Pyx_GetExceptionTuple(void); /*proto*/
+""",
+impl = """
+static PyObject *__Pyx_GetExceptionTuple(void) {
+    PyObject *type = NULL, *value = NULL, *tb = NULL;
+    if (__Pyx_GetException(&type, &value, &tb) == 0) {
+        PyObject* exc_info = PyTuple_New(3);
+        if (exc_info) {
+            Py_INCREF(type);
+            Py_INCREF(value);
+            Py_INCREF(tb);
+            PyTuple_SET_ITEM(exc_info, 0, type);
+            PyTuple_SET_ITEM(exc_info, 1, value);
+            PyTuple_SET_ITEM(exc_info, 2, tb);
+            return exc_info;
+        }
+    }
+    return NULL;
+}
+""",
+requires=[get_exception_utility_code])
+
+#------------------------------------------------------------------------------------
+
 reset_exception_utility_code = UtilityCode(
 proto = """
 static INLINE void __Pyx_ExceptionSave(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
@@ -5686,3 +5648,143 @@ proto="""
 """)
 
 #------------------------------------------------------------------------------------
+
+# Note that cPython ignores PyTrace_EXCEPTION, 
+# but maybe some other profilers don't. 
+
+profile_utility_code = UtilityCode(proto="""
+#ifndef CYTHON_PROFILE
+#define CYTHON_PROFILE 1
+#endif
+
+#ifndef CYTHON_PROFILE_REUSE_FRAME
+#define CYTHON_PROFILE_REUSE_FRAME 0
+#endif
+
+#if CYTHON_PROFILE
+
+#include "compile.h"
+#include "frameobject.h"
+#include "traceback.h"
+
+#if CYTHON_PROFILE_REUSE_FRAME
+#define CYTHON_FRAME_MODIFIER static
+#define CYTHON_FRAME_DEL
+#else
+#define CYTHON_FRAME_MODIFIER
+#define CYTHON_FRAME_DEL Py_DECREF(%(FRAME)s)
+#endif
+
+#define __Pyx_TraceCall(funcname, srcfile, firstlineno)                            \\
+static PyCodeObject *%(FRAME_CODE)s = NULL;                                        \\
+CYTHON_FRAME_MODIFIER PyFrameObject *%(FRAME)s = NULL;                             \\
+int __Pyx_use_tracing = 0;                                                         \\
+if (unlikely(PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc)) {      \\
+    __Pyx_use_tracing = __Pyx_TraceSetupAndCall(&%(FRAME_CODE)s, &%(FRAME)s, funcname, srcfile, firstlineno);  \\
+}
+
+#define __Pyx_TraceException()                                                           \\
+if (unlikely(__Pyx_use_tracing( && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) {  \\
+    PyObject *exc_info = __Pyx_GetExceptionTuple();                                      \\
+    if (exc_info) {                                                                      \\
+        PyThreadState_GET()->c_profilefunc(                                              \\
+            PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_EXCEPTION, exc_info);  \\
+        Py_DECREF(exc_info);                                                             \\
+    }                                                                                    \\
+}
+
+#define __Pyx_TraceReturn(result)                                                  \\
+if (unlikely(__Pyx_use_tracing) && PyThreadState_GET()->use_tracing && PyThreadState_GET()->c_profilefunc) {  \\
+    PyThreadState_GET()->c_profilefunc(                                            \\
+        PyThreadState_GET()->c_profileobj, %(FRAME)s, PyTrace_RETURN, (PyObject*)result);     \\
+    CYTHON_FRAME_DEL;                                                               \\
+}
+
+static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno); /*proto*/
+static int __Pyx_TraceSetupAndCall(PyCodeObject** code, PyFrameObject** frame, const char *funcname, const char *srcfile, int firstlineno); /*proto*/
+
+#else
+#define __Pyx_TraceCall(funcname, srcfile, firstlineno) 
+#define __Pyx_TraceException() 
+#define __Pyx_TraceReturn(result) 
+#endif /* CYTHON_PROFILE */
+""" 
+% {
+    "FRAME": Naming.frame_cname,
+    "FRAME_CODE": Naming.frame_code_cname,
+},
+impl = """
+
+#if CYTHON_PROFILE
+
+static int __Pyx_TraceSetupAndCall(PyCodeObject** code,
+                                   PyFrameObject** frame,
+                                   const char *funcname,
+                                   const char *srcfile,
+                                   int firstlineno) {
+    if (*frame == NULL || !CYTHON_PROFILE_REUSE_FRAME) {
+        if (*code == NULL) {
+            *code = __Pyx_createFrameCodeObject(funcname, srcfile, firstlineno);
+            if (*code == NULL) return 0;
+        }
+        *frame = PyFrame_New(
+            PyThreadState_GET(),            /*PyThreadState *tstate*/
+            *code,                          /*PyCodeObject *code*/
+            PyModule_GetDict(%(MODULE)s),      /*PyObject *globals*/
+            0                               /*PyObject *locals*/
+        );
+        if (*frame == NULL) return 0;
+    }
+    else {
+        (*frame)->f_tstate = PyThreadState_GET();
+    }
+    return PyThreadState_GET()->c_profilefunc(PyThreadState_GET()->c_profileobj, *frame, PyTrace_CALL, NULL) == 0;
+}
+
+static PyCodeObject *__Pyx_createFrameCodeObject(const char *funcname, const char *srcfile, int firstlineno) {
+    PyObject *py_srcfile = 0;
+    PyObject *py_funcname = 0;
+    PyCodeObject *py_code = 0;
+
+    #if PY_MAJOR_VERSION < 3
+    py_funcname = PyString_FromString(funcname);
+    py_srcfile = PyString_FromString(srcfile);
+    #else
+    py_funcname = PyUnicode_FromString(funcname);
+    py_srcfile = PyUnicode_FromString(srcfile);
+    #endif
+    if (!py_funcname | !py_srcfile) goto bad;
+
+    py_code = PyCode_New(
+        0,                /*int argcount,*/
+        #if PY_MAJOR_VERSION >= 3
+        0,                /*int kwonlyargcount,*/
+        #endif
+        0,                /*int nlocals,*/
+        0,                /*int stacksize,*/
+        0,                /*int flags,*/
+        %(EMPTY_BYTES)s,  /*PyObject *code,*/
+        %(EMPTY_TUPLE)s,  /*PyObject *consts,*/
+        %(EMPTY_TUPLE)s,  /*PyObject *names,*/
+        %(EMPTY_TUPLE)s,  /*PyObject *varnames,*/
+        %(EMPTY_TUPLE)s,  /*PyObject *freevars,*/
+        %(EMPTY_TUPLE)s,  /*PyObject *cellvars,*/
+        py_srcfile,       /*PyObject *filename,*/
+        py_funcname,      /*PyObject *name,*/
+        firstlineno,      /*int firstlineno,*/
+        %(EMPTY_BYTES)s   /*PyObject *lnotab*/
+    );
+
+bad: 
+    Py_XDECREF(py_srcfile);
+    Py_XDECREF(py_funcname);
+    
+    return py_code;
+}
+
+#endif /* CYTHON_PROFILE */
+""" % {
+    'EMPTY_TUPLE' : Naming.empty_tuple,
+    'EMPTY_BYTES' : Naming.empty_bytes,
+    "MODULE": Naming.module_cname,
+})