summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/ADT/APInt.h13
-rw-r--r--llvm/unittests/ADT/APIntTest.cpp17
2 files changed, 28 insertions, 2 deletions
diff --git a/llvm/include/llvm/ADT/APInt.h b/llvm/include/llvm/ADT/APInt.h
index aa3c3f67ec1..f815628f30c 100644
--- a/llvm/include/llvm/ADT/APInt.h
+++ b/llvm/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/llvm/unittests/ADT/APIntTest.cpp b/llvm/unittests/ADT/APIntTest.cpp
index 19c47ab13bf..7da3fb25548 100644
--- a/llvm/unittests/ADT/APIntTest.cpp
+++ b/llvm/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]);
+}
+
}
OpenPOWER on IntegriCloud