Issue 2235: __hash__ is once again inherited by default, but inheritance can be blocked explicitly so that collections.Hashable remains meaningful
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index e0ae55b..0af3f30 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3648,27 +3648,6 @@
 		type->tp_flags |= Py_TPFLAGS_DICT_SUBCLASS;
 }
 
-static char *hash_name_op[] = {
-	"__eq__",
-	"__cmp__",
-	"__hash__",
-	NULL
-};
-
-static int
-overrides_hash(PyTypeObject *type)
-{
-	char **p;
-	PyObject *dict = type->tp_dict;
-
-	assert(dict != NULL);
-	for (p = hash_name_op; *p; p++) {
-		if (PyDict_GetItemString(dict, *p) != NULL)
-			return 1;
-	}
-	return 0;
-}
-
 static void
 inherit_slots(PyTypeObject *type, PyTypeObject *base)
 {
@@ -3802,8 +3781,7 @@
 	if (type->tp_flags & base->tp_flags & Py_TPFLAGS_HAVE_RICHCOMPARE) {
 		if (type->tp_compare == NULL &&
 		    type->tp_richcompare == NULL &&
-		    type->tp_hash == NULL &&
-		    !overrides_hash(type))
+		    type->tp_hash == NULL)
 		{
 			type->tp_compare = base->tp_compare;
 			type->tp_richcompare = base->tp_richcompare;
@@ -3984,18 +3962,6 @@
 		}
 	}
 
-	/* Hack for tp_hash and __hash__.
-	   If after all that, tp_hash is still NULL, and __hash__ is not in
-	   tp_dict, set tp_dict['__hash__'] equal to None.
-	   This signals that __hash__ is not inherited.
-	*/
-	if (type->tp_hash == NULL &&
-	    PyDict_GetItemString(type->tp_dict, "__hash__") == NULL &&
-	    PyDict_SetItemString(type->tp_dict, "__hash__", Py_None) < 0)
-	{
-		goto error;
-	}
-
 	/* Some more special stuff */
 	base = type->tp_base;
 	if (base != NULL) {
@@ -5280,10 +5246,8 @@
 			func = lookup_method(self, "__cmp__", &cmp_str);
 		}
 		if (func != NULL) {
-			PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'",
-				     self->ob_type->tp_name);
 			Py_DECREF(func);
-			return -1;
+			return PyObject_HashNotImplemented(self);
 		}
 		PyErr_Clear();
 		h = _Py_HashPointer((void *)self);
@@ -6034,6 +5998,13 @@
 			   sanity checks.  I'll buy the first person to
 			   point out a bug in this reasoning a beer. */
 		}
+		else if (descr == Py_None &&
+			 strcmp(p->name, "__hash__") == 0) {
+			/* We specifically allow __hash__ to be set to None
+			   to prevent inheritance of the default
+			   implementation from object.__hash__ */
+			specific = PyObject_HashNotImplemented;
+		}
 		else {
 			use_generic = 1;
 			generic = p->function;
@@ -6247,12 +6218,21 @@
 			continue;
 		if (PyDict_GetItem(dict, p->name_strobj))
 			continue;
-		descr = PyDescr_NewWrapper(type, p, *ptr);
-		if (descr == NULL)
-			return -1;
-		if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)
-			return -1;
-		Py_DECREF(descr);
+		if (*ptr == PyObject_HashNotImplemented) {
+			/* Classes may prevent the inheritance of the tp_hash
+			   slot by storing PyObject_HashNotImplemented in it. Make it
+ 			   visible as a None value for the __hash__ attribute. */
+			if (PyDict_SetItem(dict, p->name_strobj, Py_None) < 0)
+				return -1;
+		}
+		else {
+			descr = PyDescr_NewWrapper(type, p, *ptr);
+			if (descr == NULL)
+				return -1;
+			if (PyDict_SetItem(dict, p->name_strobj, descr) < 0)
+				return -1;
+			Py_DECREF(descr);
+		}
 	}
 	if (type->tp_new != NULL) {
 		if (add_tp_new_wrapper(type) < 0)