Backed out changeset f3d9fbb2daf1 (bug 1613985) for causing hazard bustages on Linux.
authorMihai Alexandru Michis <malexandru@mozilla.com>
Wed, 12 Feb 2020 16:43:30 +0200
changeset 576510 1a1332949d44be803d9c065399b0883cadd5ff8c
parent 576509 63acd82c9360389a6dbd3bdf223e48bf32ca25c1
child 576511 c078d08afa05139cdd28659604214a3bf79adde9
push id12808
push userffxbld-merge
push dateMon, 09 Mar 2020 15:29:44 +0000
treeherdermozilla-beta@3bd67f111cdf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1613985
milestone75.0a1
backs outf3d9fbb2daf1a10c7167195775b88286cbfc398e
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
Backed out changeset f3d9fbb2daf1 (bug 1613985) for causing hazard bustages on Linux. CLOSED TREE
mfbt/Array.h
mfbt/Atomics.h
mfbt/DebugOnly.h
mfbt/EnumeratedArray.h
mfbt/HashTable.h
mfbt/JSONWriter.h
mfbt/LinkedList.h
mfbt/Opaque.h
mfbt/Pair.h
mfbt/RecordReplay.cpp
mfbt/RollingMean.h
mfbt/Scoped.h
mfbt/Span.h
mfbt/ThreadSafeWeakPtr.h
mfbt/UniquePtr.h
mfbt/tests/TestRollingMean.cpp
mfbt/tests/TestSPSCQueue.cpp
mfbt/tests/TestTypeTraits.cpp
mfbt/tests/TestUniquePtr.cpp
mfbt/tests/gtest/TestMozDbg.cpp
--- a/mfbt/Array.h
+++ b/mfbt/Array.h
@@ -23,17 +23,17 @@ namespace mozilla {
 template <typename T, size_t _Length>
 class Array {
   T mArr[_Length];
 
  public:
   using ElementType = T;
   static constexpr size_t Length = _Length;
 
-  Array() = default;
+  Array() {}
 
   template <typename... Args>
   MOZ_IMPLICIT constexpr Array(Args&&... aArgs)
       : mArr{std::forward<Args>(aArgs)...} {
     static_assert(sizeof...(aArgs) == Length,
                   "The number of arguments should be equal to the template "
                   "parameter Length");
   }
--- a/mfbt/Atomics.h
+++ b/mfbt/Atomics.h
@@ -155,17 +155,17 @@ namespace detail {
  * debugger activity.
  */
 template <recordreplay::Behavior Recording>
 struct AutoRecordAtomicAccess;
 
 template <>
 struct AutoRecordAtomicAccess<recordreplay::Behavior::DontPreserve> {
   explicit AutoRecordAtomicAccess(const void* aValue) {}
-  ~AutoRecordAtomicAccess() = default;
+  ~AutoRecordAtomicAccess() {}
 };
 
 template <>
 struct AutoRecordAtomicAccess<recordreplay::Behavior::Preserve> {
   explicit AutoRecordAtomicAccess(const void* aValue) {
     recordreplay::BeginOrderedAtomicAccess(aValue);
   }
   ~AutoRecordAtomicAccess() { recordreplay::EndOrderedAtomicAccess(); }
--- a/mfbt/DebugOnly.h
+++ b/mfbt/DebugOnly.h
@@ -36,17 +36,17 @@ namespace mozilla {
  * their objects in release builds.
  */
 template <typename T>
 class MOZ_STACK_CLASS DebugOnly {
  public:
 #ifdef DEBUG
   T value;
 
-  DebugOnly() = default;
+  DebugOnly() {}
   MOZ_IMPLICIT DebugOnly(const T& aOther) : value(aOther) {}
   DebugOnly(const DebugOnly& aOther) : value(aOther.value) {}
   DebugOnly& operator=(const T& aRhs) {
     value = aRhs;
     return *this;
   }
 
   void operator++(int) { value++; }
@@ -60,31 +60,31 @@ class MOZ_STACK_CLASS DebugOnly {
 
   operator T&() { return value; }
   operator const T&() const { return value; }
 
   T& operator->() { return value; }
   const T& operator->() const { return value; }
 
 #else
-  DebugOnly() = default;
+  DebugOnly() {}
   MOZ_IMPLICIT DebugOnly(const T&) {}
   DebugOnly(const DebugOnly&) {}
   DebugOnly& operator=(const T&) { return *this; }
   void operator++(int) {}
   void operator--(int) {}
   DebugOnly& operator+=(const T&) { return *this; }
   DebugOnly& operator-=(const T&) { return *this; }
   DebugOnly& operator&=(const T&) { return *this; }
   DebugOnly& operator|=(const T&) { return *this; }
   DebugOnly& operator^=(const T&) { return *this; }
 #endif
 
   /*
-   * DebugOnly must always have a user-defined destructor or else it will
+   * DebugOnly must always have a destructor or else it will
    * generate "unused variable" warnings, exactly what it's intended
    * to avoid!
    */
   ~DebugOnly() {}
 };
 
 }  // namespace mozilla
 
--- a/mfbt/EnumeratedArray.h
+++ b/mfbt/EnumeratedArray.h
@@ -45,17 +45,17 @@ class EnumeratedArray {
   static const size_t kSize = size_t(SizeAsEnumValue);
 
  private:
   typedef Array<ValueType, kSize> ArrayType;
 
   ArrayType mArray;
 
  public:
-  EnumeratedArray() = default;
+  EnumeratedArray() {}
 
   template <typename... Args>
   MOZ_IMPLICIT constexpr EnumeratedArray(Args&&... aArgs)
       : mArray{std::forward<Args>(aArgs)...} {}
 
   explicit EnumeratedArray(const EnumeratedArray& aOther) {
     for (size_t i = 0; i < kSize; i++) {
       mArray[i] = aOther.mArray[i];
--- a/mfbt/HashTable.h
+++ b/mfbt/HashTable.h
@@ -173,18 +173,21 @@ class HashMap {
 
   explicit HashMap(AllocPolicy aAllocPolicy = AllocPolicy(),
                    uint32_t aLen = Impl::sDefaultLen)
       : mImpl(std::move(aAllocPolicy), aLen) {}
 
   explicit HashMap(uint32_t aLen) : mImpl(AllocPolicy(), aLen) {}
 
   // HashMap is movable.
-  HashMap(HashMap&& aRhs) = default;
-  HashMap& operator=(HashMap&& aRhs) = default;
+  HashMap(HashMap&& aRhs) : mImpl(std::move(aRhs.mImpl)) {}
+  void operator=(HashMap&& aRhs) {
+    MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited");
+    mImpl = std::move(aRhs.mImpl);
+  }
 
   // -- Status and sizing ----------------------------------------------------
 
   // The map's current generation.
   Generation generation() const { return mImpl.generation(); }
 
   // Is the map empty?
   bool empty() const { return mImpl.empty(); }
@@ -455,18 +458,21 @@ class HashSet {
 
   explicit HashSet(AllocPolicy aAllocPolicy = AllocPolicy(),
                    uint32_t aLen = Impl::sDefaultLen)
       : mImpl(std::move(aAllocPolicy), aLen) {}
 
   explicit HashSet(uint32_t aLen) : mImpl(AllocPolicy(), aLen) {}
 
   // HashSet is movable.
-  HashSet(HashSet&& aRhs) = default;
-  HashSet& operator=(HashSet&& aRhs) = default;
+  HashSet(HashSet&& aRhs) : mImpl(std::move(aRhs.mImpl)) {}
+  void operator=(HashSet&& aRhs) {
+    MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited");
+    mImpl = std::move(aRhs.mImpl);
+  }
 
   // -- Status and sizing ----------------------------------------------------
 
   // The set's current generation.
   Generation generation() const { return mImpl.generation(); }
 
   // Is the set empty?
   bool empty() const { return mImpl.empty(); }
@@ -900,18 +906,23 @@ class HashMapEntry {
   friend class HashMap;
 
  public:
   template <typename KeyInput, typename ValueInput>
   HashMapEntry(KeyInput&& aKey, ValueInput&& aValue)
       : key_(std::forward<KeyInput>(aKey)),
         value_(std::forward<ValueInput>(aValue)) {}
 
-  HashMapEntry(HashMapEntry&& aRhs) = default;
-  HashMapEntry& operator=(HashMapEntry&& aRhs) = default;
+  HashMapEntry(HashMapEntry&& aRhs)
+      : key_(std::move(aRhs.key_)), value_(std::move(aRhs.value_)) {}
+
+  void operator=(HashMapEntry&& aRhs) {
+    key_ = std::move(aRhs.key_);
+    value_ = std::move(aRhs.value_);
+  }
 
   using KeyType = Key;
   using ValueType = Value;
 
   const Key& key() const { return key_; }
 
   // Use this method with caution! If the key is changed such that its hash
   // value also changes, the map will be left in an invalid state.
@@ -1498,24 +1509,23 @@ class HashTable : private AllocPolicy {
       mIter.rekey(aLookup, aKey);
     }
 
     void rekeyFront(const Key& aKey) { mIter.rekey(aKey); }
   };
 
   // HashTable is movable
   HashTable(HashTable&& aRhs) : AllocPolicy(std::move(aRhs)) { moveFrom(aRhs); }
-  HashTable& operator=(HashTable&& aRhs) {
+  void operator=(HashTable&& aRhs) {
     MOZ_ASSERT(this != &aRhs, "self-move assignment is prohibited");
     if (mTable) {
       destroyTable(*this, mTable, capacity());
     }
     AllocPolicy::operator=(std::move(aRhs));
     moveFrom(aRhs);
-    return *this;
   }
 
  private:
   void moveFrom(HashTable& aRhs) {
     mGen = aRhs.mGen;
     mHashShift = aRhs.mHashShift;
     mTable = aRhs.mTable;
     mEntryCount = aRhs.mEntryCount;
--- a/mfbt/JSONWriter.h
+++ b/mfbt/JSONWriter.h
@@ -105,17 +105,17 @@
 namespace mozilla {
 
 // A quasi-functor for JSONWriter. We don't use a true functor because that
 // requires templatizing JSONWriter, and the templatization seeps to lots of
 // places we don't want it to.
 class JSONWriteFunc {
  public:
   virtual void Write(const char* aStr) = 0;
-  virtual ~JSONWriteFunc() = default;
+  virtual ~JSONWriteFunc() {}
 };
 
 // Ideally this would be within |EscapedString| but when compiling with GCC
 // on Linux that caused link errors, whereas this formulation didn't.
 namespace detail {
 extern MFBT_DATA const char gTwoCharEscapes[256];
 }  // namespace detail
 
--- a/mfbt/LinkedList.h
+++ b/mfbt/LinkedList.h
@@ -615,17 +615,20 @@ template <typename T>
 class AutoCleanLinkedList : public LinkedList<T> {
  private:
   using Traits = detail::LinkedListElementTraits<T>;
   using ClientType = typename detail::LinkedListElementTraits<T>::ClientType;
 
  public:
   ~AutoCleanLinkedList() { clear(); }
 
-  AutoCleanLinkedList& operator=(AutoCleanLinkedList&& aOther) = default;
+  AutoCleanLinkedList& operator=(AutoCleanLinkedList&& aOther) {
+    LinkedList<T>::operator=(std::forward<LinkedList<T>>(aOther));
+    return *this;
+  }
 
   void clear() {
     while (ClientType element = this->popFirst()) {
       Traits::cleanElement(element);
     }
   }
 };
 
--- a/mfbt/Opaque.h
+++ b/mfbt/Opaque.h
@@ -21,17 +21,17 @@ namespace mozilla {
 template <typename T>
 class Opaque final {
   static_assert(mozilla::IsIntegral<T>::value,
                 "mozilla::Opaque only supports integral types");
 
   T mValue;
 
  public:
-  Opaque() = default;
+  Opaque() {}
   explicit Opaque(T aValue) : mValue(aValue) {}
 
   bool operator==(const Opaque& aOther) const {
     return mValue == aOther.mValue;
   }
 
   bool operator!=(const Opaque& aOther) const { return !(*this == aOther); }
 };
--- a/mfbt/Pair.h
+++ b/mfbt/Pair.h
@@ -137,20 +137,30 @@ template <typename A, typename B>
 struct Pair : private detail::PairHelper<A, B> {
   typedef typename detail::PairHelper<A, B> Base;
 
  public:
   template <typename AArg, typename BArg>
   Pair(AArg&& aA, BArg&& aB)
       : Base(std::forward<AArg>(aA), std::forward<BArg>(aB)) {}
 
-  Pair(Pair&& aOther) = default;
+  Pair(Pair&& aOther)
+      : Base(std::move(aOther.first()), std::move(aOther.second())) {}
+
   Pair(const Pair& aOther) = default;
 
-  Pair& operator=(Pair&& aOther) = default;
+  Pair& operator=(Pair&& aOther) {
+    MOZ_ASSERT(this != &aOther, "Self-moves are prohibited");
+
+    first() = std::move(aOther.first());
+    second() = std::move(aOther.second());
+
+    return *this;
+  }
+
   Pair& operator=(const Pair& aOther) = default;
 
   /** The A instance. */
   using Base::first;
   /** The B instance. */
   using Base::second;
 
   /** Swap this pair with another pair. */
--- a/mfbt/RecordReplay.cpp
+++ b/mfbt/RecordReplay.cpp
@@ -133,17 +133,17 @@ void Initialize(int aArgc, char* aArgv[]
 #undef INIT_SYMBOL_VOID
 
   initialize(aArgc, aArgv);
 }
 
 // Record/replay API functions can't GC, but we can't use
 // JS::AutoSuppressGCAnalysis here due to linking issues.
 struct AutoSuppressGCAnalysis {
-  AutoSuppressGCAnalysis() = default;
+  AutoSuppressGCAnalysis() {}
   ~AutoSuppressGCAnalysis() {
 #ifdef DEBUG
     // Need nontrivial destructor.
     static Atomic<int, SequentiallyConsistent, Behavior::DontPreserve> dummy;
     dummy++;
 #endif
   }
 } JS_HAZ_GC_SUPPRESSED;
--- a/mfbt/RollingMean.h
+++ b/mfbt/RollingMean.h
@@ -39,17 +39,25 @@ class RollingMean {
                 "floating-point types are unsupported due to rounding "
                 "errors");
 
   explicit RollingMean(size_t aMaxValues)
       : mInsertIndex(0), mMaxValues(aMaxValues), mTotal(0) {
     MOZ_ASSERT(aMaxValues > 0);
   }
 
-  RollingMean& operator=(RollingMean&& aOther) = default;
+  RollingMean& operator=(RollingMean&& aOther) {
+    MOZ_ASSERT(this != &aOther, "self-assignment is forbidden");
+    this->~RollingMean();
+    new (this) RollingMean(aOther.mMaxValues);
+    mInsertIndex = aOther.mInsertIndex;
+    mTotal = aOther.mTotal;
+    mValues.swap(aOther.mValues);
+    return *this;
+  }
 
   /**
    * Insert a value into the rolling mean.
    */
   bool insert(T aValue) {
     MOZ_ASSERT(mValues.length() <= mMaxValues);
 
     if (mValues.length() == mMaxValues) {
--- a/mfbt/Scoped.h
+++ b/mfbt/Scoped.h
@@ -169,28 +169,30 @@ class MOZ_NON_TEMPORARY_CLASS Scoped {
   struct MOZ_NON_TEMPORARY_CLASS name                                         \
       : public mozilla::Scoped<Traits<Type> > {                               \
     typedef mozilla::Scoped<Traits<Type> > Super;                             \
     typedef typename Super::Resource Resource;                                \
     name& operator=(Resource aRhs) {                                          \
       Super::operator=(aRhs);                                                 \
       return *this;                                                           \
     }                                                                         \
-    name& operator=(name&& aRhs) = default;                                   \
-                                                                              \
+    name& operator=(name&& aRhs) {                                            \
+      Super::operator=(std::move(aRhs));                                      \
+      return *this;                                                           \
+    }                                                                         \
     explicit name(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM)                       \
         : Super(MOZ_GUARD_OBJECT_NOTIFIER_ONLY_PARAM_TO_PARENT) {}            \
     explicit name(Resource aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM)              \
         : Super(aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) {}            \
     name(name&& aRhs MOZ_GUARD_OBJECT_NOTIFIER_PARAM)                         \
         : Super(std::move(aRhs) MOZ_GUARD_OBJECT_NOTIFIER_PARAM_TO_PARENT) {} \
                                                                               \
    private:                                                                   \
-    explicit name(const name&) = delete;                                      \
-    name& operator=(const name&) = delete;                                    \
+    explicit name(name&) = delete;                                            \
+    name& operator=(name&) = delete;                                          \
   };
 
 /*
  * MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE makes it easy to create scoped
  * pointers for types with custom deleters; just overload
  * TypeSpecificDelete(T*) in the same namespace as T to call the deleter for
  * type T.
  *
--- a/mfbt/Span.h
+++ b/mfbt/Span.h
@@ -255,17 +255,17 @@ inline constexpr span_iterator<Span, IsC
 
 template <size_t Ext>
 class extent_type {
  public:
   using index_type = size_t;
 
   static_assert(Ext >= 0, "A fixed-size Span must be >= 0 in size.");
 
-  constexpr extent_type() = default;
+  constexpr extent_type() {}
 
   template <index_type Other>
   constexpr MOZ_IMPLICIT extent_type(extent_type<Other> ext) {
     static_assert(
         Other == Ext || Other == dynamic_extent,
         "Mismatch between fixed-size extent and size of initializing data.");
     MOZ_RELEASE_ASSERT(ext.size() == Ext);
   }
--- a/mfbt/ThreadSafeWeakPtr.h
+++ b/mfbt/ThreadSafeWeakPtr.h
@@ -253,23 +253,31 @@ class SupportsThreadSafeWeakPtr : public
 // A thread-safe variant of a weak pointer
 template <typename T>
 class ThreadSafeWeakPtr {
   // Be careful to use the weak reference type T in the
   // SupportsThreadSafeWeakPtr<T> definition.
   typedef typename T::ThreadSafeWeakReference ThreadSafeWeakReference;
 
  public:
-  ThreadSafeWeakPtr() = default;
+  ThreadSafeWeakPtr() {}
+
+  ThreadSafeWeakPtr& operator=(const ThreadSafeWeakPtr& aOther) {
+    mRef = aOther.mRef;
+    return *this;
+  }
 
-  ThreadSafeWeakPtr& operator=(const ThreadSafeWeakPtr& aOther) = default;
-  ThreadSafeWeakPtr(const ThreadSafeWeakPtr& aOther) = default;
+  ThreadSafeWeakPtr(const ThreadSafeWeakPtr& aOther) : mRef(aOther.mRef) {}
 
-  ThreadSafeWeakPtr& operator=(ThreadSafeWeakPtr&& aOther) = default;
-  ThreadSafeWeakPtr(ThreadSafeWeakPtr&& aOther) = default;
+  ThreadSafeWeakPtr& operator=(ThreadSafeWeakPtr&& aOther) {
+    mRef = aOther.mRef.forget();
+    return *this;
+  }
+
+  ThreadSafeWeakPtr(ThreadSafeWeakPtr&& aOther) : mRef(aOther.mRef.forget()) {}
 
   ThreadSafeWeakPtr& operator=(const RefPtr<T>& aOther) {
     if (aOther) {
       // Get the underlying shared weak reference to the object, creating one if
       // necessary.
       mRef = aOther->getThreadSafeWeakReference();
     } else {
       mRef = nullptr;
--- a/mfbt/UniquePtr.h
+++ b/mfbt/UniquePtr.h
@@ -469,17 +469,17 @@ class UniquePtr<T[], D> {
  *
  * This is a non-issue for types which are always incomplete (i.e. opaque handle
  * types), since |delete|-ing such a type will always trigger a compilation
  * error.
  */
 template <typename T>
 class DefaultDelete {
  public:
-  constexpr DefaultDelete() = default;
+  constexpr DefaultDelete() {}
 
   template <typename U>
   MOZ_IMPLICIT DefaultDelete(
       const DefaultDelete<U>& aOther,
       typename EnableIf<mozilla::IsConvertible<U*, T*>::value, int>::Type
           aDummy = 0) {}
 
   void operator()(T* aPtr) const {
@@ -487,17 +487,17 @@ class DefaultDelete {
     delete aPtr;
   }
 };
 
 /** A default deletion policy using operator delete[]. */
 template <typename T>
 class DefaultDelete<T[]> {
  public:
-  constexpr DefaultDelete() = default;
+  constexpr DefaultDelete() {}
 
   void operator()(T* aPtr) const {
     static_assert(sizeof(T) > 0, "T must be complete");
     delete[] aPtr;
   }
 
   template <typename U>
   void operator()(U* aPtr) const = delete;
--- a/mfbt/tests/TestRollingMean.cpp
+++ b/mfbt/tests/TestRollingMean.cpp
@@ -27,17 +27,17 @@ class MyClass {
     return MyClass(mValue - aOther.mValue);
   }
 
   MyClass operator/(uint32_t aDiv) const { return MyClass(mValue / aDiv); }
 };
 
 class RollingMeanSuite {
  public:
-  RollingMeanSuite() = default;
+  RollingMeanSuite() {}
 
   void runTests() {
     testZero();
     testClear();
     testRolling();
     testClass();
     testMove();
   }
--- a/mfbt/tests/TestSPSCQueue.cpp
+++ b/mfbt/tests/TestSPSCQueue.cpp
@@ -18,34 +18,34 @@
 #endif
 
 using namespace mozilla;
 
 /* Generate a monotonically increasing sequence of numbers. */
 template <typename T>
 class SequenceGenerator {
  public:
-  SequenceGenerator() = default;
+  SequenceGenerator() {}
   void Get(T* aElements, size_t aCount) {
     for (size_t i = 0; i < aCount; i++) {
       aElements[i] = static_cast<T>(mIndex);
       mIndex++;
     }
   }
   void Rewind(size_t aCount) { mIndex -= aCount; }
 
  private:
   size_t mIndex = 0;
 };
 
 /* Checks that a sequence is monotonically increasing. */
 template <typename T>
 class SequenceVerifier {
  public:
-  SequenceVerifier() = default;
+  SequenceVerifier() {}
   void Check(T* aElements, size_t aCount) {
     for (size_t i = 0; i < aCount; i++) {
       if (aElements[i] != static_cast<T>(mIndex)) {
         std::cerr << "Element " << i << " is different. Expected "
                   << static_cast<T>(mIndex) << ", got " << aElements[i] << "."
                   << std::endl;
         MOZ_RELEASE_ASSERT(false);
       }
--- a/mfbt/tests/TestTypeTraits.cpp
+++ b/mfbt/tests/TestTypeTraits.cpp
@@ -163,17 +163,17 @@ union U2 {
 };
 static_assert(!mozilla::IsEmpty<U2>::value, "not a class => not empty");
 
 struct NE1 {
   int mX;
 };
 struct NE2 : virtual E1 {};
 struct NE3 : E2 {
-  virtual ~NE3() = default;
+  virtual ~NE3() {}
 };
 struct NE4 {
   virtual void f() {}
 };
 
 static_assert(!mozilla::IsEmpty<NE1>::value && !mozilla::IsEmpty<NE2>::value &&
                   !mozilla::IsEmpty<NE3>::value &&
                   !mozilla::IsEmpty<NE4>::value,
@@ -253,35 +253,35 @@ static_assert(!IsUnsigned<NotIntConstruc
               "non-arithmetic types are not unsigned");
 
 struct TrivialCtor0 {};
 struct TrivialCtor1 {
   int mX;
 };
 
 struct DefaultCtor0 {
-  DefaultCtor0() = default;
+  DefaultCtor0() {}
 };
 struct DefaultCtor1 {
   DefaultCtor1() = default;
 };
 struct DefaultCtor2 {
-  DefaultCtor2() = default;
+  DefaultCtor2() {}
   explicit DefaultCtor2(int) {}
 };
 
 struct NoDefaultCtor0 {
   explicit NoDefaultCtor0(int) {}
 };
 struct NoDefaultCtor1 {
   NoDefaultCtor1() = delete;
 };
 
 class PrivateCtor0 {
-  PrivateCtor0() = default;
+  PrivateCtor0() {}
 };
 class PrivateCtor1 {
   PrivateCtor1() = default;
 };
 
 enum EnumCtor0 {};
 enum EnumCtor1 : int {};
 
--- a/mfbt/tests/TestUniquePtr.cpp
+++ b/mfbt/tests/TestUniquePtr.cpp
@@ -72,17 +72,17 @@ static UniqueA ReturnLocalA() {
   return a;
 }
 
 static void TestDeleterType() {
   // Make sure UniquePtr will use its deleter's pointer type if it defines one.
   typedef int* Ptr;
   struct Deleter {
     typedef Ptr pointer;
-    Deleter() = default;
+    Deleter() {}
     void operator()(int* p) { delete p; }
   };
   UniquePtr<Ptr, Deleter> u(new int, Deleter());
 }
 
 static bool TestDefaultFreeGuts() {
   static_assert(IsSame<NewInt::DeleterType, DefaultDelete<int> >::value,
                 "weird deleter?");
@@ -211,17 +211,17 @@ static bool TestDefaultFree() {
   CHECK(gBDestructorCalls == 8);
   return true;
 }
 
 static size_t FreeClassCounter = 0;
 
 struct FreeClass {
  public:
-  FreeClass() = default;
+  FreeClass() {}
 
   void operator()(int* aPtr) {
     FreeClassCounter++;
     delete aPtr;
   }
 };
 
 typedef UniquePtr<int, FreeClass> NewIntCustom;
@@ -361,17 +361,17 @@ static bool TestFunctionReferenceDeleter
 
   CHECK(DeleteIntFunctionCallCount == 2);
 
   return true;
 }
 
 template <typename T>
 struct AppendNullptrTwice {
-  AppendNullptrTwice() = default;
+  AppendNullptrTwice() {}
 
   bool operator()(Vector<T>& vec) {
     CHECK(vec.append(nullptr));
     CHECK(vec.append(nullptr));
     return true;
   }
 };
 
@@ -476,18 +476,18 @@ static bool TestArray() {
 
   UniquePtr<A[]> a3(nullptr);
   a3.reset(new A[7]);
 
   return true;
 }
 
 struct Q {
-  Q() = default;
-  Q(const Q&) = default;
+  Q() {}
+  Q(const Q&) {}
 
   Q(Q&, char) {}
 
   template <typename T>
   Q(Q, T&&, int) {}
 
   Q(int, long, double, void*) {}
 };
--- a/mfbt/tests/gtest/TestMozDbg.cpp
+++ b/mfbt/tests/gtest/TestMozDbg.cpp
@@ -19,21 +19,24 @@ using namespace mozilla;
 #define TEST_MOZ_DBG_TYPE_SAME(expression_...)                                \
   static_assert(                                                              \
       IsSame<decltype((expression_)), decltype(MOZ_DBG(expression_))>::value, \
       "MOZ_DBG should return the same type")
 
 struct Number {
   explicit Number(int aValue) : mValue(aValue) {}
 
-  Number(const Number& aOther) = default;
+  Number(const Number& aOther) : mValue(aOther.mValue) {}
 
   Number(Number&& aOther) : mValue(aOther.mValue) { aOther.mValue = 0; }
 
-  Number& operator=(const Number& aOther) = default;
+  Number& operator=(const Number& aOther) {
+    mValue = aOther.mValue;
+    return *this;
+  }
 
   Number& operator=(Number&& aOther) {
     mValue = aOther.mValue;
     aOther.mValue = 0;
     return *this;
   }
 
   ~Number() { mValue = -999; }
@@ -45,17 +48,20 @@ struct Number {
 
 struct MoveOnly {
   explicit MoveOnly(int aValue) : mValue(aValue) {}
 
   MoveOnly(const MoveOnly& aOther) = delete;
 
   MoveOnly(MoveOnly&& aOther) : mValue(aOther.mValue) { aOther.mValue = 0; }
 
-  MoveOnly& operator=(MoveOnly& aOther) = default;
+  MoveOnly& operator=(MoveOnly& aOther) {
+    mValue = aOther.mValue;
+    return *this;
+  }
 
   MoveOnly& operator=(MoveOnly&& aOther) {
     mValue = aOther.mValue;
     aOther.mValue = 0;
     return *this;
   }
 
   int mValue;