From 283ec1055b06fafb5e64a124c940515e40a64f7c Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Thu, 16 Feb 2023 13:39:38 +0100 Subject: [PATCH] tst_ContainerApiSymmetry: check value_types with a const member MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QVarLengthArray is the only Qt container currently known to be fine. std::vector is supposed to be fine, too, since C++14. Turns out that libstdc++ gets resize(n, v) wrong, though, because it never implemented the resolution to wg21.link/lwg2033. Known issue, linked in code comment. Worked around for the time being. Keeping std::vector in, though, because in this test suite we do cross-check with std::vector, and other platforms, and most of GCC's std::vector functions, adhere to the standard. Pick-to: 6.5 Change-Id: I26e11c4a100695c604cebcf7e14a1ae5078d9ec7 Reviewed-by: MÃ¥rten Nordheim (cherry picked from commit 3c0fdd7341ed4bff9b5f041e9f4646265d142303) Reviewed-by: Qt Cherry-pick Bot --- .../tst_containerapisymmetry.cpp | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp index d6839504452..33d3a5bfc6f 100644 --- a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp +++ b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp @@ -331,6 +331,26 @@ private Q_SLOTS: void resize_QString() { resize_impl(); } void resize_QByteArray() { resize_impl(); } +private: + template + void copesWithValueTypesWithConstMembers_impl(); + + struct ConstMember { + #ifndef __cpp_aggregate_paren_init // also check that we can emplace aggregates (C++20 only) + explicit ConstMember(int n) : n(n) {} + #endif + const int n; + + friend bool operator==(const ConstMember &lhs, const ConstMember &rhs) noexcept + { return lhs.n == rhs.n; } + friend bool operator!=(const ConstMember &lhs, const ConstMember &rhs) noexcept + { return !(lhs == rhs); } + }; + +private Q_SLOTS: + void copesWithValueTypesWithConstMembers_std_vector() { copesWithValueTypesWithConstMembers_impl>(); } + void copesWithValueTypesWithConstMembers_QVarLengthArray() { copesWithValueTypesWithConstMembers_impl>(); } + private: template void assign_impl() const; @@ -772,6 +792,76 @@ void tst_ContainerApiSymmetry::resize_impl() const } } +template +constexpr bool is_vector_v = false; +template +constexpr bool is_vector_v> = true; + +template +void tst_ContainerApiSymmetry::copesWithValueTypesWithConstMembers_impl() +{ + // The problem: + // + // using V = ConstMember; + // V v{42}; + // assert(v.n == 42); // OK + // new (&v) V{24}; + // assert(v.n == 24); // UB in C++17: v.n could still be 42 (C++17 [basic.life]/8) + // // OK in C++20 (C++20 [basic.life]/8) + // assert(std::launder(&v)->n == 24); // OK + // assert(v.n == 24); // _still_ UB! + // + // Containers: + // - must not expose this problem + // - must compile in the first place, even though V + // - is not assignable + // - is not default-constructible + + using S = typename Container::size_type; + using V = typename Container::value_type; + + Container c; + // the following are all functions that by rights should not require the type to be + // - default-constructible + // - assignable + // make sure they work + c.reserve(S(5)); + c.shrink_to_fit(); +#ifdef __GLIBCXX__ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981 + if constexpr (is_vector_v) { + c.push_back(V(42)); + } else +#endif + { + c.resize(1, V(42)); + } + QCOMPARE(c[0], V(42)); +#ifdef __GLIBCXX__ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83981 + if constexpr (is_vector_v) { + c.push_back(V(48)); + c.push_back(V(48)); + } else +#endif + { + c.resize(2, V(48)); + } + QCOMPARE(c[0], V(42)); + QCOMPARE(c[1], V(48)); + c.clear(); + c.emplace_back(24); + QCOMPARE(c.front(), V(24)); + c.push_back(V(41)); + QCOMPARE(c.back(), V(41)); + { + const auto v142 = V(142); + c.push_back(v142); + } + QCOMPARE(c.size(), S(3)); + QCOMPARE(c[0], V(24)); + QCOMPARE(c[1], V(41)); + QCOMPARE(c[2], V(142)); +} + template void tst_ContainerApiSymmetry::assign_impl() const {