Commit ab7c282b authored by scoder's avatar scoder

Merge pull request #235 from vitek/_external_ref_assignment

 external ref assignment
parents 9abd478d eda120d5
...@@ -1738,6 +1738,12 @@ class CCodeWriter(object): ...@@ -1738,6 +1738,12 @@ class CCodeWriter(object):
self.putln("%s_%sDECREF(%s);" % ( self.putln("%s_%sDECREF(%s);" % (
prefix, X, self.as_pyobject(cname, type))) prefix, X, self.as_pyobject(cname, type)))
def put_decref_set(self, cname, rhs_cname):
self.putln("__Pyx_DECREF_SET(%s, %s);" % (cname, rhs_cname))
def put_xdecref_set(self, cname, rhs_cname):
self.putln("__Pyx_XDECREF_SET(%s, %s);" % (cname, rhs_cname))
def put_var_decref(self, entry): def put_var_decref(self, entry):
if entry.type.is_pyobject: if entry.type.is_pyobject:
self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry)) self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
......
...@@ -1895,7 +1895,7 @@ class NameNode(AtomicExprNode): ...@@ -1895,7 +1895,7 @@ class NameNode(AtomicExprNode):
# variables that the acquired buffer info is stored to is allocated # variables that the acquired buffer info is stored to is allocated
# per entry and coupled with it. # per entry and coupled with it.
self.generate_acquire_buffer(rhs, code) self.generate_acquire_buffer(rhs, code)
assigned = False
if self.type.is_pyobject: if self.type.is_pyobject:
#print "NameNode.generate_assignment_code: to", self.name ### #print "NameNode.generate_assignment_code: to", self.name ###
#print "...from", rhs ### #print "...from", rhs ###
...@@ -1910,18 +1910,26 @@ class NameNode(AtomicExprNode): ...@@ -1910,18 +1910,26 @@ class NameNode(AtomicExprNode):
code.put_xgotref(self.py_result()) code.put_xgotref(self.py_result())
else: else:
code.put_gotref(self.py_result()) code.put_gotref(self.py_result())
assigned = True
if entry.is_cglobal: if entry.is_cglobal:
code.put_decref(self.result(), self.ctype()) code.put_decref_set(
self.result(), rhs.result_as(self.ctype()))
else: else:
if not self.cf_is_null: if not self.cf_is_null:
if self.cf_maybe_null: if self.cf_maybe_null:
code.put_xdecref(self.result(), self.ctype()) code.put_xdecref_set(
self.result(), rhs.result_as(self.ctype()))
else: else:
code.put_decref(self.result(), self.ctype()) code.put_decref_set(
self.result(), rhs.result_as(self.ctype()))
else:
assigned = False
if is_external_ref: if is_external_ref:
code.put_giveref(rhs.py_result()) code.put_giveref(rhs.py_result())
if not self.type.is_memoryviewslice: if not self.type.is_memoryviewslice:
code.putln('%s = %s;' % (self.result(), rhs.result_as(self.ctype()))) if not assigned:
code.putln('%s = %s;' % (
self.result(), rhs.result_as(self.ctype())))
if debug_disposal_code: if debug_disposal_code:
print("NameNode.generate_assignment_code:") print("NameNode.generate_assignment_code:")
print("...generating post-assignment code for %s" % rhs) print("...generating post-assignment code for %s" % rhs)
......
...@@ -9,6 +9,7 @@ cython.declare(PyrexTypes=object, ExprNodes=object, Nodes=object, ...@@ -9,6 +9,7 @@ cython.declare(PyrexTypes=object, ExprNodes=object, Nodes=object,
import Builtin import Builtin
import ExprNodes import ExprNodes
import Nodes import Nodes
import Options
from PyrexTypes import py_object_type, unspecified_type from PyrexTypes import py_object_type, unspecified_type
import PyrexTypes import PyrexTypes
...@@ -574,8 +575,9 @@ def check_definitions(flow, compiler_directives): ...@@ -574,8 +575,9 @@ def check_definitions(flow, compiler_directives):
if node.allow_null or entry.from_closure or entry.is_pyclass_attr: if node.allow_null or entry.from_closure or entry.is_pyclass_attr:
pass # Can be uninitialized here pass # Can be uninitialized here
elif node.cf_is_null: elif node.cf_is_null:
if (entry.type.is_pyobject or entry.type.is_unspecified or if entry.error_on_uninitialized or (
entry.error_on_uninitialized): Options.error_on_uninitialized and (
entry.type.is_pyobject or entry.type.is_unspecified)):
messages.error( messages.error(
node.pos, node.pos,
"local variable '%s' referenced before assignment" "local variable '%s' referenced before assignment"
......
...@@ -34,6 +34,12 @@ warning_errors = False ...@@ -34,6 +34,12 @@ warning_errors = False
# you should disable this option and also 'cache_builtins'. # you should disable this option and also 'cache_builtins'.
error_on_unknown_names = True error_on_unknown_names = True
# Make uninitialized local variable reference a compile time error.
# Python raises UnboundLocalError at runtime, whereas this option makes
# them a compile time error. Note that this option affects only variables
# of "python object" type.
error_on_uninitialized = True
# This will convert statements of the form "for i in range(...)" # This will convert statements of the form "for i in range(...)"
# to "for i from ..." when i is a cdef'd integer type, and the direction # to "for i from ..." when i is a cdef'd integer type, and the direction
# (i.e. sign of step) can be determined. # (i.e. sign of step) can be determined.
......
...@@ -531,6 +531,15 @@ static int __Pyx_check_binary_version(void) { ...@@ -531,6 +531,15 @@ static int __Pyx_check_binary_version(void) {
#define __Pyx_XGIVEREF(r) #define __Pyx_XGIVEREF(r)
#endif /* CYTHON_REFNANNY */ #endif /* CYTHON_REFNANNY */
#define __Pyx_XDECREF_SET(r, v) do { \
PyObject *tmp = (PyObject *) r; \
r = v; __Pyx_XDECREF(tmp); \
} while (0)
#define __Pyx_DECREF_SET(r, v) do { \
PyObject *tmp = (PyObject *) r; \
r = v; __Pyx_DECREF(tmp); \
} while (0)
#define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0) #define __Pyx_CLEAR(r) do { PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);} while(0)
#define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0) #define __Pyx_XCLEAR(r) do { if((r) != NULL) {PyObject* tmp = ((PyObject*)(r)); r = NULL; __Pyx_DECREF(tmp);}} while(0)
......
...@@ -520,7 +520,9 @@ class CythonCompileTestCase(unittest.TestCase): ...@@ -520,7 +520,9 @@ class CythonCompileTestCase(unittest.TestCase):
def setUp(self): def setUp(self):
from Cython.Compiler import Options from Cython.Compiler import Options
self._saved_options = [ (name, getattr(Options, name)) self._saved_options = [ (name, getattr(Options, name))
for name in ('warning_errors', 'error_on_unknown_names') ] for name in ('warning_errors',
'error_on_unknown_names',
'error_on_uninitialized') ]
self._saved_default_directives = Options.directive_defaults.items() self._saved_default_directives = Options.directive_defaults.items()
Options.warning_errors = self.warning_errors Options.warning_errors = self.warning_errors
...@@ -989,6 +991,7 @@ class CythonPyregrTestCase(CythonRunTestCase): ...@@ -989,6 +991,7 @@ class CythonPyregrTestCase(CythonRunTestCase):
CythonRunTestCase.setUp(self) CythonRunTestCase.setUp(self)
from Cython.Compiler import Options from Cython.Compiler import Options
Options.error_on_unknown_names = False Options.error_on_unknown_names = False
Options.error_on_uninitialized = False
Options.directive_defaults.update(dict( Options.directive_defaults.update(dict(
binding=True, always_allow_keywords=True, binding=True, always_allow_keywords=True,
set_initial_path="SOURCEFILE")) set_initial_path="SOURCEFILE"))
......
# Test that variable visible outside of the local scope (e.g. closure, cglobals)
# is set before original value is decrefed.
cdef object g
def test_cglobals_reassignment():
"""
>>> test_cglobals_reassignment()
1234
"""
global g
class Special:
def __del__(self):
print g
g = (Special(),)
g = 1234
def test_closure_reassignment():
"""
>>> test_closure_reassignment()
4321
"""
class Special:
def __del__(self):
print c
c = (Special(),)
c = 4321
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment