1 //*******************************************
2 // THIS FILE IS INCLUDED BY HIER.C
3 //*******************************************
5 /******************************************************************************
8 virtual inheritance is what complicates things a lot
10 ******************************************************************************/
12 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
13 // virtual table structs
14 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
16 typedef struct vt_entry_t {
17 struct vt_entry_t *next;
18 Token *prototype, *xproto, *xargs;
21 bool isfunction, isconst;
34 typedef struct virtual_table {
36 vt_entry *first_entry;
38 bool inlined, constd, volatiled;
46 enum { VTI_STATUS_NI, VTI_STATUS_ND, VTI_STATUS_DD, VTI_STATUS_NU, VTI_STATUS_FINAL };
48 typedef struct vti_entry_t {
49 struct vti_entry_t *next;
51 /* code, value: explained
52 - a virtual function has value and optionaly code.
53 the code is the virtuallity function definition.
54 - a virtual variable has no value and only code --> the init expression
55 - likewise for downcast data --> only code and no value */
59 bool cast_avoid_downcast;
62 typedef struct vt_initializer_t {
69 vti_entry *first_entry;
72 static virtual_table *VirtualTable;
73 static int nVTBL, nVTBLalloc;
75 static vt_initializer *VirtualInitializer;
76 static int nVTI, nVTIalloc;
79 static void show_vt (recID r)
81 if (!structs [r].vtis)
83 PRINTF ("\n+++Virtual tables of ["COLS"%s"COLE"]:\n", expand (name_of_struct (r)));
85 for (i = 0; structs [r].vtis [i] != -1; i++) {
86 PRINTF (" --- Vtable %i:\n", i);
87 vti_entry *v = VirtualInitializer [structs [r].vtis [i]].first_entry;
88 for (;v;v = v->next) {
89 PRINTF (" + Entry ["COLS"%s"COLE"] value ["COLS"%s"COLE"] ["COLS"%i"COLE"\n",
90 expand (v->vt_ent->entry_name), v->value ? expand (v->value) : "-no value-",
93 PRINTF (" + "COLS"+ + >"COLE" constant expression ["COLS);
94 if (v->code) INTPRINT (v->code);
95 else PRINTF ("- no code -");
103 static vtblID new_virtual_table ()
105 if (nVTBL == nVTBLalloc)
106 VirtualTable = (virtual_table*) realloc (VirtualTable,
107 (nVTBLalloc += 50) * sizeof (virtual_table));
108 VirtualTable [nVTBL].first_entry = 0;
109 VirtualTable [nVTBL].vu_tree = 0;
110 VirtualTable [nVTBL].typeid = false;
111 VirtualTable [nVTBL].inlined = InlineAllVt;
112 VirtualTable [nVTBL].constd = ConstVtables;
113 VirtualTable [nVTBL].volatiled = !vtptrConst;
114 VirtualTable [nVTBL].nvti = VirtualTable [nVTBL].nvtalloc = 0;
115 VirtualTable [nVTBL].vti = 0;
119 // #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#
120 // unionify the virtual table so order
121 // of declaration not important.
122 // foreach new entry of the v-table,
123 // we store the hierarchy path in a
124 // way that can be expanded with unions
125 // afterwards in the generation of the
126 // v-table declaration.
127 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
131 static void add_parent_child (vtblID vt, recID par, recID child)
133 int mval = par * PARMUL + child;
134 if (intfind (VirtualTable [vt].vu_tree, mval))
137 intadd (&VirtualTable [vt].vu_tree, mval, i);
140 /* Make Unionified path of virtual table entry */
141 static Token *vt_path (Token entn, recID root, recID node)
149 zpath [zpi = 126] = entn;
151 while (node != root) {
152 for (a = structs [node].ancestors; a->rec != -1; a++)
153 if (a->path [1] == -1 && structs [r = a->rec].vtis)
154 for (i = 0; structs [r].vtis [i] != -1; i++)
155 if (VirtualTable [VirtualInitializer
156 [structs [r].vtis [i]].v_t_i].appeared_at == root)
160 sintprintf (zpath + zpi, name_derrive_union, '.', name_derrive_memb (node), '.', NONULL);
161 add_parent_child (VirtualInitializer [structs [r].vtis [i]].v_t_i, r, node);
165 return intdup (&zpath [zpi]);
168 static vt_entry *add_vt_entry (vtblID v, vt_entry *e)
170 vt_entry *ep = VirtualTable [v].first_entry;
172 /* make unionified path to vt entry */
173 e->zpath = vt_path (e->entry_name, VirtualTable [v].appeared_at, e->introduced_at);
175 if (!ep) VirtualTable [v].first_entry = e;
177 while (ep->next) ep = ep->next;
188 static void get_children_r (intnode *n, recID par)
191 if (i / PARMUL == par)
192 get_child_r.vchild [get_child_r.n++] = i % PARMUL;
193 if (n->less) get_children_r (n->less, par);
194 if (n->more) get_children_r (n->more, par);
197 static void get_children (vtblID vt, recID par)
199 if (VirtualTable [vt].vu_tree)
200 get_children_r (VirtualTable [vt].vu_tree, par);
203 static void declare_vtable_for (vtblID vt, recID r)
207 vt_entry *ve_r [128];
210 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
211 if (ve->introduced_at == r)
214 // bubble sort entries alphabetically
215 for (i = 0; i < n; i++)
216 for (j = i + 1; j < n; j++)
217 if (strcmp (expand (ve_r [i]->entry_name), expand (ve_r [j]->entry_name)) > 0)
218 ve = ve_r [i], ve_r [i] = ve_r [j], ve_r [j] = ve;
220 for (i = 0; i < n; i++)
221 outprintf (STRUCTS, ISTR (ve_r [i]->prototype), ';', -1);
223 // now if derrived classes also use this virtual table
224 // for new entries, do the unionification thing
226 get_child_r.vchild = children;
227 get_children (vt, r);
228 if (!(n = get_child_r.n)) return;
230 outprintf (STRUCTS, RESERVED_union, '{', -1);
231 for (i = 0; i < n; i++) {
232 outprintf (STRUCTS, RESERVED_struct, '{', -1);
233 declare_vtable_for (vt, children [i]);
234 outprintf (STRUCTS, '}', name_derrive_memb (children [i]), ';', -1);
236 outprintf (STRUCTS, '}', name_derrive_union, ';', -1);
239 static void declare_vtable (vtblID i)
241 outprintf (STRUCTS, RESERVED_struct,
242 VirtualTable [i].vtname, '{', -1);
243 declare_vtable_for (i, VirtualTable [i].appeared_at);
244 outprintf (STRUCTS, '}', ';', -1);
247 static void export_virtual_table_declaration (recID r)
251 if (structs [r].vtis) for (i = 0; i < nVTBL; i++)
252 if (VirtualTable [i].appeared_at == r)
256 // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
257 // some more allocator/initializers
258 // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
260 static initID new_v_t_initializer (recID obj)
262 if (nVTI == nVTIalloc)
263 VirtualInitializer = (vt_initializer*) realloc (VirtualInitializer,
264 (nVTIalloc += 50) * sizeof (vt_initializer));
266 VirtualInitializer [nVTI].first_entry = 0;
267 VirtualInitializer [nVTI].open = true;
268 VirtualInitializer [nVTI].unused = false;
269 // VirtualInitializer [nVTI].exportdef = structs [obj].statik;
270 VirtualInitializer [nVTI].exportdef = false;
271 VirtualInitializer [nVTI].rec = obj;
276 static void add_initializer (vtblID vt, initID vi, recID obj)
278 virtual_table *vp = &VirtualTable [vt];
280 if (vp->nvti == vp->nvtalloc)
281 vp->vti = (vt_init_entry*) realloc (vp->vti,
282 (vp->nvtalloc += 20) * sizeof (vt_init_entry));
284 vp->vti [vp->nvti].initTbl = vi;
285 vp->vti [vp->nvti++].object = obj;
288 static void add_vti_entry (initID it, vti_entry *e)
291 if (debugflag.VIRTUALTABLES)
292 PRINTF ("++Adding entry "COLS"%s"COLE" to initializer %i\n", expand (e->vt_ent->entry_name), it);
294 vti_entry *ep = VirtualInitializer [it].first_entry;
296 VirtualInitializer [it].first_entry = e;
298 while (ep->next) ep = ep->next;
303 //---------------------------------------
304 // build the path to the virtual table
305 //---------------------------------------
307 static Token *pathto_vt (Token path [], initID i, bool const_path)
311 rd = aliasclass (VirtualInitializer [i].rec);
312 ra = aliasclass (VirtualTable [VirtualInitializer [i].v_t_i].appeared_at);
315 sintprintf (path, RESERVED__v_p_t_r_, -1);
319 bool v = is_ancestor (rd, ra, &p, const_path) == 2;
320 sintprintf (path, ISTR (p), v ? POINTSAT : '.', RESERVED__v_p_t_r_, -1);
326 /* this is a path that helps us decide whether there is virtual base vti */
327 static Token *pathto_vt_virt (Token path[], initID i)
329 recID rd = VirtualInitializer [i].rec;
330 recID ra = VirtualTable [VirtualInitializer [i].v_t_i].appeared_at;
333 pathto_vt (path, i, false);
334 if ((a = structs [rd].ancestors) && ra != rd) {
335 while (a->rec != ra) ++a;
336 if (a->status == ASTATUS_VIRT2)
337 path [intlen (path) - 2] = POINTSAT;
342 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343 // best virtual table to add a new entry is the most
345 // virtual tables reached through virtual inheritance
346 // dont count because we cannot ensure that the order of
347 // declarations will not matter.
348 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350 static initID best_vti (recID r)
356 if (!structs [r].vtis)
359 for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
360 pathto_vt_virt (pathto, ii);
361 for (j = 0; pathto [j] != POINTSAT; j++)
362 if (pathto [j] == -1) {
365 ir = structs [r].vtis [i];
373 static bool has_vtable (recID r)
375 if (!structs [r].vtis)
381 for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
382 pathto_vt_virt (pathto, ii);
383 for (j = 0; pathto [j] != POINTSAT; j++)
384 if (pathto [j] == -1)
390 static inline bool vt_only (recID r)
392 return structs [r].firstmember || structs [r].ancestors || !has_vtable (r)
393 || VirtualTable [VirtualInitializer [structs [r].vtis [0]].v_t_i].inlined;
395 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
396 // Inheritance of virtual tables
397 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
399 /* class <obj> inherits virtual initializer <iid> maybe by virtual inheritance */
400 static initID inherit_virtual_tbl (recID obj, initID iid)
403 if (debugflag.VIRTUALTABLES)
404 PRINTF ("++Inherit virtual initializer %i in object %i(%s)\n", iid, obj, SNM(obj));
406 vtblID vt = VirtualInitializer [iid].v_t_i;
407 bool unused = VirtualInitializer [iid].unused;
409 initID ii = new_v_t_initializer (obj);
410 add_initializer (vt, ii, obj);
411 /* New initializer inherits values from parent */
413 for (vp = VirtualInitializer [iid].first_entry; vp; vp = vp->next) {
414 vc = (vti_entry*) malloc (sizeof * vc);
416 vc->vt_ent = vp->vt_ent;
417 vc->value = vp->value;
418 vc->code = vp->value && !unused ? 0 : vp->code;
419 vc->status = (vp->status == VTI_STATUS_DD) ? VTI_STATUS_ND : vp->status;
420 vc->cast_avoid_downcast = vp->cast_avoid_downcast;
421 add_vti_entry (ii, vc);
424 VirtualInitializer [ii].v_t_i = vt;
425 VirtualInitializer [ii].instance_name =
426 name_instance (VirtualTable [vt].appeared_at, obj);
430 static void collapse_virtuals (recID);
432 /* Inherit virtual table initializers from parents
433 Must be called after parents are set */
434 static void inherit_all_virtuales (recID obj)
439 ancestor *a = structs [obj].ancestors;
441 if (a) for (;(p = a->rec) != -1; a++)
442 if (direct_ancest (a) && structs [p].vtis)
443 for (j = 0; structs [p].vtis [j] != -1; j++)
444 tmp [ti++] = inherit_virtual_tbl (obj, structs [p].vtis [j]);
448 structs [obj].vtis = intdup (tmp);
449 collapse_virtuals (obj);
450 } else structs [obj].vtis = 0;
453 /* two initializers of the same virtual table
454 are actually initializing the same thing
455 because of virtual inheritance, or not ? */
456 static bool are_the_same (initID i1, initID i2)
459 Token p1 [128], p2 [128];
460 pathto_vt_virt (p1, i1), pathto_vt_virt (p2, i2);
462 for (i = 0; p1 [i] != -1; i++)
463 if (p1 [i] == POINTSAT)
464 for (j = 0; p2 [j] != -1; j++)
465 if (p2 [j] == p1 [i-1] && p2 [j + 1] == POINTSAT)
467 return false; /* not */
469 vti_entry *v1 = VirtualInitializer [i1].first_entry;
470 vti_entry *v2 = VirtualInitializer [i2].first_entry;
472 /* do the combination of virtual tables.
473 * in the case of functions, there must be a unique final overrider.
474 * for virtual variables, currently, no, but the value wins
475 * for downcast offsets, always pick the v1 if both have.
476 * the latter is probably impossible unless double virtual inh?
477 * 'final' wins non-final.
480 if (v1->status == VTI_STATUS_NI) {
481 if (v2->status != VTI_STATUS_NI) copy: {
482 v1->value = v2->value;
484 v1->status = v2->status;
486 } else if (v2->status != VTI_STATUS_NI) {
487 if (v1->value == RESERVED_0) {
488 if (v2->value != RESERVED_0) {
489 v1->value = v2->value;
492 } else if (v1->value == 0) {
493 if (v1->code == 0 && v2->code != 0)
495 } else if (v2->value != RESERVED_0
496 && v2->value != v1->value) {
497 if (v2->status == VTI_STATUS_FINAL) {
498 if (v2->status != v1->status)
500 else parse_error_ll ("final functions");
501 } else if (v1->status != VTI_STATUS_FINAL)
502 v1->status = VTI_STATUS_NU;
508 VirtualInitializer [i2].unused = true;
513 /* collapse initializers of virtual base classes to a common one */
514 /* this is the whole point of virtual inheritance */
515 static void collapse_virtuals (recID r)
519 initID *pa = structs [r].vtis;
521 for (i = 1; pa [i] != -1; i++) {
522 vtblID vt = VirtualInitializer [pa [i]].v_t_i;
523 Token in = VirtualInitializer [pa [i]].instance_name;
525 for (j = 0; j < i; j++) {
526 if (VirtualInitializer [pa [j]].instance_name == in)
527 VirtualInitializer [pa [i]].instance_name =
528 name_name_enumerate (in, en++);
529 if (VirtualInitializer [pa [j]].v_t_i == vt)
530 if (are_the_same (pa [j], pa [i])) {
532 for (j = i; pa [j] != -1; j++)
540 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
542 // declarations of them...
543 // #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
545 static int lookup_virtual_f_ininit (initID i, Token n, typeID *va, Token **entn)
547 vtblID vi = VirtualInitializer [i].v_t_i;
551 if (debugflag.VIRTUALTABLES)
552 PRINTF (" ++in virtual table %i, initializer %i\n", vi, i);
554 for (ve = VirtualTable [vi].first_entry; ve; ve = ve->next)
555 if (ve->isfunction && ve->fname == n && arglist_compare (va, ve->arglist)) {
558 for (vie = VirtualInitializer [i].first_entry; vie; vie = vie->next)
559 if (vie->vt_ent->entry_name == ve->entry_name)
560 if (vie->status == VTI_STATUS_NI) break;
561 else return vie->status; else;
563 return VTI_STATUS_NI;
572 static void lookup_virtual_f (recID r, Token n, typeID t, vlookup *v)
575 if (debugflag.VIRTUALTABLES)
576 PRINTF ("++Looking for %s...\n", expand (n));
578 typeID *va = promoted_arglist_t (t);
582 v->status = VTI_STATUS_NI;
585 while (structs [r].vtis [i] != -1)
586 if (structs [r].vtis [i++] == v->iid)
589 for (; structs [r].vtis [i] != -1; i++)
590 if ((ret = lookup_virtual_f_ininit (structs [r].vtis [i], n, va, &ent_ret)) != VTI_STATUS_NI) {
592 v->iid = structs [r].vtis [i];
600 // Force generation of virtual table with no entries at specific object
602 initID Here_virtualtable (OUTSTREAM o, recID r, bool inlined, bool constd, bool volatiled)
605 if (debugflag.VIRTUALTABLES)
606 PRINTF ("++New virtual table introduced at class %s (%i)\n", SNM (r), r);
610 if (structs [r].vtis)
611 for (; structs [r].vtis [i] != -1; i++)
612 if (VirtualTable [VirtualInitializer [structs [r].vtis [i]].v_t_i].
617 add_variable_member (r, RESERVED__v_p_t_r_, typeID_voidP, 0, false, false);
618 vtblID vt = new_virtual_table ();
619 VirtualTable [vt].appeared_at = r;
620 VirtualTable [vt].vtname = name_virtual_table (r);
621 VirtualTable [vt].inlined = inlined;
622 VirtualTable [vt].constd = constd;
623 VirtualTable [vt].volatiled = volatiled;
624 outprintf (o, RESERVED_struct, VirtualTable [vt].vtname,
625 CONST_IF (constd), STAR_IF (!inlined),
626 CONST_IF (!inlined && !volatiled),
627 // !inlined && vtptrConst? RESERVED_const : BLANKT,
628 RESERVED__v_p_t_r_, ';', -1);
629 initID vi = new_v_t_initializer (r);
630 VirtualInitializer [vi].v_t_i = vt;
631 VirtualInitializer [vi].instance_name = name_instance (r, r);
632 add_initializer (vt, vi, r);
633 structs [r].vtis = (initID*) realloc (structs [r].vtis, (i+2) * sizeof (int));
634 structs [r].vtis [i] = vi;
635 structs [r].vtis [i + 1] = -1;
636 structs [r].vt_inthis = true;
641 // #.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#.#
642 /* Enter_virtual_function, may do 3 things:
643 1. complain because virtual already has value
644 2. set value to virtual slot (creating internal vf)
645 3. create a new virtual table entry and set value
646 ********************************************************/
647 void Make_virtual_table (OUTSTREAM o, recID r, Token fname, typeID t)
649 if (!structs [r].vtis)
650 Here_virtualtable (o, r, InlineAllVt, ConstVtables, !vtptrConst);
652 vlookup V = { .iid = -1 };
653 lookup_virtual_f (r, fname, t, &V);
654 if (V.status == VTI_STATUS_NI && !has_vtable (r))
655 Here_virtualtable (o, r, InlineAllVt, ConstVtables, !vtptrConst);
659 static void New_virtual_function (vf_args*);
660 static void Override_virtual_function (vf_args*, vlookup*);
661 void Enter_virtual_function (vf_args *args)
664 if (debugflag.VIRTUALTABLES)
665 PRINTF ("\n++ENTER VIRTUAL: ["COLS"%s"COLE"] (%s)\n", expand (args->fname), SNM(args->r));
667 vlookup V = { .iid = -1 };
668 lookup_virtual_f (args->r, args->fname, args->ftype, &V);
671 if (V.status == VTI_STATUS_NI)
672 return New_virtual_function (args);
675 if (V.status == VTI_STATUS_DD)
676 parse_error_tok (args->fname, "Virtual function redefined?");
679 while (V.status != VTI_STATUS_NI) {
680 if (V.status == VTI_STATUS_FINAL)
681 parse_error_tok (args->fname, "Virtual function has been declared final");
682 Override_virtual_function (args, &V);
683 lookup_virtual_f (args->r, args->fname, args->ftype, &V);
687 static void New_virtual_function (vf_args *args)
689 // [by convention, add it to the first virtual table if many]
690 vtblID vt = VirtualInitializer [best_vti (args->r)].v_t_i;
692 // + + + + new virtual table entry + + + +
693 vt_entry *ve = (vt_entry*) malloc (sizeof * ve);
695 .next = 0, .entry_name = name_virtual_slot (args->r, args->fname, args->ftype),
696 .isfunction = true, .type = args->ftype, .fname = args->fname,
697 .arglist = promoted_arglist_t (args->ftype), .introduced_at = args->r,
698 .xproto = intdup (args->prototype), .xargs = intdup (args->argv),
699 .flagz = args->flagz, .isconst = true
700 /* XXX if final, give a nice warning */
702 // make pointer to function from function
704 Token *fpt = mallocint (intlen (args->prototype) + 5);
706 while (args->prototype [i] != MARKER)
707 fpt [j++] = args->prototype [i++];
711 fpt [j++] = RESERVED_attr_stdcall;
712 fpt [j++] = ve->entry_name; ++i;
714 while ((fpt [j++] = args->prototype [i++]) != -1);
717 // add to virtual table slots. table may be empty.
718 add_vt_entry (vt, ve);
719 // + + + + in all other initializers this entry is NULL/NI + + + +
720 for (i = 0; i < VirtualTable [vt].nvti; i++) {
721 vti_entry *vte = (vti_entry*) malloc (sizeof * vte);
725 vte->cast_avoid_downcast = 0;
727 if (VirtualTable [vt].vti [i].object != args->r) {
728 vte->value = RESERVED_0;
729 vte->status = VTI_STATUS_NI;
731 vte->value = args->fmemb ?: RESERVED_0;
732 vte->status = VTI_STATUS_DD;
734 add_vti_entry (VirtualTable [vt].vti [i].initTbl, vte);
738 void add_struct_to_this (Token *p)
741 for (i = 0; p [i] != RESERVED_this; i++);
742 while (p [i] != '(') i--;
743 for (k = i; p [k] != -1; k++);
744 for (j = k++; j != i; )
746 p [i+1] = RESERVED_struct;
749 static void Override_virtual_function (vf_args *args, vlookup *v)
751 Token entn = v->entn [intlen (v->entn) - 1];
752 vtblID vt = VirtualInitializer [v->iid].v_t_i;
754 Token *proto = args->prototype;
755 bool modular = args->flagz & FUNCP_MODULAR;
757 // find the virtual table entry from vlookup data
758 // get the downcast info
760 vt_entry *vp = VirtualTable [vt].first_entry;
761 while (vp->entry_name != entn) vp = vp->next;
762 dow = vp->introduced_at;
765 // create virtuallity function name
769 // rewrite the prototype
770 vfn = name_virtual_inner (args->r, dow, args->fname, args->ftype);
771 proto = allocaint (intlen (args->prototype) + 4);
772 intcpy (proto, args->prototype);
773 intsubst1 (proto, MARKER, vfn);
774 intsubst1 (proto, name_of_struct (args->r), name_of_struct (dow));
775 if (is_aliasclass (args->r) && !is_aliasclass (dow))
776 add_struct_to_this (proto);
777 else if (!is_aliasclass (args->r) && is_aliasclass (dow))
778 remove_struct_from_this (proto, dow);
779 } else vfn = args->fmemb;
780 else vfn = RESERVED_0;
782 // set the value vfn for the entry at the initializer
783 vti_entry *vtp = VirtualInitializer [v->iid].first_entry;
784 while (vtp->vt_ent->entry_name != entn)
787 vtp->status = args->flagz & FUNCP_FINAL ? VTI_STATUS_FINAL : VTI_STATUS_DD;
788 vtp->cast_avoid_downcast = 0;
789 // create the code of the virtuallity function
790 if (args->fmemb && !modular)
791 if (aliasclass (args->r) == aliasclass (dow))
792 vtp->value = args->fmemb;
793 else if (zero_offset (args->r, dow)) {
794 vtp->value = args->fmemb;
795 vtp->cast_avoid_downcast = 1;
798 Token dc = i_downcast_function (dow, args->r);
799 OUTSTREAM tmp = new_stream ();
800 outprintf (tmp, //STRNEXT, proto, linkonce_text (vfn), ';',
801 ISTR (proto), '{', RESERVED_return, args->fmemb,
802 '(', dc, '(', RESERVED_this, ')', -1);
803 for (i = 1; args->argv [i] != -1; i++)
804 outprintf (tmp, ',', args->argv [i], -1);
805 outprintf (tmp, ')', ';', '}', -1);
806 vtp->code = combine_output (tmp);
810 void purify_vfunc (Token f)
815 for (i = 0; i < nVTI; i++)
816 for (v = VirtualInitializer [i].first_entry; v; v = v->next)
817 if (v->value == f || v->code && intchr (v->code, f)) {
818 v->value = RESERVED_0;
819 VirtualInitializer [i].unused = true;
822 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
824 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
826 static void close_inits (structure *s)
828 if (!s->vtis) return;
830 for (i = 0; s->vtis [i] != -1; i++)
831 VirtualInitializer [s->vtis [i]].open = false;
834 static void v_t_instances (vtblID vi)
838 for (hp = i = ns = ne = 0; i < VirtualTable [vi].nvti; i++)
839 if (!VirtualInitializer [VirtualTable [vi].vti [i].initTbl].unused) {
840 if (structs [VirtualInitializer [VirtualTable
841 [vi].vti [i].initTbl].rec].keyfunc != -1)
847 return; // ----> leave
850 outprintf (VTABLE_DECLARATIONS, RESERVED_extern,
851 CONST_IF (VirtualTable [vi].constd), RESERVED_struct,
852 VirtualTable [vi].vtname, -1);
853 for (hp = i = 0; i < VirtualTable [vi].nvti; i++)
854 if (!VirtualInitializer [VirtualTable [vi].vti [i].initTbl].unused
855 && structs [VirtualInitializer [VirtualTable
856 [vi].vti [i].initTbl].rec].keyfunc != -1) {
857 outprintf (VTABLE_DECLARATIONS, COMMA_IF (hp),
858 VirtualInitializer [VirtualTable [vi].vti
859 [i].initTbl].instance_name, -1);
862 output_itoken (VTABLE_DECLARATIONS, ';');
865 outprintf (VTABLE_DECLARATIONS, RESERVED_static,
866 CONST_IF (VirtualTable [vi].constd), RESERVED_struct,
867 VirtualTable [vi].vtname, -1);
868 for (hp = i = 0; i < VirtualTable [vi].nvti; i++)
869 if (!VirtualInitializer [VirtualTable [vi].vti [i].initTbl].unused
870 && structs [VirtualInitializer [VirtualTable
871 [vi].vti [i].initTbl].rec].keyfunc == -1) {
872 outprintf (VTABLE_DECLARATIONS, COMMA_IF (hp),
873 VirtualInitializer [VirtualTable [vi].vti
874 [i].initTbl].instance_name, -1);
877 output_itoken (VTABLE_DECLARATIONS, ';');
881 void export_virtual_table_instances ()
884 for (i = 0; i < nVTBL; i++)
888 static void virtual_init_definition (initID i, bool stc)
890 Token inst = VirtualInitializer [i].instance_name;
891 bool constd = VirtualTable [VirtualInitializer [i].v_t_i].constd;
894 // emit the code of the virtuallity downcasting functions
895 for (ve = VirtualInitializer [i].first_entry; ve; ve = ve->next)
896 if (ve->code && ve->value && ve->value != RESERVED_0)
897 outprintf (VIRTUALTABLES, RESERVED_inline, RESERVED_static,
898 ISTR (ve->code), -1);
900 outprintf (VIRTUALTABLES, CONST_IF (constd), STATIC_IF (stc), RESERVED_struct,
901 VirtualTable [VirtualInitializer [i].v_t_i].vtname,
905 /* Not used after the discovery of the "key function" technique */
907 outprintf (VIRTUALTABLES, (constd ? linkonce_rodata : linkonce_data) (inst), -1);
908 //else output_itoken (VIRTUALTABLES, section_vtblz (structs));
911 output_itoken (VIRTUALTABLES, section_vtblz (
912 name_of_struct (VirtualTable [VirtualInitializer [i].v_t_i].appeared_at)));
914 for (ve = VirtualInitializer [i].first_entry; ve; ve = ve->next)
915 if (ve->value || ve->code)
917 if (!ve) goto closure;
919 outprintf (VIRTUALTABLES, '=', '{', -1);
920 for (ve = VirtualInitializer [i].first_entry; ve; ve = ve->next)
921 if (ve->status != VTI_STATUS_NI)
922 if (ve->cast_avoid_downcast && ve->value && ve->value != RESERVED_0)
923 // cast avoid downcast
924 outprintf (VIRTUALTABLES, '.', ISTR (ve->vt_ent->zpath),
925 '=', '(', RESERVED___typeof__, '(', inst, '.',
926 ISTR (ve->vt_ent->zpath), ')', ')', ve->value, ',', -1);
927 else if (ve->value) // functions have this
928 outprintf (VIRTUALTABLES, '.',
929 ISTR (ve->vt_ent->zpath), '=', ve->value, ',', -1);
930 else if (ve->code) // virtual variables with const initi
931 outprintf (VIRTUALTABLES, '.',
932 ISTR (ve->vt_ent->zpath), '=', ISTR (ve->code), ',', -1);
933 outprintf (VIRTUALTABLES, '}', -1);
936 outprintf (VIRTUALTABLES, ';', -1);
939 void export_virtual_definitions ()
942 for (i = 0; i < nVTI; i++)
943 if (!VirtualInitializer [i].unused &&
944 (ExportVtbl || structs [VirtualInitializer [i].rec].evt)) {
945 recID r = VirtualInitializer [i].rec;
946 if (structs [r].havekey)
947 virtual_init_definition (i, 0);
948 else if (structs [r].keyfunc == -1)
949 virtual_init_definition (i, 1);
950 else if (!structs [r].keyfunc) {
951 // PRINTF (COLS"******** NO KEYFUNC FOR %s *****\n"COLE, SNM(r));
954 // PRINTF (COLS"WILL NOT EMIT vtbl FOR %s *****\n"COLE, SNM(r));
959 void export_virtual_static_definitions ()
962 for (i = 0; i < nVTI; i++)
963 if (!VirtualInitializer [i].unused
964 && VirtualInitializer [i].exportdef)
965 virtual_init_definition (i, 1);
967 // #/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#
968 // allocate structure & all virtual base
969 // classes in one structure.
970 // Mainly useful to free() all of them
972 // #/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#/#
974 static void mark_vtinit_unused (recID r)
977 for (i = 0; (j = structs [r].vtis [i]) != -1; i++)
978 VirtualInitializer [j].unused = true;
981 /* We can instantiate a class if it has no pure virtual
982 functions and there are unique final overriders for
984 static bool can_instantiate (recID r)
986 if (structs [r].vtis) {
989 for (i = 0; structs [r].vtis [i] != -1; i++) {
990 vti_entry *v = VirtualInitializer [structs [r].vtis [i]].first_entry;
991 for (; v; v = v->next)
992 if (v->status != VTI_STATUS_NI && v->value == RESERVED_0) {
993 structs [r].caninst = CANT_PUREV;
994 mark_vtinit_unused (r);
996 } else if (v->status == VTI_STATUS_NU) {
997 structs [r].caninst = CANT_NUFO;
998 mark_vtinit_unused (r);
1004 structs [r].caninst = OK_CAN;
1008 /* We have either the definition of a common instance (class no longer abstract),
1009 * or collapse of virtual tables due to virtual inheritance.
1010 * vbase is the virtual base, r is the current class and vbpath the path
1011 * that leads to the vb instance. Calculate all related offsets and set
1012 * their values at the entries of the [r] virtual initializer */
1013 #define VOIDCAST '(', RESERVED_void, '*', ')'
1014 static void dcast_offsets (recID vbase, recID r, Token *vbpath)
1016 if (!structs [vbase].rtti) return;
1017 if (!structs [vbase].vtis) return;
1021 Token rtn, *path, d [128];
1024 for (i = 0; (dc = structs [vbase].rtti [i].to) != -1; i++)
1025 if (dc == r || is_ancestor (r, dc, &path, true)) {
1026 rtn = structs [vbase].rtti [i].entry;
1029 sintprintf (d, VOIDCAST, RESERVED_0, -1);
1031 sintprintf (d, VOIDCAST, '&', '(', '(', iRESERVED_struct (r),
1032 name_of_struct (r), '*', ')',
1033 RESERVED_0, ')', POINTSAT, ISTR (path), -1);
1036 sintprintf (d + intlen (d), '-', VOIDCAST, '&', '(', '(',
1037 iRESERVED_struct (r), name_of_struct (r), '*', ')',
1038 RESERVED_0, ')', POINTSAT, ISTR (vbpath), -1);
1040 for (j = 0; (ii = structs [r].vtis [j]) != -1; j++)
1041 for (ve = VirtualInitializer [ii].first_entry; ve; ve = ve->next)
1042 if (ve->vt_ent->entry_name == rtn)
1044 parse_error_ll ("Bug bug bug ()");
1046 ve->code = intdup (d);
1048 if (debugflag.VIRTUALBASE) {
1049 PRINTF ("\n "COLS"+"COLE"Changed offset of "COLS"%s"COLE" in the vtable of "COLS"%s"COLE" to \n\t"COLS,
1050 expand (rtn), SNM (r));
1052 PRINTF (COLE"\n\n");
1058 static inline bool ancestor_is_vbaseclass (ancestor *a)
1060 return (a->status == ASTATUS_VIRT || a->status == ASTATUS_VIRT2) && a->rec == a->vbase;
1063 static void fix_all_offsets (recID r)
1067 for (a = structs [r].ancestors; a->rec != -1; a++)
1068 if (ancestor_is_vbaseclass (a) && a->cpath)
1069 dcast_offsets (a->rec, r, a->cpath);
1072 static void update_ancestor_paths (recID r, recID vb, Token sn)
1077 for (a = structs [r].ancestors; a->rec != -1; a++)
1078 if (a->status == ASTATUS_VIRT && a->vbase == vb) {
1079 Token n = name_inherited (name_of_struct (vb));
1081 Token *p = &a->path [intlen (a->path)];
1082 while (p >= a->path && *p != n) p--;
1083 if (p [1] == -1 || p < a->path)
1084 sintprintf (tmp, sn, -1);
1086 sintprintf (tmp, sn, '.', ISTR (p + 2), -1);
1087 a->cpath = intdup (tmp);
1090 /* this is rare (chained virtual inheritance) */
1091 for (a = structs [r].ancestors; a->rec != -1; a++)
1092 if ((a->status == ASTATUS_VIRT || a->status == ASTATUS_VIRT2)
1093 && a->vbase != vb && (a->cpath && intchr (a->cpath, POINTSAT))
1094 && is_ancestor (vb, a->rec, &p, true)) {
1096 sintprintf (tmp, sn, '.', ISTR (p), -1);
1097 if (a->cpath) free (a->cpath);
1098 a->cpath = intdup (tmp);
1099 //i = 0; (restart? very rare) XXX
1102 if (debugflag.VIRTUALTABLES) show_ancest (r);
1106 /* declare common shared instance && update const ancestor paths */
1107 static void decl_vballoc_rec (OUTSTREAM o, recID r)
1112 for (a = structs [r].ancestors; a->rec != -1; a++)
1113 if (a->status == ASTATUS_VIRT && a->vbase == (vr = a->rec)
1115 Token sn = name_storage_inherit (vr);
1116 outprintf (o, iRESERVED_struct (vr), name_of_struct (vr), sn, ';', -1);
1117 sintprintf (a->cpath = mallocint (2), sn, -1);
1118 update_ancestor_paths (r, vr, sn);
1119 structs [r].need_recalc_offsets = true;
1123 /* Update all the downcast offsets so they all use the same
1124 * shared instance. This is called after multiple inheritance */
1125 static void update_dcasts (recID r, recID vbs [])
1130 if (!structs [r].need_recalc_offsets)
1131 for (i = 0; vbs [i] != -1; i++) {
1132 for (a = structs [r].ancestors; a->rec != vbs [i]; a++)
1135 structs [r].need_recalc_offsets = true;
1140 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
1141 // Requesting virtual functions from expressions
1142 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
1144 bool lookup_virtual_function_member (recID r, Token f, typeID argv[],
1145 Token *vpath, flookup *F)
1147 if (!structs [r].vtis)
1150 argv [0] = pthis_of_struct (r);
1151 typeID *va = promoted_arglist (argv);
1153 initID iid=iid; /* this is done to avoid warning for uninitialized possible use */
1154 Token *ent_ret, *entn=entn, entname=entname;
1156 ret = status = VTI_STATUS_NI;
1158 for (i = 0; structs [r].vtis [i] != -1; i++)
1159 if ((ret = lookup_virtual_f_ininit (structs [r].vtis[i], f, va, &ent_ret)) != VTI_STATUS_NI)
1160 if (status != VTI_STATUS_NI)
1161 parse_error (0, "Ambiguity virtual inheritance");
1164 iid = structs [r].vtis [i];
1166 entname = entn [intlen (entn) - 1];
1170 if (status == VTI_STATUS_NI || status == VTI_STATUS_FINAL)
1174 if (debugflag.VIRTUALTABLES)
1175 PRINTF ("++ Virtual call for ["COLS"%s"COLE"]\n", expand (f));
1177 /* We must return: The path that leads to the virtual table entry in <vpath>
1178 * The type of the <this> argument in argv [0]
1179 * And finally, the function's type in <F>
1180 * Let's go and do this
1182 vtblID vt = VirtualInitializer [iid].v_t_i;
1186 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
1187 if (ve->entry_name == entname) break;
1188 bo_rec = base_of (ve->arglist [0]);
1190 F->prototype = ve->xproto;
1191 F->xargs = ve->xargs;
1192 F->flagz = ve->flagz;
1198 sintprintf (vpath, ISTR (pathto_vt (tpath, iid, false)),
1199 VirtualTable [vt].inlined ? '.' : POINTSAT, ISTR (entn), -1);
1202 argv [0] = pthis_of_struct (bo_rec);
1206 bool Is_pure_virtual (recID r, Token f, typeID argt [], flookup *F)
1208 if (!structs [r].vtis)
1211 argt [0] = pthis_of_struct (r);
1212 typeID *va = promoted_arglist (argt);
1214 for (j = 0; (i = structs [r].vtis [j]) != -1; j++) {
1215 vtblID vi = VirtualInitializer [i].v_t_i;
1217 for (ve = VirtualTable [vi].first_entry; ve; ve = ve->next)
1218 if (ve->isfunction && ve->fname == f && arglist_compare (va, ve->arglist)) {
1222 F->oname = RESERVED_0;
1224 for (vie = VirtualInitializer [i].first_entry; ; vie = vie->next)
1225 if (vie->vt_ent->entry_name == ve->entry_name)
1226 switch (vie->status) {
1227 case VTI_STATUS_NI: return false;
1228 case VTI_STATUS_NU: return true;
1229 default: return vie->value == RESERVED_0;
1237 // #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#
1238 // Setting of pointer to virtual table at
1239 // construction of objects
1240 // Construction of common virtual base
1242 // #+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#+#
1244 bool need_construction (recID r)
1246 return structs [r].has_vbase || (!structs [r].noctor && (structs [r].vtis
1247 || structs [r].ctorables || structs [r].ancestors_have_ctors));
1250 bool need_vbase_alloc (recID r)
1252 return structs [r].has_vbase;
1255 /* assignm apropriate virtual table initializer to object */
1256 void gen_vt_init (OUTSTREAM o, recID r, Token obj, bool throuptr)
1261 for (i = 0; structs [r].vtis [i] != -1; i++) {
1262 initID ii = structs [r].vtis [i];
1263 vtblID vt = VirtualInitializer [ii].v_t_i;
1264 bool constd = VirtualTable [vt].constd;
1265 bool inlined = VirtualTable [vt].inlined;
1266 bool volatiled = VirtualTable [vt].volatiled;
1267 Token vtn = VirtualTable [vt].vtname;
1268 Token instn = VirtualInitializer [ii].instance_name;
1270 if (inlined) // write vtbl despite possible constnesses
1271 #ifdef HAVE_BUILTIN_MEMCPY // this is wrong. nothing to do with "__builtin"
1272 outprintf (o, INTERN_memcpy, '(',
1273 '(', RESERVED_void, '*', ')',
1274 '&', obj, throuptr ? POINTSAT : '.',
1275 ISTR (pathto_vt (path, ii, true)),
1276 ',', '&', instn, ',', RESERVED_sizeof, '(',
1277 instn, ')', ')', ';', -1);
1279 outprintf (o, '*', '(', '(', RESERVED_struct,
1280 VirtualTable [vt].vtname, '*', ')',
1281 '&', obj, throuptr ? POINTSAT : '.',
1282 ISTR (pathto_vt (path, ii, true)),
1283 ')', '=', instn, ';', -1);
1287 outprintf (o, '*', '(', RESERVED_struct, vtn, '*', '*',
1288 ')', '&', obj, throuptr ? POINTSAT : '.',
1289 ISTR (pathto_vt (path, ii, true)), '=', -1);//'&', instn, ';', -1);
1290 else outprintf (o, obj, throuptr ? POINTSAT : '.',
1291 ISTR (pathto_vt (path, ii, true)), '=', -1);//'&', instn, ';', -1);
1292 if (constd) outprintf (o, '(', RESERVED_void, '*', ')', -1);
1293 outprintf (o, '&', instn, ';', -1);
1298 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
1299 // rtti: when we want to downcast
1300 // from a virtual base class to a
1301 // derrived class. We have to do
1302 // that in virtual functns anyway
1303 // #*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#
1305 void downcast_rtti (recID rder, recID rbase, recID rs, Token path[])
1308 for (i = 0; structs [rbase].rtti [i].to != rder; i++)
1310 rtti_downcast *rtti = &structs [rbase].rtti [i];
1312 if ((vti = rtti->vti) == -1)
1313 parse_error (0, "Can't downcast. No virtual table. No RTTI.");
1316 vtblID vt = VirtualInitializer [vti].v_t_i;
1318 for (ve = VirtualTable [vt].first_entry;; ve = ve->next)
1319 if (ve->entry_name == rtti->entry) break;
1321 for (vti = 0; VirtualTable [vt].vti [vti].object != rs; vti++);
1322 vti = VirtualTable [vt].vti [vti].initTbl;
1325 sintprintf (path, ISTR (pathto_vt (vpath, vti, false)),
1326 VirtualTable [vt].inlined ? '.' : POINTSAT, ISTR (ve->zpath), -1);
1329 static int new_rtti_entry (recID obj)
1333 if (structs [obj].rtti)
1334 for (i = 1; structs [obj].rtti [i].to != -1; i++);
1335 structs [obj].rtti = (rtti_downcast*) realloc (structs [obj].rtti,
1336 (i + 2) * sizeof (rtti_downcast));
1337 structs [obj].rtti [i + 1].to = -1;
1342 static int lookup_rtti (recID obj, Token c)
1346 if (structs [obj].rtti)
1347 for (i = 0; structs [obj].rtti [i].to != -1; i++)
1348 if (structs [obj].rtti [i].fwd_dcl == c)
1353 int virtual_inheritance_decl (OUTSTREAM O, recID obj, Token c)
1355 int i = lookup_rtti (obj, c);
1357 if (i != -1) return i;
1358 if (O) structs [obj].have_vi_decls = true;
1360 i = new_rtti_entry (obj);
1361 structs [obj].rtti [i].fwd_dcl = c;
1362 structs [obj].rtti [i].to = 0;
1364 initID ii = best_vti (obj);
1366 if (!O) parse_error_tok (name_of_struct (obj),
1367 "In order to do virtual inheritance, please "
1368 "create a virtual table for this class");
1369 Here_virtualtable (O, obj, false, ConstVtables, !vtptrConst);
1370 ii = best_vti (obj);
1373 structs [obj].rtti [i].vti = ii;
1375 /* make virtual table entry */
1376 vtblID vt = VirtualInitializer [ii].v_t_i;
1377 vt_entry *ve = (vt_entry*) malloc (sizeof * ve);
1379 ve->entry_name = structs [obj].rtti [i].entry = name_rtti_slot (obj, c);
1381 ve->isfunction = false;
1382 ve->introduced_at = obj;
1383 ve->prototype = mallocint (5);
1385 sintprintf (ve->prototype, /*RESERVED_const,*/ RESERVED_int, ve->entry_name, -1);
1386 add_vt_entry (vt, ve);
1391 static void add_rtti (recID obj, recID der)
1398 i = lookup_rtti (obj, name_of_struct (der));
1400 if (!structs [obj].vtis) {
1401 // no virtual table! downcast impossible
1402 i = new_rtti_entry (obj);
1403 structs [obj].rtti [i].to = der;
1404 structs [obj].rtti [i].fwd_dcl = name_of_struct (der);
1405 structs [obj].rtti [i].vti = -1;
1407 } else if (VIDeclarations || structs [obj].have_vi_decls)
1408 parse_error_tok (name_of_struct (der), "Virtual inheritance not declared");
1409 else i = virtual_inheritance_decl (0, obj, name_of_struct (der));
1411 /* activate the virtual table entry */
1412 structs [obj].rtti [i].to = der;
1413 I = structs [obj].rtti [i].vti;
1414 vt = VirtualInitializer [I].v_t_i;
1415 for (ve = VirtualTable [vt].first_entry;
1416 ve->entry_name != structs [obj].rtti [i].entry; ve = ve->next);
1418 ve->type = pthis_of_struct (der);
1419 for (j = 0; j < VirtualTable [vt].nvti; j++) {
1420 vti_entry *vte = (vti_entry*) malloc (sizeof * vte);
1423 vte->code = 0; vte->value = 0;
1424 vte->status = VirtualTable [vt].vti [j].object == der ?
1425 VTI_STATUS_DD : VTI_STATUS_NI;
1426 vte->cast_avoid_downcast = 0;
1427 add_vti_entry (VirtualTable [vt].vti [j].initTbl, vte);
1431 static void make_rtti (recID r)
1435 for (a = structs [r].ancestors; a->rec != -1; a++)
1436 if (a->path [1] == -1
1437 && (a->status == ASTATUS_VIRT || a->status == ASTATUS_VIRT2))
1438 add_rtti (a->rec, r);
1441 // #<#<#<#<#<#<#<#<#<#<#<#<#<#<#<#
1442 // Virtual data members
1443 // #<#<#<#<#<#<#<#<#<#<#<#<#<#<#<#
1445 typeID lookup_virtual_varmemb (recID r, Token m, Token *path, bool const_path, Token **cval)
1454 if (!structs [r].vtis)
1457 for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
1458 vt = VirtualInitializer [ii].v_t_i;
1459 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
1460 if (!ve->isfunction && ve->fname == m)
1461 for (vte = VirtualInitializer [ii].first_entry; vte; vte = vte->next)
1462 if (vte->vt_ent->entry_name==ve->entry_name && vte->status != VTI_STATUS_NI)
1463 if (rett != -1) expr_errort ("ambiguous virtual member", m);
1468 sintprintf (path, ISTR (pathto_vt (vpath, ii, false)),
1469 VirtualTable [vt].inlined ? '.' : POINTSAT,
1470 ISTR (vte->vt_ent->zpath), -1);
1471 else sintprintf (path, VirtualInitializer [ii].
1473 ISTR (vte->vt_ent->zpath), -1);
1476 *cval = !path || VirtualTable [vt].constd
1478 vte->code ?: zinit : 0;
1480 if (objective.recording && VirtualInitializer [ii].unused
1488 /* <classname>.<member> syntax */
1489 vtvar access_virtual_variable (recID r, Token m)
1491 vtvar ret = { .t = -1 };
1499 if (!structs [r].vtis)
1502 for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
1503 vt = VirtualInitializer [ii].v_t_i;
1504 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
1505 if (!ve->isfunction && ve->fname == m)
1506 for (vte = VirtualInitializer [ii].first_entry; vte; vte = vte->next)
1507 if (vte->vt_ent->entry_name == ve->entry_name && vte->status != VTI_STATUS_NI)
1508 if (have != -1) expr_errort ("ambiguous virtual member", m);
1510 if (VirtualTable [vt].inlined)
1511 expr_errort ("can't access virtual variable of inlined virtual table", m);
1512 ret.rec = have = VirtualInitializer [ii].instance_name;
1513 ret.memb = ve->zpath;
1515 ret.expr = vte->code;
1521 bool Is_implied_virtual_variable (recID r, Token m)
1523 return lookup_virtual_varmemb (r, m, 0, 0, 0) != -1;
1526 void add_virtual_varmemb (recID r, Token m, Token a, typeID t, Token *expr, Token *proto,
1527 bool cnst, OUTSTREAM o)
1533 bool isconst = proto [0] == RESERVED_const || proto [1] == RESERVED_const;
1535 if (!structs [r].vtis) {
1537 /* XXX: why don't we call Here_virtual_table() here ?????? */
1538 /* XXX: We demand to see the persons who wrote this */
1539 /* Virtualize Class */
1540 add_variable_member (r, RESERVED__v_p_t_r_, typeID_voidP, 0, false, false);
1541 vt = new_virtual_table ();
1542 bool inlined = VirtualTable [vt].inlined;
1543 bool constd = VirtualTable [vt].constd;
1545 if (m == RESERVED_typeid)
1546 VirtualTable [vt].typeid = true;
1547 VirtualTable [vt].appeared_at = r;
1548 VirtualTable [vt].vtname = name_virtual_table (r);
1549 outprintf (o, RESERVED_struct, VirtualTable [vt].vtname,
1550 CONST_IF (constd), STAR_IF (!inlined),
1551 !inlined && vtptrConst? RESERVED_const : BLANKT,
1552 RESERVED__v_p_t_r_, ';', -1);
1554 Token entry_name = name_virtual_variable (r, m);
1555 ve = (vt_entry*) malloc (sizeof * ve);
1557 intsubst (proto, MARKER, entry_name);
1559 .next = 0, .entry_name = entry_name, .isconst = isconst,
1560 .isfunction = false, .type = t, .fname = m,
1561 .prototype = intdup (proto), .introduced_at = r
1563 add_vt_entry (vt, ve);
1565 initID vi = new_v_t_initializer (r);
1566 VirtualInitializer [vi].v_t_i = vt;
1567 VirtualInitializer [vi].instance_name = name_instance (r, r);
1568 add_initializer (vt, vi, r);
1570 vte = (vti_entry*) malloc (sizeof * vte);
1571 *vte = (vti_entry) {
1572 .next = 0, .vt_ent = ve, .value = 0,
1573 .code = expr, .status = VTI_STATUS_DD
1575 VirtualInitializer [vi].first_entry = vte;
1577 structs [r].vtis = mallocint (2);
1578 structs [r].vtis [0] = vi;
1579 structs [r].vtis [1] = -1;
1583 typeID ht = lookup_virtual_varmemb (r, m, 0, 0, &initexpr);
1585 if (!has_vtable (r))
1588 /* New Entry To Best Virtual Table */
1589 vt = VirtualInitializer [best_vti (r)].v_t_i;
1590 if (m == RESERVED_typeid)
1591 VirtualTable [vt].typeid = true;
1592 ve = (vt_entry*) malloc (sizeof * ve);
1593 Token entry_name = name_virtual_variable (r, m);
1595 intsubst (proto, MARKER, entry_name);
1597 .next = 0, .entry_name = entry_name, .isconst = isconst,
1598 .isfunction = false, .type = t, .fname = m,
1599 .prototype = intdup (proto), .introduced_at = r
1601 add_vt_entry (vt, ve);
1603 for (i = 0; i < VirtualTable [vt].nvti; i++) {
1604 vte = (vti_entry*) malloc (sizeof * vte);
1605 *vte = (vti_entry) {
1606 .next = 0, .vt_ent = ve, .value = 0
1608 if (VirtualTable [vt].vti [i].object != r) {
1610 vte->status = VTI_STATUS_NI;
1613 vte->status = VTI_STATUS_DD;
1615 add_vti_entry (VirtualTable [vt].vti [i].initTbl, vte);
1620 parse_error_tok (m, "Virtual member redefined with different type");
1621 if (in2 (a, ASSIGNBO, ASSIGNBA) && initexpr) {
1622 Token *xx = mallocint (intlen (expr) + intlen (initexpr) + 5);
1623 sintprintf (xx, '(', ISTR (initexpr), ')', a == ASSIGNBO ? '|' : '&',
1629 for (i = 0; (ii = structs [r].vtis [i]) != -1; i++) {
1630 vt = VirtualInitializer [ii].v_t_i;
1631 for (ve = VirtualTable [vt].first_entry; ve; ve = ve->next)
1633 for (vte = VirtualInitializer [ii].first_entry; vte; vte = vte->next)
1634 if (vte->vt_ent->entry_name == ve->entry_name && vte->status != VTI_STATUS_NI) {
1635 if (vte->status == VTI_STATUS_DD) parse_error_tok (m, "redefined?");
1636 vte->status = VTI_STATUS_DD;
1641 parse_error_tok (m, "Some strange kind of bug (:)");
1644 void mk_typeid (recID r)
1650 if (!structs [r].vtis)
1653 for (i = 0; structs [r].vtis [i] != -1; i++)
1654 if (VirtualTable [VirtualInitializer [structs [r].vtis [i]].v_t_i].typeid)
1655 for (v = VirtualInitializer [structs [r].vtis [i]].first_entry; v;
1657 if (!(ve = v->vt_ent)->isfunction && ve->fname == RESERVED_typeid) {
1658 if (v->status != VTI_STATUS_NI)
1659 v->code = sintprintf (mallocint (2),
1660 i_typeid_var (name_of_struct (r)), -1);
1665 Token get_class_vptr (recID r)
1668 initID *j = structs [r].vtis;
1671 if (!j) expr_errort ("No _v_p_t_r_ for class", name_of_struct (r));
1675 else for (i = 0; j [i] != -1; i++)
1676 if (VirtualTable [VirtualInitializer [j[i]].v_t_i].appeared_at == r)
1679 expr_errort ("Ambiguous _v_p_t_r_ for class", name_of_struct (r));
1680 if (objective.recording && VirtualInitializer [vid].unused)
1682 return VirtualInitializer [vid].instance_name;