Make Callback.Equals() only work when comparing against the same type.

Previously, we were using the base class's comparator to check equality, which allows us to make comparisons across callbacks of different types. This disallows such a thing.

BUG=none
TEST=New no-compile test.

Review URL: http://codereview.chromium.org/7780016

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100565 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/base/base.gyp b/base/base.gyp
index e78db0a2..ae754ce6 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -119,6 +119,7 @@
         'bind_unittest.nc',
         'bits_unittest.cc',
         'callback_unittest.cc',
+        'callback_unittest.nc',
         'command_line_unittest.cc',
         'cpu_unittest.cc',
         'debug/leak_tracker_unittest.cc',
diff --git a/base/bind_unittest.nc b/base/bind_unittest.nc
index 2d07cbb..eba8747bb 100644
--- a/base/bind_unittest.nc
+++ b/base/bind_unittest.nc
@@ -80,27 +80,6 @@
   method_to_const_cb.Run();
 }
 
-#elif defined(NCTEST_CONSTRUCTION_FROM_SUBTYPE)  // [r"conversion from 'base::Callback<int\(\)>' to non-scalar type 'base::Callback<void\(\)>'"]
-
-// Construction of Callback<A> from Callback<B> if A is supertype of B.
-//
-// While this is technically safe, most people aren't used to it when coding
-// C++ so if this is happening, it is almost certainly an error.
-void WontCompile() {
-  Callback<int(void)> cb_a = Bind(&PolymorphicIdentity<int>, 1);
-  Callback<void(void)> cb_b = cb_a;
-}
-
-#elif defined(NCTEST_ASSIGNMENT_FROM_SUBTYPE)  // [r"no match for 'operator=' in 'cb_a = cb_b'"]
-
-// Assignment of Callback<A> from Callback<B> if A is supertype of B.
-// See explanation for NCTEST_CONSTRUCTION_FROM_SUBTYPE
-void WontCompile() {
-  Callback<int(void)> cb_a = Bind(&PolymorphicIdentity<int>, 1);
-  Callback<void(void)> cb_b;
-  cb_a = cb_b;
-}
-
 #elif defined(NCTEST_METHOD_BIND_NEEDS_REFCOUNTED_OBJECT)  // [r"has no member named 'AddRef'"]
 
 // Method bound to non-refcounted object.
diff --git a/base/callback.h b/base/callback.h
index c1f584d5..03abb4b 100644
--- a/base/callback.h
+++ b/base/callback.h
@@ -258,6 +258,10 @@
                    callback_type_does_not_match_bind_result);
   }
 
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
   R Run() const {
     PolymorphicInvoke f =
         reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
@@ -292,6 +296,10 @@
                    callback_type_does_not_match_bind_result);
   }
 
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
   R Run(typename internal::ParamTraits<A1>::ForwardType a1) const {
     PolymorphicInvoke f =
         reinterpret_cast<PolymorphicInvoke>(polymorphic_invoke_);
@@ -327,6 +335,10 @@
                    callback_type_does_not_match_bind_result);
   }
 
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
   R Run(typename internal::ParamTraits<A1>::ForwardType a1,
         typename internal::ParamTraits<A2>::ForwardType a2) const {
     PolymorphicInvoke f =
@@ -365,6 +377,10 @@
                    callback_type_does_not_match_bind_result);
   }
 
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
   R Run(typename internal::ParamTraits<A1>::ForwardType a1,
         typename internal::ParamTraits<A2>::ForwardType a2,
         typename internal::ParamTraits<A3>::ForwardType a3) const {
@@ -406,6 +422,10 @@
                    callback_type_does_not_match_bind_result);
   }
 
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
   R Run(typename internal::ParamTraits<A1>::ForwardType a1,
         typename internal::ParamTraits<A2>::ForwardType a2,
         typename internal::ParamTraits<A3>::ForwardType a3,
@@ -451,6 +471,10 @@
                    callback_type_does_not_match_bind_result);
   }
 
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
   R Run(typename internal::ParamTraits<A1>::ForwardType a1,
         typename internal::ParamTraits<A2>::ForwardType a2,
         typename internal::ParamTraits<A3>::ForwardType a3,
@@ -499,6 +523,10 @@
                    callback_type_does_not_match_bind_result);
   }
 
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
   R Run(typename internal::ParamTraits<A1>::ForwardType a1,
         typename internal::ParamTraits<A2>::ForwardType a2,
         typename internal::ParamTraits<A3>::ForwardType a3,
diff --git a/base/callback.h.pump b/base/callback.h.pump
index 3b9aa733..82b643e 100644
--- a/base/callback.h.pump
+++ b/base/callback.h.pump
@@ -274,6 +274,10 @@
                    callback_type_does_not_match_bind_result);
   }
 
+  bool Equals(const Callback& other) const {
+    return CallbackBase::Equals(other);
+  }
+
   R Run($for ARG ,
         [[typename internal::ParamTraits<A$(ARG)>::ForwardType a$(ARG)]]) const {
     PolymorphicInvoke f =
diff --git a/base/callback_internal.h b/base/callback_internal.h
index 1543ecac..176547c 100644
--- a/base/callback_internal.h
+++ b/base/callback_internal.h
@@ -62,9 +62,9 @@
   // Returns the Callback into an uninitalized state.
   void Reset();
 
+ protected:
   bool Equals(const CallbackBase& other) const;
 
- protected:
   // In C++, it is safe to cast function pointers to function pointers of
   // another type. It is not okay to use void*. We create a InvokeFuncStorage
   // that that can store our function pointer, and then cast it back to
diff --git a/base/callback_unittest.nc b/base/callback_unittest.nc
new file mode 100644
index 0000000..9bddd1f8
--- /dev/null
+++ b/base/callback_unittest.nc
@@ -0,0 +1,50 @@
+// 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.
+
+#include "base/callback.h"
+
+namespace base {
+
+class Parent {
+};
+
+class Child : Parent {
+};
+
+#if defined(NCTEST_EQUALS_REQUIRES_SAMETYPE)  // [r"no matching function for call to 'base::Callback<void\(\)>::Equals\(base::Callback<int\(\)>&\)'"]
+
+// Attempting to call comparison function on two callbacks of different type.
+//
+// This should be a compile time failure because each callback type should be
+// considered distinct.
+void WontCompile() {
+  Closure c1;
+  Callback<int(void)> c2;
+  c1.Equals(c2);
+}
+
+#elif defined(NCTEST_CONSTRUCTION_FROM_SUBTYPE)  // [r"conversion from 'base::Callback<base::Parent\(\)>' to non-scalar type 'base::Callback<base::Child\(\)>'"]
+
+// Construction of Callback<A> from Callback<B> if A is supertype of B.
+//
+// While this is technically safe, most people aren't used to it when coding
+// C++ so if this is happening, it is almost certainly an error.
+void WontCompile() {
+  Callback<Parent(void)> cb_a;
+  Callback<Child(void)> cb_b = cb_a;
+}
+
+#elif defined(NCTEST_ASSIGNMENT_FROM_SUBTYPE)  // [r"no match for 'operator=' in 'cb_a = cb_b'"]
+
+// Assignment of Callback<A> from Callback<B> if A is supertype of B.
+// See explanation for NCTEST_CONSTRUCTION_FROM_SUBTYPE
+void WontCompile() {
+  Callback<Parent(void)> cb_a;
+  Callback<Child(void)> cb_b;
+  cb_a = cb_b;
+}
+
+#endif
+
+}  // namespace base