merge
authorStefan Behnel <scoder@users.berlios.de>
Wed, 25 Mar 2009 22:55:54 +0000 (23:55 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Wed, 25 Mar 2009 22:55:54 +0000 (23:55 +0100)
Cython/Compiler/Nodes.py
runtests.py
tests/bugs/return_outside_function_T135.pyx [new file with mode: 0644]
tests/errors/break_outside_loop.pyx [new file with mode: 0644]
tests/errors/continue_outside_loop.pyx [new file with mode: 0644]
tests/run/funcexceptchained.pyx
tests/run/funcexceptreplace.pyx [new file with mode: 0644]

index 68f12906440db53a9c1385b55effcca8a7742ac6..f9d7fb532de933e9dc5bed89eddf4acf10184b0a 100644 (file)
@@ -19,8 +19,6 @@ import Options
 import ControlFlow
 import DebugFlags
 
-from DebugFlags import debug_disposal_code
-
 absolute_path_length = 0
 
 def relative_position(pos):
@@ -4228,7 +4226,6 @@ class ExceptClauseNode(Node):
 
     exc_value = None
     excinfo_target = None
-    empty_body = False
 
     def analyse_declarations(self, env):
         if self.target:
@@ -4248,16 +4245,10 @@ class ExceptClauseNode(Node):
             self.pattern.release_temp(env)
             env.release_temp(self.match_flag)
 
-        # most simple case: empty body (pass)
-        self.empty_body = not self.target and not self.excinfo_target and \
-                          not getattr(self.body, 'stats', True)
-
-        if not self.empty_body:
+        if self.target or self.excinfo_target:
             self.exc_vars = [env.allocate_temp(py_object_type) for i in xrange(3)]
-            env.use_utility_code(get_exception_utility_code)
-            env.use_utility_code(restore_exception_utility_code)
         else:
-            self.exc_vars = []
+            self.exc_vars = None
 
         if self.target:
             self.exc_value = ExprNodes.ExcValueNode(self.pos, env, self.exc_vars[1])
@@ -4275,8 +4266,10 @@ class ExceptClauseNode(Node):
             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)
+
+        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)
@@ -4294,21 +4287,31 @@ class ExceptClauseNode(Node):
         else:
             code.putln("/*except:*/ {")
 
-        if self.empty_body:
-            # most simple case: reset the exception state, done
+        if self.exc_vars:
+            exc_vars = self.exc_vars
+        elif 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)]
 
         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.generate_evaluation_code(code)
@@ -4323,27 +4326,32 @@ class ExceptClauseNode(Node):
         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
-        
+
+        if not self.exc_vars:
+            # clean up locally allocated temps
+            for temp in exc_vars:
+                code.funcstate.release_temp(temp)
+
         code.putln(
             "}")
 
@@ -5594,7 +5602,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;
index d6919440cadbd0d04fcadba61067a0c44e21df50..d1ee89713b9f21f0c660eda108c7a7db9e3c78f2 100644 (file)
@@ -561,6 +561,8 @@ if __name__ == '__main__':
     if WITH_CYTHON:
         from Cython.Compiler.Version import version
         sys.stderr.write("Running tests against Cython %s\n" % version)
+        from Cython.Compiler import DebugFlags
+        DebugFlags.debug_temp_code_comments = 1
     else:
         sys.stderr.write("Running tests without Cython.\n")
     sys.stderr.write("Python %s\n" % sys.version)
diff --git a/tests/bugs/return_outside_function_T135.pyx b/tests/bugs/return_outside_function_T135.pyx
new file mode 100644 (file)
index 0000000..ba993ac
--- /dev/null
@@ -0,0 +1,38 @@
+
+return 'bar'
+
+class A:
+    return None
+
+cdef class B:
+    return None
+
+try: return None
+except: pass
+
+try: return None
+finally: pass
+
+for i in (1,2):
+    return None
+
+while True:
+    return None
+
+if True:
+    return None
+else:
+    return None
+
+
+_ERRORS = u'''
+ 2:0: Return not inside a function body
+ 5:4: Return not inside a function body
+ 8:4: Return not inside a function body
+10:5: Return not inside a function body
+13:5: Return not inside a function body
+17:4: Return not inside a function body
+20:4: Return not inside a function body
+23:4: Return not inside a function body
+25:4: Return not inside a function body
+'''
diff --git a/tests/errors/break_outside_loop.pyx b/tests/errors/break_outside_loop.pyx
new file mode 100644 (file)
index 0000000..8150872
--- /dev/null
@@ -0,0 +1,33 @@
+
+break
+
+class A:
+    break
+
+cdef class B:
+    break
+
+def test():
+    break
+
+try: break
+except: pass
+
+try: break
+finally: pass
+
+if True:
+    break
+else:
+    break
+
+
+_ERRORS = u'''
+ 2:0: break statement not inside loop
+ 5:4: break statement not inside loop
+ 8:4: break statement not inside loop
+11:4: break statement not inside loop
+16:5: break statement not inside loop
+20:4: break statement not inside loop
+22:4: break statement not inside loop
+'''
diff --git a/tests/errors/continue_outside_loop.pyx b/tests/errors/continue_outside_loop.pyx
new file mode 100644 (file)
index 0000000..6a2ef52
--- /dev/null
@@ -0,0 +1,33 @@
+
+continue
+
+class A:
+    continue
+
+cdef class B:
+    continue
+
+def test():
+    continue
+
+try: continue
+except: pass
+
+try: continue
+finally: pass
+
+if True:
+    continue
+else:
+    continue
+
+
+_ERRORS = u'''
+ 2:0: continue statement not inside loop
+ 5:4: continue statement not inside loop
+ 8:4: continue statement not inside loop
+11:4: continue statement not inside loop
+16:5: continue statement not inside loop
+20:4: continue statement not inside loop
+22:4: continue statement not inside loop
+'''
index 78c02c385af252eb4a54423f095703bbbf878de7..27881111cd4f1dbc81f886f5c3cc3a5ed9143378 100644 (file)
@@ -8,7 +8,13 @@ __doc__ = u"""
 ...   except AttributeError:
 ...     print(sys.exc_info()[0] is AttributeError or sys.exc_info()[0])
 ...     try: raise KeyError
-...     except: print(sys.exc_info()[0] is KeyError or sys.exc_info()[0])
+...     except:
+...       print(sys.exc_info()[0] is KeyError or sys.exc_info()[0])
+...       if IS_PY3:
+...         print(isinstance(sys.exc_info()[1].__context__, AttributeError)
+...               or sys.exc_info()[1].__context__)
+...       else:
+...         print(True)
 ...     print((IS_PY3 and sys.exc_info()[0] is AttributeError) or
 ...           (not IS_PY3 and sys.exc_info()[0] is KeyError) or
 ...           sys.exc_info()[0])
@@ -24,6 +30,7 @@ True
 True
 True
 True
+True
 >>> print(sys.exc_info()[0]) # test_py()
 None
 
@@ -32,6 +39,7 @@ True
 True
 True
 True
+True
 >>> print(sys.exc_info()[0]) # test_c()
 None
 
@@ -52,6 +60,7 @@ True
 True
 True
 True
+True
 >>> print(sys.exc_info()[0]) # test_py2()
 None
 
@@ -62,6 +71,7 @@ True
 True
 True
 True
+True
 >>> print(sys.exc_info()[0]) # test_c2()
 None
 """
@@ -76,7 +86,13 @@ def test_c(outer_exc):
     except AttributeError:
         print(sys.exc_info()[0] is AttributeError or sys.exc_info()[0])
         try: raise KeyError
-        except: print(sys.exc_info()[0] is KeyError or sys.exc_info()[0])
+        except:
+            print(sys.exc_info()[0] is KeyError or sys.exc_info()[0])
+            if IS_PY3:
+                print(isinstance(sys.exc_info()[1].__context__, AttributeError)
+                      or sys.exc_info()[1].__context__)
+            else:
+                print(True)
         print(sys.exc_info()[0] is AttributeError or sys.exc_info()[0])
     print(sys.exc_info()[0] is outer_exc or sys.exc_info()[0])
 
diff --git a/tests/run/funcexceptreplace.pyx b/tests/run/funcexceptreplace.pyx
new file mode 100644 (file)
index 0000000..084df4f
--- /dev/null
@@ -0,0 +1,18 @@
+__doc__ = u"""
+>>> try: exc()
+... except IndexError:
+...     if IS_PY3:
+...         print(isinstance(sys.exc_info()[1].__context__, ValueError))
+...     else:
+...         print(True)
+True
+"""
+
+import sys
+IS_PY3 = sys.version_info[0] >= 3
+
+def exc():
+    try:
+        raise ValueError
+    except ValueError:
+        raise IndexError