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