Bug 1120062 - Part 2: Remove use of IsNullPointer. r=waldo
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Thu, 15 Jan 2015 02:09:11 +0900
changeset 223782 e5fee301e66cfa4051d3a57999bbd13571f1f44c
parent 223781 ec13e4c1e1d6c26a39bc0986281e40926a52b327
child 223783 e98f0dc6b1c3e6060661b83df5c8dc2faff9d943
push id28107
push userryanvm@gmail.com
push dateWed, 14 Jan 2015 21:17:38 +0000
treeherdermozilla-central@af5716d852c6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswaldo
bugs1120062
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1120062 - Part 2: Remove use of IsNullPointer. r=waldo
js/public/RootingAPI.h
mfbt/Move.h
mfbt/NullPtr.h
mfbt/UniquePtr.h
mfbt/tests/TestUniquePtr.cpp
parser/html/jArray.h
--- a/js/public/RootingAPI.h
+++ b/js/public/RootingAPI.h
@@ -6,17 +6,16 @@
 
 #ifndef js_RootingAPI_h
 #define js_RootingAPI_h
 
 #include "mozilla/Attributes.h"
 #include "mozilla/DebugOnly.h"
 #include "mozilla/GuardObjects.h"
 #include "mozilla/LinkedList.h"
-#include "mozilla/NullPtr.h"
 #include "mozilla/TypeTraits.h"
 
 #include "jspubtd.h"
 
 #include "js/GCAPI.h"
 #include "js/HeapAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
@@ -507,25 +506,18 @@ class MOZ_NONHEAP_CLASS Handle : public 
 template <typename T>
 class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
 {
   public:
     inline MOZ_IMPLICIT MutableHandle(Rooted<T> *root);
     inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T> *root);
 
   private:
-    // Disallow true nullptr and emulated nullptr (gcc 4.4/4.5, __null, appears
-    // as int/long [32/64-bit]) for overloading purposes.
-    template<typename N>
-    MutableHandle(N,
-                  typename mozilla::EnableIf<mozilla::IsNullPointer<N>::value ||
-                                             mozilla::IsSame<N, int>::value ||
-                                             mozilla::IsSame<N, long>::value,
-                                             int>::Type dummy = 0)
-    = delete;
+    // Disallow nullptr for overloading purposes.
+    MutableHandle(decltype(nullptr)) = delete;
 
   public:
     void set(T v) {
         MOZ_ASSERT(!js::GCMethods<T>::poisoned(v));
         *ptr = v;
     }
 
     /*
--- a/mfbt/Move.h
+++ b/mfbt/Move.h
@@ -178,35 +178,24 @@ namespace mozilla {
  *
  * (C++11 says that the <utility> header file should define 'std::move' and
  * 'std::forward', which are just like our 'Move' and 'Forward'; but those
  * definitions aren't available in that header on all our platforms, so we
  * define them ourselves here.)
  *
  * 0. This pattern is known as "perfect forwarding".  Interestingly, it is not
  *    actually perfect, and it can't forward all possible argument expressions!
- *    There are two issues: one that's a C++11 issue, and one that's a legacy
- *    compiler issue.
- *
- *    The C++11 issue is that you can't form a reference to a bit-field.  As a
+ *    There is a C++11 issue: you can't form a reference to a bit-field.  As a
  *    workaround, assign the bit-field to a local variable and use that:
  *
  *      // C is as above
  *      struct S { int x : 1; } s;
  *      C(s.x, 0); // BAD: s.x is a reference to a bit-field, can't form those
  *      int tmp = s.x;
  *      C(tmp, 0); // OK: tmp not a bit-field
- *
- *    The legacy issue is that when we don't have true nullptr and must emulate
- *    it (gcc 4.4/4.5), forwarding |nullptr| results in an |int| or |long|
- *    forwarded reference.  But such a reference, even if its value is a null
- *    pointer constant expression, is not itself a null pointer constant
- *    expression.  This causes -Werror=conversion-null errors and pointer-to-
- *    integer comparison errors.  Until we always have true nullptr, users of
- *    forwarding methods must not pass |nullptr| to them.
  */
 
 /**
  * Identical to std::Move(); this is necessary until our stlport supports
  * std::move().
  */
 template<typename T>
 inline typename RemoveReference<T>::Type&&
--- a/mfbt/NullPtr.h
+++ b/mfbt/NullPtr.h
@@ -1,112 +1,31 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-/*
- * Implements a workaround for compilers which do not support the C++11 nullptr
- * constant.
- */
+/* Implements a mozilla::IsNullPointer<T> type trait. */
 
 #ifndef mozilla_NullPtr_h
 #define mozilla_NullPtr_h
 
-#if defined(__clang__)
-#  if !__has_extension(cxx_nullptr)
-#    error "clang version natively supporting nullptr is required."
-#  endif
-#  define MOZ_HAVE_CXX11_NULLPTR
-#elif defined(__GNUC__)
-#  if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
-#    include "mozilla/Compiler.h"
-#    if MOZ_GCC_VERSION_AT_LEAST(4, 6, 0)
-#      define MOZ_HAVE_CXX11_NULLPTR
-#    endif
-#  endif
-#elif defined(_MSC_VER)
-   // The minimum supported MSVC (12, _MSC_VER 1800) supports nullptr.
-#  define MOZ_HAVE_CXX11_NULLPTR
-#endif
+#include "mozilla/TypeTraits.h"
 
 namespace mozilla {
 
 /**
- * IsNullPointer<T>::value is true iff T is the type of C++11's nullptr.  If
- * nullptr is emulated, IsNullPointer<T>::value is false for all T.
- *
- * IsNullPointer is useful to give an argument the true decltype(nullptr) type.
- * decltype(nullptr) doesn't work when nullptr is emulated.  The simplest
- * workaround is to use template overloading and SFINAE to expose an overload
- * only if an argument's type is decltype(nullptr).  Some examples (that assume
- * namespace mozilla has been opened, for simplicity):
- *
- *   // foo(T*), foo(stuff that converts to T*), and foo(decltype(nullptr))
- *   // (only invoked if nullptr is true nullptr, otherwise foo(T*) is invoked)
- *   // but nothing else
- *   void foo(T*) { }
- *   template<typename N>
- *   void foo(N,
- *            typename EnableIf<IsNullPointer<N>::value, int>::Type dummy = 0)
- *   { }
- *
- *   // foo(T*) *exactly* and foo(decltype(nullptr)), nothing else
- *   void foo(T*) { }
- *   template<typename U>
- *   void foo(U,
- *            typename EnableIf<!IsNullPointer<U>::value, int>::Type dummy = 0)
- *   = delete;
- *
- * The exact details of how set up the SFINAE bits vary on a case-by-case basis.
- * If you need help with this (and unless you've internalized way more sadmaking
- * nullptr-emulation knowledge than you should have, you do), feel free to poke
- * the person with blame on this comment with questions.   :-)
+ * IsNullPointer<T>::value is true iff T is decltype(nullptr).
  *
  * Ideally this would be in TypeTraits.h, but C++11 omitted std::is_null_pointer
- * (fixed in C++1y), so in the interests of easing a switch to <type_traits>,
+ * (fixed in C++14), so in the interests of easing a switch to <type_traits>,
  * this trait lives elsewhere.
  */
 template<typename T>
-struct IsNullPointer { static const bool value = false; };
-
-} // namespace mozilla
+struct IsNullPointer : FalseType {};
 
-/**
- * mozilla::NullptrT is a type that's sort of like decltype(nullptr).  But it
- * can't be identical, because emulated nullptr doesn't have a distinct type.
- * Only with gcc 4.4/4.5, emulated nullptr is __null, and decltype(__null) is
- * int or long.  But passing __null to an int/long parameter triggers
- * -Werror=conversion-null errors with gcc 4.5, or (depending on subsequent use
- * inside the overloaded function) can trigger pointer-to-integer comparison
- * compiler errors.  So fairly often, actually, NullptrT is *not* what you want.
- *
- * Instead, often you should use template-based overloading in concert with
- * SFINAE to add a nullptr overload -- see the comments by IsNullPointer.
- *
- * So when *should* you use NullptrT?  Thus far, the only truly good use seems
- * to be as an argument type for operator overloads (because C++ doesn't allow
- * operator= to have more than one argument, operator== to have more than two,
- * &c.).  But even in such cases, it really only works if there are no other
- * overloads of the operator that accept a pointer type.  If you want both T*
- * and nullptr_t overloads, you'll have to wait til we drop gcc 4.4/4.5 support.
- * (Currently b2g is the only impediment to this.)
- */
-#ifdef MOZ_HAVE_CXX11_NULLPTR
-// decltype does the right thing for actual nullptr.
-namespace mozilla {
-typedef decltype(nullptr) NullptrT;
 template<>
-struct IsNullPointer<decltype(nullptr)> { static const bool value = true; };
+struct IsNullPointer<decltype(nullptr)> : TrueType {};
+
 }
-#  undef MOZ_HAVE_CXX11_NULLPTR
-#elif MOZ_IS_GCC
-#  define nullptr __null
-// void* sweeps up more than just nullptr, but compilers supporting true
-// nullptr are the majority now, so they should detect mistakes.  If you're
-// feeling paranoid, check/assert that your NullptrT equals nullptr.
-namespace mozilla { typedef void* NullptrT; }
-#else
-#  error "No compiler support for nullptr or its emulation."
-#endif
 
 #endif /* mozilla_NullPtr_h */
--- a/mfbt/UniquePtr.h
+++ b/mfbt/UniquePtr.h
@@ -8,17 +8,16 @@
 
 #ifndef mozilla_UniquePtr_h
 #define mozilla_UniquePtr_h
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/Compiler.h"
 #include "mozilla/Move.h"
-#include "mozilla/NullPtr.h"
 #include "mozilla/Pair.h"
 #include "mozilla/TypeTraits.h"
 
 namespace mozilla {
 
 template<typename T> class DefaultDelete;
 template<typename T, class D = DefaultDelete<T>> class UniquePtr;
 
@@ -225,20 +224,19 @@ public:
     static_assert(!IsReference<D>::value,
                   "rvalue deleter can't be stored by reference");
   }
 
   UniquePtr(UniquePtr&& aOther)
     : mTuple(aOther.release(), Forward<DeleterType>(aOther.getDeleter()))
   {}
 
-  template<typename N>
-  UniquePtr(N,
-            typename EnableIf<IsNullPointer<N>::value, int>::Type aDummy = 0)
-    : mTuple(static_cast<Pointer>(nullptr), DeleterType())
+  MOZ_IMPLICIT
+  UniquePtr(decltype(nullptr))
+    : mTuple(nullptr, DeleterType())
   {
     static_assert(!IsPointer<D>::value, "must provide a deleter instance");
     static_assert(!IsReference<D>::value, "must provide a deleter instance");
   }
 
   template<typename U, class E>
   UniquePtr(UniquePtr<U, E>&& aOther,
             typename EnableIf<IsConvertible<typename UniquePtr<U, E>::Pointer,
@@ -270,19 +268,18 @@ public:
     static_assert(!IsArray<U>::value,
                   "can't assign from UniquePtr holding an array");
 
     reset(aOther.release());
     getDeleter() = Forward<E>(aOther.getDeleter());
     return *this;
   }
 
-  UniquePtr& operator=(NullptrT aNull)
+  UniquePtr& operator=(decltype(nullptr))
   {
-    MOZ_ASSERT(aNull == nullptr);
     reset(nullptr);
     return *this;
   }
 
   T& operator*() const { return *get(); }
   Pointer operator->() const
   {
     MOZ_ASSERT(get(), "dereferencing a UniquePtr containing nullptr");
@@ -408,35 +405,34 @@ private:
                               int>::Type aDummy = 0)
   = delete;
 
 public:
   UniquePtr(UniquePtr&& aOther)
     : mTuple(aOther.release(), Forward<DeleterType>(aOther.getDeleter()))
   {}
 
-  template<typename N>
-  UniquePtr(N,
-            typename EnableIf<IsNullPointer<N>::value, int>::Type aDummy = 0)
-    : mTuple(static_cast<Pointer>(nullptr), DeleterType())
+  MOZ_IMPLICIT
+  UniquePtr(decltype(nullptr))
+    : mTuple(nullptr, DeleterType())
   {
     static_assert(!IsPointer<D>::value, "must provide a deleter instance");
     static_assert(!IsReference<D>::value, "must provide a deleter instance");
   }
 
   ~UniquePtr() { reset(nullptr); }
 
   UniquePtr& operator=(UniquePtr&& aOther)
   {
     reset(aOther.release());
     getDeleter() = Forward<DeleterType>(aOther.getDeleter());
     return *this;
   }
 
-  UniquePtr& operator=(NullptrT)
+  UniquePtr& operator=(decltype(nullptr))
   {
     reset();
     return *this;
   }
 
   T& operator[](decltype(sizeof(int)) aIndex) const { return get()[aIndex]; }
   Pointer get() const { return mTuple.first(); }
 
@@ -464,29 +460,28 @@ public:
   {
     Pointer old = mTuple.first();
     mTuple.first() = aPtr;
     if (old != nullptr) {
       mTuple.second()(old);
     }
   }
 
+  void reset(decltype(nullptr))
+  {
+    Pointer old = mTuple.first();
+    mTuple.first() = nullptr;
+    if (old != nullptr) {
+      mTuple.second()(old);
+    }
+  }
+
 private:
-  // Kill off all remaining overloads that aren't true nullptr (the overload
-  // above should handle that) or emulated nullptr (which acts like int/long
-  // on gcc 4.4/4.5).
   template<typename U>
-  void reset(U,
-             typename EnableIf<!IsNullPointer<U>::value &&
-                               !IsSame<U,
-                                       Conditional<(sizeof(int) == sizeof(void*)),
-                                                   int,
-                                                   long>::Type>::value,
-                               int>::Type aDummy = 0)
-  = delete;
+  void reset(U) = delete;
 
 public:
   void swap(UniquePtr& aOther) { mTuple.swap(aOther.mTuple); }
 
 private:
   UniquePtr(const UniquePtr& aOther) = delete; // construct using Move()!
   void operator=(const UniquePtr& aOther) = delete; // assign using Move()!
 };
@@ -547,43 +542,39 @@ template<typename T, class D, typename U
 bool
 operator!=(const UniquePtr<T, D>& aX, const UniquePtr<U, E>& aY)
 {
   return aX.get() != aY.get();
 }
 
 template<typename T, class D>
 bool
-operator==(const UniquePtr<T, D>& aX, NullptrT aNull)
+operator==(const UniquePtr<T, D>& aX, decltype(nullptr))
 {
-  MOZ_ASSERT(aNull == nullptr);
   return !aX;
 }
 
 template<typename T, class D>
 bool
-operator==(NullptrT aNull, const UniquePtr<T, D>& aX)
+operator==(decltype(nullptr), const UniquePtr<T, D>& aX)
 {
-  MOZ_ASSERT(aNull == nullptr);
   return !aX;
 }
 
 template<typename T, class D>
 bool
-operator!=(const UniquePtr<T, D>& aX, NullptrT aNull)
+operator!=(const UniquePtr<T, D>& aX, decltype(nullptr))
 {
-  MOZ_ASSERT(aNull == nullptr);
   return bool(aX);
 }
 
 template<typename T, class D>
 bool
-operator!=(NullptrT aNull, const UniquePtr<T, D>& aX)
+operator!=(decltype(nullptr), const UniquePtr<T, D>& aX)
 {
-  MOZ_ASSERT(aNull == nullptr);
   return bool(aX);
 }
 
 // No operator<, operator>, operator<=, operator>= for now because simplicity.
 
 namespace detail {
 
 template<typename T>
@@ -617,18 +608,17 @@ struct UniqueSelector<T[N]>
  *     MakeUnique<T[]>(size_t) is the only valid overload.  The pointer returned
  *     is as if by |new T[n]()|, which value-initializes each element.  (If T
  *     isn't a class type, this will zero each element.  If T is a class type,
  *     then roughly speaking, each element will be constructed using its default
  *     constructor.  See C++11 [dcl.init]p7 for the full gory details.)
  *   If Type is non-array T:
  *     The arguments passed to MakeUnique<T>(...) are forwarded into a
  *     |new T(...)| call, initializing the T as would happen if executing
- *     |T(...)|.  (Note: literal nullptr must not be provided as an argument to
- *     MakeUnique, because nullptr may be emulated.  See Move.h for details.)
+ *     |T(...)|.
  *
  * There are various benefits to using MakeUnique instead of |new| expressions.
  *
  * First, MakeUnique eliminates use of |new| from code entirely.  If objects are
  * only created through UniquePtr, then (assuming all explicit release() calls
  * are safe, including transitively, and no type-safety casting funniness)
  * correctly maintained ownership of the UniquePtr guarantees no leaks are
  * possible.  (This pays off best if a class is only ever created through a
@@ -659,20 +649,16 @@ struct UniqueSelector<T[N]>
  * An exception thrown after |new T| succeeds will leak that memory, unless the
  * pointer is assigned to an object that will manage its ownership.  UniquePtr
  * ably serves this function.)
  */
 
 // We don't have variadic template support everywhere, so just hard-code arities
 // 0-8 for now.  If you need more arguments, feel free to add the extra
 // overloads (and deletions for the T = E[N] case).
-//
-// Beware!  Due to lack of true nullptr support in gcc 4.4 and 4.5, passing
-// literal nullptr to MakeUnique will not work on some platforms.  See Move.h
-// for more details.
 
 template<typename T, typename... Args>
 typename detail::UniqueSelector<T>::SingleObject
 MakeUnique(Args&&... aArgs)
 {
   return UniquePtr<T>(new T(Forward<Args>(aArgs)...));
 }
 
--- a/mfbt/tests/TestUniquePtr.cpp
+++ b/mfbt/tests/TestUniquePtr.cpp
@@ -2,25 +2,23 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/Assertions.h"
 #include "mozilla/Compiler.h"
 #include "mozilla/Move.h"
-#include "mozilla/NullPtr.h"
 #include "mozilla/TypeTraits.h"
 #include "mozilla/UniquePtr.h"
 #include "mozilla/Vector.h"
 
 #include <stddef.h>
 
 using mozilla::DefaultDelete;
-using mozilla::IsNullPointer;
 using mozilla::IsSame;
 using mozilla::MakeUnique;
 using mozilla::Swap;
 using mozilla::UniquePtr;
 using mozilla::Vector;
 
 #define CHECK(c) \
   do { \
@@ -377,34 +375,18 @@ TestFunctionReferenceDeleter()
     CHECK(DeleteIntFunctionCallCount == 1);
   }
 
   CHECK(DeleteIntFunctionCallCount == 2);
 
   return true;
 }
 
-template<typename T, bool = IsNullPointer<decltype(nullptr)>::value>
-struct AppendNullptrTwice;
-
 template<typename T>
-struct AppendNullptrTwice<T, false>
-{
-  AppendNullptrTwice() {}
-
-  bool operator()(Vector<T>& vec)
-  {
-    CHECK(vec.append(static_cast<typename T::Pointer>(nullptr)));
-    CHECK(vec.append(static_cast<typename T::Pointer>(nullptr)));
-    return true;
-  }
-};
-
-template<typename T>
-struct AppendNullptrTwice<T, true>
+struct AppendNullptrTwice
 {
   AppendNullptrTwice() {}
 
   bool operator()(Vector<T>& vec)
   {
     CHECK(vec.append(nullptr));
     CHECK(vec.append(nullptr));
     return true;
--- a/parser/html/jArray.h
+++ b/parser/html/jArray.h
@@ -86,18 +86,17 @@ class autoJArray {
       jArray<T,L> newArray = { arr, length };
       return newArray;
     }
     void operator=(const jArray<T,L>& other) {
       delete[] arr;
       arr = other.arr;
       length = other.length;
     }
-    void operator=(decltype(nullptr) n) {
+    void operator=(decltype(nullptr)) {
       // Make assigning null to an array in Java delete the buffer in C++
-      MOZ_ASSERT(n == nullptr);
       delete[] arr;
       arr = nullptr;
       length = 0;
     }
 };
 
 #endif // jArray_h