File contents
/*ident "@(#)cls4:src/dcl4.c 1.38" */
/*******************************************************************************
C++ source for the C++ Language System, Release 3.0. This product
is a new release of the original cfront developed in the computer
science research center of AT&T Bell Laboratories.
Copyright (c) 1993 UNIX System Laboratories, Inc.
Copyright (c) 1991, 1992 AT&T and UNIX System Laboratories, Inc.
Copyright (c) 1984, 1989, 1990 AT&T. All Rights Reserved.
THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System
Laboratories, Inc. The copyright notice above does not evidence
any actual or intended publication of such source code.
dcl4.c:
Declaration of class and enum
*************************************************************************/
#include "cfront.h"
#include "size.h"
#include "template.h"
static Pname get_vf(Pname n_pvf, Pclass cl) {
/*----------------------------------------------------------------------------
search the base hierarchy of class "cl" if n_pvf (Name of Pure Virtual
Function) has a definition.
returns 0 if no definition found in the hierarchy.
returns Pname if found.
*----------------------------------------------------------------------------
*/
if(!n_pvf || !cl) return 0;
if (n_pvf->tp &&
!cl->has_base(Pfct(n_pvf->tp)->memof)) {
return 0; //if pvf is not in a base of "cl"
}
Pname n_vf = cl->memtbl->look(n_pvf->string,0);
if (n_vf && n_pvf->tp && n_vf->tp) {
if (n_vf->tp->base == OVERLOAD) {
for (Plist gl = Pgen(n_vf->tp)->fct_list; gl; gl = gl->l) {
if (!Pfct(n_pvf->tp)->check(gl->f->tp, VIRTUAL))
break;
}
if (!gl)
n_vf = 0;
}
else {
if (Pfct(n_pvf->tp)->check(Pfct(n_vf->tp), VIRTUAL))
n_vf = 0;
}
}
//error('d',"get_vf %n in %t for pure virt. %n",n_vf, cl, n_pvf);
if (n_vf==0) {
for (Pbcl b=cl->baselist; b; b = b->next) {
if (b->base == NAME || b->base == VIRTUAL) {
n_vf = get_vf(n_pvf,b->bclass);
if (n_vf && !n_vf->n_initializer) {
break;
} else {
n_vf = 0;
}
}
} //for (Pbcl b=...
} //if (n_vf==0)
return n_vf;
}
Pname find_vptr(Pclass);
void fix_args(Pfct f, Pclass cl)
/*
This function is used to cope with the case where cl::cl(cl&) is
declared AFTER f has been declared
set n_xref bit for f
*/
{
for (Pname a = f->argtype; a; a = a->n_list) {
Pname n = a->tp->is_cl_obj();
if (n && same_class(Pclass(n->tp),cl))
a->n_xref = 1;
}
}
struct typedef_info {
Pname n;
typedef_info *next;
};
static typedef_info *typedef_info_head=0, *typedef_info_tail=0;
static Pfct get_fct_node(Pname n)
{
Ptype t = n->tp ? n->tp->skiptypedefs() : 0;
if (t && t->base==RPTR)
t = Pptr(t)->typ->skiptypedefs();
while (t && t->base==PTR)
t = Pptr(t)->typ->skiptypedefs();
return t && t->base==FCT ? Pfct(t) : 0;
}
static void record_typedef(Pname tn)
{
typedef_info *p = new typedef_info;
p->n = tn;
if (typedef_info_head==0) {
typedef_info_head = typedef_info_tail = p;
} else {
typedef_info_tail->next = p;
typedef_info_tail = p;
}
}
void typedef_check(Pname n)
{
Pname cn;
Pfct f = get_fct_node(n);
if (!f) return;
for (Pname a = f->argtype; a; a = a->n_list) {
cn = a->tp ? a->tp->is_cl_obj() : 0;
if (!a->n_xref && cn && cn->tp && !(Pclass(cn->tp)->defined&DEFINED)) {
record_typedef(n);
return;
}
}
cn = f->returns ? f->returns->is_cl_obj() : 0;
if ((!f->s_returns || f->s_returns!=void_type) && cn && cn->tp && !(Pclass(cn->tp)->defined&DEFINED))
record_typedef(n);
}
static void typedef_checkall(Pclass cl)
{
for (typedef_info *p=typedef_info_head; p; p=p->next) {
Pfct f = get_fct_node(p->n);
Pname cn;
for (Pname a = f->argtype; a; a = a->n_list) {
cn = a->tp ? a->tp->is_cl_obj() : 0;
if (!a->n_xref && cn && cn->tp && same_class(Pclass(cn->tp),cl) && cl->has_itor()) {
error('s', &p->n->where, "C%t used asAT inTdef%n before it was known that%t has a copyK", cl, p->n, cl);
break;
}
}
cn = f->returns ? f->returns->is_cl_obj() : 0;
if ((!f->s_returns || f->s_returns!=void_type) && cn && cn->tp && same_class(Pclass(cn->tp),cl) && cl->has_itor())
error('s', &p->n->where, "C%t used as returnT inTdef%n before it was known that%t has a copyK", cl, p->n, cl);
}
}
Pname merge_conv(Pname c1, Pname c2)
{
if (c1 == 0)
return c2;
if (c2 == 0)
return c1;
if (c1 == c2)
return c1;
error('s',"cannot merge lists of conversion functions");
return c1;
}
static int Eppp;
char* get_classname(char* s)
/*
retrieve the outermost class name in a vtable name
*/
{
// error('d',"get_classname(%s)",s);
char* s1 = 0;
while (*s) {
s1 = s;
loop:
for ( ; s[0] && (s[0] != '_' || s[1] && s[1] != '_'); s++);
if (*s) {
if (strncmp(s,"___pt__",7)==0) {
s+=7; goto loop;
}
if (strncmp(s,"__pt__",6)==0) { // parameterized class
s+=6; goto loop;
}
if ( s[1] == 0 ) ++s;
else s += 2; // bypass "__"
}
}
return s1;
}
char* drop_classname(char* s)
/*
retrieve all but the outermost class name in a vtable name
*/
{
// error('d',"drop_classname(%s)",s);
char* r = new char[strlen(s)+1];
sprintf(r,s);
s = r;
char* s1 = s;
while (*s) {
loop:
for ( ; s[0] && (s[0] != '_' || s[1] && s[1] != '_'); s++);
if (*s) {
if (strncmp(s,"___pt__",7)==0) {
s+=7; goto loop;
}
if (strncmp(s,"__pt__",6)==0) { // parameterized class
s+=6; goto loop;
}
if ( s[1] == 0 ) { s1 = ++s; break; }
s1 = s;
s += 2; // bypass "__"
}
}
*s1 = '\0';
return (*r) ? r : 0;
}
bit classdef::has_const_mem()
/*
does this class have any constant members
*/
{
int i;
for (Pname m = memtbl->get_mem(i=1); m; NEXT_NAME(memtbl,m,i))
if (m && m->tp)
switch (m->tp->base) {
case FCT: break;
case OVERLOAD: break;
case EOBJ: break;
default:
if (m->tp->is_const_object() && m->n_stclass!=STATIC) return 1;
}
return 0;
}
Pbcl classdef::get_base( char *s )
/*
Find the base class whose name matches the argument
*/
{
//error('d',"%t::get_base(%s) baselist%d %t",this,s,this?baselist:0,this?baselist->bclass:0);
for (Pbcl b = baselist; b; b = b->next) {
//error('d'," b%t s %s",b->bclass,s);
for (
char *s1 = s, *s2 = b->bclass->string;
*s1 && *s2 && *s1 == *s2;
s1++, s2++
)
;
if (!(*s1 || *s2))
break;
}
return b;
}
static int
offset_magic_0(Pbcl b, Pbcl bb, short virt_count)
{
// error('d',"offset_magic_0(%t %t %d)", b->bclass,bb->bclass,virt_count);
Pclass bcl = bb->bclass;
int offset = 0;
for (Pbcl l = b; l; l=l->next) {
if (l->base == VIRTUAL) continue;
Pclass bc = l->bclass;
for (Pbcl ll = bc->baselist; ll; ll=ll->next) {
if (ll->base != VIRTUAL) continue;
int diff = strcmp(bcl->string,ll->bclass->string);
// if (ll->allocated && !diff) {
if (ll->allocated == 1 && !diff) {
offset = ll->obj_offset + l->obj_offset;
// error('d',"%d offset_magic_0 returning found offset of %t",offset, bcl);
return offset;
}
// if (diff && ll->allocated) {
if (diff && ll->allocated == 1) {
offset = ll->bclass->has_allocated_base(bcl);
if (offset) {
if (!virt_count)
offset += l->obj_offset;
// error('d',"%d offset_magic_0 returning allocated offset of %t",offset, bcl);
return offset;
}
}
}
}
if (Nvbc_alloc) {
offset = bb->obj_offset - Nvbc_alloc->obj_offset;
if (virt_count) offset += 4;
// error('d',"nvbc: %t %d bb: %d offset: %d",Nvbc_alloc->bclass,Nvbc_alloc->obj_offset,bb->obj_offset,offset);
}
// error('d',"offset_magic_0 offset: %d virtualBC %t",offset,bcl);
return offset;
}
static int
offset_magic_1(Pbcl b, Pbcl bl)
{
// error('d',"offset_magic_1( %t, %t )",b->bclass,bl->bclass);
char *str = b->bclass->string;
for (Pbcl bb=bl->bclass->baselist; bb; bb=bb->next) {
if (bb->base != VIRTUAL) continue;
char *s = bb->bclass->string;
if (strcmp(s,str)==0) {
int offset = bb->obj_offset - bb->ptr_offset +1;
// error('d',"str: %s offset: %d obj_offset: %d",str,offset,bl->obj_offset);
return offset + bl->obj_offset;
}
}
// error('d',"0 offset_magic_1 for virtualBC%t contained within%t",b->bclass,bl->bclass);
return 0;
}
// cope with offsets of virtuals in deep nests: promoted, not allocated
extern int link_compat_hack;
static int Voffset;
bit Vvtab;
bit Vvbc_alloc;
bit Vvbc_inher;
int classdef::get_offset(char* s, bit rechk)
/* Get offset represented by string as viewed from "this" */
{
// error('d',"%s::get_offset(%s %d)",string,s,rechk);
if (!s) return 0;
char *str = get_classname(s);
Pbcl b = get_base(str);
bit unalloc = 0;
char *found_virtual = 0;
if (rechk) {
// unalloc = (b->promoted && (b->allocated == 0));
unalloc = (b->promoted && (b->allocated != 1));
// error('d',"%s::get_offset unalloc: %d b->alloc: %d",string,unalloc,b->allocated);
if (!unalloc) return 0;
Vvtab = 0; // promoted virtual base contains vtbl
Vvbc_inher = 0;
Vvbc_alloc = 0; // promoted virtual base contains vtbl
Nvbc_alloc = 0; // set by has_allocated_base
found_virtual = has_allocated_base(str);
}
if (unalloc) {
// error('d', "recheck get_offset: voffset: %d found_virtual: %s str: %s ps: %s",Voffset,found_virtual,str);
if (found_virtual == 0) {
if (Vvbc_alloc && b->bclass->baselist)
return b->obj_offset;
if (strcmp(s,str)) {
if (Vvbc_inher)
return 0;
if (Vvtab == 0)
return b->bclass->get_offset(drop_classname(s));
return b->obj_offset + b->bclass->get_offset(drop_classname(s));
}
else {
if (Vvbc_inher) {
if (b->allocated == 2)
link_compat_hack = b->obj_offset;
return 0;
}
return offset_magic_0(baselist->next,b,virt_count);
}
}
if (found_virtual) {
if (strcmp(s,str))
return offset_magic_1(b,get_base(found_virtual));
else return b->obj_offset;
}
}
return b->obj_offset + b->bclass->get_offset(drop_classname(s));
}
char* vtbl_str(char* s1, char* s2)
/*
combine two pieces of a vtbl name
*/
{
// error('d',"vtbl_str(%s,%s)",s1,s2);
char* s3;
if (s1)
if (s2) {
s3 = new char[strlen(s1)+strlen(s2)+3];
sprintf(s3,"%s__%s",s1,s2);
return s3;
}
else
return s1;
else
return s2;
}
void classdef::add_vtbl(velem* v, char* s, bit virt_flag, int n_init)
/*
add vtbl to virt_list
*/
{
// error('d',"%t->add_vtbl(%d,%s)",this,v,s);
Pvirt vtab = new virt(this, v, s, virt_flag, n_init);
if (virt_flag)
has_vvtab = 1;
if (!virt_list) {
virt_list = vtab;
return;
}
// If conficting vtable entries are made because of
// a virtual base class, must be considered an error.
for (Pvirt vt = virt_list; vt; vt = vt->next )
if (vt->string && strcmp(vt->string,s)==0) {
velem* ivec = vt->virt_init;
Pname on = ivec[0].n;
Pname nn = v[0].n;
Pclass ocl,ncl;
for (int i=0; on && nn; i++,on=ivec[i].n,nn=v[i].n) {
ocl = Pfct(on->tp)->memof;
ncl = Pfct(nn->tp)->memof;
if (on != nn)
if (!ocl->has_base(ncl))
if (!ncl->has_base(ocl))
break;
else {
ivec[i].n = nn;
ivec[i].offset = v[i].offset;
}
}
if (on || nn)
error("virtualB: ambiguous%n and%n", on, nn);
return;
}
vtab->next = virt_list->next;
virt_list->next = vtab;
}
static int baseoffset(Pclass b, Pclass d)
/*
find offset of base class object "b" in derived class object "d"
*/
{
static int level=0;
++level;
if (!b || !d) {
error ('i', "invalidA to baseoffset()");
}
if (same_class(b,d)) { // b == d
level--;
return 0;
}
Pbcl bx;
// is "b" a direct base of "d" or a promoted indirect virtual base ?
for (bx = d->baselist; bx; bx = bx->next)
{
if (same_class(b, bx->bclass) ) { //(b == bx->bclass)
level--;
return bx->obj_offset;
}
}
// recursively search for "b" in bases of "d"
for (bx = d->baselist; bx; bx = bx->next)
{
// don't search indirect virtual bases
if (bx->promoted)
continue;
int found = baseoffset(b, bx->bclass);
if (found != -1) {
level--;
return bx->obj_offset + found;
}
}
if (level-- > 1)
return -1; // b!=d and b is not a base of d
error('i', "fall off end of baseoffset()");
return 0;
}
int vcounter;
static int vmax;
const int vpChunk = 32;
int classdef::do_virtuals(Pvirt vtab, char* str, int leftmost, bit virt_flag)
/*
make vtbl for b in "this"
match up virtuals and assign virtual indices for the base or delegate "bcl"
first base class shares ``this'' and vtbl with this class
*/
{
if (vmax<vcounter)
vmax = vcounter;
int vpsz = (vmax+vcounter)/vpChunk+1; // fragmentation prevention
vpsz *= vpChunk;
Pname* vp = new Pname[vpsz];
velem* ivec = vtab ? vtab->virt_init : 0;
int vo = Voffset;
int vc = 0;
int changed = 0;
//error('d',"%t->do_virtuals(%d,%s) voffset %d",this,vtab,str,Voffset);
//error('d',"virt_count %d vpsz %d vcounter %d",virt_count,vpsz,vcounter);
if (ivec) { // vtbl replacement for ivec
if (vtab->is_vbase) {
str = 0;
Voffset = get_offset(vtab->string);
// error('d',"vtabl->is_vbase: %s->get_offset(%s), voffset: %d",string,vtab->string,Voffset);
}
else
Voffset = Voffset + vtab->vclass->get_offset(vtab->string);
Pname vn;
for (int i=0; vn=ivec[i].n; i++) {
/*
go through virtual table's list of virtuals:
first see if the function is simply inherited
if not, check for a match
if not, then add as new
*/
if ( i >= vpsz ) { // resize vp vector
int tvpsz = vpsz + vpChunk;
Pname *tvp = new Pname[ tvpsz ];
for ( int j = 0; j < i; ++j )
tvp[ j ] = vp[ j ];
delete [/*vpsz*/] vp;
vp = tvp;
//error( 'd',"resizing: i: %d vpsz: %d tvpsz: %d", i, vpsz, tvpsz );
vpsz = tvpsz;
}
char* s = vn->n_gen_fct_name;
Pname n = memtbl->look(s?s:vn->string, 0);
//error('d',"vn %n %s n %n %d",vn,s,n,Voffset);
//error('d',"n %n %k", n, n?n->base:0 );
if (n == 0 || n->base == PUBLIC ) { // FCT + FCT
// base::FCT
inher: // inherit
if (vn->n_initializer) {
if (!get_vf(vn,this)) {
c_abstract = vn;
}
}
vp[i] = vn;
if ( ivec[i].offset && vtab->is_vbase ) {
//error('d',"voffset[1]: %d vo: %d ivec[%d].offset: %d",Voffset,vo,i,ivec[i].offset);
vp[i]->n_offset = Voffset -
baseoffset(Pfct(vn->tp)->
memof, this);
}
else vp[i]->n_offset = ivec[i].offset;
continue;
}
Pfct f = Pfct(n->tp);
if (f == 0 ) continue;
if (s && f->base==OVERLOAD) { // OVERLOAD + OVERLOAD
// vn is overloaded
// and s is its name
for (Plist gl=Pgen(f)->fct_list; gl; gl=gl->l)
if (gl->f == vn)
goto inher;
}
Pfct vnf = Pfct(vn->tp);
switch (f->base) { // re-define?
default:
error('w',&n->where,"%n hides virtual%n",n,vn);
vp[i] = vn; // not a new overloaded: inherit
if (vn->n_initializer) {
if (!get_vf(vn,this)) {
c_abstract = vn;
}
}
if ( ivec[i].offset && vtab->is_vbase ) {
if (Voffset - vo != ivec[i].offset) {
// error('d',"voffset[2]: %d vo: %d ivec[%d].offset: %d",Voffset,vo,i,ivec[i].offset);
int noffset = get_offset(vtab->string,1);
if (noffset && noffset != Voffset)
noffset -= vo;
if (noffset == 0) {
if (Vvbc_inher)
noffset = link_compat_hack
? link_compat_hack - ivec[i].offset
: ivec[i].offset;
else noffset = Voffset - vo;
}
vp[i]->n_offset = noffset;
}
else vp[i]->n_offset = Voffset - vo;
}
else vp[i]->n_offset = ivec[i].offset;
break;
case FCT: // derived::FCT
{
if (vnf->check(f,VIRTUAL)==0) { // derived::FCT match base::FCT
// VTOK: virtual, but no index assigned
// you can only inherit an index from your first base
if (Vcheckerror)
error("bad virtualT match for %n",vn);
if (f->f_virtual==VTOK)
f->f_virtual = i+1;
vp[i] = n;
vp[i]->n_offset = Voffset;
changed = 1;
}
else {
if (Vcheckerror)
error("bad virtualT match for %n",vn);
else {
// if (! vn->n_initializer) // not a pure virtual ?????
// inherits a pure virtual -- make abstract
if (vn->n_initializer) {
if (!get_vf(vn,this)) {
c_abstract = vn;
}
}
error('w',&n->where,"%n hides virtual%n",n,vn);
}
vp[i] = vn; // not a new overloaded: inherit
if ( ivec[i].offset && vtab->is_vbase ) {
if (Voffset - vo != ivec[i].offset) {
// error('d',"voffset[3]: %d vo: %d ivec[%d].offset: %d",Voffset,vo,i,ivec[i].offset);
int noffset = get_offset(vtab->string,1);
if (noffset && noffset != Voffset)
noffset -= vo;
if (noffset == 0) {
if (Vvbc_inher)
noffset = link_compat_hack
? link_compat_hack - ivec[i].offset
: ivec[i].offset;
else noffset = Voffset - vo;
}
vp[i]->n_offset = noffset;
}
else vp[i]->n_offset = Voffset - vo;
}
else vp[i]->n_offset = ivec[i].offset;
}
break;
}
case OVERLOAD: // derived::OVERLOAD
{
int hit = 0;
for (Plist gl=Pgen(f)->fct_list; gl; gl=gl->l) {
// try each fct from derived class
Pname fn = gl->f;
Pfct f = Pfct(fn->tp);
if (f->check(vnf,VIRTUAL) == 0) { // derived::FCT
if (Vcheckerror)
error("bad virtualT match for %n",vn);
if (f->f_virtual==VTOK)
f->f_virtual = i+1;
vp[i] = fn;
vp[i]->n_offset = Voffset;
changed = 1;
goto found;
}
else {
if (Vcheckerror)
error("bad virtualT match for %n",vn);
}
if (Vcheckerror == 0)
switch (f->f_virtual) {
case 0:
case VTOK:
hit = 1;
}
}
if (hit) {
// inherits a pure virtual -- make it abstract
if (vn->n_initializer) {
if (!get_vf(vn,this)) {
c_abstract = vn;
}
}
error('w',&n->where,"%n hides virtual%n ofT %t",n,vn,vn->tp);
}
vp[i] = vn; // not a new overloaded: inherit
if ( ivec[i].offset && vtab->is_vbase ) {
if (Voffset - vo != ivec[i].offset) {
// error('d',"voffset[4]: %d vo: %d ivec[%d].offset: %d",Voffset,vo,i,ivec[i].offset);
int noffset = get_offset(vtab->string,1);
if (noffset && noffset != Voffset)
noffset -= vo;
if (noffset == 0) {
if (Vvbc_inher)
noffset = link_compat_hack
? link_compat_hack - ivec[i].offset
: ivec[i].offset;
else noffset = Voffset - vo;
}
vp[i]->n_offset = noffset;
}
else vp[i]->n_offset = Voffset - vo;
}
else vp[i]->n_offset = ivec[i].offset;
found:
break;
}
}
}
Voffset = vo;
vc = i;
}
// error( 'd', "do_virtuals: out of loop: vc: %d vpsz: %d changed: %d", vc, vpsz,changed );
if (leftmost) {
/*
add new virtuals:
`VTOK' marks ``new virtual, no index assigned''.
You can only be new once (no base or first base).
*/
int i;
for (Pname nn=memtbl->get_mem(i=1); nn; NEXT_NAME(memtbl,nn,i) ) {
if ( nn->base == TNAME ) continue;
Pfct f = Pfct(nn->tp);
if ( vc >= vpsz ) { // resize vp vector
int tvpsz = vpsz + vpChunk;
Pname *tvp = new Pname[ tvpsz ];
for ( int j = 0; j < vc; ++j )
tvp[ j ] = vp[ j ];
delete [/*vpsz*/] vp;
vp = tvp;
vpsz = tvpsz;
}
// error('d',"f %n %t",nn,f);
if (f)
switch (f->base) {
case FCT:
//error('d',"fv %d",f->f_virtual);
if (f->f_virtual == VTOK) {
// declared virtual, or
// virtual in some base
f->f_virtual = ++vc;
vp[f->f_virtual-1] = nn;
vp[f->f_virtual-1]->n_offset = 0;
f->f_vdef = 1;
changed = 2;
}
break;
case OVERLOAD:
{
for (Plist gl=Pgen(f)->fct_list; gl; gl=gl->l) {
Pname fn = gl->f;
Pfct f = Pfct(fn->tp);
if ( vc >= vpsz ) { // resize vp vector
int tvpsz = vpsz + vpChunk;
Pname *tvp = new Pname[ tvpsz ];
for ( int j = 0; j < vc; ++j ) {
tvp[ j ] = vp[ j ];
}
delete [/*vpsz*/] vp;
vp = tvp;
vpsz = tvpsz;
}
if (f->f_virtual == VTOK) {
f->f_virtual = ++vc;
vp[f->f_virtual-1] = fn;
vp[f->f_virtual-1]->n_offset = 0;
f->f_vdef = 1;
changed = 2;
}
}
break;
}
}
}
// error('d',"%s changed %d has_vvtab %d",string,changed,has_vvtab);
// error('d',"vc %d vpsz %d",vc,vpsz);
virt_count = 0;
if (changed)
virt_count = vc;
else if (has_vvtab) {
virt_merge = 1;
if (vc && vtab->is_vbase)
leftmost = 0;
}
}
// error('d',"vc %d ch %d vp[%d] virt_count %d",vc,changed,vpsz,virt_count);
if (changed || !leftmost) {
// vc==0 if all explicit virtuals in fact were declared in base
velem* v = new velem[vc+1];
for (int i=0; i<vc; i++) {
v[i].n = vp[i];
v[i].offset = vp[i]->n_offset;
}
v[vc].n = 0;
if (leftmost)
add_vtbl(v,0,0,0);
else
add_vtbl(v,vtbl_str(vtab->string,str),virt_flag||vtab->is_vbase,vc+1);
delete vp;
vcounter = 0;
return 1;
}
delete vp;
vcounter = 0;
return 0;
}
int classdef::all_virt(Pclass bcl, char* s, int leftmost, bit virt_flag)
{
//error('d',"%t->all_virt( %t %s leftmost: %d",this,bcl,s,leftmost);
int i = 0;
if (bcl->virt_count) {
for (Pvirt blist = bcl->virt_list; blist; blist = blist->next) {
if (
virt_merge
&&
virt_flag==0
&&
blist->is_vbase==0
)
continue;
i += do_virtuals(blist, s, leftmost, virt_flag);
if (i==0 && leftmost && virt_merge==0)
return 0;
leftmost = 0;
}
}
// finding virt_list stops recursive step
// if vtables found and updated, return number
if (i)
return i;
for (Pbcl b = bcl->baselist; b; b = b->next) {
if (b->promoted)
continue;
// error('d',"all_virt b %t vl %d bl %d",b->bclass,b->bclass->virt_list,b->bclass->baselist);
if (leftmost && b->base == VIRTUAL) {
i += do_virtuals(0, 0, 1, 0);
if (i==0 && virt_merge==0) {
// be careful to propagate class abstraction
if (bcl == this && b->bclass->c_abstract)
c_abstract = b->bclass->c_abstract;
return 0;
}
leftmost = 0;
}
int vo = Voffset;
if (b->base == VIRTUAL)
{
Voffset = baseoffset(b->bclass,this);
}
else
{
Voffset += b->obj_offset;
}
// error('d',"all_virt obj_offset %t voffset %d vo %d %d",b->bclass,Voffset,vo);
if (b->base==VIRTUAL)
i += all_virt(b->bclass, b->bclass->string, leftmost, 1);
else i += all_virt(b->bclass, vtbl_str(b->bclass->string,s), leftmost, virt_flag);
if (i==0 && leftmost && virt_merge==0) {
// be careful to propagate class abstraction
if (bcl==this && !c_abstract && b->next) {
for (Pbcl bb = b; bb; bb = bb->next) {
if (bb->promoted) continue;
if (bb->bclass->c_abstract)
c_abstract = bb->bclass->c_abstract;
}
}
return 0;
}
Voffset = vo;
leftmost = 0;
}
// if recursion updated vtables, return number
if (i)
return i;
// no vtables updated in recursion
// look for new virtuals
if (leftmost)
return do_virtuals(0, 0, 1, 0);
else
return 0;
}
Pexpr copy_obj(Pexpr l, Pexpr r, int sz)
/*
generate:
struct _s { char[sz]; };
*(struct _s*)this->m = *(struct _s*)arg.mem;
*/
{
if ( !sz ) sz = 1;
// error('d',"copy_obj(%d)",sz);
char* s = make_name('S');
fprintf(out_file,"struct %s { char v[%d]; };\n",s,sz);
Pname n = new name(s);
Ptype t = new basetype(COBJ,n);
t = new ptr(PTR,t);
l = new texpr(G_CAST,t,l); //new cast(t,l);
l = l->contents();
r = new texpr(G_CAST,t,r); //new cast(t,r);
r = r->contents();
return new expr(ASSIGN,l,r);
}
Ptype find_arg_type(Pclass cl)
// first determine argument type
{
int i;
int mod = 0;
for (Pbcl b = cl->baselist; b; b = b->next) {
Pclass bcl = b->bclass;
switch (b->base) {
case VIRTUAL:
case NAME: // generate :b(*(b*)&arg)
{
Pname itor = bcl->has_itor();
if (itor && itor->tp->base==FCT) {
Pname a = Pfct(itor->tp)->argtype;
Pptr p = a->tp->is_ref();
if (p && p->typ->tconst()==0) {
mod = 1;
goto ll1;
}
}
}
}
}
ll1:
if (mod == 0) {
for (Pname m=cl->memtbl->get_mem(i=1); m; NEXT_NAME(cl->memtbl,m,i) ) {
if ( m->base == TNAME ) continue;
if (m->n_evaluated || m->n_stclass==STATIC) // ignore static members
continue;
Pname cln = ( m->base==PUBLIC ? m->n_qualifier : m )->tp->is_cl_obj();
if ( cln ) {
Pname itor = Pclass(cln->tp)->has_itor();
if (itor && itor->tp->base==FCT) {
Pname a = Pfct(itor->tp)->argtype;
Pptr p = a->tp->is_ref();
if (p && p->typ->tconst()==0) {
mod = 1;
goto ll2;
}
}
}
}
}
ll2:
//error('d',"mod %d",mod);
Pbase bp = new basetype(INT,0);
*bp = *Pbase(Pptr(cl->this_type)->typ);
if (mod == 0) bp->b_const = 1;
return new ptr(RPTR,bp);
}
Pname classdef::make_itor(int def)
/*
make cn::cn(const cn&) :bases_and_members_of_cn {}
*/
{
// error('d',"%t->make_itor(%d) %d",this,def,obj_size);
Pstmt s;
Pname e;
int i;
Pname arg = new name(make_name('A'));
arg->tp = find_arg_type(this);
c_xref |= C_XREF; // now it has X(X&)
if (def) { // define itor
int slow = 0; // slow==0 => copy using vector copy
int first = 1;
Pexpr es = 0;
s = new estmt(SM,no_where,0,0);
e = 0;
if (warning_opt && 128<obj_size)
error('w',"copying a %d byte object (ofC %s)",obj_size,string);
if (baselist)
slow = 1;
// initialize bases:
if (slow) {
for (Pbcl b = baselist; b; b = b->next) {
Pclass bcl = b->bclass;
Ptype pt = bcl->this_type;
if (b->base==VIRTUAL || b->base==NAME) { // generate :b(*(b*)&arg)
Pexpr b2 = new name(arg->string);
b2 = b2->address();
b2 = new texpr(G_CAST,pt,b2);//new cast(pt,b2);
b2->i2 = 1;
b2 = b2->contents();
Pname ee = new name(bcl->string);
ee->base = TNAME;
ee->n_initializer = b2;
if (e)
ee->n_list = e;
e = ee;
}
}
}
for (Pname mm=memtbl->get_mem(i=1); mm; NEXT_NAME(memtbl,mm,i)) {
Ptype t = mm->tp;
if (t && (t=t->skiptypedefs())->base==COBJ) {
Pclass mcl = Pclass(Pbase(t)->b_name->tp);
if (mcl->c_xref&(C_VBASE|C_XREF)) slow=1;
}
}
for (Pname m=memtbl->get_mem(i=1); m; NEXT_NAME(memtbl,m,i)) { // initialize members
if ( m->base == TNAME ) continue;
if (m->n_evaluated || m->n_stclass==STATIC) // ignore static members
continue;
if (strcmp(m->string,"__vptr")==0) {
if (slow==0 && first==0 && m->n_offset) {
Pexpr th = new expr(THIS,0,0);
Pexpr a = new name(arg->string);
a = a->address();
Pexpr ee = copy_obj(th,a,m->n_offset);
es = es ? new expr(CM,es,ee) : ee;
}
slow = 1;
first = 0;
continue;
}
Ptype mt = m->tp;
if ( mt )
tx: switch (mt->base) {
case TYPE:
mt = Pbase(mt)->b_name->tp;
goto tx;
case VEC:
{
Pname cn = Pvec(mt)->typ->is_cl_obj();
if (cn && Pclass(cn->tp)->c_xref&(C_XREF|C_VBASE)) {
error('s',"copy of %n[], no memberwise copy for%n",cn,cn);
slow = 1; // make sure an assignment operator
// is generated so that there will
// be no more error messages
}
if (slow && mt->tsizeof()) {
/*
generate:
struct _s { char[sizeof(m)]; };
*(struct _s*)this->m = *(struct _s*)arg.mem;
*/
Pexpr l = new name(m->string);
Pexpr r = new name(m->string);
r = new ref(DOT,new name(arg->string),r);
Pexpr ee = copy_obj(l,r,mt->tsizeof());
es = es ? new expr(CM,es,ee) : ee;
break;
}
}
case FCT:
case OVERLOAD:
case CLASS:
case ENUM:
break;
case COBJ:
{
Pclass mcl = Pclass(Pbase(mt)->b_name->tp);
if (
slow==0 // if slow, previous members have already been copied
&&
mcl->c_xref&(C_VBASE|C_XREF)
) {
slow = 1;
if (first==0 && m->n_offset) {
//AAA copy up to here
Pexpr th = new expr(THIS,0,0);
Pexpr a = new name(arg->string);
a = a->address();
Pexpr ee = copy_obj(th,a,m->n_offset);
es = es ? new expr(CM,es,ee) : ee;
}
}
// no break
}
default:
if (slow) {
// error('d',"slow %s %s",m->string,arg->string);
Pname ee = new name(m->string);
ee->n_initializer = new ref(DOT,new name(arg->string),new name(m->string));
if (e)
ee->n_list = e;
e = ee;
}
}
first = 0;
}
if (slow == 0) {
/* really simple just copy:
the only problem was a vptr which can be
ignored since X(X&) is going to reset it anyway
don't use assignment of this struct to avoid operator=
*/
Pexpr th = new expr(THIS,0,0);
Pexpr a = new name(arg->string);
a = a->address();
Pexpr ee = copy_obj(th,a,obj_size);
es = es ? new expr(CM,es,ee) : ee;
}
s->e = es;
Pname cn = this->k_tbl->find_cn(string);//SYM
if (cn)
cn = Pbase(cn->tp)->b_name;
cc->stack();
cc->not = cn;
cc->cot = this;
}
Pname fn = new name(string);
Pfct f = new fct(defa_type,arg,1);
fn->tp = f;
fn->n_oper = TNAME;
Pfct(f)->f_inline = def?1:ITOR; // ITOR means ``define itor() if used''
Pfct(f)->f_is_inline = 1;
if (def) {
f->body = new block(curloc,0,s);
f->f_init = e;
}
Pname nn = fn->dcl(memtbl,PUBLIC);
delete fn;
if (def) {
cc->unstack();
nn->simpl();
if (debug_opt)
nn->dcl_print(0);
}
return nn;
}
Ptype is_op_ass(Pfct f, Pclass tcl)
/* is the operator an assignment operator? */
{
Ptype t = f->argtype->tp;
Pname an = t->is_cl_obj(); // X::operator=(X)
if (an==0 && (t=t->is_ref())) { // X::operator=(X&)
t = Pptr(t)->typ;
Ptype nt = t;
while (nt->base == TYPE)
nt = Pbase(nt)->b_name->tp;
if (nt->base == COBJ)
an = Pbase(nt)->b_name;
}
if (an && same_class(Pclass(an->tp),tcl)) return t;
return 0;
}
int make_assignment(Pname cn)
/*
write the function:
X& X::operator=(const X&) { assign all bases and members }
return 1 is a function is really synthesized
*/
{
Pclass cl = Pclass(cn->tp);
Pstmt s = new estmt(SM,no_where,0,0);
Pexpr e = 0;
Pname arg = new name(make_name('A'));
arg->tp = find_arg_type(cl);
//error('d',"make_assignment %t %d",cl,cl->obj_size);
if (warning_opt && 128<cl->obj_size)
error('w',"copying a %d byte object (ofC %s)", cl->obj_size,cl->string);
int slow = 0; // slow==0 => copy using vector copy
int first = 1; // first==1 => first member of (derived) class
bit unconst=0;
if (cl->baselist)
slow = 1; // be dumb and safe
if (slow) {
for (Pbcl b = cl->baselist; b; b = b->next) {
Pclass bcl = b->bclass;
Ptype pt = bcl->this_type;
switch (b->base) {
case NAME:
{ // generate: *(bcl*)this = *(bcl*)&arg;
//error('d',"base %t",bcl);
Pexpr b1 = new expr(THIS,0,0);
b1 = new texpr(G_CAST,pt,b1);
b1 = b1->contents();
Pexpr b2 = new name(arg->string);
b2 = b2->address();
b2 = new texpr(G_CAST,pt,b2);
b2->i2 = 1;
b2 = b2->contents();
Pexpr ee = new expr(ASSIGN,b1,b2);
e = e ? new expr(CM,e,ee) : ee;
break;
}
case VIRTUAL:
if (warning_opt)
error('w',"copying an object ofC%n with a virtualBC",cn);
if (b->ptr_offset) {
// copy object, but not pointer
// generate: *(bcl*)this->Pw = *(bcl*)arg->Pw;
// I don't know how to avoid copying the object
// once for each pointer
Pexpr b1 = new expr(THIS,0,0);
b1 = new mdot(bcl->string,b1);
b1->i1 = 3;
b1->tp = pt;
b1 = new expr(DEREF,b1,0);//b1->contents();
Pexpr b2 = new name(arg->string);
b2 = b2->address();
b2 = new mdot(bcl->string,b2);
b2->i1 = 3;
b2->tp = pt;
b2 = new expr(DEREF,b2,0);//b2->contents();
Pexpr ee = new expr(ASSIGN,b1,b2);
e = e ? new expr(CM,e,ee) : ee;
}
break;
}
}
}
int i;
for (Pname m=cl->memtbl->get_mem(i=1); m; NEXT_NAME(cl->memtbl,m,i) ) {
if ( m->base == TNAME ) continue;
// ignore static members
if (m->n_evaluated || m->n_stclass==STATIC)
continue;
if (strcmp(m->string,"__vptr")==0) { // don't copy vptrs
// we may be copying
// into a base class object
if (first==0 && m->n_offset && !e) {
// copy up to (but not including) vptr
// don't copy if first member
Pexpr th = new expr(THIS,0,0);
Pexpr a = new name(arg->string);
a = a->address();
e = copy_obj(th,a,m->n_offset);
}
slow = 1;
first = 0;
continue;
}
Ptype mt = m->tp;
if (mt)
tx: switch (mt->base) {
case TYPE:
mt = Pbase(mt)->b_name->tp;
goto tx;
case VEC:
{
Pname cn = Pvec(mt)->typ->is_cl_obj();
if (cn && Pclass(cn->tp)->c_xref&(C_ASS|C_VBASE)) {
error('s',"copy of %n[], no memberwise copy for%n",cn,cn);
slow = 1; // make sure an assignment operator
// is generated so that there will
// be no more error messages
}
if (slow && mt->tsizeof()) {
/*
protect against sizeof(mt)==0: char[]
generate:
struct _s { char[sizeof(m)]; };
*(struct _s*)this->m = *(struct _s*)arg.mem;
*/
Pexpr l = new name(m->string);
Pexpr r = new name(m->string);
r = new ref(DOT,new name(arg->string),r);
Pexpr ee = copy_obj(l,r,mt->tsizeof());
e = e ? new expr(CM,ee,e) : ee;
break;
}
}
case FCT:
case OVERLOAD:
case CLASS:
case ENUM:
break;
case COBJ:
//error('d',"cobj %n %d %d",m,slow,Pclass(Pbase(mt)->b_name->tp)->c_xref);
{
Pclass tempcl=Pclass(Pbase(mt)->b_name->tp);
if (
slow==0
&&
Pclass(Pbase(mt)->b_name->tp)->c_xref&(C_VBASE|C_ASS)
) { // must use its assignment operation
if (first==0 && m->n_offset) { // copy up to this member
Pexpr th = new expr(THIS,0,0);
Pexpr a = new name(arg->string);
a = a->address();
e = copy_obj(th,a,m->n_offset);
}
slow = 1;
}
suppress_error++;
Pname nn = tempcl->has_oper(ASSIGN);
suppress_error--;
if( nn && nn->tp->base == FCT ) {
Pptr atp=Pptr(nn->fct_type()->argtype->tp);
if( atp && atp->typ && atp->typ->b_const==0) {
unconst = 1;
}
}
else if (nn && nn->tp->base == OVERLOAD) {
Plist pl = Pgen(nn->tp)->fct_list;
while (pl) {
Pfct ff = pl->f->fct_type();
Ptype t = is_op_ass(ff,tempcl);
if(t && t->b_const==0) {
unconst = 1;
break;
}
pl = pl->l;
}
}
}
// no break: copy cobj itself
case RPTR:
if (mt->base==RPTR)
if (cl->c_xref!=C_REFM) {
error("cannot assignC%t:RM%n",cl,m);
break;
}
else slow=1;
default:
//error('d',"defa %n %d",m,slow);
if (slow) {
if (m->tp->tconst())
error("cannot assignC%t: const M%n",cl,m);
Pname ms = new name(m->string);
Pname as = new name(arg->string);
Pexpr ee = new ref(DOT,as,new name(m->string));
ee = new expr(ASSIGN,ms,ee);
e = e ? new expr(CM,e,ee) : ee;
}
}
first = 0;
}
if (slow == 0) { // really simple just copy:
return 0;
}
Pexpr rv = new expr(THIS,0,0);
rv = new expr(DEREF,rv,0); //b1->contents();
s->e = e ? new expr(CM,e,rv) : e;
s->s_list = new estmt(RETURN,no_where,rv,0);
cc->stack();
cc->not = cn;
cc->cot = cl;
cl->c_xref |= C_ASS; // now it has X::operator=(const X&)
Pname fn = new name(oper_name(ASSIGN));
Pfct f = new fct(new ptr(RPTR,Pptr(cl->this_type)->typ),arg,1);
f->f_inline = 1;
f->f_is_inline = 1;
if (unconst)
Pptr(f->argtype->tp)->typ->b_const=0;
fn->tp = f;
fn->n_oper = ASSIGN;
fn->n_sto = STATIC;
Pname nn = fn->dcl(cl->memtbl,PUBLIC);
delete fn;
Pfct(nn->tp)->body = new block(curloc,0,s);
Pfct(nn->tp)->dcl(nn);
cc->unstack();
nn->simpl();
//error('d',"make_assign->");
return 1;
}
void prnt_all_in_scope(Pclass cl) {
//
// Lays out all members (visible from an inner _nested_ class)
// traversing the in_class chain (up to the outer most class).
//
int i;
if (cl->in_class)
prnt_all_in_scope(cl->in_class);
for (Pname nn=cl->memtbl->get_mem(i=1); nn; NEXT_NAME(cl->memtbl,nn,i))
{
if ( nn->base == TNAME ) continue;
if (
((nn->base) && nn->base==NAME)
&&
(nn->n_anon==0)
&&
(nn->n_stclass == STATIC)
&&
((nn->tp) &&
(
nn->tp->base!=FCT
&&
nn->tp->base!=OVERLOAD
&&
nn->tp->base!=CLASS
&&
nn->tp->base!=ENUM
)
)
) {
nn->dcl_print(0);
}
}
}
bit simpl_friend;
void classdef::dcl(Pname cname, Ptable tbl)
{
int bvirt = 0;
int dvirt = 0;
int scope = PUBLIC;
int protect = 0;
int st = 1; // nothing private or protected seen: a struct
int byte_old = byte_offset;
int bit_old = bit_offset;
int max_old = max_align;
int boff = 0;
int in_union = 0;
int usz;
int make_ctor = 0;
int make_dtor = 0;
if (this == 0) // this is the place for paranoia
error('i',"0->Cdef::dcl(%p)",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);
DB( if(Ddebug>=1) error('d',&cname->where,"classdef::dcl %s tbl %d gtbl %d",string,tbl,gtbl); );
// error('d',&cname->where,"classdef::dcl %s tbl %d gtbl %d",string,tbl,gtbl);
switch (csu) {
case UNION:
in_union = UNION;
break;
case ANON:
in_union = ANON;
break;
case CLASS:
scope = 0;
}
max_align = AL_STRUCT;
if ( local_sig ) {
c_context = tbl;
in_fct = cc->nof;
} else in_fct = 0;
if (baselist) {
/*
check base classes.
duplicates were removed in start_cl() in norm.c.
remove bad classes.
add virtual bases from bases to the list.
check against
class b : a {}
class c : a, b {} // first a inaccessible
*/
Pbcl ll = 0;
Pbcl lll = 0;
Pbcl vlist = 0;
for (Pbcl lx, l=baselist; l; l=lx) { // remove bad bases
Pclass cl = l->bclass;
lx = l->next;
//error('d',"base1 %t %k init %d",cl,l->ppp,l->init);
if (l->ppp == 0) { // ``class'' => private base ``struct'' => public base
l->ppp = csu==CLASS ? PRIVATE : PUBLIC;
#ifndef OLD
if (l->ppp == PRIVATE)
error('w',"B%t private by default: please be explicit ``: private%t",cl,cl);
#endif
}
// if you have a ``class'' as base you cannot remain a ``mere struct''
if (cl && cl->csu == CLASS)
st = 0;
if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) {
error("BC %tU",cl);
continue;
}
else
(void)cl->tsizeof(); // ensure printout
if (cl->csu==UNION || cl->csu==ANON) {
error("C derived from union");
continue;
}
if (in_union) {
error("derived union");
continue;
}
if (warning_opt &&
(l->base==VIRTUAL || l != baselist) &&
cl->has_dtor() && cl->has_dtor()->tp &&
!Pfct(cl->has_dtor()->tp)->f_virtual)
error('w', "second or virtualBC%tWout virtual destructor", cl);
if (l->base==VIRTUAL) { // order of virtual classes doesn't matter
l->next = vlist;
vlist = l;
}
else { // keep ordinary base classes in order
if (ll == 0) {
lll = l;
l->next = 0;
}
else
ll->next = l;
ll = l;
}
}
if (ll) {
ll->next = vlist; // put virtual bases at end
baselist = lll;
}
else
baselist = vlist;
lll = 0;
for (l=baselist; l; l=l->next) { // detect unmanageable duplicates
Pclass b = l->bclass;
for (ll=baselist; ll; ll=ll->next)
if (!::same_class(b,ll->bclass) && ll->bclass->check_dup(b,l->base)) {
if (lll)
lll->next = l->next;
else
baselist = l->next;
goto mmm;
}
lll = l;
mmm:;
}
for (l=baselist; l; l=l->next) { // promote virtual bases
Pclass b = l->bclass;
for (ll=b->baselist; ll; ll=ll->next) {
if (ll->base == VIRTUAL) {
Pclass v = ll->bclass;
for (Pbcl lll=baselist; lll; lll=lll->next)
if (::same_class(lll->bclass,v)) {
// promoted virtual base class
// takes on most accessible level
if (ll->ppp < lll->ppp)
lll->ppp = ll->ppp;
goto nnn;
}
baselist = new basecl(v,baselist);
baselist->base = VIRTUAL;
baselist->promoted = 1;
// needs a more complete check of visibility rules
//error('d',"promote %t %k",v,ll->ppp);
baselist->ppp = ll->ppp;
}
nnn:;
}
}
ll = 0;
lll = 0;
l=baselist;
baselist = 0;
vlist = 0;
for (; l; l=lx) {
// sort virtual bases so that no virtual base
// is ahead of its own virtual base
lx = l->next;
if (l->base == VIRTUAL) { // add to sorted vlist
// each class before its bases
if (vlist == 0) {
vlist = l;
l->next = 0;
}
else {
Pclass lb = l->bclass;
Pbcl v_prev = 0;
for (Pbcl vx, v = vlist; v; v=vx) {
Pclass vb = v->bclass;
vx = v->next;
if (lb->has_base(vb)) { // put l ahead of v
l->next = v;
if (v_prev)
v_prev->next = l;
else
vlist = l;
break;
}
if (vx == 0) { // stick l at end
v->next = l;
l->next = 0;
break;
}
v_prev = v;
}
}
}
else { // keep in order
if (ll == 0) {
lll = l;
l->next = 0;
}
else
ll->next = l;
ll = l;
}
}
if (ll) {
ll->next = vlist; // put virtual bases at end
baselist = lll;
}
else
baselist = vlist;
for (l=baselist; l; l=l->next) { // allocate base class objects
Pclass cl = l->bclass;
// error('d',"classdef::dcl base %t %k %k",cl,l->ppp,l->base);
if (l->base == VIRTUAL) { // : virtual bclass
// pointer and object for virtual base MAY
// be allocated at the end - but not here
c_xref |= C_VBASE;
dvirt += cl->virt_count;
}
else { // : bclass =>allocate
int ba = cl->align();
if (max_align<ba)
max_align = ba;
if (::same_class(cl,baselist->bclass)) { // pad to ensure alignment:
boff = cl->real_size;
// not obj_size-real_size, we can
// optimize vbase object away
int xtra = boff%ba;
// align
if (xtra)
boff += ba-xtra;
}
else { // let C handle the padding:
int xtra = boff%ba;
if (xtra)
boff += ba-xtra; // align
l->obj_offset = boff;
// don't use waste
boff += cl->obj_size;
}
bvirt += cl->virt_count;
}
if (cl->has_vvtab)
has_vvtab = 1;
c_xref |= cl->c_xref;
//error('d',"%t: base %t conv %d base conv %d",this,cl,conv,cl->conv);
conv = merge_conv(conv,cl->conv);
}
}
memtbl->set_name(cname);
int nmem = 0;
int fct_mem = 0;
{
for (Pname m = mem_list; m; m=m->n_list) {
nmem++;
if (m->tp && m->tp->base==FCT)
fct_mem++;
else if (m->base == TNAME)
;
else {
if (m->tp && m->tp->base==RPTR && c_xref==0)
c_xref=C_REFM;
if (ansi_opt && m->tp && m->tp->tconst() && m->n_sto!=STATIC)
Pbase(m->tp)->ansi_const=1;
}
}
}
if (nmem)
memtbl->grow((nmem<=2)?3:nmem);
cc->stack();
cc->not = cname;
cc->cot = this;
byte_offset = usz = boff;
bit_offset = 0;
int real_virts = 0;
Pbase bt = new basetype(COBJ,cname);
bt->b_table = memtbl;
Ptype cct = bt->addrof();
// for strict opt type of `this': X *const
// '2' distinguishes this case from a real constant object
if (strict_opt && perf_opt)
Pptr(cct)->b_const = 2;
this_type = cc->tot = cct;
this_type->ansi_const = 1;
PERM(cct);
PERM(bt);
for (Pname px, p=mem_list; p; p=px) {
/*
look at each member;
declare it and determine its visibility
calculate offsets and sizes
*/
px = p->n_list;
// error( 'd', "p: %n %k n_scope: %d", p, p->base, p->n_scope );
switch (p->base) {
case PUBLIC:
scope = PUBLIC;
protect = 0;
goto prpr;
case PRIVATE:
scope = 0;
protect = 0;
goto prpr;
case PROTECTED:
scope = 0;
protect = PROTECTED;
prpr:
if (in_union == ANON)
error(&p->where,"%k in anonymous unionD",p->base);
continue;
case PR: // visibility control: C::M
{
char* qs = p->n_qualifier->string;
char* ms = p->string;
TOK ppp = scope?PUBLIC:(protect?PROTECTED:PRIVATE);
p->base = NAME;
p->n_scope = scope;
p->n_protect = protect;
if (strcmp(ms,qs) == 0)
ms = "__ct";
ppbase = PUBLIC;
if (is_base(qs) == 0) {
error("%kQr %s not aBC of %t",ppp,qs,this);
continue;
}
mex = 1; // print error messages for access violations
tcl = mec = this;
Pname os = Cdcl;
Cdcl = p; // for line #s in error messages
Pexpr ee = find_name(ms,0,1);
Cdcl = os;
// error('d', "ee: %k ", ee->base );
if ( ee && ee->base != NAME && ee->base != TNAME )
error('i',"bad returnE%k from %t->find_name(%s,0,1)",ee->base,this,ms);
Pname mx = Pname(ee);
// error('d', "ee: %k mx: %n", ee->base, mx );
if (mx == 0) {
error("C %s does not have aM %s",qs,ms);
continue;
}
if (mx->tp->base == OVERLOAD) {
error('s',"%k specification of overloaded%n",ppp,mx);
continue;
}
TOK pp = mx->n_scope?PUBLIC:mx->n_protect?PROTECTED:PRIVATE;
// error('d',"mx %n pp %k ppp %k",mx,pp,ppp);
if (ppp != pp) {
error(&p->where,"%kM%n specified%k",pp,mx,ppp);
continue;
}
p->n_qualifier = mx;
Pname m = memtbl->insert(p,0);
m->base = PUBLIC;
if (Nold)
error("twoDs ofCM%n",p);
continue;
}
}
// error('d',"mem%n tp %d %k scope %d",p,p->tp->base,p->tp->base,scope);
/* XXXXX:
if (class_base == INSTANTIATED && templ_base == CL_TEMPLATE) {
if ( p->base == TNAME || p->tp->base == CLASS
|| p->tp->base == ENUM )
error('s',"nestedT%nWin specializedYC%t",p,this);
}
*/
if (scope==0) {
if (p->n_sto != STATIC)
st = 0;
}
else if ( p->tp->base == TYPE ) {
Pname nn = p->tp->is_cl_obj();
if (nn) {
// error( 'd', "nn: %n %k tp %t %k", nn, nn->base, nn->tp, nn->tp->base );
if (
Pclass(nn->tp)->csu == CLASS
&&
strcmp(this->string,nn->string)
)
st = 0;
}
}
//error('d',&p->where,"p%n base%k tp%k: ll %d",p,p->base,p->tp->base,p->lex_level);
//if(px)error('d',&p->where,"px%n base%k tp%k:%t",px,px->base,px->tp->base,px->tp);
//if ( p->tp->base == CLASS && Pclass(p->tp)->csu == ANON ) {
// if ( px == 0
// || px->tp->base != COBJ
// || px->tp->classtype() != p->tp )
// error('i',&p->where,"missing anon object");
//}
if ( in_union == ANON ) {
if ( p->tp->base == CLASS && Pclass(p->tp)->csu == ANON ) {
// anon inside an anon; lift members to enclosing class
Pname pu = Pclass(p->tp)->mem_list;
while ( pu ) {
//error('d',&p->where,"pu%n base%k tp%k: ll %d",pu,pu->base,pu->tp->base,pu->lex_level);
Ptype tx = 0;
if ( pu->base == TNAME ) tx = pu->tpdef;
else if ( pu->tp->base == CLASS
|| pu->tp->base == ENUM )
tx = pu->tp;
else --pu->lex_level;
if ( tx ) {
tx->in_class = this;
delete tx->nested_sig;
tx->nested_sig = make_nested_name(pu->string,this);
}
if ( !pu->n_list ) break;
pu = pu->n_list;
}
if ( pu ) {
pu->n_list = px->n_list;
px = Pclass(p->tp)->mem_list;
}
Pclass(p->tp)->mem_list = 0;
continue;
} // p is anon class
if ( p->base != TNAME
&& p->tp->base != CLASS
&& p->tp->base != ENUM )
--p->lex_level;
} // if this is anon
//error('d',&p->where," -- p%n base%k tp%k: ll %d",p,p->base,p->tp->base,p->lex_level);
if (p->base == TNAME) {
p->dcl(memtbl,scope);
// typedefs need to be generated outside class
if ( p->tp && Pbase(p->tp)->base != COBJ ) {
if (p->n_dcl_printed == 2)
; // don't print
else p->dcl_print(0);
}
continue;
} // if TNAME
if (p->tp->base == FCT) {
int ff = 0;
Pfct f = Pfct(p->tp);
Pblock b = f->body;
f->body = 0;
if (b) {
f->f_inline = 1;
f->f_is_inline = 1;
}
else if (lex_level)
error('w',&p->where,"non-inlineMF%n in localC %t",p,this);
else if (csu != ANON && string && string[0] == '_' && string[1] == '_' && string[2] == 'C')
error("non-inlineMF%n in unnamedC", p);
switch (p->n_sto) {
case FRIEND:
ff = 1;
break;
case STATIC: // accept static member functions
//error('d',"inline %d",f->f_inline);
if (lex_level)
error('w',&p->where,"staticMF%n in localC %t",p,this);
f->f_static = 1;
p->n_sto = 0;
break;
case AUTO:
case REGISTER:
case EXTERN:
error(&p->where,"M%n cannot be%k",p,p->n_sto);
p->n_sto = 0;
}
if (f->f_virtual) real_virts++;
if (ff && f->fct_base==FCT_TEMPLATE) continue; // already handled
Pname m = p->dcl(memtbl,scope);
if (m == 0 || m->tp->base != FCT)
continue;
if (m->n_initializer) {
c_abstract = m;
if (m->n_oper == DTOR)
error('w',"please provide an out-of-line definition: %n {}; which is needed by derived classes",m);
}
if (ff == 0)
m->n_protect = protect;
if (b) {
if (m->tp->defined&DEFINED || Pfct(m->tp)->body )
error(&p->where,"two definitions of%n",m);
else {
Pfct(m->tp)->body = b;
Pfct(m->tp)->def_context = f->def_context;
}
}
if (ff==0 && p->tp!=m->tp)
error(&p->where,"%n cannot be redeclared inCD",p);
}
else {
Eppp = scope?scope:protect?protect:0;
if (p->n_initializer) {
error(&p->where,"Ir forM%n",p);
p->n_initializer = 0;
}
if (p->tp->base==OVERLOAD) {
for (Plist gl=Pgen(p->tp)->fct_list; gl; gl=gl->l) {
Pname nn = gl->f;
Pfct ff = Pfct(nn->tp);
if ( ff->f_virtual ) real_virts++;
}
}
// error('d',"lex_level %d p %n lex %d nested_scope: %k",lex_level,p,p->lex_level, nested_scope);
TOK is_friend = p->n_sto;
if (
protect
&&
p->tp->base == COBJ
&&
Pclass(Pbase(p->tp)->b_name->tp)->csu == ANON
)
p->n_protect = protect;
Pname m = p->dcl(memtbl,scope);
Eppp = 0;
if (m == 0)
continue;
m->n_protect = protect;
if (m->n_stclass==STATIC) {
if (in_union && is_friend != FRIEND)
error(&m->where,"staticM%n in union",m);
if ( is_friend != FRIEND ) {
if (lex_level)
error(&m->where,"staticM%n in localC %t",m,this);
}
m->n_sto = EXTERN;
if (tbl == gtbl)
stat_mem_list = new name_list(m,stat_mem_list);
if (m->n_initializer)
error('s',"staticM%nWIr",m);
}
if (in_union) {
if (usz < byte_offset)
usz = byte_offset;
byte_offset = 0;
if(in_union==ANON)
m->n_offset+=byte_old;
}
}
}
if (st && csu==CLASS)
csu = STRUCT; // nothing private => STRUCT
if (st==0 && csu==STRUCT)
csu = CLASS; // all is not public => CLASS
if (in_union)
byte_offset = usz;
// now look look at the members
Pname ct = has_ctor();
Pname dt = has_dtor();
int i;
int omex = mex; mex = 0;
Pname on = has_oper(NEW);
Pname od = has_oper(DELETE);
mex = omex;
if (dt && ct==0 && Pfct(dt->tp)->f_virtual == 0 )
error('w',"%t has%n but noK",this,dt);
if (on && od==0)
error('w',"%t has%n but no operator delete()",this,on);
if (od && on==0)
error('w',"%t has%n but no operator new()",this,od);
if (dt==0 && od && od && od->n_table==memtbl)
make_dtor = 1;
for (Pname m=memtbl->get_mem(i=1); m; NEXT_NAME(memtbl,m,i) ) {
if ( m->base == TNAME ) continue;
/*
The members have been declared.
now look at each to see if it needs defining
*/
Ptype t = m->tp;
if (t == 0)
continue; // public declarations
// error('d', "m %n %d", m, m->n_scope );
switch (t->base) {
default:
if (
ct==0
&&
m->n_stclass!=ENUM
&&
m->n_stclass!=STATIC
) {
if (t->is_ref())
error("R%n inC%tWoutK",m,this);
if (
t->tconst()
&&
vec_const==0
&&
m->n_evaluated==0
)
error("const%n inC%tWoutK",m,this);
}
// no break
case VEC:
break;
case FCT:
case OVERLOAD:
case CLASS:
case ENUM:
continue;
}
Pname cn = t->is_cl_obj();
if (cn == 0)
cn = cl_obj_vec;
if (cn == 0)
continue;
Pclass cl = Pclass(cn->tp);
c_xref |= cl->c_xref;
//error('d',"m %n %t %d",m,cl,cl->c_xref);
if (cl->has_ctor()) {
if (m->n_stclass == STATIC)
;
else if (in_union) {
if (strncmp("__C",string,3) == 0)
error("M %s ofC%tWK in union",m->string,cl); // tagless union
else
error("M%n ofC%tWK in union",m,cl);
}
else if (ct == 0) {
// does mctor have a default constructor?
if (make_ctor==0 && cl->has_ictor()==0)
error("%t needs aK; it has aMWK requiringAs",this);
make_ctor = 1;
}
}
if (in_union && (c_xref & C_ASS))
error("M%n ofC%tW assignment operator in union",m,cl);
if (cl->has_dtor()) {
if (m->n_stclass==STATIC)
;
else if (in_union) {
if (strncmp("__C",string,3) == 0) // tagless union
error("M %s ofC%tW destructor in union",m->string,cl);
else
error("M%n ofC%tW destructor in union",m,cl);
}
else if (dt==0)
make_dtor = 1;
}
}
if (has_dtor()==0 && make_dtor==0) {
// can dtor be inherited (from single base class)?
Pclass bcl = 0;
for (Pbcl b = baselist; b; b = b->next) {
switch (b->base) {
case NAME:
if (bcl == 0) {
Pname d = b->bclass->has_dtor();
if (d==0)
break;
/*
this breaks CC884232
if (strict_opt == 0) {
if (
d->n_scope==PUBLIC
&&
Pfct(d->tp)->f_virtual==0
) {
bcl = b->bclass;
break;
}
}
*/
}
// two dtors or non-public dtors force creation
make_dtor = 1;
goto zbzb;
case VIRTUAL:
if (b->bclass->has_dtor())
make_dtor = 1;
goto zbzb;
}
}
if (bcl)
c_dtor = bcl->has_dtor();
zbzb:;
}
if (make_dtor && dt==0) { // make x::~x() {}
// must be done before vtbls are made in case dtor is virtual
//error('d',"%t: make_dtor",this);
Pname n = new name(string);
Pfct f = new fct(defa_type,0,1);
f->f_inline = 1;
f->f_is_inline = 1;
n->tp = f;
n->n_oper = DTOR;
dt = n->dcl(memtbl,PUBLIC);
delete n;
Pfct(dt->tp)->body = new block(curloc,0,0);
dt = has_dtor();
}
if (virt_count && find_vptr(this)==0) {
// we only need a vptr if this class has virtual
// functions and none of its first bases have vptrs
//error('d',"%s virt_count %d",string,virt_count);
Pname vp = new name("__vptr");
vp->tp = Pvptr_type;
(void) vp->dcl(memtbl,0);
delete vp;
c_xref |= C_VPTR;
}
else {
//error("byte_offset %d bit_offset %d bitsinbyte %d",byte_offset,bit_offset,BI_IN_BYTE);
//error(" div %d mod %d",bit_offset/BI_IN_BYTE,bit_offset%BI_IN_BYTE);
// no more bit fields. absorb bit_offset
if (bit_offset) {
byte_offset += (bit_offset/BI_IN_BYTE + (bit_offset%BI_IN_BYTE?1:0));
bit_offset = 0;
}
}
//error("byte_offset %d bit_offset %d",byte_offset,bit_offset);
for (Pbcl b = baselist; b; b = b->next) { // allocate virtual base pointers
if (b->base != VIRTUAL)
continue;
Pclass bcl = b->bclass;
// search non-virtual bases for this virtual base
for (Pbcl bb = baselist; bb; bb = bb->next)
if (bb->base == NAME) {
for (Pbcl l = bb->bclass->baselist; l; l=l->next)
if (l->base==VIRTUAL && ::same_class(l->bclass,bcl))
goto eee;
}
{
// error('d',"classdef::dcl vbc* allocation: bcl: %t bb: %t",bcl,bb?bb->bclass:0);
if (int(obj_align)<AL_WPTR)
obj_align = AL_WPTR;
if (max_align<AL_WPTR)
max_align = AL_WPTR;
int waste = byte_offset%AL_WPTR;
if (waste)
byte_offset += AL_WPTR-waste; // align
b->ptr_offset = byte_offset+1; // ensure != 0
byte_offset += SZ_WPTR;
}
eee:;
}
real_size = byte_offset; // the rest may be optimized away
for (b = baselist; b; b = b->next) { // allocate virtual class objects
if (b->base != VIRTUAL)
continue;
Pclass bcl = b->bclass;
// if necessary
link_compat_hack = 0;
if (b->obj_offset = has_allocated_base(bcl))
continue;
// error('d',"%t->dcl: allocating vbc %t link_compat_hack: %d",this,bcl,link_compat_hack);
int ba = bcl->align();
if (int(obj_align)<ba)
obj_align = ba;
if (max_align<ba)
max_align = ba;
int waste = byte_offset%ba;
if (waste)
byte_offset += ba-waste; // align
b->obj_offset = byte_offset; // offset in this
b->allocated = 1 + link_compat_hack;
link_compat_hack = 0;
// error('d',"virtual object allocation %t in %t at %d",bcl,this,b->obj_offset);
byte_offset += bcl->tsizeof();
}
// no more data members.
// pad object (so that copying into a base object
// doesn't destroy derevid class members):
if (byte_offset==0) { // empty struct: waste a member
Pname c = new name (make_name('W'));
c->where = cname->where;
c->tp = char_type;
(void) c->dcl(memtbl,0);
real_size = byte_offset = 1;
}
if (byte_offset < SZ_STRUCT)
byte_offset = SZ_STRUCT;
int waste = byte_offset%max_align;
//error('d',"max_align %d waste %d byte_offset %d",max_align,waste,byte_offset);
if (waste)
byte_offset += max_align-waste;
obj_size = byte_offset;
obj_align = max_align;
// make vtbls
// this cannot be done until the bases
// have been allocated in this class
// so that the offsets (deltas) are known
if (all_virt(this,0,1,0)) {
if (has_ctor()==0)
make_ctor = 1;
}
else if (has_vvtab)
error("virtualB: conflicting vtable initialization");
// error('d',"%t->classdef: virt_count: %d virt_merge: %d",this,virt_count,virt_merge);
Pname hito = has_itor();
if (hito)
c_xref |= C_XREF; // has user defined X(X&)
//error('d',"%t hito %d ctor %d",this,hito,make_ctor);
if (hito==0 && c_xref&(C_VPTR|C_VBASE|C_XREF)) {
// X(X&) needed if bitwise copy is illegal
// or if any constructor is defined
hito = make_itor(0);
// if the base has B::B(void)
// the derived should have D::D(void)
if (baselist) {
int mc = 1; // can make and ictor
for (Pbcl b = baselist; b; b = b->next) {
if (b->bclass->has_ctor() && b->bclass->has_ictor()==0)
mc = 0;
}
make_ctor = mc;
}
else
make_ctor = 1;
}
if (c_ctor==0 && make_ctor==0) { // can ctor be inherited (from single base class)?
Pname btor = 0;
Pclass bc = 0;
for (Pbcl b = baselist; b; b = b->next) {
switch (b->base) {
case NAME:
{
Pname c = b->bclass->has_ctor();
if (c == 0)
break;
if (c->n_scope==PUBLIC && b==baselist) {
bc = b->bclass;
btor = bc->has_ictor();
break;
}
}
// no break: two bases: needs ctor
case VIRTUAL:
make_ctor = 1; // virtual base: need ctor
goto zaza;
}
}
//error('d',"btor %n",btor);
if (bc) {
if (btor)
make_ctor = 1;
else
error("K needed for%t, BC%t hasK",this,bc);
}
zaza:;
}
if (make_ctor && ct==0) { // make x::x() {}
//error('d',"%t: make_ctor",this);
Pname n = new name(string);
Pfct f = new fct(defa_type,0,1);
f->f_inline = 1;
f->f_is_inline = 1;
n->tp = f;
n->n_oper = TNAME;
ct = n->dcl(memtbl,PUBLIC);
delete n;
Pfct(ct->tp)->body = new block(curloc,0,0);
}
if (pt_opt && !nested_sig && !local_sig && !is_probably_temp(string)
&& !tempdcl)
if (csu==UNION)
fprintf(pt_file,"u %s %s\n",string,curr_filename());
else if (csu==STRUCT) {
fprintf(pt_file,"s %s %s\n",string,curr_filename());
}
else if (csu==CLASS)
fprintf(pt_file,"c %s %s\n",string,curr_filename());
// if (ansi_opt && (defined&(DEFINED))==0) {
// char* s = csu==UNION || csu==ANON ? "union" : "struct";
// if ( nested_sig )
// fprintf(out_file,"%s __%s;\n",s,nested_sig);
// else
// fprintf(out_file,"%s %s;\n",s,local_sig?local_sig:string);
// }
defined |= DEFINED;
typedef_checkall(this);
//error('d',"defined %s",string);
// fix argument lists for inlines
for (p=memtbl->get_mem(i=1); p; NEXT_NAME(memtbl,p,i)) {
if ( p->base == TNAME ) continue;
Pfct f = Pfct(p->tp);
if (f==0)
continue; // public declarations
switch (f->base) {
case FCT:
//SYM remove transitional stuff
if (hito && f->argtype)
fix_args(f,this);
if (p->n_oper == CTOR)
f->s_returns = this_type;
if (f->body)
p->n_sto = STATIC;
break;
case OVERLOAD:
{
Pgen g = Pgen(f);
for (Plist gl=g->fct_list; gl; gl=gl->l) {
Pname n = gl->f;
Pfct f = Pfct(n->tp);
if (hito && f->argtype)
fix_args(f,this);
if (n->n_oper == CTOR)
f->s_returns = this_type;
if (f->body)
n->n_sto = STATIC;
}
}
}
}
// define members defined inline
for (p=memtbl->get_mem(i=1); p; NEXT_NAME(memtbl,p,i)) {
if ( p->base == TNAME ) continue;
Pfct f = Pfct(p->tp);
if (f==0)
continue; // public declarations
switch (f->base) {
case FCT:
if (f->body) {
f->dcl(p);
p->simpl();
}
break;
case OVERLOAD:
{
Pgen g = Pgen(f);
for (Plist gl=g->fct_list; gl; gl=gl->l) {
Pname n = gl->f;
Pfct f = Pfct(n->tp);
if (f->body) {
f->dcl(n);
n->simpl();
}
}
}
}
}
byte_offset = byte_old;
bit_offset = bit_old;
max_align = max_old;
cc->unstack(); // friends are not in class scope
// fix arguments lists for friends defined inline
// set global context to match current behavior in dcl.c
// for declaration of friends (needed for find_name())
cc->stack();
cc->cot = 0; cc->not = 0; cc->tot = 0; cc->c_this = 0;
for (Plist fl=friend_list; fl; fl=fl->l) {
Pname p = fl->f;
Pfct f = Pfct(p->tp);
switch (f->base) {
case FCT:
if (hito && f->argtype)
fix_args(f,this);
if (f->body && (f->defined&(DEFINED|SIMPLIFIED)) == 0)
p->n_sto = STATIC;
else if (p->n_scope == STATIC)
error(strict_opt?0:'w',"static%n declared friend toC%t",p,this);
break;
case OVERLOAD:
{
Pgen g = Pgen(f);
for (Plist gl=g->fct_list; gl; gl=gl->l) {
Pname n = gl->f;
Pfct f = Pfct(n->tp);
if (hito && f->argtype)
fix_args(f,this);
if (f->body && (f->defined&(DEFINED|SIMPLIFIED)) == 0)
n->n_sto = STATIC;
else if (p->n_scope == STATIC)
error(strict_opt?0:'w',"static%n declared friend toC%t",p,this);
}
}
}
}
// define friends defined inline and modify return types if necessary
simpl_friend=0;
for (fl=friend_list; fl; fl=fl->l) {
Pname p = fl->f;
Pfct f = Pfct(p->tp);
simpl_friend=1;
switch (f->base) {
case FCT:
if (f->body && (f->defined&(DEFINED|SIMPLIFIED)) == 0) {
f->dcl(p);
p->simpl();
}
break;
case OVERLOAD:
{
Pgen g = Pgen(f);
for (Plist 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->dcl(n);
n->simpl();
}
}
}
}
}
simpl_friend=0;
cc->unstack(); // global context for friends
if (tbl != gtbl)
this->simpl();
//SYM removed statStat stuff
// error('d',"classdef::dcl defined: %d",defined);
// catch refs to this class in body of nested class function
// (i.e., ref to member of this class...)
if ( (defined&REF_SEEN) != 0 )
dcl_print(0);
if ( debug_opt ) {
if (nested_sig) {
prnt_all_in_scope(in_class);
}
void dump_func(Pclass);
if (in_fct || !in_class)
dump_func(this);
}
void check_abst(Pclass);
if (!in_class)
check_abst(this);
}
void dump_func(Pclass th)
{
int i;
for (Pname p=th->memtbl->get_mem(i=1); p; NEXT_NAME(th->memtbl,p,i)) {
if (p->base == TNAME || !p->tp) continue;
Ptype t = p->tp->skiptypedefs();
if (t->base == CLASS) {
dump_func(Pclass(t));
continue;
}
Pfct f = Pfct(t);
if (f==0)
continue; // public declarations
switch (f->base) {
case FCT:
if (f->body) {
if ( th->c_body == 1 ) {
if (th->class_base == INSTANTIATED)
current_instantiation = th;
th->dcl_print(0);
if (th->class_base == INSTANTIATED)
current_instantiation = 0;
}
p->dcl_print(0);
}
break;
case OVERLOAD:
{
Pgen g = Pgen(f);
for (Plist gl=g->fct_list; gl; gl=gl->l) {
Pname n = gl->f;
Pfct f = Pfct(n->tp);
if (f->body) {
if ( th->c_body == 1 ) {
if (th->class_base == INSTANTIATED)
current_instantiation = th;
th->dcl_print(0);
if (th->class_base == INSTANTIATED)
current_instantiation = 0;
}
p->dcl_print(0);
}
}
}
}
}
for (Plist fl=th->friend_list; fl; fl=fl->l) {
Pname p = fl->f;
Pfct f = Pfct(p->tp);
switch (f->base) {
case FCT:
if (f->body && (f->defined&(DEFINED|SIMPLIFIED)) == 0)
p->dcl_print(0);
break;
case OVERLOAD:
{
Pgen g = Pgen(f);
for (Plist 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)
p->dcl_print(0);
}
}
}
}
}
void check_abst(Pclass th)
{
int i;
for (Pname p=th->memtbl->get_mem(i=1); p; NEXT_NAME(th->memtbl,p,i)) {
if (p->base == TNAME || !p->tp) continue;
Ptype t = p->tp->skiptypedefs();
if (t->base == CLASS) {
check_abst(Pclass(t));
continue;
}
Pfct f = Pfct(t);
void check_abst_func(Pname, Pfct);
if (f == 0)
continue;
switch (f->base) {
case FCT:
check_abst_func(p, f);
break;
case OVERLOAD: {
Pgen g = Pgen(f);
for (Plist gl = g->fct_list; gl; gl = gl->l) {
Pfct f = Pfct(gl->f->tp);
check_abst_func(gl->f, f);
}
break;
}
}
}
}
void check_abst_func(Pname p, Pfct f)
{
if (f->returns->is_cl_obj()) {
Pclass cl = f->returns->skiptypedefs()->classtype();
if (cl->c_abstract) {
error(&p->where, "abstractC%t cannot be used as aF returnT", cl);
error('C', &p->where, "\t%a is a pure virtualF ofC%t\n", cl->c_abstract, cl);
}
}
for (Pname a = f->argtype; a; a = a->n_list) {
if (a->tp && a->tp->is_cl_obj()) {
Pclass cl = a->tp->skiptypedefs()->classtype();
if (cl->c_abstract) {
error(&p->where, "abstractC%t cannot be used as anAT", cl);
error('C', &p->where, "\t%a is a pure virtualF ofC%t\n", cl->c_abstract, cl);
}
}
}
}
void enumdef::dcl(Pname n, Ptable tbl)
{
Pname px;
Pname p = mem;
DB( if(Ddebug>=1) error('d',&n->where,"enumdef(%n,%d)",n,tbl); );
Pbase b = new basetype(EOBJ,n);
b->b_const = 1;
if ( local_sig ) {
in_fct = cc->nof;
} else in_fct = 0;
#define FIRST_ENUM 0
int enum_count = FIRST_ENUM;
no_of_enumerators = mem->no_of_names();
int largest = 0;
if (p == 0)
mem = new name(make_name('e'));
for (; p; p=px) {
px = p->n_list;
// error( 'd', "p %n", p );
if (p->n_initializer) {
Pexpr i = p->n_initializer->typ(tbl);
Neval = 0;
long ii = i->eval();
// if (largest_int<ii)
// error("long enumerator");
if (i->tp) {
bit u = i->tp->skiptypedefs()->is_unsigned();
bit ok = 0;
int smallest_int = -largest_int;
switch (i->tp->skiptypedefs()->base) {
#define CHECKU(t) {ok = (unsigned t)ii <= largest_int;}
#define CHECKS(t) {ok = (t)ii >= smallest_int && (t)ii <= largest_int;}
case CHAR:
if (u)
CHECKU(char)
else
CHECKS(char)
break;
case SHORT:
if (u)
CHECKU(short)
else
CHECKS(short)
break;
case ZTYPE:
case INT:
case ENUM:
case EOBJ:
if (u)
CHECKU(int)
else
CHECKS(int)
break;
case LONG:
if (u)
CHECKU(long)
else
CHECKS(long)
break;
default:
// for error checking
// enum E {e = (void)0};
ok = 1;
break;
}
if (!ok)
error("long enumerator");
}
enum_count = int(ii);
if (Neval)
error(&p->where,"%s",Neval);
DEL(i);
p->n_initializer = 0;
}
p->n_evaluated = 1;
largest |= enum_count;
if (enum_count == largest_int && px && !px->n_initializer)
error("enumerator too large");
p->n_val = enum_count++;
p->tp = b;
Pname nn;
if ( tbl == gtbl || tbl->t_name )
nn = tbl->look(p->string,0);
else
nn = curr_block->memtbl->look(p->string,0);
if (
nn
&&
( tbl==gtbl || tbl->t_name
||
nn->n_table->real_block==curr_block->memtbl->real_block
&& nn->lex_level == p->lex_level
)
) {
if (nn->n_stclass == ENUM)
error("enumerator%n declared twice",nn);
else
error("incompatibleDs of%n",nn);
}
else {
nn = tbl->insert(p,0);
nn->n_stclass = ENUM; // no store will be allocated
if (Eppp == PROTECTED)
nn->n_protect = PROTECTED;
else if (Eppp == PUBLIC)
nn->n_scope = PUBLIC;
}
p->string = nn->string;
}
e_type = int_type;
defined |= DEFINED;
if (pt_opt && !nested_sig && !local_sig && !is_probably_temp(string))
fprintf(pt_file,"e %s %s\n",string,curr_filename());
}