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 enum HYDRATE = false;
17 enum DEHYDRATE = false;
18 
19 import core.stdc.stdio;
20 import core.stdc.stdlib;
21 import core.stdc.string;
22 
23 import dmd.backend.cdef;
24 import dmd.backend.cc;
25 import dmd.backend.cgcv;
26 import dmd.backend.dlist;
27 import dmd.backend.dt;
28 import dmd.backend.dvec;
29 import dmd.backend.el;
30 import dmd.backend.global;
31 import dmd.backend.mem;
32 import dmd.backend.oper;
33 import dmd.backend.symtab;
34 import dmd.backend.ty;
35 import dmd.backend.type;
36 
37 
38 nothrow:
39 @safe:
40 
41 import dmd.backend.code_x86;
42 
43 void struct_free(struct_t *st) { }
44 
45 @trusted @nogc
46 func_t* func_calloc()
47 {
48     func_t* f = cast(func_t *) calloc(1, func_t.sizeof);
49     if (!f)
50         err_nomem();
51     return f;
52 }
53 
54 @trusted
55 void func_free(func_t* f) { free(f); }
56 
57 /*******************************
58  * Type out symbol information.
59  */
60 @trusted
61 void symbol_print(const Symbol *s)
62 {
63 debug
64 {
65     if (!s) return;
66     printf("symbol %p '%s'\n ",s,s.Sident.ptr);
67     printf(" Sclass = %s ", class_str(s.Sclass));
68     printf(" Ssymnum = %d",cast(int)s.Ssymnum);
69     printf(" Sfl = "); WRFL(cast(FL) s.Sfl);
70     printf(" Sseg = %d\n",s.Sseg);
71 //  printf(" Ssize   = x%02x\n",s.Ssize);
72     printf(" Soffset = x%04llx",cast(ulong)s.Soffset);
73     printf(" Sweight = %d",s.Sweight);
74     printf(" Sflags = x%04x",cast(uint)s.Sflags);
75     printf(" Sxtrnnum = %d\n",s.Sxtrnnum);
76     printf("  Stype   = %p",s.Stype);
77     printf(" Sl      = %p",s.Sl);
78     printf(" Sr      = %p\n",s.Sr);
79     if (s.Sscope)
80         printf(" Sscope = '%s'\n",s.Sscope.Sident.ptr);
81     if (s.Stype)
82         type_print(s.Stype);
83     if (s.Sclass == SC.member || s.Sclass == SC.field)
84     {
85         printf("  Smemoff =%5lld", cast(long)s.Smemoff);
86         printf("  Sbit    =%3d",s.Sbit);
87         printf("  Swidth  =%3d\n",s.Swidth);
88     }
89 }
90 }
91 
92 
93 /*********************************
94  * Terminate use of symbol table.
95  */
96 
97 private __gshared Symbol *keep;
98 
99 @trusted
100 void symbol_term()
101 {
102     symbol_free(keep);
103 }
104 
105 /****************************************
106  * Keep symbol around until symbol_term().
107  */
108 
109 static if (TERMCODE)
110 {
111 
112 void symbol_keep(Symbol *s)
113 {
114     symbol_debug(s);
115     s.Sr = keep;       // use Sr so symbol_free() doesn't nest
116     keep = s;
117 }
118 
119 }
120 
121 /****************************************
122  * Return alignment of symbol.
123  */
124 @trusted
125 int Symbol_Salignsize(ref Symbol s)
126 {
127     if (s.Salignment > 0)
128         return s.Salignment;
129     int alignsize = type_alignsize(s.Stype);
130 
131     /* Reduce alignment faults when SIMD vectors
132      * are reinterpreted cast to other types with less alignment.
133      */
134     if (config.fpxmmregs && alignsize < 16 &&
135         s.Sclass == SC.auto_ &&
136         type_size(s.Stype) == 16)
137     {
138         alignsize = 16;
139     }
140 
141     return alignsize;
142 }
143 
144 /****************************************
145  * Aver if Symbol is not only merely dead, but really most sincerely dead.
146  * Params:
147  *      anyInlineAsm = true if there's any inline assembler code
148  * Returns:
149  *      true if symbol is dead.
150  */
151 
152 @trusted
153 bool Symbol_Sisdead(const ref Symbol s, bool anyInlineAsm)
154 {
155     enum vol = false;
156     return s.Sflags & SFLdead ||
157            /* SFLdead means the optimizer found no references to it.
158             * The rest deals with variables that the compiler never needed
159             * to read from memory because they were cached in registers,
160             * and so no memory needs to be allocated for them.
161             * Code that does write those variables to memory gets NOPed out
162             * during address assignment.
163             */
164            (!anyInlineAsm && !(s.Sflags & SFLread) && s.Sflags & SFLunambig &&
165 
166             // mTYvolatile means this variable has been reference by a nested function
167             (vol || !(s.Stype.Tty & mTYvolatile)) &&
168 
169             (config.flags4 & CFG4optimized || !config.fulltypes));
170 }
171 
172 /****************************************
173  * Determine if symbol needs a 'this' pointer.
174  */
175 
176 @trusted
177 int Symbol_needThis(const ref Symbol s)
178 {
179     //printf("needThis() '%s'\n", Sident.ptr);
180 
181     debug assert(isclassmember(&s));
182 
183     if (s.Sclass == SC.member || s.Sclass == SC.field)
184         return 1;
185     if (tyfunc(s.Stype.Tty) && !(s.Sfunc.Fflags & Fstatic))
186         return 1;
187     return 0;
188 }
189 
190 /************************************
191  * Determine if `s` may be affected if an assignment is done through
192  * a pointer.
193  * Params:
194  *      s = symbol to check
195  * Returns:
196  *      true if it may be modified by assignment through a pointer
197  */
198 
199 bool Symbol_isAffected(const ref Symbol s)
200 {
201     //printf("s: %s %d\n", s.Sident.ptr, !(s.Sflags & SFLunambig) && !(s.ty() & (mTYconst | mTYimmutable)));
202     //symbol_print(s);
203 
204     /* If nobody took its address and it's not statically allocated,
205      * then it is not accessible via pointer and so is not affected.
206      */
207     if (s.Sflags & SFLunambig)
208         return false;
209 
210     /* If it's immutable, it can't be affected.
211      *
212      * Disable this check because:
213      * 1. Symbol_isAffected is not used by copyprop() and should be.
214      * 2. Non-@safe functions can temporarilly cast away immutable.
215      * 3. Need to add an @safe flag to funcsym_p to enable this.
216      * 4. Const can be mutated by a separate view.
217      * Address this in a separate PR.
218      */
219     static if (0)
220     if (s.ty() & (mTYconst | mTYimmutable))
221     {
222         /* Disabled for the moment because even @safe functions
223          * may have inlined unsafe code from other functions
224          */
225         if (funcsym_p.Sfunc.Fflags3 & F3safe &&
226             s.ty() & mTYimmutable)
227         {
228             return false;
229         }
230     }
231     return true;
232 }
233 
234 
235 /***********************************
236  * Get user name of symbol.
237  */
238 
239 @trusted
240 const(char)* symbol_ident(const Symbol *s)
241 {
242     return s.Sident.ptr;
243 }
244 
245 /****************************************
246  * Create a new symbol.
247  */
248 
249 @trusted @nogc
250 extern (C)
251 Symbol * symbol_calloc(const(char)[] id)
252 {
253     //printf("sizeof(symbol)=%d, sizeof(s.Sident)=%d, len=%d\n", symbol.sizeof, s.Sident.sizeof, cast(int)id.length);
254     Symbol* s = cast(Symbol *) mem_fmalloc(Symbol.sizeof - Symbol.Sident.length + id.length + 1 + 5);
255     memset(s,0,Symbol.sizeof - s.Sident.length);
256     memcpy(s.Sident.ptr,id.ptr,id.length);
257     s.Sident.ptr[id.length] = 0;
258     s.Ssymnum = SYMIDX.max;
259     if (debugy)
260         printf("symbol_calloc('%s') = %p\n",s.Sident.ptr,s);
261     debug s.id = Symbol.IDsymbol;
262     return s;
263 }
264 
265 /****************************************
266  * Create a Symbol
267  * Params:
268  *      name = name to give the Symbol
269  *      type = type for the Symbol
270  * Returns:
271  *      created Symbol
272  */
273 
274 @trusted @nogc
275 extern (C)
276 Symbol * symbol_name(const(char)[] name, SC sclass, type *t)
277 {
278     type_debug(t);
279     Symbol *s = symbol_calloc(name);
280     s.Sclass = sclass;
281     s.Stype = t;
282     s.Stype.Tcount++;
283 
284     if (tyfunc(t.Tty))
285         symbol_func(s);
286     return s;
287 }
288 
289 /****************************************
290  * Create a symbol that is an alias to another function symbol.
291  */
292 
293 @trusted
294 Funcsym *symbol_funcalias(Funcsym *sf)
295 {
296     symbol_debug(sf);
297     assert(tyfunc(sf.Stype.Tty));
298     if (sf.Sclass == SC.funcalias)
299         sf = sf.Sfunc.Falias;
300     auto s = cast(Funcsym *)symbol_name(sf.Sident.ptr[0 .. strlen(sf.Sident.ptr)],SC.funcalias,sf.Stype);
301     s.Sfunc.Falias = sf;
302 
303     return s;
304 }
305 
306 /****************************************
307  * Create a symbol, give it a name, storage class and type.
308  */
309 
310 @trusted @nogc
311 Symbol * symbol_generate(SC sclass,type *t)
312 {
313     __gshared int tmpnum;
314     char[4 + tmpnum.sizeof * 3 + 1] name;
315 
316     //printf("symbol_generate(_TMP%d)\n", tmpnum);
317     const length = snprintf(name.ptr,name.length,"_TMP%d",tmpnum++);
318     Symbol *s = symbol_name(name.ptr[0 .. length],sclass,t);
319     //symbol_print(s);
320 
321     s.Sflags |= SFLnodebug | SFLartifical;
322 
323     return s;
324 }
325 
326 /****************************************
327  * Generate an auto symbol, and add it to the symbol table.
328  */
329 
330 Symbol * symbol_genauto(type *t)
331 {   Symbol *s;
332 
333     s = symbol_generate(SC.auto_,t);
334     s.Sflags |= SFLfree;
335     symbol_add(s);
336     return s;
337 }
338 
339 /******************************************
340  * Generate symbol into which we can copy the contents of expression e.
341  */
342 
343 Symbol *symbol_genauto(elem *e)
344 {
345     return symbol_genauto(type_fake(e.Ety));
346 }
347 
348 /******************************************
349  * Generate symbol into which we can copy the contents of expression e.
350  */
351 
352 Symbol *symbol_genauto(tym_t ty)
353 {
354     return symbol_genauto(type_fake(ty));
355 }
356 
357 /****************************************
358  * Add in the variants for a function symbol.
359  */
360 
361 @trusted @nogc
362 void symbol_func(Symbol *s)
363 {
364     //printf("symbol_func(%s, x%x)\n", s.Sident.ptr, fregsaved);
365     symbol_debug(s);
366     s.Sfl = FLfunc;
367     // Interrupt functions modify all registers
368     // BUG: do interrupt functions really save BP?
369     // Note that fregsaved may not be set yet
370     s.Sregsaved = (s.Stype && tybasic(s.Stype.Tty) == TYifunc) ? cast(regm_t) mBP : fregsaved;
371     s.Sseg = UNKNOWN;          // don't know what segment it is in
372     if (!s.Sfunc)
373         s.Sfunc = func_calloc();
374 }
375 
376 /***************************************
377  * Add a field to a struct s.
378  * Params:
379  *      s      = the struct symbol
380  *      name   = field name
381  *      t      = the type of the field
382  *      offset = offset of the field
383  */
384 
385 @trusted
386 void symbol_struct_addField(Symbol *s, const(char)* name, type *t, uint offset)
387 {
388     Symbol *s2 = symbol_name(name[0 .. strlen(name)], SC.member, t);
389     s2.Smemoff = offset;
390     list_append(&s.Sstruct.Sfldlst, s2);
391 }
392 
393 /***************************************
394  * Add a bit field to a struct s.
395  * Params:
396  *      s      = the struct symbol
397  *      name   = field name
398  *      t      = the type of the field
399  *      offset = offset of the field
400  *      fieldWidth = width of bit field
401  *      bitOffset  = bit number of start of field
402  */
403 
404 @trusted
405 void symbol_struct_addBitField(Symbol *s, const(char)* name, type *t, uint offset, uint fieldWidth, uint bitOffset)
406 {
407     //printf("symbol_struct_addBitField() s: %s\n", s.Sident.ptr);
408     Symbol *s2 = symbol_name(name[0 .. strlen(name)], SC.field, t);
409     s2.Smemoff = offset;
410     s2.Swidth = cast(ubyte)fieldWidth;
411     s2.Sbit = cast(ubyte)bitOffset;
412     list_append(&s.Sstruct.Sfldlst, s2);
413     symbol_struct_hasBitFields(s);
414 }
415 
416 /***************************************
417  * Mark struct s as having bit fields
418  * Params:
419  *      s      = the struct symbol
420  */
421 @trusted
422 void symbol_struct_hasBitFields(Symbol *s)
423 {
424     s.Sstruct.Sflags |= STRbitfields;
425 }
426 
427 /***************************************
428  * Add a base class to a struct s.
429  * Input:
430  *      s       the struct/class symbol
431  *      t       the type of the base class
432  *      offset  offset of the base class in the struct/class
433  */
434 
435 @trusted
436 void symbol_struct_addBaseClass(Symbol *s, type *t, uint offset)
437 {
438     assert(t && t.Tty == TYstruct);
439     auto bc = cast(baseclass_t*)mem_fmalloc(baseclass_t.sizeof);
440     bc.BCbase = t.Ttag;
441     bc.BCoffset = offset;
442     bc.BCnext = s.Sstruct.Sbase;
443     s.Sstruct.Sbase = bc;
444 }
445 
446 /********************************
447  * Check integrity of symbol data structure.
448  */
449 
450 debug
451 {
452 
453 void symbol_check(const Symbol *s)
454 {
455     //printf("symbol_check('%s',%p)\n",s.Sident.ptr,s);
456     symbol_debug(s);
457     if (s.Stype) type_debug(s.Stype);
458     assert(cast(uint)s.Sclass < cast(uint)SCMAX);
459 }
460 
461 void symbol_tree_check(const(Symbol)* s)
462 {
463     while (s)
464     {   symbol_check(s);
465         symbol_tree_check(s.Sl);
466         s = s.Sr;
467     }
468 }
469 
470 }
471 
472 /*************************************
473  * Search for symbol in multiple symbol tables,
474  * starting with most recently nested one.
475  * Input:
476  *      p .    identifier string
477  * Returns:
478  *      pointer to symbol
479  *      null if couldn't find it
480  */
481 
482 static if (0)
483 {
484 Symbol * lookupsym(const(char)* p)
485 {
486     return scope_search(p,SCTglobal | SCTlocal);
487 }
488 }
489 
490 /*********************************
491  * Delete symbol from symbol table, taking care to delete
492  * all children of a symbol.
493  * Make sure there are no more forward references (labels, tags).
494  * Input:
495  *      pointer to a symbol
496  */
497 
498 @trusted
499 void meminit_free(meminit_t *m)         /* helper for symbol_free()     */
500 {
501     list_free(&m.MIelemlist,cast(list_free_fp)&el_free);
502     mem_free(m);
503 }
504 
505 @trusted
506 void symbol_free(Symbol *s)
507 {
508     while (s)                           /* if symbol exists             */
509     {   Symbol *sr;
510 
511 debug
512 {
513         if (debugy)
514             printf("symbol_free('%s',%p)\n",s.Sident.ptr,s);
515         symbol_debug(s);
516         assert(/*s.Sclass != SC.unde &&*/ cast(int) s.Sclass < cast(int) SCMAX);
517 }
518         {   type *t = s.Stype;
519 
520             if (t)
521                 type_debug(t);
522             if (t && tyfunc(t.Tty) && s.Sfunc)
523             {
524                 func_t *f = s.Sfunc;
525 
526                 debug assert(f);
527                 blocklist_free(&f.Fstartblock);
528                 freesymtab(f.Flocsym[].ptr,0,f.Flocsym.length);
529 
530                 f.Flocsym.dtor();
531               if (CPP)
532               {
533                 if (f.Fflags & Fnotparent)
534                 {   debug if (debugy) printf("not parent, returning\n");
535                     return;
536                 }
537 
538                 /* We could be freeing the symbol before its class is   */
539                 /* freed, so remove it from the class's field list      */
540                 if (f.Fclass)
541                 {   list_t tl;
542 
543                     symbol_debug(f.Fclass);
544                     tl = list_inlist(f.Fclass.Sstruct.Sfldlst,s);
545                     if (tl)
546                         list_setsymbol(tl, null);
547                 }
548 
549                 if (f.Foversym && f.Foversym.Sfunc)
550                 {   f.Foversym.Sfunc.Fflags &= ~Fnotparent;
551                     f.Foversym.Sfunc.Fclass = null;
552                     symbol_free(f.Foversym);
553                 }
554 
555                 if (f.Fexplicitspec)
556                     symbol_free(f.Fexplicitspec);
557 
558                 /* If operator function, remove from list of such functions */
559                 if (f.Fflags & Foperator)
560                 {   assert(f.Foper && f.Foper < OPMAX);
561                     //if (list_inlist(cpp_operfuncs[f.Foper],s))
562                     //  list_subtract(&cpp_operfuncs[f.Foper],s);
563                 }
564 
565                 list_free(&f.Fclassfriends,FPNULL);
566                 list_free(&f.Ffwdrefinstances,FPNULL);
567                 param_free(&f.Farglist);
568                 param_free(&f.Fptal);
569                 list_free(&f.Fexcspec,cast(list_free_fp)&type_free);
570 
571 
572                 el_free(f.Fbaseinit);
573                 if (f.Fthunk && !(f.Fflags & Finstance))
574                     mem_free(f.Fthunk);
575                 list_free(&f.Fthunks,cast(list_free_fp)&symbol_free);
576               }
577                 list_free(&f.Fsymtree,cast(list_free_fp)&symbol_free);
578                 f.typesTable.dtor();
579                 func_free(f);
580             }
581             switch (s.Sclass)
582             {
583                 case SC.struct_:
584                   if (!CPP)
585                   {
586                     debug if (debugy)
587                         printf("freeing members %p\n",s.Sstruct.Sfldlst);
588 
589                     list_free(&s.Sstruct.Sfldlst,FPNULL);
590                     symbol_free(s.Sstruct.Sroot);
591                     struct_free(s.Sstruct);
592                   }
593 static if (0)       /* Don't complain anymore about these, ANSI C says  */
594 {
595                     /* it's ok                                          */
596                     if (t && t.Tflags & TFsizeunknown)
597                         synerr(EM_unknown_tag,s.Sident.ptr);
598 }
599                     break;
600                 case SC.enum_:
601                     /* The actual member symbols are either in a local  */
602                     /* table or on the member list of a class, so we    */
603                     /* don't free them here.                            */
604                     assert(s.Senum);
605                     list_free(&s.Senum.SEenumlist,FPNULL);
606                     mem_free(s.Senum);
607                     s.Senum = null;
608                     break;
609 
610                 case SC.parameter:
611                 case SC.regpar:
612                 case SC.fastpar:
613                 case SC.shadowreg:
614                 case SC.register:
615                 case SC.auto_:
616                     vec_free(s.Srange);
617 static if (0)
618 {
619                     goto case SC.const_;
620                 case SC.const_:
621                     if (s.Sflags & (SFLvalue | SFLdtorexp))
622                         el_free(s.Svalue);
623 }
624                     break;
625                 default:
626                     break;
627             }
628             if (s.Sflags & (SFLvalue | SFLdtorexp))
629                 el_free(s.Svalue);
630             if (s.Sdt)
631                 dt_free(s.Sdt);
632             type_free(t);
633             symbol_free(s.Sl);
634             sr = s.Sr;
635 debug
636 {
637             s.id = 0;
638 }
639             mem_ffree(s);
640         }
641         s = sr;
642     }
643 }
644 
645 /********************************
646  * Undefine a symbol.
647  * Assume error msg was already printed.
648  */
649 
650 static if (0)
651 {
652 private void symbol_undef(Symbol *s)
653 {
654   s.Sclass = SC.unde;
655   s.Ssymnum = SYMIDX.max;
656   type_free(s.Stype);                  /* free type data               */
657   s.Stype = null;
658 }
659 }
660 
661 /*****************************
662  * Add symbol to current symbol array.
663  */
664 
665 @trusted
666 SYMIDX symbol_add(Symbol *s)
667 {
668     return symbol_add(*cstate.CSpsymtab, s);
669 }
670 
671 @trusted
672 SYMIDX symbol_add(ref symtab_t symtab, Symbol* s)
673 {
674     //printf("symbol_add('%s')\n", s.Sident.ptr);
675     debug
676     {
677         if (!s || !s.Sident[0])
678         {   printf("bad symbol\n");
679             assert(0);
680         }
681     }
682     symbol_debug(s);
683     if (pstate.STinsizeof)
684     {   symbol_keep(s);
685         return SYMIDX.max;
686     }
687     const sitop = symtab.length;
688     symtab.setLength(sitop + 1);
689     symtab[sitop] = s;
690 
691     debug if (debugy)
692         printf("symbol_add(%p '%s') = %d\n",s,s.Sident.ptr, cast(int) symtab.length);
693 
694     debug if (s.Ssymnum != SYMIDX.max)
695         printf("symbol %s already added\n", s.Sident.ptr);
696     assert(s.Ssymnum == SYMIDX.max);
697     s.Ssymnum = sitop;
698 
699     return sitop;
700 }
701 
702 /********************************************
703  * Insert s into symtab at position n.
704  * Returns:
705  *      position in table
706  */
707 @trusted
708 SYMIDX symbol_insert(ref symtab_t symtab, Symbol* s, SYMIDX n)
709 {
710     const sinew = symbol_add(s);        // added at end, have to move it
711     for (SYMIDX i = sinew; i > n; --i)
712     {
713         symtab[i] = symtab[i - 1];
714         symtab[i].Ssymnum += 1;
715     }
716     globsym[n] = s;
717     s.Ssymnum = n;
718     return n;
719 }
720 
721 /****************************
722  * Free up the symbols stab[n1 .. n2]
723  */
724 
725 @trusted
726 void freesymtab(Symbol **stab,SYMIDX n1,SYMIDX n2)
727 {
728     if (!stab)
729         return;
730 
731     debug if (debugy)
732         printf("freesymtab(from %d to %d)\n", cast(int) n1, cast(int) n2);
733 
734     assert(stab != globsym[].ptr || (n1 <= n2 && n2 <= globsym.length));
735     foreach (ref s; stab[n1 .. n2])
736     {
737         if (s && s.Sflags & SFLfree)
738         {
739 
740             debug
741             {
742                 if (debugy)
743                     printf("Freeing %p '%s'\n",s,s.Sident.ptr);
744                 symbol_debug(s);
745             }
746             s.Sl = s.Sr = null;
747             s.Ssymnum = SYMIDX.max;
748             symbol_free(s);
749             s = null;
750         }
751     }
752 }
753 
754 /****************************
755  * Create a copy of a symbol.
756  */
757 
758 @trusted
759 Symbol * symbol_copy(Symbol *s)
760 {   Symbol *scopy;
761     type *t;
762 
763     symbol_debug(s);
764     /*printf("symbol_copy(%s)\n",s.Sident.ptr);*/
765     scopy = symbol_calloc(s.Sident.ptr[0 .. strlen(s.Sident.ptr)]);
766     memcpy(scopy,s,Symbol.sizeof - s.Sident.sizeof);
767     scopy.Sl = scopy.Sr = scopy.Snext = null;
768     scopy.Ssymnum = SYMIDX.max;
769     if (scopy.Sdt)
770     {
771         auto dtb = DtBuilder(0);
772         dtb.nzeros(cast(uint)type_size(scopy.Stype));
773         scopy.Sdt = dtb.finish();
774     }
775     if (scopy.Sflags & (SFLvalue | SFLdtorexp))
776         scopy.Svalue = el_copytree(s.Svalue);
777     t = scopy.Stype;
778     if (t)
779     {   t.Tcount++;            /* one more parent of the type  */
780         type_debug(t);
781     }
782     return scopy;
783 }
784 
785 /*******************************************
786  * Hydrate a symbol tree.
787  */
788 
789 static if (HYDRATE)
790 {
791 @trusted
792 void symbol_tree_hydrate(Symbol **ps)
793 {   Symbol *s;
794 
795     while (isdehydrated(*ps))           /* if symbol is dehydrated      */
796     {
797         s = symbol_hydrate(ps);
798         symbol_debug(s);
799         if (s.Scover)
800             symbol_hydrate(&s.Scover);
801         symbol_tree_hydrate(&s.Sl);
802         ps = &s.Sr;
803     }
804 
805 }
806 }
807 
808 /*******************************************
809  * Dehydrate a symbol tree.
810  */
811 
812 static if (DEHYDRATE)
813 {
814 @trusted
815 void symbol_tree_dehydrate(Symbol **ps)
816 {   Symbol *s;
817 
818     while ((s = *ps) != null && !isdehydrated(s)) /* if symbol exists   */
819     {
820         symbol_debug(s);
821         symbol_dehydrate(ps);
822 version (DEBUG_XSYMGEN)
823 {
824         if (xsym_gen && ph_in_head(s))
825             return;
826 }
827         symbol_dehydrate(&s.Scover);
828         symbol_tree_dehydrate(&s.Sl);
829         ps = &s.Sr;
830     }
831 }
832 }
833 
834 /*******************************************
835  * Hydrate a symbol.
836  */
837 
838 static if (HYDRATE)
839 {
840 @trusted
841 Symbol *symbol_hydrate(Symbol **ps)
842 {   Symbol *s;
843 
844     s = *ps;
845     if (isdehydrated(s))                /* if symbol is dehydrated      */
846     {   type *t;
847         struct_t *st;
848 
849         s = cast(Symbol *) ph_hydrate(cast(void**)ps);
850 
851         debug debugy && printf("symbol_hydrate('%s')\n",s.Sident.ptr);
852 
853         symbol_debug(s);
854         if (!isdehydrated(s.Stype))    // if this symbol is already dehydrated
855             return s;                   // no need to do it again
856         if (pstate.SThflag != FLAG_INPLACE && s.Sfl != FLreg)
857             s.Sxtrnnum = 0;            // not written to .OBJ file yet
858         type_hydrate(&s.Stype);
859         //printf("symbol_hydrate(%p, '%s', t = %p)\n",s,s.Sident.ptr,s.Stype);
860         t = s.Stype;
861         if (t)
862             type_debug(t);
863 
864         if (t && tyfunc(t.Tty) && ph_hydrate(cast(void**)&s.Sfunc))
865         {
866             func_t *f = s.Sfunc;
867             SYMIDX si;
868 
869             debug assert(f);
870 
871             list_hydrate(&f.Fsymtree,cast(list_free_fp)&symbol_tree_hydrate);
872             blocklist_hydrate(&f.Fstartblock);
873 
874             ph_hydrate(cast(void**)&f.Flocsym.tab);
875             for (si = 0; si < f.Flocsym.length; si++)
876                 symbol_hydrate(&f.Flocsym[].ptr[si]);
877 
878             srcpos_hydrate(&f.Fstartline);
879             srcpos_hydrate(&f.Fendline);
880 
881             symbol_hydrate(&f.F__func__);
882 
883             if (CPP)
884             {
885                 symbol_hydrate(&f.Fparsescope);
886                 Classsym_hydrate(&f.Fclass);
887                 symbol_hydrate(&f.Foversym);
888                 symbol_hydrate(&f.Fexplicitspec);
889                 symbol_hydrate(&f.Fsurrogatesym);
890 
891                 list_hydrate(&f.Fclassfriends,cast(list_free_fp)&symbol_hydrate);
892                 el_hydrate(&f.Fbaseinit);
893                 token_hydrate(&f.Fbody);
894                 symbol_hydrate(&f.Falias);
895                 list_hydrate(&f.Fthunks,cast(list_free_fp)&symbol_hydrate);
896                 if (f.Fflags & Finstance)
897                     symbol_hydrate(&f.Ftempl);
898                 else
899                     thunk_hydrate(&f.Fthunk);
900                 param_hydrate(&f.Farglist);
901                 param_hydrate(&f.Fptal);
902                 list_hydrate(&f.Ffwdrefinstances,cast(list_free_fp)&symbol_hydrate);
903                 list_hydrate(&f.Fexcspec,cast(list_free_fp)&type_hydrate);
904             }
905         }
906         if (CPP)
907             symbol_hydrate(&s.Sscope);
908         switch (s.Sclass)
909         {
910             case SC.struct_:
911               if (CPP)
912               {
913                 st = cast(struct_t *) ph_hydrate(cast(void**)&s.Sstruct);
914                 assert(st);
915                 symbol_tree_hydrate(&st.Sroot);
916                 ph_hydrate(cast(void**)&st.Spvirtder);
917                 list_hydrate(&st.Sfldlst,cast(list_free_fp)&symbol_hydrate);
918                 list_hydrate(&st.Svirtual,cast(list_free_fp)&mptr_hydrate);
919                 list_hydrate(&st.Sopoverload,cast(list_free_fp)&symbol_hydrate);
920                 list_hydrate(&st.Scastoverload,cast(list_free_fp)&symbol_hydrate);
921                 list_hydrate(&st.Sclassfriends,cast(list_free_fp)&symbol_hydrate);
922                 list_hydrate(&st.Sfriendclass,cast(list_free_fp)&symbol_hydrate);
923                 list_hydrate(&st.Sfriendfuncs,cast(list_free_fp)&symbol_hydrate);
924                 assert(!st.Sinlinefuncs);
925 
926                 baseclass_hydrate(&st.Sbase);
927                 baseclass_hydrate(&st.Svirtbase);
928                 baseclass_hydrate(&st.Smptrbase);
929                 baseclass_hydrate(&st.Sprimary);
930                 baseclass_hydrate(&st.Svbptrbase);
931 
932                 ph_hydrate(cast(void**)&st.Svecctor);
933                 ph_hydrate(cast(void**)&st.Sctor);
934                 ph_hydrate(cast(void**)&st.Sdtor);
935                 ph_hydrate(cast(void**)&st.Sprimdtor);
936                 ph_hydrate(cast(void**)&st.Spriminv);
937                 ph_hydrate(cast(void**)&st.Sscaldeldtor);
938                 ph_hydrate(cast(void**)&st.Sinvariant);
939                 ph_hydrate(cast(void**)&st.Svptr);
940                 ph_hydrate(cast(void**)&st.Svtbl);
941                 ph_hydrate(cast(void**)&st.Sopeq);
942                 ph_hydrate(cast(void**)&st.Sopeq2);
943                 ph_hydrate(cast(void**)&st.Scpct);
944                 ph_hydrate(cast(void**)&st.Sveccpct);
945                 ph_hydrate(cast(void**)&st.Salias);
946                 ph_hydrate(cast(void**)&st.Stempsym);
947                 param_hydrate(&st.Sarglist);
948                 param_hydrate(&st.Spr_arglist);
949                 ph_hydrate(cast(void**)&st.Svbptr);
950                 ph_hydrate(cast(void**)&st.Svbptr_parent);
951                 ph_hydrate(cast(void**)&st.Svbtbl);
952               }
953               else
954               {
955                 ph_hydrate(cast(void**)&s.Sstruct);
956                 symbol_tree_hydrate(&s.Sstruct.Sroot);
957                 list_hydrate(&s.Sstruct.Sfldlst,cast(list_free_fp)&symbol_hydrate);
958               }
959                 break;
960 
961             case SC.enum_:
962                 assert(s.Senum);
963                 ph_hydrate(cast(void**)&s.Senum);
964                 if (CPP)
965                 {   ph_hydrate(cast(void**)&s.Senum.SEalias);
966                     list_hydrate(&s.Senum.SEenumlist,cast(list_free_fp)&symbol_hydrate);
967                 }
968                 break;
969 
970             case SC.template_:
971             {   template_t *tm;
972 
973                 tm = cast(template_t *) ph_hydrate(cast(void**)&s.Stemplate);
974                 list_hydrate(&tm.TMinstances,cast(list_free_fp)&symbol_hydrate);
975                 list_hydrate(&tm.TMfriends,cast(list_free_fp)&symbol_hydrate);
976                 param_hydrate(&tm.TMptpl);
977                 param_hydrate(&tm.TMptal);
978                 token_hydrate(&tm.TMbody);
979                 list_hydrate(&tm.TMmemberfuncs,cast(list_free_fp)&tmf_hydrate);
980                 list_hydrate(&tm.TMexplicit,cast(list_free_fp)&tme_hydrate);
981                 list_hydrate(&tm.TMnestedexplicit,cast(list_free_fp)&tmne_hydrate);
982                 list_hydrate(&tm.TMnestedfriends,cast(list_free_fp)&tmnf_hydrate);
983                 ph_hydrate(cast(void**)&tm.TMnext);
984                 symbol_hydrate(&tm.TMpartial);
985                 symbol_hydrate(&tm.TMprimary);
986                 break;
987             }
988 
989             case SC.namespace:
990                 symbol_tree_hydrate(&s.Snameroot);
991                 list_hydrate(&s.Susing,cast(list_free_fp)&symbol_hydrate);
992                 break;
993 
994             case SC.memalias:
995             case SC.funcalias:
996             case SC.adl:
997                 list_hydrate(&s.Spath,cast(list_free_fp)&symbol_hydrate);
998                 goto case SC.alias_;
999 
1000             case SC.alias_:
1001                 ph_hydrate(cast(void**)&s.Smemalias);
1002                 break;
1003 
1004             default:
1005                 if (s.Sflags & (SFLvalue | SFLdtorexp))
1006                     el_hydrate(&s.Svalue);
1007                 break;
1008         }
1009         {   dt_t **pdt;
1010             dt_t *dt;
1011 
1012             for (pdt = &s.Sdt; isdehydrated(*pdt); pdt = &dt.DTnext)
1013             {
1014                 dt = cast(dt_t *) ph_hydrate(cast(void**)pdt);
1015                 switch (dt.dt)
1016                 {   case DT_abytes:
1017                     case DT_nbytes:
1018                         ph_hydrate(cast(void**)&dt.DTpbytes);
1019                         break;
1020                     case DT_xoff:
1021                         symbol_hydrate(&dt.DTsym);
1022                         break;
1023 
1024                     default:
1025                         break;
1026                 }
1027             }
1028         }
1029         if (s.Scover)
1030             symbol_hydrate(&s.Scover);
1031     }
1032     return s;
1033 }
1034 }
1035 
1036 /*******************************************
1037  * Dehydrate a symbol.
1038  */
1039 
1040 static if (DEHYDRATE)
1041 {
1042 @trusted
1043 void symbol_dehydrate(Symbol **ps)
1044 {
1045     Symbol *s;
1046 
1047     if ((s = *ps) != null && !isdehydrated(s)) /* if symbol exists      */
1048     {   type *t;
1049         struct_t *st;
1050 
1051         debug
1052         if (debugy)
1053             printf("symbol_dehydrate('%s')\n",s.Sident.ptr);
1054 
1055         ph_dehydrate(ps);
1056 version (DEBUG_XSYMGEN)
1057 {
1058         if (xsym_gen && ph_in_head(s))
1059             return;
1060 }
1061         symbol_debug(s);
1062         t = s.Stype;
1063         if (isdehydrated(t))
1064             return;
1065         type_dehydrate(&s.Stype);
1066 
1067         if (tyfunc(t.Tty) && !isdehydrated(s.Sfunc))
1068         {
1069             func_t *f = s.Sfunc;
1070             SYMIDX si;
1071 
1072             debug assert(f);
1073             ph_dehydrate(&s.Sfunc);
1074 
1075             list_dehydrate(&f.Fsymtree,cast(list_free_fp)&symbol_tree_dehydrate);
1076             blocklist_dehydrate(&f.Fstartblock);
1077             assert(!isdehydrated(&f.Flocsym.tab));
1078 
1079 version (DEBUG_XSYMGEN)
1080 {
1081             if (!xsym_gen || !ph_in_head(f.Flocsym[].ptr))
1082                 for (si = 0; si < f.Flocsym.length; si++)
1083                     symbol_dehydrate(&f.Flocsym.tab[si]);
1084 }
1085 else
1086 {
1087             for (si = 0; si < f.Flocsym.length; si++)
1088                 symbol_dehydrate(&f.Flocsym.tab[si]);
1089 }
1090             ph_dehydrate(&f.Flocsym.tab);
1091 
1092             srcpos_dehydrate(&f.Fstartline);
1093             srcpos_dehydrate(&f.Fendline);
1094             symbol_dehydrate(&f.F__func__);
1095             if (CPP)
1096             {
1097             symbol_dehydrate(&f.Fparsescope);
1098             ph_dehydrate(&f.Fclass);
1099             symbol_dehydrate(&f.Foversym);
1100             symbol_dehydrate(&f.Fexplicitspec);
1101             symbol_dehydrate(&f.Fsurrogatesym);
1102 
1103             list_dehydrate(&f.Fclassfriends,FPNULL);
1104             el_dehydrate(&f.Fbaseinit);
1105 version (DEBUG_XSYMGEN)
1106 {
1107             if (xsym_gen && s.Sclass == SC.functempl)
1108                 ph_dehydrate(&f.Fbody);
1109             else
1110                 token_dehydrate(&f.Fbody);
1111 }
1112 else
1113             token_dehydrate(&f.Fbody);
1114 
1115             symbol_dehydrate(&f.Falias);
1116             list_dehydrate(&f.Fthunks,cast(list_free_fp)&symbol_dehydrate);
1117             if (f.Fflags & Finstance)
1118                 symbol_dehydrate(&f.Ftempl);
1119             else
1120                 thunk_dehydrate(&f.Fthunk);
1121 //#if !TX86 && DEBUG_XSYMGEN
1122 //            if (xsym_gen && s.Sclass == SCfunctempl)
1123 //                ph_dehydrate(&f.Farglist);
1124 //            else
1125 //#endif
1126             param_dehydrate(&f.Farglist);
1127             param_dehydrate(&f.Fptal);
1128             list_dehydrate(&f.Ffwdrefinstances,cast(list_free_fp)&symbol_dehydrate);
1129             list_dehydrate(&f.Fexcspec,cast(list_free_fp)&type_dehydrate);
1130             }
1131         }
1132         if (CPP)
1133             ph_dehydrate(&s.Sscope);
1134         switch (s.Sclass)
1135         {
1136             case SC.struct_:
1137               if (CPP)
1138               {
1139                 st = s.Sstruct;
1140                 if (isdehydrated(st))
1141                     break;
1142                 ph_dehydrate(&s.Sstruct);
1143                 assert(st);
1144                 symbol_tree_dehydrate(&st.Sroot);
1145                 ph_dehydrate(&st.Spvirtder);
1146                 list_dehydrate(&st.Sfldlst,cast(list_free_fp)&symbol_dehydrate);
1147                 list_dehydrate(&st.Svirtual,cast(list_free_fp)&mptr_dehydrate);
1148                 list_dehydrate(&st.Sopoverload,cast(list_free_fp)&symbol_dehydrate);
1149                 list_dehydrate(&st.Scastoverload,cast(list_free_fp)&symbol_dehydrate);
1150                 list_dehydrate(&st.Sclassfriends,cast(list_free_fp)&symbol_dehydrate);
1151                 list_dehydrate(&st.Sfriendclass,cast(list_free_fp)&ph_dehydrate);
1152                 list_dehydrate(&st.Sfriendfuncs,cast(list_free_fp)&ph_dehydrate);
1153                 assert(!st.Sinlinefuncs);
1154 
1155                 baseclass_dehydrate(&st.Sbase);
1156                 baseclass_dehydrate(&st.Svirtbase);
1157                 baseclass_dehydrate(&st.Smptrbase);
1158                 baseclass_dehydrate(&st.Sprimary);
1159                 baseclass_dehydrate(&st.Svbptrbase);
1160 
1161                 ph_dehydrate(&st.Svecctor);
1162                 ph_dehydrate(&st.Sctor);
1163                 ph_dehydrate(&st.Sdtor);
1164                 ph_dehydrate(&st.Sprimdtor);
1165                 ph_dehydrate(&st.Spriminv);
1166                 ph_dehydrate(&st.Sscaldeldtor);
1167                 ph_dehydrate(&st.Sinvariant);
1168                 ph_dehydrate(&st.Svptr);
1169                 ph_dehydrate(&st.Svtbl);
1170                 ph_dehydrate(&st.Sopeq);
1171                 ph_dehydrate(&st.Sopeq2);
1172                 ph_dehydrate(&st.Scpct);
1173                 ph_dehydrate(&st.Sveccpct);
1174                 ph_dehydrate(&st.Salias);
1175                 ph_dehydrate(&st.Stempsym);
1176                 param_dehydrate(&st.Sarglist);
1177                 param_dehydrate(&st.Spr_arglist);
1178                 ph_dehydrate(&st.Svbptr);
1179                 ph_dehydrate(&st.Svbptr_parent);
1180                 ph_dehydrate(&st.Svbtbl);
1181               }
1182               else
1183               {
1184                 symbol_tree_dehydrate(&s.Sstruct.Sroot);
1185                 list_dehydrate(&s.Sstruct.Sfldlst,cast(list_free_fp)&symbol_dehydrate);
1186                 ph_dehydrate(&s.Sstruct);
1187               }
1188                 break;
1189 
1190             case SC.enum_:
1191                 assert(s.Senum);
1192                 if (!isdehydrated(s.Senum))
1193                 {
1194                     if (CPP)
1195                     {   ph_dehydrate(&s.Senum.SEalias);
1196                         list_dehydrate(&s.Senumlist,cast(list_free_fp)&ph_dehydrate);
1197                     }
1198                     ph_dehydrate(&s.Senum);
1199                 }
1200                 break;
1201 
1202             case SC.template_:
1203             {   template_t *tm;
1204 
1205                 tm = s.Stemplate;
1206                 if (!isdehydrated(tm))
1207                 {
1208                     ph_dehydrate(&s.Stemplate);
1209                     list_dehydrate(&tm.TMinstances,cast(list_free_fp)&symbol_dehydrate);
1210                     list_dehydrate(&tm.TMfriends,cast(list_free_fp)&symbol_dehydrate);
1211                     list_dehydrate(&tm.TMnestedfriends,cast(list_free_fp)&tmnf_dehydrate);
1212                     param_dehydrate(&tm.TMptpl);
1213                     param_dehydrate(&tm.TMptal);
1214                     token_dehydrate(&tm.TMbody);
1215                     list_dehydrate(&tm.TMmemberfuncs,cast(list_free_fp)&tmf_dehydrate);
1216                     list_dehydrate(&tm.TMexplicit,cast(list_free_fp)&tme_dehydrate);
1217                     list_dehydrate(&tm.TMnestedexplicit,cast(list_free_fp)&tmne_dehydrate);
1218                     ph_dehydrate(&tm.TMnext);
1219                     symbol_dehydrate(&tm.TMpartial);
1220                     symbol_dehydrate(&tm.TMprimary);
1221                 }
1222                 break;
1223             }
1224 
1225             case SC.namespace_:
1226                 symbol_tree_dehydrate(&s.Snameroot);
1227                 list_dehydrate(&s.Susing,cast(list_free_fp)&symbol_dehydrate);
1228                 break;
1229 
1230             case SC.memalias:
1231             case SC.funcalias:
1232             case SC.adl:
1233                 list_dehydrate(&s.Spath,cast(list_free_fp)&symbol_dehydrate);
1234             case SC.alias_:
1235                 ph_dehydrate(&s.Smemalias);
1236                 break;
1237 
1238             default:
1239                 if (s.Sflags & (SFLvalue | SFLdtorexp))
1240                     el_dehydrate(&s.Svalue);
1241                 break;
1242         }
1243         {   dt_t **pdt;
1244             dt_t *dt;
1245 
1246             for (pdt = &s.Sdt;
1247                  (dt = *pdt) != null && !isdehydrated(dt);
1248                  pdt = &dt.DTnext)
1249             {
1250                 ph_dehydrate(pdt);
1251                 switch (dt.dt)
1252                 {   case DT_abytes:
1253                     case DT_nbytes:
1254                         ph_dehydrate(&dt.DTpbytes);
1255                         break;
1256                     case DT_xoff:
1257                         symbol_dehydrate(&dt.DTsym);
1258                         break;
1259                 }
1260             }
1261         }
1262         if (s.Scover)
1263             symbol_dehydrate(&s.Scover);
1264     }
1265 }
1266 }
1267 
1268 /***************************
1269  * Dehydrate threaded list of symbols.
1270  */
1271 
1272 static if (DEHYDRATE)
1273 {
1274 @trusted
1275 void symbol_symdefs_dehydrate(Symbol **ps)
1276 {
1277     Symbol *s;
1278 
1279     for (; *ps; ps = &s.Snext)
1280     {
1281         s = *ps;
1282         symbol_debug(s);
1283         //printf("symbol_symdefs_dehydrate(%p, '%s')\n",s,s.Sident.ptr);
1284         symbol_dehydrate(ps);
1285     }
1286 }
1287 }
1288 
1289 
1290 static if (0)
1291 {
1292 
1293 /*************************************
1294  * Put symbol table s into parent symbol table.
1295  */
1296 
1297 void symboltable_hydrate(Symbol *s,Symbol **parent)
1298 {
1299     while (s)
1300     {   Symbol* sl,sr;
1301         char *p;
1302 
1303         symbol_debug(s);
1304 
1305         sl = s.Sl;
1306         sr = s.Sr;
1307         p = s.Sident.ptr;
1308 
1309         //printf("symboltable_hydrate('%s')\n",p);
1310 
1311         /* Put symbol s into symbol table       */
1312         {   Symbol **ps;
1313             Symbol *rover;
1314             int c = *p;
1315 
1316             ps = parent;
1317             while ((rover = *ps) != null)
1318             {   int cmp;
1319 
1320                 if ((cmp = c - rover.Sident[0]) == 0)
1321                 {   cmp = strcmp(p,rover.Sident.ptr); /* compare identifier strings */
1322                     if (cmp == 0)
1323                     {
1324                         if (CPP && tyfunc(s.Stype.Tty) && tyfunc(rover.Stype.Tty))
1325                         {   Symbol **ps;
1326                             Symbol *sn;
1327 
1328                             do
1329                             {
1330                                 // Tack onto end of overloaded function list
1331                                 for (ps = &rover; *ps; ps = &(*ps).Sfunc.Foversym)
1332                                 {   if (cpp_funccmp(s, *ps))
1333                                         goto L2;
1334                                 }
1335                                 s.Sl = s.Sr = null;
1336                                 *ps = s;
1337                             L2:
1338                                 sn = s.Sfunc.Foversym;
1339                                 s.Sfunc.Foversym = null;
1340                                 s = sn;
1341                             } while (s);
1342                         }
1343                         else
1344                         {
1345                             if (!typematch(s.Stype,rover.Stype,0))
1346                             {
1347                                 // cpp_predefine() will define this again
1348                                 if (type_struct(rover.Stype) &&
1349                                     rover.Sstruct.Sflags & STRpredef)
1350                                 {   s.Sl = s.Sr = null;
1351                                     symbol_keep(s);
1352                                 }
1353                                 else
1354                                     synerr(EM_multiple_def,p);  // already defined
1355                             }
1356                         }
1357                         goto L1;
1358                     }
1359                 }
1360                 ps = (cmp < 0) ?        /* if we go down left side      */
1361                     &rover.Sl :
1362                     &rover.Sr;
1363             }
1364             {
1365                 s.Sl = s.Sr = null;
1366                 *ps = s;
1367             }
1368         }
1369     L1:
1370         symboltable_hydrate(sl,parent);
1371         s = sr;
1372     }
1373 }
1374 
1375 }
1376 
1377 
1378 /************************************
1379  * Hydrate/dehydrate an mptr_t.
1380  */
1381 
1382 static if (HYDRATE)
1383 {
1384 @trusted
1385 private void mptr_hydrate(mptr_t **pm)
1386 {   mptr_t *m;
1387 
1388     m = cast(mptr_t *) ph_hydrate(cast(void**)pm);
1389     symbol_hydrate(&m.MPf);
1390     symbol_hydrate(&m.MPparent);
1391 }
1392 }
1393 
1394 static if (DEHYDRATE)
1395 {
1396 @trusted
1397 private void mptr_dehydrate(mptr_t **pm)
1398 {   mptr_t *m;
1399 
1400     m = *pm;
1401     if (m && !isdehydrated(m))
1402     {
1403         ph_dehydrate(pm);
1404 version (DEBUG_XSYMGEN)
1405 {
1406         if (xsym_gen && ph_in_head(m.MPf))
1407             ph_dehydrate(&m.MPf);
1408         else
1409             symbol_dehydrate(&m.MPf);
1410 }
1411 else
1412         symbol_dehydrate(&m.MPf);
1413 
1414         symbol_dehydrate(&m.MPparent);
1415     }
1416 }
1417 }
1418 
1419 /************************************
1420  * Hydrate/dehydrate a baseclass_t.
1421  */
1422 
1423 static if (HYDRATE)
1424 {
1425 @trusted
1426 private void baseclass_hydrate(baseclass_t **pb)
1427 {   baseclass_t *b;
1428 
1429     assert(pb);
1430     while (isdehydrated(*pb))
1431     {
1432         b = cast(baseclass_t *) ph_hydrate(cast(void**)pb);
1433 
1434         ph_hydrate(cast(void**)&b.BCbase);
1435         ph_hydrate(cast(void**)&b.BCpbase);
1436         list_hydrate(&b.BCpublics,cast(list_free_fp)&symbol_hydrate);
1437         list_hydrate(&b.BCmptrlist,cast(list_free_fp)&mptr_hydrate);
1438         symbol_hydrate(&b.BCvtbl);
1439         Classsym_hydrate(&b.BCparent);
1440 
1441         pb = &b.BCnext;
1442     }
1443 }
1444 }
1445 
1446 /**********************************
1447  * Dehydrate a baseclass_t.
1448  */
1449 
1450 static if (DEHYDRATE)
1451 {
1452 @trusted
1453 private void baseclass_dehydrate(baseclass_t **pb)
1454 {   baseclass_t *b;
1455 
1456     while ((b = *pb) != null && !isdehydrated(b))
1457     {
1458         ph_dehydrate(pb);
1459 
1460 version (DEBUG_XSYMGEN)
1461 {
1462         if (xsym_gen && ph_in_head(b))
1463             return;
1464 }
1465 
1466         ph_dehydrate(&b.BCbase);
1467         ph_dehydrate(&b.BCpbase);
1468         list_dehydrate(&b.BCpublics,cast(list_free_fp)&symbol_dehydrate);
1469         list_dehydrate(&b.BCmptrlist,cast(list_free_fp)&mptr_dehydrate);
1470         symbol_dehydrate(&b.BCvtbl);
1471         Classsym_dehydrate(&b.BCparent);
1472 
1473         pb = &b.BCnext;
1474     }
1475 }
1476 }
1477 
1478 /***************************
1479  * Look down baseclass list to find sbase.
1480  * Returns:
1481  *      null    not found
1482  *      pointer to baseclass
1483  */
1484 
1485 baseclass_t *baseclass_find(baseclass_t *bm,Classsym *sbase)
1486 {
1487     symbol_debug(sbase);
1488     for (; bm; bm = bm.BCnext)
1489         if (bm.BCbase == sbase)
1490             break;
1491     return bm;
1492 }
1493 
1494 @trusted
1495 baseclass_t *baseclass_find_nest(baseclass_t *bm,Classsym *sbase)
1496 {
1497     symbol_debug(sbase);
1498     for (; bm; bm = bm.BCnext)
1499     {
1500         if (bm.BCbase == sbase ||
1501             baseclass_find_nest(bm.BCbase.Sstruct.Sbase, sbase))
1502             break;
1503     }
1504     return bm;
1505 }
1506 
1507 /******************************
1508  * Calculate number of baseclasses in list.
1509  */
1510 
1511 int baseclass_nitems(baseclass_t *b)
1512 {   int i;
1513 
1514     for (i = 0; b; b = b.BCnext)
1515         i++;
1516     return i;
1517 }
1518 
1519 /*************************************
1520  * Reset Symbol so that it's now an "extern" to the next obj file being created.
1521  */
1522 void symbol_reset(Symbol *s)
1523 {
1524     s.Soffset = 0;
1525     s.Sxtrnnum = 0;
1526     s.Stypidx = 0;
1527     s.Sflags &= ~(STRoutdef | SFLweak);
1528     s.Sdw_ref_idx = 0;
1529     if (s.Sclass == SC.global || s.Sclass == SC.comdat ||
1530         s.Sfl == FLudata || s.Sclass == SC.static_)
1531     {   s.Sclass = SC.extern_;
1532         s.Sfl = FLextern;
1533     }
1534 }
1535 
1536 /****************************************
1537  * Determine pointer type needed to access a Symbol,
1538  * essentially what type an OPrelconst should get
1539  * for that Symbol.
1540  * Params:
1541  *      s = pointer to Symbol
1542  * Returns:
1543  *      pointer type to access it
1544  */
1545 tym_t symbol_pointerType(const Symbol* s)
1546 {
1547     return s.Stype.Tty & mTYimmutable ? TYimmutPtr : TYnptr;
1548 }