Patch #1538606, Patch to fix __index__() clipping.

I modified this patch some by fixing style, some error checking, and adding
XXX comments.  This patch requires review and some changes are to be expected.
I'm checking in now to get the greatest possible review and establish a
baseline for moving forward.  I don't want this to hold up release if possible.
diff --git a/Objects/abstract.c b/Objects/abstract.c
index bad9f96..c8e9ddc 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -8,8 +8,6 @@
 #define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \
 				Py_TPFLAGS_CHECKTYPES)
 
-#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
-
 
 /* Shorthands to return certain errors */
 
@@ -122,9 +120,9 @@
 		return m->mp_subscript(o, key);
 
 	if (o->ob_type->tp_as_sequence) {
-		PyNumberMethods *nb = key->ob_type->tp_as_number;
-		if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
-			Py_ssize_t key_value = nb->nb_index(key);
+		if (PyIndex_Check(key)) {
+			Py_ssize_t key_value;
+			key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
 			if (key_value == -1 && PyErr_Occurred())
 				return NULL;
 			return PySequence_GetItem(o, key_value);
@@ -151,9 +149,9 @@
 		return m->mp_ass_subscript(o, key, value);
 
 	if (o->ob_type->tp_as_sequence) {
-		PyNumberMethods *nb = key->ob_type->tp_as_number;
-		if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
-			Py_ssize_t key_value = nb->nb_index(key);
+		if (PyIndex_Check(key)) {
+			Py_ssize_t key_value;
+			key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
 			if (key_value == -1 && PyErr_Occurred())
 				return -1;
 			return PySequence_SetItem(o, key_value, value);
@@ -183,9 +181,9 @@
 		return m->mp_ass_subscript(o, key, (PyObject*)NULL);
 
 	if (o->ob_type->tp_as_sequence) {
-		PyNumberMethods *nb = key->ob_type->tp_as_number;
-		if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) {
-			Py_ssize_t key_value = nb->nb_index(key);
+		if (PyIndex_Check(key)) {
+			Py_ssize_t key_value;
+			key_value = PyNumber_AsSsize_t(key, PyExc_IndexError);
 			if (key_value == -1 && PyErr_Occurred())
 				return -1;
 			return PySequence_DelItem(o, key_value);
@@ -653,9 +651,8 @@
 sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n)
 {
 	Py_ssize_t count;
-	PyNumberMethods *nb = n->ob_type->tp_as_number;
-	if (nb != NULL && HASINDEX(n) && nb->nb_index != NULL) {
-		count = nb->nb_index(n);
+	if (PyIndex_Check(n)) {
+		count = PyNumber_AsSsize_t(n, PyExc_OverflowError);
 		if (count == -1 && PyErr_Occurred())
 			return NULL;
 	}
@@ -938,23 +935,89 @@
 	return x;
 }
 
-/* Return a Py_ssize_t integer from the object item */
-Py_ssize_t 
+/* Return a Python Int or Long from the object item 
+   Raise TypeError if the result is not an int-or-long
+   or if the object cannot be interpreted as an index. 
+*/
+PyObject *
 PyNumber_Index(PyObject *item)
 {
-	Py_ssize_t value = -1;
-	PyNumberMethods *nb = item->ob_type->tp_as_number;
-	if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
-		value = nb->nb_index(item);
+	PyObject *result = NULL;
+	if (item == NULL)
+		return null_error();
+	/* XXX(nnorwitz): should these be CheckExact?  Aren't subclasses ok? */
+	if (PyInt_CheckExact(item) || PyLong_CheckExact(item)) {
+		Py_INCREF(item);
+		return item;
+	}
+	if (PyIndex_Check(item)) {
+		result = item->ob_type->tp_as_number->nb_index(item);
+		/* XXX(nnorwitz): Aren't subclasses ok here too? */
+		if (result &&
+		    !PyInt_CheckExact(result) && !PyLong_CheckExact(result)) {
+			PyErr_Format(PyExc_TypeError,
+				     "__index__ returned non-(int,long) " \
+				     "(type %.200s)",
+				     result->ob_type->tp_name);
+			Py_DECREF(result);
+			return NULL;
+		}
 	}
 	else {
 		PyErr_Format(PyExc_TypeError,
 			     "'%.200s' object cannot be interpreted "
 			     "as an index", item->ob_type->tp_name);
 	}
-	return value;
+	return result;
 }
 
+/* Return an error on Overflow only if err is not NULL*/
+
+Py_ssize_t
+PyNumber_AsSsize_t(PyObject *item, PyObject *err)
+{
+	Py_ssize_t result;
+	PyObject *runerr;
+	PyObject *value = PyNumber_Index(item);
+	if (value == NULL)
+		return -1;
+
+	/* We're done if PyInt_AsSsize_t() returns without error. */
+	result = PyInt_AsSsize_t(value);
+	if (result != -1 || !(runerr = PyErr_Occurred()))
+		goto finish;
+
+	/* Error handling code -- only manage OverflowError differently */
+	if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) 
+		goto finish;
+
+	PyErr_Clear();
+	/* If no error-handling desired then the default clipping 
+	   is sufficient.
+	 */
+	if (!err) {
+		assert(PyLong_Check(value));
+		/* Whether or not it is less than or equal to 
+		   zero is determined by the sign of ob_size
+		*/
+		if (_PyLong_Sign(value) < 0) 
+			result = PY_SSIZE_T_MIN;
+		else
+			result = PY_SSIZE_T_MAX;
+	}
+	else {
+		/* Otherwise replace the error with caller's error object. */
+		PyErr_Format(err,
+			     "cannot fit '%.200s' into an index-sized integer", 
+			     item->ob_type->tp_name); 
+	}
+	
+ finish:
+	Py_DECREF(value);
+	return result;
+}
+
+
 PyObject *
 PyNumber_Int(PyObject *o)
 {
diff --git a/Objects/classobject.c b/Objects/classobject.c
index 56bf29c..1e93908 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -1670,40 +1670,28 @@
 	return outcome > 0;
 }
 
-static Py_ssize_t
+static PyObject *
 instance_index(PyInstanceObject *self)
 {
 	PyObject *func, *res;
-	Py_ssize_t outcome;
 	static PyObject *indexstr = NULL;
 
 	if (indexstr == NULL) {
 		indexstr = PyString_InternFromString("__index__");
 		if (indexstr == NULL)
-			return -1;
+			return NULL;
 	}	
 	if ((func = instance_getattr(self, indexstr)) == NULL) {
 		if (!PyErr_ExceptionMatches(PyExc_AttributeError))
-			return -1;
+			return NULL;
 		PyErr_Clear();
 		PyErr_SetString(PyExc_TypeError, 
 				"object cannot be interpreted as an index");
-		return -1;
+		return NULL;
 	}
 	res = PyEval_CallObject(func, (PyObject *)NULL);
 	Py_DECREF(func);
-	if (res == NULL)
-		return -1;
-	if (PyInt_Check(res) || PyLong_Check(res)) {
-		outcome = res->ob_type->tp_as_number->nb_index(res);
-	}
-	else {
-		PyErr_SetString(PyExc_TypeError, 
-				"__index__ must return an int or a long");
-		outcome = -1;
-	}
-	Py_DECREF(res);
-	return outcome;
+	return res;
 }
 
 
@@ -2026,7 +2014,7 @@
 	instance_truediv,		/* nb_true_divide */
 	instance_ifloordiv,		/* nb_inplace_floor_divide */
 	instance_itruediv,		/* nb_inplace_true_divide */
-	(lenfunc)instance_index,	/* nb_index */
+	(unaryfunc)instance_index,	/* nb_index */
 };
 
 PyTypeObject PyInstance_Type = {
diff --git a/Objects/intobject.c b/Objects/intobject.c
index 2062bee..c7137df 100644
--- a/Objects/intobject.c
+++ b/Objects/intobject.c
@@ -193,16 +193,21 @@
 	PyIntObject *io;
 	Py_ssize_t val;
 #endif
-	if (op && !PyInt_CheckExact(op) && PyLong_Check(op))
+
+	if (op == NULL) {
+		PyErr_SetString(PyExc_TypeError, "an integer is required");
+		return -1;
+	}
+
+	if (PyInt_Check(op))
+		return PyInt_AS_LONG((PyIntObject*) op);
+	if (PyLong_Check(op))
 		return _PyLong_AsSsize_t(op);
 #if SIZEOF_SIZE_T == SIZEOF_LONG
 	return PyInt_AsLong(op);
 #else
 
-	if (op && PyInt_Check(op))
-		return PyInt_AS_LONG((PyIntObject*) op);
-
-	if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL ||
+	if ((nb = op->ob_type->tp_as_number) == NULL ||
 	    (nb->nb_int == NULL && nb->nb_long == 0)) {
 		PyErr_SetString(PyExc_TypeError, "an integer is required");
 		return -1;
@@ -1079,7 +1084,7 @@
 	int_true_divide,	/* nb_true_divide */
 	0,			/* nb_inplace_floor_divide */
 	0,			/* nb_inplace_true_divide */
-	PyInt_AsSsize_t,	/* nb_index */
+	(unaryfunc)int_int,	/* nb_index */
 };
 
 PyTypeObject PyInt_Type = {
diff --git a/Objects/listobject.c b/Objects/listobject.c
index f917385..ad27644 100644
--- a/Objects/listobject.c
+++ b/Objects/listobject.c
@@ -2450,14 +2450,13 @@
 "list() -> new list\n"
 "list(sequence) -> new list initialized from sequence's items");
 
-#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
 
 static PyObject *
 list_subscript(PyListObject* self, PyObject* item)
 {
-	PyNumberMethods *nb = item->ob_type->tp_as_number;	
-	if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
-		Py_ssize_t i = nb->nb_index(item);
+	if (PyIndex_Check(item)) {
+		Py_ssize_t i;
+		i = PyNumber_AsSsize_t(item, PyExc_IndexError);
 		if (i == -1 && PyErr_Occurred())
 			return NULL;
 		if (i < 0)
@@ -2504,9 +2503,8 @@
 static int
 list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
 {
-	PyNumberMethods *nb = item->ob_type->tp_as_number;
-	if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
-		Py_ssize_t i = nb->nb_index(item);
+	if (PyIndex_Check(item)) {
+		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
 		if (i == -1 && PyErr_Occurred())
 			return -1;
 		if (i < 0)
diff --git a/Objects/longobject.c b/Objects/longobject.c
index 4ce9479..e32c425 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -240,8 +240,11 @@
 	return -1;
 }
 
-static Py_ssize_t
-_long_as_ssize_t(PyObject *vv) {
+/* Get a Py_ssize_t from a long int object.
+   Returns -1 and sets an error condition if overflow occurs. */
+
+Py_ssize_t
+_PyLong_AsSsize_t(PyObject *vv) {
 	register PyLongObject *v;
 	size_t x, prev;
 	Py_ssize_t i;
@@ -277,45 +280,7 @@
  overflow:
 	PyErr_SetString(PyExc_OverflowError,
 			"long int too large to convert to int");
-	if (sign > 0)
-		return PY_SSIZE_T_MAX;
-	else
-		return PY_SSIZE_T_MIN;
-}
-
-/* Get a Py_ssize_t from a long int object.
-   Returns -1 and sets an error condition if overflow occurs. */
-
-Py_ssize_t
-_PyLong_AsSsize_t(PyObject *vv)
-{
-	Py_ssize_t x;
-
-	x = _long_as_ssize_t(vv);
-	if (PyErr_Occurred()) return -1;
-	return x;
-}
-
-
-/* Get a Py_ssize_t from a long int object.
-   Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
-   and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1.
-   On error, return -1 with an exception set.
-*/
-
-static Py_ssize_t
-long_index(PyObject *vv)
-{
-	Py_ssize_t x;
-
-	x = _long_as_ssize_t(vv);
-	if (PyErr_Occurred()) {
-		/* If overflow error, ignore the error */
-		if (x != -1) {
-			PyErr_Clear();
-		}
-	}
-	return x;
+	return -1;
 }
 
 /* Get a C unsigned long int from a long int object.
@@ -3405,7 +3370,7 @@
 	long_true_divide,		/* nb_true_divide */
 	0,				/* nb_inplace_floor_divide */
 	0,				/* nb_inplace_true_divide */
-	long_index,			/* nb_index */
+	long_long,			/* nb_index */
 };
 
 PyTypeObject PyLong_Type = {
diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c
index 271a9ad..d8a2465 100644
--- a/Objects/sliceobject.c
+++ b/Objects/sliceobject.c
@@ -252,7 +252,7 @@
 {
 	Py_ssize_t ilen, start, stop, step, slicelength;
 
-	ilen = PyInt_AsSsize_t(len);
+	ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
 
 	if (ilen == -1 && PyErr_Occurred()) {
 		return NULL;
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index 91f0103..bbbeaa6 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -1184,14 +1184,11 @@
 	return x;
 }
 
-#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
-
 static PyObject*
 string_subscript(PyStringObject* self, PyObject* item)
 {
-	PyNumberMethods *nb = item->ob_type->tp_as_number;
-	if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
-		Py_ssize_t i = nb->nb_index(item);
+	if (PyIndex_Check(item)) {
+		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
 		if (i == -1 && PyErr_Occurred())
 			return NULL;
 		if (i < 0)
diff --git a/Objects/tupleobject.c b/Objects/tupleobject.c
index 2161ab9..6f3711f 100644
--- a/Objects/tupleobject.c
+++ b/Objects/tupleobject.c
@@ -577,14 +577,11 @@
 	(objobjproc)tuplecontains,		/* sq_contains */
 };
 
-#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
-
 static PyObject*
 tuplesubscript(PyTupleObject* self, PyObject* item)
 {
-	PyNumberMethods *nb = item->ob_type->tp_as_number;
-	if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
-		Py_ssize_t i = nb->nb_index(item);
+	if (PyIndex_Check(item)) {
+		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
 		if (i == -1 && PyErr_Occurred())
 			return NULL;
 		if (i < 0)
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 485d2bb..517d4db 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3527,7 +3527,7 @@
 
 	if (!PyArg_UnpackTuple(args, "", 1, 1, &o))
 		return NULL;
-	i = PyNumber_Index(o);
+	i = PyNumber_AsSsize_t(o, PyExc_OverflowError);
 	if (i == -1 && PyErr_Occurred())
 		return NULL;
 	return (*func)(self, i);
@@ -3538,7 +3538,7 @@
 {
 	Py_ssize_t i;
 
-	i = PyNumber_Index(arg);
+	i = PyNumber_AsSsize_t(arg, PyExc_OverflowError);
 	if (i == -1 && PyErr_Occurred())
 		return -1;
 	if (i < 0) {
@@ -4344,26 +4344,11 @@
 }
 
 
-static Py_ssize_t 
+static PyObject *
 slot_nb_index(PyObject *self)
 {
 	static PyObject *index_str;
-	PyObject *temp = call_method(self, "__index__", &index_str, "()");
-	Py_ssize_t result;
-
-	if (temp == NULL)
-		return -1;
-	if (PyInt_CheckExact(temp) || PyLong_CheckExact(temp)) {
-		result = temp->ob_type->tp_as_number->nb_index(temp);
-	}
-	else {
-		PyErr_Format(PyExc_TypeError, 
-			     "__index__ must return an int or a long, "
-			     "not '%.200s'", temp->ob_type->tp_name);
-		result = -1;
-	}
-	Py_DECREF(temp);
-	return result;
+	return call_method(self, "__index__", &index_str, "()");
 }
 
 
@@ -5109,7 +5094,7 @@
 	       "oct(x)"),
 	UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
 	       "hex(x)"),
-	NBSLOT("__index__", nb_index, slot_nb_index, wrap_lenfunc, 
+	NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, 
 	       "x[y:z] <==> x[y.__index__():z.__index__()]"),
 	IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
 	       wrap_binaryfunc, "+"),
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 096dfc6..ababda1 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -6985,14 +6985,11 @@
     PyUnicode_Contains, 		/* sq_contains */
 };
 
-#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX)
-
 static PyObject*
 unicode_subscript(PyUnicodeObject* self, PyObject* item)
 {
-    PyNumberMethods *nb = item->ob_type->tp_as_number;
-    if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) {
-        Py_ssize_t i = nb->nb_index(item);
+    if (PyIndex_Check(item)) {
+        Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
         if (i == -1 && PyErr_Occurred())
             return NULL;
         if (i < 0)