Changes for PEP 208.  PyObject_Compare has been rewritten.  Instances no
longer get special treatment.  The Py_NotImplemented type is here as well.
diff --git a/Objects/object.c b/Objects/object.c
index 6f22c53..b11df72 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -308,20 +308,96 @@
 	return res;
 }
 
-static PyObject *
+#define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
+				Py_TPFLAGS_NEWSTYLENUMBER)
+
+static int
+cmp_to_int(PyObject *result)
+{
+	int c;
+	if (result == NULL)
+		return -1;
+	if (!PyInt_Check(result)) {
+	    PyErr_SetString(PyExc_TypeError,
+			"comparison did not return an int");
+	    return -1;
+	}
+	c = PyInt_AS_LONG(result);
+	Py_DECREF(result);
+	return (c < 0) ? -1 : (c > 0) ? 1 : 0;	
+}
+
+static int
 do_cmp(PyObject *v, PyObject *w)
 {
-	long c;
-	/* __rcmp__ actually won't be called unless __cmp__ isn't defined,
-	   because the check in cmpobject() reverses the objects first.
-	   This is intentional -- it makes no sense to define cmp(x,y)
-	   different than -cmp(y,x). */
-	if (PyInstance_Check(v) || PyInstance_Check(w))
-		return PyInstance_DoBinOp(v, w, "__cmp__", "__rcmp__", do_cmp);
-	c = PyObject_Compare(v, w);
-	if (c && PyErr_Occurred())
-		return NULL;
-	return PyInt_FromLong(c);
+	PyNumberMethods *mv, *mw;
+	PyObject *x;
+	int c;
+
+	/* new style nb_cmp gets priority */
+	mv = v->ob_type->tp_as_number;
+	if (mv != NULL && NEW_STYLE_NUMBER(v) && mv->nb_cmp) {
+		x = (*mv->nb_cmp)(v, w);
+		if (x != Py_NotImplemented)
+			return cmp_to_int(x);
+		Py_DECREF(x);
+	}
+	mw = w->ob_type->tp_as_number;
+	if (mw != NULL && NEW_STYLE_NUMBER(w) && mw->nb_cmp) {
+		x = (*mw->nb_cmp)(v, w);
+		if (x != Py_NotImplemented)
+			return cmp_to_int(x);
+		Py_DECREF(x);
+	}
+	/* fall back to tp_compare */
+	if (v->ob_type == w->ob_type) {
+		if (v->ob_type->tp_compare != NULL) {
+			return (*v->ob_type->tp_compare)(v, w);
+		}
+		else {
+			Py_uintptr_t iv = (Py_uintptr_t)v;
+			Py_uintptr_t iw = (Py_uintptr_t)w;
+			return (iv < iw) ? -1 : (iv > iw) ? 1 : 0;
+		}
+	}
+	if (PyUnicode_Check(v) || PyUnicode_Check(w)) {
+	    c = PyUnicode_Compare(v, w);
+	    if (c == -1 &&
+		PyErr_Occurred() &&
+		PyErr_ExceptionMatches(PyExc_TypeError))
+		/* TypeErrors are ignored: if Unicode coercion
+		fails due to one of the arguments not having
+		the right type, we continue as defined by the
+		coercion protocol (see above). Luckily,
+		decoding errors are reported as ValueErrors and
+		are not masked by this technique. */
+		PyErr_Clear();
+	    else
+		return c;
+	}
+	/* fall back to coercion */
+	if (mv && mw && (!NEW_STYLE_NUMBER(v) || !NEW_STYLE_NUMBER(w))) {
+		/* old style operand, both operations numeric, coerce  */
+		int err = PyNumber_CoerceEx(&v, &w);
+		if (err < 0)
+			return -1;
+		if (err == 0) {
+			if (v->ob_type->tp_compare) {
+				c = (*v->ob_type->tp_compare)(v, w);
+			}
+			else {
+				Py_uintptr_t iv = (Py_uintptr_t)v;
+				Py_uintptr_t iw = (Py_uintptr_t)w;
+				c = (iv < iw) ? -1 : (iv > iw) ? 1 : 0;
+			}
+			Py_DECREF(v);
+			Py_DECREF(w);
+			return c;
+		}
+	}
+	/* last resort, use type names */
+	c = strcmp(v->ob_type->tp_name, w->ob_type->tp_name);
+	return (c < 0) ? -1: (c > 0) ? 1 : 0;
 }
 
 PyObject *_PyCompareState_Key;
@@ -401,128 +477,42 @@
 	}
 	if (v == w)
 		return 0;
-	if (PyInstance_Check(v) || PyInstance_Check(w)) {
-		PyObject *res;
-		int c;
-		if (!PyInstance_Check(v))
-			return -PyObject_Compare(w, v);
-		_PyCompareState_nesting++;
-		if (_PyCompareState_nesting > NESTING_LIMIT) {
-			PyObject *inprogress, *pair;
-
-			inprogress = get_inprogress_dict();
-			if (inprogress == NULL) {
-				_PyCompareState_nesting--;
-				return -1;
-			}
-			pair = make_pair(v, w);
-			if (PyDict_GetItem(inprogress, pair)) {
-				/* already comparing these objects.  assume
-				   they're equal until shown otherwise */
-				Py_DECREF(pair);
-				_PyCompareState_nesting--;
-				return 0;
-			}
-			if (PyDict_SetItem(inprogress, pair, pair) == -1) {
-				_PyCompareState_nesting--;
-				return -1;
-			}
-			res = do_cmp(v, w);
-			/* XXX DelItem shouldn't fail */
-			PyDict_DelItem(inprogress, pair);
-			Py_DECREF(pair);
-		} else {
-			res = do_cmp(v, w);
-		}
-		_PyCompareState_nesting--;
-		if (res == NULL)
-			return -1;
-		if (!PyInt_Check(res)) {
-			Py_DECREF(res);
-			PyErr_SetString(PyExc_TypeError,
-					"comparison did not return an int");
-			return -1;
-		}
-		c = PyInt_AsLong(res);
-		Py_DECREF(res);
-		return (c < 0) ? -1 : (c > 0) ? 1 : 0;	
-	}
-	if ((vtp = v->ob_type) != (wtp = w->ob_type)) {
-		char *vname = vtp->tp_name;
-		char *wname = wtp->tp_name;
-		if (vtp->tp_as_number != NULL && wtp->tp_as_number != NULL) {
-			int err;
-			err = PyNumber_CoerceEx(&v, &w);
-			if (err < 0)
-				return -1;
-			else if (err == 0) {
-				int cmp;
-				vtp = v->ob_type;
-				if (vtp->tp_compare == NULL)
-					cmp = (v < w) ? -1 : 1;
-				else
-					cmp = (*vtp->tp_compare)(v, w);
-				Py_DECREF(v);
-				Py_DECREF(w);
-				return cmp;
-			}
-		}
-		else if (PyUnicode_Check(v) || PyUnicode_Check(w)) {
-			int result = PyUnicode_Compare(v, w);
-			if (result == -1 && PyErr_Occurred() && 
-			    PyErr_ExceptionMatches(PyExc_TypeError))
-				/* TypeErrors are ignored: if Unicode coercion
-				fails due to one of the arguments not
-			 	having the right type, we continue as
-				defined by the coercion protocol (see
-				above). Luckily, decoding errors are
-				reported as ValueErrors and are not masked
-				by this technique. */
-				PyErr_Clear();
-			else
-				return result;
-		}
-		else if (vtp->tp_as_number != NULL)
-			vname = "";
-		else if (wtp->tp_as_number != NULL)
-			wname = "";
-		/* Numerical types compare smaller than all other types */
-		return strcmp(vname, wname);
-	}
-	if (vtp->tp_compare == NULL) {
-		Py_uintptr_t iv = (Py_uintptr_t)v;
-		Py_uintptr_t iw = (Py_uintptr_t)w;
-		return (iv < iw) ? -1 : 1;
-	}
+	vtp = v->ob_type;
+	wtp = w->ob_type;
 	_PyCompareState_nesting++;
-	if (_PyCompareState_nesting > NESTING_LIMIT
-	    && (vtp->tp_as_mapping 
-		|| (vtp->tp_as_sequence && !PyString_Check(v)))) {
+	if (_PyCompareState_nesting > NESTING_LIMIT &&
+		(vtp->tp_as_mapping
+		 || PyInstance_Check(v)
+		 || (vtp->tp_as_sequence && !PyString_Check(v)))) {
+		/* try to detect circular data structures */
 		PyObject *inprogress, *pair;
 
 		inprogress = get_inprogress_dict();
 		if (inprogress == NULL) {
-			_PyCompareState_nesting--;
-			return -1;
+                        result = -1;
+                        goto exit_cmp;
 		}
 		pair = make_pair(v, w);
 		if (PyDict_GetItem(inprogress, pair)) {
 			/* already comparing these objects.  assume
 			   they're equal until shown otherwise */
 			Py_DECREF(pair);
-			_PyCompareState_nesting--;
-			return 0;
+                        result = 0;
+                        goto exit_cmp;
 		}
 		if (PyDict_SetItem(inprogress, pair, pair) == -1) {
-			_PyCompareState_nesting--;
-			return -1;
+                        result = -1;
+                        goto exit_cmp;
 		}
-		result = (*vtp->tp_compare)(v, w);
-		PyDict_DelItem(inprogress, pair); /* XXX shouldn't fail */
+		result = do_cmp(v, w);
+		/* XXX DelItem shouldn't fail */
+		PyDict_DelItem(inprogress, pair);
 		Py_DECREF(pair);
-	} else {
-		result = (*vtp->tp_compare)(v, w);
 	}
+	else {
+		result = do_cmp(v, w);
+	}
+exit_cmp:
 	_PyCompareState_nesting--;
 	return result;
 }
@@ -917,6 +907,37 @@
 	PyObject_HEAD_INIT(&PyNothing_Type)
 };
 
+/* NotImplemented is an object that can be used to signal that an
+   operation is not implemented for the given type combination. */
+
+static PyObject *
+NotImplemented_repr(PyObject *op)
+{
+	return PyString_FromString("NotImplemented");
+}
+
+static PyTypeObject PyNotImplemented_Type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,
+	"NotImplemented",
+	0,
+	0,
+	0,		/*tp_dealloc*/ /*never called*/
+	0,		/*tp_print*/
+	0,		/*tp_getattr*/
+	0,		/*tp_setattr*/
+	0,		/*tp_compare*/
+	(reprfunc)NotImplemented_repr, /*tp_repr*/
+	0,		/*tp_as_number*/
+	0,		/*tp_as_sequence*/
+	0,		/*tp_as_mapping*/
+	0,		/*tp_hash */
+};
+
+PyObject _Py_NotImplementedStruct = {
+	PyObject_HEAD_INIT(&PyNotImplemented_Type)
+};
+
 
 #ifdef Py_TRACE_REFS