/*ident "@(#)cls4:src/expr2.c 1.29" */ /******************************************************************************* 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. expr2.c: type check expressions ************************************************************************/ #include "cfront.h" #include "size.h" #include "overload.h" #include "template.h" static int const_obj1,const_obj2; static void opov_error(Ptype, Ptype, TOK); static Pname compare_builtin(Ptype, Ptype, Pname, Pname, Pname, int); extern int oper_okay(Ptype, TOK); extern Pname best_conv(const Block(Pname)&, Pname&, int&, bit); Pname really_dominate(Pname on1, Pname on2, bit tc) { Pname best = hier_dominates(on1,on2); if (best) return best; Pfct f1 = on1->get_fct(); Pfct f2 = on2->get_fct(); Ptype t1=f1->returns->skiptypedefs(); Ptype t2=f2->returns->skiptypedefs(); if (t1->is_ref()) t1 = Pptr(t1)->typ; if (t2->is_ref()) t2 = Pptr(t2)->typ; if (!t1 || !t2 || (t1->check(t2,OVERLOAD) && !const_problem) || ( t1->is_ref() && t2->is_ref() && Pptr(t1)->typ->check(Pptr(t2)->typ,OVERLOAD) && !const_problem ) || ( t1->is_ptr() && t2->is_ptr() && Pptr(t1)->typ->check(Pptr(t2)->typ,OVERLOAD) && !const_problem ) ) { return 0; } // 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; 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->skiptypedefs(); switch (t->base) { 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) if ( (warning_opt) && (! n_addr_taken) && (tp) && (tp->base==FCT) && fct_type()->f_inline) error('w',"can't take address of inlineF%n,%n not inlined", this, this); n_addr_taken++; if ( n_sto == EXTERN && tp ) { Ptype t = tp->skiptypedefs(); 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 int 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) { char *ms = vec_const?"array":fct_const?"function":"const type"; if (base == NAME) { if (vec_const && Pname(this)->n_scope==ARG) break; error("%s%s%n",es,ms,this); } else error("%s%s",es,ms); } 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: case G_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->skiptypedefs(); switch (p->base) { case PTR: case VEC: break; case ANY: return 0; default: error('i',"expr::lval%t ->%n",p,n); } if (ignore_const==0 && Pptr(p)->typ->tconst()) { switch (oper) { case 0: case ADDROF: case G_ADDROF: case DEREF: 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: { if (n->n_sto == REGISTER) { if (warning_opt) error('w',"& register%n",n); // return 0; n->n_sto = 0; n->n_stclass = AUTO; } if (n->tp == 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 (n->tp->base==FCT && n->n_dcl_printed==0) { Pfct f = Pfct(n->tp); if (f->fct_base == INSTANTIATED) current_fct_instantiation = f; if (!f->fct_base || f->fct_base == INSTANTIATED) n->dcl_print(0); if (f->fct_base == INSTANTIATED) current_fct_instantiation = 0; } break; } case ASSIGN: //error('d',"ass %n %d",n,n->n_used); n->n_used--; n->assign(); break; case INCR: case DECR: if (n->tp->skiptypedefs()->base == EOBJ) { error("%s enum",es); return 0; } // no break default: /* incr ops, and asops */ if (cc->tot && n==cc->c_this) { error("%n%k",n,oper); 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 int A10 = 'A'-10; const int a10 = 'a'-10; long str_to_long(register const char* p) { register int c,j; register int dotflag=0; register int dotcount=0; register long exp=0; 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; case '.': dotflag=1; break; case 'e': case 'E': /* scientific notation */ { int negative = 1; if (*p == '+' || *p == '-') negative = (*p++ == '-' ? -1 : 1); exp=str_to_long(p)*negative; exp=exp-dotcount; if (exp >= 1) { unsigned long ii = i; for (j=0;exp>j;j++, ii=i) { i = i*10; if (ibase == 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: case G_CAST: return i1; case PLUS: return i1+i2; case MINUS: return i1-i2; case MUL: return i1*i2; case LS: return i1<>i2; case NE: return i1!=i2; case EQ: return i1==i2; case LT: return i1i2; 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); Ptype tt; 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 int no_sizeof; if (no_sizeof) Neval = "sizeof"; char *cese = "cannot evaluate sizeof expression"; if (!tp2) { Neval = cese; return 1; } else { tt = tp2; while (tt && tt->vec_type()) { // ANY,VEC,PTR,RPTR tt = tt->skiptypedefs(); if (tt->base==ANY) { Neval = cese; return 1; } tt = (tt->base==VEC) ? Pvec(tt)->typ : Pptr(tt)->typ; } } 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) { il->i_next = curr_icall; curr_icall = il; long i = e1->eval(); curr_icall = il->i_next; return i; } Neval = "void inlineF"; return 1; case ANAME: { Pname n = (Pname)this; 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[n->argno].local) { bok: Neval = "inlineF call too complicated for constant expression"; return 1; } Pexpr aa = il->i_args[n->argno].arg; return aa->eval(); } case CAST: case G_CAST: { if (tp2->base!=FLOAT && tp2->base!=DOUBLE && (e1->base==FCON || (e1->base==UMINUS || e1->base==UPLUS) && e1->e2->base==FCON)) { char*& str = (e1->base==FCON ? e1->string : e1->e2->string); char* p = str; while (*p && *p!='.' && *p!='E' && *p!='e') p++; if (*p) { if ((strchr(p,'E')==0) && (strchr(p,'e')==0)) { if (p==str) *p++ = '0'; *p = 0; } else { ftp_normalize(str); } } if (e1->base == FCON) e1->base = ICON; else e1->e2->base = ICON; } long i = e1->eval(); tt = tp2->skiptypedefs(); switch (tt->base) { default: Neval = "cast to non-integral type in constant expression"; break; case ENUM: case EOBJ: case LONG: case INT: case CHAR: case SHORT: { long j = (((~(unsigned long)0)<<(BI_IN_BYTE*(tp2->tsizeof()-1)))<is_unsigned()==0) if (long((i<<(BI_IN_BYTE*(sizeof(long)-tp2->tsizeof())))) < 0) i |= j; 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: Neval = "comma operator in constant expression"; return 1; 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&&e1->tp->is_unsigned() || e2&&e2->tp&&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: case G_CAST: return i1; case PLUS: return i1+i2; case MINUS: return i1-i2; case MUL: return i1*i2; case LS: return i1<>i2; case NE: return i1!=i2; case EQ: return i1==i2; case LT: return i1i2; 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; } error('i', "fall off end of expr::eval()"); return 0; } #if 0 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 (::same_class(cl,this)) return 1; ppbase = PUBLIC; Pclass bcl = is_base(cl->string); return (bcl && ppbase==PUBLIC); } #endif bit classdef::baseof(Pclass cl) /* is ``this'' class a public base class of "cl" */ { if (cl == 0) return 0; if (::same_class(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 && !same_class(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; static Pexpr return_elist(Pname args) { /* make a list of expressions out of a function argument list */ Pexpr head=0, tail=0; for (Pname n=args; n; n=n->n_list) { Pexpr e = new expr(ELIST,n,0); if (head==0) head = e; if (tail) tail->e2 = e; tail = e; } return head; } 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); if (e->tp && e->tp->base == FCT) e->tp = e->e2->tp; return e; case NAME: f = Pfct(e->tp); n = Pname(e); switch (f->base) { case OVERLOAD: e = Pgen(f)->find(ef,0); if (e == 0 && n->is_template_fct()) { Pexpr arg = return_elist(ef->argtype); e = has_templ_instance(n,arg); } if (e == 0) { error("cannot deduceT for &overloaded%n",n); return e; } // no break case FCT: // if (f->base == FCT && f->is_templ()) { if (f->base == FCT && f->fct_base == FCT_TEMPLATE) { Pexpr arg = return_elist(ef->argtype); e = has_templ_instance(n,arg); if (e==0) return e; // error already reported } 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); n = Pname(e->e2); // error('d',"ptof: address_of!!! f: %t n: %n ", f,n); ad: if (f->base == OVERLOAD) { Pname nn = Pgen(f)->find(ef,0); if (nn == 0 && n->is_template_fct()) { Pexpr arg = return_elist(ef->argtype); nn = has_templ_instance(n,arg); } if (nn == 0) { error("cannot deduceT for &overloaded %s()",Pgen(f)->fct_list->f->string); return nn; } n = nn; Pfct nf = n->fct_type(); Pchecked = mem_match(ef,nf); if (nf->f_static) nf->memof = 0; e->e2 = n; e->tp = n->tp; } // if (f->base == FCT && f->is_templ()) { if (f->base == FCT && f->fct_base == FCT_TEMPLATE) { Pexpr arg = return_elist(ef->argtype); Pname nn = has_templ_instance(n,arg); if (nn==0) return nn; // error already reported n = nn; Pchecked = mem_match(ef,n->fct_type()); e->e2 = n; e->tp = n->tp; } if (n) n->lval(ADDROF); break; case CAST: case G_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->skiptypedefs(); switch (it->base) { case ZTYPE: 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 ( init->base == QUEST) { // cannot have sides return (expr?{}:{}) // reuse same temp for both sides ?: Pname temp = make_tmp( 'A', mptr_type, tbl ); init->e1 = mptr_assign( temp, init->e1 ); init->e1 = new expr( G_CM, init->e1, temp ); init->e1->tp = temp->tp; init->e2 = mptr_assign( temp, init->e2 ); init->e2 = new expr( G_CM, init->e2, temp ); init->tp = p; } } if (c2 != 0 && !same_class(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 (0e1->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->skiptypedefs(); // error('d',"p %t pit %t",p,pit); switch (pit->base) { case FCT: return ptof(Pfct(pit),init,tbl); case COBJ: { Pptr r = it->is_ptr_or_ref(); Pexpr x = 0; Pname old_Ncoerce = Ncoerce; Ncoerce = 0; if ( r == 0 ) { suppress_error++; x = try_to_coerce(p,init,"initializer",tbl);; suppress_error--; } // error('d',"cobj: ptr %t, ref %t",it->is_ptr(),it->is_ref()); if (r != 0 || (x && Ncoerce && (r = x->tp->is_ptr_or_ref()))) { if (x && Ncoerce) init = x; 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 { p->base=b; if (init->base==G_ADDROF) error("no standard conversion of%t to%t",init->e2->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! Ncoerce = old_Ncoerce; return new cast(p,cp); } } Ncoerce = old_Ncoerce; // no break } default: return init; } } static Pname Lcoerce, Rcoerce; 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 if there is not 1 if there is exactly one way > 1 if there is more than one way */ { //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; int not_const1, not_const2; Lcoerce = Rcoerce = 0; Block(Pname) rconv; Block(Pname) lconv; int rfound = 0; int lfound = 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 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) { not_const1 = 0; // find best conversions for c1 for (Pname on1 = c1->conv; on1; on1=on1->n_list) { Pfct f = on1->get_fct(); lt = f->returns; if (lt->is_cl_obj()) continue; Pptr rn = lt->is_ref(); if(rn && rn->typ->is_cl_obj()) continue; // this has to be here because in np_promote // it screws up type checking if (lt->skiptypedefs()->base==EOBJ && oper >= ASPLUS && oper <= ASRS) continue; if (t1->tconst() && !f->f_const) { not_const1 = 1; continue; } lconv.reserve(lfound+1); lconv[lfound++] = on1; } if (lfound == 0) return not_const1 ? -1 : 0; Bits b(0,lfound); if (lfound == 1) b = ~b; else b = best_conv(lconv,lfound,const_obj1); // for each best conversion in c1, look at right side while (b.count()) { int i = b.signif() - 1; b.reset(i); Pfct f = lconv[i]->get_fct(); lt = f->returns; Pptr rr = lt->is_ref(); if(rr) lt = rr->typ; if(lt->base==OVERLOAD) lt = Pgen(lt)->fct_list->f->tp; int r1 = lt->kind(oper,0,0); if (c2) { not_const2 = 0; rfound = 0; for(Pname on2=c2->conv; on2; on2=on2->n_list) { Pfct f = on2->get_fct(); rt = f->returns; Pptr rn = rt->is_ref(); if(rn) rt = rn->typ; if(rt->is_cl_obj()) continue; if(rt->base==OVERLOAD) rt = Pgen(rt)->fct_list->f->tp; int r2 = rt->kind(oper,0,0); if (np_promote(oper,r1,r2,lt,rt,1,0) != any_type ) { if(t2->tconst() && !f->f_const) { not_const2 = 1; continue; } rconv.reserve(rfound+1); rconv[rfound++] = on2; } } // find Rcoerce if(rfound == 0) { //if(not_const2) return -2; //return 0; continue; } if(rfound == 1) { if(Lcoerce) return 2; Lcoerce=lconv[i]; Rcoerce=rconv[0]; continue; } Bits b2 = best_conv(rconv,rfound,const_obj2); if(rfound==1) { if(Lcoerce) return 2; Lcoerce=lconv[i]; Rcoerce=rconv[b2.signif()-1]; } //else if (b.count() == 0) { else { if(lfound > 1) return 4; return 3; } } else if (rt) { if(rt->base==OVERLOAD) rt = Pgen(rt)->fct_list->f->tp; int r2 = rt->kind(oper,0,0); if (np_promote(oper,r1,r2,lt,rt,1,0) != any_type ) { if(Lcoerce) return 2; Lcoerce = lconv[i]; if (b.count() == 0) return 1; } } else { if(oper==MUL && r1 != 'P') continue; if (oper==CALL && !lt->is_or_pts_to(FCT)) continue; if (lt->skiptypedefs()->base == EOBJ && (oper==INCR || oper==DECR) ) continue; if(Lcoerce) return 2; Lcoerce = lconv[i]; if (b.count() == 0) return 1; } } //if(lfound>1) return 2; return (Lcoerce || Rcoerce); } // otherwise, !c1 && c2 not_const2 = 0; for (Pname on = c2->conv; on; on=on->n_list) { Pfct f = on->get_fct(); rt = f->returns; Pptr rn = rt->is_ref(); if(rn) rt = rn->typ; if(rt->is_cl_obj()) continue; if(t2->tconst() && !f->f_const) { not_const2 = 1; continue; } if(rt->base==OVERLOAD) rt = Pgen(rt)->fct_list->f->tp; int r2 = rt->kind(oper,0,0); if( lt ) { if(lt->base==OVERLOAD) lt = Pgen(lt)->fct_list->f->tp; int r1 = lt->kind(oper,0,0); if (np_promote(oper,r1,r2,lt,rt,1,0)!=any_type) { rconv.reserve(rfound+1); rconv[rfound++] = on; } } else { if( oper_okay(rt,oper)) { rconv.reserve(rfound+1); rconv[rfound++] = on; } } } if(rfound==0 && not_const2) return -2; if(rfound==1) Rcoerce = rconv[0]; if(rfound>1) { Bits b = best_conv(rconv,rfound,const_obj2); Rcoerce = rconv[b.signif() - 1]; } if(rfound>1) return 3; return (Lcoerce || Rcoerce); } void opov_error(Ptype t1, Ptype t2, TOK op) { if (t1 && t2) { error('e',"ambiguous call of operator%k:%t%k%t",op,t1,op,t2); } else { Ptype tmp = t1 ? t1 : t2; error('e',"ambiguous call of operator%k:%k%t",op,op,tmp); } error('c'," (conflicts with built-in operator%k)\n",op); } int non_const; static int id_match(Pexpr th, Pfct f, Pclass cl, int anac) { Pname n = f->argtype; int ok = 0; if (!anac && th->e1 && ((cl && n && !n->n_list) || (!cl && n && n->n_list))) ok = 1; if (anac && th->e1 && ((cl && !n) || (!cl && n && !n->n_list))) ok = 1; if (th->e2 && ((cl && !n) || (!cl && n && !n->n_list))) ok = 1; if (ok && !cl) { Ptype t; if (th->e1) t = th->e1->tp; else if (th->e2->base==ELIST && !th->e2->tp) t = th->e2->e1->tp; else t = th->e2->tp; ok = can_coerce(n->tp,t); } return ok; } static Pexpr id_overload(Pexpr th, Pclass cl, int anac) { char* on = oper_name(th->base); Pexpr e; if (cl) e = cl->find_name(on, 0); else e = gtbl->look(on, 0); if (!e || !e->tp) return 0; if (e->tp->base == FCT) { if (id_match(th, Pfct(e->tp), cl, anac)) return e; } else { for (Plist gl = Pgen(e->tp)->fct_list; gl; gl = gl->l) if (id_match(th, Pfct(gl->f->tp), cl, anac)) return gl->f; } return 0; } Pexpr expr::oper_overload(Ptable tbl) { Pname n1 = 0; Ptype t1 = 0; const_obj1 = 0; const_obj2 = 0; int const_obj = 0; bit already_ambig = 0; if (e1) { t1 = e1->tp; Ptype tpx = t1->skiptypedefs(); n1 = tpx->is_cl_obj(); const_obj1 = t1->tconst() ? 1 : e1->is_const_obj(); } 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->skiptypedefs(); n2 = tpx->is_cl_obj(); const_obj2 = t2->tconst() ? 1 : e2->is_const_obj(); } if (n1==0 && n2==0) return 0; if (n1 && n1->tp == 0) return 0; // make_assign() fudge Pname Ggn=0; 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); if (bb == INCR || bb == DECR) { Pclass cl = Pclass(e1 ? n1->tp : n2->tp); char* on = oper_name(bb); bit ismem = 1; Pexpr e; Pexpr ee; bit anac = 0; e = id_overload(this, cl, 0); ee = id_overload(this, 0, 0); if (e && ee) error("ambiguous call of operator%k: %a and %a", bb, e, ee); if (!e && !ee && e1 && !strict_opt) { e = id_overload(this, cl, 1); ee = id_overload(this, 0, 1); if (e || ee) { error('w', "prefix ++/-- used as postfix (anachronism)"); anac = 1; } } if (!e) ismem = 0, e = ee; if (!e) { if (try_to_demote(bb, t1 ? t1 : t2, 0) == 1) { Pname xx = new name(Lcoerce->string); Pref r = new ref(DOT, e1 ? e1 : oe2, xx); if (e1) e1 = new expr(G_CALL, r, 0); else e2 = new expr(G_CALL, r, 0); return typ(tbl); } else { error("bad operand for%k:%t", bb, t1 ? t1 : t2); return this; } } base = (ismem ? CALL : G_CALL); if (!ismem) { Pexpr eee = 0; if (e1 && !anac) eee = new expr(ELIST, zero, 0); eee = new expr(ELIST, e1 ? e1 : oe2, eee); e1 = new name(on); Pname(e1)->n_qualifier = sta_name; e2 = eee; } else { Pexpr eee = e1; e1 = new ref(DOT, e1 ? e1 : oe2, new name(on)); e2 = (eee && !anac ? new expr(ELIST, zero, 0) : 0);; } e = typ(tbl); if (!e) return e; #if 0 if (e->base == DEREF && e->e1->tp->is_ref()) { e = e->e1; e->tp = 0; e = e->typ(tbl); } #endif return e; } // first try for non-member function Pname gname = tbl->look(obb,0); int go; if(!gname) go = 0; else if(gname->tp->base == FCT) go = matchable(gname,ee1,0); else { suppress_error++; Ggn = gname; Pgen g = Pgen(gname->tp); gname = ee1->e2 ? g->multArgMatch(ee1,0) : g->oneArgMatch(ee1,0); if(ambig) already_ambig = 1; go = gname ? matchable(gname,ee1,0) : 0; suppress_error--; } non_const = 0; if (n1) { if (bb == ASSIGN) { Pclass c1 = Pclass(n1->tp); if (c1->memtbl->look(obb,0)==0) { Pclass bcl = c1->baselist?c1->baselist->bclass:0; // if legal, a=1 can be optimized to a.ctor(1) if ( n2==0 || !same_class(Pclass(n2->tp),c1) && Pclass(n2->tp)->has_base(c1)==0 ) { //take out next line when no non- // member op= if (c1->c_xref==C_REFM) c1->c_xref=0; if (go > STD) goto glob; return 0; } // make operator=() if no base, different // (smaller) sized base, or two bases if ( bcl && c1->obj_size!=bcl->obj_size && bcl->memtbl->look(obb,0) || c1->c_xref&(C_VBASE|C_VPTR|C_ASS|C_REFM) ) { //take out next line when no non- // member op= if (go > STD) goto glob; return make_assignment(n1) ? oper_overload(tbl) : 0; } return 0; } // now take care of other assignments, } Pclass ccl = Pclass(n1->tp); if(strcmp(obb,"__as")) { tcl = ccl; // ugh!!! } Pexpr mn = ccl->find_name(obb,0); Pname mname = Pname(mn); if (mname == 0) goto glob; while (mname->base == REF || mname->base == MDOT) { mname = Pname(Pexpr(mname)->mem); } int mo = 0; if (const_obj1) const_obj = 1; if(mname->tp->base == FCT) mo = matchable(mname,e2,const_obj1); else if(mname->tp->base == OVERLOAD) { suppress_error++; Pgen g = Pgen(mname->tp); if(!e2) { mname = g->exactMatch(0,const_obj1); } else if(e2->e2) { mname = g->multArgMatch(e2,const_obj1); } else { mname = g->oneArgMatch(e2,const_obj1); } suppress_error--; if(ambig) already_ambig += 2; mo = mname ? matchable(mname,e2,const_obj1) : 0; } if (mo==0) goto glob; if ( (mo != EXACT || Pclass(n1->tp)->memtbl->look(obb,0)==0) && go != EXACT ) { if( Ggn && Pgen(Ggn->tp)->has_templ() || gname && gname->is_template_fct() ) { Pname f_inst=has_templ_instance(Ggn?Ggn:gname,ee1,1); if( f_inst ) { gname = f_inst; go = EXACT; goto glob; } } } if (mo && go) { Pfct mfct = mname->fct_type(); Ptype mt1 = mfct->f_this->tp; mt1 = Pptr(mt1)->typ; Ptype mt2 = mfct->argtype->tp; Pname mm = new name(gname->string); mm->n_oper = gname->n_oper; Pname a1 = new name; a1->tp = mt1; Pname a2 = new name; a2->tp = mt2; a1->n_list = a2; mm->tp = new fct(mfct->returns,a1,2); Pname aa = gname->fct_type()->argtype; Ptype savep = 0; Pptr p; if (p = aa->tp->is_ref()) { savep = p; aa->tp = p->typ; } Pgen tgen = new gen; name_list nl(gname,0); tgen->fct_list = new name_list(mm,&nl); Pname found = tgen->multArgMatch(ee1,0); if(ambig) already_ambig = 1; if(savep) aa->tp = p; delete a1,a2; DEL( mm->tp ); delete tgen; if(found!=mm) { // non-member best delete mm; if(already_ambig==2) already_ambig=0; goto glob; } // member better or as good if(!ambig && already_ambig==1) already_ambig=0; delete mm; } if ( (mo == EXACT && Pclass(n1->tp)->memtbl->look(obb,0)) || try_to_demote(bb,t1,t2)<=0 || already_ambig > 0 || compare_builtin(t1,t2,n1,n2,mname,mo) ) { 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 */ if (const_obj2) const_obj = 1; suppress_error++; Pexpr mn = Pclass(n2->tp)->find_name(obb,0); suppress_error--; Pname mname = Pname(mn); if (mname == 0) goto glob; while (mname->base==REF || mname->base==MDOT) { mname = Pname(Pexpr(mname)->mem); } if (mname->n_scope != 0 && mname->n_scope != PUBLIC) { goto glob; } int mo = 0; if(mname->tp->base == FCT) mo = matchable(mname,0,const_obj2); else if(mname->tp->base == OVERLOAD) { suppress_error++; Pgen g = Pgen(mname->tp); mname = g->exactMatch(0,const_obj2); if(ambig) already_ambig += 2; suppress_error--; mo = mname ? matchable(mname,0,const_obj2) : 0; } if (mo==0) { goto glob; } if ( (mo != EXACT || Pclass(n2->tp)->memtbl->look(obb,0)==0) && go != EXACT ) { if( Ggn && Pgen(Ggn->tp)->has_templ() || gname && gname->is_template_fct() ) { Pname f_inst=has_templ_instance(Ggn?Ggn:gname,ee1,1); if( f_inst ) { gname = f_inst; go = EXACT; goto glob; } } } if(mo && go) { Ptype mt1 = mname->fct_type()->f_this->tp; mt1 = Pptr(mt1)->typ; Pname marg = new name; marg->tp = mt1; Pname garg = gname->fct_type()->argtype; Pname nn = bestOfPair(marg,garg,e2->e1->tp); if(nn==garg) { if(already_ambig==2) already_ambig=0; delete marg; goto glob; } else if(nn==marg) { if(already_ambig == 1) already_ambig=0; } // member better or as good else if(!nn) { Block(Pname) errblock(3); errblock[0] = mname; errblock[1] = gname; fmError(1,errblock,e2,const_obj2); already_ambig = 1; } delete marg; } base = G_CALL; // e2.op() Pname xx = new name(mname->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: if (go != EXACT) { if( Ggn && Pgen(Ggn->tp)->has_templ() || gname && gname->is_template_fct() ) { Pname f_inst = has_templ_instance(Ggn?Ggn:gname,ee1,1); if( f_inst ) { gname = f_inst; go = EXACT; } } } if (go) { if ( go == EXACT // UDO is an exact match || try_to_demote(bb,t1,t2)<=0 // can use a built_in || already_ambig > 0 // already ambiguous || compare_builtin(t1,t2,n1,n2,gname,go) // builtin not better ) { base = gname->n_table == gtbl ? G_CALL : CALL; 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; 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 (!const_obj1 && make_assignment(n1)) return oper_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 ) ) { Pexpr te = check_cond(e2,bb,tbl); if (te == e2) { tp = any_type; return this; } e2 = te; return 0; } int ttd; switch ((ttd=try_to_demote(bb,t1,t2))) { case -2: error("no usable const conversion for%n",n2); break; case -1: error("no usable const conversion for%n",n1); break; case 0: break; case 2: error("ambiguous conversion of%n",n1); break; case 3: error("ambiguous conversion of%n",n2); break; case 4: error("ambiguous conversion of%n and%n",n1,n2); 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('e',"bad operands for%k:%t%k%t",bb,t1,bb,t2); else error('e',"bad operand for%k:%t",bb,t1?t1:t2); if (const_obj && ttd <= 0 && non_const) error('c'," (no usable const operator%k)\n",bb); else error('c',"\n"); 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->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 (ccl==0 || ocl==0 || same_class(ocl,ccl)) return ee; // error('d',"cast_cptr %t(%t) real %d",ccl,ocl,real_cast); int oo = 0; if (ocl->baselist && (!same_class(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*;%kBC",on,ccl,Nvis); else if (warning_opt) error('w',"cast:%n* ->B%t*;%kBC",on,ccl,Nvis); 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)+1]; strcpy(Nptr->string4,Nalloc_base); Nalloc_base = 0; } else Nptr->i1 = 3; extern Pexpr this_handler; if (ee->base==ADDROF || ee->base==G_ADDROF) ee = Nptr; else if (this_handler && ee->base == NAME && strcmp(ee->string,"this") == 0) ee = this_handler; else { Pexpr p = new expr(QUEST,Nptr,zero); nin = 1; if (ee->not_simple()) { // need temp Ptype t = unconst_type(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 && (!same_class(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->base==NAME && ee->tp->base==RPTR)) 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); if (pp->tp->base==VEC) pp->tp = new ptr(PTR,Pvec(pp->tp)->typ); 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*;%kBC",on,ccl,Nvis); //else // why only warn? if (warning_opt) //error('w',"cast:%n* ->B%t*;%kBC",on,ccl,Nvis); //error("cast:%n* ->B%t*;%kBC",on,ccl,Nvis); 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); error('C',"%a is a pure virtualF ofC%t\n",cl->c_abstract,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) { if (!cl->has_vtor()) cl->make_vec_ctor(ic); break; } } if (icl && cl->has_itor()==0 // incomplete: // what if X(Y&) exists // for class Y : X ? && (same_class(icl,cl) || icl->has_base(cl))) { init = 1; break; } // If link compatability is broken change the // way ctors are called. Create an expression // that will create space for the object then // call the ctor. This way you can remove the // check of this==0 from ctors. if (perf_opt && !v) { // First check that this is not a case // where the NEW is a default argument. // The rest of cfront cannot handle this // so kick out the case right now. // Set in dargs (dcl3.c) function // This is the only way to tell if // a new is in the arg list extern int New_in_arg_list; if (New_in_arg_list) error('s',"optimization option does not allow new as a default argument\n"); // create space for object then call // constructor. Pexpr p; Pexpr args = e2; Pexpr sz = new texpr(SIZEOF,tt,0); (void) tt->tsizeof(); sz->tp = uint_type; Pexpr ee = new expr(ELIST,sz,args); char *s = oper_name(NEW); Pname n = new name(s); if (base == GNEW) p = gtbl->look(s,0); else p = find_name(n,cl,cl->memtbl,CALL,cc->nof); ee = new call(p,ee); overFound = 0; //set in call_fct (void) ee->call_fct(cl->memtbl); if (overFound && overFound->n_scope != EXTERN && overFound->n_scope != STATIC) check_visibility(overFound,0,Pfct(overFound->tp)->memof,cc->ftbl,cc->nof); overFound=0; Ptype cobj_ptr = new ptr(PTR, tt); Pname cobj_tmp; Pname tn = tbl->t_name; // Create temp at global scope, for sti // because make_tmp doesn't expect to // see a temp in an sti if (tn && tn->tp) { cobj_tmp = make_tmp('B', cobj_ptr, gtbl); } else cobj_tmp = make_tmp('B', cobj_ptr, tbl); cobj_tmp->n_assigned_to = 1; cobj_tmp->n_used = 1; Pexpr ctor_expr = call_ctor(tbl,cobj_tmp,ctor,e1); ee = new expr(ASSIGN,cobj_tmp,ee); ee = new expr(ANDAND,ee,ctor_expr); ee = new expr(G_CM,ee,cobj_tmp); e1 = ee; e1->tp = cobj_ptr; return e1; } else { e1 = call_ctor(tbl,0,ctor,e1); } } else if (e1) { if (same_class(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); if (e1->base == ILIST || (e1->base == ELIST && e1->e1 && e1->e1->base == ILIST)) { if (e1->base != ILIST) e1 = e1->e1; Pname tmp2 = make_tmp('A', mptr_type, tbl); Ptype t = e1->tp; e1 = mptr_assign(tmp2, e1); e1 = new expr(G_CM, e1, tmp2); e1->tp = t; } e1 = new expr(0,tmp,e1); tmp->assign(); if (ansi_opt && tmp->tp) { Ptype t = tmp->tp; if (t->is_ptr_or_ref()) t = Pptr(t)->typ; t->ansi_const = 1; } } // tp = (v) ? tpx : tpx->addrof(); switch (v) { case 0: tp = tpx->addrof(); break; case 1: tp = tpx; break; default: tp = tpx; } return this; } static int 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 && te->base != G_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; } inline bit exact123(Pname nn, Ptype tt) { if ( exact1(nn,tt) || exact2(nn,tt) || exact3(nn,tt)) return 1; else return 0; } Pname compare_builtin(Ptype t1, Ptype t2, Pname n1, Pname n2, Pname fname, int fo) /* routine to compare user-defined operator to built-in version. returns fname if user-defined operator is preferred, and 0 otherwise. */ { if (fo == EXACT) return fname; bit binary = t1 && t2 ? 1 : 0; Pfct ff = fname->fct_type(); TOK oper = fname->n_oper; // operators which must be members are // always preferred over built-in // also ASOPs since can't assign to GCALL if( oper==DEREF || oper==CALL || oper==ASSIGN || oper==REF || oper==ASPLUS || oper==ASMINUS || oper==ASMUL || oper==ASDIV || oper==ASMOD || oper==ASAND || oper==ASOR || oper==ASER || oper==ASLS || oper==ASRS ) return fname; int t1eobj = (t1 && t1->skiptypedefs()->base == EOBJ); if (t1eobj) { Pname n1 = t2 ? t2->is_cl_obj() : 0; Pclass c1 = n1 ? Pclass(n1->tp) : 0; if (c1) { for (Pname on1 = c1->conv; on1; on1 = on1->n_list) { Pfct f = on1->get_fct(); Ptype ret = f ? f->returns : 0; if (ret && ret->skiptypedefs()->base == EOBJ && !ret->check(t1->skiptypedefs(), ASSIGN)) { t1eobj = 0; break; } } } else { t1eobj = 0; } } int t2eobj = (t2 && t2->skiptypedefs()->base == EOBJ); if (t2eobj) { Pname n1 = t1 ? t1->is_cl_obj() : 0; Pclass c1 = n1 ? Pclass(n1->tp) : 0; if (c1) { for (Pname on1 = c1->conv; on1; on1 = on1->n_list) { Pfct f = on1->get_fct(); Ptype ret = f ? f->returns : 0; if (ret && ret->skiptypedefs()->base == EOBJ && !ret->check(t2->skiptypedefs(), ASSIGN)) { t2eobj = 0; break; } } } else { t2eobj = 0; } } int teobj = t1eobj || t2eobj; if (ff->memof) { // unary member always better if ( !binary || n2) return fname; Pname nn = ff->argtype; if ((!teobj && exact1(nn,t2)) || (teobj && exact2(nn,t2))) return fname; opov_error(t1,t2,oper); return fname; } // non-member if (!binary) { // unary if (fo==UDC) { opov_error(t1,t2,oper); return fname; } } else { // binary if (n1 && n2) { if (fo < UDC) return fname; Pname nn1 = ff->argtype; Pname nn2 = nn1->n_list; if ( exact123(nn1,t1) || exact123(nn2,t2)) { return fname; } else { opov_error(t1,t2,oper); return fname; } } else { Pname carg, oarg; Ptype ct,ot; if (n1) { carg = ff->argtype; ct = t1; oarg = carg->n_list; ot = t2; } else { oarg = ff->argtype; ot = t1; carg = oarg->n_list; ct = t2; } if ( exact123(carg,ct)) { if ((!teobj && !exact1(oarg,ot)) || (teobj && !exact2(oarg,ot))) opov_error(t1,t2,oper); return fname; } else { if ((!teobj && exact1(oarg,ot)) || (teobj && exact2(oarg,ot))) { opov_error(t1,t2,oper); return fname; } else return 0; } } } error('i', "fall off end of compare_builtin()"); return 0; }