Merge of descr-branch back into trunk.
diff --git a/Modules/Setup.dist b/Modules/Setup.dist
index 9114414..e9c2a94 100644
--- a/Modules/Setup.dist
+++ b/Modules/Setup.dist
@@ -464,3 +464,5 @@
 # Example -- included for reference only:
 # xx xxmodule.c
 
+# Another example -- the 'xxsubtype' module shows C-level subtyping in action
+xxsubtype xxsubtype.c
diff --git a/Modules/cPickle.c b/Modules/cPickle.c
index e3cc58d..b27339f 100644
--- a/Modules/cPickle.c
+++ b/Modules/cPickle.c
@@ -1869,6 +1869,10 @@
                 res = save_tuple(self, args);
                 goto finally;
             }
+	    if (type == &PyType_Type) {
+		res = save_global(self, args, NULL);
+		goto finally;
+	    }
             break;
 
         case 'l':
diff --git a/Modules/config.c.in b/Modules/config.c.in
index 5a5878f..0d5e8b0 100644
--- a/Modules/config.c.in
+++ b/Modules/config.c.in
@@ -37,7 +37,7 @@
 	{"__main__", NULL},
 	{"__builtin__", NULL},
 	{"sys", NULL},
-	{"exceptions", init_exceptions},
+	{"exceptions", NULL},
 
 	/* Sentinel */
 	{0, 0}
diff --git a/Modules/xxsubtype.c b/Modules/xxsubtype.c
new file mode 100644
index 0000000..60d8c7d
--- /dev/null
+++ b/Modules/xxsubtype.c
@@ -0,0 +1,233 @@
+#include "Python.h"
+
+/* Examples showing how to subtype the builtin list and dict types from C. */
+
+/* spamlist -- a list subtype */
+
+typedef struct {
+	PyListObject list;
+	int state;
+} spamlistobject;
+
+static PyObject *
+spamlist_getstate(spamlistobject *self, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":getstate"))
+		return NULL;
+	return PyInt_FromLong(self->state);
+}
+
+static PyObject *
+spamlist_setstate(spamlistobject *self, PyObject *args)
+{
+	int state;
+
+	if (!PyArg_ParseTuple(args, "i:setstate", &state))
+		return NULL;
+	self->state = state;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMethodDef spamlist_methods[] = {
+	{"getstate", (PyCFunction)spamlist_getstate, METH_VARARGS,
+	 	"getstate() -> state"},
+	{"setstate", (PyCFunction)spamlist_setstate, METH_VARARGS,
+	 	"setstate(state)"},
+	{NULL,	NULL},
+};
+
+staticforward PyTypeObject spamlist_type;
+
+static int
+spamlist_init(spamlistobject *self, PyObject *args, PyObject *kwds)
+{
+	if (PyList_Type.tp_init((PyObject *)self, args, kwds) < 0)
+		return -1;
+	self->state = 0;
+	return 0;
+}
+
+static PyTypeObject spamlist_type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,
+	"spamlist",
+	sizeof(spamlistobject),
+	0,
+	0,					/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	0,					/* tp_getattro */
+	0,					/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+	0,					/* tp_doc */
+	0,					/* tp_traverse */
+	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,					/* tp_iter */
+	0,					/* tp_iternext */
+	spamlist_methods,			/* tp_methods */
+	0,					/* tp_members */
+	0,					/* tp_getset */
+	&PyList_Type,				/* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	(initproc)spamlist_init,		/* tp_init */
+	0,					/* tp_alloc */
+	0,					/* tp_new */
+};
+
+/* spamdict -- a dict subtype */
+
+typedef struct {
+	PyDictObject dict;
+	int state;
+} spamdictobject;
+
+static PyObject *
+spamdict_getstate(spamdictobject *self, PyObject *args)
+{
+	if (!PyArg_ParseTuple(args, ":getstate"))
+		return NULL;
+	return PyInt_FromLong(self->state);
+}
+
+static PyObject *
+spamdict_setstate(spamdictobject *self, PyObject *args)
+{
+	int state;
+
+	if (!PyArg_ParseTuple(args, "i:setstate", &state))
+		return NULL;
+	self->state = state;
+	Py_INCREF(Py_None);
+	return Py_None;
+}
+
+static PyMethodDef spamdict_methods[] = {
+	{"getstate", (PyCFunction)spamdict_getstate, METH_VARARGS,
+	 	"getstate() -> state"},
+	{"setstate", (PyCFunction)spamdict_setstate, METH_VARARGS,
+	 	"setstate(state)"},
+	{NULL,	NULL},
+};
+
+staticforward PyTypeObject spamdict_type;
+
+static int
+spamdict_init(spamdictobject *self, PyObject *args, PyObject *kwds)
+{
+	if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0)
+		return -1;
+	self->state = 0;
+	return 0;
+}
+
+static PyTypeObject spamdict_type = {
+	PyObject_HEAD_INIT(&PyType_Type)
+	0,
+	"spamdict",
+	sizeof(spamdictobject),
+	0,
+	0,					/* tp_dealloc */
+	0,					/* tp_print */
+	0,					/* tp_getattr */
+	0,					/* tp_setattr */
+	0,					/* tp_compare */
+	0,					/* tp_repr */
+	0,					/* tp_as_number */
+	0,					/* tp_as_sequence */
+	0,					/* tp_as_mapping */
+	0,					/* tp_hash */
+	0,					/* tp_call */
+	0,					/* tp_str */
+	0,					/* tp_getattro */
+	0,					/* tp_setattro */
+	0,					/* tp_as_buffer */
+	Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+	0,					/* tp_doc */
+	0,					/* tp_traverse */
+	0,					/* tp_clear */
+	0,					/* tp_richcompare */
+	0,					/* tp_weaklistoffset */
+	0,					/* tp_iter */
+	0,					/* tp_iternext */
+	spamdict_methods,			/* tp_methods */
+	0,					/* tp_members */
+	0,					/* tp_getset */
+	&PyDict_Type,				/* tp_base */
+	0,					/* tp_dict */
+	0,					/* tp_descr_get */
+	0,					/* tp_descr_set */
+	0,					/* tp_dictoffset */
+	(initproc)spamdict_init,		/* tp_init */
+	0,					/* tp_alloc */
+	0,					/* tp_new */
+};
+
+PyObject *
+spam_bench(PyObject *self, PyObject *args)
+{
+	PyObject *obj, *name, *res;
+	int n = 1000;
+	time_t t0, t1;
+
+	if (!PyArg_ParseTuple(args, "OS|i", &obj, &name, &n))
+		return NULL;
+	t0 = clock();
+	while (--n >= 0) {
+		res = PyObject_GetAttr(obj, name);
+		if (res == NULL)
+			return NULL;
+		Py_DECREF(res);
+	}
+	t1 = clock();
+	return PyFloat_FromDouble((double)(t1-t0) / CLOCKS_PER_SEC);
+}
+
+static PyMethodDef xxsubtype_functions[] = {
+	{"bench",	spam_bench, 	METH_VARARGS},
+	{NULL,		NULL}		/* sentinel */
+};
+
+DL_EXPORT(void)
+initxxsubtype(void)
+{
+	PyObject *m, *d;
+
+	m = Py_InitModule("xxsubtype", xxsubtype_functions);
+	if (m == NULL)
+		return;
+
+	if (PyType_InitDict(&spamlist_type) < 0)
+		return;
+	if (PyType_InitDict(&spamdict_type) < 0)
+		return;
+
+	d = PyModule_GetDict(m);
+	if (d == NULL)
+		return;
+
+	Py_INCREF(&spamlist_type);
+	if (PyDict_SetItemString(d, "spamlist",
+				 (PyObject *) &spamlist_type) < 0)
+		return;
+
+	Py_INCREF(&spamdict_type);
+	if (PyDict_SetItemString(d, "spamdict",
+				 (PyObject *) &spamdict_type) < 0)
+		return;
+}