Repository: cython/cython

Issue:
warn.undeclared compiler directive is broken
Using warn.undeclared with a simple empty extension type generates some warnings:
```cython
#cython: language_level=3, warn.undeclared=True

cdef class Foo:
    pass
```

```
$ cython -Werror cython_test_undeclared.pyx

Error compiling Cython file:
------------------------------------------------------------
...
def __pyx_unpickle_Foo(__pyx_type, long __pyx_checksum, __pyx_state):
    if __pyx_checksum != 0xd41d8cd:
        from pickle import PickleError as __pyx_PickleError
                          ^
------------------------------------------------------------

(tree fragment):3:27: implicit declaration of '__pyx_PickleError'

Error compiling Cython file:
------------------------------------------------------------
...
def __pyx_unpickle_Foo(__pyx_type, long __pyx_checksum, __pyx_state):
    if __pyx_checksum != 0xd41d8cd:
        from pickle import PickleError as __pyx_PickleError
        raise __pyx_PickleError("Incompatible checksums (%s vs 0xd41d8cd = ())" % __pyx_checksum)
    __pyx_result = Foo.__new__(__pyx_type)
   ^
------------------------------------------------------------

(tree fragment):5:4: implicit declaration of '__pyx_result'

Error compiling Cython file:
------------------------------------------------------------
...
def __reduce_cython__(self):
    cdef bint use_setstate
    state = ()
   ^
------------------------------------------------------------

(tree fragment):3:4: implicit declaration of 'state'

Error compiling Cython file:
------------------------------------------------------------
...
def __reduce_cython__(self):
    cdef bint use_setstate
    state = ()
    _dict = getattr(self, '__dict__', None)
   ^
------------------------------------------------------------

(tree fragment):4:4: implicit declaration of '_dict'
```


Discussion:

Resolving patch:
diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py
--- a/Cython/Compiler/ParseTreeTransforms.py
+++ b/Cython/Compiler/ParseTreeTransforms.py
@@ -1707,6 +1707,8 @@ def __setstate_cython__(self, __pyx_state):
             # so it can be pickled *after* self is memoized.
             unpickle_func = TreeFragment(u"""
                 def %(unpickle_func_name)s(__pyx_type, long __pyx_checksum, __pyx_state):
+                    cdef object __pyx_PickleError
+                    cdef object __pyx_result
                     if __pyx_checksum != %(checksum)s:
                         from pickle import PickleError as __pyx_PickleError
                         raise __pyx_PickleError("Incompatible checksums (%%s vs %(checksum)s = (%(members)s))" %% __pyx_checksum)
@@ -1735,6 +1737,8 @@ def %(unpickle_func_name)s(__pyx_type, long __pyx_checksum, __pyx_state):
 
             pickle_func = TreeFragment(u"""
                 def __reduce_cython__(self):
+                    cdef tuple state
+                    cdef object _dict
                     cdef bint use_setstate
                     state = (%(members)s)
                     _dict = getattr(self, '__dict__', None)


Test patch:
diff --git a/tests/errors/w_undeclared.pyx b/tests/errors/w_undeclared.pyx
new file mode 100644
--- /dev/null
+++ b/tests/errors/w_undeclared.pyx
@@ -0,0 +1,20 @@
+# cython: warn.undeclared=True
+# mode: error
+# tag: werror
+
+def foo():
+    a = 1
+    return a
+
+cdef class Bar:
+    cdef int baz(self, a):
+        res = 0
+        for i in range(3):
+            res += i
+        return res
+
+_ERRORS = """
+6:4: implicit declaration of 'a'
+11:8: implicit declaration of 'res'
+12:12: implicit declaration of 'i'
+"""