diff --git a/.circleci/config.yml b/.circleci/config.yml index 8a6dcdbf22b..1c05807c4e9 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -86,5 +86,8 @@ jobs: when: always - run: name: Run stdlib unittests - command: cd build && ctest -j3 --output-on-failure -E "dmd-testsuite|ldc2-unittest|lit-tests" + # FIXME: Exclude std.process unittests for now. + # CircleCI doesn't throw an expected ProcessException when spawning a + # process in a working dir with 0400 permissions (no search permissions). + command: cd build && ctest -j3 --output-on-failure -E "std\.process|dmd-testsuite|ldc2-unittest|lit-tests" when: always diff --git a/CMakeLists.txt b/CMakeLists.txt index ef8f78cf82e..0af3e7d2a75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,7 @@ endfunction() set(LDC_VERSION "1.5.0") # May be overridden by git hash tag set(DMDFE_MAJOR_VERSION 2) set(DMDFE_MINOR_VERSION 0) -set(DMDFE_PATCH_VERSION 74) +set(DMDFE_PATCH_VERSION 75) set(DMDFE_FIX_LEVEL 1) # Comment out if not used set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}${DMDFE_PATCH_VERSION}) diff --git a/appveyor.yml b/appveyor.yml index 4bdff989dfc..3979601f234 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -86,7 +86,7 @@ install: - make --version - cd .. # Download & extract a pre-built LLVM (CMAKE_BUILD_TYPE=Release, LLVM_ENABLE_ASSERTIONS=ON) - - appveyor DownloadFile "https://github.com/ldc-developers/llvm/releases/download/ldc-v4.0.1/appveyor-llvm-4.0.1-%APPVEYOR_JOB_ARCH%.7z" -FileName llvm.7z + - appveyor DownloadFile "https://github.com/ldc-developers/llvm/releases/download/ldc-v5.0.0/appveyor-llvm-5.0.0-%APPVEYOR_JOB_ARCH%.7z" -FileName llvm.7z - md llvm - cd llvm - 7z x ..\llvm.7z > nul diff --git a/ddmd/access.d b/ddmd/access.d index cbdf9e60364..0fa6d520c88 100644 --- a/ddmd/access.d +++ b/ddmd/access.d @@ -190,7 +190,7 @@ extern (C++) bool checkAccess(AggregateDeclaration ad, Loc loc, Scope* sc, Dsymb } if (!result) { - ad.error(loc, "member %s is not accessible", smember.toChars()); + ad.error(loc, "member `%s` is not accessible", smember.toChars()); //printf("smember = %s %s, prot = %d, semanticRun = %d\n", // smember.kind(), smember.toPrettyChars(), smember.prot(), smember.semanticRun); return true; @@ -412,7 +412,7 @@ extern (C++) bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d) { if (d.prot().kind == PROTprivate && d.getAccessModule() != sc._module || d.prot().kind == PROTpackage && !hasPackageAccess(sc, d)) { - error(loc, "%s %s is not accessible from module %s", d.kind(), d.toPrettyChars(), sc._module.toChars()); + error(loc, "%s `%s` is not accessible from module `%s`", d.kind(), d.toPrettyChars(), sc._module.toChars()); return true; } } @@ -448,7 +448,7 @@ extern (C++) bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d) * * Because a global symbol table tree is used for imported packages/modules, * access to them needs to be checked based on the imports in the scope chain - * (see Bugzilla 313). + * (see https://issues.dlang.org/show_bug.cgi?id=313). * */ extern (C++) bool checkAccess(Loc loc, Scope* sc, Package p) diff --git a/ddmd/aggregate.d b/ddmd/aggregate.d index de12c0c1611..10161aa1aa6 100644 --- a/ddmd/aggregate.d +++ b/ddmd/aggregate.d @@ -131,7 +131,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol // Might need a scope to resolve forward references. The check for // semanticRun prevents unnecessary setting of _scope during deferred // setScope phases for aggregates which already finished semantic(). - // Also see https://issues.dlang.org/show_bug.cgi?id=16607 + // See https://issues.dlang.org/show_bug.cgi?id=16607 if (semanticRun < PASSsemanticdone) ScopeDsymbol.setScope(sc); } @@ -164,7 +164,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol override final void semantic3(Scope* sc) { - //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type.toChars(), errors); + //printf("AggregateDeclaration::semantic3(sc=%p, %s) type = %s, errors = %d\n", sc, toChars(), type.toChars(), errors); if (!members) return; @@ -213,6 +213,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol } if (sd) sd.semanticTypeInfoMembers(); + semanticRun = PASSsemantic3done; } /*************************************** @@ -245,7 +246,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol auto ad = cast(AggregateDeclaration)param; - if (v._scope) + if (v.semanticRun < PASSsemanticdone) v.semantic(null); // Return in case a recursive determineFields triggered by v.semantic already finished if (ad.sizeok != SIZEOKnone) @@ -269,7 +270,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol if (ad == (cast(TypeStruct)tv).sym) { const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : ""; - ad.error("cannot have field %s with %ssame struct type", v.toChars(), psz); + ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz); ad.type = Type.terror; ad.errors = true; return 1; @@ -389,7 +390,10 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol { auto vd = fields[i]; if (vd.errors) + { + errors = true; continue; + } auto vx = vd; if (vd._init && vd._init.isVoidInitializer()) @@ -401,6 +405,11 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol if (i == j) continue; auto v2 = fields[j]; + if (v2.errors) + { + errors = true; + continue; + } if (!vd.isOverlappedWith(v2)) continue; @@ -420,7 +429,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol if (vx._init && v2._init) { - .error(loc, "overlapping default initialization for field %s and %s", v2.toChars(), vd.toChars()); + .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); errors = true; } } @@ -493,13 +502,13 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol } else if (v2._init) { - .error(loc, "overlapping initialization for field %s and %s", v2.toChars(), vd.toChars()); + .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); errors = true; } } else { - // Will fix Bugzilla 1432 by enabling this path always + // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always /* Prefer explicitly initialized field * union U { int a; int b = 2; } @@ -516,7 +525,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol } else if (vx._init && v2._init) { - .error(loc, "overlapping default initialization for field %s and %s", + .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); errors = true; } @@ -540,11 +549,12 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol { if ((vx.storage_class & STCnodefaultctor) && !ctorinit) { - .error(loc, "field %s.%s must be initialized because it has no default constructor", + .error(loc, "field `%s.%s` must be initialized because it has no default constructor", type.toChars(), vx.toChars()); errors = true; } - /* Bugzilla 12509: Get the element of static array type. + /* https://issues.dlang.org/show_bug.cgi?id=12509 + * Get the element of static array type. */ Type telem = vx.type; if (telem.ty == Tsarray) @@ -690,7 +700,8 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol { enclosing = fd; - /* Bugzilla 14422: If a nested class parent is a function, its + /* https://issues.dlang.org/show_bug.cgi?id=14422 + * If a nested class parent is a function, its * context pointer (== `outer`) should be void* always. */ t = Type.tvoidptr; diff --git a/ddmd/aggregate.h b/ddmd/aggregate.h index 8a271e50c28..324597370fd 100644 --- a/ddmd/aggregate.h +++ b/ddmd/aggregate.h @@ -275,11 +275,11 @@ class ClassDeclaration : public AggregateDeclaration TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration bool com; // true if this is a COM class (meaning it derives from IUnknown) bool cpp; // true if this is a C++ interface + bool isobjc; // true if this is an Objective-C class/interface bool isscope; // true if this is a scope class Abstract isabstract; // 0: fwdref, 1: is abstract class, 2: not abstract int inuse; // to prevent recursive attempts Baseok baseok; // set the progress of base classes resolving - Objc_ClassDeclaration objc; Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr Dsymbol *syntaxCopy(Dsymbol *s); diff --git a/ddmd/aliasthis.d b/ddmd/aliasthis.d index 5c4d604eba7..ffff343b376 100644 --- a/ddmd/aliasthis.d +++ b/ddmd/aliasthis.d @@ -41,19 +41,30 @@ extern (C++) final class AliasThis : Dsymbol override Dsymbol syntaxCopy(Dsymbol s) { assert(!s); - /* Since there is no semantic information stored here, - * we don't need to copy it. - */ - return this; + return new AliasThis(loc, ident); } override void semantic(Scope* sc) { + if (semanticRun != PASSinit) + return; + + if (_scope) + { + sc = _scope; + _scope = null; + } + + if (!sc) + return; + + semanticRun = PASSsemantic; + Dsymbol p = sc.parent.pastMixin(); AggregateDeclaration ad = p.isAggregateDeclaration(); if (!ad) { - .error(loc, "alias this can only be a member of aggregate, not %s %s", p.kind(), p.toChars()); + .error(loc, "alias this can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars()); return; } @@ -63,9 +74,9 @@ extern (C++) final class AliasThis : Dsymbol { s = sc.search(loc, ident, null); if (s) - .error(loc, "%s is not a member of %s", s.toChars(), ad.toChars()); + .error(loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars()); else - .error(loc, "undefined identifier %s", ident.toChars()); + .error(loc, "undefined identifier `%s`", ident.toChars()); return; } if (ad.aliasthis && s != ad.aliasthis) @@ -89,11 +100,12 @@ extern (C++) final class AliasThis : Dsymbol assert(t); if (ad.type.implicitConvTo(t) > MATCHnomatch) { - .error(loc, "alias this is not reachable as %s already converts to %s", ad.toChars(), t.toChars()); + .error(loc, "alias this is not reachable as `%s` already converts to `%s`", ad.toChars(), t.toChars()); } } ad.aliasthis = s; + semanticRun = PASSsemanticdone; } override const(char)* kind() const @@ -128,7 +140,8 @@ extern (C++) Expression resolveAliasThis(Scope* sc, Expression e, bool gag = fal { if (auto fd = (cast(VarExp)e).var.isFuncDeclaration()) { - // Bugzilla 13009: Support better match for the overloaded alias this. + // https://issues.dlang.org/show_bug.cgi?id=13009 + // Support better match for the overloaded alias this. bool hasOverloads; if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) { diff --git a/ddmd/arrayop.d b/ddmd/arrayop.d index bbfda6f2478..36d6d6097b4 100644 --- a/ddmd/arrayop.d +++ b/ddmd/arrayop.d @@ -388,7 +388,8 @@ extern (C++) void buildArrayIdent(Expression e, OutBuffer* buf, Expressions* arg (t2.ty == Tarray && !t1.equivalent(tb) || t2.ty != Tarray && !t1.nextOf().equivalent(e.e2.type))) { - // Bugzilla 12780: if A is narrower than B + // https://issues.dlang.org/show_bug.cgi?id=12780 + // if A is narrower than B: // A[] op B[] // A[] op B buf.writestring("Of"); @@ -399,7 +400,8 @@ extern (C++) void buildArrayIdent(Expression e, OutBuffer* buf, Expressions* arg (t1.ty == Tarray && !t2.equivalent(tb) || t1.ty != Tarray && !t2.nextOf().equivalent(e.e1.type))) { - // Bugzilla 12780: if B is narrower than A: + // https://issues.dlang.org/show_bug.cgi?id=12780 + // if B is narrower than A: // A[] op B[] // A op B[] buf.writestring("Of"); diff --git a/ddmd/astcodegen.d b/ddmd/astcodegen.d new file mode 100644 index 00000000000..ba9e2703d34 --- /dev/null +++ b/ddmd/astcodegen.d @@ -0,0 +1,86 @@ +module ddmd.astcodegen; + +struct ASTCodegen +{ + import ddmd.aggregate; + import ddmd.aliasthis; + import ddmd.arraytypes; + import ddmd.attrib; + import ddmd.cond; + import ddmd.dclass; + import ddmd.declaration; + import ddmd.denum; + import ddmd.dimport; + import ddmd.dmodule; + import ddmd.dstruct; + import ddmd.dsymbol; + import ddmd.dtemplate; + import ddmd.dversion; + import ddmd.expression; + import ddmd.func; + import ddmd.hdrgen; + import ddmd.init; + import ddmd.mtype; + import ddmd.nspace; + import ddmd.statement; + import ddmd.staticassert; + + alias UserAttributeDeclaration = ddmd.attrib.UserAttributeDeclaration; + + alias MODconst = ddmd.mtype.MODconst; + alias MODimmutable = ddmd.mtype.MODimmutable; + alias MODshared = ddmd.mtype.MODshared; + alias MODwild = ddmd.mtype.MODwild; + alias Type = ddmd.mtype.Type; + alias Tident = ddmd.mtype.Tident; + alias Tfunction = ddmd.mtype.Tfunction; + alias Parameter = ddmd.mtype.Parameter; + alias Taarray = ddmd.mtype.Taarray; + alias Tsarray = ddmd.mtype.Tsarray; + + alias STCconst = ddmd.declaration.STCconst; + alias STCimmutable = ddmd.declaration.STCimmutable; + alias STCshared = ddmd.declaration.STCshared; + alias STCwild = ddmd.declaration.STCwild; + alias STCin = ddmd.declaration.STCin; + alias STCout = ddmd.declaration.STCout; + alias STCref = ddmd.declaration.STCref; + alias STClazy = ddmd.declaration.STClazy; + alias STCscope = ddmd.declaration.STCscope; + alias STCfinal = ddmd.declaration.STCfinal; + alias STCauto = ddmd.declaration.STCauto; + alias STCreturn = ddmd.declaration.STCreturn; + alias STCmanifest = ddmd.declaration.STCmanifest; + alias STCgshared = ddmd.declaration.STCgshared; + alias STCtls = ddmd.declaration.STCtls; + alias STCsafe = ddmd.declaration.STCsafe; + alias STCsystem = ddmd.declaration.STCsystem; + alias STCtrusted = ddmd.declaration.STCtrusted; + alias STCnothrow = ddmd.declaration.STCnothrow; + alias STCpure = ddmd.declaration.STCpure; + alias STCproperty = ddmd.declaration.STCproperty; + alias STCnogc = ddmd.declaration.STCnogc; + alias STCdisable = ddmd.declaration.STCdisable; + alias STCundefined = ddmd.declaration.STCundefined; + alias STC_TYPECTOR = ddmd.declaration.STC_TYPECTOR; + alias STCoverride = ddmd.declaration.STCoverride; + alias STCabstract = ddmd.declaration.STCabstract; + alias STCsynchronized = ddmd.declaration.STCsynchronized; + alias STCdeprecated = ddmd.declaration.STCdeprecated; + alias STCstatic = ddmd.declaration.STCstatic; + alias STCextern = ddmd.declaration.STCextern; + + alias Dsymbol = ddmd.dsymbol.Dsymbol; + alias Dsymbols = ddmd.dsymbol.Dsymbols; + alias PROTprivate = ddmd.dsymbol.PROTprivate; + alias PROTpackage = ddmd.dsymbol.PROTpackage; + alias PROTprotected = ddmd.dsymbol.PROTprotected; + alias PROTpublic = ddmd.dsymbol.PROTpublic; + alias PROTexport = ddmd.dsymbol.PROTexport; + alias PROTundefined = ddmd.dsymbol.PROTundefined; + alias Prot = ddmd.dsymbol.Prot; + + alias stcToBuffer = ddmd.hdrgen.stcToBuffer; + alias linkageToChars = ddmd.hdrgen.linkageToChars; + alias protectionToChars = ddmd.hdrgen.protectionToChars; +} diff --git a/ddmd/attrib.d b/ddmd/attrib.d index 5359a60714a..612ae4ae296 100644 --- a/ddmd/attrib.d +++ b/ddmd/attrib.d @@ -14,6 +14,7 @@ import core.stdc.stdio; import core.stdc.string; import ddmd.aggregate; import ddmd.arraytypes; +import ddmd.astcodegen; import ddmd.cond; import ddmd.declaration; import ddmd.dinterpret; @@ -32,6 +33,7 @@ import ddmd.mtype; import ddmd.parse; import ddmd.root.outbuffer; import ddmd.root.rmem; +import ddmd.target; import ddmd.tokens; import ddmd.utf; import ddmd.utils; @@ -171,6 +173,9 @@ extern (C++) abstract class AttribDeclaration : Dsymbol override void semantic(Scope* sc) { + if (semanticRun != PASSinit) + return; + semanticRun = PASSsemantic; Dsymbols* d = include(sc, null); //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); if (d) @@ -184,6 +189,7 @@ extern (C++) abstract class AttribDeclaration : Dsymbol if (sc2 != sc) sc2.pop(); } + semanticRun = PASSsemanticdone; } override void semantic2(Scope* sc) @@ -500,7 +506,7 @@ extern (C++) final class LinkDeclaration : AttribDeclaration { super(decl); //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = p; + linkage = (p == LINKsystem) ? Target.systemLinkage() : p; } override Dsymbol syntaxCopy(Dsymbol s) @@ -808,7 +814,8 @@ extern (C++) final class AnonDeclaration : AttribDeclaration offset = 0; } - /* Bugzilla 13613: If the fields in this.members had been already + /* https://issues.dlang.org/show_bug.cgi?id=13613 + * If the fields in this.members had been already * added in ad.fields, just update *poffset for the subsequent * field offset calculation. */ @@ -1021,7 +1028,7 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration error("function name expected for start address"); else { - /* Bugzilla 11980: + /* https://issues.dlang.org/show_bug.cgi?id=11980 * resolveProperties and ctfeInterpret call are not necessary. */ Expression e = (*args)[0]; @@ -1438,7 +1445,7 @@ extern (C++) final class CompileDeclaration : AttribDeclaration se = se.toUTF8(sc); uint errors = global.errors; - scope Parser p = new Parser(loc, sc._module, se.toStringz(), false); + scope p = new Parser!ASTCodegen(loc, sc._module, se.toStringz(), false); p.nextToken(); decl = p.parseDeclDefs(0); diff --git a/ddmd/attrib.h b/ddmd/attrib.h index 107beecc78f..6c995dc2e7a 100644 --- a/ddmd/attrib.h +++ b/ddmd/attrib.h @@ -36,7 +36,7 @@ class AttribDeclaration : public Dsymbol int apply(Dsymbol_apply_ft_t fp, void *param); static Scope *createNewScope(Scope *sc, StorageClass newstc, LINK linkage, CPPMANGLE cppmangle, Prot protection, - int explictProtection, AlignDeclaration *aligndecl, PINLINE inlining); + int explicitProtection, AlignDeclaration *aligndecl, PINLINE inlining); virtual Scope *newScope(Scope *sc); void addMember(Scope *sc, ScopeDsymbol *sds); void setScope(Scope *sc); diff --git a/ddmd/blockexit.d b/ddmd/blockexit.d index 1e2eaaddaeb..53479063776 100644 --- a/ddmd/blockexit.d +++ b/ddmd/blockexit.d @@ -403,7 +403,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) Identifier id = c.type.toBasetype().isClassHandle().ident; if (c.internalCatch && (cresult & BEfallthru)) { - // Bugzilla 11542: leave blockExit flags of the body + // https://issues.dlang.org/show_bug.cgi?id=11542 + // leave blockExit flags of the body cresult &= ~BEfallthru; } else if (id == Id.Object || id == Id.Throwable) @@ -452,7 +453,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) version (none) { - // Bugzilla 13201: Mask to prevent spurious warnings for + // https://issues.dlang.org/show_bug.cgi?id=13201 + // Mask to prevent spurious warnings for // destructor call, exit of synchronized statement, etc. if (result == BEhalt && finalresult != BEhalt && s.finalbody && s.finalbody.hasCode()) { @@ -475,7 +477,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { if (s.internalThrow) { - // Bugzilla 8675: Allow throwing 'Throwable' object even if mustNotThrow. + // https://issues.dlang.org/show_bug.cgi?id=8675 + // Allow throwing 'Throwable' object even if mustNotThrow. result = BEfallthru; return; } diff --git a/ddmd/canthrow.d b/ddmd/canthrow.d index 0f1294834d8..b92ddb9c1e9 100644 --- a/ddmd/canthrow.d +++ b/ddmd/canthrow.d @@ -97,7 +97,7 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow { if (ne.allocator) { - // Bugzilla 14407 + // https://issues.dlang.org/show_bug.cgi?id=14407 Type t = ne.allocator.type.toBasetype(); if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) { diff --git a/ddmd/cond.d b/ddmd/cond.d index 8efb4549f2f..136a3f4b066 100644 --- a/ddmd/cond.d +++ b/ddmd/cond.d @@ -315,7 +315,6 @@ extern (C++) final class VersionCondition : DVCondition "HPPA", "HPPA64", "SH", - "SH64", "Alpha", "Alpha_SoftFloat", "Alpha_HardFloat", @@ -327,6 +326,8 @@ extern (C++) final class VersionCondition : DVCondition "CRuntime_DigitalMars", "CRuntime_Glibc", "CRuntime_Microsoft", + "CRuntime_Musl", + "CRuntime_UClibc", "unittest", "assert", "all", @@ -508,12 +509,20 @@ extern (C++) final class StaticIfCondition : Condition printf("\ts = '%s', kind = %s\n", sds.toChars(), sds.kind()); } } + + int errorReturn() + { + if (!global.gag) + inc = 2; // so we don't see the error message again + return 0; + } + if (inc == 0) { if (exp.op == TOKerror || nest > 100) { error(loc, (nest > 1000) ? "unresolvable circular static if expression" : "error evaluating static if expression"); - goto Lerror; + return errorReturn(); } if (!sc) { @@ -521,47 +530,28 @@ extern (C++) final class StaticIfCondition : Condition inc = 2; return 0; } + ++nest; sc = sc.push(sc.scopesym); sc.sds = sds; // sds gets any addMember() - //sc.speculative = true; // TODO: static if (is(T U)) { /* U is available */ } - sc.flags |= SCOPEcondition; - sc = sc.startCTFE(); - Expression e = exp.semantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); + + import ddmd.staticcond; + bool errors; + bool result = evalStaticCondition(sc, exp, exp, errors); sc.pop(); --nest; // Prevent repeated condition evaluation. // See: fail_compilation/fail7815.d if (inc != 0) return (inc == 1); - if (!e.type.isBoolean()) - { - if (e.type.toBasetype() != Type.terror) - exp.error("expression %s of type %s does not have a boolean value", exp.toChars(), e.type.toChars()); - goto Lerror; - } - e = e.ctfeInterpret(); - if (e.op == TOKerror) - { - goto Lerror; - } - else if (e.isBool(true)) + if (errors) + return errorReturn(); + if (result) inc = 1; - else if (e.isBool(false)) - inc = 2; else - { - e.error("expression %s is not constant or does not evaluate to a bool", e.toChars()); - goto Lerror; - } + inc = 2; } return (inc == 1); - Lerror: - if (!global.gag) - inc = 2; // so we don't see the error message again - return 0; } override void accept(Visitor v) diff --git a/ddmd/console.d b/ddmd/console.d new file mode 100644 index 00000000000..333ac9931d9 --- /dev/null +++ b/ddmd/console.d @@ -0,0 +1,221 @@ +/** + * Compiler implementation of the + * $(LINK2 http://www.dlang.org, D programming language). + * + * Copyright: Copyright (c) 1999-2017 by Digital Mars, 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: $(DMDSRC _console.d) + */ + +/******************************************** + * Control the various text mode attributes, such as color, when writing text + * to the console. + */ + +module ddmd.console; + +import core.stdc.stdio; +extern (C) int isatty(int); + + +enum Color : int +{ + black = 0, + red = 1, + green = 2, + blue = 4, + yellow = red | green, + magenta = red | blue, + cyan = green | blue, + lightGray = red | green | blue, + bright = 8, + darkGray = bright | black, + brightRed = bright | red, + brightGreen = bright | green, + brightBlue = bright | blue, + brightYellow = bright | yellow, + brightMagenta = bright | magenta, + brightCyan = bright | cyan, + white = bright | lightGray, +} + +struct Console +{ + version (Windows) + { + import core.sys.windows.windows; + + private: + CONSOLE_SCREEN_BUFFER_INFO sbi; + HANDLE handle; + FILE* _fp; + + public: + + @property FILE* fp() { return _fp; } + + /********************************* + * Create an instance of Console connected to stream fp. + * Params: + * fp = io stream + * Returns: + * pointer to created Console + * null if failed + */ + static Console* create(FILE* fp) + { + /* Determine if stream fp is a console + */ + version (CRuntime_DigitalMars) + { + if (!isatty(fp._file)) + return null; + } + else version (CRuntime_Microsoft) + { + if (!isatty(fileno(fp))) + return null; + } + else + { + return null; + } + + DWORD nStdHandle; + if (fp == stdout) + nStdHandle = STD_OUTPUT_HANDLE; + else if (fp == stderr) + nStdHandle = STD_ERROR_HANDLE; + else + return null; + + auto h = GetStdHandle(nStdHandle); + CONSOLE_SCREEN_BUFFER_INFO sbi; + if (GetConsoleScreenBufferInfo(h, &sbi) == 0) // get initial state of console + return null; + + auto c = new Console(); + c._fp = fp; + c.handle = h; + c.sbi = sbi; + return c; + } + + /******************* + * Turn on/off intensity. + * Params: + * bright = turn it on + */ + void setColorBright(bool bright) + { + SetConsoleTextAttribute(handle, sbi.wAttributes | (bright ? FOREGROUND_INTENSITY : 0)); + } + + /*************************** + * Set color and intensity. + * Params: + * color = the color + */ + void setColor(Color color) + { + enum FOREGROUND_WHITE = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; + WORD attr = sbi.wAttributes; + attr = (attr & ~(FOREGROUND_WHITE | FOREGROUND_INTENSITY)) | + ((color & Color.red) ? FOREGROUND_RED : 0) | + ((color & Color.green) ? FOREGROUND_GREEN : 0) | + ((color & Color.blue) ? FOREGROUND_BLUE : 0) | + ((color & Color.bright) ? FOREGROUND_INTENSITY : 0); + SetConsoleTextAttribute(handle, attr); + } + + /****************** + * Reset console attributes to what they were + * when create() was called. + */ + void resetColor() + { + SetConsoleTextAttribute(handle, sbi.wAttributes); + } + } + else version (Posix) + { + /* The ANSI escape codes are used. + * https://en.wikipedia.org/wiki/ANSI_escape_code + * Foreground colors: 30..37 + * Background colors: 40..47 + * Attributes: + * 0: reset all attributes + * 1: high intensity + * 2: low intensity + * 3: italic + * 4: single line underscore + * 5: slow blink + * 6: fast blink + * 7: reverse video + * 8: hidden + */ + + import core.sys.posix.unistd; + + private: + FILE* _fp; + + public: + + @property FILE* fp() { return _fp; } + + static Console* create(FILE* fp) + { + import core.stdc.stdlib : getenv; + const(char)* term = getenv("TERM"); + import core.stdc.string : strcmp; + if (!(isatty(STDERR_FILENO) && term && term[0] && 0 != strcmp(term, "dumb"))) + return null; + + auto c = new Console(); + c._fp = fp; + return c; + } + + void setColorBright(bool bright) + { + fprintf(_fp, "\033[%dm", bright); + } + + void setColor(Color color) + { + fprintf(_fp, "\033[%d;%dm", color & Color.bright ? 1 : 0, 30 + (color & ~Color.bright)); + } + + void resetColor() + { + fputs("\033[m", _fp); + } + } + else + { + @property FILE* fp() { assert(0); } + + static Console* create(FILE* fp) + { + return null; + } + + void setColorBright(bool bright) + { + assert(0); + } + + void setColor(Color color) + { + assert(0); + } + + void resetColor() + { + assert(0); + } + } + +} diff --git a/ddmd/constfold.d b/ddmd/constfold.d index 6e53a36492e..41f0d10eb31 100644 --- a/ddmd/constfold.d +++ b/ddmd/constfold.d @@ -1610,7 +1610,7 @@ extern (C++) UnionExp Cat(Type type, Expression e1, Expression e2) StringExp es; ubyte sz = es1.sz; dinteger_t v = e2.toInteger(); - // Is it a concatentation of homogenous types? + // Is it a concatenation of homogenous types? // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar) bool homoConcat = (sz == t2.size()); size_t len = es1.len; diff --git a/ddmd/cppmangle.d b/ddmd/cppmangle.d index 5a53176063a..c368b9109a3 100644 --- a/ddmd/cppmangle.d +++ b/ddmd/cppmangle.d @@ -27,10 +27,6 @@ import ddmd.root.rootobject; import ddmd.target; import ddmd.tokens; import ddmd.visitor; -version(IN_LLVM) { - import ddmd.errors; - import gen.llvmhelpers; -} /* Do mangling for C++ linkage. * No attempt is made to support mangling of templates, operator @@ -41,848 +37,854 @@ version(IN_LLVM) { * ABI has no concept of. These affect every D mangled name, * so nothing would be compatible anyway. */ -static if (IN_LLVM || TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) + +/* + * Follows Itanium C++ ABI 1.86 + */ +extern (C++) final class CppMangleVisitor : Visitor { - /* - * Follows Itanium C++ ABI 1.86 - */ - extern (C++) final class CppMangleVisitor : Visitor - { - alias visit = super.visit; - Objects components; - OutBuffer buf; - bool is_top_level; - bool components_on; + alias visit = super.visit; + Objects components; + OutBuffer buf; + bool is_top_level; + bool components_on; - void writeBase36(size_t i) + void writeBase36(size_t i) + { + if (i >= 36) { - if (i >= 36) - { - writeBase36(i / 36); - i %= 36; - } - if (i < 10) - buf.writeByte(cast(char)(i + '0')); - else if (i < 36) - buf.writeByte(cast(char)(i - 10 + 'A')); - else - assert(0); + writeBase36(i / 36); + i %= 36; } + if (i < 10) + buf.writeByte(cast(char)(i + '0')); + else if (i < 36) + buf.writeByte(cast(char)(i - 10 + 'A')); + else + assert(0); + } - bool substitute(RootObject p) - { - //printf("substitute %s\n", p ? p.toChars() : null); - if (components_on) - for (size_t i = 0; i < components.dim; i++) + bool substitute(RootObject p) + { + //printf("substitute %s\n", p ? p.toChars() : null); + if (components_on) + for (size_t i = 0; i < components.dim; i++) + { + //printf(" component[%d] = %s\n", i, components[i] ? components[i].toChars() : null); + if (p == components[i]) { - //printf(" component[%d] = %s\n", i, components[i] ? components[i].toChars() : null); - if (p == components[i]) - { - //printf("\tmatch\n"); - /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... - */ - buf.writeByte('S'); - if (i) - writeBase36(i - 1); - buf.writeByte('_'); - return true; - } + //printf("\tmatch\n"); + /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... + */ + buf.writeByte('S'); + if (i) + writeBase36(i - 1); + buf.writeByte('_'); + return true; } - return false; - } + } + return false; + } - bool exist(RootObject p) - { - //printf("exist %s\n", p ? p.toChars() : null); - if (components_on) - for (size_t i = 0; i < components.dim; i++) + bool exist(RootObject p) + { + //printf("exist %s\n", p ? p.toChars() : null); + if (components_on) + for (size_t i = 0; i < components.dim; i++) + { + if (p == components[i]) { - if (p == components[i]) - { - return true; - } + return true; } - return false; - } + } + return false; + } - void store(RootObject p) - { - //printf("store %s\n", p ? p.toChars() : "null"); - if (components_on) - components.push(p); - } + void store(RootObject p) + { + //printf("store %s\n", p ? p.toChars() : "null"); + if (components_on) + components.push(p); + } - void source_name(Dsymbol s, bool skipname = false) + void source_name(Dsymbol s, bool skipname = false) + { + //printf("source_name(%s)\n", s.toChars()); + TemplateInstance ti = s.isTemplateInstance(); + if (ti) { - //printf("source_name(%s)\n", s.toChars()); - TemplateInstance ti = s.isTemplateInstance(); - if (ti) + if (!skipname && !substitute(ti.tempdecl)) + { + store(ti.tempdecl); + const(char)* name = ti.tempdecl.toAlias().ident.toChars(); + buf.printf("%d%s", strlen(name), name); + } + buf.writeByte('I'); + bool is_var_arg = false; + for (size_t i = 0; i < ti.tiargs.dim; i++) { - if (!skipname && !substitute(ti.tempdecl)) + RootObject o = cast(RootObject)(*ti.tiargs)[i]; + TemplateParameter tp = null; + TemplateValueParameter tv = null; + TemplateTupleParameter tt = null; + if (!is_var_arg) { - store(ti.tempdecl); - const(char)* name = ti.tempdecl.toAlias().ident.toChars(); - buf.printf("%d%s", strlen(name), name); + TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); + assert(td); + tp = (*td.parameters)[i]; + tv = tp.isTemplateValueParameter(); + tt = tp.isTemplateTupleParameter(); } - buf.writeByte('I'); - bool is_var_arg = false; - for (size_t i = 0; i < ti.tiargs.dim; i++) + /* + * ::= # type or template + * ::= # simple expressions + */ + if (tt) { - RootObject o = cast(RootObject)(*ti.tiargs)[i]; - TemplateParameter tp = null; - TemplateValueParameter tv = null; - TemplateTupleParameter tt = null; - if (!is_var_arg) - { - TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); - assert(td); - tp = (*td.parameters)[i]; - tv = tp.isTemplateValueParameter(); - tt = tp.isTemplateTupleParameter(); - } - /* - * ::= # type or template - * ::= # simple expressions - */ - if (tt) - { - buf.writeByte('I'); - is_var_arg = true; - tp = null; - } - if (tv) - { - // ::= L E # integer literal - if (tv.valType.isintegral()) - { - Expression e = isExpression(o); - assert(e); - buf.writeByte('L'); - tv.valType.accept(this); - if (tv.valType.isunsigned()) - { - buf.printf("%llu", e.toUInteger()); - } - else - { - sinteger_t val = e.toInteger(); - if (val < 0) - { - val = -val; - buf.writeByte('n'); - } - buf.printf("%lld", val); - } - buf.writeByte('E'); - } - else - { - s.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); - fatal(); - } - } - else if (!tp || tp.isTemplateTypeParameter()) - { - Type t = isType(o); - assert(t); - t.accept(this); - } - else if (tp.isTemplateAliasParameter()) + buf.writeByte('I'); + is_var_arg = true; + tp = null; + } + if (tv) + { + // ::= L E # integer literal + if (tv.valType.isintegral()) { - Dsymbol d = isDsymbol(o); Expression e = isExpression(o); - if (!d && !e) + assert(e); + buf.writeByte('L'); + tv.valType.accept(this); + if (tv.valType.isunsigned()) { - s.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); - fatal(); + buf.printf("%llu", e.toUInteger()); } - if (d && d.isFuncDeclaration()) - { - bool is_nested = d.toParent() && !d.toParent().isModule() && (cast(TypeFunction)d.isFuncDeclaration().type).linkage == LINKcpp; - if (is_nested) - buf.writeByte('X'); - buf.writeByte('L'); - mangle_function(d.isFuncDeclaration()); - buf.writeByte('E'); - if (is_nested) - buf.writeByte('E'); - } - else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) - { - VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); - buf.writeByte('L'); - mangle_variable(vd, true); - buf.writeByte('E'); - } - else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) + else { - if (!substitute(d)) + sinteger_t val = e.toInteger(); + if (val < 0) { - cpp_mangle_name(d, false); + val = -val; + buf.writeByte('n'); } + buf.printf("%lld", val); } - else - { - s.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); - fatal(); - } + buf.writeByte('E'); } else { - s.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + s.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); fatal(); } } - if (is_var_arg) + else if (!tp || tp.isTemplateTypeParameter()) { - buf.writeByte('E'); + Type t = isType(o); + assert(t); + t.accept(this); } - buf.writeByte('E'); - return; - } - else - { - const(char)* name = s.ident.toChars(); - buf.printf("%d%s", strlen(name), name); - } - } - - void prefix_name(Dsymbol s) - { - //printf("prefix_name(%s)\n", s.toChars()); - if (!substitute(s)) - { - Dsymbol p = s.toParent(); - if (p && p.isTemplateInstance()) + else if (tp.isTemplateAliasParameter()) { - s = p; - if (exist(p.isTemplateInstance().tempdecl)) + Dsymbol d = isDsymbol(o); + Expression e = isExpression(o); + if (!d && !e) + { + s.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); + fatal(); + } + if (d && d.isFuncDeclaration()) + { + bool is_nested = d.toParent() && !d.toParent().isModule() && (cast(TypeFunction)d.isFuncDeclaration().type).linkage == LINKcpp; + if (is_nested) + buf.writeByte('X'); + buf.writeByte('L'); + mangle_function(d.isFuncDeclaration()); + buf.writeByte('E'); + if (is_nested) + buf.writeByte('E'); + } + else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) + { + VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); + buf.writeByte('L'); + mangle_variable(vd, true); + buf.writeByte('E'); + } + else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) { - p = null; + if (!substitute(d)) + { + cpp_mangle_name(d, false); + } } else { - p = p.toParent(); + s.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); + fatal(); } } - if (p && !p.isModule()) + else { - if (p.ident == Id.std && is_initial_qualifier(p)) - buf.writestring("St"); - else - prefix_name(p); + s.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + fatal(); } - if (!(s.ident == Id.std && is_initial_qualifier(s))) - store(s); - source_name(s); } + if (is_var_arg) + { + buf.writeByte('E'); + } + buf.writeByte('E'); + return; } + else + { + const(char)* name = s.ident.toChars(); + buf.printf("%d%s", strlen(name), name); + } + } - /* Is s the initial qualifier? - */ - bool is_initial_qualifier(Dsymbol s) + void prefix_name(Dsymbol s) + { + //printf("prefix_name(%s)\n", s.toChars()); + if (!substitute(s)) { Dsymbol p = s.toParent(); if (p && p.isTemplateInstance()) { + s = p; if (exist(p.isTemplateInstance().tempdecl)) { - return true; + p = null; + } + else + { + p = p.toParent(); } - p = p.toParent(); } - return !p || p.isModule(); + if (p && !p.isModule()) + { + if (p.ident == Id.std && is_initial_qualifier(p)) + buf.writestring("St"); + else + prefix_name(p); + } + if (!(s.ident == Id.std && is_initial_qualifier(s))) + store(s); + source_name(s); } + } - void cpp_mangle_name(Dsymbol s, bool qualified) + /* Is s the initial qualifier? + */ + bool is_initial_qualifier(Dsymbol s) + { + Dsymbol p = s.toParent(); + if (p && p.isTemplateInstance()) { - //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); - Dsymbol p = s.toParent(); - Dsymbol se = s; - bool dont_write_prefix = false; - if (p && p.isTemplateInstance()) + if (exist(p.isTemplateInstance().tempdecl)) { - se = p; - if (exist(p.isTemplateInstance().tempdecl)) - dont_write_prefix = true; - p = p.toParent(); + return true; } - if (p && !p.isModule()) + p = p.toParent(); + } + return !p || p.isModule(); + } + + void cpp_mangle_name(Dsymbol s, bool qualified) + { + //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); + Dsymbol p = s.toParent(); + Dsymbol se = s; + bool dont_write_prefix = false; + if (p && p.isTemplateInstance()) + { + se = p; + if (exist(p.isTemplateInstance().tempdecl)) + dont_write_prefix = true; + p = p.toParent(); + } + if (p && !p.isModule()) + { + /* The N..E is not required if: + * 1. the parent is 'std' + * 2. 'std' is the initial qualifier + * 3. there is no CV-qualifier or a ref-qualifier for a member function + * ABI 5.1.8 + */ + if (p.ident == Id.std && is_initial_qualifier(p) && !qualified) { - /* The N..E is not required if: - * 1. the parent is 'std' - * 2. 'std' is the initial qualifier - * 3. there is no CV-qualifier or a ref-qualifier for a member function - * ABI 5.1.8 - */ - if (p.ident == Id.std && is_initial_qualifier(p) && !qualified) + if (s.ident == Id.allocator) { - if (s.ident == Id.allocator) - { - buf.writestring("Sa"); // "Sa" is short for ::std::allocator - source_name(se, true); - } - else if (s.ident == Id.basic_string) - { - components_on = false; // turn off substitutions - buf.writestring("Sb"); // "Sb" is short for ::std::basic_string - size_t off = buf.offset; - source_name(se, true); - components_on = true; - // Replace ::std::basic_string < char, ::std::char_traits, ::std::allocator > - // with Ss - //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); - if (buf.offset - off >= 26 && memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE".ptr, 26) == 0) - { - buf.remove(off - 2, 28); - buf.insert(off - 2, "Ss"); - return; - } - buf.setsize(off); - source_name(se, true); - } - else if (s.ident == Id.basic_istream || s.ident == Id.basic_ostream || s.ident == Id.basic_iostream) + buf.writestring("Sa"); // "Sa" is short for ::std::allocator + source_name(se, true); + } + else if (s.ident == Id.basic_string) + { + components_on = false; // turn off substitutions + buf.writestring("Sb"); // "Sb" is short for ::std::basic_string + size_t off = buf.offset; + source_name(se, true); + components_on = true; + // Replace ::std::basic_string < char, ::std::char_traits, ::std::allocator > + // with Ss + //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); + if (buf.offset - off >= 26 && memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE".ptr, 26) == 0) { - /* Replace - * ::std::basic_istream > with Si - * ::std::basic_ostream > with So - * ::std::basic_iostream > with Sd - */ - size_t off = buf.offset; - components_on = false; // turn off substitutions - source_name(se, true); - components_on = true; - //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); - if (buf.offset - off >= 21 && memcmp(buf.data + off, "IcSt11char_traitsIcEE".ptr, 21) == 0) - { - buf.remove(off, 21); - char[2] mbuf; - mbuf[0] = 'S'; - mbuf[1] = 'i'; - if (s.ident == Id.basic_ostream) - mbuf[1] = 'o'; - else if (s.ident == Id.basic_iostream) - mbuf[1] = 'd'; - buf.insert(off, mbuf[]); - return; - } - buf.setsize(off); - buf.writestring("St"); - source_name(se); + buf.remove(off - 2, 28); + buf.insert(off - 2, "Ss"); + return; } - else + buf.setsize(off); + source_name(se, true); + } + else if (s.ident == Id.basic_istream || s.ident == Id.basic_ostream || s.ident == Id.basic_iostream) + { + /* Replace + * ::std::basic_istream > with Si + * ::std::basic_ostream > with So + * ::std::basic_iostream > with Sd + */ + size_t off = buf.offset; + components_on = false; // turn off substitutions + source_name(se, true); + components_on = true; + //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); + if (buf.offset - off >= 21 && memcmp(buf.data + off, "IcSt11char_traitsIcEE".ptr, 21) == 0) { - buf.writestring("St"); - source_name(se); + buf.remove(off, 21); + char[2] mbuf; + mbuf[0] = 'S'; + mbuf[1] = 'i'; + if (s.ident == Id.basic_ostream) + mbuf[1] = 'o'; + else if (s.ident == Id.basic_iostream) + mbuf[1] = 'd'; + buf.insert(off, mbuf[]); + return; } + buf.setsize(off); + buf.writestring("St"); + source_name(se); } else { - buf.writeByte('N'); - if (!dont_write_prefix) - prefix_name(p); + buf.writestring("St"); source_name(se); - buf.writeByte('E'); } } else + { + buf.writeByte('N'); + if (!dont_write_prefix) + prefix_name(p); source_name(se); - store(s); + buf.writeByte('E'); + } } + else + source_name(se); + store(s); + } - void mangle_variable(VarDeclaration d, bool is_temp_arg_ref) + void mangle_variable(VarDeclaration d, bool is_temp_arg_ref) + { + // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 + if (!(d.storage_class & (STCextern | STCfield | STCgshared))) + { + d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); + fatal(); + } + Dsymbol p = d.toParent(); + if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" { - // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 - if (!(d.storage_class & (STCextern | STCfield | STCgshared))) + buf.writestring("_ZN"); + prefix_name(p); + source_name(d); + buf.writeByte('E'); + } + else //char beta[6] should mangle as "beta" + { + if (!is_temp_arg_ref) { - d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); - fatal(); + buf.writestring(d.ident.toChars()); } - Dsymbol p = d.toParent(); - if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" + else { - buf.writestring("_ZN"); - prefix_name(p); + buf.writestring("_Z"); source_name(d); - buf.writeByte('E'); - } - else //char beta[6] should mangle as "beta" - { - if (!is_temp_arg_ref) - { - buf.writestring(d.ident.toChars()); - } - else - { - buf.writestring("_Z"); - source_name(d); - } } } + } - void mangle_function(FuncDeclaration d) - { - //printf("mangle_function(%s)\n", d.toChars()); - /* - * ::= _Z - * ::= - * ::= - * ::= - */ - TypeFunction tf = cast(TypeFunction)d.type; - buf.writestring("_Z"); - Dsymbol p = d.toParent(); - TemplateDeclaration ftd = getFuncTemplateDecl(d); + void mangle_function(FuncDeclaration d) + { + //printf("mangle_function(%s)\n", d.toChars()); + /* + * ::= _Z + * ::= + * ::= + * ::= + */ + TypeFunction tf = cast(TypeFunction)d.type; + buf.writestring("_Z"); + Dsymbol p = d.toParent(); + TemplateDeclaration ftd = getFuncTemplateDecl(d); - if (p && !p.isModule() && tf.linkage == LINKcpp && !ftd) + if (p && !p.isModule() && tf.linkage == LINKcpp && !ftd) + { + buf.writeByte('N'); + if (d.type.isConst()) + buf.writeByte('K'); + prefix_name(p); + // See ABI 5.1.8 Compression + // Replace ::std::allocator with Sa + if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator".ptr, 17) == 0) { - buf.writeByte('N'); - if (d.type.isConst()) - buf.writeByte('K'); - prefix_name(p); - // See ABI 5.1.8 Compression - // Replace ::std::allocator with Sa - if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator".ptr, 17) == 0) - { - buf.remove(3, 14); - buf.insert(3, "Sa"); - } - // Replace ::std::basic_string with Sb - if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string".ptr, 21) == 0) - { - buf.remove(3, 18); - buf.insert(3, "Sb"); - } - // Replace ::std with St - if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std".ptr, 7) == 0) - { - buf.remove(3, 4); - buf.insert(3, "St"); - } - if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std".ptr, 8) == 0) - { - buf.remove(4, 4); - buf.insert(4, "St"); - } - if (d.isDtorDeclaration()) - { - buf.writestring("D1"); - } - else - { - source_name(d); - } - buf.writeByte('E'); + buf.remove(3, 14); + buf.insert(3, "Sa"); } - else if (ftd) + // Replace ::std::basic_string with Sb + if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string".ptr, 21) == 0) { - source_name(p); - this.is_top_level = true; - tf.nextOf().accept(this); - this.is_top_level = false; + buf.remove(3, 18); + buf.insert(3, "Sb"); } - else + // Replace ::std with St + if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std".ptr, 7) == 0) { - source_name(d); + buf.remove(3, 4); + buf.insert(3, "St"); } - if (tf.linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling + if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std".ptr, 8) == 0) { - assert(tf.ty == Tfunction); - argsCppMangle(tf.parameters, tf.varargs); + buf.remove(4, 4); + buf.insert(4, "St"); } - } - - void argsCppMangle(Parameters* parameters, int varargs) - { - int paramsCppMangleDg(size_t n, Parameter fparam) + if (d.isDtorDeclaration()) { - Type t = fparam.type.merge2(); - if (fparam.storageClass & (STCout | STCref)) - t = t.referenceTo(); - else if (fparam.storageClass & STClazy) - { - // Mangle as delegate - Type td = new TypeFunction(null, t, 0, LINKd); - td = new TypeDelegate(td); - t = t.merge(); - } - if (t.ty == Tsarray) - { - // Mangle static arrays as pointers - t.error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function."); - t.error(Loc(), "Use pointer instead."); - fatal(); - //t = t.nextOf().pointerTo(); - } - /* If it is a basic, enum or struct type, - * then don't mark it const - */ - this.is_top_level = true; - if ((t.ty == Tenum || t.ty == Tstruct || t.ty == Tpointer || t.isTypeBasic()) && t.isConst()) - t.mutableOf().accept(this); - else - t.accept(this); - this.is_top_level = false; - return 0; + buf.writestring("D1"); } - - if (parameters) - Parameter._foreach(parameters, ¶msCppMangleDg); - if (varargs) - buf.writestring("z"); - else if (!parameters || !parameters.dim) - buf.writeByte('v'); // encode ( ) parameters + else + { + source_name(d); + } + buf.writeByte('E'); } - - public: - extern (D) this() + else if (ftd) { - this.components_on = true; + source_name(p); + this.is_top_level = true; + tf.nextOf().accept(this); + this.is_top_level = false; } + else + { + source_name(d); + } + if (tf.linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling + { + assert(tf.ty == Tfunction); + argsCppMangle(tf.parameters, tf.varargs); + } + } - const(char)* mangleOf(Dsymbol s) + void argsCppMangle(Parameters* parameters, int varargs) + { + int paramsCppMangleDg(size_t n, Parameter fparam) { - VarDeclaration vd = s.isVarDeclaration(); - FuncDeclaration fd = s.isFuncDeclaration(); - if (vd) + Type t = fparam.type.merge2(); + if (fparam.storageClass & (STCout | STCref)) + t = t.referenceTo(); + else if (fparam.storageClass & STClazy) { - mangle_variable(vd, false); + // Mangle as delegate + Type td = new TypeFunction(null, t, 0, LINKd); + td = new TypeDelegate(td); + t = t.merge(); } - else if (fd) + if (t.ty == Tsarray) { - mangle_function(fd); + // Mangle static arrays as pointers + t.error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function."); + t.error(Loc(), "Use pointer instead."); + fatal(); + //t = t.nextOf().pointerTo(); } + /* If it is a basic, enum or struct type, + * then don't mark it const + */ + this.is_top_level = true; + if ((t.ty == Tenum || t.ty == Tstruct || t.ty == Tpointer || t.isTypeBasic()) && t.isConst()) + t.mutableOf().accept(this); else - { - assert(0); - } - Target.prefixName(&buf, LINKcpp); - return buf.extractString(); + t.accept(this); + this.is_top_level = false; + return 0; } - override void visit(Type t) + if (parameters) + Parameter._foreach(parameters, ¶msCppMangleDg); + if (varargs) + buf.writestring("z"); + else if (!parameters || !parameters.dim) + buf.writeByte('v'); // encode ( ) parameters + } + +public: + extern (D) this() + { + this.components_on = true; + } + + const(char)* mangleOf(Dsymbol s) + { + VarDeclaration vd = s.isVarDeclaration(); + FuncDeclaration fd = s.isFuncDeclaration(); + if (vd) { - if (t.isImmutable() || t.isShared()) - { - t.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", t.toChars()); - } - else - { - t.error(Loc(), "Internal Compiler Error: unsupported type %s\n", t.toChars()); - } - fatal(); //Fatal, because this error should be handled in frontend - } - - override void visit(TypeBasic t) - { - /* ABI spec says: - * v void - * w wchar_t - * b bool - * c char - * a signed char - * h unsigned char - * s short - * t unsigned short - * i int - * j unsigned int - * l long - * m unsigned long - * x long long, __int64 - * y unsigned long long, __int64 - * n __int128 - * o unsigned __int128 - * f float - * d double - * e long double, __float80 - * g __float128 - * z ellipsis - * u # vendor extended type - */ - char c; - char p = 0; - switch (t.ty) - { - case Tvoid: - c = 'v'; - break; - case Tint8: - c = 'a'; - break; - case Tuns8: - c = 'h'; - break; - case Tint16: - c = 's'; - break; - case Tuns16: - c = 't'; - break; - case Tint32: - c = 'i'; - break; - case Tuns32: - c = 'j'; - break; - case Tfloat32: - c = 'f'; - break; - case Tint64: - c = (Target.c_longsize == 8 ? 'l' : 'x'); - break; - case Tuns64: - c = (Target.c_longsize == 8 ? 'm' : 'y'); - break; - case Tint128: - c = 'n'; - break; - case Tuns128: - c = 'o'; - break; - case Tfloat64: - c = 'd'; - break; - case Tfloat80: - c = Target.realislongdouble ? 'e' : 'g'; - break; - case Tbool: - c = 'b'; - break; - case Tchar: - c = 'c'; - break; - case Twchar: - c = 't'; - break; - // unsigned short - case Tdchar: - c = 'w'; - break; - // wchar_t (UTF-32) - case Timaginary32: - p = 'G'; - c = 'f'; - break; - case Timaginary64: - p = 'G'; - c = 'd'; - break; - case Timaginary80: - p = 'G'; - c = 'e'; - break; - case Tcomplex32: - p = 'C'; - c = 'f'; - break; - case Tcomplex64: - p = 'C'; - c = 'd'; - break; - case Tcomplex80: - p = 'C'; - c = 'e'; - break; - default: - visit(cast(Type)t); - return; - } - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (p || t.isConst()) - { - if (substitute(t)) - { - return; - } - else - { - store(t); - } - } - if (t.isConst()) - buf.writeByte('K'); - if (p) - buf.writeByte(p); - buf.writeByte(c); + mangle_variable(vd, false); } - - override void visit(TypeVector t) + else if (fd) { - is_top_level = false; - if (substitute(t)) - return; - store(t); - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - assert(t.basetype && t.basetype.ty == Tsarray); - assert((cast(TypeSArray)t.basetype).dim); - //buf.printf("Dv%llu_", ((TypeSArray *)t.basetype).dim.toInteger());// -- Gnu ABI v.4 - buf.writestring("U8__vector"); //-- Gnu ABI v.3 - t.basetype.nextOf().accept(this); + mangle_function(fd); + } + else + { + assert(0); } + Target.prefixName(&buf, LINKcpp); + return buf.extractString(); + } - override void visit(TypeSArray t) + override void visit(Type t) + { + if (t.isImmutable() || t.isShared()) { - is_top_level = false; - if (!substitute(t)) - store(t); - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - buf.printf("A%llu_", t.dim ? t.dim.toInteger() : 0); - t.next.accept(this); + t.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", t.toChars()); } + else + { + t.error(Loc(), "Internal Compiler Error: type %s can not be mapped to C++\n", t.toChars()); + } + fatal(); //Fatal, because this error should be handled in frontend + } - override void visit(TypeDArray t) + override void visit(TypeBasic t) + { + /* ABI spec says: + * v void + * w wchar_t + * b bool + * c char + * a signed char + * h unsigned char + * s short + * t unsigned short + * i int + * j unsigned int + * l long + * m unsigned long + * x long long, __int64 + * y unsigned long long, __int64 + * n __int128 + * o unsigned __int128 + * f float + * d double + * e long double, __float80 + * g __float128 + * z ellipsis + * u # vendor extended type + */ + char c; + char p = 0; + switch (t.ty) { + case Tvoid: + c = 'v'; + break; + case Tint8: + c = 'a'; + break; + case Tuns8: + c = 'h'; + break; + case Tint16: + c = 's'; + break; + case Tuns16: + c = 't'; + break; + case Tint32: + c = 'i'; + break; + case Tuns32: + c = 'j'; + break; + case Tfloat32: + c = 'f'; + break; + case Tint64: + c = (Target.c_longsize == 8 ? 'l' : 'x'); + break; + case Tuns64: + c = (Target.c_longsize == 8 ? 'm' : 'y'); + break; + case Tint128: + c = 'n'; + break; + case Tuns128: + c = 'o'; + break; + case Tfloat64: + c = 'd'; + break; + case Tfloat80: + c = 'e'; + break; + case Tbool: + c = 'b'; + break; + case Tchar: + c = 'c'; + break; + case Twchar: + c = 't'; + break; + // unsigned short + case Tdchar: + c = 'w'; + break; + // wchar_t (UTF-32) + case Timaginary32: + p = 'G'; + c = 'f'; + break; + case Timaginary64: + p = 'G'; + c = 'd'; + break; + case Timaginary80: + p = 'G'; + c = 'e'; + break; + case Tcomplex32: + p = 'C'; + c = 'f'; + break; + case Tcomplex64: + p = 'C'; + c = 'd'; + break; + case Tcomplex80: + p = 'C'; + c = 'e'; + break; + default: visit(cast(Type)t); + return; } - - override void visit(TypeAArray t) + if (t.isImmutable() || t.isShared()) { visit(cast(Type)t); } - - override void visit(TypePointer t) + if (p || t.isConst()) { - is_top_level = false; if (substitute(t)) + { return; - if (t.isImmutable() || t.isShared()) + } + else { - visit(cast(Type)t); + store(t); } - if (t.isConst()) - buf.writeByte('K'); - buf.writeByte('P'); - t.next.accept(this); - store(t); } + if (t.isConst()) + buf.writeByte('K'); - override void visit(TypeReference t) + // Handle any target-specific basic types. + if (auto tm = Target.cppTypeMangle(t)) { - is_top_level = false; - if (substitute(t)) - return; - buf.writeByte('R'); - t.next.accept(this); - store(t); + buf.writestring(tm); } + else + { + if (p) + buf.writeByte(p); + buf.writeByte(c); + } + } - override void visit(TypeFunction t) + override void visit(TypeVector t) + { + is_top_level = false; + if (substitute(t)) + return; + store(t); + if (t.isImmutable() || t.isShared()) { - is_top_level = false; - /* - * ::= F [Y] E - * ::= + - * # types are possible return type, then parameter types - */ - /* ABI says: - "The type of a non-static member function is considered to be different, - for the purposes of substitution, from the type of a namespace-scope or - static member function whose type appears similar. The types of two - non-static member functions are considered to be different, for the - purposes of substitution, if the functions are members of different - classes. In other words, for the purposes of substitution, the class of - which the function is a member is considered part of the type of - function." - - BUG: Right now, types of functions are never merged, so our simplistic - component matcher always finds them to be different. - We should use Type.equals on these, and use different - TypeFunctions for non-static member functions, and non-static - member functions of different classes. - */ - if (substitute(t)) - return; - buf.writeByte('F'); - if (t.linkage == LINKc) - buf.writeByte('Y'); - Type tn = t.next; - if (t.isref) - tn = tn.referenceTo(); - tn.accept(this); - argsCppMangle(t.parameters, t.varargs); - buf.writeByte('E'); + visit(cast(Type)t); + } + if (t.isConst()) + buf.writeByte('K'); + + // Handle any target-specific vector types. + if (auto tm = Target.cppTypeMangle(t)) + { + buf.writestring(tm); + } + else + { + assert(t.basetype && t.basetype.ty == Tsarray); + assert((cast(TypeSArray)t.basetype).dim); + //buf.printf("Dv%llu_", ((TypeSArray *)t.basetype).dim.toInteger());// -- Gnu ABI v.4 + buf.writestring("U8__vector"); //-- Gnu ABI v.3 + t.basetype.nextOf().accept(this); + } + } + + override void visit(TypeSArray t) + { + is_top_level = false; + if (!substitute(t)) store(t); + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); } + if (t.isConst()) + buf.writeByte('K'); + buf.printf("A%llu_", t.dim ? t.dim.toInteger() : 0); + t.next.accept(this); + } + + override void visit(TypeDArray t) + { + visit(cast(Type)t); + } - override void visit(TypeDelegate t) + override void visit(TypeAArray t) + { + visit(cast(Type)t); + } + + override void visit(TypePointer t) + { + is_top_level = false; + if (substitute(t)) + return; + if (t.isImmutable() || t.isShared()) { visit(cast(Type)t); } + if (t.isConst()) + buf.writeByte('K'); + buf.writeByte('P'); + t.next.accept(this); + store(t); + } - override void visit(TypeStruct t) + override void visit(TypeReference t) + { + is_top_level = false; + if (substitute(t)) + return; + buf.writeByte('R'); + t.next.accept(this); + store(t); + } + + override void visit(TypeFunction t) + { + is_top_level = false; + /* + * ::= F [Y] E + * ::= + + * # types are possible return type, then parameter types + */ + /* ABI says: + "The type of a non-static member function is considered to be different, + for the purposes of substitution, from the type of a namespace-scope or + static member function whose type appears similar. The types of two + non-static member functions are considered to be different, for the + purposes of substitution, if the functions are members of different + classes. In other words, for the purposes of substitution, the class of + which the function is a member is considered part of the type of + function." + + BUG: Right now, types of functions are never merged, so our simplistic + component matcher always finds them to be different. + We should use Type.equals on these, and use different + TypeFunctions for non-static member functions, and non-static + member functions of different classes. + */ + if (substitute(t)) + return; + buf.writeByte('F'); + if (t.linkage == LINKc) + buf.writeByte('Y'); + Type tn = t.next; + if (t.isref) + tn = tn.referenceTo(); + tn.accept(this); + argsCppMangle(t.parameters, t.varargs); + buf.writeByte('E'); + store(t); + } + + override void visit(TypeDelegate t) + { + visit(cast(Type)t); + } + + override void visit(TypeStruct t) + { + const id = t.sym.ident; + //printf("struct id = '%s'\n", id.toChars()); + char c; + if (id == Id.__c_long) + c = 'l'; + else if (id == Id.__c_ulong) + c = 'm'; + else + c = 0; + if (c) { - const id = t.sym.ident; - //printf("struct id = '%s'\n", id.toChars()); - char c; - if (id == Id.__c_long) - c = 'l'; - else if (id == Id.__c_ulong) - c = 'm'; - else - c = 0; - if (c) - { - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - { - if (substitute(t)) - { - return; - } - else - { - store(t); - } - } - if (t.isConst()) - buf.writeByte('K'); - buf.writeByte(c); - return; - } - is_top_level = false; - if (substitute(t)) - return; if (t.isImmutable() || t.isShared()) { visit(cast(Type)t); } if (t.isConst()) - buf.writeByte('K'); - if (!substitute(t.sym)) - { - cpp_mangle_name(t.sym, t.isConst()); - } - if (t.isImmutable() || t.isShared()) { - visit(cast(Type)t); + if (substitute(t)) + { + return; + } + else + { + store(t); + } } if (t.isConst()) - store(t); + buf.writeByte('K'); + buf.writeByte(c); + return; + } + is_top_level = false; + if (substitute(t)) + return; + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); } + if (t.isConst()) + buf.writeByte('K'); - override void visit(TypeEnum t) + // Handle any target-specific struct types. + if (auto tm = Target.cppTypeMangle(t)) + { + buf.writestring(tm); + } + else { - is_top_level = false; - if (substitute(t)) - return; - if (t.isConst()) - buf.writeByte('K'); if (!substitute(t.sym)) { cpp_mangle_name(t.sym, t.isConst()); @@ -891,1113 +893,1107 @@ static if (IN_LLVM || TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPE { visit(cast(Type)t); } - if (t.isConst()) - store(t); } + if (t.isConst()) + store(t); + } - override void visit(TypeClass t) + override void visit(TypeEnum t) + { + is_top_level = false; + if (substitute(t)) + return; + if (t.isConst()) + buf.writeByte('K'); + if (!substitute(t.sym)) { - if (substitute(t)) - return; - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst() && !is_top_level) - buf.writeByte('K'); - is_top_level = false; - buf.writeByte('P'); - if (t.isConst()) - buf.writeByte('K'); - if (!substitute(t.sym)) - { - cpp_mangle_name(t.sym, t.isConst()); - } - if (t.isConst()) - store(null); - store(t); + cpp_mangle_name(t.sym, t.isConst()); } - - final const(char)* mangle_typeinfo(Dsymbol s) + if (t.isImmutable() || t.isShared()) { - buf.writestring("_ZTI"); - cpp_mangle_name(s, false); - return buf.extractString(); + visit(cast(Type)t); } + if (t.isConst()) + store(t); } -version(IN_LLVM) {} else { - extern (C++) const(char)* toCppMangle(Dsymbol s) + override void visit(TypeClass t) { - //printf("toCppMangle(%s)\n", s.toChars()); - scope CppMangleVisitor v = new CppMangleVisitor(); - return v.mangleOf(s); + if (substitute(t)) + return; + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); + } + if (t.isConst() && !is_top_level) + buf.writeByte('K'); + is_top_level = false; + buf.writeByte('P'); + if (t.isConst()) + buf.writeByte('K'); + if (!substitute(t.sym)) + { + cpp_mangle_name(t.sym, t.isConst()); + } + if (t.isConst()) + store(null); + store(t); } - extern (C++) const(char)* cppTypeInfoMangle(Dsymbol s) + final const(char)* mangle_typeinfo(Dsymbol s) { - //printf("cppTypeInfoMangle(%s)\n", s.toChars()); - scope CppMangleVisitor v = new CppMangleVisitor(); - return v.mangle_typeinfo(s); + buf.writestring("_ZTI"); + cpp_mangle_name(s, false); + return buf.extractString(); } } +extern (C++) const(char)* toCppMangleItanium(Dsymbol s) +{ + //printf("toCppMangleItanium(%s)\n", s.toChars()); + scope CppMangleVisitor v = new CppMangleVisitor(); + return v.mangleOf(s); } -static if (IN_LLVM || TARGET_WINDOS) + +extern (C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s) { - // Windows DMC and Microsoft Visual C++ mangling - enum VC_SAVED_TYPE_CNT = 10u; - enum VC_SAVED_IDENT_CNT = 10u; + //printf("cppTypeInfoMangle(%s)\n", s.toChars()); + scope CppMangleVisitor v = new CppMangleVisitor(); + return v.mangle_typeinfo(s); +} - extern (C++) final class VisualCPPMangler : Visitor - { - alias visit = super.visit; - const(char)*[VC_SAVED_IDENT_CNT] saved_idents; - Type[VC_SAVED_TYPE_CNT] saved_types; +// Windows DMC and Microsoft Visual C++ mangling +enum VC_SAVED_TYPE_CNT = 10u; +enum VC_SAVED_IDENT_CNT = 10u; - // IS_NOT_TOP_TYPE: when we mangling one argument, we can call visit several times (for base types of arg type) - // but we must save only arg type: - // For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int" - // This flag is set up by the visit(NextType, ) function and should be reset when the arg type output is finished. - // MANGLE_RETURN_TYPE: return type shouldn't be saved and substituted in arguments - // IGNORE_CONST: in some cases we should ignore CV-modifiers. +extern (C++) final class VisualCPPMangler : Visitor +{ + alias visit = super.visit; + const(char)*[VC_SAVED_IDENT_CNT] saved_idents; + Type[VC_SAVED_TYPE_CNT] saved_types; + + // IS_NOT_TOP_TYPE: when we mangling one argument, we can call visit several times (for base types of arg type) + // but we must save only arg type: + // For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int" + // This flag is set up by the visit(NextType, ) function and should be reset when the arg type output is finished. + // MANGLE_RETURN_TYPE: return type shouldn't be saved and substituted in arguments + // IGNORE_CONST: in some cases we should ignore CV-modifiers. + + enum Flags : int + { + IS_NOT_TOP_TYPE = 0x1, + MANGLE_RETURN_TYPE = 0x2, + IGNORE_CONST = 0x4, + IS_DMC = 0x8, + } - enum Flags : int - { - IS_NOT_TOP_TYPE = 0x1, - MANGLE_RETURN_TYPE = 0x2, - IGNORE_CONST = 0x4, - IS_DMC = 0x8, - } + alias IS_NOT_TOP_TYPE = Flags.IS_NOT_TOP_TYPE; + alias MANGLE_RETURN_TYPE = Flags.MANGLE_RETURN_TYPE; + alias IGNORE_CONST = Flags.IGNORE_CONST; + alias IS_DMC = Flags.IS_DMC; - alias IS_NOT_TOP_TYPE = Flags.IS_NOT_TOP_TYPE; - alias MANGLE_RETURN_TYPE = Flags.MANGLE_RETURN_TYPE; - alias IGNORE_CONST = Flags.IGNORE_CONST; - alias IS_DMC = Flags.IS_DMC; + int flags; + OutBuffer buf; - int flags; - OutBuffer buf; + extern (D) this(VisualCPPMangler rvl) + { + flags |= (rvl.flags & IS_DMC); + memcpy(&saved_idents, &rvl.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); + memcpy(&saved_types, &rvl.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT); + } - extern (D) this(VisualCPPMangler rvl) +public: + extern (D) this(bool isdmc) + { + if (isdmc) { - flags |= (rvl.flags & IS_DMC); - memcpy(&saved_idents, &rvl.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); - memcpy(&saved_types, &rvl.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT); + flags |= IS_DMC; } + memset(&saved_idents, 0, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); + memset(&saved_types, 0, Type.sizeof * VC_SAVED_TYPE_CNT); + } - public: - extern (D) this(bool isdmc) + override void visit(Type type) + { + if (type.isImmutable() || type.isShared()) { - if (isdmc) - { - flags |= IS_DMC; - } - memset(&saved_idents, 0, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); - memset(&saved_types, 0, Type.sizeof * VC_SAVED_TYPE_CNT); + type.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", type.toChars()); } - - override void visit(Type type) + else { - if (type.isImmutable() || type.isShared()) - { - type.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", type.toChars()); - } - else - { - type.error(Loc(), "Internal Compiler Error: unsupported type %s\n", type.toChars()); - } - fatal(); //Fatal, because this error should be handled in frontend + type.error(Loc(), "Internal Compiler Error: type %s can not be mapped to C++\n", type.toChars()); } + fatal(); //Fatal, because this error should be handled in frontend + } - override void visit(TypeBasic type) + override void visit(TypeBasic type) + { + //printf("visit(TypeBasic); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (type.isImmutable() || type.isShared()) { - //printf("visit(TypeBasic); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) - { - if (checkTypeSaved(type)) - return; - } - if ((type.ty == Tbool) && checkTypeSaved(type)) // try to replace long name with number - { + visit(cast(Type)type); + return; + } + if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) + { + if (checkTypeSaved(type)) return; - } - if (!(flags & IS_DMC)) - { - switch (type.ty) - { - case Tint64: - case Tuns64: - case Tint128: - case Tuns128: - case Tfloat80: - case Twchar: - if (checkTypeSaved(type)) - return; - break; - - default: - break; - } - } - mangleModifier(type); + } + if ((type.ty == Tbool) && checkTypeSaved(type)) // try to replace long name with number + { + return; + } + if (!(flags & IS_DMC)) + { switch (type.ty) { - case Tvoid: - buf.writeByte('X'); - break; - case Tint8: - buf.writeByte('C'); - break; - case Tuns8: - buf.writeByte('E'); - break; - case Tint16: - buf.writeByte('F'); - break; - case Tuns16: - buf.writeByte('G'); - break; - case Tint32: - buf.writeByte('H'); - break; - case Tuns32: - buf.writeByte('I'); - break; - case Tfloat32: - buf.writeByte('M'); - break; case Tint64: - buf.writestring("_J"); - break; case Tuns64: - buf.writestring("_K"); - break; case Tint128: - buf.writestring("_L"); - break; case Tuns128: - buf.writestring("_M"); - break; - case Tfloat64: - buf.writeByte('N'); - break; - case Tbool: - buf.writestring("_N"); - break; - case Tchar: - buf.writeByte('D'); - break; - case Tdchar: - buf.writeByte('I'); - break; - // unsigned int case Tfloat80: - if (flags & IS_DMC) - buf.writestring("_Z"); // DigitalMars long double - else - buf.writestring("_T"); // Intel long double - break; case Twchar: - if (flags & IS_DMC) - buf.writestring("_Y"); // DigitalMars wchar_t - else - buf.writestring("_W"); // Visual C++ wchar_t + if (checkTypeSaved(type)) + return; break; + default: - visit(cast(Type)type); - return; + break; } - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; } + mangleModifier(type); + switch (type.ty) + { + case Tvoid: + buf.writeByte('X'); + break; + case Tint8: + buf.writeByte('C'); + break; + case Tuns8: + buf.writeByte('E'); + break; + case Tint16: + buf.writeByte('F'); + break; + case Tuns16: + buf.writeByte('G'); + break; + case Tint32: + buf.writeByte('H'); + break; + case Tuns32: + buf.writeByte('I'); + break; + case Tfloat32: + buf.writeByte('M'); + break; + case Tint64: + buf.writestring("_J"); + break; + case Tuns64: + buf.writestring("_K"); + break; + case Tint128: + buf.writestring("_L"); + break; + case Tuns128: + buf.writestring("_M"); + break; + case Tfloat64: + buf.writeByte('N'); + break; + case Tbool: + buf.writestring("_N"); + break; + case Tchar: + buf.writeByte('D'); + break; + case Tdchar: + buf.writeByte('I'); + break; + // unsigned int + case Tfloat80: + if (flags & IS_DMC) + buf.writestring("_Z"); // DigitalMars long double + else + buf.writestring("_T"); // Intel long double + break; + case Twchar: + if (flags & IS_DMC) + buf.writestring("_Y"); // DigitalMars wchar_t + else + buf.writestring("_W"); // Visual C++ wchar_t + break; + default: + visit(cast(Type)type); + return; + } + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } + + override void visit(TypeVector type) + { + //printf("visit(TypeVector); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (checkTypeSaved(type)) + return; + buf.writestring("T__m128@@"); // may be better as __m128i or __m128d? + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } + + override void visit(TypeSArray type) + { + // This method can be called only for static variable type mangling. + //printf("visit(TypeSArray); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (checkTypeSaved(type)) + return; + // first dimension always mangled as const pointer + if (flags & IS_DMC) + buf.writeByte('Q'); + else + buf.writeByte('P'); + flags |= IS_NOT_TOP_TYPE; + assert(type.next); + if (type.next.ty == Tsarray) + { + mangleArray(cast(TypeSArray)type.next); + } + else + { + type.next.accept(this); + } + } - override void visit(TypeVector type) + // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation) + // There is not way to map int C++ (*arr)[2][1] to D + override void visit(TypePointer type) + { + //printf("visit(TypePointer); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (type.isImmutable() || type.isShared()) { - //printf("visit(TypeVector); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + visit(cast(Type)type); + return; + } + assert(type.next); + if (type.next.ty == Tfunction) + { + const(char)* arg = mangleFunctionType(cast(TypeFunction)type.next); // compute args before checking to save; args should be saved before function type + // If we've mangled this function early, previous call is meaningless. + // However we should do it before checking to save types of function arguments before function type saving. + // If this function was already mangled, types of all it arguments are save too, thus previous can't save + // anything if function is saved. if (checkTypeSaved(type)) return; - buf.writestring("T__m128@@"); // may be better as __m128i or __m128d? + if (type.isConst()) + buf.writeByte('Q'); // const + else + buf.writeByte('P'); // mutable + buf.writeByte('6'); // pointer to a function + buf.writestring(arg); flags &= ~IS_NOT_TOP_TYPE; flags &= ~IGNORE_CONST; + return; } - - override void visit(TypeSArray type) + else if (type.next.ty == Tsarray) { - // This method can be called only for static variable type mangling. - //printf("visit(TypeSArray); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); if (checkTypeSaved(type)) return; - // first dimension always mangled as const pointer - if (flags & IS_DMC) - buf.writeByte('Q'); + mangleModifier(type); + if (type.isConst() || !(flags & IS_DMC)) + buf.writeByte('Q'); // const else - buf.writeByte('P'); + buf.writeByte('P'); // mutable + if (global.params.is64bit) + buf.writeByte('E'); flags |= IS_NOT_TOP_TYPE; - assert(type.next); - if (type.next.ty == Tsarray) - { - mangleArray(cast(TypeSArray)type.next); - } - else - { - type.next.accept(this); - } + mangleArray(cast(TypeSArray)type.next); + return; } - - // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation) - // There is not way to map int C++ (*arr)[2][1] to D - override void visit(TypePointer type) + else { - //printf("visit(TypePointer); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - assert(type.next); - if (type.next.ty == Tfunction) - { - const(char)* arg = mangleFunctionType(cast(TypeFunction)type.next); // compute args before checking to save; args should be saved before function type - // If we've mangled this function early, previous call is meaningless. - // However we should do it before checking to save types of function arguments before function type saving. - // If this function was already mangled, types of all it arguments are save too, thus previous can't save - // anything if function is saved. - if (checkTypeSaved(type)) - return; - if (type.isConst()) - buf.writeByte('Q'); // const - else - buf.writeByte('P'); // mutable - buf.writeByte('6'); // pointer to a function - buf.writestring(arg); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; + if (checkTypeSaved(type)) return; - } - else if (type.next.ty == Tsarray) + mangleModifier(type); + if (type.isConst()) { - if (checkTypeSaved(type)) - return; - mangleModifier(type); - if (type.isConst() || !(flags & IS_DMC)) - buf.writeByte('Q'); // const - else - buf.writeByte('P'); // mutable - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - mangleArray(cast(TypeSArray)type.next); - return; + buf.writeByte('Q'); // const } else { - if (checkTypeSaved(type)) - return; - mangleModifier(type); - if (type.isConst()) - { - buf.writeByte('Q'); // const - } - else - { - buf.writeByte('P'); // mutable - } - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - type.next.accept(this); + buf.writeByte('P'); // mutable } + if (global.params.is64bit) + buf.writeByte('E'); + flags |= IS_NOT_TOP_TYPE; + type.next.accept(this); + } + } + + override void visit(TypeReference type) + { + //printf("visit(TypeReference); type = %s\n", type.toChars()); + if (checkTypeSaved(type)) + return; + if (type.isImmutable() || type.isShared()) + { + visit(cast(Type)type); + return; + } + buf.writeByte('A'); // mutable + if (global.params.is64bit) + buf.writeByte('E'); + flags |= IS_NOT_TOP_TYPE; + assert(type.next); + if (type.next.ty == Tsarray) + { + mangleArray(cast(TypeSArray)type.next); } + else + { + type.next.accept(this); + } + } - override void visit(TypeReference type) + override void visit(TypeFunction type) + { + const(char)* arg = mangleFunctionType(type); + if ((flags & IS_DMC)) { - //printf("visit(TypeReference); type = %s\n", type.toChars()); if (checkTypeSaved(type)) return; - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - buf.writeByte('A'); // mutable - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - assert(type.next); - if (type.next.ty == Tsarray) - { - mangleArray(cast(TypeSArray)type.next); - } - else - { - type.next.accept(this); - } } - - override void visit(TypeFunction type) + else { - const(char)* arg = mangleFunctionType(type); - if ((flags & IS_DMC)) - { - if (checkTypeSaved(type)) - return; - } - else - { - buf.writestring("$$A6"); - } - buf.writestring(arg); - flags &= ~(IS_NOT_TOP_TYPE | IGNORE_CONST); + buf.writestring("$$A6"); } + buf.writestring(arg); + flags &= ~(IS_NOT_TOP_TYPE | IGNORE_CONST); + } - override void visit(TypeStruct type) + override void visit(TypeStruct type) + { + const id = type.sym.ident; + char c; + if (id == Id.__c_long_double) + c = 'O'; // VC++ long double + else if (id == Id.__c_long) + c = 'J'; // VC++ long + else if (id == Id.__c_ulong) + c = 'K'; // VC++ unsigned long + else + c = 0; + if (c) { - const id = type.sym.ident; - char c; - if (id == Id.__c_long_double) - c = 'O'; // VC++ long double - else if (id == Id.__c_long) - c = 'J'; // VC++ long - else if (id == Id.__c_ulong) - c = 'K'; // VC++ unsigned long - else - c = 0; - if (c) + if (type.isImmutable() || type.isShared()) { - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) - { - if (checkTypeSaved(type)) - return; - } - mangleModifier(type); - buf.writeByte(c); + visit(cast(Type)type); + return; } - else + if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) { if (checkTypeSaved(type)) return; - //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - mangleModifier(type); - if (type.sym.isUnionDeclaration()) - buf.writeByte('T'); - else - buf.writeByte(type.cppmangle == CPPMANGLE.asClass ? 'V' : 'U'); - mangleIdent(type.sym); } - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; + mangleModifier(type); + buf.writeByte(c); } - - override void visit(TypeEnum type) + else { - //printf("visit(TypeEnum); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); if (checkTypeSaved(type)) return; + //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); mangleModifier(type); - buf.writeByte('W'); - switch (type.sym.memtype.ty) - { - case Tchar: - case Tint8: - buf.writeByte('0'); - break; - case Tuns8: - buf.writeByte('1'); - break; - case Tint16: - buf.writeByte('2'); - break; - case Tuns16: - buf.writeByte('3'); - break; - case Tint32: - buf.writeByte('4'); - break; - case Tuns32: - buf.writeByte('5'); - break; - case Tint64: - buf.writeByte('6'); - break; - case Tuns64: - buf.writeByte('7'); - break; - default: - visit(cast(Type)type); - break; - } + if (type.sym.isUnionDeclaration()) + buf.writeByte('T'); + else + buf.writeByte(type.cppmangle == CPPMANGLE.asClass ? 'V' : 'U'); mangleIdent(type.sym); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; } + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } - // D class mangled as pointer to C++ class - // const(Object) mangled as Object const* const - override void visit(TypeClass type) + override void visit(TypeEnum type) + { + //printf("visit(TypeEnum); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (checkTypeSaved(type)) + return; + mangleModifier(type); + buf.writeByte('W'); + switch (type.sym.memtype.ty) { - //printf("visit(TypeClass); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - if (flags & IS_NOT_TOP_TYPE) - mangleModifier(type); - if (type.isConst()) - buf.writeByte('Q'); - else - buf.writeByte('P'); - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - mangleModifier(type); - buf.writeByte(type.cppmangle == CPPMANGLE.asStruct ? 'U' : 'V'); - mangleIdent(type.sym); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; + case Tchar: + case Tint8: + buf.writeByte('0'); + break; + case Tuns8: + buf.writeByte('1'); + break; + case Tint16: + buf.writeByte('2'); + break; + case Tuns16: + buf.writeByte('3'); + break; + case Tint32: + buf.writeByte('4'); + break; + case Tuns32: + buf.writeByte('5'); + break; + case Tint64: + buf.writeByte('6'); + break; + case Tuns64: + buf.writeByte('7'); + break; + default: + visit(cast(Type)type); + break; } + mangleIdent(type.sym); + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } + + // D class mangled as pointer to C++ class + // const(Object) mangled as Object const* const + override void visit(TypeClass type) + { + //printf("visit(TypeClass); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (checkTypeSaved(type)) + return; + if (flags & IS_NOT_TOP_TYPE) + mangleModifier(type); + if (type.isConst()) + buf.writeByte('Q'); + else + buf.writeByte('P'); + if (global.params.is64bit) + buf.writeByte('E'); + flags |= IS_NOT_TOP_TYPE; + mangleModifier(type); + buf.writeByte(type.cppmangle == CPPMANGLE.asStruct ? 'U' : 'V'); + mangleIdent(type.sym); + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } - const(char)* mangleOf(Dsymbol s) + const(char)* mangleOf(Dsymbol s) + { + VarDeclaration vd = s.isVarDeclaration(); + FuncDeclaration fd = s.isFuncDeclaration(); + if (vd) { - VarDeclaration vd = s.isVarDeclaration(); - FuncDeclaration fd = s.isFuncDeclaration(); - if (vd) - { - mangleVariable(vd); - } - else if (fd) - { - mangleFunction(fd); - } - else - { - assert(0); - } - return buf.extractString(); + mangleVariable(vd); + } + else if (fd) + { + mangleFunction(fd); } + else + { + assert(0); + } + return buf.extractString(); + } - private: - void mangleFunction(FuncDeclaration d) +private: + void mangleFunction(FuncDeclaration d) + { + // ? + assert(d); + buf.writeByte('?'); + mangleIdent(d); + if (d.needThis()) // ::= { - // ? - assert(d); - buf.writeByte('?'); - mangleIdent(d); - if (d.needThis()) // ::= - { - // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ - //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", - //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); - if (d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) - { - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('E'); - break; - case PROTprotected: - buf.writeByte('M'); - break; - default: - buf.writeByte('U'); - break; - } - } - else - { - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('A'); - break; - case PROTprotected: - buf.writeByte('I'); - break; - default: - buf.writeByte('Q'); - break; - } - } - if (global.params.is64bit) - buf.writeByte('E'); - if (d.type.isConst()) - { - buf.writeByte('B'); - } - else - { - buf.writeByte('A'); - } - } - else if (d.isMember2()) // static function + // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ + //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", + //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); + if (d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) { - // ::= switch (d.protection.kind) { case PROTprivate: - buf.writeByte('C'); + buf.writeByte('E'); break; case PROTprotected: - buf.writeByte('K'); + buf.writeByte('M'); break; default: - buf.writeByte('S'); + buf.writeByte('U'); break; } } - else // top-level function - { - // ::= Y - buf.writeByte('Y'); - } - const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration()); - buf.writestring(args); - } - - void mangleVariable(VarDeclaration d) - { - // ::= ? - assert(d); - // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 - if (!(d.storage_class & (STCextern | STCfield | STCgshared))) - { - d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); - fatal(); - } - buf.writeByte('?'); - mangleIdent(d); - assert((d.storage_class & STCfield) || !d.needThis()); - Dsymbol parent = d.toParent(); - while (parent && parent.isNspace()) - { - parent = parent.toParent(); - } - if (parent && parent.isModule()) // static member - { - buf.writeByte('3'); - } else { switch (d.protection.kind) { case PROTprivate: - buf.writeByte('0'); + buf.writeByte('A'); break; case PROTprotected: - buf.writeByte('1'); + buf.writeByte('I'); break; default: - buf.writeByte('2'); + buf.writeByte('Q'); break; } } - char cv_mod = 0; - Type t = d.type; - if (t.isImmutable() || t.isShared()) + if (global.params.is64bit) + buf.writeByte('E'); + if (d.type.isConst()) { - visit(t); - return; + buf.writeByte('B'); } - if (t.isConst()) + else { - cv_mod = 'B'; // const + buf.writeByte('A'); } - else + } + else if (d.isMember2()) // static function + { + // ::= + switch (d.protection.kind) { - cv_mod = 'A'; // mutable + case PROTprivate: + buf.writeByte('C'); + break; + case PROTprotected: + buf.writeByte('K'); + break; + default: + buf.writeByte('S'); + break; } - if (t.ty != Tpointer) - t = t.mutableOf(); - t.accept(this); - if ((t.ty == Tpointer || t.ty == Treference || t.ty == Tclass) && global.params.is64bit) + } + else // top-level function + { + // ::= Y + buf.writeByte('Y'); + } + const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration()); + buf.writestring(args); + } + + void mangleVariable(VarDeclaration d) + { + // ::= ? + assert(d); + // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 + if (!(d.storage_class & (STCextern | STCfield | STCgshared))) + { + d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); + fatal(); + } + buf.writeByte('?'); + mangleIdent(d); + assert((d.storage_class & STCfield) || !d.needThis()); + Dsymbol parent = d.toParent(); + while (parent && parent.isNspace()) + { + parent = parent.toParent(); + } + if (parent && parent.isModule()) // static member + { + buf.writeByte('3'); + } + else + { + switch (d.protection.kind) { - buf.writeByte('E'); + case PROTprivate: + buf.writeByte('0'); + break; + case PROTprotected: + buf.writeByte('1'); + break; + default: + buf.writeByte('2'); + break; } - buf.writeByte(cv_mod); } + char cv_mod = 0; + Type t = d.type; + if (t.isImmutable() || t.isShared()) + { + visit(t); + return; + } + if (t.isConst()) + { + cv_mod = 'B'; // const + } + else + { + cv_mod = 'A'; // mutable + } + if (t.ty != Tpointer) + t = t.mutableOf(); + t.accept(this); + if ((t.ty == Tpointer || t.ty == Treference || t.ty == Tclass) && global.params.is64bit) + { + buf.writeByte('E'); + } + buf.writeByte(cv_mod); + } - void mangleName(Dsymbol sym, bool dont_use_back_reference = false) + void mangleName(Dsymbol sym, bool dont_use_back_reference = false) + { + //printf("mangleName('%s')\n", sym.toChars()); + const(char)* name = null; + bool is_dmc_template = false; + if (sym.isDtorDeclaration()) + { + buf.writestring("?1"); + return; + } + if (TemplateInstance ti = sym.isTemplateInstance()) { - //printf("mangleName('%s')\n", sym.toChars()); - const(char)* name = null; - bool is_dmc_template = false; - if (sym.isDtorDeclaration()) + scope VisualCPPMangler tmp = new VisualCPPMangler((flags & IS_DMC) ? true : false); + tmp.buf.writeByte('?'); + tmp.buf.writeByte('$'); + tmp.buf.writestring(ti.name.toChars()); + tmp.saved_idents[0] = ti.name.toChars(); + tmp.buf.writeByte('@'); + if (flags & IS_DMC) { - buf.writestring("?1"); - return; + tmp.mangleIdent(sym.parent, true); + is_dmc_template = true; } - if (TemplateInstance ti = sym.isTemplateInstance()) + bool is_var_arg = false; + for (size_t i = 0; i < ti.tiargs.dim; i++) { - scope VisualCPPMangler tmp = new VisualCPPMangler((flags & IS_DMC) ? true : false); - tmp.buf.writeByte('?'); - tmp.buf.writeByte('$'); - tmp.buf.writestring(ti.name.toChars()); - tmp.saved_idents[0] = ti.name.toChars(); - tmp.buf.writeByte('@'); - if (flags & IS_DMC) + RootObject o = (*ti.tiargs)[i]; + TemplateParameter tp = null; + TemplateValueParameter tv = null; + TemplateTupleParameter tt = null; + if (!is_var_arg) { - tmp.mangleIdent(sym.parent, true); - is_dmc_template = true; + TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); + assert(td); + tp = (*td.parameters)[i]; + tv = tp.isTemplateValueParameter(); + tt = tp.isTemplateTupleParameter(); } - bool is_var_arg = false; - for (size_t i = 0; i < ti.tiargs.dim; i++) + if (tt) { - RootObject o = (*ti.tiargs)[i]; - TemplateParameter tp = null; - TemplateValueParameter tv = null; - TemplateTupleParameter tt = null; - if (!is_var_arg) - { - TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); - assert(td); - tp = (*td.parameters)[i]; - tv = tp.isTemplateValueParameter(); - tt = tp.isTemplateTupleParameter(); - } - if (tt) - { - is_var_arg = true; - tp = null; - } - if (tv) + is_var_arg = true; + tp = null; + } + if (tv) + { + if (tv.valType.isintegral()) { - if (tv.valType.isintegral()) + tmp.buf.writeByte('$'); + tmp.buf.writeByte('0'); + Expression e = isExpression(o); + assert(e); + if (tv.valType.isunsigned()) { - tmp.buf.writeByte('$'); - tmp.buf.writeByte('0'); - Expression e = isExpression(o); - assert(e); - if (tv.valType.isunsigned()) - { - tmp.mangleNumber(e.toUInteger()); - } - else if (is_dmc_template) - { - // NOTE: DMC mangles everything based on - // unsigned int - tmp.mangleNumber(e.toInteger()); - } - else - { - sinteger_t val = e.toInteger(); - if (val < 0) - { - val = -val; - tmp.buf.writeByte('?'); - } - tmp.mangleNumber(val); - } + tmp.mangleNumber(e.toUInteger()); + } + else if (is_dmc_template) + { + // NOTE: DMC mangles everything based on + // unsigned int + tmp.mangleNumber(e.toInteger()); } else { - sym.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); - fatal(); + sinteger_t val = e.toInteger(); + if (val < 0) + { + val = -val; + tmp.buf.writeByte('?'); + } + tmp.mangleNumber(val); } } - else if (!tp || tp.isTemplateTypeParameter()) + else + { + sym.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); + fatal(); + } + } + else if (!tp || tp.isTemplateTypeParameter()) + { + Type t = isType(o); + assert(t); + t.accept(tmp); + } + else if (tp.isTemplateAliasParameter()) + { + Dsymbol d = isDsymbol(o); + Expression e = isExpression(o); + if (!d && !e) { - Type t = isType(o); - assert(t); - t.accept(tmp); + sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); + fatal(); } - else if (tp.isTemplateAliasParameter()) + if (d && d.isFuncDeclaration()) { - Dsymbol d = isDsymbol(o); - Expression e = isExpression(o); - if (!d && !e) - { - sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); - fatal(); - } - if (d && d.isFuncDeclaration()) - { - tmp.buf.writeByte('$'); + tmp.buf.writeByte('$'); + tmp.buf.writeByte('1'); + tmp.mangleFunction(d.isFuncDeclaration()); + } + else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) + { + tmp.buf.writeByte('$'); + if (flags & IS_DMC) tmp.buf.writeByte('1'); - tmp.mangleFunction(d.isFuncDeclaration()); - } - else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) + else + tmp.buf.writeByte('E'); + tmp.mangleVariable((cast(VarExp)e).var.isVarDeclaration()); + } + else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) + { + Dsymbol ds = d.isTemplateDeclaration().onemember; + if (flags & IS_DMC) { - tmp.buf.writeByte('$'); - if (flags & IS_DMC) - tmp.buf.writeByte('1'); - else - tmp.buf.writeByte('E'); - tmp.mangleVariable((cast(VarExp)e).var.isVarDeclaration()); + tmp.buf.writeByte('V'); } - else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) + else { - Dsymbol ds = d.isTemplateDeclaration().onemember; - if (flags & IS_DMC) + if (ds.isUnionDeclaration()) + { + tmp.buf.writeByte('T'); + } + else if (ds.isStructDeclaration()) + { + tmp.buf.writeByte('U'); + } + else if (ds.isClassDeclaration()) { tmp.buf.writeByte('V'); } else { - if (ds.isUnionDeclaration()) - { - tmp.buf.writeByte('T'); - } - else if (ds.isStructDeclaration()) - { - tmp.buf.writeByte('U'); - } - else if (ds.isClassDeclaration()) - { - tmp.buf.writeByte('V'); - } - else - { - sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); - fatal(); - } + sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + fatal(); } - tmp.mangleIdent(d); - } - else - { - sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); - fatal(); } + tmp.mangleIdent(d); } else { - sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); fatal(); } } - name = tmp.buf.extractString(); - } - else - { - name = sym.ident.toChars(); - } - assert(name); - if (is_dmc_template) - { - if (checkAndSaveIdent(name)) - return; - } - else - { - if (dont_use_back_reference) - { - saveIdent(name); - } else { - if (checkAndSaveIdent(name)) - return; + sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + fatal(); } } - buf.writestring(name); - buf.writeByte('@'); + name = tmp.buf.extractString(); } - - // returns true if name already saved - bool checkAndSaveIdent(const(char)* name) + else { - foreach (i; 0 .. VC_SAVED_IDENT_CNT) - { - if (!saved_idents[i]) // no saved same name - { - saved_idents[i] = name; - break; - } - if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name - { - buf.writeByte(i + '0'); - return true; - } - } - return false; + name = sym.ident.toChars(); } - - void saveIdent(const(char)* name) + assert(name); + if (is_dmc_template) + { + if (checkAndSaveIdent(name)) + return; + } + else { - foreach (i; 0 .. VC_SAVED_IDENT_CNT) + if (dont_use_back_reference) { - if (!saved_idents[i]) // no saved same name - { - saved_idents[i] = name; - break; - } - if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name - { + saveIdent(name); + } + else + { + if (checkAndSaveIdent(name)) return; - } } } + buf.writestring(name); + buf.writeByte('@'); + } - void mangleIdent(Dsymbol sym, bool dont_use_back_reference = false) - { - // ::= @ - // ::= - // ::= - // ::= @ - // ::= ?$ @