|
|
1.1 root 1: /*ident "@(#)ctrans:src/simpl2.c 1.2.6.50" */
2: /******************************************************************
3:
4: C++ source for cfront, the C++ compiler front-end
5: written in the computer science research center of Bell Labs
6:
7: Copyright (c) 1984 AT&T, Inc. All rigths Reserved
8: THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T, INC.
9:
10: simpl2.c:
11:
12: simplify the typechecked function
13: remove: classes:
14: class fct-calls
15: operators
16: value constructors and destructors
17: new and delete operators (replace with function calls)
18: initializers (turn them into statements)
19: constant expressions (evaluate them)
20: inline functions (expand the calls)
21: enums (make const ints)
22: unreachable code (delete it)
23: make implicit coersions explicit
24:
25: in general you cannot simplify something twice
26:
27: *******************************************************************/
28:
29: #include "cfront.h"
30: #include "size.h"
31: #include <ctype.h>
32:
33: extern Pname Ntmp;
34: Pname find_vptr(Pclass);
35:
36: extern int no_of_returns;
37:
38: extern Pname new_fct;
39: //extern Pname del_fct;
40:
41: extern Pstmt del_list;
42: extern Pstmt break_del_list;
43: extern Pstmt continue_del_list;
44:
45: extern Pname curr_fct; // current function
46: extern Pexpr init_list;
47: extern loc no_where;
48: extern int imeasure;
49:
50: Pexpr cdvec(Pname f, Pexpr vec, Pclass cl, Pname cd, int tail, Pexpr i, Pexpr vec2)
51: /*
52: generate a call to construct or destroy the elements of a vector
53: */
54: {
55: Pexpr sz = new texpr(SIZEOF,cl,0); // sizeof elem
56: sz->tp = uint_type;
57: (void) cl->tsizeof();
58:
59: Pexpr esz = new texpr(SIZEOF,cl,0); // noe = sizeof(vec)/sizeof(elem)
60: esz->tp = int_type;
61:
62: Pexpr noe;
63: if (vec2) noe = new texpr(SIZEOF,vec2->tp,0);
64: else noe = new texpr(SIZEOF,vec->tp,0);
65:
66: // Pexpr noe = new texpr(SIZEOF,vec->tp,0);
67: noe->tp = int_type;
68: noe = new expr(DIV,noe,esz);
69: noe->tp = uint_type;
70: // error('d',"cdvec tail %d i %d",tail,i);
71: // Pexpr arg = (0<=tail) ? new expr(ELIST,zero,0) : 0; // 0 or 1 for dtors
72: Pexpr arg = (i) ? new expr(ELIST,i,0) : 0;
73: arg = (0<=tail) ? new expr(ELIST,zero,arg) : arg; // 0 or 1 for dtors
74: arg = new expr(ELIST,cd,arg); // constructor or destructor
75: cd->lval(ADDROF); // cd->take_addr();
76:
77: arg = new expr(ELIST,sz,arg);
78: arg = new expr(ELIST,noe,arg);
79: arg = new expr(ELIST,vec,arg);
80:
81: arg = new call(f,arg);
82: arg->base = G_CALL;
83: arg->fct_name = f;
84:
85: return arg;
86: }
87:
88: /*
89: int new_used; // pre-define new and delete only if the user didn't
90:
91: void new_init()
92: {
93: char* ns = oper_name(NEW);
94: char* ds = oper_name(DELETE);
95:
96: new_used = 1;
97:
98: new_fct = gtbl->look(ns,0);
99: del_fct = gtbl->look(ds,0);
100:
101: if (new_fct && !del_fct)
102: error('w',"%n defined but not operator delete()",new_fct);
103: if (del_fct && !new_fct)
104: error('w',"%n defined but not operator new()",del_fct);
105:
106: if (Pfct(new_fct->tp)->body==0) new_fct->dcl_print(0);
107: if (Pfct(del_fct->tp)->body==0) del_fct->dcl_print(0);
108: }
109: */
110: Pstmt trim_tail(Pstmt tt)
111: /*
112: strip off statements after RETURN etc.
113: NOT general: used for stripping off spurious destructor calls
114: */
115: {
116: if (tt == 0) return 0;
117:
118: while (tt->s_list) {
119: Pstmt tpx;
120: switch (tt->base) {
121: case PAIR:
122: tpx = trim_tail(tt->s2);
123: goto tpxl;
124: case BLOCK:
125: tpx = trim_tail(tt->s);
126: tpxl:
127: if (tpx == 0) return 0;
128:
129: switch (tpx->base) {
130: case SM:
131: break;
132: case CONTINUE:
133: case BREAK:
134: case GOTO:
135: case RETURN:
136: if (tt->s_list->base != LABEL) tt->s_list = 0;
137: default:
138: return tpx;
139: }
140: default:
141: if (tt = tt->s_list) break;
142: return 0;
143: case RETURN:
144: if (tt->s_list->base != LABEL) tt->s_list = 0;
145: return tt;
146: }
147: }
148:
149: switch (tt->base) {
150: case PAIR: return trim_tail(tt->s2);
151: // case LABEL: return trim_tail(tt->s);
152: case BLOCK: if (tt->s) return trim_tail(tt->s);
153: default: return tt;
154: }
155: }
156:
157: extern Ptype Pfct_type;
158:
159: Pexpr mptr_assign(Pexpr n, Pexpr in)
160: {
161: Pexpr i1;
162: Pexpr i2;
163: Pexpr i3;
164:
165: if ( n->base == NAME )
166: Pname(n)->use();
167:
168: if (in->base == NAME) {
169: i1 = new mdot("d",in);
170: i1->i1 = 9;
171: i2 = new mdot("i",in);
172: i2->i1 = 9;
173: i3 = new mdot("f",in);
174: i3->i1 = 9;
175: }
176: else {
177: i1 = in->e1->e1;
178: i2 = in->e1->e2;
179: i3 = in->e2;
180: }
181: Pexpr nd = new mdot("d",n);
182: nd->i1 = 9;
183: Pexpr e1 = new expr(ASSIGN,nd,i1);
184:
185: Pexpr ni = new mdot("i",n);
186: ni->i1 = 9;
187: Pexpr e2 = new expr(ASSIGN,ni,i2);
188:
189: Pexpr nf = new mdot("f",n);
190: nf->i1 = 9;
191: // Pexpr ii = in->e2; //new cast(Pfct_type,in->e2);
192: Pexpr e3 = new expr(ASSIGN,nf,i3);
193:
194: Pexpr ee = new expr(CM,e2,e3);
195: return new expr(CM,e1,ee);
196: }
197:
198: Pstmt block::simpl()
199: {
200: int i;
201: Pname n;
202: Pstmt ss=0, sst=0;
203: Pstmt dd=0, ddt=0;
204: Pstmt stail;
205: Ptable old_scope = scope;
206: DB( if(Sdebug>=1)
207: error('d',"%d->block::simple() own_tbl %d memtbl %d curr_fct%n",this,own_tbl,memtbl,curr_fct);
208: );
209: if (own_tbl == 0) {
210: ss = (s) ? s->simpl() : 0;
211: return ss;
212: }
213:
214: scope = memtbl;
215: if (scope->init_stat == 0) scope->init_stat = 1; /* table is simplified. */
216:
217: for (n=scope->get_mem(i=1); n; n=scope->get_mem(++i)) {
218: Pstmt st = 0;
219: Pname cln;
220: Pexpr in = n->n_initializer;
221: // error('d',"local %k %n in %k %t",n->n_sto,n,in?in->base:0,in?in->tp:0);
222: if (in || n->n_evaluated) {
223: scope->init_stat = 2; /* initializer in this scope */
224: if (n->n_sto == EXTERN) {
225: error(&n->where,"Id local extern%n",n);
226: continue;
227: }
228: }
229:
230: switch (n->n_scope) {
231: case ARG:
232: case 0:
233: case PUBLIC:
234: continue;
235: }
236:
237: if (n->n_stclass == STATIC) { // local static class object
238: if (in && in->base==STAT_INIT) {
239: // dynamic initialization
240: // introduce first time switch
241: Pname cn;
242: Pname x;
243: Ptype ct;
244: int vec_seen = 0;
245:
246: cn = n->tp->is_cl_obj();
247: if ( cn == 0 ) { ++vec_seen; cn = cl_obj_vec; }
248:
249: if ( cn ) {
250: ct = new ptr(PTR,vec_seen?Pvec(n->tp)->typ:n->tp);
251: x = make_tmp('F', ct, gtbl );
252: x->n_initializer = zero;
253: }
254: else
255: x = make_tmp('F',int_type,scope);
256:
257: x->n_sto = n->n_stclass = STATIC;
258: if (in->e2)
259: in->base = ASSIGN;
260: else
261: in = in->e1;
262:
263: Pexpr set;
264: if ( cn ) {
265: x->dcl_print(0);
266: Pclass cl = Pclass(cn->tp);
267: Pname dtor = cl->has_dtor();
268:
269: Pexpr cc;
270: if ( dtor ) {
271: if ( vec_seen == 0 ) {
272: Pexpr eee = new expr(DEREF, x, 0 );
273: Pexpr c = call_dtor(eee,dtor,0,DOT,one);
274: c->tp = any_type;
275: cc = new expr( QUEST, c, zero );
276: cc->cond = x;
277: }
278: else cc = cdvec(vec_del_fct,x,cl,dtor,0,zero,n);
279: cc->tp = any_type; // arghh!
280:
281: Pstmt dls = new estmt( SM, n->where, cc, 0 );
282: if ( st_dlist ) dls->s_list = st_dlist;
283: st_dlist = dls;
284: }
285:
286: Pexpr xe;
287: if (cn) {
288: if ( vec_seen == 0 )
289: xe = new expr( G_ADDROF, 0, n );
290: else {
291: Pexpr ee = new expr( DEREF, n, zero );
292: xe = new expr( G_ADDROF, 0, ee );
293: }
294: }
295:
296: set = new expr(ASSIGN,x,xe);
297: set->tp = ct;
298: }
299: else {
300: set = new expr(ASSIGN,x,one);
301: set->tp = int_type;
302: }
303:
304: in = new expr(G_CM,in,set);
305: in = new expr(STAT_INIT,zero,in);
306: in->cond = x;
307: }
308: else
309: continue;
310: }
311:
312: if ( in ) {
313: if ((in->base == ILIST && in->e2 == 0) ||
314: (in->base == STRING && n->tp->base == VEC))
315: if (ansi_opt==0) {
316: error('s',&n->where,"initialization of%n (automatic aggregate)",n);
317: continue;
318: }
319: }
320:
321: if (n->tp == 0) continue; /* label */
322: if (n->n_evaluated) continue;
323:
324: /* construction and destruction of temporaries is handled locally */
325: { char* s = n->string;
326: register char c3 = s[4];
327: if (s[0]=='_' && s[1]=='_' && s[2]=='D' && isdigit(c3)) continue;
328: }
329:
330: if ( cln=n->tp->is_cl_obj() ) {
331: Pclass cl = Pclass(cln->tp);
332: Pname d = cl->has_dtor();
333:
334: if ( n->n_stclass == STATIC // local static class object
335: && in && in->base==STAT_INIT )
336: goto stat_init;
337:
338: if (d) { // n->cl.dtor(0);
339: Pexpr dl = call_dtor(n,d,0,DOT,one);
340: // Pstmt dls = new estmt(SM,n->where,dl,0);
341: Pstmt dls = new estmt(SM,no_where,dl,0);
342: if (dd) {
343: dls->s_list = dd;
344: dd = dls;
345: }
346: else
347: ddt = dd = dls;
348: }
349:
350: // error('d',"%n: in %d",n,in?in->base:0);
351: if (in) {
352: switch (in->base) {
353: case DEREF: // *constructor?
354: if (in->e1->base == G_CALL) {
355: Pname fn = in->e1->fct_name;
356: if (fn==0 || fn->n_oper!=CTOR) goto ddd;
357: st = new estmt(SM,n->where,in->e1,0);
358: n->n_initializer = 0;
359: break;
360: }
361: goto ddd;
362: case STAT_INIT:
363: stat_init:
364: // error('d', "block::simpl: case #1 stat_init : n: %n", n );
365: in->base = QUEST;
366: st = new estmt(SM,n->where,in,0);
367: n->n_initializer = 0;
368: break;
369: case G_CM:
370: st = new estmt(SM,n->where,in->e1,0);
371: n->n_initializer = 0;
372: break;
373: case ASSIGN: // assignment to "n"?
374: if (in->e1 == n) {
375: st = new estmt(SM,n->where,in,0);
376: n->n_initializer = 0;
377: break;
378: }
379: default:
380: goto ddd;
381: }
382: }
383: }
384: else if (cl_obj_vec) {
385: Pclass cl = Pclass(cl_obj_vec->tp);
386: Pname d = cl->has_dtor();
387: Pname c = cl->has_ictor();
388: n->n_initializer = 0;
389:
390: if ( n->n_stclass == STATIC // local static class object
391: && in && in->base==STAT_INIT )
392: goto stat_init2;
393:
394: if (c) { // _vec_new(vec,noe,sz,ctor);
395: if (in==0 || in->base==ILIST) {
396: Pexpr a = cdvec(vec_new_fct,n,cl,c,-1,0);
397: st = new estmt(SM,n->where,a,0);
398: }
399: else
400: st = new estmt(SM,n->where,in,0);
401: }
402: // no default ctor but provided all elements with argument
403: else if ( in ) st = new estmt(SM,n->where,in,0);
404:
405:
406: if (d) { // __vec_delete(vec,noe,sz,dtor,0);
407: Pfct f = Pfct(d->tp);
408: int i = 0;
409: for (Pname nn = f->f_args->n_list;
410: nn && nn->n_list; nn=nn->n_list) i++;
411: Pexpr a = cdvec(vec_del_fct,n,cl,d,0,new ival(i));
412: // Pstmt dls = new estmt(SM,n->where,a,0);
413: Pstmt dls = new estmt(SM,no_where,a,0);
414: if (dd) {
415: dls->s_list = dd;
416: dd = dls;
417: }
418: else
419: ddt = dd = dls;
420: }
421: }
422: else if (in) {
423: switch (in->base) {
424: case ILIST:
425: switch (n->n_scope) {
426: case FCT:
427: if (in->e2) { // pointer to member
428: Pexpr ee = mptr_assign(n,in);
429: st = new estmt(SM,n->where,ee,0);
430: n->n_initializer = 0;
431: break;
432: }
433: case ARG:
434: if (ansi_opt == 0) error('s',"Ir list for localV%n",n);
435: }
436: break;
437: case STAT_INIT:
438: stat_init2:
439: // error('d', "block::simpl: case #2 stat_init : n: %n", n );
440: in->base = QUEST;
441: st = new estmt(SM,n->where,in,0);
442: n->n_initializer = 0;
443: break;
444: case STRING:
445: if (n->tp->base==VEC) break; /* BUG char vec only */
446: default:
447: ddd:
448: { Pexpr ee = new expr(ASSIGN,n,in);
449: st = new estmt(SM,n->where,ee,0);
450: n->n_initializer = 0;
451: }
452: }
453: }
454:
455: if (st) {
456: if (ss)
457: sst->s_list = st;
458: else
459: ss = st;
460: sst = st;
461: }
462: }
463:
464: if (dd) {
465: Pstmt od = del_list;
466: Pstmt obd = break_del_list;
467: Pstmt ocd = continue_del_list;
468:
469: dd->simpl();
470: del_list = (od) ? Pstmt(new pair(curloc,dd,od)) : dd;
471: break_del_list = (break_del_list&&obd) ? Pstmt(new pair(curloc,dd,obd)) : dd;
472: continue_del_list = (continue_del_list&&ocd) ? Pstmt(new pair(curloc,dd,ocd)) : dd;
473:
474: stail = s ? s->simpl() : 0;
475:
476: Pfct f = Pfct(curr_fct->tp);
477: if (this!=f->body
478: || f->returns->base==VOID
479: || (f->returns->base!=VOID && no_of_returns==0 ) // you have been warned!
480: || strcmp(curr_fct->string,"main")==0 ) {
481: // not dropping through the bottom of a value returning function
482: if (stail) {
483: Pstmt tt = (stail->base==RETURN || stail->base==LABEL) ? stail : trim_tail(stail);
484: if (tt && tt->base != RETURN) stail->s_list = dd;
485: }
486: else
487: s = dd;
488: stail = ddt;
489: }
490:
491: del_list = od;
492: continue_del_list = ocd;
493: break_del_list = obd;
494: }
495: else
496: stail = s ? s->simpl() : 0;
497:
498: if (ss) { /* place constructor calls */
499: ss->simpl();
500: sst->s_list = s;
501: s = ss;
502: if (stail == 0) stail = sst;
503: }
504:
505: scope = old_scope;
506:
507: return stail;
508: }
509:
510: int no_sizeof;
511:
512: void expr::simpl()
513: {
514: DB(if(Sdebug>=2){
515: error('d',"%d->expr::simpl() %k",this,this?base:0);
516: if(Sdebug>=3) display_expr(this);
517: });
518: if (this==0 || permanent==2) return; // already expanded
519: static TOK obase = 0;
520:
521: switch (base) {
522: case MDOT:
523: obase = base;
524: mem->simpl();
525: obase = 0;
526: // no break
527:
528: case ICALL: // already expanded
529: return;
530:
531: case G_ADDROF:
532: case ADDROF:
533: // error('d',"simpl & %k",e2->base);
534:
535: e2->simpl();
536: switch (e2->base) {
537: case DOT:
538: case REF:
539: { Pref r = Pref(e2);
540: Pname m = Pname(r->mem);
541: while (m->base == MDOT) m = Pname(m->mem);
542: if (m->n_stclass == STATIC) { // & static member
543: Pexpr x;
544: delp:
545: x = e2;
546: e2 = m;
547: r->mem = 0;
548: DEL(x);
549: }
550: else if (m->tp->base == FCT) { // & member fct
551: Pfct f = Pfct(m->tp);
552: if (f->f_virtual) { // &p->f ==> p->vtbl[fi].f
553: int index = f->f_virtual;
554: Pexpr ie = index ? new ival(index):0;
555: if (ie) ie->tp = int_type;
556: Pname cn = m->n_table->t_name;
557: Pname vp = find_vptr(Pclass(cn->tp));
558: r->mem = vp;
559:
560: if ( obase == MDOT ) {
561: base = DEREF;
562: e1 = e2;
563: e2 = ie;
564: }
565: else { // support old style &b.vf
566: base = MDOT;
567: mem = new expr(DEREF,e2,ie);
568: string2 = "f";
569: i1 = 9;
570: }
571: }
572: else {
573: goto delp;
574: }
575: }
576: break;
577: }
578: }
579: break;
580:
581: case ANDAND:
582: case OROR:
583: Ntmp = 0;
584: // no break
585:
586: default:
587: if (e1) e1->simpl();
588: if (e2) e2->simpl();
589: break;
590:
591: case CM:
592: case G_CM:
593: {
594: Pname n = 0;
595: e1->simpl();
596: e2->simpl();
597: if (e1->base==ICALL && e1->e1==0) n = e1->il->fct_name;
598: if (e2->base==ICALL && e2->e1==0) n = e2->il->fct_name;
599: if (n) error('s',"cannot expand inline void%n called in commaE",n);
600: // no break
601: }
602: case NAME:
603: case DUMMY:
604: case ICON:
605: case FCON:
606: case CCON:
607: case IVAL:
608: // case FVAL:
609: // case LVAL:
610: case STRING:
611: case ZERO:
612: case ILIST:
613: // case MDOT:
614: return;
615: /*
616: case SIZEOF:
617: base = IVAL;
618: i1 = tp2->tsizeof();
619: tp2 = 0; // can't DEL(tp2)
620: break;
621: */
622: case SIZEOF:
623: if (e1) e1->simpl();
624: return;
625:
626: case G_CALL:
627: case CALL:
628: Pcall(this)->simpl();
629: break;
630:
631: case NEW:
632: case GNEW:
633: simpl_new();
634: return;
635:
636: case DELETE:
637: case GDELETE:
638: simpl_delete();
639: break;
640:
641: case QUEST:
642: cond->simpl();
643: Ntmp = 0;
644: e2->simpl();
645: // no break
646:
647: case CAST:
648: case REF:
649: e1->simpl();
650: break;
651:
652: case DOT:
653: e1->simpl();
654: switch (e1->base) {
655: case CM:
656: case G_CM:
657: { // &( , name). => ( ... , &name)->
658: Pexpr ex = e1;
659: cfr:
660: switch (ex->e2->base) {
661: case NAME:
662: base = REF;
663: ex->e2 = ex->e2->address();
664: break;
665: case CM:
666: case G_CM:
667: ex = ex->e2;
668: goto cfr;
669: }
670: }
671: }
672: break;
673:
674: case ASSIGN:
675: {
676: Pfct f = 0;
677: Pexpr th = 0;
678: if ( curr_fct ) {
679: f = Pfct(curr_fct->tp);
680: th = f->f_this;
681: }
682:
683: imeasure++;
684: if (e1) e1->simpl();
685: if (e2) {
686: Pexpr c = e2;
687: c->simpl();
688: while (c->base == CAST) c = c->e1;
689: if (c->base == ILIST) e2 = c;
690:
691: if (e2->base == ILIST) { // pointer to member assignment
692: Pexpr ee = mptr_assign(e1,e2);
693: Pexpr eee = new expr(CM,ee->e2,e1);
694: e1 = ee->e1;
695: e2 = eee;
696: base = CM;
697: delete ee;
698: }
699: }
700:
701: if (th && th==e1 && curr_fct->n_oper==CTOR && init_list) {
702: // this=e2 => (this=e2,init_list)
703: Pclass cl = Pclass(Pbase(Pptr(th->tp)->typ)->b_name->tp);
704: if (cl->c_body == 1) cl->dcl_print(0);
705: imeasure++;
706: base = CM;
707: e1 = new expr(ASSIGN,e1,e2);
708: e2 = init_list;
709: if (warning_opt) // timid
710: error('w',"assignment to ``this'' inK: try defining%t::operator new() instead",f->memof);
711: }
712: break;
713: }
714: }
715:
716: switch (base) {
717: case QUEST:
718: case ANDAND:
719: case OROR:
720: if (Ntmp) error('s',"temporary ofC%n with destructor needed in%kE",Ntmp,base);
721: // no break;
722: default:
723: Ntmp = 0;
724: }
725:
726: if (tp==int_type || tp==defa_type) {
727: Neval = 0;
728: no_sizeof = 1; // do not convert sizeof's to ints
729: long i = eval();
730: no_sizeof = 0;
731: if (Neval == 0) {
732: base = IVAL;
733: i1 = i;
734: }
735: }
736:
737: }
738:
739: Pexpr vptr_entry(Pexpr pp, Pexpr ie, Pclass cl)
740: {
741: Pptr ttemp = pp->tp->is_ptr_or_ref();
742:
743: if (ttemp) {
744: Ptype pt = ttemp->typ; // check if cast pp = (base*)pp
745: Pclass pc = Pclass(pt->is_cl_obj()->tp); // is needed
746: if (pc!=cl) pp = new cast(cl,pp);
747: }
748: Pname vp = find_vptr(cl);
749: if (vp == 0) error('i',"can't find vptr");
750: Pexpr vptr = new ref(REF,pp,vp); // pp->vptr
751: return new expr(DEREF,vptr,ie); // pp->vptr[i]
752: }
753:
754: Pexpr new_this(Pexpr pp, Pexpr ee)
755: {
756: //error('d',"new this");
757: Pexpr dee = new mdot("d",ee); // pp->vptr[i].d
758: dee->i1 = 9;
759: Pexpr nthis = new cast(Pchar_type,pp);
760: nthis = new expr(PLUS,nthis,dee); // ((char*)pp)+delta
761: Ptype ct = pp->tp;
762: if (pp->base==NAME && Pname(pp)->n_xref) ct = pp->tp->addrof();
763: return new cast(ct,nthis);
764: }
765:
766: Pcall vcall(Pexpr pp, Pexpr ie, Pfct f, Pclass cl, Pexpr args)
767: /*
768: generate a call of the virtual function with the index ``ie''
769: and type "f" in class ``cl'' for the object pointed to by ``pp''
770:
771: multiple inheritance virtual call:
772:
773: p->f(x) is resolved like this
774: pp = p; // avoid side effects
775: pp = p.base_object; // often: pp = p;
776: // done when the name was resolved
777: i = index(f);
778: entry = pp->_vtbl[i-1];
779: pp = (T*)(((char*)pp)+entry.d)
780: (*(ftype)entry.f)(pp,x)
781: */
782: {
783: //error('d',"vcall %t",cl);
784: if (cl->c_body==1) cl->dcl_print(0); // look for first use of cl
785:
786: imeasure+=6;
787: Pexpr ee = vptr_entry(pp,ie,cl);
788:
789: Pexpr fee = new mdot("f",ee);
790: fee->i1 = 9;
791: Ptype pft = f->addrof();
792: fee = new cast(pft,fee); // (T)pp->vptr[i].f
793: Pexpr r = new expr(DEREF,fee,0); // *(T)pp->vptr[i].f
794: // e1->tp must be 0, means "argtype encoded"
795: r->tp2 = Ptype(f->f_this); // encode argtype
796:
797: Pexpr nthis = new_this(pp,ee);
798:
799: args = new expr(ELIST,nthis,args);
800: args->simpl();
801:
802: Pcall c = new call(r,args);
803: c->tp = f->returns;
804: return c;
805: }
806:
807: void call::simpl()
808: /*
809: fix member function calls:
810: p->f(x) becomes f(p,x)
811: o.f(x) becomes f(&o,x)
812: or if f is virtual:
813: p->f(x) is resolved like this
814: pp = p;
815: i = index(f);
816: entry = pp->_vtbl[i-1];
817: pp = (T*)(((char*)pp)+entry.i)
818: (*entry.f)(pp,x)
819: replace calls to inline functions by the expanded code
820: */
821: {
822: Pname fn = fct_name;
823: //error('d',"%d call::simpl() fn %n %d e1 %d",this,fn,fn,e1);
824: Pfct f = fn ? Pfct(fn->tp) : 0;
825:
826: if (fn == 0) e1->simpl();
827:
828: if (f) {
829: switch(f->base) {
830: case ANY:
831: return;
832: case OVERLOAD:
833: fct_name = fn = Pgen(f)->fct_list->f;
834: f = Pfct(fn->tp);
835: }
836: }
837:
838: switch (e1->base) {
839: case MEMPTR: // (p ->* q)(args)
840: {
841: Pexpr p = e1->e1;
842: Pexpr q = e1->e2;
843: Pclass cl = Pclass(e1->tp2);
844: Pfct f = Pfct(q->tp->deref());
845:
846: if (e2) e2->simpl();
847:
848: if (f->f_this == 0) { // might not know about ``this'' yet
849: if (f->memof == 0) error('i',"memof missing");
850: Pname tt = new name("this");
851: tt->n_scope = ARG;
852: tt->tp = f->memof->this_type;
853: PERM(tt);
854: // f->f_this = f->f_args = tt;
855: tt->n_list = f->argtype;
856: // f->f_this = tt;
857: tt->n_list = f->f_result ? f->f_result : f->argtype;
858: f->f_this = f->f_args = tt;
859: }
860: //error('d',"f_this %d",f->f_this);
861: extern has_virt(Pclass);
862:
863: // beware of sideeffects:
864: nin = 1;
865: if (q->not_simple()) error('s',"2nd operand of .* too complicated");
866: nin = 0;
867:
868: Pexpr qq = new mdot("f",q); // the function: (*(right type)q.f)
869: qq->i1 = 9;
870: qq = new cast(f->addrof(),qq);
871: Pexpr nc = new expr(DEREF,qq,0);
872: nc->tp2 = Ptype(f->f_this); // encode argtype
873:
874: Pexpr nthis = new_this(p,q); // arguments: (p+q.d,args)
875: Pexpr args = new expr(ELIST,nthis,e2);
876: imeasure+=3;
877:
878: if (has_virt(cl) == 0) { // no virtuals: simple
879: if (cl->defined == 0)
880: error("call throughP toMF before definition ofC %t",cl);
881: //error('d',"no virt");
882: // (p ->* q)(args) => (*q.f)(p+q.d,args)
883: e1 = nc;
884: e2 = args;
885: return;
886: }
887:
888: if (find_vptr(cl) == 0) { // must be a call to a second base
889: // that we cannot handle yet
890: // it is OK not to to generate
891: // a virtual call since a
892: // `sorry' will have been generated
893: // at the point of initialization
894: e1 = nc;
895: e2 = args;
896: return;
897:
898: }
899: // beware of sideeffects:
900: nin = 1;
901: if (p->not_simple()) error('s',"1st operand of .* too complicated");
902: nin = 0;
903:
904: Pexpr c = new mdot("i",q); // condition (q.i<0)
905: c->i1 = 9;
906: c = new expr(LT,c,zero);
907:
908: Pexpr ie = new mdot("i",q);
909: ie->i1 = 9;
910:
911: base = QUEST;
912: e1 = new call(nc,args);
913: e2 = vcall(p,ie,f,cl,e2);
914: cond = c;
915: return;
916: }
917: case DOT:
918: // if e1 is an object and not just a reference
919: // the vtbl need not be used
920: case REF:
921: { Pref r = Pref(e1);
922: Pexpr a1 = r->e1;
923: int obj = r->n_initializer!=0; // if B::f don't use vcall
924:
925: if (obj == 0) { // don't use vcall if we have an object
926: // (not a pointer or a reference)
927: if (e1->base==DOT && a1->base!=DEREF) obj = 1;
928: }
929:
930: //error('d',"fct_name %n f %d %d obj %d",fct_name,f,f->f_virtual,obj);
931: if (f && obj==0 && f->f_virtual) {
932: Pexpr a11 = 0;
933:
934: switch(a1->base) { // see if temporary might be needed
935: case NAME:
936: case MDOT:
937: a11 = a1;
938: break;
939: case REF:
940: case DOT:
941: if (a1->e1->base==NAME
942: || ((a1->e1->base==DOT || a1->e1->base==REF) && a1->e1->e1->base==NAME)) a11 = a1;
943: break;
944: case ADDROF:
945: case G_ADDROF:
946: if (a1->e2->base == NAME
947: || ((a1->e2->base==DOT || a1->e2->base==REF) && a1->e2->e1->base==NAME)) a11 = a1;
948: break;
949: case CAST:
950: switch (a1->e1->base) {
951: case NAME:
952: case MDOT:
953: a11 = a1;
954: }
955: }
956:
957: // if( a1->base==REF && fn->n_oper==DTOR ){
958: // a11 = a1;
959: // goto zsw;
960: // }
961: //
962: if (e1->base == DOT) {
963: // zsw:
964: if (a11) a11 = a11->address();
965: a1 = a1->address();
966: }
967:
968: if (a11 == 0) { // temporary (maybe) needed
969: // e->f() => (t=e,t->f(t))
970: if (a1->base==NAME)
971: a11 = a1; // &*name has become name
972: else {
973: Pname nx = new name(make_name('K'));
974: nx->tp = a1->tp;
975: Pname n = nx->dcl(scope,ARG); // no init!
976: delete nx;
977: Pname cln = a1->tp->is_cl_obj();
978: if (cln) {
979: Pclass cl = Pclass(cln->tp);
980: if (Ntmp==0 && cl->has_dtor()) Ntmp = cln;
981: if (cl->has_itor()) n->n_xref = 1;
982: }
983: n->n_scope = FCT;
984: n->assign();
985: a11 = n;
986: a1 = new expr(ASSIGN,n,a1);
987: a1->tp = n->tp;
988: a1->simpl();
989: Pcall cc = new call(0,0);
990: *cc = *this;
991: base = CM;
992: e1 = a1;
993: e2 = cc;
994: this = cc;
995: }
996: }
997:
998: int i = f->f_virtual;
999: Pexpr ie = i?new ival(i):0; // index
1000: Pname cn = fn->n_table->t_name;
1001: if (fn
1002: && fn->n_initializer
1003: && cc->nof
1004: && cc->nof->n_oper==CTOR
1005: && Pfct(cc->nof->tp)->memof->c_abstract
1006: && strcmp(Pfct(cc->nof->tp)->memof->string, cn->string) == 0 ) {
1007: // permit x::x( x& xx ) { xx.pvf(); }
1008: Pexpr ee = e1->e1;
1009: while ( ee && ee->base != NAME ) ee = ee->e1;
1010: if ( ee && strcmp( ee->string, "this" )==0)
1011: error("call of pure virtualF%n inK%n",fn,cc->nof);
1012: }
1013: Pcall vc = vcall(a11,ie,f,Pclass(cn->tp),e2);
1014: *this = *vc;
1015: return;
1016: }
1017:
1018: Ptype tt = r->mem->tp;
1019: llp:
1020: //error('d',"llp %t",tt);
1021: switch (tt->base) {
1022: // default: // pointer to function: (n->ptr_mem)(args); do nothing
1023: case TYPE:
1024: tt = Pbase(tt)->b_name->tp;
1025: goto llp;
1026: case OVERLOAD: // n->fctmem(args);
1027: case FCT:
1028: if (fct_name==0) {
1029: // reconstitute fn destroyed to suppress "virtual"
1030: fct_name = fn = Pname(e1->n_initializer);
1031: f = Pfct(fn->tp);
1032: }
1033:
1034: if (e1->base == DOT) a1 = a1->address();
1035: e2 = new expr(ELIST,a1,e2);
1036: e1 = r->mem;
1037: }
1038: }
1039: }
1040:
1041: if (e2) e2->simpl();
1042: //error('d',"fn %n inl %d imes %d",fn,f->f_inline,f->f_imeasure);
1043: if (fn && f->f_inline && debug_opt==0) {
1044: imeasure += f->f_imeasure;
1045: Pclass cl = f->memof;
1046: if (cl && cl->c_body) cl->dcl_print(0);
1047: Ptable oscope = scope;
1048: Pexpr ee = f->expand(fn,scope,e2);
1049: scope = oscope;
1050: if (ee) *Pexpr(this) = *ee;
1051: }
1052: else if (fn && f->f_inline==0 && f->f_imeasure) {
1053: extern void uninline(Pname fn);
1054: uninline(fn);
1055: imeasure += 3;
1056: }
1057: else if (fn && debug_opt && f->f_inline==ITOR) {
1058: extern void expand_itor(Pclass);
1059: expand_itor(f->memof);
1060: }
1061: else
1062: imeasure += 3;
1063: }
1064:
1065: void uninline(Pname fn)
1066: // inline turned static
1067: {
1068: Pfct f = Pfct(fn->tp);
1069: //error('d',"uninline %n %d %d",fn,f->body,f->f_expr);
1070:
1071: if (warning_opt) {
1072: error('w',"%n too complex for inlining",fn);
1073: error('w',"out-of-line copy of %n created",fn);
1074: }
1075: f->f_imeasure = 0; // now it really is just static
1076:
1077: Pstmt s = f->body->s;
1078: // for (s = f->body->s; s; s=s->s_list)
1079: //error('d',"start %d %k",s->e,s->e->base);
1080: // s = f->body->s;
1081: while (s) {
1082: //error('d',"s %k %d %k",s->base,s->e,s->e->base);
1083: if (s->base == SM) {
1084: // turn comma expression into statement list
1085: Pexpr e = s->e;
1086: if (e)
1087: switch (e->base) {
1088: case CM:
1089: case G_CM:
1090: { Pstmt ss = new estmt(SM,no_where,e->e2,0);
1091: s->e = e->e1;
1092: ss->s_list = s->s_list;
1093: s->s_list = ss;
1094: delete e;
1095: continue;
1096: }
1097: }
1098: }
1099: s = s->s_list;
1100: }
1101: // for (s = f->body->s; s; s=s->s_list)
1102: //error('d',"echo %k %d %k",s->base,s->e,s->e->base);
1103:
1104: fn->dcl_print(0);
1105: }
1106:
1107: /*
1108: void ccheck(Pexpr e)
1109:
1110: Is there a conditional in this expression? (not perfect)
1111:
1112: {
1113: //error('d',"ccheck(e %k)",e,e?e->base,0);
1114: if (e)
1115: switch (e->base) {
1116: case QUEST:
1117: case ANDAND:
1118: case OROR:
1119: error('s',"E too complicated: uses%k and needs temporary ofCW destructor",e->base);
1120: break;
1121: case LT:
1122: case LE:
1123: case GT:
1124: case GE:
1125: case EQ:
1126: case NE:
1127: case ASSIGN:
1128: case ASPLUS:
1129: case ASMINUS:
1130: case G_CM:
1131: case CM:
1132: case PLUS:
1133: case MINUS:
1134: case MUL:
1135: case DIV:
1136: case OR:
1137: case ER:
1138: case AND:
1139: case G_CALL:
1140: case CALL:
1141: case ELIST:
1142: case DEREF:
1143: ccheck(e->e1);
1144: case NOT:
1145: case COMPL:
1146: case CAST:
1147: case ADDROF:
1148: case G_ADDROF:
1149: ccheck(e->e2);
1150: break;
1151: case ICALL: // check inlined arguments
1152: { Pin il = e->il;
1153: for (int i = 0; il->args[i].arg && i<il->i_slots; i++) ccheck(il->args[i].arg);
1154: }
1155: }
1156: }
1157: */
1158:
1159: void temp_in_cond(Pexpr ee, Pstmt ss, Ptable tbl)
1160: /*
1161: insert destructor calls 'ss' into condition 'ee'
1162: ee => (Qnn = ee, dtors, Qnn)
1163: */
1164: {
1165: //error('d',"temp_in_cond");
1166: // ccheck(ee);
1167: while (ee->base==CM || ee->base==G_CM) ee = ee->e2;
1168: Ptype ct = ee->tp;
1169: Pname n = new name(make_name('Q')); // int Qnn;
1170: n->tp = ct;
1171: Pname tmp = n->dcl(tbl,ARG);
1172: delete n;
1173: tmp->n_scope = FCT;
1174:
1175: Pexpr v = new expr(0,0,0);
1176: *v = *ee;
1177: PERM(ct);
1178: v = new cast(ct,v);
1179: Pexpr c = new expr(ASSIGN,tmp,v); // Qnn = ee
1180: c->tp = ct;
1181: ee->base = CM;
1182: ee->e1 = c;
1183:
1184: Pexpr ex = 0; // add dtors at end
1185:
1186: for (Pstmt sx = ss; sx; sx = sx->s_list) {
1187: if (ex) {
1188: ex = new expr(CM,ex,sx->e);
1189: ex->tp = sx->e->tp;
1190: }
1191: else
1192: ex = sx->e;
1193: }
1194: ee->e2 = new expr(CM,ex,tmp); // add Qnn at end
1195: ee->e2->tp = ct;
1196: }
1197:
1198: bit not_safe(Pexpr e)
1199: {
1200:
1201: switch (e->base) {
1202: default:
1203: return 1;
1204: /*
1205: case CALL:
1206: case G_CALL:
1207: case DOT:
1208: case REF:
1209: case ANAME:
1210: return 1;
1211: */
1212: case NAME:
1213: // if the name is automatic and has a destructor it is not safe
1214: // to destroy it before returning an expression depending on it
1215: { Pname n = Pname(e);
1216: if (n->n_table!=gtbl && n->n_table->t_name==0) {
1217: Pname cn = n->tp->is_cl_obj();
1218: if (cn && Pclass(cn->tp)->has_dtor()) return 1;
1219: }
1220: }
1221: case IVAL:
1222: case ICON:
1223: case CCON:
1224: case FCON:
1225: case STRING:
1226: return 0;
1227: case NOT:
1228: case COMPL:
1229: case ADDROF:
1230: case G_ADDROF:
1231: return not_safe(e->e2);
1232: case DEREF:
1233: // return not_safe(e->e1) || e->e2?not_safe(e->e2):0;
1234: { int i = not_safe(e->e1);
1235: if (i) return i;
1236: if (e->e2) return not_safe(e->e2);
1237: return 0;
1238: }
1239: case CM:
1240: case PLUS:
1241: case MINUS:
1242: case MUL:
1243: case DIV:
1244: case MOD:
1245: case ASSIGN:
1246: case ASPLUS:
1247: case ASMINUS:
1248: case ASMUL:
1249: case ASDIV:
1250: case OR:
1251: case AND:
1252: case OROR:
1253: case ANDAND:
1254: case LT:
1255: case LE:
1256: case GT:
1257: case GE:
1258: case EQ:
1259: case NE:
1260: return not_safe(e->e1) || not_safe(e->e2);
1261: case QUEST:
1262: return not_safe(e->cond) || not_safe(e->e1) || not_safe(e->e2);
1263: }
1264: }
1265:
1266:
1267: Pexpr curr_expr; /* to protect against an inline being expanded twice
1268: in a simple expression keep track of expressions
1269: being simplified
1270: */
1271: Pstmt stmt::simpl()
1272: /*
1273: return a pointer to the last statement in the list, or 0
1274: */
1275: {
1276: if (this == 0) error('i',"0->S::simpl()");
1277: DB( if(Sdebug>=1){
1278: error('d',"%d->stmt::simpl(): %k",this,base);
1279: if(Sdebug>=2) display_stmt(this);
1280: });
1281: Pstmt ostmt = Cstmt;
1282: if ( where.line ) Cstmt = this;
1283:
1284: stmtno++;
1285: curr_expr = e;
1286: //error('d',"stmt::simpl %k s_list %d",base,s_list);
1287:
1288: switch (base) {
1289: default:
1290: error('i',"S::simpl(%k)",base);
1291:
1292: case ASM:
1293: break;
1294:
1295: case BREAK:
1296: if (break_del_list) { // break => { _dtor()s; break; }
1297: Pstmt bs = new stmt(base,where,0);
1298: Pstmt dl = break_del_list->copy();
1299: base = BLOCK;
1300: s = new pair(where,dl,bs);
1301: }
1302: break;
1303:
1304: case CONTINUE:
1305: if (continue_del_list) { // continue => { _dtor()s; continue; }
1306: Pstmt bs = new stmt(base,where,0);
1307: Pstmt dl = continue_del_list->copy();
1308: base = BLOCK;
1309: s = new pair(where,dl,bs);
1310: }
1311: break;
1312:
1313: case DEFAULT:
1314: s->simpl();
1315: break;
1316:
1317: case SM:
1318: if (e) {
1319: if (e->base == DEREF) e = e->e1;
1320: e->simpl();
1321: if (e->base == DEREF) e = e->e1;
1322: }
1323: break;
1324:
1325: case RETURN:
1326: { /* return x;
1327: =>
1328: { dtor()s; return x; }
1329: OR (returning an X where X(X&) is defined) =>
1330: { ctor(_result,x); _dtor()s; return; }
1331: OR (where x needs temporaries)
1332: OR (where x might involve an object to be destroyed) =>
1333: { _result = x; _dtor()s; return _result; }
1334: return; =>
1335: { _dtor()s; return; }
1336: OR (in constructors) =>
1337: { _dtor()s; return _this; }
1338: */
1339: Pstmt sx = this;
1340: Pexpr ex = e;
1341:
1342: no_of_returns++;
1343:
1344: Pstmt dl = (del_list) ? del_list->copy() : 0;
1345: Pfct f = Pfct(curr_fct->tp);
1346:
1347: if (e == 0) e = dummy;
1348: if (e==dummy && curr_fct->n_oper==CTOR) e = f->f_this;
1349:
1350:
1351: // need to generate a temporary for mptr return
1352: Pexpr tt = e;
1353: while ( tt->base == CAST )
1354: tt = tt->e1;
1355: if ( tt->base == ILIST )
1356: e = tt;
1357:
1358: if (e->base == ILIST) {
1359: extern Pbase mptr_type;
1360: extern Ptype Pvptr_type;
1361: Pexpr mptr_assign(Pexpr, Pexpr);
1362: // memptr constant
1363: // return({1,2,f}) ==> memptr t; return((t={1,2,f},&t))
1364:
1365: Ptable ftbl = Pfct(curr_fct->tp)->body->memtbl;
1366: Pname temp = make_tmp('A',mptr_type,ftbl);
1367:
1368: // placed in mptr_assign()
1369: // temp->use(); // necessary for inlines to force declaration
1370:
1371: e = mptr_assign(temp,e);
1372: e = new expr(G_CM,e,temp);
1373: e->tp = mptr_type;
1374: }
1375:
1376: if (f->f_result) { // ctor(_result,x); dtors; return;
1377: if (e->base == G_CM) e = replace_temp(e,f->f_result);
1378: e->simpl();
1379: Pstmt cs = new estmt(SM,where,e,0);
1380: if (dl) cs = new pair(where,cs,dl);
1381: base = PAIR;
1382: s = cs;
1383: s2 = new estmt(RETURN,where,0,0);
1384: //#ifdef RETBUG
1385: // s2->empty = 1; // fudge to bypass C bug (see print.c)
1386: // s2->ret_tp = ret_tp;
1387: //#endif
1388: }
1389: else { // dtors; return e;
1390: e->simpl();
1391: if (dl) {
1392: if (e!=dummy && not_safe(e)) {
1393: // { _result = x; _dtor()s; return _result; }
1394: Ptable ftbl = Pfct(curr_fct->tp)->body->memtbl;
1395:
1396: Pname r = ftbl->look("_result",0);
1397: if (r == 0) {
1398: r = new name("_result");
1399: r->tp = ret_tp;
1400: Pname rn = r->dcl(ftbl,ARG);
1401: rn->n_scope = FCT;
1402: rn->where = no_where;
1403: rn->assign();
1404: delete r;
1405: r = rn;
1406: }
1407: Pexpr as = new expr(ASSIGN,r,e);
1408: as->tp = ret_tp; // wrong if = overloaded, but then X(X&) ought to have been used
1409: Pstmt cs = new estmt(SM,where,as,0);
1410: cs = new pair(where,cs,dl);
1411: base = PAIR;
1412: s = cs;
1413: s2 = new estmt(RETURN,where,r,0);
1414: // s2->ret_tp = ret_tp;
1415: }
1416: else { // { _dtor()s; return x; }
1417: base = PAIR;
1418: s = dl;
1419: s2 = new estmt(RETURN,where,e,0);
1420: }
1421: s2->ret_tp = ret_tp;
1422: }
1423: }
1424:
1425: // if (sx->memtbl) {
1426: // int i;
1427: // for (Pname n=sx->memtbl->get_mem(i=1); n; n=sx->memtbl->get_mem(++i)) {
1428: // Pname cn = n->tp->is_cl_obj();
1429: // if (cn && Pclass(cn->tp)->has_dtor()) {
1430: // ccheck(ex);
1431: // break;
1432: // }
1433: // }
1434: // }
1435: break;
1436: }
1437:
1438: case WHILE:
1439: case DO:
1440: e->simpl();
1441: { Pstmt obl = break_del_list;
1442: Pstmt ocl = continue_del_list;
1443: break_del_list = 0;
1444: continue_del_list = 0;
1445: s->simpl();
1446: break_del_list = obl;
1447: continue_del_list = ocl;
1448: }
1449: break;
1450:
1451: case SWITCH:
1452: e->simpl();
1453: { Pstmt obl = break_del_list;
1454: break_del_list = 0;
1455: s->simpl();
1456: break_del_list = obl;
1457: }
1458: switch (s->base) {
1459: case DEFAULT:
1460: case LABEL:
1461: case CASE:
1462: break;
1463: case BLOCK:
1464: if (s->s)
1465: switch (s->s->base) {
1466: case BREAK: // to cope with #define Case break; case
1467: case CASE:
1468: case LABEL:
1469: case DEFAULT:
1470: break;
1471: default:
1472: goto df;
1473: }
1474: break;
1475: default:
1476: df:
1477: error(&s->where,"S orIdE not reached: (case label missing?)");
1478: }
1479: break;
1480:
1481: case CASE:
1482: e->simpl();
1483: s->simpl();
1484: break;
1485:
1486: case LABEL:
1487: if (del_list) error('s',"label in blockW destructors");
1488: s->simpl();
1489: break;
1490:
1491: case GOTO:
1492: /* If the goto is going to a different (effective) scope,
1493: then it is necessary to activate all relevant destructors
1494: on the way out of nested scopes, and issue errors if there
1495: are any constructors on the way into the target.
1496:
1497: Only bother if the goto and label have different effective
1498: scopes. (If mem table of goto == mem table of label, then
1499: they're in the same scope for all practical purposes.
1500: */
1501: {
1502: Pname n = scope->look( d->string, LABEL );
1503: if (n == 0) error('i',&where,"label%n missing",d);
1504: if(n->n_realscope!=scope && n->n_assigned_to) {
1505:
1506: /* Find the root of the smallest subtree containing
1507: the path of the goto. This algorithm is quadratic
1508: only if the goto is to an inner or unrelated scope.
1509: */
1510:
1511: Ptable r = 0;
1512:
1513: for(Ptable q=n->n_realscope; q!=gtbl; q=q->next) {
1514: for( Ptable p = scope; p != gtbl; p = p->next ) {
1515: if( p==q ) {
1516: r = p; // found root of subtree!
1517: goto xyzzy;
1518: }
1519: }
1520: }
1521:
1522: xyzzy: if( r==0 ) error( 'i',&where,"finding root of subtree" );
1523:
1524: /* At this point, r = root of subtree, n->n_realscope
1525: * = mem table of label, and scope = mem table of goto. */
1526:
1527: /* Climb the tree from the label mem table to the table
1528: * preceding the root of the subtree, looking for
1529: * initializers and ctors. If the mem table "belongs"
1530: * to an unsimplified block(s), the n_initializer field
1531: * indicates presence of initializer, otherwise initializer
1532: * information is recorded in the init_stat field of
1533: * mem table. */
1534:
1535: for( Ptable p=n->n_realscope; p!=r; p=p->next )
1536: if( p->init_stat == 2 ) {
1537: error(&where,"goto%n pastDWIr",d);
1538: goto plugh; /* avoid multiple error msgs */
1539: }
1540: else if( p->init_stat == 0 ) {
1541: int i;
1542: for(Pname nn=p->get_mem(i=1);nn;nn=p->get_mem(++i))
1543: if(nn->n_initializer||nn->n_evaluated){
1544: error(&nn->where,"goto%n pastId%n",d,nn);
1545: goto plugh;
1546: }
1547: }
1548: plugh:
1549:
1550: /* Proceed in a similar manner from the point of the goto,
1551: * generating the code to activate dtors before the goto. */
1552: /* There is a bug in this code. If there are class objects
1553: * of the same name and type in (of course) different mem
1554: * tables on the path to the root of the subtree from the
1555: * goto, then the innermost object's dtor will be activated
1556: * more than once. */
1557:
1558: {
1559: Pstmt dd = 0, ddt = 0;
1560:
1561: for( Ptable p=scope; p!=r; p=p->next ) {
1562: int i;
1563: for(Pname n=p->get_mem(i=1);n;n=p->get_mem(++i)) {
1564: Pname cln;
1565: if (n->tp == 0) continue; /* label */
1566:
1567: if ( cln=n->tp->is_cl_obj() ) {
1568: Pclass cl = (Pclass)cln->tp;
1569: Pname d = cl->has_dtor();
1570:
1571: if (d) { /* n->cl::~cl(0); */
1572: Pexpr dl = call_dtor(n,d,0,DOT,one);
1573: Pstmt dls = new estmt(SM,n->where,dl,0);
1574: if (dd)
1575: ddt->s_list = dls;
1576: else
1577: dd = dls;
1578: ddt = dls;
1579: }
1580:
1581: }
1582: else if (cl_obj_vec) {
1583: Pclass cl = (Pclass)cl_obj_vec->tp;
1584: // Pname c = cl->has_ictor();
1585: Pname d = cl->has_dtor();
1586:
1587: if (d) { // __vec_delete(vec,noe,sz,dtor,0);
1588: Pfct f = Pfct(d->tp);
1589: int i = 0;
1590: for (Pname nn = f->f_args->n_list;
1591: nn && nn->n_list; nn=nn->n_list) i++;
1592: Pexpr a = cdvec(vec_del_fct,n,cl,d,0,new ival(i));
1593: Pstmt dls = new estmt(SM,n->where,a,0);
1594: if (dd)
1595: ddt->s_list = dls;
1596: else
1597: dd = dls;
1598: ddt = dls;
1599: }
1600: }
1601: } /* end mem table scan */
1602: } /* end dtor loop */
1603:
1604: /* "activate" the list of dtors obtained. */
1605:
1606: if( dd ) {
1607: dd->simpl();
1608: Pstmt bs = new stmt( base, where, 0 );
1609: *bs = *this;
1610: base = PAIR;
1611: s = dd;
1612: s2 = bs;
1613: }
1614: }
1615: } /* end special case for non-local goto */
1616: }
1617: break;
1618:
1619: case IF:
1620: e->simpl();
1621: s->simpl();
1622: if (else_stmt) else_stmt->simpl();
1623: break;
1624:
1625: case FOR: // "for (s;e;e2) s2; => "s; for(;e,e2) s2"
1626: if (for_init) for_init->simpl();
1627: if (e) {
1628: curr_expr = e;
1629: e->simpl();
1630: }
1631: if (e2) {
1632: curr_expr = e2;
1633: e2->simpl();
1634: if (e2->base==ICALL)
1635: if (e2->e1 == 0) error('s',"cannot expand inline void%n called in forE", e2->il->fct_name);
1636: }
1637: { Pstmt obl = break_del_list;
1638: Pstmt ocl = continue_del_list;
1639: break_del_list = 0;
1640: continue_del_list = 0;
1641: s->simpl();
1642: break_del_list = obl;
1643: continue_del_list = ocl;
1644: }
1645: break;
1646:
1647: case BLOCK:
1648: Pblock(this)->simpl();
1649: break;
1650:
1651: case PAIR:
1652: break;
1653: }
1654:
1655: /*if (s) s->simpl();*/
1656: //error('d',"base %k memtbl %d",base,memtbl);
1657: if (base!=BLOCK && memtbl) {
1658: Pstmt t1 = (s_list) ? s_list->simpl() : 0;
1659: Pstmt tpx = t1 ? t1 : this;
1660:
1661: Pstmt ss = 0;
1662: Pname cln; // used for warnings
1663: int i;
1664: Pname tn = memtbl->get_mem(i=1);
1665: for (; tn; tn=memtbl->get_mem(++i)) {
1666: if (cln = tn->tp->is_cl_obj()) {
1667: Pname d = Pclass(cln->tp)->has_dtor();
1668: if (d) { /* n->cl::~cl(0); */
1669: Pexpr dl = call_dtor(tn,d,0,DOT,one);
1670: Pstmt dls = new estmt(SM,tn->where,dl,0);
1671: dls->s_list = ss;
1672: ss = dls;
1673: }
1674: }
1675: }
1676:
1677: if (ss) {
1678: Pstmt t2 = ss->simpl();
1679:
1680: switch (base) {
1681: case IF:
1682: case WHILE:
1683: case DO:
1684: case SWITCH:
1685: temp_in_cond(e,ss,memtbl);
1686: break;
1687:
1688: case PAIR: // can hide a return
1689: { Pstmt ts = s2;
1690: while (ts->base==PAIR) ts = ts->s2;
1691: if (ts->base == RETURN) { // sordid
1692: this = ts;
1693: goto retu;
1694: }
1695: goto def;
1696: }
1697: case RETURN:
1698: retu:
1699: {
1700: if (e == 0) {
1701: // return; dtors; => dtors; return;
1702: Pstmt rs = new estmt(RETURN,where,0,0);
1703: //rs->empty = empty; // BSD fudge
1704: rs->ret_tp = ret_tp;
1705: base = PAIR;
1706: s = ss;
1707: s2 = rs;
1708: Cstmt = ostmt;
1709: return t1 ? t1 : rs;
1710: }
1711:
1712: Pname cln = e->tp->is_cl_obj();
1713: if (cln==0
1714: || Pclass(cln->tp)->has_oper(ASSIGN)==0) {
1715: // ... return e; dtors; =>
1716: // ... X r; ... r = e; dtors; return r;
1717: Pname rv = new name("_rresult"); // NOT "_result"
1718: rv->tp = ret_tp /* e->tp */;
1719: if (memtbl == 0) memtbl = new table(4,0,0);
1720: Pname n = rv->dcl(memtbl,ARG);
1721: n->where = no_where;
1722: n->n_scope = FCT;
1723: n->n_assigned_to = 1;
1724: delete rv;
1725: Pstmt rs = new estmt(RETURN,where,n,0);
1726: rs->ret_tp = ret_tp;
1727: base = SM;
1728: e = new expr(ASSIGN,n,e);
1729: e->tp = n->tp;
1730: Pstmt ps = new pair(where,ss,rs);
1731: ps->s_list = s_list;
1732: s_list = ps;
1733: Cstmt = ostmt;
1734: return t1 ? t1 : rs;
1735: }
1736: }
1737:
1738: case FOR: // don't know which expression the temp comes from
1739: error('s',&where,"E in %kS needs temporary ofC%nW destructor",base,cln);
1740: break;
1741:
1742: case SM: // place dtors after all "converted" DCLs
1743: if (t1) {
1744: // ccheck(e);
1745: for (Pstmt ttt, tt=this;
1746: (ttt=tt->s_list) && ttt->base==SM;
1747: tt = ttt) ;
1748: t2->s_list = ttt;
1749: tt->s_list = ss;
1750: Cstmt = ostmt;
1751: return t1!=tt ? t1 : t2;
1752: }
1753: default:
1754: def:
1755: // if (e) ccheck(e);
1756: if (t1) { // t1 == tail of statment list
1757: t2->s_list = s_list;
1758: s_list = ss;
1759: Cstmt = ostmt;
1760: return t1;
1761: }
1762: s_list = ss;
1763: Cstmt = ostmt;
1764: return t2;
1765: }
1766: }
1767: Cstmt = ostmt;
1768: return (t1) ? t1 : this;
1769: }
1770:
1771: Cstmt = ostmt;
1772: return (s_list) ? s_list->simpl() : this;
1773: }
1774:
1775: Pstmt stmt::copy()
1776: // now handles dtors in the expression of an IF stmt
1777: // not general!
1778: {
1779: Pstmt ns = new stmt(0,curloc,0);
1780:
1781: *ns = *this;
1782: if (s) ns->s = s->copy();
1783: if (s_list) ns->s_list = s_list->copy();
1784:
1785: switch (base) {
1786: case PAIR:
1787: ns->s2 = s2->copy();
1788: break;
1789: }
1790:
1791: return ns;
1792: }
1793:
1794: Pname overFound = 0;
1795:
1796: static Pexpr
1797: mk_new_with_args( Pexpr pe, Ptype tt, Pclass cl )
1798: { // allocate using operator new(sizeof(cl),args1)
1799: Pexpr p;
1800: Pexpr args = pe->e2;
1801:
1802: Pexpr ce = new texpr(SIZEOF,tt,0);
1803: (void) tt->tsizeof();
1804: ce->tp = size_t_type;
1805: args = new expr(ELIST,ce,args);
1806: char* s = oper_name(NEW);
1807: Pname n = new name(s);
1808: if (pe->base == GNEW) // ::new
1809: p = gtbl->look(s,0);
1810: else
1811: p = find_name(n,cl,scope,CALL,curr_fct);
1812: p = new call(p,args);
1813: overFound=0; // set in call_fct
1814: (void) p->call_fct(cl->memtbl);
1815: if (overFound && overFound->n_scope != EXTERN)
1816: check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
1817: overFound=0;
1818: return p;
1819: }
1820:
1821: void expr::simpl_new()
1822: /*
1823: change NEW or GNEW node to CALL node
1824: */
1825: {
1826: Pname cln;
1827: Pname ctor;
1828: int sz = 1;
1829: // int esz;
1830: Pexpr var_expr = 0;
1831: Pexpr const_expr = 0;
1832: Ptype tt = tp2;
1833: Pexpr arg;
1834: Pexpr szof;
1835: Pname nf;
1836: Pexpr init = e1;
1837:
1838: if (init && init->base) init = 0; // only non-ctor init
1839: // error('d',"simpl_new %k e1 %k e2 %k init %k",base, e1?e1->base:0,e2?e2->base:0,init?init->base:0);
1840:
1841: if ((cln=tt->is_cl_obj()) && init == 0) {
1842: Pclass cl = Pclass(cln->tp);
1843: Pexpr p;
1844: ctor=cl->has_ctor();
1845: //error('d',"cl %t ctor %n",cl, ctor);
1846: if (e2 // placement
1847: || ctor==0 // no constructor
1848: || ctor->n_table!=cl->memtbl // inherited constructor???
1849: || (base==GNEW && cl->has_oper(NEW)) )
1850: p = mk_new_with_args( this, tt, cl ); // new(sizeof(cl),args1)
1851: else {
1852: p = zero; // 0->ctor(args)
1853: // check visibility anyway...
1854: (void)mk_new_with_args(this,tt,cl);
1855: }
1856:
1857: if (ctor) {
1858: Pexpr c = e1; // ctor call generated in expr::typ
1859: Ptype ttt = tp;
1860: c->e1->e1 = p; // p->ctor
1861: c->simpl();
1862: *this = *c;
1863: tp = ttt;
1864: delete c;
1865: }
1866: else { // (tp)new(args)
1867: base = CAST;
1868: tp2 = tp;
1869: e1 = p;
1870: e2 = 0;
1871: simpl();
1872: }
1873: return;
1874: } else if ( cln ) {
1875: Pclass cl = Pclass(cln->tp);
1876: // check visibility anyway...
1877: (void)mk_new_with_args(this,tt,cl);
1878: }
1879:
1880: Pclass covn = 0;
1881: if (cl_obj_vec) {
1882: covn = Pclass(cl_obj_vec->tp);
1883: ctor = covn->has_ictor();
1884: if (ctor == 0) {
1885: if (covn->has_ctor()) error("new %s[], no defaultK",covn->string);
1886: cl_obj_vec = 0;
1887: }
1888: }
1889:
1890: xxx:
1891: //error('d',"xxx %t",tt);
1892: switch (tt->base) {
1893: case TYPE:
1894: tt = Pbase(tt)->b_name->tp;
1895: goto xxx;
1896:
1897: default:
1898: (void) tt->tsizeof();
1899: szof = new texpr(SIZEOF,tt,0);
1900: szof->tp = uint_type;
1901: break;
1902:
1903: case VEC:
1904: { Pvec v = Pvec(tt);
1905: //error('d',"v %d %d",v->size,v->dim);
1906: if (v->size)
1907: sz *= v->size;
1908: else if (v->dim)
1909: var_expr = v->dim;
1910: else
1911: sz = 0;
1912: tt = v->typ;
1913: goto xxx;
1914: }
1915: }
1916:
1917: if (cl_obj_vec) { // _vec_new(0,no_of_elements,element_size,ctor)
1918: const_expr = new ival(sz);
1919: Pexpr noe = (var_expr) ? (sz!=1) ? new expr(MUL,const_expr,var_expr) : var_expr : const_expr;
1920: const_expr = szof;
1921: const_expr->tp = uint_type;
1922: base = CALL;
1923: arg = new expr(ELIST,ctor,0);
1924: /*ctor->take_addr();*/
1925: ctor->lval(ADDROF);
1926: Pname tmp=0;
1927: if (e2 && e2->e1 &&
1928: e2->e1->tp &&
1929: e2->e1->tp->base != PTR )
1930: { // new(size_t, args)
1931: tmp = make_tmp( 'N', Pvoid_type, scope);
1932: tmp->n_initializer = mk_new_with_args( this, tt, covn );
1933: }
1934: arg = new expr(ELIST,const_expr,arg);
1935: arg = new expr(ELIST,noe,arg);
1936: //arg = new expr(ELIST,e2?e2:zero,arg); // may be preallocated
1937: arg = new expr(ELIST,e2?(tmp?tmp:e2):zero,arg); // may be preallocated
1938: base = CAST;
1939: tp2 = tp;
1940: e1 = new expr(G_CALL,vec_new_fct,arg);
1941: e1->fct_name = vec_new_fct;
1942: e1->tp = Pfct(vec_new_fct->tp)->returns;
1943: simpl();
1944: return;
1945: }
1946:
1947: /* call _new(element_size*no_of_elements) */
1948: //error('d',"sz %d var %d",sz,var_expr);
1949: if (sz == 1)
1950: arg = (var_expr) ? new expr(MUL,szof,var_expr) : szof;
1951: else {
1952: const_expr = new ival(sz);
1953: const_expr->tp = uint_type;
1954: const_expr = new expr(MUL,const_expr,szof);
1955: const_expr->tp = uint_type;
1956: arg = (var_expr) ? new expr(MUL,const_expr,var_expr) : const_expr;
1957: }
1958:
1959: arg->tp = uint_type;
1960: base = CAST;
1961: tp2 = tp;
1962: arg = new expr(ELIST,arg,e2);
1963: nf = gtbl->look(oper_name(NEW),0); // always global,
1964: // all class object handled above
1965: e1 = new expr(G_CALL,nf,arg);
1966: (void) e1->call_fct(gtbl);
1967: simpl();
1968:
1969: if (init) { // alloc(sz) => (p=alloc(sz),*p=init,p);
1970: Pexpr p = init->e1;
1971: Pexpr ee = new expr(0,0,0);
1972: *ee = *this;
1973: ee = new expr(ASSIGN,p,ee); // ee: p = alloc(sz);
1974: init->base = ASSIGN;
1975: init->e1 = p->contents(); // init: *p = init_val
1976: ee = new expr(CM,ee,init);
1977: ee->simpl();
1978: base = CM;
1979: e1 = ee;
1980: e2 = p;
1981: }
1982: }
1983:
1984: void expr::simpl_delete()
1985: /*
1986: delete p => _delete(p);
1987: or cl::~cl(p,1);
1988: delete[s]p => _delete(p);
1989: or vec_del_fct(p,vec_sz,elem_sz,~cl,1);
1990: */
1991: {
1992: for (Ptype tt = e1->tp; tt->base==TYPE; tt=Pbase(tt)->b_name->tp);
1993: tt = Pptr(tt)->typ;
1994: //error('d',"simpl_delete() %t",e1->tp);
1995: Pname cln = tt->is_cl_obj();
1996: Pname n;
1997: Pclass cl;
1998:
1999: if (cln) {
2000: cl = Pclass(cln->tp);
2001: if ((cl->defined&DEFINED) == 0) error('w',"delete%t (%t not defined)",cl,cl);
2002: }
2003: else
2004: cl = 0;
2005:
2006: if (cl && (n=cl->has_dtor())) { // ~cl() might be virtual
2007: //xxx check for private/protected op delete
2008: {
2009: Pexpr ee = new expr(ELIST,e1,0);
2010: char* s = oper_name(DELETE);
2011: Pname n;
2012: //error('d',"%s( %k )",s,e1->base);
2013: if (base!=GDELETE) {
2014: n = new name(s);
2015: n = (Pname)find_name(n,cl,scope,CALL,curr_fct);
2016: //error('d',"found%n %t",n,n->tp);
2017: if (n->tp->base==OVERLOAD
2018: || Pfct(n->tp)->nargs==2) {
2019: Pexpr ss = new texpr(SIZEOF,cl,0);
2020: ss->tp = size_t_type;
2021: ee->e2 = new expr(ELIST,ss,0);
2022: }
2023: }
2024: else
2025: n = gtbl->look(s,0);
2026: //error('d',"found%n %t",n,n->tp);
2027: ee = new call(n,ee);
2028: ee->base = G_CALL;
2029: //error('d',"delete..."); display_expr(ee);
2030: // following commented out to avoid typ::checking problems
2031: //overFound=0; // set in call_fct
2032: //(void) ee->call_fct(cl->memtbl);
2033: //if (overFound && overFound->n_scope != EXTERN)
2034: //check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
2035: //overFound=0;
2036: }
2037:
2038: //if ( base!=GDELETE ) (void) cl->has_oper(DELETE);
2039:
2040: if(base==GDELETE && e2==0 || Pfct(n->tp)->f_virtual) { // may need temp
2041: nin=1;
2042: int needtemp = e1->not_simple();
2043: nin=0;
2044: if(needtemp) {
2045: // convert: delete [e2] e1
2046: // to: (T=e1), delete [e2] T
2047: // where T is a new temporary.
2048: Pname tnx = new name(make_name('K'));
2049: tnx->tp = e1->tp;
2050: Pname tn = tnx->dcl(scope,FCT);
2051: delete tnx;
2052: tn->assign();
2053: e1 = new expr(ASSIGN,tn,e1);
2054: e2 = new expr(base,tn,e2);
2055: base=CM;
2056:
2057: simpl();
2058: return;
2059: }
2060: }
2061: Pexpr r = e1;
2062:
2063: // handle delete p, where p has a private destructor
2064: if (n->n_scope != PUBLIC) check_visibility(n,0,cl,cc->ftbl,cc->nof);
2065: //error('d',"e2 %d %k",e2,base);
2066: if (e2 == 0) { // e1->cl::~cl(1)
2067: Pexpr ee = call_dtor(r,n,base==GDELETE?0:one,REF,one);
2068: if (Pfct(n->tp)->f_virtual) {
2069: if (ansi_opt) { // q?void:int would be an error
2070: ee = new expr(G_CM,ee,zero);
2071: ee->tp = zero_type;
2072: }
2073: ee = new expr(QUEST,ee,zero);
2074: ee->tp = ee->e1->tp;
2075: ee->cond = r;
2076: }
2077: if (base == GDELETE) {
2078: char* s = oper_name(DELETE);
2079: Pexpr p = gtbl->look(s,0);
2080: e2 = new call(p,new expr(ELIST,e1,0));
2081: base = CM;
2082: e1 = ee;
2083: }
2084: else {
2085: *this = *ee;
2086: delete ee;
2087: }
2088: simpl();
2089: return;
2090: }
2091: else { // del_cl_vec(e1,e2,elem_size,~cl,1);
2092: Pexpr sz = new texpr(SIZEOF,tt,0);
2093: (void)tt->tsizeof();
2094: Pfct f = Pfct(n->tp);
2095: int i = 0;
2096: Pname nn = f->f_args->n_list;
2097: for (; nn && nn->n_list; nn=nn->n_list) i++;
2098: //error('d',"n %n i %d",n,i);
2099: Pexpr arg = new ival(i);
2100: sz->tp = uint_type;
2101: // Pexpr arg = one;
2102: arg = new expr(ELIST,one,arg);
2103: if (Pfct(n->tp)->f_virtual) {
2104: Pexpr a = new ref(REF,e1,n);
2105: a = a->address();
2106: a = new mdot( "f", a );
2107: a->i1 = 9;
2108: arg = new expr(ELIST,a,arg);
2109: }
2110: else {
2111: arg = new expr(ELIST,n,arg);
2112: n->lval(ADDROF); // n->take_addr();
2113: }
2114:
2115: arg = new expr(ELIST,sz,arg);
2116: if (e2->base==DUMMY) {
2117: e2 = new ival(-1); // handle `delete[]p'
2118: }
2119:
2120: arg = new expr(ELIST,e2,arg);
2121: arg = new expr(ELIST,e1,arg);
2122: Pexpr ee = new expr(G_CALL,vec_del_fct,arg);
2123: ee->fct_name = vec_del_fct;
2124: ee->tp = tp;
2125: // if (ansi_opt) { // q?void:int would be an error
2126: // ee = new expr(G_CM,ee,zero);
2127: // ee->tp = zero_type;
2128: // }
2129: // ee = new expr(QUEST,ee,zero);
2130: // ee->tp = tp;
2131: // ee->cond = r;
2132: *this = *ee;
2133: simpl();
2134: return;
2135: }
2136: }
2137: else if (cl_obj_vec) {
2138: error("delete array of arrays");
2139: }
2140: else { // _delete(e1)
2141: Pexpr ee = new expr(ELIST,e1,0);
2142: char* s = oper_name(DELETE);
2143: if (cl && base!=GDELETE) {
2144: Pname n = new name(s);
2145: e1 = find_name(n,cl,scope,CALL,curr_fct);
2146: if (e1->tp->base==OVERLOAD || Pfct(e1->tp)->nargs==2) {
2147: Pexpr ss = new texpr(SIZEOF,cl,0);
2148: ss->tp = size_t_type;
2149: ee->e2 = new expr(ELIST,ss,0);
2150: }
2151: }
2152: else
2153: e1 = gtbl->look(s,0);
2154: base = G_CALL;
2155: e2 = ee;
2156: overFound=0; // set in call_fct
2157: (void) call_fct(scope);
2158: if (overFound && overFound->n_scope != EXTERN)
2159: check_visibility(overFound,0,cl,cc->ftbl,cc->nof);
2160: overFound=0;
2161: }
2162:
2163: Pcall(this)->simpl();
2164: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.