Access checks now work, at least for instance data (not for methods
yet).  The class is now passed to eval_code and stored in the current
frame.  It is also stored in instance method objects.  An "unbound"
instance method is now returned when a function is retrieved through
"classname.funcname", which when called passes the class to eval_code.
diff --git a/Objects/classobject.c b/Objects/classobject.c
index bc61b64..e2a5e63 100644
--- a/Objects/classobject.c
+++ b/Objects/classobject.c
@@ -29,19 +29,14 @@
 #include "structmember.h"
 #include "ceval.h"
 
-typedef struct {
-	OB_HEAD
-	object	*cl_bases;	/* A tuple */
-	object	*cl_methods;	/* A dictionary */
-	object	*cl_name;	/* A string */
-} classobject;
-
 object *
-newclassobject(bases, methods, name)
+newclassobject(bases, dict, name)
 	object *bases; /* NULL or tuple of classobjects! */
-	object *methods;
+	object *dict;
 	object *name; /* String; NULL if unknown */
 {
+	int pos;
+	object *key, *value;
 	classobject *op;
 	if (bases == NULL) {
 		bases = newtupleobject(0);
@@ -56,10 +51,15 @@
 		return NULL;
 	}
 	op->cl_bases = bases;
-	INCREF(methods);
-	op->cl_methods = methods;
+	INCREF(dict);
+	op->cl_dict = dict;
 	XINCREF(name);
 	op->cl_name = name;
+	pos = 0;
+	while (mappinggetnext(dict, &pos, &key, &value)) {
+		if (is_accessobject(value))
+			setaccessowner(value, (object *)op);
+	}
 	return (object *) op;
 }
 
@@ -70,20 +70,43 @@
 	classobject *op;
 {
 	DECREF(op->cl_bases);
-	DECREF(op->cl_methods);
+	DECREF(op->cl_dict);
 	XDECREF(op->cl_name);
 	free((ANY *)op);
 }
 
 static object *
+class_lookup(cp, name, pclass)
+	classobject *cp;
+	char *name;
+	classobject **pclass;
+{
+	int i, n;
+	object *value = dictlookup(cp->cl_dict, name);
+	if (value != NULL) {
+		*pclass = cp;
+		return value;
+	}
+	n = gettuplesize(cp->cl_bases);
+	for (i = 0; i < n; i++) {
+		object *v = class_lookup((classobject *)
+				 gettupleitem(cp->cl_bases, i), name, pclass);
+		if (v != NULL)
+			return v;
+	}
+	return NULL;
+}
+
+static object *
 class_getattr(op, name)
 	register classobject *op;
 	register char *name;
 {
 	register object *v;
+	object *class;
 	if (strcmp(name, "__dict__") == 0) {
-		INCREF(op->cl_methods);
-		return op->cl_methods;
+		INCREF(op->cl_dict);
+		return op->cl_dict;
 	}
 	if (strcmp(name, "__bases__") == 0) {
 		INCREF(op->cl_bases);
@@ -97,25 +120,17 @@
 		INCREF(v);
 		return v;
 	}
-	v = dictlookup(op->cl_methods, name);
+	v = class_lookup(op, name, &class);
 	if (v != NULL) {
 		if (is_accessobject(v))
-			v = getaccessvalue(v, (object *)NULL);
+			v = getaccessvalue(v, getclass());
+		else if (is_funcobject(v))
+			v = newinstancemethodobject(v, (object *)NULL,
+						    (object *)class);
 		else
 			INCREF(v);
 		return v;
 	}
-	{
-		int n = gettuplesize(op->cl_bases);
-		int i;
-		for (i = 0; i < n; i++) {
-			v = class_getattr((classobject *)
-					gettupleitem(op->cl_bases, i), name);
-			if (v != NULL)
-				return v;
-			err_clear();
-		}
-	}
 	err_setstr(AttributeError, name);
 	return NULL;
 }
@@ -134,18 +149,18 @@
 			return -1;
 		}
 	}
-	ac = dictlookup(op->cl_methods, name);
+	ac = dictlookup(op->cl_dict, name);
 	if (ac != NULL && is_accessobject(ac))
-		return setaccessvalue(ac, (object *)NULL, v);
+		return setaccessvalue(ac, getclass(), v);
 	if (v == NULL) {
-		int rv = dictremove(op->cl_methods, name);
+		int rv = dictremove(op->cl_dict, name);
 		if (rv < 0)
 			err_setstr(AttributeError,
 				   "delete non-existing class attribute");
 		return rv;
 	}
 	else
-		return dictinsert(op->cl_methods, name, v);
+		return dictinsert(op->cl_dict, name, v);
 }
 
 static object *
@@ -179,17 +194,71 @@
 	0,		/*tp_as_mapping*/
 };
 
+int
+issubclass(class, base)
+	object *class;
+	object *base;
+{
+	int i, n;
+	classobject *cp;
+	if (class == NULL || !is_classobject(class))
+		return 0;
+	if (class == base)
+		return 1;
+	cp = (classobject *)class;
+	n = gettuplesize(cp->cl_bases);
+	for (i = 0; i < n; i++) {
+		if (issubclass(gettupleitem(cp->cl_bases, i), base))
+			return 1;
+	}
+	return 0;
+}
 
-/* We're not done yet: next, we define instance objects... */
+
+/* Instance objects */
 
 typedef struct {
 	OB_HEAD
 	classobject	*in_class;	/* The class object */
-	object		*in_attr;	/* A dictionary */
+	object		*in_dict;	/* A dictionary */
 } instanceobject;
 
 static object *instance_getattr PROTO((instanceobject *, char *));
 
+static int
+addaccess(class, inst)
+	classobject *class;
+	instanceobject *inst;
+{
+	int i, n, pos, ret;
+	object *key, *value, *ac;
+	
+	n = gettuplesize(class->cl_bases);
+	for (i = 0; i < n; i++) {
+		if (addaccess(gettupleitem(class->cl_bases, i), inst) < 0)
+			return -1;
+	}
+	
+	pos = 0;
+	while (mappinggetnext(class->cl_dict, &pos, &key, &value)) {
+		if (!is_accessobject(value))
+			continue;
+		ac = dict2lookup(inst->in_dict, key);
+		if (ac != NULL && is_accessobject(ac)) {
+			err_setval(ConflictError, key);
+			return -1;
+		}
+		ac = cloneaccessobject(value);
+		if (ac == NULL)
+			return -1;
+		ret = dict2insert(inst->in_dict, key, ac);
+		DECREF(ac);
+		if (ret != 0)
+			return -1;
+    	}
+	return 0;
+}
+
 object *
 newinstanceobject(class, arg)
 	object *class;
@@ -198,8 +267,6 @@
 	register instanceobject *inst;
 	object *v;
 	object *init;
-	int pos;
-	object *key, *value;
 	if (!is_classobject(class)) {
 		err_badcall();
 		return NULL;
@@ -209,26 +276,12 @@
 		return NULL;
 	INCREF(class);
 	inst->in_class = (classobject *)class;
-	inst->in_attr = newdictobject();
-	if (inst->in_attr == NULL) {
-	error:
+	inst->in_dict = newdictobject();
+	if (inst->in_dict == NULL ||
+	    addaccess((classobject *)class, inst) != 0) {
 		DECREF(inst);
 		return NULL;
 	}
-	pos = 0;
-	while (mappinggetnext(((classobject *)class)->cl_methods,
-			      &pos, &key, &value)) {
-		if (is_accessobject(value)) {
-			object *ac = cloneaccessobject(value);
-			int err;
-			if (ac == NULL)
-				goto error;
-			err = dict2insert(inst->in_attr, key, ac);
-			DECREF(ac);
-			if (err)
-				goto error;
-		}
-	}
 	init = instance_getattr(inst, "__init__");
 	if (init == NULL) {
 		err_clear();
@@ -288,7 +341,7 @@
 	if (--inst->ob_refcnt > 0)
 		return; /* __del__ added a reference; don't delete now */
 	DECREF(inst->in_class);
-	XDECREF(inst->in_attr);
+	XDECREF(inst->in_dict);
 	free((ANY *)inst);
 }
 
@@ -298,31 +351,30 @@
 	register char *name;
 {
 	register object *v;
+	classobject *class;
 	if (strcmp(name, "__dict__") == 0) {
-		INCREF(inst->in_attr);
-		return inst->in_attr;
+		INCREF(inst->in_dict);
+		return inst->in_dict;
 	}
 	if (strcmp(name, "__class__") == 0) {
 		INCREF(inst->in_class);
 		return (object *)inst->in_class;
 	}
-	v = dictlookup(inst->in_attr, name);
+	v = dictlookup(inst->in_dict, name);
 	if (v != NULL) {
 		if (is_accessobject(v))
-			v = getaccessvalue(v, (object *)NULL);
+			v = getaccessvalue(v, getclass());
 		else
 			INCREF(v);
 		return v;
 	}
-	v = class_getattr(inst->in_class, name);
+	v = class_lookup(inst->in_class, name, &class);
 	if (v == NULL)
-		return v; /* class_getattr() has set the error */
-	if (is_funcobject(v)) {
-		object *w = newinstancemethodobject(v, (object *)inst);
-		DECREF(v);
-		return w;
-	}
-	DECREF(v);
+		goto error;
+	if (is_funcobject(v))
+		return newinstancemethodobject(v, (object *)inst,
+					       (object *)class);
+ error:
 	err_setstr(AttributeError, name);
 	return NULL;
 }
@@ -341,18 +393,18 @@
 			return -1;
 		}
 	}
-	ac = dictlookup(inst->in_attr, name);
+	ac = dictlookup(inst->in_dict, name);
 	if (ac != NULL && is_accessobject(ac))
-		return setaccessvalue(ac, (object *)NULL, v);
+		return setaccessvalue(ac, getclass(), v);
 	if (v == NULL) {
-		int rv = dictremove(inst->in_attr, name);
+		int rv = dictremove(inst->in_dict, name);
 		if (rv < 0)
 			err_setstr(AttributeError,
 				   "delete non-existing instance attribute");
 		return rv;
 	}
 	else
-		return dictinsert(inst->in_attr, name, v);
+		return dictinsert(inst->in_dict, name, v);
 }
 
 static object *
@@ -893,18 +945,24 @@
 }
 
 
-/* And finally, here are instance method objects */
+/* Instance method objects are used for two purposes:
+   (a) as bound instance methods (returned by instancename.methodname)
+   (b) as unbound methods (returned by ClassName.methodname)
+   In case (b), im_self is NULL
+*/
 
 typedef struct {
 	OB_HEAD
-	object	*im_func;	/* The method function */
-	object	*im_self;	/* The object to which this applies */
+	object	*im_func;	/* The function implementing the method */
+	object	*im_self;	/* The instance it is bound to, or NULL */
+	object	*im_class;	/* The class that defined the method */
 } instancemethodobject;
 
 object *
-newinstancemethodobject(func, self)
+newinstancemethodobject(func, self, class)
 	object *func;
 	object *self;
+	object *class;
 {
 	register instancemethodobject *im;
 	if (!is_funcobject(func)) {
@@ -916,8 +974,10 @@
 		return NULL;
 	INCREF(func);
 	im->im_func = func;
-	INCREF(self);
+	XINCREF(self);
 	im->im_self = self;
+	INCREF(class);
+	im->im_class = class;
 	return (object *)im;
 }
 
@@ -943,6 +1003,17 @@
 	return ((instancemethodobject *)im)->im_self;
 }
 
+object *
+instancemethodgetclass(im)
+	register object *im;
+{
+	if (!is_instancemethodobject(im)) {
+		err_badcall();
+		return NULL;
+	}
+	return ((instancemethodobject *)im)->im_class;
+}
+
 /* Class method methods */
 
 #define OFF(x) offsetof(instancemethodobject, x)
@@ -950,6 +1021,7 @@
 static struct memberlist instancemethod_memberlist[] = {
 	{"im_func",	T_OBJECT,	OFF(im_func)},
 	{"im_self",	T_OBJECT,	OFF(im_self)},
+	{"im_class",	T_OBJECT,	OFF(im_class)},
 	{NULL}	/* Sentinel */
 };
 
@@ -966,7 +1038,8 @@
 	register instancemethodobject *im;
 {
 	DECREF(im->im_func);
-	DECREF(im->im_self);
+	XDECREF(im->im_self);
+	DECREF(im->im_class);
 	free((ANY *)im);
 }
 
@@ -985,20 +1058,32 @@
 	instancemethodobject *a;
 {
 	char buf[240];
-	object *classname =
-		((instanceobject *)(a->im_self))->in_class->cl_name;
-	object *funcname = ((funcobject *)(a->im_func))->func_name;
-	char *cname, *fname;
-	if (classname != NULL && is_stringobject(classname))
-		cname = getstringvalue(classname);
+	instanceobject *self = (instanceobject *)(a->im_self);
+	funcobject *func = (funcobject *)(a->im_func);
+	classobject *class = (classobject *)(a->im_class);
+	object *fclassname, *iclassname, *funcname;
+	char *fcname, *icname, *fname;
+	fclassname = class->cl_name;
+	funcname = func->func_name;
+	if (fclassname != NULL && is_stringobject(fclassname))
+		fcname = getstringvalue(fclassname);
 	else
-		cname = "?";
+		fcname = "?";
 	if (funcname != NULL && is_stringobject(funcname))
 		fname = getstringvalue(funcname);
 	else
 		fname = "?";
-	sprintf(buf, "<method %.100s of %.100s instance at %lx>",
-		fname, cname, (long)a->im_func);
+	if (self == NULL)
+		sprintf(buf, "<unbound method %.100s.%.100s>", fcname, fname);
+	else {
+		iclassname = self->in_class->cl_name;
+		if (iclassname != NULL && is_stringobject(iclassname))
+			icname = getstringvalue(iclassname);
+		else
+			icname = "?";
+		sprintf(buf, "<method %.60s.%.60s of %.60s instance at %lx>",
+			fcname, fname, icname, (long)self);
+	}
 	return newstringobject(buf);
 }
 
@@ -1007,7 +1092,10 @@
 	instancemethodobject *a;
 {
 	long x, y;
-	x = hashobject(a->im_self);
+	if (a->im_self == NULL)
+		x = hashobject(None);
+	else
+		x = hashobject(a->im_self);
 	if (x == -1)
 		return -1;
 	y = hashobject(a->im_func);