[llvm] r261259 - [ADT] Fix PointerEmbeddedInt when the underlying type is uintptr_t.

Jordan Rose via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 18 13:00:08 PST 2016


Author: jrose
Date: Thu Feb 18 15:00:08 2016
New Revision: 261259

URL: http://llvm.org/viewvc/llvm-project?rev=261259&view=rev
Log:
[ADT] Fix PointerEmbeddedInt when the underlying type is uintptr_t.

...and when you try to store negative values in it.

Modified:
    llvm/trunk/include/llvm/ADT/PointerEmbeddedInt.h
    llvm/trunk/unittests/ADT/PointerEmbeddedIntTest.cpp

Modified: llvm/trunk/include/llvm/ADT/PointerEmbeddedInt.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/PointerEmbeddedInt.h?rev=261259&r1=261258&r2=261259&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/PointerEmbeddedInt.h (original)
+++ llvm/trunk/include/llvm/ADT/PointerEmbeddedInt.h Thu Feb 18 15:00:08 2016
@@ -11,6 +11,7 @@
 #define LLVM_ADT_POINTEREMBEDDEDINT_H
 
 #include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/Support/MathExtras.h"
 #include "llvm/Support/PointerLikeTypeTraits.h"
 #include <climits>
 
@@ -30,6 +31,8 @@ template <typename IntT, int Bits = size
 class PointerEmbeddedInt {
   uintptr_t Value;
 
+  // Note: This '<' is correct; using '<=' would result in some shifts
+  // overflowing their storage types.
   static_assert(Bits < sizeof(uintptr_t) * CHAR_BIT,
                 "Cannot embed more bits than we have in a pointer!");
 
@@ -42,26 +45,34 @@ class PointerEmbeddedInt {
     Mask = static_cast<uintptr_t>(-1) << Bits
   };
 
+  static constexpr const struct RawValueTag {} RawValue = RawValueTag();
+
   friend class PointerLikeTypeTraits<PointerEmbeddedInt>;
 
-  explicit PointerEmbeddedInt(uintptr_t Value) : Value(Value) {}
+  explicit PointerEmbeddedInt(uintptr_t Value, RawValueTag) : Value(Value) {}
 
 public:
   PointerEmbeddedInt() : Value(0) {}
 
-  PointerEmbeddedInt(IntT I) : Value(static_cast<uintptr_t>(I) << Shift) {
-    assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
+  PointerEmbeddedInt(IntT I) {
+    *this = I;
   }
 
   PointerEmbeddedInt &operator=(IntT I) {
-    assert((I & Mask) == 0 && "Integer has bits outside those preserved!");
+    assert((std::is_signed<IntT>::value ? llvm::isInt<Bits>(I)
+                                        : llvm::isUInt<Bits>(I)) &&
+           "Integer has bits outside those preserved!");
     Value = static_cast<uintptr_t>(I) << Shift;
     return *this;
   }
 
   // Note that this implicit conversion additionally allows all of the basic
   // comparison operators to work transparently, etc.
-  operator IntT() const { return static_cast<IntT>(Value >> Shift); }
+  operator IntT() const {
+    if (std::is_signed<IntT>::value)
+      return static_cast<IntT>(static_cast<intptr_t>(Value) >> Shift);
+    return static_cast<IntT>(Value >> Shift);
+  }
 };
 
 // Provide pointer like traits to support use with pointer unions and sum
@@ -75,10 +86,10 @@ public:
     return reinterpret_cast<void *>(P.Value);
   }
   static inline T getFromVoidPointer(void *P) {
-    return T(reinterpret_cast<uintptr_t>(P));
+    return T(reinterpret_cast<uintptr_t>(P), T::RawValue);
   }
   static inline T getFromVoidPointer(const void *P) {
-    return T(reinterpret_cast<uintptr_t>(P));
+    return T(reinterpret_cast<uintptr_t>(P), T::RawValue);
   }
 
   enum { NumLowBitsAvailable = T::Shift };

Modified: llvm/trunk/unittests/ADT/PointerEmbeddedIntTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/PointerEmbeddedIntTest.cpp?rev=261259&r1=261258&r2=261259&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/PointerEmbeddedIntTest.cpp (original)
+++ llvm/trunk/unittests/ADT/PointerEmbeddedIntTest.cpp Thu Feb 18 15:00:08 2016
@@ -43,4 +43,38 @@ TEST(PointerEmbeddedIntTest, Basic) {
   EXPECT_FALSE(42 >= J);
 }
 
+TEST(PointerEmbeddedIntTest, intptr_t) {
+  PointerEmbeddedInt<intptr_t, CHAR_BIT> IPos = 42, INeg = -42;
+  EXPECT_EQ(42, IPos);
+  EXPECT_EQ(-42, INeg);
+
+  PointerEmbeddedInt<uintptr_t, CHAR_BIT> U = 42, USaturated = 255;
+  EXPECT_EQ(42U, U);
+  EXPECT_EQ(255U, USaturated);
+
+  PointerEmbeddedInt<intptr_t, std::numeric_limits<intptr_t>::digits>
+      IMax = std::numeric_limits<intptr_t>::max() >> 1,
+      IMin = std::numeric_limits<intptr_t>::min() >> 1;
+  EXPECT_EQ(std::numeric_limits<intptr_t>::max() >> 1, IMax);
+  EXPECT_EQ(std::numeric_limits<intptr_t>::min() >> 1, IMin);
+
+  PointerEmbeddedInt<uintptr_t, std::numeric_limits<uintptr_t>::digits - 1>
+      UMax = std::numeric_limits<uintptr_t>::max() >> 1,
+      UMin = std::numeric_limits<uintptr_t>::min() >> 1;
+  EXPECT_EQ(std::numeric_limits<uintptr_t>::max() >> 1, UMax);
+  EXPECT_EQ(std::numeric_limits<uintptr_t>::min() >> 1, UMin);
+}
+
+TEST(PointerEmbeddedIntTest, PointerLikeTypeTraits) {
+  PointerEmbeddedInt<int, CHAR_BIT> I = 42;
+  using ITraits = PointerLikeTypeTraits<decltype(I)>;
+  EXPECT_EQ(42, ITraits::getFromVoidPointer(ITraits::getAsVoidPointer(I)));
+
+  PointerEmbeddedInt<uintptr_t, std::numeric_limits<uintptr_t>::digits - 1>
+      Max = std::numeric_limits<uintptr_t>::max() >> 1;
+  using MaxTraits = PointerLikeTypeTraits<decltype(Max)>;
+  EXPECT_EQ(std::numeric_limits<uintptr_t>::max() >> 1,
+            MaxTraits::getFromVoidPointer(MaxTraits::getAsVoidPointer(Max)));
+}
+
 } // end anonymous namespace




More information about the llvm-commits mailing list