Pull the new r369476 of base library from Chromium
The merge was done against r369476 which corresponds to git commit
0471d0e2e2ef4a544a63481a389e1df33ea7c00a of Jan 14, 2016
Change-Id: Ie6894cf65424cc5ad115110faccd51602b2d1234
Reviewed-on: https://weave-review.googlesource.com/2225
Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/third_party/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h b/third_party/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
new file mode 100644
index 0000000..33bacba
--- /dev/null
+++ b/third_party/chromium/base/memory/raw_scoped_refptr_mismatch_checker.h
@@ -0,0 +1,64 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+#define BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
+
+#include "base/memory/ref_counted.h"
+#include "base/template_util.h"
+#include "base/tuple.h"
+#include "build/build_config.h"
+
+// It is dangerous to post a task with a T* argument where T is a subtype of
+// RefCounted(Base|ThreadSafeBase), since by the time the parameter is used, the
+// object may already have been deleted since it was not held with a
+// scoped_refptr. Example: http://crbug.com/27191
+// The following set of traits are designed to generate a compile error
+// whenever this antipattern is attempted.
+
+namespace base {
+
+// This is a base internal implementation file used by task.h and callback.h.
+// Not for public consumption, so we wrap it in namespace internal.
+namespace internal {
+
+template <typename T>
+struct NeedsScopedRefptrButGetsRawPtr {
+#if defined(OS_WIN)
+ enum {
+ value = base::false_type::value
+ };
+#else
+ enum {
+ // Human readable translation: you needed to be a scoped_refptr if you are a
+ // raw pointer type and are convertible to a RefCounted(Base|ThreadSafeBase)
+ // type.
+ value = (std::is_pointer<T>::value &&
+ (std::is_convertible<T, subtle::RefCountedBase*>::value ||
+ std::is_convertible<T, subtle::RefCountedThreadSafeBase*>::value))
+ };
+#endif
+};
+
+template <typename Params>
+struct ParamsUseScopedRefptrCorrectly {
+ enum { value = 0 };
+};
+
+template <>
+struct ParamsUseScopedRefptrCorrectly<Tuple<>> {
+ enum { value = 1 };
+};
+
+template <typename Head, typename... Tail>
+struct ParamsUseScopedRefptrCorrectly<Tuple<Head, Tail...>> {
+ enum { value = !NeedsScopedRefptrButGetsRawPtr<Head>::value &&
+ ParamsUseScopedRefptrCorrectly<Tuple<Tail...>>::value };
+};
+
+} // namespace internal
+
+} // namespace base
+
+#endif // BASE_MEMORY_RAW_SCOPED_REFPTR_MISMATCH_CHECKER_H_
diff --git a/third_party/chromium/base/memory/ref_counted.h b/third_party/chromium/base/memory/ref_counted.h
index 52e8f00..95fa565 100644
--- a/third_party/chromium/base/memory/ref_counted.h
+++ b/third_party/chromium/base/memory/ref_counted.h
@@ -11,8 +11,8 @@
#include "base/base_export.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/logging.h"
-#include "base/move.h"
#include "build/build_config.h"
namespace base {
@@ -105,7 +105,7 @@
// ~MyFoo();
// };
//
-// You should always make your destructor private, to avoid any code deleting
+// You should always make your destructor non-public, to avoid any code deleting
// the object accidently while there are references to it.
template <class T>
class RefCounted : public subtle::RefCountedBase {
@@ -252,7 +252,6 @@
//
template <class T>
class scoped_refptr {
- TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_refptr)
public:
typedef T element_type;
@@ -264,17 +263,24 @@
AddRef(ptr_);
}
+ // Copy constructor.
scoped_refptr(const scoped_refptr<T>& r) : ptr_(r.ptr_) {
if (ptr_)
AddRef(ptr_);
}
+ // Copy conversion constructor.
template <typename U>
scoped_refptr(const scoped_refptr<U>& r) : ptr_(r.get()) {
if (ptr_)
AddRef(ptr_);
}
+ // Move constructor. This is required in addition to the conversion
+ // constructor below in order for clang to warn about pessimizing moves.
+ scoped_refptr(scoped_refptr&& r) : ptr_(r.get()) { r.ptr_ = nullptr; }
+
+ // Move conversion constructor.
template <typename U>
scoped_refptr(scoped_refptr<U>&& r) : ptr_(r.get()) {
r.ptr_ = nullptr;
@@ -318,13 +324,13 @@
}
scoped_refptr<T>& operator=(scoped_refptr<T>&& r) {
- scoped_refptr<T>(r.Pass()).swap(*this);
+ scoped_refptr<T>(std::move(r)).swap(*this);
return *this;
}
template <typename U>
scoped_refptr<T>& operator=(scoped_refptr<U>&& r) {
- scoped_refptr<T>(r.Pass()).swap(*this);
+ scoped_refptr<T>(std::move(r)).swap(*this);
return *this;
}
diff --git a/third_party/chromium/base/memory/ref_counted_unittest.cc b/third_party/chromium/base/memory/ref_counted_unittest.cc
index 9eda813..88ee981 100644
--- a/third_party/chromium/base/memory/ref_counted_unittest.cc
+++ b/third_party/chromium/base/memory/ref_counted_unittest.cc
@@ -169,26 +169,6 @@
EXPECT_EQ(p2, p1);
}
-TEST(RefCountedUnitTest, SelfMoveAssignment) {
- ScopedRefPtrCountBase::reset_count();
-
- {
- ScopedRefPtrCountBase *raw = new ScopedRefPtrCountBase();
- scoped_refptr<ScopedRefPtrCountBase> p(raw);
- EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
- EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
-
- p = p.Pass();
- EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
- EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- EXPECT_EQ(raw, p.get());
-
- // p goes out of scope.
- }
- EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
- EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
-}
-
TEST(RefCountedUnitTest, MoveAssignment1) {
ScopedRefPtrCountBase::reset_count();
@@ -201,7 +181,7 @@
{
scoped_refptr<ScopedRefPtrCountBase> p2;
- p2 = p1.Pass();
+ p2 = std::move(p1);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -232,7 +212,7 @@
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw, p1.get());
@@ -263,7 +243,7 @@
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw, p1.get());
@@ -294,7 +274,7 @@
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p2 = p1.Pass();
+ p2 = std::move(p1);
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -326,7 +306,7 @@
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(raw2, p1.get());
@@ -363,7 +343,7 @@
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
- p1 = p2.Pass();
+ p1 = std::move(p2);
EXPECT_EQ(2, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(1, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
@@ -396,7 +376,7 @@
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
{
- scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+ scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(nullptr, p1.get());
@@ -426,7 +406,7 @@
EXPECT_EQ(0, ScopedRefPtrCountDerived::destructor_count());
{
- scoped_refptr<ScopedRefPtrCountBase> p2(p1.Pass());
+ scoped_refptr<ScopedRefPtrCountBase> p2(std::move(p1));
EXPECT_EQ(1, ScopedRefPtrCountBase::constructor_count());
EXPECT_EQ(0, ScopedRefPtrCountBase::destructor_count());
EXPECT_EQ(1, ScopedRefPtrCountDerived::constructor_count());
diff --git a/third_party/chromium/base/memory/scoped_ptr.h b/third_party/chromium/base/memory/scoped_ptr.h
index 2aa1b32..d68604e 100644
--- a/third_party/chromium/base/memory/scoped_ptr.h
+++ b/third_party/chromium/base/memory/scoped_ptr.h
@@ -37,42 +37,43 @@
// in that they are "movable but not copyable." You can use the scopers in
// the parameter and return types of functions to signify ownership transfer
// in to and out of a function. When calling a function that has a scoper
-// as the argument type, it must be called with the result of an analogous
-// scoper's Pass() function or another function that generates a temporary;
-// passing by copy will NOT work. Here is an example using scoped_ptr:
+// as the argument type, it must be called with an rvalue of a scoper, which
+// can be created by using std::move(), or the result of another function that
+// generates a temporary; passing by copy will NOT work. Here is an example
+// using scoped_ptr:
//
// void TakesOwnership(scoped_ptr<Foo> arg) {
-// // Do something with arg
+// // Do something with arg.
// }
// scoped_ptr<Foo> CreateFoo() {
-// // No need for calling Pass() because we are constructing a temporary
-// // for the return value.
+// // No need for calling std::move() for returning a move-only value, or
+// // when you already have an rvalue as we do here.
// return scoped_ptr<Foo>(new Foo("new"));
// }
// scoped_ptr<Foo> PassThru(scoped_ptr<Foo> arg) {
-// return arg.Pass();
+// return arg;
// }
//
// {
// scoped_ptr<Foo> ptr(new Foo("yay")); // ptr manages Foo("yay").
-// TakesOwnership(ptr.Pass()); // ptr no longer owns Foo("yay").
+// TakesOwnership(std::move(ptr)); // ptr no longer owns Foo("yay").
// scoped_ptr<Foo> ptr2 = CreateFoo(); // ptr2 owns the return Foo.
// scoped_ptr<Foo> ptr3 = // ptr3 now owns what was in ptr2.
-// PassThru(ptr2.Pass()); // ptr2 is correspondingly nullptr.
+// PassThru(std::move(ptr2)); // ptr2 is correspondingly nullptr.
// }
//
-// Notice that if you do not call Pass() when returning from PassThru(), or
+// Notice that if you do not call std::move() when returning from PassThru(), or
// when invoking TakesOwnership(), the code will not compile because scopers
// are not copyable; they only implement move semantics which require calling
-// the Pass() function to signify a destructive transfer of state. CreateFoo()
-// is different though because we are constructing a temporary on the return
-// line and thus can avoid needing to call Pass().
+// the std::move() function to signify a destructive transfer of state.
+// CreateFoo() is different though because we are constructing a temporary on
+// the return line and thus can avoid needing to call std::move().
//
-// Pass() properly handles upcast in initialization, i.e. you can use a
-// scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
+// The conversion move-constructor properly handles upcast in initialization,
+// i.e. you can use a scoped_ptr<Child> to initialize a scoped_ptr<Parent>:
//
// scoped_ptr<Foo> foo(new Foo());
-// scoped_ptr<FooParent> parent(foo.Pass());
+// scoped_ptr<FooParent> parent(std::move(foo));
#ifndef BASE_MEMORY_SCOPED_PTR_H_
#define BASE_MEMORY_SCOPED_PTR_H_
@@ -84,11 +85,13 @@
#include <stddef.h>
#include <stdlib.h>
-#include <algorithm> // For std::swap().
#include <iosfwd>
+#include <memory>
+#include <type_traits>
+#include <utility>
-#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "base/macros.h"
#include "base/move.h"
#include "base/template_util.h"
@@ -99,61 +102,6 @@
class RefCountedThreadSafeBase;
} // namespace subtle
-// Function object which deletes its parameter, which must be a pointer.
-// If C is an array type, invokes 'delete[]' on the parameter; otherwise,
-// invokes 'delete'. The default deleter for scoped_ptr<T>.
-template <class T>
-struct DefaultDeleter {
- DefaultDeleter() {}
- template <typename U> DefaultDeleter(const DefaultDeleter<U>& other) {
- // IMPLEMENTATION NOTE: C++11 20.7.1.1.2p2 only provides this constructor
- // if U* is implicitly convertible to T* and U is not an array type.
- //
- // Correct implementation should use SFINAE to disable this
- // constructor. However, since there are no other 1-argument constructors,
- // using a COMPILE_ASSERT() based on is_convertible<> and requiring
- // complete types is simpler and will cause compile failures for equivalent
- // misuses.
- //
- // Note, the is_convertible<U*, T*> check also ensures that U is not an
- // array. T is guaranteed to be a non-array, so any U* where U is an array
- // cannot convert to T*.
- enum { T_must_be_complete = sizeof(T) };
- enum { U_must_be_complete = sizeof(U) };
- COMPILE_ASSERT((std::is_convertible<U*, T*>::value),
- U_ptr_must_implicitly_convert_to_T_ptr);
- }
- inline void operator()(T* ptr) const {
- enum { type_must_be_complete = sizeof(T) };
- delete ptr;
- }
-};
-
-// Specialization of DefaultDeleter for array types.
-template <class T>
-struct DefaultDeleter<T[]> {
- inline void operator()(T* ptr) const {
- enum { type_must_be_complete = sizeof(T) };
- delete[] ptr;
- }
-
- private:
- // Disable this operator for any U != T because it is undefined to execute
- // an array delete when the static type of the array mismatches the dynamic
- // type.
- //
- // References:
- // C++98 [expr.delete]p3
- // http://cplusplus.github.com/LWG/lwg-defects.html#938
- template <typename U> void operator()(U* array) const;
-};
-
-template <class T, int n>
-struct DefaultDeleter<T[n]> {
- // Never allow someone to declare something like scoped_ptr<int[10]>.
- COMPILE_ASSERT(sizeof(T) == -1, do_not_use_array_with_size_as_type);
-};
-
// Function object which invokes 'free' on its parameter, which must be
// a pointer. Can be used to store malloc-allocated pointers in scoped_ptr:
//
@@ -175,17 +123,6 @@
};
};
-template <typename T>
-struct ShouldAbortOnSelfReset {
- template <typename U>
- static NoType Test(const typename U::AllowSelfReset*);
-
- template <typename U>
- static YesType Test(...);
-
- static const bool value = sizeof(Test<T>(0)) == sizeof(YesType);
-};
-
// Minimal implementation of the core logic of scoped_ptr, suitable for
// reuse in both scoped_ptr and its specializations.
template <class T, class D>
@@ -216,37 +153,28 @@
}
~scoped_ptr_impl() {
- if (data_.ptr != nullptr) {
- // Not using get_deleter() saves one function call in non-optimized
- // builds.
- static_cast<D&>(data_)(data_.ptr);
- }
+ // Match libc++, which calls reset() in its destructor.
+ // Use nullptr as the new value for three reasons:
+ // 1. libc++ does it.
+ // 2. Avoids infinitely recursing into destructors if two classes are owned
+ // in a reference cycle (see ScopedPtrTest.ReferenceCycle).
+ // 3. If |this| is accessed in the future, in a use-after-free bug, attempts
+ // to dereference |this|'s pointer should cause either a failure or a
+ // segfault closer to the problem. If |this| wasn't reset to nullptr,
+ // the access would cause the deleted memory to be read or written
+ // leading to other more subtle issues.
+ reset(nullptr);
}
void reset(T* p) {
- // This is a self-reset, which is no longer allowed for default deleters:
- // https://crbug.com/162971
- assert(!ShouldAbortOnSelfReset<D>::value || p == nullptr || p != data_.ptr);
-
- // Note that running data_.ptr = p can lead to undefined behavior if
- // get_deleter()(get()) deletes this. In order to prevent this, reset()
- // should update the stored pointer before deleting its old value.
- //
- // However, changing reset() to use that behavior may cause current code to
- // break in unexpected ways. If the destruction of the owned object
- // dereferences the scoped_ptr when it is destroyed by a call to reset(),
- // then it will incorrectly dispatch calls to |p| rather than the original
- // value of |data_.ptr|.
- //
- // During the transition period, set the stored pointer to nullptr while
- // deleting the object. Eventually, this safety check will be removed to
- // prevent the scenario initially described from occuring and
- // http://crbug.com/176091 can be closed.
+ // Match C++11's definition of unique_ptr::reset(), which requires changing
+ // the pointer before invoking the deleter on the old pointer. This prevents
+ // |this| from being accessed after the deleter is run, which may destroy
+ // |this|.
T* old = data_.ptr;
- data_.ptr = nullptr;
+ data_.ptr = p;
if (old != nullptr)
static_cast<D&>(data_)(old);
- data_.ptr = p;
}
T* get() const { return data_.ptr; }
@@ -300,25 +228,27 @@
// dereference it, you get the thread safety guarantees of T.
//
// The size of scoped_ptr is small. On most compilers, when using the
-// DefaultDeleter, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters will
-// increase the size proportional to whatever state they need to have. See
+// std::default_delete, sizeof(scoped_ptr<T>) == sizeof(T*). Custom deleters
+// will increase the size proportional to whatever state they need to have. See
// comments inside scoped_ptr_impl<> for details.
//
// Current implementation targets having a strict subset of C++11's
// unique_ptr<> features. Known deficiencies include not supporting move-only
// deleteres, function pointers as deleters, and deleters with reference
// types.
-template <class T, class D = base::DefaultDeleter<T> >
+template <class T, class D = std::default_delete<T>>
class scoped_ptr {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
- COMPILE_ASSERT(base::internal::IsNotRefCounted<T>::value,
- T_is_refcounted_type_and_needs_scoped_refptr);
+ static_assert(!std::is_array<T>::value,
+ "scoped_ptr doesn't support array with size");
+ static_assert(base::internal::IsNotRefCounted<T>::value,
+ "T is a refcounted type and needs a scoped_refptr");
public:
// The element and deleter types.
- typedef T element_type;
- typedef D deleter_type;
+ using element_type = T;
+ using deleter_type = D;
// Constructor. Defaults to initializing with nullptr.
scoped_ptr() : impl_(nullptr) {}
@@ -330,44 +260,87 @@
scoped_ptr(element_type* p, const D& d) : impl_(p, d) {}
// Constructor. Allows construction from a nullptr.
- scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+ scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
- // Constructor. Allows construction from a scoped_ptr rvalue for a
+ // Move constructor.
+ //
+ // IMPLEMENTATION NOTE: Clang requires a move constructor to be defined (and
+ // not just the conversion constructor) in order to warn on pessimizing moves.
+ // The requirements for the move constructor are specified in C++11
+ // 20.7.1.2.1.15-17, which has some subtleties around reference deleters. As
+ // we don't support reference (or move-only) deleters, the post conditions are
+ // trivially true: we always copy construct the deleter from other's deleter.
+ scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
+
+ // Conversion constructor. Allows construction from a scoped_ptr rvalue for a
// convertible type and deleter.
//
- // IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this constructor distinct
- // from the normal move constructor. By C++11 20.7.1.2.1.21, this constructor
- // has different post-conditions if D is a reference type. Since this
- // implementation does not support deleters with reference type,
- // we do not need a separate move constructor allowing us to avoid one
- // use of SFINAE. You only need to care about this if you modify the
- // implementation of scoped_ptr.
- template <typename U, typename V>
- scoped_ptr(scoped_ptr<U, V>&& other)
- : impl_(&other.impl_) {
- COMPILE_ASSERT(!std::is_array<U>::value, U_cannot_be_an_array);
+ // IMPLEMENTATION NOTE: C++ 20.7.1.2.1.19 requires this constructor to only
+ // participate in overload resolution if all the following are true:
+ // - U is implicitly convertible to T: this is important for 2 reasons:
+ // 1. So type traits don't incorrectly return true, e.g.
+ // std::is_convertible<scoped_ptr<Base>, scoped_ptr<Derived>>::value
+ // should be false.
+ // 2. To make sure code like this compiles:
+ // void F(scoped_ptr<int>);
+ // void F(scoped_ptr<Base>);
+ // // Ambiguous since both conversion constructors match.
+ // F(scoped_ptr<Derived>());
+ // - U is not an array type: to prevent conversions from scoped_ptr<T[]> to
+ // scoped_ptr<T>.
+ // - D is a reference type and E is the same type, or D is not a reference
+ // type and E is implicitly convertible to D: again, we don't support
+ // reference deleters, so we only worry about the latter requirement.
+ template <typename U,
+ typename E,
+ typename std::enable_if<!std::is_array<U>::value &&
+ std::is_convertible<U*, T*>::value &&
+ std::is_convertible<E, D>::value>::type* =
+ nullptr>
+ scoped_ptr(scoped_ptr<U, E>&& other)
+ : impl_(&other.impl_) {}
+
+ // operator=.
+ //
+ // IMPLEMENTATION NOTE: Unlike the move constructor, Clang does not appear to
+ // require a move assignment operator to trigger the pessimizing move warning:
+ // in this case, the warning triggers when moving a temporary. For consistency
+ // with the move constructor, we define it anyway. C++11 20.7.1.2.3.1-3
+ // defines several requirements around this: like the move constructor, the
+ // requirements are simplified by the fact that we don't support move-only or
+ // reference deleters.
+ scoped_ptr& operator=(scoped_ptr&& rhs) {
+ impl_.TakeState(&rhs.impl_);
+ return *this;
}
// operator=. Allows assignment from a scoped_ptr rvalue for a convertible
// type and deleter.
//
// IMPLEMENTATION NOTE: C++11 unique_ptr<> keeps this operator= distinct from
- // the normal move assignment operator. By C++11 20.7.1.2.3.4, this templated
- // form has different requirements on for move-only Deleters. Since this
- // implementation does not support move-only Deleters, we do not need a
- // separate move assignment operator allowing us to avoid one use of SFINAE.
- // You only need to care about this if you modify the implementation of
- // scoped_ptr.
- template <typename U, typename V>
- scoped_ptr& operator=(scoped_ptr<U, V>&& rhs) {
- COMPILE_ASSERT(!std::is_array<U>::value, U_cannot_be_an_array);
+ // the normal move assignment operator. C++11 20.7.1.2.3.4-7 contains the
+ // requirement for this operator, but like the conversion constructor, the
+ // requirements are greatly simplified by not supporting move-only or
+ // reference deleters.
+ template <typename U,
+ typename E,
+ typename std::enable_if<!std::is_array<U>::value &&
+ std::is_convertible<U*, T*>::value &&
+ // Note that this really should be
+ // std::is_assignable, but <type_traits>
+ // appears to be missing this on some
+ // platforms. This is close enough (though
+ // it's not the same).
+ std::is_convertible<D, E>::value>::type* =
+ nullptr>
+ scoped_ptr& operator=(scoped_ptr<U, E>&& rhs) {
impl_.TakeState(&rhs.impl_);
return *this;
}
// operator=. Allows assignment from a nullptr. Deletes the currently owned
// object, if any.
- scoped_ptr& operator=(decltype(nullptr)) {
+ scoped_ptr& operator=(std::nullptr_t) {
reset();
return *this;
}
@@ -408,12 +381,6 @@
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
}
- // Comparison operators.
- // These return whether two scoped_ptr refer to the same object, not just to
- // two different but equal objects.
- bool operator==(const element_type* p) const { return impl_.get() == p; }
- bool operator!=(const element_type* p) const { return impl_.get() != p; }
-
// Swap two scoped pointers.
void swap(scoped_ptr& p2) {
impl_.swap(p2.impl_);
@@ -434,23 +401,16 @@
// Forbidden for API compatibility with std::unique_ptr.
explicit scoped_ptr(int disallow_construction_from_null);
-
- // Forbid comparison of scoped_ptr types. If U != T, it totally
- // doesn't make sense, and if U == T, it still doesn't make sense
- // because you should never have the same object owned by two different
- // scoped_ptrs.
- template <class U> bool operator==(scoped_ptr<U> const& p2) const;
- template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
template <class T, class D>
class scoped_ptr<T[], D> {
- MOVE_ONLY_TYPE_WITH_MOVE_CONSTRUCTOR_FOR_CPP_03(scoped_ptr)
+ DISALLOW_COPY_AND_ASSIGN_WITH_MOVE_FOR_BIND(scoped_ptr)
public:
// The element and deleter types.
- typedef T element_type;
- typedef D deleter_type;
+ using element_type = T;
+ using deleter_type = D;
// Constructor. Defaults to initializing with nullptr.
scoped_ptr() : impl_(nullptr) {}
@@ -465,13 +425,11 @@
// (C++98 [expr.delete]p3). If you're doing this, fix your code.
// - it cannot be const-qualified differently from T per unique_ptr spec
// (http://cplusplus.github.com/LWG/lwg-active.html#2118). Users wanting
- // to work around this may use implicit_cast<const T*>().
- // However, because of the first bullet in this comment, users MUST
- // NOT use implicit_cast<Base*>() to upcast the static type of the array.
+ // to work around this may use const_cast<const T*>().
explicit scoped_ptr(element_type* array) : impl_(array) {}
// Constructor. Allows construction from a nullptr.
- scoped_ptr(decltype(nullptr)) : impl_(nullptr) {}
+ scoped_ptr(std::nullptr_t) : impl_(nullptr) {}
// Constructor. Allows construction from a scoped_ptr rvalue.
scoped_ptr(scoped_ptr&& other) : impl_(&other.impl_) {}
@@ -484,7 +442,7 @@
// operator=. Allows assignment from a nullptr. Deletes the currently owned
// array, if any.
- scoped_ptr& operator=(decltype(nullptr)) {
+ scoped_ptr& operator=(std::nullptr_t) {
reset();
return *this;
}
@@ -515,12 +473,6 @@
return impl_.get() ? &scoped_ptr::impl_ : nullptr;
}
- // Comparison operators.
- // These return whether two scoped_ptr refer to the same object, not just to
- // two different but equal objects.
- bool operator==(element_type* array) const { return impl_.get() == array; }
- bool operator!=(element_type* array) const { return impl_.get() != array; }
-
// Swap two scoped pointers.
void swap(scoped_ptr& p2) {
impl_.swap(p2.impl_);
@@ -553,13 +505,6 @@
// reasons as the constructor above.
template <typename U> void reset(U* array);
void reset(int disallow_reset_from_null);
-
- // Forbid comparison of scoped_ptr types. If U != T, it totally
- // doesn't make sense, and if U == T, it still doesn't make sense
- // because you should never have the same object owned by two different
- // scoped_ptrs.
- template <class U> bool operator==(scoped_ptr<U> const& p2) const;
- template <class U> bool operator!=(scoped_ptr<U> const& p2) const;
};
// Free functions
@@ -568,14 +513,84 @@
p1.swap(p2);
}
+template <class T1, class D1, class T2, class D2>
+bool operator==(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p1.get() == p2.get();
+}
template <class T, class D>
-bool operator==(T* p1, const scoped_ptr<T, D>& p2) {
- return p1 == p2.get();
+bool operator==(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return p.get() == nullptr;
+}
+template <class T, class D>
+bool operator==(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return p.get() == nullptr;
}
+template <class T1, class D1, class T2, class D2>
+bool operator!=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 == p2);
+}
template <class T, class D>
-bool operator!=(T* p1, const scoped_ptr<T, D>& p2) {
- return p1 != p2.get();
+bool operator!=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p == nullptr);
+}
+template <class T, class D>
+bool operator!=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(p == nullptr);
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator<(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p1.get() < p2.get();
+}
+template <class T, class D>
+bool operator<(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ auto* ptr = p.get();
+ return ptr < static_cast<decltype(ptr)>(nullptr);
+}
+template <class T, class D>
+bool operator<(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ auto* ptr = p.get();
+ return static_cast<decltype(ptr)>(nullptr) < ptr;
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator>(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return p2 < p1;
+}
+template <class T, class D>
+bool operator>(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return nullptr < p;
+}
+template <class T, class D>
+bool operator>(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return p < nullptr;
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator<=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 > p2);
+}
+template <class T, class D>
+bool operator<=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p > nullptr);
+}
+template <class T, class D>
+bool operator<=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(nullptr > p);
+}
+
+template <class T1, class D1, class T2, class D2>
+bool operator>=(const scoped_ptr<T1, D1>& p1, const scoped_ptr<T2, D2>& p2) {
+ return !(p1 < p2);
+}
+template <class T, class D>
+bool operator>=(const scoped_ptr<T, D>& p, std::nullptr_t) {
+ return !(p < nullptr);
+}
+template <class T, class D>
+bool operator>=(std::nullptr_t, const scoped_ptr<T, D>& p) {
+ return !(nullptr < p);
}
// A function to convert T* into scoped_ptr<T>
diff --git a/third_party/chromium/base/memory/scoped_ptr_unittest.cc b/third_party/chromium/base/memory/scoped_ptr_unittest.cc
index d4ff410..c1eb469 100644
--- a/third_party/chromium/base/memory/scoped_ptr_unittest.cc
+++ b/third_party/chromium/base/memory/scoped_ptr_unittest.cc
@@ -4,13 +4,16 @@
#include "base/memory/scoped_ptr.h"
+#include <stddef.h>
+
#include <sstream>
#include <gtest/gtest.h>
-#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
+#include "base/macros.h"
+#include "build/build_config.h"
namespace {
@@ -85,7 +88,7 @@
int OverloadedNewAndDelete::g_delete_count = 0;
scoped_ptr<ConDecLogger> PassThru(scoped_ptr<ConDecLogger> logger) {
- return logger.Pass();
+ return logger;
}
void GrabAndDrop(scoped_ptr<ConDecLogger> logger) {
@@ -103,8 +106,8 @@
int constructed = 0;
// Ensure size of scoped_ptr<> doesn't increase unexpectedly.
- COMPILE_ASSERT(sizeof(int*) >= sizeof(scoped_ptr<int>),
- scoped_ptr_larger_than_raw_ptr);
+ static_assert(sizeof(int*) >= sizeof(scoped_ptr<int>),
+ "scoped_ptr shouldn't be larger than the raw pointer");
{
scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
@@ -147,25 +150,25 @@
}
EXPECT_EQ(0, constructed);
- // Test swap(), == and !=
+ // Test swap().
{
scoped_ptr<ConDecLogger> scoper1;
scoped_ptr<ConDecLogger> scoper2;
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != scoper2.get());
ConDecLogger* logger = new ConDecLogger(&constructed);
scoper1.reset(logger);
EXPECT_EQ(logger, scoper1.get());
EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
scoper2.swap(scoper1);
EXPECT_EQ(logger, scoper2.get());
EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
}
EXPECT_EQ(0, constructed);
}
@@ -179,7 +182,7 @@
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper.get());
- scoped_ptr<ConDecLoggerParent> scoper_parent(scoper.Pass());
+ scoped_ptr<ConDecLoggerParent> scoper_parent(std::move(scoper));
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_parent.get());
EXPECT_FALSE(scoper.get());
@@ -197,7 +200,7 @@
EXPECT_TRUE(scoper.get());
scoped_ptr<ConDecLoggerParent> scoper_parent;
- scoper_parent = scoper.Pass();
+ scoper_parent = std::move(scoper);
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_parent.get());
EXPECT_FALSE(scoper.get());
@@ -210,7 +213,7 @@
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper.get());
- scoped_ptr<const ConDecLogger> scoper_const(scoper.Pass());
+ scoped_ptr<const ConDecLogger> scoper_const(std::move(scoper));
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_const.get());
EXPECT_FALSE(scoper.get());
@@ -228,7 +231,7 @@
EXPECT_TRUE(scoper.get());
scoped_ptr<const ConDecLogger> scoper_const;
- scoper_const = scoper.Pass();
+ scoper_const = std::move(scoper);
EXPECT_EQ(1, constructed);
EXPECT_TRUE(scoper_const.get());
EXPECT_FALSE(scoper.get());
@@ -252,7 +255,7 @@
EXPECT_EQ(0, alternate_deletes);
// Test this compiles and correctly overwrites the deleter state.
- scoper = scoper_child.Pass();
+ scoper = std::move(scoper_child);
EXPECT_TRUE(scoper);
EXPECT_FALSE(scoper_child);
EXPECT_EQ(1, deletes);
@@ -268,7 +271,8 @@
EXPECT_TRUE(scoper_child);
EXPECT_EQ(1, deletes);
EXPECT_EQ(1, alternate_deletes);
- scoped_ptr<double, CountingDeleter> scoper_construct(scoper_child.Pass());
+ scoped_ptr<double, CountingDeleter> scoper_construct(
+ std::move(scoper_child));
EXPECT_TRUE(scoper_construct);
EXPECT_FALSE(scoper_child);
EXPECT_EQ(1, deletes);
@@ -328,12 +332,12 @@
}
EXPECT_EQ(0, constructed);
- // Test swap(), ==, !=, and type-safe Boolean.
+ // Test swap() and type-safe Boolean.
{
scoped_ptr<ConDecLogger[]> scoper1;
scoped_ptr<ConDecLogger[]> scoper2;
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != scoper2.get());
ConDecLogger* loggers = new ConDecLogger[kNumLoggers];
for (int i = 0; i < kNumLoggers; ++i) {
@@ -344,14 +348,14 @@
EXPECT_EQ(loggers, scoper1.get());
EXPECT_FALSE(scoper2);
EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
scoper2.swap(scoper1);
EXPECT_EQ(loggers, scoper2.get());
EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
}
EXPECT_EQ(0, constructed);
@@ -364,13 +368,13 @@
}
EXPECT_EQ(kNumLoggers, constructed);
- // Test Pass() with constructor;
- scoped_ptr<ConDecLogger[]> scoper2(scoper.Pass());
+ // Test moving with constructor;
+ scoped_ptr<ConDecLogger[]> scoper2(std::move(scoper));
EXPECT_EQ(kNumLoggers, constructed);
- // Test Pass() with assignment;
+ // Test moving with assignment;
scoped_ptr<ConDecLogger[]> scoper3;
- scoper3 = scoper2.Pass();
+ scoper3 = std::move(scoper2);
EXPECT_EQ(kNumLoggers, constructed);
EXPECT_FALSE(scoper);
EXPECT_FALSE(scoper2);
@@ -379,27 +383,30 @@
EXPECT_EQ(0, constructed);
}
-TEST(ScopedPtrTest, PassBehavior) {
+TEST(ScopedPtrTest, MoveBehavior) {
int constructed = 0;
{
ConDecLogger* logger = new ConDecLogger(&constructed);
scoped_ptr<ConDecLogger> scoper(logger);
EXPECT_EQ(1, constructed);
- // Test Pass() with constructor;
- scoped_ptr<ConDecLogger> scoper2(scoper.Pass());
+ // Test moving with constructor;
+ scoped_ptr<ConDecLogger> scoper2(std::move(scoper));
EXPECT_EQ(1, constructed);
- // Test Pass() with assignment;
+ // Test moving with assignment;
scoped_ptr<ConDecLogger> scoper3;
- scoper3 = scoper2.Pass();
+ scoper3 = std::move(scoper2);
EXPECT_EQ(1, constructed);
EXPECT_FALSE(scoper.get());
EXPECT_FALSE(scoper2.get());
EXPECT_TRUE(scoper3.get());
}
- // Test uncaught Pass() does not have side effects.
+#if !defined(OS_ANDROID) && !defined(OS_LINUX)
+ // Test uncaught Pass() does not have side effects, because Pass()
+ // is implemented by std::move().
+ // TODO(danakj): Remove this test case when we remove Pass().
{
ConDecLogger* logger = new ConDecLogger(&constructed);
scoped_ptr<ConDecLogger> scoper(logger);
@@ -412,6 +419,7 @@
EXPECT_TRUE(rvalue);
}
EXPECT_EQ(0, constructed);
+#endif
// Test that passing to function which does nothing does not leak.
{
@@ -420,7 +428,7 @@
EXPECT_EQ(1, constructed);
// Should auto-destruct logger by end of scope.
- GrabAndDrop(scoper.Pass());
+ GrabAndDrop(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -435,7 +443,7 @@
scoped_ptr<ConDecLogger> scoper(logger);
EXPECT_EQ(1, constructed);
- PassThru(scoper.Pass());
+ PassThru(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -447,7 +455,7 @@
EXPECT_EQ(1, constructed);
// Should auto-destruct logger by end of scope.
- PassThru(scoper.Pass());
+ PassThru(std::move(scoper));
EXPECT_FALSE(scoper.get());
}
EXPECT_EQ(0, constructed);
@@ -538,8 +546,8 @@
// Pass the second deleter through a constructor and an operator=. Then
// reinitialize the empty scopers to ensure that each one is deleting
// properly.
- scoped_ptr<double, CountingDeleter> scoper3(scoper2.Pass());
- scoper = scoper3.Pass();
+ scoped_ptr<double, CountingDeleter> scoper3(std::move(scoper2));
+ scoper = std::move(scoper3);
EXPECT_EQ(1, deletes);
scoper2.reset(&dummy_value2);
@@ -550,33 +558,33 @@
EXPECT_EQ(1, deletes);
EXPECT_EQ(3, alternate_deletes);
- // Test swap(), ==, !=, and type-safe Boolean.
+ // Test swap(), and type-safe Boolean.
{
scoped_ptr<double, CountingDeleter> scoper1(NULL,
CountingDeleter(&deletes));
scoped_ptr<double, CountingDeleter> scoper2(NULL,
CountingDeleter(&deletes));
- EXPECT_TRUE(scoper1 == scoper2.get());
- EXPECT_FALSE(scoper1 != scoper2.get());
+ EXPECT_TRUE(scoper1.get() == scoper2.get());
+ EXPECT_FALSE(scoper1.get() != scoper2.get());
scoper1.reset(&dummy_value);
EXPECT_TRUE(scoper1);
EXPECT_EQ(&dummy_value, scoper1.get());
EXPECT_FALSE(scoper2);
EXPECT_FALSE(scoper2.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
scoper2.swap(scoper1);
EXPECT_EQ(&dummy_value, scoper2.get());
EXPECT_FALSE(scoper1.get());
- EXPECT_FALSE(scoper1 == scoper2.get());
- EXPECT_TRUE(scoper1 != scoper2.get());
+ EXPECT_FALSE(scoper1.get() == scoper2.get());
+ EXPECT_TRUE(scoper1.get() != scoper2.get());
}
}
// Sanity check test for overloaded new and delete operators. Does not do full
-// coverage of reset/release/Pass() operations as that is redundant with the
+// coverage of reset/release/move operations as that is redundant with the
// above.
TEST(ScopedPtrTest, OverloadedNewAndDelete) {
{
@@ -584,7 +592,7 @@
scoped_ptr<OverloadedNewAndDelete> scoper(new OverloadedNewAndDelete());
EXPECT_TRUE(scoper.get());
- scoped_ptr<OverloadedNewAndDelete> scoper2(scoper.Pass());
+ scoped_ptr<OverloadedNewAndDelete> scoper2(std::move(scoper));
}
EXPECT_EQ(1, OverloadedNewAndDelete::delete_count());
EXPECT_EQ(1, OverloadedNewAndDelete::new_count());
@@ -633,55 +641,15 @@
scoped_ptr<Sub> sub1(new Sub);
scoped_ptr<Sub> sub2(new Sub);
- // Upcast with Pass() works.
- scoped_ptr<Super> super1 = sub1.Pass();
- super1 = sub2.Pass();
+ // Upcast with move works.
+ scoped_ptr<Super> super1 = std::move(sub1);
+ super1 = std::move(sub2);
// Upcast with an rvalue works.
scoped_ptr<Super> super2 = SubClassReturn();
super2 = SubClassReturn();
}
-// Android death tests don't work properly with assert(). Yay.
-#if !defined(NDEBUG) && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID)
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultDeleter) {
- scoped_ptr<int> x(new int);
- EXPECT_DEATH(x.reset(x.get()), "");
-}
-
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultArrayDeleter) {
- scoped_ptr<int[]> y(new int[4]);
- EXPECT_DEATH(y.reset(y.get()), "");
-}
-
-TEST(ScopedPtrTest, SelfResetAbortsWithDefaultFreeDeleter) {
- scoped_ptr<int, base::FreeDeleter> z(static_cast<int*>(malloc(sizeof(int))));
- EXPECT_DEATH(z.reset(z.get()), "");
-}
-
-// A custom deleter that doesn't opt out should still crash.
-TEST(ScopedPtrTest, SelfResetAbortsWithCustomDeleter) {
- struct CustomDeleter {
- inline void operator()(int* x) { delete x; }
- };
- scoped_ptr<int, CustomDeleter> x(new int);
- EXPECT_DEATH(x.reset(x.get()), "");
-}
-#endif
-
-TEST(ScopedPtrTest, SelfResetWithCustomDeleterOptOut) {
- // A custom deleter should be able to opt out of self-reset abort behavior.
- struct NoOpDeleter {
-#if !defined(NDEBUG)
- typedef void AllowSelfReset;
-#endif
- inline void operator()(int*) {}
- };
- scoped_ptr<int> owner(new int);
- scoped_ptr<int, NoOpDeleter> x(owner.get());
- x.reset(x.get());
-}
-
// Logging a scoped_ptr<T> to an ostream shouldn't convert it to a boolean
// value first.
TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
@@ -694,3 +662,182 @@
EXPECT_EQ(s2.str(), s1.str());
}
+
+TEST(ScopedPtrTest, ReferenceCycle) {
+ struct StructB;
+ struct StructA {
+ scoped_ptr<StructB> b;
+ };
+
+ struct StructB {
+ scoped_ptr<StructA> a;
+ };
+
+ // Create a reference cycle.
+ StructA* a = new StructA;
+ a->b.reset(new StructB);
+ a->b->a.reset(a);
+
+ // Break the cycle by calling reset(). This will cause |a| (and hence, |a->b|)
+ // to be deleted before the call to reset() returns. This tests that the
+ // implementation of scoped_ptr::reset() doesn't access |this| after it
+ // deletes the underlying pointer. This behaviour is consistent with the
+ // definition of unique_ptr::reset in C++11.
+ a->b.reset();
+
+ // Go again, but this time, break the cycle by invoking |a|'s destructor. This
+ // tests that the implementation of ~scoped_ptr doesn't infinitely recurse
+ // into the destructors of |a| and |a->b|. Note, deleting |a| instead will
+ // cause |a| to be double-free'd because |a->b| owns |a| and deletes it via
+ // its destructor.
+ a = new StructA;
+ a->b.reset(new StructB);
+ a->b->a.reset(a);
+ a->~StructA();
+}
+
+TEST(ScopedPtrTest, Operators) {
+ struct Parent {};
+ struct Child : public Parent {};
+
+ scoped_ptr<Parent> p(new Parent);
+ scoped_ptr<Parent> p2(new Parent);
+ scoped_ptr<Child> c(new Child);
+ scoped_ptr<Parent> pnull;
+
+ // Operator==.
+ EXPECT_TRUE(p == p);
+ EXPECT_FALSE(p == c);
+ EXPECT_FALSE(p == p2);
+ EXPECT_FALSE(p == pnull);
+
+ EXPECT_FALSE(p == nullptr);
+ EXPECT_FALSE(nullptr == p);
+ EXPECT_TRUE(pnull == nullptr);
+ EXPECT_TRUE(nullptr == pnull);
+
+ // Operator!=.
+ EXPECT_FALSE(p != p);
+ EXPECT_TRUE(p != c);
+ EXPECT_TRUE(p != p2);
+ EXPECT_TRUE(p != pnull);
+
+ EXPECT_TRUE(p != nullptr);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_FALSE(pnull != nullptr);
+ EXPECT_FALSE(nullptr != pnull);
+
+ // Compare two scoped_ptr<T>.
+ EXPECT_EQ(p.get() < p2.get(), p < p2);
+ EXPECT_EQ(p.get() <= p2.get(), p <= p2);
+ EXPECT_EQ(p.get() > p2.get(), p > p2);
+ EXPECT_EQ(p.get() >= p2.get(), p >= p2);
+ EXPECT_EQ(p2.get() < p.get(), p2 < p);
+ EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
+ EXPECT_EQ(p2.get() > p.get(), p2 > p);
+ EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
+
+ // And convertible scoped_ptr<T> and scoped_ptr<U>.
+ EXPECT_EQ(p.get() < c.get(), p < c);
+ EXPECT_EQ(p.get() <= c.get(), p <= c);
+ EXPECT_EQ(p.get() > c.get(), p > c);
+ EXPECT_EQ(p.get() >= c.get(), p >= c);
+ EXPECT_EQ(c.get() < p.get(), c < p);
+ EXPECT_EQ(c.get() <= p.get(), c <= p);
+ EXPECT_EQ(c.get() > p.get(), c > p);
+ EXPECT_EQ(c.get() >= p.get(), c >= p);
+
+ // Compare to nullptr.
+ EXPECT_TRUE(p > nullptr);
+ EXPECT_FALSE(nullptr > p);
+ EXPECT_FALSE(pnull > nullptr);
+ EXPECT_FALSE(nullptr > pnull);
+
+ EXPECT_TRUE(p >= nullptr);
+ EXPECT_FALSE(nullptr >= p);
+ EXPECT_TRUE(pnull >= nullptr);
+ EXPECT_TRUE(nullptr >= pnull);
+
+ EXPECT_FALSE(p < nullptr);
+ EXPECT_TRUE(nullptr < p);
+ EXPECT_FALSE(pnull < nullptr);
+ EXPECT_FALSE(nullptr < pnull);
+
+ EXPECT_FALSE(p <= nullptr);
+ EXPECT_TRUE(nullptr <= p);
+ EXPECT_TRUE(pnull <= nullptr);
+ EXPECT_TRUE(nullptr <= pnull);
+};
+
+TEST(ScopedPtrTest, ArrayOperators) {
+ struct Parent {};
+ struct Child : public Parent {};
+
+ scoped_ptr<Parent[]> p(new Parent[1]);
+ scoped_ptr<Parent[]> p2(new Parent[1]);
+ scoped_ptr<Child[]> c(new Child[1]);
+ scoped_ptr<Parent[]> pnull;
+
+ // Operator==.
+ EXPECT_TRUE(p == p);
+ EXPECT_FALSE(p == c);
+ EXPECT_FALSE(p == p2);
+ EXPECT_FALSE(p == pnull);
+
+ EXPECT_FALSE(p == nullptr);
+ EXPECT_FALSE(nullptr == p);
+ EXPECT_TRUE(pnull == nullptr);
+ EXPECT_TRUE(nullptr == pnull);
+
+ // Operator!=.
+ EXPECT_FALSE(p != p);
+ EXPECT_TRUE(p != c);
+ EXPECT_TRUE(p != p2);
+ EXPECT_TRUE(p != pnull);
+
+ EXPECT_TRUE(p != nullptr);
+ EXPECT_TRUE(nullptr != p);
+ EXPECT_FALSE(pnull != nullptr);
+ EXPECT_FALSE(nullptr != pnull);
+
+ // Compare two scoped_ptr<T>.
+ EXPECT_EQ(p.get() < p2.get(), p < p2);
+ EXPECT_EQ(p.get() <= p2.get(), p <= p2);
+ EXPECT_EQ(p.get() > p2.get(), p > p2);
+ EXPECT_EQ(p.get() >= p2.get(), p >= p2);
+ EXPECT_EQ(p2.get() < p.get(), p2 < p);
+ EXPECT_EQ(p2.get() <= p.get(), p2 <= p);
+ EXPECT_EQ(p2.get() > p.get(), p2 > p);
+ EXPECT_EQ(p2.get() >= p.get(), p2 >= p);
+
+ // And convertible scoped_ptr<T> and scoped_ptr<U>.
+ EXPECT_EQ(p.get() < c.get(), p < c);
+ EXPECT_EQ(p.get() <= c.get(), p <= c);
+ EXPECT_EQ(p.get() > c.get(), p > c);
+ EXPECT_EQ(p.get() >= c.get(), p >= c);
+ EXPECT_EQ(c.get() < p.get(), c < p);
+ EXPECT_EQ(c.get() <= p.get(), c <= p);
+ EXPECT_EQ(c.get() > p.get(), c > p);
+ EXPECT_EQ(c.get() >= p.get(), c >= p);
+
+ // Compare to nullptr.
+ EXPECT_TRUE(p > nullptr);
+ EXPECT_FALSE(nullptr > p);
+ EXPECT_FALSE(pnull > nullptr);
+ EXPECT_FALSE(nullptr > pnull);
+
+ EXPECT_TRUE(p >= nullptr);
+ EXPECT_FALSE(nullptr >= p);
+ EXPECT_TRUE(pnull >= nullptr);
+ EXPECT_TRUE(nullptr >= pnull);
+
+ EXPECT_FALSE(p < nullptr);
+ EXPECT_TRUE(nullptr < p);
+ EXPECT_FALSE(pnull < nullptr);
+ EXPECT_FALSE(nullptr < pnull);
+
+ EXPECT_FALSE(p <= nullptr);
+ EXPECT_TRUE(nullptr <= p);
+ EXPECT_TRUE(pnull <= nullptr);
+ EXPECT_TRUE(nullptr <= pnull);
+}
diff --git a/third_party/chromium/base/memory/weak_ptr.h b/third_party/chromium/base/memory/weak_ptr.h
index e07beeb..c1c52ee 100644
--- a/third_party/chromium/base/memory/weak_ptr.h
+++ b/third_party/chromium/base/memory/weak_ptr.h
@@ -16,6 +16,7 @@
//
// class Controller {
// public:
+// Controller() : weak_factory_(this) {}
// void SpawnWorker() { Worker::StartNew(weak_factory_.GetWeakPtr()); }
// void WorkComplete(const Result& result) { ... }
// private:
@@ -58,15 +59,20 @@
// off to other task runners, e.g. to use to post tasks back to object on the
// bound sequence.
//
-// Invalidating the factory's WeakPtrs un-binds it from the sequence, allowing
-// it to be passed for a different sequence to use or delete it.
+// If all WeakPtr objects are destroyed or invalidated then the factory is
+// unbound from the SequencedTaskRunner/Thread. The WeakPtrFactory may then be
+// destroyed, or new WeakPtr objects may be used, from a different sequence.
+//
+// Thus, at least one WeakPtr object must exist and have been dereferenced on
+// the correct thread to enforce that other WeakPtr objects will enforce they
+// are used on the desired thread.
#ifndef BASE_MEMORY_WEAK_PTR_H_
#define BASE_MEMORY_WEAK_PTR_H_
-#include "base/basictypes.h"
#include "base/base_export.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/memory/ref_counted.h"
namespace base {
@@ -152,8 +158,8 @@
static WeakPtr<Derived> StaticAsWeakPtr(Derived* t) {
typedef std::is_convertible<Derived*, internal::SupportsWeakPtrBase*>
convertible;
- COMPILE_ASSERT(convertible::value,
- AsWeakPtr_argument_inherits_from_SupportsWeakPtr);
+ static_assert(convertible::value,
+ "AsWeakPtr argument must inherit from SupportsWeakPtr");
return AsWeakPtrImpl<Derived>(t, *t);
}