d: Mangled Symbols now back reference types and identifiers
authorIain Buclaw <ibuclaw@gdcproject.org>
Thu, 31 Dec 2020 00:05:01 +0000 (01:05 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Thu, 31 Dec 2020 00:27:06 +0000 (01:27 +0100)
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.

Reviewed-on: https://github.com/dlang/dmd/pull/12079

gcc/d/ChangeLog:

* dmd/MERGE: Merge upstream dmd 2bd4fc3fe.

gcc/d/dmd/MERGE
gcc/d/dmd/dmangle.c
gcc/d/dmd/dtemplate.c
gcc/testsuite/gdc.test/compilable/testInference.d
gcc/testsuite/gdc.test/fail_compilation/fail12485.d
gcc/testsuite/gdc.test/runnable/imports/testmangle.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/link6574.d
gcc/testsuite/gdc.test/runnable/mangle.d
gcc/testsuite/gdc.test/runnable/template4.d
gcc/testsuite/gdc.test/runnable/template9.d
gcc/testsuite/gdc.test/runnable/testconst.d

index 4fa62a9f56a7fdfa11decacb1503f6a2bc18de41..1f695b9d23c30f281cf1167e2fae65a84db312ee 100644 (file)
@@ -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.
index 8f8692668711e76361bd94590d6f78b943b901ba..f6eee52afbf04ff19b79619e284168ad90ae62da 100644 (file)
@@ -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);
+}
index caa8a5ba9f45575c4f0a9a72481d4306bdc907fb..fe65bd23e3cf71461a213dc0b08d55500dd49743 100644 (file)
@@ -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());
 }
 
 /*************************************
index 95f4fcba259a9f8a12dbec5ba296a305f01b7b15..5a8e1e26ac68d3528828cba3f0eb18c4905fb5d2 100644 (file)
@@ -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);
index 71f8698db999364ec0461d86b1c481c509e85e21..e1b15774f818b7536a4d4f205b21017298e11477 100644 (file)
@@ -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 (file)
index 0000000..5311a83
--- /dev/null
@@ -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;
+}
index 0f97ed716c29510715e7db4a0895d3e7577037e6..ab5e552536b654b0b0a51c5d2e36b73211eef71f 100644 (file)
@@ -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;
 }
 
index 8820a6d1fb3f0385af0a11a4f233aa369f4c8842..883d58ac07c2edc4dadd3c40c551af1e7213a192 100644 (file)
@@ -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
     }();
 }
index 77d6254361aba009c61e7cd70cb4dfcbe3b59a09..81723f601825eb4b651fa500b6a3e25732a8c455 100644 (file)
@@ -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");
 }
 
 /******************************************/
index 4f182959cb19791e707d288dcbe89838c323007f..b016ff910431c60e057fa82e70f1b14a67377da7 100644 (file)
@@ -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()
index 2da39a2cdbbab9668dddffc8a4143911990cb208..42f9c1beb7f5d19a4dceb62d6a8d313a7292eca5 100644 (file)
@@ -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");
 }
 
 /************************************/