Hi,

With this patch, symbols with `extern(D)` linkage are now mangled using
back references to types and identifiers if these occur more than once
in the mangled name as emitted before.  This reduces symbol length,
especially with chained expressions of templated functions with
Voldemort return types.

For example, the average symbol length of the 127000+ symbols created by
a libphobos unittest build is reduced by a factor of about 3, while the
longest symbol shrinks from 416133 to 1142 characters.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, with
some further testing done on x86_64-apple-darwin.

Committed to mainline.

Regards
Iain.

---
gcc/d/ChangeLog:

        * dmd/MERGE: Merge upstream dmd 2bd4fc3fe.
---
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/dmangle.c                           | 319 +++++++++++++++---
 gcc/d/dmd/dtemplate.c                         | 116 +------
 .../gdc.test/compilable/testInference.d       |   6 +-
 .../gdc.test/fail_compilation/fail12485.d     |   9 +-
 .../gdc.test/runnable/imports/testmangle.d    |  66 ++++
 gcc/testsuite/gdc.test/runnable/link6574.d    |  10 +-
 gcc/testsuite/gdc.test/runnable/mangle.d      |  82 +++--
 gcc/testsuite/gdc.test/runnable/template4.d   |  31 +-
 gcc/testsuite/gdc.test/runnable/template9.d   |  13 +-
 gcc/testsuite/gdc.test/runnable/testconst.d   |   3 +-
 11 files changed, 429 insertions(+), 228 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/runnable/imports/testmangle.d

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 4fa62a9f56a..1f695b9d23c 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-45fa6cfd20827bb4252a616dc789514a1e673687
+2bd4fc3fed8b8cd9760e77c6b2a1905cd84d0e70
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/dmangle.c b/gcc/d/dmd/dmangle.c
index 8f869266871..f6eee52afbf 100644
--- a/gcc/d/dmd/dmangle.c
+++ b/gcc/d/dmd/dmangle.c
@@ -10,6 +10,7 @@
 
 #include "root/dsystem.h"
 #include "root/root.h"
+#include "root/aav.h"
 
 #include "mangle.h"
 #include "init.h"
@@ -133,13 +134,114 @@ void MODtoDecoBuffer(OutBuffer *buf, MOD mod)
 class Mangler : public Visitor
 {
 public:
+    AA *types;
+    AA *idents;
     OutBuffer *buf;
 
     Mangler(OutBuffer *buf)
     {
+        this->types = NULL;
+        this->idents = NULL;
         this->buf = buf;
     }
 
+    /**
+    * writes a back reference with the relative position encoded with base 26
+    *  using upper case letters for all digits but the last digit which uses
+    *  a lower case letter.
+    * The decoder has to look up the referenced position to determine
+    *  whether the back reference is an identifer (starts with a digit)
+    *  or a type (starts with a letter).
+    *
+    * Params:
+    *  pos           = relative position to encode
+    */
+    void writeBackRef(size_t pos)
+    {
+        buf->writeByte('Q');
+        const size_t base = 26;
+        size_t mul = 1;
+        while (pos >= mul * base)
+            mul *= base;
+        while (mul >= base)
+        {
+            unsigned char dig = (unsigned char)(pos / mul);
+            buf->writeByte('A' + dig);
+            pos -= dig * mul;
+            mul /= base;
+        }
+        buf->writeByte('a' + (unsigned char)pos);
+    }
+
+    /**
+    * Back references a non-basic type
+    *
+    * The encoded mangling is
+    *       'Q' <relative position of first occurrence of type>
+    *
+    * Params:
+    *  t = the type to encode via back referencing
+    *
+    * Returns:
+    *  true if the type was found. A back reference has been encoded.
+    *  false if the type was not found. The current position is saved for 
later back references.
+    */
+    bool backrefType(Type *t)
+    {
+        if (!t->isTypeBasic())
+        {
+            size_t *p = (size_t *)dmd_aaGet(&types, (void *)t);
+            if (*p)
+            {
+                writeBackRef(buf->length() - *p);
+                return true;
+            }
+            *p = buf->length();
+        }
+        return false;
+    }
+
+    /**
+    * Back references a single identifier
+    *
+    * The encoded mangling is
+    *       'Q' <relative position of first occurrence of type>
+    *
+    * Params:
+    *  id = the identifier to encode via back referencing
+    *
+    * Returns:
+    *  true if the identifier was found. A back reference has been encoded.
+    *  false if the identifier was not found. The current position is saved 
for later back references.
+    */
+    bool backrefIdentifier(Identifier *id)
+    {
+        size_t *p = (size_t *)dmd_aaGet(&idents, (void *)id);
+        if (*p)
+        {
+            writeBackRef(buf->length() - *p);
+            return true;
+        }
+        *p = buf->length();
+        return false;
+    }
+
+    void mangleSymbol(Dsymbol *s)
+    {
+        s->accept(this);
+    }
+
+    void mangleType(Type *t)
+    {
+        if (!backrefType(t))
+            t->accept(this);
+    }
+
+    void mangleIdentifier(Identifier *id, Dsymbol *s)
+    {
+        if (!backrefIdentifier(id))
+            toBuffer(id->toChars(), s);
+    }
 
     
////////////////////////////////////////////////////////////////////////////
 
@@ -153,7 +255,7 @@ public:
         {
             MODtoDecoBuffer(buf, t->mod);
         }
-        t->accept(this);
+        mangleType(t);
     }
 
     void visit(Type *t)
@@ -207,8 +309,9 @@ public:
     void mangleFuncType(TypeFunction *t, TypeFunction *ta, unsigned char 
modMask, Type *tret)
     {
         //printf("mangleFuncType() %s\n", t->toChars());
-        if (t->inuse)
+        if (t->inuse && tret)
         {
+            // printf("TypeFunction.mangleFuncType() t = %s inuse\n", 
t->toChars());
             t->inuse = 2;       // flag error to caller
             return;
         }
@@ -280,35 +383,29 @@ public:
     void visit(TypeEnum *t)
     {
         visit((Type *)t);
-        t->sym->accept(this);
+        mangleSymbol(t->sym);
     }
 
     void visit(TypeStruct *t)
     {
         //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), 
name);
         visit((Type *)t);
-        t->sym->accept(this);
+        mangleSymbol(t->sym);
     }
 
     void visit(TypeClass *t)
     {
         //printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", 
t->toChars(), mod, name);
         visit((Type *)t);
-        t->sym->accept(this);
+        mangleSymbol(t->sym);
     }
 
     void visit(TypeTuple *t)
     {
         //printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars());
         visit((Type *)t);
-
-        OutBuffer buf2;
-        buf2.reserve(32);
-        Mangler v(&buf2);
-        v.paramsToDecoBuffer(t->arguments);
-        const char *s = buf2.peekChars();
-        int len = (int)buf2.length();
-        buf->printf("%d%.*s", len, len, s);
+        paramsToDecoBuffer(t->arguments);
+        buf->writeByte('Z');
     }
 
     void visit(TypeNull *t)
@@ -323,16 +420,14 @@ public:
         mangleParent(sthis);
 
         assert(sthis->ident);
-        const char *id = sthis->ident->toChars();
-        toBuffer(id, sthis);
-
+        mangleIdentifier(sthis->ident, sthis);
         if (FuncDeclaration *fd = sthis->isFuncDeclaration())
         {
             mangleFunc(fd, false);
         }
-        else if (sthis->type->deco)
+        else if (sthis->type)
         {
-            buf->writestring(sthis->type->deco);
+            visitWithMask(sthis->type, 0);
         }
         else
             assert(0);
@@ -349,12 +444,14 @@ public:
         if (p)
         {
             mangleParent(p);
-
-            if (p->getIdent())
+            TemplateInstance *ti = p->isTemplateInstance();
+            if (ti && !ti->isTemplateMixin())
             {
-                const char *id = p->ident->toChars();
-                toBuffer(id, s);
-
+                mangleTemplateInstance(ti);
+            }
+            else if (p->getIdent())
+            {
+                mangleIdentifier(p->ident, s);
                 if (FuncDeclaration *f = p->isFuncDeclaration())
                     mangleFunc(f, true);
             }
@@ -375,13 +472,13 @@ public:
             TypeFunction *tfo = (TypeFunction *)fd->originalType;
             mangleFuncType(tf, tfo, 0, NULL);
         }
-        else if (fd->type->deco)
+        else if (fd->type)
         {
-            buf->writestring(fd->type->deco);
+            visitWithMask(fd->type, 0);
         }
         else
         {
-            printf("[%s] %s %s\n", fd->loc.toChars(), fd->toChars(), 
fd->type->toChars());
+            printf("[%s] %s no type\n", fd->loc.toChars(), fd->toChars());
             assert(0);  // don't mangle function until semantic3 done.
         }
     }
@@ -392,8 +489,8 @@ public:
     void toBuffer(const char *id, Dsymbol *s)
     {
         size_t len = strlen(id);
-        if (len >= 8 * 1024 * 1024)         // 8 megs ought be enough for 
anyone
-            s->error("excessive length %llu for symbol, possible recursive 
expansion?", len);
+        if (buf->length() + len >= 8 * 1024 * 1024) // 8 megs ought be enough 
for anyone
+            s->error("excessive length %llu for symbol, possible recursive 
expansion?", buf->length() + len);
         else
         {
             buf->printf("%llu", (ulonglong)len);
@@ -401,39 +498,40 @@ public:
         }
     }
 
-    void visit(Declaration *d)
+    static const char *externallyMangledIdentifier(Declaration *d)
     {
-        //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage 
= %d)\n",
-        //        d, d->toChars(), d->parent ? d->parent->toChars() : "null", 
d->linkage);
         if (!d->parent || d->parent->isModule() || d->linkage == LINKcpp) // 
if at global scope
         {
             switch (d->linkage)
             {
                 case LINKd:
                     break;
-
                 case LINKc:
                 case LINKwindows:
                 case LINKobjc:
-                    buf->writestring(d->ident->toChars());
-                    return;
-
+                    return d->ident->toChars();
                 case LINKcpp:
-                    buf->writestring(target.cpp.toMangle(d));
-                    return;
-
+                    return target.cpp.toMangle(d);
                 case LINKdefault:
                     d->error("forward declaration");
-                    buf->writestring(d->ident->toChars());
-                    return;
-
+                    return d->ident->toChars();
                 default:
                     fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), 
d->linkage);
                     assert(0);
-                    return;
             }
         }
+        return NULL;
+    }
 
+    void visit(Declaration *d)
+    {
+        //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage 
= %d)\n",
+        //        d, d->toChars(), d->parent ? d->parent->toChars() : "null", 
d->linkage);
+        if (const char *id = externallyMangledIdentifier(d))
+        {
+            buf->writestring(id);
+            return;
+        }
         buf->writestring("_D");
         mangleDecl(d);
     }
@@ -481,7 +579,7 @@ public:
         }
         if (fa)
         {
-            fa->accept(this);
+            mangleSymbol(fa);
             return;
         }
         visit((Dsymbol *)fd);
@@ -507,7 +605,7 @@ public:
         {
             if (!od->hasOverloads || td->overnext == NULL)
             {
-                td->accept(this);
+                mangleSymbol(td);
                 return;
             }
         }
@@ -586,20 +684,131 @@ public:
         else
             mangleParent(ti);
 
-        ti->getIdent();
-        const char *id = ti->ident ? ti->ident->toChars() : ti->toChars();
-        toBuffer(id, ti);
+        if (ti->isTemplateMixin() && ti->ident)
+            mangleIdentifier(ti->ident, ti);
+        else
+            mangleTemplateInstance(ti);
+    }
+
+    void mangleTemplateInstance(TemplateInstance *ti)
+    {
+        TemplateDeclaration *tempdecl = ti->tempdecl->isTemplateDeclaration();
+        assert(tempdecl);
+
+        // Use "__U" for the symbols declared inside template constraint.
+        const char T = ti->members ? 'T' : 'U';
+        buf->printf("__%c", T);
+        mangleIdentifier(tempdecl->ident, tempdecl);
 
-        //printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), 
ti->id);
+        Objects *args = ti->tiargs;
+        size_t nparams = tempdecl->parameters->length - 
(tempdecl->isVariadic() ? 1 : 0);
+        for (size_t i = 0; i < args->length; i++)
+        {
+            RootObject *o = (*args)[i];
+            Type *ta = isType(o);
+            Expression *ea = isExpression(o);
+            Dsymbol *sa = isDsymbol(o);
+            Tuple *va = isTuple(o);
+            //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, 
sa, va);
+            if (i < nparams && (*tempdecl->parameters)[i]->specialization())
+                buf->writeByte('H'); // 
https://issues.dlang.org/show_bug.cgi?id=6574
+            if (ta)
+            {
+                buf->writeByte('T');
+                visitWithMask(ta, 0);
+            }
+            else if (ea)
+            {
+                // Don't interpret it yet, it might actually be an alias 
template parameter.
+                // Only constfold manifest constants, not const/immutable 
lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
+                const bool keepLvalue = true;
+                ea = ea->optimize(WANTvalue, keepLvalue);
+                if (ea->op == TOKvar)
+                {
+                    sa = ((VarExp *)ea)->var;
+                    ea = NULL;
+                    goto Lsa;
+                }
+                if (ea->op == TOKthis)
+                {
+                    sa = ((ThisExp *)ea)->var;
+                    ea = NULL;
+                    goto Lsa;
+                }
+                if (ea->op == TOKfunction)
+                {
+                    if (((FuncExp *)ea)->td)
+                        sa = ((FuncExp *)ea)->td;
+                    else
+                        sa = ((FuncExp *)ea)->fd;
+                    ea = NULL;
+                    goto Lsa;
+                }
+                buf->writeByte('V');
+                if (ea->op == TOKtuple)
+                {
+                    ea->error("tuple is not a valid template value argument");
+                    continue;
+                }
+                // Now that we know it is not an alias, we MUST obtain a value
+                unsigned olderr = global.errors;
+                ea = ea->ctfeInterpret();
+                if (ea->op == TOKerror || olderr != global.errors)
+                    continue;
+
+                /* Use type mangling that matches what it would be for a 
function parameter
+                */
+                visitWithMask(ea->type, 0);
+                ea->accept(this);
+            }
+            else if (sa)
+            {
+            Lsa:
+                sa = sa->toAlias();
+                if (Declaration *d = sa->isDeclaration())
+                {
+                    if (FuncAliasDeclaration *fad = 
d->isFuncAliasDeclaration())
+                        d = fad->toAliasFunc();
+                    if (d->mangleOverride.length)
+                    {
+                        buf->writeByte('X');
+                        toBuffer(d->mangleOverride.ptr, d);
+                        continue;
+                    }
+                    if (const char *id = externallyMangledIdentifier(d))
+                    {
+                        buf->writeByte('X');
+                        toBuffer(id, d);
+                        continue;
+                    }
+                    if (!d->type || !d->type->deco)
+                    {
+                        ti->error("forward reference of %s %s", d->kind(), 
d->toChars());
+                        continue;
+                    }
+                }
+                buf->writeByte('S');
+                mangleSymbol(sa);
+            }
+            else if (va)
+            {
+                assert(i + 1 == args->length); // must be last one
+                args = &va->objects;
+                i = -(size_t)1;
+            }
+            else
+                assert(0);
+        }
+        buf->writeByte('Z');
     }
 
     void visit(Dsymbol *s)
     {
         mangleParent(s);
-
-        const char *id = s->ident ? s->ident->toChars() : s->toChars();
-        toBuffer(id, s);
-
+        if (s->ident)
+            mangleIdentifier(s->ident, s);
+        else
+            toBuffer(s->toChars(), s);
         //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id);
     }
 
@@ -859,3 +1068,9 @@ void mangleToBuffer(Dsymbol *s, OutBuffer *buf)
     Mangler v(buf);
     s->accept(&v);
 }
+
+void mangleToBuffer(TemplateInstance *ti, OutBuffer *buf)
+{
+    Mangler v(buf);
+    v.mangleTemplateInstance(ti);
+}
diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c
index caa8a5ba9f4..fe65bd23e3c 100644
--- a/gcc/d/dmd/dtemplate.c
+++ b/gcc/d/dmd/dtemplate.c
@@ -7546,122 +7546,12 @@ Dsymbols *TemplateInstance::appendToModuleMember()
 
 Identifier *TemplateInstance::genIdent(Objects *args)
 {
-    TemplateDeclaration *tempdecl = this->tempdecl->isTemplateDeclaration();
-    assert(tempdecl);
-
     //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars());
+    assert(args == tiargs);
     OutBuffer buf;
-    const char *id = tempdecl->ident->toChars();
-    if (!members)
-    {
-        // Use "__U" for the symbols declared inside template constraint.
-        buf.printf("__U%llu%s", (ulonglong)strlen(id), id);
-    }
-    else
-        buf.printf("__T%llu%s", (ulonglong)strlen(id), id);
-    size_t nparams = tempdecl->parameters->length - (tempdecl->isVariadic() ? 
1 : 0);
-    for (size_t i = 0; i < args->length; i++)
-    {
-        RootObject *o = (*args)[i];
-        Type *ta = isType(o);
-        Expression *ea = isExpression(o);
-        Dsymbol *sa = isDsymbol(o);
-        Tuple *va = isTuple(o);
-        //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, 
va);
-        if (i < nparams && (*tempdecl->parameters)[i]->specialization())
-            buf.writeByte('H');     // Bugzilla 6574
-        if (ta)
-        {
-            buf.writeByte('T');
-            if (ta->deco)
-                buf.writestring(ta->deco);
-            else
-            {
-                assert(global.errors);
-            }
-        }
-        else if (ea)
-        {
-            // Don't interpret it yet, it might actually be an alias template 
parameter.
-            // Only constfold manifest constants, not const/immutable lvalues, 
see https://issues.dlang.org/show_bug.cgi?id=17339.
-            const bool keepLvalue = true;
-            ea = ea->optimize(WANTvalue, keepLvalue);
-            if (ea->op == TOKvar)
-            {
-                sa = ((VarExp *)ea)->var;
-                ea = NULL;
-                goto Lsa;
-            }
-            if (ea->op == TOKthis)
-            {
-                sa = ((ThisExp *)ea)->var;
-                ea = NULL;
-                goto Lsa;
-            }
-            if (ea->op == TOKfunction)
-            {
-                if (((FuncExp *)ea)->td)
-                    sa = ((FuncExp *)ea)->td;
-                else
-                    sa = ((FuncExp *)ea)->fd;
-                ea = NULL;
-                goto Lsa;
-            }
-            buf.writeByte('V');
-            if (ea->op == TOKtuple)
-            {
-                ea->error("tuple is not a valid template value argument");
-                continue;
-            }
-            // Now that we know it is not an alias, we MUST obtain a value
-            unsigned olderr = global.errors;
-            ea = ea->ctfeInterpret();
-            if (ea->op == TOKerror || olderr != global.errors)
-                continue;
-
-            /* Use deco that matches what it would be for a function parameter
-             */
-            buf.writestring(ea->type->deco);
-            mangleToBuffer(ea, &buf);
-        }
-        else if (sa)
-        {
-          Lsa:
-            buf.writeByte('S');
-            sa = sa->toAlias();
-            Declaration *d = sa->isDeclaration();
-            if (d && (!d->type || !d->type->deco))
-            {
-                error("forward reference of %s %s", d->kind(), d->toChars());
-                continue;
-            }
-
-            OutBuffer bufsa;
-            mangleToBuffer(sa, &bufsa);
-            const char *s = bufsa.extractChars();
-
-            /* Bugzilla 3043: if the first character of s is a digit this
-             * causes ambiguity issues because the digits of the two numbers 
are adjacent.
-             * Current demanglers resolve this by trying various places to 
separate the
-             * numbers until one gets a successful demangle.
-             * Unfortunately, fixing this ambiguity will break existing binary
-             * compatibility and the demanglers, so we'll leave it as is.
-             */
-            buf.printf("%u%s", (unsigned)strlen(s), s);
-        }
-        else if (va)
-        {
-            assert(i + 1 == args->length);         // must be last one
-            args = &va->objects;
-            i = -(size_t)1;
-        }
-        else
-            assert(0);
-    }
-    buf.writeByte('Z');
-    id = buf.peekChars();
+    mangleToBuffer(this, &buf);
     //printf("\tgenIdent = %s\n", id);
-    return Identifier::idPool(id);
+    return Identifier::idPool(buf.peekChars());
 }
 
 /*************************************
diff --git a/gcc/testsuite/gdc.test/compilable/testInference.d 
b/gcc/testsuite/gdc.test/compilable/testInference.d
index 95f4fcba259..5a8e1e26ac6 100644
--- a/gcc/testsuite/gdc.test/compilable/testInference.d
+++ b/gcc/testsuite/gdc.test/compilable/testInference.d
@@ -261,11 +261,13 @@ void test8234()
 /***************************************************/
 // 8504
 
+import core.demangle : demangle;
+
 void foo8504()()
 {
     static assert(typeof(foo8504!()).stringof == "void()");
     static assert(typeof(foo8504!()).mangleof == "FZv");
-    static assert(foo8504!().mangleof == 
"_D13testInference12__T7foo8504Z7foo8504FZv");
+    static assert(demangle(foo8504!().mangleof) == "void 
testInference.foo8504!().foo8504()");
 }
 
 auto toDelegate8504a(F)(auto ref F fp) { return fp; }
@@ -277,7 +279,7 @@ void test8504()
 {
     static assert(typeof(foo8504!()).stringof == "pure nothrow @nogc @safe 
void()");
     static assert(typeof(foo8504!()).mangleof == "FNaNbNiNfZv");
-    static assert(foo8504!().mangleof == 
"_D13testInference12__T7foo8504Z7foo8504FNaNbNiNfZv");
+    static assert(demangle(foo8504!().mangleof) == "pure nothrow @nogc @safe 
void testInference.foo8504!().foo8504()");
 
     auto fp1 = toDelegate8504a(&testC8504);
     auto fp2 = toDelegate8504b(&testC8504);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12485.d 
b/gcc/testsuite/gdc.test/fail_compilation/fail12485.d
index 71f8698db99..e1b15774f81 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12485.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12485.d
@@ -1,11 +1,12 @@
 void dorecursive()
 {
-    recursive([0]);
+    
recursive!"ratherLongSymbolNameToHitTheMaximumSymbolLengthEarlierThanTheTemplateRecursionLimit_";
 }
 
-void recursive(R)(R r)
+void recursive(string name)()
 {
-    import std.algorithm;
-    recursive( r.filter!(e=>true) );
+    struct S {} // define type to kick off mangler
+    static if (name.length <= (4 << 20))
+        recursive!(name ~ name);
 }
 
diff --git a/gcc/testsuite/gdc.test/runnable/imports/testmangle.d 
b/gcc/testsuite/gdc.test/runnable/imports/testmangle.d
new file mode 100644
index 00000000000..5311a8360da
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/testmangle.d
@@ -0,0 +1,66 @@
+// helper for mangling tests with back references
+
+module imports.testmangle;
+
+public import core.demangle : demangle, demangleType;
+
+// detect mangle version
+private
+{
+    struct Detect;
+    Detect* detectMangle(Detect*);
+    void DetectTmpl(T)() {}
+}
+
+pragma(msg,detectMangle.mangleof);
+static if(detectMangle.mangleof == 
"_D7imports10testmangle12detectMangleFPSQL3H6DetectZQ1e")
+    enum { BackRefs = true, BackRefSymbols = true }
+else static if(detectMangle.mangleof == 
"_D7imports10testmangle12detectMangleFPSQBlQBg6DetectZQq")
+    enum { BackRefs = true, BackRefSymbols = false }
+else static if(detectMangle.mangleof == 
"_D7imports10testmangle12detectMangleFPS7imports10testmangle6DetectZPS7imports10testmangle6Detect")
+    enum { BackRefs = false, BackRefSymbols = false }
+else
+    static assert(false, "unknown mangling");
+
+private enum tmplMangle = (DetectTmpl!int).mangleof;
+pragma(msg,tmplMangle);
+static if(tmplMangle[0..40] == "_D7imports10testmangle__T10DetectTmplTiZ")
+    enum HasTemplateLength = false;
+else static if(tmplMangle[0..42] == 
"_D7imports10testmangle18__T10DetectTmplTiZ")
+    enum HasTemplateLength = true;
+else
+    static assert(false, "unknown mangling");
+
+pragma(msg,BackRefs);
+pragma(msg,BackRefSymbols);
+
+static if (BackRefs)
+{
+    string tl(string s)() { return null; }
+    string id(string s, string r, string r2 = null)() { return BackRefSymbols 
&& r2 !is null ? r2 : r; }
+}
+else
+{
+    string tl(string s)() { return HasTemplateLength ? s : null; }
+    string id(string s, string r, string r2 = null)() { return s; }
+}
+
+bool equalDemangle(string m1, string m2)
+{
+    auto dm1 = demangle(m1);
+    auto dm2 = demangle(m2);
+    return dm1 == dm2;
+}
+
+string unsignedToString(ulong x)
+{
+    string s;
+    s ~= cast(char)('0' + (x % 10));
+    x /= 10;
+    while (x > 0)
+    {
+        s = cast(char)('0' + (x % 10)) ~ s;
+        x /= 10;
+    }
+    return s;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/link6574.d 
b/gcc/testsuite/gdc.test/runnable/link6574.d
index 0f97ed716c2..ab5e552536b 100644
--- a/gcc/testsuite/gdc.test/runnable/link6574.d
+++ b/gcc/testsuite/gdc.test/runnable/link6574.d
@@ -1,16 +1,18 @@
 // PERMUTE_ARGS:
 module link6574;
 
+import imports.testmangle;
+
 enum Method { A, B, }
 
 int foo(Method method = Method.A)()
 {
-    static assert(foo.mangleof == 
"_D8link657428__T3fooVE8link65746Methodi0Z3fooFZi");
+    static assert(foo.mangleof == 
"_D8link6574"~tl!"28"~"__T3fooVE"~id!("8link6574","Qs")~"6Methodi0Z"~id!("3foo","Qs")~"FZi");
     return 10 * foo!method();
 }
 int foo(Method method : Method.A)()
 {
-    static assert(foo.mangleof == 
"_D8link657429__T3fooHVE8link65746Methodi0Z3fooFZi");
+    static assert(foo.mangleof == 
"_D8link6574"~tl!"29"~"__T3fooHVE"~id!("8link6574","Qt")~"6Methodi0Z"~id!("3foo","Qt")~"FZi");
     return 2;
 }
 int foo(Method method : Method.B)()
@@ -21,7 +23,7 @@ int foo(Method method : Method.B)()
 
 int bar(Method method = Method.B)()
 {
-    static assert(bar.mangleof == 
"_D8link657428__T3barVE8link65746Methodi1Z3barFZi");
+    static assert(bar.mangleof == 
"_D8link6574"~tl!"28"~"__T3barVE"~id!("8link6574","Qs")~"6Methodi1Z"~id!("3bar","Qs")~"FZi");
     return 10 * bar!method();
 }
 int bar(Method method : Method.A)()
@@ -31,7 +33,7 @@ int bar(Method method : Method.A)()
 }
 int bar(Method method : Method.B)()
 {
-    static assert(bar.mangleof == 
"_D8link657429__T3barHVE8link65746Methodi1Z3barFZi");
+    static assert(bar.mangleof == 
"_D8link6574"~tl!"29"~"__T3barHVE"~id!("8link6574","Qt")~"6Methodi1Z"~id!("3bar","Qt")~"FZi");
     return 3;
 }
 
diff --git a/gcc/testsuite/gdc.test/runnable/mangle.d 
b/gcc/testsuite/gdc.test/runnable/mangle.d
index 8820a6d1fb3..883d58ac07c 100644
--- a/gcc/testsuite/gdc.test/runnable/mangle.d
+++ b/gcc/testsuite/gdc.test/runnable/mangle.d
@@ -1,6 +1,8 @@
 // PERMUTE_ARGS:
 // EXTRA_SOURCES: imports/mangle10077.d
 
+import imports.testmangle;
+
 /***************************************************/
 // 10077 - pragma(mangle)
 
@@ -79,7 +81,7 @@ class C2774
 static assert(C2774.foo2774.mangleof == "_D6mangle5C27747foo2774MFZi");
 
 template TFoo2774(T) {}
-static assert(TFoo2774!int.mangleof == "6mangle15__T8TFoo2774TiZ");
+static assert(TFoo2774!int.mangleof == "6mangle"~tl!"15"~"__T8TFoo2774TiZ");
 
 void test2774()
 {
@@ -175,8 +177,8 @@ void test8847b()
 
 struct Test8847
 {
-    enum result1 = "S6mangle8Test88478__T3fooZ3fooMFZ6Result";
-    enum result2 = "S6mangle8Test88478__T3fooZ3fooMxFiZ6Result";
+    enum result1 = 
"S6mangle8Test8847"~tl!("8")~"__T3fooZ"~id!("3foo","Qf")~"MFZ6Result";
+    enum result2 = 
"S6mangle8Test8847"~tl!("8")~"__T3fooZ"~id!("3foo","Qf")~"MxFiZ6Result";
 
     auto foo()()
     {
@@ -236,9 +238,10 @@ void test8847d()
 
 void test8847e()
 {
-    enum resultHere = "6mangle"~"9test8847eFZ"~"8__T3fooZ"~"3foo";
+    enum resultHere = 
"6mangle"~"9test8847eFZ"~tl!"8"~"__T3fooZ"~id!("3foo","Qf");
     enum resultBar =  "S"~resultHere~"MFNaNfNgiZ3Bar";
-    enum resultFoo = "_D"~resultHere~"MFNaNbNiNfNgiZNg"~resultBar;   // added 
'Nb'
+    static if(BackRefs) {} else
+      enum resultFoo = "_D"~resultHere~"MFNaNbNiNfNgiZNg"~resultBar;   // 
added 'Nb'
 
     // Make template function to infer 'nothrow' attributes
     auto foo()(inout int) pure @safe
@@ -248,10 +251,16 @@ void test8847e()
         return inout(Bar)();
     }
 
+    import core.demangle : demangle, demangleType;
     auto bar = foo(0);
     static assert(typeof(bar).stringof == "Bar");
     static assert(typeof(bar).mangleof == resultBar);
-    static assert(foo!().mangleof == resultFoo);
+    enum fooDemangled = "pure nothrow @nogc @safe 
inout(mangle.test8847e().foo!().foo(inout(int)).Bar) 
mangle.test8847e().foo!().foo(inout(int))";
+
+    static if (BackRefs)
+      static assert(demangle(foo!().mangleof) == fooDemangled);
+    else
+      static assert(foo!().mangleof == resultFoo);
 }
 
 // --------
@@ -287,7 +296,7 @@ auto bar12352()
 
     return S();
 }
-static assert(       bar12352        .mangleof == 
"_D6mangle8bar12352FNaNbNiNfZS6mangle8bar12352FZ1S");
+static assert(       bar12352        .mangleof == 
"_D6mangle8bar12352FNaNbNiNfZS"~id!("6mangle8bar12352FZ","QBbQxFZ","QL2H")~"1S");
 static assert(typeof(bar12352())     .mangleof ==  "S6mangle8bar12352FZ1S");
 static assert(typeof(bar12352()).func.mangleof == 
"_D6mangle8bar12352FZ1S4funcMFZv");
 
@@ -301,7 +310,7 @@ auto baz12352()
 
     return new C();
 }
-static assert(       baz12352        .mangleof == 
"_D6mangle8baz12352FNaNbNfZC6mangle8baz12352FZ1C");
+static assert(       baz12352      .mangleof == 
"_D6mangle8baz12352FNaNbNfZC"~id!("6mangle8baz12352FZ","QzQuFZ","QL2F")~"1C");
 static assert(typeof(baz12352())     .mangleof ==  "C6mangle8baz12352FZ1C");
 static assert(typeof(baz12352()).func.mangleof == 
"_D6mangle8baz12352FZ1C4funcMFZv");
 
@@ -312,8 +321,8 @@ void f9525(T)(in T*) { }
 
 void test9525()
 {
-    enum result1 = 
"S6mangle8test9525FZ26__T5test1S136mangle5f9525Z5test1MFZ1S";
-    enum result2 = 
"S6mangle8test9525FZ26__T5test2S136mangle5f9525Z5test2MFNaNbZ1S";
+    enum result1 = 
"S6mangle8test9525FZ"~tl!"26"~"__T5test1S"~tl!"13"~id!("6mangle","QBc")~"5f9525Z"~id!("5test1","Qr")~"MFZ1S";
+    enum result2 = 
"S6mangle8test9525FZ"~tl!"26"~"__T5test2S"~tl!"13"~id!("6mangle","QBc")~"5f9525Z"~id!("5test2","Qr")~"MFNaNbZ1S";
 
     void test1(alias a)()
     {
@@ -383,23 +392,32 @@ void test11718()
     string TyName(string tail)()
     {
         enum s = "__T7Ty11718" ~ tail;
-        enum int len = s.length;
-        return "S6mangle" ~ len.stringof ~ s;
+        enum len = unsignedToString(s.length);
+        return "S6mangle" ~ tl!(len) ~ s;
     }
     string fnName(string paramPart)()
     {
-        enum s = "_D6mangle35__T7fn11718T"~
+        enum s = "_D6mangle"~tl!("35")~"__T7fn11718T"~
                  "S6mangle9test11718FZ1AZ7fn11718"~paramPart~"1a"~
                  "S6mangle9test11718FZ1A";
-        enum int len = s.length;
-        return len.stringof ~ s;
+        enum len = unsignedToString(s.length);
+        return tl!len ~ s;
     }
     enum result1 = TyName!("S" ~ fnName!("F"~"S6mangle9test11718FZ1A"~"Z") ~ 
"Z") ~ "7Ty11718";
     enum result2 = TyName!("S" ~ fnName!("F"~""                      ~"Z") ~ 
"Z") ~ "7Ty11718";
 
     struct A {}
-    static assert(fn11718(A.init) == result1);
-    static assert(fn11718!A()     == result2);
+    static if (BackRefs)
+    {
+        static assert(fn11718(A.init) == 
"S6mangle__T7Ty11718S_DQv__T7fn11718TSQBk9test11718FZ1AZQBcFQxZ1aQBcZQCf");
+        static assert(fn11718!A()     == 
"S6mangle__T7Ty11718S_DQv__T7fn11718TSQBk9test11718FZ1AZQBcFZ1aQBaZQCd");
+    }
+    else
+    {
+        pragma(msg, fn11718(A.init));
+        static assert(fn11718(A.init) == result1);
+        static assert(fn11718!A()     == result2);
+    }
 }
 
 /*******************************************/
@@ -417,9 +435,10 @@ void test11776()
         {
             auto s = S11776!(a => 1)();
             static assert(typeof(s).mangleof ==
-                "S"~"6mangle"~"56"~(
-                    
"__T"~"6S11776"~"S42"~("6mangle"~"9test11776"~"FZ"~"9__lambda1MFZ"~"9__lambda1")~"Z"
-                )~"6S11776");
+                "S"~"6mangle"~tl!("56")~
+                ("__T"~"6S11776"~"S"~tl!("42")~
+                 
(id!("6mangle","Qs")~"9test11776"~"FZ"~"9__lambda1MFZ"~id!("9__lambda1","Qn"))~"Z"
+                 )~id!("6S11776", "QBm"));
         }
     };
 }
@@ -464,7 +483,7 @@ void test12217(int)
     static assert(    S.mangleof ==  "S6mangle9test12217FiZ1S");
     static assert(  bar.mangleof == "_D6mangle9test12217FiZ3barMFNaNbNiNfZv");
     static assert(  var.mangleof == "_D6mangle9test12217FiZ3vari");
-    static assert(X!int.mangleof ==   "6mangle9test12217FiZ8__T1XTiZ");
+    static assert(X!int.mangleof ==   
"6mangle9test12217FiZ"~tl!("8")~"__T1XTiZ");
 }
 
 void test12217() {}
@@ -476,22 +495,21 @@ void func12231a()()
 if (is(typeof({
         class C {}
         static assert(C.mangleof ==
-            "C6mangle16__U10func12231aZ10func12231aFZ9__lambda1MFZ1C");
+            
"C6mangle"~tl!("16")~"__U10func12231aZ"~id!("10func12231a","Qn")~"FZ9__lambda1MFZ1C");
             //         ###            L                       #
     })))
 {}
 
 void func12231b()()
 if (is(typeof({
-        class C {}
-        static assert(C.mangleof ==
-            "C6mangle16__U10func12231bZ10func12231bFZ9__lambda1MFZ1C");
+        class C {}        static assert(C.mangleof ==
+            
"C6mangle"~tl!("16")~"__U10func12231bZ"~id!("10func12231b","Qn")~"FZ9__lambda1MFZ1C");
             //         L__L           L                       LL
-    })) &&
+      })) &&
     is(typeof({
         class C {}
         static assert(C.mangleof ==
-            "C6mangle16__U10func12231bZ10func12231bFZ9__lambda2MFZ1C");
+            
"C6mangle"~tl!("16")~"__U10func12231bZ"~id!("10func12231b","Qn")~"FZ9__lambda2MFZ1C");
             //         L__L           L                       LL
     })))
 {}
@@ -500,14 +518,14 @@ void func12231c()()
 if (is(typeof({
         class C {}
         static assert(C.mangleof ==
-            "C6mangle16__U10func12231cZ10func12231cFZ9__lambda1MFZ1C");
+            
"C6mangle"~tl!("16")~"__U10func12231cZ"~id!("10func12231c","Qn")~"FZ9__lambda1MFZ1C");
             //         L__L           L                       LL
     })))
 {
     (){
         class C {}
         static assert(C.mangleof ==
-            "C6mangle16__T10func12231cZ10func12231cFZ9__lambda1MFZ1C");
+            
"C6mangle"~tl!("16")~"__T10func12231cZ"~id!("10func12231c","Qn")~"FZ9__lambda1MFZ1C");
             //         L__L           L                       LL
     }();
 }
@@ -515,15 +533,15 @@ if (is(typeof({
 void func12231c(X)()
 if (is(typeof({
         class C {}
-        static assert(C.mangleof ==
-            "C6mangle20__U10func12231cTAyaZ10func12231cFZ9__lambda1MFZ1C");
+    static assert(C.mangleof ==
+            
"C6mangle"~tl!("20")~"__U10func12231cTAyaZ"~id!("10func12231c","Qr")~"FZ9__lambda1MFZ1C");
             //         L__L           L___L                       LL
     })))
 {
     (){
         class C {}
         static assert(C.mangleof ==
-            "C6mangle20__T10func12231cTAyaZ10func12231cFZ9__lambda1MFZ1C");
+            
"C6mangle"~tl!("20")~"__T10func12231cTAyaZ"~id!("10func12231c","Qr")~"FZ9__lambda1MFZ1C");
             //         L__L           L___L                       LL
     }();
 }
diff --git a/gcc/testsuite/gdc.test/runnable/template4.d 
b/gcc/testsuite/gdc.test/runnable/template4.d
index 77d6254361a..81723f60182 100644
--- a/gcc/testsuite/gdc.test/runnable/template4.d
+++ b/gcc/testsuite/gdc.test/runnable/template4.d
@@ -1074,22 +1074,27 @@ struct Foo7469d(T...) { }
 struct Foo7469e(int a, T...) { }
 struct Foo7469f(T, int k=1) { }
 struct Foo7469g(T, int k=1) { }
+struct Foo7469h(uint x) { }
+
+import core.demangle : demangleType;
 
 void test7469()
 {
-    static assert(Foo7469a!(3 )    .mangleof[$-28 .. $] == 
"17__T8Foo7469aVii3Z8Foo7469a");
-    static assert(Foo7469a!(3u)    .mangleof[$-28 .. $] == 
"17__T8Foo7469aVii3Z8Foo7469a");
-    static assert(Foo7469b!(3u)    .mangleof[$-28 .. $] == 
"17__T8Foo7469bVii3Z8Foo7469b");
-    static assert(Foo7469b!(3 )    .mangleof[$-28 .. $] == 
"17__T8Foo7469bVii3Z8Foo7469b");
-    static assert(Foo7469c!(3 )    .mangleof[$-28 .. $] == 
"17__T8Foo7469cVii3Z8Foo7469c");
-    static assert(Foo7469c!(3u)    .mangleof[$-28 .. $] == 
"17__T8Foo7469cVki3Z8Foo7469c");
-    static assert(Foo7469d!(3 )    .mangleof[$-28 .. $] == 
"17__T8Foo7469dVii3Z8Foo7469d");
-    static assert(Foo7469d!(3u)    .mangleof[$-28 .. $] == 
"17__T8Foo7469dVki3Z8Foo7469d");
-    static assert(Foo7469e!(3u, 5u).mangleof[$-32 .. $] == 
"21__T8Foo7469eVii3Vki5Z8Foo7469e");
-    static assert(Foo7469f!(int, 1).mangleof[$-30 .. $] == 
"19__T8Foo7469fTiVii1Z8Foo7469f");
-    static assert(Foo7469f!(int)   .mangleof[$-30 .. $] == 
"19__T8Foo7469fTiVii1Z8Foo7469f");
-    static assert(Foo7469g!(int)   .mangleof[$-30 .. $] == 
"19__T8Foo7469gTiVii1Z8Foo7469g");
-    static assert(Foo7469g!(int, 1).mangleof[$-30 .. $] == 
"19__T8Foo7469gTiVii1Z8Foo7469g");
+    static assert(demangleType(Foo7469a!(3 )    .mangleof) == 
"template4.Foo7469a!(3).Foo7469a");
+    static assert(demangleType(Foo7469a!(3u)    .mangleof) == 
"template4.Foo7469a!(3).Foo7469a");
+    static assert(demangleType(Foo7469b!(3u)    .mangleof) == 
"template4.Foo7469b!(3).Foo7469b");
+    static assert(demangleType(Foo7469b!(3 )    .mangleof) == 
"template4.Foo7469b!(3).Foo7469b");
+    static assert(demangleType(Foo7469c!(3 )    .mangleof) == 
"template4.Foo7469c!(3).Foo7469c");
+    static assert(demangleType(Foo7469c!(3u)    .mangleof) == 
"template4.Foo7469c!(3u).Foo7469c");
+    static assert(demangleType(Foo7469d!(3 )    .mangleof) == 
"template4.Foo7469d!(3).Foo7469d");
+    static assert(demangleType(Foo7469d!(3u)    .mangleof) == 
"template4.Foo7469d!(3u).Foo7469d");
+    static assert(demangleType(Foo7469e!(3u, 5u).mangleof) == 
"template4.Foo7469e!(3, 5u).Foo7469e");
+    static assert(demangleType(Foo7469f!(int, 1).mangleof) == 
"template4.Foo7469f!(int, 1).Foo7469f");
+    static assert(demangleType(Foo7469f!(int)   .mangleof) == 
"template4.Foo7469f!(int, 1).Foo7469f");
+    static assert(demangleType(Foo7469g!(int)   .mangleof) == 
"template4.Foo7469g!(int, 1).Foo7469g");
+    static assert(demangleType(Foo7469g!(int, 1).mangleof) == 
"template4.Foo7469g!(int, 1).Foo7469g");
+    static assert(demangleType(Foo7469h!(3 )    .mangleof) == 
"template4.Foo7469h!(3u).Foo7469h");
+    static assert(demangleType(Foo7469h!(3u)    .mangleof) == 
"template4.Foo7469h!(3u).Foo7469h");
 }
 
 /******************************************/
diff --git a/gcc/testsuite/gdc.test/runnable/template9.d 
b/gcc/testsuite/gdc.test/runnable/template9.d
index 4f182959cb1..b016ff91043 100644
--- a/gcc/testsuite/gdc.test/runnable/template9.d
+++ b/gcc/testsuite/gdc.test/runnable/template9.d
@@ -4465,6 +4465,7 @@ void test13807()
 
 /******************************************/
 // 14174
+import imports.testmangle;
 
 struct Config14174(a, b) {}
 
@@ -4474,22 +4475,22 @@ alias defConfig14174 = Config14174!(N14174, N14174);
 
 void accepter14174a(Config : Config14174!(T) = defConfig14174, T...)()
 {
-    static assert(accepter14174a.mangleof
-        == "_D7breaker131__T14"~
+    static assert(equalDemangle(accepter14174a.mangleof,
+           "_D7breaker131__T14"~
            "accepter14174a"~
            
"HTS7breaker51__T11Config14174TS7breaker6N14174TS7breaker6N14174Z11Config14174TS7breaker6N14174TS7breaker6N14174Z14"~
            "accepter14174a"~
-           "FZv");
+           "FZv"));
 }
 
 void accepter14174b(Config : Config14174!(T) = defConfig14174, T...)()
 {
-    static assert(accepter14174b.mangleof
-        == "_D7breaker131__T14"~
+    static assert(equalDemangle(accepter14174b.mangleof,
+           "_D7breaker131__T14"~
            "accepter14174b"~
            
"HTS7breaker51__T11Config14174TS7breaker6N14174TS7breaker6N14174Z11Config14174TS7breaker6N14174TS7breaker6N14174Z14"~
            "accepter14174b"~
-           "FZv");
+           "FZv"));
 }
 
 void test14174()
diff --git a/gcc/testsuite/gdc.test/runnable/testconst.d 
b/gcc/testsuite/gdc.test/runnable/testconst.d
index 2da39a2cdbb..42f9c1beb7f 100644
--- a/gcc/testsuite/gdc.test/runnable/testconst.d
+++ b/gcc/testsuite/gdc.test/runnable/testconst.d
@@ -84,10 +84,11 @@ void foo8(const char[] s, const C8 c, const int x)
 
 void test8()
 {
+    import core.demangle : demangle;
     auto p = &foo8;
     showf(p.mangleof);
     assert(typeof(p).mangleof == "PFxAaxC9testconst2C8xiZv");
-    assert(p.mangleof == "_D9testconst5test8FZ1pPFxAaxC9testconst2C8xiZv");
+    assert(demangle(p.mangleof) == "void function(const(char[]), 
const(testconst.C8), const(int))* testconst.test8().p");
 }
 
 /************************************/
-- 
2.27.0


Reply via email to