Troubleshooting sip assignHelper != NULL assertion
Phil Thompson
phil at riverbankcomputing.com
Tue Jun 2 14:28:55 BST 2020
On 02/06/2020 14:03, Scott Talbert wrote:
> On Tue, 2 Jun 2020, Phil Thompson wrote:
>
>> On 02/06/2020 03:00, Scott Talbert wrote:
>>> On Mon, 1 Jun 2020, Phil Thompson wrote:
>>>
>>>> On 31/05/2020 17:48, Scott Talbert wrote:
>>>>> On Sun, 31 May 2020, Phil Thompson wrote:
>>>>>
>>>>>> On 31/05/2020 16:29, Scott Talbert wrote:
>>>>>>> On Sun, 31 May 2020, Phil Thompson wrote:
>>>>>>>
>>>>>>>> On 31/05/2020 01:23, Scott Talbert wrote:
>>>>>>>>> On Sat, 30 May 2020, Phil Thompson wrote:
>>>>>>>>>
>>>>>>>>>> On 28/05/2020 16:52, Scott Talbert wrote:
>>>>>>>>>>> On Thu, 28 May 2020, Phil Thompson wrote:
>>>>>>>>>>>
>>>>>>>>>>>> On 28/05/2020 16:30, Scott Talbert wrote:
>>>>>>>>>>>>> On Thu, 28 May 2020, Phil Thompson wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> Hi,
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> I'm running into the following assertion in wxPython
>>>>>>>>>>>>>>>>> that I don't
>>>>>>>>>>>>>>>>> quite understand:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> python3: ../../../../sip/siplib/siplib.c:3444:
>>>>>>>>>>>>>>>>> parseResult: Assertion
>>>>>>>>>>>>>>>>> `assign_helper != NULL' failed.
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> This is the relevant C++ class:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> class wxPGWindowList
>>>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>>>> public:
>>>>>>>>>>>>>>>>> wxPGWindowList(wxWindow* primary, wxWindow*
>>>>>>>>>>>>>>>>> secondary = NULL)
>>>>>>>>>>>>>>>>> : m_primary(primary)
>>>>>>>>>>>>>>>>> , m_secondary(secondary)
>>>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>>>> }
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> void SetSecondary(wxWindow* secondary) {
>>>>>>>>>>>>>>>>> m_secondary = secondary; }
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> wxWindow* GetPrimary() const { return m_primary; }
>>>>>>>>>>>>>>>>> wxWindow* GetSecondary() const { return
>>>>>>>>>>>>>>>>> m_secondary; }
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> wxWindow* m_primary;
>>>>>>>>>>>>>>>>> wxWindow* m_secondary;
>>>>>>>>>>>>>>>>> };
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> It doesn't matter what the C++ class looks like, it's
>>>>>>>>>>>>>>>> the corresponding .sip that would be of interest.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> My bad, here it is:
>>>>>>>>>>>>>>> class wxPGWindowList
>>>>>>>>>>>>>>> {
>>>>>>>>>>>>>>> %Docstring
>>>>>>>>>>>>>>> PGWindowList(primary, secondary=None)
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Contains a list of editor windows returned by
>>>>>>>>>>>>>>> CreateControls.
>>>>>>>>>>>>>>> %End
>>>>>>>>>>>>>>> %TypeHeaderCode
>>>>>>>>>>>>>>> #include <wx/propgrid/editors.h>
>>>>>>>>>>>>>>> %End
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> public:
>>>>>>>>>>>>>>> wxPGWindowList(
>>>>>>>>>>>>>>> wxWindow * primary,
>>>>>>>>>>>>>>> wxWindow * secondary = NULL
>>>>>>>>>>>>>>> );
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> void SetSecondary(
>>>>>>>>>>>>>>> wxWindow * secondary
>>>>>>>>>>>>>>> );
>>>>>>>>>>>>>>> %Docstring
>>>>>>>>>>>>>>> SetSecondary(secondary)
>>>>>>>>>>>>>>> %End
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> wxWindow * GetPrimary() const;
>>>>>>>>>>>>>>> %Docstring
>>>>>>>>>>>>>>> GetPrimary() -> wx.Window
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Gets window of primary editor.
>>>>>>>>>>>>>>> %End
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> wxWindow * GetSecondary() const;
>>>>>>>>>>>>>>> %Docstring
>>>>>>>>>>>>>>> GetSecondary() -> wx.Window
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Gets window of secondary editor.
>>>>>>>>>>>>>>> %End
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> public:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> %Property(name=Primary, get=GetPrimary)
>>>>>>>>>>>>>>> %Property(name=Secondary, get=GetSecondary,
>>>>>>>>>>>>>>> set=SetSecondary)
>>>>>>>>>>>>>>> }; // end of class wxPGWindowList
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> The assertion occurs when trying to return an instance
>>>>>>>>>>>>>>>>> of
>>>>>>>>>>>>>>>>> wxPGWindowList in a Python method, e.g.:
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> def foo():
>>>>>>>>>>>>>>>>> return wxpg.PGWindowList(a, b)
>>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> From what I can tell, there is no assignment helper
>>>>>>>>>>>>>>>>> assigned by sip
>>>>>>>>>>>>>>>>> because there is no default constructor? I may be
>>>>>>>>>>>>>>>>> missing something,
>>>>>>>>>>>>>>>>> but I can't see why a default constructor would be
>>>>>>>>>>>>>>>>> needed.
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>> You don't say what version of the sip module you are
>>>>>>>>>>>>>>>> using but I'm guessing that that assertion is when it's
>>>>>>>>>>>>>>>> parsing the Python object returned by a
>>>>>>>>>>>>>>>> re-implementation of a C++ virtual. That doesn't seem to
>>>>>>>>>>>>>>>> be happening in the above which suggests things aren't
>>>>>>>>>>>>>>>> happening where you think they are.
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> sip module version is 4.19.19. You are correct, I
>>>>>>>>>>>>>>> oversimplified what
>>>>>>>>>>>>>>> is actually happening. This is really what is happening:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> class LargeImageEditor(wxpg.PGEditor):
>>>>>>>>>>>>>>> def CreateControls(self, propgrid, property, pos,
>>>>>>>>>>>>>>> sz):
>>>>>>>>>>>>>>> ...
>>>>>>>>>>>>>>> return wxpg.PGWindowList(self.tc, btn)
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Where CreateControls is a C++ virtual, relevant .sip
>>>>>>>>>>>>>>> snippet:
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> virtual
>>>>>>>>>>>>>>> wxPGWindowList CreateControls(
>>>>>>>>>>>>>>> wxPropertyGrid * propgrid,
>>>>>>>>>>>>>>> wxPGProperty * property,
>>>>>>>>>>>>>>> const wxPoint & pos,
>>>>>>>>>>>>>>> const wxSize & size
>>>>>>>>>>>>>>> ) const = 0;
>>>>>>>>>>>>>>> %Docstring
>>>>>>>>>>>>>>> CreateControls(propgrid, property, pos, size) ->
>>>>>>>>>>>>>>> PGWindowList
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> Instantiates editor controls.
>>>>>>>>>>>>>>> %End
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> So SIP need to copy the wxPGWindowList from the stack to
>>>>>>>>>>>>>> the heap. Shouldn't CreateControls return a pointer to the
>>>>>>>>>>>>>> wxPGWindowList?
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Of course SIP should detect this when generating the code
>>>>>>>>>>>>>> rather than rely on a runtime assertion.
>>>>>>>>>>>>>
>>>>>>>>>>>>> That is probably how I would have designed the API, but
>>>>>>>>>>>>> alas it wasn't
>>>>>>>>>>>>> done that way. :)
>>>>>>>>>>>>>
>>>>>>>>>>>>> Shouldn't a (default) copy constructor be sufficient to
>>>>>>>>>>>>> copy the
>>>>>>>>>>>>> wxPGWindowList in this case?
>>>>>>>>>>>>
>>>>>>>>>>>> SIP may be being too conservative when determining if there
>>>>>>>>>>>> is an implied copy ctor. Try adding an explicit copy ctor to
>>>>>>>>>>>> the wxPGWindowList .sip file.
>>>>>>>>>>>
>>>>>>>>>>> I don't think that will be enough, though. SIP seems to only
>>>>>>>>>>> set the
>>>>>>>>>>> assignment helper if there are *both* a public default
>>>>>>>>>>> constructor and
>>>>>>>>>>> a public copy constructor, see:
>>>>>>>>>>>
>>>>>>>>>>> https://www.riverbankcomputing.com/hg/sip/file/d85e9957e726/sipgen/transform.c#l596
>>>>>>>>>>>
>>>>>>>>>>> Scott
>>>>>>>>>>
>>>>>>>>>> Should be fixed in the current repo. SIP v4.19.23 will be
>>>>>>>>>> released next week.
>>>>>>>>>>
>>>>>>>>>> Be aware that the fix may expose missing private ctors in
>>>>>>>>>> other .sip files - PyQt had two cases.
>>>>>>>>>
>>>>>>>>> Thanks for the quick fix.
>>>>>>>>>
>>>>>>>>> However, I think I found a situation with the new code where an
>>>>>>>>> assign
>>>>>>>>> function is getting created where it probably shouldn't be.
>>>>>>>>>
>>>>>>>>> struct wxSplitterRenderParams
>>>>>>>>> {
>>>>>>>>> %Docstring
>>>>>>>>> SplitterRenderParams(widthSash_, border_, isSens_)
>>>>>>>>>
>>>>>>>>> This is just a simple struct used as a return value of
>>>>>>>>> wxRendererNative::GetSplitterParams().
>>>>>>>>> %End
>>>>>>>>> %TypeHeaderCode
>>>>>>>>> #include <wx/renderer.h>
>>>>>>>>> %End
>>>>>>>>>
>>>>>>>>> wxSplitterRenderParams(
>>>>>>>>> wxCoord widthSash_,
>>>>>>>>> wxCoord border_,
>>>>>>>>> bool isSens_
>>>>>>>>> );
>>>>>>>>>
>>>>>>>>> const wxCoord border;
>>>>>>>>>
>>>>>>>>> const bool isHotSensitive;
>>>>>>>>>
>>>>>>>>> const wxCoord widthSash;
>>>>>>>>>
>>>>>>>>> }; // end of class wxSplitterRenderParams
>>>>>>>>>
>>>>>>>>> This results in:
>>>>>>>>>
>>>>>>>>> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp: In
>>>>>>>>> function
>>>>>>>>> ‘void assign_wxSplitterRenderParams(void*, Py_ssize_t, void*)’:
>>>>>>>>> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp:31:125:
>>>>>>>>> error:
>>>>>>>>> use of deleted function ‘wxSplitterRenderParams&
>>>>>>>>> wxSplitterRenderParams::operator=(const
>>>>>>>>> wxSplitterRenderParams&)’
>>>>>>>>> 31 | reinterpret_cast< ::wxSplitterRenderParams
>>>>>>>>> *>(sipDst)[sipDstIdx] = *reinterpret_cast<
>>>>>>>>> ::wxSplitterRenderParams
>>>>>>>>> *>(sipSrc);
>>>>>>>>> | ^
>>>>>>>>> In file included from
>>>>>>>>> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp:12:
>>>>>>>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>>>>>>>> note: ‘wxSplitterRenderParams&
>>>>>>>>> wxSplitterRenderParams::operator=(const
>>>>>>>>> wxSplitterRenderParams&)’ is implicitly deleted because the
>>>>>>>>> default
>>>>>>>>> definition would be ill-formed:
>>>>>>>>> 97 | struct WXDLLIMPEXP_CORE wxSplitterRenderParams
>>>>>>>>> | ^~~~~~~~~~~~~~~~~~~~~~
>>>>>>>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>>>>>>>> error: non-static const member ‘const wxCoord
>>>>>>>>> wxSplitterRenderParams::widthSash’, cannot use default
>>>>>>>>> assignment
>>>>>>>>> operator
>>>>>>>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>>>>>>>> error: non-static const member ‘const wxCoord
>>>>>>>>> wxSplitterRenderParams::border’, cannot use default assignment
>>>>>>>>> operator
>>>>>>>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>>>>>>>> error: non-static const member ‘const bool
>>>>>>>>> wxSplitterRenderParams::isHotSensitive’, cannot use default
>>>>>>>>> assignment
>>>>>>>>> operator
>>>>>>>>
>>>>>>>> Yes, that's what I meant by missing private copy ctors. SIP
>>>>>>>> cannot accurately determine whether a copy ctor is available
>>>>>>>> unless it knows everything about the C++ class (including
>>>>>>>> private members and their types), but SIP is not a full C++
>>>>>>>> parser (and never will be). Therefore you need to declare a
>>>>>>>> private copy ctor in the .sip file to correct the assumption
>>>>>>>> that there is a public copy ctor available. In the future I may
>>>>>>>> add a class annotation to achieve the same thing.
>>>>>>>
>>>>>>> Thanks, I understand that now. :) After declaring a private
>>>>>>> copy
>>>>>>> ctor in the above .sip file, I'm now getting this:
>>>>>>>
>>>>>>> ../../../../sip/cpp/sip_corewxDelegateRendererNative.cpp: In
>>>>>>> function
>>>>>>> ‘PyObject*
>>>>>>> meth_wxDelegateRendererNative_GetSplitterParams(PyObject*,
>>>>>>> PyObject*, PyObject*)’:
>>>>>>> ../../../../sip/cpp/sip_corewxDelegateRendererNative.cpp:1360:38:
>>>>>>> error: taking address of rvalue [-fpermissive]
>>>>>>> 1360 | sipRes = &(sipSelfWasArg ? sipCpp->
>>>>>>> ::wxDelegateRendererNative::GetSplitterParams(win) :
>>>>>>> sipCpp->GetSplitterParams(win));
>>>>>>> |
>>>>>>> ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>>>>>>>
>>>>>>> So, since SIP can't copy the wxSplitterRenderParams, it is trying
>>>>>>> to
>>>>>>> return a reference to the original one, but it seems that doesn't
>>>>>>> work?
>>>>>>
>>>>>> So what does the .sip file for wxDelegateRenderNative look like?
>>>>>
>>>>> It's a bit long, so attached.
>>>>
>>>> Can you try the current repo.
>>>>
>>>> When you are happy I'll release v4.19.23.
>>>
>>> Unfortunately, I'm still running into trouble with this
>>> wxSplitterRenderParams class. This is what I get now:
>>>
>>> ../../../../sip/cpp/sip_corewxRendererNative.cpp: In function
>>> ‘PyObject* meth_wxRendererNative_GetSplitterParams(PyObject*,
>>> PyObject*, PyObject*)’:
>>> ../../../../sip/cpp/sip_corewxRendererNative.cpp:1464:52: error: use
>>> of deleted function ‘wxSplitterRenderParams&
>>> wxSplitterRenderParams::operator=(wxSplitterRenderParams&&)’
>>> 1464 | *sipRes = sipCpp->GetSplitterParams(win);
>>> | ^
>>> In file included from
>>> ../../../../sip/cpp/sip_corewxRendererNative.cpp:12:
>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>> note: ‘wxSplitterRenderParams&
>>> wxSplitterRenderParams::operator=(wxSplitterRenderParams&&)’ is
>>> implicitly deleted because the default definition would be
>>> ill-formed:
>>> 97 | struct WXDLLIMPEXP_CORE wxSplitterRenderParams
>>> | ^~~~~~~~~~~~~~~~~~~~~~
>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>> error: non-static const member ‘const wxCoord
>>> wxSplitterRenderParams::widthSash’, cannot use default assignment
>>> operator
>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>> error: non-static const member ‘const wxCoord
>>> wxSplitterRenderParams::border’, cannot use default assignment
>>> operator
>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
>>> error: non-static const member ‘const bool
>>> wxSplitterRenderParams::isHotSensitive’, cannot use default
>>> assignment
>>> operator
>>> ../../../../sip/cpp/sip_corewxRendererNative.cpp: In function
>>> ‘PyObject* meth_wxRendererNative_GetVersion(PyObject*, PyObject*)’:
>>> ../../../../sip/cpp/sip_corewxRendererNative.cpp:1508:42: error: use
>>> of deleted function ‘wxRendererVersion&
>>> wxRendererVersion::operator=(wxRendererVersion&&)’
>>> 1508 | *sipRes = sipCpp->GetVersion();
>>> | ^
>>> In file included from
>>> ../../../../sip/cpp/sip_corewxRendererNative.cpp:12:
>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:141:25:
>>> note: ‘wxRendererVersion&
>>> wxRendererVersion::operator=(wxRendererVersion&&)’ is implicitly
>>> deleted because the default definition would be ill-formed:
>>> 141 | struct WXDLLIMPEXP_CORE wxRendererVersion
>>> | ^~~~~~~~~~~~~~~~~
>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:141:25:
>>> error: non-static const member ‘const int
>>> wxRendererVersion::version’,
>>> cannot use default assignment operator
>>> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:141:25:
>>> error: non-static const member ‘const int wxRendererVersion::age’,
>>> cannot use default assignment operator
>>>
>>>
>>> I looked at what SIP 4.19.19 generated for
>>> sip_corewxRendererNative.cpp, and this is what it did:
>>>
>>> sipRes = new
>>> ::wxSplitterRenderParams(sipCpp->GetSplitterParams(win));
>>>
>>> So, it seems the wxSplitterRenderParams class does actually have an
>>> implicit copy constructor that works. So, it doesn't have an
>>> assignment operator but DOES have a copy constructor.
>>
>> So if you take out the declaration of the private copy ctor from the
>> .sip file...
>
> I did try that way as well, but in that case I get:
>
> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp: In function
> ‘void assign_wxSplitterRenderParams(void*, Py_ssize_t, void*)’:
> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp:31:125: error:
> use of deleted function ‘wxSplitterRenderParams&
> wxSplitterRenderParams::operator=(const wxSplitterRenderParams&)’
> 31 | reinterpret_cast< ::wxSplitterRenderParams
> *>(sipDst)[sipDstIdx] = *reinterpret_cast< ::wxSplitterRenderParams
> *>(sipSrc);
> | ^
> In file included from
> ../../../../sip/cpp/sip_corewxSplitterRenderParams.cpp:12:
> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
> note: ‘wxSplitterRenderParams& wxSplitterRenderParams::operator=(const
> wxSplitterRenderParams&)’ is implicitly deleted because the default
> definition would be ill-formed:
> 97 | struct WXDLLIMPEXP_CORE wxSplitterRenderParams
> | ^~~~~~~~~~~~~~~~~~~~~~
> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
> error: non-static const member ‘const wxCoord
> wxSplitterRenderParams::widthSash’, cannot use default assignment
> operator
> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
> error: non-static const member ‘const wxCoord
> wxSplitterRenderParams::border’, cannot use default assignment
> operator
> ../../../../../Phoenix/ext/wxWidgets/include/wx/renderer.h:97:25:
> error: non-static const member ‘const bool
> wxSplitterRenderParams::isHotSensitive’, cannot use default assignment
> operator
...so follow the same logic as the copy ctor and define a private
assignment operator.
Phil
More information about the PyQt
mailing list