[packages/pyside-setup] - up to 6.11.0 + git updates for llvm 22
baggins
baggins at pld-linux.org
Sat Apr 18 19:43:04 CEST 2026
commit 5d13d2c549d125ea2a2240226e24ffa68fcaca29
Author: Jan Rękorajski <baggins at pld-linux.org>
Date: Sat Apr 18 21:42:31 2026 +0200
- up to 6.11.0 + git updates for llvm 22
git.patch | 3838 +++++++++++++++++++++++++++++++++++++++++++++++++++++
pyside-setup.spec | 26 +-
2 files changed, 3852 insertions(+), 12 deletions(-)
---
diff --git a/pyside-setup.spec b/pyside-setup.spec
index e7476a8..dab6740 100644
--- a/pyside-setup.spec
+++ b/pyside-setup.spec
@@ -7,12 +7,13 @@
Summary: Qt For Python
Name: pyside-setup
-Version: 6.10.0
-Release: 4
+Version: 6.11.0
+Release: 1
License: LGPL v2.1+ / GPL v2
Group: Libraries/Python
Source0: https://github.com/pyside/pyside-setup/archive/v%{version}/%{name}-%{version}.tar.gz
-# Source0-md5: a89a230e5b763971a43aa45c77112451
+# Source0-md5: bce6fc7597f39a53fe9f2336d5402883
+Patch0: git.patch
URL: https://wiki.qt.io/Qt_for_Python
BuildRequires: Qt63D-devel
BuildRequires: Qt6Bluetooth-devel
@@ -135,11 +136,12 @@ Dokumentacja API modułu Pythona %{module}.
%prep
%setup -q
+%patch -P0 -p1
# fix #!/usr/bin/env python -> #!/usr/bin/python:
%{__sed} -E -i -e '1s,#!\s*/usr/bin/env\s+python(\s|$),#!%{__python3}\1,' \
sources/pyside-tools/pyside_tool.py \
- sources/shiboken6/shiboken_tool.py
+ sources/shiboken6_generator/shiboken_tool.py
%build
# Can't use py3_* macros here and in install.
@@ -184,12 +186,12 @@ CXXFLAGS="${CXXFLAGS:-%rpmcppflags %rpmcxxflags}"; export CXXFLAGS; \
%{__rm} $RPM_BUILD_ROOT%{py3_sitedir}/PySide6/Qt/lib/lib{avcodec,avformat,avutil,swresample,swscale}.so*
# Fix main libs location
-%{__mv} $RPM_BUILD_ROOT%{py3_sitedir}/PySide6/libpyside6*.abi3.so.6.10 $RPM_BUILD_ROOT%{_libdir}/
-%{__mv} $RPM_BUILD_ROOT%{py3_sitedir}/shiboken6/libshiboken6.abi3.so.6.10 $RPM_BUILD_ROOT%{_libdir}/
+%{__mv} $RPM_BUILD_ROOT%{py3_sitedir}/PySide6/libpyside6*.abi3.so.6.11 $RPM_BUILD_ROOT%{_libdir}/
+%{__mv} $RPM_BUILD_ROOT%{py3_sitedir}/shiboken6/libshiboken6.abi3.so.6.11 $RPM_BUILD_ROOT%{_libdir}/
# ... but keep symlinks so linking to the library works
-ln -sr $RPM_BUILD_ROOT%{_libdir}/libpyside6*.abi3.so.6.10 $RPM_BUILD_ROOT%{py3_sitedir}/PySide6/
-ln -sr $RPM_BUILD_ROOT%{_libdir}/libshiboken6.abi3.so.6.10 $RPM_BUILD_ROOT%{py3_sitedir}/shiboken6/
+ln -sr $RPM_BUILD_ROOT%{_libdir}/libpyside6*.abi3.so.6.11 $RPM_BUILD_ROOT%{py3_sitedir}/PySide6/
+ln -sr $RPM_BUILD_ROOT%{_libdir}/libshiboken6.abi3.so.6.11 $RPM_BUILD_ROOT%{py3_sitedir}/shiboken6/
%py3_ocomp $RPM_BUILD_ROOT%{py3_sitedir}
@@ -210,10 +212,10 @@ rm -rf $RPM_BUILD_ROOT
%attr(755,root,root) %{_bindir}/pyside6-*
%attr(755,root,root) %{_bindir}/shiboken6
%attr(755,root,root) %{_bindir}/shiboken6-genpyi
-%attr(755,root,root) %{_libdir}/libpyside6*.abi3.so.6.10
+%attr(755,root,root) %{_libdir}/libpyside6*.abi3.so.6.11
%dir %{py3_sitedir}/PySide6
# symlinks
-%{py3_sitedir}/PySide6/libpyside6*.abi3.so.6.10
+%{py3_sitedir}/PySide6/libpyside6*.abi3.so.6.11
%dir %{py3_sitedir}/PySide6/Qt
%dir %{py3_sitedir}/PySide6/Qt/%{_lib}
%{py3_sitedir}/PySide6/Qt/%{_lib}/qt6
@@ -269,10 +271,10 @@ rm -rf $RPM_BUILD_ROOT
%files -n python3-shiboken6
%defattr(644,root,root,755)
%doc LICENSES README.shiboken6.md
-%attr(755,root,root) %{_libdir}/libshiboken6.abi3.so.6.10
+%attr(755,root,root) %{_libdir}/libshiboken6.abi3.so.6.11
%dir %{py3_sitedir}/shiboken6
# symlink
-%{py3_sitedir}/shiboken6/libshiboken6.abi3.so.6.10
+%{py3_sitedir}/shiboken6/libshiboken6.abi3.so.6.11
%{py3_sitedir}/shiboken6/__pycache__
%{py3_sitedir}/shiboken6/*.py
%{py3_sitedir}/shiboken6/*.pyi
diff --git a/git.patch b/git.patch
new file mode 100644
index 0000000..17c16f1
--- /dev/null
+++ b/git.patch
@@ -0,0 +1,3838 @@
+diff --git a/build_scripts/config.py b/build_scripts/config.py
+index 47dd28b7c..852c411fd 100644
+--- a/build_scripts/config.py
++++ b/build_scripts/config.py
+@@ -182,7 +182,8 @@ class Config(metaclass=Singleton):
+ "Python bindings for the Qt cross-platform application and UI framework"
+ )
+ self.setup_kwargs['install_requires'] = [
+- f"{self.shiboken_module_st_name}=={package_version}"
++ f"{self.shiboken_module_st_name}=={package_version}",
++ 'tomli>=2.0.1; python_version < "3.11"',
+ ]
+ if qt_install_dir:
+ _pyside_tools = available_pyside_tools(qt_tools_path=Path(qt_install_dir))
+diff --git a/build_scripts/utils.py b/build_scripts/utils.py
+index 3cb7ade0f..92e4ac1e7 100644
+--- a/build_scripts/utils.py
++++ b/build_scripts/utils.py
+@@ -1159,9 +1159,10 @@ def copy_cmake_config_dirs(install_dir, st_build_dir, st_package_name, cmake_pac
+ shutil.rmtree(dst_path)
+ dst_path.mkdir(parents=True)
+
+- # check for wheel target files
++ # check for wheel target and config spec files
+ wheel_path = wheel_cmake_dir / src_path.name
+ wheel_targets_exist = {}
++ wheel_config_files_exist = set()
+ if wheel_path.exists():
+ for item in wheel_path.iterdir():
+ if item.is_file() and re.search(r"Targets(-.*)?\.cmake$", item.name):
+@@ -1170,6 +1171,10 @@ def copy_cmake_config_dirs(install_dir, st_build_dir, st_package_name, cmake_pac
+ wheel_targets_exist[base_name] = True
+ # Copy wheel target file
+ shutil.copy2(str(item), str(dst_path / item.name))
++ elif item.is_file() and re.search(r"Config\..+\.cmake$", item.name):
++ # Wheel-specific config spec file
++ wheel_config_files_exist.add(item.name)
++ shutil.copy2(str(item), str(dst_path / item.name))
+
+ # Copy remaining files
+ for item in src_path.iterdir():
+@@ -1180,6 +1185,8 @@ def copy_cmake_config_dirs(install_dir, st_build_dir, st_package_name, cmake_pac
+ is_pyside_shiboken = base_name in ("PySide6", "Shiboken6", "Shiboken6Tools")
+ if is_pyside_shiboken and base_name in wheel_targets_exist:
+ skip_file = True
++ elif item.name in wheel_config_files_exist:
++ skip_file = True
+
+ if not skip_file:
+ shutil.copy2(str(item), str(dst_path / item.name))
+diff --git a/build_scripts/wheel_files.py b/build_scripts/wheel_files.py
+index 72a2641bf..db59a9f81 100644
+--- a/build_scripts/wheel_files.py
++++ b/build_scripts/wheel_files.py
+@@ -465,9 +465,13 @@ def module_QtQml() -> ModuleData:
+ _qtlib = [
+ "libQt6LabsAnimation",
+ "libQt6LabsFolderListModel",
++ "libQt6LabsPlatform",
+ "libQt6LabsQmlModels*",
+ "libQt6LabsSettings",
+ "libQt6LabsSharedImage",
++ "libQt6LabsStyleKit",
++ "libQt6LabsStyleKitImpl",
++ "libQt6LabsSynchronizer",
+ "libQt6LabsWavefrontMesh",
+ "libQt6QmlCore",
+ "libQt6QmlLocalStorage",
+@@ -489,9 +493,13 @@ def module_QtQml() -> ModuleData:
+ _metatypes = [
+ "qt6labsanimation_metatypes.json",
+ "qt6labsfolderlistmodel_metatypes.json",
++ "qt6labsplatform_metatypes.json",
+ "qt6labsqmlmodels_metatypes.json",
+ "qt6labssettings_metatypes.json",
+ "qt6labssharedimage_metatypes.json",
++ "qt6labsstylekit_metatypes.json",
++ "qt6labsstylekitimpl_metatypes.json",
++ "qt6labssynchronizer_metatypes.json",
+ "qt6labswavefrontmesh_metatypes.json",
+ "qt6packetprotocolprivate_metatypes.json",
+ "qt6qmlcompilerprivate_metatypes.json",
+@@ -509,13 +517,16 @@ def module_QtQml() -> ModuleData:
+ ]
+
+ _qml = [
++ "Qt/labs/StyleKit",
+ "Qt/labs/animation",
++ "Qt/labs/assetdownloader",
+ "Qt/labs/folderlistmodel",
+- "Qt/labs/sharedimage",
+- "Qt/labs/wavefrontmesh",
+- "Qt/labs/qmlmodels",
+ "Qt/labs/platform",
++ "Qt/labs/qmlmodels",
+ "Qt/labs/settings",
++ "Qt/labs/sharedimage",
++ "Qt/labs/synchronizer",
++ "Qt/labs/wavefrontmesh"
+ ]
+
+ data.lib.append("libpyside6qml")
+@@ -573,6 +584,9 @@ def module_QtQuick() -> ModuleData:
+ "qt6quicktimeline_metatypes.json",
+ "qt6quickvectorimage_metatypes.json",
+ "qt6quickvectorimagegeneratorprivate_metatypes.json",
++ "qt6lottie_metatypes.json",
++ "qt6lottievectorimagegeneratorprivate_metatypes.json",
++ "qt6lottievectorimagehelpers_metatypes.json",
+ ]
+ _qtlib = [
+ "libQt6QuickEffects",
+@@ -588,7 +602,10 @@ def module_QtQuick() -> ModuleData:
+ "libQt6QuickTimelineBlendTrees",
+ "libQt6QuickVectorImage",
+ "libQt6QuickVectorImageGenerator",
+- "libQt6QuickVectorImageHelpers"
++ "libQt6QuickVectorImageHelpers",
++ "libQt6Lottie",
++ "libQt6LottieVectorImageGenerator",
++ "libQt6LottieVectorImageHelpers",
+ ]
+
+ data.qtlib.extend(_qtlib)
+diff --git a/coin/dependencies.yaml b/coin/dependencies.yaml
+index a5d9feb99..85260b111 100644
+--- a/coin/dependencies.yaml
++++ b/coin/dependencies.yaml
+@@ -1,6 +1,6 @@
+ product_dependency:
+ ../../qt/qt5:
+- ref: "b3a9d45d2d5474a39c76fddc50bf6d55bcb7858d"
++ ref: "6.11"
+ dependency_source: supermodule
+ dependencies: [
+ "../../qt/qt3d",
+@@ -16,6 +16,7 @@ dependencies: [
+ "../../qt/qtgraphs",
+ "../../qt/qthttpserver",
+ "../../qt/qtimageformats",
++ "../../qt/qtlottie",
+ "../../qt/qtlocation",
+ "../../qt/qtpositioning",
+ "../../qt/qtmultimedia",
+diff --git a/create_wheels.py b/create_wheels.py
+index d9d900fb4..c4f8a365b 100644
+--- a/create_wheels.py
++++ b/create_wheels.py
+@@ -176,7 +176,12 @@ def generate_pyproject_toml(artifacts: Path, setup: SetupData) -> str:
+
+ # Installing dependencies
+ _dependencies = []
+- if _name in ("PySide6", "PySide6_Examples"):
++ if _name == "PySide6":
++ _dependencies.append(f"shiboken6=={setup.version[0]}")
++ _dependencies.append(f"PySide6_Essentials=={setup.version[0]}")
++ _dependencies.append(f"PySide6_Addons=={setup.version[0]}")
++ _dependencies.append('tomli>=2.0.1; python_version < "3.11"')
++ elif _name == "PySide6_Examples":
+ _dependencies.append(f"shiboken6=={setup.version[0]}")
+ _dependencies.append(f"PySide6_Essentials=={setup.version[0]}")
+ _dependencies.append(f"PySide6_Addons=={setup.version[0]}")
+diff --git a/requirements-doc.txt b/requirements-doc.txt
+index a7d4d5443..1f3d3ac6d 100644
+--- a/requirements-doc.txt
++++ b/requirements-doc.txt
+@@ -6,9 +6,5 @@ sphinx-tags==0.4
+ sphinx-toolbox==3.7.0
+ sphinx-reredirects==0.1.5
+ myst-parser==3.0.1
+-# FIXME: Using fork in order to enable the 'collapse_navbar=True'
+-# option for the sphinx-theme. Upstream proposal:
+-# https://github.com/pradyunsg/furo/pull/748#issuecomment-1895448722
+-# furo==2023.9.10
+-furo @ git+https://github.com/cmaureir/furo@add_collapse
++furo==2025.12.19
+ graphviz==0.20.3
+diff --git a/sources/pyside-tools/deploy_lib/config.py b/sources/pyside-tools/deploy_lib/config.py
+index 853f5f6a2..f3f72ecd1 100644
+--- a/sources/pyside-tools/deploy_lib/config.py
++++ b/sources/pyside-tools/deploy_lib/config.py
+@@ -154,7 +154,7 @@ class Config(BaseConfig):
+
+ self._qml_files = []
+ # Design Studio projects include the qml files using Qt resources
+- if source_file and not DesignStudioProject.is_ds_project(source_file):
++ if self.source_file and not DesignStudioProject.is_ds_project(self.source_file):
+ config_qml_files = self.get_value("qt", "qml_files")
+ if config_qml_files and self.project_dir and self.existing_config_file:
+ self._qml_files = [Path(self.project_dir)
+diff --git a/sources/pyside-tools/deploy_lib/default.spec b/sources/pyside-tools/deploy_lib/default.spec
+index 5e33d5399..b44a4c35e 100644
+--- a/sources/pyside-tools/deploy_lib/default.spec
++++ b/sources/pyside-tools/deploy_lib/default.spec
+@@ -24,7 +24,7 @@ icon =
+ python_path =
+
+ # Python packages to install
+-packages = Nuitka==2.7.11
++packages = Nuitka==4.0
+
+ # Buildozer: for deploying Android application
+ android_packages = buildozer==1.5.0,cython==0.29.33
+diff --git a/sources/pyside-tools/project_lib/pyproject_toml.py b/sources/pyside-tools/project_lib/pyproject_toml.py
+index bc5a0f69d..c316cad7d 100644
+--- a/sources/pyside-tools/project_lib/pyproject_toml.py
++++ b/sources/pyside-tools/project_lib/pyproject_toml.py
+@@ -4,51 +4,18 @@ from __future__ import annotations
+
+ import os
+ import sys
+-# TODO: Remove this import when Python 3.11 is the minimum supported version
+-if sys.version_info >= (3, 11):
+- import tomllib
+ from pathlib import Path
+
++try:
++ import tomllib
++except ModuleNotFoundError:
++ import tomli as tomllib # type: ignore[no-redef]
++
+ from . import PYPROJECT_JSON_PATTERN
+ from .pyproject_parse_result import PyProjectParseResult
+ from .pyproject_json import parse_pyproject_json
+
+
+-def _parse_toml_content(content: str) -> dict:
+- """
+- Parse TOML content for project name and files list only.
+- """
+- result = {"project": {}, "tool": {"pyside6-project": {}}}
+- current_section = None
+-
+- for line in content.splitlines():
+- line = line.strip()
+- if not line or line.startswith('#'):
+- continue
+-
+- if line == '[project]':
+- current_section = 'project'
+- elif line == '[tool.pyside6-project]':
+- current_section = 'tool.pyside6-project'
+- elif '=' in line and current_section:
+- key, value = [part.strip() for part in line.split('=', 1)]
+-
+- # Handle string values - name of the project
+- if value.startswith('"') and value.endswith('"'):
+- value = value[1:-1]
+- # Handle array of strings - files names
+- elif value.startswith('[') and value.endswith(']'):
+- items = value[1:-1].split(',')
+- value = [item.strip().strip('"') for item in items if item.strip()]
+-
+- if current_section == 'project':
+- result['project'][key] = value
+- else: # tool.pyside6-project
+- result['tool']['pyside6-project'][key] = value
+-
+- return result
+-
+-
+ def _write_base_toml_content(data: dict) -> str:
+ """
+ Write minimal TOML content with project and tool.pyside6-project sections.
+@@ -81,12 +48,7 @@ def parse_pyproject_toml(pyproject_toml_file: Path) -> PyProjectParseResult:
+
+ try:
+ content = pyproject_toml_file.read_text(encoding='utf-8')
+- # TODO: Remove the manual parsing when Python 3.11 is the minimum supported version
+- if sys.version_info >= (3, 11):
+- root_table = tomllib.loads(content) # Use tomllib for Python >= 3.11
+- print("Using tomllib for parsing TOML content")
+- else:
+- root_table = _parse_toml_content(content) # Fallback to manual parsing
++ root_table = tomllib.loads(content)
+ except Exception as e:
+ result.errors.append(str(e))
+ return result
+diff --git a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+index 06a1d07ce..11dd02c3e 100644
+--- a/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
++++ b/sources/pyside6/PySide6/QtCore/typesystem_core_common.xml
+@@ -896,6 +896,9 @@
+ <add-function signature="toPython()" return-type="PyObject">
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdate-topython"/>
+ </add-function>
++ <modify-function signature="QDate(QDate)">
++ <modify-argument index="1" pyi-type="Union[PySide6.QtCore.QDate, datetime.datetime, datetime.date]"/>
++ </modify-function>
+ <modify-function signature="getDate(int*,int*,int*)const" >
+ <modify-argument index="1">
+ <remove-argument/>
+@@ -969,6 +972,9 @@
+ <add-function signature="toPython()" return-type="PyObject">
+ <inject-code class="target" position="beginning" file="../glue/qtcore.cpp" snippet="qdatetime-topython"/>
+ </add-function>
++ <modify-function signature="QDateTime(QDateTime)">
++ <modify-argument index="1" pyi-type="Union[PySide6.QtCore.QDateTime, datetime.datetime]"/>
++ </modify-function>
+ </value-type>
+
+ <value-type name="QDir">
+diff --git a/sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp b/sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp
+index 2a24deca5..2bc627fb4 100644
+--- a/sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp
++++ b/sources/pyside6/PySide6/QtDesigner/qpydesignercustomwidgetcollection.cpp
+@@ -7,6 +7,7 @@
+ #include <QtCore/QVariant>
+
+ #include <sbkpep.h>
++#include <pep384ext.h>
+ #include <autodecref.h>
+ #include <basewrapper.h>
+ #include <bindingmanager.h>
+@@ -50,9 +51,12 @@ class PyDesignerCustomWidget : public QDesignerCustomWidgetInterface
+ {
+ public:
+ explicit PyDesignerCustomWidget(PyObject *pyTypeObject) :
+- m_pyTypeObject(pyTypeObject) {}
++ m_name(QString::fromUtf8(PepExt_TypeGetQualName(reinterpret_cast<PyTypeObject *>(pyTypeObject)))),
++ m_pyTypeObject(pyTypeObject)
++ {
++ }
+
+- QString name() const override;
++ QString name() const override { return m_name; }
+ QString group() const override { return m_group; }
+ QString toolTip() const override { return m_toolTip; }
+ QString whatsThis() const override { return toolTip(); }
+@@ -75,9 +79,8 @@ public:
+ void setContainer(bool container) { m_container = container; }
+
+ private:
+- const char *utf8Name() const;
+-
+ QDesignerFormEditorInterface *m_core = nullptr;
++ QString m_name;
+ QString m_group;
+ QString m_toolTip;
+ QString m_includeFile;
+@@ -87,16 +90,6 @@ private:
+ bool m_container = false;
+ };
+
+-const char *PyDesignerCustomWidget::utf8Name() const
+-{
+- return reinterpret_cast<PyTypeObject *>(m_pyTypeObject)->tp_name;
+-}
+-
+-QString PyDesignerCustomWidget::name() const
+-{
+- return QString::fromUtf8(utf8Name());
+-}
+-
+ QWidget *PyDesignerCustomWidget::createWidget(QWidget *parent)
+ {
+ // This is a copy of the similar function used for QUiLoader
+@@ -124,7 +117,7 @@ QWidget *PyDesignerCustomWidget::createWidget(QWidget *parent)
+ // Call python constructor
+ auto *obResult = PyObject_CallObject(m_pyTypeObject, pyArgs);
+ if (obResult == nullptr) {
+- qWarning("Unable to create a Python custom widget of type \"%s\".", utf8Name());
++ qWarning("Unable to create a Python custom widget of type \"%s\".", qPrintable(m_name));
+ PyErr_Print();
+ return nullptr;
+ }
+diff --git a/sources/pyside6/PySide6/QtQml/typesystem_qml.xml b/sources/pyside6/PySide6/QtQml/typesystem_qml.xml
+index caa52b30d..1cc542291 100644
+--- a/sources/pyside6/PySide6/QtQml/typesystem_qml.xml
++++ b/sources/pyside6/PySide6/QtQml/typesystem_qml.xml
+@@ -196,8 +196,7 @@
+ <!-- createWithInitialProperties_withownership: like createWithInitialProperties() but
+ the returned QObject is Python owned -->
+ <add-function signature="createWithInitialProperties_withownership(QVariantMap at initialProperties@)"
+- return-type="QObject*"
+- allow-thread="yes">
++ return-type="QObject*">
+ <modify-argument index="return">
+ <define-ownership class="target" owner="target"/>
+ </modify-argument>
+@@ -209,8 +208,7 @@
+ </add-function>
+ <!-- create_withownership: like create() but the returned QObject is Python owned -->
+ <add-function signature="create_withownership(QQmlContext*@context@=nullptr)"
+- return-type="QObject*"
+- allow-thread="yes">
++ return-type="QObject*">
+ <modify-argument index="return">
+ <define-ownership class="target" owner="target"/>
+ </modify-argument>
+diff --git a/sources/pyside6/PySide6/glue/qtcore.cpp b/sources/pyside6/PySide6/glue/qtcore.cpp
+index 39fbdb79b..3c87d6009 100644
+--- a/sources/pyside6/PySide6/glue/qtcore.cpp
++++ b/sources/pyside6/PySide6/glue/qtcore.cpp
+@@ -777,7 +777,11 @@ static int SbkQByteArray_getbufferproc(PyObject *obj, Py_buffer *view, int flags
+
+ QByteArray * cppSelf = %CONVERTTOCPP[QByteArray *](obj);
+ //XXX /|\ omitting this space crashes shiboken!
+-#ifdef Py_LIMITED_API
++
++#if !defined(Py_LIMITED_API) || Py_LIMITED_API >= 0x030B0000
++ return PyBuffer_FillInfo(view, obj, reinterpret_cast<void *>(cppSelf->data()),
++ cppSelf->size(), 0, flags);
++#else
+ view->obj = obj;
+ view->buf = reinterpret_cast<void *>(cppSelf->data());
+ view->len = cppSelf->size();
+@@ -792,21 +796,15 @@ static int SbkQByteArray_getbufferproc(PyObject *obj, Py_buffer *view, int flags
+
+ Py_XINCREF(obj);
+ return 0;
+-#else // Py_LIMITED_API
+- const int result = PyBuffer_FillInfo(view, obj, reinterpret_cast<void *>(cppSelf->data()),
+- cppSelf->size(), 0, flags);
+- if (result == 0)
+- Py_XINCREF(obj);
+- return result;
+ #endif
+ }
+
+ static PyBufferProcs SbkQByteArrayBufferProc = {
+- /*bf_getbuffer*/ (getbufferproc)SbkQByteArray_getbufferproc,
+- /*bf_releasebuffer*/ (releasebufferproc)0,
++ /*bf_getbuffer*/ SbkQByteArray_getbufferproc,
++ /*bf_releasebuffer*/ nullptr,
+ };
+
+-}
++} // extern "C"
+ // @snippet qbytearray-bufferprotocol
+
+ // @snippet qbytearray-operatorplus-1
+diff --git a/sources/pyside6/PySide6/glue/qtqml.cpp b/sources/pyside6/PySide6/glue/qtqml.cpp
+index 41c5253ce..42054902e 100644
+--- a/sources/pyside6/PySide6/glue/qtqml.cpp
++++ b/sources/pyside6/PySide6/glue/qtqml.cpp
+@@ -78,7 +78,9 @@ if (instance.isNull()) {
+
+ // @snippet qqmlcomponent-createwithinitialpropertieswithownership
+ // Like createWithInitialProperties() but with Python ownership on the returned object.
++PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS
+ QObject *%0 = %CPPSELF.createWithInitialProperties(%1);
++PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS
+ %PYARG_0 = %CONVERTTOPYTHON[QObject*](%0);
+ // @snippet qqmlcomponent-createwithinitialpropertieswithownership
+
+@@ -86,7 +88,9 @@ QObject *%0 = %CPPSELF.createWithInitialProperties(%1);
+ // Create a QML component instance and transfer ownership to Python,
+ // so no manual keep-alive bookkeeping is needed.
+ // This is specifically created and useful for QtBridges
++PyThreadState *_save = PyEval_SaveThread(); // Py_BEGIN_ALLOW_THREADS
+ QObject *%0 = %CPPSELF.create(%1);
++PyEval_RestoreThread(_save); // Py_END_ALLOW_THREADS
+ %PYARG_0 = %CONVERTTOPYTHON[QObject*](%0);
+ // @snippet qqmlcomponent-createwithownership
+
+diff --git a/sources/pyside6/doc/building_from_source/index.rst b/sources/pyside6/doc/building_from_source/index.rst
+index 020dc5f32..bd2d38612 100644
+--- a/sources/pyside6/doc/building_from_source/index.rst
++++ b/sources/pyside6/doc/building_from_source/index.rst
+@@ -31,7 +31,7 @@ website.
+ * **Qt:** 6.11+ `[online installer] <https://download.qt.io/official_releases/online_installers/>`_
+ * **CMake:** 3.22+ `[official CMake website] <https://cmake.org/download/>`_
+ * **Git:** 2.0+. `[official Git website] <https://git-scm.com/downloads>`_
+-* **libclang:** The libclang library, recommended: version 18+ for 6.10+.
++* **libclang:** The libclang library (supported versions: 16-22, recommended version: 18+ for 6.11+).
+ Prebuilt versions for each OS can be `downloaded here`_.
+ * Check the `Supported Platforms of Qt`_
+
+diff --git a/sources/pyside6/doc/deployment/deployment-pyside6-deploy.rst b/sources/pyside6/doc/deployment/deployment-pyside6-deploy.rst
+index d71018bf9..7382e42f8 100644
+--- a/sources/pyside6/doc/deployment/deployment-pyside6-deploy.rst
++++ b/sources/pyside6/doc/deployment/deployment-pyside6-deploy.rst
+@@ -10,7 +10,7 @@ compiles your Python code to C code, and links with libpython to produce the fin
+ The final executable produced has a ``.exe`` suffix on Windows, ``.bin`` on Linux and ``.app`` on
+ macOS.
+
+-.. note:: The default version of Nuitka used with the tool is version ``2.7.11``. This can be
++.. note:: The default version of Nuitka used with the tool is version ``4.0``. This can be
+ updated to a newer version by updating your ``pysidedeploy.spec`` file.
+
+ .. _how_pysidedeploy:
+diff --git a/sources/pyside6/libpyside/CMakeLists.txt b/sources/pyside6/libpyside/CMakeLists.txt
+index 4f95ce0a8..c7aa5d9b0 100644
+--- a/sources/pyside6/libpyside/CMakeLists.txt
++++ b/sources/pyside6/libpyside/CMakeLists.txt
+@@ -5,7 +5,7 @@ project(libpyside)
+
+ find_package(Qt6 COMPONENTS Core CorePrivate)
+
+-set(libpyside_libraries Qt::Core Qt::CorePrivate)
++set(libpyside_libraries Qt::Core Qt::CorePrivate Qt::PlatformCommonInternal)
+
+ set(CMAKE_AUTOMOC ON)
+
+@@ -34,7 +34,7 @@ set(libpyside_HEADERS # installed below
+ pysideqapp.h
+ pysideqenum.h
+ pysideqhash.h
+- pysideqobject.h
++ pysideqobject.h pysideqobject_p.h
+ pysideqslotobject_p.h
+ pysidesignal.h
+ pysidesignal_p.h
+@@ -160,15 +160,27 @@ configure_package_config_file(
+ INSTALL_PREFIX "${CMAKE_CURRENT_BINARY_DIR}"
+ )
+
+-# Install-tree / wheel configuration
++# Install-tree configuration (for downstream CMake projects using a regular cmake install)
++set(PYSIDE_PYTHONPATH "${PYTHON_SITE_PACKAGES}/PySide6")
++set(PYSIDE_TYPESYSTEMS "${CMAKE_INSTALL_PREFIX}/share/PySide6${pyside6_SUFFIX}/typesystems")
++set(PYSIDE_GLUE "${CMAKE_INSTALL_PREFIX}/share/PySide6${pyside6_SUFFIX}/glue")
++set(PYSIDE_SOVERSION "${pyside6_library_so_version}")
++
++configure_package_config_file(
++ "${CMAKE_CURRENT_SOURCE_DIR}/PySide6Config-spec.cmake.in"
++ "${CMAKE_CURRENT_BINARY_DIR}/install/PySide6Config${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
++ INSTALL_DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6"
++ PATH_VARS PYSIDE_PYTHONPATH PYSIDE_TYPESYSTEMS PYSIDE_GLUE
++)
++
++# Wheel configuration (typesystems/glue sit directly inside the PySide6 Python package)
+ set(PYSIDE_PYTHONPATH "")
+ set(PYSIDE_TYPESYSTEMS "typesystems")
+ set(PYSIDE_GLUE "glue")
+-set(PYSIDE_SOVERSION "${pyside6_library_so_version}")
+
+ configure_package_config_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/PySide6Config-spec.cmake.in"
+- "${CMAKE_CURRENT_BINARY_DIR}/install/PySide6Config${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
++ "${CMAKE_CURRENT_BINARY_DIR}/wheel/PySide6Config${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
+ INSTALL_DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6"
+ PATH_VARS PYSIDE_PYTHONPATH PYSIDE_TYPESYSTEMS PYSIDE_GLUE
+ )
+@@ -207,5 +219,8 @@ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/PySide6Config.cmake"
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/install/PySide6Config${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6")
+
++install(FILES "${CMAKE_CURRENT_BINARY_DIR}/wheel/PySide6Config${SHIBOKEN_PYTHON_CONFIG_SUFFIX}.cmake"
++ DESTINATION "${LIB_INSTALL_DIR}/wheels/cmake/PySide6")
++
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/PySide6ConfigVersion.cmake"
+ DESTINATION "${LIB_INSTALL_DIR}/cmake/PySide6")
+diff --git a/sources/pyside6/libpyside/dynamicqmetaobject.cpp b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
+index 70c73bc57..c538ac1cc 100644
+--- a/sources/pyside6/libpyside/dynamicqmetaobject.cpp
++++ b/sources/pyside6/libpyside/dynamicqmetaobject.cpp
+@@ -15,6 +15,7 @@
+ #include <basewrapper.h>
+ #include <gilstate.h>
+ #include <sbkpep.h>
++#include <pep384ext.h>
+ #include <sbkstaticstrings.h>
+ #include <sbkstring.h>
+
+@@ -115,7 +116,7 @@ MetaObjectBuilder::MetaObjectBuilder(PyTypeObject *type, const QMetaObject *meta
+ {
+ m_d->m_baseObject = metaObject;
+ m_d->m_builder = new QMetaObjectBuilder();
+- m_d->m_builder->setClassName(PepType_GetNameStr(type));
++ m_d->m_builder->setClassName(PepExt_TypeGetQualName(type));
+ m_d->m_builder->setSuperClass(metaObject);
+ m_d->parsePythonType(type);
+ }
+@@ -196,7 +197,7 @@ static bool checkMethodSignature(const QByteArray &signature)
+ const bool ok = openParen != -1 && closingParen != -1 && openParen < closingParen;
+ if (!ok) {
+ const QByteArray message =
+- "MetaObjectBuilder::addMethod: Invalid method signature provided for \""
++ "libpyside: MetaObjectBuilder::addMethod: Invalid method signature provided for \""
+ + signature + '"';
+ PyErr_WarnEx(PyExc_RuntimeWarning, message.constData(), 0);
+ }
+@@ -287,7 +288,7 @@ static QByteArray msgInvalidPropertyType(const QByteArray &className,
+ const QByteArray &propertyName,
+ const QByteArray &propertyType)
+ {
+- return "QMetaObjectBuilder: Failed to add property \""_ba + propertyName
++ return "libpyside: QMetaObjectBuilder: Failed to add property \""_ba + propertyName
+ + "\" to \""_ba + className + "\": Invalid property type \""
+ + propertyType + "\"."_ba;
+ }
+@@ -438,7 +439,7 @@ static QString msgMethodSortOrder(const QMetaObject *mo, int offendingIndex)
+ {
+ QString result;
+ QTextStream str(&result);
+- str << "\n\n*** Sort Warning ***\nSignals and slots in QMetaObject '"
++ str << "\n\nlibpyside: *** Sort Warning ***\nSignals and slots in QMetaObject '"
+ << mo->className()
+ << "' are not ordered correctly, this may lead to issues.\n";
+ const int methodOffset = mo->methodOffset();
+diff --git a/sources/pyside6/libpyside/dynamicslot.cpp b/sources/pyside6/libpyside/dynamicslot.cpp
+index 3d9b9c1be..7875d4327 100644
+--- a/sources/pyside6/libpyside/dynamicslot.cpp
++++ b/sources/pyside6/libpyside/dynamicslot.cpp
+@@ -346,7 +346,8 @@ static void disconnectReceiver(PyObject *pythonSelf)
+ for (auto it = connectionHash.begin(); it != connectionHash.end(); ) {
+ if (it.key().object == pythonSelf) {
+ const auto oldSize = connectionHash.size();
+- QObject::disconnect(it.value());
++ auto connId = it.value(); // QTBUG-144929, take copy
++ QObject::disconnect(connId);
+ it = connectionHash.erase(it);
+ // Check for a disconnection causing deletion of further objects
+ // by a re-entrant call.
+@@ -394,7 +395,8 @@ bool disconnectSlot(QObject *source, int signalIndex, PyObject *callback)
+ auto it = connectionHash.find(connectionKey(source, signalIndex, callback));
+ const bool ok = it != connectionHash.end();
+ if (ok) {
+- QObject::disconnect(it.value());
++ auto connId = it.value(); // QTBUG-144929, take copy
++ QObject::disconnect(connId);
+ connectionHash.erase(it);
+ }
+ return ok;
+diff --git a/sources/pyside6/libpyside/pyside.cpp b/sources/pyside6/libpyside/pyside.cpp
+index 13e815b52..9fb2630cb 100644
+--- a/sources/pyside6/libpyside/pyside.cpp
++++ b/sources/pyside6/libpyside/pyside.cpp
+@@ -7,6 +7,7 @@
+ #include "pysidemetatype.h"
+ #include "pysideqapp.h"
+ #include "pysideqobject.h"
++#include "pysideqobject_p.h"
+ #include "pysideutils.h"
+ #include "pyside_p.h"
+ #include "signalmanager.h"
+@@ -38,6 +39,7 @@
+ #include <sbkfeature_base.h>
+ #include <sbkmodule.h>
+
++#include <QtCore/qabstracteventdispatcher.h>
+ #include <QtCore/qbytearray.h>
+ #include <QtCore/qcoreapplication.h>
+ #include <QtCore/qdebug.h>
+@@ -523,8 +525,8 @@ void initQObjectSubType(PyTypeObject *type, PyObject *args, PyObject * /* kwds *
+ }
+ if (!userData) {
+ const char *className = Shiboken::String::toCString(PyTuple_GetItem(args, 0));
+- qWarning("Sub class of QObject not inheriting QObject!? Crash will happen when using %s.",
+- className);
++ qWarning("libpyside: A subclass of QObject is not inheriting QObject."
++ " A crash might happen when using %s.", className);
+ return;
+ }
+ // PYSIDE-1463: Don't change feature selection durin subtype initialization.
+@@ -1286,4 +1288,58 @@ PYSIDE_API QDebug operator<<(QDebug debug, const debugPyBuffer &b)
+ }
+ #endif // !Py_LIMITED_API || >= 3.11
+
++QDebug operator<<(QDebug debug, const PySide::debugQObject &qo)
++{
++ QDebugStateSaver saver(debug);
++ debug.noquote();
++ debug.nospace();
++
++ if (qo.m_qobject == nullptr) {
++ debug << "QObject(0)";
++ } else {
++ debug << qo.m_qobject->metaObject()->className() << '/';
++ if (const auto &on = qo.m_qobject->objectName(); !on.isEmpty())
++ debug << '"' << on << '"';
++ else
++ debug << static_cast<const void *>(qo.m_qobject);
++ }
++ return debug;
++}
++
+ } // namespace PySide
++
++void deferredDeleteQObject(void *cppSelf)
++{
++ if (cppSelf == nullptr)
++ return;
++ auto *qobject = reinterpret_cast<QObject *>(cppSelf);
++ auto *ownerThread = qobject->thread();
++ const auto *currentThread = QThread::currentThread();
++ // Directly delete when called from ownerThread
++ if (ownerThread == nullptr || ownerThread == currentThread
++ || QCoreApplication::closingDown()) {
++ delete qobject;
++ return;
++ }
++
++ qCWarning(lcPySide).noquote().nospace()
++ << "libpyside: Deferred deletion of " << PySide::debugQObject(qobject)
++ << "(owner thread: " << PySide::debugQObject(ownerThread)
++ << "), GC thread: " << PySide::debugQObject(currentThread);
++
++ // Owner thread has event loop: Schedule deleteLater()
++ if (QAbstractEventDispatcher::instance(ownerThread) != nullptr) {
++ qobject->deleteLater();
++ return;
++ }
++
++ // No event loop: Fall back to deletion in main thread
++ if (QThread::isMainThread()) {
++ delete qobject;
++ return;
++ }
++
++ auto &bm = Shiboken::BindingManager::instance();
++ bm.addToDeletionInMainThread({Shiboken::callCppDestructor<QObject>, cppSelf});
++ bm.runDeletionInMainThread();
++}
+diff --git a/sources/pyside6/libpyside/pysideqobject.h b/sources/pyside6/libpyside/pysideqobject.h
+index a6248ef6c..63cfd3114 100644
+--- a/sources/pyside6/libpyside/pysideqobject.h
++++ b/sources/pyside6/libpyside/pysideqobject.h
+@@ -76,4 +76,7 @@ PYSIDE_API PyTypeObject *getTypeForQObject(const QObject *cppSelf);
+
+ } //namespace PySide
+
++/// Deletion handler for "delete-in-owner-thread"
++extern "C" PYSIDE_API void deferredDeleteQObject(void *cppSelf);
++
+ #endif // PYSIDEQOBJECT_H
+diff --git a/sources/pyside6/libpyside/pysideqobject_p.h b/sources/pyside6/libpyside/pysideqobject_p.h
+new file mode 100644
+index 000000000..d92d35c73
+--- /dev/null
++++ b/sources/pyside6/libpyside/pysideqobject_p.h
+@@ -0,0 +1,28 @@
++// Copyright (C) 2026 The Qt Company Ltd.
++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++#ifndef PYSIDEQOBJECT_P_H
++#define PYSIDEQOBJECT_P_H
++
++#include <pysidemacros.h>
++
++#include <QtCore/qtclasshelpermacros.h>
++
++QT_FORWARD_DECLARE_CLASS(QDebug)
++QT_FORWARD_DECLARE_CLASS(QObject)
++
++namespace PySide
++{
++
++struct debugQObject
++{
++ debugQObject(const QObject *qobject) : m_qobject(qobject) {}
++
++ const QObject *m_qobject;
++};
++
++QDebug operator<<(QDebug debug, const debugQObject &qo);
++
++} //namespace PySide
++
++#endif // PYSIDEQOBJECT_P_H
+diff --git a/sources/pyside6/libpyside/pysidesignal.cpp b/sources/pyside6/libpyside/pysidesignal.cpp
+index 7a65c9a9f..7ebd88fdd 100644
+--- a/sources/pyside6/libpyside/pysidesignal.cpp
++++ b/sources/pyside6/libpyside/pysidesignal.cpp
+@@ -671,10 +671,12 @@ static inline void warnDisconnectFailed(PyObject *aSlot, const QByteArray &signa
+ {
+ if (PyErr_Occurred() != nullptr) { // avoid "%S" invoking str() when an error is set.
+ Shiboken::Errors::Stash errorStash;
+- PyErr_WarnFormat(PyExc_RuntimeWarning, 0, "Failed to disconnect (%s) from signal \"%s\".",
++ PyErr_WarnFormat(PyExc_RuntimeWarning, 0,
++ "libpyside: Failed to disconnect (%s) from signal \"%s\".",
+ Py_TYPE(aSlot)->tp_name, signature.constData());
+ } else {
+- PyErr_WarnFormat(PyExc_RuntimeWarning, 0, "Failed to disconnect (%S) from signal \"%s\".",
++ PyErr_WarnFormat(PyExc_RuntimeWarning, 0,
++ "libpyside: Failed to disconnect (%S) from signal \"%s\".",
+ aSlot, signature.constData());
+ }
+ }
+diff --git a/sources/pyside6/libpyside/pysidevariantutils.cpp b/sources/pyside6/libpyside/pysidevariantutils.cpp
+index c683c7dea..7ac17fb32 100644
+--- a/sources/pyside6/libpyside/pysidevariantutils.cpp
++++ b/sources/pyside6/libpyside/pysidevariantutils.cpp
+@@ -17,7 +17,7 @@ static const char qVariantTypeName[] = "QVariant";
+
+ static void warnConverter(const char *name)
+ {
+- qWarning("Type converter for: %s not registered.", name);
++ qWarning("libpyside: Type converter for: %s not registered.", name);
+ }
+
+ // Helper converting each item of a non-empty list using the "QVariant" converter
+diff --git a/sources/pyside6/libpyside/signalmanager.cpp b/sources/pyside6/libpyside/signalmanager.cpp
+index fbd8e1666..d8954dd42 100644
+--- a/sources/pyside6/libpyside/signalmanager.cpp
++++ b/sources/pyside6/libpyside/signalmanager.cpp
+@@ -2,6 +2,7 @@
+ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+ #include "signalmanager.h"
++#include "pysideqobject_p.h"
+ #include "pysidesignal.h"
+ #include "pysidelogging_p.h"
+ #include "pysideproperty.h"
+@@ -194,7 +195,7 @@ int PyObjectWrapper::toInt() const
+ QDataStream &operator<<(QDataStream &out, const PyObjectWrapper &myObj)
+ {
+ if (Py_IsInitialized() == 0) {
+- qWarning() << "Stream operator for PyObject called without python interpreter.";
++ qWarning("libpyside: Stream operator for PyObject called without python interpreter.");
+ return out;
+ }
+
+@@ -226,7 +227,7 @@ QDataStream &operator<<(QDataStream &out, const PyObjectWrapper &myObj)
+ QDataStream &operator>>(QDataStream &in, PyObjectWrapper &myObj)
+ {
+ if (Py_IsInitialized() == 0) {
+- qWarning() << "Stream operator for PyObject called without python interpreter.";
++ qWarning("libpyside: Stream operator for PyObject called without python interpreter.");
+ return in;
+ }
+
+@@ -400,7 +401,7 @@ int SignalManagerPrivate::qtPropertyMetacall(QObject *object,
+ Shiboken::AutoDecRef pp_name(Shiboken::String::fromCString(mp.name()));
+ PySideProperty *pp = Property::getObject(pySelf, pp_name);
+ if (!pp) {
+- qWarning("Invalid property: %s.", mp.name());
++ qWarning("libpyside: Invalid property: %s.", mp.name());
+ return false;
+ }
+ pp->d->metaCall(pySelf, call, args);
+@@ -411,8 +412,8 @@ int SignalManagerPrivate::qtPropertyMetacall(QObject *object,
+ Shiboken::Errors::Stash errorStash;
+ bool ign = call == QMetaObject::WriteProperty;
+ PyErr_WarnFormat(PyExc_RuntimeWarning, 0,
+- ign ? "Unknown property type '%s' of QObject '%s' used in fset"
+- : "Unknown property type '%s' of QObject '%s' used in fget with %R",
++ ign ? "libpyside: Unknown property type '%s' of QObject '%s' used in fset"
++ : "libpyside: Unknown property type '%s' of QObject '%s' used in fget with %R",
+ pp->d->typeName().constData(), metaObject->className(), errorStash.getException());
+ if (PyErr_Occurred())
+ Shiboken::Errors::storeErrorOrPrint();
+@@ -421,8 +422,9 @@ int SignalManagerPrivate::qtPropertyMetacall(QObject *object,
+ }
+
+ qWarning().noquote().nospace()
+- << "An error occurred executing the property metacall " << metaObjectCallName(call)
+- << " on property \"" << mp.name() << "\" of " << object;
++ << "libpyside: An error occurred executing the property metacall "
++ << metaObjectCallName(call) << " on property \"" << mp.name()
++ << "\" of " << PySide::debugQObject(object);
+ handleMetaCallError(object, &result);
+ }
+ return result;
+@@ -719,9 +721,9 @@ static int addMetaMethod(QObject *source, const QByteArray &signature,
+ const QMetaObject *metaObject = source->metaObject();
+ SbkObject *self = Shiboken::BindingManager::instance().retrieveWrapper(source);
+ if (!Shiboken::Object::hasCppWrapper(self)) {
+- qWarning().noquote().nospace() << __FUNCTION__
++ qWarning().noquote().nospace() << "libpyside: " << __FUNCTION__
+ << ": Cannot add dynamic method \"" << signature << "\" (" << type
+- << ") to " << source << ": No Wrapper found.";
++ << ") to " << PySide::debugQObject(source) << ": No Wrapper found.";
+ return -1;
+ }
+
+@@ -738,9 +740,9 @@ static int addMetaMethod(QObject *source, const QByteArray &signature,
+
+ if (type == QMetaMethod::Slot) {
+ qCWarning(lcPySide).noquote().nospace()
+- << "Warning: Registering dynamic slot \""
+- << signature << "\" on \"" << source->metaObject()->className()
+- << "\". Consider annotating with " << slotSignature(signature);
++ << "libpyside: Warning: Registering dynamic slot \""
++ << signature << "\" on " << PySide::debugQObject(source)
++ << ". Consider annotating with " << slotSignature(signature);
+ }
+
+ return type == QMetaMethod::Signal ? dmo->addSignal(signature) : dmo->addSlot(signature);
+@@ -748,7 +750,7 @@ static int addMetaMethod(QObject *source, const QByteArray &signature,
+
+ static inline void warnNullSource(const char *signature)
+ {
+- qWarning("SignalManager::registerMetaMethodGetIndex(\"%s\") called with source=nullptr.",
++ qWarning("libpyside: SignalManager::registerMetaMethodGetIndex(\"%s\") called with source=nullptr.",
+ signature);
+ }
+
+diff --git a/sources/pyside6/libpysideremoteobjects/pysiderephandler.cpp b/sources/pyside6/libpysideremoteobjects/pysiderephandler.cpp
+index ffa8af82a..d7debf285 100644
+--- a/sources/pyside6/libpysideremoteobjects/pysiderephandler.cpp
++++ b/sources/pyside6/libpysideremoteobjects/pysiderephandler.cpp
+@@ -17,6 +17,7 @@
+ #include <QtCore/qbuffer.h>
+ #include <QtCore/qiodevice.h>
+ #include <QtCore/qmetaobject.h>
++#include <QtCore/qstringlist.h>
+
+ #include <QtRemoteObjects/qremoteobjectreplica.h>
+ #include <QtRemoteObjects/qremoteobjectpendingcall.h>
+@@ -47,6 +48,16 @@ using namespace Shiboken;
+ * .rep file.
+ */
+
++struct PySideRepFilePrivate
++{
++ AST ast;
++ PyObject *podDict{};
++ PyObject *replicaDict{};
++ PyObject *sourceDict{};
++ QStringList classes;
++ QStringList pods;
++};
++
+ static QVariantList generateProperties(QMetaObject *meta, const ASTClass &astClass);
+
+ extern "C"
+diff --git a/sources/pyside6/libpysideremoteobjects/pysiderephandler_p.h b/sources/pyside6/libpysideremoteobjects/pysiderephandler_p.h
+index 5956f0b49..eb9ed7509 100644
+--- a/sources/pyside6/libpysideremoteobjects/pysiderephandler_p.h
++++ b/sources/pyside6/libpysideremoteobjects/pysiderephandler_p.h
+@@ -6,19 +6,7 @@
+
+ #include <sbkpython.h>
+
+-#include <QtRemoteObjects/repparser.h>
+-
+-#include <QtCore/qstringlist.h>
+-
+-struct PySideRepFilePrivate
+-{
+- AST ast;
+- PyObject *podDict{};
+- PyObject *replicaDict{};
+- PyObject *sourceDict{};
+- QStringList classes;
+- QStringList pods;
+-};
++struct PySideRepFilePrivate;
+
+ extern "C"
+ {
+diff --git a/sources/pyside6/plugins/designer/CMakeLists.txt b/sources/pyside6/plugins/designer/CMakeLists.txt
+index 353d526a5..d231d8258 100644
+--- a/sources/pyside6/plugins/designer/CMakeLists.txt
++++ b/sources/pyside6/plugins/designer/CMakeLists.txt
+@@ -22,10 +22,7 @@ target_sources(PySidePlugin PRIVATE
+
+ target_compile_definitions(PySidePlugin PRIVATE -DQT_NO_KEYWORDS=1)
+
+-# For Windows we use the limited API by default
+-# See ShibokenHelpers.cmake::shiboken_check_if_limited_api() which is called always
+-# with default FORCE_LIMITED_API set to TRUE for building libshiboken
+-if(FORCE_LIMITED_API OR WIN32)
++if(FORCE_LIMITED_API)
+ target_compile_definitions(PySidePlugin PRIVATE "-DPy_LIMITED_API=0x030a0000")
+ endif()
+
+diff --git a/sources/shiboken6/.cmake.conf b/sources/shiboken6/.cmake.conf
+index 44dac5182..7154d243e 100644
+--- a/sources/shiboken6/.cmake.conf
++++ b/sources/shiboken6/.cmake.conf
+@@ -1,5 +1,5 @@
+ set(shiboken_MAJOR_VERSION "6")
+ set(shiboken_MINOR_VERSION "11")
+ set(shiboken_MICRO_VERSION "0")
+-set(shiboken_PRE_RELEASE_VERSION_TYPE "")
+-set(shiboken_PRE_RELEASE_VERSION "")
++set(shiboken_PRE_RELEASE_VERSION_TYPE "a")
++set(shiboken_PRE_RELEASE_VERSION "1")
+diff --git a/sources/shiboken6/doc/typesystem_specifying_types.rst b/sources/shiboken6/doc/typesystem_specifying_types.rst
+index 7c3c1ae63..29c264321 100644
+--- a/sources/shiboken6/doc/typesystem_specifying_types.rst
++++ b/sources/shiboken6/doc/typesystem_specifying_types.rst
+@@ -501,6 +501,8 @@ contain :ref:`add-function`, :ref:`add-pymethoddef`,
+ since="..."
+ copyable="yes | no"
+ allow-thread="..."
++ delete-in-main-thread="yes | no"
++ delete-in-owner-thread="yes | no"
+ disable-wrapper="yes | no"
+ exception-handling="..."
+ generate-functions="..."
+@@ -530,6 +532,17 @@ superclass for the given type in the generated target language API.
+ This can be useful if the C++ base class is not exposed. The specified
+ super class needs to be a direct base class of the class in question.
+
++The *optional* **delete-in-main-thread** attribute specifies that the
++destructor is called in the main thread (scheduled via
++``Py_AddPendingCall()``). This is intended to ensure that Qt's Widget classes
++are deleted in the main GUI thread even when a garbage collection running in a
++different thread cleans them up.
++
++The *optional* **delete-in-owner-thread** attribute (applicable to Qt's
++``QObject``-derived types only) specifies that destruction is deferred by
++calling ``deleteLater()`` in case a garbage collection running in a thread
++different from the owner thread of the instance cleans them up.
++
+ The *optional* **force-abstract** attribute forces the class to be
+ abstract, disabling its instantiation. The generator will normally detect
+ this automatically unless the class inherits from an abstract base class
+diff --git a/sources/shiboken6/libshiboken/CMakeLists.txt b/sources/shiboken6/libshiboken/CMakeLists.txt
+index 45a967c1c..d3fef1bed 100644
+--- a/sources/shiboken6/libshiboken/CMakeLists.txt
++++ b/sources/shiboken6/libshiboken/CMakeLists.txt
+@@ -65,6 +65,7 @@ bufferprocs_py37.cpp bufferprocs_py37.h
+ debugfreehook.cpp debugfreehook.h
+ gilstate.cpp gilstate.h
+ helper.cpp helper.h
++pep384ext.cpp pep384ext.h
+ pep384impl.cpp pep384impl.h
+ pyobjectholder.h
+ sbkarrayconverter.cpp sbkarrayconverter.h sbkarrayconverter_p.h
+@@ -72,6 +73,7 @@ sbkbindingutils.cpp sbkbindingutils.h
+ sbkcontainer.cpp sbkcontainer.h
+ sbkconverter.cpp sbkconverter.h sbkconverter_p.h
+ sbkcppstring.cpp sbkcppstring.h sbkcpptonumpy.h
++sbkdestructorentry.h
+ sbkenum.cpp sbkenum.h sbkenum_p.h
+ sbkerrors.cpp sbkerrors.h
+ sbkfeature_base.cpp sbkfeature_base.h
+@@ -170,6 +172,7 @@ install(FILES
+ sbkcontainer.h
+ sbkconverter.h
+ sbkcpptonumpy.h
++ sbkdestructorentry.h
+ sbkenum.h
+ sbkenum_p.h
+ sbkerrors.h
+diff --git a/sources/shiboken6/libshiboken/basewrapper.h b/sources/shiboken6/libshiboken/basewrapper.h
+index 16ef506b5..6179a7fcf 100644
+--- a/sources/shiboken6/libshiboken/basewrapper.h
++++ b/sources/shiboken6/libshiboken/basewrapper.h
+@@ -6,6 +6,7 @@
+
+ #include "sbkpython.h"
+ #include "shibokenmacros.h"
++#include "sbkdestructorentry.h"
+
+ #include <vector>
+ #include <string>
+@@ -60,8 +61,6 @@ using TypeDiscoveryFuncV2 = void *(*)(void *, PyTypeObject *);
+ // Used in userdata dealloc function
+ using DeleteUserDataFunc = void (*)(void *);
+
+-using ObjectDestructor = void (*)(void *);
+-
+ using SubTypeInitHook = void (*)(PyTypeObject *, PyObject *, PyObject *);
+
+ /// PYSIDE-1019: Set the function to select the current feature.
+diff --git a/sources/shiboken6/libshiboken/basewrapper_p.h b/sources/shiboken6/libshiboken/basewrapper_p.h
+index e8744ad2d..94a866f6b 100644
+--- a/sources/shiboken6/libshiboken/basewrapper_p.h
++++ b/sources/shiboken6/libshiboken/basewrapper_p.h
+@@ -127,17 +127,6 @@ struct SbkObjectTypePrivate
+
+ namespace Shiboken
+ {
+-
+-/**
+- * \internal
+- * Data required to invoke a C++ destructor
+- */
+-struct DestructorEntry
+-{
+- ObjectDestructor destructor;
+- void *cppInstance;
+-};
+-
+ /**
+ * Utility function used to transform a PyObject that implements sequence protocol into a std::list.
+ **/
+diff --git a/sources/shiboken6/libshiboken/bindingmanager.h b/sources/shiboken6/libshiboken/bindingmanager.h
+index ea90bb033..97aefb596 100644
+--- a/sources/shiboken6/libshiboken/bindingmanager.h
++++ b/sources/shiboken6/libshiboken/bindingmanager.h
+@@ -6,6 +6,7 @@
+
+ #include "sbkpython.h"
+ #include "shibokenmacros.h"
++#include "sbkdestructorentry.h"
+
+ #include <set>
+ #include <utility>
+@@ -19,8 +20,6 @@ namespace Module {
+ struct TypeInitStruct;
+ }
+
+-struct DestructorEntry;
+-
+ using ObjectVisitor = void (*)(SbkObject *, void *);
+
+ class LIBSHIBOKEN_API BindingManager
+diff --git a/sources/shiboken6/libshiboken/pep384ext.cpp b/sources/shiboken6/libshiboken/pep384ext.cpp
+new file mode 100644
+index 000000000..a3f7d2d7d
+--- /dev/null
++++ b/sources/shiboken6/libshiboken/pep384ext.cpp
+@@ -0,0 +1,13 @@
++// Copyright (C) 2026 The Qt Company Ltd.
++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++#include "pep384ext.h"
++#include "autodecref.h"
++#include "sbkstaticstrings_p.h"
++#include "sbkstring.h"
++
++const char *PepExt_TypeGetQualName(PyTypeObject *type)
++{
++ Shiboken::AutoDecRef qualName(PepType_GetQualName(type));
++ return qualName.isNull() ? type->tp_name : Shiboken::String::toCString(qualName.object());
++}
+diff --git a/sources/shiboken6/libshiboken/pep384ext.h b/sources/shiboken6/libshiboken/pep384ext.h
+index f61d7ad5a..158211664 100644
+--- a/sources/shiboken6/libshiboken/pep384ext.h
++++ b/sources/shiboken6/libshiboken/pep384ext.h
+@@ -86,4 +86,6 @@ inline void PepExt_TypeCallFree(PyObject *object)
+ PepExt_Type_GetFreeSlot(Py_TYPE(object))(object);
+ }
+
++LIBSHIBOKEN_API const char *PepExt_TypeGetQualName(PyTypeObject *type);
++
+ #endif // PEP384EXT_H
+diff --git a/sources/shiboken6/libshiboken/pep384impl.cpp b/sources/shiboken6/libshiboken/pep384impl.cpp
+index 62e55b523..ef5bf20c3 100644
+--- a/sources/shiboken6/libshiboken/pep384impl.cpp
++++ b/sources/shiboken6/libshiboken/pep384impl.cpp
+@@ -711,6 +711,15 @@ const char *PepType_GetFullyQualifiedNameStr(PyTypeObject *type)
+ #endif
+ }
+
++PyObject *PepType_GetQualName(PyTypeObject *type)
++{
++#if !defined(PYPY_VERSION) && ((!defined(Py_LIMITED_API) && PY_VERSION_HEX >= 0x030B0000) || (defined(Py_LIMITED_API) && Py_LIMITED_API >= 0x030B0000))
++ return PyType_GetQualName(type);
++#else
++ return PyObject_GetAttr(reinterpret_cast<PyObject *>(type), Shiboken::PyMagicName::qualname());
++#endif
++}
++
+ // PYSIDE-2264: Find the _functools or functools module and retrieve the
+ // partial function. This can be tampered with, check carefully.
+ PyObject *
+diff --git a/sources/shiboken6/libshiboken/pep384impl.h b/sources/shiboken6/libshiboken/pep384impl.h
+index 8b24f47c7..c39ff847b 100644
+--- a/sources/shiboken6/libshiboken/pep384impl.h
++++ b/sources/shiboken6/libshiboken/pep384impl.h
+@@ -165,6 +165,8 @@ LIBSHIBOKEN_API const char *PepType_GetNameStr(PyTypeObject *type);
+ /// as C-string
+ LIBSHIBOKEN_API const char *PepType_GetFullyQualifiedNameStr(PyTypeObject *type);
+
++LIBSHIBOKEN_API PyObject *PepType_GetQualName(PyTypeObject *type);
++
+ LIBSHIBOKEN_API PyObject *Pep_GetPartialFunction(void);
+
+ /*****************************************************************************
+diff --git a/sources/shiboken6/libshiboken/sbkdestructorentry.h b/sources/shiboken6/libshiboken/sbkdestructorentry.h
+new file mode 100644
+index 000000000..929b7dfee
+--- /dev/null
++++ b/sources/shiboken6/libshiboken/sbkdestructorentry.h
+@@ -0,0 +1,24 @@
++// Copyright (C) 2026 The Qt Company Ltd.
++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++#ifndef SBKDESTRUCTORENTRY_H
++#define SBKDESTRUCTORENTRY_H
++
++extern "C"
++{
++using ObjectDestructor = void (*)(void *);
++}
++
++namespace Shiboken
++{
++
++/// Data required to invoke a C++ destructor
++struct DestructorEntry
++{
++ ObjectDestructor destructor;
++ void *cppInstance;
++};
++
++} // namespace Shiboken
++
++#endif // SBKDESTRUCTORENTRY_H
+diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
+index b31b161a3..0b1e47465 100644
+--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
++++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/enum_sig.py
+@@ -149,6 +149,9 @@ class ExactEnumerator:
+ name = base.__module__ + "." + name
+ bases_list.append(name)
+ bases_str = ', '.join(bases_list)
++ # PYSIDE-2516: see pyi_generator.
++ if class_name in ("Qt.KeyboardModifier", "Qt.Modifier"):
++ bases_str = "_SupportsOrKey"
+ class_str = f"{class_name}" if bases_str == "object" else f"{class_name}({bases_str})"
+ # class_members = inspect.getmembers(klass)
+ # gives us also the inherited things.
+diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
+index 4f5866b5c..3b7c5c168 100644
+--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
++++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/lib/pyi_generator.py
+@@ -281,6 +281,7 @@ FROM_IMPORTS = [
+ (None, ["enum"]),
+ (None, ["typing"]),
+ (None, ["collections.abc"]),
++ (None, ["datetime"]),
+ ("PySide6.QtCore", ["PyClassProperty", "Signal", "SignalInstance"]),
+ ("shiboken6", ["Shiboken"]),
+ ]
+@@ -394,6 +395,21 @@ def generate_pyi(import_name, outpath, options):
+ "bound=PySide6.QtCore.QObject)")
+ wr.print("_SlotFunc = typing.TypeVar(\"_SlotFunc\", "
+ "bound=collections.abc.Callable[..., object])")
++ wr.print()
++ # PYSIDE-2516: Qt.KeyboardModifier and Qt.Modifier support cross-type | with
++ # Qt.Key producing QKeyCombination, which enum.Flag.__or__ cannot express.
++ # Therefore these overloads must be injected manually.
++ wr.print(dedent("""\
++ class _SupportsOrKey(enum.Flag): # type: ignore[misc]
++ @typing.overload
++ def __or__(self, other: typing.Self) -> Qt.KeyboardModifier: ...
++ @typing.overload
++ def __or__(self, other: Qt.Key) -> QKeyCombination: ...
++ @typing.overload
++ def __ror__(self, other: typing.Self) -> Qt.KeyboardModifier: ...
++ @typing.overload
++ def __ror__(self, other: Qt.Key) -> QKeyCombination: ...
++ """))
+ wr.print()
+ else:
+ wr.print(line)
+diff --git a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+index 8c21e5d71..a95ca46c2 100644
+--- a/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
++++ b/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/parser.py
+@@ -12,6 +12,7 @@ import typing
+ import warnings
+ import collections.abc
+ import abc
++import datetime # noqa F:401
+
+ from types import SimpleNamespace
+ from shibokensupport.signature.mapping import (type_map, type_map_tuple, update_mapping,
+diff --git a/sources/shiboken6_generator/ApiExtractor/CMakeLists.txt b/sources/shiboken6_generator/ApiExtractor/CMakeLists.txt
+index 6adc3e10d..d726e73b4 100644
+--- a/sources/shiboken6_generator/ApiExtractor/CMakeLists.txt
++++ b/sources/shiboken6_generator/ApiExtractor/CMakeLists.txt
+@@ -12,6 +12,7 @@ set(apiextractor_SRC
+ abstractmetaargument.cpp abstractmetaargument.h
+ abstractmetabuilder.cpp abstractmetabuilder.h abstractmetabuilder_p.h
+ abstractmetabuilder_helpers.cpp
++abstractmetabuilder_testutil.cpp abstractmetabuilder_testutil.h
+ abstractmetaenum.cpp abstractmetaenum.h
+ abstractmetafield.cpp abstractmetafield.h
+ abstractmetafunction.cpp abstractmetafunction.h
+@@ -77,7 +78,8 @@ xmlutils.cpp xmlutils.h xmlutils_libxslt.h xmlutils_qt.h
+ clangparser/clangbuilder.cpp clangparser/clangbuilder.h
+ clangparser/clangdebugutils.cpp clangparser/clangdebugutils.h
+ clangparser/clangparser.cpp clangparser/clangparser.h
+-clangparser/clangutils.cpp clangparser/clangutils.h
++clangparser/clangtype.cpp clangparser/clangtype.h
++clangparser/clangutils.cpp clangparser/clangutils.h clangparser/clang_typedefs.h
+ clangparser/compilersupport.cpp clangparser/compilersupport.h
+ clangparser/triplet.cpp clangparser/triplet.h
+ # Old parser
+diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp
+index 107d6c8ee..679aa0300 100644
+--- a/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder.cpp
+@@ -535,6 +535,10 @@ FileModelItem AbstractMetaBuilderPrivate::buildDom(QByteArrayList arguments,
+ for (qsizetype i = 0; i < diagnosticsCount; ++i)
+ d << " " << diagnostics.at(i) << '\n';
+ }
++
++ if (const auto rejectedTypes = builder.rejectedTypes(); !rejectedTypes.isEmpty())
++ ReportHandler::addGeneralMessage(msgRejectedTypes(rejectedTypes));
++
+ return result;
+ }
+
+@@ -816,6 +820,7 @@ void AbstractMetaBuilderPrivate::addAbstractMetaClass(const AbstractMetaClassPtr
+ }
+ }
+
++// Returns newly created or continued namespace meta class
+ AbstractMetaClassPtr
+ AbstractMetaBuilderPrivate::traverseNamespace(const FileModelItem &dom,
+ const NamespaceModelItem &namespaceItem)
+@@ -902,7 +907,7 @@ AbstractMetaClassPtr
+ // Traverse namespaces recursively
+ for (const NamespaceModelItem &ni : namespaceItem->namespaces()) {
+ const auto mjc = traverseNamespace(dom, ni);
+- if (mjc) {
++ if (mjc && !metaClass->innerClasses().contains(mjc)) { // continued namspace?
+ metaClass->addInnerClass(mjc);
+ mjc->setEnclosingClass(metaClass);
+ m_classToItem.insert(mjc, ni.get()); // Add for enum lookup.
+@@ -2236,10 +2241,10 @@ AbstractMetaFunctionPtr
+ if (functionItem->isConstant())
+ signatures.append(signatures.constFirst().left(signatures.constFirst().size() - 5));
+ for (qsizetype i = 0, size = signatures.size(); i < size; ++i) {
+- const QString normalized =
+- QString::fromUtf8(QMetaObject::normalizedSignature(signatures.at(i).toUtf8()));
+- if (normalized != signatures.at(i))
+- signatures.append(normalized);
++ const QByteArray &signatureBA = signatures.at(i).toUtf8();
++ const QByteArray &normalizedBA = QMetaObject::normalizedSignature(signatureBA.constData());
++ if (normalizedBA != signatureBA)
++ signatures.append(QString::fromUtf8(normalizedBA));
+ }
+
+ for (const auto &signature : std::as_const(signatures)) {
+@@ -2874,7 +2879,7 @@ std::optional<AbstractMetaType>
+ newInfo.setIndirectionsV(typeInfo.indirectionsV());
+ newInfo.setConstant(typeInfo.isConstant());
+ newInfo.setVolatile(typeInfo.isVolatile());
+- newInfo.setFunctionPointer(typeInfo.isFunctionPointer());
++ newInfo.setTypeCategory(typeInfo.typeCategory());
+ newInfo.setQualifiedName(typeInfo.qualifiedName());
+ newInfo.setReferenceType(typeInfo.referenceType());
+ newInfo.setVolatile(typeInfo.isVolatile());
+@@ -3242,7 +3247,7 @@ QString AbstractMetaBuilder::fixDefaultValue(const QString &expr, const Abstract
+ bool AbstractMetaBuilderPrivate::isEnum(const FileModelItem &dom, const QStringList& qualified_name)
+ {
+ CodeModelItem item = CodeModel::findItem(qualified_name, dom);
+- return item && item->kind() == _EnumModelItem::__node_kind;
++ return item && item->kind() == _CodeModelItem::Kind_Enum;
+ }
+
+ AbstractMetaClassPtr
+@@ -3841,8 +3846,7 @@ void AbstractMetaBuilderPrivate::pushScope(const NamespaceModelItem &item)
+ }
+ }
+ if (candidates.size() > 1) {
+- auto joined = std::make_shared<_NamespaceModelItem>(m_scopes.constLast()->model(),
+- name, _CodeModelItem::Kind_Namespace);
++ auto joined = std::make_shared<_NamespaceModelItem>(name);
+ joined->setScope(item->scope());
+ for (const auto &n : candidates)
+ joined->appendNamespace(*n);
+diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_testutil.cpp b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_testutil.cpp
+new file mode 100644
+index 000000000..87e8a22d3
+--- /dev/null
++++ b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_testutil.cpp
+@@ -0,0 +1,78 @@
++// Copyright (C) 2026 The Qt Company Ltd.
++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++#include "abstractmetabuilder_testutil.h"
++#include "abstractmetabuilder.h"
++#include "abstractmetabuilder_p.h"
++#include "reporthandler.h"
++#include "typedatabase.h"
++
++#include <QtCore/qbuffer.h>
++#include <QtCore/qdebug.h>
++#include <QtCore/qdir.h>
++#include <QtCore/qtemporaryfile.h>
++
++#include <exception>
++
++static std::unique_ptr<QTemporaryFile> writeCppCode(const char *cppCode)
++{
++ const QString pattern = QDir::tempPath() + QLatin1StringView("/st_XXXXXX_main.cpp");
++ auto result = std::make_unique<QTemporaryFile>(pattern);
++ if (!result->open()) {
++ qWarning("Creation of temporary file failed: %s", qPrintable(result->errorString()));
++ return {};
++ }
++ result->write(cppCode, qint64(qstrlen(cppCode)));
++ result->close();
++ return result;
++}
++
++namespace TestUtil
++{
++std::shared_ptr<_FileModelItem>
++ buildDom(const char *cppCode, bool silent, LanguageLevel languageLevel)
++{
++ ReportHandler::setSilent(silent);
++ ReportHandler::startTimer();
++ auto tempSource = writeCppCode(cppCode);
++ if (!tempSource)
++ return {};
++ return AbstractMetaBuilderPrivate::buildDom({QFile::encodeName(tempSource->fileName())},
++ true, languageLevel, 0);
++}
++
++std::unique_ptr<AbstractMetaBuilder>
++ parse(const char *cppCode, const char *xmlCode, bool silent, const QString &apiVersion,
++ const QStringList &dropTypeEntries, LanguageLevel languageLevel)
++{
++ ReportHandler::setSilent(silent);
++ ReportHandler::startTimer();
++ auto *td = TypeDatabase::instance(true);
++ if (apiVersion.isEmpty())
++ TypeDatabase::clearApiVersions();
++ else if (!TypeDatabase::setApiVersion(QLatin1StringView("*"), apiVersion))
++ return nullptr;
++ td->setDropTypeEntries(dropTypeEntries);
++ QBuffer buffer;
++ // parse typesystem
++ buffer.setData(xmlCode);
++ if (!buffer.open(QIODevice::ReadOnly))
++ return nullptr;
++ if (!td->parseFile(&buffer))
++ return nullptr;
++ buffer.close();
++ auto tempSource = writeCppCode(cppCode);
++ if (!tempSource)
++ return nullptr;
++ auto builder = std::make_unique<AbstractMetaBuilder>();
++ try {
++ QByteArrayList arguments{QFile::encodeName(tempSource->fileName())};
++ if (!builder->build(arguments, {}, true, languageLevel))
++ builder.reset();
++ } catch (const std::exception &e) {
++ qWarning("%s", e.what());
++ builder.reset();
++ }
++ return builder;
++}
++} // namespace TestUtil
+diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_testutil.h b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_testutil.h
+new file mode 100644
+index 000000000..0c967aa62
+--- /dev/null
++++ b/sources/shiboken6_generator/ApiExtractor/abstractmetabuilder_testutil.h
+@@ -0,0 +1,27 @@
++// Copyright (C) 2026 The Qt Company Ltd.
++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++#ifndef ABSTRACTMETABUILDER_TESTUTIL_H
++#define ABSTRACTMETABUILDER_TESTUTIL_H
++
++#include "clangparser/compilersupport.h"
++
++class _FileModelItem;
++class AbstractMetaBuilder;
++
++#include <memory>
++
++namespace TestUtil
++{
++ std::shared_ptr<_FileModelItem>
++ buildDom(const char *cppCode, bool silent = true,
++ LanguageLevel languageLevel = LanguageLevel::Default);
++
++ std::unique_ptr<AbstractMetaBuilder>
++ parse(const char *cppCode, const char *xmlCode, bool silent = true,
++ const QString &apiVersion = {}, const QStringList &dropTypeEntries = {},
++ LanguageLevel languageLevel = LanguageLevel::Default);
++
++} // namespace TestUtil
++
++#endif // ABSTRACTMETABUILDER_TESTUTIL_H
+diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp b/sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp
+index 548cc8515..3206d6f41 100644
+--- a/sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/abstractmetalang.cpp
+@@ -780,11 +780,13 @@ uint AbstractMetaClass::toStringCapabilityIndirections() const
+ return d->m_toStringCapabilityIndirections;
+ }
+
+-// Does any of the base classes require deletion in the main thread?
+-bool AbstractMetaClass::deleteInMainThread() const
++// Does any of the base classes require special handling?
++TypeSystem::DeletionMode AbstractMetaClass::deletionMode() const
+ {
+- return typeEntry()->deleteInMainThread()
+- || (!d->m_baseClasses.isEmpty() && d->m_baseClasses.constFirst()->deleteInMainThread());
++ auto result = typeEntry()->deletionMode();
++ if (result == TypeSystem::DeletionMode::Default && !d->m_baseClasses.isEmpty())
++ result = d->m_baseClasses.constFirst()->deletionMode();
++ return result;
+ }
+
+ bool AbstractMetaClassPrivate::hasConstructors() const
+diff --git a/sources/shiboken6_generator/ApiExtractor/abstractmetalang.h b/sources/shiboken6_generator/ApiExtractor/abstractmetalang.h
+index a6688fd96..84da47387 100644
+--- a/sources/shiboken6_generator/ApiExtractor/abstractmetalang.h
++++ b/sources/shiboken6_generator/ApiExtractor/abstractmetalang.h
+@@ -7,6 +7,7 @@
+ #include "abstractmetalang_enums.h"
+ #include "abstractmetalang_typedefs.h"
+ #include "enclosingclassmixin.h"
++#include "typesystem_enums.h"
+ #include "typesystem_typedefs.h"
+
+ #include <QtCore/qobjectdefs.h>
+@@ -321,7 +322,7 @@ public:
+
+ uint toStringCapabilityIndirections() const;
+
+- bool deleteInMainThread() const;
++ TypeSystem::DeletionMode deletionMode() const;
+
+ // Query functions for generators
+ bool isObjectType() const;
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clang_typedefs.h b/sources/shiboken6_generator/ApiExtractor/clangparser/clang_typedefs.h
+new file mode 100644
+index 000000000..49efc2592
+--- /dev/null
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clang_typedefs.h
+@@ -0,0 +1,19 @@
++// Copyright (C) 2026 The Qt Company Ltd.
++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++#ifndef CLANG_TYPEDEFS_H
++#define CLANG_TYPEDEFS_H
++
++#include <clang-c/Index.h>
++
++namespace clang {
++
++#if LLVM_VERSION >= 22
++using PrintingPolicy = CXPrintingPolicy;
++#else
++using PrintingPolicy = void *;
++#endif
++
++} // namespace clang
++
++#endif // CLANG_TYPEDEFS_H
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp b/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp
+index 8e262d6d8..1bddbc8be 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.cpp
+@@ -4,6 +4,7 @@
+ #include "clangbuilder.h"
+ #include "compilersupport.h"
+ #include "clangutils.h"
++#include "clangtype.h"
+ #include "clangdebugutils.h"
+
+ #include <codemodel.h>
+@@ -19,6 +20,10 @@
+ #include <QtCore/qstack.h>
+ #include <QtCore/qlist.h>
+
++#include <algorithm>
++#include <optional>
++#include <set>
++
+ using namespace Qt::StringLiterals;
+
+ namespace clang {
+@@ -40,7 +45,7 @@ static inline bool withinClassDeclaration(const CXCursor &cursor)
+ return isClassCursor(clang_getCursorLexicalParent(cursor));
+ }
+
+-static QString fixTypeName(QString t)
++static QString fixOperatorTypeName(QString t)
+ {
+ // Fix "Foo &" -> "Foo&", similarly "Bar **" -> "Bar**"
+ auto pos = t.size() - 1;
+@@ -123,13 +128,9 @@ public:
+ using CursorClassHash = QHash<CXCursor, ClassModelItem>;
+ using TypeInfoHash = QHash<CXType, TypeInfo>;
+
+- explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv), m_model(new CodeModel)
+- {
+- m_scopeStack.push(NamespaceModelItem(new _FileModelItem(m_model)));
+- }
+- ~BuilderPrivate()
++ explicit BuilderPrivate(BaseVisitor *bv) : m_baseVisitor(bv)
+ {
+- delete m_model;
++ m_scopeStack.push(std::make_shared<_FileModelItem>());
+ }
+
+ // Determine scope from top item. Note that the scope list does not necessarily
+@@ -163,13 +164,15 @@ public:
+ FunctionModelItem createMemberFunction(const CXCursor &cursor,
+ bool isTemplateCode = false);
+ void qualifyConstructor(const CXCursor &cursor);
+- TypeInfo createTypeInfoUncached(const CXType &type,
+- bool *cacheable = nullptr) const;
+- TypeInfo createTypeInfo(const CXType &type) const;
+- TypeInfo createTypeInfo(const CXCursor &cursor) const
++ std::optional<TypeInfo> createTypeInfoUncached(const CXType &type,
++ bool *cacheable = nullptr) const;
++ std::optional<TypeInfo> createTypeInfo(const CXType &type) const;
++ std::optional<TypeInfo> createTypeInfo(const CXCursor &cursor) const
+ { return createTypeInfo(clang_getCursorType(cursor)); }
++ std::optional<TypeInfo> createFunctionTypeInfo(const CXType &type, TypeCategory cat,
++ bool *cacheable) const;
+ void addTemplateInstantiations(const CXType &type,
+- QString *typeName,
++ const QString &templateParameters,
+ TypeInfo *t) const;
+ bool addTemplateInstantiationsRecursion(const CXType &type, TypeInfo *t) const;
+
+@@ -180,7 +183,7 @@ public:
+
+ TemplateParameterModelItem createTemplateParameter(const CXCursor &cursor) const;
+ TemplateParameterModelItem createNonTypeTemplateParameter(const CXCursor &cursor) const;
+- void addField(const CXCursor &cursor);
++ void addField(const CXCursor &cursor, bool staticField = false);
+
+ static QString cursorValueExpression(BaseVisitor *bv, const CXCursor &cursor);
+ std::pair<QString, ClassModelItem> getBaseClass(CXType type) const;
+@@ -193,7 +196,6 @@ public:
+ void setFileName(const CXCursor &cursor, _CodeModelItem *item) const;
+
+ BaseVisitor *m_baseVisitor;
+- CodeModel *m_model;
+
+ QStack<ScopeModelItem> m_scopeStack;
+ QStringList m_scope;
+@@ -220,12 +222,13 @@ public:
+ CodeModel::FunctionType m_currentFunctionType = CodeModel::Normal;
+ bool m_withinFriendDecl = false;
+ mutable QHash<QString, SpecialSystemHeader> m_systemHeaders;
++ mutable std::set<QString> m_rejectedTypes;
+ };
+
+ bool BuilderPrivate::addClass(const CXCursor &cursor, CodeModel::ClassType t)
+ {
+ QString className = getCursorSpelling(cursor);
+- m_currentClass = std::make_shared<_ClassModelItem>(m_model, className);
++ m_currentClass = std::make_shared<_ClassModelItem>(className);
+ setFileName(cursor, m_currentClass.get());
+ m_currentClass->setClassType(t);
+ // Some inner class? Note that it does not need to be (lexically) contained in a
+@@ -329,11 +332,14 @@ FunctionModelItem BuilderPrivate::createFunction(const CXCursor &cursor,
+ QString name = getCursorSpelling(cursor);
+ // Apply type fixes to "operator X &" -> "operator X&"
+ if (name.startsWith(u"operator "))
+- name = fixTypeName(name);
+- auto result = std::make_shared<_FunctionModelItem>(m_model, name);
++ name = fixOperatorTypeName(name);
++ auto result = std::make_shared<_FunctionModelItem>(name);
+ setFileName(cursor, result.get());
+ const auto type = clang_getCursorResultType(cursor);
+- result->setType(createTypeInfo(type));
++ auto resultTypeO = createTypeInfo(type);
++ if (!resultTypeO.has_value())
++ return {};
++ result->setType(resultTypeO.value());
+ result->setScopeResolution(hasScopeResolution(type));
+ result->setFunctionType(t);
+ result->setScope(m_scope);
+@@ -392,6 +398,8 @@ FunctionModelItem BuilderPrivate::createMemberFunction(const CXCursor &cursor,
+ : functionTypeFromCursor(cursor);
+ isTemplateCode |= m_currentClass->name().endsWith(u'>');
+ auto result = createFunction(cursor, functionType, isTemplateCode);
++ if (!result)
++ return result;
+ result->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ result->setConstant(clang_CXXMethod_isConst(cursor) != 0);
+ result->setAttribute(FunctionAttribute::Static, clang_CXXMethod_isStatic(cursor) != 0);
+@@ -420,50 +428,36 @@ void BuilderPrivate::qualifyConstructor(const CXCursor &cursor)
+
+ TemplateParameterModelItem BuilderPrivate::createTemplateParameter(const CXCursor &cursor) const
+ {
+- return std::make_shared<_TemplateParameterModelItem>(m_model, getCursorSpelling(cursor));
++ return std::make_shared<_TemplateParameterModelItem>(getCursorSpelling(cursor));
+ }
+
+ TemplateParameterModelItem BuilderPrivate::createNonTypeTemplateParameter(const CXCursor &cursor) const
+ {
++ auto typeO = createTypeInfo(clang_getCursorType(cursor));
++ if (!typeO.has_value())
++ return {};
+ TemplateParameterModelItem result = createTemplateParameter(cursor);
+- result->setType(createTypeInfo(clang_getCursorType(cursor)));
++ result->setType(typeO.value());
+ return result;
+ }
+
+ // CXCursor_VarDecl, CXCursor_FieldDecl cursors
+-void BuilderPrivate::addField(const CXCursor &cursor)
++void BuilderPrivate::addField(const CXCursor &cursor, bool staticField)
+ {
+- auto field = std::make_shared<_VariableModelItem>(m_model, getCursorSpelling(cursor));
++ auto typeO = createTypeInfo(cursor);
++ if (!typeO.has_value())
++ return;
++ auto field = std::make_shared<_VariableModelItem>(getCursorSpelling(cursor));
+ field->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ field->setScope(m_scope);
+- field->setType(createTypeInfo(cursor));
++ field->setType(typeO.value());
+ field->setMutable(clang_CXXField_isMutable(cursor) != 0);
++ field->setStatic(staticField);
+ setFileName(cursor, field.get());
+ m_currentField = field;
+ m_scopeStack.back()->addVariable(field);
+ }
+
+-// Create qualified name "std::list<std::string>" -> ("std", "list<std::string>")
+-static QStringList qualifiedName(const QString &t)
+-{
+- QStringList result;
+- auto end = t.indexOf(u'<');
+- if (end == -1)
+- end = t.indexOf(u'(');
+- if (end == -1)
+- end = t.size();
+- qsizetype lastPos = 0;
+- while (true) {
+- const auto nextPos = t.indexOf(u"::"_s, lastPos);
+- if (nextPos < 0 || nextPos >= end)
+- break;
+- result.append(t.mid(lastPos, nextPos - lastPos));
+- lastPos = nextPos + 2;
+- }
+- result.append(t.right(t.size() - lastPos));
+- return result;
+-}
+-
+ static bool isArrayType(CXTypeKind k)
+ {
+ return k == CXType_ConstantArray || k == CXType_IncompleteArray
+@@ -489,7 +483,10 @@ bool BuilderPrivate::addTemplateInstantiationsRecursion(const CXType &type, Type
+ // of a non-type template (template <int v>).
+ if (argType.kind == CXType_Invalid)
+ return false;
+- t->addInstantiation(createTypeInfoUncached(argType));
++ auto typeO = createTypeInfoUncached(argType);
++ if (!typeO.has_value())
++ return false;
++ t->addInstantiation(typeO.value());
+ }
+ }
+ break;
+@@ -499,10 +496,8 @@ bool BuilderPrivate::addTemplateInstantiationsRecursion(const CXType &type, Type
+ return true;
+ }
+
+-static void dummyTemplateArgumentHandler(int, QStringView) {}
+-
+ void BuilderPrivate::addTemplateInstantiations(const CXType &type,
+- QString *typeName,
++ const QString &templateParameters,
+ TypeInfo *t) const
+ {
+ // In most cases, for templates like "Vector<A>", Clang will give us the
+@@ -513,16 +508,12 @@ void BuilderPrivate::addTemplateInstantiations(const CXType &type,
+ // Vector(const Vector&);
+ // };
+ // In that case, have TypeInfo parse the list from the spelling.
+- // Finally, remove the list "<>" from the type name.
+ const bool parsed = addTemplateInstantiationsRecursion(type, t)
+ && !t->instantiations().isEmpty();
+- if (!parsed)
++ if (!parsed) {
+ t->setInstantiations({});
+- const auto pos = parsed
+- ? parseTemplateArgumentList(*typeName, dummyTemplateArgumentHandler)
+- : t->parseTemplateArgumentList(*typeName);
+- if (pos.first != -1 && pos.second != -1 && pos.second > pos.first)
+- typeName->remove(pos.first, pos.second - pos.first);
++ t->parseTemplateArgumentList(templateParameters);
++ }
+ }
+
+ static TypeCategory typeCategoryFromClang(CXTypeKind k)
+@@ -546,22 +537,59 @@ static TypeCategory typeCategoryFromClang(CXTypeKind k)
+ return TypeCategory::Other;
+ }
+
+-TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type,
+- bool *cacheable) const
++// Reject decltype() expressions, template parameter packs, etc.
++static inline bool checkTypeName(const QString &name)
+ {
++ static constexpr QLatin1StringView exclusions[] = {
++ "decltype("_L1, "std::declval"_L1, "::detail::"_L1, "std::enable_if<"_L1,
++ "template "_L1, "..."_L1
++ };
++
++ auto excludedPred = [&name](QLatin1StringView ex) { return name.contains(ex); };
++ return std::none_of(std::begin(exclusions), std::end(exclusions), excludedPred);
++}
++
++static QString fixTypeName(QString typeName)
++{
++ while (TypeInfo::stripLeadingConst(&typeName) || TypeInfo::stripLeadingVolatile(&typeName)) {
++ }
++ static constexpr auto leadingTypename = "typename "_L1;
++ if (typeName.startsWith(leadingTypename))
++ typeName.remove(0, leadingTypename.size());
++ typeName.replace("<typename "_L1, "<"_L1);
++ typeName.replace(", typename "_L1, ", "_L1);
++ return typeName;
++}
++
++std::optional<TypeInfo>
++ BuilderPrivate::createFunctionTypeInfo(const CXType &type, TypeCategory cat, bool *cacheable) const
++{
++ const int argCount = clang_getNumArgTypes(type);
++ if (argCount < 0)
++ return std::nullopt;
++ auto resultO = createTypeInfoUncached(clang_getResultType(type), cacheable);
++ if (!resultO.has_value())
++ return std::nullopt;
++ resultO->setTypeCategory(cat);
++ for (int a = 0; a < argCount; ++a) {
++ auto argTypeO = createTypeInfoUncached(clang_getArgType(type, unsigned(a)), cacheable);
++ if (!argTypeO.has_value())
++ return std::nullopt;
++ resultO->addArgument(argTypeO.value());
++ }
++ return resultO;
++}
++
++std::optional<TypeInfo>
++ BuilderPrivate::createTypeInfoUncached(const CXType &type, bool *cacheable) const
++{
++ if (type.kind == CXType_FunctionProto)
++ return createFunctionTypeInfo(type, TypeCategory::Function, cacheable);
++
+ if (type.kind == CXType_Pointer) { // Check for function pointers, first.
+ const CXType pointeeType = clang_getPointeeType(type);
+- const int argCount = clang_getNumArgTypes(pointeeType);
+- if (argCount >= 0) {
+- TypeInfo result = createTypeInfoUncached(clang_getResultType(pointeeType),
+- cacheable);
+- result.setTypeCategory(TypeCategory::Pointer);
+- result.setFunctionPointer(true);
+- for (int a = 0; a < argCount; ++a)
+- result.addArgument(createTypeInfoUncached(clang_getArgType(pointeeType, unsigned(a)),
+- cacheable));
+- return result;
+- }
++ if (pointeeType.kind == CXType_FunctionProto)
++ return createFunctionTypeInfo(pointeeType, TypeCategory::FunctionPointer, cacheable);
+ }
+
+ TypeInfo typeInfo;
+@@ -595,9 +623,12 @@ TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type,
+ typeInfo.setConstant(clang_isConstQualifiedType(nestedType) != 0);
+ typeInfo.setVolatile(clang_isVolatileQualifiedType(nestedType) != 0);
+
+- QString typeName = getResolvedTypeName(nestedType);
+- while (TypeInfo::stripLeadingConst(&typeName)
+- || TypeInfo::stripLeadingVolatile(&typeName)) {
++ QString typeName = fixTypeName(getResolvedTypeName(nestedType,
++ m_baseVisitor->printingPolicy()));
++
++ if (!checkTypeName(typeName)) {
++ m_rejectedTypes.insert(typeName);
++ return std::nullopt;
+ }
+
+ // For typedefs within templates or nested classes within templates (iterators):
+@@ -619,33 +650,44 @@ TypeInfo BuilderPrivate::createTypeInfoUncached(const CXType &type,
+
+ // Obtain template instantiations if the name has '<' (thus excluding
+ // typedefs like "std::string".
+- if (typeName.contains(u'<'))
+- addTemplateInstantiations(nestedType, &typeName, &typeInfo);
+
+- typeInfo.setQualifiedName(qualifiedName(typeName));
++ auto clangTypeNameO = clang::parseTypeName(typeName);
++ if (!clangTypeNameO.has_value()) {
++ m_rejectedTypes.insert(typeName);
++ return std::nullopt;
++ }
++
++ const auto &clangTypeName = clangTypeNameO.value();
++ if (!clangTypeName.templateParameters.isEmpty())
++ addTemplateInstantiations(nestedType, clangTypeName.templateParameters, &typeInfo);
++
++ typeInfo.setQualifiedName(clangTypeName.name.split("::"_L1));
+ // 3320:CINDEX_LINKAGE int clang_getNumArgTypes(CXType T); function ptr types?
+ typeInfo.simplifyStdType();
+ return typeInfo;
+ }
+
+-TypeInfo BuilderPrivate::createTypeInfo(const CXType &type) const
++std::optional<TypeInfo> BuilderPrivate::createTypeInfo(const CXType &type) const
+ {
+ const auto it = m_typeInfoHash.constFind(type);
+ if (it != m_typeInfoHash.constEnd())
+ return it.value();
+ bool cacheable = true;
+- TypeInfo result = createTypeInfoUncached(type, &cacheable);
+- if (cacheable)
+- m_typeInfoHash.insert(type, result);
+- return result;
++ auto resultO = createTypeInfoUncached(type, &cacheable);
++ if (resultO.has_value() && cacheable)
++ m_typeInfoHash.insert(type, resultO.value());
++ return resultO;
+ }
+
+ void BuilderPrivate::addTypeDef(const CXCursor &cursor, const CXType &cxType)
+ {
+ const QString target = getCursorSpelling(cursor);
+- auto item = std::make_shared<_TypeDefModelItem>(m_model, target);
++ auto typeInfoO = createTypeInfo(cxType);
++ if (!typeInfoO.has_value())
++ return;
++ auto item = std::make_shared<_TypeDefModelItem>(target);
+ setFileName(cursor, item.get());
+- item->setType(createTypeInfo(cxType));
++ item->setType(typeInfoO.value());
+ item->setScope(m_scope);
+ item->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ m_scopeStack.back()->addTypeDef(item);
+@@ -664,7 +706,7 @@ ClassModelItem BuilderPrivate::currentTemplateClass() const
+ void BuilderPrivate::startTemplateTypeAlias(const CXCursor &cursor)
+ {
+ const QString target = getCursorSpelling(cursor);
+- m_currentTemplateTypeAlias = std::make_shared<_TemplateTypeAliasModelItem>(m_model, target);
++ m_currentTemplateTypeAlias = std::make_shared<_TemplateTypeAliasModelItem>(target);
+ setFileName(cursor, m_currentTemplateTypeAlias.get());
+ m_currentTemplateTypeAlias->setScope(m_scope);
+ }
+@@ -675,8 +717,10 @@ void BuilderPrivate::endTemplateTypeAlias(const CXCursor &typeAliasCursor)
+ // Usually "<elaborated>std::list<T>" or "<unexposed>Container1<T>",
+ // as obtained with parser of PYSIDE-323
+ if (type.kind == CXType_Unexposed || type.kind == CXType_Elaborated) {
+- m_currentTemplateTypeAlias->setType(createTypeInfo(type));
+- m_scopeStack.back()->addTemplateTypeAlias(m_currentTemplateTypeAlias);
++ if (auto typeO = createTypeInfo(type)) {
++ m_currentTemplateTypeAlias->setType(typeO.value());
++ m_scopeStack.back()->addTemplateTypeAlias(m_currentTemplateTypeAlias);
++ }
+ }
+ m_currentTemplateTypeAlias.reset();
+ }
+@@ -733,9 +777,11 @@ std::pair<QString, ClassModelItem> BuilderPrivate::getBaseClass(CXType type) con
+ {
+ const auto decl = resolveBaseClassType(type);
+ // Note: spelling has "struct baseClass", use type
+- QString baseClassName = getTypeName(decl.type);
+- if (baseClassName.startsWith(u"std::")) // Simplify "std::" types
+- baseClassName = createTypeInfo(decl.type).toString();
++ QString baseClassName = getTypeName(decl.type, m_baseVisitor->printingPolicy());
++ if (baseClassName.startsWith(u"std::")) { // Simplify "std::" types
++ if (auto typeO = createTypeInfo(decl.type))
++ baseClassName = typeO.value().toString();
++ }
+
+ auto it = m_cursorClassHash.constFind(decl.declaration);
+ // Not found: Set unqualified name. This happens in cases like
+@@ -917,6 +963,11 @@ FileModelItem Builder::dom() const
+ return std::dynamic_pointer_cast<_FileModelItem>(rootScope);
+ }
+
++QStringList Builder::rejectedTypes() const
++{
++ return {d->m_rejectedTypes.cbegin(), d->m_rejectedTypes.cend()};
++}
++
+ static QString msgOutOfOrder(const CXCursor &cursor, const char *expectedScope)
+ {
+ return getCursorKindName(cursor.kind) + u' '
+@@ -945,7 +996,7 @@ static NamespaceType namespaceType(const CXCursor &cursor)
+ return NamespaceType::Default;
+ }
+
+-static QString enumType(const CXCursor &cursor)
++static QString enumType(const CXCursor &cursor, PrintingPolicy p)
+ {
+ QString name = getCursorSpelling(cursor); // "enum Foo { v1, v2 };"
+ if (name.contains(u"unnamed enum")) // Clang 16.0
+@@ -953,7 +1004,7 @@ static QString enumType(const CXCursor &cursor)
+ if (name.isEmpty()) {
+ // PYSIDE-1228: For "typedef enum { v1, v2 } Foo;", type will return
+ // "Foo" as expected. Care must be taken to exclude real anonymous enums.
+- name = getTypeName(clang_getCursorType(cursor));
++ name = getTypeName(clang_getCursorType(cursor), p);
+ if (name.contains(u"(unnamed") // Clang 12.0.1
+ || name.contains(u"(anonymous")) { // earlier
+ name.clear();
+@@ -1011,7 +1062,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ d->m_scope.back() += "<>"_L1;
+ break;
+ case CXCursor_EnumDecl: {
+- QString name = enumType(cursor);
++ QString name = enumType(cursor, printingPolicy());
+ EnumKind kind = CEnum;
+ if (name.isEmpty()) {
+ kind = AnonymousEnum;
+@@ -1023,7 +1074,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ #endif
+ kind = EnumClass;
+ }
+- d->m_currentEnum = std::make_shared<_EnumModelItem>(d->m_model, name);
++ d->m_currentEnum = std::make_shared<_EnumModelItem>(name);
+ d->setFileName(cursor, d->m_currentEnum.get());
+ d->m_currentEnum->setScope(d->m_scope);
+ d->m_currentEnum->setEnumKind(kind);
+@@ -1031,7 +1082,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ d->m_currentEnum->setDeprecated(true);
+ const auto enumType = fullyResolveType(clang_getEnumDeclIntegerType(cursor));
+ d->m_currentEnum->setSigned(isSigned(enumType.kind));
+- d->m_currentEnum->setUnderlyingType(getTypeName(enumType));
++ d->m_currentEnum->setUnderlyingType(getTypeName(enumType, printingPolicy()));
+ if (std::dynamic_pointer_cast<_ClassModelItem>(d->m_scopeStack.back()))
+ d->m_currentEnum->setAccessPolicy(accessPolicy(clang_getCXXAccessSpecifier(cursor)));
+ }
+@@ -1049,7 +1100,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ enumValue.setValue(clang_getEnumConstantDeclValue(cursor));
+ else
+ enumValue.setUnsignedValue(clang_getEnumConstantDeclUnsignedValue(cursor));
+- auto enumConstant = std::make_shared<_EnumeratorModelItem>(d->m_model, name);
++ auto enumConstant = std::make_shared<_EnumeratorModelItem>(name);
+ enumConstant->setStringValue(BuilderPrivate::cursorValueExpression(this, cursor));
+ enumConstant->setValue(enumValue);
+ if (clang_getCursorAvailability(cursor) == CXAvailability_Deprecated)
+@@ -1059,10 +1110,8 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ break;
+ case CXCursor_VarDecl:
+ // static class members are seen as CXCursor_VarDecl
+- if (isClassOrNamespaceCursor(clang_getCursorSemanticParent(cursor))) {
+- d->addField(cursor);
+- d->m_currentField->setStatic(true);
+- }
++ if (isClassOrNamespaceCursor(clang_getCursorSemanticParent(cursor)))
++ d->addField(cursor, true);
+ break;
+ case CXCursor_FieldDecl:
+ d->addField(cursor);
+@@ -1073,13 +1122,16 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ case CXCursor_Constructor:
+ case CXCursor_Destructor: // Note: Also use clang_CXXConstructor_is..Constructor?
+ case CXCursor_CXXMethod:
+- case CXCursor_ConversionFunction:
++ case CXCursor_ConversionFunction: {
+ // Member functions of other classes can be declared to be friends.
+ // Skip inline member functions outside class, only go by declarations inside class
+ if (d->m_withinFriendDecl || !withinClassDeclaration(cursor))
+ return Skip;
+- d->m_currentFunction = d->createMemberFunction(cursor, false);
+- d->m_scopeStack.back()->addFunction(d->m_currentFunction);
++ auto func = d->createMemberFunction(cursor, false);
++ if (!func)
++ return Skip;
++ d->m_currentFunction = func;
++ }
+ break;
+ // Not fully supported, currently, seen as normal function
+ // Note: May appear inside class (member template) or outside (free template).
+@@ -1087,31 +1139,30 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ const CXCursor semParent = clang_getCursorSemanticParent(cursor);
+ if (isClassCursor(semParent)) {
+ if (semParent == clang_getCursorLexicalParent(cursor)) {
+- d->m_currentFunction = d->createMemberFunction(cursor, true);
+- d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+- break;
++ if (auto func = d->createMemberFunction(cursor, true)) {
++ d->m_currentFunction = func;
++ break;
++ }
+ }
+ return Skip; // inline member functions outside class
+ }
+- }
+- d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, true);
++ auto func = d->createFunction(cursor, CodeModel::Normal, true);
++ if (!func)
++ return Skip;
++ d->m_currentFunction = func;
+ d->setFileName(cursor, d->m_currentFunction.get());
+- d->m_scopeStack.back()->addFunction(d->m_currentFunction);
++ }
+ break;
+ case CXCursor_FunctionDecl:
+ // Free functions or functions completely defined within "friend" (class
+ // operators). Note: CXTranslationUnit_SkipFunctionBodies must be off for
+ // clang_isCursorDefinition() to work here.
+ if (!d->m_withinFriendDecl || clang_isCursorDefinition(cursor) != 0) {
+- auto scope = d->m_scopeStack.size() - 1; // enclosing class
+- if (d->m_withinFriendDecl) {
+- // Friend declaration: go back to namespace or file scope.
+- for (--scope; d->m_scopeStack.at(scope)->kind() == _CodeModelItem::Kind_Class; --scope) {
+- }
+- }
+- d->m_currentFunction = d->createFunction(cursor, CodeModel::Normal, false);
++ auto func = d->createFunction(cursor, CodeModel::Normal, false);
++ if (!func)
++ return Skip;
++ d->m_currentFunction = func;
+ d->m_currentFunction->setHiddenFriend(d->m_withinFriendDecl);
+- d->m_scopeStack.at(scope)->addFunction(d->m_currentFunction);
+ }
+ break;
+ case CXCursor_Namespace: {
+@@ -1128,10 +1179,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ appendDiagnostic(d);
+ return Error;
+ }
+- // Treat namespaces separately to allow for extending namespaces
+- // in subsequent modules.
+- NamespaceModelItem namespaceItem = parentNamespaceItem->findNamespace(name);
+- namespaceItem = std::make_shared<_NamespaceModelItem>(d->m_model, name);
++ auto namespaceItem = std::make_shared<_NamespaceModelItem>(name);
+ d->setFileName(cursor, namespaceItem.get());
+ namespaceItem->setScope(d->m_scope);
+ namespaceItem->setType(type);
+@@ -1144,10 +1192,15 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ // and function pointer typedefs.
+ if (!d->m_currentArgument && d->m_currentFunction) {
+ const QString name = getCursorSpelling(cursor);
+- d->m_currentArgument = std::make_shared<_ArgumentModelItem>(d->m_model, name);
+ const auto type = clang_getCursorType(cursor);
++ auto typeO = d->createTypeInfo(type);
++ if (!typeO.has_value()) {
++ d->m_currentFunction.reset();
++ return Skip;
++ }
++ d->m_currentArgument = std::make_shared<_ArgumentModelItem>(name);
+ d->m_currentArgument->setScopeResolution(hasScopeResolution(type));
+- d->m_currentArgument->setType(d->createTypeInfo(type));
++ d->m_currentArgument->setType(typeO.value());
+ d->m_currentFunction->addArgument(d->m_currentArgument);
+ QString defaultValueExpression = BuilderPrivate::cursorValueExpression(this, cursor);
+ if (!defaultValueExpression.isEmpty()) {
+@@ -1164,10 +1217,30 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ ? d->createTemplateParameter(cursor) : d->createNonTypeTemplateParameter(cursor);
+ // Apply to function/member template?
+ if (d->m_currentFunction) {
+- d->m_currentFunction->setTemplateParameters(d->m_currentFunction->templateParameters() << tItem);
++ if (!tItem) {
++ d->m_currentFunction.reset();
++ return Skip;
++ }
++ d->m_currentFunction->addTemplateParameter(tItem);
+ } else if (d->m_currentTemplateTypeAlias) {
++ if (!tItem) {
++ d->m_currentTemplateTypeAlias.reset();
++ return Skip;
++ }
+ d->m_currentTemplateTypeAlias->addTemplateParameter(tItem);
+ } else if (d->m_currentClass) { // Apply to class
++ if (!tItem) {
++ // Failure is fatal if the first parameter cannot be determined, trailing
++ // parameters will be warned about.
++ const bool fatal = d->m_currentClass->templateParameters().isEmpty();
++ const QString message = "Failed to determine template parameter of "_L1
++ + d->m_currentClass->name();
++ const Diagnostic d(message, cursor,
++ fatal ? CXDiagnostic_Error : CXDiagnostic_Warning);
++ qWarning() << d;
++ appendDiagnostic(d);
++ return fatal ? Error : Skip;
++ }
+ const QString &tplParmName = tItem->name();
+ if (Q_UNLIKELY(!insertTemplateParameterIntoClassName(tplParmName, d->m_currentClass)
+ || !insertTemplateParameterIntoClassName(tplParmName, &d->m_scope.back()))) {
+@@ -1178,7 +1251,7 @@ BaseVisitor::StartTokenResult Builder::startToken(const CXCursor &cursor)
+ appendDiagnostic(d);
+ return Error;
+ }
+- d->m_currentClass->setTemplateParameters(d->m_currentClass->templateParameters() << tItem);
++ d->m_currentClass->addTemplateParameter(tItem);
+ }
+ }
+ break;
+@@ -1289,9 +1362,10 @@ bool Builder::endToken(const CXCursor &cursor)
+ d->m_currentField.reset();
+ break;
+ case CXCursor_Constructor:
+- d->qualifyConstructor(cursor);
+ if (d->m_currentFunction) {
++ d->qualifyConstructor(cursor);
+ d->m_currentFunction->_determineType();
++ d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+ d->m_currentFunction.reset();
+ }
+ break;
+@@ -1301,12 +1375,28 @@ bool Builder::endToken(const CXCursor &cursor)
+ case CXCursor_FunctionTemplate:
+ if (d->m_currentFunction) {
+ d->m_currentFunction->_determineType();
++ auto scope = d->m_scopeStack.size() - 1; // enclosing class
++ if (cursor.kind == CXCursor_FunctionDecl) {
++ // Free functions or functions completely defined within "friend" (class
++ // operators).
++ if (!d->m_withinFriendDecl || clang_isCursorDefinition(cursor) != 0) {
++ if (d->m_withinFriendDecl) {
++ // Friend declaration: go back to namespace or file scope.
++ for (--scope;
++ d->m_scopeStack.at(scope)->kind() == _CodeModelItem::Kind_Class;
++ --scope) {
++ }
++ }
++ }
++ }
++ d->m_scopeStack.at(scope)->addFunction(d->m_currentFunction);
+ d->m_currentFunction.reset();
+ }
+ break;
+ case CXCursor_ConversionFunction:
+ if (d->m_currentFunction) {
+ d->m_currentFunction->setFunctionType(CodeModel::ConversionOperator);
++ d->m_scopeStack.back()->addFunction(d->m_currentFunction);
+ d->m_currentFunction.reset();
+ }
+ break;
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.h b/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.h
+index f60bbe155..4cc58d08d 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.h
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangbuilder.h
+@@ -33,6 +33,8 @@ public:
+
+ FileModelItem dom() const;
+
++ QStringList rejectedTypes() const;
++
+ private:
+ BuilderPrivate *d;
+ };
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangparser.cpp b/sources/shiboken6_generator/ApiExtractor/clangparser/clangparser.cpp
+index 46d2a26f7..ff18e9657 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/clangparser.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangparser.cpp
+@@ -285,7 +285,8 @@ static void setupTarget(CXTranslationUnit translationUnit)
+ QString message;
+ {
+ QTextStream str(&message);
+- str << "CLANG v" << CINDEX_VERSION_MAJOR << '.' << CINDEX_VERSION_MINOR
++ str << "CLANG v" << LLVM_VERSION << '/'
++ << CINDEX_VERSION_MAJOR << '.' << CINDEX_VERSION_MINOR
+ << " targeting \"" << targetTriple << "\"/"
+ << optionsTriplet().compilerTripletValue()
+ << ", " << pointerSize << "bit";
+@@ -320,9 +321,19 @@ bool parse(const QByteArrayList &clangArgs, bool addCompilerSupportArguments,
+ setupTarget(translationUnit);
+
+ CXCursor rootCursor = clang_getTranslationUnitCursor(translationUnit);
++#if LLVM_VERSION >= 22
++ CXPrintingPolicy printingPolicy = clang_getCursorPrintingPolicy(rootCursor);
++ clang_PrintingPolicy_setProperty(printingPolicy, CXPrintingPolicy_IncludeNewlines, 0);
++ bv.setPrintingPolicy(printingPolicy);
++#endif
+
+ clang_visitChildren(rootCursor, visitorCallback, reinterpret_cast<CXClientData>(&bv));
+
++#if LLVM_VERSION >= 22
++ bv.setPrintingPolicy(nullptr);
++ clang_PrintingPolicy_dispose(printingPolicy);
++#endif
++
+ QList<Diagnostic> diagnostics = getDiagnostics(translationUnit);
+ diagnostics.append(bv.diagnostics());
+ bv.setDiagnostics(diagnostics);
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangparser.h b/sources/shiboken6_generator/ApiExtractor/clangparser/clangparser.h
+index 79dc855e2..7cc47e849 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/clangparser.h
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangparser.h
+@@ -4,7 +4,7 @@
+ #ifndef CLANGPARSER_H
+ #define CLANGPARSER_H
+
+-#include <clang-c/Index.h>
++#include "clang_typedefs.h"
+
+ #include <QtCore/qbytearraylist.h>
+ #include <QtCore/qhash.h>
+@@ -72,10 +72,14 @@ public:
+ // For usage by the parser
+ bool _handleVisitLocation( const CXSourceLocation &location);
+
++ PrintingPolicy printingPolicy() const { return m_printingPolicy; }
++ void setPrintingPolicy(CXPrintingPolicy p) { m_printingPolicy = p; }
++
+ private:
+ SourceFileCache m_fileCache;
+ Diagnostics m_diagnostics;
+ CXFile m_currentCxFile{};
++ PrintingPolicy m_printingPolicy = nullptr;
+ bool m_visitCurrent = true;
+ };
+
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangtype.cpp b/sources/shiboken6_generator/ApiExtractor/clangparser/clangtype.cpp
+new file mode 100644
+index 000000000..bd455bd53
+--- /dev/null
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangtype.cpp
+@@ -0,0 +1,83 @@
++// Copyright (C) 2026 The Qt Company Ltd.
++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++#include "clangtype.h"
++
++#include <QtCore/qdebug.h>
++
++using namespace Qt::StringLiterals;
++
++// Up until clang version 21, clang_getTypeSpelling() was used to retrieve type names,
++// which returned fully qualified names. In clang 22, clang_getTypeSpelling() was
++// changed to return the actual spelling, that is, no longer return fully qualified names
++// (from for example inner class contexts) unless they were spelled out.
++// clang_getFullyQualifiedName() was provided as a replacement, but that returns
++// template parameters of the class as well, that is, "std::list<int>::value_type"
++// instead of "std::list::value_type". Those they need to be removed for the
++// type entry lookup system to work. This is done by parseTypeName().
++// FIXME: Keep checking whether this can be replaced by a CXPrintingPolicy setting
++// in a later clang version.
++
++namespace clang {
++
++// Find the start of a template starting from the closing '>'
++static qsizetype findTemplateStart(QStringView sv, qsizetype pos)
++{
++ Q_ASSERT(pos > 0 && pos < sv.size() && sv.at(pos) == u'>');
++ int level = 1;
++ for (--pos; pos >= 0; --pos) {
++ switch (sv.at(pos).unicode()) {
++ case '>':
++ ++level;
++ break;
++ case '<':
++ if (--level == 0)
++ return pos;
++ break;
++ default:
++ break;
++ }
++ }
++ return -1;
++}
++
++std::optional<TypeName> parseTypeName(QString t)
++{
++ TypeName result;
++ // Skip over the trailing template parameters "list<T>::iterator<V>" ->
++ // "list<T>::iterator"
++ if (t.endsWith(u'>')) {
++ const auto pos = findTemplateStart(t, t.size() - 1);
++ if (pos == -1)
++ return std::nullopt;
++ result.templateParameters = t.sliced(pos, t.size() - pos);
++ t.truncate(pos);
++ }
++
++ // Remove class template parameters "list<T>::iterator" -> "list::iterator"
++ while (true) {
++ auto specEnd = t.lastIndexOf(">::"_L1);
++ if (specEnd == -1)
++ break;
++ const auto pos = findTemplateStart(t, specEnd);
++ if (pos == -1)
++ return std::nullopt;
++ t.remove(pos, specEnd + 1 - pos);
++ }
++ result.name = t;
++ return result;
++}
++
++QDebug operator<<(QDebug debug, const TypeName &ct)
++{
++ QDebugStateSaver saver(debug);
++ debug.nospace();
++ debug.noquote();
++ debug << "ClangTypeName(name=\"" << ct.name << '"';
++ if (!ct.templateParameters.isEmpty())
++ debug << ", templateParameters=\"" << ct.templateParameters << '"';
++ debug << ')';
++ return debug;
++}
++
++} // namespace clang
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangtype.h b/sources/shiboken6_generator/ApiExtractor/clangparser/clangtype.h
+new file mode 100644
+index 000000000..0ae970648
+--- /dev/null
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangtype.h
+@@ -0,0 +1,28 @@
++// Copyright (C) 2026 The Qt Company Ltd.
++// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++
++#ifndef CLANGTYPE_H
++#define CLANGTYPE_H
++
++#include <QtCore/qstring.h>
++
++#include <optional>
++
++QT_FORWARD_DECLARE_CLASS(QDebug)
++
++namespace clang {
++
++struct TypeName
++{
++ QString name;
++ QString templateParameters;
++};
++
++// Split a type name "std::list<int>::value_type<T>" into the canonical name
++// "std::list::value_type" and its template parameters "<T>"
++std::optional<TypeName> parseTypeName(QString t);
++
++QDebug operator<<(QDebug, const TypeName &ct);
++} // namespace clang
++
++#endif // CLANGTYPE_H
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangutils.cpp b/sources/shiboken6_generator/ApiExtractor/clangparser/clangutils.cpp
+index 384fd6815..24646db53 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/clangutils.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangutils.cpp
+@@ -10,6 +10,8 @@
+
+ #include <string_view>
+
++using namespace Qt::StringLiterals;
++
+ bool operator==(const CXCursor &c1, const CXCursor &c2) noexcept
+ {
+ return c1.kind == c2.kind
+@@ -137,11 +139,18 @@ CXType fullyResolveType(const CXType &type)
+ return resolveTypedef(resolveElaboratedType(type));
+ }
+
+-QString getTypeName(const CXType &type)
++QString getTypeName(const CXType &type, [[maybe_unused]] PrintingPolicy p)
+ {
++ // Behavioral change, clang_getTypeSpelling() may no longer return the qualified name in 22.1
++#if LLVM_VERSION >= 22
++ CXString qualName = clang_getFullyQualifiedName(type, p, 0);
++ QString result = QString::fromUtf8(clang_getCString(qualName));
++ clang_disposeString(qualName);
++#else
+ CXString typeSpelling = clang_getTypeSpelling(type);
+ const QString result = QString::fromUtf8(clang_getCString(typeSpelling));
+ clang_disposeString(typeSpelling);
++#endif
+ return result;
+ }
+
+@@ -157,9 +166,9 @@ bool hasScopeResolution(const CXType &type)
+ }
+
+ // Resolve elaborated types occurring with clang 16
+-QString getResolvedTypeName(const CXType &type)
++QString getResolvedTypeName(const CXType &type, PrintingPolicy p)
+ {
+- return getTypeName(resolveElaboratedType(type));
++ return getTypeName(resolveElaboratedType(type), p);
+ }
+
+ Diagnostic::Diagnostic(const QString &m, const CXCursor &c, CXDiagnosticSeverity s)
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/clangutils.h b/sources/shiboken6_generator/ApiExtractor/clangparser/clangutils.h
+index bb819e61f..866be9282 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/clangutils.h
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/clangutils.h
+@@ -4,7 +4,8 @@
+ #ifndef CLANGUTILS_H
+ #define CLANGUTILS_H
+
+-#include <clang-c/Index.h>
++#include "clang_typedefs.h"
++
+ #include <QtCore/qstring.h>
+ #include <QtCore/qstringlist.h>
+ #include <QtCore/qcompare.h>
+@@ -26,14 +27,10 @@ namespace clang {
+ QString getCursorKindName(CXCursorKind cursorKind);
+ QString getCursorSpelling(const CXCursor &cursor);
+ QString getCursorDisplayName(const CXCursor &cursor);
+-QString getTypeName(const CXType &type);
++QString getTypeName(const CXType &type, PrintingPolicy p);
+ bool hasScopeResolution(const CXType &type);
+ CXType fullyResolveType(const CXType &type);
+-QString getResolvedTypeName(const CXType &type);
+-inline QString getCursorTypeName(const CXCursor &cursor)
+- { return getTypeName(clang_getCursorType(cursor)); }
+-inline QString getCursorResultTypeName(const CXCursor &cursor)
+- { return getTypeName(clang_getCursorResultType(cursor)); }
++QString getResolvedTypeName(const CXType &type, PrintingPolicy p);
+
+ inline bool isCursorValid(const CXCursor &c)
+ {
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/compilersupport.cpp b/sources/shiboken6_generator/ApiExtractor/clangparser/compilersupport.cpp
+index 4b15214b5..223628cd0 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/compilersupport.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/compilersupport.cpp
+@@ -50,7 +50,7 @@ QVersionNumber libClangVersion()
+ return QVersionNumber(CINDEX_VERSION_MAJOR, CINDEX_VERSION_MINOR);
+ }
+
+-static const Triplet _hostTriplet = Triplet::fromHost();
++static const Triplet _hostTriplet = Triplet::fromHost(/* detectVersion */ false);
+ static Triplet _optionsTriplet = _hostTriplet;
+
+ const Triplet &optionsTriplet()
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/triplet.cpp b/sources/shiboken6_generator/ApiExtractor/clangparser/triplet.cpp
+index e077a6b03..ad1a74768 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/triplet.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/triplet.cpp
+@@ -112,7 +112,7 @@ static Platform hostPlatform()
+ static QVersionNumber hostPlatformVersion()
+ {
+ auto ov = QOperatingSystemVersion::current();
+- return ov.type() != QOperatingSystemVersionBase::Unknown ? ov.version() : QVersionNumber{};
++ return ov.type() != QOperatingSystemVersion::Unknown ? ov.version() : QVersionNumber{};
+ }
+
+ Triplet::Triplet() = default;
+@@ -314,15 +314,16 @@ std::optional<Triplet> Triplet::fromString(QStringView name)
+ return result;
+ }
+
+-Triplet Triplet::fromHost()
++Triplet Triplet::fromHost(bool detectVersion)
+ {
+ Triplet result;
+ result.setArchitecture(hostArchitecture());
+ result.setPlatform(hostPlatform());
+ result.setCompiler(hostCompiler());
+- const auto hv = hostPlatformVersion();
+- if (!hv.isNull())
+- result.setPlatformVersion(hv);
++ if (detectVersion) {
++ if (const auto hv = hostPlatformVersion(); !hv.isNull())
++ result.setPlatformVersion(hv);
++ }
+ return result;
+ }
+
+diff --git a/sources/shiboken6_generator/ApiExtractor/clangparser/triplet.h b/sources/shiboken6_generator/ApiExtractor/clangparser/triplet.h
+index 509768153..3f9c8ba06 100644
+--- a/sources/shiboken6_generator/ApiExtractor/clangparser/triplet.h
++++ b/sources/shiboken6_generator/ApiExtractor/clangparser/triplet.h
+@@ -70,7 +70,7 @@ public:
+ QByteArray toByteArray() const;
+ QString toString() const { return QLatin1StringView(toByteArray()); }
+
+- static Triplet fromHost();
++ static Triplet fromHost(bool detectVersion);
+ static std::optional<Triplet> fromString(QStringView name);
+
+ private:
+diff --git a/sources/shiboken6_generator/ApiExtractor/complextypeentry.h b/sources/shiboken6_generator/ApiExtractor/complextypeentry.h
+index 01d204ec5..778156214 100644
+--- a/sources/shiboken6_generator/ApiExtractor/complextypeentry.h
++++ b/sources/shiboken6_generator/ApiExtractor/complextypeentry.h
+@@ -120,8 +120,8 @@ public:
+ bool isGenericClass() const;
+ void setGenericClass(bool isGeneric);
+
+- bool deleteInMainThread() const;
+- void setDeleteInMainThread(bool d);
++ TypeSystem::DeletionMode deletionMode() const;
++ void setDeletionMode(TypeSystem::DeletionMode dm);
+
+ QString hashFunction() const;
+ void setHashFunction(const QString &hashFunction);
+diff --git a/sources/shiboken6_generator/ApiExtractor/messages.cpp b/sources/shiboken6_generator/ApiExtractor/messages.cpp
+index e619f1e83..fd04d5707 100644
+--- a/sources/shiboken6_generator/ApiExtractor/messages.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/messages.cpp
+@@ -1168,3 +1168,20 @@ QString msgSynthesizedFunction(const AbstractMetaFunctionCPtr &newFunction,
+ const QString why = "from: \""_L1 + oldFunction->classQualifiedSignature() + u'"';
+ return msgSynthesizedFunction(newFunction, why);
+ }
++
++QString msgOwnerThreadForNonQObject(const AbstractMetaClassCPtr &metaClass)
++{
++ return "shiboken: delete-in-owner-thread specified for non-QObject class \""_L1
++ + metaClass->name() + u'"';
++}
++
++QString msgRejectedTypes(const QStringList &rejectedTypes)
++{
++ QString result;
++ QTextStream str(&result);
++ str << "Rejected Types (" << rejectedTypes.size() << "):\n";
++ for (const auto &rejectedType : rejectedTypes)
++ str << " \"" << rejectedType << "\"\n";
++ str << '\n';
++ return result;
++}
+diff --git a/sources/shiboken6_generator/ApiExtractor/messages.h b/sources/shiboken6_generator/ApiExtractor/messages.h
+index db32f3828..d0680e368 100644
+--- a/sources/shiboken6_generator/ApiExtractor/messages.h
++++ b/sources/shiboken6_generator/ApiExtractor/messages.h
+@@ -297,4 +297,8 @@ QString msgSynthesizedFunction(const AbstractMetaFunctionCPtr &newFunction,
+ QString msgSynthesizedFunction(const AbstractMetaFunctionCPtr &newFunction,
+ const FunctionModelItem &oldFunction);
+
++QString msgOwnerThreadForNonQObject(const AbstractMetaClassCPtr &metaClass);
++
++QString msgRejectedTypes(const QStringList &rejectedTypes);
++
+ #endif // MESSAGES_H
+diff --git a/sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp b/sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp
+index bfccacbac..afa28fee5 100644
+--- a/sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/parser/codemodel.cpp
+@@ -28,27 +28,6 @@ static std::shared_ptr<T> findModelItem(const QList<std::shared_ptr<T> > &list,
+
+ // ---------------------------------------------------------------------------
+
+-CodeModel::CodeModel() : m_globalNamespace(new _NamespaceModelItem(this))
+-{
+-}
+-
+-CodeModel::~CodeModel() = default;
+-
+-NamespaceModelItem CodeModel::globalNamespace() const
+-{
+- return m_globalNamespace;
+-}
+-
+-void CodeModel::addFile(const FileModelItem &item)
+-{
+- m_files.append(item);
+-}
+-
+-FileModelItem CodeModel::findFile(QAnyStringView name) const
+-{
+- return findModelItem(m_files, name);
+-}
+-
+ static CodeModelItem findRecursion(const ScopeModelItem &scope,
+ const QStringList &qualifiedName, int segment = 0)
+ {
+@@ -102,44 +81,14 @@ QDebug operator<<(QDebug d, Access a)
+ }
+ return d;
+ }
+-
+-QDebug operator<<(QDebug d, const CodeModel *m)
+-{
+- QDebugStateSaver s(d);
+- d.noquote();
+- d.nospace();
+- d << "CodeModel(";
+- if (m) {
+- const NamespaceModelItem globalNamespaceP = m->globalNamespace();
+- if (globalNamespaceP)
+- globalNamespaceP->formatDebug(d);
+- } else {
+- d << '0';
+- }
+- d << ')';
+- return d;
+-}
+ #endif // !QT_NO_DEBUG_STREAM
+
+ // ---------------------------------------------------------------------------
+-_CodeModelItem::_CodeModelItem(CodeModel *model, int kind)
+- : m_model(model),
+- m_kind(kind),
+- m_startLine(0),
+- m_startColumn(0),
+- m_endLine(0),
+- m_endColumn(0)
++_CodeModelItem::_CodeModelItem(Kind kind) : m_kind(kind)
+ {
+ }
+
+-_CodeModelItem::_CodeModelItem(CodeModel *model, const QString &name, int kind)
+- : m_model(model),
+- m_kind(kind),
+- m_startLine(0),
+- m_startColumn(0),
+- m_endLine(0),
+- m_endColumn(0),
+- m_name(name)
++_CodeModelItem::_CodeModelItem(const QString &name, Kind kind) : m_name(name), m_kind(kind)
+ {
+ }
+
+@@ -195,11 +144,6 @@ void _CodeModelItem::setFileName(const QString &fileName)
+ m_fileName = fileName;
+ }
+
+-FileModelItem _CodeModelItem::file() const
+-{
+- return model()->findFile(fileName());
+-}
+-
+ void _CodeModelItem::getStartPosition(int *line, int *column) const
+ {
+ *line = m_startLine;
+@@ -239,16 +183,6 @@ void _CodeModelItem::setEnclosingScope(const _ScopeModelItem *s)
+ m_enclosingScope = s;
+ }
+
+-_ScopeModelItem::_ScopeModelItem(CodeModel *model, int kind)
+- : _CodeModelItem(model, kind)
+-{
+-}
+-
+-_ScopeModelItem::_ScopeModelItem(CodeModel *model, const QString &name, int kind)
+- : _CodeModelItem(model, name, kind)
+-{
+-}
+-
+ #ifndef QT_NO_DEBUG_STREAM
+ void _CodeModelItem::formatKind(QDebug &d, int k)
+ {
+@@ -345,9 +279,9 @@ TemplateParameterList _ClassModelItem::templateParameters() const
+ return m_templateParameters;
+ }
+
+-void _ClassModelItem::setTemplateParameters(const TemplateParameterList &templateParameters)
++void _ClassModelItem::addTemplateParameter(const TemplateParameterModelItem &templateParameter)
+ {
+- m_templateParameters = templateParameters;
++ m_templateParameters.append(templateParameter);
+ }
+
+ bool _ClassModelItem::extendsClass(const QString &name) const
+@@ -358,13 +292,11 @@ bool _ClassModelItem::extendsClass(const QString &name) const
+ });
+ }
+
+-_ClassModelItem::_ClassModelItem(CodeModel *model, int kind)
+- : _ScopeModelItem(model, kind)
++_ClassModelItem::_ClassModelItem() : _ScopeModelItem(_CodeModelItem::Kind_Class)
+ {
+ }
+
+-_ClassModelItem::_ClassModelItem(CodeModel *model, const QString &name, int kind)
+- : _ScopeModelItem(model, name, kind)
++_ClassModelItem::_ClassModelItem(const QString &name) : _ScopeModelItem(name, _CodeModelItem::Kind_Class)
+ {
+ }
+
+@@ -754,13 +686,16 @@ FunctionList _ScopeModelItem::findFunctions(QAnyStringView name) const
+ }
+
+ // ---------------------------------------------------------------------------
+-_NamespaceModelItem::_NamespaceModelItem(CodeModel *model, int kind)
+- : _ScopeModelItem(model, kind)
++_NamespaceModelItem::_NamespaceModelItem() : _ScopeModelItem(_CodeModelItem::Kind_Namespace)
++{
++}
++
++_NamespaceModelItem::_NamespaceModelItem(const QString &name) :
++ _ScopeModelItem(name, _CodeModelItem::Kind_Namespace)
+ {
+ }
+
+-_NamespaceModelItem::_NamespaceModelItem(CodeModel *model, const QString &name, int kind)
+- : _ScopeModelItem(model, name, kind)
++_NamespaceModelItem::_NamespaceModelItem(Kind kind) : _ScopeModelItem(kind)
+ {
+ }
+
+@@ -777,6 +712,10 @@ NamespaceModelItem _NamespaceModelItem::findNamespace(QAnyStringView name) const
+ return findModelItem(m_namespaces, name);
+ }
+
++_FileModelItem::_FileModelItem() : _NamespaceModelItem(_CodeModelItem::Kind_File)
++{
++}
++
+ _FileModelItem::~_FileModelItem() = default;
+
+ void _NamespaceModelItem::appendNamespace(const _NamespaceModelItem &other)
+@@ -804,13 +743,12 @@ void _NamespaceModelItem::formatDebug(QDebug &d) const
+ #endif // !QT_NO_DEBUG_STREAM
+
+ // ---------------------------------------------------------------------------
+-_ArgumentModelItem::_ArgumentModelItem(CodeModel *model, int kind)
+- : _CodeModelItem(model, kind)
++_ArgumentModelItem::_ArgumentModelItem() : _CodeModelItem(_CodeModelItem::Kind_Argument)
+ {
+ }
+
+-_ArgumentModelItem::_ArgumentModelItem(CodeModel *model, const QString &name, int kind)
+- : _CodeModelItem(model, name, kind)
++_ArgumentModelItem::_ArgumentModelItem(const QString &name)
++ : _CodeModelItem(name, _CodeModelItem::Kind_Argument)
+ {
+ }
+
+@@ -894,13 +832,13 @@ bool _FunctionModelItem::isSimilar(const FunctionModelItem &other) const
+ return true;
+ }
+
+-_FunctionModelItem::_FunctionModelItem(CodeModel *model, int kind)
+- : _MemberModelItem(model, kind), m_flags(0)
++_FunctionModelItem::_FunctionModelItem()
++ : _MemberModelItem(_CodeModelItem::Kind_Function), m_flags(0)
+ {
+ }
+
+-_FunctionModelItem::_FunctionModelItem(CodeModel *model, const QString &name, int kind)
+- : _MemberModelItem(model, name, kind), m_flags(0)
++_FunctionModelItem::_FunctionModelItem(const QString &name)
++ : _MemberModelItem(name, _CodeModelItem::Kind_Function), m_flags(0)
+ {
+ }
+
+@@ -1054,7 +992,8 @@ QString _FunctionModelItem::classQualifiedSignature() const
+ QTextStream str(&result);
+ if (m_attributes.testFlag(FunctionAttribute::Virtual))
+ str << "virtual ";
+- str << type().toString() << ' ';
++ if (m_functionType != CodeModel::FunctionType::Constructor)
++ str << type().toString() << ' ';
+ const auto &scopeList = scope();
+ for (const auto &scope : scopeList)
+ str << scope << "::";
+@@ -1257,17 +1196,29 @@ void _FunctionModelItem::formatDebug(QDebug &d) const
+ }
+ #endif // !QT_NO_DEBUG_STREAM
+
++_VariableModelItem::_VariableModelItem() : _MemberModelItem(_CodeModelItem::Kind_Variable)
++{
++}
++
++_VariableModelItem::_VariableModelItem(const QString &name)
++ : _MemberModelItem(name, _CodeModelItem::Kind_Variable)
++{
++}
++
++_VariableModelItem::~_VariableModelItem() = default;
++
+ // ---------------------------------------------------------------------------
+-_TypeDefModelItem::_TypeDefModelItem(CodeModel *model, int kind)
+- : _CodeModelItem(model, kind)
++_TypeDefModelItem::_TypeDefModelItem() : _CodeModelItem(_CodeModelItem::Kind_TypeDef)
+ {
+ }
+
+-_TypeDefModelItem::_TypeDefModelItem(CodeModel *model, const QString &name, int kind)
+- : _CodeModelItem(model, name, kind)
++_TypeDefModelItem::_TypeDefModelItem(const QString &name)
++ : _CodeModelItem(name, _CodeModelItem::Kind_TypeDef)
+ {
+ }
+
++_TypeDefModelItem::~_TypeDefModelItem() = default;
++
+ TypeInfo _TypeDefModelItem::type() const
+ {
+ return m_type;
+@@ -1303,11 +1254,17 @@ void _TypeDefModelItem::formatDebug(QDebug &d) const
+
+ // ---------------------------------------------------------------------------
+
+-_TemplateTypeAliasModelItem::_TemplateTypeAliasModelItem(CodeModel *model, int kind)
+- : _CodeModelItem(model, kind) {}
++_TemplateTypeAliasModelItem::_TemplateTypeAliasModelItem()
++ : _CodeModelItem(_CodeModelItem::Kind_TemplateTypeAlias)
++{
++}
+
+-_TemplateTypeAliasModelItem::_TemplateTypeAliasModelItem(CodeModel *model, const QString &name, int kind)
+- : _CodeModelItem(model, name, kind) {}
++_TemplateTypeAliasModelItem::_TemplateTypeAliasModelItem(const QString &name)
++ : _CodeModelItem(name, _CodeModelItem::Kind_TemplateTypeAlias)
++{
++}
++
++_TemplateTypeAliasModelItem::~_TemplateTypeAliasModelItem() = default;
+
+ TemplateParameterList _TemplateTypeAliasModelItem::templateParameters() const
+ {
+@@ -1344,13 +1301,12 @@ void _TemplateTypeAliasModelItem::formatDebug(QDebug &d) const
+ #endif // !QT_NO_DEBUG_STREAM
+
+ // ---------------------------------------------------------------------------
+-_EnumModelItem::_EnumModelItem(CodeModel *model, const QString &name, int kind)
+- : _CodeModelItem(model, name, kind)
++_EnumModelItem::_EnumModelItem(const QString &name)
++ : _CodeModelItem(name, _CodeModelItem::Kind_Enum)
+ {
+ }
+
+-_EnumModelItem::_EnumModelItem(CodeModel *model, int kind)
+- : _CodeModelItem(model, kind)
++_EnumModelItem::_EnumModelItem() : _CodeModelItem(_CodeModelItem::Kind_Enum)
+ {
+ }
+
+@@ -1440,13 +1396,13 @@ void _EnumModelItem::formatDebug(QDebug &d) const
+ // ---------------------------------------------------------------------------
+ _EnumeratorModelItem::~_EnumeratorModelItem() = default;
+
+-_EnumeratorModelItem::_EnumeratorModelItem(CodeModel *model, int kind)
+- : _CodeModelItem(model, kind)
++_EnumeratorModelItem::_EnumeratorModelItem()
++ : _CodeModelItem(_CodeModelItem::Kind_Enumerator)
+ {
+ }
+
+-_EnumeratorModelItem::_EnumeratorModelItem(CodeModel *model, const QString &name, int kind)
+- : _CodeModelItem(model, name, kind)
++_EnumeratorModelItem::_EnumeratorModelItem(const QString &name)
++ : _CodeModelItem(name, _CodeModelItem::Kind_Enumerator)
+ {
+ }
+
+@@ -1483,14 +1439,13 @@ void _EnumeratorModelItem::formatDebug(QDebug &d) const
+ // ---------------------------------------------------------------------------
+ _TemplateParameterModelItem::~_TemplateParameterModelItem() = default;
+
+-_TemplateParameterModelItem::_TemplateParameterModelItem(CodeModel *model, int kind)
+- : _CodeModelItem(model, kind)
++_TemplateParameterModelItem::_TemplateParameterModelItem()
++ : _CodeModelItem(_CodeModelItem::Kind_TemplateParameter)
+ {
+ }
+
+-_TemplateParameterModelItem::_TemplateParameterModelItem(CodeModel *model,
+- const QString &name, int kind)
+- : _CodeModelItem(model, name, kind)
++_TemplateParameterModelItem::_TemplateParameterModelItem(const QString &name)
++ : _CodeModelItem(name, _CodeModelItem::Kind_TemplateParameter)
+ {
+ }
+
+@@ -1547,6 +1502,11 @@ void _MemberModelItem::setAccessPolicy(Access accessPolicy)
+ m_accessPolicy = accessPolicy;
+ }
+
++void _MemberModelItem::addTemplateParameter(const TemplateParameterModelItem &templateParameter)
++{
++ m_templateParameters.append(templateParameter);
++}
++
+ bool _MemberModelItem::isStatic() const
+ {
+ return m_isStatic;
+@@ -1557,13 +1517,13 @@ void _MemberModelItem::setStatic(bool isStatic)
+ m_isStatic = isStatic;
+ }
+
+-_MemberModelItem::_MemberModelItem(CodeModel *model, int kind)
+- : _CodeModelItem(model, kind), m_flags(0)
++_MemberModelItem::_MemberModelItem(Kind kind)
++ : _CodeModelItem(kind), m_flags(0)
+ {
+ }
+
+-_MemberModelItem::_MemberModelItem(CodeModel *model, const QString &name, int kind)
+- : _CodeModelItem(model, name, kind), m_flags(0)
++_MemberModelItem::_MemberModelItem(const QString &name, Kind kind)
++ : _CodeModelItem(name, kind), m_flags(0)
+ {
+ }
+
+diff --git a/sources/shiboken6_generator/ApiExtractor/parser/codemodel.h b/sources/shiboken6_generator/ApiExtractor/parser/codemodel.h
+index 7ff0a88e2..1641ad8f2 100644
+--- a/sources/shiboken6_generator/ApiExtractor/parser/codemodel.h
++++ b/sources/shiboken6_generator/ApiExtractor/parser/codemodel.h
+@@ -22,9 +22,6 @@
+
+ QT_FORWARD_DECLARE_CLASS(QDebug)
+
+-#define DECLARE_MODEL_NODE(k) \
+- enum { __node_kind = Kind_##k };
+-
+ class SourceLocation;
+
+ class CodeModel
+@@ -67,26 +64,14 @@ public:
+ };
+ Q_ENUM(ClassType)
+
+- CodeModel();
+- virtual ~CodeModel();
+-
+- FileList files() const { return m_files; }
+- NamespaceModelItem globalNamespace() const;
+-
+- void addFile(const FileModelItem &item);
+- FileModelItem findFile(QAnyStringView name) const;
++ CodeModel() = delete;
+
+ static CodeModelItem findItem(const QStringList &qualifiedName,
+ const ScopeModelItem &scope);
+-
+-private:
+- FileList m_files;
+- NamespaceModelItem m_globalNamespace;
+ };
+
+ #ifndef QT_NO_DEBUG_STREAM
+ QDebug operator<<(QDebug d, Access a);
+-QDebug operator<<(QDebug d, const CodeModel *m);
+ #endif
+
+ class _CodeModelItem
+@@ -131,8 +116,6 @@ public:
+ QString fileName() const;
+ void setFileName(const QString &fileName);
+
+- FileModelItem file() const;
+-
+ void getStartPosition(int *line, int *column) const;
+ int startLine() const { return m_startLine; }
+ void setStartPosition(int line, int column);
+@@ -142,8 +125,6 @@ public:
+
+ SourceLocation sourceLocation() const;
+
+- inline CodeModel *model() const { return m_model; }
+-
+ const _ScopeModelItem *enclosingScope() const;
+ void setEnclosingScope(const _ScopeModelItem *s);
+
+@@ -153,20 +134,19 @@ public:
+ #endif
+
+ protected:
+- explicit _CodeModelItem(CodeModel *model, int kind);
+- explicit _CodeModelItem(CodeModel *model, const QString &name, int kind);
++ explicit _CodeModelItem(Kind kind);
++ explicit _CodeModelItem(const QString &name, Kind kind);
+
+ private:
+- CodeModel *m_model;
+ const _ScopeModelItem *m_enclosingScope = nullptr;
+- int m_kind;
+- int m_startLine;
+- int m_startColumn;
+- int m_endLine;
+- int m_endColumn;
+ QString m_name;
+ QString m_fileName;
+ QStringList m_scope;
++ int m_startLine = 0;
++ int m_startColumn = 0;
++ int m_endLine = 0;
++ int m_endColumn = 0;
++ Kind m_kind;
+ };
+
+ #ifndef QT_NO_DEBUG_STREAM
+@@ -177,7 +157,6 @@ class _ScopeModelItem: public _CodeModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_ScopeModelItem)
+- DECLARE_MODEL_NODE(Scope)
+
+ ~_ScopeModelItem() override;
+
+@@ -222,9 +201,7 @@ public:
+ #endif
+
+ protected:
+- explicit _ScopeModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _ScopeModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
++ using _CodeModelItem::_CodeModelItem;
+
+ void appendScope(const _ScopeModelItem &other);
+
+@@ -254,7 +231,6 @@ class _ClassModelItem: public _ScopeModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_ClassModelItem)
+- DECLARE_MODEL_NODE(Class)
+
+ struct BaseClass
+ {
+@@ -270,9 +246,8 @@ public:
+ Access access = Access::Public;
+ };
+
+- explicit _ClassModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _ClassModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
++ _ClassModelItem();
++ explicit _ClassModelItem(const QString &name);
+ ~_ClassModelItem() override;
+
+ const QList<BaseClass> &baseClasses() const { return m_baseClasses; }
+@@ -284,7 +259,7 @@ public:
+ void addBaseClass(const BaseClass &b) { m_baseClasses.append(b); }
+
+ TemplateParameterList templateParameters() const;
+- void setTemplateParameters(const TemplateParameterList &templateParameters);
++ void addTemplateParameter(const TemplateParameterModelItem &templateParameter);
+
+ bool extendsClass(const QString &name) const;
+
+@@ -318,11 +293,9 @@ class _NamespaceModelItem: public _ScopeModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_NamespaceModelItem)
+- DECLARE_MODEL_NODE(Namespace)
+
+- explicit _NamespaceModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _NamespaceModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
++ _NamespaceModelItem();
++ explicit _NamespaceModelItem(const QString &name);
+ ~_NamespaceModelItem() override;
+
+ const NamespaceList &namespaces() const { return m_namespaces; }
+@@ -340,6 +313,9 @@ public:
+ void formatDebug(QDebug &d) const override;
+ #endif
+
++protected:
++ explicit _NamespaceModelItem(Kind kind);
++
+ private:
+ NamespaceList m_namespaces;
+ NamespaceType m_type = NamespaceType::Default;
+@@ -349,10 +325,8 @@ class _FileModelItem: public _NamespaceModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_FileModelItem)
+- DECLARE_MODEL_NODE(File)
+-
+- using _NamespaceModelItem::_NamespaceModelItem;
+
++ _FileModelItem();
+ ~_FileModelItem() override;
+ };
+
+@@ -360,11 +334,9 @@ class _ArgumentModelItem: public _CodeModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_ArgumentModelItem)
+- DECLARE_MODEL_NODE(Argument)
+
+- explicit _ArgumentModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _ArgumentModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
++ _ArgumentModelItem();
++ explicit _ArgumentModelItem(const QString &name);
+ ~_ArgumentModelItem() override;
+
+ TypeInfo type() const;
+@@ -397,11 +369,7 @@ class _MemberModelItem: public _CodeModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_MemberModelItem)
+- DECLARE_MODEL_NODE(Member)
+
+- explicit _MemberModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _MemberModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
+ ~_MemberModelItem() override;
+
+ bool isConstant() const;
+@@ -432,7 +400,7 @@ public:
+ void setAccessPolicy(Access accessPolicy);
+
+ TemplateParameterList templateParameters() const { return m_templateParameters; }
+- void setTemplateParameters(const TemplateParameterList &templateParameters) { m_templateParameters = templateParameters; }
++ void addTemplateParameter(const TemplateParameterModelItem &templateParameter);
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+@@ -441,6 +409,10 @@ public:
+ void formatDebug(QDebug &d) const override;
+ #endif
+
++protected:
++ explicit _MemberModelItem(Kind kind);
++ explicit _MemberModelItem(const QString &name, Kind kind);
++
+ private:
+ TemplateParameterList m_templateParameters;
+ TypeInfo m_type;
+@@ -465,12 +437,10 @@ class _FunctionModelItem: public _MemberModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_FunctionModelItem)
+- DECLARE_MODEL_NODE(Function)
+
+- explicit _FunctionModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _FunctionModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
+- ~_FunctionModelItem();
++ _FunctionModelItem();
++ explicit _FunctionModelItem(const QString &name);
++ ~_FunctionModelItem() override;
+
+ ArgumentList arguments() const;
+
+@@ -551,19 +521,21 @@ private:
+ class _VariableModelItem: public _MemberModelItem
+ {
+ public:
+- DECLARE_MODEL_NODE(Variable)
++ Q_DISABLE_COPY_MOVE(_VariableModelItem)
+
+- using _MemberModelItem::_MemberModelItem;
++ _VariableModelItem();
++ explicit _VariableModelItem(const QString &name);
++ ~_VariableModelItem() override;
+ };
+
+ class _TypeDefModelItem: public _CodeModelItem
+ {
+ public:
+- DECLARE_MODEL_NODE(TypeDef)
++ Q_DISABLE_COPY_MOVE(_TypeDefModelItem)
+
+- explicit _TypeDefModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _TypeDefModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
++ _TypeDefModelItem();
++ explicit _TypeDefModelItem(const QString &name);
++ ~_TypeDefModelItem() override;
+
+ TypeInfo type() const;
+ void setType(const TypeInfo &type);
+@@ -578,18 +550,18 @@ public:
+ #endif
+
+ private:
+- Access m_accessPolicy = Access::Public;
+ TypeInfo m_type;
++ Access m_accessPolicy = Access::Public;
+ };
+
+ class _TemplateTypeAliasModelItem : public _CodeModelItem
+ {
+ public:
+- DECLARE_MODEL_NODE(TemplateTypeAlias)
++ Q_DISABLE_COPY_MOVE(_TemplateTypeAliasModelItem)
+
+- explicit _TemplateTypeAliasModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _TemplateTypeAliasModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
++ _TemplateTypeAliasModelItem();
++ explicit _TemplateTypeAliasModelItem(const QString &name);
++ ~_TemplateTypeAliasModelItem() override;
+
+ TemplateParameterList templateParameters() const;
+ void addTemplateParameter(const TemplateParameterModelItem &templateParameter);
+@@ -610,10 +582,9 @@ class _EnumModelItem: public _CodeModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_EnumModelItem)
+- DECLARE_MODEL_NODE(Enum)
+
+- explicit _EnumModelItem(CodeModel *model, const QString &name, int kind = __node_kind);
+- explicit _EnumModelItem(CodeModel *model, int kind = __node_kind);
++ explicit _EnumModelItem(const QString &name);
++ _EnumModelItem();
+ ~_EnumModelItem() override;
+
+ Access accessPolicy() const;
+@@ -643,9 +614,9 @@ public:
+
+ private:
+ QString m_underlyingType;
+- Access m_accessPolicy = Access::Public;
+ EnumeratorList m_enumerators;
+ EnumKind m_enumKind = CEnum;
++ Access m_accessPolicy = Access::Public;
+ bool m_deprecated = false;
+ bool m_signed = true;
+ };
+@@ -654,11 +625,9 @@ class _EnumeratorModelItem: public _CodeModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_EnumeratorModelItem)
+- DECLARE_MODEL_NODE(Enumerator)
+
+- explicit _EnumeratorModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _EnumeratorModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
++ _EnumeratorModelItem();
++ explicit _EnumeratorModelItem(const QString &name);
+ ~_EnumeratorModelItem() override;
+
+ QString stringValue() const;
+@@ -684,11 +653,9 @@ class _TemplateParameterModelItem: public _CodeModelItem
+ {
+ public:
+ Q_DISABLE_COPY_MOVE(_TemplateParameterModelItem)
+- DECLARE_MODEL_NODE(TemplateParameter)
+
+- explicit _TemplateParameterModelItem(CodeModel *model, int kind = __node_kind);
+- explicit _TemplateParameterModelItem(CodeModel *model, const QString &name,
+- int kind = __node_kind);
++ _TemplateParameterModelItem();
++ explicit _TemplateParameterModelItem(const QString &name);
+ ~_TemplateParameterModelItem() override;
+
+ TypeInfo type() const;
+diff --git a/sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h b/sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h
+index 272140ae3..ae49b0e7c 100644
+--- a/sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h
++++ b/sources/shiboken6_generator/ApiExtractor/parser/codemodel_enums.h
+@@ -59,13 +59,14 @@ enum class FunctionAttribute : std::uint8_t {
+ Q_DECLARE_FLAGS(FunctionAttributes, FunctionAttribute)
+ Q_DECLARE_OPERATORS_FOR_FLAGS(FunctionAttributes)
+
+-// C++ type category for TypeInfo, reflecting clang's CXTypeKind
++// C++ type category for TypeInfo, roughly reflecting clang's CXTypeKind
+ enum class TypeCategory : unsigned char {
+ Other,
+ Builtin,
+ Enum,
+ Pointer,
+ Function,
++ FunctionPointer, // not present in clang
+ Void
+ };
+
+diff --git a/sources/shiboken6_generator/ApiExtractor/parser/typeinfo.cpp b/sources/shiboken6_generator/ApiExtractor/parser/typeinfo.cpp
+index c530cafea..7bd0223db 100644
+--- a/sources/shiboken6_generator/ApiExtractor/parser/typeinfo.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/parser/typeinfo.cpp
+@@ -41,8 +41,7 @@ public:
+ struct {
+ uint m_constant: 1;
+ uint m_volatile: 1;
+- uint m_functionPointer: 1;
+- uint m_padding: 29;
++ uint m_padding: 30;
+ };
+ };
+
+@@ -223,13 +222,7 @@ void TypeInfo::addIndirection(Indirection i)
+
+ bool TypeInfo::isFunctionPointer() const
+ {
+- return d->m_functionPointer;
+-}
+-
+-void TypeInfo::setFunctionPointer(bool is)
+-{
+- if (d->m_functionPointer != is)
+- d->m_functionPointer = is;
++ return d->m_category == TypeCategory::FunctionPointer;
+ }
+
+ const QStringList &TypeInfo::arrayElements() const
+@@ -426,8 +419,11 @@ QString TypeInfo::toString() const
+ break;
+ }
+
+- if (isFunctionPointer()) {
+- tmp += u" (*)("_s;
++ if (d->m_category == TypeCategory::Function || d->m_category == TypeCategory::FunctionPointer) {
++ tmp += u' ';
++ if (d->m_category == TypeCategory::FunctionPointer)
++ tmp += "(*)"_L1;
++ tmp += u'(';
+ for (qsizetype i = 0; i < d->m_arguments.size(); ++i) {
+ if (i != 0)
+ tmp += u", "_s;
+@@ -461,7 +457,7 @@ bool TypeInfoData::equals(const TypeInfoData &other) const
+ return flags == other.flags
+ && m_qualifiedName == other.m_qualifiedName
+ && m_category == other.m_category
+- && (!m_functionPointer || m_arguments == other.m_arguments)
++ && m_arguments == other.m_arguments
+ && m_instantiations == other.m_instantiations;
+ }
+
+@@ -602,8 +598,14 @@ void TypeInfo::formatDebug(QDebug &debug) const
+ debug << ", [pointer]";
+ break;
+ case TypeCategory::Function:
+- debug << ", [function";
++ debug << ", [function]";
++ break;
++ case TypeCategory::FunctionPointer:
++ debug << ", [function-ptr]";
+ break;
++ default:
++ break;
++
+ }
+ if (!d->m_indirections.isEmpty()) {
+ debug << ", indirections=";
+@@ -625,8 +627,12 @@ void TypeInfo::formatDebug(QDebug &debug) const
+ formatSequence(debug, d->m_instantiations.begin(), d->m_instantiations.end());
+ debug << '>';
+ }
+- if (d->m_functionPointer) {
+- debug << ", function ptr(";
++
++ if (d->m_category == TypeCategory::Function || d->m_category == TypeCategory::FunctionPointer) {
++ debug << ", function";
++ if (d->m_category == TypeCategory::FunctionPointer)
++ debug << "_ptr";
++ debug << '(';
+ formatSequence(debug, d->m_arguments.begin(), d->m_arguments.end());
+ debug << ')';
+ }
+diff --git a/sources/shiboken6_generator/ApiExtractor/parser/typeinfo.h b/sources/shiboken6_generator/ApiExtractor/parser/typeinfo.h
+index 092fbb724..43c9947d9 100644
+--- a/sources/shiboken6_generator/ApiExtractor/parser/typeinfo.h
++++ b/sources/shiboken6_generator/ApiExtractor/parser/typeinfo.h
+@@ -71,7 +71,6 @@ public:
+ void setIndirections(int indirections);
+
+ bool isFunctionPointer() const;
+- void setFunctionPointer(bool is);
+
+ const QStringList &arrayElements() const;
+ void setArrayElements(const QStringList &arrayElements);
+diff --git a/sources/shiboken6_generator/ApiExtractor/typesystem.cpp b/sources/shiboken6_generator/ApiExtractor/typesystem.cpp
+index c48fc3ac6..dfb8fde0a 100644
+--- a/sources/shiboken6_generator/ApiExtractor/typesystem.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/typesystem.cpp
+@@ -1511,8 +1511,7 @@ public:
+ ConfigurableTypeEntryPrivate(entryName, t, vr, parent),
+ m_qualifiedCppName(buildName(entryName, parent)),
+ m_polymorphicBase(false),
+- m_genericClass(false),
+- m_deleteInMainThread(false)
++ m_genericClass(false)
+ {
+ }
+
+@@ -1530,9 +1529,10 @@ public:
+ QString m_qualifiedCppName;
+ QString m_docFile;
+
++ TypeSystem::DeletionMode m_deletionMode = TypeSystem::DeletionMode::Default;
++
+ uint m_polymorphicBase : 1;
+ uint m_genericClass : 1;
+- uint m_deleteInMainThread : 1;
+
+ QString m_polymorphicIdValue;
+ QString m_polymorphicNameFunction;
+@@ -1832,16 +1832,16 @@ void ComplexTypeEntry::setGenericClass(bool isGeneric)
+ d->m_genericClass = isGeneric;
+ }
+
+-bool ComplexTypeEntry::deleteInMainThread() const
++TypeSystem::DeletionMode ComplexTypeEntry::deletionMode() const
+ {
+ S_D(const ComplexTypeEntry);
+- return d->m_deleteInMainThread;
++ return d->m_deletionMode;
+ }
+
+-void ComplexTypeEntry::setDeleteInMainThread(bool dmt)
++void ComplexTypeEntry::setDeletionMode(TypeSystem::DeletionMode dm)
+ {
+ S_D(ComplexTypeEntry);
+- d->m_deleteInMainThread = dmt;
++ d->m_deletionMode = dm;
+ }
+
+ QString ComplexTypeEntry::hashFunction() const
+@@ -2715,7 +2715,8 @@ void ComplexTypeEntry::formatDebug(QDebug &debug) const
+ TypeEntry::formatDebug(debug);
+ FORMAT_BOOL("polymorphicBase", d->m_polymorphicBase)
+ FORMAT_BOOL("genericClass", d->m_genericClass)
+- FORMAT_BOOL("deleteInMainThread", d->m_deleteInMainThread)
++ if (d->m_deletionMode != TypeSystem::DeletionMode::Default)
++ debug << ", deletionMode=" << unsigned(d->m_deletionMode);
+ if (d->m_typeFlags != 0)
+ debug << ", typeFlags=" << d->m_typeFlags;
+ debug << ", except=" << int(d->m_exceptionHandling)
+diff --git a/sources/shiboken6_generator/ApiExtractor/typesystem_enums.h b/sources/shiboken6_generator/ApiExtractor/typesystem_enums.h
+index 4237e1593..94590d47e 100644
+--- a/sources/shiboken6_generator/ApiExtractor/typesystem_enums.h
++++ b/sources/shiboken6_generator/ApiExtractor/typesystem_enums.h
+@@ -42,6 +42,12 @@ enum CodeSnipPosition : std::uint8_t {
+ CodeSnipPositionAny
+ };
+
++enum class DeletionMode : std::uint8_t {
++ Default,
++ DeleteInMainThread, // libshiboken
++ DeleteInQObjectOwnerThread, // libpyside for QObjects
++};
++
+ enum DocModificationMode : std::uint8_t {
+ DocModificationAppend,
+ DocModificationPrepend,
+diff --git a/sources/shiboken6_generator/ApiExtractor/typesystemparser.cpp b/sources/shiboken6_generator/ApiExtractor/typesystemparser.cpp
+index 96b5e84a1..aab0c50a3 100644
+--- a/sources/shiboken6_generator/ApiExtractor/typesystemparser.cpp
++++ b/sources/shiboken6_generator/ApiExtractor/typesystemparser.cpp
+@@ -62,6 +62,7 @@ constexpr auto sinceAttribute = "since"_L1;
+ constexpr auto untilAttribute = "until"_L1;
+ constexpr auto defaultSuperclassAttribute = "default-superclass"_L1;
+ constexpr auto deleteInMainThreadAttribute = "delete-in-main-thread"_L1;
++constexpr auto deleteInOwnerThreadAttribute = "delete-in-owner-thread"_L1;
+ constexpr auto deprecatedAttribute = "deprecated"_L1;
+ constexpr auto disableWrapperAttribute = "disable-wrapper"_L1;
+ constexpr auto docFileAttribute = "doc-file"_L1;
+@@ -1929,7 +1930,10 @@ bool TypeSystemParser::applyComplexTypeAttributes(const ConditionalStreamReader
+ ctype->setTypeFlags(ctype->typeFlags() | ComplexTypeEntry::DisableWrapper);
+ } else if (name == deleteInMainThreadAttribute) {
+ if (convertBoolean(attributes->takeAt(i).value(), deleteInMainThreadAttribute, false))
+- ctype->setDeleteInMainThread(true);
++ ctype->setDeletionMode(TypeSystem::DeletionMode::DeleteInMainThread);
++ } else if (name == deleteInOwnerThreadAttribute) {
++ if (convertBoolean(attributes->takeAt(i).value(), deleteInOwnerThreadAttribute, false))
++ ctype->setDeletionMode(TypeSystem::DeletionMode::DeleteInQObjectOwnerThread);
+ } else if (name == qtMetaObjectFunctionsAttribute) {
+ if (!convertBoolean(attributes->takeAt(i).value(),
+ qtMetaObjectFunctionsAttribute, true)) {
+diff --git a/sources/shiboken6_generator/cmake/ShibokenGeneratorSetup.cmake b/sources/shiboken6_generator/cmake/ShibokenGeneratorSetup.cmake
+index 137824d15..7b7c46d6b 100644
+--- a/sources/shiboken6_generator/cmake/ShibokenGeneratorSetup.cmake
++++ b/sources/shiboken6_generator/cmake/ShibokenGeneratorSetup.cmake
+@@ -36,8 +36,11 @@ compute_config_py_values(shiboken6_VERSION)
+
+ shiboken_internal_set_python_site_packages()
+
++string(REGEX REPLACE "\\.[0-9]+\\.[0-9]+$" "" LLVM_VERSION "${LLVM_PACKAGE_VERSION}")
++
+ set_cmake_cxx_flags()
+-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D QT_NO_CAST_FROM_ASCII -D QT_NO_CAST_TO_ASCII")
++set(CMAKE_CXX_FLAGS
++ "${CMAKE_CXX_FLAGS} -D QT_NO_CAST_FROM_ASCII -D QT_NO_CAST_TO_ASCII -D LLVM_VERSION=${LLVM_VERSION}")
+
+ # Force usage of the C++17 standard
+ set(CMAKE_CXX_STANDARD 17)
+diff --git a/sources/shiboken6_generator/generator/qtdoc/qtdocgenerator.cpp b/sources/shiboken6_generator/generator/qtdoc/qtdocgenerator.cpp
+index dd9bec10a..2af321eee 100644
+--- a/sources/shiboken6_generator/generator/qtdoc/qtdocgenerator.cpp
++++ b/sources/shiboken6_generator/generator/qtdoc/qtdocgenerator.cpp
+@@ -889,6 +889,13 @@ bool QtDocGenerator::writeInjectDocumentation(TextStream &s,
+ return didSomething;
+ }
+
++// Reference with a custom name
++static QString inline toRef(const QString &fullName, const QString &displayName)
++{
++ return ":class:`"_L1 + displayName + u'<' + fullName + ">`"_L1;
++}
++
++// Standard reference using unqualified class name
+ static QString inline toRef(const QString &t)
+ {
+ return ":class:`~"_L1 + t + u'`';
+@@ -972,6 +979,18 @@ QString QtDocGenerator::translateToPythonType(const AbstractMetaType &type,
+ return strType;
+ }
+
++ if (type.typeUsagePattern() == AbstractMetaType::SmartPointerPattern) {
++ auto ste = std::static_pointer_cast<const SmartPointerTypeEntry>(type.typeEntry());
++ const auto &instantiation = type.instantiations().constFirst();
++ auto instantiationTe = instantiation.typeEntry();
++ if (auto instantiationO = api().findSmartPointerInstantiation(ste, instantiation.typeEntry())) {
++ const QString &name = instantiationO->specialized->name();
++ return createRef
++ ? toRef(instantiation.fullName(), name) // link to the pointee
++ : name;
++ }
++ }
++
+ if (auto k = AbstractMetaClass::findClass(api().classes(), type.typeEntry()))
+ return createRef ? toRef(k->fullName()) : k->name();
+
+diff --git a/sources/shiboken6_generator/generator/shiboken/cppgenerator.cpp b/sources/shiboken6_generator/generator/shiboken/cppgenerator.cpp
+index 47c9f044b..f9e088139 100644
+--- a/sources/shiboken6_generator/generator/shiboken/cppgenerator.cpp
++++ b/sources/shiboken6_generator/generator/shiboken/cppgenerator.cpp
+@@ -4550,7 +4550,7 @@ QString CppGenerator::writeContainerConverterInitialization(TextStream &s,
+ const ApiExtractorResult &api)
+ {
+ const auto cppSignature =
+- QString::fromUtf8(QMetaObject::normalizedSignature(type.cppSignature().toUtf8()));
++ QString::fromUtf8(QMetaObject::normalizedSignature(type.cppSignature().toUtf8().constData()));
+ s << "// Register converter for type '" << cppSignature << "'.\n";
+ const QString converter = converterObject(type);
+ s << converter << " = Shiboken::Conversions::createConverter(";
+@@ -4716,32 +4716,57 @@ void CppGenerator::writeClassTypeFunction(TextStream &s,
+ << outdent << "}\n" << closeExternC;
+ }
+
++static QString getTpDealloc(const AbstractMetaClassCPtr &metaClass, bool isQApp)
++{
++ if (metaClass->isNamespace())
++ return u"Sbk_object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */"_s;
++ if (metaClass->hasPrivateDestructor())
++ return u"SbkDeallocWrapperWithPrivateDtor"_s;
++ if (isQApp)
++ return u"&SbkDeallocQAppWrapper"_s;
++ return u"&SbkDeallocWrapper"_s;
++}
++
++static QString getTpNew(const AbstractMetaClassCPtr &metaClass, bool isQApp)
++{
++ const bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
++ if (metaClass->hasPrivateDestructor() || onlyPrivCtor) {
++ // tp_flags = u"Py_TPFLAGS_DEFAULT"_s;
++ // This is not generally possible, because PySide does not care about
++ // privacy the same way. This worked before the heap types were used,
++ // because inheritance is not really checked for static types.
++ // Instead, we check this at runtime, see SbkObjectType_tp_new.
++ if (metaClass->fullName().startsWith(u"PySide6.Qt")) {
++ // PYSIDE-595: No idea how to do non-inheritance correctly.
++ // Since that is only relevant in shiboken, I used a shortcut for
++ // PySide.
++ return u"SbkObject_tp_new"_s;
++ }
++ return u"SbkDummyNew /* PYSIDE-595: Prevent replacement of \"0\" with base->tp_new. */"_s;
++ }
++
++ if (isQApp)
++ return u"SbkQApp_tp_new"_s; // PYSIDE-571: need singleton app
++
++ return u"SbkObject_tp_new"_s;
++}
++
+ void CppGenerator::writeClassDefinition(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass,
+ const GeneratorContext &classContext)
+ {
+- QString tp_new;
+- QString tp_dealloc;
+ QString tp_hash;
+ QString tp_call;
+ const QString className = cpythonBaseName(metaClass);
+
+- bool onlyPrivCtor = !metaClass->hasNonPrivateConstructor();
+-
+ const bool isQApp = usePySideExtensions()
+ && inheritsFrom(metaClass, u"QCoreApplication"_s);
+
++ const QString tp_dealloc = getTpDealloc(metaClass, isQApp);
++
+ QString tp_flags = u"Py_TPFLAGS_DEFAULT"_s;
+ if (!metaClass->attributes().testFlag(AbstractMetaClass::FinalCppClass))
+ tp_flags += u"|Py_TPFLAGS_BASETYPE"_s;
+- if (metaClass->isNamespace() || metaClass->hasPrivateDestructor()) {
+- tp_dealloc = metaClass->hasPrivateDestructor() ?
+- u"SbkDeallocWrapperWithPrivateDtor"_s :
+- u"Sbk_object_dealloc /* PYSIDE-832: Prevent replacement of \"0\" with subtype_dealloc. */"_s;
+- } else {
+- tp_dealloc = isQApp
+- ? u"&SbkDeallocQAppWrapper"_s : u"&SbkDeallocWrapper"_s;
+- }
+
+ const AttroCheck attroCheck = checkAttroFunctionNeeds(metaClass);
+ const QString tp_getattro = (attroCheck & AttroCheckFlag::GetattroMask) != 0
+@@ -4749,29 +4774,8 @@ void CppGenerator::writeClassDefinition(TextStream &s,
+ const QString tp_setattro = (attroCheck & AttroCheckFlag::SetattroMask) != 0
+ ? cpythonSetattroFunctionName(metaClass) : QString();
+
+- if (metaClass->hasPrivateDestructor() || onlyPrivCtor) {
+- // tp_flags = u"Py_TPFLAGS_DEFAULT"_s;
+- // This is not generally possible, because PySide does not care about
+- // privacy the same way. This worked before the heap types were used,
+- // because inheritance is not really checked for static types.
+- // Instead, we check this at runtime, see SbkObjectType_tp_new.
+- if (metaClass->fullName().startsWith(u"PySide6.Qt")) {
+- // PYSIDE-595: No idea how to do non-inheritance correctly.
+- // Since that is only relevant in shiboken, I used a shortcut for
+- // PySide.
+- tp_new = u"SbkObject_tp_new"_s;
+- }
+- else {
+- tp_new = u"SbkDummyNew /* PYSIDE-595: Prevent replacement "
+- "of \"0\" with base->tp_new. */"_s;
+- }
+- }
+- else if (isQApp) {
+- tp_new = u"SbkQApp_tp_new"_s; // PYSIDE-571: need singleton app
+- }
+- else {
+- tp_new = u"SbkObject_tp_new"_s;
+- }
++ const QString tp_new = getTpNew(metaClass, isQApp);
++
+ tp_flags.append(u"|Py_TPFLAGS_HAVE_GC"_s);
+
+ QString tp_richcompare;
+@@ -5854,23 +5858,40 @@ void CppGenerator::writeSignatureStrings(TextStream &s,
+ << "#endif\n\n";
+ }
+
+-// Return the class name for which to invoke the destructor
+-QString CppGenerator::destructorClassName(const AbstractMetaClassCPtr &metaClass,
+- const GeneratorContext &classContext)
++QString CppGenerator::callCppDestructor(const GeneratorContext &classContext,
++ const QString &dtorClassName)
++{
++ return "&Shiboken::callCppDestructor< "_L1
++ + Generator::globalScopePrefix(classContext)
++ + dtorClassName + " >"_L1;
++}
++
++// Return the function to invoke the destructor
++QString CppGenerator::destructorFunction(const AbstractMetaClassCPtr &metaClass,
++ const GeneratorContext &classContext)
+ {
+ if (metaClass->isNamespace() || metaClass->hasPrivateDestructor())
+- return {};
++ return NULL_PTR;
+ if (classContext.forSmartPointer())
+- return classContext.effectiveClassName();
+- const bool isValue = metaClass->typeEntry()->isValue();
+- const bool hasProtectedDestructor = metaClass->hasProtectedDestructor();
+- if (((avoidProtectedHack() && hasProtectedDestructor) || isValue)
+- && classContext.useWrapper()) {
+- return classContext.wrapperName();
++ return callCppDestructor(classContext, classContext.effectiveClassName());
++
++ if (metaClass->typeEntry()->isValue() && classContext.useWrapper())
++ return callCppDestructor(classContext, classContext.wrapperName());
++
++ if (avoidProtectedHack() && metaClass->hasProtectedDestructor()) {
++ return classContext.useWrapper()
++ ? callCppDestructor(classContext, classContext.wrapperName())
++ : QString{NULL_PTR}; // Cannot call (happens with "disable-wrapper").
++ }
++
++ if (usePySideExtensions()
++ && metaClass->deletionMode() == TypeSystem::DeletionMode::DeleteInQObjectOwnerThread) {
++ if (!isQObject(metaClass))
++ throw Exception(msgOwnerThreadForNonQObject(metaClass));
++ return u"deferredDeleteQObject"_s;
+ }
+- if (avoidProtectedHack() && hasProtectedDestructor)
+- return {}; // Cannot call (happens with "disable-wrapper").
+- return metaClass->qualifiedCppName();
++
++ return callCppDestructor(classContext, metaClass->qualifiedCppName());
+ }
+
+ // Return the base type entries for introduceWrapperType()
+@@ -5986,12 +6007,7 @@ void CppGenerator::writeClassRegister(TextStream &s,
+ s << '&' << pyTypePrefix << "_spec,\n";
+
+ // 5:cppObjDtor
+- QString dtorClassName = destructorClassName(metaClass, classContext);
+- if (dtorClassName.isEmpty())
+- s << "nullptr,\n";
+- else
+- s << "&Shiboken::callCppDestructor< " << globalScopePrefix(classContext)
+- << dtorClassName << " >,\n";
++ s << destructorFunction(metaClass, classContext) << ",\n";
+
+ // 7:baseTypes
+ s << pyTypeBasesVariable << ".object()," << '\n';
+@@ -6000,7 +6016,7 @@ void CppGenerator::writeClassRegister(TextStream &s,
+ QByteArrayList wrapperFlags;
+ if (enc)
+ wrapperFlags.append("Shiboken::ObjectType::WrapperFlags::InnerClass"_ba);
+- if (metaClass->deleteInMainThread())
++ if (metaClass->deletionMode() == TypeSystem::DeletionMode::DeleteInMainThread)
+ wrapperFlags.append("Shiboken::ObjectType::WrapperFlags::DeleteInMainThread"_ba);
+ if (classTypeEntry->isValue())
+ wrapperFlags.append("Shiboken::ObjectType::WrapperFlags::Value"_ba);
+diff --git a/sources/shiboken6_generator/generator/shiboken/cppgenerator.h b/sources/shiboken6_generator/generator/shiboken/cppgenerator.h
+index 592f958f4..07cad1619 100644
+--- a/sources/shiboken6_generator/generator/shiboken/cppgenerator.h
++++ b/sources/shiboken6_generator/generator/shiboken/cppgenerator.h
+@@ -447,8 +447,10 @@ private:
+ const GeneratorContext &classContext,
+ const QString &signatures) const;
+ static QStringList pyBaseTypes(const AbstractMetaClassCPtr &metaClass);
+- static QString destructorClassName(const AbstractMetaClassCPtr &metaClass,
+- const GeneratorContext &classContext);
++ static QString callCppDestructor(const GeneratorContext &classContext,
++ const QString &dtorClassName);
++ static QString destructorFunction(const AbstractMetaClassCPtr &metaClass,
++ const GeneratorContext &classContext);
+ static void writeStaticFieldInitialization(TextStream &s,
+ const AbstractMetaClassCPtr &metaClass);
+ void writeClassDefinition(TextStream &s,
+diff --git a/testing/command.py b/testing/command.py
+index 9ef35ee20..be88c8519 100644
+--- a/testing/command.py
++++ b/testing/command.py
+@@ -142,9 +142,9 @@ def main():
+ global COIN_THRESHOLD
+ # create the top-level command parser
+ start_time = timer()
+- all_projects = "shiboken6 pyside6".split()
+- tested_projects = "shiboken6 pyside6".split()
+- tested_projects_quoted = " ".join("'i'" for i in tested_projects)
++ all_projects = ["shiboken6_generator", "shiboken6", "pyside6"]
++ tested_projects = all_projects
++ tested_projects_quoted = " ".join(f'"{i}"' for i in tested_projects)
+ runs = COIN_TESTING
+ parser = argparse.ArgumentParser(
+ formatter_class=argparse.RawDescriptionHelpFormatter,
+diff --git a/testing/wheel_tester.py b/testing/wheel_tester.py
+index 5ac9333db..dc36a2b72 100644
+--- a/testing/wheel_tester.py
++++ b/testing/wheel_tester.py
+@@ -45,6 +45,13 @@ log.setLevel(logging.DEBUG)
+ NEW_WHEELS = False
+
+
++def is_pyenv_python():
++ pyenv_root = os.environ.get("PYENV_ROOT")
++ if pyenv_root and (resolved_exe := str(Path(sys.executable).resolve())):
++ return resolved_exe.startswith(pyenv_root)
++ return False
++
++
+ def find_executable(executable, command_line_value):
+ value = command_line_value
+ option_str = f"--{executable}"
+@@ -206,14 +213,16 @@ def run_nuitka_test(example):
+ raise RuntimeError(f"Failure running {example} with Nuitka.")
+
+
+-def _run_deploy_test(example, tmpdirname):
++def _run_deploy_test(example, tmpdirname, python_executable=None):
+ """Helper for running deployment and example."""
++ if python_executable is None:
++ python_executable = sys.executable
+ main_file = None
+ for py_file in example.glob("*.py"):
+ shutil.copy(py_file, tmpdirname)
+ if not main_file or py_file.name == "main.py":
+ main_file = py_file
+- deploy_tool = Path(sys.executable).parent / "pyside6-deploy"
++ deploy_tool = Path(python_executable).parent / "pyside6-deploy"
+ cmd = [os.fspath(deploy_tool), "-f", main_file.name, "--init"]
+ if run_process(cmd) != 0:
+ raise RuntimeError("Error creating pysidedeploy.spec")
+@@ -243,7 +252,7 @@ def _run_deploy_test(example, tmpdirname):
+ return True
+
+
+-def run_deploy_test(example):
++def run_deploy_test(example, python_executable=None):
+ """Test pyside6-deploy."""
+ log.info(f"Running deploy test of {example}")
+ current_dir = Path.cwd()
+@@ -251,7 +260,7 @@ def run_deploy_test(example):
+ with tempfile.TemporaryDirectory() as tmpdirname:
+ try:
+ os.chdir(tmpdirname)
+- result = _run_deploy_test(example, tmpdirname)
++ result = _run_deploy_test(example, tmpdirname, python_executable)
+ except RuntimeError as e:
+ log.error(str(e))
+ raise e
+@@ -328,8 +337,18 @@ def try_build_examples():
+ # disable for windows as it Nuitka --onefile deployment in Windows
+ # requires DependencyWalker. Download and installing will slow down
+ # Coin
+- if sys.platform != "win32":
++ # Skip on macOS with pyenv Python: Nuitka 2.8+ fails to scan OpenSSL
++ # dependencies of pyenv-built _hashlib. Homebrew Python works.
++ # See https://github.com/Nuitka/Nuitka/issues/3777
++ if sys.platform != "win32" and not (sys.platform == "darwin" and is_pyenv_python()):
+ run_deploy_test(src_path)
++ elif sys.platform == "darwin" and is_pyenv_python():
++ alt_python = os.environ.get("ALTERNATIVE_PYTHON3_PATH")
++ if alt_python:
++ log.info(f"Using alternative Python for deploy test on macOS: {alt_python}")
++ run_deploy_test(src_path, python_executable=alt_python)
++ else:
++ log.info("Skipping deploy test on macOS with pyenv Python (Nuitka OpenSSL issue).")
+
+ if False: # pre 6.4.1, kept for reference
+ # Nuitka is loaded by coin_build_instructions.py, but not when
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/pyside-setup.git/commitdiff/5d13d2c549d125ea2a2240226e24ffa68fcaca29
More information about the pld-cvs-commit
mailing list