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