[Python-checkins] python/dist/src/Objects object.c,2.175,2.176

gvanrossum@users.sourceforge.net gvanrossum@users.sourceforge.net
Fri, 31 May 2002 13:03:56 -0700


Update of /cvsroot/python/python/dist/src/Objects
In directory usw-pr-cvs1:/tmp/cvs-serv27720

Modified Files:
	object.c 
Log Message:
Implement the intention of SF patch 472523 (but coded differently).

In the past, an object's tp_compare could return any value.  In 2.2
the docs were tightened to require it to return -1, 0 or 1; and -1 for
an error.

We now issue a warning if the value is not in this range.  When an
exception is raised, we allow -1 or -2 as return value, since -2 will
the recommended return value for errors in the future.  (Eventually
tp_compare will also be allowed to return +2, to indicate
NotImplemented; but that can only be implemented once we know all
extensions return a value in [-2...1].  Or perhaps it will require the
type to set a flag bit.)

I haven't decided yet whether to backport this to 2.2.x.  The patch
applies fine.  But is it fair to start warning in 2.2.2 about code
that worked flawlessly in 2.2.1?


Index: object.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Objects/object.c,v
retrieving revision 2.175
retrieving revision 2.176
diff -C2 -d -r2.175 -r2.176
*** object.c	24 May 2002 19:01:58 -0000	2.175
--- object.c	31 May 2002 20:03:54 -0000	2.176
***************
*** 354,357 ****
--- 354,397 ----
  
  
+ /* Helper to warn about deprecated tp_compare return values.  Return:
+    -2 for an exception;
+    -1 if v <  w;
+     0 if v == w;
+     1 if v  > w.
+    (This function cannot return 2.)
+ */
+ static int
+ adjust_tp_compare(int c)
+ {
+ 	if (PyErr_Occurred()) {
+ 		if (c != -1 && c != -2) {
+ 			PyObject *t, *v, *tb;
+ 			PyErr_Fetch(&t, &v, &tb);
+ 			if (PyErr_Warn(PyExc_RuntimeWarning,
+ 				       "tp_compare didn't return -1 or -2 "
+ 				       "for exception") < 0) {
+ 				Py_XDECREF(t);
+ 				Py_XDECREF(v);
+ 				Py_XDECREF(tb);
+ 			}
+ 			else
+ 				PyErr_Restore(t, v, tb);
+ 		}
+ 		return -2;
+ 	}
+ 	else if (c < -1 || c > 1) {
+ 		if (PyErr_Warn(PyExc_RuntimeWarning,
+ 			       "tp_compare didn't return -1, 0 or 1") < 0)
+ 			return -2;
+ 		else
+ 			return c < -1 ? -1 : 1;
+ 	}
+ 	else {
+ 		assert(c >= -1 && c <= 1);
+ 		return c;
+ 	}
+ }
+ 
+ 
  /* Macro to get the tp_richcompare field of a type if defined */
  #define RICHCOMPARE(t) (PyType_HasFeature((t), Py_TPFLAGS_HAVE_RICHCOMPARE) \
***************
*** 481,487 ****
  	if (f != NULL && f == w->ob_type->tp_compare) {
  		c = (*f)(v, w);
! 		if (c < 0 && PyErr_Occurred())
! 			return -1;
! 		return c < 0 ? -1 : c > 0 ? 1 : 0;
  	}
  
--- 521,525 ----
  	if (f != NULL && f == w->ob_type->tp_compare) {
  		c = (*f)(v, w);
! 		return adjust_tp_compare(c);
  	}
  
***************
*** 503,509 ****
  		Py_DECREF(v);
  		Py_DECREF(w);
! 		if (c < 0 && PyErr_Occurred())
! 			return -2;
! 		return c < 0 ? -1 : c > 0 ? 1 : 0;
  	}
  
--- 541,545 ----
  		Py_DECREF(v);
  		Py_DECREF(w);
! 		return adjust_tp_compare(c);
  	}
  
***************
*** 513,519 ****
  		Py_DECREF(v);
  		Py_DECREF(w);
! 		if (c < 0 && PyErr_Occurred())
! 			return -2;
! 		return c < 0 ? 1 : c > 0 ? -1 : 0; /* negated! */
  	}
  
--- 549,557 ----
  		Py_DECREF(v);
  		Py_DECREF(w);
! 		c = adjust_tp_compare(c);
! 		if (c >= -1)
! 			return -c; /* Swapped! */
! 		else
! 			return c;
  	}
  
***************
*** 592,600 ****
  
  /* Do a 3-way comparison, by hook or by crook.  Return:
!    -2 for an exception;
     -1 if v <  w;
      0 if v == w;
      1 if v >  w;
!    If the object implements a tp_compare function, it returns
     whatever this function returns (whether with an exception or not).
  */
--- 630,638 ----
  
  /* Do a 3-way comparison, by hook or by crook.  Return:
!    -2 for an exception (but see below);
     -1 if v <  w;
      0 if v == w;
      1 if v >  w;
!    BUT: if the object implements a tp_compare function, it returns
     whatever this function returns (whether with an exception or not).
  */
***************
*** 608,614 ****
  	    && (f = v->ob_type->tp_compare) != NULL) {
  		c = (*f)(v, w);
! 		if (c != 2 || !PyInstance_Check(v))
! 			return c;
  	}
  	c = try_rich_to_3way_compare(v, w);
  	if (c < 2)
--- 646,665 ----
  	    && (f = v->ob_type->tp_compare) != NULL) {
  		c = (*f)(v, w);
! 		if (PyInstance_Check(v)) {
! 			/* Instance tp_compare has a different signature.
! 			   But if it returns undefined we fall through. */
! 			if (c != 2)
! 				return c;
! 			/* Else fall throug to try_rich_to_3way_compare() */
! 		}
! 		else
! 			return adjust_tp_compare(c);
  	}
+ 	/* We only get here if one of the following is true:
+ 	   a) v and w have different types
+ 	   b) v and w have the same type, which doesn't have tp_compare
+ 	   c) v and w are instances, and either __cmp__ is not defined or
+ 	      __cmp__ returns NotImplemented
+ 	*/
  	c = try_rich_to_3way_compare(v, w);
  	if (c < 2)
***************
*** 903,907 ****
  		if (fcmp != NULL) {
  			int c = (*fcmp)(v, w);
! 			if (c < 0 && PyErr_Occurred()) {
  				res = NULL;
  				goto Done;
--- 954,959 ----
  		if (fcmp != NULL) {
  			int c = (*fcmp)(v, w);
! 			c = adjust_tp_compare(c);
! 			if (c == -2) {
  				res = NULL;
  				goto Done;