Clear errors raised by PyObject_Compare() without losing any existing
exception context.  This avoids improperly propogating errors raised by
a user-defined __cmp__() by a subsequent lookup operation.

This patch does *not* include the performance enhancement patch for
dictionaries with string keys only; that will be checked in separately.

This closes SourceForge patch #101277 and bug #112558.
diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index ddd8eb8..621ed73 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -139,6 +139,10 @@
 	register unsigned int mask = mp->ma_size-1;
 	dictentry *ep0 = mp->ma_table;
 	register dictentry *ep;
+	register int restore_error = 0;
+	register int checked_error = 0;
+	register int cmp;
+	PyObject *err_type, *err_value, *err_tb;
 	/* We must come up with (i, incr) such that 0 <= i < ma_size
 	   and 0 < incr < ma_size and both are a function of hash */
 	i = (~hash) & mask;
@@ -151,14 +155,25 @@
 	if (ep->me_key == dummy)
 		freeslot = ep;
 	else {
-		if (ep->me_hash == hash &&
-		    PyObject_Compare(ep->me_key, key) == 0)
-		{
-			return ep;
+		if (ep->me_hash == hash) {
+			/* error can't have been checked yet */
+			checked_error = 1;
+			if (PyErr_Occurred()) {
+				restore_error = 1;
+				PyErr_Fetch(&err_type, &err_value, &err_tb);
+			}
+			cmp = PyObject_Compare(ep->me_key, key);
+			if (PyErr_Occurred())
+				PyErr_Clear();
+			else if (cmp == 0) {
+				if (restore_error)
+					PyErr_Restore(err_type, err_value,
+						      err_tb);
+				return ep;
+			}
 		}
 		freeslot = NULL;
 	}
-	/* XXX What if PyObject_Compare returned an exception? */
 	/* Derive incr from hash, just to make it more arbitrary. Note that
 	   incr must not be 0, or we will get into an infinite loop.*/
 	incr = (hash ^ ((unsigned long)hash >> 3)) & mask;
@@ -167,6 +182,8 @@
 	for (;;) {
 		ep = &ep0[(i+incr)&mask];
 		if (ep->me_key == NULL) {
+			if (restore_error)
+				PyErr_Restore(err_type, err_value, err_tb);
 			if (freeslot != NULL)
 				return freeslot;
 			else
@@ -176,12 +193,30 @@
 			if (freeslot == NULL)
 				freeslot = ep;
 		}
-		else if (ep->me_key == key ||
-			 (ep->me_hash == hash &&
-			  PyObject_Compare(ep->me_key, key) == 0)) {
+		else if (ep->me_key == key) {
+			if (restore_error)
+				PyErr_Restore(err_type, err_value, err_tb);
 			return ep;
+                }
+                else if (ep->me_hash == hash) {
+			if (!checked_error) {
+				checked_error = 1;
+				if (PyErr_Occurred()) {
+					restore_error = 1;
+					PyErr_Fetch(&err_type, &err_value,
+						    &err_tb);
+				}
+			}
+			cmp = PyObject_Compare(ep->me_key, key);
+			if (PyErr_Occurred())
+				PyErr_Clear();
+			else if (cmp == 0) {
+				if (restore_error)
+					PyErr_Restore(err_type, err_value,
+						      err_tb);
+				return ep;
+			}
 		}
-		/* XXX What if PyObject_Compare returned an exception? */
 		/* Cycle through GF(2^n)-{0} */
 		incr = incr << 1;
 		if (incr > mask)