fix-gcc16-sfinae-qchar.patch raw

   1  From 05f201a3d559452287b20becb960de3a50249540 Mon Sep 17 00:00:00 2001
   2  From: Giuseppe D'Angelo <giuseppe.dangelo@kdab.com>
   3  Date: Wed, 4 Feb 2026 12:12:37 +0100
   4  Subject: [PATCH] Move QChar::fromUcs4 into qchar.h
   5  
   6  Right now fromUcs4 lives in qstringview.h because the return type has an
   7  implicit conversion operator towards QStringView. This however creates
   8  an inclusion loop: qchar.h includes qstringview.h, and qstringview.h
   9  includes qchar.h. Only the latter should exist.
  10  
  11  We can move the code back into qchar.h and drop the QStringView
  12  dependency by making the type returned from fromUcs4 have data(). That
  13  would make it a string-like range and become implicitly convertible to
  14  QStringView through its ranged constructor.
  15  
  16  In fact, add a test that checks for the *implicit* conversion; and
  17  add a test that checks for a conversion towards std::u16string_view.
  18  
  19  QMetaType was calling the conversion operator from the return type of
  20  fromUcs4 to QStringView directly (...Hyrum law...), although we never
  21  documented the presence of that operator, only that the conversion was
  22  possible; fix it by using a conversion.
  23  
  24  Fixes: QTBUG-143873
  25  Task-number: QTBUG-143470
  26  Change-Id: Id07657dd411cc2e1446fb18789e04db9cecd8ae0
  27  Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
  28  Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
  29  ---
  30   src/corelib/kernel/qmetatype.cpp            |  2 +-
  31   src/corelib/text/qchar.h                    | 16 +++++++++++++---
  32   src/corelib/text/qstringview.h              | 16 ----------------
  33   tests/auto/corelib/text/qchar/tst_qchar.cpp | 10 ++++++++++
  34   4 files changed, 24 insertions(+), 20 deletions(-)
  35  
  36  diff --git a/qtbase/src/corelib/kernel/qmetatype.cpp b/qtbase/src/corelib/kernel/qmetatype.cpp
  37  index e70583404a46..54a0fe671fe0 100644
  38  --- a/qtbase/src/corelib/kernel/qmetatype.cpp
  39  +++ b/qtbase/src/corelib/kernel/qmetatype.cpp
  40  @@ -1212,7 +1212,7 @@ QT_WARNING_DISABLE_CLANG("-Wtautological-compare")
  41               return true;
  42           );
  43           QMETATYPE_CONVERTER(QString, Char32,
  44  -            result = QChar::fromUcs4(source).operator QStringView().toString();
  45  +            result = QStringView(QChar::fromUcs4(source)).toString();
  46               return true;
  47           );
  48   #if QT_CONFIG(datestring)
  49  diff --git a/qtbase/src/corelib/text/qchar.h b/qtbase/src/corelib/text/qchar.h
  50  index 4a3aad0ca0c1..f96ca590f2e2 100644
  51  --- a/qtbase/src/corelib/text/qchar.h
  52  +++ b/qtbase/src/corelib/text/qchar.h
  53  @@ -88,7 +88,19 @@ class QT6_ONLY(Q_CORE_EXPORT) QChar {
  54   #endif
  55  
  56       static constexpr QChar fromUcs2(char16_t c) noexcept { return QChar{c}; }
  57  -    static constexpr inline auto fromUcs4(char32_t c) noexcept;
  58  +    [[nodiscard]] static constexpr inline auto fromUcs4(char32_t c) noexcept
  59  +    {
  60  +        struct R {
  61  +            char16_t chars[2];
  62  +            [[nodiscard]] constexpr qsizetype size() const noexcept { return chars[1] ? 2 : 1; }
  63  +            [[nodiscard]] constexpr const char16_t *data() const noexcept { return chars; }
  64  +            [[nodiscard]] constexpr const char16_t *begin() const noexcept { return chars; }
  65  +            [[nodiscard]] constexpr const char16_t *end() const noexcept { return begin() + size(); }
  66  +        };
  67  +        return requiresSurrogates(c) ? R{{QChar::highSurrogate(c),
  68  +                                          QChar::lowSurrogate(c)}} :
  69  +                                       R{{char16_t(c), u'\0'}} ;
  70  +    }
  71  
  72       // Unicode information
  73  
  74  @@ -666,5 +678,3 @@ struct hash<QT_PREPEND_NAMESPACE(QChar)>
  75   } // namespace std
  76  
  77   #endif // QCHAR_H
  78  -
  79  -#include <QtCore/qstringview.h> // for QChar::fromUcs4() definition
  80  diff --git a/qtbase/src/corelib/text/qstringview.h b/qtbase/src/corelib/text/qstringview.h
  81  index 6d5edfc06d7d..d5897af6da2d 100644
  82  --- a/qtbase/src/corelib/text/qstringview.h
  83  +++ b/qtbase/src/corelib/text/qstringview.h
  84  @@ -472,22 +472,6 @@ template <typename QStringLike, typename std::enable_if<
  85   inline QStringView qToStringViewIgnoringNull(const QStringLike &s) noexcept
  86   { return QStringView(s.begin(), s.size()); }
  87  
  88  -// QChar inline functions:
  89  -
  90  -[[nodiscard]] constexpr auto QChar::fromUcs4(char32_t c) noexcept
  91  -{
  92  -    struct R {
  93  -        char16_t chars[2];
  94  -        [[nodiscard]] constexpr operator QStringView() const noexcept { return {begin(), end()}; }
  95  -        [[nodiscard]] constexpr qsizetype size() const noexcept { return chars[1] ? 2 : 1; }
  96  -        [[nodiscard]] constexpr const char16_t *begin() const noexcept { return chars; }
  97  -        [[nodiscard]] constexpr const char16_t *end() const noexcept { return begin() + size(); }
  98  -    };
  99  -    return requiresSurrogates(c) ? R{{QChar::highSurrogate(c),
 100  -                                      QChar::lowSurrogate(c)}} :
 101  -                                   R{{char16_t(c), u'\0'}} ;
 102  -}
 103  -
 104   qsizetype QtPrivate::findString(QStringView str, qsizetype from, QChar ch, Qt::CaseSensitivity cs) noexcept
 105   {
 106       if (from < -str.size()) // from < 0 && abs(from) > str.size(), avoiding overflow
 107  diff --git a/qtbase/tests/auto/corelib/text/qchar/tst_qchar.cpp b/qtbase/tests/auto/corelib/text/qchar/tst_qchar.cpp
 108  index 6701f0e33f3d..5781d36e458b 100644
 109  --- a/qtbase/tests/auto/corelib/text/qchar/tst_qchar.cpp
 110  +++ b/qtbase/tests/auto/corelib/text/qchar/tst_qchar.cpp
 111  @@ -142,10 +142,20 @@ void tst_QChar::fromUcs4()
 112           QCOMPARE(result.chars[0], QChar::highSurrogate(ucs4));
 113           QCOMPARE(result.chars[1], QChar::lowSurrogate(ucs4));
 114           QCOMPARE(QStringView{result}.size(), 2);
 115  +        QStringView v = result;
 116  +        QCOMPARE(v.size(), 2);
 117  +#if __cplusplus >= 202302L // no FTM for the ranged constructor of basic_string_view
 118  +        QCOMPARE(std::u16string_view{result}.size(), 2);
 119  +#endif
 120       } else {
 121           QCOMPARE(result.chars[0], ucs4);
 122           QCOMPARE(result.chars[1], 0u);
 123           QCOMPARE(QStringView{result}.size(), 1);
 124  +        QStringView v = result;
 125  +        QCOMPARE(v.size(), 1);
 126  +#if __cplusplus >= 202302L // no FTM for the ranged constructor of basic_string_view
 127  +        QCOMPARE(std::u16string_view{result}.size(), 1);
 128  +#endif
 129       }
 130   }
 131  
 132