summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cmake.conf2
-rw-r--r--cmake/QtBuildHelpers.cmake1
-rw-r--r--cmake/QtBuildRepoHelpers.cmake1
-rw-r--r--cmake/QtHeadersClean.cmake4
-rw-r--r--cmake/QtInternalTargets.cmake3
-rw-r--r--cmake/QtTestHelpers.cmake2
-rw-r--r--cmake/QtToolchainHelpers.cmake4
-rw-r--r--coin/instructions/cmake_run_ctest.yaml11
-rw-r--r--doc/global/externalsites/external-resources.qdoc217
-rw-r--r--doc/global/externalsites/qt-webpages.qdoc61
-rw-r--r--doc/global/externalsites/rfc.qdoc33
-rw-r--r--mkspecs/common/clang.conf8
-rw-r--r--mkspecs/common/g++-base.conf8
-rw-r--r--src/3rdparty/libpng/ANNOUNCE26
-rw-r--r--src/3rdparty/libpng/CHANGES6
-rw-r--r--src/3rdparty/libpng/README2
-rw-r--r--src/3rdparty/libpng/libpng-manual.txt2
-rw-r--r--src/3rdparty/libpng/png.c4
-rw-r--r--src/3rdparty/libpng/png.h14
-rw-r--r--src/3rdparty/libpng/pngconf.h2
-rw-r--r--src/3rdparty/libpng/pnglibconf.h2
-rw-r--r--src/3rdparty/libpng/pngread.c2
-rw-r--r--src/3rdparty/libpng/qt_attribution.json4
-rw-r--r--src/android/jar/src/org/qtproject/qt/android/QtWindow.java11
-rw-r--r--src/corelib/Qt6CoreMacros.cmake15
-rw-r--r--src/corelib/configure.cmake3
-rw-r--r--src/corelib/doc/src/cmake/cmake-configure-variables.qdoc1
-rw-r--r--src/corelib/doc/src/external-resources.qdoc5
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp6
-rw-r--r--src/corelib/global/qoperatingsystemversion.h1
-rw-r--r--src/corelib/global/qttranslation.qdoc2
-rw-r--r--src/corelib/io/qrandomaccessasyncfile_darwin.mm24
-rw-r--r--src/corelib/itemmodels/qrangemodel_impl.h18
-rw-r--r--src/corelib/itemmodels/qrangemodeladapter.h232
-rw-r--r--src/corelib/itemmodels/qrangemodeladapter.qdoc61
-rw-r--r--src/corelib/kernel/qassociativeiterable.h2
-rw-r--r--src/corelib/kernel/qcore_mac.mm32
-rw-r--r--src/corelib/kernel/qcore_mac_p.h17
-rw-r--r--src/corelib/kernel/qiterable.h6
-rw-r--r--src/corelib/kernel/qmetaassociation.h6
-rw-r--r--src/corelib/kernel/qmetasequence.h61
-rw-r--r--src/corelib/kernel/qsequentialiterable.h3
-rw-r--r--src/corelib/kernel/qvariant.h10
-rw-r--r--src/corelib/platform/windows/qbstr_p.h3
-rw-r--r--src/corelib/platform/windows/qcomobject_p.h1
-rw-r--r--src/corelib/platform/windows/qcomptr_p.h1
-rw-r--r--src/corelib/platform/windows/qcomvariant_p.h1
-rw-r--r--src/corelib/platform/windows/qfactorycacheregistration.cpp1
-rw-r--r--src/corelib/platform/windows/qfactorycacheregistration_p.h1
-rw-r--r--src/corelib/platform/windows/qt_winrtbase_p.h1
-rw-r--r--src/corelib/serialization/qdatastream.cpp1
-rw-r--r--src/corelib/serialization/qdatastream.h5
-rw-r--r--src/corelib/thread/qfuture_impl.h9
-rw-r--r--src/corelib/thread/qfutureinterface.h4
-rw-r--r--src/corelib/thread/qreadwritelock.cpp8
-rw-r--r--src/corelib/tools/qarraydata.cpp2
-rw-r--r--src/corelib/tools/qeasingcurve.cpp4
-rw-r--r--src/gui/accessible/qaccessiblecache.cpp10
-rw-r--r--src/gui/doc/images/coordinatesystem-transformations.pngbin59180 -> 0 bytes
-rw-r--r--src/gui/doc/images/coordinatesystem-transformations.svg148
-rw-r--r--src/gui/doc/src/coordsys.qdoc2
-rw-r--r--src/gui/doc/src/external-resources.qdoc1
-rw-r--r--src/gui/kernel/qsurface.cpp5
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp19
-rw-r--r--src/gui/math3d/qmatrix4x4.h30
-rw-r--r--src/gui/opengl/platform/egl/qeglplatformcontext.cpp15
-rw-r--r--src/gui/painting/qdrawhelper.cpp4
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp6
-rw-r--r--src/gui/painting/qpainterpath.h2
-rw-r--r--src/gui/rhi/qrhivulkan.cpp104
-rw-r--r--src/gui/rhi/qrhivulkan_p.h6
-rw-r--r--src/gui/text/qfont.cpp33
-rw-r--r--src/gui/text/qfontengine.cpp6
-rw-r--r--src/gui/text/qtextdocument.cpp2
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase.cpp4
-rw-r--r--src/gui/text/windows/qwindowsfontdatabase_p.h4
-rw-r--r--src/network/access/qformdatabuilder.cpp1
-rw-r--r--src/network/access/qformdatabuilder.h1
-rw-r--r--src/network/access/qnetworkaccesscache.cpp5
-rw-r--r--src/network/access/qnetworkcookie.cpp1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm21
-rw-r--r--src/plugins/platforms/windows/qwindowsscreen.cpp20
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp2
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp2
-rw-r--r--src/plugins/sqldrivers/.cmake.conf2
-rw-r--r--src/plugins/styles/modernwindows/qwindows11style.cpp42
-rw-r--r--src/testlib/doc/src/qt-webpages.qdoc4
-rw-r--r--src/tools/androidtestrunner/main.cpp59
-rw-r--r--src/tools/configure.cmake2
-rw-r--r--src/widgets/CMakeLists.txt2
-rw-r--r--src/widgets/accessible/qaccessiblecolorwell.cpp5
-rw-r--r--src/widgets/dialogs/qcolordialog.cpp15
-rw-r--r--src/widgets/doc/src/external-resources.qdoc6
-rw-r--r--src/widgets/kernel/qtooltip.cpp75
-rw-r--r--src/widgets/kernel/qtooltip_p.h74
-rw-r--r--src/widgets/styles/qcommonstyle.cpp9
-rw-r--r--src/xml/doc/src/external-resources.qdoc11
-rw-r--r--tests/auto/CMakeLists.txt3
-rw-r--r--tests/auto/cmake/mockplugins/.cmake.conf2
-rw-r--r--tests/auto/cmake/test_generating_cpp_exports/.cmake.conf2
-rw-r--r--tests/auto/cmake/test_static_resources/.cmake.conf2
-rw-r--r--tests/auto/corelib/animation/qparallelanimationgroup/tst_qparallelanimationgroup.cpp4
-rw-r--r--tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp74
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp282
-rw-r--r--tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp8
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp79
-rw-r--r--tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp106
-rw-r--r--tests/auto/tools/rcc/data/legal/rcc_legal.cpp2
-rw-r--r--tests/auto/util/testrunner/CMakeLists.txt14
-rw-r--r--tests/auto/util/testrunner/qt_mock_test-log.xml (renamed from util/testrunner/tests/qt_mock_test-log.xml)14
-rwxr-xr-xtests/auto/util/testrunner/qt_mock_test.py (renamed from util/testrunner/tests/qt_mock_test.py)57
-rwxr-xr-xtests/auto/util/testrunner/tst_qt_testrunner.py (renamed from util/testrunner/tests/tst_testrunner.py)300
-rw-r--r--tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp1
-rw-r--r--tests/benchmarks/gui/painting/qcolor/tst_qcolor.cpp37
-rw-r--r--util/testrunner/README8
-rwxr-xr-xutil/testrunner/qt-testrunner.py155
116 files changed, 1965 insertions, 922 deletions
diff --git a/.cmake.conf b/.cmake.conf
index e1e19d2ed2a..09e591bd25b 100644
--- a/.cmake.conf
+++ b/.cmake.conf
@@ -7,7 +7,7 @@ if (NOT DEFINED QT_SUPERBUILD OR DEFINED QT_REPO_MODULE_VERSION)
set(QT_EXTRA_INTERNAL_TARGET_DEFINES "QT_LEAN_HEADERS=1")
endif()
-set(QT_REPO_MODULE_VERSION "6.11.0")
+set(QT_REPO_MODULE_VERSION "6.12.0")
set(QT_REPO_MODULE_PRERELEASE_VERSION_SEGMENT "alpha1")
set(QT_COPYRIGHT "Copyright (C) The Qt Company Ltd. and other contributors.")
diff --git a/cmake/QtBuildHelpers.cmake b/cmake/QtBuildHelpers.cmake
index 91983636712..3ef292b27bc 100644
--- a/cmake/QtBuildHelpers.cmake
+++ b/cmake/QtBuildHelpers.cmake
@@ -6,6 +6,7 @@ function(qt_internal_validate_cmake_generator)
if(NOT warning_shown
AND NOT CMAKE_GENERATOR MATCHES "Ninja"
+ AND NOT (IOS AND QT_INTERNAL_IS_STANDALONE_TEST)
AND NOT QT_SILENCE_CMAKE_GENERATOR_WARNING
AND NOT DEFINED ENV{QT_SILENCE_CMAKE_GENERATOR_WARNING})
set_property(GLOBAL PROPERTY _qt_validate_cmake_generator_warning_shown TRUE)
diff --git a/cmake/QtBuildRepoHelpers.cmake b/cmake/QtBuildRepoHelpers.cmake
index 05876c1ad6d..ba8e2e57660 100644
--- a/cmake/QtBuildRepoHelpers.cmake
+++ b/cmake/QtBuildRepoHelpers.cmake
@@ -523,6 +523,7 @@ function(qt_internal_show_extra_ide_sources)
add_custom_target(${target_name})
set(recursive_glob_patterns
+ REUSE.toml
${QT_BUILD_EXTRA_IDE_FILE_RECURSIVE_PATTERNS}
)
set(simple_glob_patterns
diff --git a/cmake/QtHeadersClean.cmake b/cmake/QtHeadersClean.cmake
index 3e59d68629c..9d8c86cf70d 100644
--- a/cmake/QtHeadersClean.cmake
+++ b/cmake/QtHeadersClean.cmake
@@ -137,6 +137,10 @@ function(qt_internal_add_headersclean_target module_target module_headers)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
list(APPEND hcleanFLAGS -Wzero-as-null-pointer-constant
-Wdouble-promotion -Wfloat-conversion)
+ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "14.0.0")
+ list(APPEND hcleanFLAGS
+ -Wnrvo)
+ endif()
endif()
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang|IntelLLVM")
diff --git a/cmake/QtInternalTargets.cmake b/cmake/QtInternalTargets.cmake
index 0815dbe8e42..45e75d4836f 100644
--- a/cmake/QtInternalTargets.cmake
+++ b/cmake/QtInternalTargets.cmake
@@ -23,6 +23,9 @@ function(qt_internal_set_warnings_are_errors_flags target target_scope)
COMPILERS CLANG AppleClang
OPTIONS
-Werror -Wno-error=\#warnings -Wno-error=deprecated-declarations
+ CONDITIONS VERSION_GREATER_EQUAL 14
+ OPTIONS
+ -Wno-error=deprecated-pragma
COMMON_CONDITIONS
${common_conditions}
${clang_msvc_frontend_args}
diff --git a/cmake/QtTestHelpers.cmake b/cmake/QtTestHelpers.cmake
index 06228ac41de..781bdf4143a 100644
--- a/cmake/QtTestHelpers.cmake
+++ b/cmake/QtTestHelpers.cmake
@@ -1240,7 +1240,7 @@ function(qt_internal_add_test_finalizers target)
# specific platforms.
# TODO: Remove once we confirm that the new way of running test finalizers for all platforms
# doesn't cause any issues.
- if(QT_INTERNAL_SKIP_TEST_FINALIZERS_V2)
+ if(NOT QT_INTERNAL_SKIP_TEST_FINALIZERS_V2)
return()
endif()
diff --git a/cmake/QtToolchainHelpers.cmake b/cmake/QtToolchainHelpers.cmake
index 348a3c25603..b2a5575f130 100644
--- a/cmake/QtToolchainHelpers.cmake
+++ b/cmake/QtToolchainHelpers.cmake
@@ -183,6 +183,7 @@ endif()")
list(LENGTH CMAKE_OSX_ARCHITECTURES _qt_osx_architectures_count)
if(cmake_sysroot_name AND (MACOS OR (UIKIT AND NOT _qt_osx_architectures_count GREATER 1)))
list(APPEND init_platform "
+set(__qt_initial_apple_sdk \"${QT_APPLE_SDK}\")
if(NOT DEFINED CMAKE_OSX_SYSROOT)
set(CMAKE_OSX_SYSROOT \"${cmake_sysroot_name}\" CACHE STRING \"\")
endif()")
@@ -254,7 +255,8 @@ endif()")
qt_internal_get_first_osx_arch(osx_first_arch)
list(APPEND init_platform
"if((NOT CMAKE_GENERATOR STREQUAL \"Xcode\" AND NOT __qt_toolchain_building_qt_repo)
- OR (CMAKE_GENERATOR STREQUAL \"Xcode\" AND __qt_apple_sdk AND NOT QT_NO_SET_OSX_ARCHITECTURES))")
+ OR (CMAKE_GENERATOR STREQUAL \"Xcode\" AND __qt_initial_apple_sdk
+ AND NOT QT_NO_SET_OSX_ARCHITECTURES))")
list(APPEND init_platform
" set(CMAKE_OSX_ARCHITECTURES \"${osx_first_arch}\" CACHE STRING \"\")")
list(APPEND init_platform "endif()")
diff --git a/coin/instructions/cmake_run_ctest.yaml b/coin/instructions/cmake_run_ctest.yaml
index 43963fc172b..03312101117 100644
--- a/coin/instructions/cmake_run_ctest.yaml
+++ b/coin/instructions/cmake_run_ctest.yaml
@@ -92,19 +92,10 @@ instructions:
variableName: CTEST_ARGS
variableValue: " --no-label-summary"
- # Enable CTest's JUnit XML summary
+ # Enable CTest's JUnit XML summary, supported in CMake >= v3.21
- type: AppendToEnvironmentVariable
variableName: CTEST_ARGS
variableValue: " --output-junit {{.Env.COIN_CTEST_RESULTSDIR}}{{.Env.CI_PATH_SEP}}test_summary.ctest_junit_xml"
- disable_if: # CMake < v3.21 does not support it
- condition: and
- conditions:
- - condition: runtime
- env_var: CMAKE_MIN_SUPPORTED_BIN_PATH
- not_equals_value: null
- - condition: runtime
- env_var: PATH
- contains_value: "{{.Env.CMAKE_MIN_SUPPORTED_BIN_PATH}}"
- !include "{{qt/qtbase}}/coin_module_test_android_start_emulator.yaml"
diff --git a/doc/global/externalsites/external-resources.qdoc b/doc/global/externalsites/external-resources.qdoc
index 51756842ad0..8670305b00c 100644
--- a/doc/global/externalsites/external-resources.qdoc
+++ b/doc/global/externalsites/external-resources.qdoc
@@ -58,68 +58,27 @@
*/
/*!
- \externalpage https://www.freedesktop.org/wiki/Standards/xembed-spec/
- \title XEmbed Specification
-*/
-
-/*!
- \externalpage https://www.freedesktop.org/wiki/Standards/icon-theme-spec/
- \title Icon Themes Specification
-*/
-
-/*!
\externalpage https://www.cups.org/
\title Common Unix Printing System (CUPS)
\keyword CUPS
*/
/*!
- \externalpage https://www.freedesktop.org/wiki/Specifications/desktop-entry-spec/
- \title Desktop Entry Specification
-*/
-
-/*!
- \externalpage https://kde.org/
- \title The K Desktop Environment
- \keyword KDE
-*/
-
-/*!
\externalpage https://cmake.org/cmake/help/latest/
\title CMake Documentation
*/
/*!
- \externalpage https://cmake.org/cmake/help/latest/command/find_package.html
- \title CMake find_package Documentation
-*/
-
-/*!
\externalpage https://cmake.org/cmake/help/latest/manual/cmake-qt.7.html#automoc
\title CMake AUTOMOC Documentation
*/
/*!
- \externalpage https://cmake.org/cmake/help/latest/manual/cmake-qt.7.html#autorcc
- \title CMake AUTORCC Documentation
-*/
-
-/*!
\externalpage https://cmake.org/cmake/help/latest/manual/cmake-qt.7.html#autouic
\title CMake AUTOUIC Documentation
*/
/*!
- \externalpage https://cmake.org/cmake/help/latest/prop_tgt/LOCATION.html
- \title CMake LOCATION Documentation
-*/
-
-/*!
- \externalpage https://cmake.org/cmake/help/latest/prop_tgt/POSITION_INDEPENDENT_CODE.html
- \title CMake POSITION_INDEPENDENT_CODE Documentation
-*/
-
-/*!
\externalpage https://cmake.org/cmake/help/latest/command/target_link_libraries.html
\title CMake target_link_libraries Documentation
*/
@@ -130,50 +89,11 @@
*/
/*!
- \externalpage https://conan.io/
- \title Conan
-*/
-
-/*!
\externalpage https://www.gnome.org/
\title GNOME
*/
/*!
- \externalpage https://www.gnu.org/software/emacs/
- \title GNU Emacs
-*/
-
-/*!
- \externalpage https://gnuwin32.sourceforge.net/packages.html
- \title GnuWin32 Project
-*/
-
-/*!
- \externalpage https://www.w3.org/Graphics/SVG/About.html
- \title About SVG
- \keyword Scalable Vector Graphics
-*/
-
-/*!
- \externalpage https://www.w3.org/TR/SVG/types.html#ColorKeywords
- \title SVG color keyword names
-*/
-
-/*!
- \externalpage https://www.w3.org/Graphics/SVG/
- \title SVG Working Group
-*/
-
-/*!
- \externalpage https://www.w3.org/TR/SVGMobile/
- \title Mobile SVG Profiles
- \omit
- Mobile SVG Profiles: SVG Tiny and SVG Basic
- \endomit
-*/
-
-/*!
\externalpage https://www.w3.org/TR/SVGMobile12/
\title SVG 1.2 Tiny
*/
@@ -186,36 +106,16 @@
/*!
- \externalpage https://jmeubank.github.io/tdm-gcc/
- \title TDM-GCC
-*/
-
-/*!
\externalpage https://www.dependencywalker.com/
\title Dependency Walker
*/
/*!
- \externalpage https://webkit.org/
- \title WebKit Open Source Project
-*/
-
-/*!
- \externalpage https://www.informit.com/store/c-plus-plus-gui-programming-with-qt4-9780132354165
- \title C++ GUI Programming with Qt 4, 2nd Edition
-*/
-
-/*!
\externalpage https://www.openssl.org/
\title OpenSSL Toolkit
*/
/*!
- \externalpage https://www.activestate.com/platform/supported-languages/perl/
- \title ActivePerl
-*/
-
-/*!
\externalpage https://chromium.googlesource.com/angle/angle/+/master/README.md
\title ANGLE
*/
@@ -226,16 +126,6 @@
*/
/*!
- \externalpage https://www.w3.org/TR/html401/
- \title HTML 4
-*/
-
-/*!
- \externalpage https://html.spec.whatwg.org/multipage/
- \title HTML 5
-*/
-
-/*!
\externalpage https://icu.unicode.org/
\title ICU
*/
@@ -251,41 +141,16 @@
*/
/*!
- \externalpage https://pyxml.sourceforge.net/topics/xbel/
- \title XML Bookmark Exchange Language Resource Page
-*/
-
-/*!
- \externalpage https://www.w3.org/TR/xquery/#errors
- \title error handling in the XQuery language
-*/
-
-/*!
\externalpage https://xaos-project.github.io/
\title XaoS
*/
/*!
- \externalpage https://www.unixodbc.org
- \title https://www.unixodbc.org
-*/
-
-/*!
\externalpage https://www.postgresql.org
\title https://www.postgresql.org
*/
/*!
- \externalpage https://www.postgresql.org/docs/current/installation-platform-notes.html
- \title PostgreSQL MinGW/Native Windows
-*/
-
-/*!
- \externalpage https://www.freetds.org
- \title https://www.freetds.org
-*/
-
-/*!
\externalpage https://www.sqlite.org
\title https://www.sqlite.org
*/
@@ -301,11 +166,6 @@
*/
/*!
- \externalpage https://tldp.org/HOWTO/Framebuffer-HOWTO.html
- \title Framebuffer HOWTO
-*/
-
-/*!
\externalpage https://www.w3.org/TR/scxml/
\title State Chart XML: State Machine Notation for Control Abstraction
*/
@@ -321,71 +181,21 @@
*/
/*!
- \externalpage https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
- \title GNU Lesser General Public License, version 2.1
-*/
-
-/*!
- \externalpage https://www.qtcentre.org
- \title Qt Centre
-*/
-
-/*!
\externalpage https://kde.org
\title KDE
*/
/*!
- \externalpage https://cplusplus.com/reference/cstring/memcpy/
- \title C++ Reference - memcpy
-*/
-
-/*!
\externalpage https://en.cppreference.com/w/cpp/symbol_index/chrono_literals.html
\title chrono_literals Symbol Index
*/
/*!
- \externalpage https://www.w3.org/TR/CSS2/selector.html
- \title Standard CSS2 selector
-*/
-
-/*!
- \externalpage https://www.w3.org/XML/Core/#Publications
- \title W3C XML specifications
-*/
-
-/*!
- \externalpage https://www.w3.org/XML/Schema
- \title XML Schema
-*/
-
-/*!
- \externalpage https://opensource.org/license/bsd-3-clause
- \title New and Modified BSD Licenses
-*/
-
-/*!
- \externalpage https://ecma-international.org/publications-and-standards/standards/ecma-262/
- \title ECMAScript Language Specification
-*/
-
-/*!
\externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript
\title JavaScript Resources
*/
/*!
- \externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide
- \title JavaScript Guide
-*/
-
-/*!
- \externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript
- \title About JavaScript
-*/
-
-/*!
\externalpage https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#keywords
\title JavaScript Reserved Words
*/
@@ -406,41 +216,16 @@
*/
/*!
- \externalpage https://registry.khronos.org/OpenGL/index_gl.php
- \title OpenGL Registry
-*/
-
-/*!
- \externalpage https://registry.khronos.org/OpenGL/index_es.php
- \title Khronos OpenGL ES API Registry
-*/
-
-/*!
\externalpage https://www.khronos.org/opengl/wiki/Array_Texture
\title Array Texture
*/
/*!
- \externalpage https://github.com/iksaif/qsslkey-p11
- \title qsslkey example
-*/
-
-/*!
\externalpage https://www.w3.org/TR/2009/WD-webdatabase-20091029/
\title HTML5 Web Database API
*/
/*!
- \externalpage https://lldb.llvm.org/
- \title The LLDB Debugger
-*/
-
-/*!
- \externalpage https://account.qt.io/s/
- \title Qt Account Sign-up
-*/
-
-/*!
\externalpage https://facebook.github.io/zstd/
\title Zstandard Site
*/
@@ -476,6 +261,6 @@
*/
/*!
- \externalpage https://specifications.freedesktop.org/trash-spec/1.0/
+ \externalpage https://specifications.freedesktop.org/trash/1.0/
\title FreeDesktop.org Trash specification version 1.0
*/
diff --git a/doc/global/externalsites/qt-webpages.qdoc b/doc/global/externalsites/qt-webpages.qdoc
index 7b659fa5295..6cbf5f377b6 100644
--- a/doc/global/externalsites/qt-webpages.qdoc
+++ b/doc/global/externalsites/qt-webpages.qdoc
@@ -17,76 +17,15 @@
\title The Qt Company
*/
/*!
- \externalpage http://qt.io/licensing/
- \title Qt Licensing Overview
-*/
-/*!
- \externalpage http://doc.qt.io/archives/qq/
- \title Qt Quarterly
-*/
-/*!
- \externalpage http://doc.qt.io/archives/qq/qq19-plurals.html
- \title Qt Quarterly: Plural Form in Translation
-*/
-/*!
\externalpage https://code.qt.io/
\title Public Qt Repository
*/
/*!
- \externalpage https://code.qt.io/cgit/%7bnon-gerrit%7d/qt-labs/qtestlib-tools.git/
- \title qtestlib-tools
-*/
-
-/*!
- \externalpage http://wiki.qt.io/Qt_Coding_Style
- \title Qt Coding Style
-*/
-/*!
- \externalpage http://doc.qt.io/archives/qt-eclipse-1.6/index.html
- \title Eclipse Plugin
-*/
-/*!
- \externalpage http://doc.qt.io/archives/qq/qq11-events.html
- \title Qt Quarterly: Another Look at Events
-*/
-/*!
- \externalpage https://www.youtube.com/watch?v=P4kv-AoAJ-Q
- \title Livecoding video effects with Qt5
-*/
-/*!
- \externalpage http://blog.qt.io/2012/02/29/pimp-my-video-shader-effects-and-multimedia/
- \title Pimp my video
-*/
-/*!
- \externalpage http://wiki.qt.io/QtMediaHub
- \title QtMediaHub
-*/
-/*!
- \externalpage http://wiki.qt.io/Qt_RaspberryPi
- \title QtonPi
-*/
-
-/*!
- \externalpage http://wiki.qt.io/jom
- \title jom
-*/
-
-/*!
- \externalpage http://doc.qt.io/qt-4.8
- \title Qt 4.8 Reference Documentation
-*/
-
-/*!
\externalpage http://wiki.qt.io/Qt_Localization
\title external: Translating Qt Into Other Languages
*/
/*!
- \externalpage http://wiki.qt.io/Qt_Multimedia_Backends
- \title Qt Multimedia Backends
-*/
-
-/*!
\externalpage https://doc.qt.io/qt3dstudio/index.html
\title Qt 3D Studio Manual
*/
diff --git a/doc/global/externalsites/rfc.qdoc b/doc/global/externalsites/rfc.qdoc
index d0c127fb41e..071977b9a0e 100644
--- a/doc/global/externalsites/rfc.qdoc
+++ b/doc/global/externalsites/rfc.qdoc
@@ -12,12 +12,6 @@
*/
/*!
- \externalpage https://datatracker.ietf.org/doc/html/rfc1179
- \title RFC 1179
- \keyword lpr
-*/
-
-/*!
\externalpage https://datatracker.ietf.org/doc/html/rfc1738
\title RFC 1738
*/
@@ -28,43 +22,16 @@
*/
/*!
- \externalpage https://datatracker.ietf.org/doc/html/rfc1928
- \title RFC 1928
-*/
-
-/*!
- \externalpage https://datatracker.ietf.org/doc/html/rfc1929
- \title RFC 1929
-*/
-
-/*!
\externalpage https://datatracker.ietf.org/doc/html/rfc2045
\title RFC 2045
*/
/*!
- \externalpage https://datatracker.ietf.org/doc/html/rfc2109
- \title RFC 2109
- HTTP State Management Mechanism
-*/
-
-/*!
\externalpage https://datatracker.ietf.org/doc/html/rfc2822
\title RFC 2822
*/
/*!
- \externalpage https://datatracker.ietf.org/doc/html/rfc2965
- \title RFC 2965
- HTTP State Management Mechanism
-*/
-
-/*!
- \externalpage https://datatracker.ietf.org/doc/html/rfc3174
- \title RFC 3174
-*/
-
-/*!
\externalpage https://datatracker.ietf.org/doc/html/rfc3491
\title RFC 3491
*/
diff --git a/mkspecs/common/clang.conf b/mkspecs/common/clang.conf
index 82c6173a037..83867e66f94 100644
--- a/mkspecs/common/clang.conf
+++ b/mkspecs/common/clang.conf
@@ -32,14 +32,14 @@ QMAKE_CXXFLAGS_LTCG = $$QMAKE_CFLAGS_LTCG
QMAKE_CXXFLAGS_LTCG_FATOBJECTS = $$QMAKE_CFLAGS_LTCG_FATOBJECTS
QMAKE_CXXFLAGS_DISABLE_LTCG = $$QMAKE_CFLAGS_DISABLE_LTCG
QMAKE_CXXFLAGS_CXX11 = -std=c++11
-QMAKE_CXXFLAGS_CXX14 = -std=c++1y
-QMAKE_CXXFLAGS_CXX1Z = -std=c++1z
+QMAKE_CXXFLAGS_CXX14 = -std=c++14
+QMAKE_CXXFLAGS_CXX1Z = -std=c++17
QMAKE_CXXFLAGS_CXX2A = -std=c++2a
QMAKE_CXXFLAGS_CXX2B = -std=c++2b
QMAKE_CXXFLAGS_CXX2C = -std=c++2c
QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11
-QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++1y
-QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z
+QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++14
+QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++17
QMAKE_CXXFLAGS_GNUCXX2A = -std=gnu++2a
QMAKE_CXXFLAGS_GNUCXX2B = -std=gnu++2b
QMAKE_CXXFLAGS_GNUCXX2C = -std=gnu++2c
diff --git a/mkspecs/common/g++-base.conf b/mkspecs/common/g++-base.conf
index e12e41506ae..66248fb7d01 100644
--- a/mkspecs/common/g++-base.conf
+++ b/mkspecs/common/g++-base.conf
@@ -30,14 +30,14 @@ QMAKE_CXXFLAGS_USE_PRECOMPILE = $$QMAKE_CFLAGS_USE_PRECOMPILE
QMAKE_CFLAGS_GNUC99 = -std=gnu99
QMAKE_CFLAGS_GNUC11 = -std=gnu11
QMAKE_CXXFLAGS_CXX11 = -std=c++11
-QMAKE_CXXFLAGS_CXX14 = -std=c++1y
-QMAKE_CXXFLAGS_CXX1Z = -std=c++1z
+QMAKE_CXXFLAGS_CXX14 = -std=c++14
+QMAKE_CXXFLAGS_CXX1Z = -std=c++17
QMAKE_CXXFLAGS_CXX2A = -std=c++2a
QMAKE_CXXFLAGS_CXX2B = -std=c++2b
QMAKE_CXXFLAGS_CXX2C = -std=c++2c
QMAKE_CXXFLAGS_GNUCXX11 = -std=gnu++11
-QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++1y
-QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++1z
+QMAKE_CXXFLAGS_GNUCXX14 = -std=gnu++14
+QMAKE_CXXFLAGS_GNUCXX1Z = -std=gnu++17
QMAKE_CXXFLAGS_GNUCXX2A = -std=gnu++2a
QMAKE_CXXFLAGS_GNUCXX2B = -std=gnu++2b
QMAKE_CXXFLAGS_GNUCXX2C = -std=gnu++2c
diff --git a/src/3rdparty/libpng/ANNOUNCE b/src/3rdparty/libpng/ANNOUNCE
index 10dee70d834..e9a94e05de3 100644
--- a/src/3rdparty/libpng/ANNOUNCE
+++ b/src/3rdparty/libpng/ANNOUNCE
@@ -1,4 +1,4 @@
-libpng 1.6.52 - December 3, 2025
+libpng 1.6.53 - December 5, 2025
================================
This is a public release of libpng, intended for use in production code.
@@ -9,10 +9,10 @@ Files available for download
Source files:
- * libpng-1.6.52.tar.xz (LZMA-compressed, recommended)
- * libpng-1.6.52.tar.gz (deflate-compressed)
- * lpng1652.7z (LZMA-compressed)
- * lpng1652.zip (deflate-compressed)
+ * libpng-1.6.53.tar.xz (LZMA-compressed, recommended)
+ * libpng-1.6.53.tar.gz (deflate-compressed)
+ * lpng1653.7z (LZMA-compressed)
+ * lpng1653.zip (deflate-compressed)
Other information:
@@ -22,18 +22,14 @@ Other information:
* TRADEMARK.md
-Changes from version 1.6.51 to version 1.6.52
+Changes from version 1.6.52 to version 1.6.53
---------------------------------------------
- * Fixed CVE-2025-66293 (high severity):
- Out-of-bounds read in `png_image_read_composite`.
- (Reported by flyfish101 <[email protected]>.)
- * Fixed the Paeth filter handling in the RISC-V RVV implementation.
- (Reported by Filip Wasil; fixed by Liang Junzhao.)
- * Improved the performance of the RISC-V RVV implementation.
- (Contributed by Liang Junzhao.)
- * Added allocation failure fuzzing to oss-fuzz.
- (Contributed by Philippe Antoine.)
+ * Fixed a build failure on RISC-V RVV caused by a misspelled intrinsic.
+ (Contributed by Alexander Smorkalov.)
+ * Fixed a build failure with CMake 4.1 or newer, on Windows, when using
+ Visual C++ without MASM installed.
+ (Reported by Andrew Tribick; fixed by Luis Caro Campos.)
Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
diff --git a/src/3rdparty/libpng/CHANGES b/src/3rdparty/libpng/CHANGES
index f8ad74bbdf3..ea43101538a 100644
--- a/src/3rdparty/libpng/CHANGES
+++ b/src/3rdparty/libpng/CHANGES
@@ -6315,6 +6315,12 @@ Version 1.6.52 [December 3, 2025]
Added allocation failure fuzzing to oss-fuzz.
(Contributed by Philippe Antoine.)
+Version 1.6.53 [December 5, 2025]
+ Fixed a build failure on RISC-V RVV caused by a misspelled intrinsic.
+ (Contributed by Alexander Smorkalov.)
+ Fixed a build failure with CMake 4.1 or newer, on Windows, when using
+ Visual C++ without MASM installed.
+
Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
Subscription is required; visit
https://lists.sourceforge.net/lists/listinfo/png-mng-implement
diff --git a/src/3rdparty/libpng/README b/src/3rdparty/libpng/README
index 87e5f8b177e..4041ad86eb3 100644
--- a/src/3rdparty/libpng/README
+++ b/src/3rdparty/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.52
+README for libpng version 1.6.53
================================
See the note about version numbers near the top of `png.h`.
diff --git a/src/3rdparty/libpng/libpng-manual.txt b/src/3rdparty/libpng/libpng-manual.txt
index f284d987ba6..750025cfdad 100644
--- a/src/3rdparty/libpng/libpng-manual.txt
+++ b/src/3rdparty/libpng/libpng-manual.txt
@@ -9,7 +9,7 @@ libpng-manual.txt - A description on how to use and modify libpng
Based on:
- libpng version 1.6.36, December 2018, through 1.6.52 - December 2025
+ libpng version 1.6.36, December 2018, through 1.6.53 - December 2025
Updated and distributed by Cosmin Truta
Copyright (c) 2018-2025 Cosmin Truta
diff --git a/src/3rdparty/libpng/png.c b/src/3rdparty/libpng/png.c
index 11b65d1f13e..85b49496520 100644
--- a/src/3rdparty/libpng/png.c
+++ b/src/3rdparty/libpng/png.c
@@ -13,7 +13,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_52 Your_png_h_is_not_version_1_6_52;
+typedef png_libpng_version_1_6_53 Your_png_h_is_not_version_1_6_53;
/* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
* corresponding macro definitions. This causes a compile time failure if
@@ -817,7 +817,7 @@ png_get_copyright(png_const_structrp png_ptr)
return PNG_STRING_COPYRIGHT
#else
return PNG_STRING_NEWLINE \
- "libpng version 1.6.52" PNG_STRING_NEWLINE \
+ "libpng version 1.6.53" PNG_STRING_NEWLINE \
"Copyright (c) 2018-2025 Cosmin Truta" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
diff --git a/src/3rdparty/libpng/png.h b/src/3rdparty/libpng/png.h
index bceb9aa45d7..bdcd243dea2 100644
--- a/src/3rdparty/libpng/png.h
+++ b/src/3rdparty/libpng/png.h
@@ -1,6 +1,6 @@
/* png.h - header file for PNG reference library
*
- * libpng version 1.6.52
+ * libpng version 1.6.53
*
* Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -14,7 +14,7 @@
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
* libpng versions 0.97, January 1998, through 1.6.35, July 2018:
* Glenn Randers-Pehrson
- * libpng versions 1.6.36, December 2018, through 1.6.52, December 2025:
+ * libpng versions 1.6.36, December 2018, through 1.6.53, December 2025:
* Cosmin Truta
* See also "Contributing Authors", below.
*/
@@ -238,7 +238,7 @@
* ...
* 1.5.30 15 10530 15.so.15.30[.0]
* ...
- * 1.6.52 16 10651 16.so.16.52[.0]
+ * 1.6.53 16 10651 16.so.16.53[.0]
*
* Henceforth the source version will match the shared-library major and
* minor numbers; the shared-library major version number will be used for
@@ -274,7 +274,7 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.52"
+#define PNG_LIBPNG_VER_STRING "1.6.53"
#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
/* The versions of shared library builds should stay in sync, going forward */
@@ -285,7 +285,7 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 52
+#define PNG_LIBPNG_VER_RELEASE 53
/* This should be zero for a public release, or non-zero for a
* development version.
@@ -316,7 +316,7 @@
* From version 1.0.1 it is:
* XXYYZZ, where XX=major, YY=minor, ZZ=release
*/
-#define PNG_LIBPNG_VER 10652 /* 1.6.52 */
+#define PNG_LIBPNG_VER 10653 /* 1.6.53 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -426,7 +426,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char* png_libpng_version_1_6_52;
+typedef char* png_libpng_version_1_6_53;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
diff --git a/src/3rdparty/libpng/pngconf.h b/src/3rdparty/libpng/pngconf.h
index 76b5c20bdff..f4ff19209c6 100644
--- a/src/3rdparty/libpng/pngconf.h
+++ b/src/3rdparty/libpng/pngconf.h
@@ -1,6 +1,6 @@
/* pngconf.h - machine-configurable file for libpng
*
- * libpng version 1.6.52
+ * libpng version 1.6.53
*
* Copyright (c) 2018-2025 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
diff --git a/src/3rdparty/libpng/pnglibconf.h b/src/3rdparty/libpng/pnglibconf.h
index f4a993441f7..27fa87045b3 100644
--- a/src/3rdparty/libpng/pnglibconf.h
+++ b/src/3rdparty/libpng/pnglibconf.h
@@ -1,6 +1,6 @@
/* pnglibconf.h - library build configuration */
-/* libpng version 1.6.52 */
+/* libpng version 1.6.53 */
/* Copyright (c) 2018-2025 Cosmin Truta */
/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/src/3rdparty/libpng/pngread.c b/src/3rdparty/libpng/pngread.c
index f8ca2b7e31d..13a93deedcb 100644
--- a/src/3rdparty/libpng/pngread.c
+++ b/src/3rdparty/libpng/pngread.c
@@ -3278,7 +3278,7 @@ png_image_read_composite(png_voidp argument)
/* Clamp to the valid range to defend against
* unforeseen cases where the data might be sRGB
* instead of linear premultiplied.
- * (Belt-and-suspenders for GitHub Issue #764.)
+ * (Belt-and-suspenders for CVE-2025-66293.)
*/
if (component > 255*65535)
component = 255*65535;
diff --git a/src/3rdparty/libpng/qt_attribution.json b/src/3rdparty/libpng/qt_attribution.json
index 1f942f8f564..132e5e8d4cd 100644
--- a/src/3rdparty/libpng/qt_attribution.json
+++ b/src/3rdparty/libpng/qt_attribution.json
@@ -7,8 +7,8 @@
"Description": "libpng is the official PNG reference library.",
"Homepage": "http://www.libpng.org/pub/png/libpng.html",
- "Version": "1.6.52",
- "DownloadLocation": "https://download.sourceforge.net/libpng/libpng-1.6.52.tar.xz",
+ "Version": "1.6.53",
+ "DownloadLocation": "https://download.sourceforge.net/libpng/libpng-1.6.53.tar.xz",
"PURL": "pkg:github/pnggroup/libpng@v$<VERSION>",
"CPE": "cpe:2.3:a:libpng:libpng:$<VERSION>:*:*:*:*:*:*:*",
diff --git a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java
index f0d304f9e7f..c63cd1a77e3 100644
--- a/src/android/jar/src/org/qtproject/qt/android/QtWindow.java
+++ b/src/android/jar/src/org/qtproject/qt/android/QtWindow.java
@@ -32,6 +32,7 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
private QtWindow m_parentWindow;
private GestureDetector m_gestureDetector;
private final QtEditText m_editText;
+ private boolean m_editTextFocusInitialized = false;
private final QtInputConnection.QtInputConnectionListener m_inputConnectionListener;
private boolean m_firstSafeMarginsDelivered = false;
private int m_actionBarHeight = -1;
@@ -62,6 +63,8 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
if (!isForeignWindow && context instanceof Activity) {
// TODO QTBUG-122552 - Service keyboard input not implemented
m_editText = new QtEditText(context, listener);
+ m_editText.setFocusable(false);
+ m_editText.setFocusableInTouchMode(false);
m_editText.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
@@ -242,6 +245,14 @@ class QtWindow extends QtLayout implements QtSurfaceInterface {
@Override
public boolean onTouchEvent(MotionEvent event)
{
+ // Enable focus for the edit text on first touch event to avoid
+ // early QtInputConnection callbacks from blocking the UI thread.
+ if (!m_editTextFocusInitialized) {
+ m_editTextFocusInitialized = true;
+ m_editText.setFocusable(true);
+ m_editText.setFocusableInTouchMode(true);
+ }
+
windowFocusChanged(true, getId());
if (m_editText != null && m_inputConnectionListener != null)
m_inputConnectionListener.onEditTextChanged(m_editText);
diff --git a/src/corelib/Qt6CoreMacros.cmake b/src/corelib/Qt6CoreMacros.cmake
index b69d0285de2..c1f9aee0180 100644
--- a/src/corelib/Qt6CoreMacros.cmake
+++ b/src/corelib/Qt6CoreMacros.cmake
@@ -3677,21 +3677,6 @@ macro(qt6_standard_project_setup)
if(NOT DEFINED QT_I18N_SOURCE_LANGUAGE)
set(QT_I18N_SOURCE_LANGUAGE ${__qt_sps_arg_I18N_SOURCE_LANGUAGE})
endif()
-
- if(CMAKE_GENERATOR STREQUAL "Xcode")
- # Ensure we always use device SDK for Xcode for single-arch Qt builds
- set(qt_osx_arch_count 0)
- if(QT_OSX_ARCHITECTURES)
- list(LENGTH QT_OSX_ARCHITECTURES qt_osx_arch_count)
- endif()
- if(NOT qt_osx_arch_count GREATER 1 AND "${CMAKE_OSX_SYSROOT}" MATCHES "^[a-z]+simulator$")
- # Xcode expects the base SDK to be the device SDK
- set(simulator_sysroot "${CMAKE_OSX_SYSROOT}")
- string(REGEX REPLACE "simulator" "os" CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}")
- set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT}" CACHE STRING "" FORCE)
- set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "${simulator_sysroot}")
- endif()
- endif()
endif()
endmacro()
diff --git a/src/corelib/configure.cmake b/src/corelib/configure.cmake
index 7216f2920fe..90a0e359c9f 100644
--- a/src/corelib/configure.cmake
+++ b/src/corelib/configure.cmake
@@ -1278,14 +1278,13 @@ qt_feature("permissions" PUBLIC
)
qt_feature("openssl-hash" PRIVATE
LABEL "OpenSSL based cryptographic hash"
- AUTODETECT OFF
CONDITION QT_FEATURE_openssl_linked AND QT_FEATURE_opensslv30
PURPOSE "Uses OpenSSL based implementation of cryptographic hash algorithms."
)
qt_feature("async-io" PRIVATE
LABEL "Async File I/O"
PURPOSE "Provides support for asynchronous file I/O."
- CONDITION (QT_FEATURE_thread AND QT_FEATURE_future) OR APPLE
+ CONDITION (QT_FEATURE_thread AND QT_FEATURE_future) OR APPLE OR (LINUX AND QT_FEATURE_liburing) OR (WIN32 AND QT_FEATURE_windows_ioring)
)
qt_configure_add_summary_section(NAME "Qt Core")
diff --git a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
index 0a0dc0b3c50..42cb3ecb42b 100644
--- a/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
+++ b/src/corelib/doc/src/cmake/cmake-configure-variables.qdoc
@@ -133,7 +133,6 @@ use, for example, library files referenced from a Qt installation.
\summary {Forces or disables release package signing regardless of the build type.}
\cmakevariablesince 6.7
-\preliminarycmakevariable
\cmakevariableandroidonly
When set to \c Release, the \c --release flag is passed to the \c
diff --git a/src/corelib/doc/src/external-resources.qdoc b/src/corelib/doc/src/external-resources.qdoc
index 2232b49bf23..5d357c65496 100644
--- a/src/corelib/doc/src/external-resources.qdoc
+++ b/src/corelib/doc/src/external-resources.qdoc
@@ -28,11 +28,6 @@
*/
/*!
- \externalpage https://marcmutz.wordpress.com/effective-qt/containers/#containers-qlist
- \title Pros and Cons of Using QList
-*/
-
-/*!
\externalpage https://marcmutz.wordpress.com/effective-qt/containers/
\title Understand the Qt Containers
*/
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index d27a71526d8..32364fa8eb4 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -486,6 +486,12 @@ const QOperatingSystemVersionBase QOperatingSystemVersion::Windows11_22H2;
*/
/*!
+ \variable QOperatingSystemVersion::Windows11_25H2
+ \brief a version corresponding to Windows 11 Version 25H2 (version 10.0.26200).
+ \since 6.11
+ */
+
+/*!
\variable QOperatingSystemVersion::OSXMavericks
\brief a version corresponding to OS X Mavericks (version 10.9).
\since 5.9
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
index 75801a7ddcf..99866692f8c 100644
--- a/src/corelib/global/qoperatingsystemversion.h
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -148,6 +148,7 @@ public:
static constexpr QOperatingSystemVersionBase Android14 { QOperatingSystemVersionBase::Android, 14, 0 };
static constexpr QOperatingSystemVersionBase Windows11_23H2 { QOperatingSystemVersionBase::Windows, 10, 0, 22631 };
static constexpr QOperatingSystemVersionBase Windows11_24H2 { QOperatingSystemVersionBase::Windows, 10, 0, 26100 };
+ static constexpr QOperatingSystemVersionBase Windows11_25H2 { QOperatingSystemVersionBase::Windows, 10, 0, 26200 };
#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) && !defined(Q_QDOC)
};
diff --git a/src/corelib/global/qttranslation.qdoc b/src/corelib/global/qttranslation.qdoc
index 191b3777db6..c8b3764614e 100644
--- a/src/corelib/global/qttranslation.qdoc
+++ b/src/corelib/global/qttranslation.qdoc
@@ -179,7 +179,7 @@
\fn QString qTrId(const char *id, int n = -1)
\relates <QtTranslation>
\reentrant
- \since 6.9
+ \since 6.11
\brief The qTrId function is an alias for qtTrId.
diff --git a/src/corelib/io/qrandomaccessasyncfile_darwin.mm b/src/corelib/io/qrandomaccessasyncfile_darwin.mm
index 7231d12fe7d..fca225263ba 100644
--- a/src/corelib/io/qrandomaccessasyncfile_darwin.mm
+++ b/src/corelib/io/qrandomaccessasyncfile_darwin.mm
@@ -95,10 +95,8 @@ void QRandomAccessAsyncFilePrivate::close()
// cancel all operations
m_mutex.lock();
m_opToCancel = kAllOperationIds;
- m_numChannelsToClose = m_ioChannel ? 1 : 0;
for (const auto &op : m_operations) {
if (op.channel) {
- ++m_numChannelsToClose;
closeIoChannel(op.channel);
}
}
@@ -212,8 +210,8 @@ QRandomAccessAsyncFilePrivate::writeFrom(qint64 offset, QSpan<const QSpan<const
void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted()
{
QMutexLocker locker(&m_mutex);
+ --m_numChannelsToClose;
if (m_opToCancel == kAllOperationIds) {
- --m_numChannelsToClose;
if (m_numChannelsToClose == 0 && m_runningOps.isEmpty())
m_cancellationCondition.wakeOne();
}
@@ -222,11 +220,19 @@ void QRandomAccessAsyncFilePrivate::notifyIfOperationsAreCompleted()
dispatch_io_t QRandomAccessAsyncFilePrivate::createMainChannel(int fd)
{
auto sharedThis = this;
- return dispatch_io_create(DISPATCH_IO_RANDOM, fd,
- dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
- ^(int /*error*/) {
- sharedThis->notifyIfOperationsAreCompleted();
- });
+ auto channel =
+ dispatch_io_create(DISPATCH_IO_RANDOM, fd,
+ dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0),
+ ^(int /*error*/) {
+ // main I/O channel uses kInvalidOperationId
+ // as its identifier
+ sharedThis->notifyIfOperationsAreCompleted();
+ });
+ if (channel) {
+ QMutexLocker locker(&m_mutex);
+ ++m_numChannelsToClose;
+ }
+ return channel;
}
dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId)
@@ -247,6 +253,7 @@ dispatch_io_t QRandomAccessAsyncFilePrivate::duplicateIoChannel(OperationId opId
if (channel) {
QMutexLocker locker(&m_mutex);
m_runningOps.insert(opId);
+ ++m_numChannelsToClose;
}
return channel;
}
@@ -593,6 +600,7 @@ void QRandomAccessAsyncFilePrivate::executeOpen(OperationInfo &opInfo)
// So we need to notify the condition variable in
// both cases.
Q_ASSERT(sharedThis->m_runningOps.isEmpty());
+ Q_ASSERT(sharedThis->m_numChannelsToClose == 0);
sharedThis->m_cancellationCondition.wakeOne();
} else {
auto context = sharedThis->q_ptr;
diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h
index f6b08099fe7..7eca3094a66 100644
--- a/src/corelib/itemmodels/qrangemodel_impl.h
+++ b/src/corelib/itemmodels/qrangemodel_impl.h
@@ -239,17 +239,15 @@ namespace QRangeModelDetails
: std::true_type
{};
- // we use std::rotate in moveRows/Columns, which requires std::swap and the
- // iterators to be at least a forward iterator
- template <typename It, typename = void>
- struct test_rotate : std::false_type {};
-
+ // we use std::rotate in moveRows/Columns, which requires the values (which
+ // might be const if we only get a const iterator) to be swappable, and the
+ // iterator type to be at least a forward iterator
template <typename It>
- struct test_rotate<It, std::void_t<decltype(std::swap(*std::declval<It>(),
- *std::declval<It>()))>>
- : std::is_base_of<std::forward_iterator_tag,
- typename std::iterator_traits<It>::iterator_category>
- {};
+ using test_rotate = std::conjunction<
+ std::is_swappable<decltype(*std::declval<It>())>,
+ std::is_base_of<std::forward_iterator_tag,
+ typename std::iterator_traits<It>::iterator_category>
+ >;
template <typename C, typename = void>
struct test_splice : std::false_type {};
diff --git a/src/corelib/itemmodels/qrangemodeladapter.h b/src/corelib/itemmodels/qrangemodeladapter.h
index bd3342e6185..0234c402248 100644
--- a/src/corelib/itemmodels/qrangemodeladapter.h
+++ b/src/corelib/itemmodels/qrangemodeladapter.h
@@ -19,13 +19,11 @@ class QT_TECH_PREVIEW_API QRangeModelAdapter
#ifdef Q_QDOC
using range_type = Range;
- using const_row_reference = typename std::iterator_traits<Range>::const_reference;
- using row_reference = typename std::iterator_traits<Range>::reference;
#else
using range_type = QRangeModelDetails::wrapped_t<Range>;
+#endif
using const_row_reference = typename Impl::const_row_reference;
using row_reference = typename Impl::row_reference;
-#endif
using range_features = typename QRangeModelDetails::range_traits<range_type>;
using row_type = std::remove_reference_t<row_reference>;
using row_features = QRangeModelDetails::range_traits<typename Impl::wrapped_row_type>;
@@ -78,16 +76,22 @@ class QT_TECH_PREVIEW_API QRangeModelAdapter
template <typename C>
using if_compatible_row_range = std::enable_if_t<is_compatible_row_range<C>, bool>;
template <typename Data>
- static constexpr bool is_compatible_data = true;
- // std::is_convertible_v<Data, decltype(*std::begin(std::declval<const_row_reference>()))>;
+ static constexpr bool is_compatible_data = std::is_convertible_v<Data, data_type>;
template <typename Data>
using if_compatible_data = std::enable_if_t<is_compatible_data<Data>, bool>;
template <typename C>
static constexpr bool is_compatible_data_range = is_compatible_data<
+ typename QRangeModelDetails::data_type<
+ typename QRangeModelDetails::row_traits<
decltype(*std::begin(std::declval<C&>()))
- >;
+ >::item_type
+ >::type
+ >;
template <typename C>
- using if_compatible_data_range = std::enable_if_t<is_compatible_data_range<C>, bool>;
+ using if_compatible_column_data = std::enable_if_t<is_compatible_data<C>
+ || is_compatible_data_range<C>, bool>;
+ template <typename C>
+ using if_compatible_column_range = std::enable_if_t<is_compatible_data_range<C>, bool>;
template <typename R>
using if_assignable_range = std::enable_if_t<std::is_assignable_v<range_type, R>, bool>;
@@ -141,6 +145,7 @@ public:
}
DataReference(const DataReference &other) = default;
+ DataReference(DataReference &&other) = default;
// reference (not std::reference_wrapper) semantics
DataReference &operator=(const DataReference &other)
@@ -149,29 +154,23 @@ public:
return *this;
}
+ DataReference &operator=(DataReference &&other)
+ {
+ *this = other.get();
+ return *this;
+ }
+
~DataReference() = default;
DataReference &operator=(const value_type &value)
{
- constexpr Qt::ItemDataRole dataRole = Qt::RangeModelAdapterRole;
+ assign(value);
+ return *this;
+ }
- if (m_index.isValid()) {
- auto model = const_cast<QAbstractItemModel *>(m_index.model());
- [[maybe_unused]] bool couldWrite = false;
- if constexpr (std::is_same_v<q20::remove_cvref_t<value_type>, QVariant>)
- couldWrite = model->setData(m_index, value, dataRole);
- else
- couldWrite = model->setData(m_index, QVariant::fromValue(value), dataRole);
-#ifndef QT_NO_DEBUG
- if (!couldWrite) {
- qWarning() << "Writing value of type" << QMetaType::fromType<value_type>().name()
- << "to role" << dataRole << "at index" << m_index
- << "of the model failed";
- }
- } else {
- qCritical("Data reference for invalid index, can't write to model");
-#endif
- }
+ DataReference &operator=(value_type &&value)
+ {
+ assign(std::move(value));
return *this;
}
@@ -196,6 +195,33 @@ public:
private:
QModelIndex m_index;
+ template <typename Value>
+ void assign(Value &&value)
+ {
+ constexpr Qt::ItemDataRole dataRole = Qt::RangeModelAdapterRole;
+
+ if (m_index.isValid()) {
+ auto model = const_cast<QAbstractItemModel *>(m_index.model());
+ [[maybe_unused]] bool couldWrite = false;
+ if constexpr (std::is_same_v<q20::remove_cvref_t<Value>, QVariant>) {
+ couldWrite = model->setData(m_index, value, dataRole);
+ } else {
+ couldWrite = model->setData(m_index,
+ QVariant::fromValue(std::forward<Value>(value)),
+ dataRole);
+ }
+#ifndef QT_NO_DEBUG
+ if (!couldWrite) {
+ qWarning() << "Writing value of type"
+ << QMetaType::fromType<q20::remove_cvref_t<Value>>().name()
+ << "to role" << dataRole << "at index" << m_index << "failed";
+ }
+ } else {
+ qCritical("Data reference for invalid index, can't write to model");
+#endif
+ }
+ }
+
friend inline bool comparesEqual(const DataReference &lhs, const DataReference &rhs)
{
return lhs.m_index == rhs.m_index
@@ -1020,60 +1046,55 @@ public:
template <typename NewRange = range_type, if_assignable_range<NewRange> = true>
void setRange(NewRange &&newRange)
{
- using namespace QRangeModelDetails;
-
- auto *impl = storage.implementation();
- const QModelIndex root = storage.root();
- const qsizetype newLastRow = qsizetype(Impl::size(refTo(newRange))) - 1;
- auto *oldRange = impl->childRange(root);
- const qsizetype oldLastRow = qsizetype(Impl::size(oldRange)) - 1;
-
- if (!root.isValid()) {
- impl->beginResetModel();
- impl->deleteOwnedRows();
- } else if constexpr (is_tree<Impl>) {
- if (oldLastRow > 0) {
- impl->beginRemoveRows(root, 0, model()->rowCount(root) - 1);
- impl->deleteRemovedRows(refTo(oldRange));
- impl->endRemoveRows();
- }
- if (newLastRow > 0)
- impl->beginInsertRows(root, 0, newLastRow);
- } else {
- Q_ASSERT_X(false, "QRangeModelAdapter::setRange",
- "Internal error: The root index in a table or list must be invalid.");
- }
- refTo(oldRange) = std::forward<NewRange>(newRange);
- if (!root.isValid()) {
- impl->endResetModel();
- } else if constexpr (is_tree<Impl>) {
- if (newLastRow > 0) {
- Q_ASSERT(model()->hasChildren(root));
- // if it was moved, then newRange is now likely to be empty. Get
- // the inserted row.
- impl->setParentRow(refTo(impl->childRange(storage.root())),
- pointerTo(impl->rowData(root)));
- impl->endInsertRows();
- }
- }
- if constexpr (Impl::itemsAreQObjects) {
- if (model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
- const auto begin = QRangeModelDetails::begin(refTo(oldRange));
- const auto end = QRangeModelDetails::end(refTo(oldRange));
- int rowIndex = 0;
- for (auto it = begin; it != end; ++it, ++rowIndex)
- impl->autoConnectPropertiesInRow(*it, rowIndex, root);
- }
- }
+ setRangeImpl(qsizetype(Impl::size(QRangeModelDetails::refTo(newRange))) - 1,
+ [&newRange](auto &oldRange) {
+ oldRange = std::forward<NewRange>(newRange);
+ });
}
- template <typename NewRange = range_type, if_assignable_range<NewRange> = true>
+ template <typename NewRange = range_type, if_assignable_range<NewRange> = true,
+ unless_adapter<NewRange> = true>
QRangeModelAdapter &operator=(NewRange &&newRange)
{
setRange(std::forward<NewRange>(newRange));
return *this;
}
+ template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
+ void setRange(std::initializer_list<Row> newRange)
+ {
+ setRangeImpl(qsizetype(newRange.size() - 1), [&newRange](auto &oldRange) {
+ oldRange = newRange;
+ });
+ }
+
+ template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
+ QRangeModelAdapter &operator=(std::initializer_list<Row> newRange)
+ {
+ setRange(newRange);
+ return *this;
+ }
+
+ template <typename Row, if_assignable_range<std::initializer_list<Row>> = true>
+ void assign(std::initializer_list<Row> newRange)
+ {
+ setRange(newRange);
+ }
+
+ template <typename InputIterator, typename Sentinel, typename I = Impl, if_writable<I> = true>
+ void setRange(InputIterator first, Sentinel last)
+ {
+ setRangeImpl(qsizetype(std::distance(first, last) - 1), [first, last](auto &oldRange) {
+ oldRange.assign(first, last);
+ });
+ }
+
+ template <typename InputIterator, typename Sentinel, typename I = Impl, if_writable<I> = true>
+ void assign(InputIterator first, Sentinel last)
+ {
+ setRange(first, last);
+ }
+
// iterator API
ConstRowIterator cbegin() const
{
@@ -1245,12 +1266,12 @@ public:
decltype(auto) operator[](int row) const { return at(row); }
template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
- decltype(auto) at(int row)
+ auto at(int row)
{
return RowReference{index(row, 0), this};
}
template <typename I = Impl, if_table<I> = true, if_writable<I> = true>
- decltype(auto) operator[](int row) { return at(row); }
+ auto operator[](int row) { return at(row); }
// at/operator[int, int] for table: returns value at row/column
template <typename I = Impl, unless_list<I> = true>
@@ -1428,15 +1449,15 @@ public:
return storage.m_model->insertColumn(before);
}
- template <typename D = row_type, typename I = Impl,
- if_canInsertColumns<I> = true, if_compatible_data<D> = true>
+ template <typename D, typename I = Impl,
+ if_canInsertColumns<I> = true, if_compatible_column_data<D> = true>
bool insertColumn(int before, D &&data)
{
return insertColumnImpl(before, storage.root(), std::forward<D>(data));
}
template <typename C, typename I = Impl,
- if_canInsertColumns<I> = true, if_compatible_data_range<C> = true>
+ if_canInsertColumns<I> = true, if_compatible_column_range<C> = true>
bool insertColumns(int before, C &&data)
{
return insertColumnsImpl(before, storage.root(), std::forward<C>(data));
@@ -1503,6 +1524,65 @@ private:
Q_EMIT storage.implementation()->dataChanged(topLeft, bottomRight, {});
}
+ void beginSetRangeImpl(Impl *impl, range_type *oldRange, qsizetype newLastRow)
+ {
+ const QModelIndex root = storage.root();
+ const qsizetype oldLastRow = qsizetype(Impl::size(oldRange)) - 1;
+
+ if (!root.isValid()) {
+ impl->beginResetModel();
+ impl->deleteOwnedRows();
+ } else if constexpr (is_tree<Impl>) {
+ if (oldLastRow > 0) {
+ impl->beginRemoveRows(root, 0, model()->rowCount(root) - 1);
+ impl->deleteRemovedRows(QRangeModelDetails::refTo(oldRange));
+ impl->endRemoveRows();
+ }
+ if (newLastRow > 0)
+ impl->beginInsertRows(root, 0, newLastRow);
+ } else {
+ Q_ASSERT_X(false, "QRangeModelAdapter::setRange",
+ "Internal error: The root index in a table or list must be invalid.");
+ }
+ }
+
+ void endSetRangeImpl(Impl *impl, qsizetype newLastRow)
+ {
+ const QModelIndex root = storage.root();
+ if (!root.isValid()) {
+ impl->endResetModel();
+ } else if constexpr (is_tree<Impl>) {
+ if (newLastRow > 0) {
+ Q_ASSERT(model()->hasChildren(root));
+ // if it was moved, then newRange is now likely to be empty. Get
+ // the inserted row.
+ impl->setParentRow(QRangeModelDetails::refTo(impl->childRange(root)),
+ QRangeModelDetails::pointerTo(impl->rowData(root)));
+ impl->endInsertRows();
+ }
+ }
+ }
+
+ template <typename Assigner>
+ void setRangeImpl(qsizetype newLastRow, Assigner &&assigner)
+ {
+ auto *impl = storage.implementation();
+ auto *oldRange = impl->childRange(storage.root());
+ beginSetRangeImpl(impl, oldRange, newLastRow);
+ assigner(QRangeModelDetails::refTo(oldRange));
+ endSetRangeImpl(impl, newLastRow);
+
+ if constexpr (Impl::itemsAreQObjects) {
+ if (model()->autoConnectPolicy() == QRangeModel::AutoConnectPolicy::Full) {
+ const auto begin = QRangeModelDetails::begin(QRangeModelDetails::refTo(oldRange));
+ const auto end = QRangeModelDetails::end(QRangeModelDetails::refTo(oldRange));
+ int rowIndex = 0;
+ for (auto it = begin; it != end; ++it, ++rowIndex)
+ impl->autoConnectPropertiesInRow(*it, rowIndex, storage.root());
+ }
+ }
+ }
+
template <typename P>
static auto setParentRow(P protocol, row_type &newRow, row_ptr parentRow)
-> decltype(protocol.setParentRow(std::declval<row_type&>(), std::declval<row_ptr>()))
diff --git a/src/corelib/itemmodels/qrangemodeladapter.qdoc b/src/corelib/itemmodels/qrangemodeladapter.qdoc
index 263bff0dd0c..88872589299 100644
--- a/src/corelib/itemmodels/qrangemodeladapter.qdoc
+++ b/src/corelib/itemmodels/qrangemodeladapter.qdoc
@@ -277,14 +277,6 @@
*/
/*!
- \typedef QRangeModelAdapter::const_row_reference
-*/
-
-/*!
- \typedef QRangeModelAdapter::row_reference
-*/
-
-/*!
\typedef QRangeModelAdapter::range_type
*/
@@ -329,16 +321,39 @@
/*!
\fn template <typename Range, typename Protocol, typename Model> template <typename NewRange, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<NewRange>> void QRangeModelAdapter<Range, Protocol, Model>::setRange(NewRange &&newRange)
- \fn template <typename Range, typename Protocol, typename Model> template <typename NewRange, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<NewRange>> QRangeModelAdapter &QRangeModelAdapter<Range, Protocol, Model>::operator=(NewRange &&newRange)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename NewRange, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<NewRange>, QRangeModelAdapter<Range, Protocol, Model>::unless_adapter<NewRange>> QRangeModelAdapter &QRangeModelAdapter<Range, Protocol, Model>::operator=(NewRange &&newRange)
+
+ Replaces the contents of the model with the rows in \a newRange, possibly
+ using move semantics.
- Assigns \a newRange to the stored range, possibly using move semantics.
This function makes the model() emit the \l{QAbstractItemModel::}{modelAboutToBeReset()}
and \l{QAbstractItemModel::}{modelReset()} signals.
\constraints \c Range is mutable, and \a newRange is of a type that can be
- assigned to \c Range.
+ assigned to \c Range, but not a QRangeModelAdapter.
+
+ \sa range(), at(), model(), assign()
+*/
+
+/*!
+ \fn template <typename Range, typename Protocol, typename Model> template <typename Row, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<std::initializer_list<Row>>> void QRangeModelAdapter<Range, Protocol, Model>::setRange(std::initializer_list<Row> newRange)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename Row, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<std::initializer_list<Row>>> QRangeModelAdapter &QRangeModelAdapter<Range, Protocol, Model>::assign(std::initializer_list<Row> newRange)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename Row, QRangeModelAdapter<Range, Protocol, Model>::if_assignable_range<std::initializer_list<Row>>> QRangeModelAdapter &QRangeModelAdapter<Range, Protocol, Model>::operator=(std::initializer_list<Row> newRange)
+
+ Replaces the contents of the model with the rows in \a newRange.
- \sa range(), at(), model()
+ \constraints \c Range is mutable, and \a newRange can be assigned to \c Range.
+
+ \sa range(), at, model()
+*/
+
+/*!
+ \fn template <typename Range, typename Protocol, typename Model> template <typename InputIterator, typename Sentinel, typename I = Impl, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> void QRangeModelAdapter<Range, Protocol, Model>::setRange(InputIterator first, Sentinel last)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename InputIterator, typename Sentinel, typename I = Impl, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> void QRangeModelAdapter<Range, Protocol, Model>::assign(InputIterator first, Sentinel last)
+
+ Replaces the contents of the models with the rows in the range [\a first, \a last).
+
+ \sa range(), at, model()
*/
/*!
@@ -508,8 +523,8 @@
*/
/*!
- \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> QRangeModelAdapter<Range, Protocol, Model>::const_row_reference QRangeModelAdapter<Range, Protocol, Model>::at(int row) const
- \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> QRangeModelAdapter<Range, Protocol, Model>::const_row_reference QRangeModelAdapter<Range, Protocol, Model>::operator[](int row) const
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::at(int row) const
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::unless_list<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::operator[](int row) const
\return a constant reference to the row at \a row, as stored in \c Range.
@@ -517,8 +532,8 @@
*/
/*!
- \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> QRangeModelAdapter<Range, Protocol, Model>::row_reference QRangeModelAdapter<Range, Protocol, Model>::at(int row)
- \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> QRangeModelAdapter<Range, Protocol, Model>::row_reference QRangeModelAdapter<Range, Protocol, Model>::operator[](int row)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::at(int row)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_table<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::operator[](int row)
\return a mutable reference to the row at \a row, as stored in \c Range.
@@ -574,6 +589,16 @@
*/
/*!
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::at(QSpan<const int> path) const
+ \fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>> decltype(auto) QRangeModelAdapter<Range, Protocol, Model>::operator[](QSpan<const int> path) const
+
+ \return a constant reference to the row specified by \a path, as stored in
+ \c Range.
+
+ \constraints \c Range is a tree.
+*/
+
+/*!
\fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::at(QSpan<const int> path)
\fn template <typename Range, typename Protocol, typename Model> template <typename I, QRangeModelAdapter<Range, Protocol, Model>::if_tree<I>, QRangeModelAdapter<Range, Protocol, Model>::if_writable<I>> auto QRangeModelAdapter<Range, Protocol, Model>::operator[](QSpan<const int> path)
@@ -810,7 +835,7 @@
*/
/*!
- \fn template <typename Range, typename Protocol, typename Model> template <typename D, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_data<D>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumn(int before, D &&data)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename D, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_column_data<D>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumn(int before, D &&data)
\overload
Inserts a single column constructed from \a data before the column specified
@@ -838,7 +863,7 @@
*/
/*!
- \fn template <typename Range, typename Protocol, typename Model> template <typename C, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_data_range<C>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumns(int before, C &&data)
+ \fn template <typename Range, typename Protocol, typename Model> template <typename C, typename I, QRangeModelAdapter<Range, Protocol, Model>::if_canInsertColumns<I>, QRangeModelAdapter<Range, Protocol, Model>::if_compatible_column_range<C>> bool QRangeModelAdapter<Range, Protocol, Model>::insertColumns(int before, C &&data)
Inserts columns constructed from the elements in \a data before the column
specified by \a before into all rows, and returns whether the insertion was
diff --git a/src/corelib/kernel/qassociativeiterable.h b/src/corelib/kernel/qassociativeiterable.h
index 39f66d45fa0..4f9bbf67bfb 100644
--- a/src/corelib/kernel/qassociativeiterable.h
+++ b/src/corelib/kernel/qassociativeiterable.h
@@ -156,10 +156,12 @@ inline QVariantRef<QAssociativeIterator>::operator QVariant() const
if (!metaType.isValid())
return m_pointer->key();
+ return [&] {
QVariant v(metaType);
metaAssociation.mappedAtIterator(m_pointer->constIterator(),
metaType == QMetaType::fromType<QVariant>() ? &v : v.data());
return v;
+ }();
}
template<>
diff --git a/src/corelib/kernel/qcore_mac.mm b/src/corelib/kernel/qcore_mac.mm
index 687fc7e85fa..f5f1f4a8cb8 100644
--- a/src/corelib/kernel/qcore_mac.mm
+++ b/src/corelib/kernel/qcore_mac.mm
@@ -22,6 +22,10 @@
#include <spawn.h>
#include <qdebug.h>
+#include <qpoint.h>
+#include <qsize.h>
+#include <qrect.h>
+#include <qmargins.h>
#include "qendian.h"
#include "qhash.h"
@@ -222,6 +226,34 @@ QDebug operator<<(QDebug dbg, CFStringRef stringRef)
return dbg;
}
+QDebug operator<<(QDebug dbg, CGPoint point)
+{
+ dbg << QPointF::fromCGPoint(point);
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, CGSize size)
+{
+ dbg << QSizeF::fromCGSize(size);
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, CGRect rect)
+{
+ dbg << QRectF::fromCGRect(rect);
+ return dbg;
+}
+
+#if defined(Q_OS_MACOS)
+QDebug operator<<(QDebug dbg, NSEdgeInsets insets)
+#else
+QDebug operator<<(QDebug dbg, UIEdgeInsets insets)
+#endif
+{
+ dbg << QMargins(insets.left, insets.top, insets.right, insets.bottom);
+ return dbg;
+}
+
// Prevents breaking the ODR in case we introduce support for more types
// later on, and lets the user override our default QDebug operators.
#define QT_DECLARE_WEAK_QDEBUG_OPERATOR_FOR_CF_TYPE(CFType) \
diff --git a/src/corelib/kernel/qcore_mac_p.h b/src/corelib/kernel/qcore_mac_p.h
index 2c4b4c02c55..1e57ee01e1d 100644
--- a/src/corelib/kernel/qcore_mac_p.h
+++ b/src/corelib/kernel/qcore_mac_p.h
@@ -78,6 +78,15 @@ kern_return_t IOObjectRelease(io_object_t object);
Q_FORWARD_DECLARE_OBJC_CLASS(NSObject);
Q_FORWARD_DECLARE_OBJC_CLASS(NSString);
+struct CGPoint;
+struct CGSize;
+struct CGRect;
+#if defined(Q_OS_MACOS)
+struct NSEdgeInsets;
+#else
+struct UIEdgeInsets;
+#endif
+
// @compatibility_alias doesn't work with categories or their methods
#define QtExtras QT_MANGLE_NAMESPACE(QtExtras)
@@ -225,6 +234,14 @@ Q_AUTOTEST_EXPORT void qt_mac_ensureResponsible();
#ifndef QT_NO_DEBUG_STREAM
Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QMacAutoReleasePool *pool);
Q_CORE_EXPORT QDebug operator<<(QDebug debug, const QCFString &string);
+Q_CORE_EXPORT QDebug operator<<(QDebug, CGPoint);
+Q_CORE_EXPORT QDebug operator<<(QDebug, CGSize);
+Q_CORE_EXPORT QDebug operator<<(QDebug, CGRect);
+#if defined(Q_OS_MACOS)
+Q_CORE_EXPORT QDebug operator<<(QDebug, NSEdgeInsets);
+#else
+Q_CORE_EXPORT QDebug operator<<(QDebug, UIEdgeInsets);
+#endif
#endif
Q_CORE_EXPORT bool qt_apple_isApplicationExtension();
diff --git a/src/corelib/kernel/qiterable.h b/src/corelib/kernel/qiterable.h
index baab2897967..494cec73a3f 100644
--- a/src/corelib/kernel/qiterable.h
+++ b/src/corelib/kernel/qiterable.h
@@ -502,7 +502,10 @@ public:
if (m_metaContainer.hasSize())
return m_metaContainer.size(container);
- // ### Qt7: Return -1 here. We shouldn't second-guess the underlying container
+#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
+ // We shouldn't second-guess the underlying container, so we're not synthesizing a size.
+ return -1;
+#else
QtPrivate::warnSynthesizedAccess(
"size() called on an iterable without native size accessor. This is slow");
@@ -515,6 +518,7 @@ public:
m_metaContainer.destroyConstIterator(begin);
m_metaContainer.destroyConstIterator(end);
return size;
+#endif
}
void clear()
diff --git a/src/corelib/kernel/qmetaassociation.h b/src/corelib/kernel/qmetaassociation.h
index 6d8de13e90a..d481ae91079 100644
--- a/src/corelib/kernel/qmetaassociation.h
+++ b/src/corelib/kernel/qmetaassociation.h
@@ -25,8 +25,8 @@ public:
using reference = QVariant::Reference<AssociativeIterator>;
using pointer = QVariant::Pointer<AssociativeIterator>;
- static constexpr bool canNoexceptAssignQVariant = false;
- static constexpr bool canNoexceptConvertToQVariant = false;
+ static constexpr bool CanNoexceptAssignQVariant = false;
+ static constexpr bool CanNoexceptConvertToQVariant = false;
AssociativeIterator(QIterator &&it) : QIterator(std::move(it)) {}
@@ -51,7 +51,7 @@ public:
using reference = QVariant::ConstReference<AssociativeConstIterator>;
using pointer = QVariant::ConstPointer<AssociativeConstIterator>;
- static constexpr bool canNoexceptConvertToQVariant = false;
+ static constexpr bool CanNoexceptConvertToQVariant = false;
AssociativeConstIterator(QConstIterator &&it) : QConstIterator(std::move(it)) {}
diff --git a/src/corelib/kernel/qmetasequence.h b/src/corelib/kernel/qmetasequence.h
index e9505054159..26156e7924f 100644
--- a/src/corelib/kernel/qmetasequence.h
+++ b/src/corelib/kernel/qmetasequence.h
@@ -24,8 +24,8 @@ public:
using reference = QVariant::Reference<SequentialIterator>;
using pointer = QVariant::Pointer<SequentialIterator>;
- static constexpr bool canNoexceptAssignQVariant = false;
- static constexpr bool canNoexceptConvertToQVariant = false;
+ static constexpr bool CanNoexceptAssignQVariant = false;
+ static constexpr bool CanNoexceptConvertToQVariant = false;
SequentialIterator(QIterator &&it) : QIterator(std::move(it)) {}
@@ -41,7 +41,7 @@ public:
using reference = QVariant::ConstReference<SequentialConstIterator>;
using pointer = QVariant::ConstPointer<SequentialConstIterator>;
- static constexpr bool canNoexceptConvertToQVariant = false;
+ static constexpr bool CanNoexceptConvertToQVariant = false;
SequentialConstIterator(QConstIterator &&it) : QConstIterator(std::move(it)) {}
@@ -184,13 +184,15 @@ public:
return;
}
- // ### Qt7: Drop this code. We shouldn't second-guess the underlying container
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ // We shouldn't second-guess the underlying container.
QtPrivate::warnSynthesizedAccess(
"at() called on an iterable without native indexed accessors. This is slow");
void *it = meta.constBegin(m_iterable.constPointer());
meta.advanceConstIterator(it, idx);
meta.valueAtConstIterator(it, dataPtr);
meta.destroyConstIterator(it);
+#endif
});
}
@@ -204,13 +206,15 @@ public:
return;
}
- // ### Qt7: Drop this code. We shouldn't second-guess the underlying container
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ // We shouldn't second-guess the underlying container
QtPrivate::warnSynthesizedAccess(
"set() called on an iterable without native indexed accessors. This is slow");
void *it = meta.begin(m_iterable.mutablePointer());
meta.advanceIterator(it, idx);
meta.setValueAtIterator(it, dataPtr);
meta.destroyIterator(it);
+#endif
}
void append(const QVariant &value)
@@ -248,55 +252,14 @@ public:
Unspecified, AtBegin, AtEnd
};
- QT_DEPRECATED_VERSION_X_6_11("Use append() or prepend() instead.")
void addValue(const QVariant &value, Position position = Unspecified)
- {
- const QMetaSequence meta = metaContainer();
- QtPrivate::QVariantTypeCoercer coercer;
- const void *valuePtr = coercer.coerce(value, meta.valueMetaType());
-
- switch (position) {
- case AtBegin:
- if (meta.canAddValueAtBegin())
- meta.addValueAtBegin(mutableIterable(), valuePtr);
- break;
- case AtEnd:
- if (meta.canAddValueAtEnd())
- meta.addValueAtEnd(mutableIterable(), valuePtr);
- break;
- case Unspecified:
- if (meta.canAddValue())
- meta.addValue(mutableIterable(), valuePtr);
- break;
- }
- }
+ Q_DECL_EQ_DELETE_X("Use append() or prepend() instead.");
- QT_DEPRECATED_VERSION_X_6_11("Use removeLast() or removeFirst() instead.")
void removeValue(Position position = Unspecified)
- {
- const QMetaSequence meta = metaContainer();
+ Q_DECL_EQ_DELETE_X("Use removeLast() or removeFirst() instead.");
- switch (position) {
- case AtBegin:
- if (meta.canRemoveValueAtBegin())
- meta.removeValueAtBegin(mutableIterable());
- break;
- case AtEnd:
- if (meta.canRemoveValueAtEnd())
- meta.removeValueAtEnd(mutableIterable());
- break;
- case Unspecified:
- if (meta.canRemoveValue())
- meta.removeValue(mutableIterable());
- break;
- }
- }
-
- QT_DEPRECATED_VERSION_X_6_11("Use QMetaSequence::valueMetaType() instead.")
QMetaType valueMetaType() const
- {
- return metaContainer().valueMetaType();
- }
+ Q_DECL_EQ_DELETE_X("Use QMetaSequence::valueMetaType() instead.");
QT_WARNING_POP
#endif // QT_DEPRECATED_SINCE(6, 11)
diff --git a/src/corelib/kernel/qsequentialiterable.h b/src/corelib/kernel/qsequentialiterable.h
index 92252cb19dd..76908bdae4b 100644
--- a/src/corelib/kernel/qsequentialiterable.h
+++ b/src/corelib/kernel/qsequentialiterable.h
@@ -142,10 +142,13 @@ inline QVariantRef<QSequentialIterator>::operator QVariant() const
if (m_pointer == nullptr)
return QVariant();
const QMetaType metaType(m_pointer->metaContainer().valueMetaType());
+
+ return [&] {
QVariant v(metaType);
void *dataPtr = metaType == QMetaType::fromType<QVariant>() ? &v : v.data();
m_pointer->metaContainer().valueAtIterator(m_pointer->constIterator(), dataPtr);
return v;
+ }();
}
template<>
diff --git a/src/corelib/kernel/qvariant.h b/src/corelib/kernel/qvariant.h
index 82eec0693d6..19cd1fea7fb 100644
--- a/src/corelib/kernel/qvariant.h
+++ b/src/corelib/kernel/qvariant.h
@@ -263,7 +263,7 @@ public:
ConstReference &operator=(ConstReference &&value) = delete;
// To be specialized for each Referred
- operator QVariant() const noexcept(Referred::canNoexceptConvertToQVariant);
+ operator QVariant() const noexcept(Referred::CanNoexceptConvertToQVariant);
};
template<typename Referred>
@@ -288,18 +288,18 @@ public:
~Reference() = default;
Reference &operator=(const Reference &value)
- noexcept(Referred::canNoexceptAssignQVariant)
+ noexcept(Referred::CanNoexceptAssignQVariant)
{
return operator=(QVariant(value));
}
Reference &operator=(Reference &&value)
- noexcept(Referred::canNoexceptAssignQVariant)
+ noexcept(Referred::CanNoexceptAssignQVariant)
{
return operator=(QVariant(value));
}
- operator QVariant() const noexcept(Referred::canNoexceptConvertToQVariant)
+ operator QVariant() const noexcept(Referred::CanNoexceptConvertToQVariant)
{
return ConstReference(m_referred);
}
@@ -313,7 +313,7 @@ public:
}
// To be specialized for each Referred
- Reference &operator=(const QVariant &value) noexcept(Referred::canNoexceptAssignQVariant);
+ Reference &operator=(const QVariant &value) noexcept(Referred::CanNoexceptAssignQVariant);
};
template<typename Pointed>
diff --git a/src/corelib/platform/windows/qbstr_p.h b/src/corelib/platform/windows/qbstr_p.h
index 21eecfe2df7..32b1aace76f 100644
--- a/src/corelib/platform/windows/qbstr_p.h
+++ b/src/corelib/platform/windows/qbstr_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2024 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
+// Qt-Security score:significant reason:default
#ifndef QBSTR_P_H
#define QBSTR_P_H
@@ -141,4 +142,4 @@ QT_END_NAMESPACE
#endif // Q_OS_WIN
-#endif // QCOMPTR_P_H
+#endif // QBSTR_P_H
diff --git a/src/corelib/platform/windows/qcomobject_p.h b/src/corelib/platform/windows/qcomobject_p.h
index bd6f81d1c28..b7a9c56555d 100644
--- a/src/corelib/platform/windows/qcomobject_p.h
+++ b/src/corelib/platform/windows/qcomobject_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2023 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
+// Qt-Security score:significant reason:default
#ifndef QCOMOBJECT_P_H
#define QCOMOBJECT_P_H
diff --git a/src/corelib/platform/windows/qcomptr_p.h b/src/corelib/platform/windows/qcomptr_p.h
index 2a69e7b6038..e640528d3c2 100644
--- a/src/corelib/platform/windows/qcomptr_p.h
+++ b/src/corelib/platform/windows/qcomptr_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2024 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
+// Qt-Security score:significant reason:default
#ifndef QCOMPTR_P_H
#define QCOMPTR_P_H
diff --git a/src/corelib/platform/windows/qcomvariant_p.h b/src/corelib/platform/windows/qcomvariant_p.h
index 34ce5f179ce..cc4ad104106 100644
--- a/src/corelib/platform/windows/qcomvariant_p.h
+++ b/src/corelib/platform/windows/qcomvariant_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2024 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
+// Qt-Security score:significant reason:default
#ifndef QCOMVARIANT_P_H
#define QCOMVARIANT_P_H
diff --git a/src/corelib/platform/windows/qfactorycacheregistration.cpp b/src/corelib/platform/windows/qfactorycacheregistration.cpp
index 6bd69c66d14..04c81b7b665 100644
--- a/src/corelib/platform/windows/qfactorycacheregistration.cpp
+++ b/src/corelib/platform/windows/qfactorycacheregistration.cpp
@@ -1,5 +1,6 @@
// Copyright (C) 2022 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
+// Qt-Security score:significant reason:default
#include "qfactorycacheregistration_p.h"
diff --git a/src/corelib/platform/windows/qfactorycacheregistration_p.h b/src/corelib/platform/windows/qfactorycacheregistration_p.h
index d0b19b995b4..f6e7d9eb064 100644
--- a/src/corelib/platform/windows/qfactorycacheregistration_p.h
+++ b/src/corelib/platform/windows/qfactorycacheregistration_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2022 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
+// Qt-Security score:significant reason:default
#ifndef QFACTORYCACHEREGISTRATION_P_H
#define QFACTORYCACHEREGISTRATION_P_H
diff --git a/src/corelib/platform/windows/qt_winrtbase_p.h b/src/corelib/platform/windows/qt_winrtbase_p.h
index 79c2bdf6b1c..69a602a59e0 100644
--- a/src/corelib/platform/windows/qt_winrtbase_p.h
+++ b/src/corelib/platform/windows/qt_winrtbase_p.h
@@ -1,5 +1,6 @@
// Copyright (C) 2022 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
+// Qt-Security score:significant reason:default
#ifndef QT_WINRTBASE_P_H
#define QT_WINRTBASE_P_H
diff --git a/src/corelib/serialization/qdatastream.cpp b/src/corelib/serialization/qdatastream.cpp
index ae3bed5b751..fd2f7faeee5 100644
--- a/src/corelib/serialization/qdatastream.cpp
+++ b/src/corelib/serialization/qdatastream.cpp
@@ -552,6 +552,7 @@ void QDataStream::setByteOrder(ByteOrder bo)
\value Qt_6_9
\value Qt_6_10
\value Qt_6_11
+ \value Qt_6_12
\omitvalue Qt_DefaultCompiledVersion
\sa setVersion(), version()
diff --git a/src/corelib/serialization/qdatastream.h b/src/corelib/serialization/qdatastream.h
index 04373fe9c8a..d6fcf17efcd 100644
--- a/src/corelib/serialization/qdatastream.h
+++ b/src/corelib/serialization/qdatastream.h
@@ -96,8 +96,9 @@ public:
Qt_6_9 = Qt_6_7,
Qt_6_10 = 23,
Qt_6_11 = 24,
- Qt_DefaultCompiledVersion = Qt_6_11
-#if QT_VERSION >= QT_VERSION_CHECK(6, 12, 0)
+ Qt_6_12 = Qt_6_11,
+ Qt_DefaultCompiledVersion = Qt_6_12
+#if QT_VERSION >= QT_VERSION_CHECK(6, 13, 0)
#error Add the datastream version for this Qt version and update Qt_DefaultCompiledVersion
#endif
};
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 371ee524d72..d6c185cd704 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -845,7 +845,7 @@ struct UnwrapHandler
using NestedType = typename QtPrivate::Future<ResultType>::type;
QFutureInterface<NestedType> promise(QFutureInterfaceBase::State::Pending);
- outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
+ auto chain = outer->then([promise](const QFuture<ResultType> &outerFuture) mutable {
// We use the .then([](QFuture<ResultType> outerFuture) {...}) version
// (where outerFuture == *outer), to propagate the exception if the
// outer future has failed.
@@ -883,6 +883,13 @@ struct UnwrapHandler
promise.reportCanceled();
promise.reportFinished();
});
+
+ // Inject the promise into the chain.
+ // We use a fake function as a continuation, since the promise is
+ // managed by the outer future
+ chain.d.setContinuation(ContinuationWrapper(std::move([](const QFutureInterfaceBase &) {})),
+ promise.d, QFutureInterfaceBase::ContinuationType::Then);
+
return promise.future();
}
};
diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h
index 0b88013800e..ff17560d3a1 100644
--- a/src/corelib/thread/qfutureinterface.h
+++ b/src/corelib/thread/qfutureinterface.h
@@ -42,6 +42,8 @@ template<class Function, class ResultType>
class FailureHandler;
#endif
+struct UnwrapHandler;
+
#if QT_CORE_REMOVED_SINCE(6, 10)
void Q_CORE_EXPORT watchContinuationImpl(const QObject *context,
QtPrivate::QSlotObjectBase *slotObj,
@@ -187,6 +189,8 @@ private:
friend class QtPrivate::FailureHandler;
#endif
+ friend struct QtPrivate::UnwrapHandler;
+
#if QT_CORE_REMOVED_SINCE(6, 10)
friend Q_CORE_EXPORT void QtPrivate::watchContinuationImpl(
const QObject *context, QtPrivate::QSlotObjectBase *slotObj, QFutureInterfaceBase &fi);
diff --git a/src/corelib/thread/qreadwritelock.cpp b/src/corelib/thread/qreadwritelock.cpp
index 96e35dcb965..2a1af2315ca 100644
--- a/src/corelib/thread/qreadwritelock.cpp
+++ b/src/corelib/thread/qreadwritelock.cpp
@@ -234,14 +234,14 @@ QBasicReadWriteLock::contendedTryLockForRead(QDeadlineTimer timeout, void *dd)
return d->recursiveLockForRead(timeout);
auto lock = qt_unique_lock(d->mutex);
- if (d != d_ptr.loadRelaxed()) {
+ if (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) {
// d_ptr has changed: this QReadWriteLock was unlocked before we had
// time to lock d->mutex.
// We are holding a lock to a mutex within a QReadWriteLockPrivate
// that is already released (or even is already re-used). That's ok
// because the QFreeList never frees them.
// Just unlock d->mutex (at the end of the scope) and retry.
- d = d_ptr.loadAcquire();
+ d = dd;
continue;
}
return d->lockForRead(lock, timeout);
@@ -340,11 +340,11 @@ QBasicReadWriteLock::contendedTryLockForWrite(QDeadlineTimer timeout, void *dd)
return d->recursiveLockForWrite(timeout);
auto lock = qt_unique_lock(d->mutex);
- if (d != d_ptr.loadRelaxed()) {
+ if (QReadWriteLockPrivate *dd = d_ptr.loadAcquire(); d != dd) {
// The mutex was unlocked before we had time to lock the mutex.
// We are holding to a mutex within a QReadWriteLockPrivate that is already released
// (or even is already re-used) but that's ok because the QFreeList never frees them.
- d = d_ptr.loadAcquire();
+ d = dd;
continue;
}
return d->lockForWrite(lock, timeout);
diff --git a/src/corelib/tools/qarraydata.cpp b/src/corelib/tools/qarraydata.cpp
index 1c0371e463e..d173d824e88 100644
--- a/src/corelib/tools/qarraydata.cpp
+++ b/src/corelib/tools/qarraydata.cpp
@@ -162,7 +162,7 @@ allocateHelper(QArrayData **dptr, qsizetype objectSize, qsizetype alignment, qsi
QArrayData::AllocationOption option) noexcept
{
*dptr = nullptr;
- if (capacity == 0)
+ if (capacity <= 0)
return {};
const qsizetype headerSize = calculateHeaderSize(alignment);
diff --git a/src/corelib/tools/qeasingcurve.cpp b/src/corelib/tools/qeasingcurve.cpp
index de68a0042ac..ce35e8ccffe 100644
--- a/src/corelib/tools/qeasingcurve.cpp
+++ b/src/corelib/tools/qeasingcurve.cpp
@@ -332,8 +332,6 @@ struct TCBPoint
qreal _c;
qreal _b;
- TCBPoint() {}
- TCBPoint(QPointF point, qreal t, qreal c, qreal b) : _point(point), _t(t), _c(c), _b(b) {}
bool operator==(const TCBPoint &other) const
{
@@ -1381,7 +1379,7 @@ void QEasingCurve::addTCBSegment(const QPointF &nextPoint, qreal t, qreal c, qre
if (!d_ptr->config)
d_ptr->config = curveToFunctionObject(d_ptr->type);
- d_ptr->config->_tcbPoints.append(TCBPoint(nextPoint, t, c, b));
+ d_ptr->config->_tcbPoints.append(TCBPoint{nextPoint, t, c, b});
if (nextPoint == QPointF(1.0, 1.0)) {
d_ptr->config->_bezierCurves = tcbToBezier(d_ptr->config->_tcbPoints);
diff --git a/src/gui/accessible/qaccessiblecache.cpp b/src/gui/accessible/qaccessiblecache.cpp
index 311b53aeaa3..b5dcdca6270 100644
--- a/src/gui/accessible/qaccessiblecache.cpp
+++ b/src/gui/accessible/qaccessiblecache.cpp
@@ -19,6 +19,7 @@ Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCache, "qt.accessibility.cache");
*/
static QAccessibleCache *accessibleCache = nullptr;
+static bool inCacheDestructor = false;
static void cleanupAccessibleCache()
{
@@ -32,6 +33,8 @@ QAccessibleObjectDestroyedEvent::~QAccessibleObjectDestroyedEvent()
QAccessibleCache::~QAccessibleCache()
{
+ inCacheDestructor = true;
+
for (QAccessible::Id id: idToInterface.keys())
deleteInterface(id);
}
@@ -188,10 +191,9 @@ void QAccessibleCache::deleteInterface(QAccessible::Id id, QObject *obj)
return;
}
- // QObjects sends this from their destructor, but
- // the object less interfaces calls deleteInterface
- // directly
- if (!obj && !iface->object()) {
+ // QObjects send this from their destructors, but the interfaces
+ // with no associated object call deleteInterface directly.
+ if (!inCacheDestructor && !obj && !iface->object()) {
if (QGuiApplicationPrivate::is_app_running && !QGuiApplicationPrivate::is_app_closing && QAccessible::isActive()) {
QAccessibleObjectDestroyedEvent event(id);
QAccessible::updateAccessibility(&event);
diff --git a/src/gui/doc/images/coordinatesystem-transformations.png b/src/gui/doc/images/coordinatesystem-transformations.png
deleted file mode 100644
index 2736213c072..00000000000
--- a/src/gui/doc/images/coordinatesystem-transformations.png
+++ /dev/null
Binary files differ
diff --git a/src/gui/doc/images/coordinatesystem-transformations.svg b/src/gui/doc/images/coordinatesystem-transformations.svg
new file mode 100644
index 00000000000..a3bc17af3ef
--- /dev/null
+++ b/src/gui/doc/images/coordinatesystem-transformations.svg
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg width="760" height="300"
+ viewBox="0 0 760 300"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.2" baseProfile="tiny">
+
+<style>
+ svg .line-style { stroke: black; fill: none; stroke-width: 2 }
+ svg .text-style { font: 14px arial; fill: black }
+ svg .mono-text-style { font: 14px monospace; fill: black }
+ svg .heading-style { font: 14px arial; fill: black; font-weight: bold }
+ svg .shape-style { stroke: none; fill: black }
+ svg .dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none;
+ stroke: black }
+
+ svg .window-line-style { stroke: red; fill: none; stroke-width: 2 }
+ svg .window-text-style { font: 14px arial; fill: red }
+ svg .window-shape-style { stroke: none; fill: red }
+ svg .window-dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none;
+ stroke: red }
+
+ svg.dark .line-style { stroke: #f2f2f2; fill: none; stroke-width: 2 }
+ svg.dark .text-style { font: 14px arial; fill: #f2f2f2 }
+ svg.dark .mono-text-style { font: 14px monospace; fill: #f2f2f2 }
+ svg.dark .heading-style { font: 14px arial; fill: #f2f2f2; font-weight: bold }
+ svg.dark .shape-style { stroke: none; fill: #f2f2f2 }
+ svg.dark .dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none;
+ stroke: #f2f2f2 }
+ svg.dark .window-line-style { stroke: yellow; fill: none; stroke-width: 2 }
+ svg.dark .window-text-style { font: 14px arial; fill: yellow }
+ svg.dark .window-shape-style { stroke: none; fill: yellow }
+ svg.dark .window-dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none;
+ stroke: yellow }
+
+ [data-theme="dark"] svg .line-style { stroke: #f2f2f2; fill: none; stroke-width: 2 }
+ [data-theme="dark"] svg .text-style { font: 14px arial; fill: #f2f2f2 }
+ [data-theme="dark"] svg .mono-text-style { font: 14px monospace; fill: #f2f2f2 }
+ [data-theme="dark"] svg .heading-style { font: 14px arial; fill: #f2f2f2; font-weight: bold }
+ [data-theme="dark"] svg .shape-style { stroke: none; fill: #f2f2f2 }
+ [data-theme="dark"] svg .dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none;
+ stroke: #f2f2f2 }
+ [data-theme="dark"] svg .window-line-style { stroke: yellow; fill: none; stroke-width: 2 }
+ [data-theme="dark"] svg .window-text-style { font: 14px arial; fill: yellow }
+ [data-theme="dark"] svg .window-shape-style { stroke: none; fill: yellow }
+ [data-theme="dark"] svg .window-dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none;
+ stroke: yellow }
+
+ [data-theme="light"] svg .line-style { stroke: black; fill: none; stroke-width: 2 }
+ [data-theme="light"] svg .text-style { font: 14px arial; fill: black }
+ [data-theme="light"] svg .mono-text-style { font: 14px monospace; fill: black }
+ [data-theme="light"] svg .heading-style { font: 14px arial; fill: black; font-weight: bold }
+ [data-theme="light"] svg .shape-style { stroke: none; fill: black }
+ [data-theme="light"] svg .dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none;
+ stroke: black }
+ [data-theme="light"] svg .window-line-style { stroke: red; fill: none; stroke-width: 2 }
+ [data-theme="light"] svg .window-text-style { font: 14px arial; fill: red }
+ [data-theme="light"] svg .window-shape-style { stroke: none; fill: red }
+ [data-theme="light"] svg .window-dash-style { stroke-dasharray: 4,3; stroke-dashoffset: 0; fill: none;
+ stroke: red }
+</style>
+
+<text x="50" y="20" fill="black" font-size="14px" font-family="arial"
+ font-weight="bold"
+ class="heading-style">World coordinates</text>
+
+<g transform="translate(20, 30)">
+ <rect x="0" y="0" width="200" height="200" stroke="black" fill="none" stroke-dasharray="4,3" stroke-dashoffset="0"
+ class="dash-style" />
+
+ <path d="M5,5 L16,10 L10,16 L5,5" class="shape-style" />
+ <polyline points="5,5 20,20" stroke="black" stroke-width="2" fill="none" class="line-style" />
+ <text x="25" y="30" fill="black" font-size="14px" font-family="arial"
+ class="text-style">(0, 0)</text>
+
+ <path d="M195,195 L184,190 L190,184 L195,195" class="shape-style" />
+ <polyline points="195,195 180,180" stroke="black" stroke-width="2" fill="none" class="line-style" />
+ <text x="115" y="175" fill="black" font-size="14px" font-family="arial"
+ class="text-style">(100, 100)</text>
+
+ <polyline points="-3,-3 3,3" stroke="black" stroke-width="2" class="line-style" />
+ <polyline points="-3,3 3,-3" stroke="black" stroke-width="2" class="line-style" />
+</g>
+
+<g transform="translate(45,235)">
+ <path d="M 0,0 c 0,25 10,35 25,35" stroke="black" stroke-width="2" fill="none" class="line-style" />
+ <path d="M 25,30 l 10,5 l -10,5 z" class="shape-style" />
+ <text x="40" y="40" fill="black" font-size="14px" font-family="monospace"
+ class="mono-text-style">setWindow(-50, -50, 100, 100)</text>
+ <path d="M 290,35 c 15,0 25,-10 25,-35" stroke="black" stroke-width="2" fill="none" class="line-style" />
+ <path d="M 315,0 l 5,10 l -10,0 z" class="shape-style" />
+</g>
+
+<text x="300" y="20" fill="black" font-size="14px" font-family="arial"
+ font-weight="bold"
+ class="heading-style">"Window" coordinates</text>
+
+<g transform="translate(280, 30)">
+
+ <rect x="0" y="0" width="200" height="200" stroke="red" fill="none" stroke-dasharray="4,3" stroke-dashoffset="0"
+ class="window-dash-style" />
+
+ <path d="M5,5 L16,10 L10,16 L5,5" fill="red" class="window-shape-style" />
+ <polyline points="5,5 20,20" stroke="red" stroke-width="2" fill="none" class="window-line-style" />
+ <text x="25" y="30" fill="red" font-size="14px" font-family="arial"
+ class="window-text-style">(-50, -50)</text>
+
+ <path d="M195,195 L184,190 L190,184 L195,195" fill="red" class="window-shape-style" />
+ <polyline points="195,195 180,180" stroke="red" stroke-width="2" fill="none" class="window-line-style" />
+ <text x="130" y="175" fill="red" font-size="14px" font-family="arial"
+ class="window-text-style">(50, 50)</text>
+
+ <polyline points="97,97 103,103" stroke="red" stroke-width="2" class="window-line-style" />
+ <polyline points="97,103 103,97" stroke="red" stroke-width="2" class="window-line-style" />
+</g>
+
+<g transform="translate(395,235)">
+ <path d="M 0,0 c 0,25 10,35 25,35" stroke="black" stroke-width="2" fill="none" class="line-style" />
+ <path d="M 25,30 l 10,5 l -10,5 z" class="shape-style" />
+ <text x="40" y="40" fill="black" font-size="14px" font-family="monospace"
+ class="mono-text-style">setViewport(45, 25, 50, 50)</text>
+ <path d="M 270,35 c 15,0 25,-10 25,-35" stroke="black" stroke-width="2" fill="none" class="line-style" />
+ <path d="M 295,0 l 5,10 l -10,0 z" class="shape-style" />
+</g>
+
+<text x="570" y="20" fill="black" font-size="14px" font-family="arial"
+ font-weight="bold"
+ class="heading-style">Device coordinates</text>
+
+<g transform="translate(540, 30)">
+
+ <rect x="0" y="0" width="200" height="200" stroke="black" stroke-width="2" fill="none" class="line-style" />
+
+ <path d="M5,5 L16,10 L10,16 L5,5" class="shape-style" />
+ <polyline points="5,5 20,20" stroke="black" stroke-width="2" fill="none" class="line-style" />
+ <text x="25" y="30" fill="black" font-size="14px" font-family="arial"
+ class="text-style">(0, 0)</text>
+
+ <path d="M195,195 L184,190 L190,184 L195,195" class="shape-style" />
+ <polyline points="195,195 180,180" stroke="black" stroke-width="2" fill="none" class="line-style" />
+ <text x="115" y="175" fill="black" font-size="14px" font-family="arial"
+ class="text-style">(100, 100)</text>
+
+ <rect x="90" y="50" width="100" height="100" stroke="red" fill="none" stroke-dasharray="4,3" stroke-dashoffset="0"
+ class="window-dash-style" />
+ <polyline points="137,97 143,103" stroke="red" stroke-width="2" class="window-line-style" />
+ <polyline points="137,103 143,97" stroke="red" stroke-width="2" class="window-line-style" />
+</g>
+
+</svg>
diff --git a/src/gui/doc/src/coordsys.qdoc b/src/gui/doc/src/coordsys.qdoc
index 3dd064c19bc..22e14121af6 100644
--- a/src/gui/doc/src/coordsys.qdoc
+++ b/src/gui/doc/src/coordsys.qdoc
@@ -321,7 +321,7 @@
still transformed to the viewport using the same linear algebraic
approach.
- \image coordinatesystem-transformations.png {Illustration showing
+ \image coordinatesystem-transformations.svg {Illustration showing
how coordinates are mapped using viewport, "window" and
transformation matrix}
diff --git a/src/gui/doc/src/external-resources.qdoc b/src/gui/doc/src/external-resources.qdoc
index 0f356dd5046..14ed0817e62 100644
--- a/src/gui/doc/src/external-resources.qdoc
+++ b/src/gui/doc/src/external-resources.qdoc
@@ -36,6 +36,7 @@
\externalpage https://specifications.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html
\title Freedesktop Icon Naming Specification
*/
+
/*!
\externalpage https://standards.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html#directory_layout
\title Icon Theme Specification - Directory Layout
diff --git a/src/gui/kernel/qsurface.cpp b/src/gui/kernel/qsurface.cpp
index e2bafa73988..f361ec86c2d 100644
--- a/src/gui/kernel/qsurface.cpp
+++ b/src/gui/kernel/qsurface.cpp
@@ -68,7 +68,10 @@ QT_IMPL_METATYPE_EXTERN_TAGGED(QSurface*, QSurface_ptr)
bool QSurface::supportsOpenGL() const
{
- return surfaceType() == OpenGLSurface;
+ static bool openGLOnRasterSurfaceSupported =
+ QGuiApplicationPrivate::instance()->platformIntegration()->hasCapability(QPlatformIntegration::OpenGLOnRasterSurface);
+ return surfaceType() == OpenGLSurface
+ || (surfaceType() == RasterSurface && openGLOnRasterSurfaceSupported);
}
/*!
diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp
index 95b9524172f..ec6e696ba00 100644
--- a/src/gui/math3d/qmatrix4x4.cpp
+++ b/src/gui/math3d/qmatrix4x4.cpp
@@ -294,6 +294,7 @@ double QMatrix4x4::determinant() const
if ((flagBits & ~(Translation | Rotation2D | Rotation)) == Identity)
return 1.0;
+ Q_DECL_UNINITIALIZED
double mm[4][4];
copyToDoubles(m, mm);
if (flagBits < Rotation2D)
@@ -355,8 +356,10 @@ QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
*invertible = true;
return orthonormalInverse();
} else if (flagBits < Perspective) {
+ Q_DECL_UNINITIALIZED
QMatrix4x4 inv(Qt::Uninitialized);
+ Q_DECL_UNINITIALIZED
double mm[4][4];
copyToDoubles(m, mm);
@@ -391,8 +394,10 @@ QMatrix4x4 QMatrix4x4::inverted(bool *invertible) const
return inv;
}
+ Q_DECL_UNINITIALIZED
QMatrix4x4 inv(Qt::Uninitialized);
+ Q_DECL_UNINITIALIZED
double mm[4][4];
copyToDoubles(m, mm);
@@ -465,6 +470,7 @@ QMatrix3x3 QMatrix4x4::normalMatrix() const
return inv;
}
+ Q_DECL_UNINITIALIZED
double mm[4][4];
copyToDoubles(m, mm);
double det = matrixDet3(mm, 0, 1, 2, 0, 1, 2);
@@ -493,6 +499,7 @@ QMatrix3x3 QMatrix4x4::normalMatrix() const
*/
QMatrix4x4 QMatrix4x4::transposed() const
{
+ Q_DECL_UNINITIALIZED
QMatrix4x4 result(Qt::Uninitialized);
for (int row = 0; row < 4; ++row) {
for (int col = 0; col < 4; ++col) {
@@ -709,6 +716,7 @@ QMatrix4x4& QMatrix4x4::operator/=(float divisor)
*/
QMatrix4x4 operator/(const QMatrix4x4& matrix, float divisor)
{
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = matrix.m[0][0] / divisor;
m.m[0][1] = matrix.m[0][1] / divisor;
@@ -1141,6 +1149,7 @@ void QMatrix4x4::rotate(float angle, float x, float y, float z)
z = float(double(z) / len);
}
float ic = 1.0f - c;
+ Q_DECL_UNINITIALIZED
QMatrix4x4 rot(Qt::Uninitialized);
rot.m[0][0] = x * x * ic + c;
rot.m[1][0] = x * y * ic - z * s;
@@ -1244,6 +1253,7 @@ void QMatrix4x4::projectedRotate(float angle, float x, float y, float z, float d
z = float(double(z) / len);
}
const float ic = 1.0f - c;
+ Q_DECL_UNINITIALIZED
QMatrix4x4 rot(Qt::Uninitialized);
rot.m[0][0] = x * x * ic + c;
rot.m[1][0] = x * y * ic - z * s;
@@ -1306,6 +1316,7 @@ void QMatrix4x4::rotate(const QQuaternion& quaternion)
// Algorithm from:
// http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q54
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
const float f2x = quaternion.x() + quaternion.x();
@@ -1393,6 +1404,7 @@ void QMatrix4x4::ortho(float left, float right, float bottom, float top, float n
const float width = right - left;
const float invheight = top - bottom;
const float clip = farPlane - nearPlane;
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = 2.0f / width;
m.m[1][0] = 0.0f;
@@ -1431,6 +1443,7 @@ void QMatrix4x4::frustum(float left, float right, float bottom, float top, float
return;
// Construct the projection.
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
const float width = right - left;
const float invheight = top - bottom;
@@ -1474,6 +1487,7 @@ void QMatrix4x4::perspective(float verticalAngle, float aspectRatio, float nearP
return;
// Construct the projection.
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
const float radians = qDegreesToRadians(verticalAngle / 2.0f);
const float sine = std::sin(radians);
@@ -1524,6 +1538,7 @@ void QMatrix4x4::lookAt(const QVector3D& eye, const QVector3D& center, const QVe
QVector3D side = QVector3D::crossProduct(forward, up).normalized();
QVector3D upVector = QVector3D::crossProduct(side, forward);
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = side.x();
m.m[1][0] = side.y();
@@ -1573,6 +1588,7 @@ void QMatrix4x4::viewport(float left, float bottom, float width, float height, f
const float w2 = width / 2.0f;
const float h2 = height / 2.0f;
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = w2;
m.m[1][0] = 0.0f;
@@ -1871,6 +1887,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const
// of just rotations and translations.
QMatrix4x4 QMatrix4x4::orthonormalInverse() const
{
+ Q_DECL_UNINITIALIZED
QMatrix4x4 result(Qt::Uninitialized);
result.m[0][0] = m[0][0];
@@ -1943,6 +1960,7 @@ void QMatrix4x4::optimize()
flagBits &= ~Scale;
} else {
// If the columns are orthonormal and form a right-handed system, then there is no scale.
+ Q_DECL_UNINITIALIZED
double mm[4][4];
copyToDoubles(m, mm);
double det = matrixDet2(mm, 0, 1, 0, 1);
@@ -1957,6 +1975,7 @@ void QMatrix4x4::optimize()
}
} else {
// If the columns are orthonormal and form a right-handed system, then there is no scale.
+ Q_DECL_UNINITIALIZED
double mm[4][4];
copyToDoubles(m, mm);
double det = matrixDet3(mm, 0, 1, 2, 0, 1, 2);
diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h
index c2c3ece7fd6..2a801905ce0 100644
--- a/src/gui/math3d/qmatrix4x4.h
+++ b/src/gui/math3d/qmatrix4x4.h
@@ -564,6 +564,7 @@ inline bool QMatrix4x4::operator!=(const QMatrix4x4& other) const
inline QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2)
{
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = m1.m[0][0] + m2.m[0][0];
m.m[0][1] = m1.m[0][1] + m2.m[0][1];
@@ -586,6 +587,7 @@ inline QMatrix4x4 operator+(const QMatrix4x4& m1, const QMatrix4x4& m2)
inline QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2)
{
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = m1.m[0][0] - m2.m[0][0];
m.m[0][1] = m1.m[0][1] - m2.m[0][1];
@@ -608,21 +610,34 @@ inline QMatrix4x4 operator-(const QMatrix4x4& m1, const QMatrix4x4& m2)
inline QMatrix4x4 operator*(const QMatrix4x4& m1, const QMatrix4x4& m2)
{
+ Q_DECL_UNINITIALIZED
+ QMatrix4x4 m(Qt::Uninitialized);
QMatrix4x4::Flags flagBits = m1.flagBits | m2.flagBits;
if (flagBits.toInt() < QMatrix4x4::Rotation2D) {
- QMatrix4x4 m = m1;
- m.m[3][0] = m1.m[3][0] + m1.m[0][0] * m2.m[3][0];
- m.m[3][1] = m1.m[3][1] + m1.m[1][1] * m2.m[3][1];
- m.m[3][2] = m1.m[3][2] + m1.m[2][2] * m2.m[3][2];
-
+ // Scale | Translation
m.m[0][0] = m1.m[0][0] * m2.m[0][0];
+ m.m[0][1] = 0.0f;
+ m.m[0][2] = 0.0f;
+ m.m[0][3] = 0.0f;
+
+ m.m[1][0] = 0.0f;
m.m[1][1] = m1.m[1][1] * m2.m[1][1];
+ m.m[1][2] = 0.0f;
+ m.m[1][3] = 0.0f;
+
+ m.m[2][0] = 0.0f;
+ m.m[2][1] = 0.0f;
m.m[2][2] = m1.m[2][2] * m2.m[2][2];
+ m.m[2][3] = 0.0f;
+
+ m.m[3][0] = m1.m[3][0] + m1.m[0][0] * m2.m[3][0];
+ m.m[3][1] = m1.m[3][1] + m1.m[1][1] * m2.m[3][1];
+ m.m[3][2] = m1.m[3][2] + m1.m[2][2] * m2.m[3][2];
+ m.m[3][3] = 1.0f;
m.flagBits = flagBits;
return m;
}
- QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = m1.m[0][0] * m2.m[0][0]
+ m1.m[1][0] * m2.m[0][1]
+ m1.m[2][0] * m2.m[0][2]
@@ -843,6 +858,7 @@ inline QPointF operator*(const QMatrix4x4& matrix, const QPointF& point)
inline QMatrix4x4 operator-(const QMatrix4x4& matrix)
{
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = -matrix.m[0][0];
m.m[0][1] = -matrix.m[0][1];
@@ -865,6 +881,7 @@ inline QMatrix4x4 operator-(const QMatrix4x4& matrix)
inline QMatrix4x4 operator*(float factor, const QMatrix4x4& matrix)
{
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = matrix.m[0][0] * factor;
m.m[0][1] = matrix.m[0][1] * factor;
@@ -887,6 +904,7 @@ inline QMatrix4x4 operator*(float factor, const QMatrix4x4& matrix)
inline QMatrix4x4 operator*(const QMatrix4x4& matrix, float factor)
{
+ Q_DECL_UNINITIALIZED
QMatrix4x4 m(Qt::Uninitialized);
m.m[0][0] = matrix.m[0][0] * factor;
m.m[0][1] = matrix.m[0][1] * factor;
diff --git a/src/gui/opengl/platform/egl/qeglplatformcontext.cpp b/src/gui/opengl/platform/egl/qeglplatformcontext.cpp
index e56504833d1..350968b87d4 100644
--- a/src/gui/opengl/platform/egl/qeglplatformcontext.cpp
+++ b/src/gui/opengl/platform/egl/qeglplatformcontext.cpp
@@ -104,6 +104,14 @@ QT_BEGIN_NAMESPACE
#define GL_LOSE_CONTEXT_ON_RESET 0x8252
#endif
+// Constants from GL_EXT_robustness.
+#ifndef GL_RESET_NOTIFICATION_STRATEGY_EXT
+#define GL_RESET_NOTIFICATION_STRATEGY_EXT 0x8256
+#endif
+#ifndef GL_LOSE_CONTEXT_ON_RESET_EXT
+#define GL_LOSE_CONTEXT_ON_RESET_EXT 0x8252
+#endif
+
// Constants from EGL_NV_robustness_video_memory_purge
#ifndef EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV
#define EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C
@@ -452,11 +460,16 @@ void QEGLPlatformContext::updateFormatFromGL()
}
}
}
- if (hasExtension("GL_ARB_robustness")) {
+ if (m_format.renderableType() == QSurfaceFormat::OpenGL && hasExtension("GL_ARB_robustness")) {
GLint value = 0;
glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY, &value);
if (value == GL_LOSE_CONTEXT_ON_RESET)
m_format.setOption(QSurfaceFormat::ResetNotification);
+ } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES && hasExtension("GL_EXT_robustness")) {
+ GLint value = 0;
+ glGetIntegerv(GL_RESET_NOTIFICATION_STRATEGY_EXT, &value);
+ if (value == GL_LOSE_CONTEXT_ON_RESET_EXT)
+ m_format.setOption(QSurfaceFormat::ResetNotification);
}
}
runGLChecks();
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 04433c7703a..697ede42d92 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -930,7 +930,7 @@ static inline bool canUseFastMatrixPath(const qreal cx, const qreal cy, const qs
minc = std::min(minc, std::min(fx, fy));
maxc = std::max(maxc, std::max(fx, fy));
- return minc >= std::numeric_limits<int>::min() && maxc <= std::numeric_limits<int>::max();
+ return minc >= std::numeric_limits<int>::min() && maxc <= qreal(std::numeric_limits<int>::max());
}
template<TextureBlendType blendType, QPixelLayout::BPP bpp, typename T>
@@ -5179,7 +5179,7 @@ static inline bool calculate_fixed_gradient_factors(int count, const QT_FT_Span
const int gss = GRADIENT_STOPTABLE_SIZE - 1;
qreal ryinc = linear.dy * data->m22 * gss * FIXPT_SIZE;
qreal roff = (linear.dy * (data->m22 * qreal(0.5) + data->dy) + linear.off) * gss * FIXPT_SIZE;
- const int limit = std::numeric_limits<int>::max() - FIXPT_SIZE;
+ const qreal limit = qreal(std::numeric_limits<int>::max() - FIXPT_SIZE);
if (count && (std::fabs(ryinc) < limit) && (std::fabs(roff) < limit)
&& (std::fabs(ryinc * spans->y + roff) < limit)
&& (std::fabs(ryinc * (spans + count - 1)->y + roff) < limit)) {
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 74321705ff5..047be5f1c3d 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -2952,9 +2952,9 @@ inline bool QRasterPaintEnginePrivate::isUnclipped(const QRectF &rect,
int penWidth) const
{
const QRectF norm = rect.normalized();
- if (norm.left() <= INT_MIN || norm.top() <= INT_MIN
- || norm.right() > INT_MAX || norm.bottom() > INT_MAX
- || norm.width() > INT_MAX || norm.height() > INT_MAX)
+ if (norm.left() <= qreal(INT_MIN) || norm.top() <= qreal(INT_MIN)
+ || norm.right() > qreal(INT_MAX) || norm.bottom() > qreal(INT_MAX)
+ || norm.width() > qreal(INT_MAX) || norm.height() > qreal(INT_MAX))
return false;
return isUnclipped(norm.toAlignedRect(), penWidth);
}
diff --git a/src/gui/painting/qpainterpath.h b/src/gui/painting/qpainterpath.h
index cc80641ded9..ab9e7fe312a 100644
--- a/src/gui/painting/qpainterpath.h
+++ b/src/gui/painting/qpainterpath.h
@@ -6,9 +6,11 @@
#include <QtGui/qtguiglobal.h>
#include <QtGui/qtransform.h>
+
#include <QtCore/qglobal.h>
#include <QtCore/qline.h>
#include <QtCore/qlist.h>
+#include <QtCore/qpoint.h>
#include <QtCore/qrect.h>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index 33e35ba6694..202e28263c2 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -682,6 +682,12 @@ bool QRhiVulkan::create(QRhi::Flags flags)
if (devExts.contains("VK_KHR_fragment_shading_rate"))
addToChain(&physDevFeaturesChainable, &fragmentShadingRateFeatures);
#endif
+#ifdef VK_EXT_device_fault
+ VkPhysicalDeviceFaultFeaturesEXT deviceFaultFeatures = {};
+ deviceFaultFeatures.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FAULT_FEATURES_EXT;
+ if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME))
+ addToChain(&physDevFeaturesChainable, &deviceFaultFeatures);
+#endif
#endif
// Vulkan >=1.2 headers at build time, >=1.2 implementation at run time
@@ -825,6 +831,13 @@ bool QRhiVulkan::create(QRhi::Flags flags)
requestedDevExts.append(VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME);
#endif
+#ifdef VK_EXT_device_fault
+ if (devExts.contains(VK_EXT_DEVICE_FAULT_EXTENSION_NAME)) {
+ requestedDevExts.append(VK_EXT_DEVICE_FAULT_EXTENSION_NAME);
+ caps.deviceFault = true;
+ }
+#endif
+
for (const QByteArray &ext : requestedDeviceExtensions) {
if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
if (devExts.contains(ext)) {
@@ -910,6 +923,7 @@ bool QRhiVulkan::create(QRhi::Flags flags)
// Here we have no way to tell if the extensions got enabled or not.
// Pretend it's all there and supported. If getProcAddress fails, we'll
// handle that gracefully.
+ caps.deviceFault = true;
caps.vertexAttribDivisor = true;
caps.renderPass2KHR = true;
caps.depthStencilResolveKHR = true;
@@ -1126,6 +1140,12 @@ bool QRhiVulkan::create(QRhi::Flags flags)
}
#endif
+#ifdef VK_EXT_device_fault
+ if (caps.deviceFault) {
+ vkGetDeviceFaultInfoEXT = reinterpret_cast<PFN_vkGetDeviceFaultInfoEXT>(f->vkGetDeviceProcAddr(dev, "vkGetDeviceFaultInfoEXT"));
+ }
+#endif
+
deviceLost = false;
nativeHandlesStruct.physDev = physDev;
@@ -2643,6 +2663,7 @@ QRhi::FrameOpResult QRhiVulkan::beginFrame(QRhiSwapChain *swapChain, QRhi::Begin
} else {
if (err == VK_ERROR_DEVICE_LOST) {
qWarning("Device loss detected in vkAcquireNextImageKHR()");
+ printExtraErrorInfo(err);
deviceLost = true;
return QRhi::FrameOpDeviceLost;
}
@@ -2803,6 +2824,7 @@ QRhi::FrameOpResult QRhiVulkan::endFrame(QRhiSwapChain *swapChain, QRhi::EndFram
} else if (err != VK_SUBOPTIMAL_KHR) {
if (err == VK_ERROR_DEVICE_LOST) {
qWarning("Device loss detected in vkQueuePresentKHR()");
+ printExtraErrorInfo(err);
deviceLost = true;
return QRhi::FrameOpDeviceLost;
}
@@ -2862,6 +2884,7 @@ QRhi::FrameOpResult QRhiVulkan::startPrimaryCommandBuffer(VkCommandBuffer *cb)
if (err != VK_SUCCESS) {
if (err == VK_ERROR_DEVICE_LOST) {
qWarning("Device loss detected in vkAllocateCommandBuffers()");
+ printExtraErrorInfo(err);
deviceLost = true;
return QRhi::FrameOpDeviceLost;
}
@@ -2877,6 +2900,7 @@ QRhi::FrameOpResult QRhiVulkan::startPrimaryCommandBuffer(VkCommandBuffer *cb)
if (err != VK_SUCCESS) {
if (err == VK_ERROR_DEVICE_LOST) {
qWarning("Device loss detected in vkBeginCommandBuffer()");
+ printExtraErrorInfo(err);
deviceLost = true;
return QRhi::FrameOpDeviceLost;
}
@@ -2894,6 +2918,7 @@ QRhi::FrameOpResult QRhiVulkan::endAndSubmitPrimaryCommandBuffer(VkCommandBuffer
if (err != VK_SUCCESS) {
if (err == VK_ERROR_DEVICE_LOST) {
qWarning("Device loss detected in vkEndCommandBuffer()");
+ printExtraErrorInfo(err);
deviceLost = true;
return QRhi::FrameOpDeviceLost;
}
@@ -2930,6 +2955,7 @@ QRhi::FrameOpResult QRhiVulkan::endAndSubmitPrimaryCommandBuffer(VkCommandBuffer
if (err != VK_SUCCESS) {
if (err == VK_ERROR_DEVICE_LOST) {
qWarning("Device loss detected in vkQueueSubmit()");
+ printExtraErrorInfo(err);
deviceLost = true;
return QRhi::FrameOpDeviceLost;
}
@@ -2951,6 +2977,7 @@ QRhi::FrameOpResult QRhiVulkan::waitCommandCompletion(int frameSlot)
if (err != VK_SUCCESS) {
if (err == VK_ERROR_DEVICE_LOST) {
qWarning("Device loss detected in vkWaitForFences()");
+ printExtraErrorInfo(err);
deviceLost = true;
return QRhi::FrameOpDeviceLost;
}
@@ -4079,10 +4106,87 @@ void QRhiVulkan::prepareUploadSubres(QVkTexture *texD, int layer, int level,
void QRhiVulkan::printExtraErrorInfo(VkResult err)
{
+ if (err == VK_ERROR_DEVICE_LOST)
+ printDeviceLossErrorInfo();
if (err == VK_ERROR_OUT_OF_DEVICE_MEMORY)
qWarning() << "Out of device memory, current allocator statistics are" << statistics();
}
+void QRhiVulkan::printDeviceLossErrorInfo() const
+{
+#ifdef VK_EXT_device_fault
+ if (!dev || !caps.deviceFault || !vkGetDeviceFaultInfoEXT)
+ return;
+
+ VkDeviceFaultCountsEXT faultCounts{};
+ faultCounts.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_COUNTS_EXT;
+ faultCounts.pNext = nullptr;
+
+ VkResult result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, nullptr);
+ if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
+ qWarning("vkGetDeviceFaultInfoEXT failed with %d", result);
+ return;
+ }
+ faultCounts.vendorBinarySize = 0;
+
+ QVarLengthArray<VkDeviceFaultAddressInfoEXT> addressInfos;
+ addressInfos.resize(faultCounts.addressInfoCount);
+
+ QVarLengthArray<VkDeviceFaultVendorInfoEXT> vendorInfos;
+ vendorInfos.resize(faultCounts.vendorInfoCount);
+
+ VkDeviceFaultInfoEXT info{};
+ info.sType = VK_STRUCTURE_TYPE_DEVICE_FAULT_INFO_EXT;
+ info.pNext = nullptr;
+ info.pAddressInfos = addressInfos.isEmpty() ? nullptr : addressInfos.data();
+ info.pVendorInfos = vendorInfos.isEmpty() ? nullptr : vendorInfos.data();
+ info.pVendorBinaryData = nullptr;
+
+ result = vkGetDeviceFaultInfoEXT(dev, &faultCounts, &info);
+ if (result != VK_SUCCESS && result != VK_INCOMPLETE) {
+ qWarning("vkGetDeviceFaultInfoEXT failed with %d", result);
+ return;
+ }
+
+ const char *desc = info.description[0] ? info.description : "n/a";
+ qWarning("VK_ERROR_DEVICE_LOST (VK_EXT_device_fault): %u address infos, %u vendor infos, %llu bytes vendor binary: %s",
+ faultCounts.addressInfoCount,
+ faultCounts.vendorInfoCount,
+ (unsigned long long)faultCounts.vendorBinarySize,
+ desc);
+
+ for (uint32_t i = 0; i < faultCounts.addressInfoCount; ++i) {
+ const auto &a = addressInfos[i];
+ auto addressTypeString = [](const VkDeviceFaultAddressTypeEXT type) {
+ switch (type) {
+ case VK_DEVICE_FAULT_ADDRESS_TYPE_NONE_EXT: return "NONE";
+ case VK_DEVICE_FAULT_ADDRESS_TYPE_READ_INVALID_EXT: return "READ_INVALID";
+ case VK_DEVICE_FAULT_ADDRESS_TYPE_WRITE_INVALID_EXT: return "WRITE_INVALID";
+ case VK_DEVICE_FAULT_ADDRESS_TYPE_EXECUTE_INVALID_EXT: return "EXECUTE_INVALID";
+ case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_UNKNOWN_EXT: return "INSTRUCTION_POINTER_UNKNOWN";
+ case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_INVALID_EXT: return "INSTRUCTION_POINTER_INVALID";
+ case VK_DEVICE_FAULT_ADDRESS_TYPE_INSTRUCTION_POINTER_FAULT_EXT: return "INSTRUCTION_POINTER_FAULT";
+ default: return "UNKNOWN";
+ };
+ };
+ qWarning(" AddressInfo[%02u]: type=%s addr=0x%llx precision=%llu",
+ i,
+ addressTypeString(a.addressType),
+ (unsigned long long)a.reportedAddress,
+ (unsigned long long)a.addressPrecision);
+ }
+
+ for (uint32_t i = 0; i < faultCounts.vendorInfoCount; ++i) {
+ const auto &v = vendorInfos[i];
+ qWarning(" VendorInfo[%02u]: code=%llu data=%llu desc=%s",
+ i,
+ (unsigned long long)v.vendorFaultCode,
+ (unsigned long long)v.vendorFaultData,
+ v.description);
+ }
+#endif // VK_EXT_device_fault
+}
+
void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates)
{
QRhiResourceUpdateBatchPrivate *ud = QRhiResourceUpdateBatchPrivate::get(resourceUpdates);
diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h
index 21044545ad2..eb07d8be448 100644
--- a/src/gui/rhi/qrhivulkan_p.h
+++ b/src/gui/rhi/qrhivulkan_p.h
@@ -882,6 +882,7 @@ public:
void ensureCommandPoolForNewFrame();
double elapsedSecondsFromTimestamp(quint64 timestamp[2], bool *ok);
void printExtraErrorInfo(VkResult err);
+ void printDeviceLossErrorInfo() const;
QVulkanInstance *inst = nullptr;
QWindow *maybeWindow = nullptr;
@@ -942,11 +943,16 @@ public:
PFN_vkCreateRenderPass2KHR vkCreateRenderPass2KHR = nullptr;
#endif
+#ifdef VK_EXT_device_fault
+ PFN_vkGetDeviceFaultInfoEXT vkGetDeviceFaultInfoEXT = nullptr;
+#endif
+
struct {
bool compute = false;
bool depthClamp = false;
bool wideLines = false;
bool debugUtils = false;
+ bool deviceFault = false;
bool vertexAttribDivisor = false;
bool texture3DSliceAs2D = false;
bool tessellation = false;
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index c144820fa24..ba49d538c2c 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -31,6 +31,7 @@
#include <QtCore/QMutexLocker>
#include <QtCore/QMutex>
+#include <algorithm>
#include <array>
// #define QFONTCACHE_DEBUG
@@ -1853,35 +1854,13 @@ bool QFont::operator<(const QFont &f) const
int f2attrs = (d->underline << 3) + (d->overline << 2) + (d->strikeOut<<1) + d->kerning;
if (f1attrs != f2attrs) return f1attrs < f2attrs;
- if (d->features.size() != f.d->features.size())
- return f.d->features.size() < d->features.size();
-
- {
- auto it = d->features.constBegin();
- auto jt = f.d->features.constBegin();
- for (; it != d->features.constEnd(); ++it, ++jt) {
- if (it.key() != jt.key())
- return jt.key() < it.key();
- if (it.value() != jt.value())
- return jt.value() < it.value();
- }
- }
-
- if (r1.variableAxisValues.size() != r2.variableAxisValues.size())
- return r1.variableAxisValues.size() < r2.variableAxisValues.size();
-
- {
- auto it = r1.variableAxisValues.constBegin();
- auto jt = r2.variableAxisValues.constBegin();
- for (; it != r1.variableAxisValues.constEnd(); ++it, ++jt) {
- if (it.key() != jt.key())
- return jt.key() < it.key();
- if (it.value() != jt.value())
- return jt.value() < it.value();
- }
+ if (d->features != f.d->features) {
+ return std::lexicographical_compare(f.d->features.keyValueBegin(), f.d->features.keyValueEnd(),
+ d->features.keyValueBegin(), d->features.keyValueEnd());
}
- return false;
+ return std::lexicographical_compare(r1.variableAxisValues.keyValueBegin(), r1.variableAxisValues.keyValueEnd(),
+ r2.variableAxisValues.keyValueBegin(), r2.variableAxisValues.keyValueEnd());
}
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 0ad45b1f280..d41296291f6 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -402,7 +402,7 @@ bool QFontEngine::processHheaTable() const
const qreal unitsPerEm = emSquareSize().toReal();
// Bail out if values are too large for QFixed
- const auto limitForQFixed = std::numeric_limits<int>::max() / (fontDef.pixelSize * 64);
+ const auto limitForQFixed = qreal(std::numeric_limits<int>::max() / 64) / fontDef.pixelSize;
if (ascent > limitForQFixed || descent > limitForQFixed || leading > limitForQFixed)
return false;
m_ascent = QFixed::fromReal(ascent * fontDef.pixelSize / unitsPerEm);
@@ -470,7 +470,7 @@ bool QFontEngine::processOS2Table() const
if (typoAscent == 0 && typoDescent == 0)
return false;
// Bail out if values are too large for QFixed
- const auto limitForQFixed = std::numeric_limits<int>::max() / (fontDef.pixelSize * 64);
+ const auto limitForQFixed = qreal(std::numeric_limits<int>::max() / 64) / fontDef.pixelSize;
if (typoAscent > limitForQFixed || typoDescent > limitForQFixed
|| typoLineGap > limitForQFixed)
return false;
@@ -481,7 +481,7 @@ bool QFontEngine::processOS2Table() const
// Some fonts may have invalid OS/2 data. We detect this and bail out.
if (winAscent == 0 && winDescent == 0)
return false;
- const auto limitForQFixed = std::numeric_limits<int>::max() / (fontDef.pixelSize * 64);
+ const auto limitForQFixed = qreal(std::numeric_limits<int>::max() / 64) / fontDef.pixelSize;
if (winAscent > limitForQFixed || winDescent > limitForQFixed)
return false;
m_ascent = QFixed::fromReal(winAscent * fontDef.pixelSize / unitsPerEm);
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index eb0f6c3710c..4f01d09fed1 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -1976,7 +1976,7 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
return;
bool documentPaginated = d->pageSize.isValid() && !d->pageSize.isNull()
- && d->pageSize.height() != INT_MAX;
+ && d->pageSize.height() != qreal(INT_MAX);
// ### set page size to paginated size?
QMarginsF m = printer->pageLayout().margins(QPageLayout::Millimeter);
diff --git a/src/gui/text/windows/qwindowsfontdatabase.cpp b/src/gui/text/windows/qwindowsfontdatabase.cpp
index 93af1a9600b..0c6d9a31316 100644
--- a/src/gui/text/windows/qwindowsfontdatabase.cpp
+++ b/src/gui/text/windows/qwindowsfontdatabase.cpp
@@ -1113,17 +1113,21 @@ void QWindowsFontDatabase::removeApplicationFonts()
m_eudcFonts.clear();
}
+#if QT_CONFIG(directwrite)
QWindowsFontDatabase::FontHandle::FontHandle(IDWriteFontFace *face, const QString &name)
: fontFace(face), faceName(name)
{
fontFace->AddRef();
}
+#endif // !QT_NO_DIRECTWRITE
QWindowsFontDatabase::FontHandle::~FontHandle()
{
+#if QT_CONFIG(directwrite)
if (fontFace != nullptr)
fontFace->Release();
+#endif // !QT_NO_DIRECTWRITE
}
void QWindowsFontDatabase::releaseHandle(void *handle)
diff --git a/src/gui/text/windows/qwindowsfontdatabase_p.h b/src/gui/text/windows/qwindowsfontdatabase_p.h
index 92e3f04f968..856a5593722 100644
--- a/src/gui/text/windows/qwindowsfontdatabase_p.h
+++ b/src/gui/text/windows/qwindowsfontdatabase_p.h
@@ -78,10 +78,14 @@ public:
struct FontHandle {
FontHandle(const QString &name) : faceName(name) {}
+#if QT_CONFIG(directwrite)
FontHandle(IDWriteFontFace *face, const QString &name);
+#endif // !QT_NO_DIRECTWRITE
~FontHandle();
+#if QT_CONFIG(directwrite)
IDWriteFontFace *fontFace = nullptr;
+#endif // !QT_NO_DIRECTWRITE
QString faceName;
};
diff --git a/src/network/access/qformdatabuilder.cpp b/src/network/access/qformdatabuilder.cpp
index 470e285c6ad..debefd24634 100644
--- a/src/network/access/qformdatabuilder.cpp
+++ b/src/network/access/qformdatabuilder.cpp
@@ -9,6 +9,7 @@
#include "QtCore/qmimedatabase.h"
#endif
+#include <variant>
#include <vector>
QT_BEGIN_NAMESPACE
diff --git a/src/network/access/qformdatabuilder.h b/src/network/access/qformdatabuilder.h
index 7d667aea21c..3992776161d 100644
--- a/src/network/access/qformdatabuilder.h
+++ b/src/network/access/qformdatabuilder.h
@@ -15,7 +15,6 @@
#include <QtCore/qstring.h>
#include <memory>
-#include <variant>
#ifndef Q_OS_WASM
QT_REQUIRE_CONFIG(http);
diff --git a/src/network/access/qnetworkaccesscache.cpp b/src/network/access/qnetworkaccesscache.cpp
index bb1bdd87a8a..6ff70cd546d 100644
--- a/src/network/access/qnetworkaccesscache.cpp
+++ b/src/network/access/qnetworkaccesscache.cpp
@@ -5,11 +5,6 @@
#include "qnetworkaccesscache_p.h"
#include "QtCore/qpointer.h"
#include "QtCore/qdeadlinetimer.h"
-#include "qnetworkaccessmanager_p.h"
-#include "qnetworkreply_p.h"
-#include "qnetworkrequest.h"
-
-#include <vector>
//#define DEBUG_ACCESSCACHE
diff --git a/src/network/access/qnetworkcookie.cpp b/src/network/access/qnetworkcookie.cpp
index c20cd43a2fd..6c44e42dbba 100644
--- a/src/network/access/qnetworkcookie.cpp
+++ b/src/network/access/qnetworkcookie.cpp
@@ -5,7 +5,6 @@
#include "qnetworkcookie.h"
#include "qnetworkcookie_p.h"
-#include "qnetworkrequest.h"
#include "qnetworkreply.h"
#include "QtCore/qbytearray.h"
#include "QtCore/qdatetime.h"
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index adad12a4242..be05249c1b8 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -265,19 +265,26 @@ void QCocoaGLContext::updateSurfaceFormat()
return value;
};
- int colorSize = pixelFormatAttribute(NSOpenGLPFAColorSize);
- colorSize /= 4; // The attribute includes the alpha component
- m_format.setRedBufferSize(colorSize);
- m_format.setGreenBufferSize(colorSize);
- m_format.setBlueBufferSize(colorSize);
+ // Resolve color channel bits from GL, rather than NSOpenGLPFAColorSize,
+ // as the latter is not specific enough (combines all channels).
+ GLint redBits, greenBits, blueBits;
+ glGetIntegerv(GL_RED_BITS, &redBits);
+ glGetIntegerv(GL_GREEN_BITS, &greenBits);
+ glGetIntegerv(GL_BLUE_BITS, &blueBits);
+ m_format.setRedBufferSize(redBits);
+ m_format.setGreenBufferSize(greenBits);
+ m_format.setBlueBufferSize(blueBits);
// Surfaces on macOS always have an alpha channel, but unless the user requested
// one via setAlphaBufferSize(), which triggered setting NSOpenGLCPSurfaceOpacity
// to make the surface non-opaque, we don't want to report back the actual alpha
// size, as that will make the user believe the alpha channel can be used for
// something useful, when in reality it can't, due to the surface being opaque.
- if (m_format.alphaBufferSize() > 0)
- m_format.setAlphaBufferSize(pixelFormatAttribute(NSOpenGLPFAAlphaSize));
+ if (m_format.alphaBufferSize() > 0) {
+ GLint alphaBits;
+ glGetIntegerv(GL_ALPHA_BITS, &alphaBits);
+ m_format.setAlphaBufferSize(alphaBits);
+ }
m_format.setDepthBufferSize(pixelFormatAttribute(NSOpenGLPFADepthSize));
m_format.setStencilBufferSize(pixelFormatAttribute(NSOpenGLPFAStencilSize));
diff --git a/src/plugins/platforms/windows/qwindowsscreen.cpp b/src/plugins/platforms/windows/qwindowsscreen.cpp
index 0236669d6fb..23bbe409caa 100644
--- a/src/plugins/platforms/windows/qwindowsscreen.cpp
+++ b/src/plugins/platforms/windows/qwindowsscreen.cpp
@@ -450,6 +450,26 @@ QPixmap QWindowsScreen::grabWindow(WId window, int xIn, int yIn, int width, int
hwnd = GetDesktopWindow();
const QRect screenGeometry = geometry();
windowSize = screenGeometry.size();
+ // When dpi awareness is not set to PerMonitor, windows reports primary display or dummy
+ // DPI for all displays, so xIn and yIn and windowSize are calculated with a wrong DPI,
+ // so we need to recalculate them using the actual screen size we get from
+ // EnumDisplaySettings api.
+ const auto dpiAwareness = QWindowsContext::instance()->processDpiAwareness();
+ if (dpiAwareness != QtWindows::DpiAwareness::PerMonitor &&
+ dpiAwareness != QtWindows::DpiAwareness::PerMonitorVersion2) {
+ MONITORINFOEX info = {};
+ info.cbSize = sizeof(MONITORINFOEX);
+ if (GetMonitorInfo(handle(), &info)) {
+ DEVMODE dm = {};
+ dm.dmSize = sizeof(dm);
+ if (EnumDisplaySettings(info.szDevice, ENUM_CURRENT_SETTINGS, &dm)) {
+ qreal scale = static_cast<qreal>(dm.dmPelsWidth) / windowSize.width();
+ x = static_cast<int>(static_cast<qreal>(x) * scale);
+ y = static_cast<int>(static_cast<qreal>(y) * scale);
+ windowSize = QSize(dm.dmPelsWidth, dm.dmPelsHeight);
+ }
+ }
+ }
x += screenGeometry.x();
y += screenGeometry.y();
}
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index b77e985c965..2816982b1a8 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -1732,8 +1732,10 @@ void QWindowsWindow::destroyWindow()
m_surface = nullptr;
}
#endif
+ DestroyWindow(m_data.hwndTitlebar);
DestroyWindow(m_data.hwnd);
context->removeWindow(m_data.hwnd);
+ m_data.hwndTitlebar = nullptr;
m_data.hwnd = nullptr;
}
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 2c56603fef0..7d5f0155960 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -2573,7 +2573,7 @@ void QXcbWindow::setOpacity(qreal level)
if (!m_window)
return;
- quint32 value = qRound64(qBound(qreal(0), level, qreal(1)) * 0xffffffff);
+ quint32 value = qRound64(qBound(qreal(0), level, qreal(1)) * qreal(0xffffffff));
xcb_change_property(xcb_connection(),
XCB_PROP_MODE_REPLACE,
diff --git a/src/plugins/sqldrivers/.cmake.conf b/src/plugins/sqldrivers/.cmake.conf
index be788d10f8e..846c4f3b923 100644
--- a/src/plugins/sqldrivers/.cmake.conf
+++ b/src/plugins/sqldrivers/.cmake.conf
@@ -1 +1 @@
-set(QT_REPO_MODULE_VERSION "6.11.0")
+set(QT_REPO_MODULE_VERSION "6.12.0")
diff --git a/src/plugins/styles/modernwindows/qwindows11style.cpp b/src/plugins/styles/modernwindows/qwindows11style.cpp
index 7caa352afe4..ff2d4bd845f 100644
--- a/src/plugins/styles/modernwindows/qwindows11style.cpp
+++ b/src/plugins/styles/modernwindows/qwindows11style.cpp
@@ -914,12 +914,17 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
break;
case PE_IndicatorBranch: {
if (option->state & State_Children) {
+ const QStyleOptionViewItem *vopt = qstyleoption_cast<const QStyleOptionViewItem *>(option);
const bool isReverse = option->direction == Qt::RightToLeft;
const bool isOpen = option->state & QStyle::State_Open;
+ const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
QFont f(d->assetFont);
f.setPointSize(8);
painter->setFont(f);
- painter->setPen(option->palette.color(isOpen ? QPalette::Active : QPalette::Disabled,
+ if (view && view->alternatingRowColors() && vopt && vopt->state & State_Selected)
+ painter->setPen(winUI3Color(textOnAccentPrimary));
+ else
+ painter->setPen(option->palette.color(isOpen ? QPalette::Active : QPalette::Disabled,
QPalette::WindowText));
const auto ico = isOpen ? Icon::ChevronDownMed
: (isReverse ? Icon::ChevronLeftMed
@@ -1071,14 +1076,16 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
if (option->state & State_Selected && !highContrastTheme) {
// keep in sync with CE_ItemViewItem QListView indicator painting
- const auto col = option->palette.accent().color();
- painter->setBrush(col);
- painter->setPen(col);
- const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
- const auto yOfs = rect.height() / 4.;
- QRectF r(QPointF(xPos, rect.y() + yOfs),
- QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
- painter->drawRoundedRect(r, 1, 1);
+ if (!qobject_cast<const QTableView *>(widget)) {
+ const auto col = option->palette.accent().color();
+ painter->setBrush(col);
+ painter->setPen(col);
+ const auto xPos = isRtl ? rect.right() - 4.5f : rect.left() + 3.5f;
+ const auto yOfs = rect.height() / 4.;
+ QRectF r(QPointF(xPos, rect.y() + yOfs),
+ QPointF(xPos + 1, rect.y() + rect.height() - yOfs));
+ painter->drawRoundedRect(r, 1, 1);
+ }
}
const bool isTreeDecoration = vopt->features.testFlag(
@@ -1099,7 +1106,7 @@ void QWindows11Style::drawPrimitive(PrimitiveElement element, const QStyleOption
}
const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
- painter->setBrush(view->alternatingRowColors() ? vopt->palette.highlight() : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
+ painter->setBrush(view->alternatingRowColors() && state & State_Selected ? calculateAccentColor(option) : WINUI3Colors[colorSchemeIndex][subtleHighlightColor]);
painter->setPen(Qt::NoPen);
if (isFirst) {
QPainterStateGuard psg(painter);
@@ -1753,13 +1760,13 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
}
}
const bool highlightCurrent = vopt->state.testAnyFlags(State_Selected | State_MouseOver);
+ const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
if (highlightCurrent) {
if (highContrastTheme) {
painter->setBrush(vopt->palette.highlight());
} else {
- const QAbstractItemView *view = qobject_cast<const QAbstractItemView *>(widget);
- painter->setBrush(view && view->alternatingRowColors()
- ? vopt->palette.highlight()
+ painter->setBrush(view && view->alternatingRowColors() && vopt->state & State_Selected
+ ? calculateAccentColor(option)
: winUI3Color(subtleHighlightColor));
}
} else {
@@ -1815,8 +1822,13 @@ void QWindows11Style::drawControl(ControlElement element, const QStyleOption *op
vopt->icon.paint(painter, iconRect, vopt->decorationAlignment, mode, state);
}
- painter->setPen(highlightCurrent && highContrastTheme ? vopt->palette.base().color()
- : vopt->palette.text().color());
+ if (highlightCurrent && highContrastTheme) {
+ painter->setPen(vopt->palette.base().color());
+ } else if ((view && view->alternatingRowColors() && highlightCurrent && vopt->state & State_Selected)) {
+ painter->setPen(winUI3Color(textOnAccentPrimary));
+ } else {
+ painter->setPen(vopt->palette.text().color());
+ }
d->viewItemDrawText(painter, vopt, textRect);
// paint a vertical marker for QListView
diff --git a/src/testlib/doc/src/qt-webpages.qdoc b/src/testlib/doc/src/qt-webpages.qdoc
index 611f3795ba9..b32fd4f750f 100644
--- a/src/testlib/doc/src/qt-webpages.qdoc
+++ b/src/testlib/doc/src/qt-webpages.qdoc
@@ -15,7 +15,3 @@
\title Googletest Mocking (gMock) Framework
*/
-/*!
- \externalpage https://www.itk.org/Wiki/CMake_Testing_With_CTest
- \title CMake/Testing With CTest
-*/
diff --git a/src/tools/androidtestrunner/main.cpp b/src/tools/androidtestrunner/main.cpp
index b517d85c5fb..161d95db49c 100644
--- a/src/tools/androidtestrunner/main.cpp
+++ b/src/tools/androidtestrunner/main.cpp
@@ -28,7 +28,16 @@
using namespace Qt::StringLiterals;
-#define EXIT_ERROR -1
+
+// QTest-based test processes may exit with up to 127 for normal test failures
+static constexpr int HIGHEST_QTEST_EXITCODE = 127;
+// Something went wrong in androidtestrunner, in general
+static constexpr int EXIT_ERROR = 254;
+// More specific exit codes for failures in androidtestrunner:
+static constexpr int EXIT_NOEXITCODE = 253; // Failed to transfer exit code from device
+static constexpr int EXIT_ANR = 252; // Android ANR error (Application Not Responding)
+static constexpr int EXIT_NORESULTS = 251; // Failed to transfer result files from device
+
struct Options
{
@@ -71,6 +80,13 @@ struct TestInfo
static TestInfo g_testInfo;
+// QTest-based processes return 0 if all tests PASSed, or the number of FAILs up to 127.
+// Other exitcodes signify abnormal termination and are system-dependent.
+static bool isTestExitCodeNormal(const int ec)
+{
+ return (ec >= 0 && ec <= HIGHEST_QTEST_EXITCODE);
+}
+
static bool execCommand(const QString &program, const QStringList &args,
QByteArray *output = nullptr, bool verbose = false)
{
@@ -744,9 +760,9 @@ void printLogcatCrash(const QByteArray &logcat)
}
if (!crashLogcat.startsWith("********** Crash dump"))
- qDebug() << "********** Crash dump: **********";
+ qDebug() << "[androidtestrunner] ********** BEGIN crash dump **********";
qDebug().noquote() << crashLogcat.trimmed();
- qDebug() << "********** End crash dump **********";
+ qDebug() << "[androidtestrunner] ********** END crash dump **********";
}
void analyseLogcat(const QString &timeStamp, int *exitCode)
@@ -781,10 +797,13 @@ void analyseLogcat(const QString &timeStamp, int *exitCode)
// Check for ANRs
const bool anrOccurred = logcat.contains("ANR in %1"_L1.arg(g_options.package).toUtf8());
if (anrOccurred) {
- // Treat a found ANR as a test failure.
- *exitCode = *exitCode < 1 ? 1 : *exitCode;
- qCritical("An ANR has occurred while running the test %s. The logcat will include "
- "additional logs from the system_server process.",
+ // Rather improbable, but if the test managed to return a non-crash exitcode then overwrite
+ // it to signify that something blew up. Same if we didn't manage to collect an exit code.
+ // Preserve all other exitcodes, they might be useful crash information from the device.
+ if (isTestExitCodeNormal(*exitCode) || *exitCode == EXIT_NOEXITCODE)
+ *exitCode = EXIT_ANR;
+ qCritical("[androidtestrunner] An ANR has occurred while running the test '%s';"
+ " consult logcat for additional logs from the system_server process",
qPrintable(g_options.package));
}
@@ -818,13 +837,14 @@ void analyseLogcat(const QString &timeStamp, int *exitCode)
}
}
- // If we have a crash, attempt to print both logcat and the crash buffer which
- // includes the crash stacktrace that is not included in the default logcat.
- const bool testCrashed = *exitCode == EXIT_ERROR && !g_testInfo.isTestRunnerInterrupted.load();
+ // If we have an unpredictable exitcode, possibly a crash, attempt to print both logcat and the
+ // crash buffer which includes the crash stacktrace that is not included in the default logcat.
+ const bool testCrashed = ( !isTestExitCodeNormal(*exitCode)
+ && !g_testInfo.isTestRunnerInterrupted.load());
if (testCrashed) {
- qDebug() << "********** logcat dump **********";
+ qDebug() << "[androidtestrunner] ********** BEGIN logcat dump **********";
qDebug().noquote() << testLogcat.join(u'\n').trimmed();
- qDebug() << "********** End logcat dump **********";
+ qDebug() << "[androidtestrunner] ********** END logcat dump **********";
if (!crashLogcat.isEmpty())
printLogcatCrash(crashLogcat);
@@ -839,7 +859,7 @@ static QString getCurrentTimeString()
QStringList dateArgs = { "shell"_L1, "date"_L1, "+'%1'"_L1.arg(timeFormat) };
QByteArray output;
if (!execAdbCommand(dateArgs, &output, false)) {
- qWarning() << "Date/time adb command failed";
+ qWarning() << "[androidtestrunner] ERROR in command: adb shell date";
return {};
}
@@ -851,14 +871,15 @@ static int testExitCode()
QByteArray exitCodeOutput;
const QString exitCodeCmd = "cat files/qtest_last_exit_code 2> /dev/null"_L1;
if (!execAdbCommand({ "shell"_L1, runCommandAsUserArgs(exitCodeCmd) }, &exitCodeOutput, false)) {
- qCritical() << "Failed to retrieve the test exit code.";
- return EXIT_ERROR;
+ qCritical() << "[androidtestrunner] ERROR in command: adb shell cat files/qtest_last_exit_code";
+ return EXIT_NOEXITCODE;
}
+ qDebug() << "[androidtestrunner] Test exitcode: " << exitCodeOutput;
bool ok;
int exitCode = exitCodeOutput.toInt(&ok);
- return ok ? exitCode : EXIT_ERROR;
+ return ok ? exitCode : EXIT_NOEXITCODE;
}
static bool uninstallTestPackage()
@@ -899,7 +920,7 @@ void sigHandler(int signal)
// a main event loop. Since, there's no other alternative to do this,
// let's do the cleanup anyway.
if (!g_testInfo.isPackageInstalled.load())
- _exit(-1);
+ _exit(EXIT_ERROR);
g_testInfo.isTestRunnerInterrupted.store(true);
}
@@ -1031,7 +1052,9 @@ int main(int argc, char *argv[])
if (g_options.showLogcatOutput)
analyseLogcat(formattedStartTime, &exitCode);
- exitCode = pullResults() ? exitCode : EXIT_ERROR;
+ const bool pullRes = pullResults();
+ if (!pullRes && isTestExitCodeNormal(exitCode))
+ exitCode = EXIT_NORESULTS;
if (!uninstallTestPackage())
return EXIT_ERROR;
diff --git a/src/tools/configure.cmake b/src/tools/configure.cmake
index 27ea90b89ac..07e11dd935b 100644
--- a/src/tools/configure.cmake
+++ b/src/tools/configure.cmake
@@ -37,7 +37,7 @@ qt_feature("qmake" PRIVATE
QT_FEATURE_datestring AND QT_FEATURE_regularexpression AND QT_FEATURE_temporaryfile)
qt_feature("qtwaylandscanner" PRIVATE
- CONDITION TARGET Wayland::Scanner
+ CONDITION TARGET Wayland::Scanner AND NOT INTEGRITY AND NOT ANDROID AND NOT WASM AND NOT IOS AND NOT QNX AND NOT VXWORKS
)
qt_configure_add_summary_section(NAME "Core tools")
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index d43b6ec4fb2..c47e3bee13c 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -412,7 +412,7 @@ qt_internal_extend_target(Widgets CONDITION QT_FEATURE_shortcut
qt_internal_extend_target(Widgets CONDITION QT_FEATURE_tooltip
SOURCES
- kernel/qtooltip.cpp kernel/qtooltip.h
+ kernel/qtooltip.cpp kernel/qtooltip.h kernel/qtooltip_p.h
)
qt_internal_extend_target(Widgets CONDITION QT_FEATURE_whatsthis
diff --git a/src/widgets/accessible/qaccessiblecolorwell.cpp b/src/widgets/accessible/qaccessiblecolorwell.cpp
index ca08e511e9a..64fcd2a7fd1 100644
--- a/src/widgets/accessible/qaccessiblecolorwell.cpp
+++ b/src/widgets/accessible/qaccessiblecolorwell.cpp
@@ -3,6 +3,8 @@
#include "private/qaccessiblecolorwell_p.h"
+#include <QtCore/qcoreapplication.h>
+
QT_REQUIRE_CONFIG(accessibility);
#if QT_CONFIG(colordialog)
@@ -14,6 +16,7 @@ class QAccessibleColorWellItem : public QAccessibleInterface
{
QAccessibleColorWell *m_parent;
+ Q_DECLARE_TR_FUNCTIONS(QAccessibleColorWellItem)
public:
QAccessibleColorWellItem(QAccessibleColorWell *parent);
@@ -79,7 +82,7 @@ QString QAccessibleColorWellItem::text(QAccessible::Text t) const
if (t == QAccessible::Name) {
QRgb color = m_parent->colorWell()->rgbValues()[m_parent->indexOfChild(this)];
//: Color specified via its 3 RGB components (red, green, blue)
- return QObject::tr("RGB %1, %2, %3")
+ return tr("RGB %1, %2, %3")
.arg(QString::number(qRed(color)), QString::number(qGreen(color)),
QString::number(qBlue(color)));
}
diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp
index d51c408ab5c..ce46170bba5 100644
--- a/src/widgets/dialogs/qcolordialog.cpp
+++ b/src/widgets/dialogs/qcolordialog.cpp
@@ -662,7 +662,7 @@ private:
int val2y(int val);
void setVal(int v);
- QPixmap *pix;
+ QPixmap pix;
};
@@ -682,14 +682,12 @@ QColorLuminancePicker::QColorLuminancePicker(QWidget* parent)
:QWidget(parent)
{
hue = 100; val = 100; sat = 100;
- pix = nullptr;
// setAttribute(WA_NoErase, true);
setFocusPolicy(Qt::StrongFocus);
}
QColorLuminancePicker::~QColorLuminancePicker()
{
- delete pix;
}
void QColorLuminancePicker::keyPressEvent(QKeyEvent *event)
@@ -725,7 +723,7 @@ void QColorLuminancePicker::setVal(int v)
if (val == v)
return;
val = qMax(0, qMin(v,255));
- delete pix; pix=nullptr;
+ pix = QPixmap();
repaint();
emit newHsv(hue, sat, val);
}
@@ -744,8 +742,7 @@ void QColorLuminancePicker::paintEvent(QPaintEvent *)
QRect r(0, foff, w, height() - 2*foff);
int wi = r.width() - 2;
int hi = r.height() - 2;
- if (!pix || pix->height() != hi || pix->width() != wi) {
- delete pix;
+ if (pix.isNull() || pix.height() != hi || pix.width() != wi) {
QImage img(wi, hi, QImage::Format_RGB32);
int y;
uint *pixel = (uint *) img.scanLine(0);
@@ -754,10 +751,10 @@ void QColorLuminancePicker::paintEvent(QPaintEvent *)
std::fill(pixel, end, QColor::fromHsv(hue, sat, y2val(y + coff)).rgb());
pixel = end;
}
- pix = new QPixmap(QPixmap::fromImage(img));
+ pix = QPixmap::fromImage(img);
}
QPainter p(this);
- p.drawPixmap(1, coff, *pix);
+ p.drawPixmap(1, coff, pix);
const QPalette &g = palette();
qDrawShadePanel(&p, r, g, true);
p.setPen(g.windowText().color());
@@ -773,7 +770,7 @@ void QColorLuminancePicker::setCol(int h, int s , int v)
val = v;
hue = h;
sat = s;
- delete pix; pix=nullptr;
+ pix = QPixmap();
repaint();
}
diff --git a/src/widgets/doc/src/external-resources.qdoc b/src/widgets/doc/src/external-resources.qdoc
index 96117546a29..0eccc3b19d4 100644
--- a/src/widgets/doc/src/external-resources.qdoc
+++ b/src/widgets/doc/src/external-resources.qdoc
@@ -1,12 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-/*!
- \externalpage http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html
- \title Apple Human Interface Guidelines
-*/
-
/*!
\externalpage https://rk.nvg.ntnu.no/sinclair/computers/zxspectrum/zxspectrum.htm
\title Sinclair Spectrum
diff --git a/src/widgets/kernel/qtooltip.cpp b/src/widgets/kernel/qtooltip.cpp
index fa17c94a23f..97332cd7d5d 100644
--- a/src/widgets/kernel/qtooltip.cpp
+++ b/src/widgets/kernel/qtooltip.cpp
@@ -6,15 +6,12 @@
#include <qapplication.h>
#include <qevent.h>
-#include <qpointer.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qstylepainter.h>
#if QT_CONFIG(effects)
#include <private/qeffects_p.h>
#endif
-#include <qtextdocument.h>
-#include <qdebug.h>
#include <qpa/qplatformscreen.h>
#include <qpa/qplatformcursor.h>
#if QT_CONFIG(style_stylesheet)
@@ -23,12 +20,10 @@
#include <qpa/qplatformwindow.h>
#include <qpa/qplatformwindow_p.h>
-#include <qlabel.h>
#include <QtWidgets/private/qlabel_p.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <qtooltip.h>
-
-#include <QtCore/qbasictimer.h>
+#include <QtWidgets/private/qtooltip_p.h>
QT_BEGIN_NAMESPACE
@@ -93,57 +88,6 @@ using namespace Qt::StringLiterals;
\sa QWidget::toolTip, QAction::toolTip
*/
-class QTipLabel : public QLabel
-{
- Q_OBJECT
-public:
- QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int msecDisplayTime);
- ~QTipLabel();
- static QTipLabel *instance;
-
- void adjustTooltipScreen(const QPoint &pos);
- void updateSize(const QPoint &pos);
-
- bool eventFilter(QObject *, QEvent *) override;
-
- QBasicTimer hideTimer, expireTimer;
-
- bool fadingOut;
-
- void reuseTip(const QString &text, int msecDisplayTime, const QPoint &pos);
- void hideTip();
- void hideTipImmediately();
- void setTipRect(QWidget *w, const QRect &r);
- void restartExpireTimer(int msecDisplayTime);
- bool tipChanged(const QPoint &pos, const QString &text, QObject *o);
- void placeTip(const QPoint &pos, QWidget *w);
-
- static QScreen *getTipScreen(const QPoint &pos, QWidget *w);
-protected:
- void timerEvent(QTimerEvent *e) override;
- void paintEvent(QPaintEvent *e) override;
- void mouseMoveEvent(QMouseEvent *e) override;
- void resizeEvent(QResizeEvent *e) override;
-
-#if QT_CONFIG(style_stylesheet)
-public slots:
- /** \internal
- Cleanup the _q_stylesheet_parent property.
- */
- void styleSheetParentDestroyed() {
- setProperty("_q_stylesheet_parent", QVariant());
- styleSheetParent = nullptr;
- }
-
-private:
- QWidget *styleSheetParent;
-#endif
-
-private:
- QWidget *widget;
- QRect rect;
-};
-
QTipLabel *QTipLabel::instance = nullptr;
QTipLabel::QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int msecDisplayTime)
@@ -152,6 +96,7 @@ QTipLabel::QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int mse
, styleSheetParent(nullptr)
#endif
, widget(nullptr)
+ , fadingOut(false)
{
delete instance;
instance = this;
@@ -166,7 +111,6 @@ QTipLabel::QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int mse
qApp->installEventFilter(this);
setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, nullptr, this) / 255.0);
setMouseTracking(true);
- fadingOut = false;
reuseTip(text, msecDisplayTime, pos);
}
@@ -240,10 +184,10 @@ void QTipLabel::resizeEvent(QResizeEvent *e)
void QTipLabel::mouseMoveEvent(QMouseEvent *e)
{
if (!rect.isNull()) {
- QPoint pos = e->globalPosition().toPoint();
+ QPointF pos = e->globalPosition();
if (widget)
pos = widget->mapFromGlobal(pos);
- if (!rect.contains(pos))
+ if (!rect.contains(pos.toPoint()))
hideTip();
}
QLabel::mouseMoveEvent(e);
@@ -433,6 +377,15 @@ bool QTipLabel::tipChanged(const QPoint &pos, const QString &text, QObject *o)
return false;
}
+/** \internal
+ Cleanup the _q_stylesheet_parent property.
+ */
+void QTipLabel::styleSheetParentDestroyed()
+{
+ setProperty("_q_stylesheet_parent", QVariant());
+ styleSheetParent = nullptr;
+}
+
/*!
Shows \a text as a tool tip, with the global position \a pos as
the point of interest. The tool tip will be shown with a platform
@@ -594,4 +547,4 @@ void QToolTip::setFont(const QFont &font)
QT_END_NAMESPACE
-#include "qtooltip.moc"
+#include "moc_qtooltip_p.cpp"
diff --git a/src/widgets/kernel/qtooltip_p.h b/src/widgets/kernel/qtooltip_p.h
new file mode 100644
index 00000000000..51faaf58c34
--- /dev/null
+++ b/src/widgets/kernel/qtooltip_p.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2016 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
+// Qt-Security score:significant reason:default
+
+#ifndef QTOOLTIP_P_H
+#define QTOOLTIP_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qlayout*.cpp, and qabstractlayout.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QLabel>
+#include <QString>
+#include <QRect>
+#include <QToolTip>
+
+QT_REQUIRE_CONFIG(tooltip);
+QT_BEGIN_NAMESPACE
+
+class Q_WIDGETS_EXPORT QTipLabel final : public QLabel
+{
+ Q_OBJECT
+public:
+ explicit QTipLabel(const QString &text, const QPoint &pos, QWidget *w, int msecDisplayTime);
+ ~QTipLabel() override;
+
+ void adjustTooltipScreen(const QPoint &pos);
+ void updateSize(const QPoint &pos);
+
+ bool eventFilter(QObject *, QEvent *) override;
+
+ void reuseTip(const QString &text, int msecDisplayTime, const QPoint &pos);
+ void hideTip();
+ void hideTipImmediately();
+ void setTipRect(QWidget *w, const QRect &r);
+ void restartExpireTimer(int msecDisplayTime);
+ bool tipChanged(const QPoint &pos, const QString &text, QObject *o);
+ void placeTip(const QPoint &pos, QWidget *w);
+
+ static QScreen *getTipScreen(const QPoint &pos, QWidget *w);
+protected:
+ void timerEvent(QTimerEvent *e) override;
+ void paintEvent(QPaintEvent *e) override;
+ void mouseMoveEvent(QMouseEvent *e) override;
+ void resizeEvent(QResizeEvent *e) override;
+
+#if QT_CONFIG(style_stylesheet)
+public Q_SLOTS:
+ void styleSheetParentDestroyed();
+
+private:
+ QWidget *styleSheetParent;
+#endif
+
+private:
+ friend class QToolTip;
+
+ static QTipLabel *instance;
+ QBasicTimer hideTimer, expireTimer;
+ QWidget *widget;
+ QRect rect;
+ bool fadingOut;
+};
+
+QT_END_NAMESPACE
+
+#endif // QTOOLTIP_P_H
diff --git a/src/widgets/styles/qcommonstyle.cpp b/src/widgets/styles/qcommonstyle.cpp
index 90c1cfb4b86..592b70ef8ba 100644
--- a/src/widgets/styles/qcommonstyle.cpp
+++ b/src/widgets/styles/qcommonstyle.cpp
@@ -1994,12 +1994,9 @@ void QCommonStyle::drawControl(ControlElement element, const QStyleOption *opt,
tr = proxy()->subElementRect(SE_TabBarTabText, opt, widget);
if (!tab->icon.isNull()) {
- QPixmap tabIcon = tab->icon.pixmap(tab->iconSize, QStyleHelper::getDpr(p),
- (tab->state & State_Enabled) ? QIcon::Normal
- : QIcon::Disabled,
- (tab->state & State_Selected) ? QIcon::On
- : QIcon::Off);
- p->drawPixmap(iconRect.x(), iconRect.y(), tabIcon);
+ const auto mode = (tab->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled;
+ const auto state = (tab->state & State_Selected) ? QIcon::On : QIcon::Off;
+ tab->icon.paint(p, iconRect, Qt::AlignCenter, mode, state);
}
proxy()->drawItemText(p, tr, alignment, tab->palette, tab->state & State_Enabled, tab->text,
diff --git a/src/xml/doc/src/external-resources.qdoc b/src/xml/doc/src/external-resources.qdoc
index 89c30a84c47..89552477ae8 100644
--- a/src/xml/doc/src/external-resources.qdoc
+++ b/src/xml/doc/src/external-resources.qdoc
@@ -1,17 +1,6 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-/*!
- \externalpage http://www.w3.org/2000/xmlns/
- \title http://www.w3.org/2000/xmlns/
-*/
-
-/*!
- \externalpage http://www.saxproject.org/
- \title SAX2 Java interface
-*/
-
/*!
\externalpage http://www.w3.org/TR/DOM-Level-2-Core/
\title W3C DOM Level 2
diff --git a/tests/auto/CMakeLists.txt b/tests/auto/CMakeLists.txt
index ac8aece707b..7dd9340f51b 100644
--- a/tests/auto/CMakeLists.txt
+++ b/tests/auto/CMakeLists.txt
@@ -4,6 +4,9 @@
# Order by dependency [*], then alphabetic. [*] If bugs in part A of
# our source would break tests of part B, then test A before B.
+
+add_subdirectory(util/testrunner)
+
set(run_dbus_tests OFF)
if (QT_FEATURE_dbus)
set(run_dbus_tests ON)
diff --git a/tests/auto/cmake/mockplugins/.cmake.conf b/tests/auto/cmake/mockplugins/.cmake.conf
index be788d10f8e..846c4f3b923 100644
--- a/tests/auto/cmake/mockplugins/.cmake.conf
+++ b/tests/auto/cmake/mockplugins/.cmake.conf
@@ -1 +1 @@
-set(QT_REPO_MODULE_VERSION "6.11.0")
+set(QT_REPO_MODULE_VERSION "6.12.0")
diff --git a/tests/auto/cmake/test_generating_cpp_exports/.cmake.conf b/tests/auto/cmake/test_generating_cpp_exports/.cmake.conf
index be788d10f8e..846c4f3b923 100644
--- a/tests/auto/cmake/test_generating_cpp_exports/.cmake.conf
+++ b/tests/auto/cmake/test_generating_cpp_exports/.cmake.conf
@@ -1 +1 @@
-set(QT_REPO_MODULE_VERSION "6.11.0")
+set(QT_REPO_MODULE_VERSION "6.12.0")
diff --git a/tests/auto/cmake/test_static_resources/.cmake.conf b/tests/auto/cmake/test_static_resources/.cmake.conf
index be788d10f8e..846c4f3b923 100644
--- a/tests/auto/cmake/test_static_resources/.cmake.conf
+++ b/tests/auto/cmake/test_static_resources/.cmake.conf
@@ -1 +1 @@
-set(QT_REPO_MODULE_VERSION "6.11.0")
+set(QT_REPO_MODULE_VERSION "6.12.0")
diff --git a/tests/auto/corelib/animation/qparallelanimationgroup/tst_qparallelanimationgroup.cpp b/tests/auto/corelib/animation/qparallelanimationgroup/tst_qparallelanimationgroup.cpp
index c2c09a234c8..d134afc4323 100644
--- a/tests/auto/corelib/animation/qparallelanimationgroup/tst_qparallelanimationgroup.cpp
+++ b/tests/auto/corelib/animation/qparallelanimationgroup/tst_qparallelanimationgroup.cpp
@@ -463,9 +463,7 @@ void tst_QParallelAnimationGroup::deleteChildrenWithRunningGroup()
QCOMPARE(group.state(), QAnimationGroup::Running);
QCOMPARE(anim1->state(), QAnimationGroup::Running);
- QTest::qWaitFor([&]{
- return group.currentLoopTime() > 0;
- }, 200ms);
+ QVERIFY(QTest::qWaitFor([&] { return group.currentLoopTime() > 0; }, 200ms));
delete anim1;
QCOMPARE(group.animationCount(), 0);
diff --git a/tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp b/tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp
index 4124b723b4c..29e26f99bdd 100644
--- a/tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp
+++ b/tests/auto/corelib/itemmodels/qrangemodeladapter/tst_qrangemodeladapter.cpp
@@ -220,8 +220,8 @@ API_TEST(moveRows, moveRows(0, 0, 0))
API_TEST(moveTreeRows, moveRows(QList<int>{0, 0}, 0, QList<int>{0, 0}))
API_TEST(insertColumn, insertColumn(0))
-API_TEST(insertColumnWithData, insertColumn(0, {}))
-API_TEST(insertColumns, insertColumns(0, std::declval<Range&>()))
+API_TEST(insertColumnWithData, insertColumn(0, QList<int>{0}))
+API_TEST(insertColumns, insertColumns(0, QList<int>{0}))
API_TEST(removeColumn, removeColumn(0))
API_TEST(removeColumns, removeColumns(0, 0))
API_TEST(moveColumn, moveColumn(0, 0))
@@ -849,7 +849,7 @@ void tst_QRangeModelAdapter::insertColumn_API()
static_assert(has_insertColumnWithData(d.tableOfNumbers));
static_assert(!has_insertColumnWithData(d.constTableOfNumbers));
- static_assert(has_insertColumnWithData(d.tableOfPointers));
+ static_assert(!has_insertColumnWithData(d.tableOfPointers));
}
void tst_QRangeModelAdapter::insertColumns_API()
@@ -863,7 +863,7 @@ void tst_QRangeModelAdapter::insertColumns_API()
static_assert(has_insertColumns(d.tableOfNumbers));
static_assert(!has_insertColumns(d.constTableOfNumbers));
- static_assert(has_insertColumns(d.tableOfPointers));
+ static_assert(!has_insertColumns(d.tableOfPointers));
static_assert(!has_insertColumns(d.tableOfRowPointers));
static_assert(!has_insertColumns(d.listOfNamedRoles));
static_assert(!has_insertColumns(d.m_tree));
@@ -1025,8 +1025,18 @@ void tst_QRangeModelAdapter::modelReset()
QCOMPARE(adapter[0], 3);
QCOMPARE(adapter, (std::vector<int>{3, 2, 1}));
+ modelAboutToBeResetSpy.clear();
+ modelResetSpy.clear();
std::vector<int> modifiedData = adapter;
+
+ adapter.assign(modifiedData.begin(), modifiedData.end());
+ QCOMPARE(modelResetSpy.count(), 1);
+ adapter.setRange(std::vector<int>{3, 2, 1});
+ QCOMPARE(modelResetSpy.count(), 2);
+ std::vector<short> shorts = {10, 11, 12};
+ adapter.assign(shorts.begin(), shorts.end());
+ QCOMPARE(modelResetSpy.count(), 3);
}
{
@@ -1533,7 +1543,7 @@ void tst_QRangeModelAdapter::tableWriteAccess()
QTest::ignoreMessage(QtCriticalMsg,
QRegularExpression("Not able to assign QVariant"));
QTest::ignoreMessage(QtWarningMsg, QRegularExpression("Writing value of type Object\\* to "
- "role Qt::RangeModelAdapterRole at index .* of the model failed"));
+ "role Qt::RangeModelAdapterRole at index .* failed"));
#endif
adapter.at(0, 0) = new Object;
QCOMPARE(dataChangedSpy.count(), 0);
@@ -2620,11 +2630,35 @@ using ObjectTree = std::vector<ObjectTreeItem>;
class ObjectTreeItem : public ObjectRow
{
public:
- ObjectTreeItem(Object *item = nullptr)
+ ObjectTreeItem() = default;
+
+ explicit ObjectTreeItem(Object *item)
{
m_objects[0] = item;
}
+ ObjectTreeItem(const ObjectTreeItem &other) = delete;
+ ObjectTreeItem &operator=(const ObjectTreeItem &other) = delete;
+ ObjectTreeItem(ObjectTreeItem &&other) noexcept
+ {
+ m_children = std::move(other.m_children);
+ m_objects = std::move(other.m_objects);
+ other.m_objects = {};
+ }
+
+ ObjectTreeItem &operator=(ObjectTreeItem &&other) noexcept
+ {
+ m_children = std::move(other.m_children);
+ m_objects = std::move(other.m_objects);
+ other.m_objects = {};
+ return *this;
+ }
+
+ ~ObjectTreeItem()
+ {
+ qDeleteAll(m_objects);
+ }
+
ObjectTreeItem *parentRow() const { return m_parentRow; }
void setParentRow(ObjectTreeItem *parentRow) { m_parentRow = parentRow; }
const auto &childRows() const { return m_children; }
@@ -2646,9 +2680,7 @@ namespace std {
void tst_QRangeModelAdapter::insertAutoConnectObjects()
{
- ObjectTree emptyTree;
-
- QRangeModelAdapter adapter(emptyTree);
+ QRangeModelAdapter adapter(ObjectTree{});
QSignalSpy dataChangedSpy(adapter.model(), &QAbstractItemModel::dataChanged);
adapter.model()->setAutoConnectPolicy(QRangeModel::AutoConnectPolicy::Full);
@@ -2662,11 +2694,11 @@ void tst_QRangeModelAdapter::insertAutoConnectObjects()
Object *newChild = new Object;
auto firstRow = adapter.begin();
- (*firstRow).children() = ObjectTree{
- ObjectTreeItem(newChild),
- ObjectTreeItem(),
- ObjectTreeItem()
- };
+ {
+ ObjectTree children(3);
+ children[0] = ObjectTreeItem(newChild);
+ (*firstRow).children() = std::move(children);
+ }
QCOMPARE(dataChangedSpy.count(), 0);
QVERIFY(adapter.hasChildren(0));
newChild->setString("0.0");
@@ -2684,12 +2716,14 @@ void tst_QRangeModelAdapter::insertAutoConnectObjects()
newChild = new Object;
Object *newGrandChild = new Object;
ObjectTreeItem newBranch(newChild);
- newBranch.childRows() = ObjectTree{
- ObjectTreeItem(), // skip the first row to verify that we continue through nullptr
- ObjectTreeItem(newGrandChild),
- ObjectTreeItem()
- };
- adapter.at({0, 2}) = newBranch;
+ {
+ ObjectTree children(3);
+ // skip the first row to verify that we continue through nullptr
+ children[1] = ObjectTreeItem(newGrandChild);
+ newBranch.childRows() = std::move(children);
+ }
+ adapter.at({0, 2}) = std::move(newBranch);
+ QCOMPARE(adapter.rowCount({0, 2}), 3);
QCOMPARE(dataChangedSpy.count(), 1);
newChild->setNumber(1);
QCOMPARE(dataChangedSpy.count(), 2);
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index 2fcfd056882..a30ed901fe6 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -6,6 +6,8 @@
#include <qvariant.h>
#include <QtCore/qttypetraits.h>
+#include <QtCore/qsequentialiterable.h>
+#include <QtCore/qassociativeiterable.h>
// don't assume <type_traits>
template <typename T, typename U>
@@ -5025,7 +5027,7 @@ void sortIterable(QMetaSequence::Iterable *iterable)
}
template<typename Container>
-static void testSequentialIteration()
+static void testMetaSequenceIteration()
{
QFETCH(bool, hasSizeAccessor);
QFETCH(bool, hasIndexedAccessors);
@@ -5157,7 +5159,7 @@ static void testSequentialIteration()
}
template<typename Container>
-static void testAssociativeIteration()
+static void testMetaAssociationIteration()
{
using Key = typename Container::key_type;
using Mapped = typename Container::mapped_type;
@@ -5228,12 +5230,268 @@ static void testAssociativeIteration()
QCOMPARE(f, iter.constEnd());
}
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && QT_DEPRECATED_SINCE(6, 15)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+
+template<typename Iterator>
+void sortIterable(QSequentialIterable *iterable)
+{
+ std::sort(Iterator(iterable->mutableBegin()), Iterator(iterable->mutableEnd()),
+ [&](const QVariant &a, const QVariant &b) {
+ return a.toInt() < b.toInt();
+ });
+}
+
+template<typename Container>
+static void testSequentialIteration()
+{
+ QFETCH(bool, hasSizeAccessor);
+ const auto ignoreSizeWarning = [hasSizeAccessor]() {
+ if (hasSizeAccessor)
+ return;
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ "size() called on an iterable without native size accessor. This is slow");
+ };
+ QTest::failOnWarning();
+
+ int numSeen = 0;
+ Container sequence;
+ ContainerAPI<Container>::insert(sequence, 1);
+ ContainerAPI<Container>::insert(sequence, 2);
+ ContainerAPI<Container>::insert(sequence, 3);
+
+ QVariant listVariant = QVariant::fromValue(sequence);
+ QVERIFY(listVariant.canConvert<QVariantList>());
+ QVariantList varList = listVariant.value<QVariantList>();
+ ignoreSizeWarning();
+ QCOMPARE(varList.size(), (int)std::distance(sequence.begin(), sequence.end()));
+ QSequentialIterable listIter = listVariant.view<QSequentialIterable>();
+ ignoreSizeWarning();
+ QCOMPARE(varList.size(), listIter.size());
+
+ typename Container::iterator containerIter = sequence.begin();
+ const typename Container::iterator containerEnd = sequence.end();
+ ignoreSizeWarning();
+ for (int i = 0, end = listIter.size(); i < end; ++i, ++containerIter, ++numSeen)
+ {
+ QVERIFY(ContainerAPI<Container >::compare(listIter.at(i), *containerIter));
+ QVERIFY(ContainerAPI<Container >::compare(listIter.at(i), varList.at(i)));
+ }
+ QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end()));
+ QCOMPARE(containerIter, containerEnd);
+
+ numSeen = 0;
+ containerIter = sequence.begin();
+ for (QVariant v : listIter) {
+ QVERIFY(ContainerAPI<Container>::compare(v, *containerIter));
+ QVERIFY(ContainerAPI<Container>::compare(v, varList.at(numSeen)));
+ ++containerIter;
+ ++numSeen;
+ }
+ QCOMPARE(numSeen, (int)std::distance(sequence.begin(), sequence.end()));
+
+ auto compareLists = [&]() {
+ int numSeen = 0;
+ auto varList = listVariant.value<QVariantList>();
+ auto varIter = varList.begin();
+ for (const QVariant &v : std::as_const(listIter)) {
+ QVERIFY(ContainerAPI<Container>::compare(v, *varIter));
+ ++varIter;
+ ++numSeen;
+ }
+ QCOMPARE(varIter, varList.end());
+ numSeen = 0;
+ auto constVarIter = varList.constBegin();
+ for (QVariant v : listIter) {
+ QVERIFY(ContainerAPI<Container>::compare(v, *constVarIter));
+ ++constVarIter;
+ ++numSeen;
+ }
+ QCOMPARE(numSeen, (int)std::distance(varList.begin(), varList.end()));
+ };
+ compareLists();
+
+ QVariant first = listIter.at(0);
+ QVariant second = listIter.at(1);
+ QVariant third = listIter.at(2);
+ compareLists();
+ listIter.addValue(third);
+ compareLists();
+ listIter.addValue(second);
+ compareLists();
+ listIter.addValue(first);
+ compareLists();
+
+ QCOMPARE(listIter.size(), 6);
+
+ if (listIter.canRandomAccessIterate())
+ sortIterable<QSequentialIterable::RandomAccessIterator>(&listIter);
+ else if (listIter.canReverseIterate())
+ sortIterable<QSequentialIterable::BidirectionalIterator>(&listIter);
+ else if (listIter.canForwardIterate())
+ return; // std::sort cannot sort with only forward iterators.
+ else
+ QFAIL("The container has no meaningful iterators");
+
+ compareLists();
+ ignoreSizeWarning();
+ QCOMPARE(listIter.size(), 6);
+ QCOMPARE(listIter.at(0), first);
+ QCOMPARE(listIter.at(1), first);
+ QCOMPARE(listIter.at(2), second);
+ QCOMPARE(listIter.at(3), second);
+ QCOMPARE(listIter.at(4), third);
+ QCOMPARE(listIter.at(5), third);
+
+ if (listIter.metaContainer().canRemoveValue()) {
+ listIter.removeValue();
+ compareLists();
+ ignoreSizeWarning();
+ QCOMPARE(listIter.size(), 5);
+ QCOMPARE(listIter.at(0), first);
+ QCOMPARE(listIter.at(1), first);
+ QCOMPARE(listIter.at(2), second);
+ QCOMPARE(listIter.at(3), second);
+ QCOMPARE(listIter.at(4), third);
+ } else {
+ // QString and QByteArray have no pop_back or pop_front and it's unclear what other
+ // method we should use to remove an item.
+ QVERIFY((std::is_same_v<Container, QString> || std::is_same_v<Container, QByteArray>));
+ }
+
+ auto i = listIter.mutableBegin();
+ QVERIFY(i != listIter.mutableEnd());
+
+ *i = QStringLiteral("17");
+ if (listIter.metaContainer().valueMetaType() == QMetaType::fromType<int>())
+ QCOMPARE(listIter.at(0).toInt(), 17);
+ else if (listIter.metaContainer().valueMetaType() == QMetaType::fromType<bool>())
+ QCOMPARE(listIter.at(0).toBool(), false);
+
+ *i = QStringLiteral("true");
+ if (listIter.metaContainer().valueMetaType() == QMetaType::fromType<int>())
+ QCOMPARE(listIter.at(0).toInt(), 0);
+ else if (listIter.metaContainer().valueMetaType() == QMetaType::fromType<bool>())
+ QCOMPARE(listIter.at(0).toBool(), true);
+}
+
+template<typename Container>
+static void testAssociativeIteration()
+{
+ using Key = typename Container::key_type;
+ using Mapped = typename Container::mapped_type;
+
+ int numSeen = 0;
+ Container mapping;
+ mapping[5] = true;
+ mapping[15] = false;
+
+ QVariant mappingVariant = QVariant::fromValue(mapping);
+ QVariantMap varMap = mappingVariant.value<QVariantMap>();
+ QVariantMap varHash = mappingVariant.value<QVariantMap>();
+ QAssociativeIterable mappingIter = mappingVariant.view<QAssociativeIterable>();
+
+ typename Container::const_iterator containerIter = mapping.begin();
+ const typename Container::const_iterator containerEnd = mapping.end();
+ for ( ;containerIter != containerEnd; ++containerIter, ++numSeen)
+ {
+ Mapped expected = KeyGetter<Container>::value(containerIter);
+ Key key = KeyGetter<Container>::get(containerIter);
+ Mapped actual = qvariant_cast<Mapped>(mappingIter.value(key));
+ QCOMPARE(qvariant_cast<Mapped>(varMap.value(QString::number(key))), expected);
+ QCOMPARE(qvariant_cast<Mapped>(varHash.value(QString::number(key))), expected);
+ QCOMPARE(actual, expected);
+ const QAssociativeIterable::const_iterator it = mappingIter.find(key);
+ QVERIFY(it != mappingIter.end());
+ QCOMPARE(it.value().value<Mapped>(), expected);
+ }
+ QCOMPARE(numSeen, (int)std::distance(mapping.begin(), mapping.end()));
+ QCOMPARE(containerIter, containerEnd);
+ QVERIFY(mappingIter.find(10) == mappingIter.end());
+
+ auto i = mappingIter.mutableFind(QStringLiteral("nonono"));
+ QCOMPARE(i, mappingIter.mutableEnd());
+ i = mappingIter.mutableFind(QStringLiteral("5"));
+ QVERIFY(i != mappingIter.mutableEnd());
+
+ *i = QStringLiteral("17");
+
+ if (mappingIter.metaContainer().mappedMetaType() == QMetaType::fromType<int>())
+ QCOMPARE(mappingIter.value(5).toInt(), 17);
+ else if (mappingIter.metaContainer().mappedMetaType() == QMetaType::fromType<bool>())
+ QCOMPARE(mappingIter.value(5).toBool(), true);
+
+ *i = QStringLiteral("true");
+ if (mappingIter.metaContainer().mappedMetaType() == QMetaType::fromType<int>())
+ QCOMPARE(mappingIter.value(5).toInt(), 0);
+ else if (mappingIter.metaContainer().mappedMetaType() == QMetaType::fromType<bool>())
+ QCOMPARE(mappingIter.value(5).toBool(), true);
+
+ QVERIFY(mappingIter.containsKey("5"));
+ mappingIter.removeKey(QStringLiteral("5"));
+ QCOMPARE(mappingIter.find(5), mappingIter.end());
+
+ mappingIter.setValue(5, 44);
+ if (mappingIter.metaContainer().mappedMetaType() == QMetaType::fromType<int>())
+ QCOMPARE(mappingIter.value(5).toInt(), 44);
+ else if (mappingIter.metaContainer().mappedMetaType() == QMetaType::fromType<bool>())
+ QCOMPARE(mappingIter.value(5).toBool(), true);
+
+ // Test that find() does not coerce
+ auto container = Container();
+ container[0] = true;
+
+ QVariant containerVariant = QVariant::fromValue(container);
+ QAssociativeIterable iter = containerVariant.value<QAssociativeIterable>();
+ auto f = iter.constFind(QStringLiteral("anything"));
+ QCOMPARE(f, iter.constEnd());
+}
+
+template<typename T>
+static void addRowSequential(const char *name, bool hasSizeAccessor, bool hasIndexedAccessor)
+{
+ QTest::newRow(name)
+ << &testMetaSequenceIteration<T> << hasSizeAccessor << hasIndexedAccessor;
+ QTest::addRow("%s_old", name)
+ << &testSequentialIteration<T> << hasSizeAccessor << hasIndexedAccessor;
+}
+
+template<typename C>
+static void addRowAssociative(const char *name)
+{
+ QTest::newRow(name)
+ << &testMetaAssociationIteration<C>;
+ QTest::addRow("%s_old", name)
+ << &testAssociativeIteration<C>;
+}
+
+QT_WARNING_POP
+#else
+
+template<typename T>
+static void addRowSequential(const char *name, bool hasSizeAccessor, bool hasIndexedAccessor)
+{
+ QTest::newRow(name)
+ << &testMetaSequenceIteration<T> << hasSizeAccessor << hasIndexedAccessor;
+}
+
+template<typename C>
+static void addRowAssociative(const char *name)
+{
+ QTest::newRow(name)
+ << &testMetaAssociationIteration<C>;
+}
+
+#endif // QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && QT_DEPRECATED_SINCE(6, 15)
+
void tst_QVariant::iterateSequentialContainerElements_data()
{
QTest::addColumn<QFunctionPointer>("testFunction");
QTest::addColumn<bool>("hasSizeAccessor");
QTest::addColumn<bool>("hasIndexedAccessors");
-#define ADD(T) QTest::newRow(#T) << &testSequentialIteration<T> << true << true
+#define ADD(T) addRowSequential<T>(#T, true, true)
ADD(QQueue<int>);
ADD(QQueue<QVariant>);
ADD(QQueue<QString>);
@@ -5253,13 +5511,13 @@ void tst_QVariant::iterateSequentialContainerElements_data()
ADD(QByteArray);
#undef ADD
-#define ADD(T) QTest::newRow(#T) << &testSequentialIteration<T> << true << false
+#define ADD(T) addRowSequential<T>(#T, true, false)
ADD(std::list<int>);
ADD(std::list<QVariant>);
ADD(std::list<QString>);
#undef ADD
-#define ADD(T) QTest::newRow(#T) << &testSequentialIteration<T> << false << false
+#define ADD(T) addRowSequential<T>(#T, false, false)
#ifdef TEST_FORWARD_LIST
ADD(std::forward_list<int>);
ADD(std::forward_list<QVariant>);
@@ -5271,7 +5529,7 @@ void tst_QVariant::iterateSequentialContainerElements_data()
void tst_QVariant::iterateAssociativeContainerElements_data()
{
QTest::addColumn<QFunctionPointer>("testFunction");
-#define ADD(C, K, V) QTest::newRow(#C #K #V) << &testAssociativeIteration<C<K, V>>;
+#define ADD(C, K, V) addRowAssociative<C<K, V>>(#C "<" #K "," #V ">");
ADD(QHash, int, bool);
ADD(QHash, int, int);
ADD(QMap, int, bool);
@@ -6448,15 +6706,15 @@ void tst_QVariant::get_NonDefaultConstructible()
struct QVariantWrapper
{
public:
- static constexpr bool canNoexceptConvertToQVariant
+ static constexpr bool CanNoexceptConvertToQVariant
= std::is_nothrow_copy_constructible_v<QVariant>;
- static constexpr bool canNoexceptAssignQVariant
+ static constexpr bool CanNoexceptAssignQVariant
= std::is_nothrow_copy_assignable_v<QVariant>;
QVariantWrapper(QVariant *content = nullptr) noexcept : m_content(content) {}
- QVariant content() const noexcept(canNoexceptConvertToQVariant) { return *m_content; }
- void setContent(const QVariant &content) noexcept(canNoexceptAssignQVariant)
+ QVariant content() const noexcept(CanNoexceptConvertToQVariant) { return *m_content; }
+ void setContent(const QVariant &content) noexcept(CanNoexceptAssignQVariant)
{
*m_content = content;
}
@@ -6468,14 +6726,14 @@ private:
QT_BEGIN_NAMESPACE
template<>
QVariant::ConstReference<QVariantWrapper>::operator QVariant() const
- noexcept(QVariantWrapper::canNoexceptConvertToQVariant)
+ noexcept(QVariantWrapper::CanNoexceptConvertToQVariant)
{
return m_referred.content();
}
template<>
QVariant::Reference<QVariantWrapper> &QVariant::Reference<QVariantWrapper>::operator=(
- const QVariant &content) noexcept(QVariantWrapper::canNoexceptAssignQVariant)
+ const QVariant &content) noexcept(QVariantWrapper::CanNoexceptAssignQVariant)
{
m_referred.setContent(content);
return *this;
diff --git a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
index 2d9d351286f..f1f88891015 100644
--- a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
+++ b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp
@@ -63,11 +63,11 @@ using namespace Qt::StringLiterals;
#elif defined(Q_OS_WIN)
# undef dll_VALID
# define dll_VALID true
-//# ifdef QT_NO_DEBUG
+# if !defined(QT_NO_DEBUG) && defined(Q_CC_MSVC)
+# define SUFFIX "d.dll"
+# else
# define SUFFIX ".dll"
-//# else
-//# define SUFFIX "d.dll"
-//# endif
+# endif
# define PREFIX ""
#else // all other Unix
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index 806b6b43161..f7d98eb15e2 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -5656,6 +5656,12 @@ void tst_QFuture::cancelChainWithContext()
int onCancelCnt = 0;
bool unexpectedThread = false;
+ // For in-other-thread case we need a semaphore to make sure that
+ // the needed continuation is executed.
+ // Fot the in-main-thread case it's guaranteed by the unwrap()
+ // implementation.
+ QSemaphore sem;
+
auto f = p1.future()
.then(context, [&]() {
if (QThread::currentThread() != thread)
@@ -5666,6 +5672,8 @@ void tst_QFuture::cancelChainWithContext()
if (QThread::currentThread() != thread)
unexpectedThread = true;
++thenCnt;
+ if (inOtherThread)
+ sem.release();
return f;
}).unwrap()
.then(context, [&]{
@@ -5685,6 +5693,8 @@ void tst_QFuture::cancelChainWithContext()
});
p1.finish();
+ if (inOtherThread)
+ sem.acquire();
f.cancelChain();
p2.finish();
f.waitForFinished();
@@ -5737,6 +5747,75 @@ void tst_QFuture::cancelChainWithContext()
QCOMPARE_EQ(thenCnt, 4);
QCOMPARE_EQ(onCancelCnt, 0);
}
+ // cancelling propagates through unwrap()
+ {
+ QPromise<void> p1, p2;
+ p1.start();
+ p2.start();
+
+ int thenCnt = 0;
+ int onCancelCnt = 0;
+ bool unexpectedThread = false;
+
+ // For in-other-thread case we need a semaphore to make sure that
+ // the first continuation is executed.
+ // Fot the in-main-thread case it's guaranteed by the unwrap()
+ // implementation.
+ QSemaphore sem;
+
+ auto f = p1.future()
+ .then(context, [&, f2 = p2.future()]() {
+ if (QThread::currentThread() != thread)
+ unexpectedThread = true;
+ ++thenCnt;
+ if (inOtherThread)
+ sem.release();
+ return f2;
+ }).unwrap()
+ .onCanceled(context, [&] {
+ if (QThread::currentThread() != thread)
+ unexpectedThread = true;
+ ++onCancelCnt;
+ })
+ .then([&]() {
+ if (QThread::currentThread() != thread)
+ unexpectedThread = true;
+ ++thenCnt;
+ return QtFuture::makeReadyVoidFuture();
+ }).unwrap()
+ .onCanceled([&] {
+ if (QThread::currentThread() != thread)
+ unexpectedThread = true;
+ ++onCancelCnt;
+ })
+ .then(context, [&]{
+ if (QThread::currentThread() != thread)
+ unexpectedThread = true;
+ ++thenCnt;
+ return QtFuture::makeReadyVoidFuture();
+ }).unwrap()
+ .onCanceled([&] {
+ if (QThread::currentThread() != thread)
+ unexpectedThread = true;
+ ++onCancelCnt;
+ })
+ .then(context, [&]{
+ if (QThread::currentThread() != thread)
+ unexpectedThread = true;
+ ++thenCnt;
+ });
+
+ p1.finish();
+ if (inOtherThread)
+ sem.acquire();
+ f.cancelChain();
+ p2.finish();
+ f.waitForFinished();
+
+ QVERIFY(!unexpectedThread);
+ QCOMPARE_EQ(thenCnt, 1);
+ QCOMPARE_EQ(onCancelCnt, 3);
+ }
}
void tst_QFuture::cancelChainOnAnOverwrittenFuture()
diff --git a/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp b/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp
index 86dfa5faffc..4c089091f8d 100644
--- a/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp
+++ b/tests/auto/corelib/thread/qreadwritelock/tst_qreadwritelock.cpp
@@ -57,6 +57,7 @@ private slots:
void multipleReadersLoop();
void multipleWritersLoop();
void multipleReadersWritersLoop();
+ void heavyLoadLocks();
void countingTest();
void limitedReaders();
void deleteOnUnlock();
@@ -603,6 +604,111 @@ public:
}
};
+class HeavyLoadLockThread : public QThread
+{
+public:
+ QReadWriteLock &testRwlock;
+ const qsizetype iterations;
+ const int numThreads;
+ inline HeavyLoadLockThread(QReadWriteLock &l, qsizetype iters, int numThreads, QVector<QAtomicInt *> &counters):
+ testRwlock(l),
+ iterations(iters),
+ numThreads(numThreads),
+ counters(counters)
+ { }
+
+private:
+ QVector<QAtomicInt *> &counters;
+ QAtomicInt *getCounter(qsizetype index)
+ {
+ QReadLocker locker(&testRwlock);
+ /*
+ The index is increased monotonically, so the index
+ being requested should be always within or at the end of the
+ counters vector.
+ */
+ Q_ASSERT(index <= counters.size());
+ if (counters.size() <= index || counters[index] == nullptr) {
+ locker.unlock();
+ QWriteLocker wlocker(&testRwlock);
+ if (counters.size() <= index)
+ counters.resize(index + 1, nullptr);
+ if (counters[index] == nullptr)
+ counters[index] = new QAtomicInt(0);
+ return counters[index];
+ }
+ return counters[index];
+ }
+ void releaseCounter(qsizetype index)
+ {
+ QWriteLocker locker(&testRwlock);
+ delete counters[index];
+ counters[index] = nullptr;
+ }
+
+public:
+ void run() override
+ {
+ for (qsizetype i = 0; i < iterations; ++i) {
+ QAtomicInt *counter = getCounter(i);
+ /*
+ Here each counter is accessed by each thread
+ and increaed only once. As a result, when the
+ counter reaches numThreads, i.e. the fetched
+ value before the increment is numThreads-1,
+ we know all threads have accessed this counter
+ and we can delete it safely.
+ */
+ int prev = counter->fetchAndAddRelaxed(1);
+ if (prev == numThreads - 1) {
+#ifdef QT_BUILDING_UNDER_TSAN
+ /*
+ Under TSAN, deleting and freeing an object
+ will trigger a write operation on the memory
+ of the object. Since we used fetchAndAddRelaxed
+ to update the counter, TSAN will report a data
+ race when deleting the counter here. To avoid
+ the false positive, we simply reset the counter
+ to 0 here, with ordered semantics to establish
+ the sequence to ensure the the free-ing option
+ happens after all fetchAndAddRelaxed operations
+ in other threads.
+
+ When not building under TSAN, deleting the counter
+ will not result in any data read or written to the
+ memory region of the counter, so no data race will
+ happen.
+ */
+ counter->fetchAndStoreOrdered(0);
+#endif
+ releaseCounter(i);
+ }
+ }
+ }
+};
+
+/*
+ Multiple threads racing acquiring and releasing
+ locks on the same indices.
+*/
+
+void tst_QReadWriteLock::heavyLoadLocks()
+{
+ constexpr qsizetype iterations = 65536 * 4;
+ constexpr int numThreads = 8;
+ QVector<QAtomicInt *> counters;
+ QReadWriteLock testLock;
+ std::array<std::unique_ptr<HeavyLoadLockThread>, numThreads> threads;
+ for (auto &thread : threads)
+ thread = std::make_unique<HeavyLoadLockThread>(testLock, iterations, numThreads, counters);
+ for (auto &thread : threads)
+ thread->start();
+ for (auto &thread : threads)
+ thread->wait();
+ QVERIFY(counters.size() == iterations);
+ for (qsizetype i = 0; i < iterations; ++i)
+ QVERIFY(counters[i] == nullptr);
+}
/*
A writer acquires a read-lock, a reader locks
diff --git a/tests/auto/tools/rcc/data/legal/rcc_legal.cpp b/tests/auto/tools/rcc/data/legal/rcc_legal.cpp
index 248ab2e3b48..96f87d192e7 100644
--- a/tests/auto/tools/rcc/data/legal/rcc_legal.cpp
+++ b/tests/auto/tools/rcc/data/legal/rcc_legal.cpp
@@ -3,7 +3,7 @@
** Copyright (C) 2024 Intel Corporation.
** SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
**
-** Created by: The Resource Compiler for Qt version 6.11.0
+** Created by: The Resource Compiler for Qt version 6.12.0
**
** WARNING! All changes made in this file will be lost!
*****************************************************************************/
diff --git a/tests/auto/util/testrunner/CMakeLists.txt b/tests/auto/util/testrunner/CMakeLists.txt
new file mode 100644
index 00000000000..5ca8406f854
--- /dev/null
+++ b/tests/auto/util/testrunner/CMakeLists.txt
@@ -0,0 +1,14 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+
+# Run the qt-testrunner test only inside the CI.
+if(DEFINED ENV{COIN_UNIQUE_JOB_ID} AND NOT IOS)
+ qt_internal_create_test_script(
+ NAME tst_qt_testrunner
+ COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/tst_qt_testrunner.py" ARGS -v
+ WORKING_DIRECTORY "${test_working_dir}"
+ OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/tst_qt_testrunner_Wrapper$<CONFIG>.cmake"
+ ENVIRONMENT "TESTRUNNER" ""
+ )
+endif()
diff --git a/util/testrunner/tests/qt_mock_test-log.xml b/tests/auto/util/testrunner/qt_mock_test-log.xml
index 62e93bb8dcc..a164bec9f9c 100644
--- a/util/testrunner/tests/qt_mock_test-log.xml
+++ b/tests/auto/util/testrunner/qt_mock_test-log.xml
@@ -21,6 +21,16 @@
<Incident type="{{always_crash_result}}" file="" line="0" />
<Duration msecs="0.828272"/>
</TestFunction>
+
+ <!-- The strings like this one "{{fail_then_pass:2_result}}"
+ are just template strings that will be replaced by the test driver
+ before each test. The colon doesn't have a special meaning.
+ The datatags in the following tests are just "2", "5", "6".
+ We don't strictly need datatags because the tests don't include
+ specific testing for datatags. It's just that adding a couple
+ of datatags to this XML template, complicates it a bit and
+ tests somewhat that functionality as a side-effect.
+ -->
<TestFunction name="fail_then_pass">
<Incident type="{{fail_then_pass:2_result}}" file="" line="0">
<DataTag><![CDATA[2]]></DataTag>
@@ -32,5 +42,9 @@
<DataTag><![CDATA[6]]></DataTag>
</Incident>
</TestFunction>
+ <TestFunction name="fail_then_crash">
+ <Incident type="{{fail_then_crash_result}}" file="" line="0" />
+ <Duration msecs="0.828272"/>
+ </TestFunction>
<Duration msecs="1904.9"/>
</TestCase>
diff --git a/util/testrunner/tests/qt_mock_test.py b/tests/auto/util/testrunner/qt_mock_test.py
index a7adb8804af..af8fdf24509 100755
--- a/util/testrunner/tests/qt_mock_test.py
+++ b/tests/auto/util/testrunner/qt_mock_test.py
@@ -24,28 +24,36 @@
# Mode B:
#
# If invoked without any argument, it runs the tests listed in the
-# variable QT_MOCK_TEST_FAIL_LIST. If variable is empty it just runs
+# variable QT_MOCK_TEST_RUN_LIST. If variable is empty it just runs
# the always_pass test. It also understands qtestlib's `-o outfile.xml,xml`
# option for writing a mock testlog in a file. Requires environment variables:
# + QT_MOCK_TEST_STATE_FILE :: See above
# + QT_MOCK_TEST_XML_TEMPLATE_FILE :: may point to the template XML file
# located in the same source directory. Without this variable, the
# option `-o outfile.xml,xml` will be ignored.
-# + QT_MOCK_TEST_FAIL_LIST :: may contain a comma-separated list of test
+# + QT_MOCK_TEST_RUN_LIST :: may contain a comma-separated list of test
# that should run.
+# + QT_MOCK_TEST_CRASH_CLEANLY :: if set to 1, then the executable will
+# crash (exit with a high exit code)
+# after successfully running the given tests and writing the XML logfile.
+
import sys
import os
import traceback
-from tst_testrunner import write_xml_log
+from tst_qt_testrunner import write_xml_log
MY_NAME = os.path.basename(sys.argv[0])
STATE_FILE = None
XML_TEMPLATE = None
XML_OUTPUT_FILE = None
+CRASH_CLEANLY = False
+
+def crash():
+ sys.exit(131)
def put_failure(test_name):
with open(STATE_FILE, "a") as f:
@@ -98,6 +106,15 @@ def log_test(testcase, result,
testsuite=MY_NAME.rpartition(".")[0]):
print("%-7s: %s::%s()" % (result, testsuite, testcase))
+def log_xml(fail_list):
+ if XML_OUTPUT_FILE and XML_TEMPLATE is not None:
+ if XML_TEMPLATE == "":
+ # If the template is an empty file, then write an empty output file
+ with open(XML_OUTPUT_FILE, "w"):
+ pass
+ else:
+ write_xml_log(XML_OUTPUT_FILE, failure=fail_list)
+
# Return the exit code
def run_test(testname):
if testname == "initTestCase":
@@ -107,7 +124,14 @@ def run_test(testname):
elif testname == "always_fail":
exit_code = 1
elif testname == "always_crash":
- exit_code = 130
+ exit_code = 131
+ elif testname == "fail_then_crash":
+ previous_fails = get_failures(testname)
+ if previous_fails == 0:
+ put_failure(testname)
+ exit_code = 1
+ else:
+ exit_code = 131
elif testname.startswith("fail_then_pass"):
wanted_fails = int(testname.partition(":")[2])
previous_fails = get_failures(testname)
@@ -139,13 +163,16 @@ def no_args_run():
for test in run_list:
test_exit_code = run_test(test)
if test_exit_code not in (0, 1):
- sys.exit(130) # CRASH!
+ crash()
if test_exit_code != 0:
fail_list.append(test)
total_result = total_result and (test_exit_code == 0)
- if XML_TEMPLATE and XML_OUTPUT_FILE:
- write_xml_log(XML_OUTPUT_FILE, failure=fail_list)
+ log_xml(fail_list)
+
+ if CRASH_CLEANLY:
+ # Crash despite all going well and writing all output files cleanly.
+ crash()
if total_result:
sys.exit(0)
@@ -163,13 +190,25 @@ def main():
with open(os.environ["QT_MOCK_TEST_XML_TEMPLATE_FILE"]) as f:
XML_TEMPLATE = f.read()
+ global CRASH_CLEANLY
+ if ("QT_MOCK_TEST_CRASH_CLEANLY" in os.environ
+ and os.environ["QT_MOCK_TEST_CRASH_CLEANLY"] == "1"
+ ):
+ CRASH_CLEANLY = True
+
args = clean_cmdline()
if len(args) == 0:
no_args_run()
assert False, "Unreachable!"
- else:
- sys.exit(run_test(args[0]))
+ else: # run single test function
+ exit_code = run_test(args[0])
+ # Write "fail" in the XML log only if the specific run has failed.
+ if exit_code != 0:
+ log_xml([args[0]])
+ else:
+ log_xml([])
+ sys.exit(exit_code)
# TODO write XPASS test that does exit(1)
diff --git a/util/testrunner/tests/tst_testrunner.py b/tests/auto/util/testrunner/tst_qt_testrunner.py
index 4a3d92e167b..1134fa0427f 100755
--- a/util/testrunner/tests/tst_testrunner.py
+++ b/tests/auto/util/testrunner/tst_qt_testrunner.py
@@ -14,7 +14,8 @@ from tempfile import TemporaryDirectory, mkstemp
MY_NAME = os.path.basename(__file__)
my_dir = os.path.dirname(__file__)
-testrunner = os.path.join(my_dir, "..", "qt-testrunner.py")
+testrunner = os.path.join(my_dir, "..", "..", "..", "..",
+ "util", "testrunner", "qt-testrunner.py")
mock_test = os.path.join(my_dir, "qt_mock_test.py")
xml_log_template = os.path.join(my_dir, "qt_mock_test-log.xml")
@@ -26,7 +27,12 @@ import unittest
def setUpModule():
global TEMPDIR
- TEMPDIR = TemporaryDirectory(prefix="tst_testrunner-")
+ TEMPDIR = TemporaryDirectory(prefix="tst_qt_testrunner-")
+
+ global EMPTY_FILE
+ EMPTY_FILE = os.path.join(TEMPDIR.name, "EMPTY")
+ with open(EMPTY_FILE, "w") as f:
+ pass
filename = os.path.join(TEMPDIR.name, "file_1")
print("setUpModule(): setting up temporary directory and env var"
@@ -35,6 +41,7 @@ def setUpModule():
os.environ["QT_MOCK_TEST_STATE_FILE"] = filename
os.environ["QT_MOCK_TEST_XML_TEMPLATE_FILE"] = xml_log_template
+ os.environ["QT_TESTRUNNER_TESTING"] = "1"
def tearDownModule():
print("\ntearDownModule(): Cleaning up temporary directory:",
@@ -44,22 +51,32 @@ def tearDownModule():
# Helper to run a command and always capture output
-def run(*args, **kwargs):
+def run(args : list, **kwargs):
+ if args[0].endswith(".py"):
+ # Make sure we run python executables with the same python version.
+ # It also helps on Windows, that .py files are not directly executable.
+ args = [ sys.executable, *args ]
if DEBUG:
print("Running: ", args, flush=True)
- proc = subprocess.run(*args, stdout=PIPE, stderr=STDOUT, **kwargs)
+ proc = subprocess.run(args, stdout=PIPE, stderr=STDOUT, **kwargs)
if DEBUG and proc.stdout:
print(proc.stdout.decode(), flush=True)
return proc
# Helper to run qt-testrunner.py with proper testing arguments.
-def run_testrunner(xml_filename=None, testrunner_args=None,
+# Always append --log-dir=TEMPDIR unless specifically told not to.
+def run_testrunner(xml_filename=None, log_dir=None,
+ testrunner_args=None,
wrapper_script=None, wrapper_args=None,
qttest_args=None, env=None):
args = [ testrunner ]
if xml_filename:
args += [ "--parse-xml-testlog", xml_filename ]
+ if log_dir == None:
+ args += [ "--log-dir", TEMPDIR.name ]
+ elif log_dir != "":
+ args += [ "--log-dir", log_dir ]
if testrunner_args:
args += testrunner_args
@@ -75,16 +92,21 @@ def run_testrunner(xml_filename=None, testrunner_args=None,
return run(args, env=env)
# Write the XML_TEMPLATE to filename, replacing the templated results.
-def write_xml_log(filename, failure=None):
+def write_xml_log(filename, failure=None, inject_message=None):
data = XML_TEMPLATE
+ if failure is None:
+ failure = []
+ elif isinstance(failure, str):
+ failure = [ failure ]
# Replace what was asked to fail with "fail"
- if type(failure) in (list, tuple):
- for template in failure:
- data = data.replace("{{"+template+"_result}}", "fail")
- elif type(failure) is str:
- data = data.replace("{{"+failure+"_result}}", "fail")
+ for x in failure:
+ data = data.replace("{{" + x + "_result}}", "fail")
# Replace the rest with "pass"
data = re.sub(r"{{[^}]+}}", "pass", data)
+ # Inject possible <Message> tags inside the first <TestFunction>
+ if inject_message:
+ i = data.index("</TestFunction>")
+ data = data[:i] + inject_message + data[i:]
with open(filename, "w") as f:
f.write(data)
@@ -96,6 +118,12 @@ class Test_qt_mock_test(unittest.TestCase):
state_file = os.environ["QT_MOCK_TEST_STATE_FILE"]
if os.path.exists(state_file):
os.remove(state_file)
+ def assertProcessCrashed(self, proc):
+ if DEBUG:
+ print("process returncode is:", proc.returncode)
+ self.assertTrue(proc.returncode < 0 or
+ proc.returncode >= 128)
+
def test_always_pass(self):
proc = run([mock_test, "always_pass"])
self.assertEqual(proc.returncode, 0)
@@ -125,6 +153,11 @@ class Test_qt_mock_test(unittest.TestCase):
self.assertEqual(proc.returncode, 1)
proc = run([mock_test, "fail_then_pass:2"])
self.assertEqual(proc.returncode, 0)
+ def test_fail_then_crash(self):
+ proc = run([mock_test, "fail_then_crash"])
+ self.assertEqual(proc.returncode, 1)
+ proc = run([mock_test, "fail_then_crash"])
+ self.assertProcessCrashed(proc)
def test_xml_file_is_written(self):
filename = os.path.join(TEMPDIR.name, "testlog.xml")
proc = run([mock_test, "-o", filename+",xml"])
@@ -132,6 +165,39 @@ class Test_qt_mock_test(unittest.TestCase):
self.assertTrue(os.path.exists(filename))
self.assertGreater(os.path.getsize(filename), 0)
os.remove(filename)
+ # Test it will write an empty XML file if template is empty
+ def test_empty_xml_file_is_written(self):
+ my_env = {
+ **os.environ,
+ "QT_MOCK_TEST_XML_TEMPLATE_FILE": EMPTY_FILE
+ }
+ filename = os.path.join(TEMPDIR.name, "testlog.xml")
+ proc = run([mock_test, "-o", filename+",xml"],
+ env=my_env)
+ self.assertEqual(proc.returncode, 0)
+ self.assertTrue(os.path.exists(filename))
+ self.assertEqual(os.path.getsize(filename), 0)
+ os.remove(filename)
+ def test_crash_cleanly(self):
+ proc = run([mock_test],
+ env={ **os.environ, "QT_MOCK_TEST_CRASH_CLEANLY":"1" })
+ if DEBUG:
+ print("returncode:", proc.returncode)
+ self.assertProcessCrashed(proc)
+
+
+# Find in @path, files that start with @testname and end with @pattern,
+# where @pattern is a glob-like string.
+def find_test_logs(testname=None, path=None, pattern="-*[0-9].xml"):
+ if testname is None:
+ testname = os.path.basename(mock_test)
+ if path is None:
+ path = TEMPDIR.name
+ pattern = os.path.join(path, testname + pattern)
+ logfiles = glob.glob(pattern)
+ if DEBUG:
+ print(f"Test ({testname}) logfiles found: ", logfiles)
+ return logfiles
# Test regular invocations of qt-testrunner.
class Test_testrunner(unittest.TestCase):
@@ -140,19 +206,17 @@ class Test_testrunner(unittest.TestCase):
if os.path.exists(state_file):
os.remove(state_file)
# The mock_test honors only the XML output arguments, the rest are ignored.
- old_logfiles = glob.glob(os.path.basename(mock_test) + "*.xml",
- root_dir=TEMPDIR.name)
+ old_logfiles = find_test_logs(pattern="*.xml")
for fname in old_logfiles:
os.remove(os.path.join(TEMPDIR.name, fname))
- self.env = dict()
- self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"] = os.environ["QT_MOCK_TEST_XML_TEMPLATE_FILE"]
- self.env["QT_MOCK_TEST_STATE_FILE"] = state_file
- self.testrunner_args = [ "--log-dir", TEMPDIR.name ]
+ self.env = dict(os.environ)
+ self.testrunner_args = []
def prepare_env(self, run_list=None):
if run_list is not None:
self.env['QT_MOCK_TEST_RUN_LIST'] = ",".join(run_list)
def run2(self):
return run_testrunner(testrunner_args=self.testrunner_args, env=self.env)
+
def test_simple_invocation(self):
# All tests pass.
proc = self.run2()
@@ -163,11 +227,7 @@ class Test_testrunner(unittest.TestCase):
self.assertEqual(proc.returncode, 0)
def test_output_files_are_generated(self):
proc = self.run2()
- xml_output_files = glob.glob(os.path.basename(mock_test) + "-*[0-9].xml",
- root_dir=TEMPDIR.name)
- if DEBUG:
- print("Output files found: ",
- xml_output_files)
+ xml_output_files = find_test_logs()
self.assertEqual(len(xml_output_files), 1)
def test_always_fail(self):
self.prepare_env(run_list=["always_fail"])
@@ -195,10 +255,38 @@ class Test_testrunner(unittest.TestCase):
self.prepare_env(run_list=["initTestCase,always_pass"])
proc = self.run2()
self.assertEqual(proc.returncode, 3)
+ def test_fail_then_crash(self):
+ self.prepare_env(run_list=["fail_then_crash"])
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 3)
+
+ # By testing --no-extra-args, we ensure qt-testrunner works for
+ # tst_selftests and the other NON_XML_GENERATING_TESTS.
+ def test_no_extra_args_pass(self):
+ self.testrunner_args += ["--no-extra-args"]
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 0)
+ def test_no_extra_args_fail(self):
+ self.prepare_env(run_list=["always_fail"])
+ self.testrunner_args += ["--no-extra-args"]
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 3)
+ def test_no_extra_args_reruns_only_once_1(self):
+ self.prepare_env(run_list=["fail_then_pass:1"])
+ self.testrunner_args += ["--no-extra-args"]
+ proc = self.run2()
+ # The 1st rerun PASSed.
+ self.assertEqual(proc.returncode, 0)
+ def test_no_extra_args_reruns_only_once_2(self):
+ self.prepare_env(run_list=["fail_then_pass:2"])
+ self.testrunner_args += ["--no-extra-args"]
+ proc = self.run2()
+ # We never re-run more than once, so the exit code shows FAIL.
+ self.assertEqual(proc.returncode, 3)
# If no XML file is found by qt-testrunner, it is usually considered a
# CRASH and the whole test is re-run. Even when the return code is zero.
- # It is a PASS only if the test is not capable of XML output (see no_extra_args, TODO test it).
+ # It is a PASS only if the test is not capable of XML output (see no_extra_args above).
def test_no_xml_log_written_pass_crash(self):
del self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"]
self.prepare_env(run_list=["always_pass"])
@@ -220,11 +308,86 @@ class Test_testrunner(unittest.TestCase):
proc = self.run2()
self.assertEqual(proc.returncode, 3)
+ def test_empty_xml_crash_1(self):
+ self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"] = EMPTY_FILE
+ self.prepare_env(run_list=["always_pass"])
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 3)
+ def test_empty_xml_crash_2(self):
+ self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"] = EMPTY_FILE
+ self.prepare_env(run_list=["always_fail"])
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 3)
+
+ # test qFatal should be a crash in all cases.
+ def test_qfatal_crash_1(self):
+ fatal_xml_message = """
+ <Message type="qfatal" file="" line="0">
+ <DataTag><![CDATA[modal]]></DataTag>
+ <Description><![CDATA[Failed to initialize graphics backend for OpenGL.]]></Description>
+ </Message>
+ """
+ logfile = os.path.join(TEMPDIR.name, os.path.basename(mock_test) + ".xml")
+ write_xml_log(logfile, failure=None, inject_message=fatal_xml_message)
+ del self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"]
+ self.env["QT_TESTRUNNER_DEBUG_NO_UNIQUE_OUTPUT_FILENAME"] = "1"
+ self.prepare_env(run_list=["always_pass"])
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 3)
+ def test_qfatal_crash_2(self):
+ fatal_xml_message = """
+ <Message type="qfatal" file="" line="0">
+ <DataTag><![CDATA[modal]]></DataTag>
+ <Description><![CDATA[Failed to initialize graphics backend for OpenGL.]]></Description>
+ </Message>
+ """
+ logfile = os.path.join(TEMPDIR.name, os.path.basename(mock_test) + ".xml")
+ write_xml_log(logfile, failure="always_fail", inject_message=fatal_xml_message)
+ del self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"]
+ self.env["QT_TESTRUNNER_DEBUG_NO_UNIQUE_OUTPUT_FILENAME"] = "1"
+ self.prepare_env(run_list=["always_pass,always_fail"])
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 3)
+
+ def test_qwarn_is_ignored_1(self):
+ qwarn_xml_message = """
+ <Message type="qwarn" file="" line="0">
+ <DataTag><![CDATA[modal]]></DataTag>
+ <Description><![CDATA[Failed to create RHI (backend 2)]]></Description>
+ </Message>
+ """
+ logfile = os.path.join(TEMPDIR.name, os.path.basename(mock_test) + ".xml")
+ write_xml_log(logfile, failure=None, inject_message=qwarn_xml_message)
+ del self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"]
+ self.env["QT_TESTRUNNER_DEBUG_NO_UNIQUE_OUTPUT_FILENAME"] = "1"
+ self.prepare_env(run_list=["always_pass"])
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 0)
+ def test_qwarn_is_ignored_2(self):
+ fatal_xml_message = """
+ <Message type="qfatal" file="" line="0">
+ <DataTag><![CDATA[modal]]></DataTag>
+ <Description><![CDATA[Failed to initialize graphics backend for OpenGL.]]></Description>
+ </Message>
+ <Message type="qwarn" file="" line="0">
+ <DataTag><![CDATA[modal]]></DataTag>
+ <Description><![CDATA[Failed to create RHI (backend 2)]]></Description>
+ </Message>
+ """
+ logfile = os.path.join(TEMPDIR.name, os.path.basename(mock_test) + ".xml")
+ write_xml_log(logfile, failure=None, inject_message=fatal_xml_message)
+ del self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"]
+ self.env["QT_TESTRUNNER_DEBUG_NO_UNIQUE_OUTPUT_FILENAME"] = "1"
+ self.prepare_env(run_list=["always_pass"])
+ proc = self.run2()
+ self.assertEqual(proc.returncode, 3)
+
# If a test returns success but XML contains failures, it's a CRASH.
def test_wrong_xml_log_written_1_crash(self):
logfile = os.path.join(TEMPDIR.name, os.path.basename(mock_test) + ".xml")
write_xml_log(logfile, failure="always_fail")
del self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"]
+ self.env["QT_TESTRUNNER_DEBUG_NO_UNIQUE_OUTPUT_FILENAME"] = "1"
self.prepare_env(run_list=["always_pass"])
proc = self.run2()
self.assertEqual(proc.returncode, 3)
@@ -233,6 +396,7 @@ class Test_testrunner(unittest.TestCase):
logfile = os.path.join(TEMPDIR.name, os.path.basename(mock_test) + ".xml")
write_xml_log(logfile)
del self.env["QT_MOCK_TEST_XML_TEMPLATE_FILE"]
+ self.env["QT_TESTRUNNER_DEBUG_NO_UNIQUE_OUTPUT_FILENAME"] = "1"
self.prepare_env(run_list=["always_fail"])
proc = self.run2()
self.assertEqual(proc.returncode, 3)
@@ -241,25 +405,34 @@ class Test_testrunner(unittest.TestCase):
if not content:
content='exec "$@"'
filename = os.path.join(TEMPDIR.name, filename)
- # if os.path.exists(filename):
- # os.remove(filename)
with open(filename, "w") as f:
f.write(f'#!/bin/sh\n{content}\n')
self.wrapper_script = f.name
os.chmod(self.wrapper_script, 0o700)
+ # Test that it re-runs the full executable in case of crash, even if the
+ # XML file is valid and shows one specific test failing.
+ def test_crash_reruns_full_QTQAINFRA_5226(self):
+ self.env["QT_MOCK_TEST_RUN_LIST"] = "always_fail"
+ # Tell qt_mock_test to crash after writing a proper XML file.
+ self.env["QT_MOCK_TEST_CRASH_CLEANLY"] = "1"
+ proc = self.run2()
+ # Verify qt-testrunner exited with 3 which means CRASH.
+ self.assertEqual(proc.returncode, 3)
+ # Verify that a full executable re-run happened that re-runs 2 times,
+ # instead of individual functions that re-run 5 times.
+ xml_output_files = find_test_logs()
+ self.assertEqual(len(xml_output_files), 2)
+
# Test that qt-testrunner detects the correct executable name even if we
# use a special wrapper script, and that it uses that in the XML log filename.
+ @unittest.skipUnless(os.name == "posix", "Wrapper script needs POSIX shell")
def test_wrapper(self):
self.create_wrapper("coin_vxworks_qemu_runner.sh")
proc = run_testrunner(wrapper_script=self.wrapper_script,
- testrunner_args=["--log-dir",TEMPDIR.name],
env=self.env)
self.assertEqual(proc.returncode, 0)
- xml_output_files = glob.glob(os.path.basename(mock_test) + "-*[0-9].xml",
- root_dir=TEMPDIR.name)
- if DEBUG:
- print("XML output files found: ", xml_output_files)
+ xml_output_files = find_test_logs()
self.assertEqual(len(xml_output_files), 1)
# The "androidtestrunner" wrapper is special. It expects the QTest arguments after "--".
@@ -269,48 +442,50 @@ class Test_testrunner(unittest.TestCase):
self.create_wrapper("androidtestrunner", content=
'while [ "$1" != "--" ]; do shift; done; shift; exec {} "$@"'.format(mock_test))
+ @unittest.skipUnless(os.name == "posix", "Wrapper script needs POSIX shell")
def test_androidtestrunner_with_aab(self):
self.create_mock_anroidtestrunner_wrapper()
- # Copied verbatim from our CI logs. The only relevant option is --aab.
- androidtestrunner_args= ['--path', '/home/qt/work/qt/qtdeclarative_standalone_tests/tests/auto/quickcontrols/qquickpopup/android-build-tst_qquickpopup', '--adb', '/opt/android/sdk/platform-tools/adb', '--skip-install-root', '--ndk-stack', '/opt/android/android-ndk-r27c/ndk-stack', '--manifest', '/home/qt/work/qt/qtdeclarative_standalone_tests/tests/auto/quickcontrols/qquickpopup/android-build-tst_qquickpopup/app/AndroidManifest.xml', '--make', '"/opt/cmake-3.30.5/bin/cmake" --build /home/qt/work/qt/qtdeclarative_standalone_tests --target tst_qquickpopup_make_aab', '--aab', '/home/qt/work/qt/qtdeclarative_standalone_tests/tests/auto/quickcontrols/qquickpopup/android-build-tst_qquickpopup/tst_qquickpopup.aab', '--bundletool', '/opt/bundletool/bundletool', '--timeout', '1425']
+ # Copied from our CI logs. The only relevant option is --aab.
+ androidtestrunner_args= [
+ '--path', '/home/qt/work/qt/qtdeclarative_standalone_tests/tests/auto/quickcontrols/qquickpopup/android-build-tst_qquickpopup',
+ '--adb', '/opt/android/sdk/platform-tools/adb', '--skip-install-root',
+ '--ndk-stack', '/opt/android/android-ndk-r27c/ndk-stack',
+ '--manifest', '/home/qt/work/qt/qtdeclarative_standalone_tests/tests/auto/quickcontrols/qquickpopup/android-build-tst_qquickpopup/app/AndroidManifest.xml',
+ '--make', '"/opt/cmake-3.30.5/bin/cmake" --build /home/qt/work/qt/qtdeclarative_standalone_tests --target tst_qquickpopup_make_aab',
+ '--aab', '/home/qt/work/qt/qtdeclarative_standalone_tests/tests/auto/quickcontrols/qquickpopup/android-build-tst_qquickpopup/tst_qquickpopup.aab',
+ '--bundletool', '/opt/bundletool/bundletool', '--timeout', '1425'
+ ]
# In COIN CI, TESTRUNNER="qt-testrunner.py --". That's why we append "--".
- proc = run_testrunner(testrunner_args=["--log-dir", TEMPDIR.name, "--"],
+ proc = run_testrunner(testrunner_args=["--"],
wrapper_script=self.wrapper_script,
wrapper_args=androidtestrunner_args,
env=self.env)
self.assertEqual(proc.returncode, 0)
- xml_output_files = glob.glob("tst_qquickpopup-*[0-9].xml",
- root_dir=TEMPDIR.name)
- if DEBUG:
- print("XML output files found: ", xml_output_files)
+ xml_output_files = find_test_logs("tst_qquickpopup")
self.assertEqual(len(xml_output_files), 1)
# similar to above but with "--apk"
+ @unittest.skipUnless(os.name == "posix", "Wrapper script needs POSIX shell")
def test_androidtestrunner_with_apk(self):
self.create_mock_anroidtestrunner_wrapper()
androidtestrunner_args= ['--blah', '--apk', '/whatever/waza.apk', 'blue']
- proc = run_testrunner(testrunner_args=["--log-dir", TEMPDIR.name, "--"],
+ proc = run_testrunner(testrunner_args=["--"],
wrapper_script=self.wrapper_script,
wrapper_args=androidtestrunner_args,
env=self.env)
self.assertEqual(proc.returncode, 0)
- xml_output_files = glob.glob("waza-*[0-9].xml",
- root_dir=TEMPDIR.name)
- if DEBUG:
- print("XML output files found: ", xml_output_files)
+ xml_output_files = find_test_logs("waza")
self.assertEqual(len(xml_output_files), 1)
# similar to above but with neither "--apk" nor "--aab". qt-testrunner throws error.
+ @unittest.skipUnless(os.name == "posix", "Wrapper script needs POSIX shell")
def test_androidtestrunner_fail_to_detect_filename(self):
self.create_mock_anroidtestrunner_wrapper()
androidtestrunner_args= ['--blah', '--argh', '/whatever/waza.apk', 'waza.aab']
- proc = run_testrunner(testrunner_args=["--log-dir", TEMPDIR.name, "--"],
+ proc = run_testrunner(testrunner_args=["--"],
wrapper_script=self.wrapper_script,
wrapper_args=androidtestrunner_args,
env=self.env)
self.assertEqual(proc.returncode, 1)
- xml_output_files = glob.glob("waza-*[0-9].xml",
- root_dir=TEMPDIR.name)
- if DEBUG:
- print("XML output files found: ", xml_output_files)
+ xml_output_files = find_test_logs("waza")
self.assertEqual(len(xml_output_files), 0)
@@ -322,7 +497,8 @@ class Test_testrunner(unittest.TestCase):
# + No failure logged. qt-testrunner should exit(0)
# + The "always_pass" test has failed. qt-testrunner should exit(0).
# + The "always_fail" test has failed. qt-testrunner should exit(2).
-# + The "always_crash" test has failed. qt-testrunner should exit(2).
+# + The "always_crash" test has failed. qt-testrunner should exit(3)
+# since the re-run will crash.
# + The "fail_then_pass:2" test failed. qt-testrunner should exit(0).
# + The "fail_then_pass:5" test failed. qt-testrunner should exit(2).
# + The "initTestCase" failed which is listed as NO_RERUN thus
@@ -333,28 +509,32 @@ class Test_testrunner_with_xml_logfile(unittest.TestCase):
(_handle, self.xml_file) = mkstemp(
suffix=".xml", prefix="qt_mock_test-log-",
dir=TEMPDIR.name)
+ os.close(_handle)
if os.path.exists(os.environ["QT_MOCK_TEST_STATE_FILE"]):
os.remove(os.environ["QT_MOCK_TEST_STATE_FILE"])
def tearDown(self):
os.remove(self.xml_file)
del self.xml_file
+ # Run testrunner specifically for the tests here, with --parse-xml-testlog.
+ def run3(self, testrunner_args=None):
+ return run_testrunner(self.xml_file,
+ testrunner_args=testrunner_args)
def test_no_failure(self):
write_xml_log(self.xml_file, failure=None)
- proc = run_testrunner(self.xml_file)
+ proc = self.run3()
self.assertEqual(proc.returncode, 0)
def test_always_pass_failed(self):
write_xml_log(self.xml_file, failure="always_pass")
- proc = run_testrunner(self.xml_file)
+ proc = self.run3()
self.assertEqual(proc.returncode, 0)
def test_always_pass_failed_max_repeats_0(self):
write_xml_log(self.xml_file, failure="always_pass")
- proc = run_testrunner(self.xml_file,
- testrunner_args=["--max-repeats", "0"])
+ proc = self.run3(testrunner_args=["--max-repeats", "0"])
self.assertEqual(proc.returncode, 2)
def test_always_fail_failed(self):
write_xml_log(self.xml_file, failure="always_fail")
- proc = run_testrunner(self.xml_file)
+ proc = self.run3()
self.assertEqual(proc.returncode, 2)
# Assert that one of the re-runs was in verbose mode
matches = re.findall("VERBOSE RUN",
@@ -362,22 +542,22 @@ class Test_testrunner_with_xml_logfile(unittest.TestCase):
self.assertEqual(len(matches), 1)
# Assert that the environment was altered too
self.assertIn("QT_LOGGING_RULES", proc.stdout.decode())
- def test_always_crash_failed(self):
+ def test_always_crash_crashed(self):
write_xml_log(self.xml_file, failure="always_crash")
- proc = run_testrunner(self.xml_file)
- self.assertEqual(proc.returncode, 2)
+ proc = self.run3()
+ self.assertEqual(proc.returncode, 3)
def test_fail_then_pass_2_failed(self):
write_xml_log(self.xml_file, failure="fail_then_pass:2")
- proc = run_testrunner(self.xml_file)
+ proc = self.run3()
self.assertEqual(proc.returncode, 0)
def test_fail_then_pass_5_failed(self):
write_xml_log(self.xml_file, failure="fail_then_pass:5")
- proc = run_testrunner(self.xml_file)
+ proc = self.run3()
self.assertEqual(proc.returncode, 2)
def test_with_two_failures(self):
write_xml_log(self.xml_file,
failure=["always_pass", "fail_then_pass:2"])
- proc = run_testrunner(self.xml_file)
+ proc = self.run3()
self.assertEqual(proc.returncode, 0)
# Check that test output is properly interleaved with qt-testrunner's logging.
matches = re.findall(r"(PASS|FAIL!).*\n.*Test process exited with code",
@@ -385,7 +565,7 @@ class Test_testrunner_with_xml_logfile(unittest.TestCase):
self.assertEqual(len(matches), 4)
def test_initTestCase_fail_crash(self):
write_xml_log(self.xml_file, failure="initTestCase")
- proc = run_testrunner(self.xml_file)
+ proc = self.run3()
self.assertEqual(proc.returncode, 3)
diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
index 10a67daa02a..0f8a6da823e 100644
--- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
+++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
@@ -3572,6 +3572,7 @@ void tst_QComboBox::popupPositionAfterStyleChange()
QFrame *container = box.findChild<QComboBoxPrivateContainer *>();
QVERIFY(container);
QVERIFY(QTest::qWaitForWindowExposed(container));
+ container->resize(80, 80);
// Select the last menu item, which will close the popup. This item is then expected
// to be centered on top of the combobox the next time the popup opens.
diff --git a/tests/benchmarks/gui/painting/qcolor/tst_qcolor.cpp b/tests/benchmarks/gui/painting/qcolor/tst_qcolor.cpp
index 02fe3f986e9..54ba45c1256 100644
--- a/tests/benchmarks/gui/painting/qcolor/tst_qcolor.cpp
+++ b/tests/benchmarks/gui/painting/qcolor/tst_qcolor.cpp
@@ -2,8 +2,24 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <qtest.h>
+
#include <QColor>
+#include <vector>
+
+static std::vector<QColor> all_rgb_colors()
+{
+ std::vector<QColor> colors;
+ colors.reserve(256 * 256 * 256);
+ for (int r = 0; r < 256; ++r) {
+ for (int g = 0; g < 256; ++g) {
+ for (int b = 0; b < 256; ++b)
+ colors.emplace_back(r, g, b);
+ }
+ }
+ return colors;
+}
+
class tst_QColor : public QObject
{
@@ -12,6 +28,11 @@ class tst_QColor : public QObject
private slots:
void nameRgb();
void nameArgb();
+ void toHsl();
+ void toHsv();
+
+private:
+ const std::vector<QColor> m_all_rgb = all_rgb_colors();
};
void tst_QColor::nameRgb()
@@ -32,6 +53,22 @@ void tst_QColor::nameArgb()
}
}
+void tst_QColor::toHsl()
+{
+ QBENCHMARK {
+ for (const QColor &c : m_all_rgb)
+ [[maybe_unused]] const auto r = c.toHsl();
+ }
+}
+
+void tst_QColor::toHsv()
+{
+ QBENCHMARK {
+ for (const QColor &c : m_all_rgb)
+ [[maybe_unused]] const auto r = c.toHsv();
+ }
+}
+
QTEST_MAIN(tst_QColor)
#include "tst_qcolor.moc"
diff --git a/util/testrunner/README b/util/testrunner/README
index 5758e325140..cb6722ac807 100644
--- a/util/testrunner/README
+++ b/util/testrunner/README
@@ -15,10 +15,4 @@ It offers the following functionality
The script itself has a testsuite that is simply run by invoking
-qtbase/util/testrunner/tests/tst_testrunner.py
-
-Please *run this manually* before submitting a change to qt-testrunner and
-make sure it's passing. The reason it does not run automatically during the
-usual qtbase test run, is because
-+ the test run should not depend on Python
-+ we don't want to wrap the testrunner tests with testrunner.
+qtbase/tests/auto/util/testrunner/tst_qt_testrunner.py
diff --git a/util/testrunner/qt-testrunner.py b/util/testrunner/qt-testrunner.py
index 41e81e83122..1573534cee9 100755
--- a/util/testrunner/qt-testrunner.py
+++ b/util/testrunner/qt-testrunner.py
@@ -4,10 +4,9 @@
# !!!IMPORTANT!!! If you change anything to this script, run the testsuite
-# manually and make sure it still passes, as it doesn't run automatically.
-# Just execute the command line as such:
+# and make sure it still passes:
#
-# ./util/testrunner/tests/tst_testrunner.py -v [--debug]
+# qtbase/tests/auto/util/testrunner/tst_qt_testrunner.py -v [--debug]
#
# ======== qt-testrunner ========
#
@@ -15,24 +14,44 @@
# tst_whatever, and tries to iron out unpredictable test failures.
# In particular:
#
-# + Appends output argument to it: "-o tst_whatever.xml,xml"
-# + Checks the exit code. If it is zero, the script exits with zero,
-# otherwise proceeds.
-# + Reads the XML test log and Understands exactly which function
-# of the test failed.
-# + If no XML file is found or was invalid, the test executable
-# probably CRASHed, so we *re-run the full test once again*.
-# + If some testcases failed it executes only those individually
-# until they pass, or until max-repeats times is reached.
+# + Append output argument to it: "-o tst_whatever.xml,xml" and
+# execute it.
+# + Save the exit code.
+# - If it is <0 or >=128 (see NOTE_2), mark the test run as CRASH.
+# + Read the XML test log and find exactly which functions
+# of the test FAILed.
+# + Mark the test run as CRASH, if:
+# - no XML file is found,
+# - or an invalid XML file is found,
+# - or the XML contains a QFatal message: <Message type="qfatal">
+# - or no test FAILures are listed in the XML but the saved
+# exit code is not 0.
+# + If, based on the rules above, the test run is marked as CRASH,
+# then *re-run the full test once again* and start this logic over.
+# If we are on the 2nd run and CRASH happens again, then exit(3).
+# + Examine the saved exit code:
+# if it is 0, then exit(0) (success, all tests have PASSed).
+# + Otherwise, some testcases failed, so execute only those individually
+# until they pass, or until max-repeats (default: 5) times is reached.
#
# The regular way to use is to set the environment variable TESTRUNNER to
-# point to this script before invoking ctest.
+# point to this script before invoking ctest. In COIN CI it is set as
+# TESTRUNNER="qt-testrunner.py --" to stop it from parsing further args.
#
# NOTE: this script is crafted specifically for use with Qt tests and for
# using it in Qt's CI. For example it detects and acts specially if test
# executable is "tst_selftests" or "androidtestrunner". It also detects
# env var "COIN_CTEST_RESULTSDIR" and uses it as log-dir.
#
+# NOTE_2: Why is qt-testrunner considering exit code outside [0,127] as CRASH?
+# On Linux, Python subprocess module returns positive `returncode`
+# (255 for example), even if the child does exit(-1 for example). It
+# returns negative `returncode` only if the child is killed by a signal.
+# Qt-testrunner wants to catch both of these cases as CRASH.
+# On Windows, a crash is usually accompanied by exitcode >= 0xC0000000.
+# Finally, QTest is limiting itself to exit codes in [0,127]
+# so anything outside that range is abnormal, thus treated as CRASH.
+#
# TODO implement --dry-run.
# Exit codes of this script:
@@ -63,9 +82,17 @@ from pprint import pprint
from typing import NamedTuple, Tuple, List, Optional
# Define a custom type for returning a fail incident
-class WhatFailed(NamedTuple):
+class TestResult(NamedTuple):
func: str
tag: Optional[str] = None
+class WhatFailed(NamedTuple):
+ qfatal_message: Optional[str] = None
+ failed_tests: List[TestResult] = []
+
+class ReRunCrash(Exception):
+ pass
+class BadXMLCrash(Exception):
+ pass
# In the last test re-run, we add special verbosity arguments, in an attempt
@@ -83,9 +110,11 @@ NO_RERUN_FUNCTIONS = {
# not try to append "-o" to their command-line or re-run failed testcases.
# Only add tests here if absolutely necessary!
NON_XML_GENERATING_TESTS = {
- "tst_selftests", # qtestlib's selftests are using an external test framework (Catch) that does not support -o argument
- "tst_QDoc", # Some of QDoc's tests are using an external test framework (Catch) that does not support -o argument
- "tst_QDoc_Catch_Generators", # Some of QDoc's tests are using an external test framework (Catch) that does not support -o argument
+ # These tests use an external test framework (Catch) that doesn't support
+ # QtTest's -o argument.
+ "tst_selftests",
+ "tst_QDoc",
+ "tst_QDoc_Catch_Generators",
}
# These are scripts that are used to wrap test execution for special platforms.
# They need special handling (most times just skipping the wrapper name in argv[]).
@@ -131,6 +160,9 @@ Default flags: --max-repeats 5 --passes-needed 1
" -o log_file.xml -v2 -vs. This will disable some functionality like the"
" failed test repetition and the verbose output on failure. This is"
" activated by default when TESTARGS is tst_selftests.")
+ # TODO parser.parse_args(args=sys.argv[0:cmd_index]).
+ # Where cmd_index is either the first positional argument, or the argument right after "--".
+ # This way it won't interpet arguments after the first positional arg.
args = parser.parse_args()
args.self_name = os.path.basename(sys.argv[0])
args.specific_extra_args = []
@@ -198,11 +230,13 @@ Default flags: --max-repeats 5 --passes-needed 1
return args
-def parse_log(results_file) -> List[WhatFailed]:
- """Parse the XML test log file. Return the failed testcases, if any.
+def parse_log(results_file) -> WhatFailed:
+ """
+ Parse the XML test log file. Return the failed testcases, if any,
+ and the first qfatal message possibly printed.
Failures are considered the "fail" and "xpass" incidents.
- A testcase is a function with an optional data tag."""
+ """
start_timer = timeit.default_timer()
try:
@@ -222,10 +256,12 @@ def parse_log(results_file) -> List[WhatFailed]:
root = tree.getroot()
if root.tag != "TestCase":
- raise AssertionError(
+ raise BadXMLCrash(
f"The XML test log must have <TestCase> as root tag, but has: <{root.tag}>")
failures = []
+ qfatal_message = None
+
n_passes = 0
for e1 in root:
if e1.tag == "TestFunction":
@@ -233,23 +269,43 @@ def parse_log(results_file) -> List[WhatFailed]:
if e2.tag == "Incident":
if e2.attrib["type"] in ("fail", "xpass"):
func = e1.attrib["name"]
+ datatag = None
e3 = e2.find("DataTag") # every <Incident> might have a <DataTag>
if e3 is not None:
- failures.append(WhatFailed(func, tag=e3.text))
- else:
- failures.append(WhatFailed(func))
+ datatag = e3.text
+ failures.append(TestResult(func, datatag))
else:
n_passes += 1
+ # Use iter() here to _recursively_ search root for <Message>,
+ # as we don't trust that messages are always at the same depth.
+ for message_tag in root.iter(tag="Message"):
+ messagetype = message_tag.get("type")
+ if messagetype == "qfatal":
+ message_desc = message_tag.find("Description")
+ if message_desc is not None:
+ qfatal_message = message_desc.text
+ else:
+ qfatal_message = "--EMPTY QFATAL--"
+ L.warning("qFatal message ('%s') found in the XML, treating this run as a CRASH!",
+ qfatal_message)
+ break
+
end_timer = timeit.default_timer()
t = end_timer - start_timer
L.info(f"Parsed XML file {results_file} in {t:.3f} seconds")
L.info(f"Found {n_passes} passes and {len(failures)} failures")
- return failures
+ return WhatFailed(qfatal_message, failures)
def run_test(arg_list: List[str], **kwargs):
+ if (os.environ.get("QT_TESTRUNNER_TESTING", "0") == "1"
+ and os.name == "nt"
+ and arg_list[0].endswith(".py")
+ ):
+ # For executing qt_mock_test.py under the same Python interpreter when testing.
+ arg_list = [ sys.executable ] + arg_list
L.debug("Running test command line: %s", arg_list)
proc = subprocess.run(arg_list, **kwargs)
L.info("Test process exited with code: %d", proc.returncode)
@@ -257,6 +313,11 @@ def run_test(arg_list: List[str], **kwargs):
return proc
def unique_filename(test_basename: str) -> str:
+
+ # Hidden env var for testing, enforcing a predictable, non-unique filename.
+ if os.environ.get("QT_TESTRUNNER_DEBUG_NO_UNIQUE_OUTPUT_FILENAME"):
+ return f"{test_basename}"
+
timestamp = round(time.time() * 1000)
return f"{test_basename}-{timestamp}"
@@ -291,18 +352,19 @@ def run_full_test(test_basename, testargs: List[str], output_dir: str,
def rerun_failed_testcase(test_basename, testargs: List[str], output_dir: str,
- what_failed: WhatFailed,
+ testcase: TestResult,
max_repeats, passes_needed,
dryrun=False, timeout=None) -> bool:
"""Run a specific function:tag of a test, until it passes enough times, or
until max_repeats is reached.
Return True if it passes eventually, False if it fails.
+ Raise ReRunCrash Exception if it crashes.
"""
assert passes_needed <= max_repeats
- failed_arg = what_failed.func
- if what_failed.tag:
- failed_arg += ":" + what_failed.tag
+ failed_arg = testcase.func
+ if testcase.tag:
+ failed_arg += ":" + testcase.tag
n_passes = 0
@@ -325,6 +387,19 @@ def rerun_failed_testcase(test_basename, testargs: List[str], output_dir: str,
proc = run_test(testargs + output_args + VERBOSE_ARGS + [failed_arg],
timeout=timeout,
env={**os.environ, **VERBOSE_ENV})
+ # There are platforms that run tests wrapped with some test-runner
+ # script, that can possibly fail to extract a process exit code.
+ # Because of these cases, we *also* parse the XML file and signify
+ # CRASH in case of QFATAL/empty/corrupt result.
+ what_failed = parse_log(f"{pathname_stem}.xml")
+ if what_failed.qfatal_message:
+ raise ReRunCrash(f"CRASH! returncode:{proc.returncode} "
+ f"QFATAL:'{what_failed.qfatal_message}'")
+ if proc.returncode < 0 or proc.returncode >= 128:
+ raise ReRunCrash(f"CRASH! returncode:{proc.returncode}")
+ if proc.returncode == 0 and len(what_failed.failed_tests) > 0:
+ raise ReRunCrash("CRASH! returncode:0 but failures were found: "
+ + what_failed.failed_tests)
if proc.returncode == 0:
n_passes += 1
if n_passes == passes_needed:
@@ -354,20 +429,22 @@ def main():
try:
results_file = None
- failed_functions = []
+ what_failed = WhatFailed()
if args.parse_xml_testlog: # do not run test, just parse file
- failed_functions = parse_log(args.parse_xml_testlog)
+ what_failed = parse_log(args.parse_xml_testlog)
# Pretend the test returned correct exit code
- retcode = len(failed_functions)
+ retcode = len(what_failed.failed_tests)
else: # normal invocation, run test
(retcode, results_file) = \
run_full_test(args.test_basename, args.testargs, args.log_dir,
args.no_extra_args, args.dry_run, args.timeout,
args.specific_extra_args)
if results_file:
- failed_functions = parse_log(results_file)
+ what_failed = parse_log(results_file)
+
+ failed_functions = what_failed.failed_tests
- if retcode < 0:
+ if retcode < 0 or retcode >= 128 or what_failed.qfatal_message:
L.warning("CRASH detected, re-running the whole executable")
continue
if retcode == 0:
@@ -392,6 +469,8 @@ def main():
assert len(failed_functions) > 0 and retcode != 0
break # all is fine, goto re-running individual failed testcases
+ except AssertionError:
+ raise
except Exception as e:
L.error("exception:%s %s", type(e).__name__, e)
L.error("The test executable probably crashed, see above for details")
@@ -402,13 +481,15 @@ def main():
L.info("Some tests failed, will re-run at most %d times.\n",
args.max_repeats)
- for what_failed in failed_functions:
+ for test_result in failed_functions:
try:
ret = rerun_failed_testcase(args.test_basename, args.testargs, args.log_dir,
- what_failed, args.max_repeats, args.passes_needed,
+ test_result, args.max_repeats, args.passes_needed,
dryrun=args.dry_run, timeout=args.timeout)
+ except AssertionError:
+ raise
except Exception as e:
- L.error("exception:%s %s", type(e).__name__, e)
+ L.error("exception:%s", e)
L.error("The testcase re-run probably crashed, giving up")
sys.exit(3) # Test re-run CRASH