1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1984-1998 by Symantec
6  *              Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      https://github.com/dlang/dmd/blob/master/src/dmd/backend/symbol.d
10  */
11 
12 module dmd.backend.symbol;
13 
14 version (SCPP)
15 {
16     version = COMPILE;
17     version = SCPP_HTOD;
18 }
19 version (HTOD)
20 {
21     version = COMPILE;
22     version = SCPP_HTOD;
23 }
24 version (MARS)
25 {
26     version = COMPILE;
27     enum HYDRATE = false;
28     enum DEHYDRATE = false;
29 }
30 
31 version (COMPILE)
32 {
33 import core.stdc.stdio;
34 import core.stdc.stdlib;
35 import core.stdc.string;
36 
37 import dmd.backend.cdef;
38 import dmd.backend.cc;
39 import dmd.backend.cgcv;
40 import dmd.backend.dlist;
41 import dmd.backend.dt;
42 import dmd.backend.dvec;
43 import dmd.backend.el;
44 import dmd.backend.global;
45 import dmd.backend.mem;
46 import dmd.backend.oper;
47 import dmd.backend.ty;
48 import dmd.backend.type;
49 
50 version (SCPP_HTOD)
51 {
52     import cpp;
53     import dtoken;
54     import scopeh;
55     import msgs2;
56     import parser;
57     import precomp;
58 
59     extern (C++) void baseclass_free(baseclass_t *b);
60 }
61 
62 
63 extern (C++):
64 
65 nothrow:
66 
67 alias MEM_PH_MALLOC = mem_malloc;
68 alias MEM_PH_CALLOC = mem_calloc;
69 alias MEM_PH_FREE = mem_free;
70 alias MEM_PH_FREEFP = mem_freefp;
71 alias MEM_PH_STRDUP = mem_strdup;
72 alias MEM_PH_REALLOC = mem_realloc;
73 alias MEM_PARF_MALLOC = mem_malloc;
74 alias MEM_PARF_CALLOC = mem_calloc;
75 alias MEM_PARF_REALLOC = mem_realloc;
76 alias MEM_PARF_FREE = mem_free;
77 alias MEM_PARF_STRDUP = mem_strdup;
78 
79 version (SCPP_HTOD)
80     enum mBP = 0x20;
81 else
82     import dmd.backend.code_x86;
83 
84 void struct_free(struct_t *st) { }
85 
86 func_t* func_calloc() { return cast(func_t *) calloc(1, func_t.sizeof); }
87 void func_free(func_t* f) { free(f); }
88 
89 /*********************************
90  * Allocate/free symbol table.
91  */
92 
93 extern (C) Symbol **symtab_realloc(Symbol **tab, size_t symmax)
94 {   Symbol **newtab;
95 
96     if (config.flags2 & (CFG2phgen | CFG2phuse | CFG2phauto | CFG2phautoy))
97     {
98         newtab = cast(Symbol **) MEM_PH_REALLOC(tab, symmax * (Symbol *).sizeof);
99     }
100     else
101     {
102         newtab = cast(Symbol **) realloc(tab, symmax * (Symbol *).sizeof);
103         if (!newtab)
104             err_nomem();
105     }
106     return newtab;
107 }
108 
109 Symbol **symtab_malloc(size_t symmax)
110 {   Symbol **newtab;
111 
112     if (config.flags2 & (CFG2phgen | CFG2phuse | CFG2phauto | CFG2phautoy))
113     {
114         newtab = cast(Symbol **) MEM_PH_MALLOC(symmax * (Symbol *).sizeof);
115     }
116     else
117     {
118         newtab = cast(Symbol **) malloc(symmax * (Symbol *).sizeof);
119         if (!newtab)
120             err_nomem();
121     }
122     return newtab;
123 }
124 
125 Symbol **symtab_calloc(size_t symmax)
126 {   Symbol **newtab;
127 
128     if (config.flags2 & (CFG2phgen | CFG2phuse | CFG2phauto | CFG2phautoy))
129     {
130         newtab = cast(Symbol **) MEM_PH_CALLOC(symmax * (Symbol *).sizeof);
131     }
132     else
133     {
134         newtab = cast(Symbol **) calloc(symmax, (Symbol *).sizeof);
135         if (!newtab)
136             err_nomem();
137     }
138     return newtab;
139 }
140 
141 void symtab_free(Symbol **tab)
142 {
143     if (config.flags2 & (CFG2phgen | CFG2phuse | CFG2phauto | CFG2phautoy))
144         MEM_PH_FREE(tab);
145     else if (tab)
146         free(tab);
147 }
148 
149 /*******************************
150  * Type out symbol information.
151  */
152 
153 void symbol_print(const Symbol *s)
154 {
155 debug
156 {
157 version (COMPILE)
158 {
159     if (!s) return;
160     printf("symbol %p '%s'\n ",s,s.Sident.ptr);
161     printf(" Sclass = "); WRclass(cast(SC) s.Sclass);
162     printf(" Ssymnum = %d",s.Ssymnum);
163     printf(" Sfl = "); WRFL(cast(FL) s.Sfl);
164     printf(" Sseg = %d\n",s.Sseg);
165 //  printf(" Ssize   = x%02x\n",s.Ssize);
166     printf(" Soffset = x%04llx",cast(ulong)s.Soffset);
167     printf(" Sweight = %d",s.Sweight);
168     printf(" Sflags = x%04x",cast(uint)s.Sflags);
169     printf(" Sxtrnnum = %d\n",s.Sxtrnnum);
170     printf("  Stype   = %p",s.Stype);
171 version (SCPP_HTOD)
172 {
173     printf(" Ssequence = %x", s.Ssequence);
174     printf(" Scover  = %p", s.Scover);
175 }
176     printf(" Sl      = %p",s.Sl);
177     printf(" Sr      = %p\n",s.Sr);
178     if (s.Sscope)
179         printf(" Sscope = '%s'\n",s.Sscope.Sident.ptr);
180     if (s.Stype)
181         type_print(s.Stype);
182     if (s.Sclass == SCmember || s.Sclass == SCfield)
183     {
184         printf("  Smemoff =%5lld", cast(long)s.Smemoff);
185         printf("  Sbit    =%3d",s.Sbit);
186         printf("  Swidth  =%3d\n",s.Swidth);
187     }
188 version (SCPP_HTOD)
189 {
190     if (s.Sclass == SCstruct)
191     {
192         printf("  Svbptr = %p, Svptr = %p\n",s.Sstruct.Svbptr,s.Sstruct.Svptr);
193     }
194 }
195 }
196 }
197 }
198 
199 
200 /*********************************
201  * Terminate use of symbol table.
202  */
203 
204 private __gshared Symbol *keep;
205 
206 void symbol_term()
207 {
208     symbol_free(keep);
209 }
210 
211 /****************************************
212  * Keep symbol around until symbol_term().
213  */
214 
215 static if (TERMCODE)
216 {
217 
218 void symbol_keep(Symbol *s)
219 {
220     symbol_debug(s);
221     s.Sr = keep;       // use Sr so symbol_free() doesn't nest
222     keep = s;
223 }
224 
225 }
226 
227 /****************************************
228  * Return alignment of symbol.
229  */
230 int Symbol_Salignsize(Symbol* s)
231 {
232     if (s.Salignment > 0)
233         return s.Salignment;
234     int alignsize = type_alignsize(s.Stype);
235 
236     /* Reduce alignment faults when SIMD vectors
237      * are reinterpreted cast to other types with less alignment.
238      */
239     if (config.fpxmmregs && alignsize < 16 &&
240         s.Sclass == SCauto &&
241         type_size(s.Stype) == 16)
242     {
243         alignsize = 16;
244     }
245 
246     return alignsize;
247 }
248 
249 /****************************************
250  * Aver if Symbol is not only merely dead, but really most sincerely dead.
251  * Params:
252  *      anyInlineAsm = true if there's any inline assembler code
253  * Returns:
254  *      true if symbol is dead.
255  */
256 
257 bool Symbol_Sisdead(const Symbol* s, bool anyInlineAsm)
258 {
259     version (MARS)
260         enum vol = false;
261     else
262         enum vol = true;
263     return s.Sflags & SFLdead ||
264            /* SFLdead means the optimizer found no references to it.
265             * The rest deals with variables that the compiler never needed
266             * to read from memory because they were cached in registers,
267             * and so no memory needs to be allocated for them.
268             * Code that does write those variables to memory gets NOPed out
269             * during address assignment.
270             */
271            (!anyInlineAsm && !(s.Sflags & SFLread) && s.Sflags & SFLunambig &&
272 
273             // mTYvolatile means this variable has been reference by a nested function
274             (vol || !(s.Stype.Tty & mTYvolatile)) &&
275 
276             (config.flags4 & CFG4optimized || !config.fulltypes));
277 }
278 
279 /****************************************
280  * Determine if symbol needs a 'this' pointer.
281  */
282 
283 int Symbol_needThis(const Symbol* s)
284 {
285     //printf("needThis() '%s'\n", Sident.ptr);
286 
287     debug assert(isclassmember(s));
288 
289     if (s.Sclass == SCmember || s.Sclass == SCfield)
290         return 1;
291     if (tyfunc(s.Stype.Tty) && !(s.Sfunc.Fflags & Fstatic))
292         return 1;
293     return 0;
294 }
295 
296 /************************************
297  * Determine if `s` may be affected if an assignment is done through
298  * a pointer.
299  * Params:
300  *      s = symbol to check
301  * Returns:
302  *      true if it may be modified by assignment through a pointer
303  */
304 
305 bool Symbol_isAffected(const ref Symbol s)
306 {
307     //printf("s: %s %d\n", s.Sident.ptr, !(s.Sflags & SFLunambig) && !(s.ty() & (mTYconst | mTYimmutable)));
308     //symbol_print(s);
309 
310     /* If nobody took its address and it's not statically allocated,
311      * then it is not accessible via pointer and so is not affected.
312      */
313     if (s.Sflags & SFLunambig)
314         return false;
315 
316     /* If it's immutable, it can't be affected
317      */
318     if (s.ty() & (mTYconst | mTYimmutable))
319     {
320         return false;
321     }
322     return true;
323 }
324 
325 
326 /***********************************
327  * Get user name of symbol.
328  */
329 
330 const(char)* symbol_ident(const Symbol *s)
331 {
332 version (SCPP_HTOD)
333 {
334     __gshared char* noname = cast(char*)"__unnamed".ptr;
335     switch (s.Sclass)
336     {   case SCstruct:
337             if (s.Sstruct.Salias)
338                 return s.Sstruct.Salias.Sident.ptr;
339             else if (s.Sstruct.Sflags & STRnotagname)
340                 return noname;
341             break;
342         case SCenum:
343             if (CPP)
344             {   if (s.Senum.SEalias)
345                     return s.Senum.SEalias.Sident.ptr;
346                 else if (s.Senum.SEflags & SENnotagname)
347                     return noname;
348             }
349             break;
350 
351         case SCnamespace:
352             if (s.Sident[0] == '?' && s.Sident.ptr[1] == '%')
353                 return cast(char*)"unique".ptr;        // an unnamed namespace
354             break;
355 
356         default:
357             break;
358     }
359 }
360     return s.Sident.ptr;
361 }
362 
363 /****************************************
364  * Create a new symbol.
365  */
366 
367 Symbol * symbol_calloc(const(char)* id)
368 {
369     return symbol_calloc(id, cast(uint)strlen(id));
370 }
371 
372 Symbol * symbol_calloc(const(char)* id, uint len)
373 {   Symbol *s;
374 
375     //printf("sizeof(symbol)=%d, sizeof(s.Sident)=%d, len=%d\n",sizeof(symbol),sizeof(s.Sident),(int)len);
376     s = cast(Symbol *) mem_fmalloc(Symbol.sizeof - s.Sident.length + len + 1 + 5);
377     memset(s,0,Symbol.sizeof - s.Sident.length);
378 version (SCPP_HTOD)
379 {
380     s.Ssequence = pstate.STsequence;
381     pstate.STsequence += 1;
382     //if (s.Ssequence == 0x21) *cast(char*)0=0;
383 }
384 debug
385 {
386     if (debugy)
387         printf("symbol_calloc('%s') = %p\n",id,s);
388     s.id = Symbol.IDsymbol;
389 }
390     memcpy(s.Sident.ptr,id,len + 1);
391     s.Ssymnum = -1;
392     return s;
393 }
394 
395 /****************************************
396  * Create a symbol, given a name and type.
397  */
398 
399 Symbol * symbol_name(const(char)* name,int sclass,type *t)
400 {
401     return symbol_name(name, cast(uint)strlen(name), sclass, t);
402 }
403 
404 Symbol * symbol_name(const(char)* name, uint len, int sclass, type *t)
405 {
406     type_debug(t);
407     Symbol *s = symbol_calloc(name, len);
408     s.Sclass = cast(char) sclass;
409     s.Stype = t;
410     s.Stype.Tcount++;
411 
412     if (tyfunc(t.Tty))
413         symbol_func(s);
414     return s;
415 }
416 
417 /****************************************
418  * Create a symbol that is an alias to another function symbol.
419  */
420 
421 Funcsym *symbol_funcalias(Funcsym *sf)
422 {
423     Funcsym *s;
424 
425     symbol_debug(sf);
426     assert(tyfunc(sf.Stype.Tty));
427     if (sf.Sclass == SCfuncalias)
428         sf = sf.Sfunc.Falias;
429     s = cast(Funcsym *)symbol_name(sf.Sident.ptr,SCfuncalias,sf.Stype);
430     s.Sfunc.Falias = sf;
431 
432 version (SCPP_HTOD)
433     s.Scover = sf.Scover;
434 
435     return s;
436 }
437 
438 /****************************************
439  * Create a symbol, give it a name, storage class and type.
440  */
441 
442 Symbol * symbol_generate(int sclass,type *t)
443 {
444     __gshared int tmpnum;
445     char[4 + tmpnum.sizeof * 3 + 1] name;
446 
447     //printf("symbol_generate(_TMP%d)\n", tmpnum);
448     sprintf(name.ptr,"_TMP%d",tmpnum++);
449     Symbol *s = symbol_name(name.ptr,sclass,t);
450     //symbol_print(s);
451 
452 version (MARS)
453     s.Sflags |= SFLnodebug | SFLartifical;
454 
455     return s;
456 }
457 
458 /****************************************
459  * Generate an auto symbol, and add it to the symbol table.
460  */
461 
462 Symbol * symbol_genauto(type *t)
463 {   Symbol *s;
464 
465     s = symbol_generate(SCauto,t);
466 version (SCPP_HTOD)
467 {
468     //printf("symbol_genauto(t) '%s'\n", s.Sident.ptr);
469     if (pstate.STdefertemps)
470     {   symbol_keep(s);
471         s.Ssymnum = -1;
472     }
473     else
474     {   s.Sflags |= SFLfree;
475         if (init_staticctor)
476         {   // variable goes into _STI_xxxx
477             s.Ssymnum = -1;            // deferred allocation
478 //printf("test2\n");
479 //if (s.Sident[4] == '2') *(char*)0=0;
480         }
481         else
482         {
483             symbol_add(s);
484         }
485     }
486 }
487 else
488 {
489     s.Sflags |= SFLfree;
490     symbol_add(s);
491 }
492     return s;
493 }
494 
495 /******************************************
496  * Generate symbol into which we can copy the contents of expression e.
497  */
498 
499 Symbol *symbol_genauto(elem *e)
500 {
501     return symbol_genauto(type_fake(e.Ety));
502 }
503 
504 /******************************************
505  * Generate symbol into which we can copy the contents of expression e.
506  */
507 
508 Symbol *symbol_genauto(tym_t ty)
509 {
510     return symbol_genauto(type_fake(ty));
511 }
512 
513 /****************************************
514  * Add in the variants for a function symbol.
515  */
516 
517 void symbol_func(Symbol *s)
518 {
519     //printf("symbol_func(%s, x%x)\n", s.Sident.ptr, fregsaved);
520     symbol_debug(s);
521     s.Sfl = FLfunc;
522     // Interrupt functions modify all registers
523     // BUG: do interrupt functions really save BP?
524     // Note that fregsaved may not be set yet
525     s.Sregsaved = (s.Stype && tybasic(s.Stype.Tty) == TYifunc) ? cast(regm_t) mBP : fregsaved;
526     s.Sseg = UNKNOWN;          // don't know what segment it is in
527     if (!s.Sfunc)
528         s.Sfunc = func_calloc();
529 }
530 
531 /***************************************
532  * Add a field to a struct s.
533  * Input:
534  *      s       the struct symbol
535  *      name    field name
536  *      t       the type of the field
537  *      offset  offset of the field
538  */
539 
540 void symbol_struct_addField(Symbol *s, const(char)* name, type *t, uint offset)
541 {
542     Symbol *s2 = symbol_name(name, SCmember, t);
543     s2.Smemoff = offset;
544     list_append(&s.Sstruct.Sfldlst, s2);
545 }
546 
547 /********************************
548  * Define symbol in specified symbol table.
549  * Returns:
550  *      pointer to symbol
551  */
552 
553 version (SCPP_HTOD)
554 {
555 Symbol * defsy(const(char)* p,Symbol **parent)
556 {
557    Symbol *s = symbol_calloc(p);
558    symbol_addtotree(parent,s);
559    return s;
560 }
561 }
562 
563 /********************************
564  * Check integrity of symbol data structure.
565  */
566 
567 debug
568 {
569 
570 void symbol_check(const Symbol *s)
571 {
572     //printf("symbol_check('%s',%p)\n",s.Sident.ptr,s);
573     symbol_debug(s);
574     if (s.Stype) type_debug(s.Stype);
575     assert(cast(uint)s.Sclass < cast(uint)SCMAX);
576 version (SCPP_HTOD)
577 {
578     if (s.Sscope)
579         symbol_check(s.Sscope);
580     if (s.Scover)
581         symbol_check(s.Scover);
582 }
583 }
584 
585 void symbol_tree_check(const(Symbol)* s)
586 {
587     while (s)
588     {   symbol_check(s);
589         symbol_tree_check(s.Sl);
590         s = s.Sr;
591     }
592 }
593 
594 }
595 
596 /********************************
597  * Insert symbol in specified symbol table.
598  */
599 
600 version (SCPP_HTOD)
601 {
602 
603 void symbol_addtotree(Symbol **parent,Symbol *s)
604 {  Symbol *rover;
605    byte cmp;
606    size_t len;
607    const(char)* p;
608    char c;
609 
610    //printf("symbol_addtotree('%s',%p)\n",s.Sident.ptr,*parent);
611 debug
612 {
613    symbol_tree_check(*parent);
614    assert(!s.Sl && !s.Sr);
615 }
616    symbol_debug(s);
617    p = s.Sident.ptr;
618    c = *p;
619    len = strlen(p);
620    p++;
621    rover = *parent;
622    while (rover != null)                // while we haven't run out of tree
623    {    symbol_debug(rover);
624         if ((cmp = cast(byte)(c - rover.Sident[0])) == 0)
625         {   cmp = cast(byte)memcmp(p,rover.Sident.ptr + 1,len); // compare identifier strings
626             if (cmp == 0)               // found it if strings match
627             {
628                 if (CPP)
629                 {   Symbol *s2;
630 
631                     switch (rover.Sclass)
632                     {   case SCstruct:
633                             s2 = rover;
634                             goto case_struct;
635 
636                         case_struct:
637                             if (s2.Sstruct.Sctor &&
638                                 !(s2.Sstruct.Sctor.Sfunc.Fflags & Fgen))
639                                 cpperr(EM_ctor_disallowed,p);   // no ctor allowed for class rover
640                             s2.Sstruct.Sflags |= STRnoctor;
641                             goto case_cover;
642 
643                         case_cover:
644                             // Replace rover with the new symbol s, and
645                             // have s 'cover' the tag symbol s2.
646                             // BUG: memory leak on rover if s2!=rover
647                             assert(!s2.Scover);
648                             s.Sl = rover.Sl;
649                             s.Sr = rover.Sr;
650                             s.Scover = s2;
651                             *parent = s;
652                             rover.Sl = rover.Sr = null;
653                             return;
654 
655                         case SCenum:
656                             s2 = rover;
657                             goto case_cover;
658 
659                         case SCtemplate:
660                             s2 = rover;
661                             s2.Stemplate.TMflags |= STRnoctor;
662                             goto case_cover;
663 
664                         case SCalias:
665                             s2 = rover.Smemalias;
666                             if (s2.Sclass == SCstruct)
667                                 goto case_struct;
668                             if (s2.Sclass == SCenum)
669                                 goto case_cover;
670                             break;
671 
672                         default:
673                             break;
674                     }
675                 }
676                 synerr(EM_multiple_def,p - 1);  // symbol is already defined
677                 //symbol_undef(s);              // undefine the symbol
678                 return;
679             }
680         }
681         parent = (cmp < 0) ?            /* if we go down left side      */
682             &(rover.Sl) :              /* then get left child          */
683             &(rover.Sr);               /* else get right child         */
684         rover = *parent;                /* get child                    */
685    }
686    /* not in table, so insert into table        */
687    *parent = s;                         /* link new symbol into tree    */
688 }
689 }
690 
691 /*************************************
692  * Search for symbol in multiple symbol tables,
693  * starting with most recently nested one.
694  * Input:
695  *      p .    identifier string
696  * Returns:
697  *      pointer to symbol
698  *      null if couldn't find it
699  */
700 
701 static if (0)
702 {
703 Symbol * lookupsym(const(char)* p)
704 {
705     return scope_search(p,SCTglobal | SCTlocal);
706 }
707 }
708 
709 /*************************************
710  * Search for symbol in symbol table.
711  * Input:
712  *      p .    identifier string
713  *      rover . where to start looking
714  * Returns:
715  *      pointer to symbol (null if not found)
716  */
717 
718 version (SCPP_HTOD)
719 {
720 
721 Symbol * findsy(const(char)* p,Symbol *rover)
722 {
723 /+
724 #if TX86 && __DMC__
725     volatile int len;
726     __asm
727     {
728 #if !_WIN32
729         push    DS
730         pop     ES
731 #endif
732         mov     EDI,p
733         xor     AL,AL
734 
735         mov     BL,[EDI]
736         mov     ECX,-1
737 
738         repne   scasb
739 
740         not     ECX
741         mov     EDX,p
742 
743         dec     ECX
744         inc     EDX
745 
746         mov     len,ECX
747         mov     AL,BL
748 
749         mov     EBX,rover
750         mov     ESI,EDX
751 
752         test    EBX,EBX
753         je      L6
754 
755         cmp     AL,symbol.Sident[EBX]
756         js      L2
757 
758         lea     EDI,symbol.Sident+1[EBX]
759         je      L5
760 
761         mov     EBX,symbol.Sr[EBX]
762         jmp     L3
763 
764 L1:             mov     ECX,len
765 L2:             mov     EBX,symbol.Sl[EBX]
766 
767 L3:             test    EBX,EBX
768                 je      L6
769 
770 L4:             cmp     AL,symbol.Sident[EBX]
771                 js      L2
772 
773                 lea     EDI,symbol.Sident+1[EBX]
774                 je      L5
775 
776                 mov     EBX,symbol.Sr[EBX]
777                 jmp     L3
778 
779 L5:             rep     cmpsb
780 
781                 mov     ESI,EDX
782                 js      L1
783 
784                 je      L6
785 
786                 mov     EBX,symbol.Sr[EBX]
787                 mov     ECX,len
788 
789                 test    EBX,EBX
790                 jne     L4
791 
792 L6:     mov     EAX,EBX
793     }
794 #else
795 +/
796     size_t len;
797     byte cmp;                           /* set to value of strcmp       */
798     char c = *p;
799 
800     len = strlen(p);
801     p++;                                // will pick up 0 on memcmp
802     while (rover != null)               // while we haven't run out of tree
803     {   symbol_debug(rover);
804         if ((cmp = cast(byte)(c - rover.Sident[0])) == 0)
805         {   cmp = cast(byte)memcmp(p,rover.Sident.ptr + 1,len); /* compare identifier strings */
806             if (cmp == 0)
807                 return rover;           /* found it if strings match    */
808         }
809         rover = (cmp < 0) ? rover.Sl : rover.Sr;
810     }
811     return rover;                       // failed to find it
812 //#endif
813 }
814 
815 }
816 
817 /***********************************
818  * Create a new symbol table.
819  */
820 
821 version (SCPP_HTOD)
822 {
823 
824 void createglobalsymtab()
825 {
826     assert(!scope_end);
827     if (CPP)
828         scope_push(null,cast(scope_fp)&findsy, SCTcglobal);
829     else
830         scope_push(null,cast(scope_fp)&findsy, SCTglobaltag);
831     scope_push(null,cast(scope_fp)&findsy, SCTglobal);
832 }
833 
834 
835 void createlocalsymtab()
836 {
837     assert(scope_end);
838     if (!CPP)
839         scope_push(null,cast(scope_fp)&findsy, SCTtag);
840     scope_push(null,cast(scope_fp)&findsy, SCTlocal);
841 }
842 
843 
844 /***********************************
845  * Delete current symbol table and back up one.
846  */
847 
848 void deletesymtab()
849 {   Symbol *root;
850 
851     root = cast(Symbol *)scope_pop();
852     if (root)
853     {
854         if (funcsym_p)
855             list_prepend(&funcsym_p.Sfunc.Fsymtree,root);
856         else
857             symbol_free(root);  // free symbol table
858     }
859 
860     if (!CPP)
861     {
862         root = cast(Symbol *)scope_pop();
863         if (root)
864         {
865             if (funcsym_p)
866                 list_prepend(&funcsym_p.Sfunc.Fsymtree,root);
867             else
868                 symbol_free(root);      // free symbol table
869         }
870     }
871 }
872 
873 }
874 
875 /*********************************
876  * Delete symbol from symbol table, taking care to delete
877  * all children of a symbol.
878  * Make sure there are no more forward references (labels, tags).
879  * Input:
880  *      pointer to a symbol
881  */
882 
883 void meminit_free(meminit_t *m)         /* helper for symbol_free()     */
884 {
885     list_free(&m.MIelemlist,cast(list_free_fp)&el_free);
886     MEM_PARF_FREE(m);
887 }
888 
889 void symbol_free(Symbol *s)
890 {
891     while (s)                           /* if symbol exists             */
892     {   Symbol *sr;
893 
894 debug
895 {
896         if (debugy)
897             printf("symbol_free('%s',%p)\n",s.Sident.ptr,s);
898         symbol_debug(s);
899         assert(/*s.Sclass != SCunde &&*/ cast(int) s.Sclass < cast(int) SCMAX);
900 }
901         {   type *t = s.Stype;
902 
903             if (t)
904                 type_debug(t);
905             if (t && tyfunc(t.Tty) && s.Sfunc)
906             {
907                 func_t *f = s.Sfunc;
908 
909                 debug assert(f);
910                 blocklist_free(&f.Fstartblock);
911                 freesymtab(f.Flocsym.tab,0,f.Flocsym.top);
912 
913                 symtab_free(f.Flocsym.tab);
914               if (CPP)
915               {
916                 if (f.Fflags & Fnotparent)
917                 {   debug if (debugy) printf("not parent, returning\n");
918                     return;
919                 }
920 
921                 /* We could be freeing the symbol before it's class is  */
922                 /* freed, so remove it from the class's field list      */
923                 if (f.Fclass)
924                 {   list_t tl;
925 
926                     symbol_debug(f.Fclass);
927                     tl = list_inlist(f.Fclass.Sstruct.Sfldlst,s);
928                     if (tl)
929                         list_setsymbol(tl, null);
930                 }
931 
932                 if (f.Foversym && f.Foversym.Sfunc)
933                 {   f.Foversym.Sfunc.Fflags &= ~Fnotparent;
934                     f.Foversym.Sfunc.Fclass = null;
935                     symbol_free(f.Foversym);
936                 }
937 
938                 if (f.Fexplicitspec)
939                     symbol_free(f.Fexplicitspec);
940 
941                 /* If operator function, remove from list of such functions */
942                 if (f.Fflags & Foperator)
943                 {   assert(f.Foper && f.Foper < OPMAX);
944                     //if (list_inlist(cpp_operfuncs[f.Foper],s))
945                     //  list_subtract(&cpp_operfuncs[f.Foper],s);
946                 }
947 
948                 list_free(&f.Fclassfriends,FPNULL);
949                 list_free(&f.Ffwdrefinstances,FPNULL);
950                 param_free(&f.Farglist);
951                 param_free(&f.Fptal);
952                 list_free(&f.Fexcspec,cast(list_free_fp)&type_free);
953 
954 version (SCPP_HTOD)
955                 token_free(f.Fbody);
956 
957                 el_free(f.Fbaseinit);
958                 if (f.Fthunk && !(f.Fflags & Finstance))
959                     MEM_PH_FREE(f.Fthunk);
960                 list_free(&f.Fthunks,cast(list_free_fp)&symbol_free);
961               }
962                 list_free(&f.Fsymtree,cast(list_free_fp)&symbol_free);
963                 f.typesTable.__dtor();
964                 func_free(f);
965             }
966             switch (s.Sclass)
967             {
968 version (SCPP_HTOD)
969 {
970                 case SClabel:
971                     if (!s.Slabel)
972                         synerr(EM_unknown_label,s.Sident.ptr);
973                     break;
974 }
975                 case SCstruct:
976 version (SCPP_HTOD)
977 {
978                   if (CPP)
979                   {
980                     struct_t *st = s.Sstruct;
981                     assert(st);
982                     list_free(&st.Sclassfriends,FPNULL);
983                     list_free(&st.Sfriendclass,FPNULL);
984                     list_free(&st.Sfriendfuncs,FPNULL);
985                     list_free(&st.Scastoverload,FPNULL);
986                     list_free(&st.Sopoverload,FPNULL);
987                     list_free(&st.Svirtual,&MEM_PH_FREEFP);
988                     list_free(&st.Sfldlst,FPNULL);
989                     symbol_free(st.Sroot);
990                     baseclass_t* b,bn;
991 
992                     for (b = st.Sbase; b; b = bn)
993                     {   bn = b.BCnext;
994                         list_free(&b.BCpublics,FPNULL);
995                         baseclass_free(b);
996                     }
997                     for (b = st.Svirtbase; b; b = bn)
998                     {   bn = b.BCnext;
999                         baseclass_free(b);
1000                     }
1001                     for (b = st.Smptrbase; b; b = bn)
1002                     {   bn = b.BCnext;
1003                         list_free(&b.BCmptrlist,&MEM_PH_FREEFP);
1004                         baseclass_free(b);
1005                     }
1006                     for (b = st.Svbptrbase; b; b = bn)
1007                     {   bn = b.BCnext;
1008                         baseclass_free(b);
1009                     }
1010                     param_free(&st.Sarglist);
1011                     param_free(&st.Spr_arglist);
1012                     struct_free(st);
1013                   }
1014 }
1015                   if (!CPP)
1016                   {
1017                     debug if (debugy)
1018                         printf("freeing members %p\n",s.Sstruct.Sfldlst);
1019 
1020                     list_free(&s.Sstruct.Sfldlst,FPNULL);
1021                     symbol_free(s.Sstruct.Sroot);
1022                     struct_free(s.Sstruct);
1023                   }
1024 static if (0)       /* Don't complain anymore about these, ANSI C says  */
1025 {
1026                     /* it's ok                                          */
1027                     if (t && t.Tflags & TFsizeunknown)
1028                         synerr(EM_unknown_tag,s.Sident.ptr);
1029 }
1030                     break;
1031                 case SCenum:
1032                     /* The actual member symbols are either in a local  */
1033                     /* table or on the member list of a class, so we    */
1034                     /* don't free them here.                            */
1035                     assert(s.Senum);
1036                     list_free(&s.Senum.SEenumlist,FPNULL);
1037                     MEM_PH_FREE(s.Senum);
1038                     s.Senum = null;
1039                     break;
1040 
1041 version (SCPP_HTOD)
1042 {
1043                 case SCtemplate:
1044                 {   template_t *tm = s.Stemplate;
1045 
1046                     list_free(&tm.TMinstances,FPNULL);
1047                     list_free(&tm.TMmemberfuncs,cast(list_free_fp)&tmf_free);
1048                     list_free(&tm.TMexplicit,cast(list_free_fp)&tme_free);
1049                     list_free(&tm.TMnestedexplicit,cast(list_free_fp)&tmne_free);
1050                     list_free(&tm.TMnestedfriends,cast(list_free_fp)&tmnf_free);
1051                     param_free(&tm.TMptpl);
1052                     param_free(&tm.TMptal);
1053                     token_free(tm.TMbody);
1054                     symbol_free(tm.TMpartial);
1055                     list_free(&tm.TMfriends,FPNULL);
1056                     MEM_PH_FREE(tm);
1057                     break;
1058                 }
1059                 case SCnamespace:
1060                     symbol_free(s.Snameroot);
1061                     list_free(&s.Susing,FPNULL);
1062                     break;
1063 
1064                 case SCmemalias:
1065                 case SCfuncalias:
1066                 case SCadl:
1067                     list_free(&s.Spath,FPNULL);
1068                     break;
1069 }
1070                 case SCparameter:
1071                 case SCregpar:
1072                 case SCfastpar:
1073                 case SCshadowreg:
1074                 case SCregister:
1075                 case SCauto:
1076                     vec_free(s.Srange);
1077 static if (0)
1078 {
1079                     goto case SCconst;
1080                 case SCconst:
1081                     if (s.Sflags & (SFLvalue | SFLdtorexp))
1082                         el_free(s.Svalue);
1083 }
1084                     break;
1085                 default:
1086                     break;
1087             }
1088             if (s.Sflags & (SFLvalue | SFLdtorexp))
1089                 el_free(s.Svalue);
1090             if (s.Sdt)
1091                 dt_free(s.Sdt);
1092             type_free(t);
1093             symbol_free(s.Sl);
1094 version (SCPP_HTOD)
1095 {
1096             if (s.Scover)
1097                 symbol_free(s.Scover);
1098 }
1099             sr = s.Sr;
1100 debug
1101 {
1102             s.id = 0;
1103 }
1104             mem_ffree(s);
1105         }
1106         s = sr;
1107     }
1108 }
1109 
1110 /********************************
1111  * Undefine a symbol.
1112  * Assume error msg was already printed.
1113  */
1114 
1115 static if (0)
1116 {
1117 private void symbol_undef(Symbol *s)
1118 {
1119   s.Sclass = SCunde;
1120   s.Ssymnum = -1;
1121   type_free(s.Stype);                  /* free type data               */
1122   s.Stype = null;
1123 }
1124 }
1125 
1126 /*****************************
1127  * Add symbol to current symbol array.
1128  */
1129 
1130 SYMIDX symbol_add(Symbol *s)
1131 {
1132     return symbol_add(cstate.CSpsymtab, s);
1133 }
1134 
1135 SYMIDX symbol_add(symtab_t* symtab, Symbol* s)
1136 {   SYMIDX sitop;
1137 
1138     //printf("symbol_add('%s')\n", s.Sident.ptr);
1139 debug
1140 {
1141     if (!s || !s.Sident[0])
1142     {   printf("bad symbol\n");
1143         assert(0);
1144     }
1145 }
1146     symbol_debug(s);
1147     if (pstate.STinsizeof)
1148     {   symbol_keep(s);
1149         return -1;
1150     }
1151     debug assert(symtab);
1152     sitop = symtab.top;
1153     assert(sitop <= symtab.symmax);
1154     if (sitop == symtab.symmax)
1155     {
1156 debug
1157     enum SYMINC = 1;                       /* flush out reallocation bugs  */
1158 else
1159     enum SYMINC = 99;
1160 
1161         symtab.symmax += (symtab == &globsym) ? SYMINC : 1;
1162         //assert(symtab.symmax * (Symbol *).sizeof < 4096 * 4);
1163         symtab.tab = symtab_realloc(symtab.tab, symtab.symmax);
1164     }
1165     symtab.tab[sitop] = s;
1166 
1167     debug if (debugy)
1168         printf("symbol_add(%p '%s') = %d\n",s,s.Sident.ptr,symtab.top);
1169 
1170     assert(s.Ssymnum == -1);
1171     return s.Ssymnum = symtab.top++;
1172 }
1173 
1174 /********************************************
1175  * Insert s into symtab at position n.
1176  * Returns:
1177  *      position in table
1178  */
1179 SYMIDX symbol_insert(symtab_t* symtab, Symbol* s, SYMIDX n)
1180 {
1181     const sinew = symbol_add(s);        // added at end, have to move it
1182     for (SYMIDX i = sinew; i > n; --i)
1183     {
1184         symtab.tab[i] = symtab.tab[i - 1];
1185         symtab.tab[i].Ssymnum += 1;
1186     }
1187     globsym.tab[n] = s;
1188     s.Ssymnum = n;
1189     return n;
1190 }
1191 
1192 /****************************
1193  * Free up the symbol table, from symbols n1 through n2, not
1194  * including n2.
1195  */
1196 
1197 void freesymtab(Symbol **stab,SYMIDX n1,SYMIDX n2)
1198 {   SYMIDX si;
1199 
1200     if (!stab)
1201         return;
1202 
1203     debug if (debugy)
1204         printf("freesymtab(from %d to %d)\n",n1,n2);
1205 
1206     assert(stab != globsym.tab || (n1 <= n2 && n2 <= globsym.top));
1207     for (si = n1; si < n2; si++)
1208     {   Symbol *s;
1209 
1210         s = stab[si];
1211         if (s && s.Sflags & SFLfree)
1212         {   stab[si] = null;
1213 
1214 debug
1215 {
1216             if (debugy)
1217                 printf("Freeing %p '%s' (%d)\n",s,s.Sident.ptr,si);
1218             symbol_debug(s);
1219 }
1220             s.Sl = s.Sr = null;
1221             s.Ssymnum = -1;
1222             symbol_free(s);
1223         }
1224     }
1225 }
1226 
1227 /****************************
1228  * Create a copy of a symbol.
1229  */
1230 
1231 Symbol * symbol_copy(Symbol *s)
1232 {   Symbol *scopy;
1233     type *t;
1234 
1235     symbol_debug(s);
1236     /*printf("symbol_copy(%s)\n",s.Sident.ptr);*/
1237     scopy = symbol_calloc(s.Sident.ptr);
1238     memcpy(scopy,s,Symbol.sizeof - s.Sident.sizeof);
1239     scopy.Sl = scopy.Sr = scopy.Snext = null;
1240     scopy.Ssymnum = -1;
1241     if (scopy.Sdt)
1242     {
1243         auto dtb = DtBuilder(0);
1244         dtb.nzeros(cast(uint)type_size(scopy.Stype));
1245         scopy.Sdt = dtb.finish();
1246     }
1247     if (scopy.Sflags & (SFLvalue | SFLdtorexp))
1248         scopy.Svalue = el_copytree(s.Svalue);
1249     t = scopy.Stype;
1250     if (t)
1251     {   t.Tcount++;            /* one more parent of the type  */
1252         type_debug(t);
1253     }
1254     return scopy;
1255 }
1256 
1257 /*******************************
1258  * Search list for a symbol with an identifier that matches.
1259  * Returns:
1260  *      pointer to matching symbol
1261  *      null if not found
1262  */
1263 
1264 version (SCPP_HTOD)
1265 {
1266 
1267 Symbol * symbol_searchlist(symlist_t sl,const(char)* vident)
1268 {
1269     debug
1270     int count = 0;
1271 
1272     //printf("searchlist(%s)\n",vident);
1273     foreach (sln; ListRange(sl))
1274     {
1275         Symbol* s = list_symbol(sln);
1276         symbol_debug(s);
1277         /*printf("\tcomparing with %s\n",s.Sident.ptr);*/
1278         if (strcmp(vident,s.Sident.ptr) == 0)
1279             return s;
1280 
1281         debug assert(++count < 300);          /* prevent infinite loops       */
1282     }
1283     return null;
1284 }
1285 
1286 /***************************************
1287  * Search for symbol in sequence of symbol tables.
1288  * Input:
1289  *      glbl    !=0 if global symbol table only
1290  */
1291 
1292 Symbol *symbol_search(const(char)* id)
1293 {
1294     Scope *sc;
1295     if (CPP)
1296     {   uint sct;
1297 
1298         sct = pstate.STclasssym ? SCTclass : 0;
1299         sct |= SCTmfunc | SCTlocal | SCTwith | SCTglobal | SCTnspace | SCTtemparg | SCTtempsym;
1300         return scope_searchx(id,sct,&sc);
1301     }
1302     else
1303         return scope_searchx(id,SCTglobal | SCTlocal,&sc);
1304 }
1305 
1306 }
1307 
1308 
1309 /*******************************************
1310  * Hydrate a symbol tree.
1311  */
1312 
1313 static if (HYDRATE)
1314 {
1315 void symbol_tree_hydrate(Symbol **ps)
1316 {   Symbol *s;
1317 
1318     while (isdehydrated(*ps))           /* if symbol is dehydrated      */
1319     {
1320         s = symbol_hydrate(ps);
1321         symbol_debug(s);
1322         if (s.Scover)
1323             symbol_hydrate(&s.Scover);
1324         symbol_tree_hydrate(&s.Sl);
1325         ps = &s.Sr;
1326     }
1327 
1328 }
1329 }
1330 
1331 /*******************************************
1332  * Dehydrate a symbol tree.
1333  */
1334 
1335 static if (DEHYDRATE)
1336 {
1337 void symbol_tree_dehydrate(Symbol **ps)
1338 {   Symbol *s;
1339 
1340     while ((s = *ps) != null && !isdehydrated(s)) /* if symbol exists   */
1341     {
1342         symbol_debug(s);
1343         symbol_dehydrate(ps);
1344 version (DEBUG_XSYMGEN)
1345 {
1346         if (xsym_gen && ph_in_head(s))
1347             return;
1348 }
1349         symbol_dehydrate(&s.Scover);
1350         symbol_tree_dehydrate(&s.Sl);
1351         ps = &s.Sr;
1352     }
1353 }
1354 }
1355 
1356 /*******************************************
1357  * Hydrate a symbol.
1358  */
1359 
1360 static if (HYDRATE)
1361 {
1362 Symbol *symbol_hydrate(Symbol **ps)
1363 {   Symbol *s;
1364 
1365     s = *ps;
1366     if (isdehydrated(s))                /* if symbol is dehydrated      */
1367     {   type *t;
1368         struct_t *st;
1369 
1370         s = cast(Symbol *) ph_hydrate(cast(void**)ps);
1371 
1372         debug debugy && printf("symbol_hydrate('%s')\n",s.Sident.ptr);
1373 
1374         symbol_debug(s);
1375         if (!isdehydrated(s.Stype))    // if this symbol is already dehydrated
1376             return s;                   // no need to do it again
1377         if (pstate.SThflag != FLAG_INPLACE && s.Sfl != FLreg)
1378             s.Sxtrnnum = 0;            // not written to .OBJ file yet
1379         type_hydrate(&s.Stype);
1380         //printf("symbol_hydrate(%p, '%s', t = %p)\n",s,s.Sident.ptr,s.Stype);
1381         t = s.Stype;
1382         if (t)
1383             type_debug(t);
1384 
1385         if (t && tyfunc(t.Tty) && ph_hydrate(cast(void**)&s.Sfunc))
1386         {
1387             func_t *f = s.Sfunc;
1388             SYMIDX si;
1389 
1390             debug assert(f);
1391 
1392             list_hydrate(&f.Fsymtree,cast(list_free_fp)&symbol_tree_hydrate);
1393             blocklist_hydrate(&f.Fstartblock);
1394 
1395             ph_hydrate(cast(void**)&f.Flocsym.tab);
1396             for (si = 0; si < f.Flocsym.top; si++)
1397                 symbol_hydrate(&f.Flocsym.tab[si]);
1398 
1399             srcpos_hydrate(&f.Fstartline);
1400             srcpos_hydrate(&f.Fendline);
1401 
1402             symbol_hydrate(&f.F__func__);
1403 
1404             if (CPP)
1405             {
1406                 symbol_hydrate(&f.Fparsescope);
1407                 Classsym_hydrate(&f.Fclass);
1408                 symbol_hydrate(&f.Foversym);
1409                 symbol_hydrate(&f.Fexplicitspec);
1410                 symbol_hydrate(&f.Fsurrogatesym);
1411 
1412                 list_hydrate(&f.Fclassfriends,cast(list_free_fp)&symbol_hydrate);
1413                 el_hydrate(&f.Fbaseinit);
1414                 token_hydrate(&f.Fbody);
1415                 symbol_hydrate(&f.Falias);
1416                 list_hydrate(&f.Fthunks,cast(list_free_fp)&symbol_hydrate);
1417                 if (f.Fflags & Finstance)
1418                     symbol_hydrate(&f.Ftempl);
1419                 else
1420                     thunk_hydrate(&f.Fthunk);
1421                 param_hydrate(&f.Farglist);
1422                 param_hydrate(&f.Fptal);
1423                 list_hydrate(&f.Ffwdrefinstances,cast(list_free_fp)&symbol_hydrate);
1424                 list_hydrate(&f.Fexcspec,cast(list_free_fp)&type_hydrate);
1425             }
1426         }
1427         if (CPP)
1428             symbol_hydrate(&s.Sscope);
1429         switch (s.Sclass)
1430         {
1431             case SCstruct:
1432               if (CPP)
1433               {
1434                 st = cast(struct_t *) ph_hydrate(cast(void**)&s.Sstruct);
1435                 assert(st);
1436                 symbol_tree_hydrate(&st.Sroot);
1437                 ph_hydrate(cast(void**)&st.Spvirtder);
1438                 list_hydrate(&st.Sfldlst,cast(list_free_fp)&symbol_hydrate);
1439                 list_hydrate(&st.Svirtual,cast(list_free_fp)&mptr_hydrate);
1440                 list_hydrate(&st.Sopoverload,cast(list_free_fp)&symbol_hydrate);
1441                 list_hydrate(&st.Scastoverload,cast(list_free_fp)&symbol_hydrate);
1442                 list_hydrate(&st.Sclassfriends,cast(list_free_fp)&symbol_hydrate);
1443                 list_hydrate(&st.Sfriendclass,cast(list_free_fp)&symbol_hydrate);
1444                 list_hydrate(&st.Sfriendfuncs,cast(list_free_fp)&symbol_hydrate);
1445                 assert(!st.Sinlinefuncs);
1446 
1447                 baseclass_hydrate(&st.Sbase);
1448                 baseclass_hydrate(&st.Svirtbase);
1449                 baseclass_hydrate(&st.Smptrbase);
1450                 baseclass_hydrate(&st.Sprimary);
1451                 baseclass_hydrate(&st.Svbptrbase);
1452 
1453                 ph_hydrate(cast(void**)&st.Svecctor);
1454                 ph_hydrate(cast(void**)&st.Sctor);
1455                 ph_hydrate(cast(void**)&st.Sdtor);
1456                 ph_hydrate(cast(void**)&st.Sprimdtor);
1457                 ph_hydrate(cast(void**)&st.Spriminv);
1458                 ph_hydrate(cast(void**)&st.Sscaldeldtor);
1459                 ph_hydrate(cast(void**)&st.Sinvariant);
1460                 ph_hydrate(cast(void**)&st.Svptr);
1461                 ph_hydrate(cast(void**)&st.Svtbl);
1462                 ph_hydrate(cast(void**)&st.Sopeq);
1463                 ph_hydrate(cast(void**)&st.Sopeq2);
1464                 ph_hydrate(cast(void**)&st.Scpct);
1465                 ph_hydrate(cast(void**)&st.Sveccpct);
1466                 ph_hydrate(cast(void**)&st.Salias);
1467                 ph_hydrate(cast(void**)&st.Stempsym);
1468                 param_hydrate(&st.Sarglist);
1469                 param_hydrate(&st.Spr_arglist);
1470                 ph_hydrate(cast(void**)&st.Svbptr);
1471                 ph_hydrate(cast(void**)&st.Svbptr_parent);
1472                 ph_hydrate(cast(void**)&st.Svbtbl);
1473               }
1474               else
1475               {
1476                 ph_hydrate(cast(void**)&s.Sstruct);
1477                 symbol_tree_hydrate(&s.Sstruct.Sroot);
1478                 list_hydrate(&s.Sstruct.Sfldlst,cast(list_free_fp)&symbol_hydrate);
1479               }
1480                 break;
1481 
1482             case SCenum:
1483                 assert(s.Senum);
1484                 ph_hydrate(cast(void**)&s.Senum);
1485                 if (CPP)
1486                 {   ph_hydrate(cast(void**)&s.Senum.SEalias);
1487                     list_hydrate(&s.Senum.SEenumlist,cast(list_free_fp)&symbol_hydrate);
1488                 }
1489                 break;
1490 
1491             case SCtemplate:
1492             {   template_t *tm;
1493 
1494                 tm = cast(template_t *) ph_hydrate(cast(void**)&s.Stemplate);
1495                 list_hydrate(&tm.TMinstances,cast(list_free_fp)&symbol_hydrate);
1496                 list_hydrate(&tm.TMfriends,cast(list_free_fp)&symbol_hydrate);
1497                 param_hydrate(&tm.TMptpl);
1498                 param_hydrate(&tm.TMptal);
1499                 token_hydrate(&tm.TMbody);
1500                 list_hydrate(&tm.TMmemberfuncs,cast(list_free_fp)&tmf_hydrate);
1501                 list_hydrate(&tm.TMexplicit,cast(list_free_fp)&tme_hydrate);
1502                 list_hydrate(&tm.TMnestedexplicit,cast(list_free_fp)&tmne_hydrate);
1503                 list_hydrate(&tm.TMnestedfriends,cast(list_free_fp)&tmnf_hydrate);
1504                 ph_hydrate(cast(void**)&tm.TMnext);
1505                 symbol_hydrate(&tm.TMpartial);
1506                 symbol_hydrate(&tm.TMprimary);
1507                 break;
1508             }
1509 
1510             case SCnamespace:
1511                 symbol_tree_hydrate(&s.Snameroot);
1512                 list_hydrate(&s.Susing,cast(list_free_fp)&symbol_hydrate);
1513                 break;
1514 
1515             case SCmemalias:
1516             case SCfuncalias:
1517             case SCadl:
1518                 list_hydrate(&s.Spath,cast(list_free_fp)&symbol_hydrate);
1519                 goto case SCalias;
1520 
1521             case SCalias:
1522                 ph_hydrate(cast(void**)&s.Smemalias);
1523                 break;
1524 
1525             default:
1526                 if (s.Sflags & (SFLvalue | SFLdtorexp))
1527                     el_hydrate(&s.Svalue);
1528                 break;
1529         }
1530         {   dt_t **pdt;
1531             dt_t *dt;
1532 
1533             for (pdt = &s.Sdt; isdehydrated(*pdt); pdt = &dt.DTnext)
1534             {
1535                 dt = cast(dt_t *) ph_hydrate(cast(void**)pdt);
1536                 switch (dt.dt)
1537                 {   case DT_abytes:
1538                     case DT_nbytes:
1539                         ph_hydrate(cast(void**)&dt.DTpbytes);
1540                         break;
1541                     case DT_xoff:
1542                         symbol_hydrate(&dt.DTsym);
1543                         break;
1544 
1545                     default:
1546                         break;
1547                 }
1548             }
1549         }
1550         if (s.Scover)
1551             symbol_hydrate(&s.Scover);
1552     }
1553     return s;
1554 }
1555 }
1556 
1557 /*******************************************
1558  * Dehydrate a symbol.
1559  */
1560 
1561 static if (DEHYDRATE)
1562 {
1563 void symbol_dehydrate(Symbol **ps)
1564 {
1565     Symbol *s;
1566 
1567     if ((s = *ps) != null && !isdehydrated(s)) /* if symbol exists      */
1568     {   type *t;
1569         struct_t *st;
1570 
1571         debug
1572         if (debugy)
1573             printf("symbol_dehydrate('%s')\n",s.Sident.ptr);
1574 
1575         ph_dehydrate(ps);
1576 version (DEBUG_XSYMGEN)
1577 {
1578         if (xsym_gen && ph_in_head(s))
1579             return;
1580 }
1581         symbol_debug(s);
1582         t = s.Stype;
1583         if (isdehydrated(t))
1584             return;
1585         type_dehydrate(&s.Stype);
1586 
1587         if (tyfunc(t.Tty) && !isdehydrated(s.Sfunc))
1588         {
1589             func_t *f = s.Sfunc;
1590             SYMIDX si;
1591 
1592             debug assert(f);
1593             ph_dehydrate(&s.Sfunc);
1594 
1595             list_dehydrate(&f.Fsymtree,cast(list_free_fp)&symbol_tree_dehydrate);
1596             blocklist_dehydrate(&f.Fstartblock);
1597             assert(!isdehydrated(&f.Flocsym.tab));
1598 
1599 version (DEBUG_XSYMGEN)
1600 {
1601             if (!xsym_gen || !ph_in_head(f.Flocsym.tab))
1602                 for (si = 0; si < f.Flocsym.top; si++)
1603                     symbol_dehydrate(&f.Flocsym.tab[si]);
1604 }
1605 else
1606 {
1607             for (si = 0; si < f.Flocsym.top; si++)
1608                 symbol_dehydrate(&f.Flocsym.tab[si]);
1609 }
1610             ph_dehydrate(&f.Flocsym.tab);
1611 
1612             srcpos_dehydrate(&f.Fstartline);
1613             srcpos_dehydrate(&f.Fendline);
1614             symbol_dehydrate(&f.F__func__);
1615             if (CPP)
1616             {
1617             symbol_dehydrate(&f.Fparsescope);
1618             ph_dehydrate(&f.Fclass);
1619             symbol_dehydrate(&f.Foversym);
1620             symbol_dehydrate(&f.Fexplicitspec);
1621             symbol_dehydrate(&f.Fsurrogatesym);
1622 
1623             list_dehydrate(&f.Fclassfriends,FPNULL);
1624             el_dehydrate(&f.Fbaseinit);
1625 version (DEBUG_XSYMGEN)
1626 {
1627             if (xsym_gen && s.Sclass == SCfunctempl)
1628                 ph_dehydrate(&f.Fbody);
1629             else
1630                 token_dehydrate(&f.Fbody);
1631 }
1632 else
1633             token_dehydrate(&f.Fbody);
1634 
1635             symbol_dehydrate(&f.Falias);
1636             list_dehydrate(&f.Fthunks,cast(list_free_fp)&symbol_dehydrate);
1637             if (f.Fflags & Finstance)
1638                 symbol_dehydrate(&f.Ftempl);
1639             else
1640                 thunk_dehydrate(&f.Fthunk);
1641 //#if !TX86 && DEBUG_XSYMGEN
1642 //            if (xsym_gen && s.Sclass == SCfunctempl)
1643 //                ph_dehydrate(&f.Farglist);
1644 //            else
1645 //#endif
1646             param_dehydrate(&f.Farglist);
1647             param_dehydrate(&f.Fptal);
1648             list_dehydrate(&f.Ffwdrefinstances,cast(list_free_fp)&symbol_dehydrate);
1649             list_dehydrate(&f.Fexcspec,cast(list_free_fp)&type_dehydrate);
1650             }
1651         }
1652         if (CPP)
1653             ph_dehydrate(&s.Sscope);
1654         switch (s.Sclass)
1655         {
1656             case SCstruct:
1657               if (CPP)
1658               {
1659                 st = s.Sstruct;
1660                 if (isdehydrated(st))
1661                     break;
1662                 ph_dehydrate(&s.Sstruct);
1663                 assert(st);
1664                 symbol_tree_dehydrate(&st.Sroot);
1665                 ph_dehydrate(&st.Spvirtder);
1666                 list_dehydrate(&st.Sfldlst,cast(list_free_fp)&symbol_dehydrate);
1667                 list_dehydrate(&st.Svirtual,cast(list_free_fp)&mptr_dehydrate);
1668                 list_dehydrate(&st.Sopoverload,cast(list_free_fp)&symbol_dehydrate);
1669                 list_dehydrate(&st.Scastoverload,cast(list_free_fp)&symbol_dehydrate);
1670                 list_dehydrate(&st.Sclassfriends,cast(list_free_fp)&symbol_dehydrate);
1671                 list_dehydrate(&st.Sfriendclass,cast(list_free_fp)&ph_dehydrate);
1672                 list_dehydrate(&st.Sfriendfuncs,cast(list_free_fp)&ph_dehydrate);
1673                 assert(!st.Sinlinefuncs);
1674 
1675                 baseclass_dehydrate(&st.Sbase);
1676                 baseclass_dehydrate(&st.Svirtbase);
1677                 baseclass_dehydrate(&st.Smptrbase);
1678                 baseclass_dehydrate(&st.Sprimary);
1679                 baseclass_dehydrate(&st.Svbptrbase);
1680 
1681                 ph_dehydrate(&st.Svecctor);
1682                 ph_dehydrate(&st.Sctor);
1683                 ph_dehydrate(&st.Sdtor);
1684                 ph_dehydrate(&st.Sprimdtor);
1685                 ph_dehydrate(&st.Spriminv);
1686                 ph_dehydrate(&st.Sscaldeldtor);
1687                 ph_dehydrate(&st.Sinvariant);
1688                 ph_dehydrate(&st.Svptr);
1689                 ph_dehydrate(&st.Svtbl);
1690                 ph_dehydrate(&st.Sopeq);
1691                 ph_dehydrate(&st.Sopeq2);
1692                 ph_dehydrate(&st.Scpct);
1693                 ph_dehydrate(&st.Sveccpct);
1694                 ph_dehydrate(&st.Salias);
1695                 ph_dehydrate(&st.Stempsym);
1696                 param_dehydrate(&st.Sarglist);
1697                 param_dehydrate(&st.Spr_arglist);
1698                 ph_dehydrate(&st.Svbptr);
1699                 ph_dehydrate(&st.Svbptr_parent);
1700                 ph_dehydrate(&st.Svbtbl);
1701               }
1702               else
1703               {
1704                 symbol_tree_dehydrate(&s.Sstruct.Sroot);
1705                 list_dehydrate(&s.Sstruct.Sfldlst,cast(list_free_fp)&symbol_dehydrate);
1706                 ph_dehydrate(&s.Sstruct);
1707               }
1708                 break;
1709 
1710             case SCenum:
1711                 assert(s.Senum);
1712                 if (!isdehydrated(s.Senum))
1713                 {
1714                     if (CPP)
1715                     {   ph_dehydrate(&s.Senum.SEalias);
1716                         list_dehydrate(&s.Senumlist,cast(list_free_fp)&ph_dehydrate);
1717                     }
1718                     ph_dehydrate(&s.Senum);
1719                 }
1720                 break;
1721 
1722             case SCtemplate:
1723             {   template_t *tm;
1724 
1725                 tm = s.Stemplate;
1726                 if (!isdehydrated(tm))
1727                 {
1728                     ph_dehydrate(&s.Stemplate);
1729                     list_dehydrate(&tm.TMinstances,cast(list_free_fp)&symbol_dehydrate);
1730                     list_dehydrate(&tm.TMfriends,cast(list_free_fp)&symbol_dehydrate);
1731                     list_dehydrate(&tm.TMnestedfriends,cast(list_free_fp)&tmnf_dehydrate);
1732                     param_dehydrate(&tm.TMptpl);
1733                     param_dehydrate(&tm.TMptal);
1734                     token_dehydrate(&tm.TMbody);
1735                     list_dehydrate(&tm.TMmemberfuncs,cast(list_free_fp)&tmf_dehydrate);
1736                     list_dehydrate(&tm.TMexplicit,cast(list_free_fp)&tme_dehydrate);
1737                     list_dehydrate(&tm.TMnestedexplicit,cast(list_free_fp)&tmne_dehydrate);
1738                     ph_dehydrate(&tm.TMnext);
1739                     symbol_dehydrate(&tm.TMpartial);
1740                     symbol_dehydrate(&tm.TMprimary);
1741                 }
1742                 break;
1743             }
1744 
1745             case SCnamespace:
1746                 symbol_tree_dehydrate(&s.Snameroot);
1747                 list_dehydrate(&s.Susing,cast(list_free_fp)&symbol_dehydrate);
1748                 break;
1749 
1750             case SCmemalias:
1751             case SCfuncalias:
1752             case SCadl:
1753                 list_dehydrate(&s.Spath,cast(list_free_fp)&symbol_dehydrate);
1754             case SCalias:
1755                 ph_dehydrate(&s.Smemalias);
1756                 break;
1757 
1758             default:
1759                 if (s.Sflags & (SFLvalue | SFLdtorexp))
1760                     el_dehydrate(&s.Svalue);
1761                 break;
1762         }
1763         {   dt_t **pdt;
1764             dt_t *dt;
1765 
1766             for (pdt = &s.Sdt;
1767                  (dt = *pdt) != null && !isdehydrated(dt);
1768                  pdt = &dt.DTnext)
1769             {
1770                 ph_dehydrate(pdt);
1771                 switch (dt.dt)
1772                 {   case DT_abytes:
1773                     case DT_nbytes:
1774                         ph_dehydrate(&dt.DTpbytes);
1775                         break;
1776                     case DT_xoff:
1777                         symbol_dehydrate(&dt.DTsym);
1778                         break;
1779                 }
1780             }
1781         }
1782         if (s.Scover)
1783             symbol_dehydrate(&s.Scover);
1784     }
1785 }
1786 }
1787 
1788 /***************************
1789  * Dehydrate threaded list of symbols.
1790  */
1791 
1792 static if (DEHYDRATE)
1793 {
1794 void symbol_symdefs_dehydrate(Symbol **ps)
1795 {
1796     Symbol *s;
1797 
1798     for (; *ps; ps = &s.Snext)
1799     {
1800         s = *ps;
1801         symbol_debug(s);
1802         //printf("symbol_symdefs_dehydrate(%p, '%s')\n",s,s.Sident.ptr);
1803         symbol_dehydrate(ps);
1804     }
1805 }
1806 }
1807 
1808 
1809 /***************************
1810  * Hydrate threaded list of symbols.
1811  * Input:
1812  *      *psx    start of threaded list
1813  *      *parent root of symbol table to add symbol into
1814  *      flag    !=0 means add onto existing stuff
1815  *              0 means hydrate in place
1816  */
1817 
1818 version (SCPP_HTOD)
1819 {
1820 
1821 void symbol_symdefs_hydrate(Symbol **psx,Symbol **parent,int flag)
1822 {   Symbol *s;
1823 
1824     //printf("symbol_symdefs_hydrate(flag = %d)\n",flag);
1825 debug
1826 {
1827     int count = 0;
1828 
1829     if (flag) symbol_tree_check(*parent);
1830 }
1831     for (; *psx; psx = &s.Snext)
1832     {
1833         //printf("%p ",*psx);
1834 debug
1835         count++;
1836 
1837         s = dohydrate ? symbol_hydrate(psx) : *psx;
1838 
1839         //if (s.Sclass == SCstruct)
1840         //printf("symbol_symdefs_hydrate(%p, '%s')\n",s,s.Sident.ptr);
1841         symbol_debug(s);
1842 static if (0)
1843 {
1844         if (tyfunc(s.Stype.Tty))
1845         {   Outbuffer buf;
1846             char *p1;
1847 
1848             p1 = param_tostring(&buf,s.Stype);
1849             printf("'%s%s'\n",cpp_prettyident(s),p1);
1850         }
1851 }
1852         type_debug(s.Stype);
1853         if (flag)
1854         {   char *p;
1855             Symbol **ps;
1856             Symbol *rover;
1857             char c;
1858             size_t len;
1859 
1860             p = s.Sident.ptr;
1861             c = *p;
1862 
1863             // Put symbol s into symbol table
1864 
1865 static if (MMFIO)
1866 {
1867             if (s.Sl || s.Sr)         // avoid writing to page if possible
1868                 s.Sl = s.Sr = null;
1869 }
1870 else
1871                 s.Sl = s.Sr = null;
1872 
1873             len = strlen(p);
1874             p++;
1875             ps = parent;
1876             while ((rover = *ps) != null)
1877             {   byte cmp;
1878 
1879                 if ((cmp = cast(byte)(c - rover.Sident[0])) == 0)
1880                 {   cmp = cast(byte)memcmp(p,rover.Sident.ptr + 1,len); // compare identifier strings
1881                     if (cmp == 0)
1882                     {
1883                         if (CPP && tyfunc(s.Stype.Tty) && tyfunc(rover.Stype.Tty))
1884                         {   Symbol **psym;
1885                             Symbol *sn;
1886                             Symbol *so;
1887 
1888                             so = s;
1889                             do
1890                             {
1891                                 // Tack onto end of overloaded function list
1892                                 for (psym = &rover; *psym; psym = &(*psym).Sfunc.Foversym)
1893                                 {   if (cpp_funccmp(so, *psym))
1894                                     {   //printf("function '%s' already in list\n",so.Sident.ptr);
1895                                         goto L2;
1896                                     }
1897                                 }
1898                                 //printf("appending '%s' to rover\n",so.Sident.ptr);
1899                                 *psym = so;
1900                             L2:
1901                                 sn = so.Sfunc.Foversym;
1902                                 so.Sfunc.Foversym = null;
1903                                 so = sn;
1904                             } while (so);
1905                             //printf("overloading...\n");
1906                         }
1907                         else if (s.Sclass == SCstruct)
1908                         {
1909                             if (CPP && rover.Scover)
1910                             {   ps = &rover.Scover;
1911                                 rover = *ps;
1912                             }
1913                             else
1914                             if (rover.Sclass == SCstruct)
1915                             {
1916                                 if (!(s.Stype.Tflags & TFforward))
1917                                 {   // Replace rover with s in symbol table
1918                                     //printf("Replacing '%s'\n",s.Sident.ptr);
1919                                     *ps = s;
1920                                     s.Sl = rover.Sl;
1921                                     s.Sr = rover.Sr;
1922                                     rover.Sl = rover.Sr = null;
1923                                     rover.Stype.Ttag = cast(Classsym *)s;
1924                                     symbol_keep(rover);
1925                                 }
1926                                 else
1927                                     s.Stype.Ttag = cast(Classsym *)rover;
1928                             }
1929                         }
1930                         goto L1;
1931                     }
1932                 }
1933                 ps = (cmp < 0) ?        /* if we go down left side      */
1934                     &rover.Sl :
1935                     &rover.Sr;
1936             }
1937             *ps = s;
1938             if (s.Sclass == SCcomdef)
1939             {   s.Sclass = SCglobal;
1940                 outcommon(s,type_size(s.Stype));
1941             }
1942         }
1943   L1:
1944     } // for
1945 debug
1946 {
1947     if (flag) symbol_tree_check(*parent);
1948     printf("%d symbols hydrated\n",count);
1949 }
1950 }
1951 
1952 }
1953 
1954 static if (0)
1955 {
1956 
1957 /*************************************
1958  * Put symbol table s into parent symbol table.
1959  */
1960 
1961 void symboltable_hydrate(Symbol *s,Symbol **parent)
1962 {
1963     while (s)
1964     {   Symbol* sl,sr;
1965         char *p;
1966 
1967         symbol_debug(s);
1968 
1969         sl = s.Sl;
1970         sr = s.Sr;
1971         p = s.Sident.ptr;
1972 
1973         //printf("symboltable_hydrate('%s')\n",p);
1974 
1975         /* Put symbol s into symbol table       */
1976         {   Symbol **ps;
1977             Symbol *rover;
1978             int c = *p;
1979 
1980             ps = parent;
1981             while ((rover = *ps) != null)
1982             {   int cmp;
1983 
1984                 if ((cmp = c - rover.Sident[0]) == 0)
1985                 {   cmp = strcmp(p,rover.Sident.ptr); /* compare identifier strings */
1986                     if (cmp == 0)
1987                     {
1988                         if (CPP && tyfunc(s.Stype.Tty) && tyfunc(rover.Stype.Tty))
1989                         {   Symbol **ps;
1990                             Symbol *sn;
1991 
1992                             do
1993                             {
1994                                 // Tack onto end of overloaded function list
1995                                 for (ps = &rover; *ps; ps = &(*ps).Sfunc.Foversym)
1996                                 {   if (cpp_funccmp(s, *ps))
1997                                         goto L2;
1998                                 }
1999                                 s.Sl = s.Sr = null;
2000                                 *ps = s;
2001                             L2:
2002                                 sn = s.Sfunc.Foversym;
2003                                 s.Sfunc.Foversym = null;
2004                                 s = sn;
2005                             } while (s);
2006                         }
2007                         else
2008                         {
2009                             if (!typematch(s.Stype,rover.Stype,0))
2010                             {
2011                                 // cpp_predefine() will define this again
2012                                 if (type_struct(rover.Stype) &&
2013                                     rover.Sstruct.Sflags & STRpredef)
2014                                 {   s.Sl = s.Sr = null;
2015                                     symbol_keep(s);
2016                                 }
2017                                 else
2018                                     synerr(EM_multiple_def,p);  // already defined
2019                             }
2020                         }
2021                         goto L1;
2022                     }
2023                 }
2024                 ps = (cmp < 0) ?        /* if we go down left side      */
2025                     &rover.Sl :
2026                     &rover.Sr;
2027             }
2028             {
2029                 s.Sl = s.Sr = null;
2030                 *ps = s;
2031             }
2032         }
2033     L1:
2034         symboltable_hydrate(sl,parent);
2035         s = sr;
2036     }
2037 }
2038 
2039 }
2040 
2041 
2042 /************************************
2043  * Hydrate/dehydrate an mptr_t.
2044  */
2045 
2046 static if (HYDRATE)
2047 {
2048 private void mptr_hydrate(mptr_t **pm)
2049 {   mptr_t *m;
2050 
2051     m = cast(mptr_t *) ph_hydrate(cast(void**)pm);
2052     symbol_hydrate(&m.MPf);
2053     symbol_hydrate(&m.MPparent);
2054 }
2055 }
2056 
2057 static if (DEHYDRATE)
2058 {
2059 private void mptr_dehydrate(mptr_t **pm)
2060 {   mptr_t *m;
2061 
2062     m = *pm;
2063     if (m && !isdehydrated(m))
2064     {
2065         ph_dehydrate(pm);
2066 version (DEBUG_XSYMGEN)
2067 {
2068         if (xsym_gen && ph_in_head(m.MPf))
2069             ph_dehydrate(&m.MPf);
2070         else
2071             symbol_dehydrate(&m.MPf);
2072 }
2073 else
2074         symbol_dehydrate(&m.MPf);
2075 
2076         symbol_dehydrate(&m.MPparent);
2077     }
2078 }
2079 }
2080 
2081 /************************************
2082  * Hydrate/dehydrate a baseclass_t.
2083  */
2084 
2085 static if (HYDRATE)
2086 {
2087 private void baseclass_hydrate(baseclass_t **pb)
2088 {   baseclass_t *b;
2089 
2090     assert(pb);
2091     while (isdehydrated(*pb))
2092     {
2093         b = cast(baseclass_t *) ph_hydrate(cast(void**)pb);
2094 
2095         ph_hydrate(cast(void**)&b.BCbase);
2096         ph_hydrate(cast(void**)&b.BCpbase);
2097         list_hydrate(&b.BCpublics,cast(list_free_fp)&symbol_hydrate);
2098         list_hydrate(&b.BCmptrlist,cast(list_free_fp)&mptr_hydrate);
2099         symbol_hydrate(&b.BCvtbl);
2100         Classsym_hydrate(&b.BCparent);
2101 
2102         pb = &b.BCnext;
2103     }
2104 }
2105 }
2106 
2107 /**********************************
2108  * Dehydrate a baseclass_t.
2109  */
2110 
2111 static if (DEHYDRATE)
2112 {
2113 private void baseclass_dehydrate(baseclass_t **pb)
2114 {   baseclass_t *b;
2115 
2116     while ((b = *pb) != null && !isdehydrated(b))
2117     {
2118         ph_dehydrate(pb);
2119 
2120 version (DEBUG_XSYMGEN)
2121 {
2122         if (xsym_gen && ph_in_head(b))
2123             return;
2124 }
2125 
2126         ph_dehydrate(&b.BCbase);
2127         ph_dehydrate(&b.BCpbase);
2128         list_dehydrate(&b.BCpublics,cast(list_free_fp)&symbol_dehydrate);
2129         list_dehydrate(&b.BCmptrlist,cast(list_free_fp)&mptr_dehydrate);
2130         symbol_dehydrate(&b.BCvtbl);
2131         Classsym_dehydrate(&b.BCparent);
2132 
2133         pb = &b.BCnext;
2134     }
2135 }
2136 }
2137 
2138 /***************************
2139  * Look down baseclass list to find sbase.
2140  * Returns:
2141  *      null    not found
2142  *      pointer to baseclass
2143  */
2144 
2145 baseclass_t *baseclass_find(baseclass_t *bm,Classsym *sbase)
2146 {
2147     symbol_debug(sbase);
2148     for (; bm; bm = bm.BCnext)
2149         if (bm.BCbase == sbase)
2150             break;
2151     return bm;
2152 }
2153 
2154 baseclass_t *baseclass_find_nest(baseclass_t *bm,Classsym *sbase)
2155 {
2156     symbol_debug(sbase);
2157     for (; bm; bm = bm.BCnext)
2158     {
2159         if (bm.BCbase == sbase ||
2160             baseclass_find_nest(bm.BCbase.Sstruct.Sbase, sbase))
2161             break;
2162     }
2163     return bm;
2164 }
2165 
2166 /******************************
2167  * Calculate number of baseclasses in list.
2168  */
2169 
2170 int baseclass_nitems(baseclass_t *b)
2171 {   int i;
2172 
2173     for (i = 0; b; b = b.BCnext)
2174         i++;
2175     return i;
2176 }
2177 
2178 
2179 /*****************************
2180  * Go through symbol table preparing it to be written to a precompiled
2181  * header. That means removing references to things in the .OBJ file.
2182  */
2183 
2184 version (SCPP_HTOD)
2185 {
2186 
2187 void symboltable_clean(Symbol *s)
2188 {
2189     while (s)
2190     {
2191         struct_t *st;
2192 
2193         //printf("clean('%s')\n",s.Sident.ptr);
2194         if (config.fulltypes != CVTDB && s.Sxtrnnum && s.Sfl != FLreg)
2195             s.Sxtrnnum = 0;    // eliminate debug info type index
2196         switch (s.Sclass)
2197         {
2198             case SCstruct:
2199                 s.Stypidx = 0;
2200                 st = s.Sstruct;
2201                 assert(st);
2202                 symboltable_clean(st.Sroot);
2203                 //list_apply(&st.Sfldlst,cast(list_free_fp)&symboltable_clean);
2204                 break;
2205 
2206             case SCtypedef:
2207             case SCenum:
2208                 s.Stypidx = 0;
2209                 break;
2210 
2211             case SCtemplate:
2212             {   template_t *tm = s.Stemplate;
2213 
2214                 list_apply(&tm.TMinstances,cast(list_free_fp)&symboltable_clean);
2215                 break;
2216             }
2217 
2218             case SCnamespace:
2219                 symboltable_clean(s.Snameroot);
2220                 break;
2221 
2222             default:
2223                 if (s.Sxtrnnum && s.Sfl != FLreg)
2224                     s.Sxtrnnum = 0;    // eliminate external symbol index
2225                 if (tyfunc(s.Stype.Tty))
2226                 {
2227                     func_t *f = s.Sfunc;
2228                     SYMIDX si;
2229 
2230                     debug assert(f);
2231 
2232                     list_apply(&f.Fsymtree,cast(list_free_fp)&symboltable_clean);
2233                     for (si = 0; si < f.Flocsym.top; si++)
2234                         symboltable_clean(f.Flocsym.tab[si]);
2235                     if (f.Foversym)
2236                         symboltable_clean(f.Foversym);
2237                     if (f.Fexplicitspec)
2238                         symboltable_clean(f.Fexplicitspec);
2239                 }
2240                 break;
2241         }
2242         if (s.Sl)
2243             symboltable_clean(s.Sl);
2244         if (s.Scover)
2245             symboltable_clean(s.Scover);
2246         s = s.Sr;
2247     }
2248 }
2249 
2250 }
2251 
2252 version (SCPP_HTOD)
2253 {
2254 
2255 /*
2256  * Balance our symbol tree in place. This is nice for precompiled headers, since they
2257  * will typically be written out once, but read in many times. We balance the tree in
2258  * place by traversing the tree inorder and writing the pointers out to an ordered
2259  * list. Once we have a list of symbol pointers, we can create a tree by recursively
2260  * dividing the list, using the midpoint of each division as the new root for that
2261  * subtree.
2262  */
2263 
2264 struct Balance
2265 {
2266     uint nsyms;
2267     Symbol **array;
2268     uint index;
2269 }
2270 
2271 private __gshared Balance balance;
2272 
2273 private void count_symbols(Symbol *s)
2274 {
2275     while (s)
2276     {
2277         balance.nsyms++;
2278         switch (s.Sclass)
2279         {
2280             case SCnamespace:
2281                 symboltable_balance(&s.Snameroot);
2282                 break;
2283 
2284             case SCstruct:
2285                 symboltable_balance(&s.Sstruct.Sroot);
2286                 break;
2287 
2288             default:
2289                 break;
2290         }
2291         count_symbols(s.Sl);
2292         s = s.Sr;
2293     }
2294 }
2295 
2296 private void place_in_array(Symbol *s)
2297 {
2298     while (s)
2299     {
2300         place_in_array(s.Sl);
2301         balance.array[balance.index++] = s;
2302         s = s.Sr;
2303     }
2304 }
2305 
2306 /*
2307  * Create a tree in place by subdividing between lo and hi inclusive, using i
2308  * as the root for the tree. When the lo-hi interval is one, we've either
2309  * reached a leaf or an empty node. We subdivide below i by halving the interval
2310  * between i and lo, and using i-1 as our new hi point. A similar subdivision
2311  * is created above i.
2312  */
2313 private Symbol * create_tree(int i, int lo, int hi)
2314 {
2315     Symbol *s = balance.array[i];
2316 
2317     if (i < lo || i > hi)               /* empty node ? */
2318         return null;
2319 
2320     assert(cast(uint) i < balance.nsyms);
2321     if (i == lo && i == hi) {           /* leaf node ? */
2322         s.Sl = null;
2323         s.Sr = null;
2324         return s;
2325     }
2326 
2327     s.Sl = create_tree((i + lo) / 2, lo, i - 1);
2328     s.Sr = create_tree((i + hi + 1) / 2, i + 1, hi);
2329 
2330     return s;
2331 }
2332 
2333 enum METRICS = false;
2334 
2335 void symboltable_balance(Symbol **ps)
2336 {
2337     Balance balancesave;
2338 static if (METRICS)
2339 {
2340     clock_t ticks;
2341 
2342     printf("symbol table before balance:\n");
2343     symbol_table_metrics();
2344     ticks = clock();
2345 }
2346     balancesave = balance;              // so we can nest
2347     balance.nsyms = 0;
2348     count_symbols(*ps);
2349     //printf("Number of global symbols = %d\n",balance.nsyms);
2350 
2351     // Use malloc instead of mem because of pagesize limits
2352     balance.array = cast(Symbol **) malloc(balance.nsyms * (Symbol *).sizeof);
2353     if (!balance.array)
2354         goto Lret;                      // no error, just don't balance
2355 
2356     balance.index = 0;
2357     place_in_array(*ps);
2358 
2359     *ps = create_tree(balance.nsyms / 2, 0, balance.nsyms - 1);
2360 
2361     free(balance.array);
2362 static if (METRICS)
2363 {
2364     printf("time to balance: %ld\n", clock() - ticks);
2365     printf("symbol table after balance:\n");
2366     symbol_table_metrics();
2367 }
2368 Lret:
2369     balance = balancesave;
2370 }
2371 
2372 }
2373 
2374 /*****************************************
2375  * Symbol table search routine for members of structs, given that
2376  * we don't know which struct it is in.
2377  * Give error message if it appears more than once.
2378  * Returns:
2379  *      null            member not found
2380  *      symbol*         symbol matching member
2381  */
2382 
2383 version (SCPP_HTOD)
2384 {
2385 
2386 struct Paramblock       // to minimize stack usage in helper function
2387 {   const(char)* id;     // identifier we are looking for
2388     Symbol *sm;         // where to put result
2389     Symbol *s;
2390 }
2391 
2392 private void membersearchx(Paramblock *p,Symbol *s)
2393 {
2394     while (s)
2395     {
2396         symbol_debug(s);
2397 
2398         switch (s.Sclass)
2399         {
2400             case SCstruct:
2401                 foreach (sl; ListRange(s.Sstruct.Sfldlst))
2402                 {
2403                     Symbol* sm = list_symbol(sl);
2404                     symbol_debug(sm);
2405                     if ((sm.Sclass == SCmember || sm.Sclass == SCfield) &&
2406                         strcmp(p.id,sm.Sident.ptr) == 0)
2407                     {
2408                         if (p.sm && p.sm.Smemoff != sm.Smemoff)
2409                             synerr(EM_ambig_member,p.id,s.Sident.ptr,p.s.Sident.ptr);       // ambiguous reference to id
2410                         p.s = s;
2411                         p.sm = sm;
2412                         break;
2413                     }
2414                 }
2415                 break;
2416 
2417             default:
2418                 break;
2419         }
2420 
2421         if (s.Sl)
2422             membersearchx(p,s.Sl);
2423         s = s.Sr;
2424     }
2425 }
2426 
2427 Symbol *symbol_membersearch(const(char)* id)
2428 {
2429     list_t sl;
2430     Paramblock pb;
2431     Scope *sc;
2432 
2433     pb.id = id;
2434     pb.sm = null;
2435     for (sc = scope_end; sc; sc = sc.next)
2436     {
2437         if (sc.sctype & (CPP ? (SCTglobal | SCTlocal) : (SCTglobaltag | SCTtag)))
2438             membersearchx(cast(Paramblock *)&pb,cast(Symbol *)sc.root);
2439     }
2440     return pb.sm;
2441 }
2442 
2443 /*******************************************
2444  * Generate debug info for global struct tag symbols.
2445  */
2446 
2447 private void symbol_gendebuginfox(Symbol *s)
2448 {
2449     for (; s; s = s.Sr)
2450     {
2451         if (s.Sl)
2452             symbol_gendebuginfox(s.Sl);
2453         if (s.Scover)
2454             symbol_gendebuginfox(s.Scover);
2455         switch (s.Sclass)
2456         {
2457             case SCenum:
2458                 if (CPP && s.Senum.SEflags & SENnotagname)
2459                     break;
2460                 goto Lout;
2461             case SCstruct:
2462                 if (s.Sstruct.Sflags & STRanonymous)
2463                     break;
2464                 goto Lout;
2465             case SCtypedef:
2466             Lout:
2467                 if (!s.Stypidx)
2468                     cv_outsym(s);
2469                 break;
2470 
2471             default:
2472                 break;
2473         }
2474     }
2475 }
2476 
2477 void symbol_gendebuginfo()
2478 {   Scope *sc;
2479 
2480     for (sc = scope_end; sc; sc = sc.next)
2481     {
2482         if (sc.sctype & (SCTglobaltag | SCTglobal))
2483             symbol_gendebuginfox(cast(Symbol *)sc.root);
2484     }
2485 }
2486 
2487 }
2488 
2489 /*************************************
2490  * Reset Symbol so that it's now an "extern" to the next obj file being created.
2491  */
2492 void symbol_reset(Symbol *s)
2493 {
2494     s.Soffset = 0;
2495     s.Sxtrnnum = 0;
2496     s.Stypidx = 0;
2497     s.Sflags &= ~(STRoutdef | SFLweak);
2498     s.Sdw_ref_idx = 0;
2499     if (s.Sclass == SCglobal || s.Sclass == SCcomdat ||
2500         s.Sfl == FLudata || s.Sclass == SCstatic)
2501     {   s.Sclass = SCextern;
2502         s.Sfl = FLextern;
2503     }
2504 }
2505 
2506 /****************************************
2507  * Determine pointer type needed to access a Symbol,
2508  * essentially what type an OPrelconst should get
2509  * for that Symbol.
2510  * Params:
2511  *      s = pointer to Symbol
2512  * Returns:
2513  *      pointer type to access it
2514  */
2515 tym_t symbol_pointerType(const Symbol* s)
2516 {
2517     return s.Stype.Tty & mTYimmutable ? TYimmutPtr : TYnptr;
2518 }
2519 
2520 }