Exemplo n.º 1
0
void classdef.dcl(Pname cname, Ptable tbl)
{
	int nmem;
	Pname p;
	Pptr cct;
	Pbase bt;
	Pname px;
	Ptable btbl;
	int bvirt;
	Pclass bcl;
	int i;
	int fct_seen = 0;
	int static_seen = 0;
	int local = tbl!=gtbl;

	int byte_old = byte_offset;
	int bit_old = bit_offset;
	int max_old = max_align;
	int boff;

	int in_union;
	int usz;
	int make_ctor = 0;
	int make_dtor = 0;

	/* this is the place for paranoia */
	if (this == 0) error('i',"0->Cdef.dcl(%d)",tbl);
	if (base != CLASS) error('i',"Cdef.dcl(%d)",base);
	if (cname == 0) error('i',"unNdC");
	if (cname->tp != this) error('i',"badCdef");
	if (tbl == 0) error('i',"Cdef.dcl(%n,0)",cname);
	if (tbl->base != TABLE) error('i',"Cdef.dcl(%n,tbl=%d)",cname,tbl->base);

	nmem = pubmem->no_of_names() + privmem->no_of_names() + pubdef->no_of_names();
	in_union = (csu==UNION || csu==ANON);

	if (clbase) {
		if (clbase->base != TNAME) error("BC%nU",clbase);
		clbase = Pbase(clbase->tp)->b_name;
		bcl = (Pclass)clbase->tp;
		if ((bcl->defined&SIMPLIFIED) == 0) error("BC%nU",clbase);
		tbl = bcl->memtbl;
		if (tbl->base != TABLE) error('i',"badBC table %d",tbl);
		btbl = tbl;
		bvirt = bcl->virt_count;
		if (bcl->csu == UNION) error('s',"C derived from union");
		if (in_union) 
			error("derived union");
		else
			if (pubbase == 0) csu = CLASS;
		boff = bcl->real_size;
		max_align = bcl->align();
		bit_ass = bcl->bit_ass;
	}
	else {
		btbl = 0;
		bvirt = 0;
		boff = 0;
		if (!in_union) csu = (virt_count) ? CLASS : STRUCT;
		while (tbl!=gtbl && tbl->t_name) tbl = tbl->next; // nested classes
		max_align = AL_STRUCT;
		bit_ass = 1;	// can be bitwise copied
	}

	memtbl->set_scope(tbl);
	memtbl->set_name(cname);
	if (nmem) memtbl->grow((nmem<=2)?3:nmem);

	cc->stack();
	cc->not = cname;
	cc->cot = this;
//error('d',"classdef%n",cname);
	byte_offset = usz = boff;
	bit_offset = 0;

	bt = new basetype(COBJ,cname);
	bt->b_table = memtbl;
	this_type = cc->tot = cct = new ptr(PTR,bt,0);
	PERM(cct);
	PERM(bt);

	for (p=privmem; p; p=px) {
		Pname m;
		px = p->n_list;
//error('d',"privmem%n %d",p,p->tp->base);
		if (p->tp->base==FCT) {
			Pfct f = (Pfct)p->tp;
			Pblock b = f->body;
			f->body = 0;
			switch( p->n_sto ) {
			case AUTO:
			case STATIC:
			case REGISTER:
			case EXTERN:
				error("M%n cannot be%k",p,p->n_sto);
				p->n_sto = 0;
			}
			m =  p->dcl(memtbl,0);
			if (b) {
				if (m->tp->defined&(DEFINED|SIMPLIFIED))
					error("two definitions of%n",m);
				else if (p->where.line!=m->where.line)
					error('s',"previously declared%n cannot be defined inCD",p);
				else
					Pfct(m->tp)->body = b;
			}
			fct_seen = 1;
		}
		else {
			m = p->dcl(memtbl,0);
			if (m) {
				if (m->n_stclass==STATIC) {
					static_seen = 1;
					m->n_sto = (tbl == gtbl) ? 0 : STATIC;
					if (m->n_initializer) error('s',"staticM%n withIr",m);
				}
				if (in_union) {
					if (usz < byte_offset) usz = byte_offset;
					byte_offset = 0;
				}
			}
		}
	}
	if (privmem && csu==STRUCT) csu = CLASS;

	for (p=pubmem; p; p=px) {
		Pname m;
		px = p->n_list;
//error('d',"pubmem%n %d",p,p->tp->base);
		if (p->tp->base == FCT) {
			Pfct f = (Pfct)p->tp;
			Pblock b = f->body;
			f->body = 0;
			switch(p->n_sto) {
			case AUTO:
			case STATIC:
			case REGISTER:
			case EXTERN:
				error("M%n cannot be%k",p,p->n_sto);
				p->n_sto = 0;
			}
			m = p->dcl(memtbl,PUBLIC);
			if (b) {
				if (m->tp->defined&(DEFINED|SIMPLIFIED))
					error("two definitions of%n",m);
				else if (p->where.line!=m->where.line)
					error('s',"previously declared%n cannot be defined inCD",p);
				else
					Pfct(m->tp)->body = b;
			}
			fct_seen = 1;
		}
		else {
			m = p->dcl(memtbl,PUBLIC);
			if (m) {
				if (m->n_stclass==STATIC) {
					m->n_sto = (tbl == gtbl) ? 0 : STATIC;
					static_seen = 1;
					if (m->n_initializer) error('s',"staticM%n withIr",m);
				}
				if (in_union) {
					if (usz < byte_offset) usz = byte_offset;
					byte_offset = 0;
				}
			}
		}
		/*delete p;*/
	}
/*	pubmem = 0;
*/
//	if (local && fct_seen) error("FM of local%k %s",csu,string);

	if (in_union) byte_offset = usz;

	if (virt_count || bvirt) {	/* assign virtual indices */
		Pname vp[100];
		Pname nn;

		nn = has_ctor();
		if (nn==0 || nn->n_table!=memtbl) make_ctor = 1;

		{	//	FUDGE vtbl
			char* s = new char[20];
			sprintf(s,"%s__vtbl",string);
			Pname n = new name(s);
			n->tp = Pfctvec_type;
			Pname nn = gtbl->insert(n,0);
			nn->use();
		}

		if (virt_count = bvirt)
			for (i=0; i<bvirt; i++) vp[i] = bcl->virt_init[i];

for ( nn=memtbl->get_mem(i=1); nn; nn=memtbl->get_mem(++i) ) {
	switch (nn->tp->base) {
	case FCT:
	{	Pfct f = (Pfct)nn->tp;
		if (bvirt) {
			Pname vn = btbl->look(nn->string,0);
			if (vn) {	/* match up with base class */
				if (vn->n_table==gtbl) goto vvv;
				Pfct vnf;
				switch (vn->tp->base) {
				case FCT:
					vnf = (Pfct)vn->tp;
					if (vnf->f_virtual) {
						if (vnf->check(f,0)) error("virtual%nT mismatch:%t and%t",nn,f,vnf);
						f->f_virtual = vnf->f_virtual;
						vp[f->f_virtual-1] = nn;
					}
					else
						goto vvv;
					break;
				case OVERLOAD:
				{	Pgen g = (Pgen)vn->tp;
					if (f->f_virtual
					|| Pfct(g->fct_list->f->tp)->f_virtual)
						error('s',"virtual%n overloaded inBC but not in derivedC",nn);
					break;
				}
				default:
					goto vvv;
				}
			}
			else
				goto vvv;
		}
		else {
		vvv:
/*error('d',"vvv: %n f_virtual %d virt_count %d",nn,f->f_virtual,virt_count);*/
			if (f->f_virtual)  {
				f->f_virtual = ++virt_count;
				switch (f->f_virtual) {
				case 1:
				{	Pname vpn = new name("_vptr");
					vpn->tp = Pfctvec_type;
					(void) vpn->dcl(memtbl,PUBLIC);
					delete vpn;
				}
				default:
					vp[f->f_virtual-1] = nn;
				}
			}
		}
		break;
	}

	case OVERLOAD:
	{	Plist gl;
		Pgen g = (Pgen)nn->tp;
/*error('d',"overload%n bvirt==%d",nn,bvirt);*/
		if (bvirt) {
			Pname vn = btbl->look(nn->string,0);
			Pgen g2;
			Pfct f2;
			if (vn) {
/*error('d',"vn%n tp%k",vn,vn->tp->base);*/
				if (vn->n_table == gtbl) goto ovvv;
				switch (vn->tp->base) {
				default:
					goto ovvv;
				case FCT:
					f2 = (Pfct)vn->tp;
					if (f2->f_virtual
					|| Pfct(g->fct_list->f->tp)->f_virtual)
						error('s',"virtual%n overloaded in derivedC but not inBC",nn);
					break;
				case OVERLOAD:
					g2 = (Pgen)vn->tp;
						
					for (gl=g->fct_list; gl; gl=gl->l) {
						Pname fn = gl->f;
						Pfct f = (Pfct)fn->tp;
						Pname vn2 = g2->find(f);

						if (vn2 == 0) {
							if (f->f_virtual) error('s',"virtual overloaded%n not found inBC",fn);
						}
						else {
							Pfct vn2f = (Pfct)vn2->tp;
							if (vn2f->f_virtual) {
								f->f_virtual = vn2f->f_virtual;
								vp[f->f_virtual-1] = fn;
							}
						}
					}
					break;
				}
			}
			else
				goto ovvv;
		}
		else {
		ovvv:
			for (gl=g->fct_list; gl; gl=gl->l) {
				Pname fn = gl->f;
				Pfct f = (Pfct)fn->tp;

/*fprintf(stderr,"fn %s f %d %d %d count %d\n",fn->string,f,f->base,f->f_virtual,virt_count+1);*/
				if (f->f_virtual) {
					f->f_virtual = ++virt_count;
					switch (f->f_virtual) {
					case 1:
					{	Pname vpn = new name("_vptr");
						vpn->tp = Pfctvec_type;
						(void) vpn->dcl(memtbl,0);
						delete vpn;
					}
					default:
						vp[f->f_virtual-1] = fn;
					}
				}
			}
		}
		break;
	}
}
		}
		virt_init = new Pname[virt_count];
		for (i=0; i<virt_count; i++) virt_init[i] = vp[i];
	}

	Pname pnx;
	for (p=pubdef; p; p=pnx) {
		char* qs = p->n_qualifier->string;
		char* ms = p->string;
		Pname cx;
		Ptable ctbl;
		Pname mx;
		pnx = p->n_list;
//error('d',"dcl: pubdef %s::%s",qs,ms);
		if (strcmp(ms,qs)==0) ms = "_ctor";

		for (cx = clbase; cx; cx = Pclass(cx->tp)->clbase) {
			if (strcmp(cx->string,qs) == 0) goto ok;
		}
		error("publicQr %s not aBC",qs);
		continue;
	ok:
		ctbl = Pclass(cx->tp)->memtbl;
		mx = ctbl->lookc(ms,0);
//error('d',"ms %d %d %d",mx,Ebase,Epriv);
		if (Ebase) {	// cc->nof ??
			if (!Ebase->has_friend(cc->nof)) error("QdMN%n is in privateBC",p);
		}
		else if (Epriv) {
			if (!Epriv->has_friend(cc->nof)) error("QdMN%n is private",p);
		}

		if (mx == 0) {
			error("C%n does not have aM %s",cx,p->string);
			p->tp = any_type;
		}
		else {
			if (mx->tp->base==OVERLOAD) error('s',"public specification of overloaded%n",mx);
			p->base = PUBLIC;
		}
		
		p->n_qualifier = mx;
		(void) memtbl->insert(p,0);
//error('d',"bbb");
		if (Nold) error("twoDs of CM%n",p);
	}
	pubdef = 0;

	if (bit_offset) byte_offset += (bit_offset/BI_IN_BYTE+1);
	real_size = byte_offset;
//error('d',"%s: rz=%d (bits %d)",string,byte_offset,bit_offset);
	if (byte_offset < SZ_STRUCT) byte_offset = SZ_STRUCT;
	int waste = byte_offset%max_align;
	if (waste) byte_offset += max_align-waste;
//error('d',"%s: sz=%d al=%d",string,byte_offset,max_align);
	obj_size = byte_offset;
	obj_align = max_align;
	
	if ( has_dtor() && has_ctor()==0)
		error('w',"%s has destructor but no constructor",string);
	
{	// now look look at the members
	Pname m;
	Pclass oc = in_class;
	int ct = has_ctor()==0;
	int dt = has_dtor()==0;
	int un = csu==UNION;
	Pname statc = 0;
	Pname statd = 0;

	for (m=memtbl->get_mem(i=1); m; m=memtbl->get_mem(++i) ) {

		if (m->base == PUBLIC) continue;

		Ptype t = m->tp;
		switch (t->base) {
		default:
			if (ct && make_ctor==0) {
				if (t->is_ref()) error("reference%n inC %s without constructor",m,string);
				if (t->tconst() && vec_const==0) error("constant%n inC %s without constructor",m,string);
			}
			break;
		case FCT:
		case OVERLOAD:
		case CLASS:
		case ENUM:
			continue;
		case VEC:
			break;
		}
		Pname cn = t->is_cl_obj();
		if (cn == 0) cn = cl_obj_vec;
		if (cn) {
			Pclass cl = (Pclass)cn->tp;
			if (cl->bit_ass == 0) bit_ass = 0;	// no bit copy
			if (ct || dt || un) {
				Pname ctor = cl->has_ctor();
				Pname dtor = cl->has_dtor();
				if (ctor) {
					if (m->n_stclass==STATIC) {
						error('s',"staticM%n ofC%n with constructor",m,cn);
						statc = m;
					}
					else if (un)
						error("M%n ofC%n with constructor in union",m,cn);
					else if (ct) {
						if (statc) error('s',"staticM%n ofC%t with constructor",statc,statc->tp);
						make_ctor = 1;
						ct = 0;
					}
				}
				if (dtor) {
					if (m->n_stclass==STATIC) {
						error('s',"staticM%n ofC%n with destructor",m,cn);
						statd = m;
					}
					else if (un)
						error("M%n ofC%n with destructor in union",m,cn);
					else if (dt) {
						if (statd) error('s',"staticM%n ofC%t with constructor",statd,statd->tp);
						make_dtor = 1;
						dt = 0;
					}
				}
			}
		}
	}
}

	if (make_ctor) {
		Pname ct = has_ctor();
		if (ct==0 || ct->n_table!=memtbl) {
			// make a constructor for the class: x::x() {}
			// a base class's constructor is not good enough
			if (ct && has_ictor()==0) error("%k %s needs a constructor",csu,string);
			Pname n = new name(string);
			Pfct f = new fct(defa_type,0,1);
			n->tp = f;
			n->n_oper = TNAME;
			Pname m = n->dcl(memtbl,PUBLIC);
			Pfct(m->tp)->body = new block(curloc,0,0);
		}
	}

	if (make_dtor && has_dtor()==0) {
		// make a destructor for the class: x::x() {}
		Pname n = new name(string);
		Pfct f = new fct(defa_type,0,1);
		n->tp = f;
		n->n_oper = DTOR;
		Pname m = n->dcl(memtbl,PUBLIC);
		Pfct(m->tp)->body = new block(curloc,0,0);
	}

	defined |= DEFINED;

	for (p=memtbl->get_mem(i=1); p; p=memtbl->get_mem(++i)) {
	/* define members defined inline */
//error('d',"member %n",p);
		switch (p->tp->base) {
		case FCT:
		{	Pfct f = (Pfct)p->tp;
			if (f->body) {
				f->f_inline = 1;
				p->n_sto = STATIC;
				f->dcl(p);
			}
			break;
		}
		case OVERLOAD:
		{	Pgen g = (Pgen)p->tp;
			Plist gl;
			for (gl=g->fct_list; gl; gl=gl->l) {
				Pname n = gl->f;
				Pfct f = (Pfct)n->tp;
				if (f->body) {
					f->f_inline = 1;
					n->n_sto = STATIC;
					f->dcl(n);
				}
			}
		}
		}
	}

	Plist fl;			/* define friends defined inline */
	for (fl=friend_list; fl; fl=fl->l) {
		Pname p = fl->f;
		switch (p->tp->base) {
		case FCT:
		{	Pfct f = (Pfct)p->tp;
			if (f->body
			&&  (f->defined&(DEFINED|SIMPLIFIED)) == 0) {
				f->f_inline = 1;
				p->n_sto = STATIC;
				f->dcl(p);
			}
			break;
		}
		case OVERLOAD:
		{	Pgen g = (Pgen)p->tp;
			Plist gl;
			for (gl=g->fct_list; gl; gl=gl->l) {
				Pname n = gl->f;
				Pfct f = (Pfct)n->tp;
				if (f->body
				&&  (f->defined&(DEFINED|SIMPLIFIED)) == 0) {
					f->f_inline = 1;
					n->n_sto = STATIC;
					f->dcl(n);
				}
			}
		}
		}
	}

	byte_offset = byte_old;
	bit_offset = bit_old;
	max_align = max_old;

	cc->unstack();
}
Exemplo n.º 2
0
bit type::check(Ptype t, TOK oper, bit level)
/*
	check if "this" can be combined with "t" by the operator "oper"

	used for check of
			assignment types		(oper==ASSIGN)
			declaration compatability	(oper==0)
			decl. compatibility without "const"ness (oper=254) 
						(oper == IGNORE_CONST)
			parameterized type formals	(oper==255)
			  as for (oper==0) but
			  special checking for ANY types
			argument types			(oper==ARG)
			return types			(oper==RETURN)
			overloaded function name match	(oper==OVERLOAD)
			overloaded function coercion	(oper==COERCE)
			virtual function match		(oper==VIRTUAL)

	NOT for arithmetic operators

	return 1 if the check failed
*/
{

	register Ptype t1 = this, t2 = t;
	bit cnst1 = 0, cnst2 = 0;
	TOK b1, b2;
	bit vv=0, over=0, strict_any_check = 0;
	TOK rec_oper;		// value of oper for recursive calls to type::check
				//	oper, 255, or PT_OVERLOAD
	TOK rec_oper0;		// value of oper for recursive calls to type::check
				//	0, 255, or PT_OVERLOAD

	if (t1==0 || t2==0)
		error('i',"check(%p,%p,%d)",t1,t2,oper);

	if(t1==t2)
		return 0;

	switch(oper) {
	case VIRTUAL:
		vv = 1;
		Vcheckerror = 0;
		oper = 0;
		break;
	case OVERLOAD:
		over = 1;
		oper = 0;
		break;
	case PT_OVERLOAD:
		over = 1;
		// no break
	case 255:
		oper = 0;
		strict_any_check=1;
		break;
	}

	if(level==0) {
		const_problem = 0;
		return_error = 0;
		pt_ptm = 0;
		pt_over = over;
	}

	rec_oper = strict_any_check ? ( over ? PT_OVERLOAD : 255 ) : oper;
	rec_oper0 = strict_any_check ? ( over ? PT_OVERLOAD : 255 ) : 0;

	t1 = t1->skiptypedefs(cnst1);

/*
**	GLOG: the following test on ANY must be done before unrolling
**	t2, to accommodate templates (in a way I don't yet understand)
*/
	if (t1->base == ANY || t2->base == ANY)
		if (over==0 || strict_any_check==0) 
			return strict_any_check ? t1!=t2 : 0;

	t2 = t2->skiptypedefs(cnst2);

	if(t1==t2)
		goto const_check;

	b1 = t1->base;
	b2 = t2->base;

	if (b1 != b2) {
		switch (b1) {
		case PTR:
			switch (b2) {
			case VEC:
				if (
					level>0
					||
					(oper == 0 || oper == IGNORE_CONST)  
					&&
					over==0
					||
					Pptr(t1)->memof
					||
					Pptr(t1)->ptname
					||
					Pptr(t1)->typ->check(Pvec(t2)->typ,rec_oper,level+1)
				)
					return 1;

				goto const_check;

			case FCT:
				if (
					level>0
					||
					Pptr(t1)->typ->check(t2,rec_oper,level+1)
				)
					return 1;
				goto const_check;
			}
			break;

		case FCT:
			if( b2==PTR ) {
				if (
					level>0
					||
					t1->check(Pptr(t2)->typ,rec_oper,level+1)
				)
					return 1;
				goto const_check;
			}
			break;

		case VEC:
			if (b2==PTR) {
				if (
					level>0
					||
					(oper==0 || oper == IGNORE_CONST)  
					&&
					over==0
					||
					Pptr(t2)->memof
					||
					Pptr(t2)->ptname
					||
					Pvec(t1)->typ->check(Pptr(t2)->typ,rec_oper,level+1)
				)
					return 1;

				goto const_check;
			}
			break;
		}

		if(level>0) {
			if((oper != 0 && oper != IGNORE_CONST) && b1==VOID && level==1) {
				if(b2==FCT) {
					Pfct f = Pfct(t2);
					if(f->memof && f->f_static==0)
						return 1;
				}
				goto const_check;
			}
			return 1;
		}

		switch (oper) {
		case 0:
		case IGNORE_CONST:	
			if (
				b2 == ZTYPE && b1==INT && Pbase(t1)->b_unsigned==0
				||
				b1 == ZTYPE && b2==INT && Pbase(t2)->b_unsigned==0
			)
				goto const_check;
			return 1;
		case ARG:
		case ASSIGN:
		case RETURN:
		case COERCE:
			switch (b1) {
			case ZTYPE:
			case CHAR:
			case SHORT:
			case INT:
			case LONG:
			case LLONG:
			case FLOAT:
			case DOUBLE:
			case LDOUBLE:
			case FIELD:
				switch (b2) {
				case LONG:
				case LLONG:
				case FLOAT:
				case DOUBLE:
				case LDOUBLE:
				case EOBJ:
				case ZTYPE:
				case CHAR:
				case SHORT:
				case INT:
				case FIELD:
					if(oper==COERCE)
						Nstd++;
					goto const_check;
				}
				return 1;
			case PTR:
			case VEC:
				if (b2==ZTYPE) {
					if(oper==COERCE)
						Nstd++;
					goto const_check;
				}
			case RPTR:
			case COBJ:
			case FCT:
			case EOBJ:
			default:
				return 1;
			}
		}
		goto const_check;
	}

	switch (b1) {
	case VEC:
		if (
			Pvec(t1)->size!=Pvec(t2)->size
			&&
			(
			level>0
			||
			(oper==0 || oper==IGNORE_CONST)	
			&&
			strict_any_check==0
			&&
			Pvec(t1)->size
			&&
			Pvec(t2)->size
			)
		)
			return 1;

		if(Pvec(t1)->typ->check(Pvec(t2)->typ,rec_oper,level+1))
			return 1;
		break;

	case PTR:
	case RPTR:
	{
		Pptr p1 = Pptr(t1);
		Pptr p2 = Pptr(t2);

		if ((p1->ptname && p2->ptname) && (!p1->memof || !p2->memof))
			return 1;

		if (!same_class(p1->memof,p2->memof)) {
			
			// T::* requires we defer setting up memof
			// until instantiation of the Template type T
			// ptname holds the formal parameter T
			// can't merge with other if because of memof usage
			if(
				p1->memof==0 && p1->ptname
				||
				p2->memof==0 && p2->ptname
			)
			 	pt_ptm = 1; 
			else	
			if(
				p1->memof==0 
				||
				p2->memof==0
				||
				(p1->memof->baseof(p2->memof)==0 &&
				 same_class(p1->memof,p2->memof,1)==0)
			)
				return 1;

			if (pt_ptm == 0 && (oper==0 || oper==IGNORE_CONST) && 
			    same_class(p1->memof,p2->memof)==0)
				return 1;

			if(oper==COERCE)
				Nstd++;
		}

#if 0
		if (!level && (oper == 0 || oper == ASSIGN || oper == COERCE ||
		    oper == ARG || oper == RETURN)) {
			Ptype t11;
			Ptype t22;
			Ptype ta;
			Ptype tb;
			int i = 0;
			int j = 0;
			int k = 0;
			ta = t1;
			while ((ta->base == PTR || ta->base == RPTR) &&
			    (tb = ta->is_ptr_or_ref())) {
				ta = Pptr(tb)->typ;
				i++;
				k += ta->tconst();
			}
			t11 = ta;
			ta = t2;
			while ((ta->base == PTR || ta->base == RPTR) &&
			    (tb = ta->is_ptr_or_ref())) {
				ta = Pptr(tb)->typ;
				j++;
			}
			t22 = ta;
			if (i >= 2 && j == i && t11->tconst() &&
			    !t22->tconst() && k != i)
				return const_problem = 1;
		}
#endif

		if(p1->typ->check(p2->typ,rec_oper,level+1))
			return 1;

		break;
	}

	case FCT:
	{
		Pfct f1 = Pfct(t1);
		Pfct f2 = Pfct(t2);
		Pname a1 = f1->argtype;
		Pname a2 = f2->argtype;
		TOK k1 = f1->nargs_known;
		TOK k2 = f2->nargs_known;
		int n1 = f1->nargs;
		int n2 = f2->nargs;
		// if pt_ptm, want to check arguments and return type
		// but template ptm has no memof until instantiation
		if (!same_class(f1->memof,f2->memof) && pt_ptm == 0) {
			if (f1->memof==0 && f2->f_static)
				goto sss;
			if (vv == 0)	// match even if private base class
				if (
					f1->memof==0
					||
					f2->memof==0
					||
					(
					    level > 1
					    ||
					    f1->memof->baseof(f2->memof)==0
					)
					&&
					same_class(f1->memof,f2->memof)==0
				)
					return 1;
			if(oper==COERCE)
				Nstd++;
			sss:;	//SSS
		}

		if (k1 != k2)
			return 1;

		if (n1!=n2 && k1 && k2) {
			goto aaa;
		}
		else if (a1 && a2) {
			while (a1 && a2) {
				if (a1->tp->check(a2->tp,rec_oper0,level+1))
					return 1;
				a1 = a1->n_list;
				a2 = a2->n_list;
			}
			if (a1 || a2)
				goto aaa;
		}
		else if (a1 || a2) {
		aaa:
			if (k1 == ELLIPSIS) {
				switch (oper) {
				case 0:
				case IGNORE_CONST:	
					if (a2 && k2==0)
						break;
					return 1;
				case ASSIGN:
					if (a2 && k2==0)
						break;
					return 1;
				case ARG:
					if (a1)
						return 1;
					break;
				case COERCE:
					return 1;
				}
			}
			else if (k2 == ELLIPSIS) {
				return 1;
			}
			else if (k1 || k2) {
				return 1;
			}
		}

		cnst1 = f2->f_const;
		cnst2 = f1->f_const;

		if(f1->returns->check(f2->returns,rec_oper0,level+1)) {
			if(vv && cnst1==cnst2) {
				bit fail = 1;
				Ptype t1 = f1->returns;
				Ptype t2 = f2->returns;
				if ((t1->is_ptr() && t2->is_ptr()) ||
				    (t1->is_ref() && t2->is_ref())) {
					t1 = Pptr(t1->is_ptr_or_ref())->typ;
					t2 = Pptr(t2->is_ptr_or_ref())->typ;
					if (!t1->is_ptr_or_ref() &&
					    !t2->is_ptr_or_ref()) {
						t1 = t1->skiptypedefs();
						t2 = t2->skiptypedefs();
						if (t1->base == COBJ &&
						    t2->base == COBJ) {
							Pclass c1 = t1->classtype();
							Pclass c2 = t2->classtype();
							Nvis = 0;
							if (c2->has_base(c1,0,1) && !Nvis)
								fail = 0;
						}
					}
				}
				if (fail)
					Vcheckerror = 1;
				else
					break;
			}
			if (rec_oper0 == PT_OVERLOAD && level == 0)
				return_error = 1;
			return 1;
		}

		break;
	}

	case FIELD:
		switch (oper) {
		case 0:
		case IGNORE_CONST:	
		case ARG:
			error('i',"check field?");
		}
		return 0;

	case FLOAT:
	case DOUBLE:
	case LDOUBLE:
	case CHAR:
	case SHORT:
	case INT:
	case LONG:
	case LLONG:
		if (Pbase(t1)->b_unsigned != Pbase(t2)->b_unsigned) {
			if (level>0 || (oper==0 || oper==IGNORE_CONST))
				return 1;
			if (oper==COERCE)
				Nstd++;
		}
		goto const_check;

	case EOBJ:
		if (Pbase(t1)->b_name->tp != Pbase(t2)->b_name->tp)
			return 1;
		goto const_check;

	case CLASS:
	case COBJ:
	{
		Pname n1, n2;
		if (b1 == COBJ) {
			n1 = Pbase(t1)->b_name;
			n2 = Pbase(t2)->b_name;
			if (n1 == n2)
				goto const_check;
		}

		// once again, a more comprehensive check for classes,
		// since they may be parameterized.
		// same_class: handles class templates: instantiated
		// fm_same_class: handles matching uninstantiated templates
		// 	used as formal arguments for template functions

		// hack: see comment on classdef::same_class in template.c
		extern int is_arg;
		int access = template_hier || pt_over;
		if (
			same_class(Pclass(b1==COBJ?n1->tp:t1),Pclass(b1==COBJ?n2->tp:t2),access||is_arg)
			||
			rec_oper==PT_OVERLOAD
			&&
			fm_same_class(Pclass(b1==COBJ?n1->tp:t1),Pclass(b1==COBJ?n2->tp:t2))
		)
			goto const_check;

		// permit a derived class to match public base class
		if (template_hier != 0)
			goto pt_hack;

		switch (oper) {
		case ARG:
		case ASSIGN:
		case RETURN:
		case COERCE:
		{
		pt_hack:
			ppbase = PUBLIC;
			if (level<=1 && ((Pclass(b1==COBJ?n2->tp:t2))->is_base(b1==COBJ?n1->string:Pclass(t1)->string))) {
				if (ppbase!=PUBLIC) {
					const_problem = 0;
					return 1;	// private or protected base
				}
				if(oper==COERCE)
					Nstd++;
				goto const_check;
			}
		}
			// no break
		case 0:
		case IGNORE_CONST:	
			const_problem = 0;
			return 1;
		}

		goto const_check;
	}

	case ZTYPE:
	case VOID:
		goto const_check;
	default:
		error('i',"T::check(o=%d %d %d)",oper,b1,b2);
	}

const_check:


	if(cnst1==cnst2)
		return 0;

	switch(oper) {
	case IGNORE_CONST:	
		return 0;//ignore "const"ness for oper=IGNORE_CONST

	case 0:
		const_problem=1;
		return 1;

	case ASSIGN:
	case COERCE:
	case ARG:
	case RETURN:
		if(level>0) {
			if(cnst2)
				const_problem=1;
			return cnst2;
		}
		return 0;
	default:
		error('i',"oper = %k in type::check()",oper);
	}
	return 0;
}