Skip to content

Commit

Permalink
Fix: AttributeError with anonymous unions
Browse files Browse the repository at this point in the history
  • Loading branch information
Vipul-Cariappa committed Sep 7, 2024
1 parent 7541520 commit 9ae46ad
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 39 deletions.
6 changes: 4 additions & 2 deletions src/CPPDataMember.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -307,11 +307,13 @@ PyTypeObject CPPDataMember_Type = {
} // namespace CPyCppyy

//- public members -----------------------------------------------------------
void CPyCppyy::CPPDataMember::Set(Cppyy::TCppScope_t scope, Cppyy::TCppScope_t data)
void CPyCppyy::CPPDataMember::Set(Cppyy::TCppScope_t scope, Cppyy::TCppScope_t data,
intptr_t additional_offset)
{
fEnclosingScope = scope;
fScope = data;
fOffset = Cppyy::GetDatamemberOffset(data); // XXX: Check back here // TODO: make lazy
fOffset = Cppyy::GetDatamemberOffset(data) +
additional_offset; // XXX: Check back here // TODO: make lazy
fFlags = Cppyy::IsStaticDatamember(data) ? kIsStaticData : 0;

const std::string name = Cppyy::GetFinalName(data);
Expand Down
7 changes: 4 additions & 3 deletions src/CPPDataMember.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ class CPPInstance;

class CPPDataMember {
public:
void Set(Cppyy::TCppScope_t scope, Cppyy::TCppScope_t var);
void Set(Cppyy::TCppScope_t scope, Cppyy::TCppScope_t var,
intptr_t additional_offset=0);
void Set(Cppyy::TCppScope_t scope, const std::string& name, void* address);

std::string GetName();
Expand Down Expand Up @@ -56,12 +57,12 @@ inline bool CPPDataMember_CheckExact(T* object)

//- creation -----------------------------------------------------------------
inline CPPDataMember* CPPDataMember_New(
Cppyy::TCppScope_t scope, Cppyy::TCppScope_t var)
Cppyy::TCppScope_t scope, Cppyy::TCppScope_t var, intptr_t additional_offset=0)
{
// Create an initialize a new property descriptor, given the C++ datum.
CPPDataMember* pyprop =
(CPPDataMember*)CPPDataMember_Type.tp_new(&CPPDataMember_Type, nullptr, nullptr);
pyprop->Set(scope, var);
pyprop->Set(scope, var, additional_offset);
return pyprop;
}

Expand Down
70 changes: 36 additions & 34 deletions src/ProxyWrappers.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
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);
}

Expand Down

0 comments on commit 9ae46ad

Please sign in to comment.