1 /**
2  * Do mangling for C++ linkage.
3  *
4  * This is the POSIX side of the implementation.
5  * It exports two functions to C++, `toCppMangleItanium` and `cppTypeInfoMangleItanium`.
6  *
7  * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
8  * Authors: Walter Bright, https://www.digitalmars.com
9  * License:   $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
10  * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cppmangle.d, _cppmangle.d)
11  * Documentation:  https://dlang.org/phobos/dmd_cppmangle.html
12  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cppmangle.d
13  *
14  * References:
15  *  Follows Itanium C++ ABI 1.86 section 5.1
16  *  http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling
17  *  which is where the grammar comments come from.
18  *
19  * Bugs:
20  *  https://issues.dlang.org/query.cgi
21  *  enter `C++, mangling` as the keywords.
22  */
23 
24 module dmd.cppmangle;
25 
26 import core.stdc.string;
27 import core.stdc.stdio;
28 
29 import dmd.arraytypes;
30 import dmd.astenums;
31 import dmd.attrib;
32 import dmd.declaration;
33 import dmd.dsymbol;
34 import dmd.dtemplate;
35 import dmd.errors;
36 import dmd.expression;
37 import dmd.func;
38 import dmd.globals;
39 import dmd.id;
40 import dmd.identifier;
41 import dmd.location;
42 import dmd.mtype;
43 import dmd.nspace;
44 import dmd.root.array;
45 import dmd.common.outbuffer;
46 import dmd.root.rootobject;
47 import dmd.root.string;
48 import dmd.target;
49 import dmd.tokens;
50 import dmd.typesem;
51 import dmd.visitor;
52 
53 
54 // helper to check if an identifier is a C++ operator
55 enum CppOperator { Cast, Assign, Eq, Index, Call, Unary, Binary, OpAssign, Unknown }
56 package CppOperator isCppOperator(Identifier id)
57 {
58     __gshared const(Identifier)[] operators = null;
59     if (!operators)
60         operators = [Id._cast, Id.assign, Id.eq, Id.index, Id.call, Id.opUnary, Id.opBinary, Id.opOpAssign];
61     foreach (i, op; operators)
62     {
63         if (op == id)
64             return cast(CppOperator)i;
65     }
66     return CppOperator.Unknown;
67 }
68 
69 ///
70 extern(C++) const(char)* toCppMangleItanium(Dsymbol s)
71 {
72     //printf("toCppMangleItanium(%s)\n", s.toChars());
73     OutBuffer buf;
74     scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc);
75     v.mangleOf(s);
76     return buf.extractChars();
77 }
78 
79 ///
80 extern(C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s)
81 {
82     //printf("cppTypeInfoMangle(%s)\n", s.toChars());
83     OutBuffer buf;
84     buf.writestring("_ZTI");    // "TI" means typeinfo structure
85     scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc);
86     v.cpp_mangle_name(s, false);
87     return buf.extractChars();
88 }
89 
90 ///
91 extern(C++) const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
92 {
93     //printf("cppThunkMangleItanium(%s)\n", fd.toChars());
94     OutBuffer buf;
95     buf.printf("_ZThn%u_", offset);  // "Th" means thunk, "n%u" is the call offset
96     scope CppMangleVisitor v = new CppMangleVisitor(&buf, fd.loc);
97     v.mangle_function_encoding(fd);
98     return buf.extractChars();
99 }
100 
101 /******************************
102  * Determine if sym is a full aggregate destructor.
103  * Params:
104  *      sym = Dsymbol
105  * Returns:
106  *      true if sym is an aggregate destructor
107  */
108 bool isAggregateDtor(const Dsymbol sym)
109 {
110     const dtor = sym.isDtorDeclaration();
111     if (!dtor)
112         return false;
113     const ad = dtor.isMember();
114     assert(ad);
115     return dtor == ad.aggrDtor;
116 }
117 
118 /// Context used when processing pre-semantic AST
119 private struct Context
120 {
121     /// Template instance of the function being mangled
122     TemplateInstance ti;
123     /// Function declaration we're mangling
124     FuncDeclaration fd;
125     /// Current type / expression being processed (semantically analyzed)
126     RootObject res;
127 
128     @disable ref Context opAssign(ref Context other);
129     @disable ref Context opAssign(Context other);
130 
131     /**
132      * Helper function to track `res`
133      *
134      * Params:
135      *   next = Value to set `this.res` to.
136      *          If `this.res` is `null`, the expression is not evalutated.
137      *          This allow this code to be used even when no context is needed.
138      *
139      * Returns:
140      *   The previous state of this `Context` object
141      */
142     private Context push(lazy RootObject next)
143     {
144         auto r = this.res;
145         if (r !is null)
146             this.res = next;
147         return Context(this.ti, this.fd, r);
148     }
149 
150     /**
151      * Reset the context to a previous one, making any adjustment necessary
152      */
153     private void pop(ref Context prev)
154     {
155         this.res = prev.res;
156     }
157 }
158 
159 private final class CppMangleVisitor : Visitor
160 {
161     /// Context used when processing pre-semantic AST
162     private Context context;
163 
164     ABITagContainer abiTags;    /// Container for already-written ABI tags
165     Objects components;         /// array of components available for substitution
166     OutBuffer* buf;             /// append the mangling to buf[]
167     Loc loc;                    /// location for use in error messages
168 
169     /**
170      * Constructor
171      *
172      * Params:
173      *   buf = `OutBuffer` to write the mangling to
174      *   loc = `Loc` of the symbol being mangled
175      */
176     this(OutBuffer* buf, Loc loc) scope
177     {
178         this.buf = buf;
179         this.loc = loc;
180     }
181 
182     /*****
183      * Entry point. Append mangling to buf[]
184      * Params:
185      *  s = symbol to mangle
186      */
187     void mangleOf(Dsymbol s)
188     {
189         if (VarDeclaration vd = s.isVarDeclaration())
190         {
191             mangle_variable(vd, vd.cppnamespace !is null);
192         }
193         else if (FuncDeclaration fd = s.isFuncDeclaration())
194         {
195             mangle_function(fd);
196         }
197         else
198         {
199             assert(0);
200         }
201     }
202 
203     /**
204      * Mangle the return type of a function
205      *
206      * This is called on a templated function type.
207      * Context is set to the `FuncDeclaration`.
208      *
209      * Params:
210      *   preSemantic = the `FuncDeclaration`'s `originalType`
211      */
212     void mangleReturnType(TypeFunction preSemantic)
213     {
214         auto tf = this.context.res.asFuncDecl().type.isTypeFunction();
215         Type rt = preSemantic.nextOf();
216         // https://issues.dlang.org/show_bug.cgi?id=22739
217         // auto return type means that rt is null.
218         // if so, just pick up the type from the instance
219         if (!rt)
220             rt = tf.nextOf();
221         if (tf.isref)
222             rt = rt.referenceTo();
223         auto prev = this.context.push(tf.nextOf());
224         scope (exit) this.context.pop(prev);
225         this.headOfType(rt);
226     }
227 
228     /**
229      * Write a seq-id from an index number, excluding the terminating '_'
230      *
231      * Params:
232      *   idx = the index in a substitution list.
233      *         Note that index 0 has no value, and `S0_` would be the
234      *         substitution at index 1 in the list.
235      *
236      * See-Also:
237      *  https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.seq-id
238      */
239     private void writeSequenceFromIndex(size_t idx)
240     {
241         if (idx)
242         {
243             void write_seq_id(size_t i)
244             {
245                 if (i >= 36)
246                 {
247                     write_seq_id(i / 36);
248                     i %= 36;
249                 }
250                 i += (i < 10) ? '0' : 'A' - 10;
251                 buf.writeByte(cast(char)i);
252             }
253 
254             write_seq_id(idx - 1);
255         }
256     }
257 
258     /**
259      * Attempt to perform substitution on `p`
260      *
261      * If `p` already appeared in the mangling, it is stored as
262      * a 'part', and short references in the form of `SX_` can be used.
263      * Note that `p` can be anything: template declaration, struct declaration,
264      * class declaration, namespace...
265      *
266      * Params:
267      *   p = The object to attempt to substitute
268      *   nested = Whether or not `p` is to be considered nested.
269      *            When `true`, `N` will be prepended before the substitution.
270      *
271      * Returns:
272      *   Whether `p` already appeared in the mangling,
273      *   and substitution has been written to `this.buf`.
274      */
275     bool substitute(RootObject p, bool nested = false)
276     {
277         //printf("substitute %s\n", p ? p.toChars() : null);
278         auto i = find(p);
279         if (i < 0)
280             return false;
281 
282         //printf("\tmatch\n");
283         /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
284          */
285         if (nested)
286             buf.writeByte('N');
287         buf.writeByte('S');
288         writeSequenceFromIndex(i);
289         buf.writeByte('_');
290         return true;
291     }
292 
293     /******
294      * See if `p` exists in components[]
295      *
296      * Note that components can contain `null` entries,
297      * as the index used in mangling is based on the index in the array.
298      *
299      * If called with an object whose dynamic type is `Nspace`,
300      * calls the `find(Nspace)` overload.
301      *
302      * Returns:
303      *  index if found, -1 if not
304      */
305     int find(RootObject p)
306     {
307         //printf("find %p %d %s\n", p, p.dyncast(), p ? p.toChars() : null);
308         scope v = new ComponentVisitor(p);
309         foreach (i, component; components)
310         {
311             if (component)
312                 component.visitObject(v);
313             if (v.result)
314                 return cast(int)i;
315         }
316         return -1;
317     }
318 
319     /*********************
320      * Append p to components[]
321      */
322     void append(RootObject p)
323     {
324         //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null");
325         components.push(p);
326     }
327 
328     /**
329      * Write an identifier preceded by its length
330      *
331      * Params:
332      *   ident = `Identifier` to write to `this.buf`
333      */
334     void writeIdentifier(const ref Identifier ident)
335     {
336         const name = ident.toString();
337         this.buf.print(name.length);
338         this.buf.writestring(name);
339     }
340 
341     /**
342      * Insert the leftover ABI tags to the buffer
343      *
344      * This inset ABI tags that hasn't already been written
345      * after the mangled name of the function.
346      * For more details, see the `abiTags` variable.
347      *
348      * Params:
349      *   off  = Offset to insert at
350      *   tf   = Type of the function to mangle the return type of
351      */
352     void writeRemainingTags(size_t off, TypeFunction tf)
353     {
354         Array!StringExp toWrite;
355         leftOver(tf, &this.abiTags.written, &toWrite);
356         OutBuffer b2;
357         foreach (se; toWrite)
358         {
359             auto tag = se.peekString();
360             // We can only insert a slice, and each insert is a memmove,
361             // so use a temporary buffer to keep it efficient.
362             b2.reset();
363             b2.writestring("B");
364             b2.print(tag.length);
365             b2.writestring(tag);
366             this.buf.insert(off, b2[]);
367             off += b2.length;
368         }
369     }
370 
371     /************************
372      * Determine if symbol is indeed the global ::std namespace.
373      * Params:
374      *  s = symbol to check
375      * Returns:
376      *  true if it is ::std
377      */
378     static bool isStd(Dsymbol s)
379     {
380         if (!s)
381             return false;
382 
383         if (auto cnd = s.isCPPNamespaceDeclaration())
384             return isStd(cnd);
385 
386         return (s.ident == Id.std &&    // the right name
387                 s.isNspace() &&         // g++ disallows global "std" for other than a namespace
388                 !getQualifier(s));      // at global level
389     }
390 
391     /// Ditto
392     static bool isStd(CPPNamespaceDeclaration s)
393     {
394         return s && s.cppnamespace is null && s.ident == Id.std;
395     }
396 
397     /************************
398      * Determine if type is a C++ fundamental type.
399      * Params:
400      *  t = type to check
401      * Returns:
402      *  true if it is a fundamental type
403      */
404     static bool isFundamentalType(Type t)
405     {
406         // First check the target whether some specific ABI is being followed.
407         bool isFundamental = void;
408         if (target.cpp.fundamentalType(t, isFundamental))
409             return isFundamental;
410 
411         if (auto te = t.isTypeEnum())
412         {
413             // Peel off enum type from special types.
414             if (te.sym.isSpecial())
415                 t = te.memType();
416         }
417 
418         // Fundamental arithmetic types:
419         // 1. integral types: bool, char, int, ...
420         // 2. floating point types: float, double, real
421         // 3. void
422         // 4. null pointer: std::nullptr_t (since C++11)
423         if (t.ty == Tvoid || t.ty == Tbool)
424             return true;
425         else if (t.ty == Tnull && global.params.cplusplus >= CppStdRevision.cpp11)
426             return true;
427         else
428             return t.isTypeBasic() && (t.isintegral() || t.isreal());
429     }
430 
431     /******************************
432      * Write the mangled representation of a template argument.
433      * Params:
434      *  ti  = the template instance
435      *  arg = the template argument index
436      */
437     void template_arg(TemplateInstance ti, size_t arg)
438     {
439         TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
440         assert(td);
441         TemplateParameter tp = (*td.parameters)[arg];
442         RootObject o = (*ti.tiargs)[arg];
443 
444         auto prev = this.context.push({
445                 TemplateInstance parentti;
446                 if (this.context.res.dyncast() == DYNCAST.dsymbol)
447                     parentti = this.context.res.asFuncDecl().parent.isTemplateInstance();
448                 else
449                 {
450                     auto parent = this.context.res.asType().toDsymbol(null).parent;
451                     parentti = parent.isTemplateInstance();
452                     // https://issues.dlang.org/show_bug.cgi?id=22760
453                     // The template instance may sometimes have the form
454                     // S1!int.S1, therefore the above instruction might yield null
455                     if (parentti is null && parent.parent)
456                         parentti = parent.parent.isTemplateInstance();
457                 }
458                 return (*parentti.tiargs)[arg];
459             }());
460         scope (exit) this.context.pop(prev);
461 
462         if (tp.isTemplateTypeParameter())
463         {
464             Type t = isType(o);
465             assert(t);
466             t.accept(this);
467         }
468         else if (TemplateValueParameter tv = tp.isTemplateValueParameter())
469         {
470             // <expr-primary> ::= L <type> <value number> E  # integer literal
471             if (tv.valType.isintegral())
472             {
473                 Expression e = isExpression(o);
474                 assert(e);
475                 buf.writeByte('L');
476                 tv.valType.accept(this);
477                 auto val = e.toUInteger();
478                 if (!tv.valType.isunsigned() && cast(sinteger_t)val < 0)
479                 {
480                     val = -val;
481                     buf.writeByte('n');
482                 }
483                 buf.print(val);
484                 buf.writeByte('E');
485             }
486             else
487             {
488                 ti.error("internal compiler error: C++ `%s` template value parameter is not supported", tv.valType.toChars());
489                 fatal();
490             }
491         }
492         else if (tp.isTemplateAliasParameter())
493         {
494             // Passing a function as alias parameter is the same as passing
495             // `&function`
496             Dsymbol d = isDsymbol(o);
497             Expression e = isExpression(o);
498             if (d && d.isFuncDeclaration())
499             {
500                 // X .. E => template parameter is an expression
501                 // 'ad'   => unary operator ('&')
502                 // L .. E => is a <expr-primary>
503                 buf.writestring("XadL");
504                 mangle_function(d.isFuncDeclaration());
505                 buf.writestring("EE");
506             }
507             else if (e && e.isVarExp() && e.isVarExp().var.isVarDeclaration())
508             {
509                 VarDeclaration vd = e.isVarExp().var.isVarDeclaration();
510                 buf.writeByte('L');
511                 mangle_variable(vd, true);
512                 buf.writeByte('E');
513             }
514             else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember)
515             {
516                 if (!substitute(d))
517                 {
518                     cpp_mangle_name(d, false);
519                 }
520             }
521             else
522             {
523                 ti.error("internal compiler error: C++ `%s` template alias parameter is not supported", o.toChars());
524                 fatal();
525             }
526         }
527         else if (tp.isTemplateThisParameter())
528         {
529             ti.error("internal compiler error: C++ `%s` template this parameter is not supported", o.toChars());
530             fatal();
531         }
532         else
533         {
534             assert(0);
535         }
536     }
537 
538     /******************************
539      * Write the mangled representation of the template arguments.
540      * Params:
541      *  ti = the template instance
542      *  firstArg = index of the first template argument to mangle
543      *             (used for operator overloading)
544      * Returns:
545      *  true if any arguments were written
546      */
547     bool template_args(TemplateInstance ti, int firstArg = 0)
548     {
549         /* <template-args> ::= I <template-arg>+ E
550          */
551         if (!ti || ti.tiargs.length <= firstArg)   // could happen if std::basic_string is not a template
552             return false;
553         buf.writeByte('I');
554         foreach (i; firstArg .. ti.tiargs.length)
555         {
556             TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
557             assert(td);
558             TemplateParameter tp = (*td.parameters)[i];
559 
560             /*
561              * <template-arg> ::= <type>               # type or template
562              *                ::= X <expression> E     # expression
563              *                ::= <expr-primary>       # simple expressions
564              *                ::= J <template-arg>* E  # argument pack
565              *
566              * Reference: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.template-arg
567              */
568             if (TemplateTupleParameter tt = tp.isTemplateTupleParameter())
569             {
570                 buf.writeByte('J');     // argument pack
571 
572                 // mangle the rest of the arguments as types
573                 foreach (j; i .. (*ti.tiargs).length)
574                 {
575                     Type t = isType((*ti.tiargs)[j]);
576                     if (t is null)
577                     {
578                         ti.error("internal compiler error: C++ `%s` template value parameter is not supported", (*ti.tiargs)[j].toChars());
579                         fatal();
580                     }
581                     t.accept(this);
582                 }
583 
584                 buf.writeByte('E');
585                 break;
586             }
587 
588             template_arg(ti, i);
589         }
590         buf.writeByte('E');
591         return true;
592     }
593 
594     /**
595      * Write the symbol `p` if not null, then execute the delegate
596      *
597      * Params:
598      *   p = Symbol to write
599      *   dg = Delegate to execute
600      */
601     void writeChained(Dsymbol p, scope void delegate() dg)
602     {
603         if (p && !p.isModule())
604         {
605             buf.writestring("N");
606             source_name(p, true);
607             dg();
608             buf.writestring("E");
609         }
610         else
611             dg();
612     }
613 
614     /**
615      * Write the name of `s` to the buffer
616      *
617      * Params:
618      *   s = Symbol to write the name of
619      *   haveNE = Whether `N..E` is already part of the mangling
620      *            Because `Nspace` and `CPPNamespaceAttribute` can be
621      *            mixed, this is a mandatory hack.
622      */
623     void source_name(Dsymbol s, bool haveNE = false)
624     {
625         version (none)
626         {
627             printf("source_name(%s)\n", s.toChars());
628             auto sl = this.buf.peekSlice();
629             assert(sl.length == 0 || haveNE || s.cppnamespace is null || sl != "_ZN");
630         }
631         auto ti = s.isTemplateInstance();
632 
633         if (!ti)
634         {
635             auto ag = s.isAggregateDeclaration();
636             const ident = (ag && ag.pMangleOverride) ? ag.pMangleOverride.id : s.ident;
637             this.writeNamespace(s.cppnamespace, () {
638                 this.writeIdentifier(ident);
639                 this.abiTags.writeSymbol(s, this);
640                 },
641                 haveNE);
642             return;
643         }
644 
645         bool needsTa = false;
646 
647         // https://issues.dlang.org/show_bug.cgi?id=20413
648         // N..E is not needed when substituting members of the std namespace.
649         // This is observed in the GCC and Clang implementations.
650         // The Itanium specification is not clear enough on this specific case.
651         // References:
652         //   https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.name
653         //   https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression
654         Dsymbol q = getQualifier(ti.tempdecl);
655         Dsymbol ns = ti.tempdecl.cppnamespace;
656         const inStd = ns && isStd(ns) || q && isStd(q);
657         const isNested = !inStd && (ns || q);
658 
659         if (substitute(ti.tempdecl, !haveNE && isNested))
660         {
661             template_args(ti);
662             if (!haveNE && isNested)
663                 buf.writeByte('E');
664             return;
665         }
666         else if (this.writeStdSubstitution(ti, needsTa))
667         {
668             this.abiTags.writeSymbol(ti, this);
669             if (needsTa)
670                 template_args(ti);
671             return;
672         }
673 
674         auto ag = ti.aliasdecl ? ti.aliasdecl.isAggregateDeclaration() : null;
675         if (ag && ag.pMangleOverride)
676         {
677             this.writeNamespace(
678                 ti.toAlias().cppnamespace, () {
679                     this.writeIdentifier(ag.pMangleOverride.id);
680                     if (ag.pMangleOverride.agg && ag.pMangleOverride.agg.isInstantiated())
681                     {
682                         auto to = ag.pMangleOverride.agg.isInstantiated();
683                         append(to);
684                         this.abiTags.writeSymbol(to.tempdecl, this);
685                         template_args(to);
686                     }
687               }, haveNE);
688         }
689         else
690         {
691             this.writeNamespace(
692                 s.cppnamespace, () {
693                     this.writeIdentifier(ti.tempdecl.toAlias().ident);
694                     append(ti.tempdecl);
695                     this.abiTags.writeSymbol(ti.tempdecl, this);
696                     template_args(ti);
697                 }, haveNE);
698         }
699     }
700 
701     /********
702      * See if s is actually an instance of a template
703      * Params:
704      *  s = symbol
705      * Returns:
706      *  if s is instance of a template, return the instance, otherwise return s
707      */
708     static Dsymbol getInstance(Dsymbol s)
709     {
710         Dsymbol p = s.toParent();
711         if (p)
712         {
713             if (TemplateInstance ti = p.isTemplateInstance())
714                 return ti;
715         }
716         return s;
717     }
718 
719     /// Get the namespace of a template instance
720     CPPNamespaceDeclaration getTiNamespace(TemplateInstance ti)
721     {
722         // If we receive a pre-semantic `TemplateInstance`,
723         // `cppnamespace` is always `null`
724         return ti.tempdecl ? ti.cppnamespace
725             : this.context.res.asType().toDsymbol(null).cppnamespace;
726     }
727 
728     /********
729      * Get qualifier for `s`, meaning the symbol
730      * that s is in the symbol table of.
731      * The module does not count as a qualifier, because C++
732      * does not have modules.
733      * Params:
734      *  s = symbol that may have a qualifier
735      *      s is rewritten to be TemplateInstance if s is one
736      * Returns:
737      *  qualifier, null if none
738      */
739     static Dsymbol getQualifier(Dsymbol s)
740     {
741         Dsymbol p = s.toParent();
742         return (p && !p.isModule()) ? p : null;
743     }
744 
745     // Detect type char
746     static bool isChar(RootObject o)
747     {
748         Type t = isType(o);
749         return (t && t.equals(Type.tchar));
750     }
751 
752     // Detect type ::std::char_traits<char>
753     bool isChar_traits_char(RootObject o)
754     {
755         return isIdent_char(Id.char_traits, o);
756     }
757 
758     // Detect type ::std::allocator<char>
759     bool isAllocator_char(RootObject o)
760     {
761         return isIdent_char(Id.allocator, o);
762     }
763 
764     // Detect type ::std::ident<char>
765     bool isIdent_char(Identifier ident, RootObject o)
766     {
767         Type t = isType(o);
768         if (!t || !t.isTypeStruct())
769             return false;
770         Dsymbol s = t.toDsymbol(null);
771         if (s.ident != ident)
772             return false;
773         Dsymbol p = s.toParent();
774         if (!p)
775             return false;
776         TemplateInstance ti = p.isTemplateInstance();
777         if (!ti)
778             return false;
779         Dsymbol q = getQualifier(ti);
780         const bool inStd = isStd(q) || isStd(this.getTiNamespace(ti));
781         return inStd && ti.tiargs.length == 1 && isChar((*ti.tiargs)[0]);
782     }
783 
784     /***
785      * Detect template args <char, ::std::char_traits<char>>
786      * and write st if found.
787      * Returns:
788      *  true if found
789      */
790     bool char_std_char_traits_char(TemplateInstance ti, string st)
791     {
792         if (ti.tiargs.length == 2 &&
793             isChar((*ti.tiargs)[0]) &&
794             isChar_traits_char((*ti.tiargs)[1]))
795         {
796             buf.writestring(st.ptr);
797             return true;
798         }
799         return false;
800     }
801 
802 
803     void prefix_name(Dsymbol s)
804     {
805         //printf("prefix_name(%s)\n", s.toChars());
806         if (substitute(s))
807             return;
808         if (isStd(s))
809             return buf.writestring("St");
810 
811         auto si = getInstance(s);
812         Dsymbol p = getQualifier(si);
813         if (p)
814         {
815             if (isStd(p))
816             {
817                 bool needsTa;
818                 auto ti = si.isTemplateInstance();
819                 if (this.writeStdSubstitution(ti, needsTa))
820                 {
821                     this.abiTags.writeSymbol(ti, this);
822                     if (needsTa)
823                     {
824                         template_args(ti);
825                         append(ti);
826                     }
827                     return;
828                 }
829                 buf.writestring("St");
830             }
831             else
832                 prefix_name(p);
833         }
834         source_name(si, true);
835         if (!isStd(si))
836             /* Do this after the source_name() call to keep components[]
837              * in the right order.
838              * https://issues.dlang.org/show_bug.cgi?id=17947
839              */
840             append(si);
841     }
842 
843     /**
844      * Write common substitution for standard types, such as std::allocator
845      *
846      * This function assumes that the symbol `ti` is in the namespace `std`.
847      *
848      * Params:
849      *   ti = Template instance to consider
850      *   needsTa = If this function returns `true`, this value indicates
851      *             if additional template argument mangling is needed
852      *
853      * Returns:
854      *   `true` if a special std symbol was found
855      */
856     bool writeStdSubstitution(TemplateInstance ti, out bool needsTa)
857     {
858         if (!ti)
859             return false;
860         if (!isStd(this.getTiNamespace(ti)) && !isStd(getQualifier(ti)))
861             return false;
862 
863         if (ti.name == Id.allocator)
864         {
865             buf.writestring("Sa");
866             needsTa = true;
867             return true;
868         }
869         if (ti.name == Id.basic_string)
870         {
871             // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
872             if (ti.tiargs.length == 3 &&
873                 isChar((*ti.tiargs)[0]) &&
874                 isChar_traits_char((*ti.tiargs)[1]) &&
875                 isAllocator_char((*ti.tiargs)[2]))
876 
877             {
878                 buf.writestring("Ss");
879                 return true;
880             }
881             buf.writestring("Sb");      // ::std::basic_string
882             needsTa = true;
883             return true;
884         }
885 
886         // ::std::basic_istream<char, ::std::char_traits<char>>
887         if (ti.name == Id.basic_istream &&
888             char_std_char_traits_char(ti, "Si"))
889             return true;
890 
891         // ::std::basic_ostream<char, ::std::char_traits<char>>
892         if (ti.name == Id.basic_ostream &&
893             char_std_char_traits_char(ti, "So"))
894             return true;
895 
896         // ::std::basic_iostream<char, ::std::char_traits<char>>
897         if (ti.name == Id.basic_iostream &&
898             char_std_char_traits_char(ti, "Sd"))
899             return true;
900 
901         return false;
902     }
903 
904     void cpp_mangle_name(Dsymbol s, bool qualified)
905     {
906         //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified);
907         Dsymbol p = s.toParent();
908         Dsymbol se = s;
909         bool write_prefix = true;
910         if (p && p.isTemplateInstance())
911         {
912             se = p;
913             if (find(p.isTemplateInstance().tempdecl) >= 0)
914                 write_prefix = false;
915             p = p.toParent();
916         }
917         if (!p || p.isModule())
918         {
919             source_name(se, false);
920             append(s);
921             return;
922         }
923 
924         if (!isStd(p) || qualified)
925         {
926             buf.writeByte('N');
927             if (write_prefix)
928             {
929                 if (isStd(p))
930                     buf.writestring("St");
931                 else
932                     prefix_name(p);
933             }
934             source_name(se, true);
935             buf.writeByte('E');
936             append(s);
937             return;
938         }
939         /* The N..E is not required if:
940          * 1. the parent is 'std'
941          * 2. 'std' is the initial qualifier
942          * 3. there is no CV-qualifier or a ref-qualifier for a member function
943          * ABI 5.1.8
944          */
945         TemplateInstance ti = se.isTemplateInstance();
946         if (s.ident == Id.allocator)
947         {
948             buf.writestring("Sa"); // "Sa" is short for ::std::allocator
949             template_args(ti);
950         }
951         else if (s.ident == Id.basic_string)
952         {
953             // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
954             if (ti.tiargs.length == 3 &&
955                 isChar((*ti.tiargs)[0]) &&
956                 isChar_traits_char((*ti.tiargs)[1]) &&
957                 isAllocator_char((*ti.tiargs)[2]))
958             {
959                 buf.writestring("Ss");
960                 return;
961             }
962             buf.writestring("Sb");      // ::std::basic_string
963             template_args(ti);
964         }
965         else
966         {
967             // ::std::basic_istream<char, ::std::char_traits<char>>
968             if (s.ident == Id.basic_istream)
969             {
970                 if (char_std_char_traits_char(ti, "Si"))
971                     return;
972             }
973             else if (s.ident == Id.basic_ostream)
974             {
975                 if (char_std_char_traits_char(ti, "So"))
976                     return;
977             }
978             else if (s.ident == Id.basic_iostream)
979             {
980                 if (char_std_char_traits_char(ti, "Sd"))
981                     return;
982             }
983             buf.writestring("St");
984             source_name(se, true);
985         }
986         append(s);
987     }
988 
989     /**
990      * Write CV-qualifiers to the buffer
991      *
992      * CV-qualifiers are 'r': restrict (unused in D), 'V': volatile, 'K': const
993      *
994      * See_Also:
995      *   https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.CV-qualifiers
996      */
997     void CV_qualifiers(const Type t)
998     {
999         if (t.isConst())
1000             buf.writeByte('K');
1001     }
1002 
1003     /**
1004      * Mangles a variable
1005      *
1006      * Params:
1007      *   d = Variable declaration to mangle
1008      *   isNested = Whether this variable is nested, e.g. a template parameter
1009      *              or within a namespace
1010      */
1011     void mangle_variable(VarDeclaration d, bool isNested)
1012     {
1013         // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525
1014         if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared)))
1015         {
1016             d.error("internal compiler error: C++ static non-`__gshared` non-`extern` variables not supported");
1017             fatal();
1018         }
1019         Dsymbol p = d.toParent();
1020         if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE"
1021         {
1022             buf.writestring("_ZN");
1023             prefix_name(p);
1024             source_name(d, true);
1025             buf.writeByte('E');
1026         }
1027         else if (isNested)
1028         {
1029             buf.writestring("_Z");
1030             source_name(d, false);
1031         }
1032         else
1033         {
1034             if (auto varTags = ABITagContainer.forSymbol(d))
1035             {
1036                 buf.writestring("_Z");
1037                 source_name(d, false);
1038                 return;
1039             }
1040             if (auto typeTags = ABITagContainer.forSymbol(d.type.toDsymbol(null)))
1041             {
1042                 buf.writestring("_Z");
1043                 source_name(d, false);
1044                 this.abiTags.write(*this.buf, typeTags);
1045                 return;
1046             }
1047             //char beta[6] should mangle as "beta"
1048             buf.writestring(d.ident.toString());
1049         }
1050     }
1051 
1052     void mangle_function(FuncDeclaration d)
1053     {
1054         //printf("mangle_function(%s)\n", d.toChars());
1055         /*
1056          * <mangled-name> ::= _Z <encoding>
1057          */
1058         buf.writestring("_Z");
1059         this.mangle_function_encoding(d);
1060     }
1061 
1062     void mangle_function_encoding(FuncDeclaration d)
1063     {
1064         //printf("mangle_function_encoding(%s)\n", d.toChars());
1065         /*
1066          * <encoding> ::= <function name> <bare-function-type>
1067          *            ::= <data name>
1068          *            ::= <special-name>
1069          */
1070         TypeFunction tf = d.type.isTypeFunction();
1071 
1072         if (TemplateDeclaration ftd = getFuncTemplateDecl(d))
1073         {
1074             /* It's an instance of a function template
1075              */
1076             TemplateInstance ti = d.parent.isTemplateInstance();
1077             assert(ti);
1078             this.mangleTemplatedFunction(d, tf, ftd, ti);
1079             return;
1080         }
1081 
1082         Dsymbol p = d.toParent();
1083         if (p && !p.isModule() && tf.linkage == LINK.cpp)
1084         {
1085             this.mangleNestedFuncPrefix(tf, p);
1086 
1087             if (auto ctor = d.isCtorDeclaration())
1088                 buf.writestring(ctor.isCpCtor ? "C2" : "C1");
1089             else if (d.isAggregateDtor())
1090                 buf.writestring("D1");
1091             else if (d.ident && d.ident == Id.assign)
1092                 buf.writestring("aS");
1093             else if (d.ident && d.ident == Id.eq)
1094                 buf.writestring("eq");
1095             else if (d.ident && d.ident == Id.index)
1096                 buf.writestring("ix");
1097             else if (d.ident && d.ident == Id.call)
1098                 buf.writestring("cl");
1099             else
1100                 source_name(d, true);
1101             buf.writeByte('E');
1102         }
1103         else
1104         {
1105             source_name(d, false);
1106         }
1107 
1108         // Save offset for potentially writing tags
1109         const size_t off = this.buf.length();
1110 
1111         // Template args accept extern "C" symbols with special mangling
1112         if (tf.linkage == LINK.cpp)
1113             mangleFunctionParameters(tf.parameterList);
1114 
1115         if (!tf.next.isTypeBasic())
1116             this.writeRemainingTags(off, tf);
1117     }
1118 
1119     /**
1120      * Recursively mangles a non-scoped namespace
1121      *
1122      * Parameters:
1123      *   ns = Namespace to mangle
1124      *   dg = A delegate to write the identifier in this namespace
1125      *   haveNE = When `false` (the default), surround the namespace / dg
1126      *            call with nested name qualifier (`N..E`).
1127      *            Otherwise, they are already present (e.g. `Nspace` was used).
1128      */
1129     void writeNamespace(CPPNamespaceDeclaration ns, scope void delegate() dg,
1130                         bool haveNE = false)
1131     {
1132         void runDg () { if (dg !is null) dg(); }
1133 
1134         if (ns is null || ns.ident is null)
1135             return runDg();
1136 
1137         if (isStd(ns))
1138         {
1139             if (!substitute(ns))
1140                 buf.writestring("St");
1141             runDg();
1142         }
1143         else if (dg !is null)
1144         {
1145             if (!haveNE)
1146                 buf.writestring("N");
1147             if (!substitute(ns))
1148             {
1149                 this.writeNamespace(ns.cppnamespace, null);
1150                 this.writeIdentifier(ns.ident);
1151                 append(ns);
1152             }
1153             dg();
1154             if (!haveNE)
1155                 buf.writestring("E");
1156         }
1157         else if (!substitute(ns))
1158         {
1159             this.writeNamespace(ns.cppnamespace, null);
1160             this.writeIdentifier(ns.ident);
1161             append(ns);
1162         }
1163     }
1164 
1165     /**
1166      * Mangles a function template to C++
1167      *
1168      * Params:
1169      *   d = Function declaration
1170      *   tf = Function type (casted d.type)
1171      *   ftd = Template declaration (ti.templdecl)
1172      *   ti = Template instance (d.parent)
1173      */
1174     void mangleTemplatedFunction(FuncDeclaration d, TypeFunction tf,
1175                                  TemplateDeclaration ftd, TemplateInstance ti)
1176     {
1177         Dsymbol p = ti.toParent();
1178         // Check if this function is *not* nested
1179         if (!p || p.isModule() || tf.linkage != LINK.cpp)
1180         {
1181             this.context.ti = ti;
1182             this.context.fd = d;
1183             this.context.res = d;
1184             TypeFunction preSemantic = d.originalType.isTypeFunction();
1185             auto nspace = ti.toParent();
1186             if (nspace && nspace.isNspace())
1187                 this.writeChained(ti.toParent(), () => source_name(ti, true));
1188             else
1189                 source_name(ti, false);
1190             this.mangleReturnType(preSemantic);
1191             this.mangleFunctionParameters(ParameterList(preSemantic.parameterList.parameters, tf.parameterList.varargs));
1192             return;
1193         }
1194 
1195         // It's a nested function (e.g. a member of an aggregate)
1196         this.mangleNestedFuncPrefix(tf, p);
1197 
1198         if (d.isCtorDeclaration())
1199         {
1200             buf.writestring("C1");
1201             mangleFunctionParameters(tf.parameterList);
1202             return;
1203         }
1204         else if (d.isAggregateDtor())
1205         {
1206             buf.writestring("D1");
1207             mangleFunctionParameters(tf.parameterList);
1208             return;
1209         }
1210 
1211         int firstTemplateArg = 0;
1212         bool appendReturnType = true;
1213         bool isConvertFunc = false;
1214         string symName;
1215 
1216         // test for special symbols
1217         CppOperator whichOp = isCppOperator(ti.name);
1218         final switch (whichOp)
1219         {
1220         case CppOperator.Unknown:
1221             break;
1222         case CppOperator.Cast:
1223             symName = "cv";
1224             firstTemplateArg = 1;
1225             isConvertFunc = true;
1226             appendReturnType = false;
1227             break;
1228         case CppOperator.Assign:
1229             symName = "aS";
1230             break;
1231         case CppOperator.Eq:
1232             symName = "eq";
1233             break;
1234         case CppOperator.Index:
1235             symName = "ix";
1236             break;
1237         case CppOperator.Call:
1238             symName = "cl";
1239             break;
1240         case CppOperator.Unary:
1241         case CppOperator.Binary:
1242         case CppOperator.OpAssign:
1243             TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration();
1244             assert(td);
1245             assert(ti.tiargs.length >= 1);
1246             TemplateParameter tp = (*td.parameters)[0];
1247             TemplateValueParameter tv = tp.isTemplateValueParameter();
1248             if (!tv || !tv.valType.isString())
1249                 break; // expecting a string argument to operators!
1250             Expression exp = (*ti.tiargs)[0].isExpression();
1251             StringExp str = exp.toStringExp();
1252             switch (whichOp)
1253             {
1254             case CppOperator.Unary:
1255                 switch (str.peekString())
1256                 {
1257                 case "*":   symName = "de"; goto continue_template;
1258                 case "++":  symName = "pp"; goto continue_template;
1259                 case "--":  symName = "mm"; goto continue_template;
1260                 case "-":   symName = "ng"; goto continue_template;
1261                 case "+":   symName = "ps"; goto continue_template;
1262                 case "~":   symName = "co"; goto continue_template;
1263                 default:    break;
1264                 }
1265                 break;
1266             case CppOperator.Binary:
1267                 switch (str.peekString())
1268                 {
1269                 case ">>":  symName = "rs"; goto continue_template;
1270                 case "<<":  symName = "ls"; goto continue_template;
1271                 case "*":   symName = "ml"; goto continue_template;
1272                 case "-":   symName = "mi"; goto continue_template;
1273                 case "+":   symName = "pl"; goto continue_template;
1274                 case "&":   symName = "an"; goto continue_template;
1275                 case "/":   symName = "dv"; goto continue_template;
1276                 case "%":   symName = "rm"; goto continue_template;
1277                 case "^":   symName = "eo"; goto continue_template;
1278                 case "|":   symName = "or"; goto continue_template;
1279                 default:    break;
1280                 }
1281                 break;
1282             case CppOperator.OpAssign:
1283                 switch (str.peekString())
1284                 {
1285                 case "*":   symName = "mL"; goto continue_template;
1286                 case "+":   symName = "pL"; goto continue_template;
1287                 case "-":   symName = "mI"; goto continue_template;
1288                 case "/":   symName = "dV"; goto continue_template;
1289                 case "%":   symName = "rM"; goto continue_template;
1290                 case ">>":  symName = "rS"; goto continue_template;
1291                 case "<<":  symName = "lS"; goto continue_template;
1292                 case "&":   symName = "aN"; goto continue_template;
1293                 case "|":   symName = "oR"; goto continue_template;
1294                 case "^":   symName = "eO"; goto continue_template;
1295                 default:    break;
1296                 }
1297                 break;
1298             default:
1299                 assert(0);
1300             continue_template:
1301                 firstTemplateArg = 1;
1302                 break;
1303             }
1304             break;
1305         }
1306         if (symName.length == 0)
1307             source_name(ti, true);
1308         else
1309         {
1310             buf.writestring(symName);
1311             if (isConvertFunc)
1312                 template_arg(ti, 0);
1313             appendReturnType = template_args(ti, firstTemplateArg) && appendReturnType;
1314         }
1315         buf.writeByte('E');
1316         if (appendReturnType)
1317             headOfType(tf.nextOf());  // mangle return type
1318         mangleFunctionParameters(tf.parameterList);
1319     }
1320 
1321     /**
1322      * Mangle the parameters of a function
1323      *
1324      * For templated functions, `context.res` is set to the `FuncDeclaration`
1325      *
1326      * Params:
1327      *   parameters = Array of `Parameter` to mangle
1328      *   varargs = if != 0, this function has varargs parameters
1329      */
1330     void mangleFunctionParameters(ParameterList parameterList)
1331     {
1332         int numparams = 0;
1333 
1334         foreach (n, fparam; parameterList)
1335         {
1336             Type t = fparam.type.merge2();
1337             if (fparam.isReference())
1338                 t = t.referenceTo();
1339             else if (fparam.isLazy())
1340             {
1341                 // Mangle as delegate
1342                 auto tf = new TypeFunction(ParameterList(), t, LINK.d);
1343                 auto td = new TypeDelegate(tf);
1344                 t = td.merge();
1345             }
1346             else if (Type cpptype = target.cpp.parameterType(t))
1347                 t = cpptype;
1348             if (t.ty == Tsarray)
1349             {
1350                 // Static arrays in D are passed by value; no counterpart in C++
1351                 .error(loc, "internal compiler error: unable to pass static array `%s` to extern(C++) function, use pointer instead",
1352                     t.toChars());
1353                 fatal();
1354             }
1355             auto prev = this.context.push({
1356                     TypeFunction tf;
1357                     if (isDsymbol(this.context.res))
1358                         tf = this.context.res.asFuncDecl().type.isTypeFunction();
1359                     else
1360                         tf = this.context.res.asType().isTypeFunction();
1361                     assert(tf);
1362                     return (*tf.parameterList.parameters)[n].type;
1363                 }());
1364             scope (exit) this.context.pop(prev);
1365 
1366             if (this.context.ti && global.params.cplusplus >= CppStdRevision.cpp11)
1367                 handleParamPack(t, this.context.ti.tempdecl.isTemplateDeclaration().parameters);
1368 
1369             headOfType(t);
1370             ++numparams;
1371         }
1372 
1373         if (parameterList.varargs == VarArg.variadic)
1374             buf.writeByte('z');
1375         else if (!numparams)
1376             buf.writeByte('v'); // encode (void) parameters
1377     }
1378 
1379     /****** The rest is type mangling ************/
1380 
1381     void error(Type t)
1382     {
1383         const(char)* p;
1384         if (t.isImmutable())
1385             p = "`immutable` ";
1386         else if (t.isShared())
1387             p = "`shared` ";
1388         else
1389             p = "";
1390         .error(loc, "internal compiler error: %stype `%s` cannot be mapped to C++\n", p, t.toChars());
1391         fatal(); //Fatal, because this error should be handled in frontend
1392     }
1393 
1394     /****************************
1395      * Mangle a type,
1396      * treating it as a Head followed by a Tail.
1397      * Params:
1398      *  t = Head of a type
1399      */
1400     void headOfType(Type t)
1401     {
1402         if (auto tc = t.isTypeClass())
1403         {
1404             mangleTypeClass(tc, true);
1405         }
1406         else
1407         {
1408             // For value types, strip const/immutable/shared from the head of the type
1409             auto prev = this.context.push(this.context.res.asType().mutableOf().unSharedOf());
1410             scope (exit) this.context.pop(prev);
1411             t.mutableOf().unSharedOf().accept(this);
1412         }
1413     }
1414 
1415     /******
1416      * Write out 1 or 2 character basic type mangling.
1417      * Handle const and substitutions.
1418      * Params:
1419      *  t = type to mangle
1420      *  p = if not 0, then character prefix
1421      *  c = mangling character
1422      */
1423     void writeBasicType(Type t, char p, char c)
1424     {
1425         // Only do substitutions for non-fundamental types.
1426         if (!isFundamentalType(t) || t.isConst())
1427         {
1428             if (substitute(t))
1429                 return;
1430             else
1431                 append(t);
1432         }
1433         CV_qualifiers(t);
1434         if (p)
1435             buf.writeByte(p);
1436         buf.writeByte(c);
1437     }
1438 
1439 
1440     /****************
1441      * Write structs and enums.
1442      * Params:
1443      *  t = TypeStruct or TypeEnum
1444      */
1445     void doSymbol(Type t)
1446     {
1447         if (substitute(t))
1448             return;
1449         CV_qualifiers(t);
1450 
1451         // Handle any target-specific struct types.
1452         if (auto tm = target.cpp.typeMangle(t))
1453         {
1454             buf.writestring(tm);
1455         }
1456         else
1457         {
1458             Dsymbol s = t.toDsymbol(null);
1459             Dsymbol p = s.toParent();
1460             if (p && p.isTemplateInstance())
1461             {
1462                  /* https://issues.dlang.org/show_bug.cgi?id=17947
1463                   * Substitute the template instance symbol, not the struct/enum symbol
1464                   */
1465                 if (substitute(p))
1466                     return;
1467             }
1468             if (!substitute(s))
1469                 cpp_mangle_name(s, false);
1470         }
1471         if (t.isConst())
1472             append(t);
1473     }
1474 
1475 
1476 
1477     /************************
1478      * Mangle a class type.
1479      * If it's the head, treat the initial pointer as a value type.
1480      * Params:
1481      *  t = class type
1482      *  head = true for head of a type
1483      */
1484     void mangleTypeClass(TypeClass t, bool head)
1485     {
1486         if (t.isImmutable() || t.isShared())
1487             return error(t);
1488 
1489         /* Mangle as a <pointer to><struct>
1490          */
1491         if (substitute(t))
1492             return;
1493         if (!head)
1494             CV_qualifiers(t);
1495         buf.writeByte('P');
1496 
1497         CV_qualifiers(t);
1498 
1499         {
1500             Dsymbol s = t.toDsymbol(null);
1501             Dsymbol p = s.toParent();
1502             if (p && p.isTemplateInstance())
1503             {
1504                  /* https://issues.dlang.org/show_bug.cgi?id=17947
1505                   * Substitute the template instance symbol, not the class symbol
1506                   */
1507                 if (substitute(p))
1508                     return;
1509             }
1510         }
1511 
1512         if (!substitute(t.sym))
1513         {
1514             cpp_mangle_name(t.sym, false);
1515         }
1516         if (t.isConst())
1517             append(null);  // C++ would have an extra type here
1518         append(t);
1519     }
1520 
1521     /**
1522      * Mangle the prefix of a nested (e.g. member) function
1523      *
1524      * Params:
1525      *   tf = Type of the nested function
1526      *   parent = Parent in which the function is nested
1527      */
1528     void mangleNestedFuncPrefix(TypeFunction tf, Dsymbol parent)
1529     {
1530         /* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
1531          *               ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
1532          */
1533         buf.writeByte('N');
1534         CV_qualifiers(tf);
1535 
1536         /* <prefix> ::= <prefix> <unqualified-name>
1537          *          ::= <template-prefix> <template-args>
1538          *          ::= <template-param>
1539          *          ::= # empty
1540          *          ::= <substitution>
1541          *          ::= <prefix> <data-member-prefix>
1542          */
1543         prefix_name(parent);
1544     }
1545 
1546     /**
1547      * Write `Dp` (C++11 function parameter pack prefix) if 't' is a TemplateSequenceParameter (T...).
1548      *
1549      * Params:
1550      *   t      = Parameter type
1551      *   params = Template parameters of the function
1552      */
1553     private void handleParamPack(Type t, TemplateParameters* params)
1554     {
1555         if (t.isTypeReference())
1556             t = t.nextOf();
1557         auto ti = t.isTypeIdentifier();
1558         if (!ti)
1559             return;
1560 
1561         auto idx = templateParamIndex(ti.ident, params);
1562         if (idx < params.length && (*params)[idx].isTemplateTupleParameter())
1563             buf.writestring("Dp");
1564     }
1565 
1566     /**
1567      * Helper function to write a `T..._` template index.
1568      *
1569      * Params:
1570      *   idx   = Index of `param` in the template argument list
1571      *   param = Template parameter to mangle
1572      */
1573     private void writeTemplateArgIndex(size_t idx, TemplateParameter param)
1574     {
1575         // expressions are mangled in <X..E>
1576         if (param.isTemplateValueParameter())
1577             buf.writeByte('X');
1578         buf.writeByte('T');
1579         writeSequenceFromIndex(idx);
1580         buf.writeByte('_');
1581         if (param.isTemplateValueParameter())
1582             buf.writeByte('E');
1583     }
1584 
1585     /**
1586      * Given an array of template parameters and an identifier,
1587      * returns the index of the identifier in that array.
1588      *
1589      * Params:
1590      *   ident = Identifier for which substitution is attempted
1591      *           (e.g. `void func(T)(T param)` => `T` from `T param`)
1592      *   params = `TemplateParameters` of the enclosing symbol
1593      *           (in the previous example, `func`'s template parameters)
1594      *
1595      * Returns:
1596      *   The index of the identifier match in `params`,
1597      *   or `params.length` if there wasn't any match.
1598      */
1599     private static size_t templateParamIndex(
1600         const ref Identifier ident, TemplateParameters* params)
1601     {
1602         foreach (idx, param; *params)
1603             if (param.ident == ident)
1604                 return idx;
1605         return params.length;
1606     }
1607 
1608     /**
1609      * Given a template instance `t`, write its qualified name
1610      * without the template parameter list
1611      *
1612      * Params:
1613      *   t = Post-parsing `TemplateInstance` pointing to the symbol
1614      *       to mangle (one level deep)
1615      *   dg = Delegate to execute after writing the qualified symbol
1616      *
1617      */
1618     private void writeQualified(TemplateInstance t, scope void delegate() dg)
1619     {
1620         auto type = isType(this.context.res);
1621         if (!type)
1622         {
1623             this.writeIdentifier(t.name);
1624             return dg();
1625         }
1626         auto sym1 = type.toDsymbol(null);
1627         if (!sym1)
1628         {
1629             this.writeIdentifier(t.name);
1630             return dg();
1631         }
1632         // Get the template instance
1633         auto sym = getQualifier(sym1);
1634         auto sym2 = getQualifier(sym);
1635         if (sym2 && isStd(sym2)) // Nspace path
1636         {
1637             bool unused;
1638             assert(sym.isTemplateInstance());
1639             if (this.writeStdSubstitution(sym.isTemplateInstance(), unused))
1640                 return dg();
1641             // std names don't require `N..E`
1642             buf.writestring("St");
1643             this.writeIdentifier(t.name);
1644             this.append(t);
1645             return dg();
1646         }
1647         else if (sym2)
1648         {
1649             buf.writestring("N");
1650             if (!this.substitute(sym2))
1651                 sym2.accept(this);
1652         }
1653         this.writeNamespace(
1654             sym1.cppnamespace, () {
1655                 this.writeIdentifier(t.name);
1656                 this.append(t);
1657                 dg();
1658             });
1659         if (sym2)
1660             buf.writestring("E");
1661     }
1662 
1663 extern(C++):
1664 
1665     alias visit = Visitor.visit;
1666 
1667     override void visit(TypeNull t)
1668     {
1669         if (t.isImmutable() || t.isShared())
1670             return error(t);
1671 
1672         writeBasicType(t, 'D', 'n');
1673     }
1674 
1675     override void visit(TypeNoreturn t)
1676     {
1677         if (t.isImmutable() || t.isShared())
1678             return error(t);
1679 
1680         writeBasicType(t, 0, 'v');      // mangle like `void`
1681     }
1682 
1683     override void visit(TypeBasic t)
1684     {
1685         if (t.isImmutable() || t.isShared())
1686             return error(t);
1687 
1688         // Handle any target-specific basic types.
1689         if (auto tm = target.cpp.typeMangle(t))
1690         {
1691             // Only do substitutions for non-fundamental types.
1692             if (!isFundamentalType(t) || t.isConst())
1693             {
1694                 if (substitute(t))
1695                     return;
1696                 else
1697                     append(t);
1698             }
1699             CV_qualifiers(t);
1700             buf.writestring(tm);
1701             return;
1702         }
1703 
1704         /* <builtin-type>:
1705          * v        void
1706          * w        wchar_t
1707          * b        bool
1708          * c        char
1709          * a        signed char
1710          * h        unsigned char
1711          * s        short
1712          * t        unsigned short
1713          * i        int
1714          * j        unsigned int
1715          * l        long
1716          * m        unsigned long
1717          * x        long long, __int64
1718          * y        unsigned long long, __int64
1719          * n        __int128
1720          * o        unsigned __int128
1721          * f        float
1722          * d        double
1723          * e        long double, __float80
1724          * g        __float128
1725          * z        ellipsis
1726          * Dd       64 bit IEEE 754r decimal floating point
1727          * De       128 bit IEEE 754r decimal floating point
1728          * Df       32 bit IEEE 754r decimal floating point
1729          * Dh       16 bit IEEE 754r half-precision floating point
1730          * Di       char32_t
1731          * Ds       char16_t
1732          * u <source-name>  # vendor extended type
1733          */
1734         if (t.isimaginary() || t.iscomplex())
1735         {
1736             // https://issues.dlang.org/show_bug.cgi?id=22806
1737             // Complex and imaginary types are represented in the same way as
1738             // arrays or vectors in C++.  First substitute the outer type, then
1739             // write out the mangle string of the underlying type.
1740             if (substitute(t))
1741                 return;
1742             append(t);
1743             CV_qualifiers(t);
1744 
1745             if (t.isimaginary())
1746                 buf.writeByte('G'); // 'G' means imaginary
1747             else
1748                 buf.writeByte('C'); // 'C' means complex
1749 
1750             switch (t.ty)
1751             {
1752                 case Timaginary32:
1753                 case Tcomplex32:
1754                     return Type.tfloat32.accept(this);
1755                 case Timaginary64:
1756                 case Tcomplex64:
1757                     return Type.tfloat64.accept(this);
1758                 case Timaginary80:
1759                 case Tcomplex80:
1760                     return Type.tfloat80.accept(this);
1761                 default:
1762                     assert(0);
1763             }
1764         }
1765 
1766         char c;
1767         char p = 0;
1768         switch (t.ty)
1769         {
1770             case Tvoid:                 c = 'v';        break;
1771             case Tint8:                 c = 'a';        break;
1772             case Tuns8:                 c = 'h';        break;
1773             case Tint16:                c = 's';        break;
1774             case Tuns16:                c = 't';        break;
1775             case Tint32:                c = 'i';        break;
1776             case Tuns32:                c = 'j';        break;
1777             case Tfloat32:              c = 'f';        break;
1778             case Tint64:
1779                 c = target.c.longsize == 8 ? 'l' : 'x';
1780                 break;
1781             case Tuns64:
1782                 c = target.c.longsize == 8 ? 'm' : 'y';
1783                 break;
1784             case Tint128:                c = 'n';       break;
1785             case Tuns128:                c = 'o';       break;
1786             case Tfloat64:               c = 'd';       break;
1787             case Tfloat80:               c = 'e';       break;
1788             case Tbool:                  c = 'b';       break;
1789             case Tchar:                  c = 'c';       break;
1790             case Twchar:        p = 'D'; c = 's';       break;  // since C++11
1791             case Tdchar:        p = 'D'; c = 'i';       break;  // since C++11
1792 
1793             default:
1794                 return error(t);
1795         }
1796         writeBasicType(t, p, c);
1797     }
1798 
1799     override void visit(TypeVector t)
1800     {
1801         if (t.isImmutable() || t.isShared())
1802             return error(t);
1803 
1804         if (substitute(t))
1805             return;
1806         append(t);
1807         CV_qualifiers(t);
1808 
1809         // Handle any target-specific vector types.
1810         if (auto tm = target.cpp.typeMangle(t))
1811         {
1812             buf.writestring(tm);
1813         }
1814         else
1815         {
1816             assert(t.basetype && t.basetype.ty == Tsarray);
1817             auto tsa = t.basetype.isTypeSArray();
1818             assert(tsa.dim);
1819             buf.writestring("Dv");          // -- Gnu ABI v.4
1820             buf.print(tsa.dim.toInteger());
1821             buf.writeByte('_');
1822             t.basetype.nextOf().accept(this);
1823         }
1824     }
1825 
1826     override void visit(TypeSArray t)
1827     {
1828         if (t.isImmutable() || t.isShared())
1829             return error(t);
1830 
1831         if (!substitute(t))
1832             append(t);
1833         CV_qualifiers(t);
1834         buf.writeByte('A');
1835         buf.print(t.dim ? t.dim.toInteger() : 0);
1836         buf.writeByte('_');
1837         t.next.accept(this);
1838     }
1839 
1840     override void visit(TypePointer t)
1841     {
1842         if (t.isImmutable() || t.isShared())
1843             return error(t);
1844 
1845         // Check for const - Since we cannot represent C++'s `char* const`,
1846         // and `const char* const` (a.k.a `const(char*)` in D) is mangled
1847         // the same as `const char*` (`const(char)*` in D), we need to add
1848         // an extra `K` if `nextOf()` is `const`, before substitution
1849         CV_qualifiers(t);
1850         if (substitute(t))
1851             return;
1852         buf.writeByte('P');
1853         auto prev = this.context.push(this.context.res.asType().nextOf());
1854         scope (exit) this.context.pop(prev);
1855         t.next.accept(this);
1856         append(t);
1857     }
1858 
1859     override void visit(TypeReference t)
1860     {
1861         if (substitute(t))
1862             return;
1863         buf.writeByte('R');
1864         CV_qualifiers(t.nextOf());
1865         headOfType(t.nextOf());
1866         if (t.nextOf().isConst())
1867             append(t.nextOf());
1868         append(t);
1869     }
1870 
1871     override void visit(TypeFunction t)
1872     {
1873         /*
1874          *  <function-type> ::= F [Y] <bare-function-type> E
1875          *  <bare-function-type> ::= <signature type>+
1876          *  # types are possible return type, then parameter types
1877          */
1878         /* ABI says:
1879             "The type of a non-static member function is considered to be different,
1880             for the purposes of substitution, from the type of a namespace-scope or
1881             static member function whose type appears similar. The types of two
1882             non-static member functions are considered to be different, for the
1883             purposes of substitution, if the functions are members of different
1884             classes. In other words, for the purposes of substitution, the class of
1885             which the function is a member is considered part of the type of
1886             function."
1887 
1888             BUG: Right now, types of functions are never merged, so our simplistic
1889             component matcher always finds them to be different.
1890             We should use Type.equals on these, and use different
1891             TypeFunctions for non-static member functions, and non-static
1892             member functions of different classes.
1893          */
1894         if (substitute(t))
1895             return;
1896         buf.writeByte('F');
1897         if (t.linkage == LINK.c)
1898             buf.writeByte('Y');
1899         Type tn = t.next;
1900         if (t.isref)
1901             tn = tn.referenceTo();
1902         tn.accept(this);
1903         mangleFunctionParameters(t.parameterList);
1904         buf.writeByte('E');
1905         append(t);
1906     }
1907 
1908     override void visit(TypeStruct t)
1909     {
1910         if (t.isImmutable() || t.isShared())
1911             return error(t);
1912         //printf("TypeStruct %s\n", t.toChars());
1913         doSymbol(t);
1914     }
1915 
1916     override void visit(TypeEnum t)
1917     {
1918         if (t.isImmutable() || t.isShared())
1919             return error(t);
1920 
1921         /* __c_(u)long(long) and others get special mangling
1922          */
1923         const id = t.sym.ident;
1924         //printf("enum id = '%s'\n", id.toChars());
1925         if (id == Id.__c_long)
1926             return writeBasicType(t, 0, 'l');
1927         else if (id == Id.__c_ulong)
1928             return writeBasicType(t, 0, 'm');
1929         else if (id == Id.__c_char)
1930             return writeBasicType(t, 0, 'c');
1931         else if (id == Id.__c_wchar_t)
1932             return writeBasicType(t, 0, 'w');
1933         else if (id == Id.__c_longlong)
1934             return writeBasicType(t, 0, 'x');
1935         else if (id == Id.__c_ulonglong)
1936             return writeBasicType(t, 0, 'y');
1937         else if (id == Id.__c_complex_float)
1938             return Type.tcomplex32.accept(this);
1939         else if (id == Id.__c_complex_double)
1940             return Type.tcomplex64.accept(this);
1941         else if (id == Id.__c_complex_real)
1942             return Type.tcomplex80.accept(this);
1943 
1944         doSymbol(t);
1945     }
1946 
1947     override void visit(TypeClass t)
1948     {
1949         mangleTypeClass(t, false);
1950     }
1951 
1952     /**
1953      * Performs template parameter substitution
1954      *
1955      * Mangling is performed on a copy of the post-parsing AST before
1956      * any semantic pass is run.
1957      * There is no easy way to link a type to the template parameters
1958      * once semantic has run, because:
1959      * - the `TemplateInstance` installs aliases in its scope to its params
1960      * - `AliasDeclaration`s are resolved in many places
1961      * - semantic passes are destructive, so the `TypeIdentifier` gets lost
1962      *
1963      * As a result, the best approach with the current architecture is to:
1964      * - Run the visitor on the `originalType` of the function,
1965      *   looking up any `TypeIdentifier` at the template scope when found.
1966      * - Fallback to the post-semantic `TypeFunction` when the identifier is
1967      *   not a template parameter.
1968      */
1969     override void visit(TypeIdentifier t)
1970     {
1971         auto decl = this.context.ti.tempdecl.isTemplateDeclaration();
1972         assert(decl.parameters !is null);
1973         auto idx = templateParamIndex(t.ident, decl.parameters);
1974         // If not found, default to the post-semantic type
1975         if (idx >= decl.parameters.length)
1976             return this.context.res.visitObject(this);
1977 
1978         auto param = (*decl.parameters)[idx];
1979         if (auto type = this.context.res.isType())
1980             CV_qualifiers(type);
1981         // Otherwise, attempt substitution (`S_` takes precedence on `T_`)
1982         if (this.substitute(param))
1983             return;
1984 
1985         // If substitution failed, write `TX_` where `X` is the index
1986         this.writeTemplateArgIndex(idx, param);
1987         this.append(param);
1988         // Write the ABI tags, if any
1989         if (auto sym = this.context.res.isDsymbol())
1990             this.abiTags.writeSymbol(sym, this);
1991     }
1992 
1993     /// Ditto
1994     override void visit(TypeInstance t)
1995     {
1996         assert(t.tempinst !is null);
1997         t.tempinst.accept(this);
1998     }
1999 
2000     /**
2001      * Mangles a `TemplateInstance`
2002      *
2003      * A `TemplateInstance` can be found either in the parameter,
2004      * or the return value.
2005      * Arguments to the template instance needs to be mangled but the template
2006      * can be partially substituted, so for example the following:
2007      * `Container!(T, Val) func16479_12 (alias Container, T, int Val) ()`
2008      * will mangle the return value part to "T_IT0_XT1_EE"
2009      */
2010     override void visit(TemplateInstance t)
2011     {
2012         // Template names are substituted, but args still need to be written
2013         void writeArgs ()
2014         {
2015             buf.writeByte('I');
2016             // When visiting the arguments, the context will be set to the
2017             // resolved type
2018             auto analyzed_ti = this.context.res.asType().toDsymbol(null).isInstantiated();
2019             auto prev = this.context;
2020             scope (exit) this.context.pop(prev);
2021             foreach (idx, RootObject o; *t.tiargs)
2022             {
2023                 this.context.res = (*analyzed_ti.tiargs)[idx];
2024                 o.visitObject(this);
2025             }
2026             if (analyzed_ti.tiargs.length > t.tiargs.length)
2027             {
2028                 // If the resolved AST has more args than the parse one,
2029                 // we have default arguments
2030                 auto oparams = analyzed_ti.tempdecl.isTemplateDeclaration().origParameters;
2031                 foreach (idx, arg; (*oparams)[t.tiargs.length .. $])
2032                 {
2033                     this.context.res = (*analyzed_ti.tiargs)[idx + t.tiargs.length];
2034 
2035                     if (auto ttp = arg.isTemplateTypeParameter())
2036                         ttp.defaultType.accept(this);
2037                     else if (auto tvp = arg.isTemplateValueParameter())
2038                         tvp.defaultValue.accept(this);
2039                     else if (auto tvp = arg.isTemplateThisParameter())
2040                         tvp.defaultType.accept(this);
2041                     else if (auto tvp = arg.isTemplateAliasParameter())
2042                         tvp.defaultAlias.visitObject(this);
2043                     else
2044                         assert(0, arg.toString());
2045                 }
2046             }
2047             buf.writeByte('E');
2048         }
2049 
2050         // `name` is used, not `ident`
2051         assert(t.name !is null);
2052         assert(t.tiargs !is null);
2053 
2054         bool needsTa;
2055         auto decl = this.context.ti.tempdecl.isTemplateDeclaration();
2056         // Attempt to substitute the template itself
2057         auto idx = templateParamIndex(t.name, decl.parameters);
2058         if (idx < decl.parameters.length)
2059         {
2060             auto param = (*decl.parameters)[idx];
2061             if (auto type = t.getType())
2062                 CV_qualifiers(type);
2063             if (this.substitute(param))
2064                 return;
2065             this.writeTemplateArgIndex(idx, param);
2066             this.append(param);
2067             writeArgs();
2068         }
2069         else if (this.writeStdSubstitution(t, needsTa))
2070         {
2071             if (needsTa)
2072                 writeArgs();
2073         }
2074         else if (!this.substitute(t))
2075             this.writeQualified(t, &writeArgs);
2076     }
2077 
2078     /// Ditto
2079     override void visit(IntegerExp t)
2080     {
2081         this.buf.writeByte('L');
2082         t.type.accept(this);
2083         this.buf.print(t.getInteger());
2084         this.buf.writeByte('E');
2085     }
2086 
2087     override void visit(Nspace t)
2088     {
2089         if (auto p = getQualifier(t))
2090             p.accept(this);
2091 
2092         if (isStd(t))
2093             buf.writestring("St");
2094         else
2095         {
2096             this.writeIdentifier(t.ident);
2097             this.append(t);
2098         }
2099     }
2100 
2101     override void visit(Type t)
2102     {
2103         error(t);
2104     }
2105 
2106     void visit(Tuple t)
2107     {
2108         assert(0);
2109     }
2110 }
2111 
2112 /// Helper code to visit `RootObject`, as it doesn't define `accept`,
2113 /// only its direct subtypes do.
2114 private void visitObject(V : Visitor)(RootObject o, V this_)
2115 {
2116     assert(o !is null);
2117     if (Type ta = isType(o))
2118         ta.accept(this_);
2119     else if (Expression ea = isExpression(o))
2120         ea.accept(this_);
2121     else if (Dsymbol sa = isDsymbol(o))
2122         sa.accept(this_);
2123     else if (TemplateParameter t = isTemplateParameter(o))
2124         t.accept(this_);
2125     else if (Tuple t = isTuple(o))
2126         // `Tuple` inherits `RootObject` and does not define accept
2127         // For this reason, this uses static dispatch on the visitor
2128         this_.visit(t);
2129     else
2130         assert(0, o.toString());
2131 }
2132 
2133 /// Helper function to safely get a type out of a `RootObject`
2134 private Type asType(RootObject o)
2135 {
2136     if (Type ta = isType(o))
2137         return ta;
2138 
2139     // When called with context.res as argument, it can be `FuncDeclaration`
2140     if (auto fd = o.asFuncDecl())
2141         return fd.type;
2142     assert(0);
2143 }
2144 
2145 /// Helper function to safely get a `FuncDeclaration` out of a `RootObject`
2146 private FuncDeclaration asFuncDecl(RootObject o)
2147 {
2148     Dsymbol d = isDsymbol(o);
2149     assert(d !is null);
2150     auto fd = d.isFuncDeclaration();
2151     assert(fd !is null);
2152     return fd;
2153 }
2154 
2155 /// Helper class to compare entries in components
2156 private extern(C++) final class ComponentVisitor : Visitor
2157 {
2158     /// Only one of the following is not `null`, it's always
2159     /// the most specialized type, set from the ctor
2160     private Nspace namespace;
2161 
2162     /// Ditto
2163     private CPPNamespaceDeclaration namespace2;
2164 
2165     /// Ditto
2166     private TypePointer tpointer;
2167 
2168     /// Ditto
2169     private TypeReference tref;
2170 
2171     /// Ditto
2172     private TypeIdentifier tident;
2173 
2174     /// Least specialized type
2175     private RootObject object;
2176 
2177     /// Set to the result of the comparison
2178     private bool result;
2179 
2180     public this(RootObject base)
2181     {
2182         switch (base.dyncast())
2183         {
2184         case DYNCAST.dsymbol:
2185             if (auto ns = (cast(Dsymbol)base).isNspace())
2186                 this.namespace = ns;
2187             else if (auto ns = (cast(Dsymbol)base).isCPPNamespaceDeclaration())
2188                 this.namespace2 = ns;
2189             else
2190                 goto default;
2191             break;
2192 
2193         case DYNCAST.type:
2194             auto t = cast(Type)base;
2195             if (auto tp = t.isTypePointer())
2196                 this.tpointer = tp;
2197             else if (auto tr = t.isTypeReference())
2198                 this.tref = tr;
2199             else if (auto ti = t.isTypeIdentifier())
2200                 this.tident = ti;
2201             else
2202                 goto default;
2203             break;
2204 
2205         // Note: ABI tags are also handled here (they are TupleExp of StringExp)
2206         default:
2207             this.object = base;
2208         }
2209     }
2210 
2211     /// Introduce base class overloads
2212     alias visit = Visitor.visit;
2213 
2214     /// Least specialized overload of each direct child of `RootObject`
2215     public override void visit(Dsymbol o)
2216     {
2217         this.result = this.object && this.object == o;
2218     }
2219 
2220     /// Ditto
2221     public override void visit(Expression o)
2222     {
2223         this.result = this.object && this.object == o;
2224     }
2225 
2226     /// Ditto
2227     public void visit(Tuple o)
2228     {
2229         this.result = this.object && this.object == o;
2230     }
2231 
2232     /// Ditto
2233     public override void visit(Type o)
2234     {
2235         this.result = this.object && this.object == o;
2236     }
2237 
2238     /// Ditto
2239     public override void visit(TemplateParameter o)
2240     {
2241         this.result = this.object && this.object == o;
2242     }
2243 
2244     /**
2245      * This overload handles composed types including template parameters
2246      *
2247      * Components for substitutions include "next" type.
2248      * For example, if `ref T` is present, `ref T` and `T` will be present
2249      * in the substitution array.
2250      * But since we don't have the final/merged type, we cannot rely on
2251      * object comparison, and need to recurse instead.
2252      */
2253     public override void visit(TypeReference o)
2254     {
2255         if (!this.tref)
2256             return;
2257         if (this.tref == o)
2258             this.result = true;
2259         else
2260         {
2261             // It might be a reference to a template parameter that we already
2262             // saw, so we need to recurse
2263             scope v = new ComponentVisitor(this.tref.next);
2264             o.next.visitObject(v);
2265             this.result = v.result;
2266         }
2267     }
2268 
2269     /// Ditto
2270     public override void visit(TypePointer o)
2271     {
2272         if (!this.tpointer)
2273             return;
2274         if (this.tpointer == o)
2275             this.result = true;
2276         else
2277         {
2278             // It might be a pointer to a template parameter that we already
2279             // saw, so we need to recurse
2280             scope v = new ComponentVisitor(this.tpointer.next);
2281             o.next.visitObject(v);
2282             this.result = v.result;
2283         }
2284     }
2285 
2286     /// Ditto
2287     public override void visit(TypeIdentifier o)
2288     {
2289         /// Since we know they are at the same level, scope resolution will
2290         /// give us the same symbol, thus we can just compare ident.
2291         this.result = (this.tident && (this.tident.ident == o.ident));
2292     }
2293 
2294     /**
2295      * Overload which accepts a Namespace
2296      *
2297      * It is very common for large C++ projects to have multiple files sharing
2298      * the same `namespace`. If any D project adopts the same approach
2299      * (e.g. separating data structures from functions), it will lead to two
2300      * `Nspace` objects being instantiated, with different addresses.
2301      * At the same time, we cannot compare just any Dsymbol via identifier,
2302      * because it messes with templates.
2303      *
2304      * See_Also:
2305      *  https://issues.dlang.org/show_bug.cgi?id=18922
2306      *
2307      * Params:
2308      *   ns = C++ namespace to do substitution for
2309      */
2310     public override void visit(Nspace ns)
2311     {
2312         this.result = isNamespaceEqual(this.namespace, ns)
2313             || isNamespaceEqual(this.namespace2, ns);
2314     }
2315 
2316     /// Ditto
2317     public override void visit(CPPNamespaceDeclaration ns)
2318     {
2319         this.result = isNamespaceEqual(this.namespace, ns)
2320             || isNamespaceEqual(this.namespace2, ns);
2321     }
2322 }
2323 
2324 /// Transitional functions for `CPPNamespaceDeclaration` / `Nspace`
2325 /// Remove when `Nspace` is removed.
2326 private bool isNamespaceEqual (Nspace a, Nspace b)
2327 {
2328     if (a is null || b is null)
2329         return false;
2330     return a.equals(b);
2331 }
2332 
2333 /// Ditto
2334 private bool isNamespaceEqual (Nspace a, CPPNamespaceDeclaration b)
2335 {
2336     return isNamespaceEqual(b, a);
2337 }
2338 
2339 /// Ditto
2340 private bool isNamespaceEqual (CPPNamespaceDeclaration a, Nspace b, size_t idx = 0)
2341 {
2342     if ((a is null) != (b is null))
2343         return false;
2344     if (!a.ident.equals(b.ident))
2345         return false;
2346 
2347     // We need to see if there's more ident enclosing
2348     if (auto pb = b.toParent().isNspace())
2349         return isNamespaceEqual(a.cppnamespace, pb);
2350     else
2351         return a.cppnamespace is null;
2352 }
2353 
2354 /// Returns:
2355 ///   Whether  two `CPPNamespaceDeclaration` are equals
2356 private bool isNamespaceEqual (CPPNamespaceDeclaration a, CPPNamespaceDeclaration b)
2357 {
2358     if (a is null || b is null)
2359         return false;
2360 
2361     if ((a.cppnamespace is null) != (b.cppnamespace is null))
2362         return false;
2363     if (a.ident != b.ident)
2364         return false;
2365     return a.cppnamespace is null ? true : isNamespaceEqual(a.cppnamespace, b.cppnamespace);
2366 }
2367 
2368 /**
2369  * A container for ABI tags
2370  *
2371  * At its hearth, there is a sorted array of ABI tags having been written
2372  * already. ABI tags can be present on parameters, template parameters,
2373  * return value, and varaible. ABI tags for a given type needs to be written
2374  * sorted. When a function returns a type that has ABI tags, only the tags that
2375  * haven't been printed as part of the mangling (e.g. arguments) are written
2376  * directly after the function name.
2377  *
2378  * This means that:
2379  * ---
2380  * /++ C++ type definitions:
2381  * struct [[gnu::abi_tag("tag1")]] Struct1 {};
2382  * struct [[gnu::abi_tag("tag2")]] Struct2 {};
2383  * // Can also be: "tag2", "tag1", since tags are sorted.
2384  * struct [[gnu::abi_tag("tag1", "tag2")]] Struct3 {};
2385  * +/
2386  * // Functions definitions:
2387  * Struct3 func1 (Struct1);
2388  * Struct3 func2 (Struct2);
2389  * Struct3 func3 (Struct2, Struct1);
2390  * ---
2391  * Will be respectively pseudo-mangled (part of interest between stars) as:
2392  * "_Z4 func1 *B4tag2* ParamsMangling" (ParamsMangling includes tag1),
2393  * "_Z4 func2 *B4tag1* ParamsMangling" (ParamsMangling includes tag2),
2394  * "_Z4 func2 *B4tag1* ParamsMangling" (ParamsMangling includes both).
2395  *
2396  * This is why why need to keep a list of tags that were written,
2397  * and insert the missing one after parameter mangling has been written.
2398  * Since there's a lot of operations that are not easily doable in DMD
2399  * (since we can't use Phobos), this special container is implemented.
2400  */
2401 private struct ABITagContainer
2402 {
2403     private Array!StringExp written;
2404 
2405     static ArrayLiteralExp forSymbol (Dsymbol s)
2406     {
2407         if (!s)
2408             return null;
2409         // If this is a template instance, we want the declaration,
2410         // as that's where the UDAs are
2411         if (auto ti = s.isTemplateInstance())
2412             s = ti.tempdecl;
2413         if (!s.userAttribDecl || !s.userAttribDecl.atts)
2414             return null;
2415 
2416         foreach (exp; *s.userAttribDecl.atts)
2417         {
2418             if (UserAttributeDeclaration.isGNUABITag(exp))
2419                 return (*exp.isStructLiteralExp().elements)[0]
2420                     .isArrayLiteralExp();
2421         }
2422         return null;
2423     }
2424 
2425     void writeSymbol(Dsymbol s, CppMangleVisitor self)
2426     {
2427         auto tale = forSymbol(s);
2428         if (!tale) return;
2429         if (self.substitute(tale))
2430             return;
2431         this.write(*self.buf, tale);
2432     }
2433 
2434     /**
2435      * Write an ArrayLiteralExp (expected to be an ABI tag) to the buffer
2436      *
2437      * Params:
2438      *   buf = Buffer to write mangling to
2439      *   ale = GNU ABI tag array literal expression, semantically analyzed
2440      */
2441     void write (ref OutBuffer buf, ArrayLiteralExp ale, bool skipKnown = false)
2442     {
2443         void writeElem (StringExp exp)
2444         {
2445             const tag = exp.peekString();
2446             buf.writestring("B");
2447             buf.print(tag.length);
2448             buf.writestring(tag);
2449         }
2450 
2451         bool match;
2452         foreach (exp; *ale.elements)
2453         {
2454             auto elem = exp.toStringExp();
2455             auto idx = closestIndex(this.written[], elem, match);
2456             if (!match)
2457             {
2458                 writeElem(elem);
2459                 this.written.insert(idx, elem);
2460             }
2461             else if (!skipKnown)
2462                 writeElem(elem);
2463         }
2464     }
2465 }
2466 
2467 /**
2468  * Returns the closest index to to `exp` in `slice`
2469  *
2470  * Performs a binary search on `slice` (assumes `slice` is sorted),
2471  * and returns either `exp`'s index in `slice` if `exact` is `true`,
2472  * or the index at which `exp` can be inserted in `slice` if `exact is `false`.
2473  * Inserting `exp` at the return value will keep the array sorted.
2474  *
2475  * Params:
2476  *   slice = The sorted slice to search into
2477  *   exp   = The string expression to search for
2478  *   exact = If `true` on return, `exp` was found in `slice`
2479  *
2480  * Returns:
2481  *   Either the index to insert `exp` at (if `exact == false`),
2482  *   or the index of `exp` in `slice`.
2483  */
2484 private size_t closestIndex (const(StringExp)[] slice, StringExp exp, out bool exact)
2485 {
2486     if (!slice.length) return 0;
2487 
2488     const StringExp* first = slice.ptr;
2489     while (true)
2490     {
2491         int res = dstrcmp(exp.peekString(), slice[$ / 2].peekString());
2492         if (res == 0)
2493         {
2494             exact = true;
2495             return (&slice[$/2] - first);
2496         }
2497 
2498         if (slice.length == 1)
2499             return (slice.ptr - first) + (res > 0);
2500         slice = slice[(res > 0 ? $ / 2 : 0) .. (res > 0 ? $ : $ / 2)];
2501     }
2502 }
2503 
2504 //
2505 unittest
2506 {
2507     bool match;
2508     auto s1 = new StringExp(Loc.initial, "Amande");
2509     auto s2 = new StringExp(Loc.initial, "Baguette");
2510     auto s3 = new StringExp(Loc.initial, "Croissant");
2511     auto s4 = new StringExp(Loc.initial, "Framboises");
2512     auto s5 = new StringExp(Loc.initial, "Proscuitto");
2513 
2514     // Found, odd size
2515     assert(closestIndex([s1, s2, s3, s4, s5], s1, match) == 0 && match);
2516     assert(closestIndex([s1, s2, s3, s4, s5], s2, match) == 1 && match);
2517     assert(closestIndex([s1, s2, s3, s4, s5], s3, match) == 2 && match);
2518     assert(closestIndex([s1, s2, s3, s4, s5], s4, match) == 3 && match);
2519     assert(closestIndex([s1, s2, s3, s4, s5], s5, match) == 4 && match);
2520 
2521     // Not found, even size
2522     assert(closestIndex([s2, s3, s4, s5], s1, match) == 0 && !match);
2523     assert(closestIndex([s1, s3, s4, s5], s2, match) == 1 && !match);
2524     assert(closestIndex([s1, s2, s4, s5], s3, match) == 2 && !match);
2525     assert(closestIndex([s1, s2, s3, s5], s4, match) == 3 && !match);
2526     assert(closestIndex([s1, s2, s3, s4], s5, match) == 4 && !match);
2527 
2528     // Found, even size
2529     assert(closestIndex([s1, s2, s3, s4], s1, match) == 0 && match);
2530     assert(closestIndex([s1, s2, s3, s4], s2, match) == 1 && match);
2531     assert(closestIndex([s1, s2, s3, s4], s3, match) == 2 && match);
2532     assert(closestIndex([s1, s2, s3, s4], s4, match) == 3 && match);
2533     assert(closestIndex([s1, s3, s4, s5], s5, match) == 3 && match);
2534 
2535     // Not found, odd size
2536     assert(closestIndex([s2, s4, s5], s1, match) == 0 && !match);
2537     assert(closestIndex([s1, s4, s5], s2, match) == 1 && !match);
2538     assert(closestIndex([s1, s2, s4], s3, match) == 2 && !match);
2539     assert(closestIndex([s1, s3, s5], s4, match) == 2 && !match);
2540     assert(closestIndex([s1, s2, s4], s5, match) == 3 && !match);
2541 }
2542 
2543 /***
2544  * Visits the return type of a function and writes leftover ABI tags
2545  * Params:
2546  *   tf = Type of the function to mangle the return type of
2547  *   previous = already written ones
2548  *   toWrite = where to put StringExp's to be written
2549  */
2550 private
2551 void leftOver(TypeFunction tf, const(Array!StringExp)* previous, Array!StringExp* toWrite)
2552 {
2553     extern(C++) final class LeftoverVisitor : Visitor
2554     {
2555         /// List of tags to write
2556         private Array!StringExp* toWrite;
2557         /// List of tags to ignore
2558         private const(Array!StringExp)* ignore;
2559 
2560         ///
2561         public this(const(Array!StringExp)* previous, Array!StringExp* toWrite)
2562         {
2563             this.ignore = previous;
2564             this.toWrite = toWrite;
2565         }
2566 
2567         /// Reintroduce base class overloads
2568         public alias visit = Visitor.visit;
2569 
2570         /// Least specialized overload of each direct child of `RootObject`
2571         public override void visit(Dsymbol o)
2572         {
2573             auto ale = ABITagContainer.forSymbol(o);
2574             if (!ale) return;
2575 
2576             bool match;
2577             foreach (elem; *ale.elements)
2578             {
2579                 auto se = elem.toStringExp();
2580                 closestIndex((*this.ignore)[], se, match);
2581                 if (match) continue;
2582                 auto idx = closestIndex((*this.toWrite)[], se, match);
2583                 if (!match)
2584                     (*this.toWrite).insert(idx, se);
2585             }
2586         }
2587 
2588         /// Ditto
2589         public override void visit(Type o)
2590         {
2591             if (auto sym = o.toDsymbol(null))
2592                 sym.accept(this);
2593         }
2594 
2595         /// Composite type
2596         public override void visit(TypePointer o)
2597         {
2598             o.next.accept(this);
2599         }
2600 
2601         public override void visit(TypeReference o)
2602         {
2603             o.next.accept(this);
2604         }
2605     }
2606 
2607     scope remainingVisitor = new LeftoverVisitor(previous, toWrite);
2608     tf.next.accept(remainingVisitor);
2609 }