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