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