-devel mergeback
[cython.git] / Cython / Compiler / Nodes.py
index d87de5109f1c219b7f5f17601dbc1d62b5fea6d8..a3e78a9f7976db801363e0a294d67ad274e1d607 100644 (file)
@@ -13,14 +13,13 @@ 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
 import DebugFlags
 
-from DebugFlags import debug_disposal_code
-
 absolute_path_length = 0
 
 def relative_position(pos):
@@ -134,12 +133,9 @@ class Node(object):
     
     gil_message = "Operation"
 
-    gil_check = None
-    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):
@@ -457,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.get_constant_result_code()
-            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():
@@ -517,7 +514,8 @@ class CFuncDeclaratorNode(CDeclaratorNode):
         
         if self.optional_arg_count:
             scope = StructOrUnionScope()
-            scope.declare_var('%sn' % Naming.pyrex_prefix, PyrexTypes.c_int_type, self.pos)
+            arg_count_member = '%sn' % Naming.pyrex_prefix
+            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)
@@ -532,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 != '+':
@@ -540,7 +540,7 @@ class CFuncDeclaratorNode(CDeclaratorNode):
         else:
             if self.exception_value:
                 self.exception_value.analyse_const_expression(env)
-                exc_val = self.exception_value.get_constant_result_code()
+                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 \
@@ -567,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)
 
 
@@ -648,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 = []
@@ -688,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:
@@ -721,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
 
@@ -761,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 
@@ -814,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
@@ -850,7 +875,8 @@ class CStructOrUnionDefNode(StatNode):
                         cname = self.cname, visibility='ignore')
                     struct_entry.type.typedef_flag = False
                     # FIXME: this might be considered a hack ;-)
-                    struct_entry.cname = struct_entry.type.cname = '_' + self.cname
+                    struct_entry.cname = struct_entry.type.cname = \
+                                         '_' + self.entry.type.typedef_cname
     
     def analyse_expressions(self, env):
         pass
@@ -881,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):
@@ -955,19 +982,25 @@ 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:
                     arg.default.analyse_types(env)
                     arg.default = arg.default.coerce_to(arg.type, genv)
-                    arg.default.allocate_temps(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
@@ -985,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):
@@ -994,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()
@@ -1030,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:
@@ -1078,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)
 
@@ -1099,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'." \
@@ -1128,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:
@@ -1162,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);")
 
@@ -1170,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()
@@ -1262,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))
@@ -1295,7 +1342,12 @@ class CFuncDefNode(FuncDefNode):
         self.entry.inline_func_in_pxd = self.inline_in_pxd
         self.return_type = type.return_type
         
-        if self.overridable and len(self.args) > 0:
+        if self.overridable and not env.is_module_scope:
+            if len(self.args) < 1 or not self.args[0].type.is_pyobject:
+                # An error will be produced in the cdef function
+                self.overridable = False
+            
+        if self.overridable:
             import ExprNodes
             py_func_body = self.call_self_node(is_module_scope = env.is_module_scope)
             self.py_func = DefNode(pos = self.pos, 
@@ -1339,23 +1391,25 @@ class CFuncDefNode(FuncDefNode):
     def need_gil_acquisition(self, lenv):
         return self.type.with_gil
 
-    def gil_check(self, env):
+    def nogil_check(self, env):
         type = self.type
         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 env.var_entries + env.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")
 
     def analyse_expressions(self, 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 = []
@@ -1407,6 +1461,8 @@ class CFuncDefNode(FuncDefNode):
             code.putln('if (%s) {' % Naming.optional_args_cname)
             for arg in self.args:
                 if arg.default:
+                    # FIXME: simple name prefixing doesn't work when
+                    # argument name mangling is in place
                     code.putln('if (%s->%sn > %s) {' % (Naming.optional_args_cname, Naming.pyrex_prefix, i))
                     declarator = arg.declarator
                     while not hasattr(declarator, 'name'):
@@ -1527,6 +1583,7 @@ class DefNode(FuncDefNode):
     is_wrapper = 0
     decorators = None
     entry = None
+    acquire_gil = 0
     
 
     def __init__(self, pos, **kwds):
@@ -1600,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
@@ -1645,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:
@@ -1659,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):
@@ -1775,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)
@@ -1817,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";' % (
@@ -1865,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")
@@ -1877,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)
@@ -1890,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)
 
@@ -1946,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)
@@ -2036,7 +2089,7 @@ class DefNode(FuncDefNode):
                     pystring_cname = code.intern_identifier(arg.name)
                     # required keyword-only argument missing
                     code.put('__Pyx_RaiseKeywordRequired("%s", %s); ' % (
-                            self.name.utf8encode(),
+                            self.name,
                             pystring_cname))
                     code.putln(code.error_goto(self.pos))
                     break
@@ -2086,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))
@@ -2211,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(), pystring_cname))
+                                self.name, pystring_cname))
                         code.putln(code.error_goto(self.pos))
                         code.putln('}')
             if max_positional_args > 0:
@@ -2271,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('}')
 
@@ -2421,6 +2474,7 @@ 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" % (
@@ -2434,6 +2488,7 @@ class OverrideCheckNode(StatNode):
         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
@@ -2446,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:
     #
@@ -2454,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:
@@ -2505,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)
@@ -2519,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)
     
@@ -2527,24 +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.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):
@@ -2561,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
@@ -2575,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
@@ -2635,6 +2696,11 @@ class CClassDefNode(ClassDefNode):
                 return
         else:
             home_scope = env
+
+        if self.visibility == 'extern':
+            if self.module_name == '__builtin__' and self.class_name in Builtin.builtin_types:
+                warning(self.pos, "%s already a builtin Cython type" % self.class_name, 1)
+
         self.entry = home_scope.declare_c_class(
             name = self.class_name, 
             pos = self.pos,
@@ -2651,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)
@@ -2696,6 +2764,7 @@ class PropertyNode(StatNode):
     def analyse_declarations(self, env):
         entry = env.declare_property(self.name, self.doc, self.pos)
         if entry:
+            entry.scope.directives = env.directives
             self.body.analyse_declarations(entry.scope)
 
     def analyse_expressions(self, env):
@@ -2754,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)
@@ -2778,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)
@@ -2877,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)
     
@@ -2930,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)
     
@@ -2984,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:
@@ -3036,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"
@@ -3079,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(), 
@@ -3094,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)
@@ -3183,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)
 
-    gil_check = StatNode._gil_check
+    nogil_check = Node.gil_error
     gil_message = "Python print statement"
 
     def generate_execution_code(self, code):
@@ -3227,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)
 
-    gil_check = StatNode._gil_check
+    nogil_check = Node.gil_error
     gil_message = "Python exec statement"
 
     def generate_execution_code(self, code):
@@ -3242,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:
@@ -3275,10 +3300,10 @@ class DelStatNode(StatNode):
                 error(arg.pos, "Deletion of non-Python object")
             #arg.release_target_temp(env)
 
-    def gil_check(self, env):
+    def nogil_check(self, env):
         for arg in self.args:
             if arg.type.is_pyobject:
-                self._gil_check(env)
+                self.gil_error()
 
     gil_message = "Deleting Python object"
 
@@ -3340,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
@@ -3358,17 +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")
 
-    def gil_check(self, env):
+    def nogil_check(self, env):
         if self.return_type.is_pyobject:
-            self._gil_check(env)
+            self.gil_error()
 
     gil_message = "Returning Python object"
 
@@ -3397,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):
@@ -3426,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)
 
-    gil_check = StatNode._gil_check
+    nogil_check = Node.gil_error
     gil_message = "Raising exception"
 
     def generate_execution_code(self, code):
@@ -3496,7 +3501,7 @@ class ReraiseStatNode(StatNode):
         env.use_utility_code(raise_utility_code)
         env.use_utility_code(restore_exception_utility_code)
 
-    gil_check = StatNode._gil_check
+    nogil_check = Node.gil_error
     gil_message = "Raising exception"
 
     def generate_execution_code(self, code):
@@ -3521,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)
-        #env.recycle_pending_temps() # TEMPORARY
 
-    gil_check = StatNode._gil_check
+    nogil_check = Node.gil_error
     gil_message = "Raising exception"
     
     def generate_execution_code(self, code):
@@ -3625,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):
@@ -3722,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)
@@ -3786,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()
@@ -3852,6 +3844,13 @@ class ForFromStatNode(LoopNode, StatNode):
     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)
         self.body.analyse_declarations(env)
@@ -3863,61 +3862,50 @@ class ForFromStatNode(LoopNode, StatNode):
         self.target.analyse_target_types(env)
         self.bound1.analyse_types(env)
         self.bound2.analyse_types(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)
+        
+        target_type = self.target.type
         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)
+            loop_type = self.target.type
         else:
-            self.bound1 = self.bound1.coerce_to_integer(env)
-            self.bound2 = self.bound2.coerce_to_integer(env)
+            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:
-            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)
+            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()
@@ -3929,6 +3917,11 @@ class ForFromStatNode(LoopNode, StatNode):
             self.step.generate_evaluation_code(code)
             step = self.step.result()
             incop = "%s=%s" % (incop[0], step)
+        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:
             loopvar_name = code.funcstate.allocate_temp(self.target.type, False)
         else:
@@ -3948,12 +3941,30 @@ class ForFromStatNode(LoopNode, StatNode):
         self.body.generate_execution_code(code)
         code.put_label(code.continue_label)
         if self.py_loopvar_node:
-            # Reassign py variable to loop var here.
-            # (For consistancy, should rarely come up in practice.)
+            # 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
-            from_py_node = ExprNodes.CoerceFromPyTypeNode(self.loopvar_node.type, self.target, None)
+            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 
@@ -3971,11 +3982,13 @@ 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)
-        if from_range:
-            code.funcstate.release_temp(loopvar_name)
     
     relation_table = {
         # {relop : (initial offset, increment op)}
@@ -4014,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"]
     
@@ -4046,7 +4058,6 @@ class TryExceptStatNode(StatNode):
 
     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)
@@ -4058,7 +4069,7 @@ class TryExceptStatNode(StatNode):
         if self.else_clause:
             self.else_clause.analyse_expressions(env)
 
-    gil_check = StatNode._gil_check
+    nogil_check = Node.gil_error
     gil_message = "Try-except statement"
 
     def generate_execution_code(self, code):
@@ -4108,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:
@@ -4199,89 +4209,98 @@ 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)
-        self.exc_vars = [env.allocate_temp(py_object_type) for i in xrange(3)]
+
         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)
-        for var in self.exc_vars:
-            env.release_temp(var)
-        env.use_utility_code(get_exception_utility_code)
-        env.use_utility_code(restore_exception_utility_code)
-    
+
     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 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
+        
+        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 
         # exception and stores it in the thread state.
-        exc_args = "&%s, &%s, &%s" % tuple(self.exc_vars)
+        code.globalstate.use_utility_code(get_exception_utility_code)
+        exc_args = "&%s, &%s, &%s" % tuple(exc_vars)
         code.putln("if (__Pyx_GetException(%s) < 0) %s" % (exc_args,
             code.error_goto(self.pos)))
-        for x in self.exc_vars:
+        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')
 
         old_exc_vars = code.funcstate.exc_vars
-        code.funcstate.exc_vars = self.exc_vars
+        code.funcstate.exc_vars = exc_vars
         self.body.generate_execution_code(code)
         code.funcstate.exc_vars = old_exc_vars
-        for var in self.exc_vars:
+        for var in exc_vars:
             code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
         code.put_goto(end_label)
         
         if code.label_used(code.break_label):
             code.put_label(code.break_label)
-            for var in self.exc_vars:
+            for var in exc_vars:
                 code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
             code.put_goto(old_break_label)
         code.break_label = old_break_label
 
         if code.label_used(code.continue_label):
             code.put_label(code.continue_label)
-            for var in self.exc_vars:
+            for var in exc_vars:
                 code.putln("__Pyx_DECREF(%s); %s = 0;" % (var, var))
             code.put_goto(old_continue_label)
         code.continue_label = old_continue_label
-        
+
+        for temp in exc_vars:
+            code.funcstate.release_temp(temp)
+
         code.putln(
             "}")
 
@@ -4299,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
@@ -4321,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)
     
@@ -4338,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)
 
-    gil_check = StatNode._gil_check
+    nogil_check = Node.gil_error
     gil_message = "Try-finally statement"
 
     def generate_execution_code(self, code):
@@ -4444,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(
@@ -4506,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)
@@ -4605,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
@@ -4660,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 == '*':
@@ -4679,9 +4695,6 @@ class FromImportStatNode(StatNode):
                     coerced_item = self.item.coerce_to(target.type, env)
                 self.interned_items.append(
                     (name, target, coerced_item))
-                #target.release_target_temp(env) # was release_temp ?!?
-        self.module.release_temp(env)
-        self.item.release_temp(env)
     
     def generate_execution_code(self, code):
         self.module.generate_evaluation_code(code)
@@ -4691,6 +4704,7 @@ class FromImportStatNode(StatNode):
                     Naming.import_star,
                     self.module.py_result(),
                     code.error_goto(self.pos)))
+        self.item.allocate(code)
         for name, target, coerced_item in self.interned_items:
             cname = code.intern_identifier(name)
             code.putln(
@@ -4708,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)
 
@@ -4901,7 +4916,8 @@ static int __Pyx_PrintOne(PyObject *o) {
 }
 
 #endif
-""")
+""",
+requires=[printing_utility_code])
 
 
 
@@ -5266,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*/
@@ -5305,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;
 
@@ -5332,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
@@ -5346,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,*/
@@ -5355,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(
@@ -5370,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);
 }
@@ -5381,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(
@@ -5436,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*/
@@ -5533,7 +5543,12 @@ impl = """
 static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
     PyObject *tmp_type, *tmp_value, *tmp_tb;
     PyThreadState *tstate = PyThreadState_GET();
-    __Pyx_ErrFetch(type, value, tb);
+    *type = tstate->curexc_type;
+    *value = tstate->curexc_value;
+    *tb = tstate->curexc_traceback;
+    tstate->curexc_type = 0;
+    tstate->curexc_value = 0;
+    tstate->curexc_traceback = 0;
     PyErr_NormalizeException(type, value, tb);
     if (PyErr_Occurred())
         goto bad;
@@ -5563,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*/
@@ -5608,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,
+})