diff --git a/include/llvm/ADT/APInt.h b/include/llvm/ADT/APInt.h index aa3c3f67ec1..f815628f30c 100644 --- a/include/llvm/ADT/APInt.h +++ b/include/llvm/ADT/APInt.h @@ -656,13 +656,22 @@ public: /// @brief Move assignment operator. APInt &operator=(APInt &&that) { - if (!isSingleWord()) + if (!isSingleWord()) { + // The MSVC STL shipped in 2013 requires that self move assignment be a + // no-op. Otherwise algorithms like stable_sort will produce answers + // where half of the output is left in a moved-from state. + if (this == &that) + return *this; delete[] pVal; + } - BitWidth = that.BitWidth; VAL = that.VAL; + // If 'this == &that', avoid zeroing our own bitwidth by storing to 'that' + // first. + unsigned ThatBitWidth = that.BitWidth; that.BitWidth = 0; + BitWidth = ThatBitWidth; return *this; } diff --git a/unittests/ADT/APIntTest.cpp b/unittests/ADT/APIntTest.cpp index 19c47ab13bf..7da3fb25548 100644 --- a/unittests/ADT/APIntTest.cpp +++ b/unittests/ADT/APIntTest.cpp @@ -678,4 +678,21 @@ TEST(APIntTest, nearestLogBase2) { EXPECT_EQ(A9.nearestLogBase2(), UINT32_MAX); } +TEST(APIntTest, SelfMoveAssignment) { + APInt X(32, 0xdeadbeef); + X = std::move(X); + EXPECT_EQ(32, X.getBitWidth()); + EXPECT_EQ(0xdeadbeefULL, X.getLimitedValue()); + + uint64_t Bits[] = {0xdeadbeefdeadbeefULL, 0xdeadbeefdeadbeefULL}; + APInt Y(128, Bits); + Y = std::move(Y); + EXPECT_EQ(128, Y.getBitWidth()); + EXPECT_EQ(~0ULL, Y.getLimitedValue()); + const uint64_t *Raw = Y.getRawData(); + EXPECT_EQ(2, Y.getNumWords()); + EXPECT_EQ(0xdeadbeefdeadbeefULL, Raw[0]); + EXPECT_EQ(0xdeadbeefdeadbeefULL, Raw[1]); +} + }