1 /**
2  * This module contains the implementation of the C++ header generation available through
3  * the command line switch -Hc.
4  *
5  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d)
9  * Documentation:  https://dlang.org/phobos/dmd_dtoh.html
10  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtoh.d
11  */
12 module dmd.dtoh;
13 
14 import core.stdc.stdio;
15 import core.stdc..string;
16 import core.stdc.ctype;
17 
18 import dmd.astcodegen;
19 import dmd.arraytypes;
20 import dmd.globals;
21 import dmd.identifier;
22 import dmd.root.filename;
23 import dmd.visitor;
24 import dmd.tokens;
25 
26 import dmd.root.outbuffer;
27 import dmd.utils;
28 
29 //debug = Debug_DtoH;
30 enum isBuildingCompiler = false;
31 
32 private struct DMDType
33 {
34     __gshared Identifier c_long;
35     __gshared Identifier c_ulong;
36     __gshared Identifier c_longlong;
37     __gshared Identifier c_ulonglong;
38     __gshared Identifier c_long_double;
39     __gshared Identifier c_wchar_t;
40     __gshared Identifier AssocArray;
41     __gshared Identifier Array;
42 
43     static void _init()
44     {
45         c_long          = Identifier.idPool("__c_long");
46         c_ulong         = Identifier.idPool("__c_ulong");
47         c_longlong      = Identifier.idPool("__c_longlong");
48         c_ulonglong     = Identifier.idPool("__c_ulonglong");
49         c_long_double   = Identifier.idPool("__c_long_double");
50         c_wchar_t       = Identifier.idPool("__c_wchar_t");
51 
52         if (isBuildingCompiler)
53         {
54             AssocArray      = Identifier.idPool("AssocArray");
55             Array           = Identifier.idPool("Array");
56         }
57 
58     }
59 }
60 
61 private struct DMDModule
62 {
63     __gshared Identifier identifier;
64     __gshared Identifier root;
65     __gshared Identifier visitor;
66     __gshared Identifier parsetimevisitor;
67     __gshared Identifier permissivevisitor;
68     __gshared Identifier strictvisitor;
69     __gshared Identifier transitivevisitor;
70     __gshared Identifier dmd;
71     static void _init()
72     {
73         identifier          = Identifier.idPool("identifier");
74         root                = Identifier.idPool("root");
75         visitor             = Identifier.idPool("visitor");
76         parsetimevisitor    = Identifier.idPool("parsetimevisitor");
77         permissivevisitor   = Identifier.idPool("permissivevisitor");
78         strictvisitor       = Identifier.idPool("strictvisitor");
79         transitivevisitor   = Identifier.idPool("transitivevisitor");
80         dmd                 = Identifier.idPool("dmd");
81     }
82 }
83 
84 private struct DMDClass
85 {
86     __gshared Identifier ID; ////Identifier
87     __gshared Identifier Visitor;
88     __gshared Identifier ParseTimeVisitor;
89     static void _init()
90     {
91         ID                  = Identifier.idPool("Identifier");
92         Visitor             = Identifier.idPool("Visitor");
93         ParseTimeVisitor    = Identifier.idPool("ParseTimeVisitor");
94     }
95 
96 }
97 
98 private bool isIdentifierClass(ASTCodegen.ClassDeclaration cd)
99 {
100     return (cd.ident == DMDClass.ID &&
101             cd.parent !is null &&
102             cd.parent.ident == DMDModule.identifier &&
103             cd.parent.parent && cd.parent.parent.ident == DMDModule.dmd &&
104             !cd.parent.parent.parent);
105 }
106 
107 private bool isVisitorClass(ASTCodegen.ClassDeclaration cd)
108 {
109     for (auto cdb = cd; cdb; cdb = cdb.baseClass)
110     {
111         if (cdb.ident == DMDClass.Visitor ||
112             cdb.ident == DMDClass.ParseTimeVisitor)
113         return true;
114     }
115     return false;
116 }
117 
118 private bool isIgnoredModule(ASTCodegen.Module m)
119 {
120     if (!m)
121         return true;
122 
123     // Ignore dmd.root
124     if (m.parent && m.parent.ident == DMDModule.root &&
125         m.parent.parent && m.parent.parent.ident == DMDModule.dmd &&
126         !m.parent.parent.parent)
127     {
128         return true;
129     }
130 
131     // Ignore dmd.visitor and derivatives
132     if ((m.ident == DMDModule.visitor ||
133             m.ident == DMDModule.parsetimevisitor ||
134             m.ident == DMDModule.permissivevisitor ||
135             m.ident == DMDModule.strictvisitor ||
136             m.ident == DMDModule.transitivevisitor) &&
137             m.parent && m.parent.ident == DMDModule.dmd &&
138             !m.parent.parent)
139     {
140         return true;
141     }
142     return false;
143 }
144 
145 private bool isFrontendModule(ASTCodegen.Module m)
146 {
147     if (!m || !m.parent)
148         return false;
149 
150     // Ignore dmd.root
151     if (m.parent.ident == DMDModule.root &&
152         m.parent.parent && m.parent.parent.ident == DMDModule.dmd &&
153         !m.parent.parent.parent)
154     {
155         return false;
156     }
157 
158     // Ignore dmd.visitor and derivatives
159     if ((m.ident == DMDModule.visitor ||
160             m.ident == DMDModule.parsetimevisitor ||
161             m.ident == DMDModule.permissivevisitor ||
162             m.ident == DMDModule.strictvisitor ||
163             m.ident == DMDModule.transitivevisitor) &&
164             m.parent && m.parent.ident == DMDModule.dmd &&
165             !m.parent.parent)
166     {
167         return false;
168     }
169     return ((m.parent.ident == DMDModule.dmd && !m.parent.parent) ||
170             (m.parent.parent.ident == DMDModule.dmd && !m.parent.parent.parent));
171 }
172 
173 private void initialize()
174 {
175     __gshared bool initialized;
176 
177     if (!initialized)
178     {
179         initialized = true;
180 
181         DMDType._init();
182         if (isBuildingCompiler)
183         {
184             DMDModule._init();
185             DMDClass._init();
186         }
187     }
188 }
189 
190 void hashIf(ref OutBuffer buf, string content)
191 {
192     buf.writestring("#if ");
193     buf.writestringln(content);
194 }
195 
196 void hashElIf(ref OutBuffer buf, string content)
197 {
198     buf.writestring("#elif ");
199     buf.writestringln(content);
200 }
201 
202 void hashEndIf(ref OutBuffer buf)
203 {
204     buf.writestringln("#endif");
205 }
206 
207 void hashDefine(ref OutBuffer buf, string content)
208 {
209     buf.writestring("# define ");
210     buf.writestringln(content);
211 }
212 
213 void hashInclude(ref OutBuffer buf, string content)
214 {
215     buf.writestring("#include ");
216     buf.writestringln(content);
217 }
218 
219 
220 
221 extern(C++) void genCppHdrFiles(ref Modules ms)
222 {
223     initialize();
224 
225     OutBuffer fwd;
226     OutBuffer check;
227     OutBuffer done;
228     OutBuffer decl;
229 
230     // enable indent by spaces on buffers
231     decl.doindent = true;
232     decl.spaces = true;
233     check.doindent = true;
234     decl.spaces = true;
235 
236     scope v = new ToCppBuffer(&check, &fwd, &done, &decl);
237 
238     OutBuffer buf;
239     buf.doindent = true;
240     buf.spaces = true;
241 
242     foreach (m; ms)
243         m.accept(v);
244 
245     buf.printf("// Automatically generated by %s Compiler v%d", global.vendor.ptr, global.versionNumber());
246     buf.writenl();
247     buf.writenl();
248     buf.writestringln("#pragma once");
249     buf.writenl();
250 //    buf.writestring("#include <assert.h>\n");
251     hashInclude(buf, "<stddef.h>");
252     hashInclude(buf, "<stdint.h>");
253 //    buf.writestring(buf, "#include <stdio.h>\n");
254 //    buf.writestring("#include <string.h>\n");
255     buf.writenl();
256     if (v.hasReal)
257     {
258         hashIf(buf, "!defined(_d_real)");
259         {
260             hashDefine(buf, "_d_real long double");
261         }
262         hashEndIf(buf);
263     }
264     if (v.hasDefaultEnum)
265     {
266         hashIf(buf, "!defined(BEGIN_ENUM)");
267         {
268             hashDefine(buf, "BEGIN_ENUM(name, upper, lower) enum class name {");
269             hashDefine(buf, "ENUM_KEY(type, name, value, enumName, upper, lower, abbrev) name = value,");
270             hashDefine(buf, "END_ENUM(name, upper, lower) };");
271         }
272         hashEndIf(buf);
273     }
274     if (v.hasNumericEnum)
275     {
276         hashIf(buf, "!defined(BEGIN_ENUM_NUMERIC)");
277         {
278             hashDefine(buf, "BEGIN_ENUM_NUMERIC(type, name, upper, lower) enum class name : type {");
279             hashDefine(buf, "ENUM_KEY_NUMERIC(type, name, value, enumName, upper, lower, abbrev) name = value,");
280             hashDefine(buf, "END_ENUM_NUMERIC(type, name, upper, lower) };");
281         }
282         hashEndIf(buf);
283     }
284     if (v.hasTypedEnum)
285     {
286         hashIf(buf, "!defined(BEGIN_ENUM_TYPE)");
287         {
288             hashDefine(buf, "BEGIN_ENUM_TYPE(type, name, upper, lower) namespace name {");
289             hashDefine(buf, "ENUM_KEY_TYPE(type, name, value, enumName, upper, lower, abbrev) static type const name = value;");
290             hashDefine(buf, "END_ENUM_TYPE(type, name, upper, lower) };");
291         }
292         hashEndIf(buf);
293     }
294     if (v.hasAnonEnum)
295     {
296         hashIf(buf, "!defined(BEGIN_ANON_ENUM)");
297         {
298             hashDefine(buf, "BEGIN_ANON_ENUM() enum {");
299             hashDefine(buf, "ANON_ENUM_KEY(type, name, value) name = value,");
300             hashDefine(buf, "END_ANON_ENUM() };");
301         }
302         hashEndIf(buf);
303     }
304     if (v.hasAnonNumericEnum)
305     {
306         hashIf(buf, "!defined(BEGIN_ANON_ENUM_NUMERIC)");
307         {
308             hashDefine(buf, "BEGIN_ANON_ENUM_NUMERIC(type) enum : type {");
309             hashDefine(buf, "ANON_ENUM_KEY_NUMERIC(type, name, value) name = value,");
310             hashDefine(buf, "END_ANON_ENUM_NUMERIC(type) };");
311         }
312         hashEndIf(buf);
313     }
314     if (v.hasNumericConstant)
315     {
316         hashIf(buf, "!defined(ENUM_CONSTANT_NUMERIC)");
317         {
318             hashDefine(buf, "ENUM_CONSTANT_NUMERIC(type, name, value) enum : type { name = value };");
319         }
320         hashEndIf(buf);
321     }
322     if (v.hasTypedConstant)
323     {
324         hashIf(buf, "!defined(ENUM_CONSTANT)");
325         {
326             hashDefine(buf, "ENUM_CONSTANT(type, name, value) static type const name = value;");
327         }
328         hashEndIf(buf);
329     }
330     buf.writenl();
331 
332     buf.write(&fwd);
333     if (fwd.length > 0)
334         buf.writenl();
335 
336     buf.write(&done);
337     buf.write(&decl);
338 
339     debug (Debug_DtoH)
340     {
341         buf.writestring(`
342 #if OFFSETS
343     template <class T>
344     size_t getSlotNumber(int dummy, ...)
345     {
346         T c;
347         va_list ap;
348         va_start(ap, dummy);
349 
350         void *f = va_arg(ap, void*);
351         for (size_t i = 0; ; i++)
352         {
353             if ( (*(void***)&c)[i] == f)
354             return i;
355         }
356         va_end(ap);
357     }
358 
359     void testOffsets()
360     {
361 `);
362         buf.write(&check);
363         buf.writestring(`
364     }
365 #endif
366 `);
367     }
368 
369     if (global.params.cxxhdrname is null)
370     {
371         // Write to stdout; assume it succeeds
372         size_t n = fwrite(buf[].ptr, 1, buf.length, stdout);
373         assert(n == buf.length); // keep gcc happy about return values
374     }
375     else
376     {
377         const(char)[] name = FileName.combine(global.params.cxxhdrdir, global.params.cxxhdrname);
378         writeFile(Loc.initial, name, buf[]);
379     }
380 }
381 
382 /****************************************************
383  */
384 extern(C++) final class ToCppBuffer : Visitor
385 {
386     alias visit = Visitor.visit;
387 public:
388     enum EnumKind
389     {
390         Int,
391         Numeric,
392         Other
393     }
394 
395     alias AST = ASTCodegen;
396 
397     bool[void*] visited;
398     bool[void*] forwarded;
399     OutBuffer* fwdbuf;
400     OutBuffer* checkbuf;
401     OutBuffer* donebuf;
402     OutBuffer* buf;
403     AST.AggregateDeclaration adparent;
404     AST.ClassDeclaration cdparent;
405     AST.TemplateDeclaration tdparent;
406     Identifier ident;
407     LINK linkage = LINK.d;
408     bool forwardedAA;
409     AST.Type* origType;
410 
411     bool hasReal;
412     bool hasDefaultEnum;
413     bool hasNumericEnum;
414     bool hasTypedEnum;
415     bool hasAnonEnum;
416     bool hasAnonNumericEnum;
417     bool hasNumericConstant;
418     bool hasTypedConstant;
419 
420     this(OutBuffer* checkbuf, OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf)
421     {
422         this.checkbuf = checkbuf;
423         this.fwdbuf = fwdbuf;
424         this.donebuf = donebuf;
425         this.buf = buf;
426     }
427 
428     private EnumKind getEnumKind(AST.Type type)
429     {
430         if (type) switch (type.ty)
431         {
432             case AST.Tint32:
433                 return EnumKind.Int;
434             case AST.Tbool,
435                 AST.Tchar, AST.Twchar, AST.Tdchar,
436                 AST.Tint8, AST.Tuns8,
437                 AST.Tint16, AST.Tuns16,
438                 AST.Tuns32,
439                 AST.Tint64, AST.Tuns64:
440                 return EnumKind.Numeric;
441             default:
442                 break;
443         }
444         return EnumKind.Other;
445     }
446 
447     private void writeEnumTypeName(AST.Type type)
448     {
449         if (auto arr = type.isTypeDArray())
450         {
451             switch (arr.next.ty)
452             {
453                 case AST.Tchar:  buf.writestring("const char*"); return;
454                 case AST.Twchar: buf.writestring("const char16_t*"); return;
455                 case AST.Tdchar: buf.writestring("const char32_t*"); return;
456                 default: break;
457             }
458         }
459         type.accept(this);
460     }
461 
462     void writeDeclEnd()
463     {
464         buf.writestringln(";");
465 
466         if (!adparent)
467             buf.writenl();
468     }
469 
470     override void visit(AST.Dsymbol s)
471     {
472         debug (Debug_DtoH)
473         {
474             printf("[AST.Dsymbol enter] %s\n", s.toChars());
475             import dmd.asttypename;
476             printf("[AST.Dsymbol enter] %s\n", s.astTypeName().ptr);
477             scope(exit) printf("[AST.Dsymbol exit] %s\n", s.toChars());
478         }
479 
480         if (isBuildingCompiler && s.getModule() && s.getModule().isFrontendModule())
481         {
482             buf.printf("// ignored %s %s", s.kind(), s.toPrettyChars());
483             buf.writenl();
484         }
485     }
486 
487     override void visit(AST.Import i)
488     {
489         debug (Debug_DtoH)
490         {
491             printf("[AST.Import enter] %s\n", i.toChars());
492             scope(exit) printf("[AST.Import exit] %s\n", i.toChars());
493         }
494     }
495 
496     override void visit(AST.AttribDeclaration pd)
497     {
498         debug (Debug_DtoH)
499         {
500             printf("[AST.AttribDeclaration enter] %s\n", pd.toChars());
501             scope(exit) printf("[AST.AttribDeclaration exit] %s\n", pd.toChars());
502         }
503         Dsymbols* decl = pd.include(null);
504         if (!decl)
505             return;
506 
507         foreach (s; *decl)
508         {
509             if (adparent || s.prot().kind >= AST.Prot.Kind.public_)
510                 s.accept(this);
511         }
512     }
513 
514     override void visit(AST.LinkDeclaration ld)
515     {
516         debug (Debug_DtoH)
517         {
518             printf("[AST.LinkDeclaration enter] %s\n", ld.toChars());
519             scope(exit) printf("[AST.LinkDeclaration exit] %s\n", ld.toChars());
520         }
521         auto save = linkage;
522         linkage = ld.linkage;
523         if (ld.linkage != LINK.c && ld.linkage != LINK.cpp)
524         {
525             buf.printf("// ignoring %s block because of linkage", ld.toPrettyChars());
526             buf.writenl();
527         }
528         else
529         {
530             visit(cast(AST.AttribDeclaration)ld);
531         }
532         linkage = save;
533     }
534 
535     override void visit(AST.Module m)
536     {
537         debug (Debug_DtoH)
538         {
539             printf("[AST.Module enter] %s\n", m.toChars());
540             scope(exit) printf("[AST.Module exit] %s\n", m.toChars());
541         }
542         foreach (s; *m.members)
543         {
544             if (s.prot().kind < AST.Prot.Kind.public_)
545                 continue;
546             s.accept(this);
547         }
548     }
549 
550     override void visit(AST.FuncDeclaration fd)
551     {
552         debug (Debug_DtoH)
553         {
554             printf("[AST.FuncDeclaration enter] %s\n", fd.toChars());
555             scope(exit) printf("[AST.FuncDeclaration exit] %s\n", fd.toChars());
556         }
557         if (cast(void*)fd in visited)
558             return;
559         if (isBuildingCompiler && fd.getModule() && fd.getModule().isIgnoredModule())
560             return;
561 
562         // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars());
563         visited[cast(void*)fd] = true;
564 
565         auto tf = cast(AST.TypeFunction)fd.type;
566         if (!tf || !tf.deco)
567         {
568             buf.printf("// ignoring function %s because semantic hasn't been run", fd.toPrettyChars());
569             buf.writenl();
570             return;
571         }
572         if (tf.linkage != LINK.c && tf.linkage != LINK.cpp)
573         {
574             buf.printf("// ignoring function %s because of linkage", fd.toPrettyChars());
575             buf.writenl();
576             return;
577         }
578         if (!adparent && !fd.fbody)
579         {
580             buf.printf("// ignoring function %s because it's extern", fd.toPrettyChars());
581             buf.writenl();
582             return;
583         }
584 
585         if (tf.linkage == LINK.c)
586             buf.writestring("extern \"C\" ");
587         else if (!adparent)
588             buf.writestring("extern ");
589         if (adparent && fd.isStatic())
590             buf.writestring("static ");
591         if (adparent && fd.vtblIndex != -1)
592         {
593             if (!fd.isOverride())
594                 buf.writestring("virtual ");
595 
596             auto s = adparent.search(Loc.initial, fd.ident);
597             if (!(adparent.storage_class & AST.STC.abstract_) &&
598                 !(cast(AST.ClassDeclaration)adparent).isAbstract() &&
599                 s is fd && !fd.overnext)
600             {
601                 const cn = adparent.ident.toChars();
602                 const fn = fd.ident.toChars();
603                 const vi = fd.vtblIndex;
604 
605                 checkbuf.printf("assert(getSlotNumber <%s>(0, &%s::%s) == %d);",
606                                                        cn,     cn, fn,    vi);
607                 checkbuf.writenl();
608            }
609         }
610 
611         if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11)
612             buf.printf("private: ");
613         funcToBuffer(tf, fd);
614         if (adparent && tf.isConst())
615         {
616             bool fdOverridesAreConst = true;
617             foreach (fdv; fd.foverrides)
618             {
619                 auto tfv = cast(AST.TypeFunction)fdv.type;
620                 if (!tfv.isConst())
621                 {
622                     fdOverridesAreConst = false;
623                     break;
624                 }
625             }
626 
627             buf.writestring(fdOverridesAreConst ? " const" : " /* const */");
628         }
629         if (adparent && fd.isAbstract())
630             buf.writestring(" = 0");
631         if (adparent && fd.isDisabled && global.params.cplusplus >= CppStdRevision.cpp11)
632             buf.writestring(" = delete");
633         buf.writestringln(";");
634         if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11)
635             buf.writestringln("public:");
636 
637         if (!adparent)
638             buf.writenl();
639 
640     }
641 
642     override void visit(AST.UnitTestDeclaration utd)
643     {
644         debug (Debug_DtoH)
645         {
646             printf("[AST.UnitTestDeclaration enter] %s\n", utd.toChars());
647             scope(exit) printf("[AST.UnitTestDeclaration exit] %s\n", utd.toChars());
648         }
649     }
650 
651     override void visit(AST.VarDeclaration vd)
652     {
653         debug (Debug_DtoH)
654         {
655             printf("[AST.VarDeclaration enter] %s\n", vd.toChars());
656             scope(exit) printf("[AST.VarDeclaration exit] %s\n", vd.toChars());
657         }
658         if (cast(void*)vd in visited)
659             return;
660         if (isBuildingCompiler && vd.getModule() && vd.getModule().isIgnoredModule())
661             return;
662 
663         visited[cast(void*)vd] = true;
664 
665         if (vd.type == AST.Type.tsize_t)
666             origType = &vd.originalType;
667         scope(exit) origType = null;
668 
669         if (vd.alignment != STRUCTALIGN_DEFAULT)
670         {
671             buf.printf("// Ignoring var %s alignment %u", vd.toChars(), vd.alignment);
672             buf.writenl();
673         }
674 
675         if (vd.storage_class & AST.STC.manifest &&
676             vd._init && vd._init.isExpInitializer())
677         {
678             AST.Type type = vd.type;
679             EnumKind kind = getEnumKind(type);
680 
681             if (kind != EnumKind.Other)
682             {
683                 hasNumericConstant = true;
684                 buf.writestring("ENUM_CONSTANT_NUMERIC(");
685             }
686             else
687             {
688                 hasTypedConstant = true;
689                 buf.writestring("ENUM_CONSTANT(");
690             }
691             writeEnumTypeName(type);
692             buf.writestring(", ");
693             buf.writestring(vd.ident.toString());
694             buf.writestring(", ");
695             auto e = AST.initializerToExpression(vd._init);
696             if (kind != EnumKind.Other)
697             {
698                 auto ie = e.isIntegerExp();
699                 visitInteger(ie.toInteger(), type);
700             }
701             else
702                 e.accept(this);
703             buf.writestringln(")");
704             buf.writenl();
705             return;
706         }
707 
708         if (tdparent && vd.type && !vd.type.deco)
709         {
710             if (linkage != LINK.c && linkage != LINK.cpp)
711             {
712                 buf.printf("// ignoring variable %s because of linkage", vd.toPrettyChars());
713                 buf.writenl();
714                 return;
715             }
716             typeToBuffer(vd.type, vd.ident);
717             buf.writestringln(";");
718             return;
719         }
720 
721         if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.tls | AST.STC.gshared) ||
722         vd.parent && vd.parent.isModule())
723         {
724             if (vd.linkage != LINK.c && vd.linkage != LINK.cpp)
725             {
726                 buf.printf("// ignoring variable %s because of linkage", vd.toPrettyChars());
727                 buf.writenl();
728                 return;
729             }
730             if (vd.storage_class & AST.STC.tls)
731             {
732                 buf.printf("// ignoring variable %s because of thread-local storage", vd.toPrettyChars());
733                 buf.writenl();
734                 return;
735             }
736             if (vd.linkage == LINK.c)
737                 buf.writestring("extern \"C\" ");
738             else if (!adparent)
739                 buf.writestring("extern ");
740             if (adparent)
741                 buf.writestring("static ");
742             typeToBuffer(vd.type, vd.ident);
743             writeDeclEnd();
744             return;
745         }
746 
747         if (adparent && vd.type && vd.type.deco)
748         {
749             auto save = cdparent;
750             cdparent = vd.isField() ? adparent.isClassDeclaration() : null;
751             typeToBuffer(vd.type, vd.ident);
752             cdparent = save;
753             buf.writestringln(";");
754 
755             if (auto t = vd.type.isTypeStruct())
756                 includeSymbol(t.sym);
757 
758             checkbuf.level++;
759             const pn = adparent.ident.toChars();
760             const vn = vd.ident.toChars();
761             const vo = vd.offset;
762             checkbuf.printf("assert(offsetof(%s, %s) == %d);",
763                                              pn, vn,    vo);
764             checkbuf.writenl();
765             checkbuf.level--;
766             return;
767         }
768 
769         visit(cast(AST.Dsymbol)vd);
770     }
771 
772     override void visit(AST.TypeInfoDeclaration tid)
773     {
774         debug (Debug_DtoH)
775         {
776             printf("[AST.TypeInfoDeclaration enter] %s\n", tid.toChars());
777             scope(exit) printf("[AST.TypeInfoDeclaration exit] %s\n", tid.toChars());
778         }
779     }
780 
781     override void visit(AST.AliasDeclaration ad)
782     {
783         debug (Debug_DtoH)
784         {
785             printf("[AST.AliasDeclaration enter] %s\n", ad.toChars());
786             scope(exit) printf("[AST.AliasDeclaration exit] %s\n", ad.toChars());
787         }
788         if (isBuildingCompiler && ad.getModule() && ad.getModule().isIgnoredModule())
789             return;
790 
791         if (auto t = ad.type)
792         {
793             if (t.ty == AST.Tdelegate)
794             {
795                 visit(cast(AST.Dsymbol)ad);
796                 return;
797             }
798 
799             // for function pointers we need to original type
800             if (ad.type.ty == AST.Tpointer &&
801                 (cast(AST.TypePointer)t).nextOf.ty == AST.Tfunction)
802             {
803                 origType = &ad.originalType;
804             }
805             scope(exit) origType = null;
806 
807             buf.writestring("typedef ");
808             typeToBuffer(origType ? *origType : t, ad.ident);
809             writeDeclEnd();
810             return;
811         }
812         if (!ad.aliassym)
813         {
814             assert(0);
815         }
816         if (auto ti = ad.aliassym.isTemplateInstance())
817         {
818             visitTi(ti);
819             return;
820         }
821         if (auto sd = ad.aliassym.isStructDeclaration())
822         {
823             buf.writestring("typedef ");
824             sd.type.accept(this);
825             buf.writestring(" ");
826             buf.writestring(ad.ident.toChars());
827             writeDeclEnd();
828             return;
829         }
830         if (ad.aliassym.isDtorDeclaration())
831         {
832             // Ignore. It's taken care of while visiting FuncDeclaration
833             return;
834         }
835         buf.printf("// ignored %s %s", ad.aliassym.kind(), ad.aliassym.toPrettyChars());
836         buf.writenl();
837     }
838 
839     override void visit(AST.Nspace ns)
840     {
841         handleNspace(ns.ident, ns.members);
842     }
843 
844     override void visit(AST.CPPNamespaceDeclaration ns)
845     {
846         handleNspace(ns.ident, ns.decl);
847     }
848 
849     void handleNspace(Identifier name, Dsymbols* members)
850     {
851         buf.printf("namespace %s", name.toChars());
852         buf.writenl();
853         buf.writestring("{");
854         buf.writenl();
855         buf.level++;
856         foreach(decl;(*members))
857         {
858             decl.accept(this);
859         }
860         buf.level--;
861         buf.writestring("}");
862         buf.writenl();
863     }
864 
865     override void visit(AST.AnonDeclaration ad)
866     {
867         debug (Debug_DtoH)
868         {
869             printf("[AST.AnonDeclaration enter] %s\n", ad.toChars());
870             scope(exit) printf("[AST.AnonDeclaration exit] %s\n", ad.toChars());
871         }
872 
873         buf.writestringln(ad.isunion ? "union" : "struct");
874         buf.writestringln("{");
875         buf.level++;
876         foreach (s; *ad.decl)
877         {
878             s.accept(this);
879         }
880         buf.level--;
881         buf.writestringln("};");
882     }
883 
884     private bool memberField(AST.VarDeclaration vd)
885     {
886         if (!vd.type || !vd.type.deco || !vd.ident)
887             return false;
888         if (!vd.isField())
889             return false;
890         if (vd.type.ty == AST.Tfunction)
891             return false;
892         if (vd.type.ty == AST.Tsarray)
893             return false;
894         return true;
895     }
896 
897     override void visit(AST.StructDeclaration sd)
898     {
899         debug (Debug_DtoH)
900         {
901             printf("[AST.StructDeclaration enter] %s\n", sd.toChars());
902             scope(exit) printf("[AST.StructDeclaration exit] %s\n", sd.toChars());
903         }
904         if (sd.isInstantiated())
905             return;
906         if (cast(void*)sd in visited)
907             return;
908         if (!sd.type || !sd.type.deco)
909             return;
910         if (isBuildingCompiler && sd.getModule() && sd.getModule().isIgnoredModule())
911             return;
912 
913         visited[cast(void*)sd] = true;
914         if (linkage != LINK.c && linkage != LINK.cpp)
915         {
916             buf.printf("// ignoring non-cpp struct %s because of linkage", sd.toChars());
917             buf.writenl();
918             return;
919         }
920 
921         pushAlignToBuffer(sd.alignment);
922         buf.writestring(sd.isUnionDeclaration() ? "union " : "struct ");
923         buf.writestring(sd.ident.toChars());
924         if (!sd.members)
925         {
926             buf.writestringln(";");
927             buf.writenl();
928             return;
929         }
930 
931         buf.writenl();
932         buf.writestring("{");
933         buf.level++;
934         buf.writenl();
935         auto save = adparent;
936         adparent = sd;
937 
938         foreach (m; *sd.members)
939         {
940             m.accept(this);
941         }
942         buf.level--;
943         adparent = save;
944         // Generate default ctor
945         if (!sd.noDefaultCtor)
946         {
947             buf.level++;
948             buf.printf("%s()", sd.ident.toChars());
949             size_t varCount;
950             bool first = true;
951             foreach (m; *sd.members)
952             {
953                 if (auto vd = m.isVarDeclaration())
954                 {
955                     if (!memberField(vd))
956                         continue;
957                     varCount++;
958 
959                     if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct &&
960                         !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray)
961                     {
962                         continue;
963                     }
964                     if (vd._init && vd._init.isVoidInitializer())
965                         continue;
966 
967                     if (first)
968                     {
969                         buf.printf(" : ");
970                         first = false;
971                     }
972                     else
973                     {
974                         buf.printf(", ");
975                     }
976                     buf.printf("%s(", vd.ident.toChars());
977 
978                     if (vd._init)
979                     {
980                         AST.initializerToExpression(vd._init).accept(this);
981                     }
982                     buf.printf(")");
983                 }
984             }
985             buf.writestringln(" {}");
986             buf.level--;
987         }
988 
989         version (none)
990         {
991             if (varCount)
992             {
993                 buf.printf("    %s(", sd.ident.toChars());
994                 bool first = true;
995                 foreach (m; *sd.members)
996                 {
997                     if (auto vd = m.isVarDeclaration())
998                     {
999                         if (!memberField(vd))
1000                             continue;
1001                         if (first)
1002                             first = false;
1003                         else
1004                             buf.writestring(", ");
1005                         assert(vd.type);
1006                         assert(vd.ident);
1007                         typeToBuffer(vd.type, vd.ident);
1008                     }
1009                 }
1010                 buf.printf(") {");
1011                 foreach (m; *sd.members)
1012                 {
1013                     if (auto vd = m.isVarDeclaration())
1014                     {
1015                         if (!memberField(vd))
1016                             continue;
1017                         buf.printf(" this->%s = %s;", vd.ident.toChars(), vd.ident.toChars());
1018                     }
1019                 }
1020                 buf.printf(" }");
1021                 buf.writenl();
1022             }
1023         }
1024         buf.writestringln("};");
1025 
1026         popAlignToBuffer(sd.alignment);
1027         buf.writenl();
1028 
1029         checkbuf.level++;
1030         const sn = sd.ident.toChars();
1031         const sz = sd.size(Loc.initial);
1032         checkbuf.printf("assert(sizeof(%s) == %d);", sn, sz);
1033         checkbuf.writenl();
1034         checkbuf.level--;
1035     }
1036 
1037     private void pushAlignToBuffer(uint alignment)
1038     {
1039         // DMD ensures alignment is a power of two
1040         //assert(alignment > 0 && ((alignment & (alignment - 1)) == 0),
1041         //       "Invalid alignment size");
1042 
1043         // When no alignment is specified, `uint.max` is the default
1044         if (alignment == STRUCTALIGN_DEFAULT)
1045         {
1046             return;
1047         }
1048 
1049         buf.printf("#pragma pack(push, %d)", alignment);
1050         buf.writenl();
1051     }
1052 
1053     private void popAlignToBuffer(uint alignment)
1054     {
1055         if (alignment == STRUCTALIGN_DEFAULT)
1056             return;
1057 
1058         buf.writestringln("#pragma pack(pop)");
1059     }
1060 
1061     private void includeSymbol(AST.Dsymbol ds)
1062     {
1063         debug (Debug_DtoH)
1064         {
1065             printf("[includeSymbol(AST.Dsymbol) enter] %s\n", ds.toChars());
1066             scope(exit) printf("[includeSymbol(AST.Dsymbol) exit] %s\n", ds.toChars());
1067         }
1068         if (cast(void*) ds in visited)
1069             return;
1070 
1071         OutBuffer decl;
1072         auto save = buf;
1073         buf = &decl;
1074         ds.accept(this);
1075         buf = save;
1076         donebuf.writestring(decl.peekChars());
1077     }
1078 
1079     override void visit(AST.ClassDeclaration cd)
1080     {
1081         debug (Debug_DtoH)
1082         {
1083             printf("[AST.ClassDeclaration enter] %s\n", cd.toChars());
1084             scope(exit) printf("[AST.ClassDeclaration exit] %s\n", cd.toChars());
1085         }
1086         if (cast(void*)cd in visited)
1087             return;
1088         if (isBuildingCompiler)
1089         {
1090             if (cd.getModule() && cd.getModule().isIgnoredModule())
1091                 return;
1092             if (cd.isVisitorClass())
1093                 return;
1094         }
1095 
1096         visited[cast(void*)cd] = true;
1097         if (!cd.isCPPclass())
1098         {
1099             buf.printf("// ignoring non-cpp class %s\n", cd.toChars());
1100             return;
1101         }
1102 
1103         buf.writestring("class ");
1104         buf.writestring(cd.ident.toChars());
1105         if (cd.baseClass)
1106         {
1107             buf.writestring(" : public ");
1108             buf.writestring(cd.baseClass.ident.toChars());
1109 
1110             includeSymbol(cd.baseClass);
1111         }
1112         if (!cd.members)
1113         {
1114             buf.writestring(";");
1115             buf.writenl();
1116             buf.writenl();
1117             return;
1118         }
1119 
1120         buf.writenl();
1121         buf.writestringln("{");
1122         buf.writestringln("public:");
1123 
1124         auto save = adparent;
1125         adparent = cd;
1126         buf.level++;
1127         foreach (m; *cd.members)
1128         {
1129             m.accept(this);
1130         }
1131         buf.level--;
1132         adparent = save;
1133 
1134         // Generate special static inline function.
1135         if (isBuildingCompiler && cd.isIdentifierClass())
1136         {
1137             buf.writestringln("static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); }");
1138         }
1139 
1140         buf.writestringln("};");
1141         buf.writenl();
1142     }
1143 
1144     override void visit(AST.EnumDeclaration ed)
1145     {
1146         debug (Debug_DtoH)
1147         {
1148             printf("[AST.EnumDeclaration enter] %s\n", ed.toChars());
1149             scope(exit) printf("[AST.EnumDeclaration exit] %s\n", ed.toChars());
1150         }
1151         if (cast(void*)ed in visited)
1152             return;
1153 
1154         if (isBuildingCompiler && ed.getModule() && ed.getModule().isIgnoredModule())
1155             return;
1156 
1157         visited[cast(void*)ed] = true;
1158 
1159         //if (linkage != LINK.c && linkage != LINK.cpp)
1160         //{
1161             //buf.printf("// ignoring non-cpp enum %s because of linkage\n", ed.toChars());
1162             //return;
1163         //}
1164 
1165         // we need to know a bunch of stuff about the enum...
1166         bool isAnonymous = ed.ident is null;
1167         AST.Type type = ed.memtype;
1168         if (!type)
1169         {
1170             // check all keys have matching type
1171             foreach (_m; *ed.members)
1172             {
1173                 auto m = _m.isEnumMember();
1174                 if (!type)
1175                     type = m.type;
1176                 else if (m.type !is type)
1177                 {
1178                     type = null;
1179                     break;
1180                 }
1181             }
1182         }
1183         EnumKind kind = getEnumKind(type);
1184 
1185         // determine if this is an enum, or just a group of manifest constants
1186         bool manifestConstants = !type || (isAnonymous && kind == EnumKind.Other);
1187         assert(!manifestConstants || isAnonymous);
1188 
1189         const(char)[] name = null;
1190         char[] nameLower = null;
1191         char[] nameUpper = null;
1192         char[] nameAbbrev = null;
1193         if (!isAnonymous)
1194         {
1195             name = ed.ident.toString;
1196             nameLower = new char[name.length];
1197             nameUpper = new char[name.length];
1198             foreach (i, c; name)
1199             {
1200                 nameUpper[i] = cast(char)toupper(c);
1201                 nameLower[i] = cast(char)tolower(c);
1202                 if (isupper(c))
1203                     nameAbbrev ~= c;
1204             }
1205         }
1206 
1207         // write the enum header
1208         if (!manifestConstants)
1209         {
1210             if (!isAnonymous && kind == EnumKind.Int)
1211             {
1212                 hasDefaultEnum = true;
1213                 buf.writestring("BEGIN_ENUM(");
1214             }
1215             else if (!isAnonymous && kind == EnumKind.Numeric)
1216             {
1217                 hasNumericEnum = true;
1218                 buf.writestring("BEGIN_ENUM_NUMERIC(");
1219             }
1220             else if(!isAnonymous)
1221             {
1222                 hasTypedEnum = true;
1223                 buf.writestring("BEGIN_ENUM_TYPE(");
1224             }
1225             else if (kind == EnumKind.Int)
1226             {
1227                 hasAnonEnum = true;
1228                 buf.writestring("BEGIN_ANON_ENUM(");
1229             }
1230             else
1231             {
1232                 hasAnonNumericEnum = true;
1233                 buf.writestring("BEGIN_ANON_ENUM_NUMERIC(");
1234             }
1235             if (kind != EnumKind.Int)
1236                 writeEnumTypeName(type);
1237             if (!isAnonymous)
1238             {
1239                 if (kind != EnumKind.Int)
1240                     buf.writestring(", ");
1241                 buf.writestring(name);
1242                 buf.writestring(", ");
1243                 buf.writestring(nameUpper);
1244                 buf.writestring(", ");
1245                 buf.writestring(nameLower);
1246             }
1247             buf.writestringln(")");
1248         }
1249 
1250         // emit constant for each member
1251         if (!manifestConstants)
1252             buf.level++;
1253 
1254         foreach (_m; *ed.members)
1255         {
1256             auto m = _m.isEnumMember();
1257             AST.Type memberType = type ? type : m.type;
1258             const EnumKind memberKind = type ? kind : getEnumKind(memberType);
1259 
1260             if (!manifestConstants && !isAnonymous && kind == EnumKind.Int)
1261                 buf.writestring("ENUM_KEY(");
1262             else if (!manifestConstants && !isAnonymous && kind == EnumKind.Numeric)
1263                 buf.writestring("ENUM_KEY_NUMERIC(");
1264             else if(!manifestConstants && !isAnonymous)
1265                 buf.writestring("ENUM_KEY_TYPE(");
1266             else if (!manifestConstants && kind == EnumKind.Int)
1267                 buf.writestring("ANON_ENUM_KEY(");
1268             else if (!manifestConstants)
1269                 buf.writestring("ANON_ENUM_KEY_NUMERIC(");
1270             else if (manifestConstants && memberKind != EnumKind.Other)
1271             {
1272                 hasNumericConstant = true;
1273                 buf.writestring("ENUM_CONSTANT_NUMERIC(");
1274             }
1275             else if (manifestConstants)
1276             {
1277                 hasTypedConstant = true;
1278                 buf.writestring("ENUM_CONSTANT(");
1279             }
1280             writeEnumTypeName(memberType);
1281             buf.printf(", %s, ", m.ident.toChars());
1282 
1283             if (memberKind != EnumKind.Other)
1284             {
1285                 auto ie = cast(AST.IntegerExp)m.value;
1286                 visitInteger(ie.toInteger(), memberType);
1287             }
1288             else
1289                 m.value.accept(this);
1290             if (!isAnonymous)
1291             {
1292                 buf.writestring(", ");
1293                 buf.writestring(name);
1294                 buf.writestring(", ");
1295                 buf.writestring(nameUpper);
1296                 buf.writestring(", ");
1297                 buf.writestring(nameLower);
1298                 if (!manifestConstants)
1299                 {
1300                     buf.writestring(", ");
1301                     buf.writestring(nameAbbrev);
1302                 }
1303             }
1304             buf.writestringln(")");
1305         }
1306 
1307         if (!manifestConstants)
1308             buf.level--;
1309         // write the enum tail
1310         if (!manifestConstants)
1311         {
1312             if (!isAnonymous && kind == EnumKind.Int)
1313                 buf.writestring("END_ENUM(");
1314             else if (!isAnonymous && kind == EnumKind.Numeric)
1315                 buf.writestring("END_ENUM_NUMERIC(");
1316             else if(!isAnonymous)
1317                 buf.writestring("END_ENUM_TYPE(");
1318             else if (kind == EnumKind.Int)
1319                 buf.writestring("END_ANON_ENUM(");
1320             else
1321                 buf.writestring("END_ANON_ENUM_NUMERIC(");
1322             if (kind != EnumKind.Int)
1323                 writeEnumTypeName(type);
1324             if (!isAnonymous)
1325             {
1326                 if (kind != EnumKind.Int)
1327                     buf.writestring(", ");
1328                 buf.writestring(name);
1329                 buf.writestring(", ");
1330                 buf.writestring(nameUpper);
1331                 buf.writestring(", ");
1332                 buf.writestring(nameLower);
1333             }
1334             buf.writestring(")");
1335         }
1336         buf.writenl();
1337         buf.writenl();
1338     }
1339 
1340     override void visit(AST.EnumMember em)
1341     {
1342         assert(false, "This node type should be handled in the EnumDeclaration");
1343     }
1344 
1345     private void typeToBuffer(AST.Type t, Identifier ident)
1346     {
1347         debug (Debug_DtoH)
1348         {
1349             printf("[typeToBuffer(AST.Type) enter] %s ident %s\n", t.toChars(), ident.toChars());
1350             scope(exit) printf("[typeToBuffer(AST.Type) exit] %s ident %s\n", t.toChars(), ident.toChars());
1351         }
1352 
1353         this.ident = ident;
1354         origType ? origType.accept(this) : t.accept(this);
1355         if (this.ident)
1356         {
1357             buf.writeByte(' ');
1358             buf.writestring(ident.toChars());
1359         }
1360         this.ident = null;
1361         if (auto tsa = t.isTypeSArray())
1362         {
1363             buf.writeByte('[');
1364             tsa.dim.accept(this);
1365             buf.writeByte(']');
1366         }
1367     }
1368 
1369     override void visit(AST.Type t)
1370     {
1371         debug (Debug_DtoH)
1372         {
1373             printf("[AST.Type enter] %s\n", t.toChars());
1374             scope(exit) printf("[AST.Type exit] %s\n", t.toChars());
1375         }
1376         printf("Invalid type: %s\n", t.toPrettyChars());
1377         assert(0);
1378     }
1379 
1380     override void visit(AST.TypeIdentifier t)
1381     {
1382         debug (Debug_DtoH)
1383         {
1384             printf("[AST.TypeIdentifier enter] %s\n", t.toChars());
1385             scope(exit) printf("[AST.TypeIdentifier exit] %s\n", t.toChars());
1386         }
1387         buf.writestring(t.ident.toChars());
1388     }
1389 
1390     override void visit(AST.TypeBasic t)
1391     {
1392         debug (Debug_DtoH)
1393         {
1394             printf("[AST.TypeBasic enter] %s\n", t.toChars());
1395             scope(exit) printf("[AST.TypeBasic exit] %s\n", t.toChars());
1396         }
1397         if (!cdparent && t.isConst())
1398             buf.writestring("const ");
1399         string typeName;
1400         switch (t.ty)
1401         {
1402             case AST.Tvoid:     typeName = "void";      break;
1403             case AST.Tbool:     typeName = "bool";      break;
1404             case AST.Tchar:     typeName = "char";      break;
1405             case AST.Twchar:    typeName = "char16_t";  break;
1406             case AST.Tdchar:    typeName = "char32_t";  break;
1407             case AST.Tint8:     typeName = "int8_t";    break;
1408             case AST.Tuns8:     typeName = "uint8_t";   break;
1409             case AST.Tint16:    typeName = "int16_t";   break;
1410             case AST.Tuns16:    typeName = "uint16_t";  break;
1411             case AST.Tint32:    typeName = "int32_t";   break;
1412             case AST.Tuns32:    typeName = "uint32_t";  break;
1413             case AST.Tint64:    typeName = "int64_t";   break;
1414             case AST.Tuns64:    typeName = "uint64_t";  break;
1415             case AST.Tfloat32:  typeName = "float";     break;
1416             case AST.Tfloat64:  typeName = "double";    break;
1417             case AST.Tfloat80:
1418                 typeName = "_d_real";
1419                 hasReal = true;
1420                 break;
1421             default:
1422                 //t.print();
1423                 assert(0);
1424         }
1425         buf.writestring(typeName);
1426     }
1427 
1428     override void visit(AST.TypePointer t)
1429     {
1430         debug (Debug_DtoH)
1431         {
1432             printf("[AST.TypePointer enter] %s\n", t.toChars());
1433             scope(exit) printf("[AST.TypePointer exit] %s\n", t.toChars());
1434         }
1435         auto ts = t.next.isTypeStruct();
1436         if (ts && !strcmp(ts.sym.ident.toChars(), "__va_list_tag"))
1437         {
1438             buf.writestring("va_list");
1439             return;
1440         }
1441         t.next.accept(this);
1442         if (t.next.ty != AST.Tfunction)
1443             buf.writeByte('*');
1444         if (!cdparent && t.isConst())
1445             buf.writestring(" const");
1446     }
1447 
1448     override void visit(AST.TypeSArray t)
1449     {
1450         debug (Debug_DtoH)
1451         {
1452             printf("[AST.TypeSArray enter] %s\n", t.toChars());
1453             scope(exit) printf("[AST.TypeSArray exit] %s\n", t.toChars());
1454         }
1455         t.next.accept(this);
1456     }
1457 
1458     override void visit(AST.TypeAArray t)
1459     {
1460         debug (Debug_DtoH)
1461         {
1462             printf("[AST.TypeAArray enter] %s\n", t.toChars());
1463             scope(exit) printf("[AST.TypeAArray exit] %s\n", t.toChars());
1464         }
1465         AST.Type.tvoidptr.accept(this);
1466     }
1467 
1468     override void visit(AST.TypeFunction tf)
1469     {
1470         debug (Debug_DtoH)
1471         {
1472             printf("[AST.TypeFunction enter] %s\n", tf.toChars());
1473             scope(exit) printf("[AST.TypeFunction exit] %s\n", tf.toChars());
1474         }
1475         tf.next.accept(this);
1476         buf.writeByte('(');
1477         buf.writeByte('*');
1478         if (ident)
1479             buf.writestring(ident.toChars());
1480         ident = null;
1481         buf.writeByte(')');
1482         buf.writeByte('(');
1483         foreach (i; 0 .. AST.Parameter.dim(tf.parameterList.parameters))
1484         {
1485             if (i)
1486                 buf.writestring(", ");
1487             auto fparam = AST.Parameter.getNth(tf.parameterList.parameters, i);
1488             fparam.accept(this);
1489         }
1490         if (tf.parameterList.varargs)
1491         {
1492             if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1)
1493                 buf.writestring(", ");
1494             buf.writestring("...");
1495         }
1496         buf.writeByte(')');
1497     }
1498 
1499     private void enumToBuffer(AST.EnumDeclaration ed)
1500     {
1501         debug (Debug_DtoH)
1502         {
1503             printf("[enumToBuffer(AST.EnumDeclaration) enter] %s\n", ed.toChars());
1504             scope(exit) printf("[enumToBuffer(AST.EnumDeclaration) exit] %s\n", ed.toChars());
1505         }
1506         if (ed.isSpecial())
1507         {
1508             if (ed.ident == DMDType.c_long)
1509                 buf.writestring("long");
1510             else if (ed.ident == DMDType.c_ulong)
1511                 buf.writestring("unsigned long");
1512             else if (ed.ident == DMDType.c_longlong)
1513                 buf.writestring("long long");
1514             else if (ed.ident == DMDType.c_ulonglong)
1515                 buf.writestring("unsigned long long");
1516             else if (ed.ident == DMDType.c_long_double)
1517                 buf.writestring("long double");
1518             else if (ed.ident == DMDType.c_wchar_t)
1519                 buf.writestring("wchar_t");
1520             else
1521             {
1522                 //ed.print();
1523                 assert(0);
1524             }
1525             return;
1526         }
1527 
1528         buf.writestring(ed.toChars());
1529     }
1530 
1531     override void visit(AST.TypeEnum t)
1532     {
1533         debug (Debug_DtoH)
1534         {
1535             printf("[AST.TypeEnum enter] %s\n", t.toChars());
1536             scope(exit) printf("[AST.TypeEnum exit] %s\n", t.toChars());
1537         }
1538         if (cast(void*)t.sym !in forwarded)
1539         {
1540             forwarded[cast(void*)t.sym] = true;
1541             auto save = buf;
1542             buf = fwdbuf;
1543             //printf("Visiting enum %s from module %s %s\n", t.sym.toPrettyChars(), t.toChars(), t.sym.loc.toChars());
1544             t.sym.accept(this);
1545             buf = save;
1546         }
1547         if (!cdparent && t.isConst())
1548             buf.writestring("const ");
1549         enumToBuffer(t.sym);
1550     }
1551 
1552     override void visit(AST.TypeStruct t)
1553     {
1554         debug (Debug_DtoH)
1555         {
1556             printf("[AST.TypeStruct enter] %s\n", t.toChars());
1557             scope(exit) printf("[AST.TypeStruct exit] %s\n", t.toChars());
1558         }
1559         if (cast(void*)t.sym !in forwarded && !t.sym.parent.isTemplateInstance())
1560         {
1561             forwarded[cast(void*)t.sym] = true;
1562             fwdbuf.writestring(t.sym.isUnionDeclaration() ? "union " : "struct ");
1563             fwdbuf.writestring(t.sym.toChars());
1564             fwdbuf.writestringln(";");
1565         }
1566 
1567         if (!cdparent && t.isConst())
1568             buf.writestring("const ");
1569         if (auto ti = t.sym.parent.isTemplateInstance())
1570         {
1571             visitTi(ti);
1572             return;
1573         }
1574         buf.writestring(t.sym.toChars());
1575     }
1576 
1577     override void visit(AST.TypeDArray t)
1578     {
1579         debug (Debug_DtoH)
1580         {
1581             printf("[AST.TypeDArray enter] %s\n", t.toChars());
1582             scope(exit) printf("[AST.TypeDArray exit] %s\n", t.toChars());
1583         }
1584         if (!cdparent && t.isConst())
1585             buf.writestring("const ");
1586         buf.writestring("DArray< ");
1587         t.next.accept(this);
1588         buf.writestring(" >");
1589     }
1590 
1591     private void visitTi(AST.TemplateInstance ti)
1592     {
1593         debug (Debug_DtoH)
1594         {
1595             printf("[visitTi(AST.TemplateInstance) enter] %s\n", ti.toChars());
1596             scope(exit) printf("[visitTi(AST.TemplateInstance) exit] %s\n", ti.toChars());
1597         }
1598 
1599         // FIXME: Restricting this to DMD seems wrong ...
1600         if (isBuildingCompiler)
1601         {
1602             if (ti.tempdecl.ident == DMDType.AssocArray)
1603             {
1604                 if (!forwardedAA)
1605                 {
1606                     forwardedAA = true;
1607                     fwdbuf.writestring("struct AA;\n");
1608                 }
1609                 buf.writestring("AA*");
1610                 return;
1611             }
1612             if (ti.tempdecl.ident == DMDType.Array)
1613             {
1614                 buf.writestring("Array");
1615             }
1616             else
1617                 goto LprintTypes;
1618         }
1619         else
1620         {
1621             LprintTypes:
1622             foreach (o; *ti.tiargs)
1623             {
1624                 if (!AST.isType(o))
1625                     return;
1626             }
1627             buf.writestring(ti.tempdecl.ident.toChars());
1628         }
1629         buf.writeByte('<');
1630         foreach (i, o; *ti.tiargs)
1631         {
1632             if (i)
1633                 buf.writestring(", ");
1634             if (auto tt = AST.isType(o))
1635             {
1636                 tt.accept(this);
1637             }
1638             else
1639             {
1640                 //ti.print();
1641                 //o.print();
1642                 assert(0);
1643             }
1644         }
1645         buf.writeByte('>');
1646     }
1647 
1648     override void visit(AST.TemplateDeclaration td)
1649     {
1650         debug (Debug_DtoH)
1651         {
1652             printf("[AST.TemplateDeclaration enter] %s\n", td.toChars());
1653             scope(exit) printf("[AST.TemplateDeclaration exit] %s\n", td.toChars());
1654         }
1655         if (cast(void*)td in visited)
1656             return;
1657         visited[cast(void*)td] = true;
1658 
1659         if (isBuildingCompiler && td.getModule() && td.getModule().isIgnoredModule())
1660             return;
1661 
1662         if (!td.parameters || !td.onemember || !td.onemember.isStructDeclaration())
1663         {
1664             visit(cast(AST.Dsymbol)td);
1665             return;
1666         }
1667 
1668         // Explicitly disallow templates with non-type parameters or specialization.
1669         foreach (p; *td.parameters)
1670         {
1671             if (!p.isTemplateTypeParameter() || p.specialization())
1672             {
1673                 visit(cast(AST.Dsymbol)td);
1674                 return;
1675             }
1676         }
1677 
1678         if (linkage != LINK.c && linkage != LINK.cpp)
1679         {
1680             buf.printf("// ignoring template %s because of linkage", td.toPrettyChars());
1681             buf.writenl();
1682             return;
1683         }
1684 
1685         auto sd = td.onemember.isStructDeclaration();
1686         auto save = tdparent;
1687         tdparent = td;
1688 
1689         buf.writestring("template <");
1690         bool first = true;
1691         foreach (p; *td.parameters)
1692         {
1693             if (first)
1694                 first = false;
1695             else
1696                 buf.writestring(", ");
1697             buf.writestring("typename ");
1698             buf.writestring(p.ident.toChars());
1699         }
1700         buf.writestringln(">");
1701 
1702         // TODO replace this block with a sd.accept
1703         {
1704             buf.writestring(sd.isUnionDeclaration() ? "union " : "struct ");
1705             buf.writestring(sd.ident.toChars());
1706             if (sd.members)
1707             {
1708                 buf.writenl();
1709                 buf.writestringln("{");
1710                 auto savex = adparent;
1711                 adparent = sd;
1712                 buf.level++;
1713                 foreach (m; *sd.members)
1714                 {
1715                     m.accept(this);
1716                 }
1717                 buf.level--;
1718                 adparent = savex;
1719                 buf.writestringln("};");
1720                 buf.writenl();
1721             }
1722             else
1723             {
1724                 buf.writestringln(";");
1725                 buf.writenl();
1726             }
1727         }
1728 
1729         tdparent = save;
1730     }
1731 
1732     override void visit(AST.TypeClass t)
1733     {
1734         debug (Debug_DtoH)
1735         {
1736             printf("[AST.TypeClass enter] %s\n", t.toChars());
1737             scope(exit) printf("[AST.TypeClass exit] %s\n", t.toChars());
1738         }
1739         if (cast(void*)t.sym !in forwarded)
1740         {
1741             forwarded[cast(void*)t.sym] = true;
1742             fwdbuf.writestring("class ");
1743             fwdbuf.writestring(t.sym.toChars());
1744             fwdbuf.writestringln(";");
1745         }
1746 
1747         if (!cdparent && t.isConst())
1748             buf.writestring("const ");
1749         buf.writestring(t.sym.toChars());
1750         buf.writeByte('*');
1751         if (!cdparent && t.isConst())
1752             buf.writestring(" const");
1753     }
1754 
1755     private void funcToBuffer(AST.TypeFunction tf, AST.FuncDeclaration fd)
1756     {
1757         debug (Debug_DtoH)
1758         {
1759             printf("[funcToBuffer(AST.TypeFunction) enter] %s\n", tf.toChars());
1760             scope(exit) printf("[funcToBuffer(AST.TypeFunction) exit] %s\n", tf.toChars());
1761         }
1762 
1763         Identifier ident = fd.ident;
1764         auto originalType = cast(AST.TypeFunction)fd.originalType;
1765 
1766         assert(tf.next);
1767 
1768         if (fd.isCtorDeclaration() || fd.isDtorDeclaration())
1769         {
1770             if (fd.isDtorDeclaration())
1771             {
1772                 buf.writeByte('~');
1773             }
1774             buf.writestring(adparent.toChars());
1775         }
1776         else
1777         {
1778             tf.next == AST.Type.tsize_t ? originalType.next.accept(this) : tf.next.accept(this);
1779             if (tf.isref)
1780                 buf.writeByte('&');
1781             buf.writeByte(' ');
1782             buf.writestring(ident.toChars());
1783         }
1784 
1785         buf.writeByte('(');
1786         foreach (i; 0 .. AST.Parameter.dim(tf.parameterList.parameters))
1787         {
1788             if (i)
1789                 buf.writestring(", ");
1790             auto fparam = AST.Parameter.getNth(tf.parameterList.parameters, i);
1791             if (fparam.type == AST.Type.tsize_t && originalType)
1792             {
1793                 fparam = AST.Parameter.getNth(originalType.parameterList.parameters, i);
1794             }
1795             fparam.accept(this);
1796 
1797         }
1798         if (tf.parameterList.varargs)
1799         {
1800             if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1)
1801                 buf.writestring(", ");
1802             buf.writestring("...");
1803         }
1804         buf.writeByte(')');
1805     }
1806 
1807     override void visit(AST.Parameter p)
1808     {
1809         debug (Debug_DtoH)
1810         {
1811             printf("[AST.Parameter enter] %s\n", p.toChars());
1812             scope(exit) printf("[AST.Parameter exit] %s\n", p.toChars());
1813         }
1814         ident = p.ident;
1815         p.type.accept(this);
1816         assert(!(p.storageClass & ~(AST.STC.ref_)));
1817         if (p.storageClass & AST.STC.ref_)
1818             buf.writeByte('&');
1819         buf.writeByte(' ');
1820         if (ident)
1821             buf.writestring(ident.toChars());
1822         ident = null;
1823         version (all)
1824         {
1825             if (p.defaultArg && p.defaultArg.op >= TOK.int32Literal && p.defaultArg.op < TOK.struct_)
1826             {
1827                 //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op);
1828                 buf.writestring(" = ");
1829                 buf.writestring(p.defaultArg.toChars());
1830             }
1831         }
1832         else
1833         {
1834             if (p.defaultArg)
1835             {
1836                 //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op);
1837                 //return;
1838                 buf.writestring("/*");
1839                 buf.writestring(" = ");
1840                 buf.writestring(p.defaultArg.toChars());
1841                 //p.defaultArg.accept(this);
1842                 buf.writestring("*/");
1843             }
1844         }
1845     }
1846 
1847     override void visit(AST.Expression e)
1848     {
1849         debug (Debug_DtoH)
1850         {
1851             printf("[AST.Expression enter] %s\n", e.toChars());
1852             scope(exit) printf("[AST.Expression exit] %s\n", e.toChars());
1853         }
1854         assert(0);
1855     }
1856 
1857     override void visit(AST.NullExp e)
1858     {
1859         debug (Debug_DtoH)
1860         {
1861             printf("[AST.NullExp enter] %s\n", e.toChars());
1862             scope(exit) printf("[AST.NullExp exit] %s\n", e.toChars());
1863         }
1864         buf.writestring("nullptr");
1865     }
1866 
1867     override void visit(AST.ArrayLiteralExp e)
1868     {
1869         debug (Debug_DtoH)
1870         {
1871             printf("[AST.ArrayLiteralExp enter] %s\n", e.toChars());
1872             scope(exit) printf("[AST.ArrayLiteralExp exit] %s\n", e.toChars());
1873         }
1874         buf.writestring("arrayliteral");
1875     }
1876 
1877     override void visit(AST.StringExp e)
1878     {
1879         debug (Debug_DtoH)
1880         {
1881             printf("[AST.StringExp enter] %s\n", e.toChars());
1882             scope(exit) printf("[AST.StringExp exit] %s\n", e.toChars());
1883         }
1884         if (e.sz == 2)
1885             buf.writeByte('u');
1886         else if (e.sz == 4)
1887             buf.writeByte('U');
1888         buf.writeByte('"');
1889 
1890         for (size_t i = 0; i < e.len; i++)
1891         {
1892             uint c = e.charAt(i);
1893             switch (c)
1894             {
1895                 case '"':
1896                 case '\\':
1897                     buf.writeByte('\\');
1898                     goto default;
1899                 default:
1900                     if (c <= 0xFF)
1901                     {
1902                         if (c >= 0x20 && c < 0x80)
1903                             buf.writeByte(c);
1904                         else
1905                             buf.printf("\\x%02x", c);
1906                     }
1907                     else if (c <= 0xFFFF)
1908                         buf.printf("\\u%04x", c);
1909                     else
1910                         buf.printf("\\U%08x", c);
1911                     break;
1912             }
1913         }
1914         buf.writeByte('"');
1915     }
1916 
1917     override void visit(AST.RealExp e)
1918     {
1919         debug (Debug_DtoH)
1920         {
1921             printf("[AST.RealExp enter] %s\n", e.toChars());
1922             scope(exit) printf("[AST.RealExp exit] %s\n", e.toChars());
1923         }
1924 
1925         // TODO: Needs to implemented, properly switching on the e.type
1926         buf.printf("%ff", e.value);
1927     }
1928 
1929     override void visit(AST.IntegerExp e)
1930     {
1931         debug (Debug_DtoH)
1932         {
1933             printf("[AST.IntegerExp enter] %s\n", e.toChars());
1934             scope(exit) printf("[AST.IntegerExp exit] %s\n", e.toChars());
1935         }
1936         visitInteger(e.toInteger, e.type);
1937     }
1938 
1939     private void visitInteger(dinteger_t v, AST.Type t)
1940     {
1941         debug (Debug_DtoH)
1942         {
1943             printf("[visitInteger(AST.Type) enter] %s\n", t.toChars());
1944             scope(exit) printf("[visitInteger(AST.Type) exit] %s\n", t.toChars());
1945         }
1946         switch (t.ty)
1947         {
1948             case AST.Tenum:
1949                 auto te = cast(AST.TypeEnum)t;
1950                 buf.writestring("(");
1951                 enumToBuffer(te.sym);
1952                 buf.writestring(")");
1953                 visitInteger(v, te.sym.memtype);
1954                 break;
1955             case AST.Tbool:
1956                 buf.writestring(v ? "true" : "false");
1957                 break;
1958             case AST.Tint8:
1959                 buf.printf("%d", cast(byte)v);
1960                 break;
1961             case AST.Tuns8:
1962                 buf.printf("%uu", cast(ubyte)v);
1963                 break;
1964             case AST.Tint16:
1965                 buf.printf("%d", cast(short)v);
1966                 break;
1967             case AST.Tuns16:
1968             case AST.Twchar:
1969                 buf.printf("%uu", cast(ushort)v);
1970                 break;
1971             case AST.Tint32:
1972             case AST.Tdchar:
1973                 buf.printf("%d", cast(int)v);
1974                 break;
1975             case AST.Tuns32:
1976                 buf.printf("%uu", cast(uint)v);
1977                 break;
1978             case AST.Tint64:
1979                 buf.printf("%lldLL", v);
1980                 break;
1981             case AST.Tuns64:
1982                 buf.printf("%lluLLU", v);
1983                 break;
1984             case AST.Tchar:
1985                 if (v > 0x20 && v < 0x80)
1986                     buf.printf("'%c'", cast(int)v);
1987                 else
1988                     buf.printf("%uu", cast(ubyte)v);
1989                 break;
1990             default:
1991                 //t.print();
1992                 assert(0);
1993         }
1994     }
1995 
1996     override void visit(AST.StructLiteralExp sle)
1997     {
1998         debug (Debug_DtoH)
1999         {
2000             printf("[AST.StructLiteralExp enter] %s\n", sle.toChars());
2001             scope(exit) printf("[AST.StructLiteralExp exit] %s\n", sle.toChars());
2002         }
2003         buf.writestring(sle.sd.ident.toChars());
2004         buf.writeByte('(');
2005         foreach(i, e; *sle.elements)
2006         {
2007             if (i)
2008                 buf.writestring(", ");
2009             e.accept(this);
2010         }
2011         buf.writeByte(')');
2012     }
2013 }