Index: ChangeLog =================================================================== diff -u -ra65ff6b8258c66e5e7bb6c4e8567111baa0f08a3 -r802641dc2edee9e8ac569ad9c9cbadc949df8d47 --- ChangeLog (.../ChangeLog) (revision a65ff6b8258c66e5e7bb6c4e8567111baa0f08a3) +++ ChangeLog (.../ChangeLog) (revision 802641dc2edee9e8ac569ad9c9cbadc949df8d47) @@ -1,3 +1,10 @@ +2008-12-01 + * Correct deletion of user-metaclasses: Deletion of + user-metaclasses could lead to undestroyable objects, since the + instances of the user-metaclasses were reclassed to + ::xotcl::Object instead of ::xotcl::Class. + * extend regression test for such situations + 2008-11-02 * Release of XOTcl 1.6.2 Index: generic/xotcl.c =================================================================== diff -u -rda111296df2bd2460f13bce2ebbd2c4a69027ae8 -r802641dc2edee9e8ac569ad9c9cbadc949df8d47 --- generic/xotcl.c (.../xotcl.c) (revision da111296df2bd2460f13bce2ebbd2c4a69027ae8) +++ generic/xotcl.c (.../xotcl.c) (revision 802641dc2edee9e8ac569ad9c9cbadc949df8d47) @@ -7643,20 +7643,36 @@ NSDeleteChildren(interp, cl->nsPtr); if (!softrecreate) { - /* reset all instances to the class ::xotcl::Object, that makes no sense - for ::Object itself */ + /* Reclass all instances of the current class the the appropriate + most general class ("baseClass"). The most general class of a + metaclass is ::xotcl::Class, the most general class of an + object is ::xotcl::Object. Instances of metaclasses can be only + reset to ::xotcl::Class (and not to ::xotcl::Object as in + earlier versions), since otherwise their instances can't be + deleted, because ::xotcl::Object has no method "instdestroy". + + We do not have to reclassing in case, cl == ::xotcl::Object + */ if (cl != theobj) { + XOTclClass *baseClass = IsMetaClass(interp, cl) ? RUNTIME_STATE(interp)->theClass : theobj; + if (baseClass == cl) { + /* During final cleanup, we delete ::xotcl::Class; there are + no more Classes or user objects available at that time, so + we reclass to ::xotcl::Object. + */ + baseClass = theobj; + } hPtr = &cl->instances ? Tcl_FirstHashEntry(&cl->instances, &hSrch) : 0; for (; hPtr != 0; hPtr = Tcl_NextHashEntry(&hSrch)) { XOTclObject *inst = (XOTclObject*)Tcl_GetHashKey(&cl->instances, hPtr); if (inst && inst != (XOTclObject*)cl && inst->id) { - if (inst != &(theobj->object)) { + if (inst != &(baseClass->object)) { (void)RemoveInstance(inst, cl->object.cl); - AddInstance(inst, theobj); + AddInstance(inst, baseClass); } } } - } + } Tcl_DeleteHashTable(&cl->instances); MEM_COUNT_FREE("Tcl_InitHashTable",&cl->instances); } Index: tests/testx.xotcl =================================================================== diff -u -r0037211cd9632cbb418f9f8ca40a001a51d1598d -r802641dc2edee9e8ac569ad9c9cbadc949df8d47 --- tests/testx.xotcl (.../testx.xotcl) (revision 0037211cd9632cbb418f9f8ca40a001a51d1598d) +++ tests/testx.xotcl (.../testx.xotcl) (revision 802641dc2edee9e8ac569ad9c9cbadc949df8d47) @@ -3326,9 +3326,9 @@ ::errorCheck [Object ismetaclass M] 0 "is metaclass 0" ::errorCheck [M isclass] 0 "is isclass 0" ::errorCheck [Class info instances M] "" "is not an instance of Class" - ::errorCheck [m1 info class] ::xotcl::Object "m1 is now an instance of Object" + ::errorCheck [m1 info class] ::xotcl::Class "m1 is now an instance of Class" ::errorCheck [m1 isclass] 1 "m1 is isclass 1" - ::errorCheck [m1 info class] ::xotcl::Object "m1 is of class ::xotcl::Object" + ::errorCheck [m1 info class] ::xotcl::Class "m1 is of class ::xotcl::Class" M destroy # to be completed XXX