Closed saraedum closed 2 years ago
Thanks for the nice reproducer! Here's a simpler one:
class Z {
public:
virtual ~Z() {}
};
class X : Z {
X();
X(const X&&) = delete;
};
It's an odd combo of different errors: to only truly have no contructors (not even Cling-provided faux default ones), the move and/or copy constructor needs to be deleted (that's the contribution from std::atomic<size_t>
in the original reproducer). I figured it's a bug that upstream still provides the move constructor in the reflection info otherwise, but that's actually proper per C++ rules (and they are provided by Clang, not Cling).
Then the derivation from the base Z
without an __init__
in X
, makes Python call Z
's __init__
, which resolves on the cppyy side as if X
were a Python-side derived class without provided __init__
. It then proceeds to call the expected internal dispatcher constructor. However, since it's not a Python class, there is no dispatcher, and the contructor found is again the Z
base class one. Hence infinite recursion. Cute.
The cppyy side is now fixed in repo (preventing the infinite recursion): both a check for __init__
belonging to the proper class on call, and a proper error for the case where there are no (public) constructors available. Tests are in, including a test for the case of a protected constructor and Python-side derivation.
Fix released with 2.3.0 and its dependencies.
Consider the following code snippet:
This crashes for me with:
Debugging with GDB shows the following infinite recursion:
I don’t except calling a private constructor to actually yield an instance of the object so this should be an error. However, this problem shows up when cppyy attempts to convert arguments, i.e., when invoking an overloaded function with some argument that is not X:
Conversion to X is apparently attempted when invoking say
f([])
which then leads to the above crash.This happened on Linux with the latest cppyy from conda-forge: