diff --git a/src/ddmd/dmangle.d b/src/ddmd/dmangle.d index 7668333c9f80..98d03158faeb 100644 --- a/src/ddmd/dmangle.d +++ b/src/ddmd/dmangle.d @@ -25,10 +25,13 @@ import ddmd.expression; import ddmd.func; import ddmd.globals; import ddmd.id; +import ddmd.identifier; import ddmd.mtype; import ddmd.root.ctfloat; import ddmd.root.outbuffer; +import ddmd.root.aav; import ddmd.target; +import ddmd.tokens; import ddmd.utf; import ddmd.visitor; @@ -79,7 +82,7 @@ private immutable char[TMAX] mangleChar = // N // Nh:vector Ng:wild // O // shared Tpointer : 'P', - // Q + // Q // Type/symbol/identifier backward reference Treference : 'R', Tstruct : 'S', // T // Ttypedef @@ -165,6 +168,9 @@ extern (C++) final class Mangler : Visitor { alias visit = super.visit; public: + static assert(Key.sizeof == size_t.sizeof); + AA* types; + AA* idents; OutBuffer* buf; extern (D) this(OutBuffer* buf) @@ -172,22 +178,115 @@ public: 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 + */ + final void writeBackRef(size_t pos) + { + buf.writeByte('Q'); + enum base = 26; + size_t mul = 1; + while (pos >= mul * base) + mul *= base; + while (mul >= base) + { + auto dig = cast(ubyte)(pos / mul); + buf.writeByte('A' + dig); + pos -= dig * mul; + mul /= base; + } + buf.writeByte('a' + cast(ubyte)pos); + } + + /** + * Back references a non-basic type + * + * The encoded mangling is + * 'Q' + * + * 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. + */ + final bool backrefType(Type t) + { + if (!t.isTypeBasic()) + { + auto p = cast(size_t*)dmd_aaGet(&types, cast(Key)t); + if (*p) + { + writeBackRef(buf.offset - *p); + return true; + } + *p = buf.offset; + } + return false; + } + + /** + * Back references a single identifier + * + * The encoded mangling is + * 'Q' + * + * 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. + */ + final bool backrefIdentifier(Identifier id) + { + auto p = cast(size_t*)dmd_aaGet(&idents, cast(Key)id); + if (*p) + { + writeBackRef(buf.offset - *p); + return true; + } + *p = buf.offset; + return false; + } + + final void mangleSymbol(Dsymbol s) + { + s.accept(this); + } + + final void mangleType(Type t) + { + if (!backrefType(t)) + t.accept(this); + } + + final void mangleIdentifier(Identifier id, Dsymbol s) + { + if (!backrefIdentifier(id)) + toBuffer(id.toChars(), s); + } + //////////////////////////////////////////////////////////////////////////// /************************************************** * Type mangling */ void visitWithMask(Type t, ubyte modMask) { - if (t.deco && modMask == 0) - { - buf.writestring(t.deco); // don't need to recreate it - return; - } if (modMask != t.mod) { MODtoDecoBuffer(buf, t.mod); } - t.accept(this); + mangleType(t); } override void visit(Type t) @@ -240,8 +339,9 @@ public: void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte 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; } @@ -321,34 +421,29 @@ public: override void visit(TypeEnum t) { visit(cast(Type)t); - t.sym.accept(this); + mangleSymbol(t.sym); } override void visit(TypeStruct t) { //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name); visit(cast(Type)t); - t.sym.accept(this); + mangleSymbol(t.sym); } override void visit(TypeClass t) { //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name); visit(cast(Type)t); - t.sym.accept(this); + mangleSymbol(t.sym); } override void visit(TypeTuple t) { //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars()); visit(cast(Type)t); - OutBuffer buf2; - buf2.reserve(32); - scope Mangler v = new Mangler(&buf2); - v.paramsToDecoBuffer(t.arguments); - auto s = buf2.peekSlice(); - int len = cast(int)s.length; - buf.printf("%d%.*s", len, len, s.ptr); + paramsToDecoBuffer(t.arguments); + buf.writeByte('Z'); } override void visit(TypeNull t) @@ -361,15 +456,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); @@ -385,10 +479,14 @@ public: if (p) { mangleParent(p); - if (p.getIdent()) + auto ti = p.isTemplateInstance(); + if (ti && !ti.isTemplateMixin()) + { + mangleTemplateInstance(ti); + } + else if (p.getIdent()) { - const(char)* id = p.ident.toChars(); - toBuffer(id, s); + mangleIdentifier(p.ident, s); if (FuncDeclaration f = p.isFuncDeclaration()) mangleFunc(f, true); } @@ -409,13 +507,13 @@ public: TypeFunction tfo = cast(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. } } @@ -426,7 +524,7 @@ 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 + if (buf.offset >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone s.error("excessive length %llu for symbol, possible recursive expansion?", len); else { @@ -435,34 +533,41 @@ public: } } - override 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 LINKpascal: - case LINKobjc: - buf.writestring(d.ident.toChars()); - return; - case LINKcpp: - buf.writestring(Target.toCppMangle(d)); - return; - case LINKdefault: - d.error("forward declaration"); - buf.writestring(d.ident.toChars()); - return; - default: - fprintf(stderr, "'%s', linkage = %d\n", d.toChars(), d.linkage); - assert(0); + case LINKd: + break; + case LINKc: + case LINKwindows: + case LINKpascal: + case LINKobjc: + return d.ident.toChars(); + case LINKcpp: + return Target.toCppMangle(d); + case LINKdefault: + d.error("forward declaration"); + return d.ident.toChars(); + default: + fprintf(stderr, "'%s', linkage = %d\n", d.toChars(), d.linkage); + assert(0); } } + return null; + } + + override 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 (auto id = externallyMangledIdentifier(d)) + { + buf.writestring(id); + return; + } buf.writestring("_D"); mangleDecl(d); debug @@ -519,7 +624,7 @@ public: } if (fa) { - fa.accept(this); + mangleSymbol(fa); return; } visit(cast(Dsymbol)fd); @@ -544,7 +649,7 @@ public: { if (!od.hasOverloads || td.overnext is null) { - td.accept(this); + mangleSymbol(td); return; } } @@ -614,10 +719,123 @@ public: ti.error("is not defined"); else mangleParent(ti); - ti.getIdent(); - const(char)* id = ti.ident ? ti.ident.toChars() : ti.toChars(); - toBuffer(id, ti); - //printf("TemplateInstance.mangle() %s = %s\n", ti.toChars(), ti.id); + + if (ti.isTemplateMixin() && ti.ident) + mangleIdentifier(ti.ident, ti); + else + mangleTemplateInstance(ti); + } + + final 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); + + auto args = ti.tiargs; + size_t nparams = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0); + for (size_t i = 0; i < args.dim; i++) + { + auto 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. + enum keepLvalue = true; + ea = ea.optimize(WANTvalue, keepLvalue); + if (ea.op == TOKvar) + { + sa = (cast(VarExp)ea).var; + ea = null; + goto Lsa; + } + if (ea.op == TOKthis) + { + sa = (cast(ThisExp)ea).var; + ea = null; + goto Lsa; + } + if (ea.op == TOKfunction) + { + if ((cast(FuncExp)ea).td) + sa = (cast(FuncExp)ea).td; + else + sa = (cast(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 + uint 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 (auto fad = d.isFuncAliasDeclaration()) + d = fad.toAliasFunc(); + if (d.mangleOverride) + { + buf.writeByte('X'); + toBuffer(d.mangleOverride, d); + continue; + } + if (auto 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.dim); // must be last one + args = &va.objects; + i = -cast(size_t)1; + } + else + assert(0); + } + buf.writeByte('Z'); } override void visit(Dsymbol s) @@ -630,8 +848,10 @@ public: printf("\n"); } mangleParent(s); - auto 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); } @@ -889,3 +1109,9 @@ extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf) s.accept(v); } +extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf) +{ + scope Mangler v = new Mangler(buf); + v.mangleTemplateInstance(ti); +} + diff --git a/src/ddmd/dtemplate.d b/src/ddmd/dtemplate.d index e454ba932499..44486a838266 100644 --- a/src/ddmd/dtemplate.d +++ b/src/ddmd/dtemplate.d @@ -8223,123 +8223,10 @@ extern (C++) class TemplateInstance : ScopeDsymbol */ final Identifier genIdent(Objects* args) { - TemplateDeclaration tempdecl = this.tempdecl.isTemplateDeclaration(); - assert(tempdecl); - //printf("TemplateInstance.genIdent('%s')\n", tempdecl.ident.toChars()); + assert(args is tiargs); OutBuffer buf; - - const id = tempdecl.ident.toString(); - // Use "__U" for the symbols declared inside template constraint. - const char T = members ? 'T' : 'U'; - buf.printf("__%c%u%.*s", T, cast(int)id.length, cast(int)id.length, id.ptr); - - size_t nparams = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0); - for (size_t i = 0; i < args.dim; 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'); - if (ta.deco) - buf.writestring(ta.deco); - else - { - debug - { - if (!global.errors) - printf("ta = %d, %s\n", ta.ty, ta.toChars()); - } - 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. - enum keepLvalue = true; - ea = ea.optimize(WANTvalue, keepLvalue); - if (ea.op == TOKvar) - { - sa = (cast(VarExp)ea).var; - ea = null; - goto Lsa; - } - if (ea.op == TOKthis) - { - sa = (cast(ThisExp)ea).var; - ea = null; - goto Lsa; - } - if (ea.op == TOKfunction) - { - if ((cast(FuncExp)ea).td) - sa = (cast(FuncExp)ea).td; - else - sa = (cast(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 - uint 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); - auto s = bufsa.peekSlice(); - - /* https://issues.dlang.org/show_bug.cgi?id=3043 - * If the first character of p 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", cast(uint)s.length, cast(int)s.length, s.ptr); - } - else if (va) - { - assert(i + 1 == args.dim); // must be last one - args = &va.objects; - i = -cast(size_t)1; - } - else - assert(0); - } - buf.writeByte('Z'); + mangleToBuffer(this, &buf); //printf("\tgenIdent = %s\n", buf.peekString()); return Identifier.idPool(buf.peekSlice()); } diff --git a/src/ddmd/toir.d b/src/ddmd/toir.d index 81c34474b541..c7e888d982b9 100644 --- a/src/ddmd/toir.d +++ b/src/ddmd/toir.d @@ -415,15 +415,15 @@ int intrinsic_op(FuncDeclaration fd) "4math6yl2xp1FNaNbNiNfeeZe", "4simd10__prefetchFNaNbNiNfxPvhZv", - "4simd10__simd_stoFNaNbNiNfE4core4simd3XMMNhG16vNhG16vZNhG16v", - "4simd10__simd_stoFNaNbNiNfE4core4simd3XMMdNhG16vZNhG16v", - "4simd10__simd_stoFNaNbNiNfE4core4simd3XMMfNhG16vZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMNhG16vNhG16vZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMNhG16vNhG16vhZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMNhG16vZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMdZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMfZNhG16v", - "4simd9__simd_ibFNaNbNiNfE4core4simd3XMMNhG16vhZNhG16v", + "4simd10__simd_stoFNaNbNiNfEQBgQBe3XMMNhG16vQgZQj", + "4simd10__simd_stoFNaNbNiNfEQBgQBe3XMMdNhG16vZQh", + "4simd10__simd_stoFNaNbNiNfEQBgQBe3XMMfNhG16vZQh", + "4simd6__simdFNaNbNiNfEQBbQz3XMMNhG16vQgZQj", + "4simd6__simdFNaNbNiNfEQBbQz3XMMNhG16vQghZQk", + "4simd6__simdFNaNbNiNfEQBbQz3XMMNhG16vZQh", + "4simd6__simdFNaNbNiNfEQBbQz3XMMdZNhG16v", + "4simd6__simdFNaNbNiNfEQBbQz3XMMfZNhG16v", + "4simd9__simd_ibFNaNbNiNfEQBeQBc3XMMNhG16vhZQi", "5bitop12volatileLoadFNbNiNfPhZh", "5bitop12volatileLoadFNbNiNfPkZk", @@ -469,15 +469,15 @@ int intrinsic_op(FuncDeclaration fd) "4math6yl2xp1FNaNbNiNfeeZe", "4simd10__prefetchFNaNbNiNfxPvhZv", - "4simd10__simd_stoFNaNbNiNfE4core4simd3XMMNhG16vNhG16vZNhG16v", - "4simd10__simd_stoFNaNbNiNfE4core4simd3XMMdNhG16vZNhG16v", - "4simd10__simd_stoFNaNbNiNfE4core4simd3XMMfNhG16vZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMNhG16vNhG16vZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMNhG16vNhG16vhZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMNhG16vZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMdZNhG16v", - "4simd6__simdFNaNbNiNfE4core4simd3XMMfZNhG16v", - "4simd9__simd_ibFNaNbNiNfE4core4simd3XMMNhG16vhZNhG16v", + "4simd10__simd_stoFNaNbNiNfEQBgQBe3XMMNhG16vQgZQj", + "4simd10__simd_stoFNaNbNiNfEQBgQBe3XMMdNhG16vZQh", + "4simd10__simd_stoFNaNbNiNfEQBgQBe3XMMfNhG16vZQh", + "4simd6__simdFNaNbNiNfEQBbQz3XMMNhG16vQgZQj", + "4simd6__simdFNaNbNiNfEQBbQz3XMMNhG16vQghZQk", + "4simd6__simdFNaNbNiNfEQBbQz3XMMNhG16vZQh", + "4simd6__simdFNaNbNiNfEQBbQz3XMMdZNhG16v", + "4simd6__simdFNaNbNiNfEQBbQz3XMMfZNhG16v", + "4simd9__simd_ibFNaNbNiNfEQBeQBc3XMMNhG16vhZQi", "5bitop12volatileLoadFNbNiNfPhZh", "5bitop12volatileLoadFNbNiNfPkZk", diff --git a/test/compilable/extra-files/json-postscript.sh b/test/compilable/extra-files/json-postscript.sh index eb0ceca226a2..e4b3d472ef57 100755 --- a/test/compilable/extra-files/json-postscript.sh +++ b/test/compilable/extra-files/json-postscript.sh @@ -1,10 +1,13 @@ #!/usr/bin/env bash grep -v "\"file\" : " ${RESULTS_DIR}/compilable/json.out | grep -v "\"offset\" : " > ${RESULTS_DIR}/compilable/json.out.2 -diff --strip-trailing-cr compilable/extra-files/json.out ${RESULTS_DIR}/compilable/json.out.2 +grep -v "\"deco\" : " ${RESULTS_DIR}/compilable/json.out.2 > ${RESULTS_DIR}/compilable/json.out.3 +grep -v "\"deco\" : " compilable/extra-files/json.out > ${RESULTS_DIR}/compilable/json.out.4 + +diff --strip-trailing-cr ${RESULTS_DIR}/compilable/json.out.4 ${RESULTS_DIR}/compilable/json.out.3 if [ $? -ne 0 ]; then exit 1; fi -rm ${RESULTS_DIR}/compilable/json.out{,.2} +rm ${RESULTS_DIR}/compilable/json.out{,.2,.3,.4} diff --git a/test/compilable/test10993.d b/test/compilable/test10993.d index e5a1b847976f..a69d0c616cf0 100644 --- a/test/compilable/test10993.d +++ b/test/compilable/test10993.d @@ -1,5 +1,7 @@ module test10993; +import core.demangle : demangleType; + auto foo(T)(T a) { static immutable typeof(a) q; @@ -29,5 +31,7 @@ void main() auto y = cast()x; enum mangle_y = typeof(y).mangleof; // pragma(msg, "y : " ~ mangle_y); - static assert (mangle_y == mangle_x[1..$]); + enum demangle_x = demangleType(mangle_x); + enum demangle_y = demangleType(mangle_y); + static assert ("immutable(" ~ demangle_y ~ ")" == demangle_x); } diff --git a/test/compilable/testInference.d b/test/compilable/testInference.d index 95f4fcba259a..5a8e1e26ac68 100644 --- a/test/compilable/testInference.d +++ b/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/test/runnable/extra-files/test10386.d b/test/runnable/extra-files/test10386.d index 3bcd3a08e474..aa260d0f2cc4 100644 --- a/test/runnable/extra-files/test10386.d +++ b/test/runnable/extra-files/test10386.d @@ -3,9 +3,11 @@ module test10386; // import lib.foo.bar; // ok import lib10386.foo; // linker failure +import imports.testmangle; + void main() { - static assert(foo.mangleof == "_D8lib103863foo3bar3fooFiZv"); + static assert(equalDemangle(foo.mangleof, "_D8lib103863foo3bar3fooFiZv")); foo(1); } diff --git a/test/runnable/imports/testmangle.d b/test/runnable/imports/testmangle.d new file mode 100644 index 000000000000..5311a8360dae --- /dev/null +++ b/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/test/runnable/link6574.d b/test/runnable/link6574.d index 0f97ed716c29..ab5e552536b6 100644 --- a/test/runnable/link6574.d +++ b/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/test/runnable/mangle.d b/test/runnable/mangle.d index 8820a6d1fb3f..883d58ac07c2 100644 --- a/test/runnable/mangle.d +++ b/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/test/runnable/template4.d b/test/runnable/template4.d index ab082d9f5d7d..4f0061007c92 100644 --- a/test/runnable/template4.d +++ b/test/runnable/template4.d @@ -1073,22 +1073,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/test/runnable/template9.d b/test/runnable/template9.d index 0f1309fe581b..3abb66540cae 100644 --- a/test/runnable/template9.d +++ b/test/runnable/template9.d @@ -4464,6 +4464,7 @@ void test13807() /******************************************/ // 14174 +import imports.testmangle; struct Config14174(a, b) {} @@ -4473,22 +4474,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/test/runnable/test10386.sh b/test/runnable/test10386.sh index c116563d03b1..1fae5bc15323 100755 --- a/test/runnable/test10386.sh +++ b/test/runnable/test10386.sh @@ -11,8 +11,8 @@ else fi libname=${dir}${SEP}lib10386${LIBEXT} -$DMD -m${MODEL} -I${src} -of${libname} -c ${src}${SEP}lib10386${SEP}foo${SEP}bar.d ${src}${SEP}lib10386${SEP}foo${SEP}package.d -lib || exit 1 -$DMD -m${MODEL} -I${src} -of${dir}${SEP}test10386${EXE} ${src}${SEP}test10386.d ${libname} || exit 1 +$DMD -m${MODEL} -Irunnable -I${src} -of${libname} -c ${src}${SEP}lib10386${SEP}foo${SEP}bar.d ${src}${SEP}lib10386${SEP}foo${SEP}package.d -lib || exit 1 +$DMD -m${MODEL} -Irunnable -I${src} -of${dir}${SEP}test10386${EXE} ${src}${SEP}test10386.d ${libname} || exit 1 rm ${dir}/{lib10386${LIBEXT},test10386${OBJ},test10386${EXE}} diff --git a/test/runnable/testconst.d b/test/runnable/testconst.d index 2da39a2cdbba..42f9c1beb7f5 100644 --- a/test/runnable/testconst.d +++ b/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"); } /************************************/ diff --git a/test/runnable/testxmm.d b/test/runnable/testxmm.d index 304f4a95ef18..3074cf5b4e0b 100644 --- a/test/runnable/testxmm.d +++ b/test/runnable/testxmm.d @@ -1884,6 +1884,32 @@ void test17356() /*****************************************/ +void refIntrinsics() +{ + // never called, but check for link errors + void16 v; + void16 a; + float f = 1; + double d = 1; + + a = __simd(XMM.ADDPD, a, v); + a = __simd(XMM.CMPSS, a, v, cast(ubyte)0x7A); + + a = __simd(XMM.LODSS, v); + a = __simd(XMM.LODSS, f); + a = __simd(XMM.LODSS, d); + + __simd_sto(XMM.STOUPS, v, a); + __simd_sto(XMM.STOUPS, f, a); + __simd_sto(XMM.STOUPS, d, a); + + a = __simd_ib(XMM.PSLLW, a, cast(ubyte)0x7A); + + prefetch!(false, 0)(&a); +} + +/*****************************************/ + int main() { test1();