Commit 5c79474f authored by Xavier Thompson's avatar Xavier Thompson

Fix template cypclass field reference counting

parent 7f1cf72d
...@@ -7759,8 +7759,9 @@ class AttributeNode(ExprNode): ...@@ -7759,8 +7759,9 @@ class AttributeNode(ExprNode):
elif self.type.is_cyp_class: elif self.type.is_cyp_class:
rhs.make_owned_reference(code) rhs.make_owned_reference(code)
rhs.generate_giveref(code) rhs.generate_giveref(code)
code.put_gotref(select_code, self.type) if not self.entry.is_specialised:
code.put_xdecref(select_code, self.type) code.put_gotref(select_code, self.type)
code.put_xdecref(select_code, self.type)
if not self.type.is_memoryviewslice: if not self.type.is_memoryviewslice:
code.putln( code.putln(
......
...@@ -6022,7 +6022,12 @@ class SingleAssignmentNode(AssignmentNode): ...@@ -6022,7 +6022,12 @@ class SingleAssignmentNode(AssignmentNode):
not rhs.is_name and not rhs.is_literal and not rhs.is_name and not rhs.is_literal and
(rhs.type.is_pyobject or rhs.type.is_cyp_class)): (rhs.type.is_pyobject or rhs.type.is_cyp_class)):
# things like (cdef) attribute access are not safe (traverses pointers) # things like (cdef) attribute access are not safe (traverses pointers)
rhs = rhs.coerce_to_temp(env) if rhs.is_attribute and rhs.type.is_cyp_class and rhs.entry.is_specialised:
rhs = rhs.coerce_to_temp(env)
# cypclass fields specialised from a template do their own reference counting.
rhs.use_managed_ref = False
else:
rhs = rhs.coerce_to_temp(env)
elif rhs.type.is_pyobject: elif rhs.type.is_pyobject:
rhs = rhs.coerce_to_simple(env) rhs = rhs.coerce_to_simple(env)
self.rhs = rhs self.rhs = rhs
...@@ -6576,7 +6581,10 @@ class DelStatNode(StatNode): ...@@ -6576,7 +6581,10 @@ class DelStatNode(StatNode):
arg.free_temps(code) arg.free_temps(code)
elif arg.type.is_cyp_class: elif arg.type.is_cyp_class:
arg.generate_evaluation_code(code) arg.generate_evaluation_code(code)
code.put_xdecref_clear(arg.result(), arg.type) if arg.is_attribute and arg.entry.is_specialised:
code.putln("%s = nullptr;" % arg.result())
else:
code.put_xdecref_clear(arg.result(), arg.type)
arg.generate_disposal_code(code) arg.generate_disposal_code(code)
arg.free_temps(code) arg.free_temps(code)
# else error reported earlier # else error reported earlier
......
...@@ -182,6 +182,8 @@ class Entry(object): ...@@ -182,6 +182,8 @@ class Entry(object):
# active_entry Entry Entry for the active version of an asyncable cypclass method # active_entry Entry Entry for the active version of an asyncable cypclass method
# #
# is_consumed boolean The entry is the operand of a 'consume' expression. # is_consumed boolean The entry is the operand of a 'consume' expression.
#
# is_specialised boolean The entry is a template specialisation.
# TODO: utility_code and utility_code_definition serves the same purpose... # TODO: utility_code and utility_code_definition serves the same purpose...
...@@ -261,6 +263,7 @@ class Entry(object): ...@@ -261,6 +263,7 @@ class Entry(object):
original_name = None original_name = None
active_entry = None active_entry = None
is_consumed = False is_consumed = False
is_specialised = False
def __init__(self, name, cname, type, pos = None, init = None): def __init__(self, name, cname, type, pos = None, init = None):
self.name = name self.name = name
...@@ -3136,11 +3139,12 @@ class CppClassScope(Scope): ...@@ -3136,11 +3139,12 @@ class CppClassScope(Scope):
e.cname, e.cname,
utility_code=e.utility_code) utility_code=e.utility_code)
else: else:
scope.declare_var(entry.name, e = scope.declare_var(entry.name,
entry.type.specialize(values), entry.type.specialize(values),
entry.pos, entry.pos,
entry.cname, entry.cname,
entry.visibility) entry.visibility)
e.is_specialised = True
return scope return scope
......
...@@ -129,3 +129,57 @@ def test_getting_and_setting(): ...@@ -129,3 +129,57 @@ def test_getting_and_setting():
if Cy_GETREF(v) != 3: if Cy_GETREF(v) != 3:
return -(i+2) return -(i+2)
return 0 return 0
def test_field_getting():
"""
>>> test_field_getting()
Template destroyed
Value destroyed
0
"""
v = Value()
h = Template[Value](v)
if Cy_GETREF(v) != 3:
return -1
for i in range(10):
v = h.value
if Cy_GETREF(v) != 3:
return -(i+2)
return 0
def test_field_setting():
"""
>>> test_field_setting()
Template destroyed
Value destroyed
0
"""
h = Template[Value](NULL)
v = Value()
for i in range(10):
h.value = v
if Cy_GETREF(v) != 3:
return -(i+1)
return 0
def test_field_deleting():
"""
>>> test_field_deleting()
Template destroyed
Value destroyed
0
"""
v = Value()
h = Template[Value](v)
if Cy_GETREF(v) != 3:
return -1
del h.value
if Cy_GETREF(v) != 2:
return -1
del h
return 0
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