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): ...@@ -4739,8 +4739,7 @@ class SimpleCallNode(CallNode):
# func_type.exception_check = True # func_type.exception_check = True
if self.is_temp and self.type.is_reference: if self.is_temp and self.type.is_reference:
# TODO: Avoid the copy. self.type = PyrexTypes.CFakeReferenceType(self.type.ref_base_type)
self.type = self.type.ref_base_type
# Called in 'nogil' context? # Called in 'nogil' context?
self.nogil = env.nogil self.nogil = env.nogil
...@@ -5702,6 +5701,8 @@ class AttributeNode(ExprNode): ...@@ -5702,6 +5701,8 @@ class AttributeNode(ExprNode):
self.op = "->" self.op = "->"
elif obj_type.is_extension_type or obj_type.is_builtin_type: elif obj_type.is_extension_type or obj_type.is_builtin_type:
self.op = "->" self.op = "->"
elif obj_type.is_reference and obj_type.is_fake_reference:
self.op = "->"
else: else:
self.op = "." self.op = "."
if obj_type.has_attributes: if obj_type.has_attributes:
......
...@@ -2422,6 +2422,7 @@ class CNullPtrType(CPtrType): ...@@ -2422,6 +2422,7 @@ class CNullPtrType(CPtrType):
class CReferenceType(BaseType): class CReferenceType(BaseType):
is_reference = 1 is_reference = 1
is_fake_reference = 0
def __init__(self, base_type): def __init__(self, base_type):
self.ref_base_type = base_type self.ref_base_type = base_type
...@@ -2444,7 +2445,7 @@ class CReferenceType(BaseType): ...@@ -2444,7 +2445,7 @@ class CReferenceType(BaseType):
if base_type == self.ref_base_type: if base_type == self.ref_base_type:
return self return self
else: else:
return CReferenceType(base_type) return type(self)(base_type)
def deduce_template_params(self, actual): def deduce_template_params(self, actual):
return self.ref_base_type.deduce_template_params(actual) return self.ref_base_type.deduce_template_params(actual)
...@@ -2453,6 +2454,22 @@ class CReferenceType(BaseType): ...@@ -2453,6 +2454,22 @@ class CReferenceType(BaseType):
return getattr(self.ref_base_type, name) 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): class CFuncType(CType):
# return_type CType # return_type CType
# args [CFuncTypeArg] # args [CFuncTypeArg]
......
...@@ -217,12 +217,24 @@ static CYTHON_INLINE float __PYX_NAN() { ...@@ -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) #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 #ifdef __cplusplus
// Work around clang bug http://stackoverflow.com/questions/21847816/c-invoke-nested-template-class-destructor
template<typename T> template<typename T>
void __Pyx_call_destructor(T* x) { void __Pyx_call_destructor(T* x) {
x->~T(); 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 #endif
/////////////// UtilityFunctionPredeclarations.proto /////////////// /////////////// UtilityFunctionPredeclarations.proto ///////////////
......
...@@ -5,8 +5,9 @@ cdef extern from "cpp_template_ref_args.h": ...@@ -5,8 +5,9 @@ cdef extern from "cpp_template_ref_args.h":
cdef cppclass Bar[T]: cdef cppclass Bar[T]:
Bar() Bar()
Bar[T] & ref() # bug: Bar[T] created before class fully defined
T value T value
Bar[T] & ref() except +
cdef cppclass Foo[T]: cdef cppclass Foo[T]:
Foo() Foo()
...@@ -28,3 +29,12 @@ def test_template_ref_arg(int x): ...@@ -28,3 +29,12 @@ def test_template_ref_arg(int x):
bar.value = x bar.value = x
return foo.bar_value(bar.ref()) 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