/*ident "@(#)cls4:src/expr3.c 1.38" */ /******************************************************************************* C++ source for the C++ Language System, Release 3.0. This product is a new release of the original cfront developed in the computer science research center of AT&T Bell Laboratories. Copyright (c) 1993 UNIX System Laboratories, Inc. Copyright (c) 1991, 1992 AT&T and UNIX System Laboratories, Inc. Copyright (c) 1984, 1989, 1990 AT&T. All Rights Reserved. THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE of AT&T and UNIX System Laboratories, Inc. The copyright notice above does not evidence any actual or intended publication of such source code. expr3.c: type check function calls, casts, and explicit coercions ************************************************************************/ #include "cfront.h" #include "size.h" #include "template.h" #include "overload.h" static Bits intersectRule(const Block(BlockPname)&, int, Pexpr); static Bits bestMatch(const Block(Pname)&, int, Ptype); static Bits best_const(const Block(Pname)&, int, Ptype); static Pname breakTie(const Block(Pname)&, Bits&, Pexpr, int); static int pr_dominate(Ptype, Ptype); static int refd;// initialization routine called by ref_init, do not apply itor static int no_sti; static int miFlag; int no_const; extern int stat_init; int ambig; bit in_return=0; int pr_dominate(Ptype t1, Ptype t2) /* */ { Pname cn1 = t1->is_cl_obj(); Pname cn2 = t2->is_cl_obj(); if (cn1==0 || cn2==0) { Ptype p1 = t1->is_ptr(); Ptype p2 = t2->is_ptr(); if (p1 && p2) { // pointers cn1 = Pptr(p1)->typ->is_cl_obj(); cn2 = Pptr(p2)->typ->is_cl_obj(); if (cn1==0 || cn2==0) return 0; } else { p1 = t1->is_ref(); p2 = t2->is_ref(); if (p1 && p2) { // references cn1 = Pptr(p1)->typ->is_cl_obj(); cn2 = Pptr(p2)->typ->is_cl_obj(); if (cn1==0 || cn2==0) return 0; } else return 0; // not the same and not classes } } Pclass c1 = Pclass(cn1->tp); Pclass c2 = Pclass(cn2->tp); if (c1->has_base(c2)) return 1; if (c2->has_base(c1)) return 2; return 0; } Pname Ntmp; Pname Ntmp_refd; Pname Ntmp_flag; extern Pname Ntmp_flag_list; Pname make_tmp(char c, Ptype t, Ptable tbl) { int dt = 0; Pname tn = tbl->t_name; Pname cn = t->is_cl_obj(); if (tn && tn->tp) error('s',"defaultA too complicated"); if (cn && Pclass(cn->tp)->has_dtor()) dt = 1; if (Ntmp == 0 && dt ) Ntmp = cn; //error('d',"tbl %d cstmt %d %d sti %d",tbl,Cstmt,Cstmt?Cstmt->memtbl:0,sti_tbl); if (Cstmt) { // make Cstmt into a block if (Cstmt->memtbl == 0) Cstmt->memtbl = new table(4,tbl,0); tbl = Cstmt->memtbl; } else if (tbl == gtbl && no_sti == 0) { if (sti_tbl == 0) sti_tbl = new table(8,gtbl,0); tbl = sti_tbl; } Pname tmpx = new name(make_name(c)); tmpx->where = no_where; tmpx->tp = t; (void) t->tsizeof(); if ( t->base == COBJ ) { Pclass cl = Pclass(Pbase(t)->b_name->tp); if ( cl->lex_level ) tmpx->lex_level = cl->lex_level; } TOK scop = ARG; if (stat_init && dt) { tmpx->n_sto = STATIC; scop = ARGS; } else if (gtbl == tbl) { tmpx->n_sto = STATIC; } // ARG[S]: no init; ARGS: static dtor Pname tmp = tmpx->dcl(tbl,scop); delete tmpx; // n_scope == ARGS sets static dtor in simpl2.c tmp->n_scope = (scop==ARG) ? FCT : ARGS; return tmp; } Pexpr init_tmp(Pname tmp, Pexpr init, Ptable tbl) { Pname cn = tmp->tp->is_cl_obj(); Pname ct = cn ? Pclass(cn->tp)->has_itor() : 0; tmp->n_assigned_to = 1; //error('d',"init_tmp %n ct %n refd %d",tmp,ct,refd); if (ct) { // must initialize if (refd) { //error('d',"'orrible %k",init->e1->base); switch (init->e1->base) { // 'orrible 'ack case NAME: case REF: case DEREF: if (init->base == QUEST) init = init->address(); else if (init->e1->tp->is_ptr()) init = init->e1; else init = new expr(G_CM,init,init->e1->address()); } if (ct->tp->base == OVERLOAD) ct = Pgen(ct->tp)->fct_list->f; // first fct tbl = 0; // when tbl==0, call_ctor will not force declaration of ct if (ct->n_dcl_printed==0) ct->dcl_print(0); } return call_ctor(tbl,tmp,ct,init,DOT); } if (ansi_opt) tmp->tp->ansi_const=1; Pexpr ass; if(init->base == ZERO && tmp->tp->memptr()) ass = mptr_assign(tmp,init); else ass = new expr(ASSIGN,tmp,init); // no ctor: can assign ass->tp = tmp->tp; return ass; } int exact3(Pname nn, Ptype at) /* return 1 if match with standard conversions */ { if (nn == 0) return 0; Ptype nt = nn->tp->skiptypedefs(); if (at == nt) return 1; switch (nt->base) { case RPTR: if (nt->base==RPTR && Pptr(nt)->typ->check(at,COERCE)==0) return 1; if (at==zero_type && Pptr(nt)->typ->is_ptr()==0) return 0; if (nt->check(at,COERCE)) { Pptr pt = at->addrof(); nt->base = PTR; // handle derived classes if (nt->check(pt,COERCE)) { nt->base = RPTR; delete pt; return 0; } nt->base = RPTR; delete pt; } break; default: switch (at->base) { default: if (nt->check(at,COERCE)) return 0; break; case OVERLOAD: // the actual argument is an overloaded function // we'll try each instance until one matches register Plist gl; int no_match = 1; for (gl = Pgen(at)->fct_list; gl; gl=gl->l) { if (nt->check(gl->f->tp,COERCE)==0) { no_match = 0; break; } } if ( no_match ) return 0; } } return 1; } int exact1(Pname nn, Ptype at) /* return 1 if exact match with T <-> const T X -> X& T* -> const T* T* -> T*const taken into account */ { if (nn == 0) return 0; Ptype nt = nn->tp->skiptypedefs(); if (at == nt) return 1; if (at->base == ZTYPE) at = int_type; // if the actual argument is an overloaded function // we'll see if any instance matches exactly if (at->base == OVERLOAD) { register Plist gl; for (gl = Pgen(at)->fct_list; gl; gl=gl->l) { if (nt->check(gl->f->tp,0)==0) { return 1; } } return 0; } Pptr rt = nt->is_ptr(); Pptr art = at->is_ptr(); if (nt->check(at,0)) { // handle T <-> const T if (const_problem && nt->base != PTR) return 1; // reject ptmfs of different classes if (rt && rt->memof || art && art->memof) return 0; rt = nt->is_ref(); //handle X -> X& if (rt && (at->check(Pptr(rt)->typ,0)==0 || const_problem)) return 1; if (rt && art) return 0; // ptrs do not match refs // handle T* -> const T* and // T* -> T*const if (rt || (rt = nt->is_ptr())) { if (art == 0) art = at->is_ref(); if (art) { if (art->typ->check(rt->typ,0)) { if (const_problem && Pbase(art->typ)->b_const != 1) return 1; } else // T* -> T*const return 1; } } return 0; } return 1; } int exact2(Pname nn, Ptype at) /* return 1 if do integral promotion and float->double on at, then match */ { //error('d',"exact2 nt %t at %t",nn?nn->tp:0,at); at = at->skiptypedefs(); switch (at->base) { case EOBJ: at = Penum(Pbase(at)->b_name->tp)->e_type; break; case ZTYPE: at = int_type; break; case CHAR: case SHORT: at = (Pbase(at)->b_unsigned && at->tsizeof()==SZ_INT) ? uint_type : int_type; break; case FLOAT: at = double_type; } if (nn == 0) return 0; return exact1(nn,at); } Pname Ncoerce; static int ref_cast; int Nstd; bit can_coerce(Ptype t1, Ptype t2) /* return number of possible coercions of t2 into t1, Ncoerce holds a coercion function (not constructor), if found */ { int zz = 0; Ncoerce = 0; no_const = 0; if (t2->base == ANY) return 0; if (!t1->check(t2,COERCE)) // see if any std conversions return 1; //t1 = t1->skiptypedefs(); if (t1->is_ref()) { if (t1->check(t2->skiptypedefs()->addrof(),COERCE) == 0) return 1; if (!ref_cast) { // (T&): no coercions // except operator T&() Ptype tt1 = Pptr(t1->skiptypedefs())->typ->skiptypedefs(); int bc; if ( tt1->base != PTR && tt1->base != RPTR ) { bc = Pbase(tt1)->b_const; Pbase(tt1)->b_const = 0; } int i = can_coerce(tt1,t2); if ( tt1->base != PTR && tt1->base != RPTR ) Pbase(tt1)->b_const = bc; if (i) return i; zz = 1; } } Pname c1 = t1->is_cl_obj(); Pname c2 = t2->is_cl_obj(); int val = 0; if (c1 && !ref_cast && !zz) { Pclass cl = Pclass(c1->tp); if (c2 && same_class(Pclass(c2->tp),cl)) return 1; // A more comprehensive test for template classes if (c2 && same_class(Pclass(c1->tp), Pclass(c2->tp))) return 1 ; /* look for a constructor with one argument or with default for second argument of acceptable type */ Pname ctor = cl->has_ctor(); register Pfct f = ctor ? Pfct(ctor->tp) : 0; if(f && f->base == FCT) { if (f->nargs==1 || f->nargs > 1 && f->argtype->n_list->n_initializer ) { if (exact3(f->argtype,t2)) { val = 1; } } } else if (f && f->base == OVERLOAD) { register Plist gl; for (gl=Pgen(f)->fct_list; gl; gl=gl->l) { Pname nn = gl->f; Pfct ff = Pfct(nn->tp); if (ff->nargs==1 || ff->nargs>1 && ff->argtype->n_list->n_initializer ) { if (exact3(ff->argtype,t2)) { val = 1; break; } } } } else if (f) { error('i',"cannot_coerce(%k)\n",f->base); } } if (c2) { const int REALLY_EXACT = 6; Block(Pname) conv; int found = 0; Pclass cl = Pclass(c2->tp); int best = 0; for (Pname ox, on=cl->conv; on; on=ox) { ox = on->n_list; Pfct f = on->get_fct(); // const check should be here Ptype rt = f->returns; Pptr rr = rt->is_ref(); if (rr && !t1->is_ref()) rt = rr->typ; Nstd = 0; int howgood = 0; if (t1->check(rt,0) == 0) { howgood = REALLY_EXACT; } else if (t1->check(rt,COERCE)==0) { if (!Nstd) howgood = EXACT; else { Pname t_nn = new name; t_nn->tp = t1->skiptypedefs(); if(exact2(t_nn,rt)) howgood = PROM; else howgood = STD; } } // this check here for the sake of an error message if(t2->tconst() && f->f_const==0) { if(howgood) no_const++; continue; } if(howgood == 0 || howgood < best) continue; if(howgood > best) { found = 0; best = howgood; } conv.size(found+1); conv[found++] = on; } if (found) { if(found == 1) Ncoerce = conv[0]; else { Bits b = best_conv(conv,found,t1->tconst()); Ncoerce = conv[b.signif() - 1]; } val = val + found; } } if (val) return val; if (c1 && Pclass(c1->tp)->has_itor()) return 0; if (t1->check(t2,COERCE)) return 0; return 1; } int matchable(Pname n, Pexpr arg, int constObj) /* look to see if the argument list "arg" can match a call of "n" return worst kind of conversion done or NONE */ { Pfct f = n->fct_type(); register Pexpr e; register Pname nn; int worst = EXACT; //for compatibilty if (n->is_template_fct()) return 0; if(constObj && n->n_oper!=CTOR && !f->f_const && !f->f_static) { non_const++; return NONE; } for(e=arg, nn=f->argtype; e; e=e->e2, nn=nn->n_list) { if (nn == 0) return f->nargs_known==ELLIPSIS; Pexpr a = e->e1; Ptype at = a->tp; if (at->base==ANY) return NONE; if (exact1(nn,at)) {worst=min(worst,EXACT);continue;} if (exact2(nn,at)) {worst=min(worst,PROM);continue;} if (exact3(nn,at)) {worst=min(worst,STD);continue;} int cc = can_coerce(nn->tp,at); if (cc != 1) return NONE; else worst=UDC; } if (nn && nn->n_initializer==0) return NONE; return min(worst,EXACT); } int is_arg; Ptype expr::call_fct(Ptable tbl) /* check "this" call: e1(e2) e1->typ() and e2->typ() has been done */ { Pfct f; Pname fn; int x; int k; Pname nn; Pexpr e; Ptype t; Pexpr arg = e2; Ptype t1 = e1?e1->tp:0; ambig = 0; int argno; Pexpr etail = 0; bit no_change = 0; Pname no_virt = 0; // set if explicit qualifier was used: c::f() Pname chk = 0; // set if visibility check is needed // that is if function name might have been // found without use of find_name() int const_obj = 0; if (t1 == any_type) return any_type; switch (base) { case CALL: case G_CALL: break; default: error('i',"call_fct(%k)",base); } //error('d',"call %d %k %n arg %d",this,e1->base,e1->base==NAME?e1:0,arg); if (t1 == 0) error('i',"call_fct(e1=%d,e1->tp=%t)",e1,t1); if (arg && arg->base!=ELIST) error('i',"badAL%d%k",arg,arg->base); switch (e1->base) { case DTOR: // dummy type destructor fn = Pname(e1); break; case NAME: fn = Pname(e1); switch (fn->n_oper) { case 0: case CTOR: case DTOR: case TYPE: case NEW: case DELETE: break; default: // real operator: check for operator+(1,2); { if (arg == 0) break; Pexpr a = arg->e1; // first operand if (Pfct(fn->tp)->memof // obj.operator(1) is OK || a->tp->is_cl_obj() || a->tp->is_ref()) break; a = arg->e2; if (a == 0) // unary error("%k of basicT",fn->n_oper); else { // binary a = a->e1; // second operand if (a->tp->is_cl_obj() || a->tp->is_ref()) break; error("%k of basicTs",fn->n_oper); } break; } } break; case REF: case DOT: no_virt = Pname(e1->n_initializer); e1->n_initializer = 0; if (e1 && e1->e1) { Ptype t = e1->e1->tp; Pptr tt = t->is_ref(); t = tt ? tt->typ : t; Pptr p_t = t->is_ptr(); t = e1->base==REF && p_t ? p_t->typ : t; tt = t->is_ref(); t = tt ? tt->typ : t; const_obj = t->tconst() ;// ? 1 : e1->e1->is_const_obj(); } case MDOT: { Pexpr n = e1->mem; lxlx: switch (n->base) { case MDOT: // reverse mdot (see expr::print()) // p->a.b() => (&p->a)->b() => b(&p->a) // or p->a->b() => (p->a)->b() => b(p->a) // or oo.a.b() => (&oo.a)->b() => b(&oo.a) // or oo.a->b() => (oo.a)->b() => b(oo.a) { Pexpr r = e1; Pexpr p = r->e1; for (Pexpr m = r->mem; m->base==MDOT; m = r->mem) { p = new mdot(m->string2,p); p->i1 = m->i1+2; if (p->mem && Pexpr(p->mem) != Pexpr(1)) p->tp = p->mem->tp; r->mem = m->mem; r->e1 = p; } } case REF: case DOT: n = n->mem; goto lxlx; case NAME: case DTOR: break; default: error('i',"ref %k",n->base); } fn = Pname(n); break; } case MEMPTR: default: fn = 0; } lll: //error('d',"lll: %t %k",t1,t1->base); switch (t1->base) { case TYPE: t1 = Pbase(t1)->b_name->tp; goto lll; case PTR: // pf() allowed as shorthand for (*pf)() switch (Pptr(t1)->typ->skiptypedefs()->base) { case FCT: case OVERLOAD: if (Pptr(t1)->memof) error("O missing in call throughP toMF"); t1 = Pptr(t1)->typ; fn = 0; goto lll; } default: if (fn) error("call of%n;%n is a%t",fn,fn,e1->tp); else error("call of%kE ofT%t",e1->base,e1->tp); case ANY: return any_type; case OVERLOAD: { Pgen g = Pgen(t1); Pname found = 0; // look for an exact match found = g->exactMatch(arg,const_obj); // code for calls with template versions if(!found && arg && g->has_templ()) { found = has_templ_instance(fn,arg); } // one argument in call: no need for intersect rule if (!found && arg && arg->e2 == 0) { found = g->oneArgMatch(arg,const_obj); } // multiple arguments in call: potential need for // intersect rule and simple rule else if (!found && arg) { found = g->multArgMatch(arg,const_obj); } // no functions are matchable if (!found) { Block(Pname) tmp(1); tmp[0] = fn; fmError(0,tmp,arg,const_obj); return any_type; } overFound = chk = fn = found; f = fn->fct_type(); break; } case FCT: f = Pfct(t1); if (fn) { if (fn->is_template_fct()) { Pname f_inst = has_templ_instance(fn,arg); if (f_inst) { e1 = f_inst; fn = f_inst; t1 = f_inst->tp; f = Pfct(f_inst->tp); } } else switch (fn->n_oper) { case CTOR: case TYPE: chk = fn; } } } if (chk) { Ptype t = 0; Pexpr ee = e1->e1; switch (e1->base) { case REF: // ptr->chk() if (ee == 0) { // 0->x() fudge handling new x() check_visibility(chk,no_virt,Pclass(chk->n_table->t_name->tp),tbl,cc->nof); break; }; t = ee->tp->skiptypedefs(); t = Pptr(t)->typ; break; case DOT: // obj.chk() t = ee->tp; } Pname cn = t?t->is_cl_obj():0; Pclass cl = cn?Pclass(cn->tp):0; // class of ``this'' for chk if (cl) { if (chk->n_oper==CTOR && chk->n_protect && cc->nof && cc->nof->n_oper==CTOR) // BUG: cannot handle protected base // class constructor ; else { check_visibility(chk,no_virt,cl,tbl,cc->nof); } } } if (fn && f->returns->is_cl_obj() && f->f_result==0) { // protect against class cn; cn f(); ... class cn { cn(cn&); ... }; make_res(f); f->returns->tsizeof(); // make sure it is declared } //error('d',"fn %n %t printed %d",fn,fn?fn->tp:0,fn?fn->n_dcl_printed:0); if (fn) { // ensure printout of class declaration: for (Pname nn=f->argtype; nn; nn=nn->n_list) if (nn->tp->is_cl_obj()) (void) nn->tp->tsizeof(); } if (fn && fn->n_dcl_printed==0) { if (f->f_inline==0 && f->f_imeasure) { extern void uninline(Pname fn); uninline(fn); } // // ensure printout of class declaration: // for (Pname nn=f->argtype; nn; nn=nn->n_list) // if (nn->tp->is_cl_obj()) (void) nn->tp->tsizeof(); fn->dcl_print(0); } if (no_virt && f->f_static==0) { if (e1->base==REF || e1->base==DOT) e1->n_initializer = fn; } else fct_name = fn; //error('d',"fn %n %t %d %d",fn,f,f->f_this,f->f_static); if (f->f_this) { //SSS call of non-static memberfunction switch (e1->base) { case MEMPTR: case REF: case DOT: break; default: error("O orP missing for%n ofT %t",fct_name,f); } } else if (fn) { //SSS call of static function sss: switch (e1->base) { case REF: case DOT: case MDOT: e1 = e1->mem; goto sss; } } if (fn) fn->use(); // a patch: ctors are sometimes not use()d if (f->f_const==0 && e1->tp && !e1->tp->is_ptr() && (fn==0 || (fn->n_oper!=CTOR && fn->n_oper!=DTOR))) { //CCC switch (e1->base) { case REF: { Pptr p = e1->e1->tp?e1->e1->tp->is_ptr():0; if (p && p->typ->tconst()) error("non-constMF%n called for constO",fn); break; } case DOT: { int tc = e1->e1->tp ? e1->e1->tp->tconst() : 0; if (e1->tp && tc && (!strict_opt || tc!=2)) error("non-constMF%n called for constO",fn); break; } case MEMPTR: { Pptr p = e1->e1->tp?e1->e1->tp->is_ptr():0; if (p && p->typ->tconst()) error("non-constMF called for constO"); break; } } } t = f->returns; x = f->nargs; k = f->nargs_known; e = arg; if (k == 0) goto rlab; for (nn=f->argtype, argno=1; e||nn; nn=nn->n_list, e=etail->e2, argno++) { Pexpr a; int save_base = 0; char* save_name = 0; bit mpt = (nn && nn->tp && nn->tp->skiptypedefs()->memptr()); if (e) { a = e->e1; etail = e; if (nn) { /* type check */ Ptype t1 = nn->tp->skiptypedefs(); //error('d',"argtp %t etp %t a %k",t1,a->tp,a->base); switch (t1->base) { case RPTR: { Ptype pt = Pptr(t1)->typ; if (pt->skiptypedefs()->base==VEC ) { if (pt->check(a->tp,IGNORE_CONST)) { error("badA %dT for%n:%t (%tX)",argno,fn,a->tp,nn->tp); return any_type; }; } if (pt->base != FCT || pt->check(a->tp,0) ) { is_arg = 1; a = ref_init(Pptr(nn->tp),a,tbl); is_arg = 0; } goto cbcb; } case COBJ: if (a->base!=G_CM || nn->tp->check(a->tp,ASSIGN)) a = class_init(0,t1,a,tbl); else if (a->e2->tp!=nn->tp) a->e2=class_init(0,t1,a->e2,tbl); if (nn->n_xref) { // (temp.ctor(arg),&arg) a = a->address(); } else { // defend against: // int f(X); ... X(X&); Pname cln = Pbase(t1)->b_name; if (cln && Pclass(cln->tp)->has_itor()) { // mark X(X&) arguments nn->n_xref = 1; a = a->address(); } } cbcb: //error('d',"cbcb: a %d %k %t",a->base,a->base,a->tp); if (a->base==G_CM) { if (a->e1->base==DEREF) a->e1 = a->e1->e2; // (*e1,e2) => (e1,e2) if (a->e1->base==G_CALL && Pname(a->e1->fct_name) && Pname(a->e1->fct_name)->n_oper==CTOR && (a->e2->base==G_ADDROF || a->e2->base==ADDROF)) { a = a->e1; // (ctor(&tmp),&tmp) => ctor(&tmp) goto cccc; } else if (a->e2->base==G_ADDROF && a->e2->e2->base==NAME) { cccc: if (t1->base==RPTR && Pptr(t1)->typ->tconst()==0) { if (strict_opt) error("temporary used for non-const%tA",nn->tp); else error('w',"temporary used for non-const%tA; no changes will be propagated to actual argument (anachronism)",nn->tp); } } } e->e1 = a; break; case ANY: goto rlab; case PTR: { save_base = e->e1->base; if(a->tp->base==OVERLOAD) save_name = Pgen(a->tp)->fct_list->f->string; Pexpr te_a = a; e->e1 = a = ptr_init(Pptr(t1),a,tbl); no_change = (te_a == a); if (Pchecked == 0) goto def; break; } case CHAR: case SHORT: case INT: { Ptype t = a->tp->skiptypedefs(); switch (t->base) { case LONG: case FLOAT: case DOUBLE: case LDOUBLE: if(!ambig) error('w',"A%d: %t passed as %t",argno,a->tp,t1); } } // no break case LONG: if (Pbase(t1)->b_unsigned && a->base==UMINUS && a->e2->base==ICON) error('w',"negativeA for%n, unsignedX",fn); default: def: { Pexpr x = try_to_coerce(t1,a,"argument",tbl); int ct = no_const; //error('d',"x %d t1 %t nn %t a1 %t",x,t1,nn->tp,a->tp); if (x) { if (t1->is_ptr() && Pchecked == 0 && no_change) { Pexpr te_x = ptr_init(Pptr(t1), x, tbl); if ( te_x != x ) e->e1 = a = te_x; else e->e1=x; } else e->e1 = x; } else if (nn->tp->check(a->tp,ARG)) { error('e',"badA %dT for%n:%t (%tX)",argno,fn,a->tp,nn->tp); if (ct) error('c'," (no usable const conversion)\n"); else error('c',"\n"); return any_type; } } } Pexpr tt = e->e1; while ( tt->base == CAST || tt->base == G_CAST ) tt = tt->e1; if ( tt->base == ILIST ) e->e1 = tt; if (e->e1->base == ILIST) { // memptr constant // f({1,2,f}) ==> memptr t; f((t={1,2,f},t)) if(save_base == REF) { Pptr m = Pptr(a->tp); error( "address of boundF (try using ``%s::*'' forPT and ``&%s::%s'' for address)", m->memof->string, m->memof->string, save_name ); } if (mpt) { Pname temp = make_tmp('A',mptr_type,tbl); e->e1 = mptr_assign(temp,e->e1); e->e1 = a = new expr(G_CM,e->e1,temp); a->tp = temp->tp; } else { Ptype t = e->e1->e1->e1->tp; e->e1 = e->e1->e1->e1; a->tp = e->e1->tp = t; } } } else { if (k != ELLIPSIS) { error("unexpected %dA for%n",argno,fn); return any_type; } if (!a->tp->skiptypedefs()->check(void_type, 0)) error("badA %dT for%n:%t",argno,fn,a->tp); Pexpr te=e; while(e) { if (e->tp) e->tp->tsizeof(); if (e->e1->base == ILIST) { // memptr constant // f({1,2,f}) ==> memptr t; f((t={1,2,f},t)) Pname temp = make_tmp('A',mptr_type,tbl); e->e1 = mptr_assign(temp,e->e1); e->e1 = a = new expr(G_CM,e->e1,temp); a->tp = temp->tp; } e = e->e2; } e = te; goto rlab; } } else { /* default argument? */ a = nn->n_initializer; if (a == 0) { if (fn == 0) error("A %d ofT%tX for call",argno,nn->tp); else error("A %d ofT%tX for%n",argno,nn->tp,fn); return any_type; } if (a->base == ILIST || ((a->base == CAST || a->base == G_CAST) && a->e1->base == ILIST)) { // memptr constant // f({1,2,f}) ==> memptr t; f((t={1,2,f},t)) Pname temp = make_tmp('A',mptr_type,tbl); if (a->base != ILIST) a = a->e1; a = mptr_assign(temp,a); a = new expr(G_CM,a,temp); a->tp = temp->tp; } a->permanent = 2; // ought not be necessary, but it is e = new expr(ELIST,a,0); if (etail) etail->e2 = e; else e2 = e; etail = e; } } rlab: //error('d',"rlab fct_name %n %t",fct_name,fct_name?fct_name->tp:0); for (; e; e = e->e2) { // unchecked arguments Pexpr a = e->e1; Pname cn; if (a->base==NAME && a->tp->base==FCT) { // function name that escaped the type system: // update use count a->lval(ADDROF); } else if (warning_opt && (cn = a->tp->is_cl_obj())) { Pclass cl = Pclass(cn->tp); if (cl->has_ctor() || cl->memtbl->look("__as",0))//cl->has_oper(ASSIGN) { if (fct_name) error('w',"O ofC%t withK or = copied asA to%n (%t)",cl,fct_name,fct_name->tp); else error('w',"O ofC%t withK or = copied asA to `...'",cl); } } else if (a->tp->is_ref()) e->e1 = a->contents(); } if (f->f_result) { // f(args) => (f(&temp,args),temp) Pname oldNtmp = Ntmp; Ntmp = 0; // set in make_tmp if tn has associated dtor Pname tn = make_tmp('R',f->returns,tbl); extern bit in_quest; if (Ntmp) { if (Ntmp_refd && in_quest) { tn->n_list = Ntmp_refd; Ntmp_refd = tn; } else Ntmp_refd = tn; } // better might be: if (Ntmp == 0 && oldNtmp) // but this mimics the old behavior ... if (oldNtmp) Ntmp = oldNtmp; if (Ntmp_refd && in_quest) { Ntmp_flag = make_tmp('Q',int_type,tbl); Ntmp_flag->n_initializer = new ival(0L); Ntmp_flag->assign(); if (Ntmp_flag_list && in_quest) { Ntmp_flag->n_list = Ntmp_flag_list; Ntmp_flag_list = Ntmp_flag; } else Ntmp_flag_list = Ntmp_flag; } e2 = new expr(ELIST,tn->address(),e2); Pexpr ee = new expr(0,0,0); *ee = *this; base = G_CM; // (f(&temp,args),temp) e1 = ee; if (refd == 2) e2 = tn->address(); else e2 = tn; tp = tn->tp; } return t; } Pexpr ref_init(Pptr p, Pexpr init, Ptable tbl) /* initialize the "p" with the "init" remember to call ptr_init to ensure that pointers to second bases are handled correctly. */ { register Ptype it = init->tp->skiptypedefs(); Pptr px = Pptr(p->skiptypedefs()); Ptype p1 = px->typ; Pname c1 = p1->is_cl_obj(); // error('d',"ref_init: p %t, p1 %t, px %t, init->tp %t",p,p1,px,it); // error('d', "ref_init: nof: %n f_const: %d", cc?cc->nof:0, cc?(cc->nof?Pfct(cc->nof->tp)->f_const:0):0); if (init->base == ILIST) error("IrL as RIr"); if (init->base==NAME && Pname(init)->n_scope==ARG && init->tp->base==FLOAT) error('w',"initializing a float& with floatA is non-portable"); Ptype tt = it->addrof(); px->base = PTR; // allow &x for y& when y : public x // but not &char for int& int x = px->check(tt,COERCE); if (x == 0) { //CCC type is fine check for constness: if (init->tp->tconst() && vec_const==0 && fct_const==0) { // not ``it'' if (init->base == ELIST) init = init->e1; if (px->typ->tconst() == 0) if (cc->nof && in_return) error("cannot return a reference to a non-constO from const member function %n",cc->nof); else error("R to constO"); px->base = RPTR; // if we have a const lvalue we can still pass its address ignore_const++; if (init->lval(0)) { init->lval(ADDROF); // force output ignore_const--; //error('d',"in1 %t",init->tp); return ptr_init(px,init->address(),tbl);//return init->address(); } ignore_const--; goto xxx; } px->base = RPTR; if (init->lval(0)) { // can pass the address // no temporary needed init->lval(ADDROF); // force output //error('d',"px %t init %t ",px,init->tp); { Pname name_in_deref =0; Pexpr act_param=0, ret_exp=0; if ((init->base == DEREF) && (init->e1 && (init->e1->base == NAME)) ) { name_in_deref = Pname(init->e1); }; if (name_in_deref && (name_in_deref->n_xref && name_in_deref->n_scope == ARG) ) { //"n_xref" is set when a formal class object //is treated as a pointer object, in Print phase //let us make it as a pointer expression, so //ptr_init logic works correctly (generates //valid MDOT expression when necessary). //But have to watch out while printing "mem" //of MDOT expression in expr::print (print.c). if (init->e1->tp) { act_param = new expr (G_ADDROF, 0, init->e1); act_param->tp = init->e1->tp->addrof(); //error('d',"px %t act_param %t ",px,act_param->tp); ret_exp = ptr_init(px, act_param, tbl); } else { error ("i", "No type for actual param %n", name_in_deref); } } else { ret_exp = ptr_init(px, init->address(),tbl); }; return ret_exp; }; } goto xxx; } px->base = RPTR; //error('d',"c1 %n",c1); if (c1) { // assigning to a const X & is fine ref_cast++; Pexpr x = try_to_coerce(p,init,"reference initialization",tbl); ref_cast--; if (x) { init = x; goto xxx; } if (init->tp->tconst() && !vec_const && !p1->tconst()) { error("R to constO"); return init; } switch ( init->base ) { case STRING: case ZERO: case CCON: case ICON: case FCON: case IVAL: case NAME: refd = 1; break; default: refd = (init->e1 && init->e1->base == NAME && init->e1->tp->base != RPTR && Pname(init->e1)->n_xref == 0) ? 2: 1; break; } // error('d', "***** refd: %d", refd ); Pexpr a = class_init(0,p1,init,tbl); refd = 0; if (a==init && init->tp!=any_type) goto xxx; // error('d',"ri a %d %k",a->base,a->base); switch (a->base) { case G_CALL: init = a; goto xxx; } switch (init->base) { case CM: case G_CM: break; case NAME: case DEREF: case REF: case DOT: if ((it->tconst()==0 || vec_const) && (fct_const==0 || p1->is_ptr()==0) ) break; default: if (p1 && p1->b_const==0) { if (tbl == gtbl || (strict_opt && !is_arg)) error("Ir for%snon-constR not an lvalue", strict_opt?"":" global "); else if(!is_arg) error('w',"Ir for non-constR not an lvalue (anachronism)"); } } a = a->address(); a = ptr_init(px,a,tbl); return a; } //error('d',"p1 %t it %t",p1,it); if (p1->check(it,0)) { if (p1->check(it,ASSIGN) == 0) { goto def; } Pexpr x = try_to_coerce(p1,init,"reference",tbl); // x==init if (x==0) x = try_to_coerce(px,init,"reference",tbl); // x&=init if (x) { init = x; goto def; } int nc = no_const; Pptr p1_ptr = p1->is_ptr(); if (p1_ptr && p1_ptr->typ->skiptypedefs()->base == FCT && it->is_or_pts_to(OVERLOAD) ) { Pexpr op = ptof( Pfct(p1_ptr->typ->skiptypedefs()), init, tbl ); if(op) {init = op; goto def; } } error('e',"badIrT:%t (%tX)",it,p); if (nc) error('c'," (no usable const conversion)\n"); else error('c',"\n"); if (init->base != NAME) init->tp = any_type; return init; } xxx: /* here comes the test of a ``fundamental theorem'': a structure valued expression is (1) an lvalue of type T (possibly const) or (2) the result of a function (a _result if X(X&) is defined) or (3) a * or [] or ? or , expression */ //error('d',"xxx %k %d %t",init->base,init->base,init->tp); switch (init->base) { case NAME: case DEREF: case REF: case DOT: // init => &init { bit it_isconst = it->tconst(); bit vec_const_save = vec_const; bit fct_const_save = fct_const; if ( (init->base==NAME && Pname(init)->n_stclass==ENUM) || it_isconst && Pbase(p->typ) && !Pbase(p->typ)->tconst() && vec_const_save==0 && fct_const_save==0 ) { goto def; } init->lval(ADDROF); if (vec_const_save) return init; if (fct_const_save && p1->is_ptr()) goto def; // fptr& = fct } // no break case CM: case G_CM: // & (f(&temp), temp) return ptr_init(px,init->address(),tbl);//init->address(); default: def: { // error('d',"def: init->tp %t p1 %t ",init->tp,p1); if (p1 && p1->b_const==0) { if (tbl == gtbl || (strict_opt && !is_arg)) error("Ir for%snon-constR not an lvalue", strict_opt?"":" global "); else if(!is_arg) error('w',"Ir for non-constR not an lvalue (anachronism)"); } Pname tcl = p1->is_cl_obj (); if(tcl && Pclass(tcl->tp)->c_abstract) { error("a temporary is needed for a parameter, but the AT is abstractC %t.", tcl->tp); error('C',"%a is a pure virtualF ofC%t",Pclass(tcl->tp)->c_abstract,tcl->tp); } no_sti=1; Pname n = make_tmp('I', unconst_type(p1), tbl); no_sti=0; n->assign(); if (tbl == gtbl) n->dcl_print(0); // a hack Pexpr a = 0; Pname ic = init->tp->is_cl_obj(); switch (p1->base) { case INT: case CHAR: case SHORT: switch (it->base) { case LONG: case FLOAT: case DOUBLE: case LDOUBLE: error('w',"%t assigned to %t inRIr",it,p1); } } if (ic && c1 && ic!=c1 && !same_class(Pclass(ic->tp),Pclass(c1->tp))) { // derived class1 => must cast: ``it Ix; (Ix=init,(p)&Ix);'' n->tp = init->tp; a = ptr_init(px,n->address(),tbl);//n->address(); PERM(p); a = new texpr(G_CAST,p,a); a->tp = p; } else if (!ic && !c1 && init->tp->is_ptr() && p1->is_ptr()) { Pname icx = (Pptr(init->tp->skiptypedefs()))->typ->is_cl_obj(); Pname c1x = (Pptr(p1->skiptypedefs()))->typ->is_cl_obj(); if (icx && c1x && icx!=c1x && !same_class(Pclass(icx->tp),Pclass(c1x->tp))) { // Base*const& = Derived* init = ptr_init(Pptr(p1->skiptypedefs()),init,tbl); } } if (!a) a = n->address(); refd = 1; Pexpr as; if (init->tp->memptr() || init->tp->base == FCT && Pfct(init->tp)->memof ) { Ptype pit = p->typ->skiptypedefs(); as = mptr_assign(n,ptof(Pfct(pit),init,tbl)); } else { as = init_tmp(n,init,tbl); } refd = 0; a = new expr(G_CM,as,a); a->tp = a->e2->tp; return a; } } } Pexpr class_init(Pexpr nn, Ptype tt, Pexpr init, Ptable tbl) /* initialize "nn" of type "tt" with "init" if nn==0 make a temporary, nn may not be a name */ { if (init == dummy) return 0; //error('d',"class_init %t with %t init %k refd %d",tt,init->tp,init->base,refd); Pname c1 = tt->is_cl_obj(); if (init == 0) { error("emptyIr"); return dummy; } if (c1) { Pclass cl = Pclass(c1->tp); Pname c2 = init->tp->is_cl_obj(); if ((c1!=c2 && (c2 == 0 || same_class(cl,Pclass(c2->tp),1) == 0)) || (refd==0 && cl->has_itor())) { // really ought to make a temp if refd, // but ref_init can do that int i = can_coerce(tt,init->tp); //error('d',"i %d nn %n",i,nn); switch (i) { default: error("%d ways of making a%n from a%t",i,c1,init->tp); init->tp = any_type; return init; case 0: if (c2 && Pclass(c2->tp)->has_base(cl)) { init = init->address(); Pexpr x = cast_cptr(cl,init,tbl,0); if (x == init) { Ptype pt = tt->addrof(); PERM(pt); x = new cast(pt,init); } return x->contents(); } error("cannot make a%t from a%t",cl,init->tp); init->tp = any_type; return init; case 1: //error('d',"ncoerce %n %k %d",Ncoerce,init->base,init->base); if (Ncoerce == 0) { Pexpr a = new expr(ELIST,init,0); a = new texpr(VALUE,tt->skiptypedefs(),a); a->e2 = nn; a = a->typ(tbl); //error('d',"ci a %k %d %t",a->base,a->base,a->tp); return a; } switch (init->base) { case CM: case G_CM: //ddd case NAME: /* init.coerce() */ /* *ref */ case DEREF: { Pref r = new ref(DOT,init,new name(Ncoerce->string)); Pexpr rr = r->typ(tbl); init = new expr(G_CALL,rr,0); break; } default: // (temp=init,temp.coerce()) { Pname tmp = make_tmp('U',init->tp,tbl); int x = refd; refd = 0; // ?? Pexpr ass = init_tmp(tmp,init,tbl); refd = x; Pref r = new ref(DOT,tmp,new name(Ncoerce->string)); Pexpr rr = r->typ(tbl); Pexpr c = new expr(G_CALL,rr,0); c = c->typ(tbl); init = new expr(CM,ass,c); init->tp = c->tp; if (refd) { // &f() => (t=f(), &t) Pname tmp2 = make_tmp('L',c->tp,tbl); ass = init_tmp(tmp2,init,tbl); init = new expr(G_CM,ass,tmp2); } } } //error('d',"nn %n",nn); if (nn) { Pexpr a = new expr(ELIST,init,0); a = new texpr(VALUE,tt->skiptypedefs(),a); a->e2 = nn; return a->typ(tbl); } } //error('d',"c1 %n c2 %n",c1,c2); return init->typ(tbl); } return init; } //error('d',"ci check tt %t init->tp %t",tt,init->tp); if (tt->check(init->tp,ASSIGN) && refd==0) { error("badIrT:%t (%tX)",init->tp,tt); init->tp = any_type; } return init; } extern int bound; // fudge for bound pointers to functions Pexpr expr::docast(Ptable tbl) { // check cast against value, INCOMPLETE //error('d',"docast %d %t %k",this,tp2,e1->base); if (e1 == dummy) { error("E missing for cast"); tp = any_type; return this; } int pmf = 0; int ptom_cast = 0; int noconst = 0; Pexpr ee = e1; //error('d',"ee %k %d",ee->base,ee->base); switch (ee->base) { case ADDROF: ee = ee->e2; switch (ee->base) { case NAME: goto nm; case REF: goto rf; } break; case NAME: nm: if (Pname(ee)->n_qualifier) pmf = 1; break; case REF: rf: if (ee->e1->base == THIS) bound = 1; break; } e1 = e1->typ(tbl); int b = bound; // distinguish between explicit and implicit THIS bound = 0; //pmf = pmf && e1->base==CAST; pmf = pmf && ((e1->base==CAST || e1->base==G_CAST) || e1->base==ILIST); Ptype etp = e1->tp->skiptypedefs(); Ptype tt = tp2; Ptype t = tt; tt->dcl(tbl); tt = tt->skiptypedefs(); //error('d',"e1 %k etp %t tt %t",e1->base,etp,tt); bit isptm = 0; switch (etp->base) { case PTR: if (!etp->memptr()) break; if (etp->memptr()->f_static) break; isptm = 1; break; case FCT: if (!Pfct(etp)->memof) break; if (Pfct(etp)->f_static) break; isptm = 1; break; case ILIST: isptm = 1; break; } if (isptm && !tt->memptr() && tt->base != VOID) error(strict_opt ? 0 : 'w', "cast to%t ofP toM (anachronism)", tt); switch (etp->base) { case PTR: case RPTR: if (Pptr(etp)->typ->base == OVERLOAD) goto over; if (Pptr(etp)->typ->base == FCT && Pfct(Pptr(etp)->typ)->fct_base) goto over; if (warning_opt && i2==0 && Pptr(etp)->typ->tconst()) { switch (tt->base) { case FCT: break; case PTR: case RPTR: if (Pptr(tt)->typ->tconst()) break; default: // casting away const // should be an error // but ANSI says OK so I chicken out // to be able to compile strtok(), etc. error('w',"const cast away:%t->%t",e1->tp,tp2); } } else i2 = 0; // to allow cfront to escape its own checking break; case COBJ: { ref_cast = 1; Pexpr x = try_to_coerce(tt,e1,"cast",tbl); if (!x && tt->base == EOBJ) x = try_to_coerce(int_type, e1, "cast", tbl); noconst = no_const; ref_cast = 0; //error('d',"x %k %t tt %d %t",x?x->base:0,x?x->tp:0,tt,tt); if (x) { if (x!=e1 && x->base==DEREF && tt->is_ref()) x = x->e1; if (tt==x->tp || tt->check(x->tp,0)==0 || const_problem) return x; else return new cast(tt,x); } break; } case VOID: if (tt->base == VOID) { tp = t; return this; } error("cast of void value"); // no break; case ANY: any: tp = any_type; return this; case FCT: if (tt->base == PTR && Pptr(tt)->typ->base != FCT) error('w',"P toF cast toP to nonF"); if (Pfct(etp)->fct_base) goto over; break; case OVERLOAD: over: error("cast of overloaded"); goto any; } //error('d',"tt %t",tt); switch (tt->base) { case VEC: error("cast to arrayT %t", tt); break; case PTR: if (tt->memptr()) { if (etp->memptr() == 0 && (etp->base!=FCT || Pfct(etp)->memof == 0) ) { if (etp->base == ZTYPE) { e1 = new expr(ELIST,zero,zero); e1 = new expr(ILIST,e1,zero); e1->tp = tt; return e1; } error("cast toP toM %t",tt); } else { // adjust delta in MI case // for the moment just suppress the cast // all pmfs are the same to cc ptom_cast = 1; tp2 = mptr_type; } } switch (etp->base) { case COBJ: error('e',"cannot castCO toP"); if (noconst) error('c'," (no usable const conversion)\n"); else error('c',"\n"); break; case FCT: e1 = new expr(G_ADDROF,0,e1); bound = b; e1 = e1->typ(tbl); bound = 0; if (e1->base == CAST || e1->base == G_CAST) pmf = 1; else break; // no break; case RPTR: case PTR: { Pname cn = Pptr(tt)->typ->is_cl_obj(); if (cn) { Pexpr x = cast_cptr(Pclass(cn->tp),e1,tbl,base==CAST?1:0); if (x == e1) { PERM(tt); e1 = new cast(tt,e1); e1->i2 = i2; } else e1 = x; } if (pmf) { tt = tt->skiptypedefs(); switch (tt->base) { case PTR: if (Pptr(tt)->memof) break; default: error("%t cast to%t (%t is not aP toM)",e1->tp,tp2,tp2); } } } } break; case RPTR: // (x&)e: pretend e is an x { Ptype er = etp; Ptype cr = tt; do { if (er = er->is_ptr_or_ref()) er = Pptr(er)->typ; if (cr = cr->is_ptr_or_ref()) cr = Pptr(cr)->typ; } while (er && cr); int pp = er!=0; // if `e' is a suitable pointer cast it: // (x&)e => (x*)e, otherwise // (x&)e => *(x*)&e // error('d',"rptr tt %t e1->base %k e1->tp %t",tt,e1->base,e1->tp); if (e1->base==G_CM || e1->base==CALL || e1->base==G_CALL || e1->lval(0)) ; else if (e1->tp->tconst()) { // casting away const // should be an error // but ANSI says OK so I chicken out // to be able to compile strtok(), etc. if (warning_opt && Pptr(tt)->typ->tconst()==0) error('w',"const cast away:%t->%t",e1->tp,tp2); } else error("cannot cast%t to%t",etp,t); //error('d',"e1 %k %t %d",e1->base,e1->tp,pp); if (pp == 0) e1 = e1->address(); // *(x*)&e tp = t; // do proper pointer manipulation for multiple inheritance Pname cn = Pptr(tt)->typ->is_cl_obj(); if (cn) { Pexpr x = cast_cptr(Pclass(cn->tp),e1,tbl,base==CAST?1:0); if (x == e1) { PERM(tt); e1 = new cast(tt,e1); e1->i2 = i2; } else e1 = x; } return pp ? this : contents(); } case COBJ: base = VALUE; // (x)e => x(e): construct an x from e e1 = new expr(ELIST,e1,0); return typ(tbl); case CHAR: case INT: case SHORT: case LONG: case EOBJ: switch (etp->base) { case FCT: e1 = new expr(ADDROF,0,e1); e1 = e1->typ(tbl); case PTR: if(!e1->tp->memptr() && e1->tp->tsizeof()>tt->tsizeof()) error("type ``%t'' not large enough for values of ``%t ''",tt,etp); break; case COBJ: error('e',"cannot castCO to%k",tt->base); if (noconst) error('c'," (no usable const conversion)\n"); else error('c',"\n"); break; } break; case FLOAT: case DOUBLE: case LDOUBLE: switch (etp->base) { case FLOAT: case DOUBLE: case LDOUBLE: case CHAR: case INT: case SHORT: case LONG: case EOBJ: case ZTYPE: break; default: error("cannot cast ``%t '' to ``%t''",etp,tt); break; } break; case FCT: error("cannot cast toFT"); break; } tp = t; if (e1->base==ILIST && ptom_cast==0) { // ptm constant Pexpr ee = e1->e1; // ELIST int i; switch (ee->e2->base) { case IVAL: i = int(ee->e2->i1); break; case ZERO: i = 0; } if (i<0) e1 = e1->e2; // just the function else e1 = ee->e2; // just the index return this; } if (etp->memptr()) { Pclass cl = Pptr(etp)->memof; if (Pptr(tt)->memof==0 && b == 0 ) { Pexpr y; if((e1->base == G_CAST || e1->base == CAST) && e1->e1->base == ILIST) { e1 = e1->e1; y = e1->e2; } else { y = new mdot("f",e1); y->i1 = 9; } y = new cast(tt,y); if (cl->virt_count && b==0) { // ERROR: no check for side effects Pexpr z = new mdot("i",e1); Pexpr x = new mdot("i",e1); x->i1 = 9; x = new cast(tt,x); z->i1 = 9; Pexpr q = new expr (QUEST,x,y); q->cond = new expr(LE,zero,z); q->tp = tt; delete this; return q; } delete this; return y; } } return this; } Pexpr expr::dovalue(Ptable tbl) { Ptype tt = tp2; Pclass cl; Pname cn; // error('d',"value %d %t e1 %d e2 %d",tt,tt,e1,e2); tt->dcl(tbl); tt = tt->skiptypedefs(); switch (tt->base) { case EOBJ: default: if (e1 == 0) { //error("value missing in conversion to%t",tt); e1 = zero; } else { // convert elist to expr if ( e1->e2 == 0 ) { e1 = e1->e1; if (e1->base==NAME && e1->permanent == 0) PERM(e1); } else { // int( x, y ) error("more than oneA for basicTK"); for ( Pexpr e = e1; e->e2->e2; e = e->e2 ) e->base = CM; e->base = CM; e->e2 = e->e2->e1; } } base = G_CAST; return typ(tbl); case CLASS: cl = Pclass(tt); if (cl->this_type) tp2 = Pptr(cl->this_type)->typ; break; case COBJ: cn = Pbase(tt)->b_name; cl = Pclass(cn->tp); } Pname ctor = cl->has_ctor(); //error('d',"e1 %k e1->e2 %k",e1->base,e1?e1->e2->base:0); if (e1 && e1->e2==0) { // single argument if (e1->e1->base==ELIST) e1->e1 = e1->e1->e1; // spurious elist e1->e1 = e1->e1->typ(tbl); if (tt->base==COBJ) { Pexpr x = try_to_coerce(tt,e1->e1,"type conversion",tbl); if (cl->has_itor()==0) { if (x) return x; } else { if (x && x->base != DEREF) return x; } } Pname acn = e1->e1->tp->is_cl_obj(); //error('d',"acn %n %d",acn,cl->has_itor()); if (acn && cl->has_itor()==0) { Pclass acl = Pclass(acn->tp); int hb = acl->has_base(cl); // special case handling: Base(Derived); if (ctor && hb) { Pname n = 0; switch (ctor->tp->base) { case OVERLOAD: n = Pgen(ctor->tp)->exactMatch(e1,0); if (n) ctor = n; break; case FCT: // improbable ever be traversed { Pfct f = Pfct(ctor->tp); if ( f->nargs != 1 ) break; n = exact1(f->argtype,e1->e1->tp) ? ctor : 0; break; } } if (n) goto mk_ctor_call; } if (same_class(acl,cl) || hb) { vcllist->clear(); vcllist=0; if (1string,0)) error("ambiguous assignment to base %t",cl); Pexpr ee = e1->e1; if (ee->base == ELIST) ee = ee->e1; // ??? if (hb) { // ee => *(tp2*)&ee // remember = may be overloaded //error('d',"hb %k %t %d",ee->base,ee->tp,ee->lval(0)); ignore_const++; if (ee->lval(0)==0) { Pname tmp = make_tmp('T',ee->tp,tbl); ee = init_tmp(tmp,ee,tbl); ee = new expr(G_CM,ee,tmp->address()); } else ee = ee->address(); ignore_const--; ee = new texpr(G_CAST,new ptr(PTR,tp2),ee); //new cast(new ptr(PTR,tp2),ee); ee = ee->contents(); ee->typ(tbl); } if (e2) { // x(x_obj) => e2=x_obj base = ASSIGN; e1 = e2; e2 = ee; tp = tp2; return this; } return ee; // strip ELIST: x(x_obj) => x_obj } } } /* x(a) => obj.ctor(a); where e1==obj */ if (ctor == 0) { error("cannot make a%t",cl); return dummy; } // error('d',"e2 %k",e2?e2->base:0); mk_ctor_call: // beats duplicating the code if (e2 == 0) { // x(a) => x temp; (temp.x(a),temp) if (e1 && e1->e1 && !e1->e2) { char* s = e1->e1->string; if (s && s[0] == '_' && s[1] == '_' && s[2] == 'V' && e1->e1->tp && tp2 && !e1->e1->tp->check(tp2, 0)) return e1; } no_sti = 1; Ntmp = 0; Pname n = make_tmp('V',tp2,tbl); no_sti = 0; n->assign(); if (tbl == gtbl) n->dcl_print(0); // a hack Pexpr c = call_ctor(tbl,n,ctor,e1,DOT); extern bit in_quest; if (Ntmp && in_quest) { if (Ntmp_refd) { n->n_list = Ntmp_refd; Ntmp_refd = n; } else Ntmp_refd = n; Ntmp_flag = make_tmp('Q',int_type,tbl); Ntmp_flag->n_initializer = new ival(0L); Ntmp_flag->assign(); if (Ntmp_flag_list) { Ntmp_flag->n_list = Ntmp_flag_list; Ntmp_flag_list = Ntmp_flag; } else Ntmp_flag_list = Ntmp_flag; Pexpr e = new expr(ASSIGN,Ntmp_flag,one); e->tp = int_type; Ptype t = c->tp; Ntmp_flag = 0; c = new expr(G_CM,e,c); c->tp = t; } c = new expr(G_CM,c,n); c->tp = n->tp; return c; } else { Pexpr c = call_ctor(tbl,e2,ctor,e1,DOT); c = new expr(DEREF,c,0); // deref value returned by constructor c->tp = c->e1->tp; return c; } } Pname gen::exactMatch(Pexpr arg, int constObj) /* look through this gen for an exact match with arg if found, return it; if ambiguous, issue error and return dummy function if not found, return 0; */ { if (pure_templ()) return 0; // only holds templates register Plist gl; register int ok; Block(Pname) funVec; register int numEx = 0; for (gl=fct_list; gl; gl=gl->l) { register Pname nn = gl->f; if (nn->is_template_fct()) continue; Pfct f = nn->fct_type(); register Pname n = f->argtype; if(constObj && nn->n_oper!=CTOR && !f->f_const && !f->f_static){ non_const++; continue; } ok = 0; if (!arg) ok = 1; else { for(Pexpr e=arg; e; e=e->e2, n=n->n_list) { if (!n && f->nargs_known!=ELLIPSIS) break; Pexpr a = e->e1; Ptype at = a->tp; if(at->base == ANY) break; if (at->base == ZTYPE) at = int_type; if (!exact1(n,at)) break; if (!e->e2) ok = 1; } } if(!ok || n && !n->n_initializer) continue; funVec.reserve(numEx+1); funVec[numEx++] = nn; } if (!numEx) return 0; if (numEx==1) return funVec[0]; // see if ``const'' break ties Bits bestOnes = ~(Bits(0,numEx)); return breakTie(funVec,bestOnes,arg,constObj); } Pname gen::oneArgMatch(Pexpr aarg, int constObj) /* for a call with one argument: look through this gen for the best match for arg if found, return it; if ambiguous, issue error and return dummy function if not found, return 0; */ { if (pure_templ()) return 0; register Plist gl; int numFunc = 0; Block(Pname) ArgVec; Block(Pname) funVec; Pname fn = fct_list->f; for (gl=fct_list; gl; gl=gl->l) { Pname nn = gl->f; Pfct ft = nn->fct_type(); Pname nnargs = ft->argtype; if (nn->is_template_fct()) continue; if(constObj && fn->n_oper!=CTOR && !ft->f_const && !ft->f_static) { non_const++; continue; } if (!nnargs && ft->nargs_known != ELLIPSIS) continue; if (nnargs && nnargs->n_list && !nnargs->n_list->n_initializer) continue; ArgVec.reserve(numFunc+1); funVec.reserve(numFunc+1); ArgVec[numFunc] = nnargs ? nnargs : (Pname)ELLIPSIS; funVec[numFunc++] = nn; } if(!numFunc) return 0; Bits bestOnes = bestMatch(ArgVec, numFunc, aarg->e1->tp); int numFuncs = bestOnes.count(); if(!numFuncs) return 0; if(numFuncs == 1) return funVec[bestOnes.signif() - 1]; return breakTie(funVec,bestOnes,aarg,constObj); } Pname gen::multArgMatch(Pexpr arg, int constObj) /* for a call with multiple arguments: look through this gen for the best match for arg if found, return it; if ambiguous, issue error and return dummy function if not found, return 0; */ { if (pure_templ()) return 0; int numargs = 1; Pexpr tmp = arg; if(!tmp) return 0; while((tmp=tmp->e2)) numargs++; Block(BlockPname) intFun(numargs); miFlag = 0; register int numFunc = 0; Block(Pname) funVec; for (Plist gl=fct_list; gl; gl=gl->l) { register Pname nn = gl->f; if (nn->is_template_fct()) continue; // first weed out unmatchable functions if (!matchable(nn,arg,constObj)) continue; // store types in ``matrix'' for bestMatching register int ai = 0; Pfct tf = nn->fct_type(); funVec.reserve(numFunc+1); funVec[numFunc] = nn; for (Pname x=tf->argtype; x&&ain_list) { intFun[ai].reserve(numFunc+1); intFun[ai][numFunc] = x; ai++; } // extend ellipsis arguments if(tf->nargs_known == ELLIPSIS) { while(ai < numargs) { intFun[ai].reserve(numFunc+1); intFun[ai++][numFunc] = (Pname)ELLIPSIS; } } numFunc++; } // no matchable functions if(numFunc == 0) return 0; // finished: only one matchable function if(numFunc == 1) return funVec[0]; // more matchable functions: need intersect rule if(numFunc > 1) { Bits bestFuncs = intersectRule(intFun,numFunc,arg); Pname best = 0; register int sigbit = bestFuncs.signif() - 1; switch(bestFuncs.count()) { case 0: // null intersection fmError(1,funVec,arg,constObj); best = funVec[0]; break; default: //multiple elements in intersection best = breakTie(funVec,bestFuncs,arg,constObj); sigbit = bestFuncs.signif() - 1; case 1: // one element in intersection // before or after breakTie if (miFlag==1 && numFunc > 2) { // suspect: need simple rule for(int K = 0; K < numFunc; K++) { if(K == sigbit) continue; int gotit = 0; Pexpr targ = arg; for(int I=0;Ie1->tp)) { gotit = 1; break; } targ = targ->e2; } if(!gotit) { if(!best) { fmError(1,funVec,arg,constObj); break; } Bits temp = bestFuncs; bestFuncs.set(K); if(breakTie( funVec, temp, arg, constObj)!=funVec[sigbit]) { fmError(1,funVec,arg,constObj); break; } } } } best = funVec[sigbit]; } return best; } error('i', "fall off end of gen::multArgMatch()"); return 0; } Bits bestMatch(const Block(Pname)& AV, int nav, Ptype at) /* find the indices of the elements of AV which best match at. return a Bits with bits set which correspond to these indices */ { Bits zeroBits(0,nav); Bits result = zeroBits; Block(int) rate(nav); Block(Pname) udcBlock(nav); int i = -1; while(++i < nav) { Pname aa = AV[i]; if(aa == 0) continue; if(aa == (Pname)ELLIPSIS) { rate[i] = ELLIP; continue; } Ptype t1 = aa->tp; if (t1==at || exact1(aa,at)) { rate[i] = EXACT; continue; } if (exact2(aa,at)) { rate[i] = PROM; continue; } if (exact3(aa,at)) { rate[i] = STD; continue; } int cc = can_coerce(t1,at); if (cc == 1) { udcBlock[i] = Ncoerce; rate[i] = UDC; continue; } rate[i] = NONE; } int max = NONE; for(i=0;i max ) { max = rate[i]; result = zeroBits; } if( rate[i] && rate[i] == max ) { result.set(i); } } if (result.count() <= 1) return result; // break ties for STD's involving inheritance if (max == STD ) { if(at->is_ptr_or_ref()) at = Pptr(at)->typ; if (!at->is_cl_obj()) return result; Bits tempBits = result; tempBits.reset(tempBits.signif() - 1); // nice little algo to find ``real'' best matches // taking derivation and MI into account while(tempBits.count()) { int tempPtr = tempBits.signif() - 1; Ptype t1 = AV[tempPtr]->tp; Pptr p_t1 = t1->is_ptr(); for(int k = nav - 1; k > tempPtr; k--) { if(!result[k]) continue; Ptype t2 = AV[k]->tp; if (t1->check(t2,0)==0 || const_problem) continue; int r = pr_dominate(t1,t2); Pptr p_t2 = t2->is_ptr(); if (r==1 || p_t2 && p_t2->typ->base==VOID) { result.reset(k); } if (r==2 || p_t1 && p_t1->typ->base==VOID) { result.reset(tempPtr); break; } if(r==0 && miFlag==0) miFlag = 1; } tempBits.reset(tempPtr); } } // find UDC sequences which are prefix's of others if (max == UDC ) { Bits tempBits = result; int sigbit = tempBits.signif() - 1; tempBits.reset(sigbit); while(tempBits.count()) { int tempPtr = tempBits.signif() - 1; Pname tname = AV[tempPtr]; bit done = 0; for(int k = nav - 1; k > tempPtr; k--) { if(!result[k] || !udcBlock[k]) continue; if (udcBlock[k]->tp->base == OVERLOAD) { for (Plist gl = Pgen(udcBlock[k]->tp)->fct_list; gl; gl=gl->l) { Ptype tt = gl->f->fct_type()->returns; Pname r = udcBlock[tempPtr]==udcBlock[k] ? bestOfPair(tname,AV[k],tt) : 0; if (r==tname) result.reset(k); if (r==AV[k]) { result.reset(tempPtr); done = 1; break; } } } else { Ptype tt = udcBlock[k]->fct_type()->returns; Pname r = udcBlock[tempPtr]==udcBlock[k] ? bestOfPair(tname,AV[k],tt) : 0; if (r==tname) result.reset(k); if (r==AV[k]) { result.reset(tempPtr); break; } } if (done) break; } tempBits.reset(tempPtr); } } return result; } Pname bestOfPair(Pname a1, Pname a2, Ptype at) /* return the bestMatch of a pair of names to at if one exists. otherwise, return 0; */ { if(a1->tp == a2->tp) return 0; Block(Pname) tryBlock(3); tryBlock[0] = a1; tryBlock[1] = a2; Bits bestBits = bestMatch(tryBlock,2,at); if (bestBits.count()==1) { return tryBlock[bestBits.signif() - 1]; } return 0; } Bits intersectRule(const Block(BlockPname)& intFun, int numFunc, Pexpr arg) /* intersect rule */ { Bits zeroBits(0,numFunc); Bits result = ~zeroBits; int ai = 0; for(Pexpr aargu = arg; aargu; aargu = aargu->e2) { Ptype at = aargu->e1->tp; Bits tryit = bestMatch(intFun[ai++],numFunc,at); if(tryit.count()==1) miFlag = -1; result &= tryit; if(!result.count()) { return zeroBits; } } return result; } Pname breakTie(const Block(Pname)& FV,Bits& bestOnes,Pexpr arg,int cO) /* all functions in Block are equal after the intersect rule use a mini-intersect rule on the array to see if one dominates all others when trivial conversions involving const are considered. if so, return it; if not, issue ambiguity error and return any function */ { register int numFunc = bestOnes.size(); Bits zeroBits(0,numFunc); Bits result = ~zeroBits; Block(Pname) rfunc(numFunc); int i = 0; while(FV[i]) { if(bestOnes[i]) rfunc[i]=FV[i]->fct_type()->argtype; i++; } int stat = FV[bestOnes.signif()-1]->fct_type()->f_static; for(int k = 0; k < numFunc; k++) { if(bestOnes[k]) { if(stat != FV[k]->fct_type()->f_static) { fmError(1,FV,arg,cO); miFlag = 0; return FV[bestOnes.signif() - 1]; } } } // see if ``const'' breaks tie for(Pexpr aargu = arg; aargu; aargu = aargu->e2) { Ptype at = aargu->e1->tp; // best_const Bits temp = best_const(rfunc,numFunc,at); if(temp.count()) result &= temp; if(!result.count()) break; for(int k = 0; k < numFunc; k++) { if(rfunc[k]) rfunc[k] = rfunc[k]->n_list; } } Pfct pf = FV[0]->fct_type(); if(result.count()>=1 && pf->memof) { // && FV[0]->n_oper != CTOR) { Bits temp = zeroBits; for(int k = 0; k < numFunc; k++) { if(bestOnes[k]) { if(stat != FV[k]->fct_type()->f_static) { result = zeroBits; break; } if(cO == FV[k]->fct_type()->f_const) temp.set(k); } } if(temp.count()) result &= temp; } if(result.count()==0 || result.count()>=2) { fmError(1,FV,arg,cO); miFlag = 0; } else bestOnes = result; return FV[bestOnes.signif() - 1]; } Bits best_const(const Block(Pname)& CONV, int nfound, Ptype at) { Bits zeroBits(0,nfound); Bits result = ~zeroBits; Bits tempBits = ~zeroBits; int sigbit = tempBits.signif() - 1; tempBits.reset(sigbit); for (int i=0; i tempPtr; k--) { if(!result[k]) continue; Pname t2name = CONV[k]; Ptype t1 = t1name->tp; Ptype t2 = t2name->tp; Pptr p1=t1->is_ref(),p2=t2->is_ref(); if (p1 && !p2) t1 = p1->typ; if (p2 && !p1) t2 = p2->typ; p1=t1->is_ptr(),p2=t2->is_ptr(); if (p1 && p2) { if (at->check(t1,OVERLOAD)==0 && at->check(t2,OVERLOAD) ) result.reset(k); else if (at->check(t1,OVERLOAD) && at->check(t2,OVERLOAD)==0 ) { result.reset(tempPtr); break; } } else { Pptr p1=t1->is_ref(); Pptr p2=t2->is_ref(); if (p1 && p2) { if (at->check(p1->typ,OVERLOAD)==0 && at->check(p2->typ,OVERLOAD) ) result.reset(k); else if ( at->check(p1->typ,OVERLOAD) && at->check(p2->typ,OVERLOAD)==0 ) { result.reset(tempPtr); break; } } } } tempBits.reset(tempPtr); } return result; } void fmError(int errorKind, const Block(Pname)& FV, Pexpr arg, bit co) { Pname fn = FV[0]->tp->base==OVERLOAD ? Pgen(FV[0]->tp)->fct_list->f : FV[0]; switch (errorKind) { case 0: error('e',"no match for call: "); break; case 1: ambig = 1; error('e',"ambiguous call: "); break; } // call Pclass tmp = fn->get_fct()->memof; if (tmp) error('c',"%s %t* -> ",co?"const":"",tmp); if(fn->n_oper && fn->n_oper!=CTOR) error('c',"operator %s(",keys[fn->n_oper]); else if(fn->n_oper==CTOR) { error('c',"%t::%t(",tmp,tmp); } else error('c',"%s(",fn->string); if(arg) { Pexpr tmp = arg; error('c',"%t",tmp->e1->tp->skiptypedefs()); while((tmp=tmp->e2)) { error('c',",%t",tmp->e1->tp->skiptypedefs()); } } error('c',")\n"); // possible functions error('C',"choice of%ns:\n",fn); if(FV[0]->tp->base == OVERLOAD) { int num_templ=0; int no_const=0; int num_all=0; for(Plist gl = Pgen(FV[0]->tp)->fct_list;gl;gl=gl->l) { if(gl->f->is_template_fct()) { num_templ++; } else error('C'," %a;\n",gl->f); if (co && !Pfct(gl->f->tp)->f_const) no_const++; num_all++; } if(num_templ) { error( 'C', " %d template version%s;\n", num_templ, num_templ==1 ? "" : "s" ); } if(no_const == num_all) error('C',"(no usable const member function)\n"); return; } int numFunc = FV.size(); for(int i=0; i