From 56faffd92bf0ac459a921ec043a6f3b3dba51acc Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 25 Apr 2023 23:35:37 +0200 Subject: [PATCH] QStringView: fix construction from arrays of unknown size The original idea (8b5aa7b6c40d70a7ec15b3ea485f28a142fb247c) of the separation of array and pointer ctors was to determine string literal sizes at compile-time in C++11's limited constexpr semantics. But when the scanning for NUL characters was added to the array ctor in 107ff4c1d6b5da2cb11c65b2bd9106817f7fdb02, the distinction between the two ctors became meaningless, because we were able to assume post-C++11 constexpr to make the Char(0) scan a compile-time action. Finally, 9e1dc1e8a9fda1a7576cc6377c8a36decff631eb removed the array ctor in favor of the generic Container ctor. I didn't check whether the old code handled arrays of unknown size, as in extern const char16_t str[]; QStringView sv = str; ~~~ const char16_t str[] = "str"; but std::size() (and therefore if_compatible_container) surely bails on such arrays, and if_compatible_pointer also SFINAEs out. As a consequence, such arrays cannot be used to construct QStringViews atm. Fix by adding a new constructor for arrays of unknown size, delegating to the existing pointer overload. The GHS compiler doesn't like the CanConvert static_asserts, so comment them out for it. The functionality itself is tested by the from*ArrayWithUnknownSize tests. [ChangeLog][QtCore][QStringView] Made construction from arrays of unknown size compile. Such arrays will use the const Char* constructor, determining the size of the array at runtime. Pick-to: 6.9 6.8 6.5 Task-number: QTBUG-112746 Change-Id: Ifdb217350d93d38f081c99f14661975491d32076 Reviewed-by: Thiago Macieira --- src/corelib/text/qstringview.h | 5 +++- .../corelib/text/qstringview/CMakeLists.txt | 1 + .../qstringview/arrays_of_unknown_bounds.cpp | 9 +++++++ .../qstringview/arrays_of_unknown_bounds.h | 25 +++++++++++++++++++ .../text/qstringview/tst_qstringview.cpp | 24 ++++++++++++++++++ 5 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 tests/auto/corelib/text/qstringview/arrays_of_unknown_bounds.cpp create mode 100644 tests/auto/corelib/text/qstringview/arrays_of_unknown_bounds.h diff --git a/src/corelib/text/qstringview.h b/src/corelib/text/qstringview.h index dfcd0e1c1fa..3dcfa3771ab 100644 --- a/src/corelib/text/qstringview.h +++ b/src/corelib/text/qstringview.h @@ -150,10 +150,13 @@ public: template constexpr QStringView(const Char *str) noexcept; #else - template = true> constexpr QStringView(const Pointer &str) noexcept : QStringView(str, str ? lengthHelperPointer(str) : 0) {} + + template = true> + constexpr QStringView(const Char (&str)[]) noexcept // array of unknown bounds + : QStringView{&*str} {} // decay to pointer #endif #ifdef Q_QDOC diff --git a/tests/auto/corelib/text/qstringview/CMakeLists.txt b/tests/auto/corelib/text/qstringview/CMakeLists.txt index b541cdd0edb..3e02d2ec05c 100644 --- a/tests/auto/corelib/text/qstringview/CMakeLists.txt +++ b/tests/auto/corelib/text/qstringview/CMakeLists.txt @@ -14,6 +14,7 @@ endif() qt_internal_add_test(tst_qstringview SOURCES tst_qstringview.cpp + arrays_of_unknown_bounds.cpp arrays_of_unknown_bounds.h LIBRARIES Qt::CorePrivate ) diff --git a/tests/auto/corelib/text/qstringview/arrays_of_unknown_bounds.cpp b/tests/auto/corelib/text/qstringview/arrays_of_unknown_bounds.cpp new file mode 100644 index 00000000000..3f53504a4aa --- /dev/null +++ b/tests/auto/corelib/text/qstringview/arrays_of_unknown_bounds.cpp @@ -0,0 +1,9 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "arrays_of_unknown_bounds.h" + +const char16_t u16string_array[] = u"abc\0def"; +const int u16string_array_size = 3; +const wchar_t wstring_array[] = L"abc\0def"; +const int wstring_array_size = 3; diff --git a/tests/auto/corelib/text/qstringview/arrays_of_unknown_bounds.h b/tests/auto/corelib/text/qstringview/arrays_of_unknown_bounds.h new file mode 100644 index 00000000000..1198b1048fb --- /dev/null +++ b/tests/auto/corelib/text/qstringview/arrays_of_unknown_bounds.h @@ -0,0 +1,25 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#pragma once + +#include + +extern const char16_t u16string_array[]; +extern const int u16string_array_size; +extern const wchar_t wstring_array[]; +extern const int wstring_array_size; + +template +void from_u16array_of_unknown_size() +{ + StringView sv = u16string_array; + QCOMPARE(sv.size(), u16string_array_size); +} + +template +void from_warray_of_unknown_size() +{ + StringView sv = wstring_array; + QCOMPARE(sv.size(), wstring_array_size); +} diff --git a/tests/auto/corelib/text/qstringview/tst_qstringview.cpp b/tests/auto/corelib/text/qstringview/tst_qstringview.cpp index 1121de787c1..208ae99ca3c 100644 --- a/tests/auto/corelib/text/qstringview/tst_qstringview.cpp +++ b/tests/auto/corelib/text/qstringview/tst_qstringview.cpp @@ -1,6 +1,8 @@ // Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include "arrays_of_unknown_bounds.h" + #include #include #include @@ -45,6 +47,9 @@ static_assert(!CanConvert::value); static_assert(!CanConvert::value); static_assert(CanConvert::value); +#ifndef Q_OS_INTEGRITY // ¯\_(ツ)_/¯ +static_assert(CanConvert::value); +#endif static_assert(CanConvert< QString >::value); static_assert(CanConvert::value); @@ -58,6 +63,9 @@ static_assert(CanConvert::value); static_assert(!CanConvert::value); static_assert(CanConvert::value); +#ifndef Q_OS_INTEGRITY // ¯\_(ツ)_/¯ +static_assert(CanConvert::value); +#endif static_assert(CanConvert< ushort*>::value); static_assert(CanConvert::value); @@ -76,6 +84,9 @@ static_assert(!CanConvert>::value); static_assert(!CanConvert::value); static_assert(CanConvert::value); +#ifndef Q_OS_INTEGRITY // ¯\_(ツ)_/¯ +static_assert(CanConvert::value); +#endif static_assert(CanConvert< char16_t*>::value); static_assert(CanConvert::value); @@ -114,6 +125,9 @@ constexpr bool CanConvertFromWCharT = static_assert(!CanConvert::value); static_assert(CanConvert::value == CanConvertFromWCharT); +#ifndef Q_OS_INTEGRITY // ¯\_(ツ)_/¯ +static_assert(CanConvert::value == CanConvertFromWCharT); +#endif static_assert(CanConvert< wchar_t*>::value == CanConvertFromWCharT); static_assert(CanConvert::value == CanConvertFromWCharT); @@ -189,6 +203,16 @@ private Q_SLOTS: #endif } + void fromChar16TArrayWithUnknownSize() { from_u16array_of_unknown_size(); } + void fromWCharTArrayWithUnknownSize() + { +#ifdef Q_OS_WIN + from_warray_of_unknown_size(); +#else + QSKIP("This is a Windows-only test"); +#endif + } + void fromQCharRange() const { const QChar str[] = { 'H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!' };