Completely get rid of __dynamic__ and the corresponding
Py_TPFLAGS_DYNAMICTYPE bit.  There is no longer a performance benefit,
and I don't really see the use case any more.
diff --git a/Include/object.h b/Include/object.h
index 8620766..a943c00 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -432,9 +432,6 @@
 /* Set if the type allows subclassing */
 #define Py_TPFLAGS_BASETYPE (1L<<10)
 
-/* Set if the type's __dict__ may change */
-#define Py_TPFLAGS_DYNAMICTYPE (1L<<11)
-
 /* Set if the type is 'ready' -- fully initialized */
 #define Py_TPFLAGS_READY (1L<<12)
 
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index e5ee591..a15e7a0 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -17,6 +17,8 @@
     vereq(eval(expr, dict), res)
     t = type(a)
     m = getattr(t, meth)
+    while meth not in t.__dict__:
+        t = t.__bases__[0]
     vereq(m, t.__dict__[meth])
     vereq(m(a), res)
     bm = getattr(a, meth)
@@ -28,6 +30,8 @@
     vereq(eval(expr, dict), res)
     t = type(a)
     m = getattr(t, meth)
+    while meth not in t.__dict__:
+        t = t.__bases__[0]
     vereq(m, t.__dict__[meth])
     vereq(m(a, b), res)
     bm = getattr(a, meth)
@@ -39,6 +43,8 @@
     vereq(eval(expr, dict), res)
     t = type(a)
     m = getattr(t, meth)
+    while meth not in t.__dict__:
+        t = t.__bases__[0]
     vereq(m, t.__dict__[meth])
     vereq(m(a, b, c), res)
     bm = getattr(a, meth)
@@ -51,6 +57,8 @@
     vereq(dict['a'], res)
     t = type(a)
     m = getattr(t, meth)
+    while meth not in t.__dict__:
+        t = t.__bases__[0]
     vereq(m, t.__dict__[meth])
     dict['a'] = deepcopy(a)
     m(dict['a'], b)
@@ -67,6 +75,8 @@
     vereq(dict['a'], res)
     t = type(a)
     m = getattr(t, meth)
+    while meth not in t.__dict__:
+        t = t.__bases__[0]
     vereq(m, t.__dict__[meth])
     dict['a'] = deepcopy(a)
     m(dict['a'], b, c)
@@ -82,6 +92,8 @@
     exec stmt in dict
     vereq(dict['a'], res)
     t = type(a)
+    while meth not in t.__dict__:
+        t = t.__bases__[0]
     m = getattr(t, meth)
     vereq(m, t.__dict__[meth])
     dict['a'] = deepcopy(a)
@@ -104,23 +116,19 @@
 
     class NewStatic(object):
         "Another docstring."
-        __dynamic__ = 0
     vereq(NewStatic.__doc__, "Another docstring.")
     vereq(NewStatic.__dict__['__doc__'], "Another docstring.")
 
     class NewStatic2(object):
-        __dynamic__ = 0
         pass
     verify(NewStatic2.__doc__ is None)
 
     class NewDynamic(object):
         "Another docstring."
-        __dynamic__ = 1
     vereq(NewDynamic.__doc__, "Another docstring.")
     vereq(NewDynamic.__dict__['__doc__'], "Another docstring.")
 
     class NewDynamic2(object):
-        __dynamic__ = 1
         pass
     verify(NewDynamic2.__doc__ is None)
 
@@ -628,7 +636,6 @@
         # Automatically add __super to the class
         # This trick only works for dynamic classes
         def __new__(metaclass, name, bases, dict):
-            assert dict.get("__dynamic__", 1)
             cls = super(autosuper, metaclass).__new__(metaclass,
                                                       name, bases, dict)
             # Name mangling for __super removes leading underscores
@@ -863,54 +870,21 @@
     vereq(x.c, 3)
 
 def dynamics():
-    if verbose: print "Testing __dynamic__..."
-    vereq(object.__dynamic__, 0)
-    vereq(list.__dynamic__, 0)
-    class S1:
-        __metaclass__ = type
-        __dynamic__ = 0
-    vereq(S1.__dynamic__, 0)
-    class S(object):
-        __dynamic__ = 0
-    vereq(S.__dynamic__, 0)
+    if verbose: print "Testing class attribute propagation..."
     class D(object):
-        __dynamic__ = 1
-    vereq(D.__dynamic__, 1)
-    class E(D, S):
         pass
-    vereq(E.__dynamic__, 1)
-    class F(S, D):
+    class E(D):
         pass
-    vereq(F.__dynamic__, 1)
-    try:
-        S.foo = 1
-    except (AttributeError, TypeError):
+    class F(D):
         pass
-    else:
-        verify(0, "assignment to a static class attribute should be illegal")
     D.foo = 1
     vereq(D.foo, 1)
     # Test that dynamic attributes are inherited
     vereq(E.foo, 1)
     vereq(F.foo, 1)
-    class SS(D):
-        __dynamic__ = 0
-    vereq(SS.__dynamic__, 0)
-    vereq(SS.foo, 1)
-    try:
-        SS.foo = 1
-    except (AttributeError, TypeError):
-        pass
-    else:
-        verify(0, "assignment to SS.foo should be illegal")
     # Test dynamic instances
     class C(object):
-        __dynamic__ = 1
-        # XXX Ideally the following def shouldn't be necessary,
-        # but it's too much of a performance burden.
-        # See XXX comment in slot_tp_getattr_hook.
-        def __getattr__(self, name):
-            raise AttributeError, name
+        pass
     a = C()
     verify(not hasattr(a, "foobar"))
     C.foobar = 2
@@ -951,7 +925,7 @@
 
     # Test handling of int*seq and seq*int
     class I(int):
-        __dynamic__ = 1 # XXX why?
+        pass
     vereq("a"*I(2), "aa")
     vereq(I(2)*"a", "aa")
     vereq(2*I(3), 6)
@@ -960,7 +934,7 @@
 
     # Test handling of long*seq and seq*long
     class L(long):
-        __dynamic__ = 1 # XXX why?
+        pass
     vereq("a"*L(2L), "aa")
     vereq(L(2L)*"a", "aa")
     vereq(2*L(3), 6)
@@ -969,7 +943,7 @@
 
     # Test comparison of classes with dynamic metaclasses
     class dynamicmetaclass(type):
-        __dynamic__ = 1 # XXX ???
+        pass
     class someclass:
         __metaclass__ = dynamicmetaclass
     verify(someclass != object)
@@ -1255,7 +1229,6 @@
     verify(10 not in c1)
     # Test the default behavior for dynamic classes
     class D(object):
-        __dynamic__ = 1 # XXX why?
         def __getitem__(self, i):
             if 0 <= i < 10: return i
             raise IndexError
@@ -1318,7 +1291,6 @@
     verify(10 not in p10)
     # Test overridden behavior for dynamic classes
     class DProxy(object):
-        __dynamic__ = 1
         def __init__(self, x):
             self.x = x
         def __nonzero__(self):
@@ -1469,7 +1441,6 @@
     vereq(B().meth(2), "B(2)A(2)")
 
     class C(A):
-        __dynamic__ = 1
         def meth(self, a):
             return "C(%r)" % a + self.__super.meth(a)
     C._C__super = super(C)
@@ -1565,7 +1536,6 @@
     verify((+a).__class__ is float)
 
     class madcomplex(complex):
-        __dynamic__ = 0 # XXX Shouldn't be necessary
         def __repr__(self):
             return "%.17gj%+.17g" % (self.imag, self.real)
     a = madcomplex(-3, 4)
@@ -1967,12 +1937,11 @@
     if verbose:
         print "Testing rich comparisons..."
     class Z(complex):
-        __dynamic__ = 0
+        pass
     z = Z(1)
     vereq(z, 1+0j)
     vereq(1+0j, z)
     class ZZ(complex):
-        __dynamic__ = 0
         def __eq__(self, other):
             try:
                 return abs(self - other) <= 1e-6
@@ -2059,8 +2028,7 @@
     coerce(0, F(0))
     coerce(0L, F(0))
     coerce(0., F(0))
-    class C(complex):
-        __dynamic__ = 0
+    class C(complex): pass
     coerce(C(0), 0)
     coerce(C(0), 0L)
     coerce(C(0), 0.)
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index b401abc..8a78e69 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -56,7 +56,7 @@
 static int
 type_set_module(PyTypeObject *type, PyObject *value, void *context)
 {
-	if (!(type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) ||
+	if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE) ||
 	    strrchr(type->tp_name, '.')) {
 		PyErr_Format(PyExc_TypeError,
 			     "can't set %s.__module__", type->tp_name);
@@ -77,10 +77,6 @@
 		Py_INCREF(Py_None);
 		return Py_None;
 	}
- 	if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
-		Py_INCREF(type->tp_dict);
-		return type->tp_dict;
-	}
 	return PyDictProxy_New(type->tp_dict);
 }
 
@@ -91,29 +87,14 @@
 		Py_INCREF(Py_None);
 		return Py_None;
 	}
-	if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
-		Py_INCREF(type->tp_defined);
-		return type->tp_defined;
-	}
 	return PyDictProxy_New(type->tp_defined);
 }
 
-static PyObject *
-type_dynamic(PyTypeObject *type, void *context)
-{
-	PyObject *res;
-
-	res = (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) ? Py_True : Py_False;
-	Py_INCREF(res);
-	return res;
-}
-
 PyGetSetDef type_getsets[] = {
 	{"__name__", (getter)type_name, NULL, NULL},
 	{"__module__", (getter)type_module, (setter)type_set_module, NULL},
 	{"__dict__",  (getter)type_dict,  NULL, NULL},
 	{"__defined__",  (getter)type_defined,  NULL, NULL},
-	{"__dynamic__", (getter)type_dynamic, NULL, NULL},
 	{0}
 };
 
@@ -711,7 +692,7 @@
 	PyTypeObject *type, *base, *tmptype, *winner;
 	etype *et;
 	PyMemberDef *mp;
-	int i, nbases, nslots, slotoffset, dynamic, add_dict, add_weak;
+	int i, nbases, nslots, slotoffset, add_dict, add_weak;
 
 	/* Special case: type(x) should return x->ob_type */
 	if (metatype == &PyType_Type &&
@@ -777,38 +758,6 @@
 		return NULL;
 	}
 
-	/* Should this be a dynamic class (i.e. modifiable __dict__)?
-	   Look in two places for a variable named __dynamic__:
-	   1) in the class dict
-	   2) in the module dict (globals)
-	   The first variable that is an int >= 0 is used.
-	   Otherwise, the default is dynamic. */
-	dynamic = -1; /* Not yet determined */
-	/* Look in the class */
-	tmp = PyDict_GetItemString(dict, "__dynamic__");
-	if (tmp != NULL) {
-		dynamic = PyInt_AsLong(tmp);
-		if (dynamic < 0)
-			PyErr_Clear();
-	}
-	if (dynamic < 0) {
-		/* Look in the module globals */
-		tmp = PyEval_GetGlobals();
-		if (tmp != NULL) {
-			tmp = PyDict_GetItemString(tmp, "__dynamic__");
-			if (tmp != NULL) {
-				dynamic = PyInt_AsLong(tmp);
-				if (dynamic < 0)
-					PyErr_Clear();
-			}
-		}
-	}
-	if (dynamic < 0) {
-		/* Default to dynamic */
-		dynamic = 1;
-
-	}
-
 	/* Check for a __slots__ sequence variable in dict, and count it */
 	slots = PyDict_GetItemString(dict, "__slots__");
 	nslots = 0;
@@ -868,8 +817,6 @@
 	/* Initialize tp_flags */
 	type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE |
 		Py_TPFLAGS_BASETYPE;
-	if (dynamic)
-		type->tp_flags |= Py_TPFLAGS_DYNAMICTYPE;
 	if (base->tp_flags & Py_TPFLAGS_HAVE_GC)
 		type->tp_flags |= Py_TPFLAGS_HAVE_GC;
 
@@ -1026,14 +973,7 @@
 	int i, n;
 	PyObject *mro, *res, *dict;
 
-	/* For static types, look in tp_dict */
-	if (!(type->tp_flags & Py_TPFLAGS_DYNAMICTYPE)) {
-		dict = type->tp_dict;
-		assert(dict && PyDict_Check(dict));
-		return PyDict_GetItem(dict, name);
-	}
-
-	/* For dynamic types, look in tp_defined of types in MRO */
+	/* Look in tp_defined of types in MRO */
 	mro = type->tp_mro;
 	assert(PyTuple_Check(mro));
 	n = PyTuple_GET_SIZE(mro);
@@ -1104,13 +1044,16 @@
 static int
 type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
 {
-	if (type->tp_flags & Py_TPFLAGS_DYNAMICTYPE) {
-		if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
-			return -1;
-		return update_slot(type, name);
+	if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+		PyErr_Format(
+			PyExc_TypeError,
+			"can't set attributes of built-in/extension type '%s'",
+			type->tp_name);
+		return -1;
 	}
-	PyErr_SetString(PyExc_TypeError, "can't set static type attributes");
-	return -1;
+	if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
+		return -1;
+	return update_slot(type, name);
 }
 
 static void
@@ -1794,7 +1737,7 @@
 int
 PyType_Ready(PyTypeObject *type)
 {
-	PyObject *dict, *bases, *x;
+	PyObject *dict, *bases;
 	PyTypeObject *base;
 	int i, n;
 
@@ -1871,37 +1814,14 @@
 		inherit_special(type, type->tp_base);
 
 	/* Initialize tp_dict properly */
-	if (!PyType_HasFeature(type, Py_TPFLAGS_DYNAMICTYPE)) {
-		/* For a static type, tp_dict is the consolidation
-		   of the tp_defined of its bases in MRO. */
-		Py_DECREF(type->tp_dict);
-		type->tp_dict = PyDict_Copy(type->tp_defined);
-		if (type->tp_dict == NULL)
-			goto error;
-		bases = type->tp_mro;
-		assert(bases != NULL);
-		assert(PyTuple_Check(bases));
-		n = PyTuple_GET_SIZE(bases);
-		for (i = 1; i < n; i++) {
-			base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
-			assert(PyType_Check(base));
-			x = base->tp_defined;
-			if (x != NULL && PyDict_Merge(type->tp_dict, x, 0) < 0)
-				goto error;
-			inherit_slots(type, base);
-		}
-	}
-	else {
-		/* For a dynamic type, we simply inherit the base slots. */
-		bases = type->tp_mro;
-		assert(bases != NULL);
-		assert(PyTuple_Check(bases));
-		n = PyTuple_GET_SIZE(bases);
-		for (i = 1; i < n; i++) {
-			base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
-			assert(PyType_Check(base));
-			inherit_slots(type, base);
-		}
+	bases = type->tp_mro;
+	assert(bases != NULL);
+	assert(PyTuple_Check(bases));
+	n = PyTuple_GET_SIZE(bases);
+	for (i = 1; i < n; i++) {
+		base = (PyTypeObject *)PyTuple_GET_ITEM(bases, i);
+		assert(PyType_Check(base));
+		inherit_slots(type, base);
 	}
 
 	/* Some more special stuff */