-
Notifications
You must be signed in to change notification settings - Fork 5
Fix: AttributeError with anonymous unions #57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -89,10 +89,42 @@ static PyObject* CreateNewCppProxyClass(Cppyy::TCppScope_t klass, PyObject* pyba | |
| } | ||
|
|
||
| static inline | ||
| void AddPropertyToClass(PyObject* pyclass, | ||
| Cppyy::TCppScope_t scope, Cppyy::TCppScope_t data) | ||
| void AddPropertyToClass(PyObject* pyclass, Cppyy::TCppScope_t scope, | ||
| Cppyy::TCppScope_t data, intptr_t additional_offset=0) | ||
| { | ||
| CPyCppyy::CPPDataMember* property = CPyCppyy::CPPDataMember_New(scope, data); | ||
| if (!Cppyy::IsPublicData(data)) | ||
| return; | ||
|
|
||
| // enum datamembers (this in conjunction with previously collected enums above) | ||
| if (Cppyy::IsEnumType(Cppyy::GetDatamemberType(data)) && | ||
| Cppyy::IsStaticDatamember(data)) { | ||
| // some implementation-specific data members have no address: ignore them | ||
| if (!Cppyy::GetDatamemberOffset(data)) | ||
| return; | ||
|
|
||
| // two options: this is a static variable, or it is the enum value, the latter | ||
| // already exists, so check for it and move on if set | ||
| PyObject* eset = PyObject_GetAttrString(pyclass, | ||
| const_cast<char*>(Cppyy::GetFinalName(data).c_str())); | ||
| if (eset) { | ||
| Py_DECREF(eset); | ||
| return; | ||
| } | ||
|
|
||
| PyErr_Clear(); | ||
| } | ||
|
|
||
| if (strstr(Cppyy::GetDatamemberTypeAsString(data).c_str(), "anonymous struct at") || | ||
| strstr(Cppyy::GetDatamemberTypeAsString(data).c_str(), "anonymous union at")) { | ||
| std::vector<Cppyy::TCppScope_t> datamembers = Cppyy::GetDatamembers(Cppyy::GetTypeScope(data)); | ||
| for (auto &datamember: datamembers) { | ||
| // properties (aka public (static) data members) | ||
| AddPropertyToClass(pyclass, scope, datamember, | ||
| additional_offset + Cppyy::GetDatamemberOffset(data)); | ||
| } | ||
| } | ||
|
|
||
| CPyCppyy::CPPDataMember* property = CPyCppyy::CPPDataMember_New(scope, data, additional_offset); | ||
| PyObject* pname = CPyCppyy_PyText_InternFromString(const_cast<char*>(property->GetName().c_str())); | ||
|
|
||
| // allow access at the instance level | ||
|
|
@@ -371,37 +403,7 @@ static int BuildScopeProxyDict(Cppyy::TCppScope_t scope, PyObject* pyclass, cons | |
| // collect data members (including enums) | ||
| std::vector<Cppyy::TCppScope_t> datamembers = Cppyy::GetDatamembers(scope); | ||
| for (auto &datamember : datamembers) { | ||
| // allow only public members | ||
| if (!Cppyy::IsPublicData(datamember)) | ||
| continue; | ||
|
|
||
| // enum datamembers (this in conjunction with previously collected enums above) | ||
| if (Cppyy::IsEnumType(Cppyy::GetDatamemberType(datamember)) && Cppyy::IsStaticDatamember(datamember)) { | ||
| // some implementation-specific data members have no address: ignore them | ||
| if (!Cppyy::GetDatamemberOffset(datamember)) | ||
| continue; | ||
|
|
||
| // two options: this is a static variable, or it is the enum value, the latter | ||
| // already exists, so check for it and move on if set | ||
| PyObject* eset = PyObject_GetAttrString(pyclass, | ||
| const_cast<char*>(Cppyy::GetFinalName(datamember).c_str())); | ||
| if (eset) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should get by with less refactoring (i.e. retain the changes in the anonymus enum block in BuildScopeProxyDict(adding the offset), instead of moving the whole block that collects datamembers to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The reason behind moving the entire logic into Let me know if there is a specific change that looks off to you. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes I was wondering whether the recursion is a good idea but I guess since it only happens when we have anonymous structs and unions, it should not be too expensive in the normal case. I was wondering how masters support nested anonymous structs and unions without recursion? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I did not have a look at it. I saw the problem and came up with a solution. The solution looked simple and easy to implement. So I did not look at how master does this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I understand that but one of the main points here is not to diverge from master as much as possible. We can make as many changes in clingwrapper and add interfaces in InterOp to facilitate/emulate what is made available to CPyCppyy to achieve the same result. Since the support does not use recursion in master and is achieved with the interfaces at hand, I would recommend a side-by-side debug to emulate the same on the backend side. @vgvassilev what do you think? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, eventually we should merge all of this work back to upstream and if that change is not mergeable will be a problem. I cannot judge that now but perhaps we could discuss that at the meeting later today. |
||
| Py_DECREF(eset); | ||
| continue; | ||
| } | ||
|
|
||
| PyErr_Clear(); | ||
|
|
||
| // it could still be that this is an anonymous enum, which is not in the list | ||
| // provided by the class | ||
| if (strstr(Cppyy::GetDatamemberTypeAsString(datamember).c_str(), "(anonymous)") != 0 || | ||
| strstr(Cppyy::GetDatamemberTypeAsString(datamember).c_str(), "(unnamed)") != 0) { | ||
| AddPropertyToClass(pyclass, scope, datamember); | ||
| continue; | ||
| } | ||
| } | ||
|
|
||
| // properties (aka public (static) data members) | ||
| // properties (aka public (static) data members) | ||
| AddPropertyToClass(pyclass, scope, datamember); | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recursion is used here.
I can undo the changes in
BuildScopeProxyDict, but then I will have to duplicate the same things inAddPropertyToClassfor recursion to work.