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):
self.putln("%s_%sDECREF(%s);" % (
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):
if entry.type.is_pyobject:
self.putln("__Pyx_XDECREF(%s);" % self.entry_as_pyobject(entry))
......
......@@ -1895,7 +1895,7 @@ class NameNode(AtomicExprNode):
# variables that the acquired buffer info is stored to is allocated
# per entry and coupled with it.
self.generate_acquire_buffer(rhs, code)
assigned = False
if self.type.is_pyobject:
#print "NameNode.generate_assignment_code: to", self.name ###
#print "...from", rhs ###
......@@ -1910,18 +1910,26 @@ class NameNode(AtomicExprNode):
code.put_xgotref(self.py_result())
else:
code.put_gotref(self.py_result())
assigned = True
if entry.is_cglobal:
code.put_decref(self.result(), self.ctype())
code.put_decref_set(
self.result(), rhs.result_as(self.ctype()))
else:
if not self.cf_is_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:
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:
code.put_giveref(rhs.py_result())
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:
print("NameNode.generate_assignment_code:")
print("...generating post-assignment code for %s" % rhs)
......
......@@ -9,6 +9,7 @@ cython.declare(PyrexTypes=object, ExprNodes=object, Nodes=object,
import Builtin
import ExprNodes
import Nodes
import Options
from PyrexTypes import py_object_type, unspecified_type
import PyrexTypes
......@@ -574,8 +575,9 @@ def check_definitions(flow, compiler_directives):
if node.allow_null or entry.from_closure or entry.is_pyclass_attr:
pass # Can be uninitialized here
elif node.cf_is_null:
if (entry.type.is_pyobject or entry.type.is_unspecified or
entry.error_on_uninitialized):
if entry.error_on_uninitialized or (
Options.error_on_uninitialized and (
entry.type.is_pyobject or entry.type.is_unspecified)):
messages.error(
node.pos,
"local variable '%s' referenced before assignment"
......
......@@ -34,6 +34,12 @@ warning_errors = False
# you should disable this option and also 'cache_builtins'.
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(...)"
# to "for i from ..." when i is a cdef'd integer type, and the direction
# (i.e. sign of step) can be determined.
......
......@@ -531,6 +531,15 @@ static int __Pyx_check_binary_version(void) {
#define __Pyx_XGIVEREF(r)
#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_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):
def setUp(self):
from Cython.Compiler import Options
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()
Options.warning_errors = self.warning_errors
......@@ -989,6 +991,7 @@ class CythonPyregrTestCase(CythonRunTestCase):
CythonRunTestCase.setUp(self)
from Cython.Compiler import Options
Options.error_on_unknown_names = False
Options.error_on_uninitialized = False
Options.directive_defaults.update(dict(
binding=True, always_allow_keywords=True,
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