summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarc Mutz <marc.mutz@qt.io>2023-02-16 13:39:38 +0100
committerMarc Mutz <marc.mutz@qt.io>2023-12-07 06:16:23 +0100
commit3c0fdd7341ed4bff9b5f041e9f4646265d142303 (patch)
tree5a90e34d7692ea72203670dc52bae39ef016bda5
parent5f775e671973b1549a48ae8c69c5db7494f6a6d3 (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.cpp90
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
{