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