From 2110a41c0d099e4dfb296aa1c1564375650aff2e Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Wed, 22 Aug 2018 01:11:22 +0200 Subject: [PATCH 1/7] Generate C++ header files from public extern (C++) declarations The -HC switch let's dmd output header files from existing extern(C++) files to ease C++ interoperation. Use -HCd= / -HCf= to select the directory/file where the header should be generated. The following commits were squashed from #9971 without the changes to the existing C++ interface/test suite: Testing D to H tool Remove unused and redundant dmd headers Improve dtoh Factor out compiler specific parts Attempt to make cross platform Fix stuff Add dtoh as a compiler switch Update code after rebase Compile frontend srcs and write to flie Add dtoh enum test Add free functions dtoh test Add unittest block dtoh test Add VarDeclaration dtoh test Add AliasDeclaration dtoh test Add AnonDeclaration dtoh test Add StructDeclaration dtoh test Add ClassDeclaration dtoh test Add TemplateDeclaration dtoh test Add debug prints Fix struct field void initializer Add ignoredModule tmp helper Add tmp workaround for alias forward decl and >> template issue Add support for enum base type Add support for alignment of pow2 Fix alignment issues Generate enums based on -extern-std version Update tool auto-gen message Update tests Code cleanup CPP does not support covariant const methods Correctly write ctor declarations Generate default args for literals Generate dtor and copy ctor declarations Rebase with master Add compiler switch to cli.d Update tests Add support for @disable Improve default ctor generation Update struct decl test Use member initializer list for default ctor definition Co-Authored-By: Eduard Staniloiu (Rebase + Fixup) Co-Authored-By: MoonlightSentinel --- src/build.d | 2 +- src/dmd/cli.d | 9 + src/dmd/dtoh.d | 1724 +++++++++++++++++ src/dmd/globals.d | 5 + src/dmd/mars.d | 31 + src/dmd/root/dcompat.h | 13 + test/compilable/dtoh_AliasDeclaration.d | 45 + test/compilable/dtoh_AnonDeclaration.d | 26 + test/compilable/dtoh_ClassDeclaration.d | 90 + test/compilable/dtoh_StructDeclaration.d | 87 + test/compilable/dtoh_TemplateDeclaration.d | 22 + test/compilable/dtoh_VarDeclaration.d | 29 + test/compilable/dtoh_enum.d | 15 + test/compilable/dtoh_functions.d | 57 + test/compilable/dtoh_unittest_block.d | 17 + .../compilable/extra-files/dtoh-postscript.sh | 5 + .../extra-files/dtoh_AliasDeclaration.out | 61 + .../extra-files/dtoh_AnonDeclaration.out | 48 + .../extra-files/dtoh_ClassDeclaration.out | 103 + .../extra-files/dtoh_StructDeclaration.out | 108 ++ .../extra-files/dtoh_TemplateDeclaration.out | 45 + .../extra-files/dtoh_VarDeclaration.out | 48 + test/compilable/extra-files/dtoh_enum.out | 37 + .../compilable/extra-files/dtoh_functions.out | 46 + .../extra-files/dtoh_unittest_block.out | 31 + 25 files changed, 2703 insertions(+), 1 deletion(-) create mode 100644 src/dmd/dtoh.d create mode 100644 test/compilable/dtoh_AliasDeclaration.d create mode 100644 test/compilable/dtoh_AnonDeclaration.d create mode 100644 test/compilable/dtoh_ClassDeclaration.d create mode 100644 test/compilable/dtoh_StructDeclaration.d create mode 100644 test/compilable/dtoh_TemplateDeclaration.d create mode 100644 test/compilable/dtoh_VarDeclaration.d create mode 100644 test/compilable/dtoh_enum.d create mode 100644 test/compilable/dtoh_functions.d create mode 100644 test/compilable/dtoh_unittest_block.d create mode 100644 test/compilable/extra-files/dtoh-postscript.sh create mode 100644 test/compilable/extra-files/dtoh_AliasDeclaration.out create mode 100644 test/compilable/extra-files/dtoh_AnonDeclaration.out create mode 100644 test/compilable/extra-files/dtoh_ClassDeclaration.out create mode 100644 test/compilable/extra-files/dtoh_StructDeclaration.out create mode 100644 test/compilable/extra-files/dtoh_TemplateDeclaration.out create mode 100644 test/compilable/extra-files/dtoh_VarDeclaration.out create mode 100644 test/compilable/extra-files/dtoh_enum.out create mode 100644 test/compilable/extra-files/dtoh_functions.out create mode 100644 test/compilable/extra-files/dtoh_unittest_block.out diff --git a/src/build.d b/src/build.d index f6d3613eb137..caf80a809f12 100755 --- a/src/build.d +++ b/src/build.d @@ -1167,7 +1167,7 @@ auto sourceFiles() cli.d clone.d compiler.d complex.d cond.d constfold.d cppmangle.d cppmanglewin.d ctfeexpr.d ctorflow.d dcast.d dclass.d declaration.d delegatize.d denum.d dimport.d dinifile.d dinterpret.d dmacro.d dmangle.d dmodule.d doc.d dscope.d dstruct.d dsymbol.d dsymbolsem.d - dtemplate.d dversion.d env.d escape.d expression.d expressionsem.d func.d hdrgen.d impcnvtab.d + dtemplate.d dtoh.d dversion.d env.d escape.d expression.d expressionsem.d func.d hdrgen.d impcnvtab.d imphint.d init.d initsem.d inline.d inlinecost.d intrange.d json.d lambdacomp.d lib.d libelf.d libmach.d libmscoff.d libomf.d link.d mars.d mtype.d nogc.d nspace.d ob.d objc.d opover.d optimize.d parse.d parsetimevisitor.d permissivevisitor.d printast.d safe.d sapply.d scanelf.d scanmach.d diff --git a/src/dmd/cli.d b/src/dmd/cli.d index a299f42fec96..dd1b87cbaa08 100644 --- a/src/dmd/cli.d +++ b/src/dmd/cli.d @@ -370,6 +370,15 @@ dmd -cov -unittest myprog.d Option("Hf=", "write 'header' file to filename" ), + Option("HC", + "generate C++ 'header' file" + ), + Option("HCd=", + "write C++ 'header' file to directory" + ), + Option("HCf=", + "write C++ 'header' file to filename" + ), Option("-help", "print help and exit" ), diff --git a/src/dmd/dtoh.d b/src/dmd/dtoh.d new file mode 100644 index 000000000000..0e261164f1cb --- /dev/null +++ b/src/dmd/dtoh.d @@ -0,0 +1,1724 @@ +/** + * Compiler implementation of the + * $(LINK2 http://www.dlang.org, D programming language). + * + * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d) + * Documentation: https://dlang.org/phobos/dmd_dtoh.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dtoh.d + */ +module dmd.dtoh; + +import core.stdc.stdio; +import core.stdc.string; +import core.stdc.ctype; + +import dmd.astcodegen; +import dmd.arraytypes; +import dmd.globals; +import dmd.identifier; +import dmd.json; +import dmd.mars; +import dmd.root.array; +import dmd.root.file; +import dmd.root.filename; +import dmd.root.rmem; +import dmd.visitor; +import dmd.tokens; + +import dmd.root.outbuffer; +import dmd.utils; + +//debug = Debug_DtoH; + +private struct DMDType +{ + __gshared static Identifier c_long; + __gshared static Identifier c_ulong; + __gshared static Identifier c_longlong; + __gshared static Identifier c_ulonglong; + __gshared static Identifier c_long_double; + //version(BUILD_COMPILER) + //{ + __gshared static Identifier AssocArray; + __gshared static Identifier Array; + //} + + static void _init() + { + c_long = Identifier.idPool("__c_long"); + c_ulong = Identifier.idPool("__c_ulong"); + c_longlong = Identifier.idPool("__c_longlong"); + c_ulonglong = Identifier.idPool("__c_ulonglong"); + c_long_double = Identifier.idPool("__c_long_double"); + //version(BUILD_COMPILER) + //{ + AssocArray = Identifier.idPool("AssocArray"); + Array = Identifier.idPool("Array"); + //} + + } +} +//version(BUILD_COMPILER) +//{ + private struct DMDModule + { + __gshared static Identifier identifier; + __gshared static Identifier root; + __gshared static Identifier visitor; + __gshared static Identifier parsetimevisitor; + __gshared static Identifier permissivevisitor; + __gshared static Identifier strictvisitor; + __gshared static Identifier transitivevisitor; + __gshared static Identifier dmd; + static void _init() + { + identifier = Identifier.idPool("identifier"); + root = Identifier.idPool("root"); + visitor = Identifier.idPool("visitor"); + parsetimevisitor = Identifier.idPool("parsetimevisitor"); + permissivevisitor = Identifier.idPool("permissivevisitor"); + strictvisitor = Identifier.idPool("strictvisitor"); + transitivevisitor = Identifier.idPool("transitivevisitor"); + dmd = Identifier.idPool("dmd"); + } + } + + private struct DMDClass + { + __gshared static Identifier ID; ////Identifier + __gshared static Identifier Visitor; + __gshared static Identifier ParseTimeVisitor; + __gshared static void _init() + { + ID = Identifier.idPool("Identifier"); + Visitor = Identifier.idPool("Visitor"); + ParseTimeVisitor = Identifier.idPool("ParseTimeVisitor"); + } + + } + + private bool isIdentifierClass(ASTCodegen.ClassDeclaration cd) + { + return (cd.ident == DMDClass.ID && + cd.parent !is null && + cd.parent.ident == DMDModule.identifier && + cd.parent.parent && cd.parent.parent.ident == DMDModule.dmd && + !cd.parent.parent.parent); + } + + private bool isVisitorClass(ASTCodegen.ClassDeclaration cd) + { + for (auto cdb = cd; cdb; cdb = cdb.baseClass) + { + if (cdb.ident == DMDClass.Visitor || + cdb.ident == DMDClass.ParseTimeVisitor) + return true; + } + return false; + } + + private bool isIgnoredModule(ASTCodegen.Module m) + { + //if (!m || !m.parent) + if (!m) + return true; + + // Ignore dmd.root + if (m.parent && m.parent.ident == DMDModule.root && + m.parent.parent && m.parent.parent.ident == DMDModule.dmd && + !m.parent.parent.parent) + { + return true; + } + + // Ignore dmd.visitor and derivatives + if ((m.ident == DMDModule.visitor || + m.ident == DMDModule.parsetimevisitor || + m.ident == DMDModule.permissivevisitor || + m.ident == DMDModule.strictvisitor || + m.ident == DMDModule.transitivevisitor) && + m.parent && m.parent.ident == DMDModule.dmd && + !m.parent.parent) + { + return true; + } + return false; + } + + private bool isFrontendModule(ASTCodegen.Module m) + { + if (!m || !m.parent) + return false; + + // Ignore dmd.root + if (m.parent.ident == DMDModule.root && + m.parent.parent && m.parent.parent.ident == DMDModule.dmd && + !m.parent.parent.parent) + { + return false; + } + + // Ignore dmd.visitor and derivatives + if ((m.ident == DMDModule.visitor || + m.ident == DMDModule.parsetimevisitor || + m.ident == DMDModule.permissivevisitor || + m.ident == DMDModule.strictvisitor || + m.ident == DMDModule.transitivevisitor) && + m.parent && m.parent.ident == DMDModule.dmd && + !m.parent.parent) + { + return false; + } + return ((m.parent.ident == DMDModule.dmd && !m.parent.parent) || + (m.parent.parent.ident == DMDModule.dmd && !m.parent.parent.parent)); + } +//} + +void genCppHdrFiles(ref Modules ms) +{ + DMDType._init(); + //version(BUILD_COMPILER) + //{ + DMDModule._init(); + DMDClass._init(); + //} + + OutBuffer buf; + buf.writestring("#pragma once\n"); + buf.writeByte('\n'); + buf.printf("// Automatically generated by dmd -HC\n"); + buf.writeByte('\n'); + buf.writestring("#include \n"); + buf.writestring("#include \n"); + buf.writestring("#include \n"); + buf.writestring("#include \n"); + buf.writeByte('\n'); + buf.writestring("#define _d_void void\n"); + buf.writestring("#define _d_bool bool\n"); + buf.writestring("#define _d_byte signed char\n"); + buf.writestring("#define _d_ubyte unsigned char\n"); + buf.writestring("#define _d_short short\n"); + buf.writestring("#define _d_ushort unsigned short\n"); + buf.writestring("#define _d_int int\n"); + buf.writestring("#define _d_uint unsigned\n"); + if (global.params.isLP64) + { + buf.writestring("#define _d_long long\n"); + buf.writestring("#define _d_ulong unsigned long\n"); + } + else + { + buf.writestring("#define _d_long long long\n"); + buf.writestring("#define _d_ulong unsigned long long\n"); + } + buf.writestring("#define _d_float float\n"); + buf.writestring("#define _d_double double\n"); + buf.writestring("#define _d_real long double\n"); + buf.writestring("#define _d_char char\n"); + buf.writestring("#define _d_wchar wchar_t\n"); + buf.writestring("#define _d_dchar unsigned\n"); + buf.writestring("typedef _d_long d_int64;\n"); + buf.writestring("\n"); + buf.writestring("#define _d_null NULL\n"); + buf.writestring("\n\n"); + + OutBuffer check; + check.writestring(` + #if OFFSETS + + template + size_t getSlotNumber(int dummy, ...) + { + T c; + va_list ap; + va_start(ap, dummy); + void *f = va_arg(ap, void*); + for (size_t i = 0; ; i++) + { + if ( (*(void***)&c)[i] == f) + return i; + } + va_end(ap); + } + + void testOffsets() + { + `); + + OutBuffer done; + OutBuffer decl; + scope v = new ToCppBuffer!ASTCodegen(&check, &buf, &done, &decl); + foreach (m; ms) + { + //printf("// Parsing module %s\n", m.toPrettyChars()); + buf.printf("// Parsing module %s\n", m.toPrettyChars()); + m.accept(v); + } + buf.write(&done); + buf.write(&decl); + //printf("%s\n", decl.peekSlice().ptr); + + check.writestring(` + } + #endif + `); + + debug buf.write(&check); + + if (global.params.cxxhdrname is null) + { + // Write to stdout; assume it succeeds + size_t n = fwrite(buf[].ptr, 1, buf.length, stdout); + assert(n == buf.length); // keep gcc happy about return values + } + else + { + const(char)[] name = FileName.combine(global.params.cxxhdrdir, global.params.cxxhdrname); + writeFile(Loc.initial, name, buf[]); + } +} + +/**************************************************** + */ +extern(C++) final class ToCppBuffer(AST) : Visitor +{ + alias visit = Visitor.visit; +public: + bool[void*] visited; + bool[void*] forwarded; + OutBuffer *fwdbuf; + OutBuffer *checkbuf; + OutBuffer *donebuf; + OutBuffer *buf; + AST.AggregateDeclaration adparent; + AST.ClassDeclaration cdparent; + AST.TemplateDeclaration tdparent; + Identifier ident; + LINK linkage = LINK.d; + bool forwardedAA; + + this(OutBuffer* checkbuf, OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) + { + this.checkbuf = checkbuf; + this.fwdbuf = fwdbuf; + this.donebuf = donebuf; + this.buf = buf; + } + + private void indent() + { + if (adparent) + buf.writestring(" "); + } + + override void visit(AST.Dsymbol s) + { + debug (Debug_DtoH) + { + printf("[AST.Dsymbol enter] %s\n", s.toChars()); + scope(exit) printf("[AST.Dsymbol exit] %s\n", s.toChars()); + } + version(BUILD_COMPILER) + { + if (s.getModule() && s.getModule().isFrontendModule()) + { + indent(); + buf.printf("// ignored %s %s\n", s.kind(), s.toPrettyChars()); + } + } + } + + override void visit(AST.Import i) + { + debug (Debug_DtoH) + { + printf("[AST.Import enter] %s\n", i.toChars()); + scope(exit) printf("[AST.Import exit] %s\n", i.toChars()); + } + } + + override void visit(AST.AttribDeclaration pd) + { + debug (Debug_DtoH) + { + printf("[AST.AttribDeclaration enter] %s\n", pd.toChars()); + scope(exit) printf("[AST.AttribDeclaration exit] %s\n", pd.toChars()); + } + Dsymbols* decl = pd.include(null); + if (decl) + { + foreach (s; *decl) + { + if (!adparent && s.prot().kind < AST.Prot.Kind.public_) + continue; + s.accept(this); + } + } + } + + override void visit(AST.LinkDeclaration ld) + { + debug (Debug_DtoH) + { + printf("[AST.LinkDeclaration enter] %s\n", ld.toChars()); + scope(exit) printf("[AST.LinkDeclaration exit] %s\n", ld.toChars()); + } + auto save = linkage; + linkage = ld.linkage; + if (ld.linkage != LINK.c && ld.linkage != LINK.cpp) + { + indent(); + buf.printf("// ignoring %s block because of linkage\n", ld.toPrettyChars()); + } + else + { + visit(cast(AST.AttribDeclaration)ld); + } + linkage = save; + } + + override void visit(AST.Module m) + { + debug (Debug_DtoH) + { + printf("[AST.Module enter] %s\n", m.toChars()); + scope(exit) printf("[AST.Module exit] %s\n", m.toChars()); + } + foreach (s; *m.members) + { + if (s.prot().kind < AST.Prot.Kind.public_) + continue; + s.accept(this); + } + } + + override void visit(AST.FuncDeclaration fd) + { + debug (Debug_DtoH) + { + printf("[AST.FuncDeclaration enter] %s\n", fd.toChars()); + scope(exit) printf("[AST.FuncDeclaration exit] %s\n", fd.toChars()); + } + if (cast(void*)fd in visited) + return; + //version(BUILD_COMPILER) + //{ + if (fd.getModule() && fd.getModule().isIgnoredModule()) + return; + //} + + // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars()); + visited[cast(void*)fd] = true; + + auto tf = cast(AST.TypeFunction)fd.type; + indent(); + if (!tf || !tf.deco) + { + buf.printf("// ignoring function %s because semantic hasn't been run\n", fd.toPrettyChars()); + return; + } + if (tf.linkage != LINK.c && tf.linkage != LINK.cpp) + { + buf.printf("// ignoring function %s because of linkage\n", fd.toPrettyChars()); + return; + } + if (!adparent && !fd.fbody) + { + buf.printf("// ignoring function %s because it's extern\n", fd.toPrettyChars()); + return; + } + + if (tf.linkage == LINK.c) + buf.writestring("extern \"C\" "); + else if (!adparent) + buf.writestring("extern "); + if (adparent && fd.isStatic()) + buf.writestring("static "); + if (adparent && fd.vtblIndex != -1) + { + if (!fd.isOverride()) + buf.writestring("virtual "); + + auto s = adparent.search(Loc.initial, fd.ident); + if (!(adparent.storage_class & AST.STC.abstract_) && + !(cast(AST.ClassDeclaration)adparent).isAbstract() && + s is fd && !fd.overnext) + { + auto save = buf; + buf = checkbuf; + buf.writestring(" assert(getSlotNumber<"); + buf.writestring(adparent.ident.toChars()); + buf.writestring(">(0, &"); + buf.writestring(adparent.ident.toChars()); + buf.writestring("::"); + buf.writestring(fd.ident.toChars()); + buf.printf(") == %d);\n", fd.vtblIndex); + buf = save; + } + } + + if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11) + buf.printf("private: "); + funcToBuffer(tf, fd); + if (adparent && tf.isConst()) + { + bool fdOverridesAreConst = true; + foreach (fdv; fd.foverrides) + { + auto tfv = cast(AST.TypeFunction)fdv.type; + if (!tfv.isConst()) + { + fdOverridesAreConst = false; + break; + } + } + + if (fdOverridesAreConst) + { + buf.writestring(" const"); + } + else + { + buf.writestring(" /* const */"); + } + } + if (adparent && fd.isAbstract()) + buf.writestring(" = 0"); + if (adparent && fd.isDisabled && global.params.cplusplus >= CppStdRevision.cpp11) + buf.printf(" = delete"); + buf.printf(";\n"); + if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11) + buf.printf("public:\n"); + if (!adparent) + buf.printf("\n"); + } + + override void visit(AST.UnitTestDeclaration utd) + { + debug (Debug_DtoH) + { + printf("[AST.UnitTestDeclaration enter] %s\n", utd.toChars()); + scope(exit) printf("[AST.UnitTestDeclaration exit] %s\n", utd.toChars()); + } + } + + override void visit(AST.VarDeclaration vd) + { + debug (Debug_DtoH) + { + printf("[AST.VarDeclaration enter] %s\n", vd.toChars()); + scope(exit) printf("[AST.VarDeclaration exit] %s\n", vd.toChars()); + } + if (cast(void*)vd in visited) + return; + //version(BUILD_COMPILER) + //{ + if (vd.getModule() && vd.getModule().isIgnoredModule()) + return; + //} + + visited[cast(void*)vd] = true; + + if (vd.alignment != uint.max) + { + indent(); + buf.printf("// Ignoring var %s alignment %u\n", vd.toChars(), vd.alignment); + } + + if (vd.storage_class & AST.STC.manifest && + vd.type.isintegral() && + vd._init && vd._init.isExpInitializer()) + { + indent(); + buf.writestring("#define "); + buf.writestring(vd.ident.toChars()); + buf.writestring(" "); + auto e = AST.initializerToExpression(vd._init); + if (e.type.ty == AST.Tbool) + buf.printf("%d", e.toInteger()); + else + AST.initializerToExpression(vd._init).accept(this); + buf.writestring("\n"); + if (!adparent) + buf.printf("\n"); + return; + } + + if (tdparent && vd.type && !vd.type.deco) + { + indent(); + if (linkage != LINK.c && linkage != LINK.cpp) + { + buf.printf("// ignoring variable %s because of linkage\n", vd.toPrettyChars()); + return; + } + typeToBuffer(vd.type, vd.ident); + buf.writestring(";\n"); + return; + } + + if (vd.storage_class & (AST.STC.static_ | AST.STC.extern_ | AST.STC.tls | AST.STC.gshared) || + vd.parent && vd.parent.isModule()) + { + indent(); + if (vd.linkage != LINK.c && vd.linkage != LINK.cpp) + { + buf.printf("// ignoring variable %s because of linkage\n", vd.toPrettyChars()); + return; + } + if (vd.storage_class & AST.STC.tls) + { + buf.printf("// ignoring variable %s because of thread-local storage\n", vd.toPrettyChars()); + return; + } + if (vd.linkage == LINK.c) + buf.writestring("extern \"C\" "); + else if (!adparent) + buf.writestring("extern "); + if (adparent) + buf.writestring("static "); + typeToBuffer(vd.type, vd.ident); + buf.writestring(";\n"); + if (!adparent) + buf.printf("\n"); + return; + } + + if (adparent && vd.type && vd.type.deco) + { + indent(); + auto save = cdparent; + cdparent = vd.isField() ? adparent.isClassDeclaration() : null; + typeToBuffer(vd.type, vd.ident); + cdparent = save; + buf.writestring(";\n"); + if (vd.type.ty == AST.Tstruct) + { + auto t = cast(AST.TypeStruct)vd.type; + includeSymbol(t.sym); + } + auto savex = buf; + buf = checkbuf; + buf.writestring(" assert(offsetof("); + buf.writestring(adparent.ident.toChars()); + buf.writestring(", "); + buf.writestring(vd.ident.toChars()); + buf.printf(") == %d);\n", vd.offset); + buf = savex; + return; + } + visit(cast(AST.Dsymbol)vd); + } + + override void visit(AST.TypeInfoDeclaration tid) + { + debug (Debug_DtoH) + { + printf("[AST.TypeInfoDeclaration enter] %s\n", tid.toChars()); + scope(exit) printf("[AST.TypeInfoDeclaration exit] %s\n", tid.toChars()); + } + } + + override void visit(AST.AliasDeclaration ad) + { + debug (Debug_DtoH) + { + printf("[AST.AliasDeclaration enter] %s\n", ad.toChars()); + scope(exit) printf("[AST.AliasDeclaration exit] %s\n", ad.toChars()); + } + //version(BUILD_COMPILER) + //{ + if (ad.getModule() && ad.getModule().isIgnoredModule()) + return; + //} + + if (auto t = ad.type) + { + if (t.ty == AST.Tdelegate) + { + visit(cast(AST.Dsymbol)ad); + return; + } + buf.writestring("typedef "); + typeToBuffer(t, ad.ident); + buf.writestring(";\n"); + if (!adparent) + buf.printf("\n"); + return; + } + if (!ad.aliassym) + { + assert(0); + } + if (auto ti = ad.aliassym.isTemplateInstance()) + { + visitTi(ti); + return; + } + if (auto sd = ad.aliassym.isStructDeclaration()) + { + buf.writestring("typedef "); + sd.type.accept(this); + buf.writestring(" "); + buf.writestring(ad.ident.toChars()); + buf.writestring(";\n"); + if (!adparent) + buf.printf("\n"); + return; + } + if (auto fd = ad.aliassym.isDtorDeclaration()) + { + // Ignore. It's taken care of while visiting FuncDeclaration + return; + } + indent(); + buf.printf("// ignored %s %s\n", ad.aliassym.kind(), ad.aliassym.toPrettyChars()); + } + + override void visit(AST.AnonDeclaration ad) + { + debug (Debug_DtoH) + { + printf("[AST.AnonDeclaration enter] %s\n", ad.toChars()); + scope(exit) printf("[AST.AnonDeclaration exit] %s\n", ad.toChars()); + } + indent(); + buf.writestring(ad.isunion ? "union\n" : "struct\n"); + indent(); + buf.writestring("{\n"); + foreach (s; *ad.decl) + { + indent(); + s.accept(this); + } + indent(); + buf.writestring("};\n"); + } + + private bool memberField(AST.VarDeclaration vd) + { + if (!vd.type || !vd.type.deco || !vd.ident) + return false; + if (!vd.isField()) + return false; + if (vd.type.ty == AST.Tfunction) + return false; + if (vd.type.ty == AST.Tsarray) + return false; + return true; + } + + override void visit(AST.StructDeclaration sd) + { + debug (Debug_DtoH) + { + printf("[AST.StructDeclaration enter] %s\n", sd.toChars()); + scope(exit) printf("[AST.StructDeclaration exit] %s\n", sd.toChars()); + } + if (sd.isInstantiated()) + return; + if (cast(void*)sd in visited) + return; + if (!sd.type || !sd.type.deco) + return; + //version(BUILD_COMPILER) + //{ + if (sd.getModule() && sd.getModule().isIgnoredModule()) + return; + //} + + visited[cast(void*)sd] = true; + if (linkage != LINK.c && linkage != LINK.cpp) + { + buf.printf("// ignoring non-cpp struct %s because of linkage\n", sd.toChars()); + return; + } + + buf.writestring(sd.isUnionDeclaration() ? "union" : "struct"); + pushAlignToBuffer(sd.alignment); + buf.writestring(sd.ident.toChars()); + if (sd.members) + { + buf.writestring("\n{\n"); + auto save = adparent; + adparent = sd; + foreach (m; *sd.members) + { + m.accept(this); + } + adparent = save; + // Generate default ctor + if (!sd.noDefaultCtor) + { + buf.printf(" %s()", sd.ident.toChars()); + size_t varCount; + bool first = true; + foreach (m; *sd.members) + { + if (auto vd = m.isVarDeclaration()) + { + if (!memberField(vd)) + continue; + varCount++; + + if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct && + !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray) + { + continue; + } + if (vd._init && vd._init.isVoidInitializer()) + continue; + + if (first) + { + buf.printf(" : "); + first = false; + } + else + { + buf.printf(", "); + } + buf.printf("%s(", vd.ident.toChars()); + + if (vd._init) + { + AST.initializerToExpression(vd._init).accept(this); + } + buf.printf(")"); + } + } + buf.printf(" {}\n"); + } + + version (none) + { + if (varCount) + { + buf.printf(" %s(", sd.ident.toChars()); + bool first = true; + foreach (m; *sd.members) + { + if (auto vd = m.isVarDeclaration()) + { + if (!memberField(vd)) + continue; + if (first) + first = false; + else + buf.writestring(", "); + assert(vd.type); + assert(vd.ident); + typeToBuffer(vd.type, vd.ident); + } + } + buf.printf(") {"); + foreach (m; *sd.members) + { + if (auto vd = m.isVarDeclaration()) + { + if (!memberField(vd)) + continue; + buf.printf(" this->%s = %s;", vd.ident.toChars(), vd.ident.toChars()); + } + } + buf.printf(" }\n"); + } + } + buf.writestring("};\n"); + + popAlignToBuffer(sd.alignment); + buf.writestring("\n"); + + auto savex = buf; + buf = checkbuf; + buf.writestring(" assert(sizeof("); + buf.writestring(sd.ident.toChars()); + buf.printf(") == %d);\n", sd.size(Loc.initial)); + buf = savex; + } + else + { + buf.writestring(";\n\n"); + } + } + + private void pushAlignToBuffer(uint alignment) + { + // DMD ensures alignment is a power of two + //assert(alignment > 0 && ((alignment & (alignment - 1)) == 0), + // "Invalid alignment size"); + + // When no alignment is specified, `uint.max` is the default + if (alignment != uint.max) + { + buf.writestring("\n#if defined(__GNUC__) || defined(__clang__)\n"); + // The equivalent of `#pragma pack(push, n)` is `__attribute__((packed, aligned(n)))` + // NOTE: removing the packed attribute will might change the resulting size + buf.printf(" __attribute__((packed, aligned(%d)))\n", alignment); + buf.writestring("#elif defined(_MSC_VER)\n"); + buf.printf(" __declspec(align(%d))\n", alignment); + buf.writestring("#elif defined(__DMC__)\n"); + buf.printf(" #pragma pack(push, %d)\n", alignment); + //buf.printf("#pragma pack(%d)\n", alignment); + buf.writestring("#endif\n"); + } + else + { + buf.writeByte(' '); + } + } + + private void popAlignToBuffer(uint alignment) + { + if (alignment != uint.max) + { + buf.writestring("#if defined(__DMC__)\n"); + buf.writestring(" #pragma pack(pop)\n"); + //buf.writestring("#pragma pack()\n"); + buf.writestring("#endif\n"); + } + } + + private void includeSymbol(AST.Dsymbol ds) + { + debug (Debug_DtoH) + { + printf("[includeSymbol(AST.Dsymbol) enter] %s\n", ds.toChars()); + scope(exit) printf("[includeSymbol(AST.Dsymbol) exit] %s\n", ds.toChars()); + } + if (cast(void*)ds !in visited) + { + OutBuffer decl; + auto save = buf; + buf = &decl; + ds.accept(this); + buf = save; + donebuf.writestring(decl.peekChars()); + } + } + + override void visit(AST.ClassDeclaration cd) + { + debug (Debug_DtoH) + { + printf("[AST.ClassDeclaration enter] %s\n", cd.toChars()); + scope(exit) printf("[AST.ClassDeclaration exit] %s\n", cd.toChars()); + } + if (cast(void*)cd in visited) + return; + //version(BUILD_COMPILER) + //{ + if (cd.getModule() && cd.getModule().isIgnoredModule()) + return; + if (cd.isVisitorClass()) + return; + //} + + visited[cast(void*)cd] = true; + if (!cd.isCPPclass()) + { + buf.printf("// ignoring non-cpp class %s\n", cd.toChars()); + return; + } + + buf.writestring("class "); + buf.writestring(cd.ident.toChars()); + if (cd.baseClass) + { + buf.writestring(" : public "); + buf.writestring(cd.baseClass.ident.toChars()); + + includeSymbol(cd.baseClass); + } + if (cd.members) + { + buf.writestring("\n{\npublic:\n"); + auto save = adparent; + adparent = cd; + foreach (m; *cd.members) + { + m.accept(this); + } + adparent = save; + //version(BUILD_COMPILER) + //{ + // Generate special static inline function. + if (cd.isIdentifierClass()) + { + buf.writestring(" static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); }\n"); + } + //} + + buf.writestring("};\n\n"); + } + else + { + buf.writestring(";\n\n"); + } + } + + override void visit(AST.EnumDeclaration ed) + { + debug (Debug_DtoH) + { + printf("[AST.EnumDeclaration enter] %s\n", ed.toChars()); + scope(exit) printf("[AST.EnumDeclaration exit] %s\n", ed.toChars()); + } + if (cast(void*)ed in visited) + return; + + //version(BUILD_COMPILER) + //{ + if (ed.getModule() && ed.getModule().isIgnoredModule()) + return; + //} + + visited[cast(void*)ed] = true; + + //if (linkage != LINK.c && linkage != LINK.cpp) + //{ + //buf.printf("// ignoring non-cpp enum %s because of linkage\n", ed.toChars()); + //return; + //} + + bool hasBaseType = false; + + switch (ed.memtype.ty) + { + case AST.Tbool, AST.Tvoid: + case AST.Tchar, AST.Twchar, AST.Tdchar: + case AST.Tint8, AST.Tuns8: + case AST.Tint16, AST.Tuns16: + case AST.Tint64, AST.Tuns64: + case AST.Tfloat32, AST.Tfloat64, AST.Tfloat80: + hasBaseType = true; + break; + case AST.Tint32, AST.Tuns32, AST.Tenum: // by default, the base is an int + break; + default: + import dmd.root.string : toDString; + printf ("%s\n", ed.ident.toChars()); + assert(0, ed.memtype.kind.toDString); + } + + if (ed.isSpecial()) + return; + const(char)* ident = null; + if (ed.ident) + ident = ed.ident.toChars(); + if (!ident) + { + buf.writestring("enum"); + } + else + { + if (hasBaseType) + { + //printf("typedef _d_%s %s;\n", ed.memtype.kind, ident); + if (global.params.cplusplus >= CppStdRevision.cpp11) + { + //printf("Using cpp 11 and beyond\n"); + buf.printf("enum %s : %s", ident, ed.memtype.kind); + } + else + { + //printf("Using cpp 98\n"); + buf.writestring("typedef _d_"); + buf.writestring(ed.memtype.kind); + buf.writeByte(' '); + buf.writestring(ident); + buf.writestring(";\n"); + buf.writestring("enum"); + } + } + else + { + buf.writestring("enum "); + buf.writestring(ident); + } + } + if (ed.members) + { + buf.writestring("\n{\n"); + foreach (i, m; *ed.members) + { + if (i) + buf.writestring(",\n"); + buf.writestring(" "); + if (ident && global.params.cplusplus == CppStdRevision.cpp98) + { + foreach (c; ident[0 .. strlen(ident)]) + buf.writeByte(toupper(c)); + } + m.accept(this); + } + buf.writestring("\n};\n\n"); + } + else + { + buf.writestring(";\n\n"); + } + //printf("Enum %s min %d max %d\n", ident, ed.minval.toInteger(), ed.maxval.toInteger()); + } + + override void visit(AST.EnumMember em) + { + debug (Debug_DtoH) + { + printf("[AST.EnumMember enter] %s\n", em.toChars()); + scope(exit) printf("[AST.EnumMember exit] %s\n", em.toChars()); + } + buf.writestring(em.ident.toChars()); + buf.writestring(" = "); + //if (cast(AST.StringExp)em.value) + //{ + //em.value.error("cannot convert string enum"); + //return ; + //} + auto ie = cast(AST.IntegerExp)em.value; + visitInteger(ie.toInteger(), em.ed.memtype); + } + + private void typeToBuffer(AST.Type t, Identifier ident) + { + debug (Debug_DtoH) + { + printf("[typeToBuffer(AST.Type) enter] %s ident %s\n", t.toChars(), ident.toChars()); + scope(exit) printf("[typeToBuffer(AST.Type) exit] %s ident %s\n", t.toChars(), ident.toChars()); + } + this.ident = ident; + t.accept(this); + if (this.ident) + { + buf.writeByte(' '); + buf.writestring(ident.toChars()); + } + this.ident = null; + if (t.ty == AST.Tsarray) + { + auto tsa = cast(AST.TypeSArray)t; + buf.writeByte('['); + tsa.dim.accept(this); + buf.writeByte(']'); + } + } + + override void visit(AST.Type t) + { + debug (Debug_DtoH) + { + printf("[AST.Type enter] %s\n", t.toChars()); + scope(exit) printf("[AST.Type exit] %s\n", t.toChars()); + } + printf("Invalid type: %s\n", t.toPrettyChars()); + assert(0); + } + + override void visit(AST.TypeIdentifier t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeIdentifier enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeIdentifier exit] %s\n", t.toChars()); + } + buf.writestring(t.ident.toChars()); + } + + override void visit(AST.TypeBasic t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeBasic enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeBasic exit] %s\n", t.toChars()); + } + if (!cdparent && t.isConst()) + buf.writestring("const "); + switch (t.ty) + { + case AST.Tbool, AST.Tvoid: + case AST.Tchar, AST.Twchar, AST.Tdchar: + case AST.Tint8, AST.Tuns8: + case AST.Tint16, AST.Tuns16: + case AST.Tint32, AST.Tuns32: + case AST.Tint64, AST.Tuns64: + case AST.Tfloat32, AST.Tfloat64, AST.Tfloat80: + buf.writestring("_d_"); + buf.writestring(t.dstring); + break; + default: + //t.print(); + assert(0); + } + } + + override void visit(AST.TypePointer t) + { + debug (Debug_DtoH) + { + printf("[AST.TypePointer enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypePointer exit] %s\n", t.toChars()); + } + if (t.next.ty == AST.Tstruct && + !strcmp((cast(AST.TypeStruct)t.next).sym.ident.toChars(), "__va_list_tag")) + { + buf.writestring("va_list"); + return; + } + t.next.accept(this); + if (t.next.ty != AST.Tfunction) + buf.writeByte('*'); + if (!cdparent && t.isConst()) + buf.writestring(" const"); + } + + override void visit(AST.TypeSArray t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeSArray enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeSArray exit] %s\n", t.toChars()); + } + t.next.accept(this); + } + + override void visit(AST.TypeAArray t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeAArray enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeAArray exit] %s\n", t.toChars()); + } + AST.Type.tvoidptr.accept(this); + } + + override void visit(AST.TypeFunction tf) + { + debug (Debug_DtoH) + { + printf("[AST.TypeFunction enter] %s\n", tf.toChars()); + scope(exit) printf("[AST.TypeFunction exit] %s\n", tf.toChars()); + } + tf.next.accept(this); + buf.writeByte('('); + buf.writeByte('*'); + if (ident) + buf.writestring(ident.toChars()); + ident = null; + buf.writeByte(')'); + buf.writeByte('('); + foreach (i; 0 .. AST.Parameter.dim(tf.parameterList.parameters)) + { + if (i) + buf.writestring(", "); + auto fparam = AST.Parameter.getNth(tf.parameterList.parameters, i); + fparam.accept(this); + } + if (tf.parameterList.varargs) + { + if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1) + buf.writestring(", "); + buf.writestring("..."); + } + buf.writeByte(')'); + } + + private void enumToBuffer(AST.EnumDeclaration ed) + { + debug (Debug_DtoH) + { + printf("[enumToBuffer(AST.EnumDeclaration) enter] %s\n", ed.toChars()); + scope(exit) printf("[enumToBuffer(AST.EnumDeclaration) exit] %s\n", ed.toChars()); + } + if (ed.isSpecial()) + { + if (ed.ident == DMDType.c_long) + buf.writestring("long"); + else if (ed.ident == DMDType.c_ulong) + buf.writestring("unsigned long"); + else if (ed.ident == DMDType.c_longlong) + buf.writestring("long long"); + else if (ed.ident == DMDType.c_ulonglong) + buf.writestring("unsigned long long"); + else if (ed.ident == DMDType.c_long_double) + buf.writestring("long double"); + else + { + //ed.print(); + assert(0); + } + } + else + { + buf.writestring(ed.toChars()); + } + } + + override void visit(AST.TypeEnum t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeEnum enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeEnum exit] %s\n", t.toChars()); + } + if (cast(void*)t.sym !in forwarded) + { + forwarded[cast(void*)t.sym] = true; + auto save = buf; + buf = fwdbuf; + //printf("Visiting enum %s from module %s %s\n", t.sym.toPrettyChars(), t.toChars(), t.sym.loc.toChars()); + t.sym.accept(this); + buf = save; + } + if (!cdparent && t.isConst()) + buf.writestring("const "); + enumToBuffer(t.sym); + } + + override void visit(AST.TypeStruct t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeStruct enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeStruct exit] %s\n", t.toChars()); + } + if (cast(void*)t.sym !in forwarded && !t.sym.parent.isTemplateInstance()) + { + forwarded[cast(void*)t.sym] = true; + fwdbuf.writestring(t.sym.isUnionDeclaration() ? "union " : "struct "); + fwdbuf.writestring(t.sym.toChars()); + fwdbuf.writestring(";\n"); + } + + if (!cdparent && t.isConst()) + buf.writestring("const "); + if (auto ti = t.sym.parent.isTemplateInstance()) + { + visitTi(ti); + return; + } + buf.writestring(t.sym.toChars()); + } + + override void visit(AST.TypeDArray t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeDArray enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeDArray exit] %s\n", t.toChars()); + } + if (!cdparent && t.isConst()) + buf.writestring("const "); + buf.writestring("DArray< "); + t.next.accept(this); + buf.writestring(" >"); + } + + private void visitTi(AST.TemplateInstance ti) + { + debug (Debug_DtoH) + { + printf("[visitTi(AST.TemplateInstance) enter] %s\n", ti.toChars()); + scope(exit) printf("[visitTi(AST.TemplateInstance) exit] %s\n", ti.toChars()); + } + //version(BUILD_COMPILER) + //{ + if (ti.tempdecl.ident == DMDType.AssocArray) + { + if (!forwardedAA) + { + forwardedAA = true; + fwdbuf.writestring("struct AA;\n"); + } + buf.writestring("AA*"); + return; + } + if (ti.tempdecl.ident == DMDType.Array) + { + buf.writestring("Array"); + } + else + { + foreach (o; *ti.tiargs) + { + if (!AST.isType(o)) + return; + } + buf.writestring(ti.tempdecl.ident.toChars()); + } + //} + //else + //{ + //foreach (o; *ti.tiargs) + //{ + //if (!AST.isType(o)) + //return; + //} + //buf.writestring(ti.tempdecl.ident.toChars()); + //} + buf.writeByte('<'); + foreach (i, o; *ti.tiargs) + { + if (i) + buf.writestring(", "); + if (auto tt = AST.isType(o)) + { + tt.accept(this); + } + else + { + //ti.print(); + //o.print(); + assert(0); + } + } + buf.writeByte('>'); + } + + override void visit(AST.TemplateDeclaration td) + { + debug (Debug_DtoH) + { + printf("[AST.TemplateDeclaration enter] %s\n", td.toChars()); + scope(exit) printf("[AST.TemplateDeclaration exit] %s\n", td.toChars()); + } + if (cast(void*)td in visited) + return; + visited[cast(void*)td] = true; + //version(BUILD_COMPILER) + //{ + if (td.getModule() && td.getModule().isIgnoredModule()) + return; + //} + + if (!td.parameters || !td.onemember || !td.onemember.isStructDeclaration()) + { + visit(cast(AST.Dsymbol)td); + return; + } + + // Explicitly disallow templates with non-type parameters or specialization. + foreach (p; *td.parameters) + { + if (!p.isTemplateTypeParameter() || p.specialization()) + { + visit(cast(AST.Dsymbol)td); + return; + } + } + + if (linkage != LINK.c && linkage != LINK.cpp) + { + buf.printf("// ignoring template %s because of linkage\n", td.toPrettyChars()); + return; + } + + auto sd = td.onemember.isStructDeclaration(); + auto save = tdparent; + tdparent = td; + indent(); + buf.writestring("template <"); + bool first = true; + foreach (p; *td.parameters) + { + if (first) + first = false; + else + buf.writestring(", "); + buf.writestring("typename "); + buf.writestring(p.ident.toChars()); + } + buf.writestring(">\n"); + buf.writestring(sd.isUnionDeclaration() ? "union " : "struct "); + buf.writestring(sd.ident.toChars()); + if (sd.members) + { + buf.writestring("\n{\n"); + auto savex = adparent; + adparent = sd; + foreach (m; *sd.members) + { + m.accept(this); + } + adparent = savex; + buf.writestring("};\n\n"); + } + else + { + buf.writestring(";\n\n"); + } + tdparent = save; + } + + override void visit(AST.TypeClass t) + { + debug (Debug_DtoH) + { + printf("[AST.TypeClass enter] %s\n", t.toChars()); + scope(exit) printf("[AST.TypeClass exit] %s\n", t.toChars()); + } + if (cast(void*)t.sym !in forwarded) + { + forwarded[cast(void*)t.sym] = true; + fwdbuf.writestring("class "); + fwdbuf.writestring(t.sym.toChars()); + fwdbuf.writestring(";\n"); + } + + if (!cdparent && t.isConst()) + buf.writestring("const "); + buf.writestring(t.sym.toChars()); + buf.writeByte('*'); + if (!cdparent && t.isConst()) + buf.writestring(" const"); + } + + private void funcToBuffer(AST.TypeFunction tf, AST.FuncDeclaration fd) + { + debug (Debug_DtoH) + { + printf("[funcToBuffer(AST.TypeFunction) enter] %s\n", tf.toChars()); + scope(exit) printf("[funcToBuffer(AST.TypeFunction) exit] %s\n", tf.toChars()); + } + + Identifier ident = fd.ident; + + assert(tf.next); + if (fd.isCtorDeclaration() || fd.isDtorDeclaration()) + { + if (fd.isDtorDeclaration()) + { + buf.writeByte('~'); + } + buf.writestring(adparent.toChars()); + } + else + { + tf.next.accept(this); + if (tf.isref) + buf.writeByte('&'); + buf.writeByte(' '); + buf.writestring(ident.toChars()); + } + + buf.writeByte('('); + foreach (i; 0 .. AST.Parameter.dim(tf.parameterList.parameters)) + { + if (i) + buf.writestring(", "); + auto fparam = AST.Parameter.getNth(tf.parameterList.parameters, i); + fparam.accept(this); + } + if (tf.parameterList.varargs) + { + if (tf.parameterList.parameters.dim && tf.parameterList.varargs == 1) + buf.writestring(", "); + buf.writestring("..."); + } + buf.writeByte(')'); + } + + override void visit(AST.Parameter p) + { + debug (Debug_DtoH) + { + printf("[AST.Parameter enter] %s\n", p.toChars()); + scope(exit) printf("[AST.Parameter exit] %s\n", p.toChars()); + } + ident = p.ident; + p.type.accept(this); + assert(!(p.storageClass & ~(AST.STC.ref_))); + if (p.storageClass & AST.STC.ref_) + buf.writeByte('&'); + buf.writeByte(' '); + if (ident) + buf.writestring(ident.toChars()); + ident = null; + version (all) + { + if (p.defaultArg && p.defaultArg.op >= TOK.int32Literal && p.defaultArg.op < TOK.struct_) + { + //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op); + buf.writestring(" = "); + buf.writestring(p.defaultArg.toChars()); + } + } + else + { + if (p.defaultArg) + { + //printf("%s %d\n", p.defaultArg.toChars, p.defaultArg.op); + //return; + buf.writestring("/*"); + buf.writestring(" = "); + buf.writestring(p.defaultArg.toChars()); + //p.defaultArg.accept(this); + buf.writestring("*/"); + } + } + } + + override void visit(AST.Expression e) + { + debug (Debug_DtoH) + { + printf("[AST.Expression enter] %s\n", e.toChars()); + scope(exit) printf("[AST.Expression exit] %s\n", e.toChars()); + } + assert(0); + } + + override void visit(AST.NullExp e) + { + debug (Debug_DtoH) + { + printf("[AST.NullExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.NullExp exit] %s\n", e.toChars()); + } + buf.writestring("_d_null"); + } + + override void visit(AST.ArrayLiteralExp e) + { + debug (Debug_DtoH) + { + printf("[AST.ArrayLiteralExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.ArrayLiteralExp exit] %s\n", e.toChars()); + } + buf.writestring("arrayliteral"); + } + + override void visit(AST.StringExp e) + { + debug (Debug_DtoH) + { + printf("[AST.StringExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.StringExp exit] %s\n", e.toChars()); + } + assert(e.sz == 1 || e.sz == 2); + if (e.sz == 2) + buf.writeByte('L'); + buf.writeByte('"'); + size_t o = buf.length; + for (size_t i = 0; i < e.len; i++) + { + uint c = e.charAt(i); + switch (c) + { + case '"': + case '\\': + buf.writeByte('\\'); + goto default; + default: + if (c <= 0xFF) + { + if (c <= 0x7F && isprint(c)) + buf.writeByte(c); + else + buf.printf("\\x%02x", c); + } + else if (c <= 0xFFFF) + { + buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); + } + else + { + buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", + c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); + } + break; + } + } + buf.writeByte('"'); + } + + override void visit(AST.RealExp e) + { + debug (Debug_DtoH) + { + printf("[AST.RealExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.RealExp exit] %s\n", e.toChars()); + } + buf.writestring("0"); + } + + override void visit(AST.IntegerExp e) + { + debug (Debug_DtoH) + { + printf("[AST.IntegerExp enter] %s\n", e.toChars()); + scope(exit) printf("[AST.IntegerExp exit] %s\n", e.toChars()); + } + visitInteger(e.toInteger, e.type); + } + + private void visitInteger(dinteger_t v, AST.Type t) + { + debug (Debug_DtoH) + { + printf("[visitInteger(AST.Type) enter] %s\n", t.toChars()); + scope(exit) printf("[visitInteger(AST.Type) exit] %s\n", t.toChars()); + } + switch (t.ty) + { + case AST.Tenum: + auto te = cast(AST.TypeEnum)t; + buf.writestring("("); + enumToBuffer(te.sym); + buf.writestring(")"); + visitInteger(v, te.sym.memtype); + break; + case AST.Tbool: + buf.writestring(v ? "true" : "false"); + break; + case AST.Tint8: + buf.printf("%d", cast(byte)v); + break; + case AST.Tuns8: + case AST.Tchar: + buf.printf("%uu", cast(ubyte)v); + break; + case AST.Tint16: + buf.printf("%d", cast(short)v); + break; + case AST.Tuns16: + buf.printf("%uu", cast(ushort)v); + break; + case AST.Tint32: + buf.printf("%d", cast(int)v); + break; + case AST.Tuns32: + buf.printf("%uu", cast(uint)v); + break; + case AST.Tint64: + buf.printf("%lldLL", v); + break; + case AST.Tuns64: + buf.printf("%lluLLU", v); + break; + default: + //t.print(); + assert(0); + } + } + + override void visit(AST.StructLiteralExp sle) + { + debug (Debug_DtoH) + { + printf("[AST.StructLiteralExp enter] %s\n", sle.toChars()); + scope(exit) printf("[AST.StructLiteralExp exit] %s\n", sle.toChars()); + } + buf.writestring(sle.sd.ident.toChars()); + buf.writeByte('('); + foreach(i, e; *sle.elements) + { + if (i) + buf.writestring(", "); + e.accept(this); + } + buf.writeByte(')'); + } +} diff --git a/src/dmd/globals.d b/src/dmd/globals.d index e8eb7eb44e99..d87fd6edd905 100644 --- a/src/dmd/globals.d +++ b/src/dmd/globals.d @@ -239,6 +239,10 @@ extern (C++) struct Param const(char)[] hdrname; // write 'header' file to docname bool hdrStripPlainFunctions = true; // strip the bodies of plain (non-template) functions + bool doCxxHdrGeneration; // write 'Cxx header' file + const(char)[] cxxhdrdir; // write 'header' file to docdir directory + const(char)[] cxxhdrname; // write 'header' file to docname + bool doJsonGeneration; // write JSON file const(char)[] jsonfilename; // write JSON file to jsonfilename JsonFieldFlags jsonFieldFlags; // JSON field flags to include @@ -300,6 +304,7 @@ extern (C++) struct Global string doc_ext = "html"; // for Ddoc generated files string ddoc_ext = "ddoc"; // for Ddoc macro include files string hdr_ext = "di"; // for D 'header' import files + string cxxhdr_ext = "h"; // for C/C++ 'header' files string json_ext = "json"; // for JSON files string map_ext = "map"; // for .map files bool run_noext; // allow -run sources without extensions. diff --git a/src/dmd/mars.d b/src/dmd/mars.d index d7e0a047bb35..65319c9b0450 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -65,6 +65,8 @@ import dmd.semantic3; import dmd.target; import dmd.utils; +import dmd.dtoh; + /** * Print DMD's logo on stdout */ @@ -684,6 +686,14 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) File.write(cgFilename.ptr, buf[]); } } + + if (global.params.doCxxHdrGeneration) + { + genCppHdrFiles(modules); + } + if (global.errors) + fatal(); + if (!params.obj) { } @@ -2138,6 +2148,27 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param goto Lerror; } } + else if (p[1] == 'H' && p[2] == 'C') // https://dlang.org/dmd.html#switch-HC + { + params.doCxxHdrGeneration = true; + switch (p[3]) + { + case 'd': // https://dlang.org/dmd.html#switch-HCd + if (!p[4]) + goto Lnoarg; + params.cxxhdrdir = (p + 4 + (p[4] == '=')).toDString; + break; + case 'f': // https://dlang.org/dmd.html#switch-HCf + if (!p[4]) + goto Lnoarg; + params.cxxhdrname = (p + 4 + (p[4] == '=')).toDString; + break; + case 0: + break; + default: + goto Lerror; + } + } else if (p[1] == 'H') // https://dlang.org/dmd.html#switch-H { params.doHdrGeneration = true; diff --git a/src/dmd/root/dcompat.h b/src/dmd/root/dcompat.h index e1ae9bc0fc15..2158069a1944 100644 --- a/src/dmd/root/dcompat.h +++ b/src/dmd/root/dcompat.h @@ -24,6 +24,19 @@ struct DArray : length(length_in), ptr(ptr_in) { } }; +template<> +struct DArray +{ + size_t length; + const char *ptr; + + DArray() : length(0), ptr(NULL) {} + + DArray(const char str[]) : length(strlen(str)), ptr(str) {} + + DArray& operator=(const char str[]) { ptr = str; length = strlen(str); } +}; + struct DString : public DArray { DString() : DArray() { } diff --git a/test/compilable/dtoh_AliasDeclaration.d b/test/compilable/dtoh_AliasDeclaration.d new file mode 100644 index 000000000000..ced46ff95850 --- /dev/null +++ b/test/compilable/dtoh_AliasDeclaration.d @@ -0,0 +1,45 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_AliasDeclaration.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +alias T = int; + +extern (C) int x; + +alias u = x; + +extern (C) int foo(int x) +{ + return x * 42; +} + +alias fun = foo; + +extern (C++) int foo2(int x) +{ + return x * 42; +} + +alias fun2 = foo2; + +extern (C) struct S; + +alias aliasS = S; + +extern (C++) struct S2; + +alias aliasS2 = S2; + +extern (C) class C; + +alias aliasC = C; + +extern (C++) class C2; + +alias aliasC2 = C2; diff --git a/test/compilable/dtoh_AnonDeclaration.d b/test/compilable/dtoh_AnonDeclaration.d new file mode 100644 index 000000000000..5ad36c2effcf --- /dev/null +++ b/test/compilable/dtoh_AnonDeclaration.d @@ -0,0 +1,26 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_AnonDeclaration.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +extern (C++) struct S +{ + union + { + int x; + char[4] c; + } + + struct + { + int y; + double z; + extern(C) void foo() {} + extern(C++) void bar() {} + } +} diff --git a/test/compilable/dtoh_ClassDeclaration.d b/test/compilable/dtoh_ClassDeclaration.d new file mode 100644 index 000000000000..2586e6409fa3 --- /dev/null +++ b/test/compilable/dtoh_ClassDeclaration.d @@ -0,0 +1,90 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_ClassDeclaration.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +/* +ClassDeclaration has the following issues: + * align(n) does nothing. You can use align on classes in C++, though It is generally regarded as bad practice and should be avoided +*/ + +extern (C++) class C +{ + byte a; + int b; + long c; +} + +extern (C++) class C2 +{ + int a = 42; + int b; + long c; + + this(int a) {} +} + +extern (C) class C3 +{ + int a = 42; + int b; + long c; + + this(int a) {} +} + +extern (C++) align(1) class Aligned +{ + byte a; + int b; + long c; + + this(int a) {} +} + +extern (C++) class A +{ + int a; + C c; + + void foo(); + extern (C) void bar() {} + extern (C++) void baz(int x = 42) {} + + struct + { + int x; + int y; + } + + union + { + int u1; + char[4] u2; + } + + struct Inner + { + int x; + } + + static extern(C++) class InnerC + { + int x; + } + + class NonStaticInnerC + { + int x; + } + + alias I = Inner; + + extern(C++) class CC; + +} diff --git a/test/compilable/dtoh_StructDeclaration.d b/test/compilable/dtoh_StructDeclaration.d new file mode 100644 index 000000000000..d9440337b8cc --- /dev/null +++ b/test/compilable/dtoh_StructDeclaration.d @@ -0,0 +1,87 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_StructDeclaration.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +/* +StructDeclaration has the following issues: + * align different than 1 does nothing; we should support align(n), where `n` in [1, 2, 4, 8, 16] + * align(n): inside struct definition doesn’t add alignment, but breaks generation of default ctors + * default ctors should be generated only if struct has no ctors + * if a struct has ctors defined, only default ctor (S() { … }) should be generated to init members to default values, and the defined ctors must be declared + * if a struct has ctors defined, the declared ctors must have the name of the struct, not __ctor, as `__ctor` might not be portable + * if a struct has a `member = void`, dtoh code segfaults + * a struct should only define ctors if it’s extern (C++) +*/ + +extern (C++) struct S +{ + byte a; + int b; + long c; +} + +extern (C++) struct S2 +{ + int a = 42; + int b; + long c; + + this(int a) {} +} + +extern (C) struct S3 +{ + int a = 42; + int b; + long c; + + this(int a) {} +} + +extern (C++) align(1) struct Aligned +{ + //align(1): + byte a; + int b; + long c; + + this(int a) {} +} + +extern (C++) struct A +{ + int a; + S s; + + extern (D) void foo(); + extern (C) void bar() {} + extern (C++) void baz(int x = 42) {} + + struct + { + int x; + int y; + } + + union + { + int u1; + char[4] u2; + } + + struct Inner + { + int x; + } + + alias I = Inner; + + extern(C++) class C; + +} diff --git a/test/compilable/dtoh_TemplateDeclaration.d b/test/compilable/dtoh_TemplateDeclaration.d new file mode 100644 index 000000000000..b5eb7be5bfee --- /dev/null +++ b/test/compilable/dtoh_TemplateDeclaration.d @@ -0,0 +1,22 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_TemplateDeclaration.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +extern (C++) struct A(T) +{ + T x; + // enum Num = 42; // dtoh segfaults at enum + + void foo() {} +} + +extern (C++) struct B +{ + A!int x; +} diff --git a/test/compilable/dtoh_VarDeclaration.d b/test/compilable/dtoh_VarDeclaration.d new file mode 100644 index 000000000000..0f249e9b9e0a --- /dev/null +++ b/test/compilable/dtoh_VarDeclaration.d @@ -0,0 +1,29 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_VarDeclaration.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +int x = 42; + +extern int y; + +extern (C) int z; + +extern (C++) __gshared int t; + +extern (C) struct S; + +extern (C++) struct S2; + +extern (C) class C; + +extern (C++) class C2; + +extern (C) union U; + +extern (C++) union U2; diff --git a/test/compilable/dtoh_enum.d b/test/compilable/dtoh_enum.d new file mode 100644 index 000000000000..66fcfd7c1c5f --- /dev/null +++ b/test/compilable/dtoh_enum.d @@ -0,0 +1,15 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_enum.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +enum Dummy +{ + One, + Two +} diff --git a/test/compilable/dtoh_functions.d b/test/compilable/dtoh_functions.d new file mode 100644 index 000000000000..07a3225fa37b --- /dev/null +++ b/test/compilable/dtoh_functions.d @@ -0,0 +1,57 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_functions.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +int foo(int x) +{ + return x * 42; +} + +extern (C) int fun(); +extern (C++) int fun2(); + +extern (C) int bar(int x) +{ + return x * 42; +} + +extern (C) static int bar2(int x) +{ + return x * 42; +} + +extern (C) private int bar3(int x) +{ + return x * 42; +} + +extern (C) int bar4(int x = 42) +{ + return x * 42; +} + +extern (C++) int baz(int x) +{ + return x * 42; +} + +extern (C++) static int baz2(int x) +{ + return x * 42; +} + +extern (C++) private int baz3(int x) +{ + return x * 42; +} + +extern (C++) int baz3(int x = 42) +{ + return x * 42; +} diff --git a/test/compilable/dtoh_unittest_block.d b/test/compilable/dtoh_unittest_block.d new file mode 100644 index 000000000000..da9fc0c5d276 --- /dev/null +++ b/test/compilable/dtoh_unittest_block.d @@ -0,0 +1,17 @@ +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_unittest_block.out -c +// PERMUTE_ARGS: +// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh + +/* +TEST_OUTPUT: +--- +--- +*/ + +unittest +{ + extern (C++) int foo(int x) + { + return x * 42; + } +} diff --git a/test/compilable/extra-files/dtoh-postscript.sh b/test/compilable/extra-files/dtoh-postscript.sh new file mode 100644 index 000000000000..92c7f50e2645 --- /dev/null +++ b/test/compilable/extra-files/dtoh-postscript.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +diff -pu --strip-trailing-cr ${EXTRA_FILES}/${TEST_NAME}.out ${OUTPUT_BASE}.out + +rm -f ${OUTPUT_BASE}.out diff --git a/test/compilable/extra-files/dtoh_AliasDeclaration.out b/test/compilable/extra-files/dtoh_AliasDeclaration.out new file mode 100644 index 000000000000..ed59bb2ab7ff --- /dev/null +++ b/test/compilable/extra-files/dtoh_AliasDeclaration.out @@ -0,0 +1,61 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_AliasDeclaration +struct S; +struct S2; +class C; +class C2; +typedef _d_int T; + +extern "C" _d_int x; + +// ignored variable dtoh_AliasDeclaration.x +extern "C" _d_int foo(_d_int x); + +// ignored function dtoh_AliasDeclaration.foo +extern _d_int foo2(_d_int x); + +// ignored function dtoh_AliasDeclaration.foo2 +struct S; + +typedef S aliasS; + +struct S2; + +typedef S2 aliasS2; + +// ignoring non-cpp class C +typedef C* aliasC; + +class C2; + +typedef C2* aliasC2; + diff --git a/test/compilable/extra-files/dtoh_AnonDeclaration.out b/test/compilable/extra-files/dtoh_AnonDeclaration.out new file mode 100644 index 000000000000..4d959afb68db --- /dev/null +++ b/test/compilable/extra-files/dtoh_AnonDeclaration.out @@ -0,0 +1,48 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_AnonDeclaration +struct S +{ + union + { + _d_int x; + _d_char c[4LLU]; + }; + struct + { + _d_int y; + _d_double z; + extern "C" _d_void foo(); + _d_void bar(); + }; + S() {} +}; + diff --git a/test/compilable/extra-files/dtoh_ClassDeclaration.out b/test/compilable/extra-files/dtoh_ClassDeclaration.out new file mode 100644 index 000000000000..21236d62e733 --- /dev/null +++ b/test/compilable/extra-files/dtoh_ClassDeclaration.out @@ -0,0 +1,103 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_ClassDeclaration +class C; +class A; +struct Inner; +class C +{ +public: + _d_byte a; + _d_int b; + _d_long c; +}; + +class C2 +{ +public: + _d_int a; + _d_int b; + _d_long c; + C2(_d_int a); +}; + +// ignoring non-cpp class C3 +class Aligned +{ +public: + _d_byte a; + _d_int b; + _d_long c; + Aligned(_d_int a); +}; + +class A +{ +public: + _d_int a; + C* c; + virtual _d_void foo(); + extern "C" virtual _d_void bar(); + virtual _d_void baz(_d_int x = 42); + struct + { + _d_int x; + _d_int y; + }; + union + { + _d_int u1; + _d_char u2[4LLU]; + }; +struct Inner +{ + _d_int x; + Inner() : x() {} +}; + +class InnerC +{ +public: + _d_int x; +}; + +class NonStaticInnerC +{ +public: + _d_int x; + A* this; +}; + +typedef Inner I; +class CC; + +}; + diff --git a/test/compilable/extra-files/dtoh_StructDeclaration.out b/test/compilable/extra-files/dtoh_StructDeclaration.out new file mode 100644 index 000000000000..5ed37bf7d522 --- /dev/null +++ b/test/compilable/extra-files/dtoh_StructDeclaration.out @@ -0,0 +1,108 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_StructDeclaration +struct S; +struct Inner; +struct S +{ + _d_byte a; + _d_int b; + _d_long c; + S() : a(), b(), c() {} +}; + +struct S2 +{ + _d_int a; + _d_int b; + _d_long c; + S2(_d_int a); + S2() : a(42), b(), c() {} +}; + +struct S3 +{ + _d_int a; + _d_int b; + _d_long c; + extern "C" S3(_d_int a); + S3() : a(42), b(), c() {} +}; + +struct +#if defined(__GNUC__) || defined(__clang__) + __attribute__((packed, aligned(1))) +#elif defined(_MSC_VER) + __declspec(align(1)) +#elif defined(__DMC__) + #pragma pack(push, 1) +#endif +Aligned +{ + _d_byte a; + _d_int b; + _d_long c; + Aligned(_d_int a); + Aligned() : a(), b(), c() {} +}; +#if defined(__DMC__) + #pragma pack(pop) +#endif + +struct A +{ + _d_int a; + S s; + // ignoring extern () block because of linkage + extern "C" _d_void bar(); + _d_void baz(_d_int x = 42); + struct + { + _d_int x; + _d_int y; + }; + union + { + _d_int u1; + _d_char u2[4LLU]; + }; +struct Inner +{ + _d_int x; + Inner() : x() {} +}; + +typedef Inner I; +class C; + + A() : a(), s() {} +}; + diff --git a/test/compilable/extra-files/dtoh_TemplateDeclaration.out b/test/compilable/extra-files/dtoh_TemplateDeclaration.out new file mode 100644 index 000000000000..c9d42e732592 --- /dev/null +++ b/test/compilable/extra-files/dtoh_TemplateDeclaration.out @@ -0,0 +1,45 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_TemplateDeclaration +template +struct A +{ + // Ignoring var x alignment 0 + T x; + // ignoring function foo because semantic hasn't been run +}; + +struct B +{ + A<_d_int> x; + B() : x() {} +}; + diff --git a/test/compilable/extra-files/dtoh_VarDeclaration.out b/test/compilable/extra-files/dtoh_VarDeclaration.out new file mode 100644 index 000000000000..eaced69390ea --- /dev/null +++ b/test/compilable/extra-files/dtoh_VarDeclaration.out @@ -0,0 +1,48 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_VarDeclaration +// ignoring variable dtoh_VarDeclaration.x because of linkage +// ignoring variable dtoh_VarDeclaration.y because of linkage +extern "C" _d_int z; + +extern _d_int t; + +struct S; + +struct S2; + +// ignoring non-cpp class C +class C2; + +union U; + +union U2; + diff --git a/test/compilable/extra-files/dtoh_enum.out b/test/compilable/extra-files/dtoh_enum.out new file mode 100644 index 000000000000..6135d77a2767 --- /dev/null +++ b/test/compilable/extra-files/dtoh_enum.out @@ -0,0 +1,37 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_enum +enum Dummy +{ + DUMMYOne = 0, + DUMMYTwo = 1 +}; + diff --git a/test/compilable/extra-files/dtoh_functions.out b/test/compilable/extra-files/dtoh_functions.out new file mode 100644 index 000000000000..d9d9260fed83 --- /dev/null +++ b/test/compilable/extra-files/dtoh_functions.out @@ -0,0 +1,46 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_functions +// ignoring function dtoh_functions.foo because of linkage +// ignoring function dtoh_functions.fun because it's extern +// ignoring function dtoh_functions.fun2 because it's extern +extern "C" _d_int bar(_d_int x); + +extern "C" _d_int bar2(_d_int x); + +extern "C" _d_int bar4(_d_int x = 42); + +extern _d_int baz(_d_int x); + +extern _d_int baz2(_d_int x); + +extern _d_int baz3(_d_int x = 42); + diff --git a/test/compilable/extra-files/dtoh_unittest_block.out b/test/compilable/extra-files/dtoh_unittest_block.out new file mode 100644 index 000000000000..c6a05985e077 --- /dev/null +++ b/test/compilable/extra-files/dtoh_unittest_block.out @@ -0,0 +1,31 @@ +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long +#define _d_ulong unsigned long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_unittest_block From 5132db2c6970da15bccc5a95f12fb4808f198d0a Mon Sep 17 00:00:00 2001 From: MoonlightSentinel Date: Tue, 18 Feb 2020 13:05:52 +0100 Subject: [PATCH 2/7] Address style feedback by thewilsonator --- src/dmd/dtoh.d | 423 ++++++++++++++++++++++++------------------------- 1 file changed, 205 insertions(+), 218 deletions(-) diff --git a/src/dmd/dtoh.d b/src/dmd/dtoh.d index 0e261164f1cb..5be7a70c3332 100644 --- a/src/dmd/dtoh.d +++ b/src/dmd/dtoh.d @@ -91,7 +91,7 @@ private struct DMDType __gshared static Identifier ID; ////Identifier __gshared static Identifier Visitor; __gshared static Identifier ParseTimeVisitor; - __gshared static void _init() + static void _init() { ID = Identifier.idPool("Identifier"); Visitor = Identifier.idPool("Visitor"); @@ -226,9 +226,24 @@ void genCppHdrFiles(ref Modules ms) buf.writestring("\n\n"); OutBuffer check; - check.writestring(` - #if OFFSETS + OutBuffer done; + OutBuffer decl; + scope v = new ToCppBuffer!ASTCodegen(&check, &buf, &done, &decl); + foreach (m; ms) + { + //printf("// Parsing module %s\n", m.toPrettyChars()); + buf.printf("// Parsing module %s\n", m.toPrettyChars()); + m.accept(v); + } + buf.write(&done); + buf.write(&decl); + //printf("%s\n", decl.peekSlice().ptr); + + debug (Debug_DtoH) + { + buf.writestring(` +#if OFFSETS template size_t getSlotNumber(int dummy, ...) { @@ -246,27 +261,13 @@ void genCppHdrFiles(ref Modules ms) void testOffsets() { - `); - - OutBuffer done; - OutBuffer decl; - scope v = new ToCppBuffer!ASTCodegen(&check, &buf, &done, &decl); - foreach (m; ms) - { - //printf("// Parsing module %s\n", m.toPrettyChars()); - buf.printf("// Parsing module %s\n", m.toPrettyChars()); - m.accept(v); - } - buf.write(&done); - buf.write(&decl); - //printf("%s\n", decl.peekSlice().ptr); - - check.writestring(` +`); + buf.write(&check); + buf.writestring(` + } +#endif +`); } - #endif - `); - - debug buf.write(&check); if (global.params.cxxhdrname is null) { @@ -348,14 +349,13 @@ public: scope(exit) printf("[AST.AttribDeclaration exit] %s\n", pd.toChars()); } Dsymbols* decl = pd.include(null); - if (decl) + if (!decl) + return; + + foreach (s; *decl) { - foreach (s; *decl) - { - if (!adparent && s.prot().kind < AST.Prot.Kind.public_) - continue; + if (adparent || s.prot().kind >= AST.Prot.Kind.public_) s.accept(this); - } } } @@ -476,14 +476,7 @@ public: } } - if (fdOverridesAreConst) - { - buf.writestring(" const"); - } - else - { - buf.writestring(" /* const */"); - } + buf.writestring(fdOverridesAreConst ? " const" : " /* const */"); } if (adparent && fd.isAbstract()) buf.writestring(" = 0"); @@ -740,21 +733,68 @@ public: buf.writestring(sd.isUnionDeclaration() ? "union" : "struct"); pushAlignToBuffer(sd.alignment); buf.writestring(sd.ident.toChars()); - if (sd.members) + if (!sd.members) { - buf.writestring("\n{\n"); - auto save = adparent; - adparent = sd; + buf.writestring(";\n\n"); + return; + } + + buf.writestring("\n{\n"); + auto save = adparent; + adparent = sd; + foreach (m; *sd.members) + { + m.accept(this); + } + adparent = save; + // Generate default ctor + if (!sd.noDefaultCtor) + { + buf.printf(" %s()", sd.ident.toChars()); + size_t varCount; + bool first = true; foreach (m; *sd.members) { - m.accept(this); + if (auto vd = m.isVarDeclaration()) + { + if (!memberField(vd)) + continue; + varCount++; + + if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct && + !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray) + { + continue; + } + if (vd._init && vd._init.isVoidInitializer()) + continue; + + if (first) + { + buf.printf(" : "); + first = false; + } + else + { + buf.printf(", "); + } + buf.printf("%s(", vd.ident.toChars()); + + if (vd._init) + { + AST.initializerToExpression(vd._init).accept(this); + } + buf.printf(")"); + } } - adparent = save; - // Generate default ctor - if (!sd.noDefaultCtor) + buf.printf(" {}\n"); + } + + version (none) + { + if (varCount) { - buf.printf(" %s()", sd.ident.toChars()); - size_t varCount; + buf.printf(" %s(", sd.ident.toChars()); bool first = true; foreach (m; *sd.members) { @@ -762,87 +802,39 @@ public: { if (!memberField(vd)) continue; - varCount++; - - if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct && - !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray) - { - continue; - } - if (vd._init && vd._init.isVoidInitializer()) - continue; - if (first) - { - buf.printf(" : "); first = false; - } else - { - buf.printf(", "); - } - buf.printf("%s(", vd.ident.toChars()); - - if (vd._init) - { - AST.initializerToExpression(vd._init).accept(this); - } - buf.printf(")"); + buf.writestring(", "); + assert(vd.type); + assert(vd.ident); + typeToBuffer(vd.type, vd.ident); } } - buf.printf(" {}\n"); - } - - version (none) - { - if (varCount) + buf.printf(") {"); + foreach (m; *sd.members) { - buf.printf(" %s(", sd.ident.toChars()); - bool first = true; - foreach (m; *sd.members) - { - if (auto vd = m.isVarDeclaration()) - { - if (!memberField(vd)) - continue; - if (first) - first = false; - else - buf.writestring(", "); - assert(vd.type); - assert(vd.ident); - typeToBuffer(vd.type, vd.ident); - } - } - buf.printf(") {"); - foreach (m; *sd.members) + if (auto vd = m.isVarDeclaration()) { - if (auto vd = m.isVarDeclaration()) - { - if (!memberField(vd)) - continue; - buf.printf(" this->%s = %s;", vd.ident.toChars(), vd.ident.toChars()); - } + if (!memberField(vd)) + continue; + buf.printf(" this->%s = %s;", vd.ident.toChars(), vd.ident.toChars()); } - buf.printf(" }\n"); } + buf.printf(" }\n"); } - buf.writestring("};\n"); + } + buf.writestring("};\n"); - popAlignToBuffer(sd.alignment); - buf.writestring("\n"); + popAlignToBuffer(sd.alignment); + buf.writestring("\n"); - auto savex = buf; - buf = checkbuf; - buf.writestring(" assert(sizeof("); - buf.writestring(sd.ident.toChars()); - buf.printf(") == %d);\n", sd.size(Loc.initial)); - buf = savex; - } - else - { - buf.writestring(";\n\n"); - } + auto savex = buf; + buf = checkbuf; + buf.writestring(" assert(sizeof("); + buf.writestring(sd.ident.toChars()); + buf.printf(") == %d);\n", sd.size(Loc.initial)); + buf = savex; } private void pushAlignToBuffer(uint alignment) @@ -852,34 +844,33 @@ public: // "Invalid alignment size"); // When no alignment is specified, `uint.max` is the default - if (alignment != uint.max) - { - buf.writestring("\n#if defined(__GNUC__) || defined(__clang__)\n"); - // The equivalent of `#pragma pack(push, n)` is `__attribute__((packed, aligned(n)))` - // NOTE: removing the packed attribute will might change the resulting size - buf.printf(" __attribute__((packed, aligned(%d)))\n", alignment); - buf.writestring("#elif defined(_MSC_VER)\n"); - buf.printf(" __declspec(align(%d))\n", alignment); - buf.writestring("#elif defined(__DMC__)\n"); - buf.printf(" #pragma pack(push, %d)\n", alignment); - //buf.printf("#pragma pack(%d)\n", alignment); - buf.writestring("#endif\n"); - } - else + if (alignment == uint.max) { buf.writeByte(' '); + return; } + + buf.writestring("\n#if defined(__GNUC__) || defined(__clang__)\n"); + // The equivalent of `#pragma pack(push, n)` is `__attribute__((packed, aligned(n)))` + // NOTE: removing the packed attribute will might change the resulting size + buf.printf(" __attribute__((packed, aligned(%d)))\n", alignment); + buf.writestring("#elif defined(_MSC_VER)\n"); + buf.printf(" __declspec(align(%d))\n", alignment); + buf.writestring("#elif defined(__DMC__)\n"); + buf.printf(" #pragma pack(push, %d)\n", alignment); + //buf.printf("#pragma pack(%d)\n", alignment); + buf.writestring("#endif\n"); } private void popAlignToBuffer(uint alignment) { - if (alignment != uint.max) - { - buf.writestring("#if defined(__DMC__)\n"); - buf.writestring(" #pragma pack(pop)\n"); - //buf.writestring("#pragma pack()\n"); - buf.writestring("#endif\n"); - } + if (alignment == uint.max) + return; + + buf.writestring("#if defined(__DMC__)\n"); + buf.writestring(" #pragma pack(pop)\n"); + //buf.writestring("#pragma pack()\n"); + buf.writestring("#endif\n"); } private void includeSymbol(AST.Dsymbol ds) @@ -889,15 +880,15 @@ public: printf("[includeSymbol(AST.Dsymbol) enter] %s\n", ds.toChars()); scope(exit) printf("[includeSymbol(AST.Dsymbol) exit] %s\n", ds.toChars()); } - if (cast(void*)ds !in visited) - { - OutBuffer decl; - auto save = buf; - buf = &decl; - ds.accept(this); - buf = save; - donebuf.writestring(decl.peekChars()); - } + if (cast(void*) ds in visited) + return; + + OutBuffer decl; + auto save = buf; + buf = &decl; + ds.accept(this); + buf = save; + donebuf.writestring(decl.peekChars()); } override void visit(AST.ClassDeclaration cd) @@ -933,31 +924,30 @@ public: includeSymbol(cd.baseClass); } - if (cd.members) + if (!cd.members) { - buf.writestring("\n{\npublic:\n"); - auto save = adparent; - adparent = cd; - foreach (m; *cd.members) - { - m.accept(this); - } - adparent = save; - //version(BUILD_COMPILER) - //{ - // Generate special static inline function. - if (cd.isIdentifierClass()) - { - buf.writestring(" static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); }\n"); - } - //} - - buf.writestring("};\n\n"); + buf.writestring(";\n\n"); + return; } - else + + buf.writestring("\n{\npublic:\n"); + auto save = adparent; + adparent = cd; + foreach (m; *cd.members) { - buf.writestring(";\n\n"); + m.accept(this); } + adparent = save; + //version(BUILD_COMPILER) + //{ + // Generate special static inline function. + if (cd.isIdentifierClass()) + { + buf.writestring(" static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); }\n"); + } + //} + + buf.writestring("};\n\n"); } override void visit(AST.EnumDeclaration ed) @@ -1013,54 +1003,52 @@ public: { buf.writestring("enum"); } - else + else if (hasBaseType) { - if (hasBaseType) + //printf("typedef _d_%s %s;\n", ed.memtype.kind, ident); + if (global.params.cplusplus >= CppStdRevision.cpp11) { - //printf("typedef _d_%s %s;\n", ed.memtype.kind, ident); - if (global.params.cplusplus >= CppStdRevision.cpp11) - { - //printf("Using cpp 11 and beyond\n"); - buf.printf("enum %s : %s", ident, ed.memtype.kind); - } - else - { - //printf("Using cpp 98\n"); - buf.writestring("typedef _d_"); - buf.writestring(ed.memtype.kind); - buf.writeByte(' '); - buf.writestring(ident); - buf.writestring(";\n"); - buf.writestring("enum"); - } + //printf("Using cpp 11 and beyond\n"); + buf.printf("enum %s : %s", ident, ed.memtype.kind); } else { - buf.writestring("enum "); + //printf("Using cpp 98\n"); + buf.writestring("typedef _d_"); + buf.writestring(ed.memtype.kind); + buf.writeByte(' '); buf.writestring(ident); + buf.writestring(";\n"); + buf.writestring("enum"); } } - if (ed.members) + else { - buf.writestring("\n{\n"); - foreach (i, m; *ed.members) - { - if (i) - buf.writestring(",\n"); - buf.writestring(" "); - if (ident && global.params.cplusplus == CppStdRevision.cpp98) - { - foreach (c; ident[0 .. strlen(ident)]) - buf.writeByte(toupper(c)); - } - m.accept(this); - } - buf.writestring("\n};\n\n"); + buf.writestring("enum "); + buf.writestring(ident); } - else + + if (!ed.members) { buf.writestring(";\n\n"); + return; } + + buf.writestring("\n{\n"); + foreach (i, m; *ed.members) + { + if (i) + buf.writestring(",\n"); + buf.writestring(" "); + if (ident && global.params.cplusplus == CppStdRevision.cpp98) + { + foreach (c; ident[0 .. strlen(ident)]) + buf.writeByte(toupper(c)); + } + m.accept(this); + } + buf.writestring("\n};\n\n"); + //printf("Enum %s min %d max %d\n", ident, ed.minval.toInteger(), ed.maxval.toInteger()); } @@ -1234,25 +1222,24 @@ public: } if (ed.isSpecial()) { - if (ed.ident == DMDType.c_long) - buf.writestring("long"); - else if (ed.ident == DMDType.c_ulong) - buf.writestring("unsigned long"); - else if (ed.ident == DMDType.c_longlong) - buf.writestring("long long"); - else if (ed.ident == DMDType.c_ulonglong) - buf.writestring("unsigned long long"); - else if (ed.ident == DMDType.c_long_double) - buf.writestring("long double"); - else - { - //ed.print(); - assert(0); - } + buf.writestring(ed.toChars()); + return; } + + if (ed.ident == DMDType.c_long) + buf.writestring("long"); + else if (ed.ident == DMDType.c_ulong) + buf.writestring("unsigned long"); + else if (ed.ident == DMDType.c_longlong) + buf.writestring("long long"); + else if (ed.ident == DMDType.c_ulonglong) + buf.writestring("unsigned long long"); + else if (ed.ident == DMDType.c_long_double) + buf.writestring("long double"); else { - buf.writestring(ed.toChars()); + //ed.print(); + assert(0); } } From 288d5c20432b0e11cfc49d06a0c3eb27d2d385ee Mon Sep 17 00:00:00 2001 From: MoonlightSentinel Date: Tue, 18 Feb 2020 15:04:14 +0100 Subject: [PATCH 3/7] Address Geod24's feedback - Documentation for dtoh.d - Removed redundant static - Add missing members to globals.h - Generate .h instead of .out files in tests - Add a changelog --- changelog/headers.dd | 104 ++++++++++++++++++ src/dmd/dtoh.d | 41 +++---- src/dmd/globals.h | 5 + src/dmd/root/dcompat.h | 13 --- test/compilable/dtoh_AliasDeclaration.d | 2 +- test/compilable/dtoh_AnonDeclaration.d | 2 +- test/compilable/dtoh_ClassDeclaration.d | 2 +- test/compilable/dtoh_StructDeclaration.d | 2 +- test/compilable/dtoh_TemplateDeclaration.d | 2 +- test/compilable/dtoh_VarDeclaration.d | 2 +- test/compilable/dtoh_enum.d | 2 +- test/compilable/dtoh_functions.d | 2 +- test/compilable/dtoh_unittest_block.d | 2 +- .../compilable/extra-files/dtoh-postscript.sh | 4 +- ...eclaration.out => dtoh_AliasDeclaration.h} | 0 ...Declaration.out => dtoh_AnonDeclaration.h} | 0 ...eclaration.out => dtoh_ClassDeclaration.h} | 0 ...claration.out => dtoh_StructDeclaration.h} | 0 ...aration.out => dtoh_TemplateDeclaration.h} | 0 ...rDeclaration.out => dtoh_VarDeclaration.h} | 0 .../{dtoh_enum.out => dtoh_enum.h} | 0 .../{dtoh_functions.out => dtoh_functions.h} | 0 ...ittest_block.out => dtoh_unittest_block.h} | 0 23 files changed, 142 insertions(+), 43 deletions(-) create mode 100644 changelog/headers.dd rename test/compilable/extra-files/{dtoh_AliasDeclaration.out => dtoh_AliasDeclaration.h} (100%) rename test/compilable/extra-files/{dtoh_AnonDeclaration.out => dtoh_AnonDeclaration.h} (100%) rename test/compilable/extra-files/{dtoh_ClassDeclaration.out => dtoh_ClassDeclaration.h} (100%) rename test/compilable/extra-files/{dtoh_StructDeclaration.out => dtoh_StructDeclaration.h} (100%) rename test/compilable/extra-files/{dtoh_TemplateDeclaration.out => dtoh_TemplateDeclaration.h} (100%) rename test/compilable/extra-files/{dtoh_VarDeclaration.out => dtoh_VarDeclaration.h} (100%) rename test/compilable/extra-files/{dtoh_enum.out => dtoh_enum.h} (100%) rename test/compilable/extra-files/{dtoh_functions.out => dtoh_functions.h} (100%) rename test/compilable/extra-files/{dtoh_unittest_block.out => dtoh_unittest_block.h} (100%) diff --git a/changelog/headers.dd b/changelog/headers.dd new file mode 100644 index 000000000000..17fd31b8d40d --- /dev/null +++ b/changelog/headers.dd @@ -0,0 +1,104 @@ +Added experimental `C++` header generation from `extern(C|C++)` declarations + +DMD can now write C++ header files which contain bindings for declarations +in existing D files that were marked as `extern(C)` or `extern(C++)`. + +This feature is available via the following command line switches: +- `-HC`: Write the generated headers to standard output +- `-HCf=`: Write the generated headers to file +- `-HCd=`: Write the generated headers to file (not implemented yet) + +Consider the following example: + +``` +module a; + +extern(C) int foo(int a) { ... } +extern(C++) void bar() { ... } +void ignored() { ... } +``` +``` +module b; + +extern (C++) struct S +{ + string name; + this (string name) { ... } + bool bar() { ... } +} +``` +``` +module c; + +import a, b; + +extern (C++) class C +{ + S[] s; + this () {} + bool bar() { ...} +} + +``` + +Compiling these modules with `dmd -c -o- -HC a.d b.d c.d` will generate the following header: + +``` +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long long long +#define _d_ulong unsigned long long +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; +#define _d_null NULL + +// Parsing module a +// Parsing module b +// Parsing module c +struct S; +extern "C" _d_int foo(_d_int a); + +extern _d_void bar(); + +// ignoring function a.ignored because of linkage +struct S +{ + DArray< _d_char > name; + S(DArray< _d_char > name); + _d_bool bar(); + S() : name() {} +}; + +class C +{ +public: + DArray< S > s; + C(); + virtual _d_bool bar(); +}; +``` + +Refer to the $(LINK2 $(ROOT_DIR)/spec/cpp_interface.html, documentation) for further information regarding C++ interoperation. + +Note that this feature is considered experimental and might not work correctly sometimes. +Please open an issue in the $(LINK2 https://issues.dlang.org, bug tracker) if you encounter a bug while using this feature. diff --git a/src/dmd/dtoh.d b/src/dmd/dtoh.d index 5be7a70c3332..9ff846d0f30b 100644 --- a/src/dmd/dtoh.d +++ b/src/dmd/dtoh.d @@ -2,7 +2,10 @@ * Compiler implementation of the * $(LINK2 http://www.dlang.org, D programming language). * - * Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved + * This module contains the implementation of the C++ header generation available through + * the command line switch -Hc. + * + * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dtohd, _dtoh.d) @@ -35,15 +38,15 @@ import dmd.utils; private struct DMDType { - __gshared static Identifier c_long; - __gshared static Identifier c_ulong; - __gshared static Identifier c_longlong; - __gshared static Identifier c_ulonglong; - __gshared static Identifier c_long_double; + __gshared Identifier c_long; + __gshared Identifier c_ulong; + __gshared Identifier c_longlong; + __gshared Identifier c_ulonglong; + __gshared Identifier c_long_double; //version(BUILD_COMPILER) //{ - __gshared static Identifier AssocArray; - __gshared static Identifier Array; + __gshared Identifier AssocArray; + __gshared Identifier Array; //} static void _init() @@ -65,14 +68,14 @@ private struct DMDType //{ private struct DMDModule { - __gshared static Identifier identifier; - __gshared static Identifier root; - __gshared static Identifier visitor; - __gshared static Identifier parsetimevisitor; - __gshared static Identifier permissivevisitor; - __gshared static Identifier strictvisitor; - __gshared static Identifier transitivevisitor; - __gshared static Identifier dmd; + __gshared Identifier identifier; + __gshared Identifier root; + __gshared Identifier visitor; + __gshared Identifier parsetimevisitor; + __gshared Identifier permissivevisitor; + __gshared Identifier strictvisitor; + __gshared Identifier transitivevisitor; + __gshared Identifier dmd; static void _init() { identifier = Identifier.idPool("identifier"); @@ -88,9 +91,9 @@ private struct DMDType private struct DMDClass { - __gshared static Identifier ID; ////Identifier - __gshared static Identifier Visitor; - __gshared static Identifier ParseTimeVisitor; + __gshared Identifier ID; ////Identifier + __gshared Identifier Visitor; + __gshared Identifier ParseTimeVisitor; static void _init() { ID = Identifier.idPool("Identifier"); diff --git a/src/dmd/globals.h b/src/dmd/globals.h index d196686829b9..ecf014475ed0 100644 --- a/src/dmd/globals.h +++ b/src/dmd/globals.h @@ -205,6 +205,10 @@ struct Param DString hdrname; // write 'header' file to docname bool hdrStripPlainFunctions; // strip the bodies of plain (non-template) functions + bool doCxxHdrGeneration; // write 'Cxx header' file + DString cxxhdrdir; // write 'header' file to docdir directory + DString cxxhdrname; // write 'header' file to docname + bool doJsonGeneration; // write JSON file DString jsonfilename; // write JSON file to jsonfilename unsigned jsonFieldFlags; // JSON field flags to include @@ -265,6 +269,7 @@ struct Global const DString doc_ext; // for Ddoc generated files const DString ddoc_ext; // for Ddoc macro include files const DString hdr_ext; // for D 'header' import files + const DString cxxhdr_ext; // for C/C++ 'header' files const DString json_ext; // for JSON files const DString map_ext; // for .map files bool run_noext; // allow -run sources without extensions. diff --git a/src/dmd/root/dcompat.h b/src/dmd/root/dcompat.h index 2158069a1944..e1ae9bc0fc15 100644 --- a/src/dmd/root/dcompat.h +++ b/src/dmd/root/dcompat.h @@ -24,19 +24,6 @@ struct DArray : length(length_in), ptr(ptr_in) { } }; -template<> -struct DArray -{ - size_t length; - const char *ptr; - - DArray() : length(0), ptr(NULL) {} - - DArray(const char str[]) : length(strlen(str)), ptr(str) {} - - DArray& operator=(const char str[]) { ptr = str; length = strlen(str); } -}; - struct DString : public DArray { DString() : DArray() { } diff --git a/test/compilable/dtoh_AliasDeclaration.d b/test/compilable/dtoh_AliasDeclaration.d index ced46ff95850..7e6d3b593d46 100644 --- a/test/compilable/dtoh_AliasDeclaration.d +++ b/test/compilable/dtoh_AliasDeclaration.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_AliasDeclaration.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_AliasDeclaration.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/dtoh_AnonDeclaration.d b/test/compilable/dtoh_AnonDeclaration.d index 5ad36c2effcf..2cc36cb03407 100644 --- a/test/compilable/dtoh_AnonDeclaration.d +++ b/test/compilable/dtoh_AnonDeclaration.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_AnonDeclaration.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_AnonDeclaration.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/dtoh_ClassDeclaration.d b/test/compilable/dtoh_ClassDeclaration.d index 2586e6409fa3..4cc449eec33d 100644 --- a/test/compilable/dtoh_ClassDeclaration.d +++ b/test/compilable/dtoh_ClassDeclaration.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_ClassDeclaration.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_ClassDeclaration.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/dtoh_StructDeclaration.d b/test/compilable/dtoh_StructDeclaration.d index d9440337b8cc..865ad2b2d7d6 100644 --- a/test/compilable/dtoh_StructDeclaration.d +++ b/test/compilable/dtoh_StructDeclaration.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_StructDeclaration.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_StructDeclaration.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/dtoh_TemplateDeclaration.d b/test/compilable/dtoh_TemplateDeclaration.d index b5eb7be5bfee..913febe8a483 100644 --- a/test/compilable/dtoh_TemplateDeclaration.d +++ b/test/compilable/dtoh_TemplateDeclaration.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_TemplateDeclaration.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_TemplateDeclaration.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/dtoh_VarDeclaration.d b/test/compilable/dtoh_VarDeclaration.d index 0f249e9b9e0a..7eba8a59a50e 100644 --- a/test/compilable/dtoh_VarDeclaration.d +++ b/test/compilable/dtoh_VarDeclaration.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_VarDeclaration.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_VarDeclaration.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/dtoh_enum.d b/test/compilable/dtoh_enum.d index 66fcfd7c1c5f..f1ec65fd903f 100644 --- a/test/compilable/dtoh_enum.d +++ b/test/compilable/dtoh_enum.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_enum.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_enum.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/dtoh_functions.d b/test/compilable/dtoh_functions.d index 07a3225fa37b..87b74e802ce2 100644 --- a/test/compilable/dtoh_functions.d +++ b/test/compilable/dtoh_functions.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_functions.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_functions.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/dtoh_unittest_block.d b/test/compilable/dtoh_unittest_block.d index da9fc0c5d276..e3bd47cc4f51 100644 --- a/test/compilable/dtoh_unittest_block.d +++ b/test/compilable/dtoh_unittest_block.d @@ -1,4 +1,4 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_unittest_block.out -c +// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_unittest_block.h -c // PERMUTE_ARGS: // POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh diff --git a/test/compilable/extra-files/dtoh-postscript.sh b/test/compilable/extra-files/dtoh-postscript.sh index 92c7f50e2645..dd3bed1b763d 100644 --- a/test/compilable/extra-files/dtoh-postscript.sh +++ b/test/compilable/extra-files/dtoh-postscript.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -diff -pu --strip-trailing-cr ${EXTRA_FILES}/${TEST_NAME}.out ${OUTPUT_BASE}.out +diff -pu --strip-trailing-cr ${EXTRA_FILES}/${TEST_NAME}.h ${OUTPUT_BASE}.h -rm -f ${OUTPUT_BASE}.out +rm -f ${OUTPUT_BASE}.h diff --git a/test/compilable/extra-files/dtoh_AliasDeclaration.out b/test/compilable/extra-files/dtoh_AliasDeclaration.h similarity index 100% rename from test/compilable/extra-files/dtoh_AliasDeclaration.out rename to test/compilable/extra-files/dtoh_AliasDeclaration.h diff --git a/test/compilable/extra-files/dtoh_AnonDeclaration.out b/test/compilable/extra-files/dtoh_AnonDeclaration.h similarity index 100% rename from test/compilable/extra-files/dtoh_AnonDeclaration.out rename to test/compilable/extra-files/dtoh_AnonDeclaration.h diff --git a/test/compilable/extra-files/dtoh_ClassDeclaration.out b/test/compilable/extra-files/dtoh_ClassDeclaration.h similarity index 100% rename from test/compilable/extra-files/dtoh_ClassDeclaration.out rename to test/compilable/extra-files/dtoh_ClassDeclaration.h diff --git a/test/compilable/extra-files/dtoh_StructDeclaration.out b/test/compilable/extra-files/dtoh_StructDeclaration.h similarity index 100% rename from test/compilable/extra-files/dtoh_StructDeclaration.out rename to test/compilable/extra-files/dtoh_StructDeclaration.h diff --git a/test/compilable/extra-files/dtoh_TemplateDeclaration.out b/test/compilable/extra-files/dtoh_TemplateDeclaration.h similarity index 100% rename from test/compilable/extra-files/dtoh_TemplateDeclaration.out rename to test/compilable/extra-files/dtoh_TemplateDeclaration.h diff --git a/test/compilable/extra-files/dtoh_VarDeclaration.out b/test/compilable/extra-files/dtoh_VarDeclaration.h similarity index 100% rename from test/compilable/extra-files/dtoh_VarDeclaration.out rename to test/compilable/extra-files/dtoh_VarDeclaration.h diff --git a/test/compilable/extra-files/dtoh_enum.out b/test/compilable/extra-files/dtoh_enum.h similarity index 100% rename from test/compilable/extra-files/dtoh_enum.out rename to test/compilable/extra-files/dtoh_enum.h diff --git a/test/compilable/extra-files/dtoh_functions.out b/test/compilable/extra-files/dtoh_functions.h similarity index 100% rename from test/compilable/extra-files/dtoh_functions.out rename to test/compilable/extra-files/dtoh_functions.h diff --git a/test/compilable/extra-files/dtoh_unittest_block.out b/test/compilable/extra-files/dtoh_unittest_block.h similarity index 100% rename from test/compilable/extra-files/dtoh_unittest_block.out rename to test/compilable/extra-files/dtoh_unittest_block.h From b66e26569482e545019c0cbf27c3fab4997c9dc0 Mon Sep 17 00:00:00 2001 From: MoonlightSentinel Date: Tue, 18 Feb 2020 17:35:13 +0100 Subject: [PATCH 4/7] Replace `version (BUILD_COMPILER)` with a runtime check --- src/dmd/dtoh.d | 308 +++++++++++++++++++++++-------------------------- 1 file changed, 143 insertions(+), 165 deletions(-) diff --git a/src/dmd/dtoh.d b/src/dmd/dtoh.d index 9ff846d0f30b..00a96ddf753e 100644 --- a/src/dmd/dtoh.d +++ b/src/dmd/dtoh.d @@ -35,6 +35,7 @@ import dmd.root.outbuffer; import dmd.utils; //debug = Debug_DtoH; +enum isBuildingCompiler = false; private struct DMDType { @@ -43,11 +44,8 @@ private struct DMDType __gshared Identifier c_longlong; __gshared Identifier c_ulonglong; __gshared Identifier c_long_double; - //version(BUILD_COMPILER) - //{ - __gshared Identifier AssocArray; - __gshared Identifier Array; - //} + __gshared Identifier AssocArray; + __gshared Identifier Array; static void _init() { @@ -56,138 +54,137 @@ private struct DMDType c_longlong = Identifier.idPool("__c_longlong"); c_ulonglong = Identifier.idPool("__c_ulonglong"); c_long_double = Identifier.idPool("__c_long_double"); - //version(BUILD_COMPILER) - //{ + + if (isBuildingCompiler) + { AssocArray = Identifier.idPool("AssocArray"); Array = Identifier.idPool("Array"); - //} + } } } -//version(BUILD_COMPILER) -//{ - private struct DMDModule + +private struct DMDModule +{ + __gshared Identifier identifier; + __gshared Identifier root; + __gshared Identifier visitor; + __gshared Identifier parsetimevisitor; + __gshared Identifier permissivevisitor; + __gshared Identifier strictvisitor; + __gshared Identifier transitivevisitor; + __gshared Identifier dmd; + static void _init() { - __gshared Identifier identifier; - __gshared Identifier root; - __gshared Identifier visitor; - __gshared Identifier parsetimevisitor; - __gshared Identifier permissivevisitor; - __gshared Identifier strictvisitor; - __gshared Identifier transitivevisitor; - __gshared Identifier dmd; - static void _init() - { - identifier = Identifier.idPool("identifier"); - root = Identifier.idPool("root"); - visitor = Identifier.idPool("visitor"); - parsetimevisitor = Identifier.idPool("parsetimevisitor"); - permissivevisitor = Identifier.idPool("permissivevisitor"); - strictvisitor = Identifier.idPool("strictvisitor"); - transitivevisitor = Identifier.idPool("transitivevisitor"); - dmd = Identifier.idPool("dmd"); - } + identifier = Identifier.idPool("identifier"); + root = Identifier.idPool("root"); + visitor = Identifier.idPool("visitor"); + parsetimevisitor = Identifier.idPool("parsetimevisitor"); + permissivevisitor = Identifier.idPool("permissivevisitor"); + strictvisitor = Identifier.idPool("strictvisitor"); + transitivevisitor = Identifier.idPool("transitivevisitor"); + dmd = Identifier.idPool("dmd"); } +} - private struct DMDClass +private struct DMDClass +{ + __gshared Identifier ID; ////Identifier + __gshared Identifier Visitor; + __gshared Identifier ParseTimeVisitor; + static void _init() { - __gshared Identifier ID; ////Identifier - __gshared Identifier Visitor; - __gshared Identifier ParseTimeVisitor; - static void _init() - { - ID = Identifier.idPool("Identifier"); - Visitor = Identifier.idPool("Visitor"); - ParseTimeVisitor = Identifier.idPool("ParseTimeVisitor"); - } - + ID = Identifier.idPool("Identifier"); + Visitor = Identifier.idPool("Visitor"); + ParseTimeVisitor = Identifier.idPool("ParseTimeVisitor"); } - private bool isIdentifierClass(ASTCodegen.ClassDeclaration cd) +} + +private bool isIdentifierClass(ASTCodegen.ClassDeclaration cd) +{ + return (cd.ident == DMDClass.ID && + cd.parent !is null && + cd.parent.ident == DMDModule.identifier && + cd.parent.parent && cd.parent.parent.ident == DMDModule.dmd && + !cd.parent.parent.parent); +} + +private bool isVisitorClass(ASTCodegen.ClassDeclaration cd) +{ + for (auto cdb = cd; cdb; cdb = cdb.baseClass) { - return (cd.ident == DMDClass.ID && - cd.parent !is null && - cd.parent.ident == DMDModule.identifier && - cd.parent.parent && cd.parent.parent.ident == DMDModule.dmd && - !cd.parent.parent.parent); + if (cdb.ident == DMDClass.Visitor || + cdb.ident == DMDClass.ParseTimeVisitor) + return true; } + return false; +} + +private bool isIgnoredModule(ASTCodegen.Module m) +{ + //if (!m || !m.parent) + if (!m) + return true; - private bool isVisitorClass(ASTCodegen.ClassDeclaration cd) + // Ignore dmd.root + if (m.parent && m.parent.ident == DMDModule.root && + m.parent.parent && m.parent.parent.ident == DMDModule.dmd && + !m.parent.parent.parent) { - for (auto cdb = cd; cdb; cdb = cdb.baseClass) - { - if (cdb.ident == DMDClass.Visitor || - cdb.ident == DMDClass.ParseTimeVisitor) - return true; - } - return false; + return true; } - private bool isIgnoredModule(ASTCodegen.Module m) + // Ignore dmd.visitor and derivatives + if ((m.ident == DMDModule.visitor || + m.ident == DMDModule.parsetimevisitor || + m.ident == DMDModule.permissivevisitor || + m.ident == DMDModule.strictvisitor || + m.ident == DMDModule.transitivevisitor) && + m.parent && m.parent.ident == DMDModule.dmd && + !m.parent.parent) { - //if (!m || !m.parent) - if (!m) - return true; + return true; + } + return false; +} - // Ignore dmd.root - if (m.parent && m.parent.ident == DMDModule.root && - m.parent.parent && m.parent.parent.ident == DMDModule.dmd && - !m.parent.parent.parent) - { - return true; - } +private bool isFrontendModule(ASTCodegen.Module m) +{ + if (!m || !m.parent) + return false; - // Ignore dmd.visitor and derivatives - if ((m.ident == DMDModule.visitor || - m.ident == DMDModule.parsetimevisitor || - m.ident == DMDModule.permissivevisitor || - m.ident == DMDModule.strictvisitor || - m.ident == DMDModule.transitivevisitor) && - m.parent && m.parent.ident == DMDModule.dmd && - !m.parent.parent) - { - return true; - } + // Ignore dmd.root + if (m.parent.ident == DMDModule.root && + m.parent.parent && m.parent.parent.ident == DMDModule.dmd && + !m.parent.parent.parent) + { return false; } - private bool isFrontendModule(ASTCodegen.Module m) + // Ignore dmd.visitor and derivatives + if ((m.ident == DMDModule.visitor || + m.ident == DMDModule.parsetimevisitor || + m.ident == DMDModule.permissivevisitor || + m.ident == DMDModule.strictvisitor || + m.ident == DMDModule.transitivevisitor) && + m.parent && m.parent.ident == DMDModule.dmd && + !m.parent.parent) { - if (!m || !m.parent) - return false; - - // Ignore dmd.root - if (m.parent.ident == DMDModule.root && - m.parent.parent && m.parent.parent.ident == DMDModule.dmd && - !m.parent.parent.parent) - { - return false; - } - - // Ignore dmd.visitor and derivatives - if ((m.ident == DMDModule.visitor || - m.ident == DMDModule.parsetimevisitor || - m.ident == DMDModule.permissivevisitor || - m.ident == DMDModule.strictvisitor || - m.ident == DMDModule.transitivevisitor) && - m.parent && m.parent.ident == DMDModule.dmd && - !m.parent.parent) - { - return false; - } - return ((m.parent.ident == DMDModule.dmd && !m.parent.parent) || - (m.parent.parent.ident == DMDModule.dmd && !m.parent.parent.parent)); + return false; } -//} + return ((m.parent.ident == DMDModule.dmd && !m.parent.parent) || + (m.parent.parent.ident == DMDModule.dmd && !m.parent.parent.parent)); +} void genCppHdrFiles(ref Modules ms) { DMDType._init(); - //version(BUILD_COMPILER) - //{ + if (isBuildingCompiler) + { DMDModule._init(); DMDClass._init(); - //} + } OutBuffer buf; buf.writestring("#pragma once\n"); @@ -325,13 +322,11 @@ public: printf("[AST.Dsymbol enter] %s\n", s.toChars()); scope(exit) printf("[AST.Dsymbol exit] %s\n", s.toChars()); } - version(BUILD_COMPILER) + + if (isBuildingCompiler && s.getModule() && s.getModule().isFrontendModule()) { - if (s.getModule() && s.getModule().isFrontendModule()) - { - indent(); - buf.printf("// ignored %s %s\n", s.kind(), s.toPrettyChars()); - } + indent(); + buf.printf("// ignored %s %s\n", s.kind(), s.toPrettyChars()); } } @@ -407,11 +402,8 @@ public: } if (cast(void*)fd in visited) return; - //version(BUILD_COMPILER) - //{ - if (fd.getModule() && fd.getModule().isIgnoredModule()) - return; - //} + if (isBuildingCompiler && fd.getModule() && fd.getModule().isIgnoredModule()) + return; // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars()); visited[cast(void*)fd] = true; @@ -510,11 +502,8 @@ public: } if (cast(void*)vd in visited) return; - //version(BUILD_COMPILER) - //{ - if (vd.getModule() && vd.getModule().isIgnoredModule()) - return; - //} + if (isBuildingCompiler && vd.getModule() && vd.getModule().isIgnoredModule()) + return; visited[cast(void*)vd] = true; @@ -625,11 +614,8 @@ public: printf("[AST.AliasDeclaration enter] %s\n", ad.toChars()); scope(exit) printf("[AST.AliasDeclaration exit] %s\n", ad.toChars()); } - //version(BUILD_COMPILER) - //{ - if (ad.getModule() && ad.getModule().isIgnoredModule()) - return; - //} + if (isBuildingCompiler && ad.getModule() && ad.getModule().isIgnoredModule()) + return; if (auto t = ad.type) { @@ -720,11 +706,8 @@ public: return; if (!sd.type || !sd.type.deco) return; - //version(BUILD_COMPILER) - //{ - if (sd.getModule() && sd.getModule().isIgnoredModule()) - return; - //} + if (isBuildingCompiler && sd.getModule() && sd.getModule().isIgnoredModule()) + return; visited[cast(void*)sd] = true; if (linkage != LINK.c && linkage != LINK.cpp) @@ -903,13 +886,13 @@ public: } if (cast(void*)cd in visited) return; - //version(BUILD_COMPILER) - //{ + if (isBuildingCompiler) + { if (cd.getModule() && cd.getModule().isIgnoredModule()) return; if (cd.isVisitorClass()) return; - //} + } visited[cast(void*)cd] = true; if (!cd.isCPPclass()) @@ -941,14 +924,12 @@ public: m.accept(this); } adparent = save; - //version(BUILD_COMPILER) - //{ - // Generate special static inline function. - if (cd.isIdentifierClass()) - { - buf.writestring(" static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); }\n"); - } - //} + + // Generate special static inline function. + if (isBuildingCompiler && cd.isIdentifierClass()) + { + buf.writestring(" static inline Identifier *idPool(const char *s) { return idPool(s, strlen(s)); }\n"); + } buf.writestring("};\n\n"); } @@ -963,11 +944,8 @@ public: if (cast(void*)ed in visited) return; - //version(BUILD_COMPILER) - //{ - if (ed.getModule() && ed.getModule().isIgnoredModule()) - return; - //} + if (isBuildingCompiler && ed.getModule() && ed.getModule().isIgnoredModule()) + return; visited[cast(void*)ed] = true; @@ -1313,8 +1291,10 @@ public: printf("[visitTi(AST.TemplateInstance) enter] %s\n", ti.toChars()); scope(exit) printf("[visitTi(AST.TemplateInstance) exit] %s\n", ti.toChars()); } - //version(BUILD_COMPILER) - //{ + + // FIXME: Restricting this to DMD seems wrong ... + if (isBuildingCompiler) + { if (ti.tempdecl.ident == DMDType.AssocArray) { if (!forwardedAA) @@ -1338,16 +1318,16 @@ public: } buf.writestring(ti.tempdecl.ident.toChars()); } - //} - //else - //{ - //foreach (o; *ti.tiargs) - //{ - //if (!AST.isType(o)) - //return; - //} - //buf.writestring(ti.tempdecl.ident.toChars()); - //} + } + else + { + foreach (o; *ti.tiargs) + { + if (!AST.isType(o)) + return; + } + buf.writestring(ti.tempdecl.ident.toChars()); + } buf.writeByte('<'); foreach (i, o; *ti.tiargs) { @@ -1377,11 +1357,9 @@ public: if (cast(void*)td in visited) return; visited[cast(void*)td] = true; - //version(BUILD_COMPILER) - //{ - if (td.getModule() && td.getModule().isIgnoredModule()) - return; - //} + + if (isBuildingCompiler && td.getModule() && td.getModule().isIgnoredModule()) + return; if (!td.parameters || !td.onemember || !td.onemember.isStructDeclaration()) { From 4b4172b0e7ec158df7722101c947e78d6a14cd82 Mon Sep 17 00:00:00 2001 From: MoonlightSentinel Date: Wed, 19 Feb 2020 20:47:26 +0100 Subject: [PATCH 5/7] Move extra header files into TEST_OUTPUT --- test/compilable/dtoh_AliasDeclaration.d | 67 ++++++++++- test/compilable/dtoh_AnonDeclaration.d | 53 +++++++- test/compilable/dtoh_ClassDeclaration.d | 108 ++++++++++++++++- test/compilable/dtoh_StructDeclaration.d | 113 +++++++++++++++++- test/compilable/dtoh_TemplateDeclaration.d | 50 +++++++- test/compilable/dtoh_VarDeclaration.d | 53 +++++++- test/compilable/dtoh_enum.d | 42 ++++++- test/compilable/dtoh_functions.d | 51 +++++++- test/compilable/dtoh_unittest_block.d | 37 +++++- .../compilable/extra-files/dtoh-postscript.sh | 5 - .../extra-files/dtoh_AliasDeclaration.h | 61 ---------- .../extra-files/dtoh_AnonDeclaration.h | 48 -------- .../extra-files/dtoh_ClassDeclaration.h | 103 ---------------- .../extra-files/dtoh_StructDeclaration.h | 108 ----------------- .../extra-files/dtoh_TemplateDeclaration.h | 45 ------- .../extra-files/dtoh_VarDeclaration.h | 48 -------- test/compilable/extra-files/dtoh_enum.h | 37 ------ test/compilable/extra-files/dtoh_functions.h | 46 ------- .../extra-files/dtoh_unittest_block.h | 31 ----- 19 files changed, 538 insertions(+), 568 deletions(-) delete mode 100644 test/compilable/extra-files/dtoh-postscript.sh delete mode 100644 test/compilable/extra-files/dtoh_AliasDeclaration.h delete mode 100644 test/compilable/extra-files/dtoh_AnonDeclaration.h delete mode 100644 test/compilable/extra-files/dtoh_ClassDeclaration.h delete mode 100644 test/compilable/extra-files/dtoh_StructDeclaration.h delete mode 100644 test/compilable/extra-files/dtoh_TemplateDeclaration.h delete mode 100644 test/compilable/extra-files/dtoh_VarDeclaration.h delete mode 100644 test/compilable/extra-files/dtoh_enum.h delete mode 100644 test/compilable/extra-files/dtoh_functions.h delete mode 100644 test/compilable/extra-files/dtoh_unittest_block.h diff --git a/test/compilable/dtoh_AliasDeclaration.d b/test/compilable/dtoh_AliasDeclaration.d index 7e6d3b593d46..1314e2b6b1db 100644 --- a/test/compilable/dtoh_AliasDeclaration.d +++ b/test/compilable/dtoh_AliasDeclaration.d @@ -1,10 +1,69 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_AliasDeclaration.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_AliasDeclaration +struct S; +struct S2; +class C; +class C2; +typedef _d_int T; + +extern "C" _d_int x; + +// ignored variable dtoh_AliasDeclaration.x +extern "C" _d_int foo(_d_int x); + +// ignored function dtoh_AliasDeclaration.foo +extern _d_int foo2(_d_int x); + +// ignored function dtoh_AliasDeclaration.foo2 +struct S; + +typedef S aliasS; + +struct S2; + +typedef S2 aliasS2; + +// ignoring non-cpp class C +typedef C* aliasC; + +class C2; + +typedef C2* aliasC2; + --- */ diff --git a/test/compilable/dtoh_AnonDeclaration.d b/test/compilable/dtoh_AnonDeclaration.d index 2cc36cb03407..c55b07638037 100644 --- a/test/compilable/dtoh_AnonDeclaration.d +++ b/test/compilable/dtoh_AnonDeclaration.d @@ -1,10 +1,55 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_AnonDeclaration.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_AnonDeclaration +struct S +{ + union + { + _d_int x; + _d_char c[4$?:32=u|64=LLU$]; + }; + struct + { + _d_int y; + _d_double z; + extern "C" _d_void foo(); + _d_void bar(); + }; + S() {} +}; --- */ diff --git a/test/compilable/dtoh_ClassDeclaration.d b/test/compilable/dtoh_ClassDeclaration.d index 4cc449eec33d..2e2a65eb9de2 100644 --- a/test/compilable/dtoh_ClassDeclaration.d +++ b/test/compilable/dtoh_ClassDeclaration.d @@ -1,10 +1,110 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_ClassDeclaration.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_ClassDeclaration +class C; +class A; +struct Inner; +class C +{ +public: + _d_byte a; + _d_int b; + _d_long c; +}; + +class C2 +{ +public: + _d_int a; + _d_int b; + _d_long c; + C2(_d_int a); +}; + +// ignoring non-cpp class C3 +class Aligned +{ +public: + _d_byte a; + _d_int b; + _d_long c; + Aligned(_d_int a); +}; + +class A +{ +public: + _d_int a; + C* c; + virtual _d_void foo(); + extern "C" virtual _d_void bar(); + virtual _d_void baz(_d_int x = 42); + struct + { + _d_int x; + _d_int y; + }; + union + { + _d_int u1; + _d_char u2[4$?:32=u|64=LLU$]; + }; +struct Inner +{ + _d_int x; + Inner() : x() {} +}; + +class InnerC +{ +public: + _d_int x; +}; + +class NonStaticInnerC +{ +public: + _d_int x; + A* this; +}; + +typedef Inner I; +class CC; + +}; --- */ diff --git a/test/compilable/dtoh_StructDeclaration.d b/test/compilable/dtoh_StructDeclaration.d index 865ad2b2d7d6..ec31b974f003 100644 --- a/test/compilable/dtoh_StructDeclaration.d +++ b/test/compilable/dtoh_StructDeclaration.d @@ -1,10 +1,115 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_StructDeclaration.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_StructDeclaration +struct S; +struct Inner; +struct S +{ + _d_byte a; + _d_int b; + _d_long c; + S() : a(), b(), c() {} +}; + +struct S2 +{ + _d_int a; + _d_int b; + _d_long c; + S2(_d_int a); + S2() : a(42), b(), c() {} +}; + +struct S3 +{ + _d_int a; + _d_int b; + _d_long c; + extern "C" S3(_d_int a); + S3() : a(42), b(), c() {} +}; + +struct +#if defined(__GNUC__) || defined(__clang__) + __attribute__((packed, aligned(1))) +#elif defined(_MSC_VER) + __declspec(align(1)) +#elif defined(__DMC__) + #pragma pack(push, 1) +#endif +Aligned +{ + _d_byte a; + _d_int b; + _d_long c; + Aligned(_d_int a); + Aligned() : a(), b(), c() {} +}; +#if defined(__DMC__) + #pragma pack(pop) +#endif + +struct A +{ + _d_int a; + S s; + // ignoring extern () block because of linkage + extern "C" _d_void bar(); + _d_void baz(_d_int x = 42); + struct + { + _d_int x; + _d_int y; + }; + union + { + _d_int u1; + _d_char u2[4$?:32=u|64=LLU$]; + }; +struct Inner +{ + _d_int x; + Inner() : x() {} +}; + +typedef Inner I; +class C; + + A() : a(), s() {} +}; --- */ diff --git a/test/compilable/dtoh_TemplateDeclaration.d b/test/compilable/dtoh_TemplateDeclaration.d index 913febe8a483..857d1a214099 100644 --- a/test/compilable/dtoh_TemplateDeclaration.d +++ b/test/compilable/dtoh_TemplateDeclaration.d @@ -1,10 +1,52 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_TemplateDeclaration.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_TemplateDeclaration +template +struct A +{ + // Ignoring var x alignment 0 + T x; + // ignoring function foo because semantic hasn't been run +}; + +struct B +{ + A<_d_int> x; + B() : x() {} +}; --- */ diff --git a/test/compilable/dtoh_VarDeclaration.d b/test/compilable/dtoh_VarDeclaration.d index 7eba8a59a50e..545564833d19 100644 --- a/test/compilable/dtoh_VarDeclaration.d +++ b/test/compilable/dtoh_VarDeclaration.d @@ -1,10 +1,55 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_VarDeclaration.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_VarDeclaration +// ignoring variable dtoh_VarDeclaration.x because of linkage +// ignoring variable dtoh_VarDeclaration.y because of linkage +extern "C" _d_int z; + +extern _d_int t; + +struct S; + +struct S2; + +// ignoring non-cpp class C +class C2; + +union U; + +union U2; --- */ diff --git a/test/compilable/dtoh_enum.d b/test/compilable/dtoh_enum.d index f1ec65fd903f..0e3381fce2c5 100644 --- a/test/compilable/dtoh_enum.d +++ b/test/compilable/dtoh_enum.d @@ -1,10 +1,44 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_enum.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_enum +enum Dummy +{ + DUMMYOne = 0, + DUMMYTwo = 1 +}; --- */ diff --git a/test/compilable/dtoh_functions.d b/test/compilable/dtoh_functions.d index 87b74e802ce2..5071bd7206eb 100644 --- a/test/compilable/dtoh_functions.d +++ b/test/compilable/dtoh_functions.d @@ -1,10 +1,53 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_functions.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_functions +// ignoring function dtoh_functions.foo because of linkage +// ignoring function dtoh_functions.fun because it's extern +// ignoring function dtoh_functions.fun2 because it's extern +extern "C" _d_int bar(_d_int x); + +extern "C" _d_int bar2(_d_int x); + +extern "C" _d_int bar4(_d_int x = 42); + +extern _d_int baz(_d_int x); + +extern _d_int baz2(_d_int x); + +extern _d_int baz3(_d_int x = 42); --- */ diff --git a/test/compilable/dtoh_unittest_block.d b/test/compilable/dtoh_unittest_block.d index e3bd47cc4f51..965c66ae34ba 100644 --- a/test/compilable/dtoh_unittest_block.d +++ b/test/compilable/dtoh_unittest_block.d @@ -1,10 +1,39 @@ -// REQUIRED_ARGS: -HCf=${RESULTS_DIR}/compilable/dtoh_unittest_block.h -c -// PERMUTE_ARGS: -// POST_SCRIPT: compilable/extra-files/dtoh-postscript.sh - /* +REQUIRED_ARGS: -HC -c -o- +PERMUTE_ARGS: TEST_OUTPUT: --- +#pragma once + +// Automatically generated by dmd -HC + +#include +#include +#include +#include + +#define _d_void void +#define _d_bool bool +#define _d_byte signed char +#define _d_ubyte unsigned char +#define _d_short short +#define _d_ushort unsigned short +#define _d_int int +#define _d_uint unsigned +#define _d_long $?:32=long long|64=long$ +#define _d_ulong unsigned $?:32=long long|64=long$ +#define _d_float float +#define _d_double double +#define _d_real long double +#define _d_char char +#define _d_wchar wchar_t +#define _d_dchar unsigned +typedef _d_long d_int64; + +#define _d_null NULL + + +// Parsing module dtoh_unittest_block --- */ diff --git a/test/compilable/extra-files/dtoh-postscript.sh b/test/compilable/extra-files/dtoh-postscript.sh deleted file mode 100644 index dd3bed1b763d..000000000000 --- a/test/compilable/extra-files/dtoh-postscript.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -diff -pu --strip-trailing-cr ${EXTRA_FILES}/${TEST_NAME}.h ${OUTPUT_BASE}.h - -rm -f ${OUTPUT_BASE}.h diff --git a/test/compilable/extra-files/dtoh_AliasDeclaration.h b/test/compilable/extra-files/dtoh_AliasDeclaration.h deleted file mode 100644 index ed59bb2ab7ff..000000000000 --- a/test/compilable/extra-files/dtoh_AliasDeclaration.h +++ /dev/null @@ -1,61 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_AliasDeclaration -struct S; -struct S2; -class C; -class C2; -typedef _d_int T; - -extern "C" _d_int x; - -// ignored variable dtoh_AliasDeclaration.x -extern "C" _d_int foo(_d_int x); - -// ignored function dtoh_AliasDeclaration.foo -extern _d_int foo2(_d_int x); - -// ignored function dtoh_AliasDeclaration.foo2 -struct S; - -typedef S aliasS; - -struct S2; - -typedef S2 aliasS2; - -// ignoring non-cpp class C -typedef C* aliasC; - -class C2; - -typedef C2* aliasC2; - diff --git a/test/compilable/extra-files/dtoh_AnonDeclaration.h b/test/compilable/extra-files/dtoh_AnonDeclaration.h deleted file mode 100644 index 4d959afb68db..000000000000 --- a/test/compilable/extra-files/dtoh_AnonDeclaration.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_AnonDeclaration -struct S -{ - union - { - _d_int x; - _d_char c[4LLU]; - }; - struct - { - _d_int y; - _d_double z; - extern "C" _d_void foo(); - _d_void bar(); - }; - S() {} -}; - diff --git a/test/compilable/extra-files/dtoh_ClassDeclaration.h b/test/compilable/extra-files/dtoh_ClassDeclaration.h deleted file mode 100644 index 21236d62e733..000000000000 --- a/test/compilable/extra-files/dtoh_ClassDeclaration.h +++ /dev/null @@ -1,103 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_ClassDeclaration -class C; -class A; -struct Inner; -class C -{ -public: - _d_byte a; - _d_int b; - _d_long c; -}; - -class C2 -{ -public: - _d_int a; - _d_int b; - _d_long c; - C2(_d_int a); -}; - -// ignoring non-cpp class C3 -class Aligned -{ -public: - _d_byte a; - _d_int b; - _d_long c; - Aligned(_d_int a); -}; - -class A -{ -public: - _d_int a; - C* c; - virtual _d_void foo(); - extern "C" virtual _d_void bar(); - virtual _d_void baz(_d_int x = 42); - struct - { - _d_int x; - _d_int y; - }; - union - { - _d_int u1; - _d_char u2[4LLU]; - }; -struct Inner -{ - _d_int x; - Inner() : x() {} -}; - -class InnerC -{ -public: - _d_int x; -}; - -class NonStaticInnerC -{ -public: - _d_int x; - A* this; -}; - -typedef Inner I; -class CC; - -}; - diff --git a/test/compilable/extra-files/dtoh_StructDeclaration.h b/test/compilable/extra-files/dtoh_StructDeclaration.h deleted file mode 100644 index 5ed37bf7d522..000000000000 --- a/test/compilable/extra-files/dtoh_StructDeclaration.h +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_StructDeclaration -struct S; -struct Inner; -struct S -{ - _d_byte a; - _d_int b; - _d_long c; - S() : a(), b(), c() {} -}; - -struct S2 -{ - _d_int a; - _d_int b; - _d_long c; - S2(_d_int a); - S2() : a(42), b(), c() {} -}; - -struct S3 -{ - _d_int a; - _d_int b; - _d_long c; - extern "C" S3(_d_int a); - S3() : a(42), b(), c() {} -}; - -struct -#if defined(__GNUC__) || defined(__clang__) - __attribute__((packed, aligned(1))) -#elif defined(_MSC_VER) - __declspec(align(1)) -#elif defined(__DMC__) - #pragma pack(push, 1) -#endif -Aligned -{ - _d_byte a; - _d_int b; - _d_long c; - Aligned(_d_int a); - Aligned() : a(), b(), c() {} -}; -#if defined(__DMC__) - #pragma pack(pop) -#endif - -struct A -{ - _d_int a; - S s; - // ignoring extern () block because of linkage - extern "C" _d_void bar(); - _d_void baz(_d_int x = 42); - struct - { - _d_int x; - _d_int y; - }; - union - { - _d_int u1; - _d_char u2[4LLU]; - }; -struct Inner -{ - _d_int x; - Inner() : x() {} -}; - -typedef Inner I; -class C; - - A() : a(), s() {} -}; - diff --git a/test/compilable/extra-files/dtoh_TemplateDeclaration.h b/test/compilable/extra-files/dtoh_TemplateDeclaration.h deleted file mode 100644 index c9d42e732592..000000000000 --- a/test/compilable/extra-files/dtoh_TemplateDeclaration.h +++ /dev/null @@ -1,45 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_TemplateDeclaration -template -struct A -{ - // Ignoring var x alignment 0 - T x; - // ignoring function foo because semantic hasn't been run -}; - -struct B -{ - A<_d_int> x; - B() : x() {} -}; - diff --git a/test/compilable/extra-files/dtoh_VarDeclaration.h b/test/compilable/extra-files/dtoh_VarDeclaration.h deleted file mode 100644 index eaced69390ea..000000000000 --- a/test/compilable/extra-files/dtoh_VarDeclaration.h +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_VarDeclaration -// ignoring variable dtoh_VarDeclaration.x because of linkage -// ignoring variable dtoh_VarDeclaration.y because of linkage -extern "C" _d_int z; - -extern _d_int t; - -struct S; - -struct S2; - -// ignoring non-cpp class C -class C2; - -union U; - -union U2; - diff --git a/test/compilable/extra-files/dtoh_enum.h b/test/compilable/extra-files/dtoh_enum.h deleted file mode 100644 index 6135d77a2767..000000000000 --- a/test/compilable/extra-files/dtoh_enum.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_enum -enum Dummy -{ - DUMMYOne = 0, - DUMMYTwo = 1 -}; - diff --git a/test/compilable/extra-files/dtoh_functions.h b/test/compilable/extra-files/dtoh_functions.h deleted file mode 100644 index d9d9260fed83..000000000000 --- a/test/compilable/extra-files/dtoh_functions.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_functions -// ignoring function dtoh_functions.foo because of linkage -// ignoring function dtoh_functions.fun because it's extern -// ignoring function dtoh_functions.fun2 because it's extern -extern "C" _d_int bar(_d_int x); - -extern "C" _d_int bar2(_d_int x); - -extern "C" _d_int bar4(_d_int x = 42); - -extern _d_int baz(_d_int x); - -extern _d_int baz2(_d_int x); - -extern _d_int baz3(_d_int x = 42); - diff --git a/test/compilable/extra-files/dtoh_unittest_block.h b/test/compilable/extra-files/dtoh_unittest_block.h deleted file mode 100644 index c6a05985e077..000000000000 --- a/test/compilable/extra-files/dtoh_unittest_block.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -// Automatically generated by dmd -HC - -#include -#include -#include -#include - -#define _d_void void -#define _d_bool bool -#define _d_byte signed char -#define _d_ubyte unsigned char -#define _d_short short -#define _d_ushort unsigned short -#define _d_int int -#define _d_uint unsigned -#define _d_long long -#define _d_ulong unsigned long -#define _d_float float -#define _d_double double -#define _d_real long double -#define _d_char char -#define _d_wchar wchar_t -#define _d_dchar unsigned -typedef _d_long d_int64; - -#define _d_null NULL - - -// Parsing module dtoh_unittest_block From 88fb68d1693871c2e2d366ef224d7479aa12c886 Mon Sep 17 00:00:00 2001 From: MoonlightSentinel Date: Wed, 19 Feb 2020 23:11:08 +0100 Subject: [PATCH 6/7] Apply further cleanup - remove unused variables - sort import in mars.d - remove unecessary braces - pointer style - replace duplication with goto - TODO comments for missing implementation - Replace Type[...].ty check + cast with isType[...] --- src/dmd/dtoh.d | 38 ++++++++++++++++---------------------- src/dmd/mars.d | 6 ++---- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/src/dmd/dtoh.d b/src/dmd/dtoh.d index 00a96ddf753e..c4600ecb1350 100644 --- a/src/dmd/dtoh.d +++ b/src/dmd/dtoh.d @@ -290,10 +290,10 @@ extern(C++) final class ToCppBuffer(AST) : Visitor public: bool[void*] visited; bool[void*] forwarded; - OutBuffer *fwdbuf; - OutBuffer *checkbuf; - OutBuffer *donebuf; - OutBuffer *buf; + OutBuffer* fwdbuf; + OutBuffer* checkbuf; + OutBuffer* donebuf; + OutBuffer* buf; AST.AggregateDeclaration adparent; AST.ClassDeclaration cdparent; AST.TemplateDeclaration tdparent; @@ -580,11 +580,10 @@ public: typeToBuffer(vd.type, vd.ident); cdparent = save; buf.writestring(";\n"); - if (vd.type.ty == AST.Tstruct) - { - auto t = cast(AST.TypeStruct)vd.type; + + if (auto t = vd.type.isTypeStruct()) includeSymbol(t.sym); - } + auto savex = buf; buf = checkbuf; buf.writestring(" assert(offsetof("); @@ -651,7 +650,7 @@ public: buf.printf("\n"); return; } - if (auto fd = ad.aliassym.isDtorDeclaration()) + if (ad.aliassym.isDtorDeclaration()) { // Ignore. It's taken care of while visiting FuncDeclaration return; @@ -1066,9 +1065,8 @@ public: buf.writestring(ident.toChars()); } this.ident = null; - if (t.ty == AST.Tsarray) + if (auto tsa = t.isTypeSArray()) { - auto tsa = cast(AST.TypeSArray)t; buf.writeByte('['); tsa.dim.accept(this); buf.writeByte(']'); @@ -1130,8 +1128,8 @@ public: printf("[AST.TypePointer enter] %s\n", t.toChars()); scope(exit) printf("[AST.TypePointer exit] %s\n", t.toChars()); } - if (t.next.ty == AST.Tstruct && - !strcmp((cast(AST.TypeStruct)t.next).sym.ident.toChars(), "__va_list_tag")) + auto ts = t.next.isTypeStruct(); + if (ts && !strcmp(ts.sym.ident.toChars(), "__va_list_tag")) { buf.writestring("va_list"); return; @@ -1310,17 +1308,11 @@ public: buf.writestring("Array"); } else - { - foreach (o; *ti.tiargs) - { - if (!AST.isType(o)) - return; - } - buf.writestring(ti.tempdecl.ident.toChars()); - } + goto LprintTypes; } else { + LprintTypes: foreach (o; *ti.tiargs) { if (!AST.isType(o)) @@ -1569,7 +1561,7 @@ public: if (e.sz == 2) buf.writeByte('L'); buf.writeByte('"'); - size_t o = buf.length; + for (size_t i = 0; i < e.len; i++) { uint c = e.charAt(i); @@ -1609,6 +1601,8 @@ public: printf("[AST.RealExp enter] %s\n", e.toChars()); scope(exit) printf("[AST.RealExp exit] %s\n", e.toChars()); } + + // TODO: Needs to implemented, used e.g. for struct member initializers buf.writestring("0"); } diff --git a/src/dmd/mars.d b/src/dmd/mars.d index 65319c9b0450..cb3cb2445015 100644 --- a/src/dmd/mars.d +++ b/src/dmd/mars.d @@ -36,6 +36,7 @@ import dmd.dmodule; import dmd.doc; import dmd.dsymbol; import dmd.dsymbolsem; +import dmd.dtoh; import dmd.errors; import dmd.expression; import dmd.globals; @@ -65,8 +66,6 @@ import dmd.semantic3; import dmd.target; import dmd.utils; -import dmd.dtoh; - /** * Print DMD's logo on stdout */ @@ -688,9 +687,8 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params) } if (global.params.doCxxHdrGeneration) - { genCppHdrFiles(modules); - } + if (global.errors) fatal(); From d0d5f08960f41c7d93c91b70121a54dc044d55ca Mon Sep 17 00:00:00 2001 From: MoonlightSentinel Date: Thu, 20 Feb 2020 00:51:08 +0100 Subject: [PATCH 7/7] Address wilzbach's review - Remove leftover comment - Guard against multiple initializations - Add a dshell test --- src/dmd/dtoh.d | 23 +++-- test/dshell/cpp_header_gen.d | 25 +++++ .../dshell/extra-files/cpp_header_gen/app.cpp | 45 +++++++++ .../extra-files/cpp_header_gen/library.d | 91 +++++++++++++++++++ 4 files changed, 178 insertions(+), 6 deletions(-) create mode 100644 test/dshell/cpp_header_gen.d create mode 100644 test/dshell/extra-files/cpp_header_gen/app.cpp create mode 100644 test/dshell/extra-files/cpp_header_gen/library.d diff --git a/src/dmd/dtoh.d b/src/dmd/dtoh.d index c4600ecb1350..869142211434 100644 --- a/src/dmd/dtoh.d +++ b/src/dmd/dtoh.d @@ -123,7 +123,6 @@ private bool isVisitorClass(ASTCodegen.ClassDeclaration cd) private bool isIgnoredModule(ASTCodegen.Module m) { - //if (!m || !m.parent) if (!m) return true; @@ -177,14 +176,26 @@ private bool isFrontendModule(ASTCodegen.Module m) (m.parent.parent.ident == DMDModule.dmd && !m.parent.parent.parent)); } -void genCppHdrFiles(ref Modules ms) +private void initialize() { - DMDType._init(); - if (isBuildingCompiler) + __gshared bool initialized; + + if (!initialized) { - DMDModule._init(); - DMDClass._init(); + initialized = true; + + DMDType._init(); + if (isBuildingCompiler) + { + DMDModule._init(); + DMDClass._init(); + } } +} + +void genCppHdrFiles(ref Modules ms) +{ + initialize(); OutBuffer buf; buf.writestring("#pragma once\n"); diff --git a/test/dshell/cpp_header_gen.d b/test/dshell/cpp_header_gen.d new file mode 100644 index 000000000000..235b6ba275b3 --- /dev/null +++ b/test/dshell/cpp_header_gen.d @@ -0,0 +1,25 @@ +module test.dshell.cpp_header_gen; + +import dshell; + +void main() +{ + if (OS != "linux") + { + writeln("CPP header generation test was skipped on non-linux platform."); + return; + } + + // FIXME: Should be a default variable + Vars.set("CC", "g++"); + + Vars.set("SOURCE_DIR", "$EXTRA_FILES/cpp_header_gen"); + Vars.set("LIB", "$OUTPUT_BASE/lib$LIBEXT"); + Vars.set("CPP_OBJ", "$OUTPUT_BASE/cpp.o"); + Vars.set("HEADER_EXE", "$OUTPUT_BASE/test"); + + run("$DMD -m$MODEL -c -lib -of=$LIB -HCf=$OUTPUT_BASE/library.h $SOURCE_DIR/library.d"); + run("$CC -m$MODEL -c -o $CPP_OBJ -I$OUTPUT_BASE -I$EXTRA_FILES/../../../src/dmd/root $SOURCE_DIR/app.cpp"); + run("$DMD -m$MODEL -conf= -defaultlib= -of=$HEADER_EXE $LIB $CPP_OBJ"); + run("$HEADER_EXE"); +} diff --git a/test/dshell/extra-files/cpp_header_gen/app.cpp b/test/dshell/extra-files/cpp_header_gen/app.cpp new file mode 100644 index 000000000000..de198810e236 --- /dev/null +++ b/test/dshell/extra-files/cpp_header_gen/app.cpp @@ -0,0 +1,45 @@ +// This should be solved by the header generator +#include "dcompat.h" +#include "library.h" + +#include + +int main() +{ + char name[] = "Header"; + const int length = sizeof(name) - 1; + + C* c = C::create(name, length); + assert(c); + assert(c->s.i == length); + assert(!c->s.b); + assert(c->name.ptr == name); + assert(c->name.length == length); + c->verify(); + + assert(foo(c->s) == bar(c)); + + c->s.multiply(c->s); + assert(c->s.i == length * length); + assert(c->s.b); + + U u; + u.b = false; + toggle(u); + assert(u.b); + + assert(3 <= PI && PI <= 4); + assert(counter = 42); + + // FIXME: Maybe improve naming convention or use enum class (C++11) + // assert(Weather::Sun != Weather::Rain); + // assert(Weather::Rain != Weather::Storm); + + assert(WEATHERSun != WEATHERRain); + assert(WEATHERRain != WEATHERStorm); + + S2 s2; + s2.s = c->s; + + return 0; +} diff --git a/test/dshell/extra-files/cpp_header_gen/library.d b/test/dshell/extra-files/cpp_header_gen/library.d new file mode 100644 index 000000000000..0500295988f5 --- /dev/null +++ b/test/dshell/extra-files/cpp_header_gen/library.d @@ -0,0 +1,91 @@ +module library; + +extern (C++): + +int foo(ref const S s) +{ + return s.i; +} + +int bar(const C c) +{ + return c.s.i; +} + +/* +// TODO: Seems not implemented yet +interface I +{ + void verify(); +} +*/ + +class C // : I +{ + S s; + char[] name; + + extern(D) this(ref S s, char[] name) + { + this.s = s; + this.name = name; + } + + static C create(char* name, const int length) + { + auto s = S(length, length & 1); + return new C(s, name[0 .. length]); + } + + void verify() + { + assert(s.i == 6); + assert(!s.b); + assert(name == "Header"); + } +} + +struct S +{ + int i; + bool b = true; + + void multiply(ref const S other) + { + i *= other.i; + b = b || !other.b; + } +} + +union U +{ + // int a; // FIXME: Generates struct constructor + // U() : a(), b() {} + bool b; +} + +void toggle(ref U u) +{ + u.b = !u.b; +} + +// FIXME: Generates non-existant global +// enum PI = 3.141; // extern _d_double PI; + +__gshared immutable PI = 3.141; +__gshared int counter = 42; + +enum Weather +{ + Sun, + Rain, + Storm +} + +static if (true) +{ + struct S2 + { + S s; + } +}