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