diff options
author | Marc Mutz <marc.mutz@qt.io> | 2023-02-16 13:39:38 +0100 |
---|---|---|
committer | Marc Mutz <marc.mutz@qt.io> | 2023-12-07 06:16:23 +0100 |
commit | 3c0fdd7341ed4bff9b5f041e9f4646265d142303 (patch) | |
tree | 5a90e34d7692ea72203670dc52bae39ef016bda5 | |
parent | 5f775e671973b1549a48ae8c69c5db7494f6a6d3 (diff) |
tst_ContainerApiSymmetry: check value_types with a const member
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.6 6.5
Change-Id: I26e11c4a100695c604cebcf7e14a1ae5078d9ec7
Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r-- | tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp index bac6745607..05d8dac126 100644 --- a/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp +++ b/tests/auto/corelib/tools/containerapisymmetry/tst_containerapisymmetry.cpp @@ -329,6 +329,26 @@ private Q_SLOTS: private: template <typename Container> + 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<std::vector<ConstMember>>(); } + void copesWithValueTypesWithConstMembers_QVarLengthArray() { copesWithValueTypesWithConstMembers_impl<QVarLengthArray<ConstMember, 2>>(); } + +private: + template <typename Container> void assign_impl() const; private Q_SLOTS: @@ -760,6 +780,76 @@ void tst_ContainerApiSymmetry::resize_impl() const } } +template <typename T> +constexpr bool is_vector_v = false; +template <typename...Args> +constexpr bool is_vector_v<std::vector<Args...>> = true; + +template <typename Container> +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<Container>) { + 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<Container>) { + 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 <typename Container> void tst_ContainerApiSymmetry::assign_impl() const { |