[pypy-commit] pypy cpyext-macros-cast: Cast inside of macros so that callers don't get compilation errors in PyPy.

devin.jeanpierre pypy.commits at gmail.com
Fri May 6 20:39:11 EDT 2016


Author: Devin Jeanpierre <jeanpierreda at gmail.com>
Branch: cpyext-macros-cast
Changeset: r84272:cf292feacdbb
Date: 2016-05-06 17:37 -0700
http://bitbucket.org/pypy/pypy/changeset/cf292feacdbb/

Log:	Cast inside of macros so that callers don't get compilation errors
	in PyPy.

	CPython defines many macros like so:

	 #define PyWhatever_FOO(x) (((PyWhatever*)(x))->foo)

	And callers can pass in a `void*`, a `PyWhatever*`, a `PyObject*`,
	and it all works assuming that the dynamic type is correct for the
	cast.

	In PyPy, without these casts, a warning is emitted if you pass the
	"wrong" type, even though it would work in CPython. This breaks
	compatibility for projects that build with -Werror.

	(This used to be many commits, but I ended up gluing them all
	together because I am no good at mercurial. Original is mostly at
	this bitbucket repo for now:
	https://bitbucket.org/devin.jeanpierre/pypy )

diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -179,67 +179,67 @@
 # Accessors
 
 @cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_YEAR(space, w_obj):
+def _PyDateTime_GET_YEAR(space, w_obj):
     """Return the year, as a positive int.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("year")))
 
 @cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_MONTH(space, w_obj):
+def _PyDateTime_GET_MONTH(space, w_obj):
     """Return the month, as an int from 1 through 12.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("month")))
 
 @cpython_api([PyDateTime_Date], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_GET_DAY(space, w_obj):
+def _PyDateTime_GET_DAY(space, w_obj):
     """Return the day, as an int from 1 through 31.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("day")))
 
 @cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_HOUR(space, w_obj):
+def _PyDateTime_DATE_GET_HOUR(space, w_obj):
     """Return the hour, as an int from 0 through 23.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("hour")))
 
 @cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_MINUTE(space, w_obj):
+def _PyDateTime_DATE_GET_MINUTE(space, w_obj):
     """Return the minute, as an int from 0 through 59.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("minute")))
 
 @cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_SECOND(space, w_obj):
+def _PyDateTime_DATE_GET_SECOND(space, w_obj):
     """Return the second, as an int from 0 through 59.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("second")))
 
 @cpython_api([PyDateTime_DateTime], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DATE_GET_MICROSECOND(space, w_obj):
+def _PyDateTime_DATE_GET_MICROSECOND(space, w_obj):
     """Return the microsecond, as an int from 0 through 999999.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("microsecond")))
 
 @cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_HOUR(space, w_obj):
+def _PyDateTime_TIME_GET_HOUR(space, w_obj):
     """Return the hour, as an int from 0 through 23.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("hour")))
 
 @cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_MINUTE(space, w_obj):
+def _PyDateTime_TIME_GET_MINUTE(space, w_obj):
     """Return the minute, as an int from 0 through 59.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("minute")))
 
 @cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_SECOND(space, w_obj):
+def _PyDateTime_TIME_GET_SECOND(space, w_obj):
     """Return the second, as an int from 0 through 59.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("second")))
 
 @cpython_api([PyDateTime_Time], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_TIME_GET_MICROSECOND(space, w_obj):
+def _PyDateTime_TIME_GET_MICROSECOND(space, w_obj):
     """Return the microsecond, as an int from 0 through 999999.
     """
     return space.int_w(space.getattr(w_obj, space.wrap("microsecond")))
@@ -249,13 +249,13 @@
 # for types defined in a python module like lib/datetime.py.
 
 @cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DELTA_GET_DAYS(space, w_obj):
+def _PyDateTime_DELTA_GET_DAYS(space, w_obj):
     return space.int_w(space.getattr(w_obj, space.wrap("days")))
 
 @cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DELTA_GET_SECONDS(space, w_obj):
+def _PyDateTime_DELTA_GET_SECONDS(space, w_obj):
     return space.int_w(space.getattr(w_obj, space.wrap("seconds")))
 
 @cpython_api([PyDateTime_Delta], rffi.INT_real, error=CANNOT_FAIL)
-def PyDateTime_DELTA_GET_MICROSECONDS(space, w_obj):
+def _PyDateTime_DELTA_GET_MICROSECONDS(space, w_obj):
     return space.int_w(space.getattr(w_obj, space.wrap("microseconds")))
diff --git a/pypy/module/cpyext/floatobject.py b/pypy/module/cpyext/floatobject.py
--- a/pypy/module/cpyext/floatobject.py
+++ b/pypy/module/cpyext/floatobject.py
@@ -49,7 +49,7 @@
     return space.float_w(space.float(w_obj))
 
 @cpython_api([PyObject], lltype.Float, error=CANNOT_FAIL)
-def PyFloat_AS_DOUBLE(space, w_float):
+def _PyFloat_AS_DOUBLE(space, w_float):
     """Return a C double representation of the contents of w_float, but
     without error checking."""
     return space.float_w(w_float)
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -87,6 +87,7 @@
 #include "pymath.h"
 #include "pyport.h"
 #include "warnings.h"
+#include "weakrefobject.h"
 
 #include <stdarg.h>
 #include <stdio.h>
@@ -102,6 +103,7 @@
 #include "funcobject.h"
 #include "code.h"
 
+#include "abstract.h"
 #include "modsupport.h"
 #include "pythonrun.h"
 #include "pyerrors.h"
@@ -129,6 +131,7 @@
 #include "fileobject.h"
 #include "pysignals.h"
 #include "pythread.h"
+#include "setobject.h"
 #include "traceback.h"
 
 /* Missing definitions */
diff --git a/pypy/module/cpyext/include/abstract.h b/pypy/module/cpyext/include/abstract.h
--- a/pypy/module/cpyext/include/abstract.h
+++ b/pypy/module/cpyext/include/abstract.h
@@ -1,1 +1,3 @@
-/* empty */
+#define PySequence_Fast_GET_ITEM(seq, i) _PySequence_Fast_GET_ITEM((PyObject*)(seq), (i))
+#define PySequence_Fast_GET_SIZE(seq) _PySequence_Fast_GET_SIZE((PyObject*)(seq))
+#define PySequence_ITEM(seq, i) _PySequence_ITEM((PyObject*)(seq), (i))
diff --git a/pypy/module/cpyext/include/datetime.h b/pypy/module/cpyext/include/datetime.h
--- a/pypy/module/cpyext/include/datetime.h
+++ b/pypy/module/cpyext/include/datetime.h
@@ -4,6 +4,27 @@
 extern "C" {
 #endif
 
+
+#define PyDateTime_GET_YEAR(o)  _PyDateTime_GET_YEAR((PyDateTime_Date*)(o))
+#define PyDateTime_GET_MONTH(o) _PyDateTime_GET_MONTH((PyDateTime_Date*)(o))
+#define PyDateTime_GET_DAY(o)   _PyDateTime_GET_DAY((PyDateTime_Date*)(o))
+
+#define PyDateTime_DATE_GET_HOUR(o)        _PyDateTime_DATE_GET_HOUR((PyDateTime_DateTime*)(o))
+#define PyDateTime_DATE_GET_MINUTE(o)      _PyDateTime_DATE_GET_MINUTE((PyDateTime_DateTime*)(o))
+#define PyDateTime_DATE_GET_SECOND(o)      _PyDateTime_DATE_GET_SECOND((PyDateTime_DateTime*)(o))
+#define PyDateTime_DATE_GET_MICROSECOND(o) _PyDateTime_DATE_GET_MICROSECOND((PyDateTime_DateTime*)(o))
+
+#define PyDateTime_TIME_GET_HOUR(o)        _PyDateTime_TIME_GET_HOUR((PyDateTime_Time*)(o))
+#define PyDateTime_TIME_GET_MINUTE(o)      _PyDateTime_TIME_GET_MINUTE((PyDateTime_Time*)(o))
+#define PyDateTime_TIME_GET_SECOND(o)      _PyDateTime_TIME_GET_SECOND((PyDateTime_Time*)(o))
+#define PyDateTime_TIME_GET_MICROSECOND(o) _PyDateTime_TIME_GET_MICROSECOND((PyDateTime_Time*)(o))
+
+#define PyDateTime_DELTA_GET_DAYS(o)         _PyDateTime_DELTA_GET_DAYS((PyDateTime_Delta*)(o))
+#define PyDateTime_DELTA_GET_SECONDS(o)      _PyDateTime_DELTA_GET_SECONDS((PyDateTime_Delta*)(o))
+#define PyDateTime_DELTA_GET_MICROSECONDS(o) _PyDateTime_DELTA_GET_MICROSECONDS((PyDateTime_Delta*)(o))
+
+
+
 /* Define structure for C API. */
 typedef struct {
     /* type objects */
diff --git a/pypy/module/cpyext/include/floatobject.h b/pypy/module/cpyext/include/floatobject.h
--- a/pypy/module/cpyext/include/floatobject.h
+++ b/pypy/module/cpyext/include/floatobject.h
@@ -19,6 +19,8 @@
     double ob_fval;
 } PyFloatObject;
 
+#define PyFloat_AS_DOUBLE(o) _PyFloat_AS_DOUBLE((PyObject*)(o))
+
 #define PyFloat_STR_PRECISION 12
 
 #ifdef Py_NAN
diff --git a/pypy/module/cpyext/include/intobject.h b/pypy/module/cpyext/include/intobject.h
--- a/pypy/module/cpyext/include/intobject.h
+++ b/pypy/module/cpyext/include/intobject.h
@@ -7,6 +7,8 @@
 extern "C" {
 #endif
 
+#define PyInt_AS_LONG(obj) _PyInt_AS_LONG((PyObject*)obj);
+
 typedef struct {
     PyObject_HEAD
     long ob_ival;
diff --git a/pypy/module/cpyext/include/listobject.h b/pypy/module/cpyext/include/listobject.h
--- a/pypy/module/cpyext/include/listobject.h
+++ b/pypy/module/cpyext/include/listobject.h
@@ -1,1 +1,3 @@
-#define PyList_GET_ITEM PyList_GetItem
+#define PyList_GET_ITEM(o, i)     PyList_GetItem((PyObject*)(o), (i))
+#define PyList_SET_ITEM(o, i, v)  _PyList_SET_ITEM((PyObject*)(o), (i), (v))
+#define PyList_GET_SIZE(o)        _PyList_GET_SIZE((PyObject*)(o))
diff --git a/pypy/module/cpyext/include/setobject.h b/pypy/module/cpyext/include/setobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/setobject.h
@@ -0,0 +1,14 @@
+/* Int object interface */
+
+#ifndef Py_SETOBJECT_H
+#define Py_SETOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PySet_GET_SIZE(obj) _PySet_GET_SIZE((PyObject*)obj);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_SETOBJECT_H */
diff --git a/pypy/module/cpyext/include/unicodeobject.h b/pypy/module/cpyext/include/unicodeobject.h
--- a/pypy/module/cpyext/include/unicodeobject.h
+++ b/pypy/module/cpyext/include/unicodeobject.h
@@ -5,6 +5,10 @@
 extern "C" {
 #endif
 
+#define PyUnicode_GET_SIZE(o) _PyUnicode_GET_SIZE((PyObject*)(o))
+#define PyUnicode_GET_DATA_SIZE(o) _PyUnicode_GET_DATA_SIZE((PyObject*)(o))
+#define PyUnicode_AS_UNICODE(o) _PyUnicode_AS_UNICODE((PyObject*)(o))
+
 
 typedef unsigned int Py_UCS4;
 #ifdef HAVE_USABLE_WCHAR_T
diff --git a/pypy/module/cpyext/include/weakrefobject.h b/pypy/module/cpyext/include/weakrefobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/weakrefobject.h
@@ -0,0 +1,1 @@
+#define PyWeakref_GET_OBJECT(o) PyWeakref_GetObject((PyObject*)(o))
diff --git a/pypy/module/cpyext/intobject.py b/pypy/module/cpyext/intobject.py
--- a/pypy/module/cpyext/intobject.py
+++ b/pypy/module/cpyext/intobject.py
@@ -105,7 +105,7 @@
         return num.ulonglongmask()
 
 @cpython_api([PyObject], lltype.Signed, error=CANNOT_FAIL)
-def PyInt_AS_LONG(space, w_int):
+def _PyInt_AS_LONG(space, w_int):
     """Return the value of the object w_int. No error checking is performed."""
     return space.int_w(w_int)
 
diff --git a/pypy/module/cpyext/listobject.py b/pypy/module/cpyext/listobject.py
--- a/pypy/module/cpyext/listobject.py
+++ b/pypy/module/cpyext/listobject.py
@@ -23,7 +23,7 @@
 
 @cpython_api([PyObject, Py_ssize_t, PyObject], PyObject, error=CANNOT_FAIL,
              result_borrowed=True)
-def PyList_SET_ITEM(space, w_list, index, w_item):
+def _PyList_SET_ITEM(space, w_list, index, w_item):
     """Macro form of PyList_SetItem() without error checking. This is normally
     only used to fill in new lists where there is no previous content.
 
@@ -88,7 +88,7 @@
     return 0
 
 @cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PyList_GET_SIZE(space, w_list):
+def _PyList_GET_SIZE(space, w_list):
     """Macro form of PyList_Size() without error checking.
     """
     assert isinstance(w_list, W_ListObject)
@@ -102,7 +102,7 @@
     """
     if not PyList_Check(space, ref):
         raise oefmt(space.w_TypeError, "expected list object")
-    return PyList_GET_SIZE(space, ref)
+    return _PyList_GET_SIZE(space, ref)
 
 @cpython_api([PyObject], PyObject)
 def PyList_AsTuple(space, w_list):
diff --git a/pypy/module/cpyext/sequence.py b/pypy/module/cpyext/sequence.py
--- a/pypy/module/cpyext/sequence.py
+++ b/pypy/module/cpyext/sequence.py
@@ -46,7 +46,7 @@
     members of the result.  Returns NULL on failure.  If the object is not a
     sequence, raises TypeError with m as the message text."""
     if isinstance(w_obj, W_ListObject):
-        # make sure we can return a borrowed obj from PySequence_Fast_GET_ITEM    
+        # make sure we can return a borrowed obj from _PySequence_Fast_GET_ITEM
         w_obj.convert_to_cpy_strategy(space)
         return w_obj
     try:
@@ -55,7 +55,7 @@
         raise OperationError(space.w_TypeError, space.wrap(rffi.charp2str(m)))
 
 @cpython_api([PyObject, Py_ssize_t], PyObject, result_borrowed=True)
-def PySequence_Fast_GET_ITEM(space, w_obj, index):
+def _PySequence_Fast_GET_ITEM(space, w_obj, index):
     """Return the ith element of o, assuming that o was returned by
     PySequence_Fast(), o is not NULL, and that i is within bounds.
     """
@@ -68,7 +68,7 @@
                 "sequence")
 
 @cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PySequence_Fast_GET_SIZE(space, w_obj):
+def _PySequence_Fast_GET_SIZE(space, w_obj):
     """Returns the length of o, assuming that o was returned by
     PySequence_Fast() and that o is not NULL.  The size can also be
     gotten by calling PySequence_Size() on o, but
@@ -120,7 +120,7 @@
     return 0
 
 @cpython_api([PyObject, Py_ssize_t], PyObject)
-def PySequence_ITEM(space, w_obj, i):
+def _PySequence_ITEM(space, w_obj, i):
     """Return the ith element of o or NULL on failure. Macro form of
     PySequence_GetItem() but without checking that
     PySequence_Check(o)() is true and without adjustment for negative
@@ -134,7 +134,7 @@
 def PySequence_GetItem(space, w_obj, i):
     """Return the ith element of o, or NULL on failure. This is the equivalent of
     the Python expression o[i]."""
-    return PySequence_ITEM(space, w_obj, i)
+    return _PySequence_ITEM(space, w_obj, i)
 
 @cpython_api([PyObject], PyObject)
 def PySequence_List(space, w_obj):
diff --git a/pypy/module/cpyext/setobject.py b/pypy/module/cpyext/setobject.py
--- a/pypy/module/cpyext/setobject.py
+++ b/pypy/module/cpyext/setobject.py
@@ -75,7 +75,7 @@
     return 0
 
 @cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PySet_GET_SIZE(space, w_s):
+def _PySet_GET_SIZE(space, w_s):
     """Macro form of PySet_Size() without error checking."""
     return space.int_w(space.len(w_s))
 
@@ -86,7 +86,7 @@
     or an instance of a subtype."""
     if not PySet_Check(space, ref):
         raise oefmt(space.w_TypeError, "expected set object")
-    return PySet_GET_SIZE(space, ref)
+    return _PySet_GET_SIZE(space, ref)
 
 @cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
 def PySet_Contains(space, w_obj, w_key):
diff --git a/pypy/module/cpyext/test/test_bytesobject.py b/pypy/module/cpyext/test/test_bytesobject.py
--- a/pypy/module/cpyext/test/test_bytesobject.py
+++ b/pypy/module/cpyext/test/test_bytesobject.py
@@ -288,6 +288,24 @@
         # This does not test much, but at least the refcounts are checked.
         assert module.test_intern_inplace('s') == 's'
 
+    def test_bytes_macros(self):
+        """The PyString_* macros cast, and calls expecting that build."""
+        module = self.import_extension('foo', [
+             ("test_macro_invocations", "METH_NOARGS",
+             """
+                PyObject* o = PyString_FromString("");
+                PyStringObject* u = (PyStringObject*)o;
+
+                PyString_GET_SIZE(u);
+                PyString_GET_SIZE(o);
+
+                PyString_AS_STRING(o);
+                PyString_AS_STRING(u);
+
+                return o;
+             """)])
+        assert module.test_macro_invocations() == ''
+
     def test_hash_and_state(self):
         module = self.import_extension('foo', [
             ("test_hash", "METH_VARARGS",
diff --git a/pypy/module/cpyext/test/test_datetime.py b/pypy/module/cpyext/test/test_datetime.py
--- a/pypy/module/cpyext/test/test_datetime.py
+++ b/pypy/module/cpyext/test/test_datetime.py
@@ -10,9 +10,9 @@
         assert api.PyDate_Check(w_date)
         assert api.PyDate_CheckExact(w_date)
 
-        assert api.PyDateTime_GET_YEAR(w_date) == 2010
-        assert api.PyDateTime_GET_MONTH(w_date) == 6
-        assert api.PyDateTime_GET_DAY(w_date) == 3
+        assert api._PyDateTime_GET_YEAR(w_date) == 2010
+        assert api._PyDateTime_GET_MONTH(w_date) == 6
+        assert api._PyDateTime_GET_DAY(w_date) == 3
 
     def test_time(self, space, api):
         w_time = api.PyTime_FromTime(23, 15, 40, 123456)
@@ -21,10 +21,10 @@
         assert api.PyTime_Check(w_time)
         assert api.PyTime_CheckExact(w_time)
 
-        assert api.PyDateTime_TIME_GET_HOUR(w_time) == 23
-        assert api.PyDateTime_TIME_GET_MINUTE(w_time) == 15
-        assert api.PyDateTime_TIME_GET_SECOND(w_time) == 40
-        assert api.PyDateTime_TIME_GET_MICROSECOND(w_time) == 123456
+        assert api._PyDateTime_TIME_GET_HOUR(w_time) == 23
+        assert api._PyDateTime_TIME_GET_MINUTE(w_time) == 15
+        assert api._PyDateTime_TIME_GET_SECOND(w_time) == 40
+        assert api._PyDateTime_TIME_GET_MICROSECOND(w_time) == 123456
 
     def test_datetime(self, space, api):
         w_date = api.PyDateTime_FromDateAndTime(
@@ -36,13 +36,13 @@
         assert api.PyDate_Check(w_date)
         assert not api.PyDate_CheckExact(w_date)
 
-        assert api.PyDateTime_GET_YEAR(w_date) == 2010
-        assert api.PyDateTime_GET_MONTH(w_date) == 6
-        assert api.PyDateTime_GET_DAY(w_date) == 3
-        assert api.PyDateTime_DATE_GET_HOUR(w_date) == 23
-        assert api.PyDateTime_DATE_GET_MINUTE(w_date) == 15
-        assert api.PyDateTime_DATE_GET_SECOND(w_date) == 40
-        assert api.PyDateTime_DATE_GET_MICROSECOND(w_date) == 123456
+        assert api._PyDateTime_GET_YEAR(w_date) == 2010
+        assert api._PyDateTime_GET_MONTH(w_date) == 6
+        assert api._PyDateTime_GET_DAY(w_date) == 3
+        assert api._PyDateTime_DATE_GET_HOUR(w_date) == 23
+        assert api._PyDateTime_DATE_GET_MINUTE(w_date) == 15
+        assert api._PyDateTime_DATE_GET_SECOND(w_date) == 40
+        assert api._PyDateTime_DATE_GET_MICROSECOND(w_date) == 123456
 
     def test_delta(self, space, api):
         w_delta = space.appexec(
@@ -57,9 +57,9 @@
         assert api.PyDelta_Check(w_delta)
         assert api.PyDelta_CheckExact(w_delta)
 
-        assert api.PyDateTime_DELTA_GET_DAYS(w_delta) == 10
-        assert api.PyDateTime_DELTA_GET_SECONDS(w_delta) == 20
-        assert api.PyDateTime_DELTA_GET_MICROSECONDS(w_delta) == 30
+        assert api._PyDateTime_DELTA_GET_DAYS(w_delta) == 10
+        assert api._PyDateTime_DELTA_GET_SECONDS(w_delta) == 20
+        assert api._PyDateTime_DELTA_GET_MICROSECONDS(w_delta) == 30
 
     def test_fromtimestamp(self, space, api):
         w_args = space.wrap((0,))
@@ -117,3 +117,106 @@
                                       datetime.timedelta,
                                       datetime.tzinfo)
         module.clear_types()
+
+    def test_macros(self):
+        module = self.import_extension('foo', [
+            ("test_date_macros", "METH_NOARGS",
+             """
+                 PyDateTime_IMPORT;
+                 if (!PyDateTimeAPI) {
+                     PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+                     return NULL;
+                 }
+                 PyObject* obj = PyDate_FromDate(2000, 6, 6);
+                 PyDateTime_Date* d = (PyDateTime_Date*)obj;
+
+                 PyDateTime_GET_YEAR(obj);
+                 PyDateTime_GET_YEAR(d);
+
+                 PyDateTime_GET_MONTH(obj);
+                 PyDateTime_GET_MONTH(d);
+
+                 PyDateTime_GET_DAY(obj);
+                 PyDateTime_GET_DAY(d);
+
+                 return obj;
+             """),
+            ("test_datetime_macros", "METH_NOARGS",
+             """
+                 PyDateTime_IMPORT;
+                 if (!PyDateTimeAPI) {
+                     PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+                     return NULL;
+                 }
+                 PyObject* obj = PyDateTime_FromDateAndTime(2000, 6, 6, 6, 6, 6, 6);
+                 PyDateTime_DateTime* dt = (PyDateTime_DateTime*)obj;
+
+                 PyDateTime_GET_YEAR(obj);
+                 PyDateTime_GET_YEAR(dt);
+
+                 PyDateTime_GET_MONTH(obj);
+                 PyDateTime_GET_MONTH(dt);
+
+                 PyDateTime_GET_DAY(obj);
+                 PyDateTime_GET_DAY(dt);
+
+                 PyDateTime_DATE_GET_HOUR(obj);
+                 PyDateTime_DATE_GET_HOUR(dt);
+
+                 PyDateTime_DATE_GET_MINUTE(obj);
+                 PyDateTime_DATE_GET_MINUTE(dt);
+
+                 PyDateTime_DATE_GET_SECOND(obj);
+                 PyDateTime_DATE_GET_SECOND(dt);
+
+                 PyDateTime_DATE_GET_MICROSECOND(obj);
+                 PyDateTime_DATE_GET_MICROSECOND(dt);
+
+                 return obj;
+             """),
+            ("test_time_macros", "METH_NOARGS",
+             """
+                 PyDateTime_IMPORT;
+                 if (!PyDateTimeAPI) {
+                     PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+                     return NULL;
+                 }
+                 PyObject* obj = PyTime_FromTime(6, 6, 6, 6);
+                 PyDateTime_Time* t = (PyDateTime_Time*)obj;
+
+                 PyDateTime_TIME_GET_HOUR(obj);
+                 PyDateTime_TIME_GET_HOUR(t);
+
+                 PyDateTime_TIME_GET_MINUTE(obj);
+                 PyDateTime_TIME_GET_MINUTE(t);
+
+                 PyDateTime_TIME_GET_SECOND(obj);
+                 PyDateTime_TIME_GET_SECOND(t);
+
+                 PyDateTime_TIME_GET_MICROSECOND(obj);
+                 PyDateTime_TIME_GET_MICROSECOND(t);
+
+                 return obj;
+             """),
+            ("test_delta_macros", "METH_NOARGS",
+             """
+                 PyDateTime_IMPORT;
+                 if (!PyDateTimeAPI) {
+                     PyErr_SetString(PyExc_RuntimeError, "No PyDateTimeAPI");
+                     return NULL;
+                 }
+                 PyObject* obj = PyDelta_FromDSU(6, 6, 6);
+                 PyDateTime_Delta* delta = (PyDateTime_Delta*)obj;
+
+                 PyDateTime_DELTA_GET_DAYS(obj);
+                 PyDateTime_DELTA_GET_DAYS(delta);
+
+                 PyDateTime_DELTA_GET_SECONDS(obj);
+                 PyDateTime_DELTA_GET_SECONDS(delta);
+
+                 PyDateTime_DELTA_GET_MICROSECONDS(obj);
+                 PyDateTime_DELTA_GET_MICROSECONDS(delta);
+
+                 return obj;
+             """),
+            ])
diff --git a/pypy/module/cpyext/test/test_floatobject.py b/pypy/module/cpyext/test/test_floatobject.py
--- a/pypy/module/cpyext/test/test_floatobject.py
+++ b/pypy/module/cpyext/test/test_floatobject.py
@@ -6,7 +6,7 @@
     def test_floatobject(self, space, api):
         assert space.unwrap(api.PyFloat_FromDouble(3.14)) == 3.14
         assert api.PyFloat_AsDouble(space.wrap(23.45)) == 23.45
-        assert api.PyFloat_AS_DOUBLE(space.wrap(23.45)) == 23.45
+        assert api._PyFloat_AS_DOUBLE(space.wrap(23.45)) == 23.45
 
         assert api.PyFloat_AsDouble(space.w_None) == -1
         api.PyErr_Clear()
@@ -77,3 +77,19 @@
         neginf = module.return_neginf()
         assert neginf < 0
         assert math.isinf(neginf)
+
+    def test_macro_accepts_wrong_pointer_type(self):
+        import math
+
+        module = self.import_extension('foo', [
+            ("test_macros", "METH_NOARGS",
+             """
+             PyObject* o = PyFloat_FromDouble(1.0);
+             // no PyFloatObject
+             char* dumb_pointer = (char*)o;
+
+             PyFloat_AS_DOUBLE(o);
+             PyFloat_AS_DOUBLE(dumb_pointer);
+
+             Py_RETURN_NONE;"""),
+            ])
diff --git a/pypy/module/cpyext/test/test_intobject.py b/pypy/module/cpyext/test/test_intobject.py
--- a/pypy/module/cpyext/test/test_intobject.py
+++ b/pypy/module/cpyext/test/test_intobject.py
@@ -9,7 +9,7 @@
         assert not api.PyInt_Check(space.wrap((1, 2, 3)))
         for i in [3, -5, -1, -sys.maxint, sys.maxint - 1]:
             x = api.PyInt_AsLong(space.wrap(i))
-            y = api.PyInt_AS_LONG(space.wrap(i))
+            y = api._PyInt_AS_LONG(space.wrap(i))
             assert x == i
             assert y == i
             w_x = api.PyInt_FromLong(x + 1)
@@ -191,3 +191,17 @@
         i = mod.test_int()
         assert isinstance(i, int)
         assert i == 42
+
+    def test_int_macros(self):
+        mod = self.import_extension('foo', [
+                ("test_macros", "METH_NOARGS",
+                """
+                PyObject * obj = PyInt_FromLong(42);
+                PyIntObject * i = (PyIntObject*)obj;
+                PyInt_AS_LONG(obj);
+                PyInt_AS_LONG(i);
+                Py_RETURN_NONE;
+                """
+                ),
+                ])
+
diff --git a/pypy/module/cpyext/test/test_listobject.py b/pypy/module/cpyext/test/test_listobject.py
--- a/pypy/module/cpyext/test/test_listobject.py
+++ b/pypy/module/cpyext/test/test_listobject.py
@@ -22,9 +22,9 @@
     
     def test_get_size(self, space, api):
         l = api.PyList_New(0)
-        assert api.PyList_GET_SIZE(l) == 0
+        assert api._PyList_GET_SIZE(l) == 0
         api.PyList_Append(l, space.wrap(3))
-        assert api.PyList_GET_SIZE(l) == 1
+        assert api._PyList_GET_SIZE(l) == 1
     
     def test_size(self, space, api):
         l = space.newlist([space.w_None, space.w_None])
@@ -137,6 +137,33 @@
         module.setlistitem(l,0)
         assert l == [None, 2, 3]
 
+    def test_list_macros(self):
+        """The PyList_* macros cast, and calls expecting that build."""
+        module = self.import_extension('foo', [
+            ("test_macro_invocations", "METH_NOARGS",
+             """
+             PyObject* o = PyList_New(2);
+             PyListObject* l = (PyListObject*)o;
+
+
+             Py_INCREF(o);
+             PyList_SET_ITEM(o, 0, o);
+             Py_INCREF(o);
+             PyList_SET_ITEM(l, 1, o);
+
+             PyList_GET_ITEM(o, 0);
+             PyList_GET_ITEM(l, 1);
+
+             PyList_GET_SIZE(o);
+             PyList_GET_SIZE(l);
+
+             return o;
+             """
+            )
+        ])
+        x = module.test_macro_invocations()
+        assert x[0] is x[1] is x
+
     def test_get_item_macro(self):
         module = self.import_extension('foo', [
              ("test_get_item", "METH_NOARGS",
diff --git a/pypy/module/cpyext/test/test_sequence.py b/pypy/module/cpyext/test/test_sequence.py
--- a/pypy/module/cpyext/test/test_sequence.py
+++ b/pypy/module/cpyext/test/test_sequence.py
@@ -14,8 +14,8 @@
         w_l = space.wrap([1, 2, 3, 4])
         assert api.PySequence_Fast(w_l, "message") is w_l
 
-        assert space.int_w(api.PySequence_Fast_GET_ITEM(w_l, 1)) == 2
-        assert api.PySequence_Fast_GET_SIZE(w_l) == 4
+        assert space.int_w(api._PySequence_Fast_GET_ITEM(w_l, 1)) == 2
+        assert api._PySequence_Fast_GET_SIZE(w_l) == 4
 
         w_set = space.wrap(set((1, 2, 3, 4)))
         w_seq = api.PySequence_Fast(w_set, "message")
@@ -130,7 +130,7 @@
         result = api.PySequence_GetItem(w_l, 4)
         assert space.is_true(space.eq(result, space.wrap(4)))
 
-        result = api.PySequence_ITEM(w_l, 4)
+        result = api._PySequence_ITEM(w_l, 4)
         assert space.is_true(space.eq(result, space.wrap(4)))
 
         self.raises(space, api, IndexError, api.PySequence_GetItem, w_l, 9000)
@@ -155,6 +155,28 @@
         result = api.PySequence_Index(w_gen, w_tofind)
         assert result == 4
 
+class AppTestSetObject(AppTestCpythonExtensionBase):
+    def test_sequence_macro_cast(self):
+        module = self.import_extension('foo', [
+            ("test_macro_cast", "METH_NOARGS",
+             """
+             PyObject* o = PyList_New(0);
+             PyList_Append(o, o);
+             PyListObject* l = (PyListObject*)o;
+
+             PySequence_Fast_GET_ITEM(o, 0);
+             PySequence_Fast_GET_ITEM(l, 0);
+
+             PySequence_Fast_GET_SIZE(o);
+             PySequence_Fast_GET_SIZE(l);
+
+             PySequence_ITEM(o, 0);
+             PySequence_ITEM(l, 0);
+
+             return o;
+             """
+            )
+        ])
 class TestCPyListStrategy(BaseApiTest):
     def test_getitem_setitem(self, space, api):
         w_l = space.wrap([1, 2, 3, 4])
diff --git a/pypy/module/cpyext/test/test_setobject.py b/pypy/module/cpyext/test/test_setobject.py
--- a/pypy/module/cpyext/test/test_setobject.py
+++ b/pypy/module/cpyext/test/test_setobject.py
@@ -2,6 +2,7 @@
 
 from pypy.module.cpyext.pyobject import PyObject, PyObjectP, make_ref, from_ref
 from pypy.module.cpyext.test.test_api import BaseApiTest
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
 from rpython.rtyper.lltypesystem import rffi, lltype
 
 
@@ -13,7 +14,7 @@
         w_set = space.call_function(space.w_set)
         space.call_method(w_set, 'update', space.wrap([1,2,3,4]))
         assert api.PySet_Size(w_set) == 4
-        assert api.PySet_GET_SIZE(w_set) == 4
+        assert api._PySet_GET_SIZE(w_set) == 4
         raises(TypeError, api.PySet_Size(space.newlist([])))
         api.PyErr_Clear()
 
@@ -45,3 +46,20 @@
         w_frozenset = space.newfrozenset([space.wrap(i) for i in [1, 2, 3, 4]])
         assert api.PyAnySet_CheckExact(w_set)
         assert api.PyAnySet_CheckExact(w_frozenset)
+
+class AppTestSetObject(AppTestCpythonExtensionBase):
+    def test_set_macro_cast(self):
+        module = self.import_extension('foo', [
+            ("test_macro_cast", "METH_NOARGS",
+             """
+             PyObject* o = PySet_New(NULL);
+             // no PySetObject
+             char* dumb_pointer = (char*) o;
+
+             PySet_GET_SIZE(o);
+             PySet_GET_SIZE(dumb_pointer);
+
+             return o;
+             """
+            )
+        ])
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -111,12 +111,32 @@
         assert isinstance(res, str)
         assert res == 'caf?'
 
+    def test_unicode_macros(self):
+        """The PyUnicode_* macros cast, and calls expecting that build."""
+        module = self.import_extension('foo', [
+             ("test_macro_invocations", "METH_NOARGS",
+             """
+                PyObject* o = PyUnicode_FromString("");
+                PyUnicodeObject* u = (PyUnicodeObject*)o;
+
+                PyUnicode_GET_SIZE(u);
+                PyUnicode_GET_SIZE(o);
+
+                PyUnicode_GET_DATA_SIZE(u);
+                PyUnicode_GET_DATA_SIZE(o);
+
+                PyUnicode_AS_UNICODE(o);
+                PyUnicode_AS_UNICODE(u);
+                return o;
+             """)])
+        assert module.test_macro_invocations() == u''
+
 class TestUnicode(BaseApiTest):
     def test_unicodeobject(self, space, api):
-        assert api.PyUnicode_GET_SIZE(space.wrap(u'sp�m')) == 4
+        assert api._PyUnicode_GET_SIZE(space.wrap(u'sp�m')) == 4
         assert api.PyUnicode_GetSize(space.wrap(u'sp�m')) == 4
         unichar = rffi.sizeof(Py_UNICODE)
-        assert api.PyUnicode_GET_DATA_SIZE(space.wrap(u'sp�m')) == 4 * unichar
+        assert api._PyUnicode_GET_DATA_SIZE(space.wrap(u'sp�m')) == 4 * unichar
 
         encoding = rffi.charp2str(api.PyUnicode_GetDefaultEncoding())
         w_default_encoding = space.call_function(
@@ -140,7 +160,7 @@
     def test_AS(self, space, api):
         word = space.wrap(u'spam')
         array = rffi.cast(rffi.CWCHARP, api.PyUnicode_AS_DATA(word))
-        array2 = api.PyUnicode_AS_UNICODE(word)
+        array2 = api._PyUnicode_AS_UNICODE(word)
         array3 = api.PyUnicode_AsUnicode(word)
         for (i, char) in enumerate(space.unwrap(word)):
             assert array[i] == char
@@ -478,13 +498,13 @@
         count1 = space.int_w(space.len(w_x))
         target_chunk = lltype.malloc(rffi.CWCHARP.TO, count1, flavor='raw')
 
-        x_chunk = api.PyUnicode_AS_UNICODE(w_x)
+        x_chunk = api._PyUnicode_AS_UNICODE(w_x)
         api.Py_UNICODE_COPY(target_chunk, x_chunk, 4)
         w_y = space.wrap(rffi.wcharpsize2unicode(target_chunk, 4))
 
         assert space.eq_w(w_y, space.wrap(u"abcd"))
 
-        size = api.PyUnicode_GET_SIZE(w_x)
+        size = api._PyUnicode_GET_SIZE(w_x)
         api.Py_UNICODE_COPY(target_chunk, x_chunk, size)
         w_y = space.wrap(rffi.wcharpsize2unicode(target_chunk, size))
 
diff --git a/pypy/module/cpyext/test/test_weakref.py b/pypy/module/cpyext/test/test_weakref.py
--- a/pypy/module/cpyext/test/test_weakref.py
+++ b/pypy/module/cpyext/test/test_weakref.py
@@ -7,7 +7,6 @@
         w_ref = api.PyWeakref_NewRef(w_obj, space.w_None)
         assert w_ref is not None
         assert space.is_w(api.PyWeakref_GetObject(w_ref), w_obj)
-        assert space.is_w(api.PyWeakref_GET_OBJECT(w_ref), w_obj)
         assert space.is_w(api.PyWeakref_LockObject(w_ref), w_obj)
 
         w_obj = space.newtuple([])
@@ -34,3 +33,25 @@
         del w_obj
         import gc; gc.collect()
         assert space.is_w(api.PyWeakref_LockObject(w_ref), space.w_None)
+
+
+class AppTestWeakReference(AppTestCpythonExtensionBase):
+
+    def test_weakref_macro(self):
+        module = self.import_extension('foo', [
+            ("test_macro_cast", "METH_NOARGS",
+             """
+             // PyExc_Warning is some weak-reffable PyObject*.
+             PyObject* weakref_obj = PyWeakref_NewRef(PyExc_Warning, NULL);
+             if (!weakref_obj) return weakref_obj;
+             // No public PyWeakReference type.
+             char* dumb_pointer = (char*) weakref_obj;
+
+             PyWeakref_GET_OBJECT(weakref_obj);
+             PyWeakref_GET_OBJECT(dumb_pointer);
+
+             return weakref_obj;
+             """
+            )
+        ])
+        module.test_macro_cast()
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -192,23 +192,23 @@
 def PyUnicode_AS_DATA(space, ref):
     """Return a pointer to the internal buffer of the object. o has to be a
     PyUnicodeObject (not checked)."""
-    return rffi.cast(rffi.CCHARP, PyUnicode_AS_UNICODE(space, ref))
+    return rffi.cast(rffi.CCHARP, _PyUnicode_AS_UNICODE(space, ref))
 
 @cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PyUnicode_GET_DATA_SIZE(space, w_obj):
+def _PyUnicode_GET_DATA_SIZE(space, w_obj):
     """Return the size of the object's internal buffer in bytes.  o has to be a
     PyUnicodeObject (not checked)."""
-    return rffi.sizeof(lltype.UniChar) * PyUnicode_GET_SIZE(space, w_obj)
+    return rffi.sizeof(lltype.UniChar) * _PyUnicode_GET_SIZE(space, w_obj)
 
 @cpython_api([PyObject], Py_ssize_t, error=CANNOT_FAIL)
-def PyUnicode_GET_SIZE(space, w_obj):
+def _PyUnicode_GET_SIZE(space, w_obj):
     """Return the size of the object.  o has to be a PyUnicodeObject (not
     checked)."""
     assert isinstance(w_obj, unicodeobject.W_UnicodeObject)
     return space.len_w(w_obj)
 
 @cpython_api([PyObject], rffi.CWCHARP, error=CANNOT_FAIL)
-def PyUnicode_AS_UNICODE(space, ref):
+def _PyUnicode_AS_UNICODE(space, ref):
     """Return a pointer to the internal Py_UNICODE buffer of the object.  ref
     has to be a PyUnicodeObject (not checked)."""
     ref_unicode = rffi.cast(PyUnicodeObject, ref)
@@ -227,7 +227,7 @@
     w_type = from_ref(space, rffi.cast(PyObject, ref.c_ob_type))
     if not space.is_true(space.issubtype(w_type, space.w_unicode)):
         raise oefmt(space.w_TypeError, "expected unicode object")
-    return PyUnicode_AS_UNICODE(space, ref)
+    return _PyUnicode_AS_UNICODE(space, ref)
 
 @cpython_api([PyObject], Py_ssize_t, error=-1)
 def PyUnicode_GetSize(space, ref):
@@ -247,7 +247,7 @@
     string may or may not be 0-terminated.  It is the responsibility of the caller
     to make sure that the wchar_t string is 0-terminated in case this is
     required by the application."""
-    c_str = PyUnicode_AS_UNICODE(space, rffi.cast(PyObject, ref))
+    c_str = _PyUnicode_AS_UNICODE(space, rffi.cast(PyObject, ref))
     c_length = ref.c_length
 
     # If possible, try to copy the 0-termination as well
diff --git a/pypy/module/cpyext/weakrefobject.py b/pypy/module/cpyext/weakrefobject.py
--- a/pypy/module/cpyext/weakrefobject.py
+++ b/pypy/module/cpyext/weakrefobject.py
@@ -37,13 +37,6 @@
     """
     return space.call_function(w_ref)     # borrowed ref
 
- at cpython_api([PyObject], PyObject, result_borrowed=True)
-def PyWeakref_GET_OBJECT(space, w_ref):
-    """Similar to PyWeakref_GetObject(), but implemented as a macro that does no
-    error checking.
-    """
-    return space.call_function(w_ref)     # borrowed ref
-
 @cpython_api([PyObject], PyObject)
 def PyWeakref_LockObject(space, w_ref):
     """Return the referenced object from a weak reference.  If the referent is


More information about the pypy-commit mailing list