summaryrefslogtreecommitdiffstats
path: root/src/corelib/global
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/global')
-rw-r--r--src/corelib/global/archdetect.cpp10
-rw-r--r--src/corelib/global/minimum-linux_p.h9
-rw-r--r--src/corelib/global/q20algorithm.h36
-rw-r--r--src/corelib/global/q20chrono.h62
-rw-r--r--src/corelib/global/q20functional.h19
-rw-r--r--src/corelib/global/q20iterator.h16
-rw-r--r--src/corelib/global/q20map.h72
-rw-r--r--src/corelib/global/q20memory.h93
-rw-r--r--src/corelib/global/q20type_traits.h81
-rw-r--r--src/corelib/global/q20vector.h90
-rw-r--r--src/corelib/global/q23functional.h6
-rw-r--r--src/corelib/global/q23utility.cpp25
-rw-r--r--src/corelib/global/q23utility.h75
-rw-r--r--src/corelib/global/qassert.cpp112
-rw-r--r--src/corelib/global/qassert.h18
-rw-r--r--src/corelib/global/qcompare.cpp1357
-rw-r--r--src/corelib/global/qcompare.h863
-rw-r--r--src/corelib/global/qcompare.qdoc113
-rw-r--r--src/corelib/global/qcompare_impl.h11
-rw-r--r--src/corelib/global/qcomparehelpers.h567
-rw-r--r--src/corelib/global/qcompilerdetection.h152
-rw-r--r--src/corelib/global/qcompilerdetection.qdoc39
-rw-r--r--src/corelib/global/qconfig-bootstrapped.h14
-rw-r--r--src/corelib/global/qcontainerinfo.h5
-rw-r--r--src/corelib/global/qdarwinhelpers.h4
-rw-r--r--src/corelib/global/qendian.cpp4
-rw-r--r--src/corelib/global/qendian.h19
-rw-r--r--src/corelib/global/qexceptionhandling.h1
-rw-r--r--src/corelib/global/qflags.h10
-rw-r--r--src/corelib/global/qflags.qdoc4
-rw-r--r--src/corelib/global/qfloat16.cpp38
-rw-r--r--src/corelib/global/qfloat16.h288
-rw-r--r--src/corelib/global/qforeach.h9
-rw-r--r--src/corelib/global/qforeach.qdoc16
-rw-r--r--src/corelib/global/qglobal.cpp117
-rw-r--r--src/corelib/global/qglobal.h16
-rw-r--r--src/corelib/global/qglobal_p.h15
-rw-r--r--src/corelib/global/qglobalstatic.h21
-rw-r--r--src/corelib/global/qlibraryinfo.cpp40
-rw-r--r--src/corelib/global/qlibraryinfo.h21
-rw-r--r--src/corelib/global/qlibraryinfo_p.h2
-rw-r--r--src/corelib/global/qlogging.cpp814
-rw-r--r--src/corelib/global/qlogging.h44
-rw-r--r--src/corelib/global/qlogging_p.h48
-rw-r--r--src/corelib/global/qnamespace.h50
-rw-r--r--src/corelib/global/qnamespace.qdoc134
-rw-r--r--src/corelib/global/qnumeric.cpp4
-rw-r--r--src/corelib/global/qnumeric.h4
-rw-r--r--src/corelib/global/qnumeric_p.h131
-rw-r--r--src/corelib/global/qoperatingsystemversion.cpp93
-rw-r--r--src/corelib/global/qoperatingsystemversion.h124
-rw-r--r--src/corelib/global/qoperatingsystemversion_darwin.mm49
-rw-r--r--src/corelib/global/qprocessordetection.h40
-rw-r--r--src/corelib/global/qprocessordetection.qdoc52
-rw-r--r--src/corelib/global/qrandom.cpp11
-rw-r--r--src/corelib/global/qsimd.cpp34
-rw-r--r--src/corelib/global/qsimd.h4
-rw-r--r--src/corelib/global/qsimd_p.h83
-rw-r--r--src/corelib/global/qsimd_x86.cpp66
-rw-r--r--src/corelib/global/qsimd_x86_p.h218
-rw-r--r--src/corelib/global/qswap.h30
-rw-r--r--src/corelib/global/qswap.qdoc36
-rw-r--r--src/corelib/global/qsysinfo.cpp46
-rw-r--r--src/corelib/global/qsysinfo.h8
-rw-r--r--src/corelib/global/qsystemdetection.h131
-rw-r--r--src/corelib/global/qsystemdetection.qdoc17
-rw-r--r--src/corelib/global/qt_pch.h49
-rw-r--r--src/corelib/global/qt_windows.h2
-rw-r--r--src/corelib/global/qtclasshelpermacros.h11
-rw-r--r--src/corelib/global/qtconfiginclude.h22
-rw-r--r--src/corelib/global/qtconfigmacros.h68
-rw-r--r--src/corelib/global/qtdeprecationmarkers.h30
-rw-r--r--src/corelib/global/qtenvironmentvariables.cpp84
-rw-r--r--src/corelib/global/qtenvironmentvariables_p.h39
-rw-r--r--src/corelib/global/qtnoop.h9
-rw-r--r--src/corelib/global/qtrace_p.h131
-rw-r--r--src/corelib/global/qtsymbolmacros.h65
-rw-r--r--src/corelib/global/qttypetraits.h19
-rw-r--r--src/corelib/global/qttypetraits.qdoc43
-rw-r--r--src/corelib/global/qtversion.h38
-rw-r--r--src/corelib/global/qtversionchecks.h53
-rw-r--r--src/corelib/global/qtypeinfo.h79
-rw-r--r--src/corelib/global/qtypeinfo.qdoc23
-rw-r--r--src/corelib/global/qtypes.cpp130
-rw-r--r--src/corelib/global/qtypes.h134
-rw-r--r--src/corelib/global/qversiontagging.h16
-rw-r--r--src/corelib/global/qxpfunctional.h35
-rw-r--r--src/corelib/global/qxptype_traits.h121
88 files changed, 6629 insertions, 1313 deletions
diff --git a/src/corelib/global/archdetect.cpp b/src/corelib/global/archdetect.cpp
index a0ce5baa43..6a1e110a73 100644
--- a/src/corelib/global/archdetect.cpp
+++ b/src/corelib/global/archdetect.cpp
@@ -15,14 +15,24 @@
# define ARCH_PROCESSOR "avr32"
#elif defined(Q_PROCESSOR_BLACKFIN)
# define ARCH_PROCESSOR "bfin"
+#elif defined(Q_PROCESSOR_WASM_64)
+# define ARCH_PROCESSOR "wasm64"
#elif defined(Q_PROCESSOR_WASM)
# define ARCH_PROCESSOR "wasm"
+#elif defined(Q_PROCESSOR_HPPA)
+# define ARCH_PROCESSOR "hppa"
#elif defined(Q_PROCESSOR_X86_32)
# define ARCH_PROCESSOR "i386"
#elif defined(Q_PROCESSOR_X86_64)
# define ARCH_PROCESSOR "x86_64"
#elif defined(Q_PROCESSOR_IA64)
# define ARCH_PROCESSOR "ia64"
+#elif defined(Q_PROCESSOR_LOONGARCH_32)
+# define ARCH_PROCESSOR "loongarch32"
+#elif defined(Q_PROCESSOR_LOONGARCH_64)
+# define ARCH_PROCESSOR "loongarch64"
+#elif defined(Q_PROCESSOR_M68K)
+# define ARCH_PROCESSOR "m68k"
#elif defined(Q_PROCESSOR_MIPS_64)
# define ARCH_PROCESSOR "mips64"
#elif defined(Q_PROCESSOR_MIPS)
diff --git a/src/corelib/global/minimum-linux_p.h b/src/corelib/global/minimum-linux_p.h
index 509ad792f7..d52df474fb 100644
--- a/src/corelib/global/minimum-linux_p.h
+++ b/src/corelib/global/minimum-linux_p.h
@@ -22,6 +22,7 @@
//
#include "private/qglobal_p.h"
+#include <sys/stat.h>
QT_BEGIN_NAMESPACE
@@ -35,18 +36,17 @@ QT_BEGIN_NAMESPACE
* - FUTEX_PRIVATE_FLAG 2.6.22
* - O_CLOEXEC 2.6.23
* - eventfd 2.6.23
+ * - FUTEX_WAIT_BITSET 2.6.25
* - pipe2 & dup3 2.6.27
* - accept4 2.6.28
* - renameat2 3.16 QT_CONFIG(renameat2)
* - getrandom 3.17 QT_CONFIG(getentropy)
- * - statx 4.11 QT_CONFIG(statx)
+ * - statx 4.11 STATX_BASIC_STATS
*/
-#if QT_CONFIG(statx) && !QT_CONFIG(glibc)
+#if defined(__GLIBC__) && defined(STATX_BASIC_STATS)
// if using glibc, the statx() function in sysdeps/unix/sysv/linux/statx.c
// falls back to stat() for us.
-// (Using QT_CONFIG(glibc) instead of __GLIBC__ because the macros aren't
-// defined in assembler mode)
# define QT_ELF_NOTE_OS_MAJOR 4
# define QT_ELF_NOTE_OS_MINOR 11
# define QT_ELF_NOTE_OS_PATCH 0
@@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE
# define QT_ELF_NOTE_OS_MINOR 16
# define QT_ELF_NOTE_OS_PATCH 0
#else
+
# define QT_ELF_NOTE_OS_MAJOR 2
# define QT_ELF_NOTE_OS_MINOR 6
# define QT_ELF_NOTE_OS_PATCH 28
diff --git a/src/corelib/global/q20algorithm.h b/src/corelib/global/q20algorithm.h
index 1d2e0117f4..24d801b2cd 100644
--- a/src/corelib/global/q20algorithm.h
+++ b/src/corelib/global/q20algorithm.h
@@ -12,9 +12,9 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. Types and functions defined
-// in this file will behave exactly as their std counterparts. You
-// may use these definitions in your own code, but be aware that we
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
// will remove them once Qt depends on the C++ version that supports
// them in namespace std. There will be NO deprecation warning, the
// definitions will JUST go away.
@@ -32,6 +32,8 @@ namespace q20 {
using std::copy;
using std::copy_if;
using std::copy_n;
+using std::fill;
+using std::fill_n;
using std::is_sorted_until;
using std::is_sorted;
using std::transform;
@@ -75,6 +77,28 @@ copy_n(InputIterator first, Size n, OutputIterator dest)
return dest;
}
+template <typename ForwardIterator, typename Value>
+constexpr void
+fill(ForwardIterator first, ForwardIterator last, const Value &value)
+{
+ while (first != last) {
+ *first = value;
+ ++first;
+ }
+}
+
+template <typename OutputIterator, typename Size, typename Value>
+constexpr OutputIterator
+fill_n(OutputIterator first, Size n, const Value &value)
+{
+ while (n > Size{0}) {
+ *first = value;
+ ++first;
+ --n;
+ }
+ return first;
+}
+
template <typename ForwardIterator, typename BinaryPredicate = std::less<>>
constexpr ForwardIterator
is_sorted_until(ForwardIterator first, ForwardIterator last, BinaryPredicate p = {})
@@ -123,7 +147,7 @@ using std::ranges::none_of;
[[maybe_unused]] inline constexpr struct { // Niebloid
template <typename InputIterator, typename Sentinel,
typename Predicate, typename Projection = q20::identity>
- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
{
while (first != last) {
if (std::invoke(pred, std::invoke(proj, *first)))
@@ -136,7 +160,7 @@ using std::ranges::none_of;
[[maybe_unused]] inline constexpr struct { // Niebloid
template <typename InputIterator, typename Sentinel,
typename Predicate, typename Projection = q20::identity>
- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
{
while (first != last) {
if (!std::invoke(pred, std::invoke(proj, *first)))
@@ -149,7 +173,7 @@ using std::ranges::none_of;
[[maybe_unused]] inline constexpr struct { // Niebloid
template <typename InputIterator, typename Sentinel,
typename Predicate, typename Projection = q20::identity>
- constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
+ [[maybe_unused]] constexpr bool operator()(InputIterator first, Sentinel last, Predicate pred, Projection proj = {}) const
{
while (first != last) {
if (std::invoke(pred, std::invoke(proj, *first)))
diff --git a/src/corelib/global/q20chrono.h b/src/corelib/global/q20chrono.h
new file mode 100644
index 0000000000..19c2eabe3d
--- /dev/null
+++ b/src/corelib/global/q20chrono.h
@@ -0,0 +1,62 @@
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q20CHRONO_H
+#define Q20CHRONO_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <chrono>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace q20 {
+namespace chrono {
+
+#if defined(__GLIBCXX__)
+// https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/include/bits/chrono.h
+using IntRep = int64_t;
+#else
+// https://github.com/llvm/llvm-project/blob/main/libcxx/include/__chrono/duration.h
+// https://github.com/microsoft/STL/blob/main/stl/inc/__msvc_chrono.hpp
+using IntRep = int;
+#endif
+
+#if __cpp_lib_chrono >= 201907L
+using std::chrono::days;
+using std::chrono::weeks;
+using std::chrono::years;
+using std::chrono::months;
+
+static_assert(std::is_same_v<days::rep, IntRep>);
+static_assert(std::is_same_v<weeks::rep, IntRep>);
+static_assert(std::is_same_v<years::rep, IntRep>);
+static_assert(std::is_same_v<months::rep, IntRep>);
+#else
+using days = std::chrono::duration<IntRep, std::ratio<86400>>;
+using weeks = std::chrono::duration<IntRep, std::ratio_multiply<std::ratio<7>, days::period>>;
+using years = std::chrono::duration<IntRep, std::ratio_multiply<std::ratio<146097, 400>, days::period>>;
+using months = std::chrono::duration<IntRep, std::ratio_divide<years::period, std::ratio<12>>>;
+#endif // __cpp_lib_chrono >= 201907L
+} // namespace chrono
+} // namespace q20
+
+QT_END_NAMESPACE
+
+#endif /* Q20CHRONO_H */
diff --git a/src/corelib/global/q20functional.h b/src/corelib/global/q20functional.h
index 9584252663..a39b4fceb3 100644
--- a/src/corelib/global/q20functional.h
+++ b/src/corelib/global/q20functional.h
@@ -11,9 +11,9 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. Types and functions defined
-// in this file will behave exactly as their std counterparts. You
-// may use these definitions in your own code, but be aware that we
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
// will remove them once Qt depends on the C++ version that supports
// them in namespace std. There will be NO deprecation warning, the
// definitions will JUST go away.
@@ -41,19 +41,6 @@ struct identity
#endif // __cpp_lib_ranges
} // namespace q20
-namespace q20 {
-// like std::remove_cvref(_t)
-#ifdef __cpp_lib_remove_cvref
-using std::remove_cvref;
-using std::remove_cvref_t;
-#else
-template <typename T>
-struct remove_cvref : std::remove_cv<std::remove_reference_t<T>> {};
-template <typename T>
-using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
-#endif // __cpp_lib_remove_cvref
-}
-
QT_END_NAMESPACE
#endif /* Q20FUNCTIONAL_H */
diff --git a/src/corelib/global/q20iterator.h b/src/corelib/global/q20iterator.h
index a7f1cf3cfc..9ed4d69965 100644
--- a/src/corelib/global/q20iterator.h
+++ b/src/corelib/global/q20iterator.h
@@ -11,9 +11,9 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. Types and functions defined
-// in this file will behave exactly as their std counterparts. You
-// may use these definitions in your own code, but be aware that we
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
// will remove them once Qt depends on the C++ version that supports
// them in namespace std. There will be NO deprecation warning, the
// definitions will JUST go away.
@@ -39,6 +39,16 @@ namespace q20 {
#endif
} // namespace q20
+// like q20::iter_reference_t
+namespace q20 {
+#ifdef __cpp_lib_ranges
+ using std::iter_reference_t;
+#else
+ template <typename Dereferencable> // unconstrained (constraint requires concepts)
+ using iter_reference_t = decltype(*std::declval<Dereferencable&>());
+#endif // __cpp_lib_ranges
+} // namespace q20
+
QT_END_NAMESPACE
#endif /* Q20ITERATOR_H */
diff --git a/src/corelib/global/q20map.h b/src/corelib/global/q20map.h
new file mode 100644
index 0000000000..c719067480
--- /dev/null
+++ b/src/corelib/global/q20map.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// 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
+
+#ifndef Q20MAP_H
+#define Q20MAP_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <map>
+#if __has_include(<memory_resource>)
+# include <memory_resource>
+#endif
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace q20 {
+// like std::erase/std::erase_if for std::map
+#if defined(__cpp_lib_erase_if) && __cpp_lib_erase_if >= 202002L // the one returning size_type
+using std::erase_if;
+#else
+
+// Make it more specialized than the compiler's, so that our implementation is preferred over
+// the compiler's (which may be present, but return void instead of the number of erased elements).
+
+#define MAKE_OVERLOAD(map, allocator) \
+ template <typename Key, typename T, typename Compare, typename Pred> \
+ constexpr typename std::map<Key, T, Compare, std::allocator<std::pair<const Key, T>>>::size_type \
+ erase_if(std::map<Key, T, Compare, std::allocator<std::pair<const Key, T>>> &c, Pred p) \
+ { \
+ const auto origSize = c.size(); \
+ for (auto it = c.begin(), end = c.end(); it != end; /* erasing */) { \
+ if (p(*it)) \
+ it = c.erase(it); \
+ else \
+ ++it; \
+ } \
+ return origSize - c.size(); \
+ } \
+ /* end */
+
+MAKE_OVERLOAD(map, allocator)
+MAKE_OVERLOAD(multimap, allocator)
+#ifdef __cpp_lib_polymorphic_allocator
+MAKE_OVERLOAD(map, pmr::polymorphic_allocator)
+MAKE_OVERLOAD(multimap, pmr::polymorphic_allocator)
+#endif // __cpp_lib_polymorphic_allocator
+
+#undef MAKE_OVERLOAD
+
+#endif // __cpp_lib_erase_if
+} // namespace q20
+
+QT_END_NAMESPACE
+
+#endif /* Q20MAP_H */
diff --git a/src/corelib/global/q20memory.h b/src/corelib/global/q20memory.h
new file mode 100644
index 0000000000..008f4ddeb2
--- /dev/null
+++ b/src/corelib/global/q20memory.h
@@ -0,0 +1,93 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q20MEMORY_H
+#define Q20MEMORY_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <memory>
+
+#include <type_traits>
+#include <utility>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+// like std::construct_at (but not whitelisted for constexpr)
+namespace q20 {
+#ifdef __cpp_lib_constexpr_dynamic_alloc
+using std::construct_at;
+#else
+template <typename T,
+ typename... Args,
+ typename Enable = std::void_t<decltype(::new (std::declval<void *>()) T(std::declval<Args>()...))> >
+T *construct_at(T *ptr, Args && ... args)
+{
+ return ::new (const_cast<void *>(static_cast<const volatile void *>(ptr)))
+ T(std::forward<Args>(args)...);
+}
+#endif // __cpp_lib_constexpr_dynamic_alloc
+} // namespace q20
+
+
+namespace q20 {
+// like std::to_address
+#ifdef __cpp_lib_to_address
+using std::to_address;
+#else
+// http://eel.is/c++draft/pointer.conversion
+template <typename T>
+constexpr T *to_address(T *p) noexcept {
+ // http://eel.is/c++draft/pointer.conversion#1:
+ // Mandates: T is not a function type.
+ static_assert(!std::is_function_v<T>, "to_address must not be used on function types");
+ return p;
+}
+
+template <typename Ptr, typename std::enable_if_t<!std::is_pointer_v<Ptr>, bool> = true>
+constexpr auto to_address(const Ptr &ptr) noexcept; // fwd declared
+
+namespace detail {
+ // http://eel.is/c++draft/pointer.conversion#3
+ template <typename Ptr, typename = void>
+ struct to_address_helper {
+ static auto get(const Ptr &ptr) noexcept
+ { return q20::to_address(ptr.operator->()); }
+ };
+ template <typename Ptr>
+ struct to_address_helper<Ptr, std::void_t<
+ decltype(std::pointer_traits<Ptr>::to_address(std::declval<const Ptr&>()))
+ >>
+ {
+ static auto get(const Ptr &ptr) noexcept
+ { return std::pointer_traits<Ptr>::to_address(ptr); }
+ };
+} // namespace detail
+
+template <typename Ptr, typename std::enable_if_t<!std::is_pointer_v<Ptr>, bool>>
+constexpr auto to_address(const Ptr &ptr) noexcept
+{ return detail::to_address_helper<Ptr>::get(ptr); }
+
+#endif // __cpp_lib_to_address
+} // namespace q20
+
+QT_END_NAMESPACE
+
+#endif /* Q20MEMORY_H */
diff --git a/src/corelib/global/q20type_traits.h b/src/corelib/global/q20type_traits.h
new file mode 100644
index 0000000000..63a453daca
--- /dev/null
+++ b/src/corelib/global/q20type_traits.h
@@ -0,0 +1,81 @@
+// Copyright (C) 2021 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef Q20TYPE_TRAITS_H
+#define Q20TYPE_TRAITS_H
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qsystemdetection.h>
+#include <QtCore/qtconfigmacros.h>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+#include <type_traits>
+
+QT_BEGIN_NAMESPACE
+
+namespace q20 {
+// like std::is_constant_evaluated
+#ifdef __cpp_lib_is_constant_evaluated
+using std::is_constant_evaluated;
+#define QT_SUPPORTS_IS_CONSTANT_EVALUATED
+#else
+constexpr bool is_constant_evaluated() noexcept
+{
+#ifdef Q_OS_INTEGRITY
+ // Integrity complains "calling __has_builtin() from a constant expression".
+ // Avoid the __has_builtin check until we know what's going on.
+ return false;
+#elif __has_builtin(__builtin_is_constant_evaluated) || \
+ (defined(Q_CC_MSVC_ONLY) /* >= 1925, but we require 1927 in qglobal.h */)
+# define QT_SUPPORTS_IS_CONSTANT_EVALUATED
+ return __builtin_is_constant_evaluated();
+#else
+ return false;
+#endif
+}
+#endif // __cpp_lib_is_constant_evaluated
+}
+
+namespace q20 {
+// like std::remove_cvref(_t)
+#ifdef __cpp_lib_remove_cvref
+using std::remove_cvref;
+using std::remove_cvref_t;
+#else
+template <typename T>
+using remove_cvref = std::remove_cv<std::remove_reference_t<T>>;
+template <typename T>
+using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
+#endif // __cpp_lib_remove_cvref
+}
+
+namespace q20 {
+// like std::type_identity(_t)
+#ifdef __cpp_lib_type_identity
+using std::type_identity;
+using std::type_identity_t;
+#else
+template <typename T>
+struct type_identity { using type = T; };
+template <typename T>
+using type_identity_t = typename type_identity<T>::type;
+#endif // __cpp_lib_type_identity
+}
+
+QT_END_NAMESPACE
+
+#endif /* Q20TYPE_TRAITS_H */
diff --git a/src/corelib/global/q20vector.h b/src/corelib/global/q20vector.h
new file mode 100644
index 0000000000..9d312355ea
--- /dev/null
+++ b/src/corelib/global/q20vector.h
@@ -0,0 +1,90 @@
+// Copyright (C) 2023 Ahmad Samir <a.samirh78@gmail.com>
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef Q20VECTOR_H
+#define Q20VECTOR_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <algorithm>
+#include <vector>
+#if __has_include(<memory_resource>)
+# include <memory_resource>
+#endif
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace q20 {
+// like std::erase/std::erase_if for std::vector
+#if defined(__cpp_lib_erase_if) && __cpp_lib_erase_if >= 202002L // the one returning size_type
+using std::erase;
+using std::erase_if;
+#else
+
+// Make it more specialized than the compiler's, so that our implementation is preferred over
+// the compiler's (which may be present, but return void instead of the number of erased elements).
+
+template <typename T, typename U>
+constexpr typename std::vector<T, std::allocator<T>>::size_type
+erase(std::vector<T, std::allocator<T>> &c, const U &value)
+{
+ const auto origSize = c.size();
+ auto it = std::remove(c.begin(), c.end(), value);
+ c.erase(it, c.end());
+ return origSize - c.size();
+}
+
+template <typename T, typename Pred>
+constexpr typename std::vector<T, std::allocator<T>>::size_type
+erase_if(std::vector<T, std::allocator<T>> &c, Pred pred)
+{
+ const auto origSize = c.size();
+ auto it = std::remove_if(c.begin(), c.end(), pred);
+ c.erase(it, c.end());
+ return origSize - c.size();
+}
+
+#ifdef __cpp_lib_polymorphic_allocator
+template <typename T, typename U>
+constexpr typename std::vector<T, std::pmr::polymorphic_allocator<T>>::size_type
+erase(std::vector<T, std::pmr::polymorphic_allocator<T>> &c, const U &value)
+{
+ const auto origSize = c.size();
+ auto it = std::remove(c.begin(), c.end(), value);
+ c.erase(it, c.end());
+ return origSize - c.size();
+}
+
+template <typename T, typename Pred>
+constexpr typename std::vector<T, std::pmr::polymorphic_allocator<T>>::size_type
+erase_if(std::vector<T, std::pmr::polymorphic_allocator<T>> &c, Pred pred)
+{
+ const auto origSize = c.size();
+ auto it = std::remove_if(c.begin(), c.end(), pred);
+ c.erase(it, c.end());
+ return origSize - c.size();
+}
+#endif // __cpp_lib_polymorphic_allocator
+
+#endif // __cpp_lib_erase_if
+} // namespace q20
+
+QT_END_NAMESPACE
+
+#endif /* Q20VECTOR_H */
diff --git a/src/corelib/global/q23functional.h b/src/corelib/global/q23functional.h
index 5f83df698e..ae8f78a3d0 100644
--- a/src/corelib/global/q23functional.h
+++ b/src/corelib/global/q23functional.h
@@ -10,9 +10,9 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. Types and functions defined
-// in this file will behave exactly as their std counterparts. You
-// may use these definitions in your own code, but be aware that we
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
// will remove them once Qt depends on the C++ version that supports
// them in namespace std. There will be NO deprecation warning, the
// definitions will JUST go away.
diff --git a/src/corelib/global/q23utility.cpp b/src/corelib/global/q23utility.cpp
new file mode 100644
index 0000000000..9c5365c547
--- /dev/null
+++ b/src/corelib/global/q23utility.cpp
@@ -0,0 +1,25 @@
+// 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
+
+#include <QtCore/q23utility.h>
+
+QT_BEGIN_NAMESPACE
+
+#define CHECK2(cvref_in, cvref_out) \
+ static_assert(std::is_same_v< \
+ decltype(q23::forward_like<int cvref_in >(std::declval<long&>())), \
+ long cvref_out \
+ >, "oops: cvref '" #cvref_in "' doesn't work") \
+ /* end */
+#define CHECK(cvref) CHECK2(cvref, cvref)
+CHECK2(/**/, &&);
+CHECK(&);
+CHECK(&&);
+CHECK2(const, const &&);
+CHECK(const &);
+CHECK(const &&);
+// volatile is not supported
+#undef CHECK
+#undef CHECK2
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/q23utility.h b/src/corelib/global/q23utility.h
new file mode 100644
index 0000000000..9ae5389b56
--- /dev/null
+++ b/src/corelib/global/q23utility.h
@@ -0,0 +1,75 @@
+// 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
+#ifndef Q23UTILITY_H
+#define Q23UTILITY_H
+
+#include <QtCore/qtconfigmacros.h>
+
+#include <utility>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+namespace q23 {
+// like std::forward_like
+#ifdef __cpp_lib_forward_like
+using std::forward_like;
+#else
+
+namespace _detail {
+
+// [forward]/6.1 COPY_CONST
+template <typename A, typename B>
+using copy_const_t = std::conditional_t<
+ std::is_const_v<A>, const B,
+ /* else */ B
+ >;
+
+// [forward]/6.2 OVERRIDE_REF
+template <typename A, typename B>
+using override_ref_t = std::conditional_t<
+ std::is_rvalue_reference_v<A>, std::remove_reference_t<B>&&,
+ /* else */ B&
+ >;
+
+// [forward]/6.3 "V"
+template <typename T, typename U>
+using forward_like_ret_t = override_ref_t<
+ T&&,
+ copy_const_t<
+ std::remove_reference_t<T>,
+ std::remove_reference_t<U>
+ >
+ >;
+
+} // namespace detail
+
+// http://eel.is/c++draft/forward#lib:forward_like
+template <class T, class U>
+[[nodiscard]] constexpr auto forward_like(U &&x) noexcept
+ -> _detail::forward_like_ret_t<T, U>
+{
+ using V = _detail::forward_like_ret_t<T, U>;
+ return static_cast<V>(x);
+}
+#endif // __cpp_lib_forward_like
+} // namespace q23
+
+QT_END_NAMESPACE
+
+#endif /* Q23UTILITY_H */
diff --git a/src/corelib/global/qassert.cpp b/src/corelib/global/qassert.cpp
index 2e340ebbb2..6a29cbfa21 100644
--- a/src/corelib/global/qassert.cpp
+++ b/src/corelib/global/qassert.cpp
@@ -5,14 +5,51 @@
#include <QtCore/qlogging.h>
+#include <cstdlib>
#include <cstdio>
#include <exception>
#ifndef QT_NO_EXCEPTIONS
#include <new>
#endif
+#if defined(Q_CC_MSVC)
+# include <crtdbg.h>
+#endif
+#ifdef Q_OS_WIN
+# include <qt_windows.h>
+#endif
+
QT_BEGIN_NAMESPACE
+void qAbort()
+{
+#ifdef Q_OS_WIN
+ // std::abort() in the MSVC runtime will call _exit(3) if the abort
+ // behavior is _WRITE_ABORT_MSG - see also _set_abort_behavior(). This is
+ // the default for a debug-mode build of the runtime. Worse, MinGW's
+ // std::abort() implementation (in msvcrt.dll) is basically a call to
+ // _exit(3) too. Unfortunately, _exit() and _Exit() *do* run the static
+ // destructors of objects in DLLs, a violation of the C++ standard (see
+ // [support.start.term]). So we bypass std::abort() and directly
+ // terminate the application.
+
+# if defined(Q_CC_MSVC)
+ if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
+ __fastfail(FAST_FAIL_FATAL_APP_EXIT);
+# else
+ RaiseFailFastException(nullptr, nullptr, 0);
+# endif
+
+ // Fallback
+ TerminateProcess(GetCurrentProcess(), STATUS_FATAL_APP_EXIT);
+
+ // Tell the compiler the application has stopped.
+ Q_UNREACHABLE_IMPL();
+#else // !Q_OS_WIN
+ std::abort();
+#endif
+}
+
/*!
\macro void Q_ASSERT(bool test)
\relates <QtAssert>
@@ -139,31 +176,52 @@ void qBadAlloc()
/*!
\macro void Q_ASSUME(bool expr)
+ \deprecated
\relates <QtAssert>
\since 5.0
- Causes the compiler to assume that \a expr is \c true. This macro is useful
- for improving code generation, by providing the compiler with hints about
- conditions that it would not otherwise know about. However, there is no
- guarantee that the compiler will actually use those hints.
+ Causes the compiler to assume that \a expr is \c true.
- This macro could be considered a "lighter" version of \l{Q_ASSERT()}. While
- Q_ASSERT will abort the program's execution if the condition is \c false,
- Q_ASSUME will tell the compiler not to generate code for those conditions.
- Therefore, it is important that the assumptions always hold, otherwise
- undefined behavior may occur.
+ This macro is known to produce worse code than when no assumption was
+ inserted in the code, with some compiler versions. The arguments passed to
+ it are always evaluated, even in release mode, with some compilers and not
+ others, so application code needs to be aware of those possible differences
+ in behavior.
- If \a expr is a constantly \c false condition, Q_ASSUME will tell the compiler
- that the current code execution cannot be reached. That is, Q_ASSUME(false)
- is equivalent to Q_UNREACHABLE().
+ Do not use it in new code. It is retained as-is for compatibility with old
+ code and will likely be removed in the next major version Qt.
- In debug builds the condition is enforced by an assert to facilitate debugging.
+ \sa Q_ASSERT(), Q_UNREACHABLE(), Q_LIKELY()
+*/
- \note Q_LIKELY() tells the compiler that the expression is likely, but not
- the only possibility. Q_ASSUME tells the compiler that it is the only
- possibility.
+/*!
+ \macro QT_TERMINATE_ON_EXCEPTION(expr)
+ \relates <QtGlobal>
+ \internal
- \sa Q_ASSERT(), Q_UNREACHABLE(), Q_LIKELY()
+ In general, use of the Q_DECL_NOEXCEPT macro is preferred over
+ Q_DECL_NOTHROW, because it exhibits well-defined behavior and
+ supports the more powerful Q_DECL_NOEXCEPT_EXPR variant. However,
+ use of Q_DECL_NOTHROW has the advantage that Windows builds
+ benefit on a wide range or compiler versions that do not yet
+ support the C++11 noexcept feature.
+
+ It may therefore be beneficial to use Q_DECL_NOTHROW and emulate
+ the C++11 behavior manually with an embedded try/catch.
+
+ Qt provides the QT_TERMINATE_ON_EXCEPTION(expr) macro for this
+ purpose. It either expands to \c expr (if Qt is compiled without
+ exception support or the compiler supports C++11 noexcept
+ semantics) or to
+ \snippet code/src_corelib_global_qglobal.cpp qterminate
+ otherwise.
+
+ Since this macro expands to just \c expr if the compiler supports
+ C++11 noexcept, expecting the compiler to take over responsibility
+ of calling std::terminate() in that case, it should not be used
+ outside Q_DECL_NOTHROW functions.
+
+ \sa Q_DECL_NOEXCEPT, Q_DECL_NOTHROW, qTerminate()
*/
/*!
@@ -195,7 +253,25 @@ void qBadAlloc()
In debug builds the condition is enforced by an assert to facilitate debugging.
- \sa Q_ASSERT(), Q_ASSUME(), qFatal()
+ \note Use the macro Q_UNREACHABLE_RETURN() to insert return statements for
+ compilers that need them, without causing warnings for compilers that
+ complain about its presence.
+
+ \sa Q_ASSERT(), qFatal(), Q_UNREACHABLE_RETURN()
*/
+/*!
+ \macro void Q_UNREACHABLE_RETURN(...)
+ \relates <QtAssert>
+ \since 6.5
+
+ This is equivalent to
+ \code
+ Q_UNREACHABLE();
+ return __VA_ARGS__;
+ \endcode
+ except it omits the return on compilers that would warn about it.
+
+ \sa Q_UNREACHABLE()
+*/
QT_END_NAMESPACE
diff --git a/src/corelib/global/qassert.h b/src/corelib/global/qassert.h
index c7ee13176a..388932a8f7 100644
--- a/src/corelib/global/qassert.h
+++ b/src/corelib/global/qassert.h
@@ -7,6 +7,7 @@
#include <QtCore/qcompilerdetection.h>
#include <QtCore/qtconfigmacros.h>
#include <QtCore/qtcoreexports.h>
+#include <QtCore/qtnoop.h>
#if 0
#pragma qt_class(QtAssert)
@@ -17,7 +18,7 @@ QT_BEGIN_NAMESPACE
#if defined(__cplusplus)
-#ifndef Q_CC_MSVC
+#if !defined(Q_CC_MSVC_ONLY)
Q_NORETURN
#endif
Q_DECL_COLD_FUNCTION
@@ -31,7 +32,7 @@ Q_CORE_EXPORT void qt_assert(const char *assertion, const char *file, int line)
# endif
#endif
-#ifndef Q_CC_MSVC
+#if !defined(Q_CC_MSVC_ONLY)
Q_NORETURN
#endif
Q_DECL_COLD_FUNCTION
@@ -70,11 +71,22 @@ inline T *q_check_ptr(T *p) { Q_CHECK_PTR(p); return p; }
Q_UNREACHABLE_IMPL();\
} while (false)
+#ifndef Q_UNREACHABLE_RETURN
+# ifdef Q_COMPILER_COMPLAINS_ABOUT_RETURN_AFTER_UNREACHABLE
+# define Q_UNREACHABLE_RETURN(...) Q_UNREACHABLE()
+# else
+# define Q_UNREACHABLE_RETURN(...) do { Q_UNREACHABLE(); return __VA_ARGS__; } while (0)
+# endif
+#endif
+
+Q_DECL_DEPRECATED_X("Q_ASSUME() is deprecated because it can produce worse code than when it's absent; "
+ "use C++23 [[assume]] instead")
+inline bool qt_assume_is_deprecated(bool cond) noexcept { return cond; }
#define Q_ASSUME(Expr) \
[] (bool valueOfExpression) {\
Q_ASSERT_X(valueOfExpression, "Q_ASSUME()", "Assumption in Q_ASSUME(\"" #Expr "\") was not correct");\
Q_ASSUME_IMPL(valueOfExpression);\
- }(Expr)
+ }(qt_assume_is_deprecated(Expr))
// Don't use these in C++ mode, use static_assert directly.
// These are here only to keep old code compiling.
diff --git a/src/corelib/global/qcompare.cpp b/src/corelib/global/qcompare.cpp
new file mode 100644
index 0000000000..ac220b8434
--- /dev/null
+++ b/src/corelib/global/qcompare.cpp
@@ -0,0 +1,1357 @@
+// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// 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
+
+#include "qcompare.h"
+
+#ifdef __cpp_lib_bit_cast
+#include <bit>
+#endif
+
+QT_BEGIN_NAMESPACE
+
+#ifdef __cpp_lib_three_way_comparison
+#ifdef __cpp_lib_bit_cast
+#define CHECK(type, flag) \
+ static_assert(std::bit_cast<Qt:: type ## _ordering>(std:: type ## _ordering:: flag) \
+ == Qt:: type ## _ordering :: flag); \
+ static_assert(std::bit_cast<std:: type ## _ordering>(Qt:: type ## _ordering:: flag) \
+ == std:: type ## _ordering :: flag) \
+ /* end */
+CHECK(partial, unordered);
+CHECK(partial, less);
+CHECK(partial, greater);
+CHECK(partial, equivalent);
+CHECK(weak, less);
+CHECK(weak, greater);
+CHECK(weak, equivalent);
+CHECK(strong, less);
+CHECK(strong, greater);
+CHECK(strong, equal);
+CHECK(strong, equivalent);
+#undef CHECK
+#endif // __cpp_lib_bit_cast
+#endif //__cpp_lib_three_way_comparison
+
+
+/*!
+ \page comparison-types.html overview
+ \title Comparison types overview
+ \keyword three-way comparison
+ \inmodule QtCore
+ \sa Qt::strong_ordering, Qt::weak_ordering, Qt::partial_ordering
+
+ \note Qt's comparison types provide functionality equivalent to their C++20
+ standard counterparts. The only reason why they exist is to make the
+ functionality available in C++17 builds, too. In a C++20 build, they
+ implicitly convert to and from the \c std types, making them fully
+ interchangeable. We therefore recommended that you prefer to use the C++
+ standard types in your code, if you can use C++20 in your projects already.
+ The Qt comparison types will be removed in Qt 7.
+
+ Qt provides several comparison types for a \l
+ {https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison}
+ {three-way comparison}, which are comparable against a \e {zero literal}.
+ To use these comparison types, you need to include the \c <QtCompare>
+ header. These comparison types are categorized based on their \e order,
+ which is a mathematical concept used to describe the arrangement or ranking
+ of elements. The following categories are provided:
+
+ \table 100 %
+ \header
+ \li C++ type
+ \li Qt type
+ \li strict
+ \li total
+ \li Example
+ \row
+ \li \l {https://en.cppreference.com/w/cpp/utility/compare/strong_ordering}
+ {std::strong_ordering}
+ \li Qt::strong_ordering
+ \li yes
+ \li yes
+ \li integral types, case-sensitive strings, QDate, QTime
+ \row
+ \li \l {https://en.cppreference.com/w/cpp/utility/compare/weak_ordering}
+ {std::weak_ordering}
+ \li Qt::weak_ordering
+ \li no
+ \li yes
+ \li case-insensitive strings, unordered associative containers, QDateTime
+ \row
+ \li \l {https://en.cppreference.com/w/cpp/utility/compare/partial_ordering}
+ {std::partial_ordering}
+ \li Qt::partial_ordering
+ \li no
+ \li no
+ \li floating-point types, QOperatingSystemVersion, QVariant
+ \endtable
+
+ The strongest comparison type, Qt::strong_ordering, represents a strict total
+ order. It requires that any two elements be comparable in a way where
+ equality implies substitutability. In other words, equivalent values
+ cannot be distinguished from each other. A practical example would be the
+ case-sensitive comparison of two strings. For instance, when comparing the
+ values \c "Qt" and \c "Qt" the result would be \l Qt::strong_ordering::equal.
+ Both values are indistinguishable and all deterministic operations performed
+ on these values would yield identical results.
+
+ Qt::weak_ordering represents a total order. While any two values still need to
+ be comparable, equivalent values may be distinguishable. The canonical
+ example here would be the case-insensitive comparison of two strings. For
+ instance, when comparing the values \c "Qt" and \c "qt" both hold the same
+ letters but with different representations. This comparison would
+ result in \l Qt::weak_ordering::equivalent, but not actually \c Equal.
+ Another example would be QDateTime, which can represent a given instant in
+ time in terms of local time or any other time-zone, including UTC. The
+ different representations are equivalent, even though their \c time() and
+ sometimes \c date() may differ.
+
+ Qt::partial_ordering represents, as the name implies, a partial ordering. It
+ allows for the possibility that two values may not be comparable, resulting
+ in an \l {Qt::partial_ordering::}{unordered} state. Additionally, equivalent
+ values may still be distinguishable. A practical example would be the
+ comparison of two floating-point values, comparing with NaN (Not-a-Number)
+ would yield an unordered result. Another example is the comparison of two
+ QOperatingSystemVersion objects. Comparing versions of two different
+ operating systems, such as Android and Windows, would produce an unordered
+ result.
+
+ Utilizing these comparison types enhances the expressiveness of defining
+ relations. Furthermore, they serve as a fundamental component for
+ implementing three-way comparison with C++17.
+*/
+
+/*!
+ \headerfile <QtCompare>
+ \inmodule QtCore
+ \title Classes and helpers for defining comparison operators
+ \keyword qtcompare
+
+ \brief The <QtCompare> header file defines \c {Qt::*_ordering} types and helper
+ macros for defining comparison operators.
+
+ This header introduces the \l Qt::partial_ordering, \l Qt::weak_ordering, and
+ \l Qt::strong_ordering types, which are Qt's C++17 backports of
+ \c {std::*_ordering} types.
+
+ This header also contains functions for implementing three-way comparison
+ in C++17.
+
+ The \c {Qt::compareThreeWay()} function overloads provide three-way
+ comparison for built-in C++ types.
+
+ The \l qCompareThreeWay() template serves as a generic three-way comparison
+ implementation. It relies on \c {Qt::compareThreeWay()} and free
+ \c {compareThreeWay()} functions in its implementation.
+*/
+
+/*!
+ \class Qt::strong_ordering
+ \inmodule QtCore
+ \brief Qt::strong_ordering represents a comparison where equivalent values are
+ indistinguishable.
+ \sa Qt::weak_ordering, Qt::partial_ordering, {Comparison types overview}
+ \since 6.7
+
+ A value of type Qt::strong_ordering is typically returned from a three-way
+ comparison function. Such a function compares two objects and establishes
+ how they are ordered. It uses this return type to indicate that the ordering
+ is strict; that is, the function establishes a well-defined total order.
+
+ Qt::strong_ordering has four values, represented by the following symbolic
+ constants:
+
+ \list
+ \li \l less represents that the left operand is less than the right;
+ \li \l equal represents that the left operand is equivalent to the right;
+ \li \l equivalent is an alias for \c equal;
+ \li \l greater represents that the left operand is greater than the right.
+ \endlist
+
+ Qt::strong_ordering is idiomatically used by comparing an instance against a
+ literal zero, for instance like this:
+
+ \code
+
+ // given a, b, c, d as objects of some type that allows for a 3-way compare,
+ // and a compare function declared as follows:
+
+ Qt::strong_ordering compare(T lhs, T rhs); // defined out-of-line
+ ~~~
+
+ Qt::strong_ordering result = compare(a, b);
+ if (result < 0) {
+ // a is less than b
+ }
+
+ if (compare(c, d) >= 0) {
+ // c is greater than or equal to d
+ }
+
+ \endcode
+*/
+
+/*!
+ \fn Qt::strong_ordering::operator Qt::partial_ordering() const
+
+ Converts this Qt::strong_ordering value to a Qt::partial_ordering object using the
+ following rules:
+
+ \list
+ \li \l less converts to \l {Qt::partial_ordering::less}.
+ \li \l equivalent converts to \l {Qt::partial_ordering::equivalent}.
+ \li \l equal converts to \l {Qt::partial_ordering::equivalent}.
+ \li \l greater converts to \l {Qt::partial_ordering::greater}.
+ \endlist
+*/
+
+/*!
+ \fn Qt::strong_ordering::operator Qt::weak_ordering() const
+
+ Converts this Qt::strong_ordering value to a Qt::weak_ordering object using the
+ following rules:
+
+ \list
+ \li \l less converts to \l {Qt::weak_ordering::less}.
+ \li \l equivalent converts to \l {Qt::weak_ordering::equivalent}.
+ \li \l equal converts to \l {Qt::weak_ordering::equivalent}.
+ \li \l greater converts to \l {Qt::weak_ordering::greater}.
+ \endlist
+*/
+
+/*!
+ \fn Qt::strong_ordering::strong_ordering(std::strong_ordering stdorder)
+
+ Constructs a Qt::strong_ordering object from \a stdorder using the following rules:
+
+ \list
+ \li std::strong_ordering::less converts to \l less.
+ \li std::strong_ordering::equivalent converts to \l equivalent.
+ \li std::strong_ordering::equal converts to \l equal.
+ \li std::strong_ordering::greater converts to \l greater.
+ \endlist
+*/
+
+/*!
+ \fn Qt::strong_ordering::operator std::strong_ordering() const
+
+ Converts this Qt::strong_ordering value to a std::strong_ordering object using
+ the following rules:
+
+ \list
+ \li \l less converts to std::strong_ordering::less.
+ \li \l equivalent converts to std::strong_ordering::equivalent.
+ \li \l equal converts to std::strong_ordering::equal.
+ \li \l greater converts to std::strong_ordering::greater.
+ \endlist
+*/
+
+/*!
+ \fn bool Qt::strong_ordering::operator==(Qt::strong_ordering lhs, Qt::strong_ordering rhs)
+
+ Returns true if \a lhs and \a rhs represent the same result;
+ otherwise, returns false.
+*/
+
+/*!
+ \fn bool Qt::strong_ordering::operator!=(Qt::strong_ordering lhs, Qt::strong_ordering rhs)
+
+ Returns true if \a lhs and \a rhs represent different results;
+ otherwise, returns true.
+*/
+
+/*!
+ \internal
+ \relates Qt::strong_ordering
+ \fn bool operator==(Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator!=(Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator< (Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator<=(Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator> (Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator>=(Qt::strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+
+ \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, Qt::strong_ordering rhs)
+*/
+
+/*!
+ \fn Qt::strong_ordering::is_eq (Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_neq (Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_lt (Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_lteq(Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_gt (Qt::strong_ordering o)
+ \fn Qt::strong_ordering::is_gteq(Qt::strong_ordering o)
+
+//! [is_eq_table]
+ Converts \a o into the result of one of the six relational operators:
+ \table
+ \header \li Function \li Operation
+ \row \li \c{is_eq} \li \a o \c{== 0}
+ \row \li \c{is_neq} \li \a o \c{!= 0}
+ \row \li \c{is_lt} \li \a o \c{< 0}
+ \row \li \c{is_lteq} \li \a o \c{<= 0}
+ \row \li \c{is_gt} \li \a o \c{> 0}
+ \row \li \c{is_gteq} \li \a o \c{>= 0}
+ \endtable
+//! [is_eq_table]
+
+ These functions are provided for compatibility with \c{std::strong_ordering}.
+*/
+
+/*!
+ \variable Qt::strong_ordering::less
+
+ Represents the result of a comparison where the left operand is less
+ than the right operand.
+*/
+
+/*!
+ \variable Qt::strong_ordering::equivalent
+
+ Represents the result of a comparison where the left operand is equal
+ to the right operand. Same as \l {Qt::strong_ordering::equal}.
+*/
+
+/*!
+ \variable Qt::strong_ordering::equal
+
+ Represents the result of a comparison where the left operand is equal
+ to the right operand. Same as \l {Qt::strong_ordering::equivalent}.
+*/
+
+/*!
+ \variable Qt::strong_ordering::greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \class Qt::weak_ordering
+ \inmodule QtCore
+ \brief Qt::weak_ordering represents a comparison where equivalent values are
+ still distinguishable.
+ \sa Qt::strong_ordering, Qt::partial_ordering, {Comparison types overview}
+ \since 6.7
+
+ A value of type Qt::weak_ordering is typically returned from a three-way
+ comparison function. Such a function compares two objects and establishes
+ how they are ordered. It uses this return type to indicate that the ordering
+ is weak; that is, equivalent values may be distinguishable.
+
+ Qt::weak_ordering has three values, represented by the following symbolic
+ constants:
+
+ \list
+ \li \l less represents that the left operand is less than the right;
+ \li \l equivalent represents that the left operand is equivalent to the
+ right;
+ \li \l greater represents that the left operand is greater than the right,
+ \endlist
+
+ Qt::weak_ordering is idiomatically used by comparing an instance against a
+ literal zero, for instance like this:
+
+ \code
+
+ // given a, b, c, d as objects of some type that allows for a 3-way compare,
+ // and a compare function declared as follows:
+
+ Qt::weak_ordering compare(T lhs, T rhs); // defined out-of-line
+ ~~~
+
+ Qt::weak_ordering result = compare(a, b);
+ if (result < 0) {
+ // a is less than b
+ }
+
+ if (compare(c, d) >= 0) {
+ // c is greater than or equivalent to d
+ }
+
+ \endcode
+*/
+
+/*!
+ \fn Qt::weak_ordering::operator Qt::partial_ordering() const
+
+ Converts this Qt::weak_ordering value to a Qt::partial_ordering object using the
+ following rules:
+
+ \list
+ \li \l less converts to \l {Qt::partial_ordering::less}.
+ \li \l equivalent converts to \l {Qt::partial_ordering::equivalent}.
+ \li \l greater converts to \l {Qt::partial_ordering::greater}.
+ \endlist
+*/
+
+/*!
+ \fn Qt::weak_ordering::weak_ordering(std::weak_ordering stdorder)
+
+ Constructs a Qt::weak_ordering object from \a stdorder using the following rules:
+
+ \list
+ \li std::weak_ordering::less converts to \l less.
+ \li std::weak_ordering::equivalent converts to \l equivalent.
+ \li std::weak_ordering::greater converts to \l greater.
+ \endlist
+*/
+
+/*!
+ \fn Qt::weak_ordering::operator std::weak_ordering() const
+
+ Converts this Qt::weak_ordering value to a std::weak_ordering object using
+ the following rules:
+
+ \list
+ \li \l less converts to std::weak_ordering::less.
+ \li \l equivalent converts to std::weak_ordering::equivalent.
+ \li \l greater converts to std::weak_ordering::greater.
+ \endlist
+*/
+
+/*!
+ \fn bool Qt::weak_ordering::operator==(Qt::weak_ordering lhs, Qt::weak_ordering rhs)
+
+ Return true if \a lhs and \a rhs represent the same result;
+ otherwise, returns false.
+*/
+
+/*!
+ \fn bool Qt::weak_ordering::operator!=(Qt::weak_ordering lhs, Qt::weak_ordering rhs)
+
+ Return true if \a lhs and \a rhs represent different results;
+ otherwise, returns true.
+*/
+
+/*!
+ \internal
+ \relates Qt::weak_ordering
+ \fn bool operator==(Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator!=(Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator< (Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator<=(Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator> (Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator>=(Qt::weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+
+ \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, Qt::weak_ordering rhs)
+*/
+
+/*!
+ \fn Qt::weak_ordering::is_eq (Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_neq (Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_lt (Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_lteq(Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_gt (Qt::weak_ordering o)
+ \fn Qt::weak_ordering::is_gteq(Qt::weak_ordering o)
+
+ \include qcompare.cpp is_eq_table
+
+ These functions are provided for compatibility with \c{std::weak_ordering}.
+*/
+
+/*!
+ \variable Qt::weak_ordering::less
+
+ Represents the result of a comparison where the left operand is less than
+ the right operand.
+*/
+
+/*!
+ \variable Qt::weak_ordering::equivalent
+
+ Represents the result of a comparison where the left operand is equivalent
+ to the right operand.
+*/
+
+/*!
+ \variable Qt::weak_ordering::greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \class Qt::partial_ordering
+ \inmodule QtCore
+ \brief Qt::partial_ordering represents the result of a comparison that allows
+ for unordered results.
+ \sa Qt::strong_ordering, Qt::weak_ordering, {Comparison types overview}
+ \since 6.7
+
+ A value of type Qt::partial_ordering is typically returned from a
+ three-way comparison function. Such a function compares two objects,
+ establishing whether they are ordered and, if so, their ordering. It uses
+ this return type to indicate that the ordering is partial; that is, not all
+ pairs of values are ordered.
+
+ Qt::partial_ordering has four values, represented by the following symbolic
+ constants:
+
+ \list
+ \li \l less represents that the left operand is less than the right;
+ \li \l equivalent represents that the two operands are equivalent;
+ \li \l greater represents that the left operand is greater than the right;
+ \li \l unordered represents that the two operands are \e {not ordered}.
+ \endlist
+
+ Qt::partial_ordering is idiomatically used by comparing an instance
+ against a literal zero, for instance like this:
+
+ \code
+
+ // given a, b, c, d as objects of some type that allows for a 3-way compare,
+ // and a compare function declared as follows:
+
+ Qt::partial_ordering compare(T lhs, T rhs); // defined out-of-line
+ ~~~
+
+ Qt::partial_ordering result = compare(a, b);
+ if (result < 0) {
+ // a is less than b
+ }
+
+ if (compare(c, d) >= 0) {
+ // c is greater than or equal to d
+ }
+
+ \endcode
+
+ Comparing Qt::partial_ordering::unordered against literal 0 always returns
+ a \c false result.
+*/
+
+/*!
+ \fn Qt::partial_ordering::partial_ordering(std::partial_ordering stdorder)
+
+ Constructs a Qt::partial_ordering object from \a stdorder using the following
+ rules:
+
+ \list
+ \li std::partial_ordering::less converts to \l less.
+ \li std::partial_ordering::equivalent converts to \l equivalent.
+ \li std::partial_ordering::greater converts to \l greater.
+ \li std::partial_ordering::unordered converts to \l unordered
+ \endlist
+*/
+
+/*!
+ \fn Qt::partial_ordering::operator std::partial_ordering() const
+
+ Converts this Qt::partial_ordering value to a std::partial_ordering object using
+ the following rules:
+
+ \list
+ \li \l less converts to std::partial_ordering::less.
+ \li \l equivalent converts to std::partial_ordering::equivalent.
+ \li \l greater converts to std::partial_ordering::greater.
+ \li \l unordered converts to std::partial_ordering::unordered.
+ \endlist
+*/
+
+/*!
+ \fn bool Qt::partial_ordering::operator==(Qt::partial_ordering lhs, Qt::partial_ordering rhs)
+
+ Return true if \a lhs and \a rhs represent the same result;
+ otherwise, returns false.
+*/
+
+/*!
+ \fn bool Qt::partial_ordering::operator!=(Qt::partial_ordering lhs, Qt::partial_ordering rhs)
+
+ Return true if \a lhs and \a rhs represent different results;
+ otherwise, returns true.
+*/
+
+/*!
+ \internal
+ \relates Qt::partial_ordering
+ \fn bool operator==(Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator!=(Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator< (Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator<=(Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator> (Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator>=(Qt::partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero)
+
+ \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, Qt::partial_ordering rhs)
+*/
+
+/*!
+ \fn Qt::partial_ordering::is_eq (Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_neq (Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_lt (Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_lteq(Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_gt (Qt::partial_ordering o)
+ \fn Qt::partial_ordering::is_gteq(Qt::partial_ordering o)
+
+ \include qcompare.cpp is_eq_table
+
+ These functions are provided for compatibility with \c{std::partial_ordering}.
+*/
+
+/*!
+ \variable Qt::partial_ordering::less
+
+ Represents the result of a comparison where the left operand is less than
+ the right operand.
+*/
+
+/*!
+ \variable Qt::partial_ordering::equivalent
+
+ Represents the result of a comparison where the two operands are equivalent.
+*/
+
+/*!
+ \variable Qt::partial_ordering::greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \variable Qt::partial_ordering::unordered
+
+ Represents the result of a comparison where there is no ordering
+ relationship between the two operands.
+*/
+
+/*!
+ \class QPartialOrdering
+ \inmodule QtCore
+ \brief QPartialOrdering represents the result of a comparison that allows
+ for unordered results.
+ \sa Qt::strong_ordering, Qt::weak_ordering, {Comparison types overview}
+ \since 6.0
+
+ A value of type QPartialOrdering is typically returned from a
+ three-way comparison function. Such a function compares two objects,
+ establishing whether they are ordered and, if so, their ordering. It uses
+ this return type to indicate that the ordering is partial; that is, not all
+ pairs of values are ordered.
+
+ QPartialOrdering has four values, represented by the following symbolic
+ constants:
+
+ \list
+ \li \l less represents that the left operand is less than the right;
+ \li \l equivalent represents that the two operands are equivalent;
+ \li \l greater represents that the left operand is greater than the right;
+ \li \l unordered represents that the two operands are \e {not ordered}.
+ \endlist
+
+ QPartialOrdering is idiomatically used by comparing an instance
+ against a literal zero, for instance like this:
+
+ \code
+
+ // given a, b, c, d as objects of some type that allows for a 3-way compare,
+ // and a compare function declared as follows:
+
+ QPartialOrdering compare(T lhs, T rhs); // defined out-of-line
+ ~~~
+
+ QPartialOrdering result = compare(a, b);
+ if (result < 0) {
+ // a is less than b
+ }
+
+ if (compare(c, d) >= 0) {
+ // c is greater than or equal to d
+ }
+
+ \endcode
+
+ Comparing QPartialOrdering::unordered against literal 0 always returns
+ a \c false result.
+*/
+
+/*!
+ \fn QPartialOrdering::QPartialOrdering(std::partial_ordering stdorder)
+
+ Constructs a QPartialOrdering object from \a stdorder using the following
+ rules:
+
+ \list
+ \li std::partial_ordering::less converts to \l less.
+ \li std::partial_ordering::equivalent converts to \l equivalent.
+ \li std::partial_ordering::greater converts to \l greater.
+ \li std::partial_ordering::unordered converts to \l unordered
+ \endlist
+*/
+
+/*!
+ \fn QPartialOrdering::operator std::partial_ordering() const
+
+ Converts this QPartialOrdering value to a std::partial_ordering object using
+ the following rules:
+
+ \list
+ \li \l less converts to std::partial_ordering::less.
+ \li \l equivalent converts to std::partial_ordering::equivalent.
+ \li \l greater converts to std::partial_ordering::greater.
+ \li \l unordered converts to std::partial_ordering::unordered.
+ \endlist
+*/
+
+/*!
+ \fn bool QPartialOrdering::operator==(QPartialOrdering lhs, QPartialOrdering rhs)
+
+ Return true if \a lhs and \a rhs represent the same result;
+ otherwise, returns false.
+*/
+
+/*!
+ \fn bool QPartialOrdering::operator!=(QPartialOrdering lhs, QPartialOrdering rhs)
+
+ Return true if \a lhs and \a rhs represent different results;
+ otherwise, returns true.
+*/
+
+/*!
+ \internal
+ \relates QPartialOrdering
+ \fn bool operator==(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator!=(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator< (QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator<=(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator> (QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+ \fn bool operator>=(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero)
+
+ \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+ \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs)
+*/
+
+/*!
+ \fn QPartialOrdering::is_eq (QPartialOrdering o)
+ \fn QPartialOrdering::is_neq (QPartialOrdering o)
+ \fn QPartialOrdering::is_lt (QPartialOrdering o)
+ \fn QPartialOrdering::is_lteq(QPartialOrdering o)
+ \fn QPartialOrdering::is_gt (QPartialOrdering o)
+ \fn QPartialOrdering::is_gteq(QPartialOrdering o)
+
+ \since 6.7
+ \include qcompare.cpp is_eq_table
+
+ These functions are provided for compatibility with \c{std::partial_ordering}.
+*/
+
+/*!
+ \variable QPartialOrdering::less
+
+ Represents the result of a comparison where the left operand is less than
+ the right operand.
+*/
+
+/*!
+ \variable QPartialOrdering::equivalent
+
+ Represents the result of a comparison where the two operands are equivalent.
+*/
+
+/*!
+ \variable QPartialOrdering::greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \variable QPartialOrdering::unordered
+
+ Represents the result of a comparison where there is no ordering
+ relationship between the two operands.
+*/
+
+/*!
+ \variable QPartialOrdering::Less
+
+ Represents the result of a comparison where the left operand is less than
+ the right operand.
+*/
+
+/*!
+ \variable QPartialOrdering::Equivalent
+
+ Represents the result of a comparison where the two operands are equivalent.
+*/
+
+/*!
+ \variable QPartialOrdering::Greater
+
+ Represents the result of a comparison where the left operand is greater
+ than the right operand.
+*/
+
+/*!
+ \variable QPartialOrdering::Unordered
+
+ Represents the result of a comparison where there is no ordering
+ relationship between the two operands.
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_EQUALITY_COMPARABLE(Type)
+ \macro Q_DECLARE_EQUALITY_COMPARABLE(LeftType, RightType)
+ \macro Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(Type)
+ \macro Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(LeftType, RightType)
+ \since 6.7
+ \relates <QtCompare>
+
+ These macros are used to generate \c {operator==()} and \c {operator!=()}.
+
+ In C++17 mode, the mixed-type overloads also generate the reversed
+ operators.
+
+ In C++20 mode, only \c {operator==()} is defined. \c {operator!=()},
+ as well as the reversed operators for mixed-type comparison, are synthesized
+ by the compiler.
+
+ The operators are implemented in terms of a helper function
+ \c {comparesEqual()}.
+ It's the user's responsibility to declare and define this function.
+
+ Consider the following example of a comparison operators declaration:
+
+ \code
+ class MyClass {
+ ...
+ private:
+ friend bool comparesEqual(const MyClass &, const MyClass &) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE(MyClass)
+ };
+ \endcode
+
+ When compiled with C++17, the macro will expand into the following code:
+
+ \code
+ friend bool operator==(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend bool operator!=(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ \endcode
+
+ When compiled with C++20, the macro will expand only into \c {operator==()}:
+
+ \code
+ friend bool operator==(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ \endcode
+
+ The \c {*_LITERAL_TYPE} versions of the macros are used to generate
+ \c constexpr operators. This means that the helper \c {comparesEqual()}
+ function must also be \c constexpr.
+
+ Consider the following example of a mixed-type \c constexpr comparison
+ operators declaration:
+
+ \code
+ class MyClass {
+ ...
+ private:
+ friend constexpr bool comparesEqual(const MyClass &, int) noexcept;
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(MyClass, int)
+ };
+ \endcode
+
+ When compiled with C++17, the macro will expand into the following code:
+
+ \code
+ friend constexpr bool operator==(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend constexpr bool operator!=(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend constexpr bool operator==(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend constexpr bool operator!=(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ \endcode
+
+ When compiled with C++20, the macro expands only into \c {operator==()}:
+
+ \code
+ friend constexpr bool operator==(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ \endcode
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_PARTIALLY_ORDERED(Type)
+ \macro Q_DECLARE_PARTIALLY_ORDERED(LeftType, RightType)
+ \macro Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(Type)
+ \macro Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(LeftType, RightType)
+ \since 6.7
+ \relates <QtCompare>
+
+ These macros are used to generate all six relational operators.
+ The operators represent
+ \l {https://en.cppreference.com/w/cpp/utility/compare/partial_ordering}
+ {partial ordering}.
+
+ These macros use respective overloads of the
+ \l {Q_DECLARE_EQUALITY_COMPARABLE} macro to generate \c {operator==()} and
+ \c {operator!=()}, and also generate the four relational operators:
+ \c {operator<()}, \c {operator>()}, \c {operator<=()}, and \c {operator>()}.
+
+ In C++17 mode, the mixed-type overloads also generate the reversed
+ operators.
+
+ In C++20 mode, only \c {operator==()} and \c {operator<=>()} are defined.
+ Other operators, as well as the reversed operators for mixed-type
+ comparison, are synthesized by the compiler.
+
+ The (in)equality operators are implemented in terms of a helper function
+ \c {comparesEqual()}. The other relational operators are implemented in
+ terms of a helper function \c {compareThreeWay()}.
+ The \c {compareThreeWay()} function \e must return an object of type
+ \l Qt::partial_ordering. It's the user's responsibility to declare and define
+ both helper functions.
+
+ Consider the following example of a comparison operators declaration:
+
+ \code
+ class MyClass {
+ ...
+ private:
+ friend bool comparesEqual(const MyClass &, const MyClass &) noexcept;
+ friend Qt::partial_ordering compareThreeWay(const MyClass &, const MyClass &) noexcept;
+ Q_DECLARE_PARTIALLY_ORDERED(MyClass)
+ };
+ \endcode
+
+ When compiled with C++17, the macro will expand into the following code:
+
+ \code
+ // operator==() and operator!=() are generated from
+ // Q_DECLARE_EQUALITY_COMPARABLE
+ friend bool operator<(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend bool operator>(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend bool operator<=(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend bool operator>=(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ \endcode
+
+ When compiled with C++20, the macro will expand into \c {operator==()} and
+ \c {operator<=>()}:
+
+ \code
+ friend bool operator==(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend std::partial_ordering
+ operator<=>(const MyClass &lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ \endcode
+
+ The \c {*_LITERAL_TYPE} versions of the macros are used to generate
+ \c constexpr operators. This means that the helper \c {comparesEqual()} and
+ \c {compareThreeWay()} functions must also be \c constexpr.
+
+ Consider the following example of a mixed-type \c constexpr comparison
+ operators declaration:
+
+ \code
+ class MyClass {
+ ...
+ private:
+ friend constexpr bool comparesEqual(const MyClass &, int) noexcept;
+ friend constexpr Qt::partial_ordering compareThreeWay(const MyClass &, int) noexcept;
+ Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(MyClass, int)
+ };
+ \endcode
+
+ When compiled with C++17, the macro will expand into the following code:
+
+ \code
+ // operator==(), operator!=(), and their reversed versions are generated
+ // from Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE
+ friend constexpr bool operator<(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator>(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator<=(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator>=(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator<(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator>(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator<=(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ friend constexpr bool operator>=(int lhs, const MyClass &rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ \endcode
+
+ When compiled with C++20, the macro will expand into \c {operator==()} and
+ \c {operator<=>()}:
+
+ \code
+ friend constexpr bool operator==(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses comparesEqual()
+ }
+ friend constexpr std::partial_ordering
+ operator<=>(const MyClass &lhs, int rhs) noexcept
+ {
+ // inline implementation which uses compareThreeWay()
+ }
+ \endcode
+
+ \sa Q_DECLARE_EQUALITY_COMPARABLE, Q_DECLARE_WEAKLY_ORDERED,
+ Q_DECLARE_STRONGLY_ORDERED
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_WEAKLY_ORDERED(Type)
+ \macro Q_DECLARE_WEAKLY_ORDERED(LeftType, RightType)
+ \macro Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(Type)
+ \macro Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(LeftType, RightType)
+ \since 6.7
+ \relates <QtCompare>
+
+ These macros behave similarly to the
+ \l {Q_DECLARE_PARTIALLY_ORDERED} overloads, but represent
+ \l {https://en.cppreference.com/w/cpp/utility/compare/weak_ordering}
+ {weak ordering}.
+
+ The (in)equality operators are implemented in terms of a helper function
+ \c {comparesEqual()}. The other relational operators are implemented in
+ terms of a helper function \c {compareThreeWay()}.
+ The \c {compareThreeWay()} function \e must return an object of type
+ \l Qt::weak_ordering. It's the user's responsibility to declare and define both
+ helper functions.
+
+ The \c {*_LITERAL_TYPE} overloads are used to generate \c constexpr
+ operators. This means that the helper \c {comparesEqual()} and
+ \c {compareThreeWay()} functions must also be \c constexpr.
+
+ See \l {Q_DECLARE_PARTIALLY_ORDERED} for usage examples.
+
+ \sa Q_DECLARE_PARTIALLY_ORDERED, Q_DECLARE_STRONGLY_ORDERED,
+ Q_DECLARE_EQUALITY_COMPARABLE
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_STRONGLY_ORDERED(Type)
+ \macro Q_DECLARE_STRONGLY_ORDERED(LeftType, RightType)
+ \macro Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(Type)
+ \macro Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(LeftType, RightType)
+ \since 6.7
+ \relates <QtCompare>
+
+ These macros behave similarly to the
+ \l {Q_DECLARE_PARTIALLY_ORDERED} overloads, but represent
+ \l {https://en.cppreference.com/w/cpp/utility/compare/strong_ordering}
+ {strong ordering}.
+
+ The (in)equality operators are implemented in terms of a helper function
+ \c {comparesEqual()}. The other relational operators are implemented in
+ terms of a helper function \c {compareThreeWay()}.
+ The \c {compareThreeWay()} function \e must return an object of type
+ \l Qt::strong_ordering. It's the user's responsibility to declare and define
+ both helper functions.
+
+ The \c {*_LITERAL_TYPE} overloads are used to generate \c constexpr
+ operators. This means that the helper \c {comparesEqual()} and
+ \c {compareThreeWay()} functions must also be \c constexpr.
+
+ See \l {Q_DECLARE_PARTIALLY_ORDERED} for usage examples.
+
+ \sa Q_DECLARE_PARTIALLY_ORDERED, Q_DECLARE_WEAKLY_ORDERED,
+ Q_DECLARE_EQUALITY_COMPARABLE
+*/
+
+/*!
+ \internal
+ \macro Q_DECLARE_EQUALITY_COMPARABLE(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_PARTIALLY_ORDERED(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_WEAKLY_ORDERED(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_STRONGLY_ORDERED(LeftType, RightType, Attributes)
+ \macro Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(LeftType, RightType, Attributes)
+ \since 6.8
+ \relates <QtCompare>
+
+ These macros behave like their two-argument versions, but allow
+ specification of C++ attributes to add before every generated relational
+ operator.
+
+ As an example, the \c Attributes parameter can be used in Qt to pass
+ the \c QT_ASCII_CAST_WARN marco (whose expansion can mark the function as
+ deprecated) when implementing comparison of encoding-aware string types
+ with C-style strings or byte arrays.
+*/
+
+/*!
+ \fn template <typename LeftInt, typename RightInt, Qt::if_integral<LeftInt> = true, Qt::if_integral<RightInt> = true> auto Qt::compareThreeWay(LeftInt lhs, RightInt rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of integral types.
+
+ \note This function participates in overload resolution only if both
+ \c LeftInt and \c RightInt are built-in integral types.
+
+ Returns \c {lhs <=> rhs}, provided \c LeftInt and \c RightInt are built-in
+ integral types. Unlike \c {operator<=>()}, this function template is also
+ available in C++17. See
+ \l {https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison}
+ {cppreference} for more details.
+
+ This function can also be used in custom \c {compareThreeWay()} functions,
+ when ordering members of a custom class represented by built-in types:
+
+ \code
+ class MyClass {
+ public:
+ ...
+ private:
+ int value;
+ ...
+ friend Qt::strong_ordering
+ compareThreeWay(const MyClass &lhs, const MyClass &rhs) noexcept
+ { return Qt::compareThreeWay(lhs.value, rhs.value); }
+ Q_DECLARE_STRONGLY_ORDERED(MyClass)
+ };
+ \endcode
+
+ Returns an instance of \l Qt::strong_ordering that represents the relation
+ between \a lhs and \a rhs.
+*/
+
+/*!
+ \fn template <typename LeftFloat, typename RightFloat, Qt::if_floating_point<LeftFloat> = true, Qt::if_floating_point<RightFloat> = true> auto Qt::compareThreeWay(LeftFloat lhs, RightFloat rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of floating point types.
+
+ \note This function participates in overload resolution only if both
+ \c LeftFloat and \c RightFloat are built-in floating-point types.
+
+ Returns \c {lhs <=> rhs}, provided \c LeftFloat and \c RightFloat are
+ built-in floating-point types. Unlike \c {operator<=>()}, this function
+ template is also available in C++17. See
+ \l {https://en.cppreference.com/w/cpp/language/operator_comparison#Three-way_comparison}
+ {cppreference} for more details.
+
+ This function can also be used in custom \c {compareThreeWay()} functions,
+ when ordering members of a custom class represented by built-in types:
+
+ \code
+ class MyClass {
+ public:
+ ...
+ private:
+ double value;
+ ...
+ friend Qt::partial_ordering
+ compareThreeWay(const MyClass &lhs, const MyClass &rhs) noexcept
+ { return Qt::compareThreeWay(lhs.value, rhs.value); }
+ Q_DECLARE_PARTIALLY_ORDERED(MyClass)
+ };
+ \endcode
+
+ Returns an instance of \l Qt::partial_ordering that represents the relation
+ between \a lhs and \a rhs. If \a lhs or \a rhs is not a number (NaN),
+ \l Qt::partial_ordering::unordered is returned.
+*/
+
+/*!
+ \fn template <typename IntType, typename FloatType, Qt::if_integral<IntType> = true, Qt::if_floating_point<FloatType> = true> auto Qt::compareThreeWay(IntType lhs, FloatType rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of integral and floating point types.
+
+ \note This function participates in overload resolution only if \c IntType
+ is a built-in integral type and \c FloatType is a built-in floating-point
+ type.
+
+ This function converts \a lhs to \c FloatType and calls the overload for
+ floating-point types.
+
+ Returns an instance of \l Qt::partial_ordering that represents the relation
+ between \a lhs and \a rhs. If \a rhs is not a number (NaN),
+ \l Qt::partial_ordering::unordered is returned.
+*/
+
+/*!
+ \fn template <typename FloatType, typename IntType, Qt::if_floating_point<FloatType> = true, Qt::if_integral<IntType> = true> auto Qt::compareThreeWay(FloatType lhs, IntType rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of floating point and integral types.
+
+ \note This function participates in overload resolution only if \c FloatType
+ is a built-in floating-point type and \c IntType is a built-in integral
+ type.
+
+ This function converts \a rhs to \c FloatType and calls the overload for
+ floating-point types.
+
+ Returns an instance of \l Qt::partial_ordering that represents the relation
+ between \a lhs and \a rhs. If \a lhs is not a number (NaN),
+ \l Qt::partial_ordering::unordered is returned.
+*/
+
+/*!
+ \fn template <typename LeftType, typename RightType, Qt::if_compatible_pointers<LeftType, RightType> = true> Qt::compareThreeWay(const LeftType *lhs, const RightType *rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of pointers.
+
+ \note This function participates in overload resolution if \c LeftType and
+ \c RightType are the same type, or base and derived types. It is also used
+ to compare any pointer to \c {std::nullptr_t}.
+
+ Returns an instance of \l Qt::strong_ordering that represents the relation
+ between \a lhs and \a rhs.
+*/
+
+/*!
+ \fn template <class Enum, Qt::if_enum<Enum> = true> Qt::compareThreeWay(Enum lhs, Enum rhs)
+ \since 6.7
+ \relates <QtCompare>
+ \overload
+
+ Implements three-way comparison of enum types.
+
+ \note This function participates in overload resolution only if \c Enum
+ is an enum type.
+
+ This function converts \c Enum to its underlying type and calls the
+ overload for integral types.
+
+ Returns an instance of \l Qt::strong_ordering that represents the relation
+ between \a lhs and \a rhs.
+*/
+
+/*!
+ \fn template <typename LeftType, typename RightType> qCompareThreeWay(const LeftType &lhs, const RightType &rhs)
+ \since 6.7
+ \relates <QtCompare>
+
+ Performs the three-way comparison on \a lhs and \a rhs and returns one of
+ the Qt ordering types as a result. This function is available for both
+ C++17 and C++20.
+
+ The actual returned type depends on \c LeftType and \c RightType.
+
+ \note This function template is only available when \c {compareThreeWay()}
+ is implemented for the \c {(LeftType, RightType)} pair or the reversed
+ \c {(RightType, LeftType)} pair.
+
+ This method is equivalent to
+
+ \code
+ using Qt::compareThreeWay;
+ return compareThreeWay(lhs, rhs);
+ \endcode
+
+ where \c {Qt::compareThreeWay} is the Qt implementation of three-way
+ comparison for built-in types.
+
+ The free \c {compareThreeWay} functions should provide three-way comparison
+ for custom types. The functions should return one of the Qt ordering types.
+
+ Qt provides \c {compareThreeWay} implementation for some of its types.
+
+ \note \b {Do not} re-implement \c {compareThreeWay()} for Qt types, as more
+ Qt types will get support for it in future Qt releases.
+
+ Use this function primarly in generic code, when you know nothing about
+ \c LeftType and \c RightType.
+
+ If you know the types, use
+
+ \list
+ \li \c {Qt::compareThreeWay} for built-in types
+ \li \c {compareThreeWay} for custom types
+ \endlist
+
+ Use \c {operator<=>()} directly in code that will only be compiled with
+ C++20 or later.
+
+ \sa Qt::partial_ordering, Qt::weak_ordering, Qt::strong_ordering
+*/
+
+QT_END_NAMESPACE
diff --git a/src/corelib/global/qcompare.h b/src/corelib/global/qcompare.h
index aa0e5eefa8..9dd244c8f9 100644
--- a/src/corelib/global/qcompare.h
+++ b/src/corelib/global/qcompare.h
@@ -1,4 +1,5 @@
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// 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
#ifndef QCOMPARE_H
@@ -11,6 +12,13 @@
#include <QtCore/qglobal.h>
#include <QtCore/qcompare_impl.h>
+#ifdef __cpp_lib_bit_cast
+#include <bit>
+#endif
+#ifdef __cpp_lib_three_way_comparison
+#include <compare>
+#endif
+
QT_BEGIN_NAMESPACE
namespace QtPrivate {
@@ -27,11 +35,645 @@ enum class Ordering : CompareUnderlyingType
enum class Uncomparable : CompareUnderlyingType
{
- Unordered = -127
+ Unordered =
+ #if defined(_LIBCPP_VERSION) // libc++
+ -127
+ #elif defined(__GLIBCXX__) // libstdc++
+ 2
+ #else // assume MSSTL
+ -128
+ #endif
};
} // namespace QtPrivate
+namespace QtOrderingPrivate {
+
+template <typename O>
+constexpr O reversed(O o) noexcept
+{
+ // https://eel.is/c++draft/cmp.partialord#5
+ return is_lt(o) ? O::greater :
+ is_gt(o) ? O::less :
+ /*else*/ o ;
+}
+
+} // namespace QtOrderingPrivate
+
+namespace Qt {
+
+class partial_ordering
+{
+public:
+ static const partial_ordering less;
+ static const partial_ordering equivalent;
+ static const partial_ordering greater;
+ static const partial_ordering unordered;
+
+ friend constexpr bool operator==(partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order == 0; }
+
+ friend constexpr bool operator!=(partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order != 0; }
+
+ friend constexpr bool operator< (partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order < 0; }
+
+ friend constexpr bool operator<=(partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order <= 0; }
+
+ friend constexpr bool operator> (partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order > 0; }
+
+ friend constexpr bool operator>=(partial_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order >= 0; }
+
+
+ friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 == rhs.m_order; }
+
+ friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 != rhs.m_order; }
+
+ friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 < rhs.m_order; }
+
+ friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 <= rhs.m_order; }
+
+ friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 > rhs.m_order; }
+
+ friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
+ partial_ordering rhs) noexcept
+ { return rhs.isOrdered() && 0 >= rhs.m_order; }
+
+
+#ifdef __cpp_lib_three_way_comparison
+ friend constexpr std::partial_ordering
+ operator<=>(partial_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs; } // https://eel.is/c++draft/cmp.partialord#4
+
+ friend constexpr std::partial_ordering
+ operator<=>(QtPrivate::CompareAgainstLiteralZero, partial_ordering rhs) noexcept
+ { return QtOrderingPrivate::reversed(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+
+ friend constexpr bool operator==(partial_ordering lhs, partial_ordering rhs) noexcept
+ { return lhs.m_order == rhs.m_order; }
+
+ friend constexpr bool operator!=(partial_ordering lhs, partial_ordering rhs) noexcept
+ { return lhs.m_order != rhs.m_order; }
+
+#ifdef __cpp_lib_three_way_comparison
+ constexpr Q_IMPLICIT partial_ordering(std::partial_ordering stdorder) noexcept
+ {
+ if (stdorder == std::partial_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (stdorder == std::partial_ordering::equivalent)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
+ else if (stdorder == std::partial_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ else if (stdorder == std::partial_ordering::unordered)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered);
+ }
+
+ constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept
+ {
+ static_assert(sizeof(*this) == sizeof(std::partial_ordering));
+#ifdef __cpp_lib_bit_cast
+ return std::bit_cast<std::partial_ordering>(*this);
+#else
+ using O = QtPrivate::Ordering;
+ using U = QtPrivate::Uncomparable;
+ using R = std::partial_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equivalent): return R::equivalent;
+ case qToUnderlying(U::Unordered): return R::unordered;
+ }
+ Q_UNREACHABLE_RETURN(R::unordered);
+#endif // __cpp_lib_bit_cast
+ }
+
+ friend constexpr bool operator==(partial_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(partial_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::partial_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(std::partial_ordering lhs, partial_ordering rhs) noexcept
+ { return lhs == static_cast<std::partial_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::partial_ordering lhs, partial_ordering rhs) noexcept
+ { return lhs != static_cast<std::partial_ordering>(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+private:
+ friend class weak_ordering;
+ friend class strong_ordering;
+
+ constexpr explicit partial_ordering(QtPrivate::Ordering order) noexcept
+ : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
+ {}
+ constexpr explicit partial_ordering(QtPrivate::Uncomparable order) noexcept
+ : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
+ {}
+
+ QT_WARNING_PUSH
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
+ QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
+ friend constexpr bool is_eq (partial_ordering o) noexcept { return o == 0; }
+ friend constexpr bool is_neq (partial_ordering o) noexcept { return o != 0; }
+ friend constexpr bool is_lt (partial_ordering o) noexcept { return o < 0; }
+ friend constexpr bool is_lteq(partial_ordering o) noexcept { return o <= 0; }
+ friend constexpr bool is_gt (partial_ordering o) noexcept { return o > 0; }
+ friend constexpr bool is_gteq(partial_ordering o) noexcept { return o >= 0; }
+ QT_WARNING_POP
+
+ // instead of the exposition only is_ordered member in [cmp.partialord],
+ // use a private function
+ constexpr bool isOrdered() const noexcept
+ { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); }
+
+ QtPrivate::CompareUnderlyingType m_order;
+};
+
+inline constexpr partial_ordering partial_ordering::less(QtPrivate::Ordering::Less);
+inline constexpr partial_ordering partial_ordering::equivalent(QtPrivate::Ordering::Equivalent);
+inline constexpr partial_ordering partial_ordering::greater(QtPrivate::Ordering::Greater);
+inline constexpr partial_ordering partial_ordering::unordered(QtPrivate::Uncomparable::Unordered);
+
+class weak_ordering
+{
+public:
+ static const weak_ordering less;
+ static const weak_ordering equivalent;
+ static const weak_ordering greater;
+
+ constexpr Q_IMPLICIT operator partial_ordering() const noexcept
+ { return partial_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
+
+ friend constexpr bool operator==(weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order == 0; }
+
+ friend constexpr bool operator!=(weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order != 0; }
+
+ friend constexpr bool operator< (weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order < 0; }
+
+ friend constexpr bool operator<=(weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order <= 0; }
+
+ friend constexpr bool operator> (weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order > 0; }
+
+ friend constexpr bool operator>=(weak_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order >= 0; }
+
+
+ friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 == rhs.m_order; }
+
+ friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 != rhs.m_order; }
+
+ friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 < rhs.m_order; }
+
+ friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 <= rhs.m_order; }
+
+ friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 > rhs.m_order; }
+
+ friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
+ weak_ordering rhs) noexcept
+ { return 0 >= rhs.m_order; }
+
+
+#ifdef __cpp_lib_three_way_comparison
+ friend constexpr std::weak_ordering
+ operator<=>(weak_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs; } // https://eel.is/c++draft/cmp.weakord#5
+
+ friend constexpr std::weak_ordering
+ operator<=>(QtPrivate::CompareAgainstLiteralZero, weak_ordering rhs) noexcept
+ { return QtOrderingPrivate::reversed(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+
+ friend constexpr bool operator==(weak_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs.m_order == rhs.m_order; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs.m_order != rhs.m_order; }
+
+ friend constexpr bool operator==(weak_ordering lhs, partial_ordering rhs) noexcept
+ { return static_cast<partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, partial_ordering rhs) noexcept
+ { return static_cast<partial_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(partial_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs == static_cast<partial_ordering>(rhs); }
+
+ friend constexpr bool operator!=(partial_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs != static_cast<partial_ordering>(rhs); }
+
+#ifdef __cpp_lib_three_way_comparison
+ constexpr Q_IMPLICIT weak_ordering(std::weak_ordering stdorder) noexcept
+ {
+ if (stdorder == std::weak_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (stdorder == std::weak_ordering::equivalent)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
+ else if (stdorder == std::weak_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ }
+
+ constexpr Q_IMPLICIT operator std::weak_ordering() const noexcept
+ {
+ static_assert(sizeof(*this) == sizeof(std::weak_ordering));
+#ifdef __cpp_lib_bit_cast
+ return std::bit_cast<std::weak_ordering>(*this);
+#else
+ using O = QtPrivate::Ordering;
+ using R = std::weak_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equivalent): return R::equivalent;
+ }
+ Q_UNREACHABLE_RETURN(R::equivalent);
+#endif // __cpp_lib_bit_cast
+ }
+
+ friend constexpr bool operator==(weak_ordering lhs, std::weak_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, std::weak_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(weak_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(weak_ordering lhs, std::strong_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(weak_ordering lhs, std::strong_ordering rhs) noexcept
+ { return static_cast<std::weak_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(std::weak_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs == static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::weak_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs != static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator==(std::partial_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs == static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::partial_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs != static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator==(std::strong_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs == static_cast<std::weak_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::strong_ordering lhs, weak_ordering rhs) noexcept
+ { return lhs != static_cast<std::weak_ordering>(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+private:
+ friend class strong_ordering;
+
+ constexpr explicit weak_ordering(QtPrivate::Ordering order) noexcept
+ : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
+ {}
+
+ QT_WARNING_PUSH
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
+ QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
+ friend constexpr bool is_eq (weak_ordering o) noexcept { return o == 0; }
+ friend constexpr bool is_neq (weak_ordering o) noexcept { return o != 0; }
+ friend constexpr bool is_lt (weak_ordering o) noexcept { return o < 0; }
+ friend constexpr bool is_lteq(weak_ordering o) noexcept { return o <= 0; }
+ friend constexpr bool is_gt (weak_ordering o) noexcept { return o > 0; }
+ friend constexpr bool is_gteq(weak_ordering o) noexcept { return o >= 0; }
+ QT_WARNING_POP
+
+ QtPrivate::CompareUnderlyingType m_order;
+};
+
+inline constexpr weak_ordering weak_ordering::less(QtPrivate::Ordering::Less);
+inline constexpr weak_ordering weak_ordering::equivalent(QtPrivate::Ordering::Equivalent);
+inline constexpr weak_ordering weak_ordering::greater(QtPrivate::Ordering::Greater);
+
+class strong_ordering
+{
+public:
+ static const strong_ordering less;
+ static const strong_ordering equivalent;
+ static const strong_ordering equal;
+ static const strong_ordering greater;
+
+ constexpr Q_IMPLICIT operator partial_ordering() const noexcept
+ { return partial_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
+
+ constexpr Q_IMPLICIT operator weak_ordering() const noexcept
+ { return weak_ordering(static_cast<QtPrivate::Ordering>(m_order)); }
+
+ friend constexpr bool operator==(strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order == 0; }
+
+ friend constexpr bool operator!=(strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order != 0; }
+
+ friend constexpr bool operator< (strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order < 0; }
+
+ friend constexpr bool operator<=(strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order <= 0; }
+
+ friend constexpr bool operator> (strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order > 0; }
+
+ friend constexpr bool operator>=(strong_ordering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.m_order >= 0; }
+
+
+ friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 == rhs.m_order; }
+
+ friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 != rhs.m_order; }
+
+ friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 < rhs.m_order; }
+
+ friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 <= rhs.m_order; }
+
+ friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 > rhs.m_order; }
+
+ friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
+ strong_ordering rhs) noexcept
+ { return 0 >= rhs.m_order; }
+
+
+#ifdef __cpp_lib_three_way_comparison
+ friend constexpr std::strong_ordering
+ operator<=>(strong_ordering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs; } // https://eel.is/c++draft/cmp.strongord#6
+
+ friend constexpr std::strong_ordering
+ operator<=>(QtPrivate::CompareAgainstLiteralZero, strong_ordering rhs) noexcept
+ { return QtOrderingPrivate::reversed(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+
+ friend constexpr bool operator==(strong_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs.m_order == rhs.m_order; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs.m_order != rhs.m_order; }
+
+ friend constexpr bool operator==(strong_ordering lhs, partial_ordering rhs) noexcept
+ { return static_cast<partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, partial_ordering rhs) noexcept
+ { return static_cast<partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator==(partial_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<partial_ordering>(rhs); }
+
+ friend constexpr bool operator!=(partial_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<partial_ordering>(rhs); }
+
+ friend constexpr bool operator==(strong_ordering lhs, weak_ordering rhs) noexcept
+ { return static_cast<weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, weak_ordering rhs) noexcept
+ { return static_cast<weak_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator==(weak_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<weak_ordering>(rhs); }
+
+ friend constexpr bool operator!=(weak_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<weak_ordering>(rhs); }
+
+#ifdef __cpp_lib_three_way_comparison
+ constexpr Q_IMPLICIT strong_ordering(std::strong_ordering stdorder) noexcept
+ {
+ if (stdorder == std::strong_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (stdorder == std::strong_ordering::equivalent)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
+ else if (stdorder == std::strong_ordering::equal)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equal);
+ else if (stdorder == std::strong_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ }
+
+ constexpr Q_IMPLICIT operator std::strong_ordering() const noexcept
+ {
+ static_assert(sizeof(*this) == sizeof(std::strong_ordering));
+#ifdef __cpp_lib_bit_cast
+ return std::bit_cast<std::strong_ordering>(*this);
+#else
+ using O = QtPrivate::Ordering;
+ using R = std::strong_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equal): return R::equal;
+ }
+ Q_UNREACHABLE_RETURN(R::equal);
+#endif // __cpp_lib_bit_cast
+ }
+
+ friend constexpr bool operator==(strong_ordering lhs, std::strong_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, std::strong_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(strong_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(strong_ordering lhs, std::weak_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(strong_ordering lhs, std::weak_ordering rhs) noexcept
+ { return static_cast<std::strong_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(std::strong_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::strong_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator==(std::partial_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::partial_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator==(std::weak_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs == static_cast<std::strong_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::weak_ordering lhs, strong_ordering rhs) noexcept
+ { return lhs != static_cast<std::strong_ordering>(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+ private:
+ constexpr explicit strong_ordering(QtPrivate::Ordering order) noexcept
+ : m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
+ {}
+
+ QT_WARNING_PUSH
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
+ QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
+ friend constexpr bool is_eq (strong_ordering o) noexcept { return o == 0; }
+ friend constexpr bool is_neq (strong_ordering o) noexcept { return o != 0; }
+ friend constexpr bool is_lt (strong_ordering o) noexcept { return o < 0; }
+ friend constexpr bool is_lteq(strong_ordering o) noexcept { return o <= 0; }
+ friend constexpr bool is_gt (strong_ordering o) noexcept { return o > 0; }
+ friend constexpr bool is_gteq(strong_ordering o) noexcept { return o >= 0; }
+ QT_WARNING_POP
+
+ QtPrivate::CompareUnderlyingType m_order;
+};
+
+inline constexpr strong_ordering strong_ordering::less(QtPrivate::Ordering::Less);
+inline constexpr strong_ordering strong_ordering::equivalent(QtPrivate::Ordering::Equivalent);
+inline constexpr strong_ordering strong_ordering::equal(QtPrivate::Ordering::Equal);
+inline constexpr strong_ordering strong_ordering::greater(QtPrivate::Ordering::Greater);
+
+} // namespace Qt
+
+QT_BEGIN_INCLUDE_NAMESPACE
+
+// This is intentionally included after Qt::*_ordering types and before
+// qCompareThreeWay. Do not change!
+#include <QtCore/qcomparehelpers.h>
+
+QT_END_INCLUDE_NAMESPACE
+
+namespace QtPrivate {
+
+namespace CompareThreeWayTester {
+
+ using Qt::compareThreeWay;
+
+ // Check if compareThreeWay is implemented for the (LT, RT) argument
+ // pair.
+ template <typename LT, typename RT, typename = void>
+ constexpr bool hasCompareThreeWay = false;
+
+ template <typename LT, typename RT>
+ constexpr bool hasCompareThreeWay<
+ LT, RT, std::void_t<decltype(compareThreeWay(std::declval<LT>(), std::declval<RT>()))>
+ > = true;
+
+ // Check if the operation is noexcept. We have two different overloads,
+ // depending on the available compareThreeWay() implementation.
+ // Both are declared, but not implemented. To be used only in unevaluated
+ // context.
+
+ template <typename LT, typename RT,
+ std::enable_if_t<hasCompareThreeWay<LT, RT>, bool> = true>
+ constexpr bool compareThreeWayNoexcept() noexcept
+ { return noexcept(compareThreeWay(std::declval<LT>(), std::declval<RT>())); }
+
+ template <typename LT, typename RT,
+ std::enable_if_t<!hasCompareThreeWay<LT, RT> && hasCompareThreeWay<RT, LT>,
+ bool> = true>
+ constexpr bool compareThreeWayNoexcept() noexcept
+ { return noexcept(compareThreeWay(std::declval<RT>(), std::declval<LT>())); }
+
+} // namespace CompareThreeWayTester
+
+} // namespace QtPrivate
+
+#if defined(Q_QDOC)
+
+template <typename LeftType, typename RightType>
+auto qCompareThreeWay(const LeftType &lhs, const RightType &rhs);
+
+#else
+
+template <typename LT, typename RT,
+ std::enable_if_t<QtPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT>
+ || QtPrivate::CompareThreeWayTester::hasCompareThreeWay<RT, LT>,
+ bool> = true>
+auto qCompareThreeWay(const LT &lhs, const RT &rhs)
+ noexcept(QtPrivate::CompareThreeWayTester::compareThreeWayNoexcept<LT, RT>())
+{
+ using Qt::compareThreeWay;
+ if constexpr (QtPrivate::CompareThreeWayTester::hasCompareThreeWay<LT, RT>) {
+ return compareThreeWay(lhs, rhs);
+ } else {
+ const auto retval = compareThreeWay(rhs, lhs);
+ return QtOrderingPrivate::reversed(retval);
+ }
+}
+
+#endif // defined(Q_QDOC)
+
+//
+// Legacy QPartialOrdering
+//
+
+namespace QtPrivate {
+enum class LegacyUncomparable : CompareUnderlyingType
+{
+ Unordered = -127
+};
+}
+
// [cmp.partialord]
class QPartialOrdering
{
@@ -41,49 +683,195 @@ public:
static const QPartialOrdering Greater;
static const QPartialOrdering Unordered;
- friend constexpr bool operator==(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order == 0; }
- friend constexpr bool operator!=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order != 0; }
- friend constexpr bool operator< (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order < 0; }
- friend constexpr bool operator<=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order <= 0; }
- friend constexpr bool operator> (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order > 0; }
- friend constexpr bool operator>=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- { return p.isOrdered() && p.m_order >= 0; }
-
- friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 == p.m_order; }
- friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 != p.m_order; }
- friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 < p.m_order; }
- friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 <= p.m_order; }
- friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 > p.m_order; }
- friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- { return p.isOrdered() && 0 >= p.m_order; }
-
- friend constexpr bool operator==(QPartialOrdering p1, QPartialOrdering p2) noexcept
- { return p1.m_order == p2.m_order; }
- friend constexpr bool operator!=(QPartialOrdering p1, QPartialOrdering p2) noexcept
- { return p1.m_order != p2.m_order; }
+ static const QPartialOrdering less;
+ static const QPartialOrdering equivalent;
+ static const QPartialOrdering greater;
+ static const QPartialOrdering unordered;
+
+ friend constexpr bool operator==(QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order == 0; }
+
+ friend constexpr bool operator!=(QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order != 0; }
+
+ friend constexpr bool operator< (QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order < 0; }
+
+ friend constexpr bool operator<=(QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order <= 0; }
+
+ friend constexpr bool operator> (QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order > 0; }
+
+ friend constexpr bool operator>=(QPartialOrdering lhs,
+ QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs.isOrdered() && lhs.m_order >= 0; }
+
+
+ friend constexpr bool operator==(QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 == rhs.m_order; }
+
+ friend constexpr bool operator!=(QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 != rhs.m_order; }
+
+ friend constexpr bool operator< (QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 < rhs.m_order; }
+
+ friend constexpr bool operator<=(QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 <= rhs.m_order; }
+
+ friend constexpr bool operator> (QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 > rhs.m_order; }
+
+ friend constexpr bool operator>=(QtPrivate::CompareAgainstLiteralZero,
+ QPartialOrdering rhs) noexcept
+ { return rhs.isOrdered() && 0 >= rhs.m_order; }
+
+
+#ifdef __cpp_lib_three_way_comparison
+ friend constexpr std::partial_ordering
+ operator<=>(QPartialOrdering lhs, QtPrivate::CompareAgainstLiteralZero) noexcept
+ { return lhs; } // https://eel.is/c++draft/cmp.partialord#4
+
+ friend constexpr std::partial_ordering
+ operator<=>(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering rhs) noexcept
+ { return QtOrderingPrivate::reversed(rhs); }
+#endif // __cpp_lib_three_way_comparison
+
+
+ friend constexpr bool operator==(QPartialOrdering lhs, QPartialOrdering rhs) noexcept
+ { return lhs.m_order == rhs.m_order; }
+
+ friend constexpr bool operator!=(QPartialOrdering lhs, QPartialOrdering rhs) noexcept
+ { return lhs.m_order != rhs.m_order; }
+
+ constexpr Q_IMPLICIT QPartialOrdering(Qt::partial_ordering order) noexcept
+ : m_order{} // == equivalent
+ {
+ if (order == Qt::partial_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (order == Qt::partial_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ else if (order == Qt::partial_ordering::unordered)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered);
+ }
+
+ constexpr Q_IMPLICIT QPartialOrdering(Qt::weak_ordering stdorder) noexcept
+ : QPartialOrdering(Qt::partial_ordering{stdorder}) {}
+
+ constexpr Q_IMPLICIT QPartialOrdering(Qt::strong_ordering stdorder) noexcept
+ : QPartialOrdering(Qt::partial_ordering{stdorder}) {}
+
+ constexpr Q_IMPLICIT operator Qt::partial_ordering() const noexcept
+ {
+ using O = QtPrivate::Ordering;
+ using U = QtPrivate::LegacyUncomparable;
+ using R = Qt::partial_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equivalent): return R::equivalent;
+ case qToUnderlying(U::Unordered): return R::unordered;
+ }
+ // GCC 8.x does not treat __builtin_unreachable() as constexpr
+#if !defined(Q_CC_GNU_ONLY) || (Q_CC_GNU >= 900)
+ // NOLINTNEXTLINE(qt-use-unreachable-return): Triggers on Clang, breaking GCC 8
+ Q_UNREACHABLE();
+#endif
+ return R::unordered;
+ }
+
+ friend constexpr bool operator==(QPartialOrdering lhs, Qt::partial_ordering rhs) noexcept
+ { Qt::partial_ordering qt = lhs; return qt == rhs; }
+
+ friend constexpr bool operator!=(QPartialOrdering lhs, Qt::partial_ordering rhs) noexcept
+ { Qt::partial_ordering qt = lhs; return qt != rhs; }
+
+ friend constexpr bool operator==(Qt::partial_ordering lhs, QPartialOrdering rhs) noexcept
+ { Qt::partial_ordering qt = rhs; return lhs == qt; }
+
+ friend constexpr bool operator!=(Qt::partial_ordering lhs, QPartialOrdering rhs) noexcept
+ { Qt::partial_ordering qt = rhs; return lhs != qt; }
+
+#ifdef __cpp_lib_three_way_comparison
+ constexpr Q_IMPLICIT QPartialOrdering(std::partial_ordering stdorder) noexcept
+ {
+ if (stdorder == std::partial_ordering::less)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Less);
+ else if (stdorder == std::partial_ordering::equivalent)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Equivalent);
+ else if (stdorder == std::partial_ordering::greater)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Ordering::Greater);
+ else if (stdorder == std::partial_ordering::unordered)
+ m_order = static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered);
+ }
+
+ constexpr Q_IMPLICIT QPartialOrdering(std::weak_ordering stdorder) noexcept
+ : QPartialOrdering(std::partial_ordering(stdorder)) {}
+
+ constexpr Q_IMPLICIT QPartialOrdering(std::strong_ordering stdorder) noexcept
+ : QPartialOrdering(std::partial_ordering(stdorder)) {}
+
+ constexpr Q_IMPLICIT operator std::partial_ordering() const noexcept
+ {
+ using O = QtPrivate::Ordering;
+ using U = QtPrivate::LegacyUncomparable;
+ using R = std::partial_ordering;
+ switch (m_order) {
+ case qToUnderlying(O::Less): return R::less;
+ case qToUnderlying(O::Greater): return R::greater;
+ case qToUnderlying(O::Equivalent): return R::equivalent;
+ case qToUnderlying(U::Unordered): return R::unordered;
+ }
+ Q_UNREACHABLE_RETURN(R::unordered);
+ }
+
+ friend constexpr bool operator==(QPartialOrdering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::partial_ordering>(lhs) == rhs; }
+
+ friend constexpr bool operator!=(QPartialOrdering lhs, std::partial_ordering rhs) noexcept
+ { return static_cast<std::partial_ordering>(lhs) != rhs; }
+
+ friend constexpr bool operator==(std::partial_ordering lhs, QPartialOrdering rhs) noexcept
+ { return lhs == static_cast<std::partial_ordering>(rhs); }
+
+ friend constexpr bool operator!=(std::partial_ordering lhs, QPartialOrdering rhs) noexcept
+ { return lhs != static_cast<std::partial_ordering>(rhs); }
+#endif // __cpp_lib_three_way_comparison
private:
constexpr explicit QPartialOrdering(QtPrivate::Ordering order) noexcept
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
{}
- constexpr explicit QPartialOrdering(QtPrivate::Uncomparable order) noexcept
+ constexpr explicit QPartialOrdering(QtPrivate::LegacyUncomparable order) noexcept
: m_order(static_cast<QtPrivate::CompareUnderlyingType>(order))
{}
+ QT_WARNING_PUSH
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=100903
+ QT_WARNING_DISABLE_GCC("-Wzero-as-null-pointer-constant")
+ friend constexpr bool is_eq (QPartialOrdering o) noexcept { return o == 0; }
+ friend constexpr bool is_neq (QPartialOrdering o) noexcept { return o != 0; }
+ friend constexpr bool is_lt (QPartialOrdering o) noexcept { return o < 0; }
+ friend constexpr bool is_lteq(QPartialOrdering o) noexcept { return o <= 0; }
+ friend constexpr bool is_gt (QPartialOrdering o) noexcept { return o > 0; }
+ friend constexpr bool is_gteq(QPartialOrdering o) noexcept { return o >= 0; }
+ QT_WARNING_POP
+
// instead of the exposition only is_ordered member in [cmp.partialord],
// use a private function
- constexpr bool isOrdered() noexcept
- { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::Uncomparable::Unordered); }
+ constexpr bool isOrdered() const noexcept
+ { return m_order != static_cast<QtPrivate::CompareUnderlyingType>(QtPrivate::LegacyUncomparable::Unordered); }
QtPrivate::CompareUnderlyingType m_order;
};
@@ -91,7 +879,12 @@ private:
inline constexpr QPartialOrdering QPartialOrdering::Less(QtPrivate::Ordering::Less);
inline constexpr QPartialOrdering QPartialOrdering::Equivalent(QtPrivate::Ordering::Equivalent);
inline constexpr QPartialOrdering QPartialOrdering::Greater(QtPrivate::Ordering::Greater);
-inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::Uncomparable::Unordered);
+inline constexpr QPartialOrdering QPartialOrdering::Unordered(QtPrivate::LegacyUncomparable::Unordered);
+
+inline constexpr QPartialOrdering QPartialOrdering::less(QtPrivate::Ordering::Less);
+inline constexpr QPartialOrdering QPartialOrdering::equivalent(QtPrivate::Ordering::Equivalent);
+inline constexpr QPartialOrdering QPartialOrdering::greater(QtPrivate::Ordering::Greater);
+inline constexpr QPartialOrdering QPartialOrdering::unordered(QtPrivate::LegacyUncomparable::Unordered);
QT_END_NAMESPACE
diff --git a/src/corelib/global/qcompare.qdoc b/src/corelib/global/qcompare.qdoc
deleted file mode 100644
index e822f40490..0000000000
--- a/src/corelib/global/qcompare.qdoc
+++ /dev/null
@@ -1,113 +0,0 @@
-// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-
-/*!
- \class QPartialOrdering
- \inmodule QtCore
- \brief QPartialOrdering represents the result of a comparison that allows for unordered results.
- \since 6.0
-
- A value of type QPartialOrdering is typically returned from a
- three-way comparison function. Such a function compares two
- objects, and it may either establish that the two objects are
- ordered relative to each other, or that they are not ordered. The
- QPartialOrdering value returned from the comparison function
- represents one of those possibilities.
-
- The possible values of type QPartialOrdering are, in fact, fully
- represented by the following four static values:
-
- \list
-
- \li \c QPartialOrdering::Less represents that the first object is
- less than the second;
-
- \li \c QPartialOrdering::Equivalent represents that the first
- object is equivalent to the second;
-
- \li \c QPartialOrdering::Greater represents that the first object
- is equivalent to the second;
-
- \li \c QPartialOrdering::Unordered represents that the first object
- is \e{not ordered} with respect to the second.
-
- \endlist
-
- QPartialOrdering is idiomatically used by comparing an instance
- against a literal zero, for instance like this:
-
- \code
-
- // given a, b, c, d as objects of some type that allows for a 3-way compare
-
- QPartialOrdering result = a.compare(b);
- if (result < 0) {
- // a is less than b
- }
-
- if (c.compare(d) >= 0) {
- // c is greater than or equal to d
- }
-
- \endcode
-
- A QPartialOrdering value which represents an unordered result will
- always return false when compared against literal 0.
-*/
-
-/*!
- \fn bool QPartialOrdering::operator==(QPartialOrdering p1, QPartialOrdering p2) noexcept
-
- Return true if \a p1 and \a p2 represent the same result;
- otherwise, returns false.
-*/
-
-/*!
- \fn bool QPartialOrdering::operator!=(QPartialOrdering p1, QPartialOrdering p2) noexcept
-
- Return true if \a p1 and \a p2 represent different results;
- otherwise, returns true.
-*/
-
-/*!
- \fn bool operator==(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator!=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator< (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator<=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator> (QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
- \fn bool operator>=(QPartialOrdering p, QtPrivate::CompareAgainstLiteralZero) noexcept
-
- \fn bool operator==(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator!=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator< (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator<=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator> (QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \fn bool operator>=(QtPrivate::CompareAgainstLiteralZero, QPartialOrdering p) noexcept
- \relates QPartialOrdering
- \internal
-*/
-
-/*!
- \variable QPartialOrdering::Less
- Represents the result of a comparison where the value on the left
- hand side is less than the value on right hand side.
-*/
-
-/*!
- \variable QPartialOrdering::Equivalent
- Represents the result of a comparison where the value on the left
- hand side is equivalent to the value on right hand side.
-*/
-
-/*!
- \variable QPartialOrdering::Greater
- Represents the result of a comparison where the value on the left
- hand side is greater than the value on right hand side.
-*/
-
-/*!
- \variable QPartialOrdering::Unordered
- Represents the result of a comparison where the value on the left
- hand side is not ordered with respect to the value on right hand
- side.
-*/
diff --git a/src/corelib/global/qcompare_impl.h b/src/corelib/global/qcompare_impl.h
index a2670a2b49..c52417fcec 100644
--- a/src/corelib/global/qcompare_impl.h
+++ b/src/corelib/global/qcompare_impl.h
@@ -1,15 +1,16 @@
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#ifndef QCOMPARE_IMPL_H
+#define QCOMPARE_IMPL_H
+
#if 0
#pragma qt_sync_skip_header_check
#pragma qt_sync_stop_processing
#endif
-#ifndef QCOMPARE_IMPL_H
-#define QCOMPARE_IMPL_H
-
-#include <QtCore/qglobal.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qcompilerdetection.h>
QT_BEGIN_NAMESPACE
@@ -22,7 +23,7 @@ public:
using SafeZero = void (CompareAgainstLiteralZero::*)();
Q_IMPLICIT constexpr CompareAgainstLiteralZero(SafeZero) noexcept {}
- template <typename T, std::enable_if_t<!std::is_same_v<T, int>, bool> = false>
+ template <typename T, std::enable_if_t<std::is_null_pointer_v<T>, bool> = true>
CompareAgainstLiteralZero(T) = delete;
};
diff --git a/src/corelib/global/qcomparehelpers.h b/src/corelib/global/qcomparehelpers.h
new file mode 100644
index 0000000000..0e43ac296b
--- /dev/null
+++ b/src/corelib/global/qcomparehelpers.h
@@ -0,0 +1,567 @@
+// 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
+
+#ifndef QCOMPARE_H
+#error "Do not include qcomparehelpers.h directly. Use qcompare.h instead."
+#endif
+
+#ifndef QCOMPAREHELPERS_H
+#define QCOMPAREHELPERS_H
+
+#if 0
+#pragma qt_no_master_include
+#pragma qt_sync_skip_header_check
+#pragma qt_sync_stop_processing
+#endif
+
+#include <QtCore/qoverload.h>
+#include <QtCore/qttypetraits.h>
+#include <QtCore/qtypes.h>
+
+#ifdef __cpp_lib_three_way_comparison
+#include <compare>
+#endif
+#include <QtCore/q20type_traits.h>
+
+#include <functional> // std::less
+
+QT_BEGIN_NAMESPACE
+
+class QPartialOrdering;
+
+namespace QtOrderingPrivate {
+#ifdef __cpp_lib_three_way_comparison
+
+template <typename QtOrdering> struct StdOrdering;
+template <typename StdOrdering> struct QtOrdering;
+
+#define QT_STD_MAP(x) \
+ template <> struct StdOrdering< Qt::x##_ordering> : q20::type_identity<std::x##_ordering> {};\
+ template <> struct StdOrdering<std::x##_ordering> : q20::type_identity<std::x##_ordering> {};\
+ template <> struct QtOrdering<std::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\
+ template <> struct QtOrdering< Qt::x##_ordering> : q20::type_identity< Qt::x##_ordering> {};\
+ /* end */
+QT_STD_MAP(partial)
+QT_STD_MAP(weak)
+QT_STD_MAP(strong)
+#undef QT_STD_MAP
+
+template <> struct StdOrdering<QPartialOrdering> : q20::type_identity<std::partial_ordering> {};
+template <> struct QtOrdering<QPartialOrdering> : q20::type_identity< Qt::partial_ordering> {};
+
+template <typename In> constexpr auto to_std(In in) noexcept
+ -> typename QtOrderingPrivate::StdOrdering<In>::type
+{ return in; }
+
+template <typename In> constexpr auto to_Qt(In in) noexcept
+ -> typename QtOrderingPrivate::QtOrdering<In>::type
+{ return in; }
+
+#endif // __cpp_lib_three_way_comparison
+} // namespace QtOrderingPrivate
+
+/*
+ For all the macros these parameter names are used:
+ * LeftType - the type of the left operand of the comparison
+ * RightType - the type of the right operand of the comparison
+ * Constexpr - must be either constexpr or empty. Defines whether the
+ operator is constexpr or not
+ * Attributes - an optional list of attributes. For example, pass
+ \c QT_ASCII_CAST_WARN when defining comparisons between
+ C-style string and an encoding-aware string type.
+
+ The macros require two helper functions. For operators to be constexpr,
+ these must be constexpr, too. Additionally, other attributes (like
+ Q_<Module>_EXPORT, Q_DECL_CONST_FUNCTION, etc) can be applied to them.
+ Aside from that, their declaration should match:
+ bool comparesEqual(LeftType, RightType) noexcept;
+ ReturnType compareThreeWay(LeftType, RightType) noexcept;
+
+ The ReturnType can be one of Qt::{partial,weak,strong}_ordering. The actual
+ type depends on the macro being used.
+ It makes sense to define the helper functions as hidden friends of the
+ class, so that they could be found via ADL, and don't participate in
+ unintended implicit conversions.
+*/
+
+// Seems that qdoc uses C++20 even when Qt is compiled in C++17 mode.
+// Or at least it defines __cpp_lib_three_way_comparison.
+// Let qdoc see only the C++17 operators for now, because that's what our docs
+// currently describe.
+#if defined(__cpp_lib_three_way_comparison) && !defined(Q_QDOC)
+// C++20 - provide operator==() for equality, and operator<=>() for ordering
+
+#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(comparesEqual(lhs, rhs))) \
+ { return comparesEqual(lhs, rhs); }
+
+#define QT_DECLARE_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::strong_ordering \
+ operator<=>(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { \
+ return compareThreeWay(lhs, rhs); \
+ }
+
+#define QT_DECLARE_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::weak_ordering \
+ operator<=>(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { \
+ return compareThreeWay(lhs, rhs); \
+ }
+
+#define QT_DECLARE_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::partial_ordering \
+ operator<=>(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { \
+ return compareThreeWay(lhs, rhs); \
+ }
+
+#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingType, LeftType, RightType, Constexpr, \
+ Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_3WAY_HELPER_ ## OrderingType (LeftType, RightType, Constexpr, Attributes)
+
+#ifdef Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
+
+// define reversed versions of the operators manually, because buggy MSVC versions do not do it
+#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(comparesEqual(rhs, lhs))) \
+ { return comparesEqual(rhs, lhs); }
+
+#define QT_DECLARE_REVERSED_3WAY_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::strong_ordering \
+ operator<=>(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { \
+ const auto r = compareThreeWay(rhs, lhs); \
+ if (r > 0) return std::strong_ordering::less; \
+ if (r < 0) return std::strong_ordering::greater; \
+ return r; \
+ }
+
+#define QT_DECLARE_REVERSED_3WAY_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::weak_ordering \
+ operator<=>(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { \
+ const auto r = compareThreeWay(rhs, lhs); \
+ if (r > 0) return std::weak_ordering::less; \
+ if (r < 0) return std::weak_ordering::greater; \
+ return r; \
+ }
+
+#define QT_DECLARE_REVERSED_3WAY_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr std::partial_ordering \
+ operator<=>(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { \
+ const auto r = compareThreeWay(rhs, lhs); \
+ if (r > 0) return std::partial_ordering::less; \
+ if (r < 0) return std::partial_ordering::greater; \
+ return r; \
+ }
+
+#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
+ Constexpr, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_3WAY_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, Attributes)
+
+#else
+
+// dummy macros for C++17 compatibility, reversed operators are generated by the compiler
+#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes)
+#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
+ Constexpr, Attributes)
+
+#endif // Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
+
+#else
+// C++17 - provide operator==() and operator!=() for equality,
+// and all 4 comparison operators for ordering
+
+#define QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr bool operator==(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(comparesEqual(lhs, rhs))) \
+ { return comparesEqual(lhs, rhs); } \
+ Attributes \
+ friend Constexpr bool operator!=(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(comparesEqual(lhs, rhs))) \
+ { return !comparesEqual(lhs, rhs); }
+
+// Helpers for reversed comparison, using the existing comparesEqual() function.
+#define QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ Attributes \
+ friend Constexpr bool operator==(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(comparesEqual(rhs, lhs))) \
+ { return comparesEqual(rhs, lhs); } \
+ Attributes \
+ friend Constexpr bool operator!=(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(comparesEqual(rhs, lhs))) \
+ { return !comparesEqual(rhs, lhs); }
+
+#define QT_DECLARE_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr, \
+ Attributes) \
+ Attributes \
+ friend Constexpr bool operator<(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { return compareThreeWay(lhs, rhs) < 0; } \
+ Attributes \
+ friend Constexpr bool operator>(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { return compareThreeWay(lhs, rhs) > 0; } \
+ Attributes \
+ friend Constexpr bool operator<=(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { return compareThreeWay(lhs, rhs) <= 0; } \
+ Attributes \
+ friend Constexpr bool operator>=(LeftType const &lhs, RightType const &rhs) \
+ noexcept(noexcept(compareThreeWay(lhs, rhs))) \
+ { return compareThreeWay(lhs, rhs) >= 0; }
+
+#define QT_DECLARE_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, Constexpr, \
+ Attributes)
+
+#define QT_DECLARE_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, Constexpr, \
+ Attributes)
+
+#define QT_DECLARE_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, Constexpr, \
+ Attributes)
+
+#define QT_DECLARE_ORDERING_OPERATORS_HELPER(OrderingString, LeftType, RightType, Constexpr, \
+ Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, Attributes)
+
+// Helpers for reversed ordering, using the existing compareThreeWay() function.
+#define QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(OrderingType, LeftType, RightType, Constexpr, \
+ Attributes) \
+ Attributes \
+ friend Constexpr bool operator<(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { return compareThreeWay(rhs, lhs) > 0; } \
+ Attributes \
+ friend Constexpr bool operator>(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { return compareThreeWay(rhs, lhs) < 0; } \
+ Attributes \
+ friend Constexpr bool operator<=(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { return compareThreeWay(rhs, lhs) >= 0; } \
+ Attributes \
+ friend Constexpr bool operator>=(RightType const &lhs, LeftType const &rhs) \
+ noexcept(noexcept(compareThreeWay(rhs, lhs))) \
+ { return compareThreeWay(rhs, lhs) <= 0; }
+
+#define QT_DECLARE_REVERSED_ORDERING_HELPER_PARTIAL(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::partial_ordering, LeftType, RightType, \
+ Constexpr, Attributes)
+
+#define QT_DECLARE_REVERSED_ORDERING_HELPER_WEAK(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::weak_ordering, LeftType, RightType, \
+ Constexpr, Attributes)
+
+#define QT_DECLARE_REVERSED_ORDERING_HELPER_STRONG(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_ORDERING_HELPER_TEMPLATE(Qt::strong_ordering, LeftType, RightType, \
+ Constexpr, Attributes)
+
+#define QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(OrderingString, LeftType, RightType, \
+ Constexpr, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, Constexpr, Attributes) \
+ QT_DECLARE_REVERSED_ORDERING_HELPER_ ## OrderingString (LeftType, RightType, Constexpr, \
+ Attributes)
+
+#endif // __cpp_lib_three_way_comparison
+
+/* Public API starts here */
+
+// Equality operators
+#define QT_DECLARE_EQUALITY_COMPARABLE_1(Type) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, /* non-constexpr */, /* no attributes */)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_2(LeftType, RightType) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, /* non-constexpr */, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, /* non-constexpr */, \
+ Attributes)
+
+#define Q_DECLARE_EQUALITY_COMPARABLE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE, __VA_ARGS__)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_1(Type) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(Type, Type, constexpr, /* no attributes */)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_2(LeftType, RightType) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr, /* no attributes */) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr, \
+ /* no attributes */)
+
+#define QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_HELPER(LeftType, RightType, constexpr, Attributes) \
+ QT_DECLARE_EQUALITY_OPERATORS_REVERSED_HELPER(LeftType, RightType, constexpr, Attributes)
+
+#define Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE, __VA_ARGS__)
+
+// Partial ordering operators
+#define QT_DECLARE_PARTIALLY_ORDERED_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, /* non-constexpr */, \
+ /* no attributes */)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
+ /* non-constexpr */, /* no attributes */)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, /* non-constexpr */, \
+ Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, \
+ /* non-constexpr */, Attributes)
+
+#define Q_DECLARE_PARTIALLY_ORDERED(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED, __VA_ARGS__)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, Type, Type, constexpr, /* no attributes */)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr, \
+ /* no attributes */)
+
+#define QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(PARTIAL, LeftType, RightType, constexpr, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(PARTIAL, LeftType, RightType, constexpr, \
+ Attributes)
+
+#define Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
+
+// Weak ordering operators
+#define QT_DECLARE_WEAKLY_ORDERED_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, /* non-constexpr */, /* no attributes */)
+
+#define QT_DECLARE_WEAKLY_ORDERED_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */)
+
+#define QT_DECLARE_WEAKLY_ORDERED_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
+ Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, /* non-constexpr */, \
+ Attributes)
+
+#define Q_DECLARE_WEAKLY_ORDERED(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED, __VA_ARGS__)
+
+#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, Type, Type, constexpr, /* no attributes */)
+
+#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr, \
+ /* no attributes */)
+
+#define QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
+QT_DECLARE_ORDERING_OPERATORS_HELPER(WEAK, LeftType, RightType, constexpr, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(WEAK, LeftType, RightType, constexpr, \
+ Attributes)
+
+#define Q_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_WEAKLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
+
+// Strong ordering operators
+#define QT_DECLARE_STRONGLY_ORDERED_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, /* non-constexpr */, \
+ /* no attributes */)
+
+#define QT_DECLARE_STRONGLY_ORDERED_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
+ /* non-constexpr */, /* no attributes */)
+
+#define QT_DECLARE_STRONGLY_ORDERED_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, /* non-constexpr */, \
+ Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, \
+ /* non-constexpr */, Attributes)
+
+#define Q_DECLARE_STRONGLY_ORDERED(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED, __VA_ARGS__)
+
+#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_1(Type) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, Type, Type, constexpr, /* no attributes */)
+
+#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_2(LeftType, RightType) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr, \
+ /* no attributes */) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr, \
+ /* no attributes */)
+
+#define QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE_3(LeftType, RightType, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_HELPER(STRONG, LeftType, RightType, constexpr, Attributes) \
+ QT_DECLARE_ORDERING_OPERATORS_REVERSED_HELPER(STRONG, LeftType, RightType, constexpr, \
+ Attributes)
+
+#define Q_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE(...) \
+ QT_OVERLOADED_MACRO(QT_DECLARE_STRONGLY_ORDERED_LITERAL_TYPE, __VA_ARGS__)
+
+namespace QtPrivate {
+
+template <typename T>
+constexpr bool IsIntegralType_v = std::numeric_limits<std::remove_const_t<T>>::is_specialized
+ && std::numeric_limits<std::remove_const_t<T>>::is_integer;
+
+template <typename T>
+constexpr bool IsFloatType_v = std::is_floating_point_v<T>;
+
+#if QFLOAT16_IS_NATIVE
+template <>
+constexpr bool IsFloatType_v<QtPrivate::NativeFloat16Type> = true;
+#endif
+
+} // namespace QtPrivate
+
+namespace Qt {
+
+template <typename T>
+using if_integral = std::enable_if_t<QtPrivate::IsIntegralType_v<T>, bool>;
+
+template <typename T>
+using if_floating_point = std::enable_if_t<QtPrivate::IsFloatType_v<T>, bool>;
+
+template <typename T, typename U>
+using if_compatible_pointers =
+ std::enable_if_t<std::disjunction_v<std::is_same<T, U>,
+ std::is_base_of<T, U>,
+ std::is_base_of<U, T>>,
+ bool>;
+
+template <typename Enum>
+using if_enum = std::enable_if_t<std::is_enum_v<Enum>, bool>;
+
+template <typename LeftInt, typename RightInt,
+ if_integral<LeftInt> = true,
+ if_integral<RightInt> = true>
+constexpr Qt::strong_ordering compareThreeWay(LeftInt lhs, RightInt rhs) noexcept
+{
+ static_assert(std::is_signed_v<LeftInt> == std::is_signed_v<RightInt>,
+ "Qt::compareThreeWay() does not allow mixed-sign comparison.");
+
+#ifdef __cpp_lib_three_way_comparison
+ return lhs <=> rhs;
+#else
+ if (lhs == rhs)
+ return Qt::strong_ordering::equivalent;
+ else if (lhs < rhs)
+ return Qt::strong_ordering::less;
+ else
+ return Qt::strong_ordering::greater;
+#endif // __cpp_lib_three_way_comparison
+}
+
+template <typename LeftFloat, typename RightFloat,
+ if_floating_point<LeftFloat> = true,
+ if_floating_point<RightFloat> = true>
+constexpr Qt::partial_ordering compareThreeWay(LeftFloat lhs, RightFloat rhs) noexcept
+{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_FLOAT_COMPARE
+#ifdef __cpp_lib_three_way_comparison
+ return lhs <=> rhs;
+#else
+ if (lhs < rhs)
+ return Qt::partial_ordering::less;
+ else if (lhs > rhs)
+ return Qt::partial_ordering::greater;
+ else if (lhs == rhs)
+ return Qt::partial_ordering::equivalent;
+ else
+ return Qt::partial_ordering::unordered;
+#endif // __cpp_lib_three_way_comparison
+QT_WARNING_POP
+}
+
+template <typename IntType, typename FloatType,
+ if_integral<IntType> = true,
+ if_floating_point<FloatType> = true>
+constexpr Qt::partial_ordering compareThreeWay(IntType lhs, FloatType rhs) noexcept
+{
+ return compareThreeWay(FloatType(lhs), rhs);
+}
+
+template <typename FloatType, typename IntType,
+ if_floating_point<FloatType> = true,
+ if_integral<IntType> = true>
+constexpr Qt::partial_ordering compareThreeWay(FloatType lhs, IntType rhs) noexcept
+{
+ return compareThreeWay(lhs, FloatType(rhs));
+}
+
+template <typename LeftType, typename RightType,
+ if_compatible_pointers<LeftType, RightType> = true>
+constexpr Qt::strong_ordering compareThreeWay(const LeftType *lhs, const RightType *rhs) noexcept
+{
+#ifdef __cpp_lib_three_way_comparison
+ return std::compare_three_way{}(lhs, rhs);
+#else
+ if (lhs == rhs)
+ return Qt::strong_ordering::equivalent;
+ else if (std::less<>{}(lhs, rhs))
+ return Qt::strong_ordering::less;
+ else
+ return Qt::strong_ordering::greater;
+#endif // __cpp_lib_three_way_comparison
+}
+
+template <typename T>
+constexpr Qt::strong_ordering compareThreeWay(const T *lhs, std::nullptr_t rhs) noexcept
+{
+ return compareThreeWay(lhs, static_cast<const T *>(rhs));
+}
+
+template <typename T>
+constexpr Qt::strong_ordering compareThreeWay(std::nullptr_t lhs, const T *rhs) noexcept
+{
+ return compareThreeWay(static_cast<const T *>(lhs), rhs);
+}
+
+template <class Enum, if_enum<Enum> = true>
+constexpr Qt::strong_ordering compareThreeWay(Enum lhs, Enum rhs) noexcept
+{
+ return compareThreeWay(qToUnderlying(lhs), qToUnderlying(rhs));
+}
+
+} // namespace Qt
+
+QT_END_NAMESPACE
+
+#endif // QCOMPAREHELPERS_H
diff --git a/src/corelib/global/qcompilerdetection.h b/src/corelib/global/qcompilerdetection.h
index c74f68324a..b2340bff8e 100644
--- a/src/corelib/global/qcompilerdetection.h
+++ b/src/corelib/global/qcompilerdetection.h
@@ -2,10 +2,6 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QGLOBAL_H
-# include <QtCore/qglobal.h>
-#endif
-
#if 0
#pragma qt_class(QtCompilerDetection)
#pragma qt_sync_skip_header_check
@@ -16,10 +12,13 @@
#define QCOMPILERDETECTION_H
#include <QtCore/qprocessordetection.h>
+#include <QtCore/qsystemdetection.h>
+#include <QtCore/qtconfiginclude.h>
/*
The compiler, must be one of: (Q_CC_x)
+ COVERITY - Coverity cov-scan
SYM - Digital Mars C/C++ (used to be Symantec C++)
MSVC - Microsoft Visual C/C++, Intel C++ for Windows
BOR - Borland/Turbo C++
@@ -46,6 +45,11 @@
Should be sorted most to least authoritative.
*/
+#if defined(__COVERITY__)
+# define Q_CC_COVERITY
+# define Q_COMPILER_COMPLAINS_ABOUT_RETURN_AFTER_UNREACHABLE
+#endif
+
/* Symantec C++ is now Digital Mars */
#if defined(__DMC__) || defined(__SC__)
# define Q_CC_SYM
@@ -65,13 +69,16 @@
# endif
# define Q_OUTOFLINE_TEMPLATE inline
# define Q_COMPILER_MANGLES_RETURN_TYPE
+# define Q_COMPILER_MANGLES_ACCESS_SPECIFIER
# define Q_FUNC_INFO __FUNCSIG__
# define Q_ASSUME_IMPL(expr) __assume(expr)
# define Q_UNREACHABLE_IMPL() __assume(0)
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
-# define QT_MAKE_UNCHECKED_ARRAY_ITERATOR(x) stdext::make_unchecked_array_iterator(x) // Since _MSC_VER >= 1800
-# define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) stdext::make_checked_array_iterator(x, size_t(N)) // Since _MSC_VER >= 1500
+# if _MSC_VER < 1938 // stdext is deprecated since VS 2022 17.8
+# define QT_MAKE_CHECKED_ARRAY_ITERATOR(x, N) stdext::make_checked_array_iterator(x, size_t(N)) // Since _MSC_VER >= 1500
+# endif
+# define Q_COMPILER_COMPLAINS_ABOUT_RETURN_AFTER_UNREACHABLE
#elif defined(__BORLANDC__) || defined(__TURBOC__)
# define Q_CC_BOR
@@ -115,7 +122,11 @@
// define to verify the Clang version we hard-code the versions
// based on the best available info we have about the actual
// version: http://en.wikipedia.org/wiki/Xcode#Toolchain_Versions
-# if __apple_build_version__ >= 13160021 // Xcode 13.3
+# if __apple_build_version__ >= 14030022 // Xcode 14.3
+# define Q_CC_CLANG 1500
+# elif __apple_build_version__ >= 14000029 // Xcode 14.0
+# define Q_CC_CLANG 1400
+# elif __apple_build_version__ >= 13160021 // Xcode 13.3
# define Q_CC_CLANG 1300
# elif __apple_build_version__ >= 13000029 // Xcode 13.0
# define Q_CC_CLANG 1200
@@ -168,7 +179,7 @@
# ifdef Q_OS_WIN
# define Q_DECL_EXPORT __declspec(dllexport)
# define Q_DECL_IMPORT __declspec(dllimport)
-# elif defined(QT_VISIBILITY_AVAILABLE)
+# else
# define Q_DECL_EXPORT_OVERRIDABLE __attribute__((visibility("default"), weak))
# ifdef QT_USE_PROTECTED_VISIBILITY
# define Q_DECL_EXPORT __attribute__((visibility("protected")))
@@ -439,13 +450,21 @@
# define __has_include_next(x) 0
#endif
-// Kept around until all submodules have transitioned
-#define QT_HAS_BUILTIN(x) __has_builtin(x)
-#define QT_HAS_FEATURE(x) __has_feature(x)
-#define QT_HAS_ATTRIBUTE(x) __has_attribute(x)
-#define QT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
-#define QT_HAS_INCLUDE(x) __has_include(x)
-#define QT_HAS_INCLUDE_NEXT(x) __has_include_next(x)
+/*
+ detecting ASAN can be helpful to disable slow tests
+ clang uses feature, gcc defines __SANITIZE_ADDRESS__
+ unconditionally check both in case other compilers mirror
+ either of those options
+ */
+#if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
+# define QT_ASAN_ENABLED
+#endif
+
+#ifdef __cplusplus
+# if __has_include(<version>) /* remove this check once Integrity, QNX have caught up */
+# include <version>
+# endif
+#endif
/*
* C++11 support
@@ -487,9 +506,14 @@
* N1653 Q_COMPILER_VARIADIC_MACROS
* N2242 N2555 Q_COMPILER_VARIADIC_TEMPLATES __cpp_variadic_templates = 200704
*
- * For any future version of the C++ standard, we use only the SD-6 macro.
- * For full listing, see
- * http://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
+ *
+ * For the C++ standards C++14 and C++17, we use only the SD-6 macro.
+ *
+ * For any future version of the C++ standard, we use only the C++20 feature test macro.
+ * For library features, we assume <version> is present (this header includes it).
+ *
+ * For a full listing of feature test macros, see
+ * https://en.cppreference.com/w/cpp/feature_test
*
* C++ extensions:
* Q_COMPILER_RESTRICTED_VLA variable-length arrays, prior to __cpp_runtime_arrays
@@ -523,7 +547,8 @@
# endif
/* C++11 features, see http://clang.llvm.org/cxx_status.html */
-# if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
+# if (defined(__cplusplus) && __cplusplus >= 201103L) \
+ || defined(__GXX_EXPERIMENTAL_CXX0X__)
/* Detect C++ features using __has_feature(), see http://clang.llvm.org/docs/LanguageExtensions.html#cxx11 */
# if __has_feature(cxx_alignas)
# define Q_COMPILER_ALIGNAS
@@ -621,10 +646,10 @@
# if Q_CC_CLANG >= 209 /* since clang 2.9 */
# define Q_COMPILER_EXTERN_TEMPLATES
# endif
-# endif
+# endif // (defined(__cplusplus) && __cplusplus >= 201103L) || defined(__GXX_EXPERIMENTAL_CXX0X__)
/* C++1y features, deprecated macros. Do not update this list. */
-# if __cplusplus > 201103L
+# if defined(__cplusplus) && __cplusplus > 201103L
//# if __has_feature(cxx_binary_literals)
//# define Q_COMPILER_BINARY_LITERALS // see above
//# endif
@@ -646,7 +671,7 @@
# if __has_feature(cxx_runtime_array)
# define Q_COMPILER_VLA
# endif
-# endif
+# endif // if defined(__cplusplus) && __cplusplus > 201103L
# if defined(__STDC_VERSION__)
# if __has_feature(c_static_assert)
@@ -825,6 +850,15 @@
# if _MSC_VER >= 1910
# define Q_COMPILER_CONSTEXPR
# endif
+// MSVC versions before 19.36 have a bug in C++20 comparison implementation.
+// This leads to ambiguities when resolving comparison operator overloads in
+// certain scenarios (the buggy MSVC versions were checked using our CI and
+// compiler explorer).
+# if _MSC_VER < 1936
+# define Q_COMPILER_LACKS_THREE_WAY_COMPARE_SYMMETRY
+# endif
+// QTBUG-124376: MSVC is slow at compiling qstrnlen()
+# define Q_COMPILER_SLOW_QSTRNLEN_COMPILATION
# endif /* __cplusplus */
#endif // defined(Q_CC_MSVC) && !defined(Q_CC_CLANG)
@@ -870,16 +904,22 @@
# endif // !_HAS_CONSTEXPR
# endif // !__GLIBCXX__ && !_LIBCPP_VERSION
# endif // Q_OS_QNX
-# if defined(Q_CC_CLANG) && defined(Q_OS_MAC) && defined(__GNUC_LIBSTD__) \
- && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402)
+# if defined(Q_CC_CLANG) && defined(Q_OS_DARWIN)
+# if defined(__GNUC_LIBSTD__) && ((__GNUC_LIBSTD__-0) * 100 + __GNUC_LIBSTD_MINOR__-0 <= 402)
// Apple has not updated libstdc++ since 2007, which means it does not have
// <initializer_list> or std::move. Let's disable these features
-# undef Q_COMPILER_INITIALIZER_LISTS
-# undef Q_COMPILER_RVALUE_REFS
-# undef Q_COMPILER_REF_QUALIFIERS
+# undef Q_COMPILER_INITIALIZER_LISTS
+# undef Q_COMPILER_RVALUE_REFS
+# undef Q_COMPILER_REF_QUALIFIERS
// Also disable <atomic>, since it's clearly not there
-# undef Q_COMPILER_ATOMICS
-# endif
+# undef Q_COMPILER_ATOMICS
+# endif
+# if defined(__cpp_lib_memory_resource) \
+ && ((defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED < 140000) \
+ || (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED < 170000))
+# undef __cpp_lib_memory_resource // Only supported on macOS 14 and iOS 17
+# endif
+# endif // defined(Q_CC_CLANG) && defined(Q_OS_DARWIN)
#endif
// Don't break code that is already using Q_COMPILER_DEFAULT_DELETE_MEMBERS
@@ -925,6 +965,20 @@
# define Q_REQUIRED_RESULT [[nodiscard]]
#endif
+#if __has_cpp_attribute(nodiscard) >= 201907L /* used for both P1771 and P1301... */
+// [[nodiscard]] constructor (P1771)
+# ifndef Q_NODISCARD_CTOR
+# define Q_NODISCARD_CTOR [[nodiscard]]
+# endif
+// [[nodiscard("reason")]] (P1301)
+# ifndef Q_NODISCARD_X
+# define Q_NODISCARD_X(message) [[nodiscard(message)]]
+# endif
+# ifndef Q_NODISCARD_CTOR_X
+# define Q_NODISCARD_CTOR_X(message) [[nodiscard(message)]]
+# endif
+#endif
+
#if __has_cpp_attribute(maybe_unused)
# undef Q_DECL_UNUSED
# define Q_DECL_UNUSED [[maybe_unused]]
@@ -974,6 +1028,15 @@
#ifndef Q_REQUIRED_RESULT
# define Q_REQUIRED_RESULT
#endif
+#ifndef Q_NODISCARD_X
+# define Q_NODISCARD_X(message) Q_REQUIRED_RESULT
+#endif
+#ifndef Q_NODISCARD_CTOR
+# define Q_NODISCARD_CTOR
+#endif
+#ifndef Q_NODISCARD_CTOR_X
+# define Q_NODISCARD_CTOR_X(message) Q_NODISCARD_CTOR
+#endif
#ifndef Q_DECL_DEPRECATED
# define Q_DECL_DEPRECATED
#endif
@@ -1034,7 +1097,7 @@
* "Weak overloads" - makes an otherwise confliciting overload weaker
* (by making it a template)
*/
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
# define Q_WEAK_OVERLOAD template <typename = void>
#else
# define Q_WEAK_OVERLOAD
@@ -1058,7 +1121,7 @@
* The workaround: declare such functions as function templates.
* (Obviously a function template does not need this marker.)
*/
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
# define QT_POST_CXX17_API_IN_EXPORTED_CLASS template <typename = void>
#else
# define QT_POST_CXX17_API_IN_EXPORTED_CLASS
@@ -1160,11 +1223,11 @@
#endif
#endif
#ifndef Q_FALLTHROUGH
-# if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 700
+# ifdef Q_CC_GNU
# define Q_FALLTHROUGH() __attribute__((fallthrough))
# else
# define Q_FALLTHROUGH() (void)0
-#endif
+# endif
#endif
@@ -1337,6 +1400,29 @@ QT_WARNING_DISABLE_MSVC(4530) /* C++ exception handler used, but unwind semantic
# endif
#endif
+// libstdc++ shipped with gcc < 11 does not have a fix for defect LWG 3346
+#if __cplusplus >= 202002L && (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE >= 11)
+# define QT_COMPILER_HAS_LWG3346
+#endif
+
+#if defined(__cplusplus) && __cplusplus >= 202002L // P0846 doesn't have a feature macro :/
+# if !defined(Q_CC_MSVC_ONLY) || Q_CC_MSVC < 1939 // claims C++20 support but lacks P0846
+ // 1939 is known to work
+ // 1936 is known to fail
+# define QT_COMPILER_HAS_P0846
+# endif
+#endif
+
+#ifdef QT_COMPILER_HAS_P0846
+# define QT_ENABLE_P0846_SEMANTICS_FOR(func)
+#else
+ class QT_CLASS_JUST_FOR_P0846_SIMULATION;
+# define QT_ENABLE_P0846_SEMANTICS_FOR(func) \
+ template <typename T> \
+ void func (QT_CLASS_JUST_FOR_P0846_SIMULATION *); \
+ /* end */
+#endif // !P0846
+
#endif // __cplusplus
#endif // QCOMPILERDETECTION_H
diff --git a/src/corelib/global/qcompilerdetection.qdoc b/src/corelib/global/qcompilerdetection.qdoc
index 05a4b89f1d..191f26cc1f 100644
--- a/src/corelib/global/qcompilerdetection.qdoc
+++ b/src/corelib/global/qcompilerdetection.qdoc
@@ -175,12 +175,12 @@
\since 5.8
Can be used in switch statements at the end of case block to tell the compiler
- and other developers that that the lack of a break statement is intentional.
+ and other developers that the lack of a break statement is intentional.
This is useful since a missing break statement is often a bug, and some
compilers can be configured to emit warnings when one is not found.
- \sa Q_UNREACHABLE()
+ \sa Q_UNREACHABLE(), Q_UNREACHABLE_RETURN()
*/
/*!
@@ -197,7 +197,7 @@
\snippet code/src_corelib_global_qglobal.cpp qlikely
- \sa Q_UNLIKELY(), Q_ASSUME()
+ \sa Q_UNLIKELY()
*/
/*!
@@ -392,3 +392,36 @@
If this macro is used outside a function, the behavior is undefined.
*/
+
+/*!
+ \macro Q_NODISCARD_CTOR
+ \relates <QtCompilerDetection>
+ \since 6.6
+
+ \brief Expands to \c{[[nodiscard]]} on compilers that accept it on constructors.
+
+ Otherwise it expands to nothing.
+
+ Constructors marked as Q_NODISCARD_CTOR cause a compiler warning if a call
+ site doesn't use the resulting object.
+
+ This macro is exists solely to prevent warnings on compilers that don't
+ implement the feature. If your supported platforms all allow \c{[[nodiscard]]}
+ on constructors, we strongly recommend you use the C++ attribute directly instead
+ of this macro.
+
+ \sa Q_NODISCARD_CTOR_X
+*/
+
+/*!
+ \macro Q_NODISCARD_X(message)
+ \macro Q_NODISCARD_CTOR_X(message)
+ \relates <QtCompilerDetection>
+ \since 6.7
+
+ \brief Expand to \c{[[nodiscard(message)]]} on compilers that support the feature.
+
+ Otherwise they expand to \c {[[nodiscard]]} and Q_NODISCARD_CTOR, respectively.
+
+ \sa Q_NODISCARD_CTOR
+*/
diff --git a/src/corelib/global/qconfig-bootstrapped.h b/src/corelib/global/qconfig-bootstrapped.h
index 5d42facca3..4d80f23786 100644
--- a/src/corelib/global/qconfig-bootstrapped.h
+++ b/src/corelib/global/qconfig-bootstrapped.h
@@ -43,7 +43,6 @@
#define QT_FEATURE_cborstreamreader -1
#define QT_FEATURE_cborstreamwriter 1
#define QT_CRYPTOGRAPHICHASH_ONLY_SHA1
-#define QT_FEATURE_cxx11_random (__has_include(<random>) ? 1 : -1)
#define QT_FEATURE_cxx17_filesystem -1
#define QT_NO_DATASTREAM
#define QT_FEATURE_datestring 1
@@ -63,7 +62,7 @@
#define QT_FEATURE_jalalicalendar -1
#define QT_FEATURE_journald -1
#define QT_FEATURE_futimens -1
-#define QT_FEATURE_futimes -1
+#undef QT_FEATURE_future
#define QT_FEATURE_future -1
#define QT_FEATURE_itemmodel -1
#define QT_FEATURE_library -1
@@ -82,22 +81,18 @@
# define QT_FEATURE_renameat2 -1
#endif
#define QT_FEATURE_shortcut -1
-#define QT_FEATURE_signaling_nan -1
#define QT_FEATURE_slog2 -1
-#ifdef __GLIBC_PREREQ
-# define QT_FEATURE_statx (__GLIBC_PREREQ(2, 28) ? 1 : -1)
-#else
-# define QT_FEATURE_statx -1
-#endif
#define QT_FEATURE_syslog -1
#define QT_NO_SYSTEMLOCALE
-#define QT_FEATURE_temporaryfile 1
+#define QT_FEATURE_temporaryfile -1
#define QT_FEATURE_textdate 1
+#undef QT_FEATURE_thread
#define QT_FEATURE_thread -1
#define QT_FEATURE_timezone -1
#define QT_FEATURE_topleveldomain -1
#define QT_NO_TRANSLATION
#define QT_FEATURE_translation -1
+#define QT_NO_VARIANT -1
#define QT_NO_COMPRESS
@@ -108,6 +103,7 @@
#define QT_FEATURE_commandlineparser 1
#define QT_FEATURE_settings -1
+#define QT_FEATURE_permissions -1
#define QT_NO_TEMPORARYFILE
diff --git a/src/corelib/global/qcontainerinfo.h b/src/corelib/global/qcontainerinfo.h
index e27877073f..14468510a5 100644
--- a/src/corelib/global/qcontainerinfo.h
+++ b/src/corelib/global/qcontainerinfo.h
@@ -51,6 +51,11 @@ template<typename C>
inline constexpr bool has_size_v<C, std::void_t<decltype(C().size())>> = true;
template<typename C, typename = void>
+inline constexpr bool has_reserve_v = false;
+template<typename C>
+inline constexpr bool has_reserve_v<C, std::void_t<decltype(C().reserve(0))>> = true;
+
+template<typename C, typename = void>
inline constexpr bool has_clear_v = false;
template<typename C>
inline constexpr bool has_clear_v<C, std::void_t<decltype(C().clear())>> = true;
diff --git a/src/corelib/global/qdarwinhelpers.h b/src/corelib/global/qdarwinhelpers.h
index 2ffc740d58..ad72211663 100644
--- a/src/corelib/global/qdarwinhelpers.h
+++ b/src/corelib/global/qdarwinhelpers.h
@@ -27,10 +27,10 @@
# define Q_FORWARD_DECLARE_MUTABLE_CF_TYPE(type) typedef struct __ ## type * type ## Ref
#endif
#ifndef Q_FORWARD_DECLARE_CG_TYPE
-#define Q_FORWARD_DECLARE_CG_TYPE(type) typedef const struct type *type ## Ref;
+# define Q_FORWARD_DECLARE_CG_TYPE(type) typedef const struct type *type##Ref
#endif
#ifndef Q_FORWARD_DECLARE_MUTABLE_CG_TYPE
-#define Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) typedef struct type *type ## Ref;
+# define Q_FORWARD_DECLARE_MUTABLE_CG_TYPE(type) typedef struct type *type##Ref
#endif
diff --git a/src/corelib/global/qendian.cpp b/src/corelib/global/qendian.cpp
index 2fa7404507..5e46109dd1 100644
--- a/src/corelib/global/qendian.cpp
+++ b/src/corelib/global/qendian.cpp
@@ -445,8 +445,8 @@ QT_BEGIN_NAMESPACE
The template parameter \c T must be a C++ integer type:
\list
\li 8-bit: char, signed char, unsigned char, qint8, quint8
- \li 16-bit: short, unsigned short, qint16, quint16, char16_t (C++11)
- \li 32-bit: int, unsigned int, qint32, quint32, char32_t (C++11)
+ \li 16-bit: short, unsigned short, qint16, quint16, char16_t
+ \li 32-bit: int, unsigned int, qint32, quint32, char32_t
\li 64-bit: long long, unsigned long long, qint64, quint64
\li platform-specific size: long, unsigned long
\li pointer size: qintptr, quintptr, qptrdiff
diff --git a/src/corelib/global/qendian.h b/src/corelib/global/qendian.h
index b803a27674..8c3b5e4374 100644
--- a/src/corelib/global/qendian.h
+++ b/src/corelib/global/qendian.h
@@ -105,6 +105,23 @@ inline constexpr T qbswap(T source)
return T(qbswap_helper(typename QIntegerForSizeof<T>::Unsigned(source)));
}
+#ifdef QT_SUPPORTS_INT128
+// extra definitions for q(u)int128, in case std::is_integral_v<~~> == false
+inline constexpr quint128 qbswap(quint128 source)
+{
+ quint128 result = {};
+ result = qbswap_helper(quint64(source));
+ result <<= 64;
+ result |= qbswap_helper(quint64(source >> 64));
+ return result;
+}
+
+inline constexpr qint128 qbswap(qint128 source)
+{
+ return qint128(qbswap(quint128(source)));
+}
+#endif
+
// floating specializations
template<typename Float>
Float qbswapFloatHelper(Float source)
@@ -302,7 +319,7 @@ public:
static constexpr T fromSpecial(T source) { return qFromBigEndian(source); }
};
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
template<typename T>
class QLEInteger {
public:
diff --git a/src/corelib/global/qexceptionhandling.h b/src/corelib/global/qexceptionhandling.h
index aca8de9003..76c6185c3e 100644
--- a/src/corelib/global/qexceptionhandling.h
+++ b/src/corelib/global/qexceptionhandling.h
@@ -6,6 +6,7 @@
#include <QtCore/qtconfigmacros.h>
#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtcoreexports.h>
#if 0
#pragma qt_class(QtExceptionHandling)
diff --git a/src/corelib/global/qflags.h b/src/corelib/global/qflags.h
index c791c26ac1..cc028e0095 100644
--- a/src/corelib/global/qflags.h
+++ b/src/corelib/global/qflags.h
@@ -1,12 +1,12 @@
// 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
-#include <QtCore/qglobal.h>
-#include <QtCore/qcompare_impl.h>
-
#ifndef QFLAGS_H
#define QFLAGS_H
+#include <QtCore/qcompare_impl.h>
+#include <QtCore/qtypeinfo.h>
+
#include <initializer_list>
QT_BEGIN_NAMESPACE
@@ -24,7 +24,7 @@ public:
// Microsoft Visual Studio has buggy behavior when it comes to
// unsigned enums: even if the enum is unsigned, the enum tags are
// always signed
-# if !defined(__LP64__) && !defined(Q_CLANG_QDOC)
+# if !defined(__LP64__) && !defined(Q_QDOC)
constexpr inline Q_IMPLICIT QFlag(long value) noexcept : i(int(value)) {}
constexpr inline Q_IMPLICIT QFlag(ulong value) noexcept : i(int(long(value))) {}
# endif
@@ -57,7 +57,7 @@ class QFlags
static_assert((std::is_enum<Enum>::value), "QFlags is only usable on enumeration types.");
public:
-#if defined(Q_CC_MSVC) || defined(Q_CLANG_QDOC)
+#if defined(Q_CC_MSVC) || defined(Q_QDOC)
// see above for MSVC
// the definition below is too complex for qdoc
typedef int Int;
diff --git a/src/corelib/global/qflags.qdoc b/src/corelib/global/qflags.qdoc
index 4542d99268..dd3b1e4c9b 100644
--- a/src/corelib/global/qflags.qdoc
+++ b/src/corelib/global/qflags.qdoc
@@ -98,7 +98,7 @@
\section1 Flags and the Meta-Object System
The Q_DECLARE_FLAGS() macro does not expose the flags to the meta-object
- system, so they cannot be used by Qt Script or edited in Qt Designer.
+ system, so they cannot be used by Qt Script or edited in \QD.
To make the flags available for these purposes, the Q_FLAG() macro must
be used:
@@ -174,7 +174,7 @@
/*!
\fn template <typename Enum> QFlags &QFlags<Enum>::operator=(const QFlags &other)
- Assigns \e other to this object and returns a reference to this
+ Assigns \a other to this object and returns a reference to this
object.
*/
diff --git a/src/corelib/global/qfloat16.cpp b/src/corelib/global/qfloat16.cpp
index b7f1a559b1..f6f782e364 100644
--- a/src/corelib/global/qfloat16.cpp
+++ b/src/corelib/global/qfloat16.cpp
@@ -7,7 +7,10 @@
#include <cmath> // for fpclassify()'s return values
#include <QtCore/qdatastream.h>
+#include <QtCore/qmetatype.h>
+#include <QtCore/qtextstream.h>
+QT_DECL_METATYPE_EXTERN(qfloat16, Q_CORE_EXPORT)
QT_BEGIN_NAMESPACE
QT_IMPL_METATYPE_EXTERN(qfloat16)
@@ -20,6 +23,15 @@ QT_IMPL_METATYPE_EXTERN(qfloat16)
\inheaderfile QFloat16
\brief Provides 16-bit floating point support.
+ \compares partial
+ \compareswith partial float double {long double} qint8 quint8 qint16 quint16 \
+ qint32 quint32 long {unsigned long} qint64 quint64
+ \endcompareswith
+ \compareswith partial qint128 quint128
+ Comparison with 128-bit integral types is only supported if Qt provides
+ these types.
+ \endcompareswith
+
The \c qfloat16 class provides support for half-precision (16-bit) floating
point data. It is fully compliant with IEEE 754 as a storage type. This
implies that any arithmetic operation on a \c qfloat16 instance results in
@@ -360,6 +372,19 @@ Q_CORE_EXPORT void qFloatFromFloat16(float *out, const qfloat16 *in, qsizetype l
out[i] = float(in[i]);
}
+/*!
+ \fn size_t qfloat16::qHash(qfloat16 key, size_t seed)
+ \since 6.5.3
+
+ Returns the hash value for the \a key, using \a seed to seed the
+ calculation.
+
+ \note In Qt versions before 6.5, this operation was provided by the
+ qHash(float) overload. In Qt versions 6.5.0 to 6.5.2, this functionality
+ was broken in various ways. In Qt versions 6.5.3 and 6.6 onwards, this
+ overload restores the Qt 6.4 behavior.
+*/
+
#ifndef QT_NO_DATASTREAM
/*!
\fn qfloat16::operator<<(QDataStream &ds, qfloat16 f)
@@ -395,6 +420,19 @@ QDataStream &operator>>(QDataStream &ds, qfloat16 &f)
}
#endif
+QTextStream &operator>>(QTextStream &ts, qfloat16 &f16)
+{
+ float f;
+ ts >> f;
+ f16 = qfloat16(f);
+ return ts;
+}
+
+QTextStream &operator<<(QTextStream &ts, qfloat16 f)
+{
+ return ts << float(f);
+}
+
QT_END_NAMESPACE
#include "qfloat16tables.cpp"
diff --git a/src/corelib/global/qfloat16.h b/src/corelib/global/qfloat16.h
index fc0d9e2702..30dd9a60af 100644
--- a/src/corelib/global/qfloat16.h
+++ b/src/corelib/global/qfloat16.h
@@ -5,11 +5,17 @@
#ifndef QFLOAT16_H
#define QFLOAT16_H
+#include <QtCore/qcompare.h>
#include <QtCore/qglobal.h>
-#include <QtCore/qmetatype.h>
+#include <QtCore/qhashfunctions.h>
+#include <QtCore/qmath.h>
#include <QtCore/qnamespace.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtypes.h>
+
#include <limits>
#include <string.h>
+#include <type_traits>
#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__AVX2__) && !defined(__F16C__)
// All processors that support AVX2 do support F16C too, so we could enable the
@@ -35,6 +41,7 @@ QT_BEGIN_NAMESPACE
#ifndef QT_NO_DATASTREAM
class QDataStream;
#endif
+class QTextStream;
class qfloat16
{
@@ -45,11 +52,38 @@ class qfloat16
quint16 b16;
constexpr inline explicit Wrap(int value) : b16(quint16(value)) {}
};
+
+#ifdef QT_SUPPORTS_INT128
+ template <typename T>
+ using IsIntegral = std::disjunction<std::is_integral<T>,
+ std::is_same<std::remove_const_t<T>, qint128>,
+ std::is_same<std::remove_const_t<T>, quint128>>;
+#else
+ template <typename T>
+ using IsIntegral = std::is_integral<T>;
+#endif
+ template <typename T>
+ using if_type_is_integral = std::enable_if_t<IsIntegral<std::remove_reference_t<T>>::value,
+ bool>;
+
public:
+ using NativeType = QtPrivate::NativeFloat16Type;
+
+ static constexpr bool IsNative = QFLOAT16_IS_NATIVE;
+ using NearestFloat = std::conditional_t<IsNative, NativeType, float>;
+
constexpr inline qfloat16() noexcept : b16(0) {}
explicit qfloat16(Qt::Initialization) noexcept { }
+
+#if QFLOAT16_IS_NATIVE
+ constexpr inline qfloat16(NativeType f) : nf(f) {}
+ constexpr operator NativeType() const noexcept { return nf; }
+#else
inline qfloat16(float f) noexcept;
inline operator float() const noexcept;
+#endif
+ template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T> && !std::is_same_v<T, NearestFloat>>>
+ constexpr explicit qfloat16(T value) noexcept : qfloat16(NearestFloat(value)) {}
// Support for qIs{Inf,NaN,Finite}:
bool isInf() const noexcept { return (b16 & 0x7fff) == 0x7c00; }
@@ -60,6 +94,22 @@ public:
qfloat16 copySign(qfloat16 sign) const noexcept
{ return qfloat16(Wrap((sign.b16 & 0x8000) | (b16 & 0x7fff))); }
// Support for std::numeric_limits<qfloat16>
+
+#ifdef __STDCPP_FLOAT16_T__
+private:
+ using Bounds = std::numeric_limits<NativeType>;
+public:
+ static constexpr qfloat16 _limit_epsilon() noexcept { return Bounds::epsilon(); }
+ static constexpr qfloat16 _limit_min() noexcept { return Bounds::min(); }
+ static constexpr qfloat16 _limit_denorm_min() noexcept { return Bounds::denorm_min(); }
+ static constexpr qfloat16 _limit_max() noexcept { return Bounds::max(); }
+ static constexpr qfloat16 _limit_lowest() noexcept { return Bounds::lowest(); }
+ static constexpr qfloat16 _limit_infinity() noexcept { return Bounds::infinity(); }
+ static constexpr qfloat16 _limit_quiet_NaN() noexcept { return Bounds::quiet_NaN(); }
+#if QT_CONFIG(signaling_nan)
+ static constexpr qfloat16 _limit_signaling_NaN() noexcept { return Bounds::signaling_NaN(); }
+#endif
+#else
static constexpr qfloat16 _limit_epsilon() noexcept { return qfloat16(Wrap(0x1400)); }
static constexpr qfloat16 _limit_min() noexcept { return qfloat16(Wrap(0x400)); }
static constexpr qfloat16 _limit_denorm_min() noexcept { return qfloat16(Wrap(1)); }
@@ -70,11 +120,29 @@ public:
#if QT_CONFIG(signaling_nan)
static constexpr qfloat16 _limit_signaling_NaN() noexcept { return qfloat16(Wrap(0x7d00)); }
#endif
+#endif
inline constexpr bool isNormal() const noexcept
{ return (b16 & 0x7c00) && (b16 & 0x7c00) != 0x7c00; }
private:
- quint16 b16;
- constexpr inline explicit qfloat16(Wrap nibble) noexcept : b16(nibble.b16) {}
+ // ABI note: Qt 6's qfloat16 began with just a quint16 member so it ended
+ // up passed in general purpose registers in any function call taking
+ // qfloat16 by value (it has trivial copy constructors). This means the
+ // integer member in the anonymous union below must remain until a
+ // binary-incompatible version of Qt. If you remove it, on platforms using
+ // the System V ABI for C, the native type is passed in FP registers.
+ union {
+ quint16 b16;
+#if QFLOAT16_IS_NATIVE
+ NativeType nf;
+#endif
+ };
+ constexpr inline explicit qfloat16(Wrap nibble) noexcept :
+#if QFLOAT16_IS_NATIVE && defined(__cpp_lib_bit_cast)
+ nf(std::bit_cast<NativeType>(nibble.b16))
+#else
+ b16(nibble.b16)
+#endif
+ {}
Q_CORE_EXPORT static const quint32 mantissatable[];
Q_CORE_EXPORT static const quint32 exponenttable[];
@@ -92,17 +160,23 @@ private:
return f;
}
- friend inline qfloat16 operator+(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<float>(a) + static_cast<float>(b)); }
- friend inline qfloat16 operator-(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<float>(a) - static_cast<float>(b)); }
- friend inline qfloat16 operator*(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<float>(a) * static_cast<float>(b)); }
- friend inline qfloat16 operator/(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<float>(a) / static_cast<float>(b)); }
+ friend inline qfloat16 operator+(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) + static_cast<NearestFloat>(b)); }
+ friend inline qfloat16 operator-(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) - static_cast<NearestFloat>(b)); }
+ friend inline qfloat16 operator*(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) * static_cast<NearestFloat>(b)); }
+ friend inline qfloat16 operator/(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<NearestFloat>(a) / static_cast<NearestFloat>(b)); }
+
+ friend size_t qHash(qfloat16 key, size_t seed = 0) noexcept
+ { return qHash(float(key), seed); } // 6.4 algorithm, so keep using it; ### Qt 7: fix QTBUG-116077
+
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wfloat-conversion")
#define QF16_MAKE_ARITH_OP_FP(FP, OP) \
friend inline FP operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \
friend inline FP operator OP(FP lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<FP>(rhs); }
#define QF16_MAKE_ARITH_OP_EQ_FP(FP, OP_EQ, OP) \
friend inline qfloat16& operator OP_EQ(qfloat16& lhs, FP rhs) noexcept \
- { lhs = qfloat16(float(static_cast<FP>(lhs) OP rhs)); return lhs; }
+ { lhs = qfloat16(NearestFloat(static_cast<FP>(lhs) OP rhs)); return lhs; }
#define QF16_MAKE_ARITH_OP(FP) \
QF16_MAKE_ARITH_OP_FP(FP, +) \
QF16_MAKE_ARITH_OP_FP(FP, -) \
@@ -116,6 +190,9 @@ private:
QF16_MAKE_ARITH_OP(long double)
QF16_MAKE_ARITH_OP(double)
QF16_MAKE_ARITH_OP(float)
+#if QFLOAT16_IS_NATIVE
+ QF16_MAKE_ARITH_OP(NativeType)
+#endif
#undef QF16_MAKE_ARITH_OP
#undef QF16_MAKE_ARITH_OP_FP
@@ -129,44 +206,63 @@ private:
QF16_MAKE_ARITH_OP_INT(/)
#undef QF16_MAKE_ARITH_OP_INT
-QT_WARNING_PUSH
QT_WARNING_DISABLE_FLOAT_COMPARE
- friend inline bool operator>(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) > static_cast<float>(b); }
- friend inline bool operator<(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) < static_cast<float>(b); }
- friend inline bool operator>=(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) >= static_cast<float>(b); }
- friend inline bool operator<=(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) <= static_cast<float>(b); }
- friend inline bool operator==(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) == static_cast<float>(b); }
- friend inline bool operator!=(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) != static_cast<float>(b); }
-
-#define QF16_MAKE_BOOL_OP_FP(FP, OP) \
- friend inline bool operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \
- friend inline bool operator OP(FP lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<FP>(rhs); }
-#define QF16_MAKE_BOOL_OP(FP) \
- QF16_MAKE_BOOL_OP_FP(FP, <) \
- QF16_MAKE_BOOL_OP_FP(FP, >) \
- QF16_MAKE_BOOL_OP_FP(FP, >=) \
- QF16_MAKE_BOOL_OP_FP(FP, <=) \
- QF16_MAKE_BOOL_OP_FP(FP, ==) \
- QF16_MAKE_BOOL_OP_FP(FP, !=)
-
- QF16_MAKE_BOOL_OP(long double)
- QF16_MAKE_BOOL_OP(double)
- QF16_MAKE_BOOL_OP(float)
-#undef QF16_MAKE_BOOL_OP
-#undef QF16_MAKE_BOOL_OP_FP
-
-#define QF16_MAKE_BOOL_OP_INT(OP) \
- friend inline bool operator OP(qfloat16 a, int b) noexcept { return static_cast<float>(a) OP static_cast<float>(b); } \
- friend inline bool operator OP(int a, qfloat16 b) noexcept { return static_cast<float>(a) OP static_cast<float>(b); }
-
- QF16_MAKE_BOOL_OP_INT(>)
- QF16_MAKE_BOOL_OP_INT(<)
- QF16_MAKE_BOOL_OP_INT(>=)
- QF16_MAKE_BOOL_OP_INT(<=)
- QF16_MAKE_BOOL_OP_INT(==)
- QF16_MAKE_BOOL_OP_INT(!=)
-#undef QF16_MAKE_BOOL_OP_INT
+#if QFLOAT16_IS_NATIVE
+# define QF16_CONSTEXPR constexpr
+# define QF16_PARTIALLY_ORDERED Q_DECLARE_PARTIALLY_ORDERED_LITERAL_TYPE
+#else
+# define QF16_CONSTEXPR
+# define QF16_PARTIALLY_ORDERED Q_DECLARE_PARTIALLY_ORDERED
+#endif
+
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, const qfloat16 &rhs) noexcept
+ { return static_cast<NearestFloat>(lhs) == static_cast<NearestFloat>(rhs); }
+ friend QF16_CONSTEXPR
+ Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, const qfloat16 &rhs) noexcept
+ { return Qt::compareThreeWay(static_cast<NearestFloat>(lhs), static_cast<NearestFloat>(rhs)); }
+ QF16_PARTIALLY_ORDERED(qfloat16)
+
+#define QF16_MAKE_ORDER_OP_FP(FP) \
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, FP rhs) noexcept \
+ { return static_cast<FP>(lhs) == rhs; } \
+ friend QF16_CONSTEXPR \
+ Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, FP rhs) noexcept \
+ { return Qt::compareThreeWay(static_cast<FP>(lhs), rhs); } \
+ QF16_PARTIALLY_ORDERED(qfloat16, FP)
+
+ QF16_MAKE_ORDER_OP_FP(long double)
+ QF16_MAKE_ORDER_OP_FP(double)
+ QF16_MAKE_ORDER_OP_FP(float)
+#if QFLOAT16_IS_NATIVE
+ QF16_MAKE_ORDER_OP_FP(qfloat16::NativeType)
+#endif
+#undef QF16_MAKE_ORDER_OP_FP
+
+ template <typename T, if_type_is_integral<T> = true>
+ friend QF16_CONSTEXPR bool comparesEqual(const qfloat16 &lhs, T rhs) noexcept
+ { return static_cast<NearestFloat>(lhs) == static_cast<NearestFloat>(rhs); }
+ template <typename T, if_type_is_integral<T> = true>
+ friend QF16_CONSTEXPR Qt::partial_ordering compareThreeWay(const qfloat16 &lhs, T rhs) noexcept
+ { return Qt::compareThreeWay(static_cast<NearestFloat>(lhs), static_cast<NearestFloat>(rhs)); }
+
+ QF16_PARTIALLY_ORDERED(qfloat16, qint8)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint8)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint16)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint16)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint32)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint32)
+ QF16_PARTIALLY_ORDERED(qfloat16, long)
+ QF16_PARTIALLY_ORDERED(qfloat16, unsigned long)
+ QF16_PARTIALLY_ORDERED(qfloat16, qint64)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint64)
+#ifdef QT_SUPPORTS_INT128
+ QF16_PARTIALLY_ORDERED(qfloat16, qint128)
+ QF16_PARTIALLY_ORDERED(qfloat16, quint128)
+#endif
+
+#undef QF16_PARTIALLY_ORDERED
+#undef QF16_CONSTEXPR
QT_WARNING_POP
@@ -174,6 +270,8 @@ QT_WARNING_POP
friend Q_CORE_EXPORT QDataStream &operator<<(QDataStream &ds, qfloat16 f);
friend Q_CORE_EXPORT QDataStream &operator>>(QDataStream &ds, qfloat16 &f);
#endif
+ friend Q_CORE_EXPORT QTextStream &operator<<(QTextStream &ts, qfloat16 f);
+ friend Q_CORE_EXPORT QTextStream &operator>>(QTextStream &ts, qfloat16 &f);
};
Q_DECLARE_TYPEINFO(qfloat16, Q_PRIMITIVE_TYPE);
@@ -188,6 +286,43 @@ Q_CORE_EXPORT void qFloatFromFloat16(float *, const qfloat16 *, qsizetype length
[[nodiscard]] inline int qFpClassify(qfloat16 f) noexcept { return f.fpClassify(); }
// [[nodiscard]] quint32 qFloatDistance(qfloat16 a, qfloat16 b);
+[[nodiscard]] inline qfloat16 qSqrt(qfloat16 f)
+{
+#if defined(__cpp_lib_extended_float) && defined(__STDCPP_FLOAT16_T__) && 0
+ // https://wg21.link/p1467 - disabled until tested
+ using namespace std;
+ return sqrt(f);
+#elif QFLOAT16_IS_NATIVE && defined(__HAVE_FLOAT16) && __HAVE_FLOAT16
+ // This C library (glibc) has sqrtf16().
+ return sqrtf16(f);
+#else
+ bool mathUpdatesErrno = true;
+# if defined(__NO_MATH_ERRNO__) || defined(_M_FP_FAST)
+ mathUpdatesErrno = false;
+# elif defined(math_errhandling)
+ mathUpdatesErrno = (math_errhandling & MATH_ERRNO);
+# endif
+
+ // We don't need to set errno to EDOM if (f >= 0 && f != -0 && !isnan(f))
+ // (or if we don't care about errno in the first place). We can merge the
+ // NaN check with by negating and inverting: !(0 > f), and leaving zero to
+ // sqrtf().
+ if (!mathUpdatesErrno || !(0 > f)) {
+# if defined(__AVX512FP16__)
+ __m128h v = _mm_set_sh(f);
+ v = _mm_sqrt_sh(v, v);
+ return _mm_cvtsh_h(v);
+# endif
+ }
+
+ // WG14's N2601 does not provide a way to tell which types an
+ // implementation supports, so we assume it doesn't and fall back to FP32
+ float f32 = float(f);
+ f32 = sqrtf(f32);
+ return qfloat16::NearestFloat(f32);
+#endif
+}
+
// The remainder of these utility functions complement qglobal.h
[[nodiscard]] inline int qRound(qfloat16 d) noexcept
{ return qRound(static_cast<float>(d)); }
@@ -197,8 +332,8 @@ Q_CORE_EXPORT void qFloatFromFloat16(float *, const qfloat16 *, qsizetype length
[[nodiscard]] inline bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
{
- float f1 = static_cast<float>(p1);
- float f2 = static_cast<float>(p2);
+ qfloat16::NearestFloat f1 = static_cast<qfloat16::NearestFloat>(p1);
+ qfloat16::NearestFloat f2 = static_cast<qfloat16::NearestFloat>(p2);
// The significand precision for IEEE754 half precision is
// 11 bits (10 explicitly stored), or approximately 3 decimal
// digits. In selecting the fuzzy comparison factor of 102.5f
@@ -222,9 +357,9 @@ Q_CORE_EXPORT void qFloatFromFloat16(float *, const qfloat16 *, qsizetype length
}
inline int qIntCast(qfloat16 f) noexcept
-{ return int(static_cast<float>(f)); }
+{ return int(static_cast<qfloat16::NearestFloat>(f)); }
-#ifndef Q_QDOC
+#if !defined(Q_QDOC) && !QFLOAT16_IS_NATIVE
QT_WARNING_PUSH
QT_WARNING_DISABLE_CLANG("-Wc99-extensions")
QT_WARNING_DISABLE_GCC("-Wold-style-cast")
@@ -284,33 +419,52 @@ inline qfloat16::operator float() const noexcept
return f;
#endif
}
-#endif
+#endif // Q_QDOC and non-native
/*
qHypot compatibility; see ../kernel/qmath.h
*/
namespace QtPrivate {
-template <typename R>
-struct QHypotType<R, qfloat16> { using type = decltype(std::hypot(R(1), 1.0f)); };
-template <typename R>
-struct QHypotType<qfloat16, R> { using type = decltype(std::hypot(1.0f, R(1))); };
-template <> struct QHypotType<qfloat16, qfloat16> { using type = qfloat16; };
+template <> struct QHypotType<qfloat16, qfloat16>
+{
+ using type = qfloat16;
+};
+template <typename R> struct QHypotType<R, qfloat16>
+{
+ using type = std::conditional_t<std::is_floating_point_v<R>, R, double>;
+};
+template <typename R> struct QHypotType<qfloat16, R> : QHypotType<R, qfloat16>
+{
+};
}
+
// Avoid passing qfloat16 to std::hypot(), while ensuring return types
// consistent with the above:
-template<typename F, typename ...Fs> auto qHypot(F first, Fs... rest);
-template <typename T, typename std::enable_if<!std::is_same<qfloat16, T>::value, int>::type = 0>
-auto qHypot(T x, qfloat16 y) { return qHypot(x, float(y)); }
-template <typename T, typename std::enable_if<!std::is_same<qfloat16, T>::value, int>::type = 0>
-auto qHypot(qfloat16 x, T y) { return qHypot(float(x), y); }
-template <> inline auto qHypot(qfloat16 x, qfloat16 y)
+inline auto qHypot(qfloat16 x, qfloat16 y)
{
-#if (defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__)) || defined (__ARM_FP16_FORMAT_IEEE)
+#if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__) || QFLOAT16_IS_NATIVE
return QtPrivate::QHypotHelper<qfloat16>(x).add(y).result();
#else
return qfloat16(qHypot(float(x), float(y)));
#endif
}
+
+// in ../kernel/qmath.h
+template<typename F, typename ...Fs> auto qHypot(F first, Fs... rest);
+
+template <typename T> typename QtPrivate::QHypotType<T, qfloat16>::type
+qHypot(T x, qfloat16 y)
+{
+ if constexpr (std::is_floating_point_v<T>)
+ return qHypot(x, float(y));
+ else
+ return qHypot(qfloat16(x), y);
+}
+template <typename T> auto qHypot(qfloat16 x, T y)
+{
+ return qHypot(y, x);
+}
+
#if defined(__cpp_lib_hypot) && __cpp_lib_hypot >= 201603L // Expected to be true
// If any are not qfloat16, convert each qfloat16 to float:
/* (The following splits the some-but-not-all-qfloat16 cases up, using
@@ -320,22 +474,22 @@ template <typename Ty, typename Tz,
typename std::enable_if<
// Ty, Tz aren't both qfloat16:
!(std::is_same_v<qfloat16, Ty> && std::is_same_v<qfloat16, Tz>), int>::type = 0>
-auto qHypot(qfloat16 x, Ty y, Tz z) { return qHypot(float(x), y, z); }
+auto qHypot(qfloat16 x, Ty y, Tz z) { return qHypot(qfloat16::NearestFloat(x), y, z); }
template <typename Tx, typename Tz,
typename std::enable_if<
// Tx isn't qfloat16:
!std::is_same_v<qfloat16, Tx>, int>::type = 0>
-auto qHypot(Tx x, qfloat16 y, Tz z) { return qHypot(x, float(y), z); }
+auto qHypot(Tx x, qfloat16 y, Tz z) { return qHypot(x, qfloat16::NearestFloat(y), z); }
template <typename Tx, typename Ty,
typename std::enable_if<
// Neither Tx nor Ty is qfloat16:
!std::is_same_v<qfloat16, Tx> && !std::is_same_v<qfloat16, Ty>, int>::type = 0>
-auto qHypot(Tx x, Ty y, qfloat16 z) { return qHypot(x, y, float(z)); }
+auto qHypot(Tx x, Ty y, qfloat16 z) { return qHypot(x, y, qfloat16::NearestFloat(z)); }
+
// If all are qfloat16, stay with qfloat16 (albeit via float, if no native support):
-template <>
inline auto qHypot(qfloat16 x, qfloat16 y, qfloat16 z)
{
-#if (defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__)) || defined (__ARM_FP16_FORMAT_IEEE)
+#if (defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__)) || QFLOAT16_IS_NATIVE
return QtPrivate::QHypotHelper<qfloat16>(x).add(y).add(z).result();
#else
return qfloat16(qHypot(float(x), float(y), float(z)));
@@ -345,8 +499,6 @@ inline auto qHypot(qfloat16 x, qfloat16 y, qfloat16 z)
QT_END_NAMESPACE
-QT_DECL_METATYPE_EXTERN(qfloat16, Q_CORE_EXPORT)
-
namespace std {
template<>
class numeric_limits<QT_PREPEND_NAMESPACE(qfloat16)> : public numeric_limits<float>
diff --git a/src/corelib/global/qforeach.h b/src/corelib/global/qforeach.h
index e8396c4fb0..ab0e20b989 100644
--- a/src/corelib/global/qforeach.h
+++ b/src/corelib/global/qforeach.h
@@ -1,11 +1,12 @@
-// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2022 The Qt Company Ltd.
// Copyright (C) 2019 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QFOREACH_H
#define QFOREACH_H
-#include <QtCore/qglobal.h>
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qtconfigmacros.h>
#include <QtCore/qtdeprecationmarkers.h>
#include <QtCore/qttypetraits.h>
@@ -24,8 +25,8 @@ template <typename T>
class QForeachContainer {
Q_DISABLE_COPY_MOVE(QForeachContainer)
public:
- QForeachContainer(const T &t) : c(t), i(qAsConst(c).begin()), e(qAsConst(c).end()) {}
- QForeachContainer(T &&t) : c(std::move(t)), i(qAsConst(c).begin()), e(qAsConst(c).end()) {}
+ QForeachContainer(const T &t) : c(t), i(std::as_const(c).begin()), e(std::as_const(c).end()) {}
+ QForeachContainer(T &&t) : c(std::move(t)), i(std::as_const(c).begin()), e(std::as_const(c).end()) {}
T c;
typename T::const_iterator i, e;
diff --git a/src/corelib/global/qforeach.qdoc b/src/corelib/global/qforeach.qdoc
index 278f1a1007..e6abf0e29c 100644
--- a/src/corelib/global/qforeach.qdoc
+++ b/src/corelib/global/qforeach.qdoc
@@ -52,11 +52,9 @@
\snippet code/src_corelib_global_qglobal.cpp 33
- \note Since Qt 5.7, the use of this macro is discouraged. It will
- be removed in a future version of Qt. Please use C++11 range-for,
- possibly with qAsConst(), as needed.
-
- \sa qAsConst()
+ \note Since Qt 5.7, the use of this macro is discouraged.
+ Use C++11 range-based \c for, possibly with \c {std::as_const()},
+ as needed.
*/
/*!
@@ -68,9 +66,7 @@
This macro is available even when \c no_keywords is specified
using the \c .pro file's \c CONFIG variable.
- \note Since Qt 5.7, the use of this macro is discouraged. It will
- be removed in a future version of Qt. Please use C++11 range-for,
- possibly with qAsConst(), as needed.
-
- \sa qAsConst()
+ \note Since Qt 5.7, the use of this macro is discouraged.
+ Use C++11 range-based \c for, possibly with \c {std::as_const()},
+ as needed.
*/
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 238b9cf4b4..222c008f8a 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -12,15 +12,6 @@
#include "qnativeinterface.h"
#include "qnativeinterface_p.h"
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-
-#include <errno.h>
-#if defined(Q_CC_MSVC)
-# include <crtdbg.h>
-#endif
-
#ifdef Q_OS_WIN
# include <qt_windows.h>
#endif
@@ -42,12 +33,6 @@ extern "C" {
}
#endif
-#ifdef qFatal
-// the qFatal in this file are just redirections from elsewhere, so
-// don't capture any context again
-# undef qFatal
-#endif
-
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
@@ -100,14 +85,15 @@ using namespace Qt::StringLiterals;
\row \li \l <QtTranslation> \li Qt translation helpers
\row \li \l <QtTypeTraits> \li Qt type traits
\row \li \l <QtTypes> \li Qt fundamental type declarations
- \row \li \l <QtVersionChecks> \li Qt Version related checks
+ \row \li \l <QtVersionChecks> \li QT_VERSION_CHECK and related checks
+ \row \li \l <QtVersion> \li QT_VERSION_STR and qVersion()
\endtable
*/
/*
Dijkstra's bisection algorithm to find the square root of an integer.
- Deliberately not exported as part of the Qt API, but used in both
- qsimplerichtext.cpp and qgfxraster_qws.cpp
+ Deliberately not exported as part of the Qt API, but used in
+ qtextdocument.cpp.
*/
Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
{
@@ -132,35 +118,6 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION unsigned int qt_int_sqrt(unsigned int n)
return p;
}
-void qAbort()
-{
-#ifdef Q_OS_WIN
- // std::abort() in the MSVC runtime will call _exit(3) if the abort
- // behavior is _WRITE_ABORT_MSG - see also _set_abort_behavior(). This is
- // the default for a debug-mode build of the runtime. Worse, MinGW's
- // std::abort() implementation (in msvcrt.dll) is basically a call to
- // _exit(3) too. Unfortunately, _exit() and _Exit() *do* run the static
- // destructors of objects in DLLs, a violation of the C++ standard (see
- // [support.start.term]). So we bypass std::abort() and directly
- // terminate the application.
-
-# if defined(Q_CC_MSVC)
- if (IsProcessorFeaturePresent(PF_FASTFAIL_AVAILABLE))
- __fastfail(FAST_FAIL_FATAL_APP_EXIT);
-# else
- RaiseFailFastException(nullptr, nullptr, 0);
-# endif
-
- // Fallback
- TerminateProcess(GetCurrentProcess(), STATUS_FATAL_APP_EXIT);
-
- // Tell the compiler the application has stopped.
- Q_UNREACHABLE_IMPL();
-#else // !Q_OS_WIN
- std::abort();
-#endif
-}
-
// Also specified to behave as if they call tzset():
// localtime() -- but not localtime_r(), which we use when threaded
// strftime() -- not used (except in tests)
@@ -354,33 +311,49 @@ bool QInternal::activateCallbacks(Callback cb, void **parameters)
*/
/*!
- \macro QT_TERMINATE_ON_EXCEPTION(expr)
+ \macro QT_ENABLE_STRICT_MODE_UP_TO
\relates <QtGlobal>
- \internal
+ \since 6.8
+
+ Defining this macro will disable a number of Qt APIs that are
+ deemed suboptimal or dangerous.
+
+ This macro's value must be set to a Qt version, using
+ \l{QT_VERSION_CHECK}'s encoding. For instance, in order to set it
+ to Qt 6.6, define \c{QT_ENABLE_STRICT_MODE_UP_TO=0x060600}.
+ This will disable only the APIs introduced in versions up to (and
+ including) the specified Qt version.
+
+ If the \l QT_DISABLE_DEPRECATED_UP_TO macro is \e not defined,
+ then QT_ENABLE_STRICT_MODE_UP_TO will define it as well,
+ to the same value.
+
+ This macro should always be set to the minimum Qt version that
+ your project wants to support.
+
+ The APIs disabled by this macro are listed in the table below,
+ together with the minimum value to use in order to disable them.
+
+ \table
+ \header \li Version \li Disabled APIs
+ \row \li 6.0.0 \li \l{foreach-keyword}{foreach} (see \l{QT_NO_FOREACH})
+ \row \li 6.0.0 \li QString constructors from \c{const char *} (see \l{QT_NO_CAST_FROM_ASCII})
+ \row \li 6.0.0 \li QString conversions towards \c{const char *} / QByteArray (see \l{QT_NO_CAST_TO_ASCII})
+ \row \li 6.0.0 \li QByteArray implicit conversions towards \c{const char *} (see \l{QT_NO_CAST_FROM_BYTEARRAY})
+ \row \li 6.0.0 \li QUrl implicit conversions from QString (see \l{QT_NO_URL_CAST_FROM_STRING})
+ \row \li 6.0.0 \li Allowing narrowing conversions in signal-slot connections (see \l{QT_NO_NARROWING_CONVERSIONS_IN_CONNECT})
+ \row \li 6.0.0 \li Java-style iterators for Qt containers
+ \row \li 6.6.0 \li The qExchange() function (see \l{QT_NO_QEXCHANGE})
+ \row \li 6.7.0 \li Overloads of QObject::connect that do not take a context object (see \l{QT_NO_CONTEXTLESS_CONNECT})
+ \row \li 6.8.0 \li The qAsConst() function (see \l{QT_NO_QASCONST})
+ \row \li 6.8.0 \li File-related I/O classes have their \c{open()} functions marked \c{[[nodiscard]]} (see \l{QT_USE_NODISCARD_FILE_OPEN})
+ \endtable
+
+ Moreover, individual APIs may also get disabled as part of the
+ setting of QT_DISABLE_DEPRECATED_UP_TO. Please refer to each class'
+ documentation for more details.
- In general, use of the Q_DECL_NOEXCEPT macro is preferred over
- Q_DECL_NOTHROW, because it exhibits well-defined behavior and
- supports the more powerful Q_DECL_NOEXCEPT_EXPR variant. However,
- use of Q_DECL_NOTHROW has the advantage that Windows builds
- benefit on a wide range or compiler versions that do not yet
- support the C++11 noexcept feature.
-
- It may therefore be beneficial to use Q_DECL_NOTHROW and emulate
- the C++11 behavior manually with an embedded try/catch.
-
- Qt provides the QT_TERMINATE_ON_EXCEPTION(expr) macro for this
- purpose. It either expands to \c expr (if Qt is compiled without
- exception support or the compiler supports C++11 noexcept
- semantics) or to
- \snippet code/src_corelib_global_qglobal.cpp qterminate
- otherwise.
-
- Since this macro expands to just \c expr if the compiler supports
- C++11 noexcept, expecting the compiler to take over responsibility
- of calling std::terminate() in that case, it should not be used
- outside Q_DECL_NOTHROW functions.
-
- \sa Q_DECL_NOEXCEPT, Q_DECL_NOTHROW, qTerminate()
+ \sa QT_DISABLE_DEPRECATED_UP_TO, QT_NO_KEYWORDS, QT_VERSION_CHECK
*/
namespace QtPrivate {
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index f78d7e9445..1009057bad 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -27,20 +27,21 @@
#include <QtCore/qtpreprocessorsupport.h>
-#include <QtCore/qtnoop.h>
-
#include <QtCore/qsystemdetection.h>
#include <QtCore/qprocessordetection.h>
#include <QtCore/qcompilerdetection.h>
-#include <QtCore/qassert.h>
-#include <QtCore/qtypes.h>
-#include <QtCore/qtclasshelpermacros.h>
-
-
#ifndef __ASSEMBLER__
+# include <QtCore/qassert.h>
+# include <QtCore/qtnoop.h>
+# include <QtCore/qtypes.h>
+#endif /* !__ASSEMBLER__ */
+#include <QtCore/qtversion.h>
+
#if defined(__cplusplus)
+#include <QtCore/qtclasshelpermacros.h>
+
// We need to keep QTypeInfo, QSysInfo, QFlags, qDebug & family in qglobal.h for compatibility with Qt 4.
// Be careful when changing the order of these files.
#include <QtCore/qtypeinfo.h>
@@ -69,6 +70,5 @@
#include <QtCore/qversiontagging.h>
#endif /* __cplusplus */
-#endif /* !__ASSEMBLER__ */
#endif /* QGLOBAL_H */
diff --git a/src/corelib/global/qglobal_p.h b/src/corelib/global/qglobal_p.h
index d6e84acd3e..31f67510e3 100644
--- a/src/corelib/global/qglobal_p.h
+++ b/src/corelib/global/qglobal_p.h
@@ -52,21 +52,9 @@
#endif
#if defined(__cplusplus)
-#ifdef Q_CC_MINGW
-# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
-#endif
-#include <time.h>
-
QT_BEGIN_NAMESPACE
-// These behave as if they consult the environment, so need to share its locking:
-Q_CORE_EXPORT void qTzSet();
-Q_CORE_EXPORT time_t qMkTime(struct tm *when);
-
-#if !defined(Q_CC_MSVC)
-Q_NORETURN
-#endif
-Q_CORE_EXPORT void qAbort();
+Q_NORETURN Q_CORE_EXPORT void qAbort();
QT_END_NAMESPACE
@@ -142,4 +130,3 @@ QT_END_NAMESPACE
#endif // defined(__cplusplus)
#endif // QGLOBAL_P_H
-
diff --git a/src/corelib/global/qglobalstatic.h b/src/corelib/global/qglobalstatic.h
index d865e08fdd..93127adab3 100644
--- a/src/corelib/global/qglobalstatic.h
+++ b/src/corelib/global/qglobalstatic.h
@@ -1,12 +1,12 @@
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-
#ifndef QGLOBALSTATIC_H
#define QGLOBALSTATIC_H
+#include <QtCore/qassert.h>
#include <QtCore/qatomic.h>
+#include <QtCore/qtclasshelpermacros.h>
#include <atomic> // for bootstrapped (no thread) builds
#include <type_traits>
@@ -40,9 +40,18 @@ template <typename QGS> union Holder
~Holder()
{
+ // TSAN does not support atomic_thread_fence and GCC complains:
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=97868
+ // https://github.com/google/sanitizers/issues/1352
+QT_WARNING_PUSH
+#if defined(Q_CC_GNU_ONLY) && Q_CC_GNU >= 1100
+QT_WARNING_DISABLE_GCC("-Wtsan")
+#endif
+ // import changes to *pointer() by other threads before running ~PlainType():
+ std::atomic_thread_fence(std::memory_order_acquire);
+QT_WARNING_POP
pointer()->~PlainType();
- std::atomic_thread_fence(std::memory_order_acquire); // avoid mixing stores to guard and *pointer()
- guard.storeRelaxed(QtGlobalStatic::Destroyed);
+ guard.storeRelease(QtGlobalStatic::Destroyed);
}
PlainType *pointer() noexcept
@@ -74,13 +83,13 @@ template <typename Holder> struct QGlobalStatic
}
Type *operator->()
{
- Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC",
+ Q_ASSERT_X(!isDestroyed(), Q_FUNC_INFO,
"The global static was used after being destroyed");
return instance();
}
Type &operator*()
{
- Q_ASSERT_X(!isDestroyed(), "Q_GLOBAL_STATIC",
+ Q_ASSERT_X(!isDestroyed(), Q_FUNC_INFO,
"The global static was used after being destroyed");
return *instance();
}
diff --git a/src/corelib/global/qlibraryinfo.cpp b/src/corelib/global/qlibraryinfo.cpp
index 64fc9fff01..92729b06f1 100644
--- a/src/corelib/global/qlibraryinfo.cpp
+++ b/src/corelib/global/qlibraryinfo.cpp
@@ -87,10 +87,19 @@ void QLibrarySettings::load()
}
}
+namespace {
+const QString *qtconfManualPath = nullptr;
+}
+
+void QLibraryInfoPrivate::setQtconfManualPath(const QString *path)
+{
+ qtconfManualPath = path;
+}
+
static QSettings *findConfiguration()
{
- if (QLibraryInfoPrivate::qtconfManualPath)
- return new QSettings(*QLibraryInfoPrivate::qtconfManualPath, QSettings::IniFormat);
+ if (qtconfManualPath)
+ return new QSettings(*qtconfManualPath, QSettings::IniFormat);
QString qtconfig = QStringLiteral(":/qt/etc/qt.conf");
if (QFile::exists(qtconfig))
@@ -122,8 +131,6 @@ static QSettings *findConfiguration()
return nullptr; //no luck
}
-const QString *QLibraryInfoPrivate::qtconfManualPath = nullptr;
-
QSettings *QLibraryInfoPrivate::configuration()
{
QLibrarySettings *ls = qt_library_settings();
@@ -365,6 +372,11 @@ static QString getRelocatablePrefix(QLibraryInfoPrivate::UsageMode usageMode)
const QString prefixDir = QString(libDirCFString) + "/" QT_CONFIGURE_LIBLOCATION_TO_PREFIX_PATH;
prefixPath = QDir::cleanPath(prefixDir);
+#elif defined(Q_OS_WASM)
+ // Emscripten expects to find shared libraries at the root of the in-memory
+ // file system when resolving dependencies for for dlopen() calls. So that's
+ // where libqt6core.so would be.
+ prefixPath = QStringLiteral("/");
#elif QT_CONFIG(dlopen)
Q_UNUSED(usageMode);
Dl_info info;
@@ -475,9 +487,8 @@ QLibraryInfoPrivate::LocationInfo QLibraryInfoPrivate::locationInfo(QLibraryInfo
"Examples", "examples",
"Tests", "tests"
);
- static constexpr QByteArrayView dot = qtConfEntries.viewAt(1);
- static_assert(dot.size() == 1);
- static_assert(dot[0] == '.');
+ [[maybe_unused]]
+ constexpr QByteArrayView dot{"."};
LocationInfo result;
@@ -542,8 +553,8 @@ QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMo
ret = v.toString();
}
- int startIndex = 0;
- forever {
+ qsizetype startIndex = 0;
+ while (true) {
startIndex = ret.indexOf(u'$', startIndex);
if (startIndex < 0)
break;
@@ -553,7 +564,7 @@ QString QLibraryInfoPrivate::path(QLibraryInfo::LibraryPath p, UsageMode usageMo
startIndex++;
continue;
}
- int endIndex = ret.indexOf(u')', startIndex + 2);
+ qsizetype endIndex = ret.indexOf(u')', startIndex + 2);
if (endIndex < 0)
break;
auto envVarName = QStringView{ret}.mid(startIndex + 2, endIndex - startIndex - 2);
@@ -661,7 +672,7 @@ QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
/*!
\macro QT_VERSION_STR
- \relates <QLibraryInfo>
+ \relates <QtVersion>
This macro expands to a string that specifies Qt's version number (for
example, "6.1.2"). This is the version with which the application is
@@ -672,7 +683,7 @@ QStringList QLibraryInfo::platformPluginArguments(const QString &platformName)
*/
/*!
- \relates <QLibraryInfo>
+ \relates <QtVersion>
Returns the version number of Qt at runtime as a string (for example,
"6.1.2"). This is the version of the Qt library in use at \e runtime,
@@ -745,13 +756,14 @@ extern "C" void qt_core_boilerplate() __attribute__((force_align_arg_pointer));
void qt_core_boilerplate()
{
printf("This is the QtCore library version %s\n"
- "Copyright (C) 2016 The Qt Company Ltd.\n"
- "Contact: http://www.qt.io/licensing/\n"
+ "%s\n"
+ "Contact: https://www.qt.io/licensing/\n"
"\n"
"Installation prefix: %s\n"
"Library path: %s\n"
"Plugin path: %s\n",
QT_PREPEND_NAMESPACE(qt_build_string)(),
+ QT_COPYRIGHT,
QT_CONFIGURE_PREFIX_PATH,
qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::LibrariesPath - 1],
qt_configure_strs[QT_PREPEND_NAMESPACE(QLibraryInfo)::PluginsPath - 1]);
diff --git a/src/corelib/global/qlibraryinfo.h b/src/corelib/global/qlibraryinfo.h
index 71d9a01308..d4e8f8b050 100644
--- a/src/corelib/global/qlibraryinfo.h
+++ b/src/corelib/global/qlibraryinfo.h
@@ -4,18 +4,12 @@
#ifndef QLIBRARYINFO_H
#define QLIBRARYINFO_H
-#if defined(__cplusplus)
#include <QtCore/qstring.h>
#include <QtCore/qdatetime.h>
#include <QtCore/qversionnumber.h>
-#else
-#include <QtCore/qglobal.h>
-#endif
QT_BEGIN_NAMESPACE
-#if defined(__cplusplus)
-
class Q_CORE_EXPORT QLibraryInfo
{
public:
@@ -67,21 +61,6 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION bool qSharedBuild() noexcept;
#endif
-#endif // __cplusplus
-
-/*
- * If we're compiling C++ code:
- * - and this is a non-namespace build, declare qVersion as extern "C"
- * - and this is a namespace build, declare it as a regular function
- * (we're already inside QT_BEGIN_NAMESPACE / QT_END_NAMESPACE)
- * If we're compiling C code, simply declare the function. If Qt was compiled
- * in a namespace, qVersion isn't callable anyway.
- */
-#if !defined(QT_NAMESPACE) && defined(__cplusplus) && !defined(Q_QDOC)
-extern "C"
-#endif
-Q_CORE_EXPORT Q_DECL_CONST_FUNCTION const char *qVersion(void) Q_DECL_NOEXCEPT;
-
QT_END_NAMESPACE
#endif // QLIBRARYINFO_H
diff --git a/src/corelib/global/qlibraryinfo_p.h b/src/corelib/global/qlibraryinfo_p.h
index d3c458290b..4b471b932e 100644
--- a/src/corelib/global/qlibraryinfo_p.h
+++ b/src/corelib/global/qlibraryinfo_p.h
@@ -32,7 +32,7 @@ public:
#if QT_CONFIG(settings)
static QSettings *configuration();
static void reload();
- static const QString *qtconfManualPath;
+ static void setQtconfManualPath(const QString *qtconfManualPath);
#endif
struct LocationInfo
diff --git a/src/corelib/global/qlogging.cpp b/src/corelib/global/qlogging.cpp
index b64099b7c9..dec16e4a77 100644
--- a/src/corelib/global/qlogging.cpp
+++ b/src/corelib/global/qlogging.cpp
@@ -23,7 +23,6 @@
#include "qthread.h"
#include "private/qloggingregistry_p.h"
#include "private/qcoreapplication_p.h"
-#include "private/qsimd_p.h"
#include <qtcore_tracepoints_p.h>
#endif
#ifdef Q_OS_WIN
@@ -70,17 +69,19 @@
extern char *__progname;
#endif
-#ifndef QT_BOOTSTRAPPED
-#if __has_include(<cxxabi.h>) && QT_CONFIG(backtrace) && QT_CONFIG(regularexpression)
+#ifdef QLOGGING_HAVE_BACKTRACE
# include <qregularexpression.h>
+#endif
+
+#ifdef QLOGGING_USE_EXECINFO_BACKTRACE
# if QT_CONFIG(dladdr)
# include <dlfcn.h>
# endif
# include BACKTRACE_HEADER
# include <cxxabi.h>
-# define QLOGGING_HAVE_BACKTRACE
-#endif
+#endif // QLOGGING_USE_EXECINFO_BACKTRACE
+#ifndef QT_BOOTSTRAPPED
#if defined(Q_OS_LINUX) && (defined(__GLIBC__) || __has_include(<sys/syscall.h>))
# include <sys/syscall.h>
@@ -129,6 +130,10 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+#ifndef QT_BOOTSTRAPPED
+Q_TRACE_POINT(qtcore, qt_message_print, int type, const char *category, const char *function, const char *file, int line, const QString &message);
+#endif
+
/*!
\headerfile <QtLogging>
\inmodule QtCore
@@ -159,12 +164,15 @@ using namespace Qt::StringLiterals;
\snippet code/src_corelib_global_qglobal.cpp 4
*/
-#if !defined(Q_CC_MSVC)
+template <typename String>
+#if !defined(Q_CC_MSVC_ONLY)
Q_NORETURN
#endif
-static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message);
+static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, String &&message);
static void qt_message_print(QtMsgType, const QMessageLogContext &context, const QString &message);
-static void qt_message_print(const QString &message);
+static void preformattedMessageHandler(QtMsgType type, const QMessageLogContext &context,
+ const QString &formattedMessage);
+static QString formatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str);
static int checked_var_value(const char *varname)
{
@@ -180,6 +188,17 @@ static int checked_var_value(const char *varname)
return ok ? value : 1;
}
+static bool is_fatal_count_down(QAtomicInt &n)
+{
+ // it's fatal if the current value is exactly 1,
+ // otherwise decrement if it's non-zero
+
+ int v = n.loadRelaxed();
+ while (v != 0 && !n.testAndSetRelaxed(v, v - 1, v))
+ qYieldCpu();
+ return v == 1; // we exited the loop, so either v == 0 or CAS succeeded to set n from v to v-1
+}
+
static bool isFatal(QtMsgType msgType)
{
if (msgType == QtFatalMsg)
@@ -187,28 +206,17 @@ static bool isFatal(QtMsgType msgType)
if (msgType == QtCriticalMsg) {
static QAtomicInt fatalCriticals = checked_var_value("QT_FATAL_CRITICALS");
-
- // it's fatal if the current value is exactly 1,
- // otherwise decrement if it's non-zero
- return fatalCriticals.loadRelaxed() && fatalCriticals.fetchAndAddRelaxed(-1) == 1;
+ return is_fatal_count_down(fatalCriticals);
}
if (msgType == QtWarningMsg || msgType == QtCriticalMsg) {
static QAtomicInt fatalWarnings = checked_var_value("QT_FATAL_WARNINGS");
-
- // it's fatal if the current value is exactly 1,
- // otherwise decrement if it's non-zero
- return fatalWarnings.loadRelaxed() && fatalWarnings.fetchAndAddRelaxed(-1) == 1;
+ return is_fatal_count_down(fatalWarnings);
}
return false;
}
-static bool isDefaultCategory(const char *category)
-{
- return !category || strcmp(category, "default") == 0;
-}
-
/*!
Returns true if writing to \c stderr is supported.
@@ -220,6 +228,8 @@ static bool systemHasStderr()
return true;
}
+#ifndef Q_OS_WASM
+
/*!
Returns true if writing to \c stderr will end up in a console/terminal visible to the user.
@@ -304,6 +314,8 @@ bool shouldLogToStderr()
using namespace QtPrivate;
+#endif // ifndef Q_OS_WASM
+
/*!
\class QMessageLogContext
\inmodule QtCore
@@ -338,7 +350,7 @@ using namespace QtPrivate;
\sa QMessageLogContext, qDebug(), qInfo(), qWarning(), qCritical(), qFatal()
*/
-#if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
+#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
static inline void convert_to_wchar_t_elided(wchar_t *d, size_t space, const char *s) noexcept
{
size_t len = qstrlen(s);
@@ -359,14 +371,15 @@ static inline void convert_to_wchar_t_elided(wchar_t *d, size_t space, const cha
\internal
*/
Q_NEVER_INLINE
-static QString qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
+static void qt_message(QtMsgType msgType, const QMessageLogContext &context, const char *msg, va_list ap)
{
QString buf = QString::vasprintf(msg, ap);
qt_message_print(msgType, context, buf);
- return buf;
+
+ if (isFatal(msgType))
+ qt_message_fatal(msgType, context, buf);
}
-#undef qDebug
/*!
Logs a debug message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -375,17 +388,13 @@ static QString qt_message(QtMsgType msgType, const QMessageLogContext &context,
*/
void QMessageLogger::debug(const char *msg, ...) const
{
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtDebugMsg, context, msg, ap);
+ qt_message(QtDebugMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtDebugMsg))
- qt_message_fatal(QtDebugMsg, context, message);
}
-
-#undef qInfo
/*!
Logs an informational message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -395,13 +404,11 @@ void QMessageLogger::debug(const char *msg, ...) const
*/
void QMessageLogger::info(const char *msg, ...) const
{
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtInfoMsg, context, msg, ap);
+ qt_message(QtInfoMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtInfoMsg))
- qt_message_fatal(QtInfoMsg, context, message);
}
/*!
@@ -430,17 +437,12 @@ void QMessageLogger::debug(const QLoggingCategory &cat, const char *msg, ...) co
if (!cat.isDebugEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtDebugMsg, ctxt, msg, ap);
+ qt_message(QtDebugMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtDebugMsg))
- qt_message_fatal(QtDebugMsg, ctxt, message);
}
/*!
@@ -457,17 +459,12 @@ void QMessageLogger::debug(QMessageLogger::CategoryFunction catFunc,
if (!cat.isDebugEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtDebugMsg, ctxt, msg, ap);
+ qt_message(QtDebugMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtDebugMsg))
- qt_message_fatal(QtDebugMsg, ctxt, message);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -541,17 +538,12 @@ void QMessageLogger::info(const QLoggingCategory &cat, const char *msg, ...) con
if (!cat.isInfoEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtInfoMsg, ctxt, msg, ap);
+ qt_message(QtInfoMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtInfoMsg))
- qt_message_fatal(QtInfoMsg, ctxt, message);
}
/*!
@@ -568,17 +560,12 @@ void QMessageLogger::info(QMessageLogger::CategoryFunction catFunc,
if (!cat.isInfoEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtInfoMsg, ctxt, msg, ap);
+ qt_message(QtInfoMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtInfoMsg))
- qt_message_fatal(QtInfoMsg, ctxt, message);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -629,7 +616,6 @@ QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc) const
#endif
-#undef qWarning
/*!
Logs a warning message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -638,13 +624,11 @@ QDebug QMessageLogger::info(QMessageLogger::CategoryFunction catFunc) const
*/
void QMessageLogger::warning(const char *msg, ...) const
{
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtWarningMsg, context, msg, ap);
+ qt_message(QtWarningMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtWarningMsg))
- qt_message_fatal(QtWarningMsg, context, message);
}
/*!
@@ -659,17 +643,12 @@ void QMessageLogger::warning(const QLoggingCategory &cat, const char *msg, ...)
if (!cat.isWarningEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtWarningMsg, ctxt, msg, ap);
+ qt_message(QtWarningMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtWarningMsg))
- qt_message_fatal(QtWarningMsg, ctxt, message);
}
/*!
@@ -686,17 +665,12 @@ void QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc,
if (!cat.isWarningEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtWarningMsg, ctxt, msg, ap);
+ qt_message(QtWarningMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtWarningMsg))
- qt_message_fatal(QtWarningMsg, ctxt, message);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -744,8 +718,6 @@ QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc) const
#endif
-#undef qCritical
-
/*!
Logs a critical message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -754,13 +726,11 @@ QDebug QMessageLogger::warning(QMessageLogger::CategoryFunction catFunc) const
*/
void QMessageLogger::critical(const char *msg, ...) const
{
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtCriticalMsg, context, msg, ap);
+ qt_message(QtCriticalMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtCriticalMsg))
- qt_message_fatal(QtCriticalMsg, context, message);
}
/*!
@@ -775,17 +745,12 @@ void QMessageLogger::critical(const QLoggingCategory &cat, const char *msg, ...)
if (!cat.isCriticalEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtCriticalMsg, ctxt, msg, ap);
+ qt_message(QtCriticalMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtCriticalMsg))
- qt_message_fatal(QtCriticalMsg, ctxt, message);
}
/*!
@@ -802,17 +767,12 @@ void QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc,
if (!cat.isCriticalEnabled())
return;
- QMessageLogContext ctxt;
- ctxt.copyContextFrom(context);
- ctxt.category = cat.categoryName();
+ QInternalMessageLogContext ctxt(context, cat());
va_list ap;
va_start(ap, msg); // use variable arg list
- const QString message = qt_message(QtCriticalMsg, ctxt, msg, ap);
+ qt_message(QtCriticalMsg, ctxt, msg, ap);
va_end(ap);
-
- if (isFatal(QtCriticalMsg))
- qt_message_fatal(QtCriticalMsg, ctxt, message);
}
#ifndef QT_NO_DEBUG_STREAM
@@ -861,7 +821,51 @@ QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc) const
#endif
-#undef qFatal
+/*!
+ Logs a fatal message specified with format \a msg for the context \a cat.
+ Additional parameters, specified by \a msg, may be used.
+
+ \since 6.5
+ \sa qCFatal()
+*/
+void QMessageLogger::fatal(const QLoggingCategory &cat, const char *msg, ...) const noexcept
+{
+ QInternalMessageLogContext ctxt(context, cat());
+
+ va_list ap;
+ va_start(ap, msg); // use variable arg list
+ QT_TERMINATE_ON_EXCEPTION(qt_message(QtFatalMsg, ctxt, msg, ap));
+ va_end(ap);
+
+#ifndef Q_CC_MSVC_ONLY
+ Q_UNREACHABLE();
+#endif
+}
+
+/*!
+ Logs a fatal message specified with format \a msg for the context returned
+ by \a catFunc. Additional parameters, specified by \a msg, may be used.
+
+ \since 6.5
+ \sa qCFatal()
+*/
+void QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc,
+ const char *msg, ...) const noexcept
+{
+ const QLoggingCategory &cat = (*catFunc)();
+
+ QInternalMessageLogContext ctxt(context, cat());
+
+ va_list ap;
+ va_start(ap, msg); // use variable arg list
+ QT_TERMINATE_ON_EXCEPTION(qt_message(QtFatalMsg, ctxt, msg, ap));
+ va_end(ap);
+
+#ifndef Q_CC_MSVC_ONLY
+ Q_UNREACHABLE();
+#endif
+}
+
/*!
Logs a fatal message specified with format \a msg. Additional
parameters, specified by \a msg, may be used.
@@ -870,14 +874,66 @@ QDebug QMessageLogger::critical(QMessageLogger::CategoryFunction catFunc) const
*/
void QMessageLogger::fatal(const char *msg, ...) const noexcept
{
- QString message;
-
+ QInternalMessageLogContext ctxt(context);
va_list ap;
va_start(ap, msg); // use variable arg list
- QT_TERMINATE_ON_EXCEPTION(message = qt_message(QtFatalMsg, context, msg, ap));
+ QT_TERMINATE_ON_EXCEPTION(qt_message(QtFatalMsg, ctxt, msg, ap));
va_end(ap);
- qt_message_fatal(QtFatalMsg, context, message);
+#ifndef Q_CC_MSVC_ONLY
+ Q_UNREACHABLE();
+#endif
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+/*!
+ Logs a fatal message using a QDebug stream.
+
+ \since 6.5
+
+ \sa qFatal(), QDebug
+*/
+QDebug QMessageLogger::fatal() const
+{
+ QDebug dbg = QDebug(QtFatalMsg);
+ QMessageLogContext &ctxt = dbg.stream->context;
+ ctxt.copyContextFrom(context);
+ return dbg;
+}
+
+/*!
+ Logs a fatal message into category \a cat using a QDebug stream.
+
+ \since 6.5
+ \sa qCFatal(), QDebug
+*/
+QDebug QMessageLogger::fatal(const QLoggingCategory &cat) const
+{
+ QDebug dbg = QDebug(QtFatalMsg);
+
+ QMessageLogContext &ctxt = dbg.stream->context;
+ ctxt.copyContextFrom(context);
+ ctxt.category = cat.categoryName();
+
+ return dbg;
+}
+
+/*!
+ Logs a fatal message into category returned by \a catFunc using a QDebug stream.
+
+ \since 6.5
+ \sa qCFatal(), QDebug
+*/
+QDebug QMessageLogger::fatal(QMessageLogger::CategoryFunction catFunc) const
+{
+ return fatal((*catFunc)());
+}
+#endif // QT_NO_DEBUG_STREAM
+
+#if !defined(QT_BOOTSTRAPPED)
+static bool isDefaultCategory(const char *category)
+{
+ return !category || strcmp(category, "default") == 0;
}
/*!
@@ -892,15 +948,20 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
if (info.isEmpty())
return info;
- int pos;
+ qsizetype pos;
// Skip trailing [with XXX] for templates (gcc), but make
// sure to not affect Objective-C message names.
pos = info.size() - 1;
if (info.endsWith(']') && !(info.startsWith('+') || info.startsWith('-'))) {
while (--pos) {
- if (info.at(pos) == '[')
- info.truncate(pos);
+ if (info.at(pos) == '[') {
+ info.truncate(pos);
+ break;
+ }
+ }
+ if (info.endsWith(' ')) {
+ info.chop(1);
}
}
@@ -914,14 +975,21 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
// canonize operator names
info.replace("operator ", "operator");
+ pos = -1;
// remove argument list
forever {
int parencount = 0;
- pos = info.lastIndexOf(')');
+ pos = info.lastIndexOf(')', pos);
if (pos == -1) {
// Don't know how to parse this function name
return info;
}
+ if (info.indexOf('>', pos) != -1
+ || info.indexOf(':', pos) != -1) {
+ // that wasn't the function argument list.
+ --pos;
+ continue;
+ }
// find the beginning of the argument list
--pos;
@@ -939,7 +1007,7 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
info.truncate(++pos);
if (info.at(pos - 1) == ')') {
- if (info.indexOf(operator_call) == pos - (int)strlen(operator_call))
+ if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)))
break;
// this function returns a pointer to a function
@@ -962,19 +1030,19 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
if (pos > -1) {
switch (info.at(pos)) {
case ')':
- if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1)
+ if (info.indexOf(operator_call) == pos - qsizetype(strlen(operator_call)) + 1)
pos -= 2;
break;
case '<':
- if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1)
+ if (info.indexOf(operator_lessThan) == pos - qsizetype(strlen(operator_lessThan)) + 1)
--pos;
break;
case '>':
- if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1)
+ if (info.indexOf(operator_greaterThan) == pos - qsizetype(strlen(operator_greaterThan)) + 1)
--pos;
break;
case '=': {
- int operatorLength = (int)strlen(operator_lessThanEqual);
+ auto operatorLength = qsizetype(strlen(operator_lessThanEqual));
if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1)
pos -= 2;
else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1)
@@ -1018,7 +1086,7 @@ Q_AUTOTEST_EXPORT QByteArray qCleanupFuncinfo(QByteArray info)
break;
// find the matching close
- int end = pos;
+ qsizetype end = pos;
templatecount = 1;
--pos;
while (pos && templatecount) {
@@ -1081,6 +1149,7 @@ struct QMessagePattern
int backtraceDepth;
};
QList<BacktraceParams> backtraceArgs; // backtrace arguments in sequence of %{backtrace
+ int maxBacktraceDepth = 0;
#endif
bool fromEnvironment;
@@ -1114,6 +1183,7 @@ void QMessagePattern::setPattern(const QString &pattern)
timeArgs.clear();
#ifdef QLOGGING_HAVE_BACKTRACE
backtraceArgs.clear();
+ maxBacktraceDepth = 0;
#endif
// scanner
@@ -1181,7 +1251,7 @@ void QMessagePattern::setPattern(const QString &pattern)
tokens[i] = qthreadptrTokenC;
else if (lexeme.startsWith(QLatin1StringView(timeTokenC))) {
tokens[i] = timeTokenC;
- int spaceIdx = lexeme.indexOf(QChar::fromLatin1(' '));
+ qsizetype spaceIdx = lexeme.indexOf(QChar::fromLatin1(' '));
if (spaceIdx > 0)
timeArgs.append(lexeme.mid(spaceIdx + 1, lexeme.size() - spaceIdx - 2));
else
@@ -1208,6 +1278,7 @@ void QMessagePattern::setPattern(const QString &pattern)
backtraceParams.backtraceDepth = backtraceDepth;
backtraceParams.backtraceSeparator = backtraceSeparator;
backtraceArgs.append(backtraceParams);
+ maxBacktraceDepth = qMax(maxBacktraceDepth, backtraceDepth);
#else
error += "QT_MESSAGE_PATTERN: %{backtrace} is not supported by this Qt build\n"_L1;
tokens[i] = "";
@@ -1235,15 +1306,11 @@ void QMessagePattern::setPattern(const QString &pattern)
inIf = false;
} else {
tokens[i] = emptyTokenC;
- error += QStringLiteral("QT_MESSAGE_PATTERN: Unknown placeholder %1\n")
- .arg(lexeme);
+ error += "QT_MESSAGE_PATTERN: Unknown placeholder "_L1 + lexeme + '\n'_L1;
}
} else {
- char *literal = new char[lexeme.size() + 1];
- strncpy(literal, lexeme.toLatin1().constData(), lexeme.size());
- literal[lexeme.size()] = '\0';
- literalsVar.emplace_back(literal);
- tokens[i] = literal;
+ using UP = std::unique_ptr<char[]>;
+ tokens[i] = literalsVar.emplace_back(UP(qstrdup(lexeme.toLatin1().constData()))).get();
}
}
if (nestedIfError)
@@ -1251,35 +1318,94 @@ void QMessagePattern::setPattern(const QString &pattern)
else if (inIf)
error += "QT_MESSAGE_PATTERN: missing %{endif}\n"_L1;
- if (!error.isEmpty())
- qt_message_print(error);
+ if (!error.isEmpty()) {
+ // remove the last '\n' because the sinks deal with that on their own
+ error.chop(1);
+
+ QMessageLogContext ctx(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE,
+ "QMessagePattern::setPattern", nullptr);
+ preformattedMessageHandler(QtWarningMsg, ctx, error);
+ }
literals.reset(new std::unique_ptr<const char[]>[literalsVar.size() + 1]);
std::move(literalsVar.begin(), literalsVar.end(), &literals[0]);
}
-#if defined(QLOGGING_HAVE_BACKTRACE) && !defined(QT_BOOTSTRAPPED)
+#if defined(QLOGGING_HAVE_BACKTRACE)
// make sure the function has "Message" in the name so the function is removed
/*
A typical backtrace in debug mode looks like:
- #0 backtraceFramesForLogMessage (frameCount=5) at qlogging.cpp:1296
- #1 formatBacktraceForLogMessage (backtraceParams=..., function=0x4040b8 "virtual void MyClass::myFunction(int)") at qlogging.cpp:1344
- #2 qFormatLogMessage (type=QtDebugMsg, context=..., str=...) at qlogging.cpp:1452
- #3 stderr_message_handler (type=QtDebugMsg, context=..., message=...) at qlogging.cpp:1744
- #4 qDefaultMessageHandler (type=QtDebugMsg, context=..., message=...) at qlogging.cpp:1795
- #5 qt_message_print (msgType=QtDebugMsg, context=..., message=...) at qlogging.cpp:1840
- #6 qt_message_output (msgType=QtDebugMsg, context=..., message=...) at qlogging.cpp:1891
- #7 QDebug::~QDebug (this=<optimized out>, __in_chrg=<optimized out>) at qdebug.h:111
+ #0 QInternalMessageLogContext::populateBacktrace (this=0x7fffffffd660, frameCount=5) at qlogging.cpp:1342
+ #1 QInternalMessageLogContext::QInternalMessageLogContext (logContext=..., this=<optimized out>) at qlogging_p.h:42
+ #2 QDebug::~QDebug (this=0x7fffffffdac8, __in_chrg=<optimized out>) at qdebug.cpp:160
+
+ In release mode, the QInternalMessageLogContext constructor will be usually
+ inlined. Empirical testing with GCC 13 and Clang 17 suggest they do obey the
+ Q_ALWAYS_INLINE in that constructor even in debug mode and do inline it.
+ Unfortunately, we can't know for sure if it has been.
*/
-static constexpr int TypicalBacktraceFrameCount = 8;
+static constexpr int TypicalBacktraceFrameCount = 3;
+static constexpr const char *QtCoreLibraryName = "Qt" QT_STRINGIFY(QT_VERSION_MAJOR) "Core";
-# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
-// force skipping the frame pointer, to save the backtrace() function some work
-# pragma GCC push_options
-# pragma GCC optimize ("omit-frame-pointer")
-# endif
+#if defined(QLOGGING_USE_STD_BACKTRACE)
+Q_NEVER_INLINE void QInternalMessageLogContext::populateBacktrace(int frameCount)
+{
+ assert(frameCount >= 0);
+ backtrace = std::stacktrace::current(0, TypicalBacktraceFrameCount + frameCount);
+}
+
+static QStringList
+backtraceFramesForLogMessage(int frameCount,
+ const QInternalMessageLogContext::BacktraceStorage &buffer)
+{
+ QStringList result;
+ result.reserve(buffer.size());
+
+ const auto shouldSkipFrame = [](QByteArrayView description)
+ {
+#if defined(_MSVC_STL_VERSION)
+ const auto libraryNameEnd = description.indexOf('!');
+ if (libraryNameEnd != -1) {
+ const auto libraryName = description.first(libraryNameEnd);
+ if (!libraryName.contains(QtCoreLibraryName))
+ return false;
+ }
+#endif
+ if (description.contains("populateBacktrace"))
+ return true;
+ if (description.contains("QInternalMessageLogContext"))
+ return true;
+ if (description.contains("~QDebug"))
+ return true;
+ return false;
+ };
+
+ for (const auto &entry : buffer) {
+ const std::string description = entry.description();
+ if (result.isEmpty() && shouldSkipFrame(description))
+ continue;
+ result.append(QString::fromStdString(description));
+ }
+
+ return result;
+}
-static QStringList backtraceFramesForLogMessage(int frameCount)
+#elif defined(QLOGGING_USE_EXECINFO_BACKTRACE)
+
+Q_NEVER_INLINE void QInternalMessageLogContext::populateBacktrace(int frameCount)
+{
+ assert(frameCount >= 0);
+ BacktraceStorage &result = backtrace.emplace(TypicalBacktraceFrameCount + frameCount);
+ int n = ::backtrace(result.data(), result.size());
+ if (n <= 0)
+ result.clear();
+ else
+ result.resize(n);
+}
+
+static QStringList
+backtraceFramesForLogMessage(int frameCount,
+ const QInternalMessageLogContext::BacktraceStorage &buffer)
{
struct DecodedFrame {
QString library;
@@ -1290,20 +1416,18 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
if (frameCount == 0)
return result;
- QVarLengthArray<void *, 32> buffer(TypicalBacktraceFrameCount + frameCount);
- int n = backtrace(buffer.data(), buffer.size());
- if (n <= 0)
- return result;
- buffer.resize(n);
-
auto shouldSkipFrame = [&result](const auto &library, const auto &function) {
- if (!result.isEmpty() || !library.contains("Qt6Core"_L1))
+ if (!result.isEmpty() || !library.contains(QLatin1StringView(QtCoreLibraryName)))
return false;
if (function.isEmpty())
return true;
if (function.contains("6QDebug"_L1))
return true;
- if (function.contains("Message"_L1) || function.contains("_message"_L1))
+ if (function.contains("14QMessageLogger"_L1))
+ return true;
+ if (function.contains("17qt_message_output"_L1))
+ return true;
+ if (function.contains("26QInternalMessageLogContext"_L1))
return true;
return false;
};
@@ -1382,7 +1506,7 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
};
# endif
- for (void *&addr : buffer) {
+ for (void *const &addr : buffer) {
DecodedFrame frame = decodeFrame(addr);
if (!frame.library.isEmpty()) {
if (frame.function.isEmpty())
@@ -1400,27 +1524,34 @@ static QStringList backtraceFramesForLogMessage(int frameCount)
}
return result;
}
+#else
+#error "Internal error: backtrace enabled, but no way to gather backtraces available"
+#endif // QLOGGING_USE_..._BACKTRACE
static QString formatBacktraceForLogMessage(const QMessagePattern::BacktraceParams backtraceParams,
- const char *function)
+ const QMessageLogContext &ctx)
{
+ // do we have a backtrace stored?
+ if (ctx.version <= QMessageLogContext::CurrentVersion)
+ return QString();
+
+ auto &fullctx = static_cast<const QInternalMessageLogContext &>(ctx);
+ if (!fullctx.backtrace.has_value())
+ return QString();
+
QString backtraceSeparator = backtraceParams.backtraceSeparator;
int backtraceDepth = backtraceParams.backtraceDepth;
- QStringList frames = backtraceFramesForLogMessage(backtraceDepth);
+ QStringList frames = backtraceFramesForLogMessage(backtraceDepth, *fullctx.backtrace);
if (frames.isEmpty())
return QString();
// if the first frame is unknown, replace it with the context function
- if (function && frames.at(0).startsWith(u'?'))
- frames[0] = QString::fromUtf8(qCleanupFuncinfo(function));
+ if (ctx.function && frames.at(0).startsWith(u'?'))
+ frames[0] = QString::fromUtf8(qCleanupFuncinfo(ctx.function));
return frames.join(backtraceSeparator);
}
-
-# if defined(Q_CC_GNU) && !defined(Q_CC_CLANG)
-# pragma GCC pop_options
-# endif
#endif // QLOGGING_HAVE_BACKTRACE && !QT_BOOTSTRAPPED
Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
@@ -1441,6 +1572,14 @@ Q_GLOBAL_STATIC(QMessagePattern, qMessagePattern)
*/
QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
{
+ return formatLogMessage(type, context, str);
+}
+
+// Separate function so the default message handler can bypass the public,
+// exported function above. Static functions can't get added to the dynamic
+// symbol tables, so they never show up in backtrace_symbols() or equivalent.
+static QString formatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
+{
QString message;
const auto locker = qt_scoped_lock(QMessagePattern::mutex);
@@ -1454,12 +1593,10 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
bool skip = false;
-#ifndef QT_BOOTSTRAPPED
int timeArgsIdx = 0;
#ifdef QLOGGING_HAVE_BACKTRACE
int backtraceArgsIdx = 0;
#endif
-#endif
// we do not convert file, function, line literals to local encoding due to overhead
for (int i = 0; pattern->tokens[i]; ++i) {
@@ -1469,14 +1606,12 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
} else if (skip) {
// we skip adding messages, but we have to iterate over
// timeArgsIdx and backtraceArgsIdx anyway
-#ifndef QT_BOOTSTRAPPED
if (token == timeTokenC)
timeArgsIdx++;
#ifdef QLOGGING_HAVE_BACKTRACE
else if (token == backtraceTokenC)
backtraceArgsIdx++;
#endif
-#endif
} else if (token == messageTokenC) {
message.append(str);
} else if (token == categoryTokenC) {
@@ -1504,7 +1639,6 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
message.append(QString::fromLatin1(qCleanupFuncinfo(context.function)));
else
message.append("unknown"_L1);
-#ifndef QT_BOOTSTRAPPED
} else if (token == pidTokenC) {
message.append(QString::number(QCoreApplication::applicationPid()));
} else if (token == appnameTokenC) {
@@ -1519,18 +1653,18 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
} else if (token == backtraceTokenC) {
QMessagePattern::BacktraceParams backtraceParams = pattern->backtraceArgs.at(backtraceArgsIdx);
backtraceArgsIdx++;
- message.append(formatBacktraceForLogMessage(backtraceParams, context.function));
+ message.append(formatBacktraceForLogMessage(backtraceParams, context));
#endif
} else if (token == timeTokenC) {
QString timeFormat = pattern->timeArgs.at(timeArgsIdx);
timeArgsIdx++;
if (timeFormat == "process"_L1) {
- quint64 ms = pattern->timer.elapsed();
- message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
+ quint64 ms = pattern->timer.elapsed();
+ message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
} else if (timeFormat == "boot"_L1) {
// just print the milliseconds since the elapsed timer reference
// like the Linux kernel does
- uint ms = QDeadlineTimer::current().deadline();
+ qint64 ms = QDeadlineTimer::current().deadline();
message.append(QString::asprintf("%6d.%03d", uint(ms / 1000), uint(ms % 1000)));
#if QT_CONFIG(datestring)
} else if (timeFormat.isEmpty()) {
@@ -1539,7 +1673,6 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
message.append(QDateTime::currentDateTime().toString(timeFormat));
#endif // QT_CONFIG(datestring)
}
-#endif // !QT_BOOTSTRAPPED
} else if (token == ifCategoryTokenC) {
if (isDefaultCategory(context.category))
skip = true;
@@ -1558,6 +1691,20 @@ QString qFormatLogMessage(QtMsgType type, const QMessageLogContext &context, con
}
return message;
}
+#else // QT_BOOTSTRAPPED
+static QString formatLogMessage(QtMsgType type, const QMessageLogContext &context, const QString &str)
+{
+ Q_UNUSED(type);
+ Q_UNUSED(context);
+ return str;
+}
+#endif
+#ifndef QLOGGING_HAVE_BACKTRACE
+void QInternalMessageLogContext::populateBacktrace(int)
+{
+ Q_UNREACHABLE();
+}
+#endif
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &buf);
@@ -1575,12 +1722,13 @@ Q_CONSTINIT static QBasicAtomicPointer<void (QtMsgType, const QMessageLogContext
#define QT_LOG_CODE 9000
#endif
-static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &,
+ const QString &message)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- QString formattedMessage = qFormatLogMessage(type, context, message);
+ QString formattedMessage = message;
formattedMessage.append(u'\n');
if (slog2_set_default_buffer((slog2_buffer_t)-1) == 0) {
slog2_buffer_set_config_t buffer_config;
@@ -1631,13 +1779,11 @@ static bool slog2_default_handler(QtMsgType type, const QMessageLogContext &cont
#if QT_CONFIG(journald)
static bool systemd_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
- const QString &message)
+ const QString &formattedMessage)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- QString formattedMessage = qFormatLogMessage(type, context, message);
-
int priority = LOG_INFO; // Informational
switch (type) {
case QtDebugMsg:
@@ -1670,13 +1816,12 @@ static bool systemd_default_message_handler(QtMsgType type,
#endif
#if QT_CONFIG(syslog)
-static bool syslog_default_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+static bool syslog_default_message_handler(QtMsgType type, const QMessageLogContext &context,
+ const QString &formattedMessage)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- QString formattedMessage = qFormatLogMessage(type, context, message);
-
int priority = LOG_INFO; // Informational
switch (type) {
case QtDebugMsg:
@@ -1705,13 +1850,11 @@ static bool syslog_default_message_handler(QtMsgType type, const QMessageLogCont
#ifdef Q_OS_ANDROID
static bool android_default_message_handler(QtMsgType type,
const QMessageLogContext &context,
- const QString &message)
+ const QString &formattedMessage)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- QString formattedMessage = qFormatLogMessage(type, context, message);
-
android_LogPriority priority = ANDROID_LOG_DEBUG;
switch (type) {
case QtDebugMsg:
@@ -1763,13 +1906,13 @@ static void win_outputDebugString_helper(const QString &message)
}
}
-static bool win_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+static bool win_message_handler(QtMsgType, const QMessageLogContext &,
+ const QString &formattedMessage)
{
if (shouldLogToStderr())
return false; // Leave logging up to stderr handler
- const QString formattedMessage = qFormatLogMessage(type, context, message).append(u'\n');
- win_outputDebugString_helper(formattedMessage);
+ win_outputDebugString_helper(formattedMessage + u'\n');
return true; // Prevent further output to stderr
}
@@ -1777,15 +1920,15 @@ static bool win_message_handler(QtMsgType type, const QMessageLogContext &contex
#ifdef Q_OS_WASM
static bool wasm_default_message_handler(QtMsgType type,
- const QMessageLogContext &context,
- const QString &message)
+ const QMessageLogContext &,
+ const QString &formattedMessage)
{
- if (shouldLogToStderr())
- return false; // Leave logging up to stderr handler
+ static bool forceStderrLogging = qEnvironmentVariableIntValue("QT_FORCE_STDERR_LOGGING");
+ if (forceStderrLogging)
+ return false;
- QString formattedMessage = qFormatLogMessage(type, context, message);
- int emOutputFlags = (EM_LOG_CONSOLE | EM_LOG_DEMANGLE);
- QByteArray localMsg = message.toLocal8Bit();
+ int emOutputFlags = EM_LOG_CONSOLE;
+ QByteArray localMsg = formattedMessage.toLocal8Bit();
switch (type) {
case QtDebugMsg:
break;
@@ -1810,56 +1953,87 @@ static bool wasm_default_message_handler(QtMsgType type,
// --------------------------------------------------------------------------
-static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context, const QString &message)
+static void stderr_message_handler(QtMsgType type, const QMessageLogContext &context,
+ const QString &formattedMessage)
{
- QString formattedMessage = qFormatLogMessage(type, context, message);
+ Q_UNUSED(type);
+ Q_UNUSED(context);
// print nothing if message pattern didn't apply / was empty.
// (still print empty lines, e.g. because message itself was empty)
if (formattedMessage.isNull())
return;
-
fprintf(stderr, "%s\n", formattedMessage.toLocal8Bit().constData());
fflush(stderr);
}
+namespace {
+struct SystemMessageSink
+{
+ using Fn = bool(QtMsgType, const QMessageLogContext &, const QString &);
+ Fn *sink;
+ bool messageIsUnformatted = false;
+};
+}
+
+static constexpr SystemMessageSink systemMessageSink = {
+#if defined(QT_BOOTSTRAPPED)
+ nullptr
+#elif defined(Q_OS_WIN)
+ win_message_handler
+#elif QT_CONFIG(slog2)
+ slog2_default_handler
+#elif QT_CONFIG(journald)
+ systemd_default_message_handler
+#elif QT_CONFIG(syslog)
+ syslog_default_message_handler
+#elif defined(Q_OS_ANDROID)
+ android_default_message_handler
+#elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
+ AppleUnifiedLogger::messageHandler, true
+#elif defined Q_OS_WASM
+ wasm_default_message_handler
+#else
+ nullptr
+#endif
+};
+
+static void preformattedMessageHandler(QtMsgType type, const QMessageLogContext &context,
+ const QString &formattedMessage)
+{
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Waddress") // "the address of ~~ will never be NULL
+ if (systemMessageSink.sink && systemMessageSink.sink(type, context, formattedMessage))
+ return;
+QT_WARNING_POP
+
+ stderr_message_handler(type, context, formattedMessage);
+}
+
/*!
\internal
*/
static void qDefaultMessageHandler(QtMsgType type, const QMessageLogContext &context,
const QString &message)
{
- bool handledStderr = false;
-
// A message sink logs the message to a structured or unstructured destination,
// optionally formatting the message if the latter, and returns true if the sink
// handled stderr output as well, which will shortcut our default stderr output.
- // In the future, if we allow multiple/dynamic sinks, this will be iterating
- // a list of sinks.
-#if !defined(QT_BOOTSTRAPPED)
-# if defined(Q_OS_WIN)
- handledStderr |= win_message_handler(type, context, message);
-# elif QT_CONFIG(slog2)
- handledStderr |= slog2_default_handler(type, context, message);
-# elif QT_CONFIG(journald)
- handledStderr |= systemd_default_message_handler(type, context, message);
-# elif QT_CONFIG(syslog)
- handledStderr |= syslog_default_message_handler(type, context, message);
-# elif defined(Q_OS_ANDROID)
- handledStderr |= android_default_message_handler(type, context, message);
-# elif defined(QT_USE_APPLE_UNIFIED_LOGGING)
- handledStderr |= AppleUnifiedLogger::messageHandler(type, context, message);
-# elif defined Q_OS_WASM
- handledStderr |= wasm_default_message_handler(type, context, message);
-# endif
-#endif
+ if (systemMessageSink.messageIsUnformatted) {
+ if (systemMessageSink.sink(type, context, message))
+ return;
+ }
- if (!handledStderr)
- stderr_message_handler(type, context, message);
+ preformattedMessageHandler(type, context, formatLogMessage(type, context, message));
}
-#if defined(Q_COMPILER_THREAD_LOCAL)
+#if defined(QT_BOOTSTRAPPED)
+// there's no message handler in bootstrapped mode; force everything to stderr
+static bool grabMessageHandler() { return false; }
+static void ungrabMessageHandler() { }
+
+#elif defined(Q_COMPILER_THREAD_LOCAL)
Q_CONSTINIT static thread_local bool msgHandlerGrabbed = false;
@@ -1903,25 +2077,14 @@ static void qt_message_print(QtMsgType msgType, const QMessageLogContext &contex
auto msgHandler = messageHandler.loadAcquire();
(msgHandler ? msgHandler : qDefaultMessageHandler)(msgType, context, message);
} else {
- fprintf(stderr, "%s\n", message.toLocal8Bit().constData());
- }
-}
-
-static void qt_message_print(const QString &message)
-{
-#if defined(Q_OS_WIN) && !defined(QT_BOOTSTRAPPED)
- if (!shouldLogToStderr()) {
- win_outputDebugString_helper(message);
- return;
+ stderr_message_handler(msgType, context, message);
}
-#endif
- fprintf(stderr, "%s", message.toLocal8Bit().constData());
- fflush(stderr);
}
-static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const QString &message)
+template <typename String>
+static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, String &&message)
{
-#if defined(Q_CC_MSVC) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
+#if defined(Q_CC_MSVC_ONLY) && defined(QT_DEBUG) && defined(_DEBUG) && defined(_CRT_ERROR)
wchar_t contextFileL[256];
// we probably should let the compiler do this for us, by declaring QMessageLogContext::file to
// be const wchar_t * in the first place, but the #ifdefery above is very complex and we
@@ -1940,21 +2103,24 @@ static void qt_message_fatal(QtMsgType, const QMessageLogContext &context, const
_CrtDbgBreak();
#else
Q_UNUSED(context);
- Q_UNUSED(message);
#endif
+ if constexpr (std::is_class_v<String> && !std::is_const_v<String>)
+ message.clear();
+ else
+ Q_UNUSED(message);
qAbort();
}
-
/*!
\internal
*/
void qt_message_output(QtMsgType msgType, const QMessageLogContext &context, const QString &message)
{
- qt_message_print(msgType, context, message);
+ QInternalMessageLogContext ctx(context);
+ qt_message_print(msgType, ctx, message);
if (isFatal(msgType))
- qt_message_fatal(msgType, context, message);
+ qt_message_fatal(msgType, ctx, message);
}
void qErrnoWarning(const char *msg, ...)
@@ -1969,8 +2135,8 @@ void qErrnoWarning(const char *msg, ...)
va_end(ap);
buf += " ("_L1 + error_string + u')';
- QMessageLogContext context;
- qt_message_output(QtCriticalMsg, context, buf);
+ QInternalMessageLogContext context{QMessageLogContext()};
+ qt_message_output(QtWarningMsg, context, buf);
}
void qErrnoWarning(int code, const char *msg, ...)
@@ -1983,8 +2149,8 @@ void qErrnoWarning(int code, const char *msg, ...)
va_end(ap);
buf += " ("_L1 + qt_error_string(code) + u')';
- QMessageLogContext context;
- qt_message_output(QtCriticalMsg, context, buf);
+ QInternalMessageLogContext context{QMessageLogContext()};
+ qt_message_output(QtWarningMsg, context, buf);
}
/*!
@@ -2005,34 +2171,61 @@ void qErrnoWarning(int code, const char *msg, ...)
\relates <QtLogging>
\since 5.0
- Installs a Qt message \a handler which has been defined
- previously. Returns a pointer to the previous message handler.
-
- The message handler is a function that prints out debug messages,
- warnings, critical and fatal error messages. The Qt library (debug
- mode) contains hundreds of warning messages that are printed
- when internal errors (usually invalid function arguments)
- occur. Qt built in release mode also contains such warnings unless
- QT_NO_WARNING_OUTPUT and/or QT_NO_DEBUG_OUTPUT have been set during
- compilation. If you implement your own message handler, you get total
- control of these messages.
-
- The default message handler prints the message to the standard output
- under X11 or to the debugger under Windows. If it is a fatal message, the
- application aborts immediately after handling that message. Custom
- message handlers should not attempt to exit an application on their own.
-
- Only one message handler can be defined, since this is usually
- done on an application-wide basis to control debug output.
-
- To restore the message handler, call \c qInstallMessageHandler(0).
-
- Example:
+ Installs a Qt message \a handler.
+ Returns a pointer to the previously installed message handler.
+
+ A message handler is a function that prints out debug, info,
+ warning, critical, and fatal messages from Qt's logging infrastructure.
+ By default, Qt uses a standard message handler that formats and
+ prints messages to different sinks specific to the operating system
+ and Qt configuration. Installing your own message handler allows you
+ to assume full control, and for instance log messages to the
+ file system.
+
+ Note that Qt supports \l{QLoggingCategory}{logging categories} for
+ grouping related messages in semantic categories. You can use these
+ to enable or disable logging per category and \l{QtMsgType}{message type}.
+ As the filtering for logging categories is done even before a message
+ is created, messages for disabled types and categories will not reach
+ the message handler.
+
+ A message handler needs to be
+ \l{Reentrancy and Thread-Safety}{reentrant}. That is, it might be called
+ from different threads, in parallel. Therefore, writes to common sinks
+ (like a database, or a file) often need to be synchronized.
+
+ Qt allows to enrich logging messages with further meta-information
+ by calling \l qSetMessagePattern(), or setting the \c QT_MESSAGE_PATTERN
+ environment variable. To keep this formatting, a custom message handler
+ can use \l qFormatLogMessage().
+
+ Try to keep the code in the message handler itself minimal, as expensive
+ operations might block the application. Also, to avoid recursion, any
+ logging messages generated in the message handler itself will be ignored.
+
+ The message handler should always return. For
+ \l{QtFatalMsg}{fatal messages}, the application aborts immediately after
+ handling that message.
+
+ Only one message handler can be installed at a time, for the whole application.
+ If there was a previous custom message handler installed,
+ the function will return a pointer to it. This handler can then
+ be later reinstalled by another call to the method. Also, calling
+ \c qInstallMessageHandler(nullptr) will restore the default
+ message handler.
+
+ Here is an example of a message handler that logs to a local file
+ before calling the default handler:
\snippet code/src_corelib_global_qglobal.cpp 23
+ Note that the C++ standard guarantees that \c{static FILE *f} is
+ initialized in a thread-safe way. We can also expect \c{fprintf()}
+ and \c{fflush()} to be thread-safe, so no further synchronization
+ is necessary.
+
\sa QtMessageHandler, QtMsgType, qDebug(), qInfo(), qWarning(), qCritical(), qFatal(),
- {Debugging Techniques}
+ {Debugging Techniques}, qFormatLogMessage()
*/
/*!
@@ -2071,8 +2264,18 @@ void qErrnoWarning(int code, const char *msg, ...)
specified by the optional \c depth parameter (defaults to 5), and separated by the optional
\c separator parameter (defaults to "|").
- This expansion is available only on some platforms (currently only platfoms using glibc).
- Names are only known for exported functions. If you want to see the name of every function
+ This expansion is available only on some platforms:
+
+ \list
+ \li platforms using glibc;
+ \li platforms shipping C++23's \c{<stacktrace>} header (requires compiling Qt in C++23 mode).
+ \endlist
+
+ Depending on the platform, there are some restrictions on the function
+ names printed by this expansion.
+
+ On some platforms,
+ names are only known for exported functions. If you want to see the name of every function
in your application, make sure your application is compiled and linked with \c{-rdynamic},
or an equivalent of it.
@@ -2118,6 +2321,7 @@ QtMessageHandler qInstallMessageHandler(QtMessageHandler h)
return qDefaultMessageHandler;
}
+#ifndef QT_BOOTSTRAPPED
void qSetMessagePattern(const QString &pattern)
{
const auto locker = qt_scoped_lock(QMessagePattern::mutex);
@@ -2125,7 +2329,38 @@ void qSetMessagePattern(const QString &pattern)
if (!qMessagePattern()->fromEnvironment)
qMessagePattern()->setPattern(pattern);
}
+#endif
+
+static void copyInternalContext(QInternalMessageLogContext *self,
+ const QMessageLogContext &logContext) noexcept
+{
+ if (logContext.version == self->version) {
+ auto other = static_cast<const QInternalMessageLogContext *>(&logContext);
+ self->backtrace = other->backtrace;
+ }
+}
+
+/*!
+ \internal
+ Copies context information from \a logContext into this QMessageLogContext.
+ Returns the number of backtrace frames that are desired.
+*/
+int QInternalMessageLogContext::initFrom(const QMessageLogContext &logContext)
+{
+ version = CurrentVersion + 1;
+ copyContextFrom(logContext);
+
+#ifdef QLOGGING_HAVE_BACKTRACE
+ if (backtrace.has_value())
+ return 0; // we have a stored backtrace, no need to get it again
+
+ // initializes the message pattern, if needed
+ if (auto pattern = qMessagePattern())
+ return pattern->maxBacktraceDepth;
+#endif
+ return 0;
+}
/*!
Copies context information from \a logContext into this QMessageLogContext.
@@ -2141,6 +2376,8 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
this->file = logContext.file;
this->line = logContext.line;
this->function = logContext.function;
+ if (Q_UNLIKELY(version == CurrentVersion + 1))
+ copyInternalContext(static_cast<QInternalMessageLogContext *>(this), logContext);
return *this;
}
@@ -2271,13 +2508,7 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
Calls the message handler with the warning message \a message. If no
message handler has been installed, the message is printed to
stderr. Under Windows, the message is sent to the debugger.
- On QNX the message is sent to slogger2. This
- function does nothing if \c QT_NO_WARNING_OUTPUT was defined
- during compilation; it exits if at the nth warning corresponding to the
- counter in environment variable \c QT_FATAL_WARNINGS. That is, if the
- environment variable contains the value 1, it will exit on the 1st message;
- if it contains the value 10, it will exit on the 10th message. Any
- non-numeric value is equivalent to 1.
+ On QNX the message is sent to slogger2.
This function takes a format string and a list of arguments,
similar to the C printf() function. The format should be a Latin-1
@@ -2294,8 +2525,20 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
This syntax inserts a space between each item, and
appends a newline at the end.
- To suppress the output at runtime, install your own message handler
- with qInstallMessageHandler().
+ This function does nothing if \c QT_NO_WARNING_OUTPUT was defined
+ during compilation.
+ To suppress the output at runtime, you can set
+ \l{QLoggingCategory}{logging rules} or register a custom
+ \l{QLoggingCategory::installFilter()}{filter}.
+
+ For debugging purposes, it is sometimes convenient to let the
+ program abort for warning messages. This allows you then
+ to inspect the core dump, or attach a debugger - see also \l{qFatal()}.
+ To enable this, set the environment variable \c{QT_FATAL_WARNINGS}
+ to a number \c n. The program terminates then for the n-th warning.
+ That is, if the environment variable is set to 1, it will terminate
+ on the first call; if it contains the value 10, it will exit on the 10th
+ call. Any non-numeric value in the environment variable is equivalent to 1.
\sa qDebug(), qInfo(), qCritical(), qFatal(), qInstallMessageHandler(),
{Debugging Techniques}
@@ -2311,8 +2554,6 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
stderr. Under Windows, the message is sent to the debugger.
On QNX the message is sent to slogger2.
- It exits if the environment variable QT_FATAL_CRITICALS is not empty.
-
This function takes a format string and a list of arguments,
similar to the C printf() function. The format should be a Latin-1
string.
@@ -2328,8 +2569,19 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
A space is inserted between the items, and a newline is
appended at the end.
- To suppress the output at runtime, install your own message handler
- with qInstallMessageHandler().
+ To suppress the output at runtime, you can define
+ \l{QLoggingCategory}{logging rules} or register a custom
+ \l{QLoggingCategory::installFilter()}{filter}.
+
+ For debugging purposes, it is sometimes convenient to let the
+ program abort for critical messages. This allows you then
+ to inspect the core dump, or attach a debugger - see also \l{qFatal()}.
+ To enable this, set the environment variable \c{QT_FATAL_CRITICALS}
+ to a number \c n. The program terminates then for the n-th critical
+ message.
+ That is, if the environment variable is set to 1, it will terminate
+ on the first call; if it contains the value 10, it will exit on the 10th
+ call. Any non-numeric value in the environment variable is equivalent to 1.
\sa qDebug(), qInfo(), qWarning(), qFatal(), qInstallMessageHandler(),
{Debugging Techniques}
@@ -2381,7 +2633,7 @@ QMessageLogContext &QMessageLogContext::copyContextFrom(const QMessageLogContext
A message generated by the qCritical() function.
\value QtFatalMsg
A message generated by the qFatal() function.
- \value QtSystemMsg
+ \omitvalue QtSystemMsg
\c QtInfoMsg was added in Qt 5.5.
diff --git a/src/corelib/global/qlogging.h b/src/corelib/global/qlogging.h
index 5111daefd3..aa0ab93a2d 100644
--- a/src/corelib/global/qlogging.h
+++ b/src/corelib/global/qlogging.h
@@ -1,11 +1,14 @@
// 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
-#include <QtCore/qglobal.h>
-
#ifndef QLOGGING_H
#define QLOGGING_H
+#include <QtCore/qtclasshelpermacros.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtcoreexports.h>
+#include <QtCore/qcontainerfwd.h>
+
#if 0
// header is automatically included in qglobal.h
#pragma qt_no_master_include
@@ -22,24 +25,29 @@ QT_BEGIN_NAMESPACE
class QDebug;
class QNoDebug;
+
enum QtMsgType {
QtDebugMsg,
QtWarningMsg,
QtCriticalMsg,
QtFatalMsg,
QtInfoMsg,
- QtSystemMsg = QtCriticalMsg
+#if QT_DEPRECATED_SINCE(6, 7)
+ QtSystemMsg Q_DECL_ENUMERATOR_DEPRECATED_X("Use QtCriticalMsg instead.") = QtCriticalMsg
+#endif
};
+class QInternalMessageLogContext;
class QMessageLogContext
{
Q_DISABLE_COPY(QMessageLogContext)
public:
+ static constexpr int CurrentVersion = 2;
constexpr QMessageLogContext() noexcept = default;
constexpr QMessageLogContext(const char *fileName, int lineNumber, const char *functionName, const char *categoryName) noexcept
: line(lineNumber), file(fileName), function(functionName), category(categoryName) {}
- int version = 2;
+ int version = CurrentVersion;
int line = 0;
const char *file = nullptr;
const char *function = nullptr;
@@ -48,12 +56,18 @@ public:
private:
QMessageLogContext &copyContextFrom(const QMessageLogContext &logContext) noexcept;
+ friend class QInternalMessageLogContext;
friend class QMessageLogger;
- friend class QDebug;
};
class QLoggingCategory;
+#if defined(Q_CC_MSVC_ONLY)
+# define QT_MESSAGE_LOGGER_NORETURN
+#else
+# define QT_MESSAGE_LOGGER_NORETURN Q_NORETURN
+#endif
+
class Q_CORE_EXPORT QMessageLogger
{
Q_DISABLE_COPY(QMessageLogger)
@@ -72,6 +86,8 @@ public:
void warning(const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
Q_DECL_COLD_FUNCTION
void critical(const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
+ QT_MESSAGE_LOGGER_NORETURN Q_DECL_COLD_FUNCTION
+ void fatal(const char *msg, ...) const noexcept Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
typedef const QLoggingCategory &(*CategoryFunction)();
@@ -87,12 +103,10 @@ public:
void critical(const QLoggingCategory &cat, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
Q_DECL_COLD_FUNCTION
void critical(CategoryFunction catFunc, const char *msg, ...) const Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
-
-#ifndef Q_CC_MSVC
- Q_NORETURN
-#endif
- Q_DECL_COLD_FUNCTION
- void fatal(const char *msg, ...) const noexcept Q_ATTRIBUTE_FORMAT_PRINTF(2, 3);
+ QT_MESSAGE_LOGGER_NORETURN Q_DECL_COLD_FUNCTION
+ void fatal(const QLoggingCategory &cat, const char *msg, ...) const noexcept Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
+ QT_MESSAGE_LOGGER_NORETURN Q_DECL_COLD_FUNCTION
+ void fatal(CategoryFunction catFunc, const char *msg, ...) const noexcept Q_ATTRIBUTE_FORMAT_PRINTF(3, 4);
#ifndef QT_NO_DEBUG_STREAM
QDebug debug() const;
@@ -113,6 +127,12 @@ public:
QDebug critical(const QLoggingCategory &cat) const;
Q_DECL_COLD_FUNCTION
QDebug critical(CategoryFunction catFunc) const;
+ Q_DECL_COLD_FUNCTION
+ QDebug fatal() const;
+ Q_DECL_COLD_FUNCTION
+ QDebug fatal(const QLoggingCategory &cat) const;
+ Q_DECL_COLD_FUNCTION
+ QDebug fatal(CategoryFunction catFunc) const;
QNoDebug noDebug() const noexcept;
#endif // QT_NO_DEBUG_STREAM
@@ -121,6 +141,8 @@ private:
QMessageLogContext context;
};
+#undef QT_MESSAGE_LOGGER_NORETURN
+
#if !defined(QT_MESSAGELOGCONTEXT) && !defined(QT_NO_MESSAGELOGCONTEXT)
# if defined(QT_NO_DEBUG)
# define QT_NO_MESSAGELOGCONTEXT
diff --git a/src/corelib/global/qlogging_p.h b/src/corelib/global/qlogging_p.h
index 9492f10f1f..bc331c80c0 100644
--- a/src/corelib/global/qlogging_p.h
+++ b/src/corelib/global/qlogging_p.h
@@ -16,6 +16,22 @@
//
#include <QtCore/private/qglobal_p.h>
+#include "qlogging.h"
+#include "qloggingcategory.h"
+
+#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(regularexpression)
+# if __has_include(<cxxabi.h>) && QT_CONFIG(backtrace)
+# include <optional>
+# include "qvarlengtharray.h"
+# define QLOGGING_USE_EXECINFO_BACKTRACE
+# define QLOGGING_HAVE_BACKTRACE
+# elif QT_CONFIG(cxx23_stacktrace)
+# include <optional>
+# include <stacktrace>
+# define QLOGGING_USE_STD_BACKTRACE
+# define QLOGGING_HAVE_BACKTRACE
+# endif
+#endif // QT_BOOTSTRAPPED
QT_BEGIN_NAMESPACE
@@ -25,6 +41,38 @@ Q_CORE_EXPORT bool shouldLogToStderr();
}
+class QInternalMessageLogContext : public QMessageLogContext
+{
+public:
+ static constexpr int DefaultBacktraceDepth = 32;
+
+#if defined(QLOGGING_USE_EXECINFO_BACKTRACE)
+ using BacktraceStorage = QVarLengthArray<void *, DefaultBacktraceDepth>;
+#elif defined(QLOGGING_USE_STD_BACKTRACE)
+ using BacktraceStorage = std::stacktrace;
+#else
+ using BacktraceStorage = bool; // dummy
+#endif
+
+ std::optional<BacktraceStorage> backtrace;
+
+ Q_ALWAYS_INLINE QInternalMessageLogContext(const QMessageLogContext &logContext)
+ {
+ int backtraceFrames = initFrom(logContext);
+ if (backtraceFrames)
+ populateBacktrace(backtraceFrames);
+ }
+ QInternalMessageLogContext(const QMessageLogContext &logContext,
+ const QLoggingCategory &categoryOverride)
+ : QInternalMessageLogContext(logContext)
+ {
+ category = categoryOverride.categoryName();
+ }
+
+ int initFrom(const QMessageLogContext &logContext);
+ void populateBacktrace(int frameCount);
+};
+
QT_END_NAMESPACE
#endif // QLOGGING_P_H
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 52a9099964..2398c0a1a4 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -10,6 +10,7 @@
#endif
#include <QtCore/qglobal.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qtmetamacros.h>
#if defined(__OBJC__) && !defined(__cplusplus)
@@ -46,10 +47,10 @@ namespace Qt {
transparent
};
- enum class Appearance {
- Unknown = 0x0000,
- Light = 0x0001,
- Dark = 0x0002
+ enum class ColorScheme {
+ Unknown,
+ Light,
+ Dark,
};
enum MouseButton {
@@ -212,7 +213,7 @@ namespace Qt {
ToolTip = Popup | Sheet,
SplashScreen = ToolTip | Dialog,
Desktop = 0x00000010 | Window,
- SubWindow = 0x00000012,
+ SubWindow = 0x00000012, // Note QTBUG-115729 before using
ForeignWindow = 0x00000020 | Window,
CoverWindow = 0x00000040 | Window,
@@ -422,7 +423,7 @@ namespace Qt {
enum ApplicationAttribute
{
// AA_ImmediateWidgetCreation = 0,
- // AA_MSWindowsUseDirect3DByDefault = 1,
+ AA_QtQuickUseDefaultSizePolicy = 1 QT_TECH_PREVIEW_API,
AA_DontShowIconsInMenus = 2,
AA_NativeWindows = 3,
AA_DontCreateNativeWidgetSiblings = 4,
@@ -431,7 +432,7 @@ namespace Qt {
AA_MacDontSwapCtrlAndMeta = 7,
AA_Use96Dpi = 8,
AA_DisableNativeVirtualKeyboard = 9,
- // AA_X11InitThreads = 10,
+ AA_DontUseNativeMenuWindows = 10,
AA_SynthesizeTouchForUnhandledMouseEvents = 11,
AA_SynthesizeMouseForUnhandledTouchEvents = 12,
#if QT_DEPRECATED_SINCE(6, 0)
@@ -461,7 +462,7 @@ namespace Qt {
AA_DisableShaderDiskCache = 27,
AA_DontShowShortcutsInContextMenus = 28,
AA_CompressTabletEvents = 29,
- // AA_DisableWindowContextHelpButton = 30,
+ AA_DontUsePopupWindows = 30,
AA_DisableSessionManager = 31,
// Add new attributes before this line
@@ -602,7 +603,11 @@ namespace Qt {
Key_twosuperior = 0x0b2,
Key_threesuperior = 0x0b3,
Key_acute = 0x0b4,
- Key_mu = 0x0b5,
+ Key_micro = 0x0b5,
+#if QT_DEPRECATED_SINCE(6, 11)
+ Key_mu Q_DECL_ENUMERATOR_DEPRECATED_X("This key was misnamed, use Key_micro instead")
+ = Key_micro,
+#endif
Key_paragraph = 0x0b6,
Key_periodcentered = 0x0b7,
Key_cedilla = 0x0b8,
@@ -1671,6 +1676,10 @@ namespace Qt {
VeryCoarseTimer
};
+ enum class TimerId {
+ Invalid = 0,
+ };
+
enum ScrollPhase {
NoScrollPhase = 0,
ScrollBegin,
@@ -1708,6 +1717,12 @@ namespace Qt {
PassThrough
};
+ enum class PermissionStatus {
+ Undetermined,
+ Granted,
+ Denied,
+ };
+
// QTBUG-48701
enum ReturnByValueConstant { ReturnByValue }; // ### Qt 7: Remove me
@@ -1751,7 +1766,7 @@ namespace Qt {
Q_ENUM_NS(DayOfWeek)
Q_ENUM_NS(CursorShape)
Q_ENUM_NS(GlobalColor)
- Q_ENUM_NS(Appearance)
+ Q_ENUM_NS(ColorScheme)
Q_ENUM_NS(AspectRatioMode)
Q_ENUM_NS(TransformationMode)
Q_FLAG_NS(ImageConversionFlags)
@@ -1803,6 +1818,7 @@ namespace Qt {
Q_ENUM_NS(ChecksumType)
Q_ENUM_NS(HighDpiScaleFactorRoundingPolicy)
Q_ENUM_NS(TabFocusBehavior)
+ Q_ENUM_NS(PermissionStatus)
#endif // Q_DOC
}
@@ -1893,18 +1909,14 @@ public:
return combination;
}
#endif
-
- friend constexpr bool operator==(QKeyCombination lhs, QKeyCombination rhs) noexcept
+ bool operator<(QKeyCombination) const = delete;
+private:
+ friend constexpr bool comparesEqual(const QKeyCombination &lhs,
+ const QKeyCombination &rhs) noexcept
{
return lhs.combination == rhs.combination;
}
-
- friend constexpr bool operator!=(QKeyCombination lhs, QKeyCombination rhs) noexcept
- {
- return lhs.combination != rhs.combination;
- }
-
- bool operator<(QKeyCombination) const = delete;
+ Q_DECLARE_EQUALITY_COMPARABLE_LITERAL_TYPE(QKeyCombination)
};
Q_DECLARE_TYPEINFO(QKeyCombination, Q_RELOCATABLE_TYPE);
diff --git a/src/corelib/global/qnamespace.qdoc b/src/corelib/global/qnamespace.qdoc
index 1a57c92199..ddfade675a 100644
--- a/src/corelib/global/qnamespace.qdoc
+++ b/src/corelib/global/qnamespace.qdoc
@@ -84,6 +84,19 @@
QCoreApplication::testAttribute().
+ \value [since 6.7] AA_QtQuickUseDefaultSizePolicy Qt Quick Layouts use the built-in size
+ policy of \l Item. For example, when this is set, \l Button fills the available
+ width, but has a fixed height. When this is not set, it will use the default
+ sizing behavior of the layout it's in, which is to use its implicit size as the
+ preferred size. This is explained in detail in \l {Specifying preferred size} and
+ \l {Size constraints}. When this is set, the default size policy of the item
+ with the layout can be overridden by explicitly setting
+ \l{Layout::fillWidth}{Layout.fillWidth} or
+ \l{Layout::fillHeight}{Layout.fillHeight}.
+ \b Note: This API is considered tech preview and may change or be removed in future
+ versions of Qt.
+
+
\value AA_DontShowIconsInMenus Actions with the Icon property won't be
shown in any menus unless specifically set by the
QAction::iconVisibleInMenu property.
@@ -94,9 +107,11 @@
\value AA_DontShowShortcutsInContextMenus Actions with the Shortcut property
won't be shown in any shortcut menus unless specifically set by the
QAction::shortcutVisibleInContextMenu property. This value was added
- in Qt 5.10, and defaults to the preference reported by the implementation
- of QPlatformIntegration::styleHint. To override the platform integration,
- set this attribute after QCoreApplication has been instantiated.
+ in Qt 5.10, and is by default based on the value reported by
+ QStyleHints::showShortcutsInContextMenus(). To override the default
+ behavior, set the style hint before QCoreApplication has been
+ instantiated, or set this attribute after QCoreApplication has
+ been instantiated.
\value AA_NativeWindows Ensures that widgets have native windows.
@@ -118,15 +133,15 @@
set to true won't be used as a native menubar (e.g, the menubar at
the top of the main screen on \macos).
- \value AA_MacDontSwapCtrlAndMeta Keyboard shortcuts on \macos are typically
+ \value AA_MacDontSwapCtrlAndMeta Keyboard shortcuts on Apple platforms are typically
based on the Command (or Cmd) keyboard modifier, represented by
the ⌘ symbol. For example, the 'Copy' action is Command+C (⌘+C).
To ease cross platform development Qt will by default remap Command
to the Qt::ControlModifier, to align with other platforms. This
allows creating keyboard shortcuts such as "Ctrl+J", which on
\macos will then map to Command+J, as expected by \macos users. The
- actual Control (or Ctrl) modifier on \macos, represented by ⌃, is
- mapped to Qt::MetaModifier.
+ actual Control (or Ctrl) modifier on Apple platforms, represented by ⌃,
+ is mapped to Qt::MetaModifier.
When this attribute is true Qt will not do the remapping, and pressing
the Command modifier will result in Qt::MetaModifier, while pressing
@@ -189,9 +204,9 @@
\value AA_UseStyleSheetPropagationInWidgetStyles By default, Qt Style Sheets
disable regular QWidget palette and font propagation. When this flag
- is enabled, font and palette changes propagate as though the user had
- manually called the corresponding QWidget methods. See
- \l{The Style Sheet Syntax#Inheritance}{The Style Sheet Syntax - Inheritance}
+ is enabled, font and palette changes done from a style sheet will propagate
+ a single time, when the style sheet is set.
+ See \l{The Style Sheet Syntax#Inheritance}{The Style Sheet Syntax - Inheritance}
for more details.
This value was added in Qt 5.7.
@@ -258,6 +273,17 @@
Currently supported on the Windows platform only.
This value was added in 5.15
+ \value AA_DontUseNativeMenuWindows Menu popup windows (e.g. context menus,
+ combo box menus, and non-native menubar menus) created while this
+ attribute is set to true will not be represented as native top
+ level windows, unless required by the implementation.
+ This value was added in Qt 6.8.
+
+ \value AA_DontUsePopupWindows When this attribute is set, popups will always appear
+ as items in the scene, rather than having their own dedicated windows.
+ Setting this attribute will only affect Qt Quick applications.
+ This value was added in Qt 6.8.
+
\omitvalue AA_AttributeCount
\omitvalue AA_EnableHighDpiScaling
\omitvalue AA_UseHighDpiPixmaps
@@ -615,7 +641,7 @@
connection types, using a bitwise OR. When Qt::UniqueConnection is
set, QObject::connect() will fail if the connection already exists
(i.e. if the same signal is already connected to the same slot
- for the same pair of objects). This flag was introduced in Qt 4.6.
+ for the same pair of objects).
\value SingleShotConnection
This is a flag that can be combined with any one of the above
@@ -728,15 +754,25 @@
Mean Time has zero offset from it. Neither UTC nor OffsetFromUTC
has any transitions.
+ When specifying a datetime using OffsetFromUTC, the offset from UTC must
+ also be supplied (it is measured in seconds). To specify a datetime using
+ TimeZone, a QTimeZone must be supplied. From Qt 6.5, a QTimeZone can now
+ package a timespec with, where needed, an offset as a lightweight time
+ description, so that passing a QTimeZone now provides a uniform way to use
+ datetime APIs, saving the need to call them differently for different
+ timespecs.
+
\note After a change to the system time-zone setting, the behavior
of LocalTime-based QDateTime objects created before the change is
undefined: QDateTime may have cached data that the change
- invalidates. (This is not triggered by transitions of the system
+ invalidates. (This is not triggered by \e transitions of the system
time-zone.) In long-running processes, updates to the system's
time-zone data (e.g. when politicians change the rules for a zone)
may likewise lead to conflicts between the updated time-zone
information and data cached by QDateTime objects created before
the update, using either LocalTime or TimeZone.
+
+ \sa QTimeZone, QDateTime
*/
/*!
@@ -789,7 +825,7 @@
*/
/*!
- \enum Qt::Appearance
+ \enum Qt::ColorScheme
Represents the appearance of an application's theme,
defined by QGuiApplication::palette().
@@ -968,8 +1004,7 @@
\value WA_Hover Forces Qt to generate paint events when the mouse
enters or leaves the widget. This feature is typically used when
- implementing custom styles; see the \l{widgets/styles}{Styles}
- example for details.
+ implementing custom styles.
\value WA_InputMethodEnabled Enables input methods for Asian languages.
Must be set when creating custom text editing widgets.
@@ -1430,6 +1465,7 @@
\value Key_Help
\value Key_Direction_L
\value Key_Direction_R
+
\value Key_Space
\value Key_Any
\value Key_Exclam
@@ -1521,7 +1557,8 @@
\value Key_twosuperior
\value Key_threesuperior
\value Key_acute
- \value Key_mu
+ \value [since 6.7] Key_micro
+ \value Key_mu Deprecated alias for Key_micro
\value Key_paragraph
\value Key_periodcentered
\value Key_cedilla
@@ -1566,6 +1603,7 @@
\value Key_ssharp
\value Key_division
\value Key_ydiaeresis
+
\value Key_Multi_key
\value Key_Codeinput
\value Key_SingleCandidate
@@ -2758,8 +2796,7 @@
\value CheckStateRole This role is used to obtain the checked state of
an item. (Qt::CheckState)
\value InitialSortOrderRole This role is used to obtain the initial sort order
- of a header view section. (Qt::SortOrder). This
- role was introduced in Qt 4.8.
+ of a header view section. (Qt::SortOrder).
Accessibility roles (with associated types):
@@ -2862,7 +2899,10 @@
\value ElideLeft The ellipsis should appear at the beginning of the text.
\value ElideRight The ellipsis should appear at the end of the text.
\value ElideMiddle The ellipsis should appear in the middle of the text.
- \value ElideNone Ellipsis should NOT appear in the text.
+ \value ElideNone Ellipsis should NOT appear in the text. When passed to functions such as
+ QFontMetrics::elidedText(), this will cause the full string to return unless
+ the text contains multi-length variants. Elision in this case must be done
+ by clipping to the component width.
Qt::ElideMiddle is normally the most appropriate choice for URLs (e.g.,
"\l{http://bugreports.qt.io/browse/QTWEBSITE-13}{http://bugreports.qt.../QTWEBSITE-13/}"),
@@ -3201,6 +3241,26 @@
*/
/*!
+ \enum Qt::TimerId
+ \since 6.8
+ \relates QObject
+ \relates QTimer
+ \relates QChronoTimer
+
+ This is used to represent timer IDs (for example, QTimer and QChronoTimer).
+ The underlying type is \c int. You can use \l qToUnderlying() to convert
+ Qt::TimerId to \c int.
+
+ \value Invalid Represents a no-op timer ID; it's usage depends on the
+ context, for example, this is the value returned by QObject::startTimer()
+ to indicate it failed to start a timer; whereas QChronoTimer::id() returns
+ this value when the timer is inactive, that is, \c timer.isActive()
+ returns \c false.
+
+ \sa QTimer::id(), QChronoTimer::id(), QObject::startTimer()
+*/
+
+/*!
\enum Qt::ScrollPhase
\since 5.2
@@ -3296,6 +3356,38 @@
*/
/*!
+ \enum Qt::PermissionStatus
+
+ This enum describes the possible statuses of a permissions.
+
+ \value Undetermined
+ The permission status is not yet known. Permission should be requested
+ via QCoreApplication::requestPermission() to determine the actual status.
+ This status will never be the result of requesting a permission.
+
+ \value Granted
+ The user has explicitly granted the application the permission,
+ or the permission is known to not require user authorization on
+ the given platform.
+
+ \value Denied
+ The user has explicitly denied the application the requested permission,
+ or the permission is known to not be accessible or applicable to applications
+ on the given platform.
+
+ \note On Android, there is no \c Undetermined status by the platform's APIs.
+ Thus, if a permission is denied for an app,
+ \l QCoreApplication::checkPermission() returns \c Undetermined
+ by default until \l QCoreApplication::requestPermission() is called.
+ After that \l QCoreApplication::checkPermission() reports a non \c Undetermined
+ status.
+
+ \since 6.5
+ \sa QCoreApplication::requestPermission(), QCoreApplication::checkPermission(),
+ {Application Permissions}
+*/
+
+/*!
\enum Qt::ReturnByValueConstant
\since 5.15
@@ -3315,6 +3407,8 @@
\since 6.0
\brief The QKeyCombination class stores a combination of a key with optional modifiers.
+ \compares equality
+
The QKeyCombination class can be used to represent a combination of a key
with zero or more keyboard modifiers.
@@ -3397,14 +3491,14 @@
#endif
/*!
- \fn bool QKeyCombination::operator==(QKeyCombination lhs, QKeyCombination rhs) noexcept
+ \fn bool QKeyCombination::operator==(const QKeyCombination &lhs, const QKeyCombination &rhs)
Returns \c true if \a lhs and \a rhs have the same combination
of key and modifiers, and \c false otherwise.
*/
/*!
- \fn bool QKeyCombination::operator!=(QKeyCombination lhs, QKeyCombination rhs) noexcept
+ \fn bool QKeyCombination::operator!=(const QKeyCombination &lhs, const QKeyCombination &rhs)
Returns \c true if \a lhs and \a rhs have different combinations
of key and modifiers, otherwise \c false.
diff --git a/src/corelib/global/qnumeric.cpp b/src/corelib/global/qnumeric.cpp
index e492e3f02a..a46039c5da 100644
--- a/src/corelib/global/qnumeric.cpp
+++ b/src/corelib/global/qnumeric.cpp
@@ -458,6 +458,8 @@ Q_CORE_EXPORT quint64 qFloatDistance(double a, double b)
Returns true if the absolute value of \a f is within 0.00001f of 0.0.
*/
+namespace QtNumericTests {
+
template <typename T> static constexpr T max = std::numeric_limits<T>::max();
template <typename T> static constexpr T min = std::numeric_limits<T>::min();
@@ -489,4 +491,6 @@ static_assert(qt_saturate<int>(min<qint64>) == min<int>);
static_assert(qt_saturate<unsigned>(min<qint64>) == 0);
static_assert(qt_saturate<quint64>(min<qint64>) == 0);
+} // namespace QtNumericTests
+
QT_END_NAMESPACE
diff --git a/src/corelib/global/qnumeric.h b/src/corelib/global/qnumeric.h
index 7779c03515..2238c13da0 100644
--- a/src/corelib/global/qnumeric.h
+++ b/src/corelib/global/qnumeric.h
@@ -8,7 +8,9 @@
#pragma qt_class(QtNumeric)
#endif
-#include <QtCore/qglobal.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtcoreexports.h>
+#include <QtCore/qtypes.h>
#include <cmath>
#include <limits>
diff --git a/src/corelib/global/qnumeric_p.h b/src/corelib/global/qnumeric_p.h
index f5beb4d38d..d40e6b964b 100644
--- a/src/corelib/global/qnumeric_p.h
+++ b/src/corelib/global/qnumeric_p.h
@@ -23,6 +23,10 @@
#include <limits>
#include <type_traits>
+#ifndef __has_extension
+# define __has_extension(X) 0
+#endif
+
#if !defined(Q_CC_MSVC) && defined(Q_OS_QNX)
# include <math.h>
# ifdef isnan
@@ -51,6 +55,8 @@ QT_END_NAMESPACE
QT_BEGIN_NAMESPACE
+class qfloat16;
+
namespace qnumeric_std_wrapper {
#if defined(QT_MATH_H_DEFINES_MACROS)
# undef QT_MATH_H_DEFINES_MACROS
@@ -138,22 +144,23 @@ Q_DECL_CONST_FUNCTION static inline int qt_fpclassify(float f)
return qnumeric_std_wrapper::fpclassify(f);
}
-#ifndef Q_CLANG_QDOC
+#ifndef Q_QDOC
namespace {
/*!
Returns true if the double \a v can be converted to type \c T, false if
it's out of range. If the conversion is successful, the converted value is
stored in \a value; if it was not successful, \a value will contain the
minimum or maximum of T, depending on the sign of \a d. If \c T is
- unsigned, then \a value contains the absolute value of \a v.
+ unsigned, then \a value contains the absolute value of \a v. If \c T is \c
+ float, an underflow is also signalled by returning false and setting \a
+ value to zero.
This function works for v containing infinities, but not NaN. It's the
caller's responsibility to exclude that possibility before calling it.
*/
-template<typename T>
-static inline bool convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
+template <typename T> static inline std::enable_if_t<std::is_integral_v<T>, bool>
+convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
{
- static_assert(std::numeric_limits<T>::is_integer);
static_assert(std::is_integral_v<T>);
constexpr bool TypeIsLarger = std::numeric_limits<T>::digits > std::numeric_limits<double>::digits;
@@ -180,7 +187,7 @@ static inline bool convertDoubleTo(double v, T *value, bool allow_precision_upgr
// correct, but Clang, ICC and MSVC don't realize that it's a constant and
// the math call stays in the compiled code.
-#ifdef Q_PROCESSOR_X86_64
+#if defined(Q_PROCESSOR_X86_64) && defined(__SSE2__)
// Of course, UB doesn't apply if we use intrinsics, in which case we are
// allowed to dpeend on exactly the processor's behavior. This
// implementation uses the truncating conversions from Scalar Double to
@@ -278,6 +285,116 @@ QT_WARNING_DISABLE_FLOAT_COMPARE
QT_WARNING_POP
}
+template <typename T> static
+std::enable_if_t<std::is_floating_point_v<T> || std::is_same_v<T, qfloat16>, bool>
+convertDoubleTo(double v, T *value, bool allow_precision_upgrade = true)
+{
+ Q_UNUSED(allow_precision_upgrade);
+ constexpr T Huge = std::numeric_limits<T>::infinity();
+
+ if constexpr (std::numeric_limits<double>::max_exponent <=
+ std::numeric_limits<T>::max_exponent) {
+ // no UB can happen
+ *value = T(v);
+ return true;
+ }
+
+#if defined(__SSE2__) && (defined(Q_CC_GNU) || __has_extension(gnu_asm))
+ // The x86 CVTSD2SH instruction from SSE2 does what we want:
+ // - converts out-of-range doubles to ±infinity and sets #O
+ // - converts underflows to zero and sets #U
+ // We need to clear any previously-stored exceptions from it before the
+ // operation (3-cycle cost) and obtain the new state afterwards (1 cycle).
+
+ unsigned csr = _MM_MASK_MASK; // clear stored exception indicators
+ auto sse_check_result = [&](auto result) {
+ if ((csr & (_MM_EXCEPT_UNDERFLOW | _MM_EXCEPT_OVERFLOW)) == 0)
+ return true;
+ if (csr & _MM_EXCEPT_OVERFLOW)
+ return false;
+
+ // According to IEEE 754[1], #U is also set when the result is tiny and
+ // inexact, but still non-zero, so detect that (this won't generate
+ // good code for types without hardware support).
+ // [1] https://en.wikipedia.org/wiki/Floating-point_arithmetic#Exception_handling
+ return result != 0;
+ };
+
+ // Written directly in assembly because both Clang and GCC have been
+ // observed to reorder the STMXCSR instruction above the conversion
+ // operation. MSVC generates horrid code when using the intrinsics anyway,
+ // so it's not a loss.
+ // See https://github.com/llvm/llvm-project/issues/83661.
+ if constexpr (std::is_same_v<T, float>) {
+# ifdef __AVX__
+ asm ("vldmxcsr %[csr]\n\t"
+ "vcvtsd2ss %[in], %[in], %[out]\n\t"
+ "vstmxcsr %[csr]"
+ : [csr] "+m" (csr), [out] "=v" (*value) : [in] "v" (v));
+# else
+ asm ("ldmxcsr %[csr]\n\t"
+ "cvtsd2ss %[in], %[out]\n\t"
+ "stmxcsr %[csr]"
+ : [csr] "+m" (csr), [out] "=v" (*value) : [in] "v" (v));
+# endif
+ return sse_check_result(*value);
+ }
+
+# if defined(__F16C__) || defined(__AVX512FP16__)
+ if constexpr (sizeof(T) == 2 && std::numeric_limits<T>::max_exponent == 16) {
+ // qfloat16 or std::float16_t, but not std::bfloat16_t or std::bfloat8_t
+ auto doConvert = [&](auto *out) {
+ asm ("vldmxcsr %[csr]\n\t"
+# ifdef __AVX512FP16__
+ // AVX512FP16 & AVX10 have an instruction for this
+ "vcvtsd2sh %[in], %[in], %[out]\n\t"
+# else
+ "vcvtsd2ss %[in], %[in], %[out]\n\t" // sets DEST[MAXVL-1:128] := 0
+ "vcvtps2ph %[rc], %[out], %[out]\n\t"
+# endif
+ "vstmxcsr %[csr]"
+ : [csr] "+m" (csr), [out] "=v" (*out)
+ : [in] "v" (v), [rc] "i" (_MM_FROUND_CUR_DIRECTION)
+ );
+ return sse_check_result(out);
+ };
+
+ if constexpr (std::is_same_v<T, qfloat16> && !std::is_void_v<typename T::NativeType>) {
+ typename T::NativeType tmp;
+ bool b = doConvert(&tmp);
+ *value = tmp;
+ return b;
+ } else {
+# ifndef Q_CC_CLANG
+ // Clang can only implement this if it has a native FP16 type
+ return doConvert(value);
+# endif
+ }
+ }
+# endif
+#endif // __SSE2__ && inline assembly
+
+ if (!qt_is_finite(v) && std::numeric_limits<T>::has_infinity) {
+ // infinity (or NaN)
+ *value = T(v);
+ return true;
+ }
+
+ // Check for in-range value to ensure the conversion is not UB (see the
+ // comment above for Standard language).
+ if (std::fabs(v) > (std::numeric_limits<T>::max)()) {
+ *value = v < 0 ? -Huge : Huge;
+ return false;
+ }
+
+ *value = T(v);
+ if (v != 0 && *value == 0) {
+ // Underflow through loss of precision
+ return false;
+ }
+ return true;
+}
+
template <typename T> inline bool add_overflow(T v1, T v2, T *r) { return qAddOverflow(v1, v2, r); }
template <typename T> inline bool sub_overflow(T v1, T v2, T *r) { return qSubOverflow(v1, v2, r); }
template <typename T> inline bool mul_overflow(T v1, T v2, T *r) { return qMulOverflow(v1, v2, r); }
@@ -312,7 +429,7 @@ template <auto V2, typename T> bool mul_overflow(T v1, T *r)
return qMulOverflow<V2, T>(v1, r);
}
}
-#endif // Q_CLANG_QDOC
+#endif // Q_QDOC
/*
Safely narrows \a x to \c{To}. Let \c L be
diff --git a/src/corelib/global/qoperatingsystemversion.cpp b/src/corelib/global/qoperatingsystemversion.cpp
index bb29a6b1a0..cf6063fca0 100644
--- a/src/corelib/global/qoperatingsystemversion.cpp
+++ b/src/corelib/global/qoperatingsystemversion.cpp
@@ -34,7 +34,7 @@ QT_BEGIN_NAMESPACE
operating system version (as opposed to the kernel version number or
marketing version).
- Presently, Android, Apple Platforms (iOS, macOS, tvOS, and watchOS),
+ Presently, Android, Apple Platforms (iOS, macOS, tvOS, watchOS, and visionOS),
and Windows are supported.
The \a majorVersion(), \a minorVersion(), and \a microVersion() functions
@@ -98,6 +98,7 @@ QT_BEGIN_NAMESPACE
\value MacOS The Apple macOS operating system.
\value TvOS The Apple tvOS operating system.
\value WatchOS The Apple watchOS operating system.
+ \value VisionOS The Apple visionOS operating system.
\value Windows The Microsoft Windows operating system.
\value Unknown An unknown or unsupported operating system.
@@ -111,15 +112,11 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \fn QOperatingSystemVersion::current()
Returns a QOperatingSystemVersion indicating the current OS and its version number.
\sa currentType()
*/
-QOperatingSystemVersion QOperatingSystemVersion::current()
-{
- return QOperatingSystemVersionBase::current();
-}
-
QOperatingSystemVersionBase QOperatingSystemVersionBase::current()
{
static const QOperatingSystemVersionBase v = current_impl();
@@ -203,13 +200,13 @@ QOperatingSystemVersionBase QOperatingSystemVersionBase::current_impl()
}
#endif
-static inline int compareVersionComponents(int lhs, int rhs)
+static inline int compareVersionComponents(int lhs, int rhs) noexcept
{
return lhs >= 0 && rhs >= 0 ? lhs - rhs : 0;
}
int QOperatingSystemVersionBase::compare(QOperatingSystemVersionBase v1,
- QOperatingSystemVersionBase v2)
+ QOperatingSystemVersionBase v2) noexcept
{
if (v1.m_major == v2.m_major) {
if (v1.m_minor == v2.m_minor) {
@@ -306,11 +303,6 @@ int QOperatingSystemVersionBase::compare(QOperatingSystemVersionBase v1,
\sa type()
*/
-QString QOperatingSystemVersion::name() const
-{
- return QOperatingSystemVersionBase::name();
-}
-
QString QOperatingSystemVersionBase::name(QOperatingSystemVersionBase osversion)
{
switch (osversion.type()) {
@@ -334,6 +326,8 @@ QString QOperatingSystemVersionBase::name(QOperatingSystemVersionBase osversion)
return QStringLiteral("tvOS");
case QOperatingSystemVersionBase::WatchOS:
return QStringLiteral("watchOS");
+ case QOperatingSystemVersionBase::VisionOS:
+ return QStringLiteral("visionOS");
case QOperatingSystemVersionBase::Android:
return QStringLiteral("Android");
case QOperatingSystemVersionBase::Unknown:
@@ -359,6 +353,8 @@ bool QOperatingSystemVersionBase::isAnyOfType(std::initializer_list<OSType> type
return std::find(types.begin(), types.end(), type) != types.end();
}
+#ifndef QT_BOOTSTRAPPED
+
/*!
\variable QOperatingSystemVersion::Windows7
\brief a version corresponding to Windows 7 (version 6.1).
@@ -397,6 +393,7 @@ const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
Version 1809 (version 10.0.17763).
\since 6.3
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows10_1809;
/*!
\variable QOperatingSystemVersion::Windows10_1903
@@ -404,6 +401,7 @@ const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
Version 1903 (version 10.0.18362).
\since 6.3
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows10_1903;
/*!
\variable QOperatingSystemVersion::Windows10_1909
@@ -411,6 +409,7 @@ const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
Version 1909 (version 10.0.18363).
\since 6.3
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows10_1909;
/*!
\variable QOperatingSystemVersion::Windows10_2004
@@ -418,6 +417,7 @@ const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
Version 2004 (version 10.0.19041).
\since 6.3
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows10_2004;
/*!
\variable QOperatingSystemVersion::Windows10_20H2
@@ -425,6 +425,7 @@ const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
Version 20H2 (version 10.0.19042).
\since 6.3
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows10_20H2;
/*!
\variable QOperatingSystemVersion::Windows10_21H1
@@ -432,6 +433,7 @@ const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
Version 21H1 (version 10.0.19043).
\since 6.3
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows10_21H1;
/*!
\variable QOperatingSystemVersion::Windows10_21H2
@@ -439,6 +441,15 @@ const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
Version 21H2 (version 10.0.19044).
\since 6.3
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows10_21H2;
+
+/*!
+ \variable QOperatingSystemVersion::Windows10_22H2
+ \brief a version corresponding to Windows 10 October 2022 Update
+ Version 22H2 (version 10.0.19045).
+ \since 6.5
+ */
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows10_22H2;
/*!
\variable QOperatingSystemVersion::Windows11
@@ -446,18 +457,27 @@ const QOperatingSystemVersion QOperatingSystemVersion::Windows10 =
(version 10.0.22000).
\since 6.3
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows11;
/*!
\variable QOperatingSystemVersion::Windows11_21H2
\brief a version corresponding to Windows 11 Version 21H2 (version 10.0.22000).
\since 6.4
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows11_21H2;
/*!
\variable QOperatingSystemVersion::Windows11_22H2
\brief a version corresponding to Windows 11 Version 22H2 (version 10.0.22621).
\since 6.4
*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::Windows11_22H2;
+
+/*!
+ \variable QOperatingSystemVersion::Windows11_23H2
+ \brief a version corresponding to Windows 11 Version 23H2 (version 10.0.22631).
+ \since 6.6
+ */
/*!
\variable QOperatingSystemVersion::OSXMavericks
@@ -517,24 +537,11 @@ const QOperatingSystemVersion QOperatingSystemVersion::MacOSCatalina =
/*!
\variable QOperatingSystemVersion::MacOSBigSur
- \brief a version corresponding to macOS Big Sur
-
- The actual version number depends on whether the application was built
- using the Xcode 12 SDK. If it was, the version number corresponds
- to macOS 11.0. If not it will correspond to macOS 10.16.
-
- By comparing QOperatingSystemVersion::current() to this constant
- you will always end up comparing to the right version number.
+ \brief a version corresponding to macOS Big Sur (version 11).
\since 6.0
*/
-const QOperatingSystemVersion QOperatingSystemVersion::MacOSBigSur = [] {
-#if defined(Q_OS_DARWIN)
- if (QMacVersion::buildSDK(QMacVersion::ApplicationBinary) >= QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 16))
- return QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 11, 0);
- else
-#endif
- return QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 16);
-}();
+const QOperatingSystemVersion QOperatingSystemVersion::MacOSBigSur =
+ QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 11, 0);
/*!
\variable QOperatingSystemVersion::MacOSMonterey
@@ -545,6 +552,19 @@ const QOperatingSystemVersion QOperatingSystemVersion::MacOSMonterey =
QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 12, 0);
/*!
+ \variable QOperatingSystemVersion::MacOSVentura
+ \brief a version corresponding to macOS Ventura (version 13).
+ \since 6.4
+*/
+const QOperatingSystemVersionBase QOperatingSystemVersion::MacOSVentura;
+
+/*!
+ \variable QOperatingSystemVersion::MacOSSonoma
+ \brief a version corresponding to macOS Sonoma (version 14).
+ \since 6.5
+*/
+
+/*!
\variable QOperatingSystemVersion::AndroidJellyBean
\brief a version corresponding to Android Jelly Bean (version 4.1, API level 16).
\since 5.9
@@ -665,26 +685,29 @@ const QOperatingSystemVersion QOperatingSystemVersion::Android11 =
\brief a version corresponding to Android 12 (version 12.0, API level 31).
\since 6.5
*/
-const QOperatingSystemVersion QOperatingSystemVersion::Android12 =
- QOperatingSystemVersion(QOperatingSystemVersion::Android, 12, 0);
+const QOperatingSystemVersionBase QOperatingSystemVersion::Android12;
/*!
\variable QOperatingSystemVersion::Android12L
\brief a version corresponding to Android 12L (version 12.0, API level 32).
\since 6.5
*/
-const QOperatingSystemVersion QOperatingSystemVersion::Android12L =
- QOperatingSystemVersion(QOperatingSystemVersion::Android, 12, 0);
+const QOperatingSystemVersionBase QOperatingSystemVersion::Android12L;
/*!
\variable QOperatingSystemVersion::Android13
\brief a version corresponding to Android 13 (version 13.0, API level 33).
\since 6.5
*/
-const QOperatingSystemVersion QOperatingSystemVersion::Android13 =
- QOperatingSystemVersion(QOperatingSystemVersion::Android, 13, 0);
+const QOperatingSystemVersionBase QOperatingSystemVersion::Android13;
+/*!
+ \variable QOperatingSystemVersion::Android14
+ \brief a version corresponding to Android 14 (version 14.0, API level 34).
+ \since 6.7
+ */
+#endif // !QT_BOOTSTRAPPED
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug debug, const QOperatingSystemVersion &ov)
diff --git a/src/corelib/global/qoperatingsystemversion.h b/src/corelib/global/qoperatingsystemversion.h
index d6fee2980c..a9f30dc275 100644
--- a/src/corelib/global/qoperatingsystemversion.h
+++ b/src/corelib/global/qoperatingsystemversion.h
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include <QtCore/qglobal.h>
+#include <QtCore/qcompare.h>
#include <QtCore/qversionnumber.h>
#ifndef QOPERATINGSYSTEMVERSION_H
@@ -9,6 +10,12 @@
QT_BEGIN_NAMESPACE
+#if 0
+# pragma qt_class(QOperatingSystemVersionBase)
+# pragma qt_class(QOperatingSystemVersion)
+# pragma qt_sync_stop_processing // we have some ifdef'ery fooling syncqt
+#endif
+
class QString;
class QOperatingSystemVersionBase
@@ -23,7 +30,8 @@ public:
IOS,
TvOS,
WatchOS,
- Android
+ Android,
+ VisionOS
};
constexpr QOperatingSystemVersionBase(OSType osType,
@@ -50,6 +58,8 @@ public:
return TvOS;
#elif defined(Q_OS_WATCHOS)
return WatchOS;
+#elif defined(Q_OS_VISIONOS)
+ return VisionOS;
#elif defined(Q_OS_ANDROID)
return Android;
#else
@@ -73,39 +83,77 @@ public:
constexpr OSType type() const { return m_os; }
inline QString name() const { return name(*this); }
- friend bool operator>(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs)
- { return lhs.type() == rhs.type() && QOperatingSystemVersionBase::compare(lhs, rhs) > 0; }
+protected:
+ static Q_CORE_EXPORT int compare(QOperatingSystemVersionBase v1,
+ QOperatingSystemVersionBase v2) noexcept;
- friend bool operator>=(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs)
- { return lhs.type() == rhs.type() && QOperatingSystemVersionBase::compare(lhs, rhs) >= 0; }
+ friend Qt::partial_ordering compareThreeWay(const QOperatingSystemVersionBase &lhs,
+ const QOperatingSystemVersionBase &rhs) noexcept
+ {
+ if (lhs.type() != rhs.type())
+ return Qt::partial_ordering::unordered;
+ const int res = QOperatingSystemVersionBase::compare(lhs, rhs);
+ return Qt::compareThreeWay(res, 0);
+ }
+#ifdef __cpp_lib_three_way_comparison
+ friend std::partial_ordering
+ operator<=>(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return compareThreeWay(lhs, rhs); }
+#else
+ friend bool
+ operator>(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return is_gt(compareThreeWay(lhs, rhs)); }
- friend bool operator<(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs)
- { return lhs.type() == rhs.type() && QOperatingSystemVersionBase::compare(lhs, rhs) < 0; }
+ friend bool
+ operator>=(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return is_gteq(compareThreeWay(lhs, rhs)); }
- friend bool operator<=(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs)
- { return lhs.type() == rhs.type() && QOperatingSystemVersionBase::compare(lhs, rhs) <= 0; }
+ friend bool
+ operator<(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return is_lt(compareThreeWay(lhs, rhs)); }
-protected:
- static Q_CORE_EXPORT int compare(QOperatingSystemVersionBase v1,
- QOperatingSystemVersionBase v2);
+ friend bool
+ operator<=(QOperatingSystemVersionBase lhs, QOperatingSystemVersionBase rhs) noexcept
+ { return is_lteq(compareThreeWay(lhs, rhs)); }
+#endif
QOperatingSystemVersionBase() = default;
private:
static QOperatingSystemVersionBase current_impl();
-
OSType m_os;
int m_major;
int m_minor;
int m_micro;
};
-// ### Qt 7: Un-export the class, export relevant functions. Remove the enum.
-class Q_CORE_EXPORT QOperatingSystemVersion : public QOperatingSystemVersionBase
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) && !defined(Q_QDOC)
+class QOperatingSystemVersionUnexported : public QOperatingSystemVersionBase
{
public:
+ using QOperatingSystemVersionBase::QOperatingSystemVersionBase;
+ constexpr QOperatingSystemVersionUnexported(QOperatingSystemVersionBase other) noexcept
+ : QOperatingSystemVersionBase(other) {}
+#else
+class QOperatingSystemVersion : public QOperatingSystemVersionBase
+{
+ using QOperatingSystemVersionUnexported = QOperatingSystemVersionBase;
+#endif
+
+ // ### Qt7: Regroup with the rest below
+ static constexpr QOperatingSystemVersionBase MacOSSonoma { QOperatingSystemVersionBase::MacOS, 14, 0 };
+ static constexpr QOperatingSystemVersionBase Android14 { QOperatingSystemVersionBase::Android, 14, 0 };
+ static constexpr QOperatingSystemVersionBase Windows11_23H2 { QOperatingSystemVersionBase::Windows, 10, 0, 22631 };
+
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED) && !defined(Q_QDOC)
+};
+
+class Q_CORE_EXPORT QOperatingSystemVersion : public QOperatingSystemVersionUnexported
+{
+#endif
+public:
// ### Qt7: Remove. Keep synchronized with QOperatingSystemVersionBase::OSType until then!
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
enum OSType {
Unknown = 0,
Windows,
@@ -113,16 +161,15 @@ public:
IOS,
TvOS,
WatchOS,
- Android
+ Android,
+ VisionOS
};
#endif
- // ### Qt7: remove the branch with static const variables. Then group and sort the inline ones.
- // Since the exported variables emit symbols they cannot be cherry-picked back to patch-releases
- // without breaking our BC promises. They must be fully inline but we cannot make that change
- // until Qt7
- // @note: New entries should be added after the if-def-ery until Qt 7!!
-#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
+ // ### Qt7: remove the branch with static const variables. Then group and
+ // sort the inline ones. Until then, new entries should be added to
+ // QOperatingSystemVersionUnexported.
+#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) && !defined(QT_BOOTSTRAPPED)
static const QOperatingSystemVersion Windows7;
static const QOperatingSystemVersion Windows8;
static const QOperatingSystemVersion Windows8_1;
@@ -152,9 +199,6 @@ public:
static const QOperatingSystemVersion AndroidPie;
static const QOperatingSystemVersion Android10;
static const QOperatingSystemVersion Android11;
- static const QOperatingSystemVersion Android12;
- static const QOperatingSystemVersion Android12L;
- static const QOperatingSystemVersion Android13;
#else
static constexpr QOperatingSystemVersionBase Windows7 { QOperatingSystemVersionBase::Windows, 6, 1 };
static constexpr QOperatingSystemVersionBase Windows8 { QOperatingSystemVersionBase::Windows, 6, 2 };
@@ -168,12 +212,8 @@ public:
static constexpr QOperatingSystemVersionBase MacOSHighSierra { QOperatingSystemVersionBase::MacOS, 10, 13 };
static constexpr QOperatingSystemVersionBase MacOSMojave { QOperatingSystemVersionBase::MacOS, 10, 14 };
static constexpr QOperatingSystemVersionBase MacOSCatalina { QOperatingSystemVersionBase::MacOS, 10, 15 };
-#if !defined(Q_OS_DARWIN) || QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_11_0)
static constexpr QOperatingSystemVersionBase MacOSBigSur = { QOperatingSystemVersionBase::MacOS, 11, 0 };
static constexpr QOperatingSystemVersionBase MacOSMonterey = { QOperatingSystemVersionBase::MacOS, 12, 0 };
-#else // ### Qt 7: Verify the assumption
-# error Either you are using an outdated SDK or my assumption that Qt7 would require at least 11.0 was wrong
-#endif
static constexpr QOperatingSystemVersionBase AndroidJellyBean { QOperatingSystemVersionBase::Android, 4, 1 };
static constexpr QOperatingSystemVersionBase AndroidJellyBean_MR1 { QOperatingSystemVersionBase::Android, 4, 2 };
@@ -189,10 +229,7 @@ public:
static constexpr QOperatingSystemVersionBase AndroidPie { QOperatingSystemVersionBase::Android, 9, 0 };
static constexpr QOperatingSystemVersionBase Android10 { QOperatingSystemVersionBase::Android, 10, 0 };
static constexpr QOperatingSystemVersionBase Android11 { QOperatingSystemVersionBase::Android, 11, 0 };
- static constexpr QOperatingSystemVersionBase Android12 { QOperatingSystemVersionBase::Android, 12, 0 };
- static constexpr QOperatingSystemVersionBase Android12L { QOperatingSystemVersionBase::Android, 12, 0 };
- static constexpr QOperatingSystemVersionBase Android13 { QOperatingSystemVersionBase::Android, 13, 0 };
-#endif // New (static constexpr) entries go here, only cherry-pick as far back as 6.3 (QTBUG-97808):
+#endif
static constexpr QOperatingSystemVersionBase Windows10_1809 { QOperatingSystemVersionBase::Windows, 10, 0, 17763 }; // RS5
static constexpr QOperatingSystemVersionBase Windows10_1903 { QOperatingSystemVersionBase::Windows, 10, 0, 18362 }; // 19H1
@@ -201,26 +238,36 @@ public:
static constexpr QOperatingSystemVersionBase Windows10_20H2 { QOperatingSystemVersionBase::Windows, 10, 0, 19042 };
static constexpr QOperatingSystemVersionBase Windows10_21H1 { QOperatingSystemVersionBase::Windows, 10, 0, 19043 };
static constexpr QOperatingSystemVersionBase Windows10_21H2 { QOperatingSystemVersionBase::Windows, 10, 0, 19044 };
+ static constexpr QOperatingSystemVersionBase Windows10_22H2 { QOperatingSystemVersionBase::Windows, 10, 0, 19045 };
static constexpr QOperatingSystemVersionBase Windows11 { QOperatingSystemVersionBase::Windows, 10, 0, 22000 };
static constexpr QOperatingSystemVersionBase Windows11_21H2 = Windows11;
static constexpr QOperatingSystemVersionBase Windows11_22H2 { QOperatingSystemVersionBase::Windows, 10, 0, 22621 };
+ static constexpr QOperatingSystemVersionBase Android12 { QOperatingSystemVersionBase::Android, 12, 0 };
+ static constexpr QOperatingSystemVersionBase Android12L { QOperatingSystemVersionBase::Android, 12, 0 };
+ static constexpr QOperatingSystemVersionBase Android13 { QOperatingSystemVersionBase::Android, 13, 0 };
+
+ static constexpr QOperatingSystemVersionBase MacOSVentura { QOperatingSystemVersionBase::MacOS, 13, 0 };
+
constexpr QOperatingSystemVersion(const QOperatingSystemVersionBase &osversion)
- : QOperatingSystemVersionBase(osversion) {}
+ : QOperatingSystemVersionUnexported(osversion) {}
constexpr QOperatingSystemVersion(OSType osType, int vmajor, int vminor = -1, int vmicro = -1)
- : QOperatingSystemVersionBase(QOperatingSystemVersionBase::OSType(osType), vmajor, vminor,
+ : QOperatingSystemVersionUnexported(QOperatingSystemVersionBase::OSType(osType), vmajor, vminor,
vmicro)
{
}
+#if QT_CORE_REMOVED_SINCE(6, 3) || defined(Q_QDOC)
static QOperatingSystemVersion current();
+#endif
static constexpr OSType currentType()
{
return OSType(QOperatingSystemVersionBase::currentType());
}
+#if QT_CORE_REMOVED_SINCE(6, 3) || defined(Q_QDOC)
QVersionNumber version() const { return QOperatingSystemVersionBase::version(); }
constexpr int majorVersion() const { return QOperatingSystemVersionBase::majorVersion(); }
@@ -229,10 +276,13 @@ public:
constexpr int segmentCount() const
{ return QOperatingSystemVersionBase::segmentCount(); }
+#endif // QT_CORE_REMOVED_SINCE(6, 3)
constexpr OSType type() const { return OSType(QOperatingSystemVersionBase::type()); }
- bool isAnyOfType(std::initializer_list<OSType> types) const;
+ QT7_ONLY(Q_CORE_EXPORT) bool isAnyOfType(std::initializer_list<OSType> types) const;
+#if QT_CORE_REMOVED_SINCE(6, 3) || defined(Q_QDOC)
QString name() const;
+#endif
private:
QOperatingSystemVersion() = default;
diff --git a/src/corelib/global/qoperatingsystemversion_darwin.mm b/src/corelib/global/qoperatingsystemversion_darwin.mm
index 6581244821..f8d9fbd027 100644
--- a/src/corelib/global/qoperatingsystemversion_darwin.mm
+++ b/src/corelib/global/qoperatingsystemversion_darwin.mm
@@ -2,19 +2,56 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qoperatingsystemversion_p.h"
+
#import <Foundation/Foundation.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qversionnumber.h>
+
+#if !defined(QT_BOOTSTRAPPED)
+#include <QtCore/qprocess.h>
+#endif
+
QT_BEGIN_NAMESPACE
+using namespace Qt::StringLiterals;
+
QOperatingSystemVersionBase QOperatingSystemVersionBase::current_impl()
{
NSOperatingSystemVersion osv = NSProcessInfo.processInfo.operatingSystemVersion;
- QOperatingSystemVersionBase v;
- v.m_os = currentType();
- v.m_major = osv.majorVersion;
- v.m_minor = osv.minorVersion;
- v.m_micro = osv.patchVersion;
- return v;
+ QVersionNumber versionNumber(osv.majorVersion, osv.minorVersion, osv.patchVersion);
+
+ if (versionNumber.majorVersion() == 10 && versionNumber.minorVersion() >= 16) {
+ // The process is running in system version compatibility mode,
+ // due to the executable being built against a pre-macOS 11 SDK.
+ // This might happen even if we require a more recent SDK for
+ // building Qt applications, as the Qt 'app' might be a plugin
+ // hosted inside a host that used an earlier SDK. But, since we
+ // require a recent SDK for the Qt app itself, the application
+ // should be prepared for versions numbers beyond 10, and we can
+ // resolve the real version number here.
+#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(process)
+ QProcess sysctl;
+ QProcessEnvironment nonCompatEnvironment;
+ nonCompatEnvironment.insert("SYSTEM_VERSION_COMPAT"_L1, "0"_L1);
+ sysctl.setProcessEnvironment(nonCompatEnvironment);
+ sysctl.start("/usr/sbin/sysctl"_L1, QStringList() << "-b"_L1 << "kern.osproductversion"_L1);
+ if (sysctl.waitForFinished()) {
+ auto versionString = QString::fromLatin1(sysctl.readAll());
+ auto nonCompatSystemVersion = QVersionNumber::fromString(versionString);
+ if (!nonCompatSystemVersion.isNull())
+ versionNumber = nonCompatSystemVersion;
+ }
+#endif
+ }
+
+ QOperatingSystemVersionBase operatingSystemVersion;
+ operatingSystemVersion.m_os = currentType();
+ operatingSystemVersion.m_major = versionNumber.majorVersion();
+ operatingSystemVersion.m_minor = versionNumber.minorVersion();
+ operatingSystemVersion.m_micro = versionNumber.microVersion();
+
+ return operatingSystemVersion;
}
QT_END_NAMESPACE
diff --git a/src/corelib/global/qprocessordetection.h b/src/corelib/global/qprocessordetection.h
index 34d39512e9..f7298bbb86 100644
--- a/src/corelib/global/qprocessordetection.h
+++ b/src/corelib/global/qprocessordetection.h
@@ -51,8 +51,8 @@
Alpha is bi-endian, use endianness auto-detection implemented below.
*/
-// #elif defined(__alpha__) || defined(_M_ALPHA)
-// # define Q_PROCESSOR_ALPHA
+#if defined(__alpha__) || defined(_M_ALPHA)
+# define Q_PROCESSOR_ALPHA
// Q_BYTE_ORDER not defined, use endianness auto-detection
/*
@@ -61,7 +61,7 @@
ARM is bi-endian, detect using __ARMEL__ or __ARMEB__, falling back to
auto-detection implemented below.
*/
-#if defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || defined(__ARM64__)
+#elif defined(__arm__) || defined(__TARGET_ARCH_ARM) || defined(_M_ARM) || defined(_M_ARM64) || defined(__aarch64__) || defined(__ARM64__)
# if defined(__aarch64__) || defined(__ARM64__) || defined(_M_ARM64)
# define Q_PROCESSOR_ARM_64
# define Q_PROCESSOR_WORDSIZE 8
@@ -143,6 +143,15 @@
// # define Q_BYTE_ORDER Q_LITTLE_ENDIAN
/*
+ PA-RISC family, no revisions or variants
+
+ PA-RISC is big-endian.
+*/
+#elif defined(__hppa__)
+# define Q_PROCESSOR_HPPA
+# define Q_BYTE_ORDER Q_BIG_ENDIAN
+
+/*
X86 family, known variants: 32- and 64-bit
X86 is little-endian.
@@ -191,6 +200,29 @@
// Q_BYTE_ORDER not defined, use endianness auto-detection
/*
+ LoongArch family, known variants: 32- and 64-bit
+
+ LoongArch is little-endian.
+*/
+#elif defined(__loongarch__)
+# define Q_PROCESSOR_LOONGARCH
+# if __loongarch_grlen == 64
+# define Q_PROCESSOR_LOONGARCH_64
+# else
+# define Q_PROCESSOR_LOONGARCH_32
+# endif
+# define Q_BYTE_ORDER Q_LITTLE_ENDIAN
+
+/*
+ Motorola 68000 family, no revisions or variants
+
+ M68K is big-endian.
+*/
+#elif defined(__m68k__)
+# define Q_PROCESSOR_M68K
+# define Q_BYTE_ORDER Q_BIG_ENDIAN
+
+/*
MIPS family, known revisions: I, II, III, IV, 32, 64
MIPS is bi-endian, use endianness auto-detection implemented below.
@@ -309,6 +341,8 @@
# define Q_PROCESSOR_WORDSIZE 8
#ifdef QT_COMPILER_SUPPORTS_SSE2
# define Q_PROCESSOR_X86 6 // enables SIMD support
+# define Q_PROCESSOR_X86_64 // wasm64
+# define Q_PROCESSOR_WASM_64
#endif
#endif
diff --git a/src/corelib/global/qprocessordetection.qdoc b/src/corelib/global/qprocessordetection.qdoc
index 1cb16fce0c..e6605fb9b9 100644
--- a/src/corelib/global/qprocessordetection.qdoc
+++ b/src/corelib/global/qprocessordetection.qdoc
@@ -87,6 +87,15 @@
*/
/*!
+ \macro Q_PROCESSOR_HPPA
+ \relates <QtProcessorDetection>
+
+ Defined if the application is compiled for PA-RISC processors.
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+
+/*!
\macro Q_PROCESSOR_IA64
\relates <QtProcessorDetection>
@@ -97,6 +106,49 @@
*/
/*!
+ \macro Q_PROCESSOR_LOONGARCH
+ \relates <QtProcessorDetection>
+ \since 6.5
+
+ Defined if the application is compiled for LoongArch processors.
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+
+/*!
+ \macro Q_PROCESSOR_LOONGARCH_32
+ \relates <QtProcessorDetection>
+ \since 6.5
+
+ Defined if the application is compiled for 32-bit LoongArch processors.
+ The \l Q_PROCESSOR_LOONGARCH macro is also defined when
+ Q_PROCESSOR_LOONGARCH_32 is defined.
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+
+/*!
+ \macro Q_PROCESSOR_LOONGARCH_64
+ \relates <QtProcessorDetection>
+ \since 6.5
+
+ Defined if the application is compiled for 64-bit LoongArch processors.
+ The \l Q_PROCESSOR_LOONGARCH macro is also defined when
+ Q_PROCESSOR_LOONGARCH_64 is defined.
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+
+/*!
+ \macro Q_PROCESSOR_M68K
+ \relates <QtProcessorDetection>
+
+ Defined if the application is compiled for Motorola 68000 processors.
+
+ \sa QSysInfo::buildCpuArchitecture()
+*/
+
+/*!
\macro Q_PROCESSOR_MIPS
\relates <QtProcessorDetection>
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp
index b276f9445f..fd742898f8 100644
--- a/src/corelib/global/qrandom.cpp
+++ b/src/corelib/global/qrandom.cpp
@@ -377,8 +377,9 @@ struct QRandomGenerator::SystemAndGlobalGenerators
struct PRNGLocker
{
+ Q_DISABLE_COPY_MOVE(PRNGLocker)
const bool locked;
- PRNGLocker(const QRandomGenerator *that)
+ Q_NODISCARD_CTOR explicit PRNGLocker(const QRandomGenerator *that)
: locked(that == globalNoInit())
{
if (locked)
@@ -647,7 +648,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel
\fn bool operator==(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
\relates QRandomGenerator
- Returns true if the two the two engines \a rng1 and \a rng2 are at the same
+ Returns true if the two engines \a rng1 and \a rng2 are at the same
state or if they are both reading from the operating system facilities,
false otherwise.
*/
@@ -655,7 +656,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel
/*!
\fn bool QRandomGenerator::operator!=(const QRandomGenerator &rng1, const QRandomGenerator &rng2)
- Returns \c true if the two the two engines \a rng1 and \a rng2 are at
+ Returns \c true if the two engines \a rng1 and \a rng2 are at
different states or if one of them is reading from the operating system
facilities and the other is not, \c false otherwise.
*/
@@ -765,7 +766,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel
*/
/*!
- \fn template <typename UInt> void QRandomGenerator::fillRange(UInt *buffer, qsizetype count)
+ \fn template <typename UInt, QRandomGenerator::IfValidUInt<UInt> = true> void QRandomGenerator::fillRange(UInt *buffer, qsizetype count)
Generates \a count 32- or 64-bit quantities (depending on the type \c UInt)
and stores them in the buffer pointed by \a buffer. This is the most
@@ -781,7 +782,7 @@ inline QRandomGenerator::SystemGenerator &QRandomGenerator::SystemGenerator::sel
*/
/*!
- \fn template <typename UInt, size_t N> void QRandomGenerator::fillRange(UInt (&buffer)[N])
+ \fn template <typename UInt, size_t N, QRandomGenerator::IfValidUInt<UInt> = true> void QRandomGenerator::fillRange(UInt (&buffer)[N])
Generates \c N 32- or 64-bit quantities (depending on the type \c UInt) and
stores them in the \a buffer array. This is the most efficient way to
diff --git a/src/corelib/global/qsimd.cpp b/src/corelib/global/qsimd.cpp
index cc90433567..8bc5381591 100644
--- a/src/corelib/global/qsimd.cpp
+++ b/src/corelib/global/qsimd.cpp
@@ -9,8 +9,6 @@
#include "qsimd_p.h"
#include "qalgorithms.h"
-#include <array> // for std::size
-
#include <stdio.h>
#include <string.h>
@@ -64,6 +62,14 @@
QT_BEGIN_NAMESPACE
+template <typename T, uint N> QT_FUNCTION_TARGET_BASELINE
+uint arraysize(T (&)[N])
+{
+ // Same as std::size, but with QT_FUNCTION_TARGET_BASELIE,
+ // otherwise some versions of GCC fail to compile.
+ return N;
+}
+
#if defined(Q_PROCESSOR_ARM)
/* Data:
neon
@@ -97,12 +103,7 @@ static const int features_indices[] = { 0 };
#endif
// end generated
-#if defined (Q_OS_NACL)
-static inline uint detectProcessorFeatures()
-{
- return 0;
-}
-#elif defined(Q_PROCESSOR_ARM)
+#if defined(Q_PROCESSOR_ARM)
static inline quint64 detectProcessorFeatures()
{
quint64 features = 0;
@@ -364,7 +365,7 @@ static quint64 detectProcessorFeatures()
cpuidFeatures07_00(results[Leaf07_00EBX], results[Leaf07_00ECX], results[Leaf07_00EDX]);
// populate our feature list
- for (uint i = 0; i < std::size(x86_locators); ++i) {
+ for (uint i = 0; i < arraysize(x86_locators); ++i) {
uint word = x86_locators[i] / 32;
uint bit = 1U << (x86_locators[i] % 32);
quint64 feature = Q_UINT64_C(1) << i;
@@ -560,11 +561,6 @@ QT_FUNCTION_TARGET_BASELINE
uint64_t QT_MANGLE_NAMESPACE(qDetectCpuFeatures)()
{
auto minFeatureTest = minFeature;
-#if defined(Q_OS_LINUX) && defined(Q_PROCESSOR_ARM_64)
- // Yocto hard-codes CRC32+AES on. Since they are unlikely to be used
- // automatically by compilers, we can just add runtime check.
- minFeatureTest &= ~(CpuFeatureAES|CpuFeatureCRC32);
-#endif
#if defined(Q_PROCESSOR_X86_64) && defined(cpu_feature_shstk)
// Controlflow Enforcement Technology (CET) is an OS-assisted
// hardware-feature, meaning the CPUID bit may be disabled if the OS
@@ -583,7 +579,7 @@ uint64_t QT_MANGLE_NAMESPACE(qDetectCpuFeatures)()
#endif
while (char *token = strtok(disable, " ")) {
disable = nullptr;
- for (uint i = 0; i < std::size(features_indices); ++i) {
+ for (uint i = 0; i < arraysize(features_indices); ++i) {
if (strcmp(token, features_string + features_indices[i]) == 0)
f &= ~(Q_UINT64_C(1) << i);
}
@@ -598,7 +594,7 @@ uint64_t QT_MANGLE_NAMESPACE(qDetectCpuFeatures)()
if (Q_UNLIKELY(!runningOnValgrind && minFeatureTest != 0 && (f & minFeatureTest) != minFeatureTest)) {
quint64 missing = minFeatureTest & ~quint64(f);
fprintf(stderr, "Incompatible processor. This Qt build requires the following features:\n ");
- for (uint i = 0; i < std::size(features_indices); ++i) {
+ for (uint i = 0; i < arraysize(features_indices); ++i) {
if (missing & (Q_UINT64_C(1) << i))
fprintf(stderr, "%s", features_string + features_indices[i]);
}
@@ -618,14 +614,14 @@ void qDumpCPUFeatures()
{
quint64 features = detectProcessorFeatures() & ~SimdInitialized;
printf("Processor features: ");
- for (uint i = 0; i < std::size(features_indices); ++i) {
+ for (uint i = 0; i < arraysize(features_indices); ++i) {
if (features & (Q_UINT64_C(1) << i))
printf("%s%s", features_string + features_indices[i],
minFeature & (Q_UINT64_C(1) << i) ? "[required]" : "");
}
if ((features = (qCompilerCpuFeatures & ~features))) {
printf("\n!!!!!!!!!!!!!!!!!!!!\n!!! Missing required features:");
- for (uint i = 0; i < std::size(features_indices); ++i) {
+ for (uint i = 0; i < arraysize(features_indices); ++i) {
if (features & (Q_UINT64_C(1) << i))
printf("%s", features_string + features_indices[i]);
}
@@ -760,7 +756,7 @@ QT_FUNCTION_TARGET(RDRND) qsizetype qRandomCpu(void *buffer, qsizetype count) no
ptr = qt_random_rdrnd(ptr, end);
return ptr - reinterpret_cast<unsigned *>(buffer);
}
-#elif defined(Q_PROCESSOR_X86) && !defined(Q_OS_NACL) && !defined(Q_PROCESSOR_ARM)
+#elif defined(Q_PROCESSOR_X86) && !defined(Q_PROCESSOR_ARM)
static bool checkRdrndWorks() noexcept { return false; }
#endif // Q_PROCESSOR_X86 && RDRND
diff --git a/src/corelib/global/qsimd.h b/src/corelib/global/qsimd.h
index 87e9d0d098..4ef925ca33 100644
--- a/src/corelib/global/qsimd.h
+++ b/src/corelib/global/qsimd.h
@@ -55,7 +55,7 @@
#if defined(Q_PROCESSOR_X86) && defined(Q_CC_MSVC)
// MSVC doesn't define __SSE2__, so do it ourselves
-# if (defined(_M_X64) || _M_IX86_FP >= 2)
+# if (defined(_M_X64) || _M_IX86_FP >= 2) && defined(QT_COMPILER_SUPPORTS_SSE2)
# define __SSE__ 1
# define __SSE2__ 1
# endif
@@ -77,9 +77,11 @@
# ifdef __AVX2__
// MSVC defines __AVX2__ with /arch:AVX2
# define __F16C__ 1
+# define __RDRND__ 1
# define __FMA__ 1
# define __BMI__ 1
# define __BMI2__ 1
+# define __MOVBE__ 1
# define __LZCNT__ 1
# endif
// Starting with /arch:AVX512, MSVC defines all the macros
diff --git a/src/corelib/global/qsimd_p.h b/src/corelib/global/qsimd_p.h
index 344aeefc71..012eb6cf4f 100644
--- a/src/corelib/global/qsimd_p.h
+++ b/src/corelib/global/qsimd_p.h
@@ -218,29 +218,31 @@ asm(
// x86-64 sub-architecture version 3
//
// The Intel Core 4th generation was codenamed "Haswell" and introduced AVX2,
-// BMI1, BMI2, FMA, LZCNT, MOVBE, which makes it a good divider for a
-// sub-target for us. The first AMD processor with AVX2 support (Zen) has the
-// same features, but had already introduced BMI1 in the previous generation.
-// This feature set was chosen as the version 3 of the x86-64 ISA (x86-64-v3)
-// and is supported by GCC and Clang.
-//
-// macOS's fat binaries support the "x86_64h" sub-architecture and the GNU libc
-// ELF loader also supports a "haswell/" subdir (e.g., /usr/lib/haswell).
-# define ARCH_HASWELL_MACROS (__AVX2__ + __BMI2__ + __FMA__ + __LZCNT__)
-# if ARCH_HASWELL_MACROS != 0
-# if ARCH_HASWELL_MACROS != 4
+// BMI1, BMI2, FMA, LZCNT, MOVBE. This feature set was chosen as the version 3
+// of the x86-64 ISA (x86-64-v3) and is supported by GCC and Clang. On systems
+// with the GNU libc, libraries with this feature can be installed on a
+// "glibc-hwcaps/x86-64-v3" subdir. macOS's fat binaries support the "x86_64h"
+// sub-architecture too.
+
+# if defined(__AVX2__)
+// List of features present with -march=x86-64-v3 and not architecturally
+// implied by __AVX2__
+# define ARCH_HASWELL_MACROS \
+ (__AVX2__ + __BMI__ + __BMI2__ + __F16C__ + __FMA__ + __LZCNT__ + __POPCNT__)
+# if ARCH_HASWELL_MACROS != 7
# error "Please enable all x86-64-v3 extensions; you probably want to use -march=haswell or -march=x86-64-v3 instead of -mavx2"
# endif
static_assert(ARCH_HASWELL_MACROS, "Undeclared identifiers indicate which features are missing.");
# define __haswell__ 1
+# undef ARCH_HASWELL_MACROS
# endif
-# undef ARCH_HASWELL_MACROS
// x86-64 sub-architecture version 4
//
// Similar to the above, x86-64-v4 matches the AVX512 variant of the Intel Core
// 6th generation (codename "Skylake"). AMD Zen4 is the their first processor
-// with AVX512 support and it includes all of these too.
+// with AVX512 support and it includes all of these too. The GNU libc subdir for
+// this is "glibc-hwcaps/x86-64-v4".
//
# define ARCH_SKX_MACROS (__AVX512F__ + __AVX512BW__ + __AVX512CD__ + __AVX512DQ__ + __AVX512VL__)
# if ARCH_SKX_MACROS != 0
@@ -323,12 +325,19 @@ static const uint64_t qCompilerCpuFeatures = 0
#if defined __ARM_NEON__
| CpuFeatureNEON
#endif
+#if !(defined(Q_OS_LINUX) && defined(Q_PROCESSOR_ARM_64))
+ // Yocto Project recipes enable Crypto extension for all ARMv8 configs,
+ // even for targets without the Crypto extension. That's wrong, but as
+ // the compiler never generates the code for them on their own, most
+ // code never notices the problem. But we would. By not setting the
+ // bits here, we force a runtime detection.
#if defined __ARM_FEATURE_CRC32
| CpuFeatureCRC32
#endif
#if defined __ARM_FEATURE_CRYPTO
| CpuFeatureAES
#endif
+#endif // Q_OS_LINUX && Q_PROCESSOR_ARM64
#if defined __mips_dsp
| CpuFeatureDSP
#endif
@@ -363,61 +372,21 @@ Q_CORE_EXPORT uint64_t QT_MANGLE_NAMESPACE(qDetectCpuFeatures)();
static inline uint64_t qCpuFeatures()
{
+#ifdef QT_BOOTSTRAPPED
+ return qCompilerCpuFeatures; // no detection
+#else
quint64 features = atomic_load_explicit(QT_MANGLE_NAMESPACE(qt_cpu_features), memory_order_relaxed);
if (!QT_SUPPORTS_INIT_PRIORITY) {
if (Q_UNLIKELY(features == 0))
features = QT_MANGLE_NAMESPACE(qDetectCpuFeatures)();
}
return features;
+#endif
}
#define qCpuHasFeature(feature) (((qCompilerCpuFeatures & CpuFeature ## feature) == CpuFeature ## feature) \
|| ((qCpuFeatures() & CpuFeature ## feature) == CpuFeature ## feature))
-/*
- Small wrapper around x86's PAUSE and ARM's YIELD instructions.
-
- This is completely different from QThread::yieldCurrentThread(), which is
- an OS-level operation that takes the whole thread off the CPU.
-
- This is just preventing one SMT thread from filling a core's pipeline with
- speculated further loop iterations (which need to be expensively flushed on
- final success) when it could just give those pipeline slots to a second SMT
- thread that can do something useful with the core, such as unblocking this
- SMT thread :)
-
- So, instead of
-
- while (!condition)
- ;
-
- it's better to use
-
- while (!condition)
- qYieldCpu();
-*/
-static inline void qYieldCpu()
-{
-#if defined(Q_PROCESSOR_X86)
- _mm_pause();
-#elif defined(Q_PROCESSOR_ARM) && Q_PROCESSOR_ARM >= 7 /* yield was added in ARMv7 */
-# if __has_builtin(__builtin_arm_yield) /* e.g. Clang */
- __builtin_arm_yield();
-# elif defined(Q_OS_INTEGRITY) || \
- (defined(Q_CC_GNU) && !defined(Q_CC_CLANG))
- /*
- - Integrity is missing the arm_acle.h header
- - GCC doesn't have __yield() in arm_acle.h
- https://stackoverflow.com/a/70076751/134841
- https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105416
- */
- asm volatile("yield"); /* this works everywhere */
-# else
- __yield(); /* this is what should work everywhere */
-# endif
-#endif
-}
-
#ifdef __cplusplus
} // extern "C"
diff --git a/src/corelib/global/qsimd_x86.cpp b/src/corelib/global/qsimd_x86.cpp
index f1a08e05e8..9a3bd80b39 100644
--- a/src/corelib/global/qsimd_x86.cpp
+++ b/src/corelib/global/qsimd_x86.cpp
@@ -1,8 +1,8 @@
// Copyright (C) 2022 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
// This is a generated file. DO NOT EDIT.
// Please see util/x86simdgen/README.md
+
#include "qsimd_x86_p.h"
static const char features_string[] =
@@ -30,24 +30,28 @@ static const char features_string[] =
" avx512bw\0"
" avx512vl\0"
" avx512vbmi\0"
+ " waitpkg\0"
" avx512vbmi2\0"
" shstk\0"
" gfni\0"
" vaes\0"
- " avx512vnni\0"
" avx512bitalg\0"
" avx512vpopcntdq\0"
" hybrid\0"
" ibt\0"
" avx512fp16\0"
+ " raoint\0"
+ " cmpccxadd\0"
+ " avxifma\0"
+ " lam\0"
"\0";
static const uint16_t features_indices[] = {
0, 6, 12, 19, 24, 32, 40, 47,
55, 60, 65, 71, 78, 83, 89, 95,
104, 114, 122, 134, 144, 149, 159, 169,
- 181, 194, 201, 207, 213, 225, 239, 256,
- 264, 269,
+ 181, 190, 203, 210, 216, 222, 236, 253,
+ 261, 266, 278, 286, 297, 306,
};
enum X86CpuidLeaves {
@@ -57,6 +61,7 @@ enum X86CpuidLeaves {
Leaf07_00ECX,
Leaf07_00EDX,
Leaf07_01EAX,
+ Leaf07_01EDX,
Leaf13_01EAX,
Leaf80000001hECX,
Leaf80000008hEBX,
@@ -88,16 +93,20 @@ static const uint16_t x86_locators[] = {
Leaf07_00EBX*32 + 30, // avx512bw
Leaf07_00EBX*32 + 31, // avx512vl
Leaf07_00ECX*32 + 1, // avx512vbmi
+ Leaf07_00ECX*32 + 5, // waitpkg
Leaf07_00ECX*32 + 6, // avx512vbmi2
Leaf07_00ECX*32 + 7, // shstk
Leaf07_00ECX*32 + 8, // gfni
Leaf07_00ECX*32 + 9, // vaes
- Leaf07_00ECX*32 + 11, // avx512vnni
Leaf07_00ECX*32 + 12, // avx512bitalg
Leaf07_00ECX*32 + 14, // avx512vpopcntdq
Leaf07_00EDX*32 + 15, // hybrid
Leaf07_00EDX*32 + 20, // ibt
Leaf07_00EDX*32 + 23, // avx512fp16
+ Leaf07_01EAX*32 + 3, // raoint
+ Leaf07_01EAX*32 + 6, // cmpccxadd
+ Leaf07_01EAX*32 + 23, // avxifma
+ Leaf07_01EAX*32 + 26, // lam
};
struct X86Architecture
@@ -107,25 +116,31 @@ struct X86Architecture
};
static const struct X86Architecture x86_architectures[] = {
- { cpu_sapphirerapids, "Sapphire Rapids" },
- { cpu_tigerlake, "Tiger Lake" },
- { cpu_icelake_server, "Ice Lake (Server)" },
- { cpu_icelake_client, "Ice Lake (Client)" },
- { cpu_alderlake, "Alder Lake" },
- { cpu_cannonlake, "Cannon Lake" },
- { cpu_cooperlake, "Cooper Lake" },
- { cpu_cascadelake, "Cascade Lake" },
- { cpu_skylake_avx512, "Skylake (Avx512)" },
- { cpu_skylake, "Skylake" },
- { cpu_tremont, "Tremont" },
- { cpu_broadwell, "Broadwell" },
- { cpu_haswell, "Haswell" },
- { cpu_goldmont, "Goldmont" },
- { cpu_ivybridge, "Ivy Bridge" },
- { cpu_silvermont, "Silvermont" },
- { cpu_sandybridge, "Sandy Bridge" },
- { cpu_westmere, "Westmere" },
{ cpu_core2, "Core2" },
+ { cpu_westmere, "Westmere" },
+ { cpu_sandybridge, "Sandy Bridge" },
+ { cpu_silvermont, "Silvermont" },
+ { cpu_ivybridge, "Ivy Bridge" },
+ { cpu_goldmont, "Goldmont" },
+ { cpu_haswell, "Haswell" },
+ { cpu_broadwell, "Broadwell" },
+ { cpu_tremont, "Tremont" },
+ { cpu_skylake, "Skylake" },
+ { cpu_skylake_avx512, "Skylake (Avx512)" },
+ { cpu_cascadelake, "Cascade Lake" },
+ { cpu_cooperlake, "Cooper Lake" },
+ { cpu_cannonlake, "Cannon Lake" },
+ { cpu_gracemont, "Gracemont" },
+ { cpu_icelake_client, "Ice Lake (Client)" },
+ { cpu_icelake_server, "Ice Lake (Server)" },
+ { cpu_crestmont, "Crestmont" },
+ { cpu_tigerlake, "Tiger Lake" },
+ { cpu_clearwaterforest, "Clearwater Forest" },
+ { cpu_grandridge, "Grand Ridge" },
+ { cpu_raptorcove, "Raptor Cove" },
+ { cpu_redwoodcove, "Redwood Cove" },
+ { cpu_emeraldrapids, "Emerald Rapids" },
+ { cpu_graniterapids, "Granite Rapids" },
};
enum XSaveBits {
@@ -168,10 +183,10 @@ static const uint64_t XSaveReq_AvxState = 0
| cpu_feature_avx512vbmi
| cpu_feature_avx512vbmi2
| cpu_feature_vaes
- | cpu_feature_avx512vnni
| cpu_feature_avx512bitalg
| cpu_feature_avx512vpopcntdq
- | cpu_feature_avx512fp16;
+ | cpu_feature_avx512fp16
+ | cpu_feature_avxifma;
// List of features requiring XSave_Avx512State
static const uint64_t XSaveReq_Avx512State = 0
@@ -183,7 +198,6 @@ static const uint64_t XSaveReq_Avx512State = 0
| cpu_feature_avx512vl
| cpu_feature_avx512vbmi
| cpu_feature_avx512vbmi2
- | cpu_feature_avx512vnni
| cpu_feature_avx512bitalg
| cpu_feature_avx512vpopcntdq
| cpu_feature_avx512fp16;
diff --git a/src/corelib/global/qsimd_x86_p.h b/src/corelib/global/qsimd_x86_p.h
index 3e7427b0b1..1ec89d0c6c 100644
--- a/src/corelib/global/qsimd_x86_p.h
+++ b/src/corelib/global/qsimd_x86_p.h
@@ -1,5 +1,7 @@
// Copyright (C) 2022 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+// This is a generated file. DO NOT EDIT.
+// Please see util/x86simdgen/README.md
//
// W A R N I N G
@@ -50,11 +52,11 @@
// in CPUID Leaf 7, Sub-leaf 0, ECX:
#define cpu_feature_avx512vbmi (UINT64_C(1) << 23)
-#define cpu_feature_avx512vbmi2 (UINT64_C(1) << 24)
-#define cpu_feature_shstk (UINT64_C(1) << 25)
-#define cpu_feature_gfni (UINT64_C(1) << 26)
-#define cpu_feature_vaes (UINT64_C(1) << 27)
-#define cpu_feature_avx512vnni (UINT64_C(1) << 28)
+#define cpu_feature_waitpkg (UINT64_C(1) << 24)
+#define cpu_feature_avx512vbmi2 (UINT64_C(1) << 25)
+#define cpu_feature_shstk (UINT64_C(1) << 26)
+#define cpu_feature_gfni (UINT64_C(1) << 27)
+#define cpu_feature_vaes (UINT64_C(1) << 28)
#define cpu_feature_avx512bitalg (UINT64_C(1) << 29)
#define cpu_feature_avx512vpopcntdq (UINT64_C(1) << 30)
@@ -63,6 +65,12 @@
#define cpu_feature_ibt (UINT64_C(1) << 32)
#define cpu_feature_avx512fp16 (UINT64_C(1) << 33)
+// in CPUID Leaf 7, Sub-leaf 1, EAX:
+#define cpu_feature_raoint (UINT64_C(1) << 34)
+#define cpu_feature_cmpccxadd (UINT64_C(1) << 35)
+#define cpu_feature_avxifma (UINT64_C(1) << 36)
+#define cpu_feature_lam (UINT64_C(1) << 37)
+
// CPU architectures
#define cpu_x86_64 (0 \
| cpu_feature_sse2)
@@ -89,42 +97,65 @@
| cpu_feature_rdseed)
#define cpu_bdx (cpu_bdw)
#define cpu_skl (cpu_bdw)
-#define cpu_adl (cpu_skl \
- | cpu_feature_gfni \
- | cpu_feature_vaes \
- | cpu_feature_shstk \
- | cpu_feature_ibt)
#define cpu_skx (cpu_skl \
| cpu_feature_avx512f \
| cpu_feature_avx512dq \
| cpu_feature_avx512cd \
| cpu_feature_avx512bw \
| cpu_feature_avx512vl)
-#define cpu_clx (cpu_skx \
- | cpu_feature_avx512vnni)
+#define cpu_clx (cpu_skx)
#define cpu_cpx (cpu_clx)
-#define cpu_cnl (cpu_skx \
+#define cpu_plc (cpu_skx \
| cpu_feature_avx512ifma \
| cpu_feature_avx512vbmi)
-#define cpu_icl (cpu_cnl \
+#define cpu_snc (cpu_plc \
| cpu_feature_avx512vbmi2 \
| cpu_feature_gfni \
| cpu_feature_vaes \
- | cpu_feature_avx512vnni \
| cpu_feature_avx512bitalg \
| cpu_feature_avx512vpopcntdq)
-#define cpu_icx (cpu_icl)
-#define cpu_tgl (cpu_icl \
+#define cpu_wlc (cpu_snc \
| cpu_feature_shstk \
| cpu_feature_ibt)
-#define cpu_spr (cpu_tgl)
+#define cpu_glc (cpu_wlc \
+ | cpu_feature_waitpkg)
+#define cpu_rpc (cpu_glc)
+#define cpu_rwc (cpu_rpc)
#define cpu_slm (cpu_wsm \
| cpu_feature_rdrnd \
| cpu_feature_movbe)
#define cpu_glm (cpu_slm \
| cpu_feature_rdseed)
#define cpu_tnt (cpu_glm \
- | cpu_feature_gfni)
+ | cpu_feature_gfni \
+ | cpu_feature_waitpkg)
+#define cpu_grt (cpu_skl \
+ | cpu_feature_gfni \
+ | cpu_feature_vaes \
+ | cpu_feature_shstk \
+ | cpu_feature_ibt \
+ | cpu_feature_waitpkg)
+#define cpu_cmt (cpu_grt \
+ | cpu_feature_cmpccxadd \
+ | cpu_feature_avxifma)
+#define cpu_cnl (cpu_plc)
+#define cpu_icl (cpu_snc)
+#define cpu_tgl (cpu_wlc)
+#define cpu_adl (cpu_grt)
+#define cpu_rpl (cpu_grt)
+#define cpu_mtl (cpu_cmt)
+#define cpu_arl (cpu_cmt)
+#define cpu_lnl (cpu_cmt)
+#define cpu_icx (cpu_snc)
+#define cpu_spr (cpu_glc)
+#define cpu_emr (cpu_spr)
+#define cpu_gnr (cpu_glc)
+#define cpu_srf (cpu_cmt \
+ | cpu_feature_cmpccxadd \
+ | cpu_feature_avxifma)
+#define cpu_grr (cpu_srf \
+ | cpu_feature_raoint)
+#define cpu_cwf (cpu_srf)
#define cpu_nehalem (cpu_nhm)
#define cpu_westmere (cpu_wsm)
#define cpu_sandybridge (cpu_snb)
@@ -135,15 +166,32 @@
#define cpu_skylake_avx512 (cpu_skx)
#define cpu_cascadelake (cpu_clx)
#define cpu_cooperlake (cpu_cpx)
+#define cpu_palmcove (cpu_plc)
#define cpu_cannonlake (cpu_cnl)
+#define cpu_sunnycove (cpu_snc)
#define cpu_icelake_client (cpu_icl)
#define cpu_icelake_server (cpu_icx)
+#define cpu_willowcove (cpu_wlc)
+#define cpu_tigerlake (cpu_tgl)
+#define cpu_goldencove (cpu_glc)
#define cpu_alderlake (cpu_adl)
+#define cpu_raptorcove (cpu_rpc)
+#define cpu_raptorlake (cpu_rpl)
+#define cpu_redwoodcove (cpu_rwc)
+#define cpu_meteorlake (cpu_mtl)
+#define cpu_arrowlake (cpu_arl)
+#define cpu_lunarlake (cpu_lnl)
#define cpu_sapphirerapids (cpu_spr)
-#define cpu_tigerlake (cpu_tgl)
+#define cpu_emeraldrapids (cpu_emr)
+#define cpu_graniterapids (cpu_gnr)
#define cpu_silvermont (cpu_slm)
#define cpu_goldmont (cpu_glm)
#define cpu_tremont (cpu_tnt)
+#define cpu_gracemont (cpu_grt)
+#define cpu_crestmont (cpu_cmt)
+#define cpu_grandridge (cpu_grr)
+#define cpu_sierraforest (cpu_srf)
+#define cpu_clearwaterforest (cpu_cwf)
// __attribute__ target strings for GCC and Clang
#define QT_FUNCTION_TARGET_STRING_SSE2 "sse2"
@@ -170,16 +218,20 @@
#define QT_FUNCTION_TARGET_STRING_AVX512BW "avx512bw,avx512f"
#define QT_FUNCTION_TARGET_STRING_AVX512VL "avx512vl,avx512f"
#define QT_FUNCTION_TARGET_STRING_AVX512VBMI "avx512vbmi,avx512f"
+#define QT_FUNCTION_TARGET_STRING_WAITPKG "waitpkg"
#define QT_FUNCTION_TARGET_STRING_AVX512VBMI2 "avx512vbmi2,avx512f"
#define QT_FUNCTION_TARGET_STRING_SHSTK "shstk"
#define QT_FUNCTION_TARGET_STRING_GFNI "gfni"
#define QT_FUNCTION_TARGET_STRING_VAES "vaes,avx2,avx,aes"
-#define QT_FUNCTION_TARGET_STRING_AVX512VNNI "avx512vnni,avx512f"
#define QT_FUNCTION_TARGET_STRING_AVX512BITALG "avx512bitalg,avx512f"
#define QT_FUNCTION_TARGET_STRING_AVX512VPOPCNTDQ "avx512vpopcntdq,avx512f"
#define QT_FUNCTION_TARGET_STRING_HYBRID "hybrid"
#define QT_FUNCTION_TARGET_STRING_IBT "ibt"
#define QT_FUNCTION_TARGET_STRING_AVX512FP16 "avx512fp16,avx512f,f16c"
+#define QT_FUNCTION_TARGET_STRING_RAOINT "raoint"
+#define QT_FUNCTION_TARGET_STRING_CMPCCXADD "cmpccxadd"
+#define QT_FUNCTION_TARGET_STRING_AVXIFMA "avxifma,avx"
+#define QT_FUNCTION_TARGET_STRING_LAM "lam"
#define QT_FUNCTION_TARGET_STRING_ARCH_X86_64 "sse2"
#define QT_FUNCTION_TARGET_STRING_ARCH_CORE2 QT_FUNCTION_TARGET_STRING_ARCH_X86_64 ",sse3,ssse3,cx16"
#define QT_FUNCTION_TARGET_STRING_ARCH_NHM QT_FUNCTION_TARGET_STRING_ARCH_CORE2 ",sse4.1,sse4.2,popcnt"
@@ -190,18 +242,35 @@
#define QT_FUNCTION_TARGET_STRING_ARCH_BDW QT_FUNCTION_TARGET_STRING_ARCH_HSW ",adx,rdseed"
#define QT_FUNCTION_TARGET_STRING_ARCH_BDX QT_FUNCTION_TARGET_STRING_ARCH_BDW
#define QT_FUNCTION_TARGET_STRING_ARCH_SKL QT_FUNCTION_TARGET_STRING_ARCH_BDW ",xsavec,xsaves"
-#define QT_FUNCTION_TARGET_STRING_ARCH_ADL QT_FUNCTION_TARGET_STRING_ARCH_SKL ",avxvnni,gfni,vaes,vpclmulqdq,serialize,shstk,cldemote,movdiri,movdir64b,ibt,waitpkg,keylocker"
#define QT_FUNCTION_TARGET_STRING_ARCH_SKX QT_FUNCTION_TARGET_STRING_ARCH_SKL ",avx512f,avx512dq,avx512cd,avx512bw,avx512vl"
#define QT_FUNCTION_TARGET_STRING_ARCH_CLX QT_FUNCTION_TARGET_STRING_ARCH_SKX ",avx512vnni"
#define QT_FUNCTION_TARGET_STRING_ARCH_CPX QT_FUNCTION_TARGET_STRING_ARCH_CLX ",avx512bf16"
-#define QT_FUNCTION_TARGET_STRING_ARCH_CNL QT_FUNCTION_TARGET_STRING_ARCH_SKX ",avx512ifma,avx512vbmi"
-#define QT_FUNCTION_TARGET_STRING_ARCH_ICL QT_FUNCTION_TARGET_STRING_ARCH_CNL ",avx512vbmi2,gfni,vaes,vpclmulqdq,avx512vnni,avx512bitalg,avx512vpopcntdq"
-#define QT_FUNCTION_TARGET_STRING_ARCH_ICX QT_FUNCTION_TARGET_STRING_ARCH_ICL ",pconfig"
-#define QT_FUNCTION_TARGET_STRING_ARCH_TGL QT_FUNCTION_TARGET_STRING_ARCH_ICL ",avx512vp2intersect,shstk,,movdiri,movdir64b,ibt,keylocker"
-#define QT_FUNCTION_TARGET_STRING_ARCH_SPR QT_FUNCTION_TARGET_STRING_ARCH_TGL ",avx512bf16,amxtile,amxbf16,amxint8,avxvnni,cldemote,pconfig,waitpkg,serialize,tsxldtrk,uintr"
+#define QT_FUNCTION_TARGET_STRING_ARCH_PLC QT_FUNCTION_TARGET_STRING_ARCH_SKX ",avx512ifma,avx512vbmi"
+#define QT_FUNCTION_TARGET_STRING_ARCH_SNC QT_FUNCTION_TARGET_STRING_ARCH_PLC ",avx512vbmi2,gfni,vaes,vpclmulqdq,avx512vnni,avx512bitalg,avx512vpopcntdq"
+#define QT_FUNCTION_TARGET_STRING_ARCH_WLC QT_FUNCTION_TARGET_STRING_ARCH_SNC ",shstk,movdiri,movdir64b,ibt,keylocker"
+#define QT_FUNCTION_TARGET_STRING_ARCH_GLC QT_FUNCTION_TARGET_STRING_ARCH_WLC ",avx512bf16,avxvnni,cldemote,waitpkg,serialize,uintr"
+#define QT_FUNCTION_TARGET_STRING_ARCH_RPC QT_FUNCTION_TARGET_STRING_ARCH_GLC
+#define QT_FUNCTION_TARGET_STRING_ARCH_RWC QT_FUNCTION_TARGET_STRING_ARCH_RPC ",prefetchiti"
#define QT_FUNCTION_TARGET_STRING_ARCH_SLM QT_FUNCTION_TARGET_STRING_ARCH_WSM ",rdrnd,movbe"
#define QT_FUNCTION_TARGET_STRING_ARCH_GLM QT_FUNCTION_TARGET_STRING_ARCH_SLM ",fsgsbase,rdseed,lzcnt,xsavec,xsaves"
#define QT_FUNCTION_TARGET_STRING_ARCH_TNT QT_FUNCTION_TARGET_STRING_ARCH_GLM ",clwb,gfni,cldemote,waitpkg,movdiri,movdir64b"
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRT QT_FUNCTION_TARGET_STRING_ARCH_SKL ",avxvnni,gfni,vaes,vpclmulqdq,serialize,shstk,cldemote,movdiri,movdir64b,ibt,waitpkg,keylocker"
+#define QT_FUNCTION_TARGET_STRING_ARCH_CMT QT_FUNCTION_TARGET_STRING_ARCH_GRT ",cmpccxadd,avxifma,avxneconvert,avxvnniint8"
+#define QT_FUNCTION_TARGET_STRING_ARCH_CNL QT_FUNCTION_TARGET_STRING_ARCH_PLC
+#define QT_FUNCTION_TARGET_STRING_ARCH_ICL QT_FUNCTION_TARGET_STRING_ARCH_SNC
+#define QT_FUNCTION_TARGET_STRING_ARCH_TGL QT_FUNCTION_TARGET_STRING_ARCH_WLC
+#define QT_FUNCTION_TARGET_STRING_ARCH_ADL QT_FUNCTION_TARGET_STRING_ARCH_GRT
+#define QT_FUNCTION_TARGET_STRING_ARCH_RPL QT_FUNCTION_TARGET_STRING_ARCH_GRT
+#define QT_FUNCTION_TARGET_STRING_ARCH_MTL QT_FUNCTION_TARGET_STRING_ARCH_CMT
+#define QT_FUNCTION_TARGET_STRING_ARCH_ARL QT_FUNCTION_TARGET_STRING_ARCH_CMT
+#define QT_FUNCTION_TARGET_STRING_ARCH_LNL QT_FUNCTION_TARGET_STRING_ARCH_CMT
+#define QT_FUNCTION_TARGET_STRING_ARCH_ICX QT_FUNCTION_TARGET_STRING_ARCH_SNC ",pconfig"
+#define QT_FUNCTION_TARGET_STRING_ARCH_SPR QT_FUNCTION_TARGET_STRING_ARCH_GLC ",pconfig,amx-tile,amx-bf16,amx-int8"
+#define QT_FUNCTION_TARGET_STRING_ARCH_EMR QT_FUNCTION_TARGET_STRING_ARCH_SPR
+#define QT_FUNCTION_TARGET_STRING_ARCH_GNR QT_FUNCTION_TARGET_STRING_ARCH_GLC ",pconfig,amx-tile,amx-bf16,amx-int8,amx-fp16,amx-complex"
+#define QT_FUNCTION_TARGET_STRING_ARCH_SRF QT_FUNCTION_TARGET_STRING_ARCH_CMT ",cmpccxadd,avxifma,avxneconvert,avxvnniint8"
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRR QT_FUNCTION_TARGET_STRING_ARCH_SRF ",raoint"
+#define QT_FUNCTION_TARGET_STRING_ARCH_CWF QT_FUNCTION_TARGET_STRING_ARCH_SRF
#define QT_FUNCTION_TARGET_STRING_ARCH_NEHALEM QT_FUNCTION_TARGET_STRING_ARCH_NHM
#define QT_FUNCTION_TARGET_STRING_ARCH_WESTMERE QT_FUNCTION_TARGET_STRING_ARCH_WSM
#define QT_FUNCTION_TARGET_STRING_ARCH_SANDYBRIDGE QT_FUNCTION_TARGET_STRING_ARCH_SNB
@@ -212,15 +281,32 @@
#define QT_FUNCTION_TARGET_STRING_ARCH_SKYLAKE_AVX512 QT_FUNCTION_TARGET_STRING_ARCH_SKX
#define QT_FUNCTION_TARGET_STRING_ARCH_CASCADELAKE QT_FUNCTION_TARGET_STRING_ARCH_CLX
#define QT_FUNCTION_TARGET_STRING_ARCH_COOPERLAKE QT_FUNCTION_TARGET_STRING_ARCH_CPX
+#define QT_FUNCTION_TARGET_STRING_ARCH_PALMCOVE QT_FUNCTION_TARGET_STRING_ARCH_PLC
#define QT_FUNCTION_TARGET_STRING_ARCH_CANNONLAKE QT_FUNCTION_TARGET_STRING_ARCH_CNL
+#define QT_FUNCTION_TARGET_STRING_ARCH_SUNNYCOVE QT_FUNCTION_TARGET_STRING_ARCH_SNC
#define QT_FUNCTION_TARGET_STRING_ARCH_ICELAKE_CLIENT QT_FUNCTION_TARGET_STRING_ARCH_ICL
#define QT_FUNCTION_TARGET_STRING_ARCH_ICELAKE_SERVER QT_FUNCTION_TARGET_STRING_ARCH_ICX
+#define QT_FUNCTION_TARGET_STRING_ARCH_WILLOWCOVE QT_FUNCTION_TARGET_STRING_ARCH_WLC
+#define QT_FUNCTION_TARGET_STRING_ARCH_TIGERLAKE QT_FUNCTION_TARGET_STRING_ARCH_TGL
+#define QT_FUNCTION_TARGET_STRING_ARCH_GOLDENCOVE QT_FUNCTION_TARGET_STRING_ARCH_GLC
#define QT_FUNCTION_TARGET_STRING_ARCH_ALDERLAKE QT_FUNCTION_TARGET_STRING_ARCH_ADL
+#define QT_FUNCTION_TARGET_STRING_ARCH_RAPTORCOVE QT_FUNCTION_TARGET_STRING_ARCH_RPC
+#define QT_FUNCTION_TARGET_STRING_ARCH_RAPTORLAKE QT_FUNCTION_TARGET_STRING_ARCH_RPL
+#define QT_FUNCTION_TARGET_STRING_ARCH_REDWOODCOVE QT_FUNCTION_TARGET_STRING_ARCH_RWC
+#define QT_FUNCTION_TARGET_STRING_ARCH_METEORLAKE QT_FUNCTION_TARGET_STRING_ARCH_MTL
+#define QT_FUNCTION_TARGET_STRING_ARCH_ARROWLAKE QT_FUNCTION_TARGET_STRING_ARCH_ARL
+#define QT_FUNCTION_TARGET_STRING_ARCH_LUNARLAKE QT_FUNCTION_TARGET_STRING_ARCH_LNL
#define QT_FUNCTION_TARGET_STRING_ARCH_SAPPHIRERAPIDS QT_FUNCTION_TARGET_STRING_ARCH_SPR
-#define QT_FUNCTION_TARGET_STRING_ARCH_TIGERLAKE QT_FUNCTION_TARGET_STRING_ARCH_TGL
+#define QT_FUNCTION_TARGET_STRING_ARCH_EMERALDRAPIDS QT_FUNCTION_TARGET_STRING_ARCH_EMR
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRANITERAPIDS QT_FUNCTION_TARGET_STRING_ARCH_GNR
#define QT_FUNCTION_TARGET_STRING_ARCH_SILVERMONT QT_FUNCTION_TARGET_STRING_ARCH_SLM
#define QT_FUNCTION_TARGET_STRING_ARCH_GOLDMONT QT_FUNCTION_TARGET_STRING_ARCH_GLM
#define QT_FUNCTION_TARGET_STRING_ARCH_TREMONT QT_FUNCTION_TARGET_STRING_ARCH_TNT
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRACEMONT QT_FUNCTION_TARGET_STRING_ARCH_GRT
+#define QT_FUNCTION_TARGET_STRING_ARCH_CRESTMONT QT_FUNCTION_TARGET_STRING_ARCH_CMT
+#define QT_FUNCTION_TARGET_STRING_ARCH_GRANDRIDGE QT_FUNCTION_TARGET_STRING_ARCH_GRR
+#define QT_FUNCTION_TARGET_STRING_ARCH_SIERRAFOREST QT_FUNCTION_TARGET_STRING_ARCH_SRF
+#define QT_FUNCTION_TARGET_STRING_ARCH_CLEARWATERFOREST QT_FUNCTION_TARGET_STRING_ARCH_CWF
static const uint64_t _compilerCpuFeatures = 0
#ifdef __SSE2__
@@ -295,6 +381,9 @@ static const uint64_t _compilerCpuFeatures = 0
#ifdef __AVX512VBMI__
| cpu_feature_avx512vbmi
#endif
+#ifdef __WAITPKG__
+ | cpu_feature_waitpkg
+#endif
#ifdef __AVX512VBMI2__
| cpu_feature_avx512vbmi2
#endif
@@ -307,9 +396,6 @@ static const uint64_t _compilerCpuFeatures = 0
#ifdef __VAES__
| cpu_feature_vaes
#endif
-#ifdef __AVX512VNNI__
- | cpu_feature_avx512vnni
-#endif
#ifdef __AVX512BITALG__
| cpu_feature_avx512bitalg
#endif
@@ -325,6 +411,18 @@ static const uint64_t _compilerCpuFeatures = 0
#ifdef __AVX512FP16__
| cpu_feature_avx512fp16
#endif
+#ifdef __RAOINT__
+ | cpu_feature_raoint
+#endif
+#ifdef __CMPCCXADD__
+ | cpu_feature_cmpccxadd
+#endif
+#ifdef __AVXIFMA__
+ | cpu_feature_avxifma
+#endif
+#ifdef __LAM__
+ | cpu_feature_lam
+#endif
;
#if (defined __cplusplus) && __cplusplus >= 201103L
@@ -353,16 +451,20 @@ enum X86CpuFeatures : uint64_t {
CpuFeatureAVX512BW = cpu_feature_avx512bw, ///< AVX512 Byte & Word
CpuFeatureAVX512VL = cpu_feature_avx512vl, ///< AVX512 Vector Length
CpuFeatureAVX512VBMI = cpu_feature_avx512vbmi, ///< AVX512 Vector Byte Manipulation Instructions
+ CpuFeatureWAITPKG = cpu_feature_waitpkg, ///< User-Level Monitor / Wait
CpuFeatureAVX512VBMI2 = cpu_feature_avx512vbmi2, ///< AVX512 Vector Byte Manipulation Instructions 2
CpuFeatureSHSTK = cpu_feature_shstk, ///< Control Flow Enforcement Technology Shadow Stack
CpuFeatureGFNI = cpu_feature_gfni, ///< Galois Field new instructions
CpuFeatureVAES = cpu_feature_vaes, ///< 256- and 512-bit AES
- CpuFeatureAVX512VNNI = cpu_feature_avx512vnni, ///< AVX512 Vector Neural Network Instructions
CpuFeatureAVX512BITALG = cpu_feature_avx512bitalg, ///< AVX512 Bit Algorithms
CpuFeatureAVX512VPOPCNTDQ = cpu_feature_avx512vpopcntdq, ///< AVX512 Population Count
CpuFeatureHYBRID = cpu_feature_hybrid, ///< Hybrid processor
CpuFeatureIBT = cpu_feature_ibt, ///< Control Flow Enforcement Technology Indirect Branch Tracking
CpuFeatureAVX512FP16 = cpu_feature_avx512fp16, ///< AVX512 16-bit Floating Point
+ CpuFeatureRAOINT = cpu_feature_raoint, ///< Remote Atomic Operations, Integer
+ CpuFeatureCMPCCXADD = cpu_feature_cmpccxadd, ///< CMPccXADD instructions
+ CpuFeatureAVXIFMA = cpu_feature_avxifma, ///< AVX-IFMA instructions
+ CpuFeatureLAM = cpu_feature_lam, ///< Linear Address Masking
}; // enum X86CpuFeatures
enum X86CpuArchitectures : uint64_t {
@@ -372,22 +474,39 @@ enum X86CpuArchitectures : uint64_t {
CpuArchWSM = cpu_wsm,
CpuArchSNB = cpu_snb,
CpuArchIVB = cpu_ivb,
- CpuArchHSW = cpu_hsw,
+ CpuArchHSW = cpu_hsw, ///< hle,rtm
CpuArchBDW = cpu_bdw,
CpuArchBDX = cpu_bdx,
CpuArchSKL = cpu_skl,
- CpuArchADL = cpu_adl,
- CpuArchSKX = cpu_skx,
+ CpuArchSKX = cpu_skx, ///< clwb
CpuArchCLX = cpu_clx,
CpuArchCPX = cpu_cpx,
+ CpuArchPLC = cpu_plc, ///< sha
+ CpuArchSNC = cpu_snc, ///< fsrm,rdpid
+ CpuArchWLC = cpu_wlc, ///< avx512vp2intersect
+ CpuArchGLC = cpu_glc, ///< tsxldtrk
+ CpuArchRPC = cpu_rpc,
+ CpuArchRWC = cpu_rwc,
+ CpuArchSLM = cpu_slm,
+ CpuArchGLM = cpu_glm,
+ CpuArchTNT = cpu_tnt,
+ CpuArchGRT = cpu_grt, ///< rdpid
+ CpuArchCMT = cpu_cmt,
CpuArchCNL = cpu_cnl,
CpuArchICL = cpu_icl,
- CpuArchICX = cpu_icx,
CpuArchTGL = cpu_tgl,
+ CpuArchADL = cpu_adl,
+ CpuArchRPL = cpu_rpl,
+ CpuArchMTL = cpu_mtl,
+ CpuArchARL = cpu_arl,
+ CpuArchLNL = cpu_lnl,
+ CpuArchICX = cpu_icx,
CpuArchSPR = cpu_spr,
- CpuArchSLM = cpu_slm,
- CpuArchGLM = cpu_glm,
- CpuArchTNT = cpu_tnt,
+ CpuArchEMR = cpu_emr,
+ CpuArchGNR = cpu_gnr,
+ CpuArchSRF = cpu_srf,
+ CpuArchGRR = cpu_grr,
+ CpuArchCWF = cpu_cwf,
CpuArchNehalem = cpu_nehalem, ///< Intel Core i3/i5/i7
CpuArchWestmere = cpu_westmere, ///< Intel Core i3/i5/i7
CpuArchSandyBridge = cpu_sandybridge, ///< Second Generation Intel Core i3/i5/i7
@@ -398,15 +517,32 @@ enum X86CpuArchitectures : uint64_t {
CpuArchSkylakeAvx512 = cpu_skylake_avx512, ///< Intel Xeon Scalable
CpuArchCascadeLake = cpu_cascadelake, ///< Second Generation Intel Xeon Scalable
CpuArchCooperLake = cpu_cooperlake, ///< Third Generation Intel Xeon Scalable
+ CpuArchPalmCove = cpu_palmcove,
CpuArchCannonLake = cpu_cannonlake, ///< Intel Core i3-8121U
+ CpuArchSunnyCove = cpu_sunnycove,
CpuArchIceLakeClient = cpu_icelake_client, ///< Tenth Generation Intel Core i3/i5/i7
CpuArchIceLakeServer = cpu_icelake_server, ///< Third Generation Intel Xeon Scalable
- CpuArchAlderLake = cpu_alderlake,
- CpuArchSapphireRapids = cpu_sapphirerapids,
+ CpuArchWillowCove = cpu_willowcove,
CpuArchTigerLake = cpu_tigerlake, ///< Eleventh Generation Intel Core i3/i5/i7
+ CpuArchGoldenCove = cpu_goldencove,
+ CpuArchAlderLake = cpu_alderlake, ///< Twelfth Generation Intel Core
+ CpuArchRaptorCove = cpu_raptorcove,
+ CpuArchRaptorLake = cpu_raptorlake, ///< Thirteenth Generation Intel Core
+ CpuArchRedwoodCove = cpu_redwoodcove,
+ CpuArchMeteorLake = cpu_meteorlake,
+ CpuArchArrowLake = cpu_arrowlake,
+ CpuArchLunarLake = cpu_lunarlake,
+ CpuArchSapphireRapids = cpu_sapphirerapids, ///< Fourth Generation Intel Xeon Scalable
+ CpuArchEmeraldRapids = cpu_emeraldrapids, ///< Fifth Generation Intel Xeon Scalable
+ CpuArchGraniteRapids = cpu_graniterapids,
CpuArchSilvermont = cpu_silvermont,
CpuArchGoldmont = cpu_goldmont,
CpuArchTremont = cpu_tremont,
+ CpuArchGracemont = cpu_gracemont,
+ CpuArchCrestmont = cpu_crestmont,
+ CpuArchGrandRidge = cpu_grandridge,
+ CpuArchSierraForest = cpu_sierraforest,
+ CpuArchClearwaterForest = cpu_clearwaterforest,
}; // enum X86cpuArchitectures
#endif /* C++11 */
diff --git a/src/corelib/global/qswap.h b/src/corelib/global/qswap.h
index 9ff6c7d9c5..3d533c8a95 100644
--- a/src/corelib/global/qswap.h
+++ b/src/corelib/global/qswap.h
@@ -1,11 +1,13 @@
// 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
-#ifndef QSWAP_H
-#define QSWAP_H
+#ifndef QTCORE_QSWAP_H
+#define QTCORE_QSWAP_H
#include <QtCore/qtconfigmacros.h>
-#include <QtCore/qcompilerdetection.h>
+
+#include <type_traits>
+#include <utility>
#if 0
#pragma qt_class(QtSwap)
@@ -14,25 +16,9 @@
QT_BEGIN_NAMESPACE
-QT_WARNING_PUSH
-// warning: noexcept-expression evaluates to 'false' because of a call to 'void swap(..., ...)'
-QT_WARNING_DISABLE_GCC("-Wnoexcept")
-
-namespace QtPrivate
-{
-namespace SwapExceptionTester { // insulate users from the "using std::swap" below
- using std::swap; // import std::swap
- template <typename T>
- void checkSwap(T &t)
- noexcept(noexcept(swap(t, t)));
- // declared, but not implemented (only to be used in unevaluated contexts (noexcept operator))
-}
-} // namespace QtPrivate
-
-// Documented in ../tools/qalgorithm.qdoc
template <typename T>
constexpr void qSwap(T &value1, T &value2)
- noexcept(noexcept(QtPrivate::SwapExceptionTester::checkSwap(value1)))
+ noexcept(std::is_nothrow_swappable_v<T>)
{
using std::swap;
swap(value1, value2);
@@ -47,8 +33,6 @@ constexpr inline void qt_ptr_swap(T* &lhs, T* &rhs) noexcept
rhs = tmp;
}
-QT_WARNING_POP
-
QT_END_NAMESPACE
-#endif // QSWAP_H
+#endif // QTCORE_QSWAP_H
diff --git a/src/corelib/global/qswap.qdoc b/src/corelib/global/qswap.qdoc
index 2d9d56b694..bffad903f9 100644
--- a/src/corelib/global/qswap.qdoc
+++ b/src/corelib/global/qswap.qdoc
@@ -1,14 +1,38 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
-/*! \fn template <typename T> void qSwap(T &var1, T &var2)
+/*!
+ \fn template <typename T> void qSwap(T &lhs, T &rhs)
\relates <QtSwap>
- \deprecated
- Use \c std::swap instead.
+ Exchanges the values of variables \a lhs and \a rhs,
+ taking type-specific \c{swap()} overloads into account.
- Exchanges the values of variables \a var1 and \a var2.
+ This function is Qt's version of
+ \l{https://www.boost.org/doc/libs/release/libs/core/doc/html/core/swap.html}{\c{boost::swap()}},
+ and is equivalent to
+ \code
+ using std::swap; // bring std::swap into scope (for built-in types)
+ swap(lhs, rhs); // unqualified call (picks up type-specific overloads
+ // via Argument-Dependent Lookup, or falls back to std::swap)
+ \endcode
- Example:
- \snippet code/doc_src_qalgorithms.cpp 0
+ Use this function primarily in generic code, where you would traditionally
+ have written the above two lines, because you don't know anything about \c{T}.
+
+ If you already know what \c{T} is, then use one of the following options, in
+ order of preference:
+
+ \list
+ \li \c{lhs.swap(rhs);} if such a member-swap exists
+ \li \c{std::swap(lhs, rhs);} if no type-specific \c{swap()} exists
+ \endlist
+
+ See
+ \l{https://www.boost.org/doc/libs/release/libs/core/doc/html/core/swap.html}{\c{boost::swap()} on boost.org}
+ for more details.
+
+ See also
+ \l{https://en.cppreference.com/w/cpp/algorithm/swap}{\c{std::swap} on cppreference.com},
+ \l{https://en.cppreference.com/w/cpp/named_req/Swappable}{\c{Swappable} on cppreference.com}.
*/
diff --git a/src/corelib/global/qsysinfo.cpp b/src/corelib/global/qsysinfo.cpp
index 8ddcbb0409..79cb76b236 100644
--- a/src/corelib/global/qsysinfo.cpp
+++ b/src/corelib/global/qsysinfo.cpp
@@ -91,6 +91,8 @@ using namespace Qt::StringLiterals;
static const char *osVer_helper(QOperatingSystemVersion version = QOperatingSystemVersion::current())
{
#ifdef Q_OS_MACOS
+ if (version.majorVersion() == 13)
+ return "Ventura";
if (version.majorVersion() == 12)
return "Monterey";
// Compare against predefined constant to handle 10.16/11.0
@@ -222,7 +224,7 @@ struct QUnixOSVersion
QString prettyName; // $PRETTY_NAME $DISTRIB_DESCRIPTION
};
-static QString unquote(const char *begin, const char *end)
+static QString unquote(QByteArrayView str)
{
// man os-release says:
// Variable assignment values must be enclosed in double
@@ -233,10 +235,11 @@ static QString unquote(const char *begin, const char *end)
// All strings should be in UTF-8 format, and non-printable
// characters should not be used. It is not supported to
// concatenate multiple individually quoted strings.
- if (*begin == '"')
- return QString::fromUtf8(begin + 1, end - begin - 2);
- return QString::fromUtf8(begin, end - begin);
+ if (str.size() >= 2 && str.front() == '"' && str.back() == '"')
+ str = str.sliced(1).chopped(1);
+ return QString::fromUtf8(str);
}
+
static QByteArray getEtcFileContent(const char *filename)
{
// we're avoiding QFile here
@@ -277,19 +280,19 @@ static bool readEtcFile(QUnixOSVersion &v, const char *filename,
if (line.startsWith(idKey)) {
ptr += idKey.size();
- v.productType = unquote(ptr, eol);
+ v.productType = unquote({ptr, eol});
continue;
}
if (line.startsWith(prettyNameKey)) {
ptr += prettyNameKey.size();
- v.prettyName = unquote(ptr, eol);
+ v.prettyName = unquote({ptr, eol});
continue;
}
if (line.startsWith(versionKey)) {
ptr += versionKey.size();
- v.productVersion = unquote(ptr, eol);
+ v.productVersion = unquote({ptr, eol});
continue;
}
}
@@ -350,8 +353,7 @@ static QByteArray getEtcFileFirstLine(const char *fileName)
return QByteArray();
const char *ptr = buffer.constData();
- int eol = buffer.indexOf("\n");
- return QByteArray(ptr, eol).trimmed();
+ return QByteArray(ptr, buffer.indexOf("\n")).trimmed();
}
static bool readEtcRedHatRelease(QUnixOSVersion &v)
@@ -366,9 +368,9 @@ static bool readEtcRedHatRelease(QUnixOSVersion &v)
v.prettyName = QString::fromLatin1(line);
const char keyword[] = "release ";
- int releaseIndex = line.indexOf(keyword);
+ const qsizetype releaseIndex = line.indexOf(keyword);
v.productType = QString::fromLatin1(line.mid(0, releaseIndex)).remove(u' ');
- int spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword));
+ const qsizetype spaceIndex = line.indexOf(' ', releaseIndex + strlen(keyword));
v.productVersion = QString::fromLatin1(line.mid(releaseIndex + strlen(keyword),
spaceIndex > -1 ? spaceIndex - releaseIndex - int(strlen(keyword)) : -1));
return true;
@@ -782,10 +784,14 @@ QString QSysInfo::productType()
return QStringLiteral("tvos");
#elif defined(Q_OS_WATCHOS)
return QStringLiteral("watchos");
+#elif defined(Q_OS_VISIONOS)
+ return QStringLiteral("visionos");
#elif defined(Q_OS_MACOS)
return QStringLiteral("macos");
#elif defined(Q_OS_DARWIN)
return QStringLiteral("darwin");
+#elif defined(Q_OS_WASM)
+ return QStringLiteral("wasm");
#elif defined(USE_ETC_OS_RELEASE) // Q_OS_UNIX
QUnixOSVersion unixOsVersion;
@@ -934,13 +940,26 @@ QString QSysInfo::machineHostName()
# ifdef Q_OS_WIN
// Important: QtNetwork depends on machineHostName() initializing ws2_32.dll
winsockInit();
-# endif
+ QString hostName;
+ hostName.resize(512);
+ unsigned long len = hostName.size();
+ BOOL res = GetComputerNameEx(ComputerNameDnsHostname,
+ reinterpret_cast<wchar_t *>(const_cast<quint16 *>(hostName.utf16())), &len);
+ if (!res && len > 512) {
+ hostName.resize(len - 1);
+ GetComputerNameEx(ComputerNameDnsHostname,
+ reinterpret_cast<wchar_t *>(const_cast<quint16 *>(hostName.utf16())), &len);
+ }
+ hostName.truncate(len);
+ return hostName;
+# else // !Q_OS_WIN
char hostName[512];
if (gethostname(hostName, sizeof(hostName)) == -1)
return QString();
hostName[sizeof(hostName) - 1] = '\0';
return QString::fromLocal8Bit(hostName);
+# endif
#endif
}
#endif // QT_BOOTSTRAPPED
@@ -975,8 +994,7 @@ QByteArray QSysInfo::machineUniqueId()
{
#if defined(Q_OS_DARWIN) && __has_include(<IOKit/IOKitLib.h>)
char uuid[UuidStringLen + 1];
- static const mach_port_t defaultPort = 0; // Effectively kIOMasterPortDefault/kIOMainPortDefault
- io_service_t service = IOServiceGetMatchingService(defaultPort, IOServiceMatching("IOPlatformExpertDevice"));
+ io_service_t service = IOServiceGetMatchingService(kIOMainPortDefault, IOServiceMatching("IOPlatformExpertDevice"));
QCFString stringRef = (CFStringRef)IORegistryEntryCreateCFProperty(service, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
CFStringGetCString(stringRef, uuid, sizeof(uuid), kCFStringEncodingMacRoman);
return QByteArray(uuid);
diff --git a/src/corelib/global/qsysinfo.h b/src/corelib/global/qsysinfo.h
index b1d7f000be..01f6313299 100644
--- a/src/corelib/global/qsysinfo.h
+++ b/src/corelib/global/qsysinfo.h
@@ -2,11 +2,13 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
-
#ifndef QSYSINFO_H
#define QSYSINFO_H
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qprocessordetection.h>
+#include <QtCore/qtcoreexports.h>
+
QT_BEGIN_NAMESPACE
/*
@@ -14,6 +16,8 @@ QT_BEGIN_NAMESPACE
*/
class QString;
+class QByteArray;
+
class Q_CORE_EXPORT QSysInfo
{
public:
diff --git a/src/corelib/global/qsystemdetection.h b/src/corelib/global/qsystemdetection.h
index 3a992f2aba..b29f2e9496 100644
--- a/src/corelib/global/qsystemdetection.h
+++ b/src/corelib/global/qsystemdetection.h
@@ -2,10 +2,6 @@
// Copyright (C) 2019 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef QGLOBAL_H
-# include <QtCore/qglobal.h>
-#endif
-
#if 0
#pragma qt_class(QtSystemDetection)
#pragma qt_sync_skip_header_check
@@ -23,6 +19,7 @@
IOS - iOS
WATCHOS - watchOS
TVOS - tvOS
+ VISIONOS - visionOS
WIN32 - Win32 (Windows 2000/XP/Vista/7 and Windows Server 2003/2008)
CYGWIN - Cygwin
SOLARIS - Sun Solaris
@@ -42,6 +39,7 @@
ANDROID - Android platform
HAIKU - Haiku
WEBOS - LG WebOS
+ WASM - WebAssembly
The following operating systems have variants:
LINUX - both Q_OS_LINUX and Q_OS_ANDROID are defined when building for Android
@@ -54,20 +52,18 @@
#if defined(__APPLE__) && (defined(__GNUC__) || defined(__xlC__) || defined(__xlc__))
# include <TargetConditionals.h>
+# define Q_OS_APPLE
# if defined(TARGET_OS_MAC) && TARGET_OS_MAC
# define Q_OS_DARWIN
# define Q_OS_BSD4
-# ifdef __LP64__
-# define Q_OS_DARWIN64
-# else
-# define Q_OS_DARWIN32
-# endif
# if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
# define QT_PLATFORM_UIKIT
# if defined(TARGET_OS_WATCH) && TARGET_OS_WATCH
# define Q_OS_WATCHOS
# elif defined(TARGET_OS_TV) && TARGET_OS_TV
# define Q_OS_TVOS
+# elif defined(TARGET_OS_VISION) && TARGET_OS_VISION
+# define Q_OS_VISIONOS
# else
# // TARGET_OS_IOS is only available in newer SDKs,
# // so assume any other iOS-based platform is iOS for now
@@ -98,8 +94,6 @@
# define Q_OS_SOLARIS
#elif defined(hpux) || defined(__hpux)
# define Q_OS_HPUX
-#elif defined(__native_client__)
-# define Q_OS_NACL
#elif defined(__EMSCRIPTEN__)
# define Q_OS_WASM
#elif defined(__linux__) || defined(__linux)
@@ -131,7 +125,7 @@
# define Q_OS_INTEGRITY
#elif defined(__rtems__)
# define Q_OS_RTEMS
-#elif defined(VXWORKS) /* there is no "real" VxWorks define - this has to be set in the mkspec! */
+#elif defined(__vxworks)
# define Q_OS_VXWORKS
#elif defined(__HAIKU__)
# define Q_OS_HAIKU
@@ -157,92 +151,32 @@
// Compatibility synonyms
#ifdef Q_OS_DARWIN
-#define Q_OS_MAC
-#endif
-#ifdef Q_OS_DARWIN32
-#define Q_OS_MAC32
-#endif
-#ifdef Q_OS_DARWIN64
-#define Q_OS_MAC64
-#endif
-#ifdef Q_OS_MACOS
-#define Q_OS_MACX
-#define Q_OS_OSX
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wunknown-pragmas"
+# define Q_OS_MAC // FIXME: Deprecate
+# ifdef __LP64__
+# define Q_OS_DARWIN64
+# pragma clang deprecated(Q_OS_DARWIN64, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead")
+# define Q_OS_MAC64
+# pragma clang deprecated(Q_OS_MAC64, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead")
+# else
+# define Q_OS_DARWIN32
+# pragma clang deprecated(Q_OS_DARWIN32, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead")
+# define Q_OS_MAC32
+# pragma clang deprecated(Q_OS_MAC32, "use Q_OS_DARWIN and QT_POINTER_SIZE/Q_PROCESSOR_* instead")
+# endif
+# ifdef Q_OS_MACOS
+# define Q_OS_MACX
+# pragma clang deprecated(Q_OS_MACX, "use Q_OS_MACOS instead")
+# define Q_OS_OSX
+# pragma clang deprecated(Q_OS_OSX, "use Q_OS_MACOS instead")
+# endif
+# pragma clang diagnostic pop
#endif
#ifdef Q_OS_DARWIN
# include <Availability.h>
# include <AvailabilityMacros.h>
-#
-# ifdef Q_OS_MACOS
-# if !defined(__MAC_OS_X_VERSION_MIN_REQUIRED) || __MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_10_6
-# undef __MAC_OS_X_VERSION_MIN_REQUIRED
-# define __MAC_OS_X_VERSION_MIN_REQUIRED __MAC_10_6
-# endif
-# if !defined(MAC_OS_X_VERSION_MIN_REQUIRED) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
-# undef MAC_OS_X_VERSION_MIN_REQUIRED
-# define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_6
-# endif
-# endif
-#
-# // Numerical checks are preferred to named checks, but to be safe
-# // we define the missing version names in case Qt uses them.
-#
-# if !defined(__MAC_10_11)
-# define __MAC_10_11 101100
-# endif
-# if !defined(__MAC_10_12)
-# define __MAC_10_12 101200
-# endif
-# if !defined(__MAC_10_13)
-# define __MAC_10_13 101300
-# endif
-# if !defined(__MAC_10_14)
-# define __MAC_10_14 101400
-# endif
-# if !defined(__MAC_10_15)
-# define __MAC_10_15 101500
-# endif
-# if !defined(__MAC_10_16)
-# define __MAC_10_16 101600
-# endif
-# if !defined(MAC_OS_X_VERSION_10_11)
-# define MAC_OS_X_VERSION_10_11 __MAC_10_11
-# endif
-# if !defined(MAC_OS_X_VERSION_10_12)
-# define MAC_OS_X_VERSION_10_12 __MAC_10_12
-# endif
-# if !defined(MAC_OS_X_VERSION_10_13)
-# define MAC_OS_X_VERSION_10_13 __MAC_10_13
-# endif
-# if !defined(MAC_OS_X_VERSION_10_14)
-# define MAC_OS_X_VERSION_10_14 __MAC_10_14
-# endif
-# if !defined(MAC_OS_X_VERSION_10_15)
-# define MAC_OS_X_VERSION_10_15 __MAC_10_15
-# endif
-# if !defined(MAC_OS_X_VERSION_10_16)
-# define MAC_OS_X_VERSION_10_16 __MAC_10_16
-# endif
-#
-# if !defined(__IPHONE_10_0)
-# define __IPHONE_10_0 100000
-# endif
-# if !defined(__IPHONE_10_1)
-# define __IPHONE_10_1 100100
-# endif
-# if !defined(__IPHONE_10_2)
-# define __IPHONE_10_2 100200
-# endif
-# if !defined(__IPHONE_10_3)
-# define __IPHONE_10_3 100300
-# endif
-# if !defined(__IPHONE_11_0)
-# define __IPHONE_11_0 110000
-# endif
-# if !defined(__IPHONE_12_0)
-# define __IPHONE_12_0 120000
-# endif
# define QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, tvos, watchos) \
((defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && macos != __MAC_NA && __MAC_OS_X_VERSION_MAX_ALLOWED >= macos) || \
@@ -278,13 +212,7 @@
# define QT_WATCHOS_DEPLOYMENT_TARGET_BELOW(watchos) \
QT_DARWIN_DEPLOYMENT_TARGET_BELOW(__MAC_NA, __IPHONE_NA, __TVOS_NA, watchos)
-// Compatibility synonyms, do not use
-# define QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(osx, ios) QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(osx, ios)
-# define QT_MAC_DEPLOYMENT_TARGET_BELOW(osx, ios) QT_MACOS_IOS_DEPLOYMENT_TARGET_BELOW(osx, ios)
-# define QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(osx) QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(osx)
-# define QT_OSX_DEPLOYMENT_TARGET_BELOW(osx) QT_MACOS_DEPLOYMENT_TARGET_BELOW(osx)
-
-#else
+#else // !Q_OS_DARWIN
#define QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios, tvos, watchos) (0)
#define QT_MACOS_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(macos, ios) (0)
@@ -293,9 +221,6 @@
#define QT_TVOS_PLATFORM_SDK_EQUAL_OR_ABOVE(tvos) (0)
#define QT_WATCHOS_PLATFORM_SDK_EQUAL_OR_ABOVE(watchos) (0)
-#define QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(osx, ios) (0)
-#define QT_OSX_PLATFORM_SDK_EQUAL_OR_ABOVE(osx) (0)
-
#endif // Q_OS_DARWIN
#ifdef __LSB_VERSION__
diff --git a/src/corelib/global/qsystemdetection.qdoc b/src/corelib/global/qsystemdetection.qdoc
index 210f865ffe..a48a79bbb2 100644
--- a/src/corelib/global/qsystemdetection.qdoc
+++ b/src/corelib/global/qsystemdetection.qdoc
@@ -23,6 +23,16 @@
\relates <QtSystemDetection>
Defined on Darwin-based operating systems such as \macos, iOS, watchOS, and tvOS.
+
+ \note Unless you are dealing with code specific to the Darwin kernel,
+ prefer Q_OS_APPLE to refer to the family of Apple operating systems.
+*/
+
+/*!
+ \macro Q_OS_APPLE
+ \relates <QtSystemDetection>
+
+ Defined on Apple operating systems such as \macos, iOS, watchOS, and tvOS.
*/
/*!
@@ -68,6 +78,13 @@
*/
/*!
+ \macro Q_OS_VISIONOS
+ \relates <QtSystemDetection>
+
+ Defined on visionOS.
+*/
+
+/*!
\macro Q_OS_WIN
\relates <QtSystemDetection>
diff --git a/src/corelib/global/qt_pch.h b/src/corelib/global/qt_pch.h
index 207a30a5ee..3f224cda85 100644
--- a/src/corelib/global/qt_pch.h
+++ b/src/corelib/global/qt_pch.h
@@ -14,36 +14,31 @@
// for rand_s, _CRT_RAND_S must be #defined before #including stdlib.h.
// put it at the beginning so some indirect inclusion doesn't break it
#ifndef _CRT_RAND_S
-#define _CRT_RAND_S
+# define _CRT_RAND_S
#endif
#include <stdlib.h>
#include <qglobal.h>
#ifdef Q_OS_WIN
-# ifdef Q_CC_MINGW
+# ifdef Q_CC_MINGW
// <unistd.h> must be included before any other header pulls in <time.h>.
-# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
-# endif
-# define _POSIX_
-# include <limits.h>
-# undef _POSIX_
-# if defined(Q_CC_CLANG) && defined(Q_CC_MSVC)
-// See https://bugs.llvm.org/show_bug.cgi?id=41226
-# include <wchar.h>
-__declspec(selectany) auto *__wmemchr_symbol_loader_value = wmemchr(L"", L'0', 0);
-# endif
-# endif
-# include <qcoreapplication.h>
-# include <qcoreevent.h>
-# include <qiodevice.h>
-# include <qlist.h>
-# include <qvariant.h> /* All moc generated code has this include */
-# include <qobject.h>
-# if QT_CONFIG(regularexpression)
-# include <qregularexpression.h>
-# endif
-# include <qscopedpointer.h>
-# include <qshareddata.h>
-# include <qstring.h>
-# include <qstringlist.h>
-# include <qtimer.h>
+# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
+# endif // Q_CC_MINGW
+# define _POSIX_
+# include <limits.h>
+# undef _POSIX_
+#endif // Q_OS_WIN
+#include <qcoreapplication.h>
+#include <qcoreevent.h>
+#include <qiodevice.h>
+#include <qlist.h>
+#include <qvariant.h> /* All moc generated code has this include */
+#include <qobject.h>
+#if QT_CONFIG(regularexpression)
+# include <qregularexpression.h>
+#endif
+#include <qscopedpointer.h>
+#include <qshareddata.h>
+#include <qstring.h>
+#include <qstringlist.h>
+#include <qtimer.h>
#endif
diff --git a/src/corelib/global/qt_windows.h b/src/corelib/global/qt_windows.h
index 17ed094c1d..5586d0b927 100644
--- a/src/corelib/global/qt_windows.h
+++ b/src/corelib/global/qt_windows.h
@@ -19,7 +19,7 @@
# define _WIN32_IE 0x0A00
#endif
#ifndef NTDDI_VERSION
-# define NTDDI_VERSION 0x0A00000B // NTDDI_WIN10_CO
+# define NTDDI_VERSION 0x0A00000C // NTDDI_WIN10_NI
#endif
#ifndef NOMINMAX
diff --git a/src/corelib/global/qtclasshelpermacros.h b/src/corelib/global/qtclasshelpermacros.h
index e6b66ed5f2..8839e80fb9 100644
--- a/src/corelib/global/qtclasshelpermacros.h
+++ b/src/corelib/global/qtclasshelpermacros.h
@@ -78,6 +78,13 @@ template <typename T> inline T *qGetPtrHelper(T *ptr) noexcept { return ptr; }
template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype(ptr.get())
{ static_assert(noexcept(ptr.get()), "Smart d pointers for Q_DECLARE_PRIVATE must have noexcept get()"); return ptr.get(); }
+class QObject;
+class QObjectPrivate;
+namespace QtPrivate {
+ template <typename ObjPrivate> void assertObjectType(QObjectPrivate *d);
+ inline const QObject *getQObject(const QObjectPrivate *d);
+}
+
#define Q_DECLARE_PRIVATE(Class) \
inline Class##Private* d_func() noexcept \
{ Q_CAST_IGNORE_ALIGN(return reinterpret_cast<Class##Private *>(qGetPtrHelper(d_ptr));) } \
@@ -95,7 +102,9 @@ template <typename Ptr> inline auto qGetPtrHelper(Ptr &ptr) noexcept -> decltype
#define Q_DECLARE_PUBLIC(Class) \
inline Class* q_func() noexcept { return static_cast<Class *>(q_ptr); } \
inline const Class* q_func() const noexcept { return static_cast<const Class *>(q_ptr); } \
- friend class Class;
+ friend class Class; \
+ friend const QObject *QtPrivate::getQObject(const QObjectPrivate *d); \
+ template <typename ObjPrivate> friend void QtPrivate::assertObjectType(QObjectPrivate *d);
#define Q_D(Class) Class##Private * const d = d_func()
#define Q_Q(Class) Class * const q = q_func()
diff --git a/src/corelib/global/qtconfiginclude.h b/src/corelib/global/qtconfiginclude.h
new file mode 100644
index 0000000000..8b22a47ac7
--- /dev/null
+++ b/src/corelib/global/qtconfiginclude.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2022 Intel Corporation
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTCONFIGINCLUDE_H
+#define QTCONFIGINCLUDE_H
+
+#if 0
+# pragma qt_sync_stop_processing
+#endif
+
+#include <QtCore/qconfig.h>
+
+#ifdef QT_BOOTSTRAPPED
+// qconfig-bootstrapped.h is not supposed to be a part of the synced header files. So we find it by
+// the include path specified for Bootstrap library in the source tree instead of the build tree as
+// it's done for regular header files.
+#include "qconfig-bootstrapped.h"
+#else
+#include <QtCore/qtcore-config.h>
+#endif
+
+#endif // QTCONFIGINCLUDE_H
diff --git a/src/corelib/global/qtconfigmacros.h b/src/corelib/global/qtconfigmacros.h
index 7d42b13c54..018161eac4 100644
--- a/src/corelib/global/qtconfigmacros.h
+++ b/src/corelib/global/qtconfigmacros.h
@@ -7,15 +7,10 @@
#if 0
# pragma qt_sync_stop_processing
#endif
-#ifdef QT_BOOTSTRAPPED
-// qconfig-bootstrapped.h is not supposed to be a part of the synced header files. So we find it by
-// the include path specified for Bootstrap library in the source tree instead of the build tree as
-// it's done for regular header files.
-#include "qconfig-bootstrapped.h"
-#else
-#include <QtCore/qconfig.h>
-#include <QtCore/qtcore-config.h>
-#endif
+
+#include <QtCore/qtconfiginclude.h>
+
+#include <assert.h>
/*
The Qt modules' export macros.
@@ -48,6 +43,9 @@
No, this is not an evil backdoor. QT_BUILD_INTERNAL just exports more symbols
for Qt's internal unit tests. If you want slower loading times and more
symbols that can vanish from version to version, feel free to define QT_BUILD_INTERNAL.
+
+ \note After adding Q_AUTOTEST_EXPORT to a method, you'll need to wrap any unittests
+ that will use that method in "#ifdef QT_BUILD_INTERNAL".
*/
#if defined(QT_BUILD_INTERNAL) && defined(QT_BUILDING_QT) && defined(QT_SHARED)
# define Q_AUTOTEST_EXPORT Q_DECL_EXPORT
@@ -65,7 +63,7 @@
1: The feature is available
*/
#define QT_CONFIG(feature) (1/QT_FEATURE_##feature == 1)
-#define QT_REQUIRE_CONFIG(feature) Q_STATIC_ASSERT_X(QT_FEATURE_##feature == 1, "Required feature " #feature " for file " __FILE__ " not available.")
+#define QT_REQUIRE_CONFIG(feature) static_assert(QT_FEATURE_##feature == 1, "Required feature " #feature " for file " __FILE__ " not available.")
/* moc compats (signals/slots) */
#ifndef QT_MOC_COMPAT
@@ -107,6 +105,22 @@
# define QT_FORWARD_DECLARE_CLASS(name) class name;
# define QT_FORWARD_DECLARE_STRUCT(name) struct name;
+#elif defined(QT_INLINE_NAMESPACE) /* user inline namespace FIXME in Qt 7: Default */
+
+# define QT_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name
+# define QT_USE_NAMESPACE
+# define QT_BEGIN_NAMESPACE inline namespace QT_NAMESPACE {
+# define QT_END_NAMESPACE }
+# define QT_BEGIN_INCLUDE_NAMESPACE }
+# define QT_END_INCLUDE_NAMESPACE inline namespace QT_NAMESPACE {
+# define QT_FORWARD_DECLARE_CLASS(name) \
+QT_BEGIN_NAMESPACE class name; QT_END_NAMESPACE
+
+# define QT_FORWARD_DECLARE_STRUCT(name) \
+QT_BEGIN_NAMESPACE struct name; QT_END_NAMESPACE
+
+inline namespace QT_NAMESPACE {}
+
#else /* user namespace */
# define QT_PREPEND_NAMESPACE(name) ::QT_NAMESPACE::name
@@ -157,4 +171,38 @@ namespace QT_NAMESPACE {}
# define QT_END_MOC_NAMESPACE
#endif
+/*
+ Strict mode
+*/
+#ifdef QT_ENABLE_STRICT_MODE_UP_TO
+#ifndef QT_DISABLE_DEPRECATED_UP_TO
+# define QT_DISABLE_DEPRECATED_UP_TO QT_ENABLE_STRICT_MODE_UP_TO
+#endif
+
+#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 0, 0)
+# define QT_NO_FOREACH
+# define QT_NO_CAST_FROM_ASCII
+# define QT_NO_CAST_TO_ASCII
+# define QT_NO_CAST_FROM_BYTEARRAY
+# define QT_NO_URL_CAST_FROM_STRING
+# define QT_NO_NARROWING_CONVERSIONS_IN_CONNECT
+# define QT_NO_JAVA_STYLE_ITERATORS
+#endif // 6.0.0
+
+#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 6, 0)
+# define QT_NO_QEXCHANGE
+#endif // 6.6.0
+
+#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 7, 0)
+# define QT_NO_CONTEXTLESS_CONNECT
+#endif // 6.7.0
+
+#if QT_ENABLE_STRICT_MODE_UP_TO >= QT_VERSION_CHECK(6, 8, 0)
+# define QT_NO_QASCONST
+# if !defined(QT_USE_NODISCARD_FILE_OPEN) && !defined(QT_NO_USE_NODISCARD_FILE_OPEN)
+# define QT_USE_NODISCARD_FILE_OPEN
+# endif
+#endif // 6.8.0
+#endif // QT_ENABLE_STRICT_MODE_UP_TO
+
#endif /* QTCONFIGMACROS_H */
diff --git a/src/corelib/global/qtdeprecationmarkers.h b/src/corelib/global/qtdeprecationmarkers.h
index e87c860400..6df5ebce6d 100644
--- a/src/corelib/global/qtdeprecationmarkers.h
+++ b/src/corelib/global/qtdeprecationmarkers.h
@@ -40,6 +40,8 @@ QT_BEGIN_NAMESPACE
# define QT_DEPRECATED_CONSTRUCTOR
# undef Q_DECL_ENUMERATOR_DEPRECATED
# define Q_DECL_ENUMERATOR_DEPRECATED
+# undef Q_DECL_ENUMERATOR_DEPRECATED_X
+# define Q_DECL_ENUMERATOR_DEPRECATED_X(ignored)
#endif
// If the deprecated macro is defined, use its value
@@ -201,6 +203,22 @@ QT_BEGIN_NAMESPACE
# define QT_DEPRECATED_VERSION_6_9
#endif
+#if QT_WARN_DEPRECATED_UP_TO >= QT_VERSION_CHECK(6, 10, 0)
+# define QT_DEPRECATED_VERSION_X_6_10(text) QT_DEPRECATED_X(text)
+# define QT_DEPRECATED_VERSION_6_10 QT_DEPRECATED
+#else
+# define QT_DEPRECATED_VERSION_X_6_10(text)
+# define QT_DEPRECATED_VERSION_6_10
+#endif
+
+#if QT_WARN_DEPRECATED_UP_TO >= QT_VERSION_CHECK(6, 11, 0)
+# define QT_DEPRECATED_VERSION_X_6_11(text) QT_DEPRECATED_X(text)
+# define QT_DEPRECATED_VERSION_6_11 QT_DEPRECATED
+#else
+# define QT_DEPRECATED_VERSION_X_6_11(text)
+# define QT_DEPRECATED_VERSION_6_11
+#endif
+
#define QT_DEPRECATED_VERSION_X_5(minor, text) QT_DEPRECATED_VERSION_X_5_##minor(text)
#define QT_DEPRECATED_VERSION_X(major, minor, text) QT_DEPRECATED_VERSION_X_##major##_##minor(text)
@@ -297,6 +315,18 @@ QT_BEGIN_NAMESPACE
# define QT_IF_DEPRECATED_SINCE_6_9(whenTrue, whenFalse) whenTrue
#endif
+#if QT_DEPRECATED_SINCE(6, 10)
+# define QT_IF_DEPRECATED_SINCE_6_10(whenTrue, whenFalse) whenFalse
+#else
+# define QT_IF_DEPRECATED_SINCE_6_10(whenTrue, whenFalse) whenTrue
+#endif
+
+#if QT_DEPRECATED_SINCE(6, 11)
+# define QT_IF_DEPRECATED_SINCE_6_11(whenTrue, whenFalse) whenFalse
+#else
+# define QT_IF_DEPRECATED_SINCE_6_11(whenTrue, whenFalse) whenTrue
+#endif
+
#ifdef __cplusplus
// A tag to help mark stuff deprecated (cf. QStringViewLiteral)
namespace QtPrivate {
diff --git a/src/corelib/global/qtenvironmentvariables.cpp b/src/corelib/global/qtenvironmentvariables.cpp
index 4046beae1f..cf5955902a 100644
--- a/src/corelib/global/qtenvironmentvariables.cpp
+++ b/src/corelib/global/qtenvironmentvariables.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qtenvironmentvariables.h"
+#include "qtenvironmentvariables_p.h"
#include <qplatformdefs.h>
#include <QtCore/qbytearray.h>
@@ -330,9 +331,11 @@ bool qunsetenv(const char *varName)
#endif
}
-/*
- Wraps tzset(), which accesses the environment, so should only be called while
- we hold the lock on the environment mutex.
+/* Various time-related APIs that need to consult system settings also need
+ protection with the same lock as the environment, since those system settings
+ include part of the environment (principally TZ).
+
+ First, tzset(), which POSIX explicitly says accesses the environment.
*/
void qTzSet()
{
@@ -344,14 +347,83 @@ void qTzSet()
#endif // Q_OS_WIN
}
-/*
- Wrap mktime(), which is specified to behave as if it called tzset(), hence
- shares its implicit environment-dependence.
+/* Wrap mktime(), which is specified to behave as if it called tzset(), hence
+ shares its implicit environment-dependence.
*/
time_t qMkTime(struct tm *when)
{
const auto locker = qt_scoped_lock(environmentMutex);
+#if defined(Q_OS_WIN)
+ // QTBUG-83881 MS's mktime() seems to need _tzset() called first.
+ _tzset();
+#endif
return mktime(when);
}
+/* For localtime(), POSIX mandates that it behave as if it called tzset().
+ For the alternatives to it, we need (if only for compatibility) to do the
+ same explicitly, which should ensure a re-parse of timezone info.
+*/
+bool qLocalTime(time_t utc, struct tm *local)
+{
+ const auto locker = qt_scoped_lock(environmentMutex);
+#if defined(Q_OS_WIN)
+ // The doc of localtime_s() says that it corrects for the same things
+ // _tzset() sets the globals for, but QTBUG-109974 reveals a need for an
+ // explicit call, all the same.
+ _tzset();
+ return !localtime_s(local, &utc);
+#elif QT_CONFIG(thread) && defined(_POSIX_THREAD_SAFE_FUNCTIONS)
+ // Use the reentrant version of localtime() where available, as it is
+ // thread-safe and doesn't use a shared static data area.
+ // As localtime_r() is not specified to work as if it called tzset(),
+ // make an explicit call.
+ tzset();
+ if (tm *res = localtime_r(&utc, local)) {
+ Q_ASSERT(res == local);
+ Q_UNUSED(res);
+ return true;
+ }
+ return false;
+#else
+ // POSIX mandates that localtime() behaves as if it called tzset().
+ // Returns shared static data which may be overwritten at any time (albeit
+ // our lock probably keeps it safe). So copy the result promptly:
+ if (tm *res = localtime(&utc)) {
+ *local = *res;
+ return true;
+ }
+ return false;
+#endif
+}
+
+/* Access to the tzname[] global in one thread is UB if any other is calling
+ tzset() or anything that behaves as if it called tzset(). So also lock this
+ access to prevent such collisions.
+
+ Parameter dstIndex must be 1 for DST or 0 for standard time.
+ Returns the relevant form of the name of local-time's zone.
+*/
+QString qTzName(int dstIndex)
+{
+ char name[512];
+ bool ok;
+#if defined(_UCRT) // i.e., MSVC and MinGW-UCRT
+ size_t s = 0;
+ {
+ const auto locker = qt_scoped_lock(environmentMutex);
+ ok = _get_tzname(&s, name, 512, dstIndex) != 0;
+ }
+#else
+ {
+ const auto locker = qt_scoped_lock(environmentMutex);
+ const char *const src = tzname[dstIndex];
+ ok = src != nullptr;
+ if (ok)
+ memcpy(name, src, std::min(sizeof(name), strlen(src) + 1));
+ }
+#endif // Q_OS_WIN
+ return ok ? QString::fromLocal8Bit(name) : QString();
+}
+
QT_END_NAMESPACE
diff --git a/src/corelib/global/qtenvironmentvariables_p.h b/src/corelib/global/qtenvironmentvariables_p.h
new file mode 100644
index 0000000000..0c81d36db6
--- /dev/null
+++ b/src/corelib/global/qtenvironmentvariables_p.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2015 Intel Corporation.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QTENVIRONMENTVARIABLES_P_H
+#define QTENVIRONMENTVARIABLES_P_H
+// Nothing but (tests and) ../time/qlocaltime.cpp should access this.
+#if defined(__cplusplus)
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an implementation
+// detail. This header file may change from version to version without notice,
+// or even be removed.
+//
+// We mean it.
+//
+
+#include "qglobal_p.h"
+
+#ifdef Q_CC_MINGW
+# include <unistd.h> // Define _POSIX_THREAD_SAFE_FUNCTIONS to obtain localtime_r()
+#endif
+#include <time.h>
+
+QT_BEGIN_NAMESPACE
+
+// These (behave as if they) consult the environment, so need to share its locking:
+Q_CORE_EXPORT void qTzSet();
+Q_CORE_EXPORT time_t qMkTime(struct tm *when);
+Q_CORE_EXPORT bool qLocalTime(time_t utc, struct tm *local);
+Q_CORE_EXPORT QString qTzName(int dstIndex);
+
+QT_END_NAMESPACE
+
+#endif // defined(__cplusplus)
+#endif // QTENVIRONMENTVARIABLES_P_H
diff --git a/src/corelib/global/qtnoop.h b/src/corelib/global/qtnoop.h
index ea0cedd9bc..c84e6c8a99 100644
--- a/src/corelib/global/qtnoop.h
+++ b/src/corelib/global/qtnoop.h
@@ -8,6 +8,13 @@
#pragma qt_sync_stop_processing
#endif
-inline void qt_noop(void) {}
+#ifdef __cplusplus
+constexpr
+#endif
+inline void qt_noop(void)
+#ifdef __cplusplus
+ noexcept
+#endif
+{}
#endif // QTNOOP_H
diff --git a/src/corelib/global/qtrace_p.h b/src/corelib/global/qtrace_p.h
index ce90a2bf18..f4e39ffe2b 100644
--- a/src/corelib/global/qtrace_p.h
+++ b/src/corelib/global/qtrace_p.h
@@ -57,7 +57,7 @@
* qcoreapplication_qrect(const QRect &rect)
*
* The provider file is then parsed by src/tools/tracegen, which can be
- * switched to output either ETW or LTTNG tracepoint definitions. The provider
+ * switched to output either ETW, CTF or LTTNG tracepoint definitions. The provider
* name is deduced to be basename(provider_file).
*
* To use the above (inside qtcore), you need to include
@@ -75,9 +75,53 @@
* - QByteArray
* - QUrl
* - QRect
+ * - QRectF
+ * - QSize
+ * - QSizeF
*
* Dynamic arrays are supported using the syntax illustrated by
* qcoreapplication_baz above.
+ *
+ * One can also add prefix for the generated providername_tracepoints_p.h file
+ * by specifying it inside brackets '{ }' in the tracepoints file. One can
+ * for example add forward declaration for a type:
+ *
+ * {
+ * QT_BEGIN_NAMESPACE
+ * class QEvent;
+ * QT_END_NAMESPACE
+ * }
+ *
+ * Metadata
+ *
+ * Metadata is used to add textual information for different types such
+ * as enums and flags. How this data is handled depends on the used backend.
+ * For ETW, the values are converted to text, for CTF and LTTNG they are used to add
+ * CTF enumerations, which are converted to text after tracing.
+ *
+ * Enumererations are specified using ENUM:
+ *
+ * ENUM {
+ * Enum0 = 0,
+ * Enum1 = 1,
+ * Enum2,
+ * RANGE(RangeEnum, 3 ... 10),
+ * } Name;
+ *
+ * Name must match to one of the enumerations used in the tracepoints. Range of values
+ * can be provided using RANGE(name, first ... last). All values must be unique.
+ *
+ * Flags are specified using FLAGS:
+ *
+ * FLAGS {
+ * Default = 0,
+ * Flag0 = 1,
+ * Flag1 = 2,
+ * Flag2 = 4,
+ * } Name;
+ *
+ * Name must match to one of the flags used in the tracepoints. Each value must be
+ * power of two and unique.
*/
#include <QtCore/private/qglobal_p.h>
@@ -104,6 +148,91 @@ QT_BEGIN_NAMESPACE
# define Q_TRACE_ENABLED(x) false
#endif // defined(Q_TRACEPOINT) && !defined(QT_BOOTSTRAPPED)
+
+/*
+ * The Qt tracepoints can also be defined directly in the source files using
+ * the following macros. If using these macros, the tracepoints file is automatically
+ * generated using the tracepointgen tool. The tool scans the input files for
+ * these macros. These macros are ignored during compile time. Both automatic
+ * generation and manually specifying tracepoints in a file can't be done at the same
+ * time for the same provider.
+ *
+ * - Q_TRACE_INSTRUMENT(provider)
+ * Generate entry/exit tracepoints for a function. For example, member function
+ *
+ * void SomeClass::method(int param1, float param2)
+ * {
+ * ...
+ * }
+ *
+ * converted to use tracepoints:
+ *
+ * void Q_TRACE_INSTRUMENT(provider) SomeClass::method(int param1, float param2)
+ * {
+ * Q_TRACE_SCOPE(SomeClass_method, param1, param2);
+ * ...
+ * }
+ *
+ * generates following tracepoints in provider.tracepoints file:
+ *
+ * SomeClass_method_entry(int param1, float param2)
+ * SomeClass_method_exit()
+ *
+ * - Q_TRACE_PARAM_REPLACE(in, out)
+ * Can be used with Q_TRACE_INSTRUMENT to replace parameter type in with type out.
+ * If a parameter type is not supported by the tracegen tool, one can use this to
+ * change it to another supported type.
+ *
+ * void Q_TRACE_INSTRUMENT(provider) SomeClass::method(int param1, UserType param2)
+ * {
+ * Q_TRACE_PARAM_REPLACE(UserType, QString);
+ * Q_TRACE_SCOPE(SomeClass_method, param1, param2.toQString());
+ * }
+ *
+ * - Q_TRACE_POINT(provider, tracepoint, ...)
+ * Manually specify tracepoint for the provider. 'tracepoint' is the full name
+ * of the tracepoint and ... can be zero or more parameters.
+ *
+ * Q_TRACE_POINT(provider, SomeClass_function_entry, int param1, int param2);
+ *
+ * generates following tracepoint:
+ *
+ * SomeClass_function_entry(int param1, int param2)
+ *
+ * - Q_TRACE_PREFIX(provider, prefix)
+ * Provide prefix for the tracepoint. Multiple prefixes can be specified for the same
+ * provider in different files, they are all concatenated into one in the
+ * provider.tracepoints file.
+ *
+ * Q_TRACE_PREFIX(provider,
+ * "QT_BEGIN_NAMESPACE" \
+ * "class QEvent;" \
+ * "QT_END_NAMESPACE")
+ *
+ * - Q_TRACE_METADATA(provider, metadata)
+ * Provides metadata for the tracepoint provider.
+ *
+ * Q_TRACE_METADATA(qtgui,
+ * "ENUM {" \
+ * "Format_Invalid," \
+ * "Format_Mono," \
+ * "Format_MonoLSB," \
+ * "Format_Indexed8," \
+ * ...
+ * "} QImage::Format;" \
+ * );
+ *
+ * If the content of enum is empty or contains keyword AUTO, then the tracepointgen tool
+ * tries to find the enumeration from header files.
+ *
+ * Q_TRACE_METADATA(qtcore, "ENUM { AUTO, RANGE User ... MaxUser } QEvent::Type;");
+ */
+#define Q_TRACE_INSTRUMENT(provider)
+#define Q_TRACE_PARAM_REPLACE(in, out)
+#define Q_TRACE_POINT(provider, tracepoint, ...)
+#define Q_TRACE_PREFIX(provider, prefix)
+#define Q_TRACE_METADATA(provider, metadata)
+
QT_END_NAMESPACE
#endif // QTRACE_P_H
diff --git a/src/corelib/global/qtsymbolmacros.h b/src/corelib/global/qtsymbolmacros.h
new file mode 100644
index 0000000000..18cdc85f72
--- /dev/null
+++ b/src/corelib/global/qtsymbolmacros.h
@@ -0,0 +1,65 @@
+// 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
+
+#ifndef QTSYMBOLMACROS_H
+#define QTSYMBOLMACROS_H
+
+#if 0
+# pragma qt_sync_stop_processing
+#endif
+
+// For GHS symbol keeping.
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtpreprocessorsupport.h>
+
+// For handling namespaced resources.
+#ifdef QT_NAMESPACE
+# define QT_RCC_MANGLE_NAMESPACE0(x) x
+# define QT_RCC_MANGLE_NAMESPACE1(a, b) a##_##b
+# define QT_RCC_MANGLE_NAMESPACE2(a, b) QT_RCC_MANGLE_NAMESPACE1(a,b)
+# define QT_RCC_MANGLE_NAMESPACE(name) QT_RCC_MANGLE_NAMESPACE2( \
+ QT_RCC_MANGLE_NAMESPACE0(name), QT_RCC_MANGLE_NAMESPACE0(QT_NAMESPACE))
+#else
+# define QT_RCC_MANGLE_NAMESPACE(name) name
+#endif
+
+// GHS needs special handling to keep a symbol around.
+#if defined(Q_CC_GHS)
+# define Q_GHS_KEEP_REFERENCE(S) QT_DO_PRAGMA(ghs reference S ##__Fv)
+#else
+# define Q_GHS_KEEP_REFERENCE(S)
+#endif
+
+// Macros to ensure a symbol is not dropped by the linker even if it's not used.
+#define QT_DECLARE_EXTERN_SYMBOL(NAME, RETURN_TYPE) \
+ extern RETURN_TYPE NAME(); \
+ Q_GHS_KEEP_REFERENCE(NAME)
+
+#define QT_DECLARE_EXTERN_SYMBOL_INT(NAME) \
+ QT_DECLARE_EXTERN_SYMBOL(NAME, int)
+
+#define QT_DECLARE_EXTERN_SYMBOL_VOID(NAME) \
+ QT_DECLARE_EXTERN_SYMBOL(NAME, void)
+
+#define QT_KEEP_SYMBOL_VAR_NAME(NAME) NAME ## _keep
+
+#define QT_KEEP_SYMBOL_HELPER(NAME, VAR_NAME) \
+ volatile auto VAR_NAME = &NAME; \
+ Q_UNUSED(VAR_NAME)
+
+#define QT_KEEP_SYMBOL(NAME) \
+ QT_KEEP_SYMBOL_HELPER(NAME, QT_KEEP_SYMBOL_VAR_NAME(NAME))
+
+
+// Similar to the ones above, but for rcc resource symbols specifically.
+#define QT_GET_RESOURCE_INIT_SYMBOL(NAME) \
+ QT_RCC_MANGLE_NAMESPACE(qInitResources_ ## NAME)
+
+#define QT_DECLARE_EXTERN_RESOURCE(NAME) \
+ QT_DECLARE_EXTERN_SYMBOL_INT(QT_GET_RESOURCE_INIT_SYMBOL(NAME))
+
+#define QT_KEEP_RESOURCE(NAME) \
+ QT_KEEP_SYMBOL(QT_GET_RESOURCE_INIT_SYMBOL(NAME))
+
+#endif // QTSYMBOLMACROS_H
+
diff --git a/src/corelib/global/qttypetraits.h b/src/corelib/global/qttypetraits.h
index 1832a1a734..1efb24bf70 100644
--- a/src/corelib/global/qttypetraits.h
+++ b/src/corelib/global/qttypetraits.h
@@ -5,6 +5,7 @@
#define QTTYPETRAITS_H
#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtdeprecationmarkers.h>
#include <type_traits>
#include <utility>
@@ -23,13 +24,22 @@ constexpr std::underlying_type_t<Enum> qToUnderlying(Enum e) noexcept
return static_cast<std::underlying_type_t<Enum>>(e);
}
+#ifndef QT_NO_QASCONST
+#if QT_DEPRECATED_SINCE(6, 6)
+
// this adds const to non-const objects (like std::as_const)
template <typename T>
+QT_DEPRECATED_VERSION_X_6_6("Use std::as_const() instead.")
constexpr typename std::add_const<T>::type &qAsConst(T &t) noexcept { return t; }
// prevent rvalue arguments:
template <typename T>
void qAsConst(const T &&) = delete;
+#endif // QT_DEPRECATED_SINCE(6, 6)
+#endif // QT_NO_QASCONST
+
+#ifndef QT_NO_QEXCHANGE
+
// like std::exchange
template <typename T, typename U = T>
constexpr T qExchange(T &t, U &&newValue)
@@ -41,6 +51,15 @@ noexcept(std::conjunction_v<std::is_nothrow_move_constructible<T>,
return old;
}
+#endif // QT_NO_QEXCHANGE
+
+namespace QtPrivate {
+// helper to be used to trigger a "dependent static_assert(false)"
+// (for instance, in a final `else` branch of a `if constexpr`.)
+template <typename T> struct type_dependent_false : std::false_type {};
+template <auto T> struct value_dependent_false : std::false_type {};
+}
+
QT_END_NAMESPACE
#endif // QTTYPETRAITS_H
diff --git a/src/corelib/global/qttypetraits.qdoc b/src/corelib/global/qttypetraits.qdoc
index 6bb1ceba2c..ed814d6f43 100644
--- a/src/corelib/global/qttypetraits.qdoc
+++ b/src/corelib/global/qttypetraits.qdoc
@@ -2,6 +2,14 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
+ \headerfile <QtTypeTraits>
+ \inmodule QtCore
+ \since 6.5
+ \title Qt Type Traits
+ \brief Functionality for type traits and transformations.
+*/
+
+/*!
\fn template <typename Enum> std::underlying_type_t<Enum> qToUnderlying(Enum e)
\relates <QtTypeTraits>
\since 6.2
@@ -15,6 +23,8 @@
\relates <QtTypeTraits>
\since 5.7
+ \deprecated [6.6] Use std::as_const() instead.
+
Returns \a t cast to \c{const T}.
This function is a Qt implementation of C++17's std::as_const(),
@@ -44,6 +54,20 @@
To prevent this construct from compiling (and failing at runtime), qAsConst() has
a second, deleted, overload which binds to rvalues.
+
+ \note You can make the qAsConst() function unavailable by defining
+ the \l{QT_NO_QASCONST} macro.
+*/
+
+/*!
+ \macro QT_NO_QASCONST
+ \since 6.8
+ \relates <QtTypeTraits>
+
+ Defining this macro removes the availability of the qAsConst()
+ function.
+
+ \sa qAsConst
*/
/*!
@@ -52,6 +76,8 @@
\since 5.7
\overload
+ \deprecated [6.6]
+
This overload is deleted to prevent a dangling reference in code like
\snippet code/src_corelib_global_qglobal.cpp as-const-4
*/
@@ -64,8 +90,10 @@
Replaces the value of \a obj with \a newValue and returns the old value of \a obj.
This is Qt's implementation of std::exchange(). It differs from std::exchange()
- only in that it is \c constexpr already in C++14, and available on all supported
- compilers.
+ only in that it is \c constexpr already before C++20 and noexcept already before C++23.
+
+ We strongly advise to use std::exchange() when you don't need the C++20 or C++23 variants.
+ You can make qExchange() unavailable by defining the \l{QT_NO_QEXCHANGE} macro.
Here is how to use qExchange() to implement move constructors:
\code
@@ -105,3 +133,14 @@
long as the loop runs, saving the declaration of a temporary variable. Be aware, though,
that qExchange() returns a non-const object, so Qt containers may detach.
*/
+
+/*!
+ \macro QT_NO_QEXCHANGE
+ \since 6.6
+ \relates <QtTypeTraits>
+
+ Defining this macro removes the availability of the qExchange()
+ function.
+
+ \sa qExchange
+*/
diff --git a/src/corelib/global/qtversion.h b/src/corelib/global/qtversion.h
new file mode 100644
index 0000000000..775f2479a9
--- /dev/null
+++ b/src/corelib/global/qtversion.h
@@ -0,0 +1,38 @@
+// 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
+
+#ifndef QTVERSION_H
+#define QTVERSION_H
+
+#if 0
+#pragma qt_class(QtVersion)
+#pragma qt_sync_stop_processing
+#endif
+
+#ifndef __ASSEMBLER__
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtcoreexports.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ * If we're compiling C++ code:
+ * - and this is a non-namespace build, declare qVersion as extern "C"
+ * - and this is a namespace build, declare it as a regular function
+ * (we're already inside QT_BEGIN_NAMESPACE / QT_END_NAMESPACE)
+ * If we're compiling C code, simply declare the function. If Qt was compiled
+ * in a namespace, qVersion isn't callable anyway.
+ */
+#if !defined(QT_NAMESPACE) && defined(__cplusplus) && !defined(Q_QDOC)
+extern "C"
+#endif
+/* defined in qlibraryinfo.cpp */
+Q_CORE_EXPORT Q_DECL_CONST_FUNCTION const char *qVersion(void) Q_DECL_NOEXCEPT;
+
+QT_END_NAMESPACE
+
+#endif // __ASSEMBLER__
+
+#endif // QTVERSION_H
diff --git a/src/corelib/global/qtversionchecks.h b/src/corelib/global/qtversionchecks.h
index 8f3bd8b371..86fc094f4e 100644
--- a/src/corelib/global/qtversionchecks.h
+++ b/src/corelib/global/qtversionchecks.h
@@ -9,15 +9,7 @@
#pragma qt_sync_stop_processing
#endif
-#ifdef QT_BOOTSTRAPPED
-// qconfig-bootstrapped.h is not supposed to be a part of the synced header files. So we find it by
-// the include path specified for Bootstrap library in the source tree instead of the build tree as
-// it's done for regular header files.
-#include "qconfig-bootstrapped.h"
-#else
-#include <QtCore/qconfig.h>
-#include <QtCore/qtcore-config.h>
-#endif
+#include <QtCore/qtconfiginclude.h>
/*
QT_VERSION is (major << 16) | (minor << 8) | patch.
@@ -36,7 +28,7 @@
void QT7_ONLY(Q_CORE_EXPORT) void operate();
}
*/
-#if QT_VERSION_MAJOR == 7
+#if QT_VERSION_MAJOR == 7 || defined(QT_BOOTSTRAPPED)
# define QT7_ONLY(...) __VA_ARGS__
# define QT6_ONLY(...)
#elif QT_VERSION_MAJOR == 6
@@ -64,7 +56,7 @@
int size() const { return int(size(QT6_CALL_NEW_OVERLOAD)); }
*/
-#ifdef Q_CLANG_QDOC
+#ifdef Q_QDOC
# define QT6_DECL_NEW_OVERLOAD
# define QT6_DECL_NEW_OVERLOAD_TAIL
# define QT6_IMPL_NEW_OVERLOAD
@@ -80,4 +72,43 @@
# define QT6_CALL_NEW_OVERLOAD_TAIL QT6_ONLY(, QT6_CALL_NEW_OVERLOAD)
#endif
+/*
+ Macro to tag Tech Preview APIs.
+ It expands to nothing, because we want to use it in places where
+ nothing is generally allowed (not even an attribute); for instance:
+ to tag other macros, Q_PROPERTY declarations, and so on.
+
+ Still: use it as if it were an C++ attribute.
+
+ To mark a class as TP:
+ class QT_TECH_PREVIEW_API Q_CORE_EXPORT QClass { ... };
+
+ To mark a function:
+ QT_TECH_PREVIEW_API void qFunction();
+
+ To mark an enumeration or enumerator:
+ enum class QT_TECH_PREVIEW_API QEnum {
+ Enum1,
+ Enum2 QT_TECH_PREVIEW_API,
+ };
+
+ To mark parts of a class:
+ class QClass : public QObject
+ {
+ // Q_OBJECT omitted d/t QTBUG-123229
+
+ QT_TECH_PREVIEW_API
+ Q_PROPERTY(int countNG ...) // this is TP
+
+ Q_PROPERTY(int count ...) // this is stable API
+
+ public:
+ QT_TECH_PREVIEW_API
+ void f(); // TP
+
+ void g(); // stable
+ };
+*/
+#define QT_TECH_PREVIEW_API
+
#endif /* QTVERSIONCHECKS_H */
diff --git a/src/corelib/global/qtypeinfo.h b/src/corelib/global/qtypeinfo.h
index 73bf6140c7..255a2b33c6 100644
--- a/src/corelib/global/qtypeinfo.h
+++ b/src/corelib/global/qtypeinfo.h
@@ -2,14 +2,16 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include <QtCore/qglobal.h>
+#ifndef QTYPEINFO_H
+#define QTYPEINFO_H
+
+#include <QtCore/qcompilerdetection.h>
#include <QtCore/qcontainerfwd.h>
+
#include <variant>
#include <optional>
#include <tuple>
-
-#ifndef QTYPEINFO_H
-#define QTYPEINFO_H
+#include <type_traits>
QT_BEGIN_NAMESPACE
@@ -19,9 +21,30 @@ class QDebug;
QTypeInfo - type trait functionality
*/
+namespace QtPrivate {
+
+// A trivially copyable class must also have a trivial, non-deleted
+// destructor [class.prop/1.3], CWG1734. Some implementations don't
+// check for a trivial destructor, because of backwards compatibility
+// with C++98's definition of trivial copyability.
+// Since trivial copiability has implications for the ABI, implementations
+// can't "just fix" their traits. So, although formally redundant, we
+// explicitly check for trivial destruction here.
template <typename T>
inline constexpr bool qIsRelocatable = std::is_trivially_copyable_v<T> && std::is_trivially_destructible_v<T>;
+// Denotes types that are trivially default constructible, and for which
+// value-initialization can be achieved by filling their storage with 0 bits.
+// There is no type trait we can use for this, so we hardcode a list of
+// possibilities that we know are OK on the architectures that we support.
+// The most notable exception are pointers to data members, which for instance
+// on the Itanium ABI are initialized to -1.
+template <typename T>
+inline constexpr bool qIsValueInitializationBitwiseZero =
+ std::is_scalar_v<T> && !std::is_member_object_pointer_v<T>;
+
+}
+
/*
The catch-all template.
*/
@@ -31,10 +54,11 @@ class QTypeInfo
{
public:
enum {
- isPointer = std::is_pointer_v<T>,
- isIntegral = std::is_integral_v<T>,
+ isPointer [[deprecated("Use std::is_pointer instead")]] = std::is_pointer_v<T>,
+ isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral_v<T>,
isComplex = !std::is_trivial_v<T>,
- isRelocatable = qIsRelocatable<T>,
+ isRelocatable = QtPrivate::qIsRelocatable<T>,
+ isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero<T>,
};
};
@@ -43,10 +67,11 @@ class QTypeInfo<void>
{
public:
enum {
- isPointer = false,
- isIntegral = false,
+ isPointer [[deprecated("Use std::is_pointer instead")]] = false,
+ isIntegral [[deprecated("Use std::is_integral instead")]] = false,
isComplex = false,
isRelocatable = false,
+ isValueInitializationBitwiseZero = false,
};
};
@@ -77,20 +102,33 @@ class QTypeInfoMerger
public:
static constexpr bool isComplex = ((QTypeInfo<Ts>::isComplex) || ...);
static constexpr bool isRelocatable = ((QTypeInfo<Ts>::isRelocatable) && ...);
- static constexpr bool isPointer = false;
- static constexpr bool isIntegral = false;
+ [[deprecated("Use std::is_pointer instead")]] static constexpr bool isPointer = false;
+ [[deprecated("Use std::is_integral instead")]] static constexpr bool isIntegral = false;
+ static constexpr bool isValueInitializationBitwiseZero = false;
+ static_assert(!isRelocatable ||
+ std::is_copy_constructible_v<T> ||
+ std::is_move_constructible_v<T>,
+ "All Ts... are Q_RELOCATABLE_TYPE, but T is neither copy- nor move-constructible, "
+ "so cannot be Q_RELOCATABLE_TYPE. Please mark T as Q_COMPLEX_TYPE manually.");
};
+// QTypeInfo for std::pair:
+// std::pair is spec'ed to be struct { T1 first; T2 second; }, so, unlike tuple<>,
+// we _can_ specialize QTypeInfo for pair<>:
+template <class T1, class T2>
+class QTypeInfo<std::pair<T1, T2>> : public QTypeInfoMerger<std::pair<T1, T2>, T1, T2> {};
+
#define Q_DECLARE_MOVABLE_CONTAINER(CONTAINER) \
template <typename ...T> \
class QTypeInfo<CONTAINER<T...>> \
{ \
public: \
enum { \
- isPointer = false, \
- isIntegral = false, \
+ isPointer [[deprecated("Use std::is_pointer instead")]] = false, \
+ isIntegral [[deprecated("Use std::is_integral instead")]] = false, \
isComplex = true, \
isRelocatable = true, \
+ isValueInitializationBitwiseZero = false, \
}; \
}
@@ -128,10 +166,15 @@ class QTypeInfo<TYPE > \
public: \
enum { \
isComplex = (((FLAGS) & Q_PRIMITIVE_TYPE) == 0) && !std::is_trivial_v<TYPE>, \
- isRelocatable = !isComplex || ((FLAGS) & Q_RELOCATABLE_TYPE) || qIsRelocatable<TYPE>, \
- isPointer = false, \
- isIntegral = std::is_integral< TYPE >::value, \
+ isRelocatable = !isComplex || ((FLAGS) & Q_RELOCATABLE_TYPE) || QtPrivate::qIsRelocatable<TYPE>, \
+ isPointer [[deprecated("Use std::is_pointer instead")]] = std::is_pointer_v< TYPE >, \
+ isIntegral [[deprecated("Use std::is_integral instead")]] = std::is_integral< TYPE >::value, \
+ isValueInitializationBitwiseZero = QtPrivate::qIsValueInitializationBitwiseZero<TYPE>, \
}; \
+ static_assert(!isRelocatable || \
+ std::is_copy_constructible_v<TYPE > || \
+ std::is_move_constructible_v<TYPE >, \
+ #TYPE " is neither copy- nor move-constructible, so cannot be Q_RELOCATABLE_TYPE"); \
}
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS) \
@@ -211,7 +254,7 @@ using expand_operator_equal_recursive = std::conjunction<expand_operator_equal<T
template<typename T>
struct expand_operator_equal_tuple : has_operator_equal<T> {};
template<typename T>
-struct expand_operator_equal_tuple<std::optional<T>> : has_operator_equal<T> {};
+struct expand_operator_equal_tuple<std::optional<T>> : expand_operator_equal_recursive<T> {};
template<typename T1, typename T2>
struct expand_operator_equal_tuple<std::pair<T1, T2>> : expand_operator_equal_recursive<T1, T2> {};
template<typename ...T>
@@ -251,7 +294,7 @@ using expand_operator_less_than_recursive = std::conjunction<expand_operator_les
template<typename T>
struct expand_operator_less_than_tuple : has_operator_less_than<T> {};
template<typename T>
-struct expand_operator_less_than_tuple<std::optional<T>> : has_operator_less_than<T> {};
+struct expand_operator_less_than_tuple<std::optional<T>> : expand_operator_less_than_recursive<T> {};
template<typename T1, typename T2>
struct expand_operator_less_than_tuple<std::pair<T1, T2>> : expand_operator_less_than_recursive<T1, T2> {};
template<typename ...T>
diff --git a/src/corelib/global/qtypeinfo.qdoc b/src/corelib/global/qtypeinfo.qdoc
index 78d9d423cd..75a92da197 100644
--- a/src/corelib/global/qtypeinfo.qdoc
+++ b/src/corelib/global/qtypeinfo.qdoc
@@ -13,13 +13,13 @@
\a Flags can be one of the following:
\list
- \li \c Q_PRIMITIVE_TYPE specifies that \a Type can be created by
- zero-initializing its storage, requires no operation to be properly
- destroyed, and for which memcpy()ing creates a valid independent
- copy of the object.
+ \li \c Q_PRIMITIVE_TYPE specifies that \a Type requires no
+ operation to be performed in order to be properly destroyed,
+ and that it is possible to use memcpy() in order to create a
+ valid independent copy of an object.
\li \c Q_RELOCATABLE_TYPE specifies that \a Type has a constructor
- and/or a destructor but can be moved in memory using \c
- memcpy().
+ and/or a destructor, but it can still be \e{relocated} in memory
+ by using \c memcpy().
\li \c Q_MOVABLE_TYPE is the same as \c Q_RELOCATABLE_TYPE. Prefer to use
\c Q_RELOCATABLE_TYPE in new code. Note: despite the name, this
has nothing to do with move constructors or C++ move semantics.
@@ -41,15 +41,8 @@
\snippet code/src_corelib_global_qglobal.cpp 39
- Qt will try to detect the class of a type using
- \l {https://en.cppreference.com/w/cpp/types/is_trivial} {std::is_trivial_v<T>}
- to identify primitive
- types and it will require both
- \l {https://en.cppreference.com/w/cpp/types/is_trivially_copyable} {std::is_trivially_copyable_v<T>}
- and
- \l {https://en.cppreference.com/w/cpp/types/is_destructible} {std::is_trivially_destructible_v<T>}
- to identify relocatable types.
- Use this macro to tune the behavior.
+ Qt will try to detect the class of a type using standard C++ type traits;
+ use this macro to tune the behavior.
For instance many types would be candidates for Q_RELOCATABLE_TYPE despite
not being trivially-copyable.
*/
diff --git a/src/corelib/global/qtypes.cpp b/src/corelib/global/qtypes.cpp
index 515f158f52..9de3960e2f 100644
--- a/src/corelib/global/qtypes.cpp
+++ b/src/corelib/global/qtypes.cpp
@@ -145,6 +145,43 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \typedef qint128
+ \relates <QtTypes>
+ \since 6.6
+
+ Typedef for \c{__int128} on platforms that support it (Qt defines the macro
+ \l QT_SUPPORTS_INT128 if this is the case).
+
+ Literals of this type can be created using the Q_INT128_C() macro.
+
+ \sa Q_INT128_C(), Q_INT128_MIN, Q_INT128_MAX, quint128, QT_SUPPORTS_INT128
+*/
+
+/*!
+ \typedef quint128
+ \relates <QtTypes>
+ \since 6.6
+
+ Typedef for \c{unsigned __int128} on platforms that support it (Qt defines
+ the macro \l QT_SUPPORTS_INT128 if this is the case).
+
+ Literals of this type can be created using the Q_UINT128_C() macro.
+
+ \sa Q_UINT128_C(), Q_UINT128_MAX, qint128, QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro QT_SUPPORTS_INT128
+ \relates <QtTypes>
+ \since 6.6
+
+ Qt defines this macro as well as the \l qint128 and \l quint128 types if
+ the platform has support for 128-bit integer types.
+
+ \sa qint128, quint128, Q_INT128_C(), Q_UINT128_C(), Q_INT128_MIN, Q_INT128_MAX, Q_UINT128_MAX
+*/
+
+/*!
\typedef qintptr
\relates <QtTypes>
@@ -327,7 +364,7 @@ QT_BEGIN_NAMESPACE
\snippet code/src_corelib_global_qglobal.cpp 8
- \sa qint64, Q_UINT64_C()
+ \sa qint64, Q_UINT64_C(), Q_INT128_C()
*/
/*! \macro quint64 Q_UINT64_C(literal)
@@ -340,7 +377,79 @@ QT_BEGIN_NAMESPACE
\snippet code/src_corelib_global_qglobal.cpp 9
- \sa quint64, Q_INT64_C()
+ \sa quint64, Q_INT64_C(), Q_UINT128_C()
+*/
+
+/*!
+ \macro qint128 Q_INT128_C(literal)
+ \relates <QtTypes>
+ \since 6.6
+
+ Wraps the signed 128-bit integer \a literal in a
+ platform-independent way.
+
+ \note Unlike Q_INT64_C(), this macro is only available in C++, not in C.
+ This is because compilers do not provide these literals as built-ins and C
+ does not have support for user-defined literals.
+
+ \sa qint128, Q_UINT128_C(), Q_INT128_MIN, Q_INT128_MAX, Q_INT64_C(), QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro quint128 Q_UINT128_C(literal)
+ \relates <QtTypes>
+ \since 6.6
+
+ Wraps the unsigned 128-bit integer \a literal in a
+ platform-independent way.
+
+ \note Unlike Q_UINT64_C(), this macro is only available in C++, not in C.
+ This is because compilers do not provide these literals as built-ins and C
+ does not have support for user-defined literals.
+
+ \sa quint128, Q_INT128_C(), Q_UINT128_MAX, Q_UINT64_C(), QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro Q_UINT128_MAX
+ \relates <QtTypes>
+ \since 6.6
+
+ This macro expands to a compile-time constant representing the
+ maximum value representable in a \l quint128.
+
+ This macro is available in both C++ and C modes.
+
+ The minimum of \l quint128 is 0 (zero), so a \c{Q_UINT128_MIN} is neither
+ needed nor provided.
+
+ \sa Q_INT128_MAX, quint128, Q_UINT128_C, QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro Q_INT128_MIN
+ \relates <QtTypes>
+ \since 6.6
+
+ This macro expands to a compile-time constant representing the
+ minimum value representable in a \l qint128.
+
+ This macro is available in both C++ and C modes.
+
+ \sa Q_INT128_MAX, qint128, Q_INT128_C, QT_SUPPORTS_INT128
+*/
+
+/*!
+ \macro Q_INT128_MAX
+ \relates <QtTypes>
+ \since 6.6
+
+ This macro expands to a compile-time constant representing the
+ maximum value representable in a \l qint128.
+
+ This macro is available in both C++ and C modes.
+
+ \sa Q_INT128_MIN, Q_UINT128_MAX, qint128, Q_INT128_C, QT_SUPPORTS_INT128
*/
// Statically check assumptions about the environment we're running
@@ -392,11 +501,28 @@ static_assert(std::numeric_limits<float>::radix == 2,
static_assert(sizeof(size_t) == sizeof(void *), "size_t and a pointer don't have the same size");
static_assert(sizeof(size_t) == sizeof(qsizetype)); // implied by the definition
static_assert((std::is_same<qsizetype, qptrdiff>::value));
+static_assert(std::is_same_v<std::size_t, size_t>);
// Check that our own typedefs are not broken.
static_assert(sizeof(qint8) == 1, "Internal error, qint8 is misdefined");
static_assert(sizeof(qint16)== 2, "Internal error, qint16 is misdefined");
static_assert(sizeof(qint32) == 4, "Internal error, qint32 is misdefined");
static_assert(sizeof(qint64) == 8, "Internal error, qint64 is misdefined");
+#ifdef QT_SUPPORTS_INT128
+static_assert(sizeof(qint128) == 16, "Internal error, qint128 is misdefined");
+#endif
+
+#ifdef QT_SUPPORTS_INT128
+// Standard Library supports for 128-bit integers:
+// Implementation | Version | Note
+// ---------------------|---------|------
+// GNU libstdc++ | 11.1.0 |
+// LLVM libc++ | 3.5 | May change if compiler has __is_integral()
+// MS STL | none |
+
+# if defined(_LIBCPP_VERSION) || (defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE >= 11)
+static_assert(std::numeric_limits<quint128>::max() == Q_UINT128_MAX);
+# endif
+#endif
QT_END_NAMESPACE
diff --git a/src/corelib/global/qtypes.h b/src/corelib/global/qtypes.h
index f7757b4311..db9ba38e4c 100644
--- a/src/corelib/global/qtypes.h
+++ b/src/corelib/global/qtypes.h
@@ -7,10 +7,17 @@
#include <QtCore/qprocessordetection.h>
#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qassert.h>
#ifdef __cplusplus
# include <cstddef>
# include <cstdint>
+# if defined(__STDCPP_FLOAT16_T__) && __has_include(<stdfloat>)
+// P1467 implementation - https://wg21.link/p1467
+# include <stdfloat>
+# endif // defined(__STDCPP_FLOAT16_T__) && __has_include(<stdfloat>)
+#else
+# include <assert.h>
#endif
#if 0
@@ -19,8 +26,6 @@
#pragma qt_sync_stop_processing
#endif
-#ifndef __ASSEMBLER__
-
/*
Useful type definitions for Qt
*/
@@ -58,9 +63,104 @@ typedef unsigned long long quint64; /* 64 bit unsigned */
typedef qint64 qlonglong;
typedef quint64 qulonglong;
+#if defined(__SIZEOF_INT128__) && !defined(QT_NO_INT128)
+# define QT_SUPPORTS_INT128 __SIZEOF_INT128__
+#else
+# undef QT_SUPPORTS_INT128
+#endif
+
+#if defined(QT_SUPPORTS_INT128)
+__extension__ typedef __int128_t qint128;
+__extension__ typedef __uint128_t quint128;
+
+// limits:
+# ifdef __cplusplus /* need to avoid c-style-casts in C++ mode */
+# define QT_C_STYLE_CAST(type, x) static_cast<type>(x)
+# else /* but C doesn't have constructor-style casts */
+# define QT_C_STYLE_CAST(type, x) ((type)(x))
+# endif
+# ifndef Q_UINT128_MAX /* allow qcompilerdetection.h/user override */
+# define Q_UINT128_MAX QT_C_STYLE_CAST(quint128, -1)
+# endif
+# define Q_INT128_MAX QT_C_STYLE_CAST(qint128, Q_UINT128_MAX / 2)
+# define Q_INT128_MIN (-Q_INT128_MAX - 1)
+
+# ifdef __cplusplus
+ namespace QtPrivate::NumberLiterals {
+ namespace detail {
+ template <quint128 accu, int base>
+ constexpr quint128 construct() { return accu; }
+
+ template <quint128 accu, int base, char C, char...Cs>
+ constexpr quint128 construct()
+ {
+ if constexpr (C != '\'') { // ignore digit separators
+ const int digitValue = '0' <= C && C <= '9' ? C - '0' :
+ 'a' <= C && C <= 'z' ? C - 'a' + 10 :
+ 'A' <= C && C <= 'Z' ? C - 'A' + 10 :
+ /* else */ -1 ;
+ static_assert(digitValue >= 0 && digitValue < base,
+ "Invalid character");
+ // accu * base + digitValue <= MAX, but without overflow:
+ static_assert(accu <= (Q_UINT128_MAX - digitValue) / base,
+ "Overflow occurred");
+ return construct<accu * base + digitValue, base, Cs...>();
+ } else {
+ return construct<accu, base, Cs...>();
+ }
+ }
+
+ template <char C, char...Cs>
+ constexpr quint128 parse0xb()
+ {
+ constexpr quint128 accu = 0;
+ if constexpr (C == 'x' || C == 'X')
+ return construct<accu, 16, Cs...>(); // base 16, skip 'x'
+ else if constexpr (C == 'b' || C == 'B')
+ return construct<accu, 2, Cs...>(); // base 2, skip 'b'
+ else
+ return construct<accu, 8, C, Cs...>(); // base 8, include C
+ }
+
+ template <char...Cs>
+ constexpr quint128 parse0()
+ {
+ if constexpr (sizeof...(Cs) == 0) // this was just a literal 0
+ return 0;
+ else
+ return parse0xb<Cs...>();
+ }
+
+ template <char C, char...Cs>
+ constexpr quint128 parse()
+ {
+ if constexpr (C == '0')
+ return parse0<Cs...>(); // base 2, 8, or 16 (or just a literal 0), skip '0'
+ else
+ return construct<0, 10, C, Cs...>(); // initial accu 0, base 10, include C
+ }
+ } // namespace detail
+ template <char...Cs>
+ constexpr quint128 operator""_quint128() noexcept
+ { return QtPrivate::NumberLiterals::detail::parse<Cs...>(); }
+ template <char...Cs>
+ constexpr qint128 operator""_qint128() noexcept
+ { return qint128(QtPrivate::NumberLiterals::detail::parse<Cs...>()); }
+
+ #ifndef Q_UINT128_C // allow qcompilerdetection.h/user override
+ # define Q_UINT128_C(c) ([]{ using namespace QtPrivate::NumberLiterals; return c ## _quint128; }())
+ #endif
+ #ifndef Q_INT128_C // allow qcompilerdetection.h/user override
+ # define Q_INT128_C(c) ([]{ using namespace QtPrivate::NumberLiterals; return c ## _qint128; }())
+ #endif
+
+ } // namespace QtPrivate::NumberLiterals
+# endif // __cplusplus
+#endif // QT_SUPPORTS_INT128
+
#ifndef __cplusplus
// In C++ mode, we define below using QIntegerForSize template
-Q_STATIC_ASSERT_X(sizeof(ptrdiff_t) == sizeof(size_t), "Weird ptrdiff_t and size_t definitions");
+static_assert(sizeof(ptrdiff_t) == sizeof(size_t), "Weird ptrdiff_t and size_t definitions");
typedef ptrdiff_t qptrdiff;
typedef ptrdiff_t qsizetype;
typedef ptrdiff_t qintptr;
@@ -102,8 +202,8 @@ template <> struct QIntegerForSize<1> { typedef quint8 Unsigned; typedef qin
template <> struct QIntegerForSize<2> { typedef quint16 Unsigned; typedef qint16 Signed; };
template <> struct QIntegerForSize<4> { typedef quint32 Unsigned; typedef qint32 Signed; };
template <> struct QIntegerForSize<8> { typedef quint64 Unsigned; typedef qint64 Signed; };
-#if defined(Q_CC_GNU) && defined(__SIZEOF_INT128__)
-template <> struct QIntegerForSize<16> { __extension__ typedef unsigned __int128 Unsigned; __extension__ typedef __int128 Signed; };
+#if defined(QT_SUPPORTS_INT128)
+template <> struct QIntegerForSize<16> { typedef quint128 Unsigned; typedef qint128 Signed; };
#endif
template <class T> struct QIntegerForSizeof: QIntegerForSize<sizeof(T)> { };
typedef QIntegerForSize<Q_PROCESSOR_WORDSIZE>::Signed qregisterint;
@@ -154,10 +254,30 @@ using qsizetype = QIntegerForSizeof<std::size_t>::Signed;
#error Unsupported platform (unknown value for SIZE_MAX)
#endif
+// Define a native float16 type
+namespace QtPrivate {
+#if defined(__STDCPP_FLOAT16_T__)
+# define QFLOAT16_IS_NATIVE 1
+using NativeFloat16Type = std::float16_t;
+#elif defined(Q_CC_CLANG) && defined(__FLT16_MAX__) && 0
+// disabled due to https://github.com/llvm/llvm-project/issues/56963
+# define QFLOAT16_IS_NATIVE 1
+using NativeFloat16Type = decltype(__FLT16_MAX__);
+#elif defined(Q_CC_GNU_ONLY) && defined(__FLT16_MAX__)
+# define QFLOAT16_IS_NATIVE 1
+# ifdef __ARM_FP16_FORMAT_IEEE
+using NativeFloat16Type = __fp16;
+# else
+using NativeFloat16Type = _Float16;
+# endif
+#else
+# define QFLOAT16_IS_NATIVE 0
+using NativeFloat16Type = void;
+#endif
+} // QtPrivate
+
#endif // __cplusplus
QT_END_NAMESPACE
-#endif // __ASSEMBLER__
-
#endif // QTYPES_H
diff --git a/src/corelib/global/qversiontagging.h b/src/corelib/global/qversiontagging.h
index 4e0eb68bbd..965d53e88f 100644
--- a/src/corelib/global/qversiontagging.h
+++ b/src/corelib/global/qversiontagging.h
@@ -1,12 +1,18 @@
// Copyright (C) 2022 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-// qglobal.h includes this header, so keep it outside of our include guards
-#include <QtCore/qglobal.h>
-
#if !defined(QVERSIONTAGGING_H)
#define QVERSIONTAGGING_H
+#if 0
+#pragma qt_no_master_include
+#endif
+
+#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qtversionchecks.h>
+#include <QtCore/qtypes.h>
+
QT_BEGIN_NAMESPACE
/*
@@ -73,7 +79,7 @@ struct QVersionTag
};
}
-#if defined(QT_BUILD_CORE_LIB) || defined(QT_BOOTSTRAPPED) || defined(QT_STATIC)
+#if !defined(QT_NO_VERSION_TAGGING) && (defined(QT_BUILD_CORE_LIB) || defined(QT_BOOTSTRAPPED) || defined(QT_STATIC))
// don't make tags in QtCore, bootstrapped systems or if the user asked not to
# define QT_NO_VERSION_TAGGING
#endif
@@ -86,7 +92,7 @@ struct QVersionTag
// Calling convention on other architectures does not prepend a _
# define QT_MANGLE_IMPORT_PREFIX __imp_
# endif
-# ifdef Q_CC_MSVC
+# if defined(Q_CC_MSVC_ONLY)
# pragma section(".qtversion",read,shared)
# define QT_VERSION_TAG_SECTION __declspec(allocate(".qtversion"))
# define QT_VERSION_TAG_ATTRIBUTE __declspec(selectany) extern const
diff --git a/src/corelib/global/qxpfunctional.h b/src/corelib/global/qxpfunctional.h
index 67350c56ed..cbeef8b293 100644
--- a/src/corelib/global/qxpfunctional.h
+++ b/src/corelib/global/qxpfunctional.h
@@ -9,9 +9,9 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. Types and functions defined
-// in this file will behave exactly as their std counterparts. You
-// may use these definitions in your own code, but be aware that we
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
// will remove them once Qt depends on the C++ version that supports
// them in namespace std. There will be NO deprecation warning, the
// definitions will JUST go away.
@@ -22,7 +22,7 @@
//
#include <QtCore/q23functional.h>
-#include <type_traits>
+#include <QtCore/q20type_traits.h>
#include <utility>
QT_BEGIN_NAMESPACE
@@ -108,6 +108,23 @@ public:
class F,
std::enable_if_t<std::conjunction_v<
std::negation<std::is_same<q20::remove_cvref_t<F>, function_ref_base>>,
+#ifdef Q_OS_VXWORKS
+ // The VxWorks compiler is trying to match this ctor against
+ // qxp::function_ref in lieu of using the copy-constructor, so ban
+ // matching against the equivalent qxp::function_ref here.
+ // This doesn't change anything on other platforms, so to save
+ // on compile-speed, enable it only for VxWorks:
+ std::negation<
+ std::is_same<
+ q20::remove_cvref_t<F>,
+ std::conditional_t<
+ std::is_const_v<Const>,
+ qxp::function_ref<R(ArgTypes...) const noexcept(noex)>,
+ qxp::function_ref<R(ArgTypes...) noexcept(noex)>
+ >
+ >
+ >,
+#endif // Q_OS_VXWORKS
std::negation<std::is_member_pointer<std::remove_reference_t<F>>>,
is_invocable_using<copy_const_t<Const, std::remove_reference_t<F>>&>
>, bool> = true
@@ -124,9 +141,11 @@ public:
protected:
template <
class T,
- std::enable_if_t<std::conjunction_v<
- std::negation<std::is_same<q20::remove_cvref_t<T>, function_ref_base>>,
- std::negation<std::is_pointer<T>>
+ std::enable_if_t<std::negation_v<
+ std::disjunction<
+ std::is_same<T, function_ref_base>,
+ std::is_pointer<T>
+ >
>, bool> = true
>
function_ref_base& operator=(T) = delete;
@@ -165,7 +184,7 @@ QT_SPECIALIZE_FUNCTION_REF(const, true );
template <
class F,
- std::enable_if_t<std::is_function_v<F>, bool> = true
+ detail::if_function<F> = true
>
function_ref(F*) -> function_ref<F>;
diff --git a/src/corelib/global/qxptype_traits.h b/src/corelib/global/qxptype_traits.h
new file mode 100644
index 0000000000..d1641e1d0d
--- /dev/null
+++ b/src/corelib/global/qxptype_traits.h
@@ -0,0 +1,121 @@
+// Copyright (C) 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>, Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
+// 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
+
+#ifndef QXPTYPE_TRAITS_H
+#define QXPTYPE_TRAITS_H
+
+#include <QtCore/qtconfigmacros.h>
+#include <QtCore/qcompilerdetection.h>
+
+#include <type_traits>
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. Types and functions defined in this
+// file can reliably be replaced by their std counterparts, once available.
+// You may use these definitions in your own code, but be aware that we
+// will remove them once Qt depends on the C++ version that supports
+// them in namespace std. There will be NO deprecation warning, the
+// definitions will JUST go away.
+//
+// If you can't agree to these terms, don't use these definitions!
+//
+// We mean it.
+//
+
+QT_BEGIN_NAMESPACE
+
+// like std::experimental::{nonesuch,is_detected/_v}(LFTSv2)
+namespace qxp {
+
+struct nonesuch {
+ ~nonesuch() = delete;
+ nonesuch(const nonesuch&) = delete;
+ void operator=(const nonesuch&) = delete;
+};
+
+namespace _detail {
+ template <typename T, typename Void, template <typename...> class Op, typename...Args>
+ struct detector {
+ using value_t = std::false_type;
+ using type = T;
+ };
+ template <typename T, template <typename...> class Op, typename...Args>
+ struct detector<T, std::void_t<Op<Args...>>, Op, Args...> {
+ using value_t = std::true_type;
+ using type = Op<Args...>;
+ };
+} // namespace _detail
+
+template <template <typename...> class Op, typename...Args>
+using is_detected = typename _detail::detector<qxp::nonesuch, void, Op, Args...>::value_t;
+
+template <template <typename...> class Op, typename...Args>
+constexpr inline bool is_detected_v = is_detected<Op, Args...>::value;
+
+
+// qxp::is_virtual_base_of_v<B, D> is true if and only if B is a virtual base class of D.
+// Just like is_base_of:
+// * only works on complete types;
+// * B and D must be class types;
+// * ignores cv-qualifications;
+// * B may be inaccessibile.
+
+namespace _detail {
+ // Check that From* can be converted to To*, ignoring accessibility.
+ // This can be done using a C cast (see [expr.cast]/4).
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wold-style-cast")
+QT_WARNING_DISABLE_CLANG("-Wold-style-cast")
+ template <typename From, typename To>
+ using is_virtual_base_conversion_test = decltype(
+ (To *)std::declval<From *>()
+ );
+QT_WARNING_POP
+
+ template <typename Base, typename Derived, typename = void>
+ struct is_virtual_base_of : std::false_type {};
+
+ template <typename Base, typename Derived>
+ struct is_virtual_base_of<
+ Base, Derived,
+ std::enable_if_t<
+ std::conjunction_v<
+ // Base is a base class of Derived.
+ std::is_base_of<Base, Derived>,
+
+ // Check that Derived* can be converted to Base*, ignoring
+ // accessibility. If this is possible, then Base is
+ // an unambiguous base of Derived (=> virtual bases are always
+ // unambiguous).
+ qxp::is_detected<is_virtual_base_conversion_test, Derived, Base>,
+
+ // Check that Base* can _not_ be converted to Derived*,
+ // again ignoring accessibility. This seals the deal:
+ // if this conversion cannot happen, it means that Base is an
+ // ambiguous base and/or it is a virtual base.
+ // But we have already established that Base is an unambiguous
+ // base, hence: Base is a virtual base.
+ std::negation<
+ qxp::is_detected<is_virtual_base_conversion_test, Base, Derived>
+ >
+ >
+ >
+ > : std::true_type {};
+}
+
+template <typename Base, typename Derived>
+using is_virtual_base_of = _detail::is_virtual_base_of<std::remove_cv_t<Base>, std::remove_cv_t<Derived>>;
+
+template <typename Base, typename Derived>
+constexpr inline bool is_virtual_base_of_v = is_virtual_base_of<Base, Derived>::value;
+
+} // namespace qxp
+
+QT_END_NAMESPACE
+
+#endif // QXPTYPE_TRAITS_H
+