From b268b4b3d4394e860b2679c90278b8c836d60dfa Mon Sep 17 00:00:00 2001 From: Cory Fields Date: Thu, 12 Feb 2026 18:30:47 +0000 Subject: [PATCH] qt: add patch to fix build with gcc16 Backported from: https://github.com/qt/qtbase/commit/7fccc79dd5744ea837ffe200bbfc9f2756870220 Github-Pull: #34650 Rebased-From: d7e972a90d59bbf705bd06f5d2606cccd1dcdcf9 --- depends/packages/qt.mk | 4 +- depends/patches/qt/fix-gcc16-qcompare.patch | 206 ++++++++++++++++++++ 2 files changed, 209 insertions(+), 1 deletion(-) create mode 100644 depends/patches/qt/fix-gcc16-qcompare.patch diff --git a/depends/packages/qt.mk b/depends/packages/qt.mk index 608e8cdbff0..efe58f4ab18 100644 --- a/depends/packages/qt.mk +++ b/depends/packages/qt.mk @@ -20,6 +20,7 @@ $(package)_patches += qtbase_plugins_windows11style.patch $(package)_patches += qtbase_skip_tools.patch $(package)_patches += rcc_hardcode_timestamp.patch $(package)_patches += qttools_skip_dependencies.patch +$(package)_patches += fix-gcc16-qcompare.patch $(package)_qttranslations_file_name=$(qt_details_qttranslations_file_name) $(package)_qttranslations_sha256_hash=$(qt_details_qttranslations_sha256_hash) @@ -264,7 +265,8 @@ define $(package)_preprocess_cmds patch -p1 -i $($(package)_patch_dir)/qtbase_plugins_cocoa.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase_plugins_windows11style.patch && \ patch -p1 -i $($(package)_patch_dir)/qtbase_skip_tools.patch && \ - patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch + patch -p1 -i $($(package)_patch_dir)/rcc_hardcode_timestamp.patch && \ + patch -p1 -i $($(package)_patch_dir)/fix-gcc16-qcompare.patch endef ifeq ($(host),$(build)) $(package)_preprocess_cmds += && patch -p1 -i $($(package)_patch_dir)/qttools_skip_dependencies.patch diff --git a/depends/patches/qt/fix-gcc16-qcompare.patch b/depends/patches/qt/fix-gcc16-qcompare.patch new file mode 100644 index 00000000000..3eb826b3dc6 --- /dev/null +++ b/depends/patches/qt/fix-gcc16-qcompare.patch @@ -0,0 +1,206 @@ +From 7fccc79dd5744ea837ffe200bbfc9f2756870220 Mon Sep 17 00:00:00 2001 +From: Thiago Macieira +Date: Wed, 14 Jan 2026 08:57:22 -0800 +Subject: [PATCH] QtCompare: adapt to GCC 16 breaking ABI for + std::partial_ordering + +They changed[1] the stored value of the unordered constant from 2 to +-SCHAR_MAX-1 (0x80). This commit hardens the check for all three +std::*_ordering types and in all compilers, even though only the +unordered value has been observed to be a problem. + +For: + + std::partial_ordering f(Qt::partial_ordering o) { return o; } + +With GCC < 16, this remains a plain bitcast. For GCC >= 16, this now +generates: + cmpb $2, %dil + movl $-128, %eax + cmovne %edi, %eax + +Hopefully, when this is used in context, the comparisons will be elided +through constant propagation. + +[1] https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=fcb3009a32dc33906934a2360e556dfeb98980cf + +Pick-to: 6.11 6.10 6.8 6.5 +Change-Id: I04bc40f0aeef5c0c778dfffdaea0bf68c5719462 +Reviewed-by: Volker Hilsheimer +Reviewed-by: Edward Welbourne +--- + src/corelib/global/qcompare.cpp | 2 + + src/corelib/global/qcompare.h | 60 ++++++++++++++----- + .../corelib/global/qcompare/tst_qcompare.cpp | 2 + + 3 files changed, 50 insertions(+), 14 deletions(-) + +diff --git a/qtbase/src/corelib/global/qcompare.cpp b/qtbase/src/corelib/global/qcompare.cpp +index 8106a84ddcd7..7f7facafbb87 100644 +--- a/qtbase/src/corelib/global/qcompare.cpp ++++ b/qtbase/src/corelib/global/qcompare.cpp +@@ -18,7 +18,9 @@ QT_BEGIN_NAMESPACE + static_assert(std::bit_cast(Qt:: type ## _ordering:: flag) \ + == std:: type ## _ordering :: flag) \ + /* end */ ++#if !defined(__GLIBCXX__) + CHECK(partial, unordered); ++#endif + CHECK(partial, less); + CHECK(partial, greater); + CHECK(partial, equivalent); +diff --git a/qtbase/src/corelib/global/qcompare.h b/qtbase/src/corelib/global/qcompare.h +index d82cf5ab4a4e..7eee69db66a3 100644 +--- a/qtbase/src/corelib/global/qcompare.h ++++ b/qtbase/src/corelib/global/qcompare.h +@@ -35,6 +35,15 @@ enum class Ordering : CompareUnderlyingType + + enum class Uncomparable : CompareUnderlyingType + { ++ // We choose the value of our Uncomparable to be the same that the C++ ++ // Standard Library chooses for its own std::partial_ordering::unordered, ++ // so we can convert from their type to ours via simple std::bit_cast. ++#if 0 ++ // GCC 16 broke ABI, so we cannot use the std::*_ordering types ++ // in our ABI until we drop support for GCC 15 and earlier. When that ++ // happens and std::bit_cast is guaranteed, this can be simplified to: ++ Unordered = std::bit_cast(std::partial_ordering::unordered); ++#else + Unordered = + #if defined(_LIBCPP_VERSION) // libc++ + -127 +@@ -43,12 +52,25 @@ enum class Uncomparable : CompareUnderlyingType + #else // assume MSSTL + -128 + #endif ++#endif // future Qt + }; +- + } // namespace QtPrivate + + namespace QtOrderingPrivate { + ++using QtPrivate::Ordering; ++using QtPrivate::Uncomparable; ++ ++#if defined(__cpp_lib_bit_cast) && defined(__cpp_lib_three_way_comparison) ++inline constexpr bool OrderingValuesAreEqual = ++ std::bit_cast(std::weak_ordering::equivalent) == Ordering::Equivalent && ++ std::bit_cast(std::strong_ordering::equal) == Ordering::Equal && ++ std::bit_cast(std::strong_ordering::less) == Ordering::Less && ++ std::bit_cast(std::strong_ordering::greater) == Ordering::Greater; ++inline constexpr bool UnorderedValueIsEqual = ++ std::bit_cast(std::partial_ordering::unordered) == Uncomparable::Unordered; ++#endif ++ + template + constexpr O reversed(O o) noexcept + { +@@ -60,6 +82,9 @@ constexpr O reversed(O o) noexcept + + } // namespace QtOrderingPrivate + ++QT_WARNING_PUSH ++QT_WARNING_DISABLE_MSVC(4702) // unreachable code ++ + namespace Qt { + + class weak_ordering; +@@ -156,12 +181,18 @@ class partial_ordering + 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(*this); +-#else + using O = QtPrivate::Ordering; + using U = QtPrivate::Uncomparable; + using R = std::partial_ordering; ++#ifdef __cpp_lib_bit_cast ++ if constexpr (QtOrderingPrivate::OrderingValuesAreEqual) { ++ if constexpr (!QtOrderingPrivate::UnorderedValueIsEqual) { ++ if (m_order == qToUnderlying(U::Unordered)) ++ return R::unordered; ++ } ++ return std::bit_cast(*this); ++ } ++#endif // __cpp_lib_bit_cast + switch (m_order) { + case qToUnderlying(O::Less): return R::less; + case qToUnderlying(O::Greater): return R::greater; +@@ -169,7 +200,6 @@ class partial_ordering + 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 +@@ -347,18 +377,18 @@ class weak_ordering + 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(*this); +-#else + using O = QtPrivate::Ordering; + using R = std::weak_ordering; ++#ifdef __cpp_lib_bit_cast ++ if constexpr (QtOrderingPrivate::OrderingValuesAreEqual) ++ return std::bit_cast(*this); ++#endif // __cpp_lib_bit_cast + 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 +@@ -544,18 +574,18 @@ class strong_ordering + 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(*this); +-#else + using O = QtPrivate::Ordering; + using R = std::strong_ordering; ++#ifdef __cpp_lib_bit_cast ++ if constexpr (QtOrderingPrivate::OrderingValuesAreEqual) ++ return std::bit_cast(*this); ++#endif // __cpp_lib_bit_cast + 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 +@@ -621,6 +651,8 @@ inline constexpr strong_ordering strong_ordering::greater(QtPrivate::Ordering::G + + } // namespace Qt + ++QT_WARNING_POP ++ + QT_BEGIN_INCLUDE_NAMESPACE + + // This is intentionally included after Qt::*_ordering types and before +diff --git a/qtbase/tests/auto/corelib/global/qcompare/tst_qcompare.cpp b/qtbase/tests/auto/corelib/global/qcompare/tst_qcompare.cpp +index b79a6661db33..ff5920134cc8 100644 +--- a/qtbase/tests/auto/corelib/global/qcompare/tst_qcompare.cpp ++++ b/qtbase/tests/auto/corelib/global/qcompare/tst_qcompare.cpp +@@ -185,7 +185,9 @@ void tst_QCompare::stdQtBinaryCompatibility() + QCOMPARE_EQ(valueOf( Qt:: type ## _ordering :: flag), \ + valueOf(std:: type ## _ordering :: flag)) \ + /* end */ ++# if !defined(__GLIBCXX__) || QT_VERSION >= QT_VERSION_CHECK(7, 0, 0) + CHECK(partial, unordered); ++# endif + CHECK(partial, less); + CHECK(partial, greater); + CHECK(partial, equivalent);