Home | History | Annotate | Line # | Download | only in dmd
      1  1.1  mrg /**
      2  1.1  mrg  * This module contains the implementation of the C++ header generation available through
      3  1.1  mrg  * the command line switch -Hc.
      4  1.1  mrg  *
      5  1.1  mrg  * Copyright:   Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
      6  1.1  mrg  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
      7  1.1  mrg  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
      8  1.1  mrg  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d)
      9  1.1  mrg  * Documentation:  https://dlang.org/phobos/dmd_dtoh.html
     10  1.1  mrg  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtoh.d
     11  1.1  mrg  */
     12  1.1  mrg module dmd.dtoh;
     13  1.1  mrg 
     14  1.1  mrg import core.stdc.stdio;
     15  1.1  mrg import core.stdc.string;
     16  1.1  mrg import core.stdc.ctype;
     17  1.1  mrg 
     18  1.1  mrg import dmd.astcodegen;
     19  1.1  mrg import dmd.astenums;
     20  1.1  mrg import dmd.arraytypes;
     21  1.1  mrg import dmd.attrib;
     22  1.1  mrg import dmd.dsymbol;
     23  1.1  mrg import dmd.errors;
     24  1.1  mrg import dmd.globals;
     25  1.1  mrg import dmd.hdrgen;
     26  1.1  mrg import dmd.identifier;
     27  1.1  mrg import dmd.root.filename;
     28  1.1  mrg import dmd.visitor;
     29  1.1  mrg import dmd.tokens;
     30  1.1  mrg 
     31  1.1  mrg import dmd.common.outbuffer;
     32  1.1  mrg import dmd.utils;
     33  1.1  mrg 
     34  1.1  mrg //debug = Debug_DtoH;
     35  1.1  mrg 
     36  1.1  mrg // Generate asserts to validate the header
     37  1.1  mrg //debug = Debug_DtoH_Checks;
     38  1.1  mrg 
     39  1.1  mrg /**
     40  1.1  mrg  * Generates a C++ header containing bindings for all `extern(C[++])` declarations
     41  1.1  mrg  * found in the supplied modules.
     42  1.1  mrg  *
     43  1.1  mrg  * Params:
     44  1.1  mrg  *   ms = the modules
     45  1.1  mrg  *
     46  1.1  mrg  * Notes:
     47  1.1  mrg  *  - the header is written to `<global.params.cxxhdrdir>/<global.params.cxxhdrfile>`
     48  1.1  mrg  *    or `stdout` if no explicit file was specified
     49  1.1  mrg  *  - bindings conform to the C++ standard defined in `global.params.cplusplus`
     50  1.1  mrg  *  - ignored declarations are mentioned in a comment if `global.params.doCxxHdrGeneration`
     51  1.1  mrg  *    is set to `CxxHeaderMode.verbose`
     52  1.1  mrg  */
     53  1.1  mrg extern(C++) void genCppHdrFiles(ref Modules ms)
     54  1.1  mrg {
     55  1.1  mrg     initialize();
     56  1.1  mrg 
     57  1.1  mrg     OutBuffer fwd;
     58  1.1  mrg     OutBuffer done;
     59  1.1  mrg     OutBuffer decl;
     60  1.1  mrg 
     61  1.1  mrg     // enable indent by spaces on buffers
     62  1.1  mrg     fwd.doindent = true;
     63  1.1  mrg     fwd.spaces = true;
     64  1.1  mrg     decl.doindent = true;
     65  1.1  mrg     decl.spaces = true;
     66  1.1  mrg 
     67  1.1  mrg     scope v = new ToCppBuffer(&fwd, &done, &decl);
     68  1.1  mrg 
     69  1.1  mrg     // Conditionally include another buffer for sanity checks
     70  1.1  mrg     debug (Debug_DtoH_Checks)
     71  1.1  mrg     {
     72  1.1  mrg         OutBuffer check;
     73  1.1  mrg         check.doindent = true;
     74  1.1  mrg         check.spaces = true;
     75  1.1  mrg         v.checkbuf = &check;
     76  1.1  mrg     }
     77  1.1  mrg 
     78  1.1  mrg     OutBuffer buf;
     79  1.1  mrg     buf.doindent = true;
     80  1.1  mrg     buf.spaces = true;
     81  1.1  mrg 
     82  1.1  mrg     foreach (m; ms)
     83  1.1  mrg         m.accept(v);
     84  1.1  mrg 
     85  1.1  mrg     if (global.params.doCxxHdrGeneration == CxxHeaderMode.verbose)
     86  1.1  mrg         buf.printf("// Automatically generated by %s Compiler v%d", global.vendor.ptr, global.versionNumber());
     87  1.1  mrg     else
     88  1.1  mrg         buf.printf("// Automatically generated by %s Compiler", global.vendor.ptr);
     89  1.1  mrg 
     90  1.1  mrg     buf.writenl();
     91  1.1  mrg     buf.writenl();
     92  1.1  mrg     buf.writestringln("#pragma once");
     93  1.1  mrg     buf.writenl();
     94  1.1  mrg     hashInclude(buf, "<assert.h>");
     95  1.1  mrg     hashInclude(buf, "<stddef.h>");
     96  1.1  mrg     hashInclude(buf, "<stdint.h>");
     97  1.1  mrg     hashInclude(buf, "<math.h>");
     98  1.1  mrg //    buf.writestring(buf, "#include <stdio.h>\n");
     99  1.1  mrg //    buf.writestring("#include <string.h>\n");
    100  1.1  mrg 
    101  1.1  mrg     // Emit array compatibility because extern(C++) types may have slices
    102  1.1  mrg     // as members (as opposed to function parameters)
    103  1.1  mrg     buf.writestring(`
    104  1.1  mrg #ifdef CUSTOM_D_ARRAY_TYPE
    105  1.1  mrg #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
    106  1.1  mrg #else
    107  1.1  mrg /// Represents a D [] array
    108  1.1  mrg template<typename T>
    109  1.1  mrg struct _d_dynamicArray final
    110  1.1  mrg {
    111  1.1  mrg     size_t length;
    112  1.1  mrg     T *ptr;
    113  1.1  mrg 
    114  1.1  mrg     _d_dynamicArray() : length(0), ptr(NULL) { }
    115  1.1  mrg 
    116  1.1  mrg     _d_dynamicArray(size_t length_in, T *ptr_in)
    117  1.1  mrg         : length(length_in), ptr(ptr_in) { }
    118  1.1  mrg 
    119  1.1  mrg     T& operator[](const size_t idx) {
    120  1.1  mrg         assert(idx < length);
    121  1.1  mrg         return ptr[idx];
    122  1.1  mrg     }
    123  1.1  mrg 
    124  1.1  mrg     const T& operator[](const size_t idx) const {
    125  1.1  mrg         assert(idx < length);
    126  1.1  mrg         return ptr[idx];
    127  1.1  mrg     }
    128  1.1  mrg };
    129  1.1  mrg #endif
    130  1.1  mrg `);
    131  1.1  mrg 
    132  1.1  mrg     if (v.hasReal)
    133  1.1  mrg     {
    134  1.1  mrg         hashIf(buf, "!defined(_d_real)");
    135  1.1  mrg         {
    136  1.1  mrg             hashDefine(buf, "_d_real long double");
    137  1.1  mrg         }
    138  1.1  mrg         hashEndIf(buf);
    139  1.1  mrg     }
    140  1.1  mrg     buf.writenl();
    141  1.1  mrg     // buf.writestringln("// fwd:");
    142  1.1  mrg     buf.write(&fwd);
    143  1.1  mrg     if (fwd.length > 0)
    144  1.1  mrg         buf.writenl();
    145  1.1  mrg 
    146  1.1  mrg     // buf.writestringln("// done:");
    147  1.1  mrg     buf.write(&done);
    148  1.1  mrg 
    149  1.1  mrg     // buf.writestringln("// decl:");
    150  1.1  mrg     buf.write(&decl);
    151  1.1  mrg 
    152  1.1  mrg     debug (Debug_DtoH_Checks)
    153  1.1  mrg     {
    154  1.1  mrg         // buf.writestringln("// check:");
    155  1.1  mrg         buf.writestring(`
    156  1.1  mrg #if OFFSETS
    157  1.1  mrg     template <class T>
    158  1.1  mrg     size_t getSlotNumber(int dummy, ...)
    159  1.1  mrg     {
    160  1.1  mrg         T c;
    161  1.1  mrg         va_list ap;
    162  1.1  mrg         va_start(ap, dummy);
    163  1.1  mrg 
    164  1.1  mrg         void *f = va_arg(ap, void*);
    165  1.1  mrg         for (size_t i = 0; ; i++)
    166  1.1  mrg         {
    167  1.1  mrg             if ( (*(void***)&c)[i] == f)
    168  1.1  mrg             return i;
    169  1.1  mrg         }
    170  1.1  mrg         va_end(ap);
    171  1.1  mrg     }
    172  1.1  mrg 
    173  1.1  mrg     void testOffsets()
    174  1.1  mrg     {
    175  1.1  mrg `);
    176  1.1  mrg         buf.write(&check);
    177  1.1  mrg         buf.writestring(`
    178  1.1  mrg     }
    179  1.1  mrg #endif
    180  1.1  mrg `);
    181  1.1  mrg     }
    182  1.1  mrg 
    183  1.1  mrg     // prevent trailing newlines
    184  1.1  mrg     version (Windows)
    185  1.1  mrg         while (buf.length >= 4 && buf[$-4..$] == "\r\n\r\n")
    186  1.1  mrg             buf.remove(buf.length - 2, 2);
    187  1.1  mrg     else
    188  1.1  mrg         while (buf.length >= 2 && buf[$-2..$] == "\n\n")
    189  1.1  mrg             buf.remove(buf.length - 1, 1);
    190  1.1  mrg 
    191  1.1  mrg 
    192  1.1  mrg     if (global.params.cxxhdrname is null)
    193  1.1  mrg     {
    194  1.1  mrg         // Write to stdout; assume it succeeds
    195  1.1  mrg         size_t n = fwrite(buf[].ptr, 1, buf.length, stdout);
    196  1.1  mrg         assert(n == buf.length); // keep gcc happy about return values
    197  1.1  mrg     }
    198  1.1  mrg     else
    199  1.1  mrg     {
    200  1.1  mrg         const(char)[] name = FileName.combine(global.params.cxxhdrdir, global.params.cxxhdrname);
    201  1.1  mrg         writeFile(Loc.initial, name, buf[]);
    202  1.1  mrg     }
    203  1.1  mrg }
    204  1.1  mrg 
    205  1.1  mrg private:
    206  1.1  mrg 
    207  1.1  mrg /****************************************************
    208  1.1  mrg  * Visitor that writes bindings for `extern(C[++]` declarations.
    209  1.1  mrg  */
    210  1.1  mrg extern(C++) final class ToCppBuffer : Visitor
    211  1.1  mrg {
    212  1.1  mrg     alias visit = Visitor.visit;
    213  1.1  mrg public:
    214  1.1  mrg     enum EnumKind
    215  1.1  mrg     {
    216  1.1  mrg         Int,
    217  1.1  mrg         Numeric,
    218  1.1  mrg         String,
    219  1.1  mrg         Enum,
    220  1.1  mrg         Other
    221  1.1  mrg     }
    222  1.1  mrg 
    223  1.1  mrg     /// Namespace providing the actual AST nodes
    224  1.1  mrg     alias AST = ASTCodegen;
    225  1.1  mrg 
    226  1.1  mrg     /// Visited nodes
    227  1.1  mrg     bool[void*] visited;
    228  1.1  mrg 
    229  1.1  mrg     /// Forward declared nodes (which might not be emitted yet)
    230  1.1  mrg     bool[void*] forwarded;
    231  1.1  mrg 
    232  1.1  mrg     /// Buffer for forward declarations
    233  1.1  mrg     OutBuffer* fwdbuf;
    234  1.1  mrg 
    235  1.1  mrg     /// Buffer for integrity checks
    236  1.1  mrg     debug (Debug_DtoH_Checks) OutBuffer* checkbuf;
    237  1.1  mrg 
    238  1.1  mrg     /// Buffer for declarations that must emitted before the currently
    239  1.1  mrg     /// visited node but can't be forward declared (see `includeSymbol`)
    240  1.1  mrg     OutBuffer* donebuf;
    241  1.1  mrg 
    242  1.1  mrg     /// Default buffer for the currently visited declaration
    243  1.1  mrg     OutBuffer* buf;
    244  1.1  mrg 
    245  1.1  mrg     /// The generated header uses `real` emitted as `_d_real`?
    246  1.1  mrg     bool hasReal;
    247  1.1  mrg 
    248  1.1  mrg     /// The generated header should contain comments for skipped declarations?
    249  1.1  mrg     const bool printIgnored;
    250  1.1  mrg 
    251  1.1  mrg     /// State specific to the current context which depends
    252  1.1  mrg     /// on the currently visited node and it's parents
    253  1.1  mrg     static struct Context
    254  1.1  mrg     {
    255  1.1  mrg         /// Default linkage in the current scope (e.g. LINK.c inside `extern(C) { ... }`)
    256  1.1  mrg         LINK linkage = LINK.d;
    257  1.1  mrg 
    258  1.1  mrg         /// Enclosing class / struct / union
    259  1.1  mrg         AST.AggregateDeclaration adparent;
    260  1.1  mrg 
    261  1.1  mrg         /// Enclosing template declaration
    262  1.1  mrg         AST.TemplateDeclaration tdparent;
    263  1.1  mrg 
    264  1.1  mrg         /// Identifier of the currently visited `VarDeclaration`
    265  1.1  mrg         /// (required to write variables of funtion pointers)
    266  1.1  mrg         Identifier ident;
    267  1.1  mrg 
    268  1.1  mrg         /// Original type of the currently visited declaration
    269  1.1  mrg         AST.Type origType;
    270  1.1  mrg 
    271  1.1  mrg         /// Last written visibility level applying to the current scope
    272  1.1  mrg         AST.Visibility.Kind currentVisibility;
    273  1.1  mrg 
    274  1.1  mrg         /// Currently applicable storage classes
    275  1.1  mrg         AST.STC storageClass;
    276  1.1  mrg 
    277  1.1  mrg          /// How many symbols were ignored
    278  1.1  mrg         int ignoredCounter;
    279  1.1  mrg 
    280  1.1  mrg         /// Currently visited types are required by another declaration
    281  1.1  mrg         /// and hence must be emitted
    282  1.1  mrg         bool mustEmit;
    283  1.1  mrg 
    284  1.1  mrg         /// Processing a type that can be forward referenced
    285  1.1  mrg         bool forwarding;
    286  1.1  mrg 
    287  1.1  mrg         /// Inside of an anonymous struct/union (AnonDeclaration)
    288  1.1  mrg         bool inAnonymousDecl;
    289  1.1  mrg     }
    290  1.1  mrg 
    291  1.1  mrg     /// Informations about the current context in the AST
    292  1.1  mrg     Context context;
    293  1.1  mrg     alias context this;
    294  1.1  mrg 
    295  1.1  mrg     this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf)
    296  1.1  mrg     {
    297  1.1  mrg         this.fwdbuf = fwdbuf;
    298  1.1  mrg         this.donebuf = donebuf;
    299  1.1  mrg         this.buf = buf;
    300  1.1  mrg         this.printIgnored = global.params.doCxxHdrGeneration == CxxHeaderMode.verbose;
    301  1.1  mrg     }
    302  1.1  mrg 
    303  1.1  mrg     /**
    304  1.1  mrg      * Emits `dsym` into `donebuf` s.t. it is declared before the currently
    305  1.1  mrg      * visited symbol that written to `buf`.
    306  1.1  mrg      *
    307  1.1  mrg      * Temporarily clears `context` to behave as if it was visited normally.
    308  1.1  mrg      */
    309  1.1  mrg     private void includeSymbol(AST.Dsymbol dsym)
    310  1.1  mrg     {
    311  1.1  mrg         debug (Debug_DtoH)
    312  1.1  mrg         {
    313  1.1  mrg             printf("[includeSymbol(AST.Dsymbol) enter] %s\n", dsym.toChars());
    314  1.1  mrg             scope(exit) printf("[includeSymbol(AST.Dsymbol) exit] %s\n", dsym.toChars());
    315  1.1  mrg         }
    316  1.1  mrg 
    317  1.1  mrg         auto ptr = cast(void*) dsym in visited;
    318  1.1  mrg         if (ptr && *ptr)
    319  1.1  mrg             return;
    320  1.1  mrg 
    321  1.1  mrg         // Temporary replacement for `buf` which is appended to `donebuf`
    322  1.1  mrg         OutBuffer decl;
    323  1.1  mrg         decl.doindent = true;
    324  1.1  mrg         decl.spaces = true;
    325  1.1  mrg         scope (exit) donebuf.write(&decl);
    326  1.1  mrg 
    327  1.1  mrg         auto ctxStash = this.context;
    328  1.1  mrg         auto bufStash = this.buf;
    329  1.1  mrg 
    330  1.1  mrg         this.context = Context.init;
    331  1.1  mrg         this.buf = &decl;
    332  1.1  mrg         this.mustEmit = true;
    333  1.1  mrg 
    334  1.1  mrg         dsym.accept(this);
    335  1.1  mrg 
    336  1.1  mrg         this.context = ctxStash;
    337  1.1  mrg         this.buf = bufStash;
    338  1.1  mrg     }
    339  1.1  mrg 
    340  1.1  mrg     /// Determines what kind of enum `type` is (see `EnumKind`)
    341  1.1  mrg     private EnumKind getEnumKind(AST.Type type)
    342  1.1  mrg     {
    343  1.1  mrg         if (type) switch (type.ty)
    344  1.1  mrg         {
    345  1.1  mrg             case AST.Tint32:
    346  1.1  mrg                 return EnumKind.Int;
    347  1.1  mrg             case AST.Tbool,
    348  1.1  mrg                 AST.Tchar, AST.Twchar, AST.Tdchar,
    349  1.1  mrg                 AST.Tint8, AST.Tuns8,
    350  1.1  mrg                 AST.Tint16, AST.Tuns16,
    351  1.1  mrg                 AST.Tuns32,
    352  1.1  mrg                 AST.Tint64, AST.Tuns64:
    353  1.1  mrg                 return EnumKind.Numeric;
    354  1.1  mrg             case AST.Tarray:
    355  1.1  mrg                 if (type.isString())
    356  1.1  mrg                     return EnumKind.String;
    357  1.1  mrg                 break;
    358  1.1  mrg             case AST.Tenum:
    359  1.1  mrg                 return EnumKind.Enum;
    360  1.1  mrg             default:
    361  1.1  mrg                 break;
    362  1.1  mrg         }
    363  1.1  mrg         return EnumKind.Other;
    364  1.1  mrg     }
    365  1.1  mrg 
    366  1.1  mrg     /// Determines the type used to represent `type` in C++.
    367  1.1  mrg     /// Returns: `const [w,d]char*` for `[w,d]string` or `type`
    368  1.1  mrg     private AST.Type determineEnumType(AST.Type type)
    369  1.1  mrg     {
    370  1.1  mrg         if (auto arr = type.isTypeDArray())
    371  1.1  mrg         {
    372  1.1  mrg             switch (arr.next.ty)
    373  1.1  mrg             {
    374  1.1  mrg                 case AST.Tchar:  return AST.Type.tchar.constOf.pointerTo;
    375  1.1  mrg                 case AST.Twchar: return AST.Type.twchar.constOf.pointerTo;
    376  1.1  mrg                 case AST.Tdchar: return AST.Type.tdchar.constOf.pointerTo;
    377  1.1  mrg                 default: break;
    378  1.1  mrg             }
    379  1.1  mrg         }
    380  1.1  mrg         return type;
    381  1.1  mrg     }
    382  1.1  mrg 
    383  1.1  mrg     /// Writes a final `;` and insert an empty line outside of aggregates
    384  1.1  mrg     private void writeDeclEnd()
    385  1.1  mrg     {
    386  1.1  mrg         buf.writestringln(";");
    387  1.1  mrg 
    388  1.1  mrg         if (!adparent)
    389  1.1  mrg             buf.writenl();
    390  1.1  mrg     }
    391  1.1  mrg 
    392  1.1  mrg     /// Writes the corresponding access specifier if necessary
    393  1.1  mrg     private void writeProtection(const AST.Visibility.Kind kind)
    394  1.1  mrg     {
    395  1.1  mrg         // Don't write visibility for global declarations
    396  1.1  mrg         if (!adparent || inAnonymousDecl)
    397  1.1  mrg             return;
    398  1.1  mrg 
    399  1.1  mrg         string token;
    400  1.1  mrg 
    401  1.1  mrg         switch(kind) with(AST.Visibility.Kind)
    402  1.1  mrg         {
    403  1.1  mrg             case none, private_:
    404  1.1  mrg                 if (this.currentVisibility == AST.Visibility.Kind.private_)
    405  1.1  mrg                     return;
    406  1.1  mrg                 this.currentVisibility = AST.Visibility.Kind.private_;
    407  1.1  mrg                 token = "private:";
    408  1.1  mrg                 break;
    409  1.1  mrg 
    410  1.1  mrg             case package_, protected_:
    411  1.1  mrg                 if (this.currentVisibility == AST.Visibility.Kind.protected_)
    412  1.1  mrg                     return;
    413  1.1  mrg                 this.currentVisibility = AST.Visibility.Kind.protected_;
    414  1.1  mrg                 token = "protected:";
    415  1.1  mrg                 break;
    416  1.1  mrg 
    417  1.1  mrg             case undefined, public_, export_:
    418  1.1  mrg                 if (this.currentVisibility == AST.Visibility.Kind.public_)
    419  1.1  mrg                     return;
    420  1.1  mrg                 this.currentVisibility = AST.Visibility.Kind.public_;
    421  1.1  mrg                 token = "public:";
    422  1.1  mrg                 break;
    423  1.1  mrg 
    424  1.1  mrg             default:
    425  1.1  mrg                 printf("Unexpected visibility: %d!\n", kind);
    426  1.1  mrg                 assert(0);
    427  1.1  mrg         }
    428  1.1  mrg 
    429  1.1  mrg         buf.level--;
    430  1.1  mrg         buf.writestringln(token);
    431  1.1  mrg         buf.level++;
    432  1.1  mrg     }
    433  1.1  mrg 
    434  1.1  mrg     /**
    435  1.1  mrg      * Writes an identifier into `buf` and checks for reserved identifiers. The
    436  1.1  mrg      * parameter `canFix` determines how this function handles C++ keywords:
    437  1.1  mrg      *
    438  1.1  mrg      * `false` => Raise a warning and print the identifier as-is
    439  1.1  mrg      * `true`  => Append an underscore to the identifier
    440  1.1  mrg      *
    441  1.1  mrg      * Params:
    442  1.1  mrg      *   s        = the symbol denoting the identifier
    443  1.1  mrg      *   canFixup = whether the identifier may be changed without affecting
    444  1.1  mrg      *              binary compatibility
    445  1.1  mrg      */
    446  1.1  mrg     private void writeIdentifier(const AST.Dsymbol s, const bool canFix = false)
    447  1.1  mrg     {
    448  1.1  mrg         if (const mn = getMangleOverride(s))
    449  1.1  mrg             return buf.writestring(mn);
    450  1.1  mrg 
    451  1.1  mrg         writeIdentifier(s.ident, s.loc, s.kind(), canFix);
    452  1.1  mrg     }
    453  1.1  mrg 
    454  1.1  mrg     /** Overload of `writeIdentifier` used for all AST nodes not descending from Dsymbol **/
    455  1.1  mrg     private void writeIdentifier(const Identifier ident, const Loc loc, const char* kind, const bool canFix = false)
    456  1.1  mrg     {
    457  1.1  mrg         bool needsFix;
    458  1.1  mrg 
    459  1.1  mrg         void warnCxxCompat(const(char)* reason)
    460  1.1  mrg         {
    461  1.1  mrg             if (canFix)
    462  1.1  mrg             {
    463  1.1  mrg                 needsFix = true;
    464  1.1  mrg                 return;
    465  1.1  mrg             }
    466  1.1  mrg 
    467  1.1  mrg             __gshared bool warned = false;
    468  1.1  mrg             warning(loc, "%s `%s` is a %s", kind, ident.toChars(), reason);
    469  1.1  mrg 
    470  1.1  mrg             if (!warned)
    471  1.1  mrg             {
    472  1.1  mrg                 warningSupplemental(loc, "The generated C++ header will contain " ~
    473  1.1  mrg                                     "identifiers that are keywords in C++");
    474  1.1  mrg                 warned = true;
    475  1.1  mrg             }
    476  1.1  mrg         }
    477  1.1  mrg 
    478  1.1  mrg         if (global.params.warnings != DiagnosticReporting.off || canFix)
    479  1.1  mrg         {
    480  1.1  mrg             // Warn about identifiers that are keywords in C++.
    481  1.1  mrg             if (auto kc = keywordClass(ident))
    482  1.1  mrg                 warnCxxCompat(kc);
    483  1.1  mrg         }
    484  1.1  mrg         buf.writestring(ident.toString());
    485  1.1  mrg         if (needsFix)
    486  1.1  mrg             buf.writeByte('_');
    487  1.1  mrg     }
    488  1.1  mrg 
    489  1.1  mrg     /// Checks whether `t` is a type that can be exported to C++
    490  1.1  mrg     private bool isSupportedType(AST.Type t)
    491  1.1  mrg     {
    492  1.1  mrg         if (!t)
    493  1.1  mrg         {
    494  1.1  mrg             assert(tdparent);
    495  1.1  mrg             return true;
    496  1.1  mrg         }
    497  1.1  mrg 
    498  1.1  mrg         switch (t.ty)
    499  1.1  mrg         {
    500  1.1  mrg             // Nested types
    501  1.1  mrg             case AST.Tarray:
    502  1.1  mrg             case AST.Tsarray:
    503  1.1  mrg             case AST.Tpointer:
    504  1.1  mrg             case AST.Treference:
    505  1.1  mrg             case AST.Tdelegate:
    506  1.1  mrg                 return isSupportedType((cast(AST.TypeNext) t).next);
    507  1.1  mrg 
    508  1.1  mrg             // Function pointers
    509  1.1  mrg             case AST.Tfunction:
    510  1.1  mrg             {
    511  1.1  mrg                 auto tf = cast(AST.TypeFunction) t;
    512  1.1  mrg                 if (!isSupportedType(tf.next))
    513  1.1  mrg                     return false;
    514  1.1  mrg                 foreach (_, param; tf.parameterList)
    515  1.1  mrg                 {
    516  1.1  mrg                     if (!isSupportedType(param.type))
    517  1.1  mrg                         return false;
    518  1.1  mrg                 }
    519  1.1  mrg                 return true;
    520  1.1  mrg             }
    521  1.1  mrg 
    522  1.1  mrg             // Noreturn has a different mangling
    523  1.1  mrg             case AST.Tnoreturn:
    524  1.1  mrg 
    525  1.1  mrg             // _Imaginary is C only.
    526  1.1  mrg             case AST.Timaginary32:
    527  1.1  mrg             case AST.Timaginary64:
    528  1.1  mrg             case AST.Timaginary80:
    529  1.1  mrg                 return false;
    530  1.1  mrg             default:
    531  1.1  mrg                 return true;
    532  1.1  mrg         }
    533  1.1  mrg     }
    534  1.1  mrg 
    535  1.1  mrg     override void visit(AST.Dsymbol s)
    536  1.1  mrg     {
    537  1.1  mrg         debug (Debug_DtoH)
    538  1.1  mrg         {
    539  1.1  mrg             mixin(traceVisit!s);
    540  1.1  mrg             import dmd.asttypename;
    541  1.1  mrg             printf("[AST.Dsymbol enter] %s\n", s.astTypeName().ptr);
    542  1.1  mrg         }
    543  1.1  mrg     }
    544  1.1  mrg 
    545  1.1  mrg     override void visit(AST.Import i)
    546  1.1  mrg     {
    547  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!i);
    548  1.1  mrg 
    549  1.1  mrg         /// Writes `using <alias_> = <sym.ident>` into `buf`
    550  1.1  mrg         const(char*) writeImport(AST.Dsymbol sym, const Identifier alias_)
    551  1.1  mrg         {
    552  1.1  mrg             /// `using` was introduced in C++ 11 and only works for types...
    553  1.1  mrg             if (global.params.cplusplus < CppStdRevision.cpp11)
    554  1.1  mrg                 return "requires C++11";
    555  1.1  mrg 
    556  1.1  mrg             if (auto ad = sym.isAliasDeclaration())
    557  1.1  mrg             {
    558  1.1  mrg                 sym = ad.toAlias();
    559  1.1  mrg                 ad = sym.isAliasDeclaration();
    560  1.1  mrg 
    561  1.1  mrg                 // Might be an alias to a basic type
    562  1.1  mrg                 if (ad && !ad.aliassym && ad.type)
    563  1.1  mrg                     goto Emit;
    564  1.1  mrg             }
    565  1.1  mrg 
    566  1.1  mrg             // Restricted to types and other aliases
    567  1.1  mrg             if (!sym.isScopeDsymbol() && !sym.isAggregateDeclaration())
    568  1.1  mrg                 return "only supports types";
    569  1.1  mrg 
    570  1.1  mrg             // Write `using <alias_> = `<sym>`
    571  1.1  mrg             Emit:
    572  1.1  mrg             buf.writestring("using ");
    573  1.1  mrg             writeIdentifier(alias_, i.loc, "renamed import");
    574  1.1  mrg             buf.writestring(" = ");
    575  1.1  mrg             // Start at module scope to avoid collisions with local symbols
    576  1.1  mrg             if (this.context.adparent)
    577  1.1  mrg                 buf.writestring("::");
    578  1.1  mrg             buf.writestring(sym.ident.toString());
    579  1.1  mrg             writeDeclEnd();
    580  1.1  mrg             return null;
    581  1.1  mrg         }
    582  1.1  mrg 
    583  1.1  mrg         // Only missing without semantic analysis
    584  1.1  mrg         // FIXME: Templates need work due to missing parent & imported module
    585  1.1  mrg         if (!i.parent)
    586  1.1  mrg         {
    587  1.1  mrg             assert(tdparent);
    588  1.1  mrg             ignored("`%s` because it's inside of a template declaration", i.toChars());
    589  1.1  mrg             return;
    590  1.1  mrg         }
    591  1.1  mrg 
    592  1.1  mrg         // Non-public imports don't create new symbols, include as needed
    593  1.1  mrg         if (i.visibility.kind < AST.Visibility.Kind.public_)
    594  1.1  mrg             return;
    595  1.1  mrg 
    596  1.1  mrg         // Symbols from static imports should be emitted inline
    597  1.1  mrg         if (i.isstatic)
    598  1.1  mrg             return;
    599  1.1  mrg 
    600  1.1  mrg         const isLocal = !i.parent.isModule();
    601  1.1  mrg 
    602  1.1  mrg         // Need module for symbol lookup
    603  1.1  mrg         assert(i.mod);
    604  1.1  mrg 
    605  1.1  mrg         // Emit an alias for each public module member
    606  1.1  mrg         if (isLocal && i.names.length == 0)
    607  1.1  mrg         {
    608  1.1  mrg             assert(i.mod.symtab);
    609  1.1  mrg 
    610  1.1  mrg             // Sort alphabetically s.t. slight changes in semantic don't cause
    611  1.1  mrg             // massive changes in the order of declarations
    612  1.1  mrg             AST.Dsymbols entries;
    613  1.1  mrg             entries.reserve(i.mod.symtab.length);
    614  1.1  mrg 
    615  1.1  mrg             foreach (entry; i.mod.symtab.tab.asRange)
    616  1.1  mrg             {
    617  1.1  mrg                 // Skip anonymous / invisible members
    618  1.1  mrg                 import dmd.access : symbolIsVisible;
    619  1.1  mrg                 if (!entry.key.isAnonymous() && symbolIsVisible(i, entry.value))
    620  1.1  mrg                     entries.push(entry.value);
    621  1.1  mrg             }
    622  1.1  mrg 
    623  1.1  mrg             // Seperate function because of a spurious dual-context deprecation
    624  1.1  mrg             static int compare(const AST.Dsymbol* a, const AST.Dsymbol* b)
    625  1.1  mrg             {
    626  1.1  mrg                 return strcmp(a.ident.toChars(), b.ident.toChars());
    627  1.1  mrg             }
    628  1.1  mrg             entries.sort!compare();
    629  1.1  mrg 
    630  1.1  mrg             foreach (sym; entries)
    631  1.1  mrg             {
    632  1.1  mrg                 includeSymbol(sym);
    633  1.1  mrg                 if (auto err = writeImport(sym, sym.ident))
    634  1.1  mrg                     ignored("public import for `%s` because `using` %s", sym.ident.toChars(), err);
    635  1.1  mrg             }
    636  1.1  mrg             return;
    637  1.1  mrg         }
    638  1.1  mrg 
    639  1.1  mrg         // Include all public imports and emit using declarations for each alias
    640  1.1  mrg         foreach (const idx, name; i.names)
    641  1.1  mrg         {
    642  1.1  mrg             // Search the imported symbol
    643  1.1  mrg             auto sym = i.mod.search(Loc.initial, name);
    644  1.1  mrg             assert(sym); // Missing imports should error during semantic
    645  1.1  mrg 
    646  1.1  mrg             includeSymbol(sym);
    647  1.1  mrg 
    648  1.1  mrg             // Detect the assigned name for renamed import
    649  1.1  mrg             auto alias_ = i.aliases[idx];
    650  1.1  mrg             if (!alias_)
    651  1.1  mrg                 continue;
    652  1.1  mrg 
    653  1.1  mrg             if (auto err = writeImport(sym, alias_))
    654  1.1  mrg                 ignored("renamed import `%s = %s` because `using` %s", alias_.toChars(), name.toChars(), err);
    655  1.1  mrg         }
    656  1.1  mrg     }
    657  1.1  mrg 
    658  1.1  mrg     override void visit(AST.AttribDeclaration pd)
    659  1.1  mrg     {
    660  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!pd);
    661  1.1  mrg 
    662  1.1  mrg         Dsymbols* decl = pd.include(null);
    663  1.1  mrg         if (!decl)
    664  1.1  mrg             return;
    665  1.1  mrg 
    666  1.1  mrg         foreach (s; *decl)
    667  1.1  mrg         {
    668  1.1  mrg             if (adparent || s.visible().kind >= AST.Visibility.Kind.public_)
    669  1.1  mrg                 s.accept(this);
    670  1.1  mrg         }
    671  1.1  mrg     }
    672  1.1  mrg 
    673  1.1  mrg     override void visit(AST.StorageClassDeclaration scd)
    674  1.1  mrg     {
    675  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!scd);
    676  1.1  mrg 
    677  1.1  mrg         const stcStash = this.storageClass;
    678  1.1  mrg         this.storageClass |= scd.stc;
    679  1.1  mrg         visit(cast(AST.AttribDeclaration) scd);
    680  1.1  mrg         this.storageClass = stcStash;
    681  1.1  mrg     }
    682  1.1  mrg 
    683  1.1  mrg     override void visit(AST.LinkDeclaration ld)
    684  1.1  mrg     {
    685  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!ld);
    686  1.1  mrg 
    687  1.1  mrg         auto save = linkage;
    688  1.1  mrg         linkage = ld.linkage;
    689  1.1  mrg         visit(cast(AST.AttribDeclaration)ld);
    690  1.1  mrg         linkage = save;
    691  1.1  mrg     }
    692  1.1  mrg 
    693  1.1  mrg     override void visit(AST.CPPMangleDeclaration md)
    694  1.1  mrg     {
    695  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!md);
    696  1.1  mrg 
    697  1.1  mrg         const oldLinkage = this.linkage;
    698  1.1  mrg         this.linkage = LINK.cpp;
    699  1.1  mrg         visit(cast(AST.AttribDeclaration) md);
    700  1.1  mrg         this.linkage = oldLinkage;
    701  1.1  mrg     }
    702  1.1  mrg 
    703  1.1  mrg     override void visit(AST.Module m)
    704  1.1  mrg     {
    705  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!m);
    706  1.1  mrg 
    707  1.1  mrg         foreach (s; *m.members)
    708  1.1  mrg         {
    709  1.1  mrg             if (s.visible().kind < AST.Visibility.Kind.public_)
    710  1.1  mrg                 continue;
    711  1.1  mrg             s.accept(this);
    712  1.1  mrg         }
    713  1.1  mrg     }
    714  1.1  mrg 
    715  1.1  mrg     override void visit(AST.FuncDeclaration fd)
    716  1.1  mrg     {
    717  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!fd);
    718  1.1  mrg 
    719  1.1  mrg         if (cast(void*)fd in visited)
    720  1.1  mrg             return;
    721  1.1  mrg         // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars());
    722  1.1  mrg         visited[cast(void*)fd] = true;
    723  1.1  mrg 
    724  1.1  mrg         // silently ignore non-user-defined destructors
    725  1.1  mrg         if (fd.isGenerated && fd.isDtorDeclaration())
    726  1.1  mrg             return;
    727  1.1  mrg 
    728  1.1  mrg         // Note that tf might be null for templated (member) functions
    729  1.1  mrg         auto tf = cast(AST.TypeFunction)fd.type;
    730  1.1  mrg         if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
    731  1.1  mrg         {
    732  1.1  mrg             ignored("function %s because of linkage", fd.toPrettyChars());
    733  1.1  mrg             return checkFunctionNeedsPlaceholder(fd);
    734  1.1  mrg         }
    735  1.1  mrg         if (fd.mangleOverride && tf && tf.linkage != LINK.c)
    736  1.1  mrg         {
    737  1.1  mrg             ignored("function %s because C++ doesn't support explicit mangling", fd.toPrettyChars());
    738  1.1  mrg             return checkFunctionNeedsPlaceholder(fd);
    739  1.1  mrg         }
    740  1.1  mrg         if (!adparent && !fd.fbody)
    741  1.1  mrg         {
    742  1.1  mrg             ignored("function %s because it is extern", fd.toPrettyChars());
    743  1.1  mrg             return;
    744  1.1  mrg         }
    745  1.1  mrg         if (fd.visibility.kind == AST.Visibility.Kind.none || fd.visibility.kind == AST.Visibility.Kind.private_)
    746  1.1  mrg         {
    747  1.1  mrg             ignored("function %s because it is private", fd.toPrettyChars());
    748  1.1  mrg             return;
    749  1.1  mrg         }
    750  1.1  mrg         if (tf && !isSupportedType(tf.next))
    751  1.1  mrg         {
    752  1.1  mrg             ignored("function %s because its return type cannot be mapped to C++", fd.toPrettyChars());
    753  1.1  mrg             return checkFunctionNeedsPlaceholder(fd);
    754  1.1  mrg         }
    755  1.1  mrg         if (tf) foreach (i, fparam; tf.parameterList)
    756  1.1  mrg         {
    757  1.1  mrg             if (!isSupportedType(fparam.type))
    758  1.1  mrg             {
    759  1.1  mrg                 ignored("function %s because one of its parameters has type `%s` which cannot be mapped to C++",
    760  1.1  mrg                         fd.toPrettyChars(), fparam.type.toChars());
    761  1.1  mrg                 return checkFunctionNeedsPlaceholder(fd);
    762  1.1  mrg             }
    763  1.1  mrg         }
    764  1.1  mrg 
    765  1.1  mrg         writeProtection(fd.visibility.kind);
    766  1.1  mrg 
    767  1.1  mrg         if (tf && tf.linkage == LINK.c)
    768  1.1  mrg             buf.writestring("extern \"C\" ");
    769  1.1  mrg         else if (!adparent)
    770  1.1  mrg             buf.writestring("extern ");
    771  1.1  mrg         if (adparent && fd.isStatic())
    772  1.1  mrg             buf.writestring("static ");
    773  1.1  mrg         else if (adparent && (
    774  1.1  mrg             // Virtual functions in non-templated classes
    775  1.1  mrg             (fd.vtblIndex != -1 && !fd.isOverride()) ||
    776  1.1  mrg 
    777  1.1  mrg             // Virtual functions in templated classes (fd.vtblIndex still -1)
    778  1.1  mrg             (tdparent && adparent.isClassDeclaration() && !(this.storageClass & AST.STC.final_ || fd.isFinal))))
    779  1.1  mrg                 buf.writestring("virtual ");
    780  1.1  mrg 
    781  1.1  mrg         debug (Debug_DtoH_Checks)
    782  1.1  mrg         if (adparent && !tdparent)
    783  1.1  mrg         {
    784  1.1  mrg             auto s = adparent.search(Loc.initial, fd.ident);
    785  1.1  mrg             auto cd = adparent.isClassDeclaration();
    786  1.1  mrg 
    787  1.1  mrg             if (!(adparent.storage_class & AST.STC.abstract_) &&
    788  1.1  mrg                 !(cd && cd.isAbstract()) &&
    789  1.1  mrg                 s is fd && !fd.overnext)
    790  1.1  mrg             {
    791  1.1  mrg                 const cn = adparent.ident.toChars();
    792  1.1  mrg                 const fn = fd.ident.toChars();
    793  1.1  mrg                 const vi = fd.vtblIndex;
    794  1.1  mrg 
    795  1.1  mrg                 checkbuf.printf("assert(getSlotNumber <%s>(0, &%s::%s) == %d);",
    796  1.1  mrg                                                        cn,     cn, fn,    vi);
    797  1.1  mrg                 checkbuf.writenl();
    798  1.1  mrg            }
    799  1.1  mrg         }
    800  1.1  mrg 
    801  1.1  mrg         if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11)
    802  1.1  mrg             writeProtection(AST.Visibility.Kind.private_);
    803  1.1  mrg         funcToBuffer(tf, fd);
    804  1.1  mrg         // FIXME: How to determine if fd is const without tf?
    805  1.1  mrg         if (adparent && tf && (tf.isConst() || tf.isImmutable()))
    806  1.1  mrg         {
    807  1.1  mrg             bool fdOverridesAreConst = true;
    808  1.1  mrg             foreach (fdv; fd.foverrides)
    809  1.1  mrg             {
    810  1.1  mrg                 auto tfv = cast(AST.TypeFunction)fdv.type;
    811  1.1  mrg                 if (!tfv.isConst() && !tfv.isImmutable())
    812  1.1  mrg                 {
    813  1.1  mrg                     fdOverridesAreConst = false;
    814  1.1  mrg                     break;
    815  1.1  mrg                 }
    816  1.1  mrg             }
    817  1.1  mrg 
    818  1.1  mrg             buf.writestring(fdOverridesAreConst ? " const" : " /* const */");
    819  1.1  mrg         }
    820  1.1  mrg         if (adparent && fd.isAbstract())
    821  1.1  mrg             buf.writestring(" = 0");
    822  1.1  mrg         if (adparent && fd.isDisabled && global.params.cplusplus >= CppStdRevision.cpp11)
    823  1.1  mrg             buf.writestring(" = delete");
    824  1.1  mrg         buf.writestringln(";");
    825  1.1  mrg         if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11)
    826  1.1  mrg             writeProtection(AST.Visibility.Kind.public_);
    827  1.1  mrg 
    828  1.1  mrg         if (!adparent)
    829  1.1  mrg             buf.writenl();
    830  1.1  mrg 
    831  1.1  mrg     }
    832  1.1  mrg 
    833  1.1  mrg     /++
    834  1.1  mrg      + Checks whether `fd` is a function that requires a dummy declaration
    835  1.1  mrg      + instead of simply emitting the declaration (because it would cause
    836  1.1  mrg      + ABI / behaviour issues). This includes:
    837  1.1  mrg      +
    838  1.1  mrg      + - virtual functions to ensure proper vtable layout
    839  1.1  mrg      + - destructors that would break RAII
    840  1.1  mrg      +/
    841  1.1  mrg     private void checkFunctionNeedsPlaceholder(AST.FuncDeclaration fd)
    842  1.1  mrg     {
    843  1.1  mrg         // Omit redundant declarations - the slot was already
    844  1.1  mrg         // reserved in the base class
    845  1.1  mrg         if (fd.isVirtual() && fd.isIntroducing())
    846  1.1  mrg         {
    847  1.1  mrg             // Hide placeholders because they are not ABI compatible
    848  1.1  mrg             writeProtection(AST.Visibility.Kind.private_);
    849  1.1  mrg 
    850  1.1  mrg             __gshared int counter; // Ensure unique names in all cases
    851  1.1  mrg             buf.printf("virtual void __vtable_slot_%u();", counter++);
    852  1.1  mrg             buf.writenl();
    853  1.1  mrg         }
    854  1.1  mrg         else if (fd.isDtorDeclaration())
    855  1.1  mrg         {
    856  1.1  mrg             // Create inaccessible dtor to prevent code from keeping instances that
    857  1.1  mrg             // need to be destroyed on the C++ side (but cannot call the dtor)
    858  1.1  mrg             writeProtection(AST.Visibility.Kind.private_);
    859  1.1  mrg             buf.writeByte('~');
    860  1.1  mrg             buf.writestring(adparent.ident.toString());
    861  1.1  mrg             buf.writestringln("();");
    862  1.1  mrg         }
    863  1.1  mrg     }
    864  1.1  mrg 
    865  1.1  mrg     override void visit(AST.UnitTestDeclaration utd)
    866  1.1  mrg     {
    867  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!utd);
    868  1.1  mrg     }
    869  1.1  mrg 
    870  1.1  mrg     override void visit(AST.VarDeclaration vd)
    871  1.1  mrg     {
    872  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!vd);
    873  1.1  mrg 
    874  1.1  mrg         if (!shouldEmitAndMarkVisited(vd))
    875  1.1  mrg             return;
    876  1.1  mrg 
    877  1.1  mrg         // Tuple field are expanded into multiple VarDeclarations
    878  1.1  mrg         // (we'll visit them later)
    879  1.1  mrg         if (vd.type && vd.type.isTypeTuple())
    880  1.1  mrg         {
    881  1.1  mrg             assert(vd.aliassym);
    882  1.1  mrg             vd.toAlias().accept(this);
    883  1.1  mrg             return;
    884  1.1  mrg         }
    885  1.1  mrg 
    886  1.1  mrg         if (vd.originalType && vd.type == AST.Type.tsize_t)
    887  1.1  mrg             origType = vd.originalType;
    888  1.1  mrg         scope(exit) origType = null;
    889  1.1  mrg 
    890  1.1  mrg         if (!vd.alignment.isDefault() && !vd.alignment.isUnknown())
    891  1.1  mrg         {
    892  1.1  mrg             buf.printf("// Ignoring var %s alignment %d", vd.toChars(), vd.alignment.get());
    893  1.1  mrg             buf.writenl();
    894  1.1  mrg         }
    895  1.1  mrg 
    896  1.1  mrg         // Determine the variable type which might be missing inside of
    897  1.1  mrg         // template declarations. Infer the type from the initializer then
    898  1.1  mrg         AST.Type type = vd.type;
    899  1.1  mrg         if (!type)
    900  1.1  mrg         {
    901  1.1  mrg             assert(tdparent);
    902  1.1  mrg 
    903  1.1  mrg             // Just a precaution, implicit type without initializer should be rejected
    904  1.1  mrg             if (!vd._init)
    905  1.1  mrg                 return;
    906  1.1  mrg 
    907  1.1  mrg             if (auto ei = vd._init.isExpInitializer())
    908  1.1  mrg                 type = ei.exp.type;
    909  1.1  mrg 
    910  1.1  mrg             // Can happen if the expression needs further semantic
    911  1.1  mrg             if (!type)
    912  1.1  mrg             {
    913  1.1  mrg                 ignored("%s because the type could not be determined", vd.toPrettyChars());
    914  1.1  mrg                 return;
    915  1.1  mrg             }
    916  1.1  mrg 
    917  1.1  mrg             // Apply const/immutable to the inferred type
    918  1.1  mrg             if (vd.storage_class & (AST.STC.const_ | AST.STC.immutable_))
    919  1.1  mrg                 type = type.constOf();
    920  1.1  mrg         }
    921  1.1  mrg 
    922  1.1  mrg         if (vd.storage_class & AST.STC.manifest)
    923  1.1  mrg         {
    924  1.1  mrg             EnumKind kind = getEnumKind(type);
    925  1.1  mrg 
    926  1.1  mrg             if (vd.visibility.kind == AST.Visibility.Kind.none || vd.visibility.kind == AST.Visibility.Kind.private_) {
    927  1.1  mrg                 ignored("enum `%s` because it is `%s`.", vd.toPrettyChars(), AST.visibilityToChars(vd.visibility.kind));
    928  1.1  mrg                 return;
    929  1.1  mrg             }
    930  1.1  mrg 
    931  1.1  mrg             writeProtection(vd.visibility.kind);
    932  1.1  mrg 
    933  1.1  mrg             final switch (kind)
    934  1.1  mrg             {
    935  1.1  mrg                 case EnumKind.Int, EnumKind.Numeric:
    936  1.1  mrg                     // 'enum : type' is only available from C++-11 onwards.
    937  1.1  mrg                     if (global.params.cplusplus < CppStdRevision.cpp11)
    938  1.1  mrg                         goto case;
    939  1.1  mrg                     buf.writestring("enum : ");
    940  1.1  mrg                     determineEnumType(type).accept(this);
    941  1.1  mrg                     buf.writestring(" { ");
    942  1.1  mrg                     writeIdentifier(vd, true);
    943  1.1  mrg                     buf.writestring(" = ");
    944  1.1  mrg                     auto ie = AST.initializerToExpression(vd._init).isIntegerExp();
    945  1.1  mrg                     visitInteger(ie.toInteger(), type);
    946  1.1  mrg                     buf.writestring(" };");
    947  1.1  mrg                     break;
    948  1.1  mrg 
    949  1.1  mrg                 case EnumKind.String, EnumKind.Enum:
    950  1.1  mrg                     buf.writestring("static ");
    951  1.1  mrg                     auto target = determineEnumType(type);
    952  1.1  mrg                     target.accept(this);
    953  1.1  mrg                     buf.writestring(" const ");
    954  1.1  mrg                     writeIdentifier(vd, true);
    955  1.1  mrg                     buf.writestring(" = ");
    956  1.1  mrg                     auto e = AST.initializerToExpression(vd._init);
    957  1.1  mrg                     printExpressionFor(target, e);
    958  1.1  mrg                     buf.writestring(";");
    959  1.1  mrg                     break;
    960  1.1  mrg 
    961  1.1  mrg                 case EnumKind.Other:
    962  1.1  mrg                     ignored("enum `%s` because type `%s` is currently not supported for enum constants.", vd.toPrettyChars(), type.toChars());
    963  1.1  mrg                     return;
    964  1.1  mrg             }
    965  1.1  mrg             buf.writenl();
    966  1.1  mrg             buf.writenl();
    967  1.1  mrg             return;
    968  1.1  mrg         }
    969  1.1  mrg 
    970  1.1  mrg         if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.gshared) ||
    971  1.1  mrg         vd.parent && vd.parent.isModule())
    972  1.1  mrg         {
    973  1.1  mrg             const vdLinkage = vd.resolvedLinkage();
    974  1.1  mrg             if (vdLinkage != LINK.c && vdLinkage != LINK.cpp && !(tdparent && (this.linkage == LINK.c || this.linkage == LINK.cpp)))
    975  1.1  mrg             {
    976  1.1  mrg                 ignored("variable %s because of linkage", vd.toPrettyChars());
    977  1.1  mrg                 return;
    978  1.1  mrg             }
    979  1.1  mrg             if (vd.mangleOverride && vdLinkage != LINK.c)
    980  1.1  mrg             {
    981  1.1  mrg                 ignored("variable %s because C++ doesn't support explicit mangling", vd.toPrettyChars());
    982  1.1  mrg                 return;
    983  1.1  mrg             }
    984  1.1  mrg             if (!isSupportedType(type))
    985  1.1  mrg             {
    986  1.1  mrg                 ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars());
    987  1.1  mrg                 return;
    988  1.1  mrg             }
    989  1.1  mrg             if (auto kc = keywordClass(vd.ident))
    990  1.1  mrg             {
    991  1.1  mrg                 ignored("variable %s because its name is a %s", vd.toPrettyChars(), kc);
    992  1.1  mrg                 return;
    993  1.1  mrg             }
    994  1.1  mrg             writeProtection(vd.visibility.kind);
    995  1.1  mrg             if (vdLinkage == LINK.c)
    996  1.1  mrg                 buf.writestring("extern \"C\" ");
    997  1.1  mrg             else if (!adparent)
    998  1.1  mrg                 buf.writestring("extern ");
    999  1.1  mrg             if (adparent)
   1000  1.1  mrg                 buf.writestring("static ");
   1001  1.1  mrg             typeToBuffer(type, vd);
   1002  1.1  mrg             writeDeclEnd();
   1003  1.1  mrg             return;
   1004  1.1  mrg         }
   1005  1.1  mrg 
   1006  1.1  mrg         if (adparent)
   1007  1.1  mrg         {
   1008  1.1  mrg             writeProtection(vd.visibility.kind);
   1009  1.1  mrg             typeToBuffer(type, vd, true);
   1010  1.1  mrg             buf.writestringln(";");
   1011  1.1  mrg 
   1012  1.1  mrg             debug (Debug_DtoH_Checks)
   1013  1.1  mrg             {
   1014  1.1  mrg                 checkbuf.level++;
   1015  1.1  mrg                 const pn = adparent.ident.toChars();
   1016  1.1  mrg                 const vn = vd.ident.toChars();
   1017  1.1  mrg                 const vo = vd.offset;
   1018  1.1  mrg                 checkbuf.printf("assert(offsetof(%s, %s) == %d);",
   1019  1.1  mrg                                                 pn, vn,    vo);
   1020  1.1  mrg                 checkbuf.writenl();
   1021  1.1  mrg                 checkbuf.level--;
   1022  1.1  mrg             }
   1023  1.1  mrg             return;
   1024  1.1  mrg         }
   1025  1.1  mrg 
   1026  1.1  mrg         visit(cast(AST.Dsymbol)vd);
   1027  1.1  mrg     }
   1028  1.1  mrg 
   1029  1.1  mrg     override void visit(AST.TypeInfoDeclaration tid)
   1030  1.1  mrg     {
   1031  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!tid);
   1032  1.1  mrg     }
   1033  1.1  mrg 
   1034  1.1  mrg     override void visit(AST.AliasDeclaration ad)
   1035  1.1  mrg     {
   1036  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!ad);
   1037  1.1  mrg 
   1038  1.1  mrg         if (!shouldEmitAndMarkVisited(ad))
   1039  1.1  mrg             return;
   1040  1.1  mrg 
   1041  1.1  mrg         writeProtection(ad.visibility.kind);
   1042  1.1  mrg 
   1043  1.1  mrg         if (auto t = ad.type)
   1044  1.1  mrg         {
   1045  1.1  mrg             if (t.ty == AST.Tdelegate || t.ty == AST.Tident)
   1046  1.1  mrg             {
   1047  1.1  mrg                 visit(cast(AST.Dsymbol)ad);
   1048  1.1  mrg                 return;
   1049  1.1  mrg             }
   1050  1.1  mrg 
   1051  1.1  mrg             // for function pointers we need to original type
   1052  1.1  mrg             if (ad.originalType && ad.type.ty == AST.Tpointer &&
   1053  1.1  mrg                 (cast(AST.TypePointer)t).nextOf.ty == AST.Tfunction)
   1054  1.1  mrg             {
   1055  1.1  mrg                 origType = ad.originalType;
   1056  1.1  mrg             }
   1057  1.1  mrg             scope(exit) origType = null;
   1058  1.1  mrg 
   1059  1.1  mrg             buf.writestring("typedef ");
   1060  1.1  mrg             typeToBuffer(origType !is null ? origType : t, ad);
   1061  1.1  mrg             writeDeclEnd();
   1062  1.1  mrg             return;
   1063  1.1  mrg         }
   1064  1.1  mrg         if (!ad.aliassym)
   1065  1.1  mrg         {
   1066  1.1  mrg             assert(0);
   1067  1.1  mrg         }
   1068  1.1  mrg         if (auto ti = ad.aliassym.isTemplateInstance())
   1069  1.1  mrg         {
   1070  1.1  mrg             visitTi(ti);
   1071  1.1  mrg             return;
   1072  1.1  mrg         }
   1073  1.1  mrg         if (auto sd = ad.aliassym.isStructDeclaration())
   1074  1.1  mrg         {
   1075  1.1  mrg             buf.writestring("typedef ");
   1076  1.1  mrg             sd.type.accept(this);
   1077  1.1  mrg             buf.writestring(" ");
   1078  1.1  mrg             writeIdentifier(ad);
   1079  1.1  mrg             writeDeclEnd();
   1080  1.1  mrg             return;
   1081  1.1  mrg         }
   1082  1.1  mrg         else if (auto td = ad.aliassym.isTemplateDeclaration())
   1083  1.1  mrg         {
   1084  1.1  mrg             if (global.params.cplusplus < CppStdRevision.cpp11)
   1085  1.1  mrg             {
   1086  1.1  mrg                 ignored("%s because `using` declarations require C++ 11", ad.toPrettyChars());
   1087  1.1  mrg                 return;
   1088  1.1  mrg             }
   1089  1.1  mrg 
   1090  1.1  mrg             printTemplateParams(td);
   1091  1.1  mrg             buf.writestring("using ");
   1092  1.1  mrg             writeIdentifier(ad);
   1093  1.1  mrg             buf.writestring(" = ");
   1094  1.1  mrg             writeFullName(td);
   1095  1.1  mrg             buf.writeByte('<');
   1096  1.1  mrg 
   1097  1.1  mrg             foreach (const idx, const p; *td.parameters)
   1098  1.1  mrg             {
   1099  1.1  mrg                 if (idx)
   1100  1.1  mrg                     buf.writestring(", ");
   1101  1.1  mrg                 writeIdentifier(p.ident, p.loc, "parameter", true);
   1102  1.1  mrg             }
   1103  1.1  mrg             buf.writestringln(">;");
   1104  1.1  mrg             return;
   1105  1.1  mrg         }
   1106  1.1  mrg 
   1107  1.1  mrg         auto fd = ad.aliassym.isFuncDeclaration();
   1108  1.1  mrg 
   1109  1.1  mrg         if (fd && (fd.isGenerated() || fd.isDtorDeclaration()))
   1110  1.1  mrg         {
   1111  1.1  mrg             // Ignore. It's taken care of while visiting FuncDeclaration
   1112  1.1  mrg             return;
   1113  1.1  mrg         }
   1114  1.1  mrg 
   1115  1.1  mrg         // Recognize member function aliases, e.g. alias visit = Parent.visit;
   1116  1.1  mrg         if (adparent && fd)
   1117  1.1  mrg         {
   1118  1.1  mrg             auto pd = fd.isMember();
   1119  1.1  mrg             if (!pd)
   1120  1.1  mrg             {
   1121  1.1  mrg                 ignored("%s because free functions cannot be aliased in C++", ad.toPrettyChars());
   1122  1.1  mrg             }
   1123  1.1  mrg             else if (global.params.cplusplus < CppStdRevision.cpp11)
   1124  1.1  mrg             {
   1125  1.1  mrg                 ignored("%s because `using` declarations require C++ 11", ad.toPrettyChars());
   1126  1.1  mrg             }
   1127  1.1  mrg             else if (ad.ident != fd.ident)
   1128  1.1  mrg             {
   1129  1.1  mrg                 ignored("%s because `using` cannot rename functions in aggregates", ad.toPrettyChars());
   1130  1.1  mrg             }
   1131  1.1  mrg             else if (fd.toAliasFunc().parent.isTemplateMixin())
   1132  1.1  mrg             {
   1133  1.1  mrg                 // Member's of template mixins are directly emitted into the aggregate
   1134  1.1  mrg             }
   1135  1.1  mrg             else
   1136  1.1  mrg             {
   1137  1.1  mrg                 buf.writestring("using ");
   1138  1.1  mrg 
   1139  1.1  mrg                 // Print prefix of the base class if this function originates from a superclass
   1140  1.1  mrg                 // because alias might be resolved through multiple classes, e.g.
   1141  1.1  mrg                 // e.g. for alias visit = typeof(super).visit in the visitors
   1142  1.1  mrg                 if (!fd.isIntroducing())
   1143  1.1  mrg                     printPrefix(ad.toParent().isClassDeclaration().baseClass);
   1144  1.1  mrg                 else
   1145  1.1  mrg                     printPrefix(pd);
   1146  1.1  mrg 
   1147  1.1  mrg                 buf.writestring(fd.ident.toChars());
   1148  1.1  mrg                 buf.writestringln(";");
   1149  1.1  mrg             }
   1150  1.1  mrg             return;
   1151  1.1  mrg         }
   1152  1.1  mrg 
   1153  1.1  mrg         ignored("%s %s", ad.aliassym.kind(), ad.aliassym.toPrettyChars());
   1154  1.1  mrg     }
   1155  1.1  mrg 
   1156  1.1  mrg     override void visit(AST.Nspace ns)
   1157  1.1  mrg     {
   1158  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!ns);
   1159  1.1  mrg         handleNspace(ns, ns.members);
   1160  1.1  mrg     }
   1161  1.1  mrg 
   1162  1.1  mrg     override void visit(AST.CPPNamespaceDeclaration ns)
   1163  1.1  mrg     {
   1164  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!ns);
   1165  1.1  mrg         handleNspace(ns, ns.decl);
   1166  1.1  mrg     }
   1167  1.1  mrg 
   1168  1.1  mrg     /// Writes the namespace declaration and visits all members
   1169  1.1  mrg     private void handleNspace(AST.Dsymbol namespace, Dsymbols* members)
   1170  1.1  mrg     {
   1171  1.1  mrg         buf.writestring("namespace ");
   1172  1.1  mrg         writeIdentifier(namespace);
   1173  1.1  mrg         buf.writenl();
   1174  1.1  mrg         buf.writestring("{");
   1175  1.1  mrg         buf.writenl();
   1176  1.1  mrg         buf.level++;
   1177  1.1  mrg         foreach(decl;(*members))
   1178  1.1  mrg         {
   1179  1.1  mrg             decl.accept(this);
   1180  1.1  mrg         }
   1181  1.1  mrg         buf.level--;
   1182  1.1  mrg         buf.writestring("}");
   1183  1.1  mrg         buf.writenl();
   1184  1.1  mrg     }
   1185  1.1  mrg 
   1186  1.1  mrg     override void visit(AST.AnonDeclaration ad)
   1187  1.1  mrg     {
   1188  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!ad);
   1189  1.1  mrg 
   1190  1.1  mrg         const anonStash = inAnonymousDecl;
   1191  1.1  mrg         inAnonymousDecl = true;
   1192  1.1  mrg         scope (exit) inAnonymousDecl = anonStash;
   1193  1.1  mrg 
   1194  1.1  mrg         buf.writestringln(ad.isunion ? "union" : "struct");
   1195  1.1  mrg         buf.writestringln("{");
   1196  1.1  mrg         buf.level++;
   1197  1.1  mrg         foreach (s; *ad.decl)
   1198  1.1  mrg         {
   1199  1.1  mrg             s.accept(this);
   1200  1.1  mrg         }
   1201  1.1  mrg         buf.level--;
   1202  1.1  mrg         buf.writestringln("};");
   1203  1.1  mrg     }
   1204  1.1  mrg 
   1205  1.1  mrg     private bool memberField(AST.VarDeclaration vd)
   1206  1.1  mrg     {
   1207  1.1  mrg         if (!vd.type || !vd.type.deco || !vd.ident)
   1208  1.1  mrg             return false;
   1209  1.1  mrg         if (!vd.isField())
   1210  1.1  mrg             return false;
   1211  1.1  mrg         if (vd.type.ty == AST.Tfunction)
   1212  1.1  mrg             return false;
   1213  1.1  mrg         if (vd.type.ty == AST.Tsarray)
   1214  1.1  mrg             return false;
   1215  1.1  mrg         return true;
   1216  1.1  mrg     }
   1217  1.1  mrg 
   1218  1.1  mrg     override void visit(AST.StructDeclaration sd)
   1219  1.1  mrg     {
   1220  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!sd);
   1221  1.1  mrg 
   1222  1.1  mrg         if (!shouldEmitAndMarkVisited(sd))
   1223  1.1  mrg             return;
   1224  1.1  mrg 
   1225  1.1  mrg         const ignoredStash = this.ignoredCounter;
   1226  1.1  mrg         scope (exit) this.ignoredCounter = ignoredStash;
   1227  1.1  mrg 
   1228  1.1  mrg         pushAlignToBuffer(sd.alignment);
   1229  1.1  mrg 
   1230  1.1  mrg         writeProtection(sd.visibility.kind);
   1231  1.1  mrg 
   1232  1.1  mrg         const structAsClass = sd.cppmangle == CPPMANGLE.asClass;
   1233  1.1  mrg         if (sd.isUnionDeclaration())
   1234  1.1  mrg             buf.writestring("union ");
   1235  1.1  mrg         else
   1236  1.1  mrg             buf.writestring(structAsClass ? "class " : "struct ");
   1237  1.1  mrg 
   1238  1.1  mrg         writeIdentifier(sd);
   1239  1.1  mrg         if (!sd.members)
   1240  1.1  mrg         {
   1241  1.1  mrg             buf.writestringln(";");
   1242  1.1  mrg             buf.writenl();
   1243  1.1  mrg             return;
   1244  1.1  mrg         }
   1245  1.1  mrg 
   1246  1.1  mrg         // D structs are always final
   1247  1.1  mrg         if (!sd.isUnionDeclaration())
   1248  1.1  mrg             buf.writestring(" final");
   1249  1.1  mrg 
   1250  1.1  mrg         buf.writenl();
   1251  1.1  mrg         buf.writestring("{");
   1252  1.1  mrg 
   1253  1.1  mrg         const protStash = this.currentVisibility;
   1254  1.1  mrg         this.currentVisibility = structAsClass ? AST.Visibility.Kind.private_ : AST.Visibility.Kind.public_;
   1255  1.1  mrg         scope (exit) this.currentVisibility = protStash;
   1256  1.1  mrg 
   1257  1.1  mrg         buf.level++;
   1258  1.1  mrg         buf.writenl();
   1259  1.1  mrg         auto save = adparent;
   1260  1.1  mrg         adparent = sd;
   1261  1.1  mrg 
   1262  1.1  mrg         foreach (m; *sd.members)
   1263  1.1  mrg         {
   1264  1.1  mrg             m.accept(this);
   1265  1.1  mrg         }
   1266  1.1  mrg         // Generate default ctor
   1267  1.1  mrg         if (!sd.noDefaultCtor && !sd.isUnionDeclaration())
   1268  1.1  mrg         {
   1269  1.1  mrg             writeProtection(AST.Visibility.Kind.public_);
   1270  1.1  mrg             buf.printf("%s()", sd.ident.toChars());
   1271  1.1  mrg             size_t varCount;
   1272  1.1  mrg             bool first = true;
   1273  1.1  mrg             buf.level++;
   1274  1.1  mrg             foreach (m; *sd.members)
   1275  1.1  mrg             {
   1276  1.1  mrg                 if (auto vd = m.isVarDeclaration())
   1277  1.1  mrg                 {
   1278  1.1  mrg                     if (!memberField(vd))
   1279  1.1  mrg                         continue;
   1280  1.1  mrg                     varCount++;
   1281  1.1  mrg 
   1282  1.1  mrg                     if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct &&
   1283  1.1  mrg                         !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray)
   1284  1.1  mrg                     {
   1285  1.1  mrg                         continue;
   1286  1.1  mrg                     }
   1287  1.1  mrg                     if (vd._init && vd._init.isVoidInitializer())
   1288  1.1  mrg                         continue;
   1289  1.1  mrg 
   1290  1.1  mrg                     if (first)
   1291  1.1  mrg                     {
   1292  1.1  mrg                         buf.writestringln(" :");
   1293  1.1  mrg                         first = false;
   1294  1.1  mrg                     }
   1295  1.1  mrg                     else
   1296  1.1  mrg                     {
   1297  1.1  mrg                         buf.writestringln(",");
   1298  1.1  mrg                     }
   1299  1.1  mrg                     writeIdentifier(vd, true);
   1300  1.1  mrg                     buf.writeByte('(');
   1301  1.1  mrg 
   1302  1.1  mrg                     if (vd._init)
   1303  1.1  mrg                     {
   1304  1.1  mrg                         auto e = AST.initializerToExpression(vd._init);
   1305  1.1  mrg                         printExpressionFor(vd.type, e, true);
   1306  1.1  mrg                     }
   1307  1.1  mrg                     buf.printf(")");
   1308  1.1  mrg                 }
   1309  1.1  mrg             }
   1310  1.1  mrg             buf.level--;
   1311  1.1  mrg             buf.writenl();
   1312  1.1  mrg             buf.writestringln("{");
   1313  1.1  mrg             buf.writestringln("}");
   1314  1.1  mrg             auto ctor = sd.ctor ? sd.ctor.isFuncDeclaration() : null;
   1315  1.1  mrg             if (varCount && (!ctor || ctor.storage_class & AST.STC.disable))
   1316  1.1  mrg             {
   1317  1.1  mrg                 buf.printf("%s(", sd.ident.toChars());
   1318  1.1  mrg                 first = true;
   1319  1.1  mrg                 foreach (m; *sd.members)
   1320  1.1  mrg                 {
   1321  1.1  mrg                     if (auto vd = m.isVarDeclaration())
   1322  1.1  mrg                     {
   1323  1.1  mrg                         if (!memberField(vd))
   1324  1.1  mrg                             continue;
   1325  1.1  mrg                         if (!first)
   1326  1.1  mrg                             buf.writestring(", ");
   1327  1.1  mrg                         assert(vd.type);
   1328  1.1  mrg                         assert(vd.ident);
   1329  1.1  mrg                         typeToBuffer(vd.type, vd, true);
   1330  1.1  mrg                         // Don't print default value for first parameter to not clash
   1331  1.1  mrg                         // with the default ctor defined above
   1332  1.1  mrg                         if (!first)
   1333  1.1  mrg                         {
   1334  1.1  mrg                             buf.writestring(" = ");
   1335  1.1  mrg                             printExpressionFor(vd.type, findDefaultInitializer(vd));
   1336  1.1  mrg                         }
   1337  1.1  mrg                         first = false;
   1338  1.1  mrg                     }
   1339  1.1  mrg                 }
   1340  1.1  mrg                 buf.writestring(") :");
   1341  1.1  mrg                 buf.level++;
   1342  1.1  mrg                 buf.writenl();
   1343  1.1  mrg 
   1344  1.1  mrg                 first = true;
   1345  1.1  mrg                 foreach (m; *sd.members)
   1346  1.1  mrg                 {
   1347  1.1  mrg                     if (auto vd = m.isVarDeclaration())
   1348  1.1  mrg                     {
   1349  1.1  mrg                         if (!memberField(vd))
   1350  1.1  mrg                             continue;
   1351  1.1  mrg 
   1352  1.1  mrg                         if (first)
   1353  1.1  mrg                             first = false;
   1354  1.1  mrg                         else
   1355  1.1  mrg                             buf.writestringln(",");
   1356  1.1  mrg 
   1357  1.1  mrg                         writeIdentifier(vd, true);
   1358  1.1  mrg                         buf.writeByte('(');
   1359  1.1  mrg                         writeIdentifier(vd, true);
   1360  1.1  mrg                         buf.writeByte(')');
   1361  1.1  mrg                     }
   1362  1.1  mrg                 }
   1363  1.1  mrg                 buf.writenl();
   1364  1.1  mrg                 buf.writestringln("{}");
   1365  1.1  mrg                 buf.level--;
   1366  1.1  mrg             }
   1367  1.1  mrg         }
   1368  1.1  mrg 
   1369  1.1  mrg         buf.level--;
   1370  1.1  mrg         adparent = save;
   1371  1.1  mrg         buf.writestringln("};");
   1372  1.1  mrg 
   1373  1.1  mrg         popAlignToBuffer(sd.alignment);
   1374  1.1  mrg         buf.writenl();
   1375  1.1  mrg 
   1376  1.1  mrg         // Workaround because size triggers a forward-reference error
   1377  1.1  mrg         // for struct templates (the size is undetermined even if the
   1378  1.1  mrg         // size doesn't depend on the parameters)
   1379  1.1  mrg         debug (Debug_DtoH_Checks)
   1380  1.1  mrg         if (!tdparent)
   1381  1.1  mrg         {
   1382  1.1  mrg             checkbuf.level++;
   1383  1.1  mrg             const sn = sd.ident.toChars();
   1384  1.1  mrg             const sz = sd.size(Loc.initial);
   1385  1.1  mrg             checkbuf.printf("assert(sizeof(%s) == %llu);", sn, sz);
   1386  1.1  mrg             checkbuf.writenl();
   1387  1.1  mrg             checkbuf.level--;
   1388  1.1  mrg         }
   1389  1.1  mrg     }
   1390  1.1  mrg 
   1391  1.1  mrg     /// Starts a custom alignment section using `#pragma pack` if
   1392  1.1  mrg     /// `alignment` specifies a custom alignment
   1393  1.1  mrg     private void pushAlignToBuffer(structalign_t alignment)
   1394  1.1  mrg     {
   1395  1.1  mrg         // DMD ensures alignment is a power of two
   1396  1.1  mrg         //assert(alignment > 0 && ((alignment & (alignment - 1)) == 0),
   1397  1.1  mrg         //       "Invalid alignment size");
   1398  1.1  mrg 
   1399  1.1  mrg         // When no alignment is specified, `uint.max` is the default
   1400  1.1  mrg         // FIXME: alignment is 0 for structs templated members
   1401  1.1  mrg         if (alignment.isDefault() || (tdparent && alignment.isUnknown()))
   1402  1.1  mrg         {
   1403  1.1  mrg             return;
   1404  1.1  mrg         }
   1405  1.1  mrg 
   1406  1.1  mrg         buf.printf("#pragma pack(push, %d)", alignment.get());
   1407  1.1  mrg         buf.writenl();
   1408  1.1  mrg     }
   1409  1.1  mrg 
   1410  1.1  mrg     /// Ends a custom alignment section using `#pragma pack` if
   1411  1.1  mrg     /// `alignment` specifies a custom alignment
   1412  1.1  mrg     private void popAlignToBuffer(structalign_t alignment)
   1413  1.1  mrg     {
   1414  1.1  mrg         if (alignment.isDefault() || (tdparent && alignment.isUnknown()))
   1415  1.1  mrg             return;
   1416  1.1  mrg 
   1417  1.1  mrg         buf.writestringln("#pragma pack(pop)");
   1418  1.1  mrg     }
   1419  1.1  mrg 
   1420  1.1  mrg     override void visit(AST.ClassDeclaration cd)
   1421  1.1  mrg     {
   1422  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!cd);
   1423  1.1  mrg 
   1424  1.1  mrg         if (cd.baseClass && shouldEmit(cd))
   1425  1.1  mrg             includeSymbol(cd.baseClass);
   1426  1.1  mrg 
   1427  1.1  mrg         if (!shouldEmitAndMarkVisited(cd))
   1428  1.1  mrg             return;
   1429  1.1  mrg 
   1430  1.1  mrg         writeProtection(cd.visibility.kind);
   1431  1.1  mrg 
   1432  1.1  mrg         const classAsStruct = cd.cppmangle == CPPMANGLE.asStruct;
   1433  1.1  mrg         buf.writestring(classAsStruct ? "struct " : "class ");
   1434  1.1  mrg         writeIdentifier(cd);
   1435  1.1  mrg 
   1436  1.1  mrg         if (cd.storage_class & AST.STC.final_ || (tdparent && this.storageClass & AST.STC.final_))
   1437  1.1  mrg             buf.writestring(" final");
   1438  1.1  mrg 
   1439  1.1  mrg         assert(cd.baseclasses);
   1440  1.1  mrg 
   1441  1.1  mrg         foreach (i, base; *cd.baseclasses)
   1442  1.1  mrg         {
   1443  1.1  mrg             buf.writestring(i == 0 ? " : public " : ", public ");
   1444  1.1  mrg 
   1445  1.1  mrg             // Base classes/interfaces might depend on template parameters,
   1446  1.1  mrg             // e.g. class A(T) : B!T { ... }
   1447  1.1  mrg             if (base.sym is null)
   1448  1.1  mrg             {
   1449  1.1  mrg                 base.type.accept(this);
   1450  1.1  mrg             }
   1451  1.1  mrg             else
   1452  1.1  mrg             {
   1453  1.1  mrg                 writeFullName(base.sym);
   1454  1.1  mrg             }
   1455  1.1  mrg         }
   1456  1.1  mrg 
   1457  1.1  mrg         if (!cd.members)
   1458  1.1  mrg         {
   1459  1.1  mrg             buf.writestring(";");
   1460  1.1  mrg             buf.writenl();
   1461  1.1  mrg             buf.writenl();
   1462  1.1  mrg             return;
   1463  1.1  mrg         }
   1464  1.1  mrg 
   1465  1.1  mrg         buf.writenl();
   1466  1.1  mrg         buf.writestringln("{");
   1467  1.1  mrg 
   1468  1.1  mrg         const protStash = this.currentVisibility;
   1469  1.1  mrg         this.currentVisibility = classAsStruct ? AST.Visibility.Kind.public_ : AST.Visibility.Kind.private_;
   1470  1.1  mrg         scope (exit) this.currentVisibility = protStash;
   1471  1.1  mrg 
   1472  1.1  mrg         auto save = adparent;
   1473  1.1  mrg         adparent = cd;
   1474  1.1  mrg         buf.level++;
   1475  1.1  mrg         foreach (m; *cd.members)
   1476  1.1  mrg         {
   1477  1.1  mrg             m.accept(this);
   1478  1.1  mrg         }
   1479  1.1  mrg         buf.level--;
   1480  1.1  mrg         adparent = save;
   1481  1.1  mrg 
   1482  1.1  mrg         buf.writestringln("};");
   1483  1.1  mrg         buf.writenl();
   1484  1.1  mrg     }
   1485  1.1  mrg 
   1486  1.1  mrg     override void visit(AST.EnumDeclaration ed)
   1487  1.1  mrg     {
   1488  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!ed);
   1489  1.1  mrg 
   1490  1.1  mrg         if (!shouldEmitAndMarkVisited(ed))
   1491  1.1  mrg             return;
   1492  1.1  mrg 
   1493  1.1  mrg         if (ed.isSpecial())
   1494  1.1  mrg         {
   1495  1.1  mrg             //ignored("%s because it is a special C++ type", ed.toPrettyChars());
   1496  1.1  mrg             return;
   1497  1.1  mrg         }
   1498  1.1  mrg 
   1499  1.1  mrg         // we need to know a bunch of stuff about the enum...
   1500  1.1  mrg         bool isAnonymous = ed.ident is null;
   1501  1.1  mrg         const isOpaque = !ed.members;
   1502  1.1  mrg         AST.Type type = ed.memtype;
   1503  1.1  mrg         if (!type && !isOpaque)
   1504  1.1  mrg         {
   1505  1.1  mrg             // check all keys have matching type
   1506  1.1  mrg             foreach (_m; *ed.members)
   1507  1.1  mrg             {
   1508  1.1  mrg                 auto m = _m.isEnumMember();
   1509  1.1  mrg                 if (!type)
   1510  1.1  mrg                     type = m.type;
   1511  1.1  mrg                 else if (m.type !is type)
   1512  1.1  mrg                 {
   1513  1.1  mrg                     type = null;
   1514  1.1  mrg                     break;
   1515  1.1  mrg                 }
   1516  1.1  mrg             }
   1517  1.1  mrg         }
   1518  1.1  mrg         EnumKind kind = getEnumKind(type);
   1519  1.1  mrg 
   1520  1.1  mrg         if (isOpaque)
   1521  1.1  mrg         {
   1522  1.1  mrg             // Opaque enums were introduced in C++ 11 (workaround?)
   1523  1.1  mrg             if (global.params.cplusplus < CppStdRevision.cpp11)
   1524  1.1  mrg             {
   1525  1.1  mrg                 ignored("%s because opaque enums require C++ 11", ed.toPrettyChars());
   1526  1.1  mrg                 return;
   1527  1.1  mrg             }
   1528  1.1  mrg             // Opaque enum defaults to int but the type might not be set
   1529  1.1  mrg             else if (!type)
   1530  1.1  mrg             {
   1531  1.1  mrg                 kind = EnumKind.Int;
   1532  1.1  mrg             }
   1533  1.1  mrg             // Cannot apply namespace workaround for non-integral types
   1534  1.1  mrg             else if (kind != EnumKind.Int && kind != EnumKind.Numeric)
   1535  1.1  mrg             {
   1536  1.1  mrg                 ignored("enum %s because of its base type", ed.toPrettyChars());
   1537  1.1  mrg                 return;
   1538  1.1  mrg             }
   1539  1.1  mrg         }
   1540  1.1  mrg 
   1541  1.1  mrg         // determine if this is an enum, or just a group of manifest constants
   1542  1.1  mrg         bool manifestConstants = !isOpaque && (!type || (isAnonymous && kind == EnumKind.Other));
   1543  1.1  mrg         assert(!manifestConstants || isAnonymous);
   1544  1.1  mrg 
   1545  1.1  mrg         writeProtection(ed.visibility.kind);
   1546  1.1  mrg 
   1547  1.1  mrg         // write the enum header
   1548  1.1  mrg         if (!manifestConstants)
   1549  1.1  mrg         {
   1550  1.1  mrg             if (kind == EnumKind.Int || kind == EnumKind.Numeric)
   1551  1.1  mrg             {
   1552  1.1  mrg                 buf.writestring("enum");
   1553  1.1  mrg                 // D enums are strong enums, but there exists only a direct mapping
   1554  1.1  mrg                 // with 'enum class' from C++-11 onwards.
   1555  1.1  mrg                 if (global.params.cplusplus >= CppStdRevision.cpp11)
   1556  1.1  mrg                 {
   1557  1.1  mrg                     if (!isAnonymous)
   1558  1.1  mrg                     {
   1559  1.1  mrg                         buf.writestring(" class ");
   1560  1.1  mrg                         writeIdentifier(ed);
   1561  1.1  mrg                     }
   1562  1.1  mrg                     if (kind == EnumKind.Numeric)
   1563  1.1  mrg                     {
   1564  1.1  mrg                         buf.writestring(" : ");
   1565  1.1  mrg                         determineEnumType(type).accept(this);
   1566  1.1  mrg                     }
   1567  1.1  mrg                 }
   1568  1.1  mrg                 else if (!isAnonymous)
   1569  1.1  mrg                 {
   1570  1.1  mrg                     buf.writeByte(' ');
   1571  1.1  mrg                     writeIdentifier(ed);
   1572  1.1  mrg                 }
   1573  1.1  mrg             }
   1574  1.1  mrg             else
   1575  1.1  mrg             {
   1576  1.1  mrg                 buf.writestring("namespace");
   1577  1.1  mrg                 if(!isAnonymous)
   1578  1.1  mrg                 {
   1579  1.1  mrg                     buf.writeByte(' ');
   1580  1.1  mrg                     writeIdentifier(ed);
   1581  1.1  mrg                 }
   1582  1.1  mrg             }
   1583  1.1  mrg             // Opaque enums have no members, hence skip the body
   1584  1.1  mrg             if (isOpaque)
   1585  1.1  mrg             {
   1586  1.1  mrg                 buf.writestringln(";");
   1587  1.1  mrg                 return;
   1588  1.1  mrg             }
   1589  1.1  mrg             else
   1590  1.1  mrg             {
   1591  1.1  mrg                 buf.writenl();
   1592  1.1  mrg                 buf.writestringln("{");
   1593  1.1  mrg             }
   1594  1.1  mrg         }
   1595  1.1  mrg 
   1596  1.1  mrg         // emit constant for each member
   1597  1.1  mrg         if (!manifestConstants)
   1598  1.1  mrg             buf.level++;
   1599  1.1  mrg 
   1600  1.1  mrg         foreach (_m; *ed.members)
   1601  1.1  mrg         {
   1602  1.1  mrg             auto m = _m.isEnumMember();
   1603  1.1  mrg             AST.Type memberType = type ? type : m.type;
   1604  1.1  mrg             const EnumKind memberKind = type ? kind : getEnumKind(memberType);
   1605  1.1  mrg 
   1606  1.1  mrg             if (!manifestConstants && (kind == EnumKind.Int || kind == EnumKind.Numeric))
   1607  1.1  mrg             {
   1608  1.1  mrg                 // C++-98 compatible enums must use the typename as a prefix to avoid
   1609  1.1  mrg                 // collisions with other identifiers in scope.  For consistency with D,
   1610  1.1  mrg                 // the enum member `Type.member` is emitted as `Type_member` in C++-98.
   1611  1.1  mrg                 if (!isAnonymous && global.params.cplusplus < CppStdRevision.cpp11)
   1612  1.1  mrg                 {
   1613  1.1  mrg                     writeIdentifier(ed);
   1614  1.1  mrg                     buf.writeByte('_');
   1615  1.1  mrg                 }
   1616  1.1  mrg                 writeIdentifier(m, true);
   1617  1.1  mrg                 buf.writestring(" = ");
   1618  1.1  mrg 
   1619  1.1  mrg                 auto ie = cast(AST.IntegerExp)m.value;
   1620  1.1  mrg                 visitInteger(ie.toInteger(), memberType);
   1621  1.1  mrg                 buf.writestring(",");
   1622  1.1  mrg             }
   1623  1.1  mrg             else if (global.params.cplusplus >= CppStdRevision.cpp11 &&
   1624  1.1  mrg                      manifestConstants && (memberKind == EnumKind.Int || memberKind == EnumKind.Numeric))
   1625  1.1  mrg             {
   1626  1.1  mrg                 buf.writestring("enum : ");
   1627  1.1  mrg                 determineEnumType(memberType).accept(this);
   1628  1.1  mrg                 buf.writestring(" { ");
   1629  1.1  mrg                 writeIdentifier(m, true);
   1630  1.1  mrg                 buf.writestring(" = ");
   1631  1.1  mrg 
   1632  1.1  mrg                 auto ie = cast(AST.IntegerExp)m.value;
   1633  1.1  mrg                 visitInteger(ie.toInteger(), memberType);
   1634  1.1  mrg                 buf.writestring(" };");
   1635  1.1  mrg             }
   1636  1.1  mrg             else
   1637  1.1  mrg             {
   1638  1.1  mrg                 buf.writestring("static ");
   1639  1.1  mrg                 auto target = determineEnumType(memberType);
   1640  1.1  mrg                 target.accept(this);
   1641  1.1  mrg                 buf.writestring(" const ");
   1642  1.1  mrg                 writeIdentifier(m, true);
   1643  1.1  mrg                 buf.writestring(" = ");
   1644  1.1  mrg                 printExpressionFor(target, m.origValue);
   1645  1.1  mrg                 buf.writestring(";");
   1646  1.1  mrg             }
   1647  1.1  mrg             buf.writenl();
   1648  1.1  mrg         }
   1649  1.1  mrg 
   1650  1.1  mrg         if (!manifestConstants)
   1651  1.1  mrg             buf.level--;
   1652  1.1  mrg         // write the enum tail
   1653  1.1  mrg         if (!manifestConstants)
   1654  1.1  mrg             buf.writestring("};");
   1655  1.1  mrg         buf.writenl();
   1656  1.1  mrg         buf.writenl();
   1657  1.1  mrg     }
   1658  1.1  mrg 
   1659  1.1  mrg     override void visit(AST.EnumMember em)
   1660  1.1  mrg     {
   1661  1.1  mrg         assert(em.ed);
   1662  1.1  mrg 
   1663  1.1  mrg         // Members of anonymous members are reachable without referencing the
   1664  1.1  mrg         // EnumDeclaration, e.g. public import foo : someEnumMember;
   1665  1.1  mrg         if (em.ed.isAnonymous())
   1666  1.1  mrg         {
   1667  1.1  mrg             visit(em.ed);
   1668  1.1  mrg             return;
   1669  1.1  mrg         }
   1670  1.1  mrg 
   1671  1.1  mrg         assert(false, "This node type should be handled in the EnumDeclaration");
   1672  1.1  mrg     }
   1673  1.1  mrg 
   1674  1.1  mrg     override void visit(AST.TupleDeclaration tup)
   1675  1.1  mrg     {
   1676  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!tup);
   1677  1.1  mrg 
   1678  1.1  mrg         tup.foreachVar((s) { s.accept(this); });
   1679  1.1  mrg     }
   1680  1.1  mrg 
   1681  1.1  mrg     /**
   1682  1.1  mrg      * Prints a member/parameter/variable declaration into `buf`.
   1683  1.1  mrg      *
   1684  1.1  mrg      * Params:
   1685  1.1  mrg      *   t        = the type (used if `this.origType` is null)
   1686  1.1  mrg      *   s        = the symbol denoting the identifier
   1687  1.1  mrg      *   canFixup = whether the identifier may be changed without affecting
   1688  1.1  mrg      *              binary compatibility (forwarded to `writeIdentifier`)
   1689  1.1  mrg      */
   1690  1.1  mrg     private void typeToBuffer(AST.Type t, AST.Dsymbol s, const bool canFixup = false)
   1691  1.1  mrg     {
   1692  1.1  mrg         debug (Debug_DtoH)
   1693  1.1  mrg         {
   1694  1.1  mrg             printf("[typeToBuffer(AST.Type, AST.Dsymbol) enter] %s sym %s\n", t.toChars(), s.toChars());
   1695  1.1  mrg             scope(exit) printf("[typeToBuffer(AST.Type, AST.Dsymbol) exit] %s sym %s\n", t.toChars(), s.toChars());
   1696  1.1  mrg         }
   1697  1.1  mrg 
   1698  1.1  mrg         // The context pointer (represented as `ThisDeclaration`) is named
   1699  1.1  mrg         // `this` but accessible via `outer`
   1700  1.1  mrg         if (auto td = s.isThisDeclaration())
   1701  1.1  mrg         {
   1702  1.1  mrg             import dmd.id;
   1703  1.1  mrg             this.ident = Id.outer;
   1704  1.1  mrg         }
   1705  1.1  mrg         else
   1706  1.1  mrg             this.ident = s.ident;
   1707  1.1  mrg 
   1708  1.1  mrg         auto type = origType !is null ? origType : t;
   1709  1.1  mrg         AST.Dsymbol customLength;
   1710  1.1  mrg 
   1711  1.1  mrg         // Check for quirks that are usually resolved during semantic
   1712  1.1  mrg         if (tdparent)
   1713  1.1  mrg         {
   1714  1.1  mrg             // Declarations within template declarations might use TypeAArray
   1715  1.1  mrg             // instead of TypeSArray when the length is not an IntegerExp,
   1716  1.1  mrg             // e.g. int[SOME_CONSTANT]
   1717  1.1  mrg             if (auto taa = type.isTypeAArray())
   1718  1.1  mrg             {
   1719  1.1  mrg                 // Try to resolve the symbol from the key if it's not an actual type
   1720  1.1  mrg                 Identifier id;
   1721  1.1  mrg                 if (auto ti = taa.index.isTypeIdentifier())
   1722  1.1  mrg                     id = ti.ident;
   1723  1.1  mrg 
   1724  1.1  mrg                 if (id)
   1725  1.1  mrg                 {
   1726  1.1  mrg                     auto sym = findSymbol(id, adparent ? adparent : tdparent);
   1727  1.1  mrg                     if (!sym)
   1728  1.1  mrg                     {
   1729  1.1  mrg                         // Couldn't resolve, assume actual AA
   1730  1.1  mrg                     }
   1731  1.1  mrg                     else if (AST.isType(sym))
   1732  1.1  mrg                     {
   1733  1.1  mrg                         // a real associative array, forward to visit
   1734  1.1  mrg                     }
   1735  1.1  mrg                     else if (auto vd = sym.isVarDeclaration())
   1736  1.1  mrg                     {
   1737  1.1  mrg                         // Actually a static array with length symbol
   1738  1.1  mrg                         customLength = sym;
   1739  1.1  mrg                         type = taa.next; // visit the element type, length is written below
   1740  1.1  mrg                     }
   1741  1.1  mrg                     else
   1742  1.1  mrg                     {
   1743  1.1  mrg                         printf("Resolved unexpected symbol while determining static array length: %s\n", sym.toChars());
   1744  1.1  mrg                         fflush(stdout);
   1745  1.1  mrg                         fatal();
   1746  1.1  mrg                     }
   1747  1.1  mrg                 }
   1748  1.1  mrg             }
   1749  1.1  mrg         }
   1750  1.1  mrg         type.accept(this);
   1751  1.1  mrg         if (this.ident)
   1752  1.1  mrg         {
   1753  1.1  mrg             buf.writeByte(' ');
   1754  1.1  mrg             // Custom identifier doesn't need further checks
   1755  1.1  mrg             if (this.ident !is s.ident)
   1756  1.1  mrg                 buf.writestring(this.ident.toString());
   1757  1.1  mrg             else
   1758  1.1  mrg                 writeIdentifier(s, canFixup);
   1759  1.1  mrg 
   1760  1.1  mrg         }
   1761  1.1  mrg         this.ident = null;
   1762  1.1  mrg 
   1763  1.1  mrg         // Size is either taken from the type or resolved above
   1764  1.1  mrg         auto tsa = t.isTypeSArray();
   1765  1.1  mrg         if (tsa || customLength)
   1766  1.1  mrg         {
   1767  1.1  mrg             buf.writeByte('[');
   1768  1.1  mrg             if (tsa)
   1769  1.1  mrg                 tsa.dim.accept(this);
   1770  1.1  mrg             else
   1771  1.1  mrg                 writeFullName(customLength);
   1772  1.1  mrg             buf.writeByte(']');
   1773  1.1  mrg         }
   1774  1.1  mrg         else if (t.isTypeNoreturn())
   1775  1.1  mrg             buf.writestring("[0]");
   1776  1.1  mrg     }
   1777  1.1  mrg 
   1778  1.1  mrg     override void visit(AST.Type t)
   1779  1.1  mrg     {
   1780  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1781  1.1  mrg         printf("Invalid type: %s\n", t.toPrettyChars());
   1782  1.1  mrg         assert(0);
   1783  1.1  mrg     }
   1784  1.1  mrg 
   1785  1.1  mrg     override void visit(AST.TypeNoreturn t)
   1786  1.1  mrg     {
   1787  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1788  1.1  mrg 
   1789  1.1  mrg         buf.writestring("/* noreturn */ char");
   1790  1.1  mrg     }
   1791  1.1  mrg 
   1792  1.1  mrg     override void visit(AST.TypeIdentifier t)
   1793  1.1  mrg     {
   1794  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1795  1.1  mrg 
   1796  1.1  mrg         // Try to resolve the referenced symbol
   1797  1.1  mrg         if (auto sym = findSymbol(t.ident))
   1798  1.1  mrg             ensureDeclared(outermostSymbol(sym));
   1799  1.1  mrg 
   1800  1.1  mrg         if (t.idents.length)
   1801  1.1  mrg             buf.writestring("typename ");
   1802  1.1  mrg 
   1803  1.1  mrg         writeIdentifier(t.ident, t.loc, "type", tdparent !is null);
   1804  1.1  mrg 
   1805  1.1  mrg         foreach (arg; t.idents)
   1806  1.1  mrg         {
   1807  1.1  mrg             buf.writestring("::");
   1808  1.1  mrg 
   1809  1.1  mrg             import dmd.root.rootobject;
   1810  1.1  mrg             // Is this even possible?
   1811  1.1  mrg             if (arg.dyncast != DYNCAST.identifier)
   1812  1.1  mrg             {
   1813  1.1  mrg                 printf("arg.dyncast() = %d\n", arg.dyncast());
   1814  1.1  mrg                 assert(false);
   1815  1.1  mrg             }
   1816  1.1  mrg             buf.writestring((cast(Identifier) arg).toChars());
   1817  1.1  mrg         }
   1818  1.1  mrg     }
   1819  1.1  mrg 
   1820  1.1  mrg     override void visit(AST.TypeNull t)
   1821  1.1  mrg     {
   1822  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1823  1.1  mrg 
   1824  1.1  mrg         if (global.params.cplusplus >= CppStdRevision.cpp11)
   1825  1.1  mrg             buf.writestring("nullptr_t");
   1826  1.1  mrg         else
   1827  1.1  mrg             buf.writestring("void*");
   1828  1.1  mrg 
   1829  1.1  mrg     }
   1830  1.1  mrg 
   1831  1.1  mrg     override void visit(AST.TypeTypeof t)
   1832  1.1  mrg     {
   1833  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1834  1.1  mrg 
   1835  1.1  mrg         assert(t.exp);
   1836  1.1  mrg 
   1837  1.1  mrg         if (t.exp.type)
   1838  1.1  mrg         {
   1839  1.1  mrg             t.exp.type.accept(this);
   1840  1.1  mrg         }
   1841  1.1  mrg         else if (t.exp.isThisExp())
   1842  1.1  mrg         {
   1843  1.1  mrg             // Short circuit typeof(this) => <Aggregate name>
   1844  1.1  mrg             assert(adparent);
   1845  1.1  mrg             buf.writestring(adparent.ident.toChars());
   1846  1.1  mrg         }
   1847  1.1  mrg         else
   1848  1.1  mrg         {
   1849  1.1  mrg             // Relying on C++'s typeof might produce wrong results
   1850  1.1  mrg             // but it's the best we've got here.
   1851  1.1  mrg             buf.writestring("typeof(");
   1852  1.1  mrg             t.exp.accept(this);
   1853  1.1  mrg             buf.writeByte(')');
   1854  1.1  mrg         }
   1855  1.1  mrg     }
   1856  1.1  mrg 
   1857  1.1  mrg     override void visit(AST.TypeBasic t)
   1858  1.1  mrg     {
   1859  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1860  1.1  mrg 
   1861  1.1  mrg         if (t.isConst() || t.isImmutable())
   1862  1.1  mrg             buf.writestring("const ");
   1863  1.1  mrg         string typeName;
   1864  1.1  mrg         switch (t.ty)
   1865  1.1  mrg         {
   1866  1.1  mrg             case AST.Tvoid:     typeName = "void";      break;
   1867  1.1  mrg             case AST.Tbool:     typeName = "bool";      break;
   1868  1.1  mrg             case AST.Tchar:     typeName = "char";      break;
   1869  1.1  mrg             case AST.Twchar:    typeName = "char16_t";  break;
   1870  1.1  mrg             case AST.Tdchar:    typeName = "char32_t";  break;
   1871  1.1  mrg             case AST.Tint8:     typeName = "int8_t";    break;
   1872  1.1  mrg             case AST.Tuns8:     typeName = "uint8_t";   break;
   1873  1.1  mrg             case AST.Tint16:    typeName = "int16_t";   break;
   1874  1.1  mrg             case AST.Tuns16:    typeName = "uint16_t";  break;
   1875  1.1  mrg             case AST.Tint32:    typeName = "int32_t";   break;
   1876  1.1  mrg             case AST.Tuns32:    typeName = "uint32_t";  break;
   1877  1.1  mrg             case AST.Tint64:    typeName = "int64_t";   break;
   1878  1.1  mrg             case AST.Tuns64:    typeName = "uint64_t";  break;
   1879  1.1  mrg             case AST.Tfloat32:  typeName = "float";     break;
   1880  1.1  mrg             case AST.Tfloat64:  typeName = "double";    break;
   1881  1.1  mrg             case AST.Tfloat80:
   1882  1.1  mrg                 typeName = "_d_real";
   1883  1.1  mrg                 hasReal = true;
   1884  1.1  mrg                 break;
   1885  1.1  mrg             case AST.Tcomplex32:  typeName = "_Complex float";  break;
   1886  1.1  mrg             case AST.Tcomplex64:  typeName = "_Complex double"; break;
   1887  1.1  mrg             case AST.Tcomplex80:
   1888  1.1  mrg                 typeName = "_Complex _d_real";
   1889  1.1  mrg                 hasReal = true;
   1890  1.1  mrg                 break;
   1891  1.1  mrg             // ???: This is not strictly correct, but it should be ignored
   1892  1.1  mrg             // in all places where it matters most (variables, functions, ...).
   1893  1.1  mrg             case AST.Timaginary32: typeName = "float";  break;
   1894  1.1  mrg             case AST.Timaginary64: typeName = "double"; break;
   1895  1.1  mrg             case AST.Timaginary80:
   1896  1.1  mrg                 typeName = "_d_real";
   1897  1.1  mrg                 hasReal = true;
   1898  1.1  mrg                 break;
   1899  1.1  mrg             default:
   1900  1.1  mrg                 //t.print();
   1901  1.1  mrg                 assert(0);
   1902  1.1  mrg         }
   1903  1.1  mrg         buf.writestring(typeName);
   1904  1.1  mrg     }
   1905  1.1  mrg 
   1906  1.1  mrg     override void visit(AST.TypePointer t)
   1907  1.1  mrg     {
   1908  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1909  1.1  mrg 
   1910  1.1  mrg         auto ts = t.next.isTypeStruct();
   1911  1.1  mrg         if (ts && !strcmp(ts.sym.ident.toChars(), "__va_list_tag"))
   1912  1.1  mrg         {
   1913  1.1  mrg             buf.writestring("va_list");
   1914  1.1  mrg             return;
   1915  1.1  mrg         }
   1916  1.1  mrg 
   1917  1.1  mrg         // Pointer targets can be forward referenced
   1918  1.1  mrg         const fwdSave = forwarding;
   1919  1.1  mrg         forwarding = true;
   1920  1.1  mrg         scope (exit) forwarding = fwdSave;
   1921  1.1  mrg 
   1922  1.1  mrg         t.next.accept(this);
   1923  1.1  mrg         if (t.next.ty != AST.Tfunction)
   1924  1.1  mrg             buf.writeByte('*');
   1925  1.1  mrg         if (t.isConst() || t.isImmutable())
   1926  1.1  mrg             buf.writestring(" const");
   1927  1.1  mrg     }
   1928  1.1  mrg 
   1929  1.1  mrg     override void visit(AST.TypeSArray t)
   1930  1.1  mrg     {
   1931  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1932  1.1  mrg         t.next.accept(this);
   1933  1.1  mrg     }
   1934  1.1  mrg 
   1935  1.1  mrg     override void visit(AST.TypeAArray t)
   1936  1.1  mrg     {
   1937  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   1938  1.1  mrg         AST.Type.tvoidptr.accept(this);
   1939  1.1  mrg     }
   1940  1.1  mrg 
   1941  1.1  mrg     override void visit(AST.TypeFunction tf)
   1942  1.1  mrg     {
   1943  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!tf);
   1944  1.1  mrg 
   1945  1.1  mrg         tf.next.accept(this);
   1946  1.1  mrg         buf.writeByte('(');
   1947  1.1  mrg         buf.writeByte('*');
   1948  1.1  mrg         if (ident)
   1949  1.1  mrg             buf.writestring(ident.toChars());
   1950  1.1  mrg         ident = null;
   1951  1.1  mrg         buf.writeByte(')');
   1952  1.1  mrg         buf.writeByte('(');
   1953  1.1  mrg         foreach (i, fparam; tf.parameterList)
   1954  1.1  mrg         {
   1955  1.1  mrg             if (i)
   1956  1.1  mrg                 buf.writestring(", ");
   1957  1.1  mrg             fparam.accept(this);
   1958  1.1  mrg         }
   1959  1.1  mrg         if (tf.parameterList.varargs)
   1960  1.1  mrg         {
   1961  1.1  mrg             if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1)
   1962  1.1  mrg                 buf.writestring(", ");
   1963  1.1  mrg             buf.writestring("...");
   1964  1.1  mrg         }
   1965  1.1  mrg         buf.writeByte(')');
   1966  1.1  mrg     }
   1967  1.1  mrg 
   1968  1.1  mrg     ///  Writes the type that represents `ed` into `buf`.
   1969  1.1  mrg     /// (Might not be `ed` for special enums or enums that were emitted as namespaces)
   1970  1.1  mrg     private void enumToBuffer(AST.EnumDeclaration ed)
   1971  1.1  mrg     {
   1972  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!ed);
   1973  1.1  mrg 
   1974  1.1  mrg         if (ed.isSpecial())
   1975  1.1  mrg         {
   1976  1.1  mrg             if (ed.ident == DMDType.c_long)
   1977  1.1  mrg                 buf.writestring("long");
   1978  1.1  mrg             else if (ed.ident == DMDType.c_ulong)
   1979  1.1  mrg                 buf.writestring("unsigned long");
   1980  1.1  mrg             else if (ed.ident == DMDType.c_longlong)
   1981  1.1  mrg                 buf.writestring("long long");
   1982  1.1  mrg             else if (ed.ident == DMDType.c_ulonglong)
   1983  1.1  mrg                 buf.writestring("unsigned long long");
   1984  1.1  mrg             else if (ed.ident == DMDType.c_long_double)
   1985  1.1  mrg                 buf.writestring("long double");
   1986  1.1  mrg             else if (ed.ident == DMDType.c_char)
   1987  1.1  mrg                 buf.writestring("char");
   1988  1.1  mrg             else if (ed.ident == DMDType.c_wchar_t)
   1989  1.1  mrg                 buf.writestring("wchar_t");
   1990  1.1  mrg             else if (ed.ident == DMDType.c_complex_float)
   1991  1.1  mrg                 buf.writestring("_Complex float");
   1992  1.1  mrg             else if (ed.ident == DMDType.c_complex_double)
   1993  1.1  mrg                 buf.writestring("_Complex double");
   1994  1.1  mrg             else if (ed.ident == DMDType.c_complex_real)
   1995  1.1  mrg                 buf.writestring("_Complex long double");
   1996  1.1  mrg             else
   1997  1.1  mrg             {
   1998  1.1  mrg                 //ed.print();
   1999  1.1  mrg                 assert(0);
   2000  1.1  mrg             }
   2001  1.1  mrg             return;
   2002  1.1  mrg         }
   2003  1.1  mrg 
   2004  1.1  mrg         const kind = getEnumKind(ed.memtype);
   2005  1.1  mrg 
   2006  1.1  mrg         // Check if the enum was emitted as a real enum
   2007  1.1  mrg         if (kind == EnumKind.Int || kind == EnumKind.Numeric)
   2008  1.1  mrg         {
   2009  1.1  mrg             writeFullName(ed);
   2010  1.1  mrg         }
   2011  1.1  mrg         else
   2012  1.1  mrg         {
   2013  1.1  mrg             // Use the base type if the enum was emitted as a namespace
   2014  1.1  mrg             buf.printf("/* %s */ ", ed.ident.toChars());
   2015  1.1  mrg             ed.memtype.accept(this);
   2016  1.1  mrg         }
   2017  1.1  mrg     }
   2018  1.1  mrg 
   2019  1.1  mrg     override void visit(AST.TypeEnum t)
   2020  1.1  mrg     {
   2021  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   2022  1.1  mrg 
   2023  1.1  mrg         if (t.isConst() || t.isImmutable())
   2024  1.1  mrg             buf.writestring("const ");
   2025  1.1  mrg         enumToBuffer(t.sym);
   2026  1.1  mrg     }
   2027  1.1  mrg 
   2028  1.1  mrg     override void visit(AST.TypeStruct t)
   2029  1.1  mrg     {
   2030  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   2031  1.1  mrg 
   2032  1.1  mrg         if (t.isConst() || t.isImmutable())
   2033  1.1  mrg             buf.writestring("const ");
   2034  1.1  mrg         writeFullName(t.sym);
   2035  1.1  mrg     }
   2036  1.1  mrg 
   2037  1.1  mrg     override void visit(AST.TypeDArray t)
   2038  1.1  mrg     {
   2039  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   2040  1.1  mrg 
   2041  1.1  mrg         if (t.isConst() || t.isImmutable())
   2042  1.1  mrg             buf.writestring("const ");
   2043  1.1  mrg         buf.writestring("_d_dynamicArray< ");
   2044  1.1  mrg         t.next.accept(this);
   2045  1.1  mrg         buf.writestring(" >");
   2046  1.1  mrg     }
   2047  1.1  mrg 
   2048  1.1  mrg     override void visit(AST.TypeInstance t)
   2049  1.1  mrg     {
   2050  1.1  mrg         visitTi(t.tempinst);
   2051  1.1  mrg     }
   2052  1.1  mrg 
   2053  1.1  mrg     private void visitTi(AST.TemplateInstance ti)
   2054  1.1  mrg     {
   2055  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!ti);
   2056  1.1  mrg 
   2057  1.1  mrg         // Ensure that the TD appears before the instance
   2058  1.1  mrg         if (auto td = findTemplateDeclaration(ti))
   2059  1.1  mrg             ensureDeclared(td);
   2060  1.1  mrg 
   2061  1.1  mrg         foreach (o; *ti.tiargs)
   2062  1.1  mrg         {
   2063  1.1  mrg             if (!AST.isType(o))
   2064  1.1  mrg                 return;
   2065  1.1  mrg         }
   2066  1.1  mrg         buf.writestring(ti.name.toChars());
   2067  1.1  mrg         buf.writeByte('<');
   2068  1.1  mrg         foreach (i, o; *ti.tiargs)
   2069  1.1  mrg         {
   2070  1.1  mrg             if (i)
   2071  1.1  mrg                 buf.writestring(", ");
   2072  1.1  mrg             if (auto tt = AST.isType(o))
   2073  1.1  mrg             {
   2074  1.1  mrg                 tt.accept(this);
   2075  1.1  mrg             }
   2076  1.1  mrg             else
   2077  1.1  mrg             {
   2078  1.1  mrg                 //ti.print();
   2079  1.1  mrg                 //o.print();
   2080  1.1  mrg                 assert(0);
   2081  1.1  mrg             }
   2082  1.1  mrg         }
   2083  1.1  mrg         buf.writestring(" >");
   2084  1.1  mrg     }
   2085  1.1  mrg 
   2086  1.1  mrg     override void visit(AST.TemplateDeclaration td)
   2087  1.1  mrg     {
   2088  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!td);
   2089  1.1  mrg 
   2090  1.1  mrg         if (!shouldEmitAndMarkVisited(td))
   2091  1.1  mrg             return;
   2092  1.1  mrg 
   2093  1.1  mrg         if (!td.parameters || !td.onemember || (!td.onemember.isStructDeclaration && !td.onemember.isClassDeclaration && !td.onemember.isFuncDeclaration))
   2094  1.1  mrg         {
   2095  1.1  mrg             visit(cast(AST.Dsymbol)td);
   2096  1.1  mrg             return;
   2097  1.1  mrg         }
   2098  1.1  mrg 
   2099  1.1  mrg         // Explicitly disallow templates with non-type parameters or specialization.
   2100  1.1  mrg         foreach (p; *td.parameters)
   2101  1.1  mrg         {
   2102  1.1  mrg             if (!p.isTemplateTypeParameter() || p.specialization())
   2103  1.1  mrg             {
   2104  1.1  mrg                 visit(cast(AST.Dsymbol)td);
   2105  1.1  mrg                 return;
   2106  1.1  mrg             }
   2107  1.1  mrg         }
   2108  1.1  mrg 
   2109  1.1  mrg         auto save = tdparent;
   2110  1.1  mrg         tdparent = td;
   2111  1.1  mrg         const bookmark = buf.length;
   2112  1.1  mrg         printTemplateParams(td);
   2113  1.1  mrg 
   2114  1.1  mrg         const oldIgnored = this.ignoredCounter;
   2115  1.1  mrg         td.onemember.accept(this);
   2116  1.1  mrg 
   2117  1.1  mrg         // Remove "template<...>" if the symbol could not be emitted
   2118  1.1  mrg         if (oldIgnored != this.ignoredCounter)
   2119  1.1  mrg             buf.setsize(bookmark);
   2120  1.1  mrg 
   2121  1.1  mrg         tdparent = save;
   2122  1.1  mrg     }
   2123  1.1  mrg 
   2124  1.1  mrg     /// Writes the template<...> header for the supplied template declaration
   2125  1.1  mrg     private void printTemplateParams(const AST.TemplateDeclaration td)
   2126  1.1  mrg     {
   2127  1.1  mrg         buf.writestring("template <");
   2128  1.1  mrg         bool first = true;
   2129  1.1  mrg         foreach (p; *td.parameters)
   2130  1.1  mrg         {
   2131  1.1  mrg             if (first)
   2132  1.1  mrg                 first = false;
   2133  1.1  mrg             else
   2134  1.1  mrg                 buf.writestring(", ");
   2135  1.1  mrg             buf.writestring("typename ");
   2136  1.1  mrg             writeIdentifier(p.ident, p.loc, "template parameter", true);
   2137  1.1  mrg         }
   2138  1.1  mrg         buf.writestringln(">");
   2139  1.1  mrg     }
   2140  1.1  mrg 
   2141  1.1  mrg     /// Emit declarations of the TemplateMixin in the current scope
   2142  1.1  mrg     override void visit(AST.TemplateMixin tm)
   2143  1.1  mrg     {
   2144  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!tm);
   2145  1.1  mrg 
   2146  1.1  mrg         auto members = tm.members;
   2147  1.1  mrg 
   2148  1.1  mrg         // members are missing for instances inside of TemplateDeclarations, e.g.
   2149  1.1  mrg         // template Foo(T) { mixin Bar!T; }
   2150  1.1  mrg         if (!members)
   2151  1.1  mrg         {
   2152  1.1  mrg             if (auto td = findTemplateDeclaration(tm))
   2153  1.1  mrg                 members = td.members; // Emit members of the template
   2154  1.1  mrg             else
   2155  1.1  mrg                 return; // Cannot emit mixin
   2156  1.1  mrg         }
   2157  1.1  mrg 
   2158  1.1  mrg         foreach (s; *members)
   2159  1.1  mrg         {
   2160  1.1  mrg             // kind is undefined without semantic
   2161  1.1  mrg             const kind = s.visible().kind;
   2162  1.1  mrg             if (kind == AST.Visibility.Kind.public_ || kind == AST.Visibility.Kind.undefined)
   2163  1.1  mrg                 s.accept(this);
   2164  1.1  mrg         }
   2165  1.1  mrg     }
   2166  1.1  mrg 
   2167  1.1  mrg     /**
   2168  1.1  mrg      * Finds a symbol with the identifier `name` by iterating the linked list of parent
   2169  1.1  mrg      * symbols, starting from `context`.
   2170  1.1  mrg      *
   2171  1.1  mrg      * Returns: the symbol or `null` if missing
   2172  1.1  mrg      */
   2173  1.1  mrg     private AST.Dsymbol findSymbol(Identifier name, AST.Dsymbol context)
   2174  1.1  mrg     {
   2175  1.1  mrg         // Follow the declaration context
   2176  1.1  mrg         for (auto par = context; par; par = par.toParentDecl())
   2177  1.1  mrg         {
   2178  1.1  mrg             // Check that `name` doesn't refer to a template parameter
   2179  1.1  mrg             if (auto td = par.isTemplateDeclaration())
   2180  1.1  mrg             {
   2181  1.1  mrg                 foreach (const p; *td.parameters)
   2182  1.1  mrg                 {
   2183  1.1  mrg                     if (p.ident == name)
   2184  1.1  mrg                         return null;
   2185  1.1  mrg                 }
   2186  1.1  mrg             }
   2187  1.1  mrg 
   2188  1.1  mrg             if (auto mem = findMember(par, name))
   2189  1.1  mrg             {
   2190  1.1  mrg                 return mem;
   2191  1.1  mrg             }
   2192  1.1  mrg         }
   2193  1.1  mrg         return null;
   2194  1.1  mrg     }
   2195  1.1  mrg 
   2196  1.1  mrg     /// ditto
   2197  1.1  mrg     private AST.Dsymbol findSymbol(Identifier name)
   2198  1.1  mrg     {
   2199  1.1  mrg         AST.Dsymbol sym;
   2200  1.1  mrg         if (adparent)
   2201  1.1  mrg             sym = findSymbol(name, adparent);
   2202  1.1  mrg 
   2203  1.1  mrg         if (!sym && tdparent)
   2204  1.1  mrg             sym = findSymbol(name, tdparent);
   2205  1.1  mrg 
   2206  1.1  mrg         return sym;
   2207  1.1  mrg     }
   2208  1.1  mrg 
   2209  1.1  mrg     /// Finds the template declaration for instance `ti`
   2210  1.1  mrg     private AST.TemplateDeclaration findTemplateDeclaration(AST.TemplateInstance ti)
   2211  1.1  mrg     {
   2212  1.1  mrg         if (ti.tempdecl)
   2213  1.1  mrg             return ti.tempdecl.isTemplateDeclaration();
   2214  1.1  mrg 
   2215  1.1  mrg         assert(tdparent); // Only missing inside of templates
   2216  1.1  mrg 
   2217  1.1  mrg         // Search for the TemplateDeclaration, starting from the enclosing scope
   2218  1.1  mrg         // if known or the enclosing template.
   2219  1.1  mrg         auto sym = findSymbol(ti.name, ti.parent ? ti.parent : tdparent);
   2220  1.1  mrg         return sym ? sym.isTemplateDeclaration() : null;
   2221  1.1  mrg     }
   2222  1.1  mrg 
   2223  1.1  mrg     override void visit(AST.TypeClass t)
   2224  1.1  mrg     {
   2225  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   2226  1.1  mrg 
   2227  1.1  mrg         // Classes are emitted as pointer and hence can be forwarded
   2228  1.1  mrg         const fwdSave = forwarding;
   2229  1.1  mrg         forwarding = true;
   2230  1.1  mrg         scope (exit) forwarding = fwdSave;
   2231  1.1  mrg 
   2232  1.1  mrg         if (t.isConst() || t.isImmutable())
   2233  1.1  mrg             buf.writestring("const ");
   2234  1.1  mrg         writeFullName(t.sym);
   2235  1.1  mrg         buf.writeByte('*');
   2236  1.1  mrg         if (t.isConst() || t.isImmutable())
   2237  1.1  mrg             buf.writestring(" const");
   2238  1.1  mrg     }
   2239  1.1  mrg 
   2240  1.1  mrg     /**
   2241  1.1  mrg      * Writes the function signature to `buf`.
   2242  1.1  mrg      *
   2243  1.1  mrg      * Params:
   2244  1.1  mrg      *   fd     = the function to print
   2245  1.1  mrg      *   tf     = fd's type
   2246  1.1  mrg      */
   2247  1.1  mrg     private void funcToBuffer(AST.TypeFunction tf, AST.FuncDeclaration fd)
   2248  1.1  mrg     {
   2249  1.1  mrg         debug (Debug_DtoH)
   2250  1.1  mrg         {
   2251  1.1  mrg             printf("[funcToBuffer(AST.TypeFunction) enter] %s\n", fd.toChars());
   2252  1.1  mrg             scope(exit) printf("[funcToBuffer(AST.TypeFunction) exit] %s\n", fd.toChars());
   2253  1.1  mrg         }
   2254  1.1  mrg 
   2255  1.1  mrg         auto originalType = cast(AST.TypeFunction)fd.originalType;
   2256  1.1  mrg 
   2257  1.1  mrg         if (fd.isCtorDeclaration() || fd.isDtorDeclaration())
   2258  1.1  mrg         {
   2259  1.1  mrg             if (fd.isDtorDeclaration())
   2260  1.1  mrg             {
   2261  1.1  mrg                 buf.writeByte('~');
   2262  1.1  mrg             }
   2263  1.1  mrg             buf.writestring(adparent.toChars());
   2264  1.1  mrg             if (!tf)
   2265  1.1  mrg             {
   2266  1.1  mrg                 assert(fd.isDtorDeclaration());
   2267  1.1  mrg                 buf.writestring("()");
   2268  1.1  mrg                 return;
   2269  1.1  mrg             }
   2270  1.1  mrg         }
   2271  1.1  mrg         else
   2272  1.1  mrg         {
   2273  1.1  mrg             import dmd.root.string : toDString;
   2274  1.1  mrg             assert(tf.next, fd.loc.toChars().toDString());
   2275  1.1  mrg 
   2276  1.1  mrg             tf.next == AST.Type.tsize_t ? originalType.next.accept(this) : tf.next.accept(this);
   2277  1.1  mrg             if (tf.isref)
   2278  1.1  mrg                 buf.writeByte('&');
   2279  1.1  mrg             buf.writeByte(' ');
   2280  1.1  mrg             writeIdentifier(fd);
   2281  1.1  mrg         }
   2282  1.1  mrg 
   2283  1.1  mrg         buf.writeByte('(');
   2284  1.1  mrg         foreach (i, fparam; tf.parameterList)
   2285  1.1  mrg         {
   2286  1.1  mrg             if (i)
   2287  1.1  mrg                 buf.writestring(", ");
   2288  1.1  mrg             if (fparam.type == AST.Type.tsize_t && originalType)
   2289  1.1  mrg             {
   2290  1.1  mrg                 fparam = originalType.parameterList[i];
   2291  1.1  mrg             }
   2292  1.1  mrg             fparam.accept(this);
   2293  1.1  mrg         }
   2294  1.1  mrg         if (tf.parameterList.varargs)
   2295  1.1  mrg         {
   2296  1.1  mrg             if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1)
   2297  1.1  mrg                 buf.writestring(", ");
   2298  1.1  mrg             buf.writestring("...");
   2299  1.1  mrg         }
   2300  1.1  mrg         buf.writeByte(')');
   2301  1.1  mrg     }
   2302  1.1  mrg 
   2303  1.1  mrg     override void visit(AST.Parameter p)
   2304  1.1  mrg     {
   2305  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!p);
   2306  1.1  mrg 
   2307  1.1  mrg         ident = p.ident;
   2308  1.1  mrg 
   2309  1.1  mrg         {
   2310  1.1  mrg             // Reference parameters can be forwarded
   2311  1.1  mrg             const fwdStash = this.forwarding;
   2312  1.1  mrg             this.forwarding = !!(p.storageClass & AST.STC.ref_);
   2313  1.1  mrg             p.type.accept(this);
   2314  1.1  mrg             this.forwarding = fwdStash;
   2315  1.1  mrg         }
   2316  1.1  mrg 
   2317  1.1  mrg         if (p.storageClass & AST.STC.ref_)
   2318  1.1  mrg             buf.writeByte('&');
   2319  1.1  mrg         buf.writeByte(' ');
   2320  1.1  mrg         if (ident)
   2321  1.1  mrg             // FIXME: Parameter is missing a Loc
   2322  1.1  mrg             writeIdentifier(ident, Loc.initial, "parameter", true);
   2323  1.1  mrg         ident = null;
   2324  1.1  mrg 
   2325  1.1  mrg         if (p.defaultArg)
   2326  1.1  mrg         {
   2327  1.1  mrg             //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op);
   2328  1.1  mrg             buf.writestring(" = ");
   2329  1.1  mrg             printExpressionFor(p.type, p.defaultArg);
   2330  1.1  mrg         }
   2331  1.1  mrg     }
   2332  1.1  mrg 
   2333  1.1  mrg     /**
   2334  1.1  mrg      * Prints `exp` as an expression of type `target` while inserting
   2335  1.1  mrg      * appropriate code when implicit conversion does not translate
   2336  1.1  mrg      * directly to C++, e.g. from an enum to its base type.
   2337  1.1  mrg      *
   2338  1.1  mrg      * Params:
   2339  1.1  mrg      *   target = the type `exp` is converted to
   2340  1.1  mrg      *   exp    = the expression to print
   2341  1.1  mrg      *   isCtor = if `exp` is a ctor argument
   2342  1.1  mrg      */
   2343  1.1  mrg     private void printExpressionFor(AST.Type target, AST.Expression exp, const bool isCtor = false)
   2344  1.1  mrg     {
   2345  1.1  mrg         /// Determines if a static_cast is required
   2346  1.1  mrg         static bool needsCast(AST.Type target, AST.Expression exp)
   2347  1.1  mrg         {
   2348  1.1  mrg             // import std.stdio;
   2349  1.1  mrg             // writefln("%s:%s: target = %s, type = %s (%s)", exp.loc.linnum, exp.loc.charnum, target, exp.type, exp.op);
   2350  1.1  mrg 
   2351  1.1  mrg             auto source = exp.type;
   2352  1.1  mrg 
   2353  1.1  mrg             // DotVarExp resolve conversions, e.g from an enum to its base type
   2354  1.1  mrg             if (auto dve = exp.isDotVarExp())
   2355  1.1  mrg                 source = dve.var.type;
   2356  1.1  mrg 
   2357  1.1  mrg             if (!source)
   2358  1.1  mrg                 // Defensively assume that the cast is required
   2359  1.1  mrg                 return true;
   2360  1.1  mrg 
   2361  1.1  mrg             // Conversions from enum class to base type require static_cast
   2362  1.1  mrg             if (global.params.cplusplus >= CppStdRevision.cpp11 &&
   2363  1.1  mrg                 source.isTypeEnum && !target.isTypeEnum)
   2364  1.1  mrg                 return true;
   2365  1.1  mrg 
   2366  1.1  mrg             return false;
   2367  1.1  mrg         }
   2368  1.1  mrg 
   2369  1.1  mrg         // Slices are emitted as a special struct, hence we need to fix up
   2370  1.1  mrg         // any expression initialising a slice variable/member
   2371  1.1  mrg         if (auto ta = target.isTypeDArray())
   2372  1.1  mrg         {
   2373  1.1  mrg             if (exp.isNullExp())
   2374  1.1  mrg             {
   2375  1.1  mrg                 if (isCtor)
   2376  1.1  mrg                 {
   2377  1.1  mrg                     // Don't emit, use default ctor
   2378  1.1  mrg                 }
   2379  1.1  mrg                 else if (global.params.cplusplus >= CppStdRevision.cpp11)
   2380  1.1  mrg                 {
   2381  1.1  mrg                     // Prefer initializer list
   2382  1.1  mrg                     buf.writestring("{}");
   2383  1.1  mrg                 }
   2384  1.1  mrg                 else
   2385  1.1  mrg                 {
   2386  1.1  mrg                     // Write __d_dynamic_array<TYPE>()
   2387  1.1  mrg                     visit(ta);
   2388  1.1  mrg                     buf.writestring("()");
   2389  1.1  mrg                 }
   2390  1.1  mrg                 return;
   2391  1.1  mrg             }
   2392  1.1  mrg 
   2393  1.1  mrg             if (auto se = exp.isStringExp())
   2394  1.1  mrg             {
   2395  1.1  mrg                 // Rewrite as <length> + <literal> pair optionally
   2396  1.1  mrg                 // wrapped in a initializer list/ctor call
   2397  1.1  mrg 
   2398  1.1  mrg                 const initList = global.params.cplusplus >= CppStdRevision.cpp11;
   2399  1.1  mrg                 if (!isCtor)
   2400  1.1  mrg                 {
   2401  1.1  mrg                     if (initList)
   2402  1.1  mrg                         buf.writestring("{ ");
   2403  1.1  mrg                     else
   2404  1.1  mrg                     {
   2405  1.1  mrg                         visit(ta);
   2406  1.1  mrg                         buf.writestring("( ");
   2407  1.1  mrg                     }
   2408  1.1  mrg                 }
   2409  1.1  mrg 
   2410  1.1  mrg                 buf.printf("%zu, ", se.len);
   2411  1.1  mrg                 visit(se);
   2412  1.1  mrg 
   2413  1.1  mrg                 if (!isCtor)
   2414  1.1  mrg                     buf.writestring(initList ? " }" : " )");
   2415  1.1  mrg 
   2416  1.1  mrg                 return;
   2417  1.1  mrg             }
   2418  1.1  mrg         }
   2419  1.1  mrg         else if (auto ce = exp.isCastExp())
   2420  1.1  mrg         {
   2421  1.1  mrg             buf.writeByte('(');
   2422  1.1  mrg             if (ce.to)
   2423  1.1  mrg                 ce.to.accept(this);
   2424  1.1  mrg             else if (ce.e1.type)
   2425  1.1  mrg                 // Try the expression type with modifiers in case of cast(const) in templates
   2426  1.1  mrg                 ce.e1.type.castMod(ce.mod).accept(this);
   2427  1.1  mrg             else
   2428  1.1  mrg                 // Fallback, not necessarily correct but the best we've got here
   2429  1.1  mrg                 target.accept(this);
   2430  1.1  mrg             buf.writestring(") ");
   2431  1.1  mrg             ce.e1.accept(this);
   2432  1.1  mrg         }
   2433  1.1  mrg         else if (needsCast(target, exp))
   2434  1.1  mrg         {
   2435  1.1  mrg             buf.writestring("static_cast<");
   2436  1.1  mrg             target.accept(this);
   2437  1.1  mrg             buf.writestring(">(");
   2438  1.1  mrg             exp.accept(this);
   2439  1.1  mrg             buf.writeByte(')');
   2440  1.1  mrg         }
   2441  1.1  mrg         else
   2442  1.1  mrg         {
   2443  1.1  mrg             exp.accept(this);
   2444  1.1  mrg         }
   2445  1.1  mrg     }
   2446  1.1  mrg 
   2447  1.1  mrg     override void visit(AST.Expression e)
   2448  1.1  mrg     {
   2449  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2450  1.1  mrg 
   2451  1.1  mrg         // Valid in most cases, others should be overriden below
   2452  1.1  mrg         // to use the appropriate operators  (:: and ->)
   2453  1.1  mrg         buf.writestring(e.toString());
   2454  1.1  mrg     }
   2455  1.1  mrg 
   2456  1.1  mrg     override void visit(AST.UnaExp e)
   2457  1.1  mrg     {
   2458  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2459  1.1  mrg 
   2460  1.1  mrg         buf.writestring(expToString(e.op));
   2461  1.1  mrg         e.e1.accept(this);
   2462  1.1  mrg     }
   2463  1.1  mrg 
   2464  1.1  mrg     override void visit(AST.BinExp e)
   2465  1.1  mrg     {
   2466  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2467  1.1  mrg 
   2468  1.1  mrg         e.e1.accept(this);
   2469  1.1  mrg         buf.writeByte(' ');
   2470  1.1  mrg         buf.writestring(expToString(e.op));
   2471  1.1  mrg         buf.writeByte(' ');
   2472  1.1  mrg         e.e2.accept(this);
   2473  1.1  mrg     }
   2474  1.1  mrg 
   2475  1.1  mrg     /// Translates operator `op` into the C++ representation
   2476  1.1  mrg     private extern(D) static string expToString(const EXP op)
   2477  1.1  mrg     {
   2478  1.1  mrg         switch (op) with (EXP)
   2479  1.1  mrg         {
   2480  1.1  mrg             case identity:      return "==";
   2481  1.1  mrg             case notIdentity:   return "!=";
   2482  1.1  mrg             default:
   2483  1.1  mrg                 return EXPtoString(op);
   2484  1.1  mrg         }
   2485  1.1  mrg     }
   2486  1.1  mrg 
   2487  1.1  mrg     override void visit(AST.VarExp e)
   2488  1.1  mrg     {
   2489  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2490  1.1  mrg 
   2491  1.1  mrg         // Local members don't need another prefix and might've been renamed
   2492  1.1  mrg         if (e.var.isThis())
   2493  1.1  mrg         {
   2494  1.1  mrg             includeSymbol(e.var);
   2495  1.1  mrg             writeIdentifier(e.var, true);
   2496  1.1  mrg         }
   2497  1.1  mrg         else
   2498  1.1  mrg             writeFullName(e.var);
   2499  1.1  mrg     }
   2500  1.1  mrg 
   2501  1.1  mrg     /// Partially prints the FQN including parent aggregates
   2502  1.1  mrg     private void printPrefix(AST.Dsymbol var)
   2503  1.1  mrg     {
   2504  1.1  mrg         if (!var || var is adparent || var.isModule())
   2505  1.1  mrg             return;
   2506  1.1  mrg 
   2507  1.1  mrg         writeFullName(var);
   2508  1.1  mrg         buf.writestring("::");
   2509  1.1  mrg     }
   2510  1.1  mrg 
   2511  1.1  mrg     override void visit(AST.CallExp e)
   2512  1.1  mrg     {
   2513  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2514  1.1  mrg 
   2515  1.1  mrg         // Dereferencing function pointers requires additional braces: (*f)(args)
   2516  1.1  mrg         const isFp = e.e1.isPtrExp();
   2517  1.1  mrg         if (isFp)
   2518  1.1  mrg             buf.writeByte('(');
   2519  1.1  mrg         else if (e.f)
   2520  1.1  mrg             includeSymbol(outermostSymbol(e.f));
   2521  1.1  mrg 
   2522  1.1  mrg         e.e1.accept(this);
   2523  1.1  mrg 
   2524  1.1  mrg         if (isFp) buf.writeByte(')');
   2525  1.1  mrg 
   2526  1.1  mrg         assert(e.arguments);
   2527  1.1  mrg         buf.writeByte('(');
   2528  1.1  mrg         foreach (i, arg; *e.arguments)
   2529  1.1  mrg         {
   2530  1.1  mrg             if (i)
   2531  1.1  mrg                 buf.writestring(", ");
   2532  1.1  mrg             arg.accept(this);
   2533  1.1  mrg         }
   2534  1.1  mrg         buf.writeByte(')');
   2535  1.1  mrg     }
   2536  1.1  mrg 
   2537  1.1  mrg     override void visit(AST.DotVarExp e)
   2538  1.1  mrg     {
   2539  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2540  1.1  mrg 
   2541  1.1  mrg         if (auto sym = symbolFromType(e.e1.type))
   2542  1.1  mrg             includeSymbol(outermostSymbol(sym));
   2543  1.1  mrg 
   2544  1.1  mrg         // Accessing members through a pointer?
   2545  1.1  mrg         if (auto pe = e.e1.isPtrExp)
   2546  1.1  mrg         {
   2547  1.1  mrg             pe.e1.accept(this);
   2548  1.1  mrg             buf.writestring("->");
   2549  1.1  mrg         }
   2550  1.1  mrg         else
   2551  1.1  mrg         {
   2552  1.1  mrg             e.e1.accept(this);
   2553  1.1  mrg             buf.writeByte('.');
   2554  1.1  mrg         }
   2555  1.1  mrg 
   2556  1.1  mrg         // Should only be used to access non-static members
   2557  1.1  mrg         assert(e.var.isThis());
   2558  1.1  mrg 
   2559  1.1  mrg         writeIdentifier(e.var, true);
   2560  1.1  mrg     }
   2561  1.1  mrg 
   2562  1.1  mrg     override void visit(AST.DotIdExp e)
   2563  1.1  mrg     {
   2564  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2565  1.1  mrg 
   2566  1.1  mrg         e.e1.accept(this);
   2567  1.1  mrg         buf.writestring("::");
   2568  1.1  mrg         buf.writestring(e.ident.toChars());
   2569  1.1  mrg     }
   2570  1.1  mrg 
   2571  1.1  mrg     override void visit(AST.ScopeExp e)
   2572  1.1  mrg     {
   2573  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2574  1.1  mrg 
   2575  1.1  mrg         // Usually a template instance in a TemplateDeclaration
   2576  1.1  mrg         if (auto ti = e.sds.isTemplateInstance())
   2577  1.1  mrg             visitTi(ti);
   2578  1.1  mrg         else
   2579  1.1  mrg             writeFullName(e.sds);
   2580  1.1  mrg     }
   2581  1.1  mrg 
   2582  1.1  mrg     override void visit(AST.NullExp e)
   2583  1.1  mrg     {
   2584  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2585  1.1  mrg 
   2586  1.1  mrg         if (global.params.cplusplus >= CppStdRevision.cpp11)
   2587  1.1  mrg             buf.writestring("nullptr");
   2588  1.1  mrg         else
   2589  1.1  mrg             buf.writestring("NULL");
   2590  1.1  mrg     }
   2591  1.1  mrg 
   2592  1.1  mrg     override void visit(AST.ArrayLiteralExp e)
   2593  1.1  mrg     {
   2594  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2595  1.1  mrg         buf.writestring("arrayliteral");
   2596  1.1  mrg     }
   2597  1.1  mrg 
   2598  1.1  mrg     override void visit(AST.StringExp e)
   2599  1.1  mrg     {
   2600  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2601  1.1  mrg 
   2602  1.1  mrg         if (e.sz == 2)
   2603  1.1  mrg             buf.writeByte('u');
   2604  1.1  mrg         else if (e.sz == 4)
   2605  1.1  mrg             buf.writeByte('U');
   2606  1.1  mrg         buf.writeByte('"');
   2607  1.1  mrg 
   2608  1.1  mrg         foreach (i; 0 .. e.len)
   2609  1.1  mrg         {
   2610  1.1  mrg             writeCharLiteral(*buf, e.getCodeUnit(i));
   2611  1.1  mrg         }
   2612  1.1  mrg         buf.writeByte('"');
   2613  1.1  mrg     }
   2614  1.1  mrg 
   2615  1.1  mrg     override void visit(AST.RealExp e)
   2616  1.1  mrg     {
   2617  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2618  1.1  mrg 
   2619  1.1  mrg         import dmd.root.ctfloat : CTFloat;
   2620  1.1  mrg 
   2621  1.1  mrg         // Special case NaN and Infinity because floatToBuffer
   2622  1.1  mrg         // uses D literals (`nan` and `infinity`)
   2623  1.1  mrg         if (CTFloat.isNaN(e.value))
   2624  1.1  mrg         {
   2625  1.1  mrg             buf.writestring("NAN");
   2626  1.1  mrg         }
   2627  1.1  mrg         else if (CTFloat.isInfinity(e.value))
   2628  1.1  mrg         {
   2629  1.1  mrg             if (e.value < CTFloat.zero)
   2630  1.1  mrg                 buf.writeByte('-');
   2631  1.1  mrg             buf.writestring("INFINITY");
   2632  1.1  mrg         }
   2633  1.1  mrg         else
   2634  1.1  mrg         {
   2635  1.1  mrg             import dmd.hdrgen;
   2636  1.1  mrg             // Hex floating point literals were introduced in C++ 17
   2637  1.1  mrg             const allowHex = global.params.cplusplus >= CppStdRevision.cpp17;
   2638  1.1  mrg             floatToBuffer(e.type, e.value, buf, allowHex);
   2639  1.1  mrg         }
   2640  1.1  mrg     }
   2641  1.1  mrg 
   2642  1.1  mrg     override void visit(AST.IntegerExp e)
   2643  1.1  mrg     {
   2644  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!e);
   2645  1.1  mrg         visitInteger(e.toInteger, e.type);
   2646  1.1  mrg     }
   2647  1.1  mrg 
   2648  1.1  mrg     /// Writes `v` as type `t` into `buf`
   2649  1.1  mrg     private void visitInteger(dinteger_t v, AST.Type t)
   2650  1.1  mrg     {
   2651  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!t);
   2652  1.1  mrg 
   2653  1.1  mrg         switch (t.ty)
   2654  1.1  mrg         {
   2655  1.1  mrg             case AST.Tenum:
   2656  1.1  mrg                 auto te = cast(AST.TypeEnum)t;
   2657  1.1  mrg                 buf.writestring("(");
   2658  1.1  mrg                 enumToBuffer(te.sym);
   2659  1.1  mrg                 buf.writestring(")");
   2660  1.1  mrg                 visitInteger(v, te.sym.memtype);
   2661  1.1  mrg                 break;
   2662  1.1  mrg             case AST.Tbool:
   2663  1.1  mrg                 buf.writestring(v ? "true" : "false");
   2664  1.1  mrg                 break;
   2665  1.1  mrg             case AST.Tint8:
   2666  1.1  mrg                 buf.printf("%d", cast(byte)v);
   2667  1.1  mrg                 break;
   2668  1.1  mrg             case AST.Tuns8:
   2669  1.1  mrg                 buf.printf("%uu", cast(ubyte)v);
   2670  1.1  mrg                 break;
   2671  1.1  mrg             case AST.Tint16:
   2672  1.1  mrg                 buf.printf("%d", cast(short)v);
   2673  1.1  mrg                 break;
   2674  1.1  mrg             case AST.Tuns16:
   2675  1.1  mrg             case AST.Twchar:
   2676  1.1  mrg                 buf.printf("%uu", cast(ushort)v);
   2677  1.1  mrg                 break;
   2678  1.1  mrg             case AST.Tint32:
   2679  1.1  mrg             case AST.Tdchar:
   2680  1.1  mrg                 buf.printf("%d", cast(int)v);
   2681  1.1  mrg                 break;
   2682  1.1  mrg             case AST.Tuns32:
   2683  1.1  mrg                 buf.printf("%uu", cast(uint)v);
   2684  1.1  mrg                 break;
   2685  1.1  mrg             case AST.Tint64:
   2686  1.1  mrg                 buf.printf("%lldLL", v);
   2687  1.1  mrg                 break;
   2688  1.1  mrg             case AST.Tuns64:
   2689  1.1  mrg                 buf.printf("%lluLLU", v);
   2690  1.1  mrg                 break;
   2691  1.1  mrg             case AST.Tchar:
   2692  1.1  mrg                 if (v > 0x20 && v < 0x80)
   2693  1.1  mrg                     buf.printf("'%c'", cast(int)v);
   2694  1.1  mrg                 else
   2695  1.1  mrg                     buf.printf("%uu", cast(ubyte)v);
   2696  1.1  mrg                 break;
   2697  1.1  mrg             default:
   2698  1.1  mrg                 //t.print();
   2699  1.1  mrg                 assert(0);
   2700  1.1  mrg         }
   2701  1.1  mrg     }
   2702  1.1  mrg 
   2703  1.1  mrg     override void visit(AST.StructLiteralExp sle)
   2704  1.1  mrg     {
   2705  1.1  mrg         debug (Debug_DtoH) mixin(traceVisit!sle);
   2706  1.1  mrg 
   2707  1.1  mrg         const isUnion = sle.sd.isUnionDeclaration();
   2708  1.1  mrg         sle.sd.type.accept(this);
   2709  1.1  mrg         buf.writeByte('(');
   2710  1.1  mrg         foreach(i, e; *sle.elements)
   2711  1.1  mrg         {
   2712  1.1  mrg             if (i)
   2713  1.1  mrg                 buf.writestring(", ");
   2714  1.1  mrg 
   2715  1.1  mrg             auto vd = sle.sd.fields[i];
   2716  1.1  mrg 
   2717  1.1  mrg             // Expression may be null for unspecified elements
   2718  1.1  mrg             if (!e)
   2719  1.1  mrg                 e = findDefaultInitializer(vd);
   2720  1.1  mrg 
   2721  1.1  mrg             printExpressionFor(vd.type, e);
   2722  1.1  mrg 
   2723  1.1  mrg             // Only emit the initializer of the first union member
   2724  1.1  mrg             if (isUnion)
   2725  1.1  mrg                 break;
   2726  1.1  mrg         }
   2727  1.1  mrg         buf.writeByte(')');
   2728  1.1  mrg     }
   2729  1.1  mrg 
   2730  1.1  mrg     /// Finds the default initializer for the given VarDeclaration
   2731  1.1  mrg     private static AST.Expression findDefaultInitializer(AST.VarDeclaration vd)
   2732  1.1  mrg     {
   2733  1.1  mrg         if (vd._init && !vd._init.isVoidInitializer())
   2734  1.1  mrg             return AST.initializerToExpression(vd._init);
   2735  1.1  mrg         else if (auto ts = vd.type.isTypeStruct())
   2736  1.1  mrg         {
   2737  1.1  mrg             if (!ts.sym.noDefaultCtor && !ts.sym.isUnionDeclaration())
   2738  1.1  mrg             {
   2739  1.1  mrg                 // Generate a call to the default constructor that we've generated.
   2740  1.1  mrg                 auto sle = new AST.StructLiteralExp(Loc.initial, ts.sym, new AST.Expressions(0));
   2741  1.1  mrg                 sle.type = vd.type;
   2742  1.1  mrg                 return sle;
   2743  1.1  mrg             }
   2744  1.1  mrg             else
   2745  1.1  mrg                 return vd.type.defaultInitLiteral(Loc.initial);
   2746  1.1  mrg         }
   2747  1.1  mrg         else
   2748  1.1  mrg             return vd.type.defaultInitLiteral(Loc.initial);
   2749  1.1  mrg     }
   2750  1.1  mrg 
   2751  1.1  mrg     static if (__VERSION__ < 2092)
   2752  1.1  mrg     {
   2753  1.1  mrg         private void ignored(const char* format, ...) nothrow
   2754  1.1  mrg         {
   2755  1.1  mrg             this.ignoredCounter++;
   2756  1.1  mrg 
   2757  1.1  mrg             import core.stdc.stdarg;
   2758  1.1  mrg             if (!printIgnored)
   2759  1.1  mrg                 return;
   2760  1.1  mrg 
   2761  1.1  mrg             va_list ap;
   2762  1.1  mrg             va_start(ap, format);
   2763  1.1  mrg             buf.writestring("// Ignored ");
   2764  1.1  mrg             buf.vprintf(format, ap);
   2765  1.1  mrg             buf.writenl();
   2766  1.1  mrg             va_end(ap);
   2767  1.1  mrg         }
   2768  1.1  mrg     }
   2769  1.1  mrg     else
   2770  1.1  mrg     {
   2771  1.1  mrg         /// Writes a formatted message into `buf` if `printIgnored` is true
   2772  1.1  mrg         /// and increments `ignoredCounter`
   2773  1.1  mrg         pragma(printf)
   2774  1.1  mrg         private void ignored(const char* format, ...) nothrow
   2775  1.1  mrg         {
   2776  1.1  mrg             this.ignoredCounter++;
   2777  1.1  mrg 
   2778  1.1  mrg             import core.stdc.stdarg;
   2779  1.1  mrg             if (!printIgnored)
   2780  1.1  mrg                 return;
   2781  1.1  mrg 
   2782  1.1  mrg             va_list ap;
   2783  1.1  mrg             va_start(ap, format);
   2784  1.1  mrg             buf.writestring("// Ignored ");
   2785  1.1  mrg             buf.vprintf(format, ap);
   2786  1.1  mrg             buf.writenl();
   2787  1.1  mrg             va_end(ap);
   2788  1.1  mrg         }
   2789  1.1  mrg     }
   2790  1.1  mrg 
   2791  1.1  mrg     /**
   2792  1.1  mrg      * Determines whether `s` should be emitted. This requires that `sym`
   2793  1.1  mrg      * - is `extern(C[++]`)
   2794  1.1  mrg      * - is not instantiated from a template (visits the `TemplateDeclaration` instead)
   2795  1.1  mrg      *
   2796  1.1  mrg      * Params:
   2797  1.1  mrg      *   sym = the symbol
   2798  1.1  mrg      *
   2799  1.1  mrg      * Returns: whether `sym` should be emitted
   2800  1.1  mrg      */
   2801  1.1  mrg     private bool shouldEmit(AST.Dsymbol sym)
   2802  1.1  mrg     {
   2803  1.1  mrg         import dmd.aggregate : ClassKind;
   2804  1.1  mrg         debug (Debug_DtoH)
   2805  1.1  mrg         {
   2806  1.1  mrg             printf("[shouldEmitAndMarkVisited enter] %s\n", sym.toPrettyChars());
   2807  1.1  mrg             scope(exit) printf("[shouldEmitAndMarkVisited exit] %s\n", sym.toPrettyChars());
   2808  1.1  mrg         }
   2809  1.1  mrg 
   2810  1.1  mrg         // Template *instances* should not be emitted
   2811  1.1  mrg         if (sym.isInstantiated())
   2812  1.1  mrg             return false;
   2813  1.1  mrg 
   2814  1.1  mrg         // Matching linkage (except extern(C) classes which don't make sense)
   2815  1.1  mrg         if (linkage == LINK.cpp || (linkage == LINK.c && !sym.isClassDeclaration()))
   2816  1.1  mrg             return true;
   2817  1.1  mrg 
   2818  1.1  mrg         // Check against the internal information which might be missing, e.g. inside of template declarations
   2819  1.1  mrg         if (auto dec = sym.isDeclaration())
   2820  1.1  mrg         {
   2821  1.1  mrg             const l = dec.resolvedLinkage();
   2822  1.1  mrg             return l == LINK.cpp || l == LINK.c;
   2823  1.1  mrg         }
   2824  1.1  mrg 
   2825  1.1  mrg         if (auto ad = sym.isAggregateDeclaration())
   2826  1.1  mrg             return ad.classKind == ClassKind.cpp;
   2827  1.1  mrg 
   2828  1.1  mrg         return false;
   2829  1.1  mrg     }
   2830  1.1  mrg 
   2831  1.1  mrg     /**
   2832  1.1  mrg      * Determines whether `s` should be emitted. This requires that `sym`
   2833  1.1  mrg      * - was not visited before
   2834  1.1  mrg      * - is `extern(C[++]`)
   2835  1.1  mrg      * - is not instantiated from a template (visits the `TemplateDeclaration` instead)
   2836  1.1  mrg      * The result is cached in the visited nodes array.
   2837  1.1  mrg      *
   2838  1.1  mrg      * Params:
   2839  1.1  mrg      *   sym = the symbol
   2840  1.1  mrg      *
   2841  1.1  mrg      * Returns: whether `sym` should be emitted
   2842  1.1  mrg      **/
   2843  1.1  mrg     private bool shouldEmitAndMarkVisited(AST.Dsymbol sym)
   2844  1.1  mrg     {
   2845  1.1  mrg         debug (Debug_DtoH)
   2846  1.1  mrg         {
   2847  1.1  mrg             printf("[shouldEmitAndMarkVisited enter] %s\n", sym.toPrettyChars());
   2848  1.1  mrg             scope(exit) printf("[shouldEmitAndMarkVisited exit] %s\n", sym.toPrettyChars());
   2849  1.1  mrg         }
   2850  1.1  mrg 
   2851  1.1  mrg         auto statePtr = (cast(void*) sym) in visited;
   2852  1.1  mrg 
   2853  1.1  mrg          // `sym` was already emitted or skipped and isn't required
   2854  1.1  mrg         if (statePtr && (*statePtr || !mustEmit))
   2855  1.1  mrg             return false;
   2856  1.1  mrg 
   2857  1.1  mrg         // Template *instances* should not be emitted, forward to the declaration
   2858  1.1  mrg         if (auto ti = sym.isInstantiated())
   2859  1.1  mrg         {
   2860  1.1  mrg             auto td = findTemplateDeclaration(ti);
   2861  1.1  mrg             assert(td);
   2862  1.1  mrg             visit(td);
   2863  1.1  mrg             return false;
   2864  1.1  mrg         }
   2865  1.1  mrg 
   2866  1.1  mrg         // Required or matching linkage (except extern(C) classes which don't make sense)
   2867  1.1  mrg         bool res = mustEmit || linkage == LINK.cpp || (linkage == LINK.c && !sym.isClassDeclaration());
   2868  1.1  mrg         if (!res)
   2869  1.1  mrg         {
   2870  1.1  mrg             // Check against the internal information which might be missing, e.g. inside of template declarations
   2871  1.1  mrg             if (auto dec = sym.isDeclaration())
   2872  1.1  mrg             {
   2873  1.1  mrg                 const l = dec.resolvedLinkage();
   2874  1.1  mrg                 res = (l == LINK.cpp || l == LINK.c);
   2875  1.1  mrg             }
   2876  1.1  mrg         }
   2877  1.1  mrg 
   2878  1.1  mrg         // Remember result for later calls
   2879  1.1  mrg         if (statePtr)
   2880  1.1  mrg             *statePtr = res;
   2881  1.1  mrg         else
   2882  1.1  mrg             visited[(cast(void*) sym)] = res;
   2883  1.1  mrg 
   2884  1.1  mrg         // Print a warning when the symbol is ignored for the first time
   2885  1.1  mrg         // Might not be correct if it is required by symbol the is visited
   2886  1.1  mrg         // AFTER the current node
   2887  1.1  mrg         if (!statePtr && !res)
   2888  1.1  mrg             ignored("%s %s because of linkage", sym.kind(), sym.toPrettyChars());
   2889  1.1  mrg 
   2890  1.1  mrg         return res;
   2891  1.1  mrg     }
   2892  1.1  mrg 
   2893  1.1  mrg     /**
   2894  1.1  mrg      * Ensures that `sym` is declared before the current position in `buf` by
   2895  1.1  mrg      * either creating a forward reference in `fwdbuf` if possible or
   2896  1.1  mrg      * calling `includeSymbol` to emit the entire declaration into `donebuf`.
   2897  1.1  mrg      */
   2898  1.1  mrg     private void ensureDeclared(AST.Dsymbol sym)
   2899  1.1  mrg     {
   2900  1.1  mrg         auto par = sym.toParent2();
   2901  1.1  mrg         auto ed = sym.isEnumDeclaration();
   2902  1.1  mrg 
   2903  1.1  mrg         // Eagerly include the symbol if we cannot create a valid forward declaration
   2904  1.1  mrg         // Forwarding of scoped enums requires C++11 or above
   2905  1.1  mrg         if (!forwarding || (par && !par.isModule()) || (ed && global.params.cplusplus < CppStdRevision.cpp11))
   2906  1.1  mrg         {
   2907  1.1  mrg             // Emit the entire enclosing declaration if any
   2908  1.1  mrg             includeSymbol(outermostSymbol(sym));
   2909  1.1  mrg             return;
   2910  1.1  mrg         }
   2911  1.1  mrg 
   2912  1.1  mrg         auto ti = sym.isInstantiated();
   2913  1.1  mrg         auto td = ti ? findTemplateDeclaration(ti) : null;
   2914  1.1  mrg         auto check = cast(void*) (td ? td : sym);
   2915  1.1  mrg 
   2916  1.1  mrg         // Omit redundant fwd-declaration if we already emitted the entire declaration
   2917  1.1  mrg         if (visited.get(check, false))
   2918  1.1  mrg             return;
   2919  1.1  mrg 
   2920  1.1  mrg         // Already created a fwd-declaration?
   2921  1.1  mrg         if (check in forwarded)
   2922  1.1  mrg             return;
   2923  1.1  mrg         forwarded[check] = true;
   2924  1.1  mrg 
   2925  1.1  mrg         // Print template<...>
   2926  1.1  mrg         if (ti)
   2927  1.1  mrg         {
   2928  1.1  mrg             auto bufSave = buf;
   2929  1.1  mrg             buf = fwdbuf;
   2930  1.1  mrg             printTemplateParams(td);
   2931  1.1  mrg             buf = bufSave;
   2932  1.1  mrg         }
   2933  1.1  mrg 
   2934  1.1  mrg         // Determine the kind of symbol that is forwared: struct, ...
   2935  1.1  mrg         const(char)* kind;
   2936  1.1  mrg 
   2937  1.1  mrg         if (auto ad = sym.isAggregateDeclaration())
   2938  1.1  mrg         {
   2939  1.1  mrg             // Look for extern(C++, class) <some aggregate>
   2940  1.1  mrg             if (ad.cppmangle == CPPMANGLE.def)
   2941  1.1  mrg                 kind = ad.kind();
   2942  1.1  mrg             else if (ad.cppmangle == CPPMANGLE.asStruct)
   2943  1.1  mrg                 kind =  "struct";
   2944  1.1  mrg             else
   2945  1.1  mrg                 kind = "class";
   2946  1.1  mrg         }
   2947  1.1  mrg         else if (ed)
   2948  1.1  mrg         {
   2949  1.1  mrg             // Only called from enumToBuffer, so should always be emitted as an actual enum
   2950  1.1  mrg             kind = "enum class";
   2951  1.1  mrg         }
   2952  1.1  mrg         else
   2953  1.1  mrg             kind = sym.kind(); // Should be unreachable but just to be sure
   2954  1.1  mrg 
   2955  1.1  mrg         fwdbuf.writestring(kind);
   2956  1.1  mrg         fwdbuf.writeByte(' ');
   2957  1.1  mrg         fwdbuf.writestring(sym.toChars());
   2958  1.1  mrg         fwdbuf.writestringln(";");
   2959  1.1  mrg     }
   2960  1.1  mrg 
   2961  1.1  mrg     /**
   2962  1.1  mrg      * Writes the qualified name of `sym` into `buf` including parent
   2963  1.1  mrg      * symbols and template parameters.
   2964  1.1  mrg      *
   2965  1.1  mrg      * Params:
   2966  1.1  mrg      *   sym         = the symbol
   2967  1.1  mrg      *   mustInclude = whether sym may not be forward declared
   2968  1.1  mrg      */
   2969  1.1  mrg     private void writeFullName(AST.Dsymbol sym, const bool mustInclude = false)
   2970  1.1  mrg     in
   2971  1.1  mrg     {
   2972  1.1  mrg         assert(sym);
   2973  1.1  mrg         assert(sym.ident, sym.toString());
   2974  1.1  mrg         // Should never be called directly with a TI, only onemember
   2975  1.1  mrg         assert(!sym.isTemplateInstance(), sym.toString());
   2976  1.1  mrg     }
   2977  1.1  mrg     do
   2978  1.1  mrg     {
   2979  1.1  mrg         debug (Debug_DtoH)
   2980  1.1  mrg         {
   2981  1.1  mrg             printf("[writeFullName enter] %s\n", sym.toPrettyChars());
   2982  1.1  mrg             scope(exit) printf("[writeFullName exit] %s\n", sym.toPrettyChars());
   2983  1.1  mrg         }
   2984  1.1  mrg 
   2985  1.1  mrg         // Explicit `pragma(mangle, "<some string>` overrides the declared name
   2986  1.1  mrg         if (auto mn = getMangleOverride(sym))
   2987  1.1  mrg             return buf.writestring(mn);
   2988  1.1  mrg 
   2989  1.1  mrg         /// Checks whether `sym` is nested in `par` and hence doesn't need the FQN
   2990  1.1  mrg         static bool isNestedIn(AST.Dsymbol sym, AST.Dsymbol par)
   2991  1.1  mrg         {
   2992  1.1  mrg             while (par)
   2993  1.1  mrg             {
   2994  1.1  mrg                 if (sym is par)
   2995  1.1  mrg                     return true;
   2996  1.1  mrg                 par = par.toParent();
   2997  1.1  mrg             }
   2998  1.1  mrg             return false;
   2999  1.1  mrg         }
   3000  1.1  mrg         AST.TemplateInstance ti;
   3001  1.1  mrg         bool nested;
   3002  1.1  mrg 
   3003  1.1  mrg         // Check if the `sym` is nested into another symbol and hence requires `Parent::sym`
   3004  1.1  mrg         if (auto par = sym.toParent())
   3005  1.1  mrg         {
   3006  1.1  mrg             // toParent() yields the template instance if `sym` is the onemember of a TI
   3007  1.1  mrg             ti = par.isTemplateInstance();
   3008  1.1  mrg 
   3009  1.1  mrg             // Skip the TI because Foo!int.Foo is folded into Foo<int>
   3010  1.1  mrg             if (ti) par = ti.toParent();
   3011  1.1  mrg 
   3012  1.1  mrg             // Prefix the name with any enclosing declaration
   3013  1.1  mrg             // Stop at either module or enclosing aggregate
   3014  1.1  mrg             nested = !par.isModule();
   3015  1.1  mrg             if (nested && !isNestedIn(par, adparent))
   3016  1.1  mrg             {
   3017  1.1  mrg                 writeFullName(par, true);
   3018  1.1  mrg                 buf.writestring("::");
   3019  1.1  mrg             }
   3020  1.1  mrg         }
   3021  1.1  mrg 
   3022  1.1  mrg         if (!nested)
   3023  1.1  mrg         {
   3024  1.1  mrg             // Cannot forward the symbol when called recursively
   3025  1.1  mrg             // for a nested symbol
   3026  1.1  mrg             if (mustInclude)
   3027  1.1  mrg                 includeSymbol(sym);
   3028  1.1  mrg             else
   3029  1.1  mrg                 ensureDeclared(sym);
   3030  1.1  mrg         }
   3031  1.1  mrg 
   3032  1.1  mrg         if (ti)
   3033  1.1  mrg             visitTi(ti);
   3034  1.1  mrg         else
   3035  1.1  mrg             buf.writestring(sym.ident.toString());
   3036  1.1  mrg     }
   3037  1.1  mrg 
   3038  1.1  mrg     /// Returns: Explicit mangling for `sym` if present
   3039  1.1  mrg     extern(D) static const(char)[] getMangleOverride(const AST.Dsymbol sym)
   3040  1.1  mrg     {
   3041  1.1  mrg         if (auto decl = sym.isDeclaration())
   3042  1.1  mrg             return decl.mangleOverride;
   3043  1.1  mrg 
   3044  1.1  mrg         return null;
   3045  1.1  mrg     }
   3046  1.1  mrg }
   3047  1.1  mrg 
   3048  1.1  mrg /// Namespace for identifiers used to represent special enums in C++
   3049  1.1  mrg struct DMDType
   3050  1.1  mrg {
   3051  1.1  mrg     __gshared Identifier c_long;
   3052  1.1  mrg     __gshared Identifier c_ulong;
   3053  1.1  mrg     __gshared Identifier c_longlong;
   3054  1.1  mrg     __gshared Identifier c_ulonglong;
   3055  1.1  mrg     __gshared Identifier c_long_double;
   3056  1.1  mrg     __gshared Identifier c_char;
   3057  1.1  mrg     __gshared Identifier c_wchar_t;
   3058  1.1  mrg     __gshared Identifier c_complex_float;
   3059  1.1  mrg     __gshared Identifier c_complex_double;
   3060  1.1  mrg     __gshared Identifier c_complex_real;
   3061  1.1  mrg 
   3062  1.1  mrg     static void _init()
   3063  1.1  mrg     {
   3064  1.1  mrg         c_long          = Identifier.idPool("__c_long");
   3065  1.1  mrg         c_ulong         = Identifier.idPool("__c_ulong");
   3066  1.1  mrg         c_longlong      = Identifier.idPool("__c_longlong");
   3067  1.1  mrg         c_ulonglong     = Identifier.idPool("__c_ulonglong");
   3068  1.1  mrg         c_long_double   = Identifier.idPool("__c_long_double");
   3069  1.1  mrg         c_wchar_t       = Identifier.idPool("__c_wchar_t");
   3070  1.1  mrg         c_char          = Identifier.idPool("__c_char");
   3071  1.1  mrg         c_complex_float  = Identifier.idPool("__c_complex_float");
   3072  1.1  mrg         c_complex_double = Identifier.idPool("__c_complex_double");
   3073  1.1  mrg         c_complex_real = Identifier.idPool("__c_complex_real");
   3074  1.1  mrg     }
   3075  1.1  mrg }
   3076  1.1  mrg 
   3077  1.1  mrg /// Initializes all data structures used by the header generator
   3078  1.1  mrg void initialize()
   3079  1.1  mrg {
   3080  1.1  mrg     __gshared bool initialized;
   3081  1.1  mrg 
   3082  1.1  mrg     if (!initialized)
   3083  1.1  mrg     {
   3084  1.1  mrg         initialized = true;
   3085  1.1  mrg 
   3086  1.1  mrg         DMDType._init();
   3087  1.1  mrg     }
   3088  1.1  mrg }
   3089  1.1  mrg 
   3090  1.1  mrg /// Writes `#if <content>` into the supplied buffer
   3091  1.1  mrg void hashIf(ref OutBuffer buf, string content)
   3092  1.1  mrg {
   3093  1.1  mrg     buf.writestring("#if ");
   3094  1.1  mrg     buf.writestringln(content);
   3095  1.1  mrg }
   3096  1.1  mrg 
   3097  1.1  mrg /// Writes `#elif <content>` into the supplied buffer
   3098  1.1  mrg void hashElIf(ref OutBuffer buf, string content)
   3099  1.1  mrg {
   3100  1.1  mrg     buf.writestring("#elif ");
   3101  1.1  mrg     buf.writestringln(content);
   3102  1.1  mrg }
   3103  1.1  mrg 
   3104  1.1  mrg /// Writes `#endif` into the supplied buffer
   3105  1.1  mrg void hashEndIf(ref OutBuffer buf)
   3106  1.1  mrg {
   3107  1.1  mrg     buf.writestringln("#endif");
   3108  1.1  mrg }
   3109  1.1  mrg 
   3110  1.1  mrg /// Writes `#define <content>` into the supplied buffer
   3111  1.1  mrg void hashDefine(ref OutBuffer buf, string content)
   3112  1.1  mrg {
   3113  1.1  mrg     buf.writestring("#define ");
   3114  1.1  mrg     buf.writestringln(content);
   3115  1.1  mrg }
   3116  1.1  mrg 
   3117  1.1  mrg /// Writes `#include <content>` into the supplied buffer
   3118  1.1  mrg void hashInclude(ref OutBuffer buf, string content)
   3119  1.1  mrg {
   3120  1.1  mrg     buf.writestring("#include ");
   3121  1.1  mrg     buf.writestringln(content);
   3122  1.1  mrg }
   3123  1.1  mrg 
   3124  1.1  mrg /// Determines whether `ident` is a reserved keyword in C++
   3125  1.1  mrg /// Returns: the kind of keyword or `null`
   3126  1.1  mrg const(char*) keywordClass(const Identifier ident)
   3127  1.1  mrg {
   3128  1.1  mrg     if (!ident)
   3129  1.1  mrg         return null;
   3130  1.1  mrg 
   3131  1.1  mrg     const name = ident.toString();
   3132  1.1  mrg     switch (name)
   3133  1.1  mrg     {
   3134  1.1  mrg         // C++ operators
   3135  1.1  mrg         case "and":
   3136  1.1  mrg         case "and_eq":
   3137  1.1  mrg         case "bitand":
   3138  1.1  mrg         case "bitor":
   3139  1.1  mrg         case "compl":
   3140  1.1  mrg         case "not":
   3141  1.1  mrg         case "not_eq":
   3142  1.1  mrg         case "or":
   3143  1.1  mrg         case "or_eq":
   3144  1.1  mrg         case "xor":
   3145  1.1  mrg         case "xor_eq":
   3146  1.1  mrg             return "special operator in C++";
   3147  1.1  mrg 
   3148  1.1  mrg         // C++ keywords
   3149  1.1  mrg         case "_Complex":
   3150  1.1  mrg         case "const_cast":
   3151  1.1  mrg         case "delete":
   3152  1.1  mrg         case "dynamic_cast":
   3153  1.1  mrg         case "explicit":
   3154  1.1  mrg         case "friend":
   3155  1.1  mrg         case "inline":
   3156  1.1  mrg         case "mutable":
   3157  1.1  mrg         case "namespace":
   3158  1.1  mrg         case "operator":
   3159  1.1  mrg         case "register":
   3160  1.1  mrg         case "reinterpret_cast":
   3161  1.1  mrg         case "signed":
   3162  1.1  mrg         case "static_cast":
   3163  1.1  mrg         case "typedef":
   3164  1.1  mrg         case "typename":
   3165  1.1  mrg         case "unsigned":
   3166  1.1  mrg         case "using":
   3167  1.1  mrg         case "virtual":
   3168  1.1  mrg         case "volatile":
   3169  1.1  mrg             return "keyword in C++";
   3170  1.1  mrg 
   3171  1.1  mrg         // Common macros imported by this header
   3172  1.1  mrg         // stddef.h
   3173  1.1  mrg         case "offsetof":
   3174  1.1  mrg         case "NULL":
   3175  1.1  mrg             return "default macro in C++";
   3176  1.1  mrg 
   3177  1.1  mrg         // C++11 keywords
   3178  1.1  mrg         case "alignas":
   3179  1.1  mrg         case "alignof":
   3180  1.1  mrg         case "char16_t":
   3181  1.1  mrg         case "char32_t":
   3182  1.1  mrg         case "constexpr":
   3183  1.1  mrg         case "decltype":
   3184  1.1  mrg         case "noexcept":
   3185  1.1  mrg         case "nullptr":
   3186  1.1  mrg         case "static_assert":
   3187  1.1  mrg         case "thread_local":
   3188  1.1  mrg         case "wchar_t":
   3189  1.1  mrg             if (global.params.cplusplus >= CppStdRevision.cpp11)
   3190  1.1  mrg                 return "keyword in C++11";
   3191  1.1  mrg             return null;
   3192  1.1  mrg 
   3193  1.1  mrg         // C++20 keywords
   3194  1.1  mrg         case "char8_t":
   3195  1.1  mrg         case "consteval":
   3196  1.1  mrg         case "constinit":
   3197  1.1  mrg         // Concepts-related keywords
   3198  1.1  mrg         case "concept":
   3199  1.1  mrg         case "requires":
   3200  1.1  mrg         // Coroutines-related keywords
   3201  1.1  mrg         case "co_await":
   3202  1.1  mrg         case "co_yield":
   3203  1.1  mrg         case "co_return":
   3204  1.1  mrg             if (global.params.cplusplus >= CppStdRevision.cpp20)
   3205  1.1  mrg                 return "keyword in C++20";
   3206  1.1  mrg             return null;
   3207  1.1  mrg 
   3208  1.1  mrg         default:
   3209  1.1  mrg             // Identifiers starting with __ are reserved
   3210  1.1  mrg             if (name.length >= 2 && name[0..2] == "__")
   3211  1.1  mrg                 return "reserved identifier in C++";
   3212  1.1  mrg 
   3213  1.1  mrg             return null;
   3214  1.1  mrg     }
   3215  1.1  mrg }
   3216  1.1  mrg 
   3217  1.1  mrg /// Finds the outermost symbol if `sym` is nested.
   3218  1.1  mrg /// Returns `sym` if it appears at module scope
   3219  1.1  mrg ASTCodegen.Dsymbol outermostSymbol(ASTCodegen.Dsymbol sym)
   3220  1.1  mrg {
   3221  1.1  mrg     assert(sym);
   3222  1.1  mrg     while (true)
   3223  1.1  mrg     {
   3224  1.1  mrg         auto par = sym.toParent();
   3225  1.1  mrg         if (!par || par.isModule())
   3226  1.1  mrg             return sym;
   3227  1.1  mrg         sym = par;
   3228  1.1  mrg     }
   3229  1.1  mrg }
   3230  1.1  mrg 
   3231  1.1  mrg /// Fetches the symbol for user-defined types from the type `t`
   3232  1.1  mrg /// if `t` is either `TypeClass`, `TypeStruct` or `TypeEnum`
   3233  1.1  mrg ASTCodegen.Dsymbol symbolFromType(ASTCodegen.Type t)
   3234  1.1  mrg {
   3235  1.1  mrg     if (auto tc = t.isTypeClass())
   3236  1.1  mrg         return tc.sym;
   3237  1.1  mrg     if (auto ts = t.isTypeStruct())
   3238  1.1  mrg         return ts.sym;
   3239  1.1  mrg     if (auto te = t.isTypeEnum())
   3240  1.1  mrg         return te.sym;
   3241  1.1  mrg     return null;
   3242  1.1  mrg }
   3243  1.1  mrg 
   3244  1.1  mrg /**
   3245  1.1  mrg  * Searches `sym` for a member with the given name.
   3246  1.1  mrg  *
   3247  1.1  mrg  * This method usually delegates to `Dsymbol.search` but might also
   3248  1.1  mrg  * manually check the members if the symbol did not receive semantic
   3249  1.1  mrg  * analysis.
   3250  1.1  mrg  *
   3251  1.1  mrg  * Params:
   3252  1.1  mrg  *   sym  = symbol to search
   3253  1.1  mrg  *   name = identifier of the requested symbol
   3254  1.1  mrg  *
   3255  1.1  mrg  * Returns: the symbol or `null` if not found
   3256  1.1  mrg  */
   3257  1.1  mrg ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name)
   3258  1.1  mrg {
   3259  1.1  mrg     if (auto mem = sym.search(Loc.initial, name, ASTCodegen.IgnoreErrors))
   3260  1.1  mrg         return mem;
   3261  1.1  mrg 
   3262  1.1  mrg     // search doesn't work for declarations inside of uninstantiated
   3263  1.1  mrg     // `TemplateDeclaration`s due to the missing symtab.
   3264  1.1  mrg     if (sym.semanticRun >= ASTCodegen.PASS.semanticdone)
   3265  1.1  mrg         return null;
   3266  1.1  mrg 
   3267  1.1  mrg     // Manually check the members if present
   3268  1.1  mrg     auto sds = sym.isScopeDsymbol();
   3269  1.1  mrg     if (!sds || !sds.members)
   3270  1.1  mrg         return null;
   3271  1.1  mrg 
   3272  1.1  mrg     /// Recursively searches for `name` without entering nested aggregates, ...
   3273  1.1  mrg     static ASTCodegen.Dsymbol search(ASTCodegen.Dsymbols* members, Identifier name)
   3274  1.1  mrg     {
   3275  1.1  mrg         foreach (mem; *members)
   3276  1.1  mrg         {
   3277  1.1  mrg             if (mem.ident == name)
   3278  1.1  mrg                 return mem;
   3279  1.1  mrg 
   3280  1.1  mrg             // Look inside of private:, ...
   3281  1.1  mrg             if (auto ad = mem.isAttribDeclaration())
   3282  1.1  mrg             {
   3283  1.1  mrg                 if (auto s = search(ad.decl, name))
   3284  1.1  mrg                     return s;
   3285  1.1  mrg             }
   3286  1.1  mrg         }
   3287  1.1  mrg         return null;
   3288  1.1  mrg     }
   3289  1.1  mrg 
   3290  1.1  mrg     return search(sds.members, name);
   3291  1.1  mrg }
   3292  1.1  mrg 
   3293  1.1  mrg debug (Debug_DtoH)
   3294  1.1  mrg {
   3295  1.1  mrg     /// Generates code to trace the entry and exit of the enclosing `visit` function
   3296  1.1  mrg     string traceVisit(alias node)()
   3297  1.1  mrg     {
   3298  1.1  mrg         const type = typeof(node).stringof;
   3299  1.1  mrg         const method = __traits(hasMember, node, "toPrettyChars") ? "toPrettyChars" : "toChars";
   3300  1.1  mrg         const arg = __traits(identifier, node) ~ '.' ~ method;
   3301  1.1  mrg 
   3302  1.1  mrg         return `printf("[` ~ type ~  ` enter] %s\n", ` ~ arg ~ `());
   3303  1.1  mrg                 scope(exit) printf("[` ~ type ~ ` exit] %s\n", ` ~ arg ~ `());`;
   3304  1.1  mrg     }
   3305  1.1  mrg }
   3306