From 5660ce600422e734aa40086efd58c1ab7815eb3e Mon Sep 17 00:00:00 2001 From: Marc Mutz Date: Tue, 10 Nov 2015 12:41:37 +0100 Subject: [PATCH] tst_compiler: check more cases for RVALUE_REFS Check that we can use std::forward, and that the compiler synthesizes move special member functions when it should. MSVC only supports the latter since the Nov 2013 CTP, which, for our intents and purposes, means VC2015. Change-Id: I8d8e4ae064abce90076a05b3b637950ab7d21dac Reviewed-by: Olivier Goffart (Woboq GmbH) --- tests/auto/other/compiler/tst_compiler.cpp | 84 +++++++++++++++++++--- 1 file changed, 74 insertions(+), 10 deletions(-) diff --git a/tests/auto/other/compiler/tst_compiler.cpp b/tests/auto/other/compiler/tst_compiler.cpp index 981206cc9e9..af0fa4682de 100644 --- a/tests/auto/other/compiler/tst_compiler.cpp +++ b/tests/auto/other/compiler/tst_compiler.cpp @@ -1128,24 +1128,88 @@ void tst_Compiler::cxx11_ref_qualifiers() #endif } +class MoveDefinedQString { + QString s; +public: + MoveDefinedQString() : s() {} + explicit MoveDefinedQString(const QString &s) : s(s) {} + MoveDefinedQString(const MoveDefinedQString &other) : s(other.s) {} +#ifdef Q_COMPILER_RVALUE_REFS + MoveDefinedQString(MoveDefinedQString &&other) : s(std::move(other.s)) { other.s.clear(); } + MoveDefinedQString &operator=(MoveDefinedQString &&other) + { s = std::move(other.s); other.s.clear(); return *this; } +#endif + MoveDefinedQString &operator=(const MoveDefinedQString &other) { s = other.s; return *this; } + +private: + friend bool operator==(const MoveDefinedQString &lhs, const MoveDefinedQString &rhs) + { return lhs.s == rhs.s; } + friend bool operator!=(const MoveDefinedQString &lhs, const MoveDefinedQString &rhs) + { return !operator==(lhs, rhs); } + friend char* toString(const MoveDefinedQString &mds) + { using namespace QTest; return toString(mds.s); } +}; + void tst_Compiler::cxx11_rvalue_refs() { #ifndef Q_COMPILER_RVALUE_REFS QSKIP("Compiler does not support C++11 feature"); #else - int i = 1; - i = std::move(i); + // we require std::move: + { + int i = 1; + i = std::move(i); - QString s = "Hello"; - QString t = std::move(s); - QCOMPARE(t, QString("Hello")); + MoveDefinedQString s("Hello"); + MoveDefinedQString t = std::move(s); + QCOMPARE(t, MoveDefinedQString("Hello")); + QCOMPARE(s, MoveDefinedQString()); - s = t; - t = std::move(s); - QCOMPARE(t, QString("Hello")); + s = t; + t = std::move(s); + QCOMPARE(t, MoveDefinedQString("Hello")); + QCOMPARE(s, MoveDefinedQString()); - QString &&r = std::move(s); - QCOMPARE(r, QString("Hello")); + MoveDefinedQString &&r = std::move(t); // no actual move! + QCOMPARE(r, MoveDefinedQString("Hello")); + QCOMPARE(t, MoveDefinedQString("Hello")); // so 't' is unchanged + } + + // we require std::forward: + { + MoveDefinedQString s("Hello"); + MoveDefinedQString s2 = std::forward(s); // forward as rvalue + QCOMPARE(s2, MoveDefinedQString("Hello")); + QCOMPARE(s, MoveDefinedQString()); + + MoveDefinedQString s3 = std::forward(s2); // forward as lvalue + QCOMPARE(s2, MoveDefinedQString("Hello")); + QCOMPARE(s3, MoveDefinedQString("Hello")); + } + + // supported by MSVC only from November 2013 CTP, but only check for VC2015: +# if !defined(Q_CC_MSVC) || defined(Q_CC_INTEL) || _MSC_VER >= 1900 // VS14 == VC2015 + // we require automatic generation of move special member functions: + { + struct M { MoveDefinedQString s1, s2; }; + M m1 = { MoveDefinedQString("Hello"), MoveDefinedQString("World") }; + QCOMPARE(m1.s1, MoveDefinedQString("Hello")); + QCOMPARE(m1.s2, MoveDefinedQString("World")); + M m2 = std::move(m1); + QCOMPARE(m1.s1, MoveDefinedQString()); + QCOMPARE(m1.s2, MoveDefinedQString()); + QCOMPARE(m2.s1, MoveDefinedQString("Hello")); + QCOMPARE(m2.s2, MoveDefinedQString("World")); + M m3; + QCOMPARE(m3.s1, MoveDefinedQString()); + QCOMPARE(m3.s2, MoveDefinedQString()); + m3 = std::move(m2); + QCOMPARE(m2.s1, MoveDefinedQString()); + QCOMPARE(m2.s2, MoveDefinedQString()); + QCOMPARE(m3.s1, MoveDefinedQString("Hello")); + QCOMPARE(m3.s2, MoveDefinedQString("World")); + } +# endif // MSVC < 2015 #endif }