/*ident "@(#)ctrans:src/expr2.c 1.5" */ /*************************************************************************** C++ source for cfront, the C++ compiler front-end written in the computer science research center of Bell Labs Copyright (c) 1984 AT&T, Inc. All rights Reserved THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC. expr2.c: type check expressions ************************************************************************/ #include "cfront.h" #include "size.h" extern Pname conv_dominates(Pname,Pname); static int const_obj1,const_obj2; Pname really_dominate(Pname on1, Pname on2, bit tc) { Pfct f1 = on1->tp->base==FCT ? Pfct(on1->tp) : Pfct(Pgen(on1->tp)->fct_list->f->tp); Pfct f2 = on2->tp->base==FCT ? Pfct(on2->tp) : Pfct(Pgen(on2->tp)->fct_list->f->tp); // const check int c1 = f1->f_const; int c2 = f2->f_const; if(c1 == c2) ; else if(c1 && !c2) return tc ? on1 : on2; else if(c2 && !c1) return tc ? on2 : on1; // hierarchy check Pname on = conv_dominates(on1,on2); if(on) return on; else return 0; } void name::assign() { if (n_assigned_to++ == 0) { switch (n_scope) { case FCT: if (n_used && n_addr_taken==0) { Ptype t = tp; ll: switch (t->base) { case TYPE: t=Pbase(t)->b_name->tp; goto ll; case VEC: break; default: if (curr_loop) error('w',&where,"%n may have been used before set",this); else error('w',&where,"%n used before set",this); } } } } } void name::take_addr() { // error('d', "%n->take_addr tp: %t", this, tp?tp:0 ); // error('d', "%n->take_addr tp: %d %d", this, tp?tp:0, tp?tp->base:0 ); if ( (warning_opt) && (! n_addr_taken) && (tp) && (tp->base==FCT) && Pfct (tp)->f_inline) error('w',"can't take address of inline function %n, %n not inlined", this, this); n_addr_taken++; if ( n_sto == EXTERN && tp ) { Ptype t = tp; while ( t->base == TYPE ) t = Pbase(t)->b_name->tp; switch ( t->base ) { case COBJ: t = Pbase(t)->b_name->tp; // no break case CLASS: { Pclass cl = Pclass(t); if ( cl->c_body == 1 ) cl->dcl_print(0); } } } } int ignore_const; // for use by ref_init static is_dataMemPtr(Pexpr); int expr::lval(TOK oper) { register Pexpr ee = this; register Pname n; int deref = 0; char* es; //error('d',"%k expr::lval %k",base,oper); switch (oper) { case ADDROF: case G_ADDROF: es = "address of"; break; case DEREF: es = "dereference of"; break; case INCR: es = "increment of"; goto def; case DECR: es = "decrement of"; goto def; default: es = "assignment to"; def: if (ignore_const==0 && tp->tconst()) { if (oper) { if (base == NAME) { if (vec_const && Pname(this)->n_scope==ARG) break; error("%s constant%n",es,this); } else error("%s constant",es); } return 0; } } for(;;) { //error('d',"loop %k",ee->base); switch (ee->base) { // case G_CALL: // case CALL: default: defa: if (deref == 0) { if (oper) error("%s%k (not an lvalue)",es,ee->base); return 0; } return 1; case ZERO: case CCON: case ICON: case FCON: if (oper) error("%s numeric constant",es); return 0; case STRING: if (oper) error('w',"%s string constant",es); return 1; case CAST: switch( oper ) { case 0: case ADDROF: case G_ADDROF: case DEREF: goto defa; default: if ( ee->tp->base == PTR && is_dataMemPtr(ee) ) { // check for const class object Pexpr te; te = ee->e1->e1->e1; if ( te->base == G_ADDROF ) te = te->e2; if ( te->base == NAME ) { Ptype pt = te->tp; if ( pt->base == PTR ) pt = Pptr(pt)->typ; if ( pt->tconst() ) error("%sCMP of const%n",es,te); return 0; } } goto defa; } case DEREF: { Pexpr ee1 = ee->e1; // error( 'd', "ee1: %k", ee1->base ); switch (ee1->base) { // *& vanishes case ADDROF: // *& return 1; case G_CM: case CM: // look for *(a,&b) if (ee1->e2->base==G_ADDROF || ee1->e2->base==ADDROF) return 1; goto defaa; case QUEST: // look for *(q?&a:&b) if ((ee1->e1->base==G_ADDROF || ee1->e1->base==ADDROF) && (ee1->e2->base==G_ADDROF || ee1->e2->base==ADDROF)) return 1; // no break default: defaa: ee = ee1; deref = 1; } break; } case QUEST: { int x1 = ee->e1->lval(deref?0:oper); int x2 = ee->e2->lval(deref?0:oper); if (ee->e1->tp->check(ee->e2->tp,0)) return 0; if (deref) return 1; return x1 && x2; } case INCR: case DECR: if (e1) goto defa; // postfix does not preserve lval case ASSIGN: case ASPLUS: case ASMINUS: case ASMUL: case ASDIV: case ASMOD: case ASAND: case ASOR: case ASER: case ASLS: case ASRS: return 1; case CM: case G_CM: if (ee->e2->lval(deref?0:oper)==0) return deref; return 1; case MEMPTR: ee = ee->e2; break; case MDOT: ee = ee->mem; break; case DOT: { // error('d',"dot %k oper %k",ee->e1->base,oper); Pexpr e = 0; int e_const = 0; // to catch x.y.val = 1, where x is const switch (ee->e1->base) { // update use counts, etc. case NAME: switch (oper) { case ADDROF: case G_ADDROF: Pname(ee->e1)->take_addr(); case 0: break; case ASSIGN: Pname(ee->e1)->n_used--; default: Pname(ee->e1)->assign(); // asop } break; case DOT: e = ee->e1; do e=e->e1; while (e->base==DOT); if (e->base == NAME) { e_const = e->tp->tconst(); switch (oper) { case ADDROF: case G_ADDROF: Pname(e)->take_addr(); case 0: break; case ASSIGN: Pname(e)->n_used--; default: Pname(e)->assign(); // asop } } } n = Pname(ee->mem); while (n->base == MDOT) n = Pname(Pref(n)->mem); if (deref==0 && (ee->e1->tp->tconst() || e_const)) { switch (oper) { case 0: case ADDROF: case G_ADDROF: case DEREF: break; default: error("%sM%n of%t",es,n,e_const?e->tp:ee->e1->tp); } return 0; } } goto xx; case REF: n = Pname(ee->mem); while (n->base == MDOT) n = Pname(Pref(n)->mem); if (deref==0 && ee->e1) { //BR Ptype p = ee->e1->tp; zxc: switch (p->base) { case TYPE: p = Pbase(p)->b_name->tp; goto zxc; case PTR: case VEC: break; default: error('i',"expr::lval %t->%n",p,n); } if (Pptr(p)->typ->tconst()) { switch (oper) { case 0: case G_ADDROF: case DEREF: break; case ADDROF: if ( cm_const_save == 0 && const_ptr == 0 ) error(strict_opt?0:'w',"%sM%n of%t",es,n,Pptr(p)->typ); break; default: error("%sM%n of%t",es,n,Pptr(p)->typ); } return 0; } } goto xx; case NAME: n = Pname(ee); xx: // error('d',"name xx: %n oper %d lex_level: %d",n,oper,n->lex_level); if (deref) return 1; if (oper==0) return n->n_stclass != ENUM ; if (n->tp->base==FIELD && Pbase(n->tp)->b_bits==0) { error("%s 0-length field%n",es,n); return 0; } switch (oper) { case ADDROF: case G_ADDROF: { Pfct f = (Pfct)n->tp; if (n->n_sto == REGISTER) { if (warning_opt) error('w',"& register%n",n); // return 0; n->n_sto = 0; n->n_stclass = AUTO; } if (f == 0) { error("& label%n",n); return 0; } if (n->n_stclass == ENUM) { error("& enumerator%n",n); return 0; } if (n->tp->base == FIELD) { error("& field%n",n); return 0; } n->n_used--; if (n->n_qualifier) { // oops, not the real one Pname tn = Pclass(n->n_table->t_name->tp)->memtbl->look(n->string,0); n = tn ? tn : n; } n->take_addr(); // suppress hoisting of local consts int statmem = n->n_scope==0 || n->n_scope==PUBLIC || n->n_scope == FCT; if (n->n_evaluated && n->n_scope!=ARG) { // &const if (statmem == 0 && n->n_dcl_printed==0) { n->n_initializer = new ival(n->n_val); n->dcl_print(0); } } else if (f->base==FCT && n->n_dcl_printed==0) n->dcl_print(0); break; } case ASSIGN: //error('d',"ass %n %d",n,n->n_used); n->n_used--; n->assign(); break; // goto check_void; default: /* incr ops, and asops */ if (cc->tot && n==cc->c_this) { error("%n%k",n,oper); return 0; } // check_void: // { Ptype t = n->tp; // while (t->base==TYPE) t = Pbase(t)->b_name->tp; // if (t==Pvoid_type) { // error("%s%t",es,n->tp); // return 0; // } // } n->assign(); } return 1; } } } int char_to_int(char* s) /* assume s points to a string: 'c' or '\c' or '\0' or '\ddd' or multi-character versions of the above (hex constants have been converted to octal by the parser) */ { register int i = 0; register char c, d, e; switch (*s) { default: error('i',"char constant store corrupted"); case '`': error("bcd constant"); return 0; case '\'': break; } for(;;) /* also handle multi-character constants */ switch (c = *++s) { case '\'': return i; case '\\': /* special character */ switch (c = *++s) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': /* octal representation */ c -= '0'; switch (d = *++s) { /* try for 2 */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': d -= '0'; switch (e = *++s) { /* try for 3 */ case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c = c*64+d*8+e-'0'; break; default: c = c*8+d; s--; } break; default: s--; } break; case 'a': c = '\a'; break; case 'b': c = '\b'; break; case 'f': c = '\f'; break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'v': c = '\v'; break; case '\\': c = '\\'; break; case '\'': c = '\''; break; } /* no break */ default: if (i) i <<= BI_IN_BYTE; i += c; } } const A10 = 'A'-10; const a10 = 'a'-10; long str_to_long(register const char* p) { register c; register unsigned long i= 0; const char* pp = p; // error( 'd', "str_to_long: %s", p ); if ((c=*p++) == '0') { switch (c = *p++) { case 0: return 0; case 'l': case 'L': /* long zero */ return 0; case 'x': case 'X': /* hexadecimal */ while (c=*p++) { switch (c) { case 'l': case 'L': case 'U': case 'u': return i; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': i = i*16 + c-A10; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': i = i*16 + c-a10; break; default: i = i*16 + c-'0'; } } return i; default: /* octal */ do switch (c) { case 'l': case 'L': case 'U': case 'u': return i; default: i = i*8 + c-'0'; } while (c=*p++); return i; } } /* decimal */ i = c-'0'; while (c=*p++) switch (c) { case 'l': case 'L': case 'U': case 'u': return i; default: { unsigned long ii = i; i = i*10 + c-'0'; if (i<ii) goto bad; } } return i; bad: error("integer constant %s larger than the largest long",pp); return i; } bit type::is_unsigned() { Ptype t = this; while (t->base==TYPE) t = Pbase(t)->b_name->tp; if (t->base == PTR) return 0; return Pbase(t)->b_unsigned; } char* Neval; bit binary_val; unsigned long expr::ueval(long x1, long x2) { unsigned long i1 = (unsigned long) x1; unsigned long i2 = (unsigned long) x2; //error('d',"ueval %k %ld %ld",base,x1,x2); switch (base) { case UMINUS: return -i2; case UPLUS: return i2; case NOT: return !i2; case COMPL: return ~i2; case CAST: return i1; case PLUS: return i1+i2; case MINUS: return i1-i2; case MUL: return i1*i2; case LS: return i1<<i2; case RS: return i1>>i2; case NE: return i1!=i2; case EQ: return i1==i2; case LT: return i1<i2; case LE: return i1<=i2; case GT: return i1>i2; case GE: return i1>=i2; case AND: return i1&i2; case ANDAND: return i1&&i2; case OR: return i1|i2; case OROR: return i1||i2; case ER: return i1^i2; case MOD: if (i2 == 0) { if (Neval == 0) { Neval = "mod zero"; error("mod zero"); } return 1; } return i1%i2; case QUEST: return (cond->eval()) ? i1 : i2; case DIV: if (i2 == 0) { if (Neval == 0) { Neval = "divide by zero"; error("divide by zero"); } return 1; } return i1/i2; case CM: case G_CM: return i2; } Neval = "unsigned expression"; return 0; } long expr::eval() { if (Neval) return 1; // error('d',"eval %k",base); static int targno=0; static int icallflag=0; switch (base) { case ZERO: return 0; case IVAL: return i1; case ICON: return str_to_long(string); case CCON: return char_to_int(string); case FCON: Neval = "float in constant expression"; return 1; case STRING: Neval = "string in constant expression"; return 1; case EOBJ: return Pname(this)->n_val; case SIZEOF: extern no_sizeof; if (no_sizeof) Neval = "sizeof"; return tp2->tsizeof(); case NAME: { Pname n = Pname(this); // error('d',"eval %n eval %d %d",n,n->n_evaluated,n->n_val); // error('d',"eval tp->tconst() %d, n->n_initializer: %k", n->tp->tconst(), n->n_initializer?n->n_initializer->base:0 ); if (n->n_evaluated && n->n_scope!=ARG) return n->n_val; if (binary_val && strcmp(string,"_result")==0) return 8888; Neval = "cannot evaluate constant"; return 1; } case ICALL: if (e1) { icallflag=1; targno=0; il->i_next = curr_icall; curr_icall = il; long i = e1->eval(); curr_icall = il->i_next; icallflag=0; return i; } Neval = "void inlineF"; return 1; case ANAME: { Pname n = (Pname)this; /* int argno; if (icallflag) { argno=targno; targno++; } */ int argno = (int) n->n_val; Pin il; for (il=curr_icall; il; il=il->i_next) if (il->i_table == n->n_table) goto aok; goto bok; aok: if (il->i_args[argno].local) { bok: Neval = "inlineF call too complicated for constant expression"; return 1; } Pexpr aa = il->i_args[argno].arg; return aa->eval(); } case CAST: { if (e1->base==FCON && tp2->base!=FLOAT && tp2->base!=DOUBLE) { char* p = e1->string; while (*p!='.') p++; if (p==e1->string) *p++ = '0'; *p = 0; e1->base = ICON; } long i = e1->eval(); Ptype tt = tp2; strip: switch (tt->base) { default: Neval = "cast to non-integral type in constant expression"; break; case TYPE: tt = Pbase(tt)->b_name->tp; goto strip; case EOBJ: case LONG: case INT: case CHAR: case SHORT: i &= ~(((~(unsigned long)0)<<(BI_IN_BYTE*(tp2->tsizeof()-1)))<<BI_IN_BYTE); break; } return i; } case UMINUS: case UPLUS: case NOT: case COMPL: case PLUS: case MINUS: case MUL: case LS: case RS: case NE: case LT: case LE: case GT: case GE: case AND: case OR: case ER: case DIV: case MOD: case QUEST: case EQ: case ANDAND: break; case OROR: if (binary_val) { // a||b, don't evaluate b if a!=0 long i1 = (e1) ? e1->eval() : 0; if (Neval==0 && i1 && e1->tp->is_unsigned()==0) return i1; } break; case CM: case G_CM: break; case G_ADDROF: case ADDROF: if (binary_val) { // beware of &*(T*)0 switch (e2->base) { case NAME: case DOT: case REF: return 9999; } } default: Neval = "bad operator in constant expression"; return 1; } long i1 = (e1) ? e1->eval() : 0; long i2 = (e2) ? e2->eval() : 0; if (binary_val && i1==9999 && i2==9999) { Neval = ""; return 1; } if (Neval==0 && ((e1&&e1->tp->is_unsigned()) || (e2&&e2->tp->is_unsigned()))) return (long) ueval(i1,i2); switch (base) { case UMINUS: return -i2; case UPLUS: return i2; case NOT: return !i2; case COMPL: return ~i2; case CAST: return i1; case PLUS: return i1+i2; case MINUS: return i1-i2; case MUL: return i1*i2; case LS: return i1<<i2; case RS: return i1>>i2; case NE: return i1!=i2; case EQ: return i1==i2; case LT: return i1<i2; case LE: return i1<=i2; case GT: return i1>i2; case GE: return i1>=i2; case AND: return i1&i2; case ANDAND: return i1&&i2; case OR: return i1|i2; case OROR: return i1||i2; case ER: return i1^i2; case MOD: if (i2 == 0) { if (Neval == 0) { Neval = "mod zero"; error("mod zero"); } return 1; } return i1%i2; case QUEST: return (cond->eval()) ? i1 : i2; case DIV: if (i2 == 0) { if (Neval == 0) { Neval = "divide by zero"; error("divide by zero"); } return 1; } return i1/i2; case CM: case G_CM: return i2; } } bit classdef::baseof(Pname f) /* is ``this'' class a public base class of "f"'s class or its immediate base class */ { Ptable ctbl = f->n_table; Pname b = ctbl->t_name; if (b == 0) return 0; Pclass cl = Pclass(b->tp); if (cl == 0) return 0; if (cl == this) return 1; ppbase = PUBLIC; Pclass bcl = is_base(cl->string); return (bcl && ppbase==PUBLIC); } bit classdef::baseof(Pclass cl) /* is ``this'' class a public base class of "cl" */ { if (cl == 0) return 0; if (cl == this) return 1; ppbase = PUBLIC; Pclass bcl = is_base(cl->string); return (bcl && ppbase==PUBLIC); } static int mem_match(Pfct f1, Pfct f2) /* check class membership. For some reason checking f_this==0 works and f_static doesn't */ { // if (f1->memof) return f2->f_this ?f2->memof==f1->memof : 0; // if (f1 && f1->memof) return f2->f_this?f2->memof==f1->memof : 0; // return f2->f_this==0; if (f1==0 || f2==0) return 0; if (f1->memof && f2->f_this && f2->memof!=f1->memof) return 0; if (f2->f_this) return 0; if (f1->memof && f2->f_static) return 0; if (f1->check(f2,ASSIGN)) return 0; return 1; } int Pchecked; Pexpr ptof(Pfct ef, Pexpr e, Ptable tbl) /* a kludge: initialize/assign-to pointer to function */ { Pfct f; Pname n = 0; eee: //error('d',"ptof %t %t %k",ef,e->tp,e->base); switch (e->base) { case QUEST: e->e1 = ptof(ef,e->e1,tbl); e->e2 = ptof(ef,e->e2,tbl); return e; case CM: case G_CM: e->e2 = ptof(ef,e->e2,tbl); return e; case NAME: f = Pfct(e->tp); Pname nn = Pname(e); switch (f->base) { case OVERLOAD: e = Pgen(f)->find(ef,0); if (e == 0) { error("cannot deduceT for &overloaded%n",nn); return e; } // e = n; // no break case FCT: Pchecked = mem_match(ef,Pfct(e->tp)); e = new expr(G_ADDROF,0,e); return e->typ(tbl); // handle &B::f //e->tp = f; } goto ad; case ZERO: if (ef->memof) { e = new expr(ELIST,zero,zero); e = new expr(ILIST,e,zero); e->tp = zero_type; return e; } break; case MDOT: // ?? error('s',"P toM of not firstB"); do e = e->mem; while (e->base == MDOT); goto eee; case DOT: case REF: f = Pfct(e->mem->tp); switch (f->base) { case OVERLOAD: n = Pgen(f)->find(ef,0); if (n == 0) error("cannot deduceT for &overloaded%n",e->mem); else e = n; // no break case FCT: Pchecked = mem_match(ef,Pfct(e->tp)); e = new expr(G_ADDROF,0,e); return e->typ(tbl); // handle &B::f // n = Pname(e->mem); // e = n->address(); } goto ad; case ADDROF: case G_ADDROF: f = Pfct(e->e2->tp); ad: if (f->base == OVERLOAD) { n = Pgen(f)->find(ef,0); if (n == 0) error("cannot deduceT for &overloaded %s()",Pgen(f)->fct_list->f->string); Pchecked = mem_match(ef,Pfct(n->tp)); e->e2 = n; e->tp = n->tp; } if (n) n->lval(ADDROF); break; case CAST: { Pexpr te = e->e1; if (e->e1->base == G_ADDROF) te = e->e1->e2; (void) ptof(ef,te,tbl); } } return e; } Pexpr ptr_init(Pptr p, Pexpr init, Ptable tbl) /* check for silly initializers char* p = 0L; ?? fudge to allow redundant and incorrect `L' char* p = 2 - 2; ?? worse */ { // error('d',"ptr_init: p=%t init->tp=%t init->base %k",p,init->tp,init->base); Pchecked = 0; Ptype it = init->tp; itl: switch (it->base) { case TYPE: it = Pbase(it)->b_name->tp; goto itl; case ZTYPE: // if (init == zero) break; break; case EOBJ: case INT: case CHAR: case SHORT: case LONG: { Neval = 0; long i = init->eval(); if (Neval) error("badPIr: %s",Neval); else if (i) error("badPIr value %d",i); else { DEL(init); init = zero; } break; } } Pclass c1 = p->memof; if (c1) { if (init==zero) ; else { Pclass c2; // error('d',"it %t %d",it,it->base); switch (it->base) { case FCT: c2 = Pfct(it)->memof; break; case OVERLOAD: c2 = Pfct(Pgen(it)->fct_list->f->tp)->memof; break; case PTR: case RPTR: c2 = Pptr(it)->memof; break; default: c2 = 0; } if (c2 == 0) { // initialization by &A::f //error('d',"curious"); } else if (c1 != c2) { Nptr = 0; Noffset = 0; vcllist->clear(); vcllist=0; int u1 = is_unique_base(c1,c2->string,0); //error('d',"c1 %t c2 %t u1 %d off %d",c1,c2,u1,Noffset); if (u1 && (Nptr || Noffset)) { // requires offset manipulation int bad = 0; if (u1 == 1 && !Nptr) { if (init->base==ILIST) { // d = d+Noffset; switch (init->e1->e1->base) { case IVAL: init->e1->e1->i1 += Noffset; break; case ZERO: init->e1->e1 = new ival(Noffset); break; default: bad = 1; } // if (i<0) f = vptroffset switch (init->e1->e2->base) { case IVAL: if (0<init->e1->e2->i1) { // extern Ptype Pfct_type; // store vptr offset // init->e2=new cast(Pfct_type,zero); } else break; default: bad = 1; } } // end if (init->base==ILIST) else bad = 1; } // end if (u1 == 1 ... else bad = 1; if (bad) error('s',"%t assigned to %t (too complicated)",init->tp,p); } // end if (u1 && ... Nptr = 0; Noffset = 0; vcllist->clear(); vcllist=0; int u2 = is_unique_base(c2,c1->string,0); //error('d',"c1 %t c2 %t u2 %d off %d",c1,c2,u2,Noffset); if (u2 && (Nptr || Noffset)) { // requires offset manipulation error('s',"%t assigned to %t",init->tp,p); } } // end if (c1 != c2 } // end else } // end if (c1) Ptype pit = p->typ; lll: // error('d',"p %t pit %t",p,pit); switch (pit->base) { case TYPE: pit = Pbase(pit)->b_name->tp; goto lll; case FCT: return ptof(Pfct(pit),init,tbl); case COBJ: { Pptr r; // error('d',"cobj: ptr %t, ref %t",it->is_ptr(),it->is_ref()); if (r=it->is_ptr_or_ref()) { Pchecked = 1; TOK b = p->base; // could be REF TOK bb = r->base; if (b==RPTR) p->base = PTR; if (bb==RPTR) r->base = PTR; if (p->check(r,ASSIGN)) { if ( cc && cc->nof && Pfct(cc->nof->tp)->f_const && cc->c_this == init ) error("%n const: assignment of%n (%t) to%t",cc->nof,init,init->tp,p); else error("no standard conversion of %t to %t",init->tp,p); } p->base = b; r->base = bb; Pexpr cp = cast_cptr(Pclass(Pbase(pit)->b_name->tp),init,tbl,0); if (cp != init) { PERM(p); // or else it will be deleted twice! return new cast(p,cp); } } // no break } default: return init; } } static Pname Lcoerce, Rcoerce; extern int suppress_error; int try_to_demote(TOK oper, Ptype t1, Ptype t2) /* look at t1 and t2 and see if there are ``demotions'' of t1 and/or t2 so that ``t1 oper t2'' can be made legal return 0 is not 1 if there is exactly one way >1 if there is more than one way (if in doubt return 2) */ { //error('d',"try_to_demote(%k : %t : %t)",oper,t1,t2); Pname n1 = t1 ? t1->is_cl_obj() : 0; Pclass c1 = n1 ? Pclass(n1->tp) : 0; Pname n2 = t2 ? t2->is_cl_obj() : 0; Pclass c2 = n2 ? Pclass(n2->tp) : 0; Ptype lt = t1; Ptype rt = t2; Lcoerce = Rcoerce = 0; // if (oper == DOT) return 0; if (c1) switch (oper) { case ASSIGN: case ASPLUS: case ASMINUS: case ASMUL: case ASDIV: case ASMOD: case ASAND: case ASOR: case ASER: case ASLS: case ASRS: // don't coerce left hand side of assignment // c1 = 0; if (c1->memtbl->look("__as",0)) return 0; } else switch (oper) { case ADDROF: case INCR: case DECR: // don't coerce unary requiring an lval return 0; } if (c1) { //error('d',"c1 %t",c1); for (Pname on1 = c1->conv; on1; on1=on1->n_list) { // error( 'd', "on1: %s tp: %k", on1->string, on1->tp->base ); Pfct f = Pfct(on1->tp); lt = f->base==FCT ? f->returns : Pfct(Pgen(on1->tp)->fct_list->f->tp)->returns; Pname cn = lt->is_cl_obj(); if (cn && (Lcoerce==0 || Lcoerce->tp->check(f,0))) { Pclass cl = Pclass(cn->tp); Pname n = cl->has_oper(oper); if (n == 0) continue; // while (n->base==REF || n->base==MDOT) n=Pname(n->mem) ; Pfct nf = Pfct(n->tp); // error( 'd', "nf: %d %k", nf->base, nf->base ); if (nf->base == FCT) { if (nf->nargs==1 && t2 && (nf->argtype->tp->check(t2,ARG)==0 || can_coerce(nf->argtype->tp,t2)==1) ) { if (Lcoerce) return 2; Lcoerce = on1; } } else { for (Plist gl=Pgen(nf)->fct_list; gl; gl=gl->l) { Pfct nf = Pfct(gl->f->tp); if (nf->nargs==1 && t2 && (nf->argtype->tp->check(t2,ARG)==0 || can_coerce(nf->argtype->tp,t2)==1) ) { if (Lcoerce) return 2; Lcoerce = on1; } } } continue; } //if (lt->is_cl_obj()) continue; if (c2) { //error('d',"c2 %t",c2); for (Pname on2 = c2->conv; on2; on2=on2->n_list) { Pfct f = Pfct(on2->tp); rt = f->base==FCT ? f->returns : Pfct(Pgen(on2->tp)->fct_list->f->tp)->returns; if (rt->is_cl_obj()) continue; suppress_error = 1; int r1 = lt->kind(oper,0); int r2 = rt->kind(oper,0); if (np_promote(oper,r1,r2,lt,rt,1)!=any_type) { Pname sn = on1; if (Lcoerce) { Pname tn = really_dominate( Lcoerce, on1, const_obj1 ); if(!tn) { suppress_error = 0; return 2; } else sn = tn; } Lcoerce = sn; Rcoerce = on2; } suppress_error = 0; } } else if (rt) { suppress_error = 1; int r1 = lt->kind(oper,0); int r2 = rt->kind(oper,0); if (np_promote(oper,r1,r2,lt,rt,1)!=any_type) { Pname sn = on1; if (Lcoerce) { Pname tn = really_dominate( Lcoerce, on1, const_obj1 ); if(!tn) { suppress_error = 0; return 2; } else sn = tn; } Lcoerce = sn; } suppress_error = 0; } else { Pname sn = on1; if (Lcoerce) { Pname tn = really_dominate( Lcoerce, on1, const_obj1 ); if(!tn) return 2; else sn = tn; } Lcoerce = sn; } } } else if (c2) { //error('d',"c2 %n",c2); for (Pname on = c2->conv; on; on=on->n_list) { Pfct f = Pfct(on->tp); rt = f->base==FCT ? f->returns : Pfct(Pgen(on->tp)->fct_list->f->tp)->returns; Pname cn = rt->is_cl_obj(); //error('d',"cn %n",cn); if (cn && (Rcoerce==0 || Rcoerce->tp->check(f,0))) { Pclass cl = Pclass(cn->tp); Pname n = cl->has_oper(oper); if (n == 0) continue; // while (n->base==REF || n->base==MDOT) n=Pname(n->mem); Pfct nf = Pfct(n->tp); if (nf->base == FCT) { if (nf->nargs == 0) { if (Lcoerce || Rcoerce) return 2; Rcoerce = on; } } else { for (Plist gl=Pgen(nf)->fct_list; gl; gl=gl->l) if (Pfct(gl->f->tp)->nargs == 0) { if (Lcoerce || Rcoerce) return 2; Rcoerce = on; } } continue; } //if (rt->is_cl_obj()) continue; if( lt ) { suppress_error = 1; int r1 = lt->kind(oper,0); int r2 = rt->kind(oper,0); if (np_promote(oper,r1,r2,lt,rt,1)!=any_type) { Pname sn = on; if (Lcoerce || Rcoerce) { Pname tn = really_dominate( Rcoerce, on, const_obj2 ); if(!tn) { suppress_error = 0; return 2; } else sn = tn; } Rcoerce = sn; } suppress_error = 0; } } } //error('d',"->%d || %d",Lcoerce,Rcoerce); return (Lcoerce || Rcoerce); } Pexpr expr::try_to_overload(Ptable tbl) { // TOK bb = (base==DEREF && e2==0) ? MUL : base; // error('d',"try_to_overload %k %d",base,base); Pname n1 = 0; Ptype t1 = 0; const_obj1 = 0; const_obj2 = 0; if (e1) { t1 = e1->tp; Ptype tpx = t1; while (tpx->base == TYPE) tpx = Pbase(tpx)->b_name->tp; n1 = tpx->is_cl_obj(); const_obj1 = t1->tconst(); Pexpr ee = e1; while (ee && (ee->base==DOT || ee->base==REF)) { Pexpr m = ee->mem; if ( ee->base==REF && m->tp && m->tp->is_ptr()) break; ee = ee->e1; } if (ee) { int tc; Ptype ttt = ee->tp; switch (e1->base) { case REF: Pptr p = ttt?ttt->is_ptr():0; if (p && p->typ->tconst()) const_obj1 = 1; break; case DOT: tc = ttt ? ttt->tconst() : 0; if (ttt && tc && (!strict_opt || tc!=2)) const_obj1 = 1; } } } TOK bb = base; switch (bb) { case DEREF: if (e2 == 0) bb = MUL; // no break; case CALL: case G_CALL: if (n1 == 0) return 0; // ignore type of argument list } Pname n2 = 0; Ptype t2 = 0; if (e2 && e2->base!=ELIST) { t2 = e2->tp; Ptype tpx = t2; while (tpx->base == TYPE) tpx = Pbase(tpx)->b_name->tp; n2 = tpx->is_cl_obj(); const_obj2 = t2->tconst(); Pexpr ee = e2; while (ee && (ee->base==DOT || ee->base==REF)) { Pexpr m = ee->mem; if ( ee->base==REF && m->tp && m->tp->is_ptr()) break; ee = ee->e1; } if (ee) { int tc; Ptype ttt = ee->tp; switch (e2->base) { case REF: Pptr p = ttt?ttt->is_ptr():0; if (p && p->typ->tconst()) const_obj2 = 1; break; case DOT: tc = ttt ? ttt->tconst() : 0; if (ttt && tc && (!strict_opt || tc!=2)) const_obj2 = 1; } } } if (n1==0 && n2==0) return 0; if (n1 && n1->tp == 0) return 0; // make_assign() fudge // error('d',"e1: %k e2: %k", e1?e1->base:0, e2?e2->base:0 ); // error('d',"t1 %t t2 %t",t1,t2); // error('d',"n1 %n n2 %n",n1,n2); /* first try for non-member function: op(e1,e2) or op(e2) or op(e1) */ Pexpr oe2 = e2; Pexpr ee2 = (e2 && e2->base!=ELIST) ? e2 = new expr(ELIST,e2,0) : 0; Pexpr ee1 = e1 ? new expr(ELIST,e1,e2) : ee2; char* obb = oper_name(bb); Pname gname = tbl->look(obb,0); // if necessary check for ambiguities int go = gname ? over_call(gname,ee1) : 0; //error('d',"go %d",go); if (go) gname = Nover; if (n1) { if (bb == ASSIGN) { Pclass c1 = Pclass(n1->tp); //error('d',"look %k %d",bb,c1->memtbl->look(obb,0)); if (c1->memtbl->look(obb,0)==0) { Pclass bcl = c1->baselist?c1->baselist->bclass:0; if (n2==0 || (Pclass(n2->tp)!=c1 && Pclass(n2->tp)->has_base(c1)==0)) { // if legal, a=1 can be optimized to a.ctor(1) if (2 < go) goto glob; return 0; } if (bcl && c1->obj_size!=bcl->obj_size && bcl->memtbl->look(obb,0)) { // cannot inherit from smaller base class // make_assignment(n1); // return try_to_overload(tbl); goto mkas; } if (c1->c_xref&(C_VBASE|C_VPTR|C_ASS)) { // make operator=() if // no base (shouldn't happen // different (smaller) sized base // two bases mkas: if (2 < go) goto glob; // make_assignment(n1); // return try_to_overload(tbl); return make_assignment(n1) ? try_to_overload(tbl) : 0; } // error('d',"n2 %n",n2); // if (n2 && Pclass(n2->tp)==c1) return 0; } // now take care of other assignments, } int dbconv = 0; Pclass ccl = Pclass(n1->tp); // Pexpr mn = Pclass(n1->tp)->memtbl->look(obb,0); Pexpr mn = ccl->memtbl->look(obb,0); // error('d', "tcl %d %t cl %d %t", tcl, tcl, ccl, ccl); if(strcmp(obb,"__as")) { tcl = ccl; // ugh!!! if(!mn) dbconv = 2; } // tcl = ccl; // ugh!!! mn = ccl->find_name(obb,0); Pname mname = Pname(mn); // error('d',"mn %n %d %k %s",mname,mn,mn?mn->base:0,obb); if (mname == 0) goto glob; zaq: switch (mname->base) { case REF: case MDOT: mname = Pname(Pexpr(mname)->mem); goto zaq; } int mo = over_call(mname,e2); int smo = mo; if(mo && dbconv && mo >= dbconv) mo = dbconv; //error('d',"mo %d (go %d)",mo,go); if (mo==0 || mo<go) goto glob; else if (mo && mo==go) { //error('d',"t1 %t t2 %t",t1,t2); if (gname->tp->base == OVERLOAD) { // find right version for (Plist l = Pgen(gname->tp)->fct_list; l; l=l->l) { Pname n = l->f; int x = over_call(n,ee1); if (x == go) { gname = n; break; } } } //error('d',"gname %n: %t",gname,gname->tp); Pname aa = Pfct(gname->tp)->argtype; Pptr p; Ptype gt1 = aa->tp; if (p = gt1->is_ref()) gt1 = p->typ; Ptype gt2 = aa->n_list->tp; //error('d',"gt1 %t gt2 %t",gt1,gt2); if (mname->tp->base == OVERLOAD) { // find right version for (Plist l = Pgen(mname->tp)->fct_list; l; l=l->l) { Pname n = l->f; int x = over_call(n,e2); if (x == smo) { mname = n; break; } } } //error('d',"mname %n: %t",mname,mname->tp); Ptype mt1 = Pfct(mname->tp)->f_this->tp; mt1 = Pptr(mt1)->typ; Ptype mt2 = Pfct(mname->tp)->argtype->tp; //error('d',"mt1 %t mt2 %t",mt1,mt2); Pname mm = new name; Pname a1 = new name; a1->tp = mt1; Pname a2 = new name; a2->tp = mt2; a1->n_list = a2; mm->tp = new fct(void_type,a1,2); Pname gg = new name; Pname a3 = new name; a3->tp = gt1; Pname a4 = new name; a4->tp = gt2; a3->n_list = a4; gg->tp = new fct(void_type,a3,1); extern Pname dominate(Pname,Pname,Pexpr,int,int); aa = dominate(gg,mm,ee1,0,1); delete a1; delete a2; delete a3; delete a4; DEL( gg->tp ); DEL( mm->tp ); //delete gg->tp; //delete mm->tp; if (aa == 0) { delete gg; delete mm; error("ambiguous operandTs%n and%t for%k",n1,t2,bb); tp = any_type; return this; } else if (aa == gg) { delete gg; delete mm; goto glob; } delete gg; delete mm; } else if (mo < 2) { // user-defined conversion user if (try_to_demote(bb,t1,t2)) error("ambiguous use of overloaded%k",bb); } base = G_CALL; // e1.op(e2) or e1.op() Pname xx = new name(mname->string); // do another lookup // . suppresses virtual e1 = new ref(DOT,e1,xx); if (ee1) delete ee1; return typ(tbl); } if (n2 && e1==0) { /* look for unary operator */ suppress_error++; Pexpr mn = Pclass(n2->tp)->find_name(obb,0); suppress_error--; Pname mname = Pname(mn); if (mname == 0) goto glob; zaqq: switch (mname->base) { case REF: case MDOT: mname = Pname(Pexpr(mname)->mem); goto zaqq; } switch (mname->n_scope) { default: goto glob; case 0: case PUBLIC: break; // try e2.op() } int mo = over_call(mname,0); //error('d',"e2 mo %d (go %d)",mo,go); if (mo==0 || mo<go) goto glob; else if (mo==go) { error("ambiguous operandT%n for%k",n2,bb); tp = any_type; return this; } else if (mo < 2) { // user-defined conversion user if (try_to_demote(bb,t1,t2)) error("ambiguous use of overloaded%k",bb); } base = G_CALL; // e2.op() Pname xx = new name(Nover->string); // do another lookup // . suppresses virtual e1 = new ref(DOT,oe2,xx); e2 = 0; if (ee2) delete ee2; if (ee1 && ee1!=ee2) delete ee1; return typ(tbl); } glob: // error('d',"glob %d",go); if (go) { if (go < 2) { // user-defined conversion necessary => binary if (try_to_demote(bb,t1,t2)) error("ambiguous use of overloaded%k: %t and %t",bb,t1,t2); } base = gname->n_table == gtbl ? G_CALL : CALL; //error('d',"gname %n %t",gname,gname->tp); e1 = new name(gname->string); // if global scope, look only for globals if(gname->n_table == gtbl) Pname(e1)->n_qualifier = sta_name; e2 = ee1; return typ(tbl); } if (ee2) delete ee2; if (ee1 && ee1!=ee2) delete ee1; e2 = oe2; // error('d',"bb %d %k",bb,bb); switch (bb) { case CM: case G_CM: case G_ADDROF: return 0; case ASSIGN: if (n1 && n2 && (n1->tp==n2->tp || Pclass(n2->tp)->has_base(Pclass(n1->tp)))) { if (make_assignment(n1)) return try_to_overload(tbl); else return 0; } case DEREF: case CALL: if (n1 == 0) break; default: /* look for conversions to basic types */ if (n1 && Pclass(n1->tp)->conv && (bb==ANDAND || bb==OROR)) { e1 = check_cond(e1,bb,tbl); return 0; } if (n2 && Pclass(n2->tp)->conv && (bb==ANDAND || bb==OROR || bb==NOT || bb==UMINUS || bb==UPLUS || bb==COMPL)) { e2 = check_cond(e2,bb,tbl); return 0; } // error( 'd', "bb: %k t1: %k t2: %k", bb, t1?t1->base:0, t2?t2->base:0 ); switch (try_to_demote(bb,t1,t2)) { default: if (Lcoerce) error("ambiguous conversion of%n",n1); if (Rcoerce) error("ambiguous conversion of%n",n2); case 0: break; case 1: if (Lcoerce) { Pname xx = new name(Lcoerce->string); Pref r = new ref(DOT,e1,xx); e1 = new expr(G_CALL,r,0); } if (Rcoerce) { Pname xx = new name(Rcoerce->string); Pref r = new ref(DOT,e2,xx); e2 = new expr(G_CALL,r,0); } return typ(tbl); } switch (bb) { case CM: case ADDROF: // has legal built-in meaning return 0; } if (t1 && t2) error("bad operandTs%t%t for%k",t1,t2,bb); else error("bad operandT%t for%k",t1?t1:t2,bb); tp = any_type; return this; } return 0; } Pexpr cast_cptr(Pclass ccl, Pexpr ee, Ptable tbl, int real_cast) /* "ee" is being cast to pointer object of class "ccl" if necessary modify "ee" */ { // Ptype etp = ee->tp; // error('d',"cast_cptr %k ccl %t ee->tp %t",ee->tp->base,ccl,ee->tp); // if (etp->base!=PTR && etp->base!=RPTR) return ee; Ptype etp = ee->tp->is_ptr_or_ref(); if (etp == 0) return ee; Pname on = Pptr(etp)->typ->is_cl_obj(); if (on == 0) return ee; Pclass ocl = Pclass(on->tp); if (ocl==ccl || ccl==0 || ocl==0) return ee; // error('d',"cast_cptr %t(%t) real %d",ccl,ocl,real_cast); int oo = 0; Pexpr r = 0; if (ocl->baselist && (ocl->baselist->bclass!=ccl || ocl->baselist->base!=NAME)) { // casting derived to second or virtual base? Nptr = 0; Nvis = 0; Nalloc_base = 0; vcllist->clear(); vcllist=0; int x = is_unique_base(ocl,ccl->string,0); if (Nvis) { if (real_cast==0) error("cast:%n* ->B%t*; privateBC",on,ccl); else if (warning_opt) error('w',"cast:%n* ->B%t*; privateBC",on,ccl); real_cast = 1; // suppress further error mesages Nvis = 0; } switch (x) { default: error("cast:%n* ->B%t*;%t isB more than once",on,ccl,ccl); case 0: // unrelated; break; case 1: oo = Noffset; break; } if (Nptr) { // => ee?Nptr:0 if (ocl->c_body==1) ocl->dcl_print(0); Nptr->mem = ee; // ee->Pbase_class if ( Nalloc_base ) { // error('d', "cast_cptr: nalloc_base: %s", Nalloc_base); Nptr->i1 = 5; Nptr->string4 = new char[strlen(Nalloc_base)]; strcpy(Nptr->string4,Nalloc_base); Nalloc_base = 0; } else Nptr->i1 = 3; if (ee->base==ADDROF || ee->base==G_ADDROF) ee = Nptr; else { Pexpr p = new expr(QUEST,Nptr,zero); nin = 1; if (ee->not_simple()) { // need temp Ptype t = ee->tp; Pname pp = make_tmp('N',t,tbl); Pname(pp)->n_assigned_to = 1; ee = new expr(ASSIGN,pp,ee); ee->tp = t; Nptr->mem = pp; } nin = 0; p->cond = ee; p->tp = ee->tp; ee = p; } } } if (ccl->baselist && (ccl->baselist->bclass!=ocl || ccl->baselist->base!=NAME)) { // casting second or virtual base to derived? Nptr = 0; vcllist->clear(); vcllist=0; int x = is_unique_base(ccl,ocl->string,0); switch (x) { default: error("cast:%n* ->derived%t*;%n isB more than once",on,ccl,on); case 0: // unrelated; break; case 1: oo = -Noffset; if (Nptr) error("cast:%n* ->derived%t*;%n is virtualB",on,ccl,on); break; } Nvis = 0; // visibility no concern when converting from base to derived } // error('d',"oo %d ee %k",oo,ee->base); if (oo) { // => ee?ee+offset:0 if (ee->base==ADDROF || ee->base==G_ADDROF) ee = rptr(ee->tp,ee,oo); else { Pexpr p; nin = 1; if (ee->not_simple()) { // need temp Ptype t = ee->base==MDOT?ee->mem->tp:ee->tp; Pname pp = make_tmp('M',t,tbl); Pname(pp)->n_assigned_to = 1; ee = new expr(ASSIGN,pp,ee); ee->tp = t; p = rptr(t,pp,oo); } else p = rptr(ee->base==MDOT?ee->mem->tp:ee->tp,ee,oo); nin = 0; Pexpr pp = new expr(QUEST,p,zero); pp->tp = ee->tp; pp->cond = ee; ee = pp; } } Nvis = 0; // Nvis set by has_base() if (ocl->has_base(ccl) && Nvis) { if (real_cast==0) error("cast:%n* ->B%t*; privateBC",on,ccl); else if (warning_opt) error('w',"cast:%n* ->B%t*; privateBC",on,ccl); Nvis = 0; } // error('d',"return %d %k %t",ee,ee->base,ee->tp); return ee; } Pexpr expr::donew(Ptable tbl) { Ptype tt = tp2; Ptype tpx = tt; bit v = 0; bit old = new_type; int init = 0; // non-constructor initialization new_type = 1; tt->dcl(tbl); new_type = old; // error('d',"donew %d %d (%k) tt %t",e1,e2,e2?e2->base:0,tt); if (e1) e1 = e1->typ(tbl); if (e2) e2 = e2->typ(tbl); ll: //error('d',"ll %d",tt->base); switch (tt->base) { default: if ( e1) { if (v) { error("Ir for array created using \"new\""); break; } init = 1; } // if (e1) { // error("Ir for nonCO created using \"new\""); // e1 = 0; // } break; case VEC: if (v && Pvec(tt)->dim) error("only 1st array dimension can be non-constant"); if (Pvec(tt)->size==0 && Pvec(tt)->dim==0) error("array dimension missing in `new'"); // if (Pvec(tt)->dim==zero) { // Pvec(tt)->size = 0; // Pvec(tt)->dim = 0; // } v++; tt = Pvec(tt)->typ; goto ll; case TYPE: tt = Pbase(tt)->b_name->tp; goto ll; case VOID: error("badT for `new': void"); break; case COBJ: { Pname cn = Pbase(tt)->b_name; Pclass cl = Pclass(cn->tp); Pname icn = 0; if ( e1 ) { // arguments if ( e1->e2 == 0 && e1->base == ELIST ) { e1 = e1->e1; e1 = e1->typ(tbl); } icn = (e1->base!=ELIST)?e1->tp->is_cl_obj():0; } //Pname icn = (e1 && e1->base!=ELIST)?e1->tp->is_cl_obj() : 0; Pclass icl = icn ? Pclass(icn->tp) : 0; if (cl->c_abstract) { error("`new' of abstractC%t",cl); break; } if (v && e1) { error("Ir for array ofCO created using \"new\""); break; } if ((cl->defined&(DEFINED|SIMPLIFIED)) == 0) { error("new%n;%n isU",cn,cn); break; } Pname ctor = cl->has_ctor(); if (ctor) { if (v) { Pname ic; if ((ic = cl->has_ictor())==0) { error("array ofC%n that does not have aK taking noAs",cn); break; } if (Pfct(ic->tp)->nargs) { error("defaultAs forK for array ofC%n",cn); break; } } if (icl && cl->has_itor()==0 // incomplete: // what if X(Y&) exists // for class Y : X ? && (icl==cl || icl->has_base(cl))) { init = 1; break; } e1 = call_ctor(tbl,0,ctor,e1); } else if (e1) { if (icl==cl || icl->has_base(cl)) init = 1; else error("new%n(As ); %n does not have aK",cn,cn); } } } if (init) { Pname tmp = make_tmp('N',tt->addrof(),tbl); e1 = e1->typ(tbl); if (tt->check(e1->tp,ASSIGN)) error("badIrT %t for new operator (%t X)",e1->tp,tt); e1 = new expr(0,tmp,e1); tmp->assign(); } // tp = (v) ? tpx : tpx->addrof(); switch (v) { case 0: tp = tpx->addrof(); break; case 1: tp = tpx; break; default: tp = tpx; } //error('d',"donew(%d) -> %t",v,tp); return this; } static is_dataMemPtr( Pexpr ee ) /* this is utterly implementation dependent * called by expr::lval to determine * const objects bounds to pointers to data members */ { Pexpr te = ee->e1; if ( te == 0 ) return 0; if ( te->base != PLUS ) return 0; if ( (te = te->e2) == 0 ) return 0; if ( te->base != MINUS ) return 0; if ( (te = te->e1) == 0 ) return 0; if ( te->base != CAST ) return 0; if ( (te = te->e1) == 0 ) return 0; if ( te->tp->base != PTR ) return 0; if ( Pptr(te->tp)->memof == 0 ) return 0; return 1; }