1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1992-1998 by Symantec
6  *              Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/newman.c, backend/newman.c)
10  */
11 
12 module dmd.backend.newman;
13 
14 version (SCPP)
15 {
16     version = COMPILE;
17     version = SCPPorMARS;
18     version = SCPPorHTOD;
19 }
20 version (HTOD)
21 {
22     version = COMPILE;
23     version = SCPPorMARS;
24     version = SCPPorHTOD;
25 }
26 version (MARS)
27 {
28     version = COMPILE;
29     version = SCPPorMARS;
30 }
31 
32 version (COMPILE)
33 {
34 
35 import core.stdc.ctype;
36 import core.stdc.stdio;
37 import core.stdc.stdlib;
38 import core.stdc..string;
39 
40 import dmd.backend.cc;
41 import dmd.backend.cdef;
42 import dmd.backend.code;
43 import dmd.backend.code_x86;
44 import dmd.backend.mem;
45 import dmd.backend.el;
46 import dmd.backend.exh;
47 import dmd.backend.global;
48 import dmd.backend.obj;
49 import dmd.backend.oper;
50 import dmd.backend.rtlsym;
51 import dmd.backend.ty;
52 import dmd.backend.type;
53 import dmd.backend.xmm;
54 
55 version (SCPPorHTOD)
56 {
57     import cpp;
58     import dtoken;
59     import msgs2;
60     import parser;
61     import scopeh;
62 }
63 
64 version (MARS)
65     struct token_t;
66 
67 extern (C++):
68 
69 nothrow:
70 
71 bool NEWTEMPMANGLE() { return !(config.flags4 & CFG4oldtmangle); }     // do new template mangling
72 
73 enum BUFIDMAX = 2 * IDMAX;
74 
75 struct Mangle
76 {
77     char[BUFIDMAX + 2] buf;
78 
79     char *np;                   // index into buf[]
80 
81     // Used for compression of redundant znames
82     const(char)*[10] zname;
83     int znamei;
84 
85     type*[10] arg;              // argument_replicator
86     int argi;                   // number used in arg[]
87 }
88 
89 private __gshared
90 {
91     Mangle mangle;
92 
93     int mangle_inuse;
94 }
95 
96 struct MangleInuse
97 {
98 static if (0)
99 {
100     this(int i)
101     {
102         assert(mangle_inuse == 0);
103         mangle_inuse++;
104     }
105 
106     ~this()
107     {
108         assert(mangle_inuse == 1);
109         mangle_inuse--;
110     }
111 }
112 }
113 
114 /* Names for special variables  */
115 __gshared
116 {
117 char[3] cpp_name_new     = "?2";
118 char[3] cpp_name_delete  = "?3";
119 char[4] cpp_name_anew    = "?_P";
120 char[4] cpp_name_adelete = "?_Q";
121 char[3] cpp_name_ct      = "?0";
122 char[3] cpp_name_dt      = "?1";
123 char[3] cpp_name_as      = "?4";
124 char[4] cpp_name_vc      = "?_H";
125 char[4] cpp_name_primdt  = "?_D";
126 char[4] cpp_name_scaldeldt = "?_G";
127 char[4] cpp_name_priminv = "?_R";
128 }
129 
130 
131 /****************************
132  */
133 
134 version (MARS)
135 {
136 struct OPTABLE
137 {
138     ubyte tokn;
139     ubyte oper;
140     const(char)* string;
141     const(char)* pretty;
142 }
143 }
144 
145 version (SCPPorHTOD)
146 {
147 __gshared OPTABLE[57] oparray = [
148     {   TKnew, OPnew,           cpp_name_new.ptr,   "new" },
149     {   TKdelete, OPdelete,     cpp_name_delete.ptr,"del" },
150     {   TKadd, OPadd,           "?H",           "+" },
151     {   TKadd, OPuadd,          "?H",           "+" },
152     {   TKmin, OPmin,           "?G",           "-" },
153     {   TKmin, OPneg,           "?G",           "-" },
154     {   TKstar, OPmul,          "?D",           "*" },
155     {   TKstar, OPind,          "?D",           "*" },
156     {   TKdiv, OPdiv,           "?K",           "/" },
157     {   TKmod, OPmod,           "?L",           "%" },
158     {   TKxor, OPxor,           "?T",           "^" },
159     {   TKand, OPand,           "?I",           "&" },
160     {   TKand, OPaddr,          "?I",           "&" },
161     {   TKor, OPor,             "?U",           "|" },
162     {   TKcom, OPcom,           "?S",           "~" },
163     {   TKnot, OPnot,           "?7",           "!" },
164     {   TKeq, OPeq,             cpp_name_as.ptr,    "=" },
165     {   TKeq, OPstreq,          "?4",           "=" },
166     {   TKlt, OPlt,             "?M",           "<" },
167     {   TKgt, OPgt,             "?O",           ">" },
168     {   TKnew, OPanew,          cpp_name_anew.ptr,  "n[]" },
169     {   TKdelete, OPadelete,    cpp_name_adelete.ptr,"d[]" },
170     {   TKunord, OPunord,       "?_S",          "!<>=" },
171     {   TKlg, OPlg,             "?_T",          "<>"   },
172     {   TKleg, OPleg,           "?_U",          "<>="  },
173     {   TKule, OPule,           "?_V",          "!>"   },
174     {   TKul, OPul,             "?_W",          "!>="  },
175     {   TKuge, OPuge,           "?_X",          "!<"   },
176     {   TKug, OPug,             "?_Y",          "!<="  },
177     {   TKue, OPue,             "?_Z",          "!<>"  },
178     {   TKaddass, OPaddass,     "?Y",           "+=" },
179     {   TKminass, OPminass,     "?Z",           "-=" },
180     {   TKmulass, OPmulass,     "?X",           "*=" },
181     {   TKdivass, OPdivass,     "?_0",          "/=" },
182     {   TKmodass, OPmodass,     "?_1",          "%=" },
183     {   TKxorass, OPxorass,     "?_6",          "^=" },
184     {   TKandass, OPandass,     "?_4",          "&=" },
185     {   TKorass, OPorass,       "?_5",          "|=" },
186     {   TKshl, OPshl,           "?6",           "<<" },
187     {   TKshr, OPshr,           "?5",           ">>" },
188     {   TKshrass, OPshrass,     "?_2",          ">>=" },
189     {   TKshlass, OPshlass,     "?_3",          "<<=" },
190     {   TKeqeq, OPeqeq,         "?8",           "==" },
191     {   TKne, OPne,             "?9",           "!=" },
192     {   TKle, OPle,             "?N",           "<=" },
193     {   TKge, OPge,             "?P",           ">=" },
194     {   TKandand, OPandand,     "?V",           "&&" },
195     {   TKoror, OPoror,         "?W",           "||" },
196     {   TKplpl, OPpostinc,      "?E",           "++" },
197     {   TKplpl, OPpreinc,       "?E",           "++" },
198     {   TKmimi, OPpostdec,      "?F",           "--" },
199     {   TKmimi, OPpredec,       "?F",           "--" },
200     {   TKlpar, OPcall,         "?R",           "()" },
201     {   TKlbra, OPbrack,        "?A",           "[]" },
202     {   TKarrow, OParrow,       "?C",           "->" },
203     {   TKcomma, OPcomma,       "?Q",           "," },
204     {   TKarrowstar, OParrowstar, "?J",         "->*" },
205 ];
206 }
207 
208 /****************************************
209  * Convert from identifier to operator
210  */
211 version (SCPPorHTOD)
212 {
213 
214 static if (0) //__GNUC__    // NOT DONE - FIX
215 {
216 char * unmangle_pt(const(char)** s)
217 {
218     return cast(char *)*s;
219 }
220 }
221 else
222 {
223     extern (C) char *unmangle_pt(const(char)**);
224 }
225 
226 char *cpp_unmangleident(const(char)* p)
227 {
228     MangleInuse m;
229 
230     //printf("cpp_unmangleident('%s')\n", p);
231     if (*p == '$')              // if template name
232     {
233     L1:
234         const(char)* q = p;
235         char* s = unmangle_pt(&q);
236         if (s)
237         {   if (strlen(s) <= BUFIDMAX)
238                 p = strcpy(mangle.buf.ptr, s);
239             free(s);
240         }
241     }
242     else if (*p == '?')         // if operator name
243     {   int i;
244 
245         if (NEWTEMPMANGLE && p[1] == '$')       // if template name
246             goto L1;
247         for (i = 0; i < oparray.length; i++)
248         {   if (strcmp(p,oparray[i].string) == 0)
249             {   const(char)* s;
250 
251                 strcpy(mangle.buf.ptr, "operator ");
252                 switch (oparray[i].oper)
253                 {   case OPanew:
254                         s = "new[]";
255                         break;
256                     case OPadelete:
257                         s = "delete[]";
258                         break;
259                     case OPdelete:
260                         s = "delete";
261                         break;
262                     default:
263                         s = oparray[i].pretty.ptr;
264                         break;
265                 }
266                 strcat(mangle.buf.ptr,s);
267                 p = mangle.buf.ptr;
268                 break;
269             }
270         }
271     }
272     //printf("-cpp_unmangleident() = '%s'\n", p);
273     return cast(char *)p;
274 }
275 }
276 
277 /****************************************
278  * Find index in oparray[] for operator.
279  * Returns:
280  *      index or -1 if not found
281  */
282 
283 version (SCPPorHTOD)
284 {
285 
286 int cpp_opidx(int op)
287 {   int i;
288 
289     for (i = 0; i < oparray.length; i++)
290         if (oparray[i].oper == op)
291             return i;
292     return -1;
293 }
294 
295 }
296 
297 /***************************************
298  * Find identifier string associated with operator.
299  * Returns:
300  *      null if not found
301  */
302 
303 version (SCPPorHTOD)
304 {
305 
306 char *cpp_opident(int op)
307 {   int i;
308 
309     i = cpp_opidx(op);
310     return (i == -1) ? null : cast(char*)oparray[i].string;
311 }
312 
313 }
314 
315 /**********************************
316  * Convert from operator token to name.
317  * Output:
318  *      *poper  OPxxxx
319  *      *pt     set to type for user defined conversion
320  * Returns:
321  *      pointer to corresponding name
322  */
323 
324 version (SCPPorHTOD)
325 {
326 
327 char *cpp_operator(int *poper,type **pt)
328 {
329     int i;
330     type *typ_spec;
331     char *s;
332 
333     *pt = null;
334     stoken();                           /* skip over operator keyword   */
335     for (i = 0; i < oparray.length; i++)
336     {   if (oparray[i].tokn == tok.TKval)
337             goto L1;
338     }
339 
340     /* Look for type conversion */
341     if (type_specifier(&typ_spec))
342     {   type *t;
343 
344         t = ptr_operator(typ_spec);     // parse ptr-operator
345         fixdeclar(t);
346         type_free(typ_spec);
347         *pt = t;
348         return cpp_typetostring(t,cast(char*)"?B".ptr);
349     }
350 
351     cpperr(EM_not_overloadable);        // that token cannot be overloaded
352     s = cast(char*)"_".ptr;
353     goto L2;
354 
355 L1:
356     s = cast(char*)oparray[i].string;
357     *poper = oparray[i].oper;
358     switch (*poper)
359     {   case OPcall:
360             if (stoken() != TKrpar)
361                 synerr(EM_rpar);                /* ')' expected                 */
362             break;
363 
364         case OPbrack:
365             if (stoken() != TKrbra)
366                 synerr(EM_rbra);                /* ']' expected                 */
367             break;
368 
369         case OPnew:
370             if (stoken() != TKlbra)
371                 goto Lret;
372             *poper = OPanew;            // operator new[]
373             s = cpp_name_anew.ptr;
374             goto L3;
375 
376         case OPdelete:
377             if (stoken() != TKlbra)
378                 goto Lret;
379             *poper = OPadelete;         // operator delete[]
380             s = cpp_name_adelete.ptr;
381         L3:
382             if (stoken() != TKrbra)
383                 synerr(EM_rbra);                // ']' expected
384             if (!(config.flags4 & CFG4anew))
385             {   cpperr(EM_enable_anew);         // throw -Aa to support this
386                 config.flags4 |= CFG4anew;
387             }
388             break;
389 
390         default:
391             break;
392     }
393 L2:
394     stoken();
395 Lret:
396     return s;
397 }
398 
399 /******************************************
400  * Alternate version that works on a list of token's.
401  * Input:
402  *      to      list of tokens
403  * Output:
404  *      *pcastoverload  1 if user defined type conversion
405  */
406 
407 char *cpp_operator2(token_t *to, int *pcastoverload)
408 {
409     int i;
410     char *s;
411     token_t *tn;
412     int oper;
413 
414     *pcastoverload = 0;
415     if (!to || !to.TKnext)
416         return null;
417 
418     for (i = 0; i < oparray.length; i++)
419     {
420         //printf("[%d] %d, %d\n", i, oparray[i].tokn, tok.TKval);
421         if (oparray[i].tokn == to.TKval)
422             goto L1;
423     }
424 
425     //printf("cpp_operator2(): castoverload\n");
426     *pcastoverload = 1;
427     return null;
428 
429 L1:
430     tn = to.TKnext;
431     s = cast(char*)oparray[i].string;
432     oper = oparray[i].oper;
433     switch (oper)
434     {   case OPcall:
435             if (tn.TKval != TKrpar)
436                 synerr(EM_rpar);        // ')' expected
437             break;
438 
439         case OPbrack:
440             if (tn.TKval != TKrbra)
441                 synerr(EM_rbra);        // ']' expected
442             break;
443 
444         case OPnew:
445             if (tn.TKval != TKlbra)
446                 break;
447             oper = OPanew;              // operator new[]
448             s = cpp_name_anew.ptr;
449             goto L3;
450 
451         case OPdelete:
452             if (tn.TKval != TKlbra)
453                 break;
454             oper = OPadelete;           // operator delete[]
455             s = cpp_name_adelete.ptr;
456         L3:
457             if (tn.TKval != TKrbra)
458                 synerr(EM_rbra);                // ']' expected
459             if (!(config.flags4 & CFG4anew))
460             {   cpperr(EM_enable_anew);         // throw -Aa to support this
461                 config.flags4 |= CFG4anew;
462             }
463             break;
464 
465         default:
466             break;
467     }
468     return s;
469 }
470 
471 }
472 
473 /***********************************
474  * Generate and return a pointer to a string constructed from
475  * the type, appended to the prefix.
476  * Since these generated strings determine the uniqueness of names,
477  * they are also used to determine if two types are the same.
478  * Returns:
479  *      pointer to static name[]
480  */
481 
482 char *cpp_typetostring(type *t,char *prefix)
483 {   int i;
484 
485     if (prefix)
486     {   strcpy(mangle.buf.ptr,prefix);
487         i = cast(int)strlen(prefix);
488     }
489     else
490         i = 0;
491     //dbg_printf("cpp_typetostring:\n");
492     //type_print(t);
493     MangleInuse m;
494     mangle.znamei = 0;
495     mangle.argi = 0;
496     mangle.np = mangle.buf.ptr + i;
497     mangle.buf[BUFIDMAX + 1] = 0x55;
498     cpp_data_type(t);
499     *mangle.np = 0;                     // 0-terminate mangle.buf[]
500     //dbg_printf("cpp_typetostring: '%s'\n", mangle.buf);
501     assert(strlen(mangle.buf.ptr) <= BUFIDMAX);
502     assert(mangle.buf[BUFIDMAX + 1] == 0x55);
503     return mangle.buf.ptr;
504 }
505 
506 version (MARS) { } else
507 {
508 
509 /********************************
510  * 'Mangle' a name for output.
511  * Returns:
512  *      pointer to mangled name (a static buffer)
513  */
514 
515 char *cpp_mangle(Symbol *s)
516 {
517     symbol_debug(s);
518     //printf("cpp_mangle(s = %p, '%s')\n", s, s.Sident);
519     //type_print(s.Stype);
520 
521 version (SCPPorHTOD)
522 {
523     if (!CPP)
524         return symbol_ident(s);
525 }
526 
527     if (type_mangle(s.Stype) != mTYman_cpp)
528         return symbol_ident(s);
529     else
530     {
531         MangleInuse m;
532 
533         mangle.znamei = 0;
534         mangle.argi = 0;
535         mangle.np = mangle.buf.ptr;
536         mangle.buf[BUFIDMAX + 1] = 0x55;
537         cpp_decorated_name(s);
538         *mangle.np = 0;                 // 0-terminate cpp_name[]
539         //dbg_printf("cpp_mangle() = '%s'\n", mangle.buf);
540         assert(strlen(mangle.buf.ptr) <= BUFIDMAX);
541         assert(mangle.buf[BUFIDMAX + 1] == 0x55);
542         return mangle.buf.ptr;
543     }
544 }
545 
546 }
547 ///////////////////////////////////////////////////////
548 
549 /*********************************
550  * Add char into cpp_name[].
551  */
552 
553 private void CHAR(int c)
554 {
555     if (mangle.np < &mangle.buf[BUFIDMAX])
556         *mangle.np++ = cast(char)c;
557 }
558 
559 /*********************************
560  * Add char into cpp_name[].
561  */
562 
563 private void STR(const(char)* p)
564 {
565     size_t len;
566 
567     len = strlen(p);
568     if (mangle.np + len <= &mangle.buf[BUFIDMAX])
569     {   memcpy(mangle.np,p,len);
570         mangle.np += len;
571     }
572     else
573         for (; *p; p++)
574             CHAR(*p);
575 }
576 
577 /***********************************
578  * Convert const volatile combinations into 0..3
579  */
580 
581 private int cpp_cvidx(tym_t ty)
582 {   int i;
583 
584     i  = (ty & mTYconst) ? 1 : 0;
585     i |= (ty & mTYvolatile) ? 2 : 0;
586     return i;
587 }
588 
589 /******************************
590  * Turn protection into 0..2
591  */
592 
593 private int cpp_protection(Symbol *s)
594 {   int i;
595 
596     switch (s.Sflags & SFLpmask)
597     {   case SFLprivate:        i = 0;  break;
598         case SFLprotected:      i = 1;  break;
599         case SFLpublic:         i = 2;  break;
600         default:
601             symbol_print(s);
602             assert(0);
603     }
604     return i;
605 }
606 
607 /***********************************
608  * Create mangled name for template instantiation.
609  */
610 
611 version (SCPPorHTOD)
612 {
613 
614 char *template_mangle(Symbol *s,param_t *arglist)
615 {
616     /*  mangling ::= '$' template_name { type | expr }
617         type ::= "T" mangled type
618         expr ::= integer | string | address | float | double | long_double
619         integer ::= "I" dimension
620         string ::= "S" string
621         address ::= "R" zname
622         float ::= "F" hex_digits
623         double ::= "D" hex_digits
624         long_double ::= "L" hex_digits
625      */
626     param_t *p;
627 
628     assert(s);
629     symbol_debug(s);
630     //assert(s.Sclass == SCtemplate);
631 
632     //printf("\ntemplate_mangle(s = '%s', arglist = %p)\n", s.Sident, arglist);
633     //arglist.print_list();
634 
635     MangleInuse m;
636     mangle.znamei = 0;
637     mangle.argi = 0;
638     mangle.np = mangle.buf.ptr;
639     mangle.buf[BUFIDMAX + 1] = 0x55;
640 
641     if (NEWTEMPMANGLE)
642         STR("?$");
643     else
644         CHAR('$');
645 
646     // BUG: this is for templates nested inside class scopes.
647     // Need to check if it creates names that are properly unmanglable.
648     cpp_zname(s.Sident.ptr);
649     if (s.Sscope)
650         cpp_scope(s.Sscope);
651 
652     for (p = arglist; p; p = p.Pnext)
653     {
654         if (p.Ptype)
655         {   /* Argument is a type       */
656             if (!NEWTEMPMANGLE)
657                 CHAR('T');
658             cpp_argument_list(p.Ptype, 1);
659         }
660         else if (p.Psym)
661         {
662             CHAR('V');  // this is a 'class' name, but it should be a 'template' name
663             cpp_ecsu_name(p.Psym);
664         }
665         else
666         {   /* Argument is an expression        */
667             elem *e = p.Pelem;
668             tym_t ty = tybasic(e.ET.Tty);
669             char *p2;
670             char[2] a = void;
671             int ni;
672             char c;
673 
674         L2:
675             switch (e.Eoper)
676             {   case OPconst:
677                     switch (ty)
678                     {   case TYfloat:   ni = FLOATSIZE;  c = 'F'; goto L1;
679                         case TYdouble_alias:
680                         case TYdouble:  ni = DOUBLESIZE; c = 'D'; goto L1;
681                         case TYldouble: ni = tysize(TYldouble); c = 'L'; goto L1;
682                         L1:
683                             if (NEWTEMPMANGLE)
684                                 CHAR('$');
685                             CHAR(c);
686                             p2 = cast(char *)&e.EV.Vdouble;
687                             while (ni--)
688                             {   char ch;
689                                 static immutable char[16] hex = "0123456789ABCDEF";
690 
691                                 ch = *p2++;
692                                 CHAR(hex[ch & 15]);
693                                 CHAR(hex[(ch >> 4) & 15]);
694                             }
695                             break;
696                         default:
697 debug
698 {
699                             if (!tyintegral(ty) && !tymptr(ty))
700                                 elem_print(e);
701 }
702                             assert(tyintegral(ty) || tymptr(ty));
703                             if (NEWTEMPMANGLE)
704                                 STR("$0");
705                             else
706                                 CHAR('I');
707                             cpp_dimension(el_tolongt(e));
708                             break;
709                     }
710                     break;
711                 case OPstring:
712                     if (NEWTEMPMANGLE)
713                         STR("$S");
714                     else
715                         CHAR('S');
716                     if (e.EV.Voffset)
717                         synerr(EM_const_init);          // constant initializer expected
718                     cpp_string(e.EV.Vstring,e.EV.Vstrlen);
719                     break;
720                 case OPrelconst:
721                     if (e.EV.Voffset)
722                         synerr(EM_const_init);          // constant initializer expected
723                     s = e.EV.Vsym;
724                     if (NEWTEMPMANGLE)
725                     {   STR("$1");
726                         cpp_decorated_name(s);
727                     }
728                     else
729                     {   CHAR('R');
730                         cpp_zname(s.Sident.ptr);
731                     }
732                     break;
733                 case OPvar:
734                     if (e.EV.Vsym.Sflags & SFLvalue &&
735                         tybasic(e.ET.Tty) != TYstruct)
736                     {
737                         e = e.EV.Vsym.Svalue;
738                         goto L2;
739                     }
740                     else if (e.EV.Vsym.Sclass == SCconst /*&&
741                              pstate.STintemplate*/)
742                     {
743                         CHAR('V');              // pretend to be a class name
744                         cpp_zname(e.EV.Vsym.Sident.ptr);
745                         break;
746                     }
747                     goto default;
748 
749                 default:
750 version (SCPPorHTOD)
751 {
752 debug
753 {
754                     if (!errcnt)
755                         elem_print(e);
756 }
757                     synerr(EM_const_init);              // constant initializer expected
758                     assert(errcnt);
759 }
760                     break;
761             }
762         }
763     }
764     *mangle.np = 0;
765     //printf("template_mangle() = '%s'\n", mangle.buf);
766     assert(strlen(mangle.buf.ptr) <= BUFIDMAX);
767     assert(mangle.buf[BUFIDMAX + 1] == 0x55);
768     return mangle.buf.ptr;
769 }
770 
771 }
772 
773 //////////////////////////////////////////////////////
774 // Functions corresponding to the name mangling grammar in the
775 // "Microsoft Object Mapping Specification"
776 
777 private void cpp_string(char *s,size_t len)
778 {   char c;
779 
780     for (; --len; s++)
781     {   static immutable char[11] special_char = ",/\\:. \n\t'-";
782         char *p;
783 
784         c = *s;
785         if (c & 0x80 && isalpha(c & 0x7F))
786         {   CHAR('?');
787             c &= 0x7F;
788         }
789         else if (isalnum(c))
790         { }
791         else
792         {
793             CHAR('?');
794             if ((p = cast(char *)strchr(special_char.ptr,c)) != null)
795                 c = cast(char)('0' + (p - special_char.ptr));
796             else
797             {
798                 CHAR('$');
799                 CHAR('A' + ((c >> 4) & 0x0F));
800                 c = 'A' + (c & 0x0F);
801             }
802         }
803         CHAR(c);
804     }
805     CHAR('@');
806 }
807 
808 private void cpp_dimension(targ_ullong u)
809 {
810     if (u && u <= 10)
811         CHAR('0' + cast(char)u - 1);
812     else
813     {   char[u.sizeof * 2 + 1] buffer = void;
814         char *p;
815 
816         buffer[buffer.length - 1] = 0;
817         for (p = &buffer[buffer.length - 1]; u; u >>= 4)
818         {
819             *--p = 'A' + (u & 0x0F);
820         }
821         STR(p);
822         CHAR('@');
823     }
824 }
825 
826 static if (0)
827 {
828 private void cpp_dimension_ld(targ_ldouble ld)
829 {   ubyte[targ_ldouble.sizeof] ldbuf = void;
830 
831     memcpy(ldbuf.ptr,&ld,ld.sizeof);
832     if (u && u <= 10)
833         CHAR('0' + cast(char)u - 1);
834     else
835     {   char[u.sizeof * 2 + 1] buffer = void;
836         char *p;
837 
838         buffer[buffer.length - 1] = 0;
839         for (p = &buffer[buffer.length - 1]; u; u >>= 4)
840         {
841             *--p = 'A' + (u & 0x0F);
842         }
843         STR(p);
844         CHAR('@');
845     }
846 }
847 }
848 
849 private void cpp_enum_name(Symbol *s)
850 {   type *t;
851     char c;
852 
853     t = tstypes[TYint];
854     switch (tybasic(t.Tty))
855     {
856         case TYschar:   c = '0';        break;
857         case TYuchar:   c = '1';        break;
858         case TYshort:   c = '2';        break;
859         case TYushort:  c = '3';        break;
860         case TYint:     c = '4';        break;
861         case TYuint:    c = '5';        break;
862         case TYlong:    c = '6';        break;
863         case TYulong:   c = '7';        break;
864         default:        assert(0);
865     }
866     CHAR(c);
867     cpp_ecsu_name(s);
868 }
869 
870 private void cpp_reference_data_type(type *t, int flag)
871 {
872     if (tybasic(t.Tty) == TYarray)
873     {
874         int ndim;
875         type *tn;
876         int i;
877 
878         CHAR('Y');
879 
880         // Compute number of dimensions (we have at least one)
881         ndim = 0;
882         tn = t;
883         do
884         {   ndim++;
885             tn = tn.Tnext;
886         } while (tybasic(tn.Tty) == TYarray);
887 
888         cpp_dimension(ndim);
889         for (; tybasic(t.Tty) == TYarray; t = t.Tnext)
890         {
891             if (t.Tflags & TFvla)
892                 CHAR('X');                      // DMC++ extension
893             else
894                 cpp_dimension(t.Tdim);
895         }
896 
897         // DMC++ extension
898         if (flag)                       // if template type argument
899         {
900             i = cpp_cvidx(t.Tty);
901             if (i)
902             {   CHAR('_');
903                 //CHAR('X' + i - 1);            // _X, _Y, _Z
904                 CHAR('O' + i - 1);              // _O, _P, _Q
905             }
906         }
907 
908         cpp_basic_data_type(t);
909     }
910     else
911         cpp_basic_data_type(t);
912 }
913 
914 private void cpp_pointer_data_type(type *t)
915 {
916     if (tybasic(t.Tty) == TYvoid)
917         CHAR('X');
918     else
919         cpp_reference_data_type(t, 0);
920 }
921 
922 private void cpp_ecsu_data_type(type *t)
923 {   char c;
924     Symbol *stag;
925     int i;
926 
927     type_debug(t);
928     switch (tybasic(t.Tty))
929     {
930         case TYstruct:
931             stag = t.Ttag;
932             switch (stag.Sstruct.Sflags & (STRclass | STRunion))
933             {   case 0:         c = 'U';        break;
934                 case STRunion:  c = 'T';        break;
935                 case STRclass:  c = 'V';        break;
936                 default:
937                     assert(0);
938             }
939             CHAR(c);
940             cpp_ecsu_name(stag);
941             break;
942         case TYenum:
943             CHAR('W');
944             cpp_enum_name(t.Ttag);
945             break;
946         default:
947             debug
948             type_print(t);
949 
950             assert(0);
951     }
952 }
953 
954 private void cpp_basic_data_type(type *t)
955 {   char c;
956     int i;
957 
958     //printf("cpp_basic_data_type(t)\n");
959     //type_print(t);
960     switch (tybasic(t.Tty))
961     {
962         case TYschar:   c = 'C';        goto dochar;
963         case TYchar:    c = 'D';        goto dochar;
964         case TYuchar:   c = 'E';        goto dochar;
965         case TYshort:   c = 'F';        goto dochar;
966         case TYushort:  c = 'G';        goto dochar;
967         case TYint:     c = 'H';        goto dochar;
968         case TYuint:    c = 'I';        goto dochar;
969         case TYlong:    c = 'J';        goto dochar;
970         case TYulong:   c = 'K';        goto dochar;
971         case TYfloat:   c = 'M';        goto dochar;
972         case TYdouble:  c = 'N';        goto dochar;
973 
974         case TYdouble_alias:
975                         if (_tysize[TYint] == 4)
976                         {   c = 'O';
977                             goto dochar;
978                         }
979                         c = 'Z';
980                         goto dochar2;
981 
982         case TYldouble:
983                         if (_tysize[TYint] == 2)
984                         {   c = 'O';
985                             goto dochar;
986                         }
987                         c = 'Z';
988                         goto dochar2;
989         dochar:
990             CHAR(c);
991             break;
992 
993         case TYllong:   c = 'J';        goto dochar2;
994         case TYullong:  c = 'K';        goto dochar2;
995         case TYbool:    c = 'N';        goto dochar2;   // was 'X' prior to 8.1b8
996         case TYwchar_t:
997             if (config.flags4 & CFG4nowchar_t)
998             {
999                 c = 'G';
1000                 goto dochar;    // same as TYushort
1001             }
1002             else
1003             {
1004                 pstate.STflags |= PFLmfc;
1005                 c = 'Y';
1006                 goto dochar2;
1007             }
1008 
1009         // Digital Mars extensions
1010         case TYifloat:  c = 'R';        goto dochar2;
1011         case TYidouble: c = 'S';        goto dochar2;
1012         case TYildouble: c = 'T';       goto dochar2;
1013         case TYcfloat:  c = 'U';        goto dochar2;
1014         case TYcdouble: c = 'V';        goto dochar2;
1015         case TYcldouble: c = 'W';       goto dochar2;
1016 
1017         case TYchar16:   c = 'X';       goto dochar2;
1018         case TYdchar:    c = 'Y';       goto dochar2;
1019         case TYnullptr:  c = 'Z';       goto dochar2;
1020 
1021         dochar2:
1022             CHAR('_');
1023             goto dochar;
1024 
1025         case TYsptr:
1026         case TYcptr:
1027         case TYf16ptr:
1028         case TYfptr:
1029         case TYhptr:
1030         case TYvptr:
1031         case TYmemptr:
1032         case TYnptr:
1033         case TYimmutPtr:
1034         case TYsharePtr:
1035         case TYrestrictPtr:
1036         case TYfgPtr:
1037             c = cast(char)('P' + cpp_cvidx(t.Tty));
1038             CHAR(c);
1039             if(I64)
1040                 CHAR('E'); // __ptr64 modifier
1041             cpp_pointer_type(t);
1042             break;
1043         case TYstruct:
1044         case TYenum:
1045             cpp_ecsu_data_type(t);
1046             break;
1047         case TYarray:
1048             i = cpp_cvidx(t.Tty);
1049             i |= 1;                     // always const
1050             CHAR('P' + i);
1051             cpp_pointer_type(t);
1052             break;
1053         case TYvoid:
1054             c = 'X';
1055             goto dochar;
1056 version (SCPPorHTOD)
1057 {
1058         case TYident:
1059             if (pstate.STintemplate)
1060             {
1061                 CHAR('V');              // pretend to be a class name
1062                 cpp_zname(t.Tident);
1063             }
1064             else
1065             {
1066 version (SCPPorHTOD)
1067 {
1068                 cpperr(EM_no_type,t.Tident);   // no type for argument
1069 }
1070                 c = 'X';
1071                 goto dochar;
1072             }
1073             break;
1074         case TYtemplate:
1075             if (pstate.STintemplate)
1076             {
1077                 CHAR('V');              // pretend to be a class name
1078                 cpp_zname((cast(typetemp_t *)t).Tsym.Sident.ptr);
1079             }
1080             else
1081                 goto Ldefault;
1082             break;
1083 }
1084 
1085         default:
1086         Ldefault:
1087             if (tyfunc(t.Tty))
1088                 cpp_function_type(t);
1089             else
1090             {
1091 version (SCPPorHTOD)
1092 {
1093                 debug
1094                 if (!errcnt)
1095                     type_print(t);
1096                 assert(errcnt);
1097 }
1098             }
1099     }
1100 }
1101 
1102 private void cpp_function_indirect_type(type *t)
1103 {   int farfunc;
1104 
1105     farfunc = tyfarfunc(t.Tnext.Tty) != 0;
1106 version (SCPPorHTOD)
1107 {
1108     if (tybasic(t.Tty) == TYmemptr)
1109     {
1110         CHAR('8' + farfunc);
1111         cpp_scope(t.Ttag);
1112         CHAR('@');
1113         //cpp_this_type(t.Tnext,t.Ttag);      // MSC doesn't do this
1114     }
1115     else
1116         CHAR('6' + farfunc);
1117 }
1118 else
1119     CHAR('6' + farfunc);
1120 }
1121 
1122 private void cpp_data_indirect_type(type *t)
1123 {   int i;
1124 version (SCPPorHTOD)
1125 {
1126     if (tybasic(t.Tty) == TYmemptr)    // if pointer to member
1127     {
1128         i = cpp_cvidx(t.Tty);
1129         if (t.Tty & mTYfar)
1130             i += 4;
1131         CHAR('Q' + i);
1132         cpp_scope(t.Ttag);
1133         CHAR('@');
1134     }
1135     else
1136         cpp_ecsu_data_indirect_type(t);
1137 }
1138 else
1139 {
1140     cpp_ecsu_data_indirect_type(t);
1141 }
1142 }
1143 
1144 private void cpp_ecsu_data_indirect_type(type *t)
1145 {   int i;
1146     tym_t ty;
1147 
1148     i = 0;
1149     if (t.Tnext)
1150     {   ty = t.Tnext.Tty & (mTYconst | mTYvolatile);
1151         switch (tybasic(t.Tty))
1152         {
1153             case TYfptr:
1154             case TYvptr:
1155             case TYfref:
1156                 ty |= mTYfar;
1157                 break;
1158 
1159             case TYhptr:
1160                 i += 8;
1161                 break;
1162             case TYref:
1163             case TYarray:
1164                 if (LARGEDATA && !(ty & mTYLINK))
1165                     ty |= mTYfar;
1166                 break;
1167 
1168             default:
1169                 break;
1170         }
1171     }
1172     else
1173         ty = t.Tty & (mTYLINK | mTYconst | mTYvolatile);
1174     i |= cpp_cvidx(ty);
1175     if (ty & (mTYcs | mTYfar))
1176         i += 4;
1177     CHAR('A' + i);
1178 }
1179 
1180 private void cpp_pointer_type(type *t)
1181 {   tym_t ty;
1182 
1183     if (tyfunc(t.Tnext.Tty))
1184     {
1185         cpp_function_indirect_type(t);
1186         cpp_function_type(t.Tnext);
1187     }
1188     else
1189     {
1190         cpp_data_indirect_type(t);
1191         cpp_pointer_data_type(t.Tnext);
1192     }
1193 }
1194 
1195 private void cpp_reference_type(type *t)
1196 {
1197     cpp_data_indirect_type(t);
1198     cpp_reference_data_type(t.Tnext, 0);
1199 }
1200 
1201 private void cpp_primary_data_type(type *t)
1202 {
1203     if (tyref(t.Tty))
1204     {
1205 static if (1)
1206 {
1207         // C++98 8.3.2 says cv-qualified references are ignored
1208         CHAR('A');
1209 }
1210 else
1211 {
1212         switch (t.Tty & (mTYconst | mTYvolatile))
1213         {
1214             case 0:                      CHAR('A');     break;
1215             case mTYvolatile:            CHAR('B');     break;
1216 
1217             // Digital Mars extensions
1218             case mTYconst | mTYvolatile: CHAR('_'); CHAR('L');  break;
1219             case mTYconst:               CHAR('_'); CHAR('M');  break;
1220 
1221             default:
1222                 break;
1223         }
1224 }
1225         cpp_reference_type(t);
1226     }
1227     else
1228         cpp_basic_data_type(t);
1229 }
1230 
1231 /*****
1232  * flag: 1 = template argument
1233  */
1234 
1235 private void cpp_argument_list(type *t, int flag)
1236 {   int i;
1237     tym_t ty;
1238 
1239     //printf("cpp_argument_list(flag = %d)\n", flag);
1240     // If a data type that encodes only into one character
1241     ty = tybasic(t.Tty);
1242     if (ty <= TYldouble && ty != TYenum
1243         && ty != TYbool         // added for versions >= 8.1b9
1244         && !(t.Tty & (mTYconst | mTYvolatile))
1245        )
1246     {
1247         cpp_primary_data_type(t);
1248     }
1249     else
1250     {
1251         // See if a match with a previously used type
1252         for (i = 0; 1; i++)
1253         {
1254             if (i == mangle.argi)               // no match
1255             {
1256                 if (ty <= TYcldouble || ty == TYstruct)
1257                 {
1258                     int cvidx = cpp_cvidx(t.Tty);
1259                     if (cvidx)
1260                     {
1261                         // Digital Mars extensions
1262                         CHAR('_');
1263                         CHAR('N' + cvidx);      // _O, _P, _Q prefix
1264                     }
1265                 }
1266                 if (flag && tybasic(t.Tty) == TYarray)
1267                 {
1268                    cpp_reference_data_type(t, flag);
1269                 }
1270                 else
1271                     cpp_primary_data_type(t);
1272                 if (mangle.argi < 10)
1273                     mangle.arg[mangle.argi++] = t;
1274                 break;
1275             }
1276             if (typematch(t,mangle.arg[i],0))
1277             {
1278                 CHAR('0' + i);          // argument_replicator
1279                 break;
1280             }
1281         }
1282     }
1283 }
1284 
1285 private void cpp_argument_types(type *t)
1286 {   param_t *p;
1287     char c;
1288 
1289     //printf("cpp_argument_types()\n");
1290     //type_debug(t);
1291     for (p = t.Tparamtypes; p; p = p.Pnext)
1292         cpp_argument_list(p.Ptype, 0);
1293     if (t.Tflags & TFfixed)
1294         c = t.Tparamtypes ? '@' : 'X';
1295     else
1296         c = 'Z';
1297     CHAR(c);
1298 }
1299 
1300 private void cpp_calling_convention(type *t)
1301 {   char c;
1302 
1303     switch (tybasic(t.Tty))
1304     {
1305         case TYnfunc:
1306         case TYhfunc:
1307         case TYffunc:
1308             c = 'A';        break;
1309         case TYf16func:
1310         case TYfpfunc:
1311         case TYnpfunc:
1312             c = 'C';        break;
1313         case TYnsfunc:
1314         case TYfsfunc:
1315             c = 'G';        break;
1316         case TYjfunc:
1317         case TYmfunc:
1318         case TYnsysfunc:
1319         case TYfsysfunc:
1320             c = 'E';       break;
1321         case TYifunc:
1322             c = 'K';        break;
1323         default:
1324             assert(0);
1325     }
1326     CHAR(c);
1327 }
1328 
1329 private void cpp_vcall_model_type()
1330 {
1331 }
1332 
1333 version (SCPPorMARS)
1334 {
1335 
1336 private void cpp_this_type(type *tfunc,Classsym *stag)
1337 {   type *t;
1338 
1339     type_debug(tfunc);
1340     symbol_debug(stag);
1341 
1342 version (MARS)
1343     t = type_pointer(stag.Stype);
1344 else
1345     t = cpp_thistype(tfunc,stag);
1346 
1347     //cpp_data_indirect_type(t);
1348     cpp_ecsu_data_indirect_type(t);
1349     type_free(t);
1350 }
1351 
1352 }
1353 
1354 private void cpp_storage_convention(Symbol *s)
1355 {   tym_t ty;
1356     type *t = s.Stype;
1357 
1358     ty = t.Tty;
1359     if (LARGEDATA && !(ty & mTYLINK))
1360         t.Tty |= mTYfar;
1361     cpp_data_indirect_type(t);
1362     t.Tty = ty;
1363 }
1364 
1365 private void cpp_data_type(type *t)
1366 {
1367     type_debug(t);
1368     switch (tybasic(t.Tty))
1369     {   case TYvoid:
1370             CHAR('X');
1371             break;
1372         case TYstruct:
1373         case TYenum:
1374             CHAR('?');
1375             cpp_ecsu_data_indirect_type(t);
1376             cpp_ecsu_data_type(t);
1377             break;
1378         default:
1379             cpp_primary_data_type(t);
1380             break;
1381     }
1382 }
1383 
1384 private void cpp_return_type(Symbol *s)
1385 {
1386     if (s.Sfunc.Fflags & (Fctor | Fdtor))     // if ctor or dtor
1387         CHAR('@');                              // no type
1388     else
1389         cpp_data_type(s.Stype.Tnext);
1390 }
1391 
1392 private void cpp_ecsu_name(Symbol *s)
1393 {
1394     //printf("cpp_ecsu_name(%s)\n", symbol_ident(s));
1395     cpp_zname(symbol_ident(s));
1396 version (SCPPorMARS)
1397 {
1398     if (s.Sscope)
1399         cpp_scope(s.Sscope);
1400 }
1401     CHAR('@');
1402 }
1403 
1404 private void cpp_throw_types(type *t)
1405 {
1406     //cpp_argument_types(?);
1407     CHAR('Z');
1408 }
1409 
1410 private void cpp_function_type(type *t)
1411 {   tym_t ty;
1412     type *tn;
1413 
1414     //printf("cpp_function_type()\n");
1415     //type_debug(t);
1416     assert(tyfunc(t.Tty));
1417     cpp_calling_convention(t);
1418     //cpp_return_type(s);
1419     tn = t.Tnext;
1420     ty = tn.Tty;
1421     if (LARGEDATA && (tybasic(ty) == TYstruct || tybasic(ty) == TYenum) &&
1422         !(ty & mTYLINK))
1423         tn.Tty |= mTYfar;
1424     cpp_data_type(tn);
1425     tn.Tty = ty;
1426     cpp_argument_types(t);
1427     cpp_throw_types(t);
1428 }
1429 
1430 private void cpp_adjustor_thunk_type(Symbol *s)
1431 {
1432 }
1433 
1434 private void cpp_vftable_type(Symbol *s)
1435 {
1436     cpp_ecsu_data_indirect_type(s.Stype);
1437 //      vpath_name();
1438     CHAR('@');
1439 }
1440 
1441 private void cpp_local_static_data_type(Symbol *s)
1442 {
1443     //cpp_lexical_frame(?);
1444     cpp_external_data_type(s);
1445 }
1446 
1447 private void cpp_static_member_data_type(Symbol *s)
1448 {
1449     cpp_external_data_type(s);
1450 }
1451 
1452 private void cpp_static_member_function_type(Symbol *s)
1453 {
1454     cpp_function_type(s.Stype);
1455 }
1456 
1457 version (SCPPorMARS)
1458 {
1459 private void cpp_member_function_type(Symbol *s)
1460 {
1461     assert(tyfunc(s.Stype.Tty));
1462     cpp_this_type(s.Stype,cast(Classsym *)s.Sscope);
1463     if (s.Sfunc.Fflags & (Fctor | Fdtor))
1464     {   type *t = s.Stype;
1465 
1466         cpp_calling_convention(t);
1467         CHAR('@');                      // return_type for ctors & dtors
1468         cpp_argument_types(t);
1469         cpp_throw_types(t);
1470     }
1471     else
1472         cpp_static_member_function_type(s);
1473 }
1474 }
1475 
1476 private void cpp_external_data_type(Symbol *s)
1477 {
1478     cpp_primary_data_type(s.Stype);
1479     cpp_storage_convention(s);
1480 }
1481 
1482 private void cpp_external_function_type(Symbol *s)
1483 {
1484     cpp_function_type(s.Stype);
1485 }
1486 
1487 private void cpp_type_encoding(Symbol *s)
1488 {   char c;
1489 
1490     //printf("cpp_type_encoding()\n");
1491     if (tyfunc(s.Stype.Tty))
1492     {   int farfunc;
1493 
1494         farfunc = tyfarfunc(s.Stype.Tty) != 0;
1495 version (SCPPorMARS)
1496 {
1497         if (isclassmember(s))
1498         {   // Member function
1499             int protection;
1500             int ftype;
1501 
1502             protection = cpp_protection(s);
1503             if (s.Sfunc.Fthunk && !(s.Sfunc.Fflags & Finstance))
1504                 ftype = 3;
1505             else
1506                 switch (s.Sfunc.Fflags & (Fvirtual | Fstatic))
1507                 {   case Fvirtual:      ftype = 2;      break;
1508                     case Fstatic:       ftype = 1;      break;
1509                     case 0:             ftype = 0;      break;
1510                     default:            assert(0);
1511                 }
1512             CHAR('A' + farfunc + protection * 8 + ftype * 2);
1513             switch (ftype)
1514             {   case 0: cpp_member_function_type(s);            break;
1515                 case 1: cpp_static_member_function_type(s);     break;
1516                 case 2: cpp_member_function_type(s);            break;
1517                 case 3: cpp_adjustor_thunk_type(s);             break;
1518                 default:
1519                     break;
1520             }
1521         }
1522         else
1523         {   // Non-member function
1524             CHAR('Y' + farfunc);
1525             cpp_external_function_type(s);
1526         }
1527 }
1528 else
1529 {
1530         // Non-member function
1531         CHAR('Y' + farfunc);
1532         cpp_external_function_type(s);
1533 }
1534     }
1535     else
1536     {
1537 version (SCPPorMARS)
1538 {
1539         if (isclassmember(s))
1540         {
1541             // Static data member
1542             CHAR(cpp_protection(s) + '0');
1543             cpp_static_member_data_type(s);
1544         }
1545         else
1546         {
1547             if (s.Sclass == SCstatic ||
1548                 (s.Sscope &&
1549                  s.Sscope.Sclass != SCstruct &&
1550                  s.Sscope.Sclass != SCnamespace))
1551             {
1552                 CHAR('4');
1553                 cpp_local_static_data_type(s);
1554             }
1555             else
1556             {
1557                 CHAR('3');
1558                 cpp_external_data_type(s);
1559             }
1560         }
1561 }
1562 else
1563 {
1564         if (s.Sclass == SCstatic)
1565         {
1566             CHAR('4');
1567             cpp_local_static_data_type(s);
1568         }
1569         else
1570         {
1571             CHAR('3');
1572             cpp_external_data_type(s);
1573         }
1574 }
1575     }
1576 }
1577 
1578 private void cpp_scope(Symbol *s)
1579 {
1580     /*  scope ::=
1581                 zname [ scope ]
1582                 '?' decorated_name [ scope ]
1583                 '?' lexical_frame [ scope ]
1584                 '?' '$' template_name [ scope ]
1585      */
1586     while (s)
1587     {   char *p;
1588 
1589         symbol_debug(s);
1590         switch (s.Sclass)
1591         {
1592             case SCnamespace:
1593                 cpp_zname(s.Sident.ptr);
1594                 break;
1595 
1596             case SCstruct:
1597                 cpp_zname(symbol_ident(s));
1598                 break;
1599 
1600             default:
1601                 STR("?1?");                     // Why? Who knows.
1602                 cpp_decorated_name(s);
1603                 break;
1604         }
1605 
1606 version (SCPPorMARS)
1607         s = s.Sscope;
1608 else
1609         break;
1610 
1611     }
1612 }
1613 
1614 private void cpp_zname(const(char)* p)
1615 {
1616     //printf("cpp_zname(%s)\n", p);
1617     if (*p != '?' ||                            // if not operator_name
1618         (NEWTEMPMANGLE && p[1] == '$'))         // ?$ is a template name
1619     {
1620 version (MARS)
1621 {
1622         /* Scan forward past any dots
1623          */
1624         for (const(char)* q = p; *q; q++)
1625         {
1626             if (*q == '.')
1627                 p = q + 1;
1628         }
1629 }
1630 
1631         for (int i = 0; i < mangle.znamei; i++)
1632         {
1633             if (strcmp(p,mangle.zname[i]) == 0)
1634             {   CHAR('0' + i);
1635                 return;
1636             }
1637         }
1638         if (mangle.znamei < 10)
1639             mangle.zname[mangle.znamei++] = p;
1640         STR(p);
1641         CHAR('@');
1642     }
1643     else if (p[1] == 'B')
1644         STR("?B");                      // skip return value encoding
1645     else
1646     {
1647         STR(p);
1648     }
1649 }
1650 
1651 private void cpp_symbol_name(Symbol *s)
1652 {   char *p;
1653 
1654     p = s.Sident.ptr;
1655 version (SCPPorHTOD)
1656 {
1657     if (tyfunc(s.Stype.Tty) && s.Sfunc)
1658     {
1659         if (s.Sfunc.Fflags & Finstance)
1660         {
1661             Mangle save = mangle;
1662             char *q;
1663             int len;
1664 
1665             p = template_mangle(s, s.Sfunc.Fptal);
1666             len = strlen(p);
1667             q = cast(char *)alloca(len + 1);
1668             assert(q);
1669             memcpy(q, p, len + 1);
1670             mangle = save;
1671             p = q;
1672         }
1673         else if (s.Sfunc.Fflags & Foperator)
1674         {   // operator_name ::= '?' operator_code
1675             //CHAR('?');                        // already there
1676             STR(p);
1677             return;
1678         }
1679     }
1680 }
1681 version (none) //#if MARS && 0
1682 {
1683     //It mangles correctly, but the ABI doesn't match,
1684     // leading to copious segfaults. At least with the
1685     // wrong mangling you get link errors.
1686     if (tyfunc(s.Stype.Tty) && s.Sfunc)
1687     {
1688         if (s.Sfunc.Fflags & Fctor)
1689         {
1690             cpp_zname(cpp_name_ct);
1691             return;
1692         }
1693         if (s.Sfunc.Fflags & Fdtor)
1694         {
1695             cpp_zname(cpp_name_dt);
1696             return;
1697         }
1698     }
1699 }
1700     cpp_zname(p);
1701 }
1702 
1703 private void cpp_decorated_name(Symbol *s)
1704 {   char *p;
1705 
1706     CHAR('?');
1707     cpp_symbol_name(s);
1708 version (SCPPorMARS)
1709 {
1710     if (s.Sscope)
1711         cpp_scope(s.Sscope);
1712 }
1713     CHAR('@');
1714     cpp_type_encoding(s);
1715 }
1716 
1717 /*********************************
1718  * Mangle a vtbl or vbtbl name.
1719  * Returns:
1720  *      pointer to generated symbol with mangled name
1721  */
1722 
1723 version (SCPPorHTOD)
1724 {
1725 
1726 Symbol *mangle_tbl(
1727         int flag,       // 0: vtbl, 1: vbtbl
1728         type *t,        // type for symbol
1729         Classsym *stag, // class we're putting tbl in
1730         baseclass_t *b) // base class (null if none)
1731 {   const(char)* id;
1732     Symbol *s;
1733 
1734 static if (0)
1735 {
1736     printf("mangle_tbl(stag = '%s', sbase = '%s', parent = '%s')\n",
1737         stag.Sident.ptr,b ? b.BCbase.Sident.ptr : "null", b ? b.parent.Sident.ptr : "null");
1738 }
1739     if (flag == 0)
1740         id = config.flags3 & CFG3rtti ? "?_Q" : "?_7";
1741     else
1742         id = "?_8";
1743     MangleInuse m;
1744     mangle.znamei = 0;
1745     mangle.argi = 0;
1746     mangle.np = mangle.buf.ptr;
1747     CHAR('?');
1748     cpp_zname(id);
1749     cpp_scope(stag);
1750     CHAR('@');
1751     CHAR('6' + flag);
1752     cpp_ecsu_data_indirect_type(t);
1753 static if (1)
1754 {
1755     while (b)
1756     {
1757         cpp_scope(b.BCbase);
1758         CHAR('@');
1759         b = b.BCpbase;
1760     }
1761 }
1762 else
1763 {
1764     if (b)
1765     {   cpp_scope(b.BCbase);
1766         CHAR('@');
1767         // BUG: what if b is more than one level down?
1768         if (b.parent != stag)
1769         {   cpp_scope(b.BCparent);
1770             CHAR('@');
1771         }
1772     }
1773 }
1774     CHAR('@');
1775     *mangle.np = 0;                     // 0-terminate mangle.buf[]
1776     assert(strlen(mangle.buf.ptr) <= BUFIDMAX);
1777     s = scope_define(mangle.buf.ptr,SCTglobal | SCTnspace | SCTlocal,SCunde);
1778     s.Stype = t;
1779     t.Tcount++;
1780     return s;
1781 }
1782 
1783 }
1784 
1785 }