[Cython] operator() bug in cython

2015-02-11 Thread Ulrich Dobramysl
Dear all,

I tried to declare an external c++ class that includes an operator()
function in a pxd file. When I then call a class instance, cython generates
faulty c++ code. It includes a call to "operator()()", and not a call to
the instance object. Here is a minimum working example:

call_operator.pxd:

cdef extern from "call_operator.hpp" nogil:
cdef cppclass OperatorTest:
int operator()()


test_call_operator.pyx:

from call_operator cimport OperatorTest
def test():
cdef OperatorTest t
t()


Running "cython --cplus test_call_operator.pyx" generates the following
code for the test() function:

 (relevant part only)
  /* "test_call_operator.pyx":4
 * def test():
 * cdef OperatorTest t
 * t() # <<
 */
  operator()();

As you can see, the code that is generated is a call to "operator()()" and
not "t()" as it should be.

>From what I've been able to work out, the problem seems to be that the call
to "t()" is treated as a NameNode in ExprNodes.py and not an AttributeNode.
However, I don't know enough about Cython's internals to track where
exactly this decision is made.

Curiously, this bug isn't always triggered in more complex situations. I
had a larger pxd file with multiple external declarations where one class
operator() was treated correctly, while others weren't. I haven't been able
to find out why this was the case.

Ulrich
___
cython-devel mailing list
cython-devel@python.org
https://mail.python.org/mailman/listinfo/cython-devel


Re: [Cython] operator() bug in cython

2015-02-13 Thread Ulrich Dobramysl
On Fri Feb 13 2015 at 2:23:45 PM Stefan Behnel  wrote:

> Ulrich Dobramysl schrieb am 11.02.2015 um 09:56:
> > From what I've been able to work out, the problem seems to be that the
> call
> > to "t()" is treated as a NameNode in ExprNodes.py and not an
> AttributeNode.
> > However, I don't know enough about Cython's internals to track where
> > exactly this decision is made.
> >
> > Curiously, this bug isn't always triggered in more complex situations. I
> > had a larger pxd file with multiple external declarations where one class
> > operator() was treated correctly, while others weren't. I haven't been
> able
> > to find out why this was the case.
>
> It happens only with stack allocated C++ objects, not with heap objects
> (i.e. pointers). That can be used as a work-around, I guess.
>
>
Thanks! I haven't figured out how to call heap allocated objects, as the
code
---
cdef OperatorTest *t = new OperatorTest()
t()
---
is not translatable by Cython. Is there a special syntax for calling cython
"function pointers"? The trick dereference(t)() doesn't work either.

However, one thing that works is if the (stack-allocated) called object is
not a local variable (a NameNode), but an attribute of some object (an
AttributeNode). A quick and dirty fix for this would be this patch for
NameNode.calculate_result_code:
---
diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index f99ec6e..f894a64 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -1904,6 +1904,8 @@ class NameNode(AtomicExprNode):
 entry = self.entry
 if not entry:
 return "" # There was an error earlier
+if entry.cname=='operator()':
+return self.name
 return entry.cname

 def generate_result_code(self, code):
---
But I have no idea what other side effects that might have.

Ulrich
___
cython-devel mailing list
cython-devel@python.org
https://mail.python.org/mailman/listinfo/cython-devel


Re: [Cython] operator() bug in cython

2015-02-17 Thread Ulrich Dobramysl
On Fri Feb 13 2015 at 11:07:39 PM Greg Ewing 
wrote:

> Ulrich Dobramysl wrote:
>
> > Thanks! I haven't figured out how to call heap allocated objects, as the
> > code
> > ---
> > cdef OperatorTest *t = new OperatorTest()
> > t()
> > ---
> > is not translatable by Cython.
>
> Have you tried:
>
> t[0]()
>
> ?
>

Thanks, I didn't think about the t[0] trick!


> I haven't been following the development of Cython's internals,
> so I may be speaking naively here, but it looks wrong to me that
> the cname of that entry should be 'operator()' rather than the
> c-level name of the variable that the NameNode refers to.
>
>
The cname of the entry is correct IMO, because it cannot have any knowledge
about the cname of the object it is being called as later. The logic
dealing with the special case of an operator() member function of a c++
class in SimpleCallNode.analyse_c_function_call() needs to be changed
slightly to not treat operator() as an overloaded entry. Rather, the
function type of the SimpleCallNode needs to be set to the type of the
looked-up operator() entry. Then, at the code generation stage, the correct
cname of the SimpleCallNode entry is used and not the entry of operator().
With the patch below my test case compiles and runs without problems:

diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py
index f99ec6e..88522c9 100644
--- a/Cython/Compiler/ExprNodes.py
+++ b/Cython/Compiler/ExprNodes.py
@@ -4569,11 +4569,13 @@ class SimpleCallNode(CallNode):
 args = self.args

 if func_type.is_cpp_class:
-overloaded_entry =
self.function.type.scope.lookup("operator()")
-if overloaded_entry is None:
+call_operator = self.function.type.scope.lookup("operator()")
+if call_operator is None:
 self.type = PyrexTypes.error_type
 self.result_code = ""
 return
+self.function.type = call_operator.type
+overloaded_entry = None
 elif hasattr(self.function, 'entry'):
 overloaded_entry = self.function.entry
 elif (isinstance(self.function, IndexNode) and
@@ -4603,7 +4605,7 @@ class SimpleCallNode(CallNode):
 else:
 entry = None
 func_type = self.function_type()
-if not func_type.is_cfunction:
+if not (func_type.is_cfunction or func_type.is_cpp_class):
 error(self.pos, "Calling non-function type '%s'" %
func_type)
 self.type = PyrexTypes.error_type
 self.result_code = ""

What do you think? I don't know a lot about cython's internals, so there
might be use cases which break this code.

Ulrich
___
cython-devel mailing list
cython-devel@python.org
https://mail.python.org/mailman/listinfo/cython-devel