aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2024-12-04 12:27:33 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2024-12-09 15:08:12 +0100
commit206b907dec8e6feddb495ca177ca20fd446efddc (patch)
treeb35aca3af55a80405ca815fa8f33f79878f8fb1d
parent3da05cc765ab16b3622e2262022a40aa92fc0334 (diff)
Fix crash instantiating smart pointer types
For a smart pointer to a derived class, the smart pointer to the base class needs to be generated first for the conversion to the base class to work. Topologically sort instantiated smart pointers by base classes. Fixes: PYSIDE-2946 Task-number: PYSIDE-454 Pick-to: 6.8 Change-Id: If7be39e72312f8fe61ef7fbc0b351e070894d22e Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
-rw-r--r--sources/shiboken6/ApiExtractor/apiextractor.cpp46
1 files changed, 45 insertions, 1 deletions
diff --git a/sources/shiboken6/ApiExtractor/apiextractor.cpp b/sources/shiboken6/ApiExtractor/apiextractor.cpp
index 847377332..f3d9d0b58 100644
--- a/sources/shiboken6/ApiExtractor/apiextractor.cpp
+++ b/sources/shiboken6/ApiExtractor/apiextractor.cpp
@@ -11,6 +11,7 @@
#include "abstractmetalang.h"
#include "codesnip.h"
#include "exception.h"
+#include "graph.h"
#include "messages.h"
#include "modifications.h"
#include "optionsparser.h"
@@ -401,6 +402,48 @@ bool ApiExtractorPrivate::runHelper(ApiExtractorFlags flags)
return result;
}
+static qsizetype indexOfPointee(const InstantiatedSmartPointers &instantiatedList,
+ const AbstractMetaClassCPtr &pointee)
+{
+ for (qsizetype i = 0, size = instantiatedList.size(); i < size; ++i) {
+ if (instantiatedList.at(i).pointee == pointee)
+ return i;
+ }
+ return -1;
+}
+
+// Sort the list of instantiated smart pointers such that base classes go before
+// descendant classes since those register conversions to smart_ptr<base> for
+// which the base definition needs to exist (PYSIDE-2946).
+static InstantiatedSmartPointers
+ topologicalSortSmartPointers(const InstantiatedSmartPointers &instantiatedList)
+{
+ const auto size = instantiatedList.size();
+ if (size < 2)
+ return instantiatedList;
+
+ // Create a graph (using int indexes for sorting) with dependency edges for the inheritance
+ // within the pointee classes list.
+ Graph<InstantiatedSmartPointer> graph(instantiatedList);
+ for (qsizetype i = 0; i < size; ++i) {
+ const auto &smp = instantiatedList.at(i);
+ if (smp.pointee) {
+ for (const auto &base : smp.pointee->baseClasses()) {
+ const auto baseIndex = indexOfPointee(instantiatedList, base);
+ if (baseIndex != -1)
+ graph.addEdgeByIndexes(baseIndex, i);
+ }
+ }
+ }
+
+ const auto sortedGraphResult = graph.topologicalSort();
+ // Should not really fail since it is only by base classes ATM...
+ if (!sortedGraphResult.isValid())
+ throw Exception("Failed to sort the list of instantiated smart pointers (cyclic dependency?)"_L1);
+
+ return sortedGraphResult.result;
+}
+
static inline void classListToCList(const AbstractMetaClassList &list, AbstractMetaClassCList *target)
{
target->reserve(list.size());
@@ -430,7 +473,8 @@ std::optional<ApiExtractorResult> ApiExtractor::run(ApiExtractorFlags flags)
if (instantiationTe->isComplex())
smp.pointee = AbstractMetaClass::findClass(result.m_metaClasses, instantiationTe);
}
- qSwap(result.m_instantiatedSmartPointers, collectContext.instantiatedSmartPointers);
+ result.m_instantiatedSmartPointers =
+ topologicalSortSmartPointers(collectContext.instantiatedSmartPointers);
return result;
}