Fix QAnyStringView build with GCC 13

The problem is caused by GCC 13 having an intrinsic for is_convertible,
and that (correctly) checks for incomplete types. We then manage to
trigger the instantiation of the QAnyStringView converting constructor from isUtf16 etc.,
and that triggers the enable_if and is_convertible. The fix is to move
the Tag definition earlier, and to eagerly SFINAE away the Tag type so
that the converting constructor rejects it. Otherwise, the converting
constructor is considered a candidate for comparisons of Tags, and gets
instantiated for overload resolution.

Fixes: QTBUG-108136
Change-Id: I9b0c0f7ac771cdbf6a9c35a3d3b0ea01b88b970e
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
bb10
Ville Voutilainen 2022-11-11 04:53:36 +02:00
parent 2fd4d0586f
commit 8a11f16dc0
1 changed files with 24 additions and 22 deletions

View File

@ -33,6 +33,29 @@ public:
typedef qptrdiff difference_type;
typedef qsizetype size_type;
private:
// TODO: Optimize by inverting and storing the flags in the low bits and
// the size in the high.
static_assert(std::is_same_v<std::size_t, size_t>);
static_assert(sizeof(size_t) == sizeof(qsizetype));
static constexpr size_t SizeMask = (std::numeric_limits<size_t>::max)() / 4;
static constexpr size_t Latin1Flag = SizeMask + 1;
static constexpr size_t TwoByteCodePointFlag = Latin1Flag << 1;
static constexpr size_t TypeMask = (std::numeric_limits<size_t>::max)() & ~SizeMask;
static_assert(TypeMask == (Latin1Flag|TwoByteCodePointFlag));
// HI HI LO LO ...
// 0 0 SZ SZ Utf8
// 0 1 SZ SZ Latin1
// 1 0 SZ SZ Utf16
// 1 1 SZ SZ Unused
// ^ ^ latin1
// | sizeof code-point == 2
enum Tag : size_t {
Utf8 = 0,
Latin1 = Latin1Flag,
Utf16 = TwoByteCodePointFlag,
Unused = TypeMask,
};
template <typename Char>
using if_compatible_char = std::enable_if_t<std::disjunction_v<
QtPrivate::IsCompatibleCharType<Char>,
@ -56,6 +79,7 @@ private:
using if_convertible_to = std::enable_if_t<std::conjunction_v<
// need to exclude a bunch of stuff, because we take by universal reference:
std::negation<std::disjunction<
std::is_same<q20::remove_cvref_t<T>, QAnyStringView::Tag>,
std::is_same<q20::remove_cvref_t<T>, QAnyStringView>, // don't make a copy/move ctor
std::is_pointer<std::decay_t<T>>, // const char*, etc
std::is_same<q20::remove_cvref_t<T>, QByteArray>,
@ -273,28 +297,6 @@ private:
{ return QAnyStringView::compare(lhs, rhs) > 0; }
#endif
// TODO: Optimize by inverting and storing the flags in the low bits and
// the size in the high.
static_assert(std::is_same_v<std::size_t, size_t>);
static_assert(sizeof(size_t) == sizeof(qsizetype));
static constexpr size_t SizeMask = (std::numeric_limits<size_t>::max)() / 4;
static constexpr size_t Latin1Flag = SizeMask + 1;
static constexpr size_t TwoByteCodePointFlag = Latin1Flag << 1;
static constexpr size_t TypeMask = (std::numeric_limits<size_t>::max)() & ~SizeMask;
static_assert(TypeMask == (Latin1Flag|TwoByteCodePointFlag));
// HI HI LO LO ...
// 0 0 SZ SZ Utf8
// 0 1 SZ SZ Latin1
// 1 0 SZ SZ Utf16
// 1 1 SZ SZ Unused
// ^ ^ latin1
// | sizeof code-point == 2
enum Tag : size_t {
Utf8 = 0,
Latin1 = Latin1Flag,
Utf16 = TwoByteCodePointFlag,
Unused = TypeMask,
};
[[nodiscard]] constexpr Tag tag() const noexcept { return Tag{m_size & TypeMask}; }
[[nodiscard]] constexpr bool isUtf16() const noexcept { return tag() == Tag::Utf16; }
[[nodiscard]] constexpr bool isUtf8() const noexcept { return tag() == Tag::Utf8; }