/*ident "@(#)cls4:src/dcl2.c 1.12" */ /******************************************************************************* 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. *******************************************************************************/ #include "cfront.h" #include "size.h" #include "overload.h" extern Pexpr make_dot(Pexpr, Ptable, char* s = "i"); extern Pblock top_block; struct for_info { char* s; Pstmt rb; for_info* next; }; static for_info* for_info_head = 0; static int for_check(Pname n, Pstmt rb) { for_info* p; if (!n || !rb) error('i', "for_check(n=%d,rb=%d)", n, rb); if (n->tp->base == FCT || n->tp->base == OVERLOAD) return 0; p = for_info_head; while (p && (strcmp(p->s, n->string) || p->rb != rb)) p = p->next; if (p) { return 1; } else { p = new for_info; p->s = new char[strlen(n->string) + 1]; strcpy(p->s, n->string); p->rb = rb; p->next = for_info_head; for_info_head = p; return 0; } } void for_check_delete() { for_info* p; for_info* r; p = for_info_head; while (p) { r = p; delete p->s; p = p->next; delete r; } for_info_head = 0; } static Pname is_decl(Pblock cb, Pname v) { if (!cb->d) return 0; for (Pname n=cb->d; n; n=n->n_list) { if (strcmp(v->string,n->string)==0) return n; } return 0; } static Pname redecl = 0; Pstmt find_return(Pstmt s, Pname v) { while (s) { switch(s->base) { case RETURN: { Pname te = s->e->base==NAME ? Pname(s->e) : 0; if (!te || strcmp(te->string,v->string) ) { return s; } if (te == v) return 0; if (redecl) return s; else return 0; } case BLOCK: { if(!redecl) redecl = is_decl(Pblock(s),v); Pstmt tt = find_return(Pblock(s)->s,v); if (tt) return tt; redecl = 0; break; } case DO: case WHILE: case FOR: case SWITCH: case CASE: case DEFAULT: { Pstmt tt = find_return(s->s,v); if (tt) return tt; break; } case IF: { Pstmt tt = find_return(s->s,v); if (tt) return tt; tt = find_return(s->else_stmt,v); if (tt) return tt; break; } } s = s->s_list; } return 0; } Pname hier_dominates(Pname on1, Pname on2) /* compare for duplicates and dominance: on1 and on2 are two conversion operator functions return the the one that dominates the other (according to the class hierarchy) otherwise 0 (0 thus indicates ambiguous conversion) */ { Pfct f1 = on1->get_fct(); Pfct f2 = on2->get_fct(); Ptype r1 = f1->returns; Ptype r2 = f2->returns; if (r1==r2 || r1->check(r2,0)==0) { Pclass m1 = f1->memof; Pclass m2 = f2->memof; if (m1->has_base(m2)) return on1; if (m2->has_base(m1)) return on2; return 0; } Pptr p1 = r1->is_ptr_or_ref(); Pptr p2 = r2->is_ptr_or_ref(); if (p1 && p2) { Pname cn1 = p1->typ->is_cl_obj(); Pname cn2 = p2->typ->is_cl_obj(); if (cn1 && cn2) { Pclass c1 = Pclass(cn1->tp); Pclass c2 = Pclass(cn2->tp); if (c1 && c2) { if (c1->has_base(c2)) return on1; else if (c2->has_base(c1)) return on2; } } } return 0; } Bits best_conv(const Block(Pname)& CONV, int& nfound, bit cO) { Bits zeroBits(0,nfound); Bits result = ~zeroBits; Bits tempBits = ~zeroBits; int sigbit = tempBits.signif() - 1; tempBits.reset(sigbit); while(tempBits.count()) { int tempPtr = tempBits.signif() - 1; Pname tname = CONV[tempPtr]; for(int k = nfound - 1; k > tempPtr; k--) { if(!result[k]) continue; Pname r = really_dominate(tname,CONV[k],cO); if (r==tname) result.reset(k); if (r==CONV[k]) { result.reset(tempPtr); break; } } tempBits.reset(tempPtr); } nfound = result.count(); return result; } Pstmt curr_loop; Pstmt curr_switch; Pblock curr_block; static Pstmt curr_case; // case or default static Pblock block_since_case; // set to curr_block if it follows curr_case void stmt::reached() { register Pstmt ss = s_list; if (ss == 0) return; switch (ss->base) { case LABEL: case CASE: case DEFAULT: break; default: if (ss->where.line != 0) error('w',&ss->where,"S after%k not reached",base); else error('w',"S after%k not reached",base); for (; ss; ss=ss->s_list) { // delete unreacheable code switch (ss->base) { case LABEL: case CASE: case DEFAULT: // reachable s_list = ss; return; case DCL: // the dcl may be used later // keep to avoid cascading errors case IF: case DO: case WHILE: case SWITCH: case FOR: case BLOCK: // may hide a label s_list = ss; return; } } s_list = 0; } } bit oper_okay(Ptype t, TOK b) { if (t->is_ref()) t = Pptr(t)->typ; switch (t->base) { case PTR: if (b == UMINUS) break; case FLOAT: case DOUBLE: case LDOUBLE: if (b == COMPL || b == DEREF || b == SWITCH) break; case CHAR: case SHORT: case INT: case LONG: case EOBJ: return 1; } return 0; } Pexpr check_cond(Pexpr e, TOK b, Ptable tbl) { Pname cn; if (e == dummy) error("empty condition for %k",b); int const_obj = 0; const_obj = e->tp->tconst() ? 1 : e->is_const_obj(); if (cn = e->tp->is_cl_obj()) { int no_const = 0; // for better error reporting Pclass cl = Pclass(cn->tp); Pname found = 0; Pname other = 0; int nfound = 0; Block(Pname) conv; for (Pname on = cl->conv; on; on=on->n_list) { Pfct f = on->get_fct(); Ptype t = f->returns->skiptypedefs(); if (oper_okay(t,b) == 1) { if (const_obj && !f->f_const) { no_const++; continue; } conv.reserve(nfound+1); conv[nfound++] = on; } } if (nfound==1) found = conv[nfound-1]; if (nfound > 1) { Bits b = best_conv(conv,nfound,const_obj); int i = b.signif() - 1; found = conv[i]; if(b.count() == 2) { b.reset(i); other = conv[b.signif() - 1]; } } switch (nfound) { case 0: if (no_const) error("%nO in%kE (no usable const conversion)",cn,b); else error("%nO in%kE",cn,b); break; case 1: { Pname xx = new name(found->string); Pexpr c; if (e->lval(0)) { Pref r = new ref(DOT,e,xx); Pexpr rr = r->typ(tbl); c = new expr(G_CALL,rr,0); } else { // (temp=init,temp.coerce()) //Pname tmp = make_tmp('U',e->tp,tbl); //Pexpr ass = init_tmp(tmp,e,tbl); Pref r = new ref(DOT,e,xx); Pexpr rr = r->typ(tbl); c = new expr(G_CALL,rr,0); //c = new expr(CM,ass,c); } Pexpr E = c->typ(tbl); if(E->tp->memptr()) { E = make_dot(E,tbl); E = new expr(NE,E,zero); E->tp = int_type; } e = E; break; } case 2: error("two conversions for%nO in%kE: %n and %n", cn,b,found,other); break; default: error("multiple conversions for%nO in%kE",cn,b); break; } return e; } if(e->tp->base == FCT) { e = new expr(G_ADDROF,0,e); e = e->typ(tbl); } if (e->tp->memptr()) { if (b == SWITCH) { error("P toM as switchE"); return e; } if (e->base == ILIST || ((e->base == CAST || e->base == G_CAST) && e->e1->base == ILIST)) { if (e->base != ILIST) e = e->e1; if (e->e1->e2 != zero) e = one; else e = zero; } else { e = make_dot(e,tbl); e = new expr(NE,e,zero); e->tp = int_type; } } else if (e->tp->num_ptr(b) == FCT) error("%k(F)",b); return e; } void stmt::dcl(int forflag) /* typecheck statement "this" in scope "curr_block->tbl" */ { Pstmt ss; Pname n; Pname nn; Pstmt ostmt = Cstmt; DB( if(Ddebug>=1) error('d',&where,"'%k'->stmt::dcl()",base); ); for (ss=this; ss; ss=ss->s_list) { Pstmt old_loop, old_switch; Cstmt = ss; Ptable tbl = curr_block->memtbl; //error('d',"stmt::dcl %k",ss->base); switch (ss->base) { case BREAK: inline_restr |= 16; if (curr_loop==0 && curr_switch==0) error("break not in loop or switch"); ss->reached(); break; case CONTINUE: inline_restr |= 32; if (curr_loop == 0) error("continue not in loop"); ss->reached(); break; case DEFAULT: if (curr_switch == 0) { error("default not in switch"); break; } if (curr_switch->has_default) error("two defaults in switch"); curr_case = ss; block_since_case = 0; curr_switch->has_default = ss; ss->s->s_list = ss->s_list; ss->s_list = 0; ss->s->dcl(); break; case SM: { if (ss->e ==0) break; TOK b = ss->e->base; switch (b) { case DUMMY: // null or error case DTOR: // dummy type destructor ss->e = 0; break; // check for unused results // don't check operators that are likely // to be overloaded to represent "actions": // ! ~ < <= > >= << >> case EQ: case NE: case GT: case GE: case LT: case LE: case PLUS: case MINUS: case REF: case DOT: case MUL: case DIV: case ADDROF: case AND: case OR: case ER: case DEREF: case ANDAND: case OROR: case NAME: case VALUE: if (ss->e->tp) break; // avoid looking at generated code ss->e = ss->e->typ(tbl); if (ss->e->base == CALL) break; if (ss->e->tp->base != VOID) { if ( ss->e->base == DEREF ) error('w',"result of %sE not used",ss->e->e2?"[]":"*"); else { error('w',"result of%kE not used",b); if ( ss->e->base == NAME && ss->e->tp->base == FCT ) { int i = Pname(ss->e)->n_addr_taken; Pname(ss->e)->n_addr_taken = 1; Pname(ss->e)->dcl_print(0); Pname(ss->e)->n_addr_taken = i; } } if (ss->e->not_simple()==0) ss->e = dummy; } if (ss->e->base == ILIST) { Pname tt = make_tmp('A',mptr_type,tbl); ss->e = mptr_assign(tt,ss->e); } break; default: ss->e = ss->e->typ(tbl); } break; } case RETURN: { Pname fn = cc->nof; Pfct f = Pfct(fn->tp); Ptype rt = f->returns->skiptypedefs(); Pexpr v = ss->e; //error('d',"rt %t",rt); if (v != dummy) { if (rt->base == RPTR) { ref_initializer++; v = v->typ(tbl); ref_initializer--; } else v = v->typ(tbl); if ( fn->n_oper==CTOR || fn->n_oper==DTOR || rt->base==VOID ) { error("unexpected return value"); // refuse to return the value: ss->e = dummy; } else { switch (rt->base) { case RPTR: switch (v->base) { case NAME: if ( Pname(v)->n_scope==FCT || Pname(v)->n_scope==ARG ) error('w',"R to localV returned"); break; case ICON: case CCON: case FCON: case STRING: if (Pptr(rt)->typ->tconst()==0) error('w',"R to literal returned"); } in_return=1; v = ref_init(Pptr(rt),v,tbl); in_return=0; if ( v->base==G_CM && v->e2->base==G_ADDROF && v->e2->e2->base==NAME && is_probably_temp(v->e2->e2->string) ) error('w',"R to temporary returned (return value is not lvalue or of wrongT)"); case ANY: break; case COBJ: if (v->base == DEREF) { Pexpr v1 = v->e1; if (v1->base==CAST || v1->base==G_CAST) { Pexpr v2 = v1->e1; if (v2->base == G_CM) { // *(T)(e1,e2) => (e1,*(T)e2) Pexpr v3 = v2->e2; v2->e2 = v; v2->tp = v->tp; v = v2; v1->e1 = v3; } } } if (f->f_result) { if ( v->base==G_CM && rt->check(v->tp,0/*ASSIGN*/)==0 ) v = replace_temp(v,f->f_result); else { if (!f->nrv) v = class_init(f->f_result->contents(),rt,v,tbl); Pname rcn = rt->is_cl_obj(); if (Pclass(rcn->tp)->has_itor()==0) { // can happen for virtuals and for user defined conversions v->tp = rt; v = new expr(ASSIGN,f->f_result->contents(),v); v->tp = rt; } } } else v = class_init(0,rt,v,tbl); break; case PTR: { v = ptr_init(Pptr(rt),v,tbl); if ( v->base == ADDROF && v->e2->base == NAME && Pname(v->e2)->n_stclass == AUTO ) error('w',"P to local variable%n returned",Pname(v->e2)); if (Pchecked == 0) goto def; goto ret_save; } case INT: case CHAR: case LONG: case SHORT: if ( Pbase(rt)->b_unsigned && v->base==UMINUS && v->e2->base==ICON ) error('w',"negative returned fromF returning unsigned"); default: def: { Pexpr x = try_to_coerce(rt,v,"return value",tbl); int ct = no_const; if (x) v = x; else if (rt->check(v->tp,ASSIGN)) { error('e',"bad return valueT for%n:%t (%tX)",fn,v->tp,rt); if (ct) error('c'," (no usable const conversion)\n"); else error('c',"\n"); } break; } } ret_save: ss->ret_tp = rt; ss->e = v; } } else { if (rt->base != VOID) error("return valueX"); } ss->reached(); break; } case DO: // in DO the stmt is before the test inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; { Pstmt st = ss->s; while(st && st->base == FOR) st = st->for_init; if (st && st->base == DCL) if (st==ss->s) error("D as onlyS in do-loop"); } ss->s->dcl(); ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,DO,tbl); curr_loop = old_loop; break; case WHILE: inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,WHILE,tbl); { Pstmt st = ss->s; while(st && st->base == FOR) st = st->for_init; if (st && st->base == DCL) if(st==ss->s) error("D as onlyS in while-loop"); } ss->s->dcl(); curr_loop = old_loop; break; case SWITCH: { int ne = 0; Pstmt old_case = curr_case; Pblock old_bsc = block_since_case; curr_case = 0; block_since_case = 0; inline_restr |= 4; old_switch = curr_switch; curr_switch = ss; ss->e = ss->e->typ(tbl); ss->e = check_cond(ss->e,SWITCH,tbl); { Pstmt st = ss->s; while(st && st->base == FOR) st = st->for_init; if (st && st->base == DCL) if(st==ss->s) error("D as onlyS in switchS"); } { Ptype tt = ss->e->tp->skiptypedefs(); switch (tt->base) { case EOBJ: ne = Penum(Pbase(tt)->b_name->tp)->no_of_enumerators; case ZTYPE: case ANY: case CHAR: case SHORT: case INT: case LONG: case FIELD: break; default: error("%t switchE",ss->e->tp); } } ss->s->dcl(); if (ne) { // see if the number of cases is "close to" // but not equal to the number of enumerators int i = 0; Pstmt cs; for (cs=ss->case_list; cs; cs=cs->case_list) i++; if (i && i!=ne) { if (ne < i) { ee: if (ss->has_default==0) error('w',"switch (%t)W %d cases (%d enumerators)",ss->e->tp,i,ne); } else { switch (ne-i) { case 1: if (3e = ss->e->typ(tbl); ss->e->tp->num_ptr(CASE); { Ptype tt = ss->e->tp->skiptypedefs(); switch (tt->base) { case ZTYPE: case ANY: case CHAR: case SHORT: case INT: case LONG: case EOBJ: { Neval = 0; long i = ss->e->eval(); if (Neval == 0) { Pstmt cs; if (largest_intcase_list; cs; cs=cs->case_list) { if (cs->case_value == i) error("case %d used twice in switch",i); } ss->case_value = int(i); ss->case_list = curr_switch->case_list; curr_switch->case_list = ss; } else error("bad case label: %s",Neval); break; } default: error("%t caseE",ss->e->tp); } } if (ss->s->s_list) error('i',"case%k",ss->s->s_list->base); ss->s->s_list = ss->s_list; ss->s_list = 0; ss->s->dcl(); break; case GOTO: inline_restr |= 2; ss->reached(); case LABEL: // Insert label in function mem table; // labels have function scope. n = ss->d; nn = cc->ftbl->insert(n,LABEL); // Set a ptr to the mem table corresponding to the scope // in which the label actually occurred. This allows the // processing of goto's in the presence of ctors and dtors if (ss->base == LABEL) { nn->n_realscope = curr_block->memtbl; inline_restr |= 1; } if (Nold) { if (ss->base == LABEL) { if (nn->n_initializer) error("twoDs of label%n",n); nn->n_initializer = (Pexpr)1; } if (n != nn) ss->d = nn; } else { if (ss->base == LABEL) nn->n_initializer = (Pexpr)1; nn->where = ss->where; } if (ss->base == GOTO) nn->use(); else { if (ss->s->s_list) error('i',"label%k",ss->s->s_list->base); ss->s->s_list = ss->s_list; ss->s_list = 0; nn->assign(); } if (ss->s) ss->s->dcl(); break; case IF: { Pexpr ee = ss->e->typ(tbl); if (ee->base == ASSIGN) { Neval = 0; (void)ee->e2->eval(); if (Neval == 0) error('w',"constant assignment in condition"); } ss->e = ee = check_cond(ee,IF,tbl); if (ss->s && (ss->s->base == DCL || ss->s->base==FDCL)) error(&ss->s->where,"D as onlyS after `if'"); // pointer to member returns with a tp set to 0 if ( ee->tp ) switch (ee->tp->base) { case INT: case EOBJ: case ZTYPE: { long i; Neval = 0; i = ee->eval(); if (Neval == 0) { Pstmt sl = ss->s_list; if (i) { DEL(ss->else_stmt); ss->s->dcl(); *ss = *ss->s; } else { DEL(ss->s); if (ss->else_stmt) { ss->else_stmt->dcl(); *ss = *ss->else_stmt; } else { ss->base = SM; ss->e = dummy; ss->s = 0; } } ss->s_list = sl; continue; } } } if (ss->s->base !=FDCL) ss->s->dcl(); if (ss->else_stmt) { if (ss->else_stmt->base == DCL || ss->else_stmt->base==FDCL) error(&ss->else_stmt->where,"D as onlyS after `else'"); if (ss->else_stmt->base != FDCL) ss->else_stmt->dcl(); } break; } case FOR: inline_restr |= 8; old_loop = curr_loop; curr_loop = ss; if (ss->for_init) { Pstmt fi = ss->for_init; switch (fi->base) { case SM: if (fi->e == dummy) { ss->for_init = 0; break; } fi->dcl(); break; default: // for (stmt; e1; e2) stmt1 stmt2 // => {stmt; for(; e1; e2) stmt1 stmt2} // if stmt != declaration // if stmt == declaration, temporarily // rewrite to avoid symbol table // problems in some contexts. // Then put decl back to avoid // extraneous {}. // Note: to maintain pointers, ss // must not change { Pstmt tmp = new stmt (SM,curloc,0); *tmp = *ss; // tmp = original for tmp->for_init = 0; fi->s_list = tmp; *ss = *fi; curr_loop = old_loop; ss->dcl(1); tmp = ss->s_list; if ( ss->base == DCL && tmp->base == FOR // sanity check && tmp->for_init == 0 // sanity check ) { // put DCL back in for init *fi = *ss; *ss = *tmp; ss->for_init = fi; fi->s_list = 0; } else { // non-decl stmt in for init // put stmts in block in case // they follow a condition... // allocate tmp to be sure // fields are initialized *fi = *ss; tmp = new block(ss->where,0,fi); tmp->own_tbl = 0; tmp->memtbl = curr_block->memtbl; tmp->permanent = ss->permanent; *ss = *tmp; tmp->permanent = 0; delete tmp; } // don't repeat stmt::dcl() for // remaining stmts goto done; } } } if (ss->e == dummy) ss->e = 0; else { ss->e = ss->e->typ(tbl); // handle temporary of class object with dtor if (Ntmp) { Ntmp_dtor = new expr(ELIST,ss->e,Ntmp_dtor); // error('d',"dcl2: stmt::simpl (e %d) temp %n",ss->e,Ntmp); } ss->e = check_cond(ss->e,FOR,tbl); } { Pstmt st = ss->s; while(st && st->base == FOR) st = st->for_init; if (st && (st->base == DCL || st->base == FDCL)) if(st==ss->s) error(&ss->s->where,"D as onlyS in for-loop"); } if (ss->s->base != FDCL) ss->s->dcl(); ss->e2 = (ss->e2 == dummy) ? 0 : ss->e2->typ(tbl); curr_loop = old_loop; break; case DCL: /* declaration after statement */ { // collect all the contiguous DCL nodes from the // head of the s_list. find the next statement int non_trivial = 0; int count = 0; Pname tail = ss->d; for (Pname nn=tail; nn; nn=nn->n_list) { // find tail; // detect non-trivial declarations count++; if (nn->n_list) tail = nn->n_list; Pname n = tbl->look(nn->string,0); if (n && n->n_table==tbl) non_trivial = 2; if (non_trivial >= 2) continue; if ( nn->n_sto==STATIC && nn->tp->base!=FCT || nn->tp->is_ref() || nn->tp->tconst() && fct_const==0 ) { non_trivial = 2; continue; } if ( nn->base == NAME ) { Pexpr in = nn->n_initializer; if (in) switch (in->base) { case ILIST: case STRING: non_trivial = 2; continue; } if (in) non_trivial=3; else non_trivial = 1; } Pname cln = nn->tp->is_cl_obj(); if (cln == 0) cln = cl_obj_vec; if (cln == 0) continue; if (Pclass(cln->tp)->has_ctor()) { non_trivial = 3; continue; } if (Pclass(cln->tp)->has_dtor()) non_trivial = 2; } while( ss->s_list && ss->s_list->base==DCL ) { Pstmt sx = ss->s_list; tail = tail->n_list = sx->d; // add to tail for (nn=sx->d; nn; nn=nn->n_list) { // find tail; // detect non-trivial declarations count++; if (nn->n_list) tail = nn->n_list; Pname n = tbl->look(nn->string,0); if (n && n->n_table==tbl) non_trivial = 2; if (non_trivial >= 2) continue; if ( nn->n_sto==STATIC && nn->tp->base!=FCT || nn->tp->is_ref() || nn->tp->tconst() && fct_const==0 ) { non_trivial = 2; continue; } if ( nn->base == NAME ) { Pexpr in = nn->n_initializer; if (in) switch (in->base) { case ILIST: case STRING: non_trivial = 2; continue; } } non_trivial = 1; Pname cln = nn->tp->is_cl_obj(); if (cln == 0) cln = cl_obj_vec; if (cln == 0) continue; if (Pclass(cln->tp)->has_ctor()) { non_trivial = 2; continue; } if (Pclass(cln->tp)->has_dtor()) non_trivial = 2; } ss->s_list = sx->s_list; } Pstmt next_st = ss->s_list; //error('d',"dcl stmt : d %n non_trivial %d curr own_tbl %d inline_restr 0%o",ss->d,non_trivial,curr_block->own_tbl,inline_restr); if ( non_trivial==3 || non_trivial==2 // must || non_trivial==1 // might && ( curr_block->own_tbl==0 // why not? || inline_restr&3 // label seen ) ) { if (curr_switch && non_trivial>=2) { if ( curr_case == 0 || block_since_case == 0 ) if (non_trivial==3) error("jump past initializer (did you forget a '{ }'?)"); else error("non trivialD in switchS (try enclosing it in a block)"); } // Create a new block, // put all the declarations at the head, // and the remainder of the slist as the // statement list of the block. // check that there are no redefinitions // since the last "real" (user-written, // non-generated) block { Pname lastnn = 0; for( nn=ss->d; nn; nn=nn->n_list ) { Pname n; //error('d',"checking %n lex_level: %d n: %n n->lex_level: %d",nn,nn->lex_level,n,n?n->lex_level:0); //error('d'," own_tbl: %d curr_block: %d n->n_table: %d",curr_block->own_tbl,curr_block,n->n_table); //error('d'," real_block: %d n's real_block: %d",curr_block->memtbl->real_block,n->n_table->real_block); if ( (n=curr_block->memtbl->look(nn->string,0)) && n->n_table->real_block==curr_block->memtbl->real_block && n->tp->base!=FCT && n->tp->base!=OVERLOAD && nn->lex_level == n->lex_level || (forflag && for_check(n=nn, curr_block->memtbl->real_block)) ) { error("twoDs of%n",n); if (lastnn==0) ss->d=nn->n_list; else lastnn->n_list=nn->n_list; } else lastnn = nn; } // for nn } // attach the remainder of the s_list // as the statement part of the block. ss->s = next_st; ss->s_list = 0; // create the table in advance, // in order to set the real_block // ptr to that of the enclosing table ss->memtbl = new table(count+4,tbl,0); ss->memtbl->real_block = curr_block->memtbl->real_block; Pblock(ss)->dcl(ss->memtbl); } else { // to reduce the number of symbol tables, // do not make a new block, // instead insert names in enclosing block, // and make the initializers into expression // statements. Pstmt sss = ss; { Pname lastnn = 0; for( nn=ss->d; nn; nn=nn->n_list ) { Pname n; if ( (n=curr_block->memtbl->look(nn->string,0)) && n->n_table->real_block==curr_block->memtbl->real_block && n->tp->base!=FCT && n->tp->base!=OVERLOAD && nn->lex_level == n->lex_level || (forflag && for_check(n=nn, curr_block->memtbl->real_block)) ) { error("twoDs of%n",n); n = 0; if (lastnn==0) ss->d=nn->n_list; else lastnn->n_list=nn->n_list; } else { n = nn->dcl(tbl,FCT); lastnn=nn; } if (n == 0) { if (ss) { ss->base = SM; ss->e = 0; } continue; } //error('d',"hoisted %n to outer blk",n); if (ss) { sss->base = SM; ss = 0; } else sss = sss->s_list = new estmt(SM,sss->where,0,0); if (n->base==NAME && n->n_initializer) { Pexpr in = n->n_initializer; n->n_initializer = 0; switch (in->base) { case G_CALL: /* constructor? */ { Pname fn = in->fct_name; if (fn && fn->n_oper==CTOR) break; } default: in = new expr(ASSIGN,n,in); in->tp = n->tp; } sss->e = in; sss->where=n->where; } else sss->e = dummy; } // for nn } ss = sss; ss->s_list = next_st; } break; } case BLOCK: Pblock(ss)->dcl(tbl); break; case ASM: /* save string */ { char* s = (char*)ss->e; int ll = strlen(s); char* s2 = new char[ll+1]; strcpy(s2,s); ss->e = Pexpr(s2); break; } default: error('i',"badS(%p %d)",ss,ss->base); } } done: Cstmt = ostmt; } void block::dcl(Ptable tbl) /* Note: for a block without declarations memtbl denotes the table for the enclosing scope. A function body has its memtbl created by fct::dcl(). */ { int bit_old = bit_offset; int byte_old = byte_offset; Pblock block_old = curr_block; Pstmt save_case = curr_case; Pblock old_bsc = block_since_case; Pfct f = cc->nof->fct_type(); if (base != BLOCK && base != DCL) error('i',"block::dcl(%d)",base); curr_block = this; if ( curr_case && base == BLOCK ) block_since_case = this; Pname re_decl = 0; if (f->f_result && s && f->nrv == 0 && (this == top_block || memtbl && memtbl->real_block == top_block) ) { Pstmt tmp = s; while (tmp->base != RETURN && tmp->s_list) tmp = tmp->s_list; if(tmp->base == RETURN) { Pname tt = tmp->e->base == NAME ? Pname(tmp->e) : 0; Pname td; if (tt && (td=is_decl(curr_block,tt)) && td->n_sto != STATIC && td->tp->check(f->returns,0) == 0 ) { f->nrv = tt; } } // disable optimization if something other than // the nrv variable is returned if (f->nrv) { if (find_return(s,f->nrv)) f->nrv = 0; } } else if (f->nrv) re_decl = is_decl(curr_block,f->nrv); Pktab otbl = Ctbl;//SYM if ( k_tbl ) Ctbl = k_tbl;//SYM if (d) { own_tbl = 1; base = BLOCK; if (memtbl == 0) { int nmem = d->no_of_names()+4; memtbl = new table(nmem,tbl,0); memtbl->real_block = this; // this is a "real" block from the // source text, and not one created by DCL's // inside a block. } else if (memtbl != tbl) error('i',"block::dcl(?)"); Pname nx; for (Pname n=d; n; n=nx) { nx = n->n_list; if (f->nrv && !re_decl && strcmp(f->nrv->string,n->string)==0 ) { // found nrv in declaration n->string = new char[6]; strcpy(n->string,"__NRV"); } n->dcl(memtbl,FCT); switch (n->tp->base) { case CLASS: case ANON: case ENUM: break; default: delete n; } } } else if ( base == BLOCK ) { own_tbl = 1; if (memtbl == 0) { int nmem = 4; memtbl = new table(nmem,tbl,0); memtbl->real_block = this; // this is a "real" block from the // source text, and not one created by DCL's // inside a block. } else if (memtbl != tbl) error('i',"block::dcl(?)"); } else { base = BLOCK; memtbl = tbl; } Pname odcl = Cdcl; if (s) s->dcl(); if (own_tbl) { Pname m; int i; for (m=memtbl->get_mem(i=1); m; NEXT_NAME(memtbl,m,i)) { Ptype t = m->tp; if (in_class_dcl) m->lex_level -= 1; if (t == 0) { if (m->n_assigned_to == 0) error("label %sU",m->string); if (m->n_used == 0) error('w',&m->where,"label %s not used", m->string); continue; } t = t->skiptypedefs(); switch (t->base) { case CLASS: case ANON: case ENUM: case FCT: continue; } if (m->n_addr_taken == 0) { if (m->n_used) { if ( m->n_assigned_to==0 && t->base != VEC && m->n_scope==FCT ) { Cdcl = m; if (m->string[0] != '_' && m->string[1] != '_' ) error('w',&m->where,"%n used but not set",m); } } else { if ( m->n_assigned_to==0 && (m->string[0]!='_' || m->string[1]!='_') && (m->n_scope==ARG || m->n_scope==FCT) ) { Cdcl = m; error('w',&m->where,"%n not used",m); } } } } } Cdcl = odcl; d = 0; if (bit_offset) byte_offset += SZ_WORD; bit_offset = bit_old; byte_offset = byte_old; if ( curr_case == save_case ) block_since_case = old_bsc; curr_block = block_old; Ctbl = otbl;//SYM } void name::field_align() /* adjust alignment */ { Pbase fld = (Pbase)tp; int nbits = fld->b_bits; int a = (F_SENSITIVE) ? fld->b_fieldtype->align() : SZ_WORD; if (max_align < a) max_align = a; if (nbits == 0) { // force word alignment int b; if (bit_offset) nbits = BI_IN_WORD - bit_offset; else if (b = byte_offset%SZ_WORD) nbits = b * BI_IN_BYTE; if (max_align < SZ_WORD) max_align = SZ_WORD; } else if (bit_offset == 0) { // take care of part of word int b = byte_offset%SZ_WORD; if (b) { byte_offset -= b; bit_offset = b*BI_IN_BYTE; } } //error('d',"byteoff %d bitoff %d bits %d",byte_offset,bit_offset,nbits); int x = (bit_offset += nbits); if (SZ_INT * BI_IN_BYTE < x) { fld->b_offset = 0; byte_offset += SZ_INT; bit_offset = nbits; } else { fld->b_offset = bit_offset; if (SZ_INT * BI_IN_BYTE == x) { bit_offset = 0; byte_offset += SZ_INT; } else bit_offset = x; } n_offset = byte_offset; }