Commit 40cb5671 authored by Robert Bradshaw's avatar Robert Bradshaw

Avoid incorrect copy when reference is stored to a temporary variable.

parent 52b8a0e8
......@@ -4739,8 +4739,7 @@ class SimpleCallNode(CallNode):
# func_type.exception_check = True
if self.is_temp and self.type.is_reference:
# TODO: Avoid the copy.
self.type = self.type.ref_base_type
self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type)
# Called in 'nogil' context?
self.nogil = env.nogil
......@@ -5702,6 +5701,8 @@ class AttributeNode(ExprNode):
self.op = "->"
elif obj_type.is_extension_type or obj_type.is_builtin_type:
self.op = "->"
elif obj_type.is_reference and obj_type.is_fake_reference:
self.op = "->"
else:
self.op = "."
if obj_type.has_attributes:
......
......@@ -2422,6 +2422,7 @@ class CNullPtrType(CPtrType):
class CReferenceType(BaseType):
is_reference = 1
is_fake_reference = 0
def __init__(self, base_type):
self.ref_base_type = base_type
......@@ -2444,7 +2445,7 @@ class CReferenceType(BaseType):
if base_type == self.ref_base_type:
return self
else:
return CReferenceType(base_type)
return type(self)(base_type)
def deduce_template_params(self, actual):
return self.ref_base_type.deduce_template_params(actual)
......@@ -2453,6 +2454,22 @@ class CReferenceType(BaseType):
return getattr(self.ref_base_type, name)
class CFakeReferenceType(CReferenceType):
is_fake_reference = 1
def __repr__(self):
return "<CFakeReferenceType %s>" % repr(self.ref_base_type)
def __str__(self):
return "%s [&]" % self.ref_base_type
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
#print "CReferenceType.declaration_code: pointer to", self.base_type ###
return "__Pyx_FakeReference<%s> %s" % (self.ref_base_type.empty_declaration_code(), entity_code)
class CFuncType(CType):
# return_type CType
# args [CFuncTypeArg]
......
......@@ -217,12 +217,24 @@ static CYTHON_INLINE float __PYX_NAN() {
#define __Pyx_void_to_None(void_result) (void_result, Py_INCREF(Py_None), Py_None)
// Work around clang bug http://stackoverflow.com/questions/21847816/c-invoke-nested-template-class-destructor
#ifdef __cplusplus
// Work around clang bug http://stackoverflow.com/questions/21847816/c-invoke-nested-template-class-destructor
template<typename T>
void __Pyx_call_destructor(T* x) {
x->~T();
}
// Used for temporary variables of "reference" type.
template<typename T>
class __Pyx_FakeReference {
public:
__Pyx_FakeReference() : ptr(NULL) { }
__Pyx_FakeReference(T& ref) : ptr(&ref) { }
T *operator->() { return ptr; }
operator T&() { return *ptr; }
private:
T *ptr;
};
#endif
/////////////// UtilityFunctionPredeclarations.proto ///////////////
......
......@@ -5,8 +5,9 @@ cdef extern from "cpp_template_ref_args.h":
cdef cppclass Bar[T]:
Bar()
Bar[T] & ref()
# bug: Bar[T] created before class fully defined
T value
Bar[T] & ref() except +
cdef cppclass Foo[T]:
Foo()
......@@ -28,3 +29,12 @@ def test_template_ref_arg(int x):
bar.value = x
return foo.bar_value(bar.ref())
def test_template_ref_attr(int x):
"""
>>> test_template_ref_attr(4)
4
"""
cdef Bar[int] bar
bar.value = x
return bar.ref().value
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