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