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/accessobject.c b/Objects/accessobject.c
new file mode 100644
index 0000000..41790cd
--- /dev/null
+++ b/Objects/accessobject.c
@@ -0,0 +1,320 @@
+/***********************************************************
+Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
+Amsterdam, The Netherlands.
+
+                        All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its 
+documentation for any purpose and without fee is hereby granted, 
+provided that the above copyright notice appear in all copies and that
+both that copyright notice and this permission notice appear in 
+supporting documentation, and that the names of Stichting Mathematisch
+Centrum or CWI not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior permission.
+
+STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
+THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
+FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+******************************************************************/
+
+/* Access object implementation */
+
+#include "allobjects.h"
+
+#include "structmember.h"
+#include "modsupport.h"		/* For getargs() etc. */
+
+typedef struct {
+	OB_HEAD
+	object		*ac_value;
+	object		*ac_class;
+	typeobject	*ac_type;
+	int		ac_mode;
+} accessobject;
+
+/* Forward */
+static int typecheck PROTO((object *, typeobject *));
+static int classcheck PROTO((object *, object *, int, int));
+
+object *
+newaccessobject(value, class, type, mode)
+	object *value;
+	object *class;
+	typeobject *type;
+	int mode;
+{
+	accessobject *ap;
+	if (class != NULL && !is_classobject(class)) {
+		err_badcall();
+		return NULL;
+	}
+	if (!typecheck(value, type)) {
+		err_setstr(AccessError,
+		"access: initial value has inappropriate type");
+		return NULL;
+	}
+	ap = NEWOBJ(accessobject, &Accesstype);
+	if (ap == NULL)
+		return NULL;
+	XINCREF(value);
+	ap->ac_value = value;
+	XINCREF(class);
+	ap->ac_class = class;
+	XINCREF(type);
+	ap->ac_type = (typeobject *)type;
+	ap->ac_mode = mode;
+	return (object *)ap;
+}
+
+object *
+cloneaccessobject(op)
+	object *op;
+{
+	register accessobject *ap;
+	if (!is_accessobject(op)) {
+		err_badcall();
+		return NULL;
+	}
+	ap = (accessobject *)op;
+	return newaccessobject(ap->ac_value, ap->ac_class,
+			       ap->ac_type, ap->ac_mode);
+}
+
+void
+setaccessowner(op, class)
+	object *op;
+	object *class;
+{
+	register accessobject *ap;
+	if (!is_accessobject(op) || class != NULL && !is_classobject(class))
+		return; /* XXX no error */
+	ap = (accessobject *)op;
+	XDECREF(ap->ac_class);
+	XINCREF(class);
+	ap->ac_class = class;
+}
+
+object *
+getaccessvalue(op, class)
+	object *op;
+	object *class;
+{
+	register accessobject *ap;
+	if (!is_accessobject(op)) {
+		err_badcall();
+		return NULL;
+	}
+	ap = (accessobject *)op;
+	
+	if (!classcheck(class, ap->ac_class, AC_R, ap->ac_mode)) {
+		err_setstr(AccessError, "read access denied");
+		return NULL;
+	}
+	
+	if (ap->ac_value == NULL) {
+		err_setstr(AccessError, "no current value");
+		return NULL;
+	}
+	INCREF(ap->ac_value);
+	return ap->ac_value;
+}
+
+int
+setaccessvalue(op, class, value)
+	object *op;
+	object *class;
+	object *value;
+{
+	register accessobject *ap;
+	if (!is_accessobject(op)) {
+		err_badcall();
+		return -1;
+	}
+	ap = (accessobject *)op;
+	
+	if (!classcheck(class, ap->ac_class, AC_W, ap->ac_mode)) {
+		err_setstr(AccessError, "write access denied");
+		return -1;
+	}
+	
+	if (!typecheck(value, ap->ac_type)) {
+		err_setstr(AccessError, "assign value of inappropriate type");
+		return -1;
+	}
+	
+	if (value == NULL) { /* Delete it */
+		if (ap->ac_value == NULL) {
+			err_setstr(AccessError, "no current value");
+			return -1;
+		}
+		DECREF(ap->ac_value);
+		ap->ac_value = NULL;
+		return 0;
+	}
+	XDECREF(ap->ac_value);
+	INCREF(value);
+	ap->ac_value = value;
+	return 0;
+}
+
+static int
+typecheck(value, type)
+	object *value;
+	typeobject *type;
+{
+	object *x;
+	if (value == NULL || type == NULL)
+		return 1; /* No check */
+	if (value->ob_type == type)
+		return 1; /* Exact match */
+	if (type == &Anynumbertype) {
+		if (value->ob_type->tp_as_number == NULL)
+			return 0;
+		if (!is_instanceobject(value))
+			return 1;
+		/* For instances, make sure it really looks like a number */
+		x = getattr(value, "__sub__");
+		if (x == NULL) {
+			err_clear();
+			return 0;
+		}
+		DECREF(x);
+		return 1;
+	}
+	if (type == &Anysequencetype) {
+		if (value->ob_type->tp_as_sequence == NULL)
+			return 0;
+		if (!is_instanceobject(value))
+			return 1;
+		/* For instances, make sure it really looks like a sequence */
+		x = getattr(value, "__getslice__");
+		if (x == NULL) {
+			err_clear();
+			return 0;
+		}
+		DECREF(x);
+		return 1;
+	}
+	if (type == &Anymappingtype) {
+		if (value->ob_type->tp_as_mapping == NULL)
+			return 0;
+		if (!is_instanceobject(value))
+			return 1;
+		/* For instances, make sure it really looks like a mapping */
+		x = getattr(value, "__getitem__");
+		if (x == NULL) {
+			err_clear();
+			return 0;
+		}
+		DECREF(x);
+		return 1;
+	}
+	return 0;
+}
+
+static int
+classcheck(caller, owner, access, mode)
+	object *caller;
+	object *owner;
+	int access;
+	int mode;
+{
+	if (caller == owner && owner != NULL)
+		return access & mode & (AC_PRIVATE|AC_PROTECTED|AC_PUBLIC);
+	if (caller != NULL && owner != NULL && issubclass(caller, owner))
+		return access & mode & (AC_PROTECTED|AC_PUBLIC);
+	return access & mode & AC_PUBLIC;
+}
+
+/* Access methods */
+
+static void
+access_dealloc(ap)
+	accessobject *ap;
+{
+	XDECREF(ap->ac_value);
+	XDECREF(ap->ac_class);
+	XDECREF(ap->ac_type);
+	DEL(ap);
+}
+
+#define OFF(x) offsetof(accessobject, x)
+
+static struct memberlist access_memberlist[] = {
+	{"ac_value",	T_OBJECT,	OFF(ac_value)},
+	{"ac_class",	T_OBJECT,	OFF(ac_class)},
+	{"ac_type",	T_OBJECT,	OFF(ac_type)},
+	{"ac_mode",	T_INT,		OFF(ac_mode)},
+	{NULL}	/* Sentinel */
+};
+
+static object *
+access_getattr(ap, name)
+	accessobject *ap;
+	char *name;
+{
+	return getmember((char *)ap, access_memberlist, name);
+}
+
+static object *
+access_repr(ap)
+	accessobject *ap;
+{
+	char buf[300];
+	classobject *class = (classobject *)ap->ac_class;
+	typeobject *type = ap->ac_type;
+	sprintf(buf, "<access object, class %.100s, type %.100s, mode 0%o>",
+		class ? getstringvalue(class->cl_name) : "-",
+		type ? type->tp_name : "-",
+		ap->ac_mode);
+	return newstringobject(buf);
+}
+
+typeobject Accesstype = {
+	OB_HEAD_INIT(&Typetype)
+	0,			/*ob_size*/
+	"access",		/*tp_name*/
+	sizeof(accessobject),	/*tp_size*/
+	0,			/*tp_itemsize*/
+	/* methods */
+	access_dealloc,		/*tp_dealloc*/
+	0,			/*tp_print*/
+	access_getattr,		/*tp_getattr*/
+	0,			/*tp_setattr*/
+	0,			/*tp_compare*/
+	access_repr,		/*tp_repr*/
+	0,			/*tp_as_number*/
+	0,			/*tp_as_sequence*/
+	0,			/*tp_as_mapping*/
+	0,			/*tp_hash*/
+};
+
+/* Dummy type objects to indicate classes of types */
+
+/* XXX This should be replaced by a more general "subclassing"
+   XXX mechanism for type objects... */
+
+typeobject Anynumbertype = {
+	OB_HEAD_INIT(&Typetype)
+	0,			/*ob_size*/
+	"*number*",		/*tp_name*/
+};
+
+/* XXX Should really distinguish mutable and immutable sequences as well */
+
+typeobject Anysequencetype = {
+	OB_HEAD_INIT(&Typetype)
+	0,			/*ob_size*/
+	"*sequence*",		/*tp_name*/
+};
+
+typeobject Anymappingtype = {
+	OB_HEAD_INIT(&Typetype)
+	0,			/*ob_size*/
+	"*mapping*",		/*tp_name*/
+};
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);
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index aa29795..7c2aeae 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -38,6 +38,7 @@
 	{"f_code",	T_OBJECT,	OFF(f_code)},
 	{"f_globals",	T_OBJECT,	OFF(f_globals)},
 	{"f_locals",	T_OBJECT,	OFF(f_locals)},
+	{"f_class",	T_OBJECT,	OFF(f_class)},
 /*	{"f_fastlocals",T_OBJECT,	OFF(f_fastlocals)}, /* XXX Unsafe */
 	{"f_localmap",	T_OBJECT,	OFF(f_localmap)},
 	{"f_lasti",	T_INT,		OFF(f_lasti)},
@@ -84,6 +85,7 @@
 	XDECREF(f->f_code);
 	XDECREF(f->f_globals);
 	XDECREF(f->f_locals);
+	XDECREF(f->f_class);
 	XDECREF(f->f_fastlocals);
 	XDECREF(f->f_localmap);
 	f->f_back = free_list;
@@ -108,11 +110,12 @@
 };
 
 frameobject *
-newframeobject(back, code, globals, locals, nvalues, nblocks)
+newframeobject(back, code, globals, locals, class, nvalues, nblocks)
 	frameobject *back;
 	codeobject *code;
 	object *globals;
 	object *locals;
+	object *class;
 	int nvalues;
 	int nblocks;
 {
@@ -121,6 +124,7 @@
 		code == NULL || !is_codeobject(code) ||
 		globals == NULL || !is_dictobject(globals) ||
 		locals == NULL || !is_dictobject(locals) ||
+	        (class != NULL && !is_classobject(class)) ||
 		nvalues < 0 || nblocks < 0) {
 		err_badcall();
 		return NULL;
@@ -146,6 +150,8 @@
 		f->f_globals = globals;
 		INCREF(locals);
 		f->f_locals = locals;
+		XINCREF(class);
+		f->f_class = class;
 		f->f_fastlocals = NULL;
 		f->f_localmap = NULL;
 		if (nvalues > f->f_nvalues || f->f_valuestack == NULL) {
diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c
index 8949c7d..5c0db15 100644
--- a/Objects/moduleobject.c
+++ b/Objects/moduleobject.c
@@ -25,6 +25,7 @@
 /* Module object implementation */
 
 #include "allobjects.h"
+#include "ceval.h"
 
 typedef struct {
 	OB_HEAD
@@ -111,7 +112,7 @@
 		err_setstr(AttributeError, name);
 	else {
 		if (is_accessobject(res))
-			res = getaccessvalue(res, (object *)NULL);
+			res = getaccessvalue(res, getclass());
 		else
 			INCREF(res);
 	}
@@ -134,7 +135,7 @@
 	}
 	ac = dictlookup(m->md_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(m->md_dict, name);
 		if (rv < 0)