d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / gcc / d / dmd / dmangle.d
blob5bd1379d17053dec994a1e0ba99f9bae1bd7dbe6
1 /**
2 * Does name mangling for `extern(D)` symbols.
4 * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling)
6 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
7 * Authors: Walter Bright, https://www.digitalmars.com
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dmangle.d, _dmangle.d)
10 * Documentation: https://dlang.org/phobos/dmd_dmangle.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dmangle.d
12 * References: https://dlang.org/blog/2017/12/20/ds-newfangled-name-mangling/
15 module dmd.dmangle;
18 /******************************************************************************
19 * Returns exact mangled name of function.
21 extern (C++) const(char)* mangleExact(FuncDeclaration fd)
23 //printf("mangleExact()\n");
24 if (!fd.mangleString)
26 OutBuffer buf;
27 auto backref = Backref(null);
28 scope Mangler v = new Mangler(buf, &backref);
29 v.mangleExact(fd);
30 fd.mangleString = buf.extractChars();
32 return fd.mangleString;
35 extern (C++) void mangleToBuffer(Type t, ref OutBuffer buf)
37 //printf("mangleToBuffer t()\n");
38 if (t.deco)
39 buf.writestring(t.deco);
40 else
42 auto backref = Backref(t);
43 mangleType(t, 0, buf, backref);
44 //printf("%s\n", buf.peekChars());
48 extern (C++) void mangleToBuffer(Expression e, ref OutBuffer buf)
50 //printf("mangleToBuffer e()\n");
51 auto backref = Backref(null);
52 scope Mangler v = new Mangler(buf, &backref);
53 e.accept(v);
56 extern (C++) void mangleToBuffer(Dsymbol s, ref OutBuffer buf)
58 //printf("mangleToBuffer s(%s)\n", s.toChars());
59 auto backref = Backref(null);
60 scope Mangler v = new Mangler(buf, &backref);
61 s.accept(v);
64 extern (C++) void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
66 //printf("mangleToBuffer ti()\n");
67 auto backref = Backref(null);
68 scope Mangler v = new Mangler(buf, &backref);
69 v.mangleTemplateInstance(ti);
72 /// Returns: `true` if the given character is a valid mangled character
73 package bool isValidMangling(dchar c) nothrow
75 return
76 c >= 'A' && c <= 'Z' ||
77 c >= 'a' && c <= 'z' ||
78 c >= '0' && c <= '9' ||
79 c != 0 && strchr("$%().:?@[]_", c) ||
80 isUniAlpha(c);
83 // valid mangled characters
84 unittest
86 assert('a'.isValidMangling);
87 assert('B'.isValidMangling);
88 assert('2'.isValidMangling);
89 assert('@'.isValidMangling);
90 assert('_'.isValidMangling);
93 // invalid mangled characters
94 unittest
96 assert(!'-'.isValidMangling);
97 assert(!0.isValidMangling);
98 assert(!'/'.isValidMangling);
99 assert(!'\\'.isValidMangling);
102 /**********************************************
103 * Convert a string representing a type (the deco) and
104 * return its equivalent Type.
105 * Params:
106 * deco = string containing the deco
107 * Returns:
108 * null for failed to convert
109 * Type for succeeded
112 public Type decoToType(const(char)[] deco)
114 //printf("decoToType(): %.*s\n", cast(int)deco.length, deco.ptr);
115 if (auto sv = Type.stringtable.lookup(deco))
117 if (sv.value)
119 Type t = cast(Type)sv.value;
120 assert(t.deco);
121 return t;
124 return null;
128 /***************************************** private ***************************************/
130 private:
133 import core.stdc.ctype;
134 import core.stdc.stdio;
135 import core.stdc.string;
137 import dmd.aggregate;
138 import dmd.arraytypes;
139 import dmd.astenums;
140 import dmd.basicmangle;
141 import dmd.dclass;
142 import dmd.declaration;
143 import dmd.dinterpret;
144 import dmd.dmodule;
145 import dmd.dsymbol;
146 import dmd.dtemplate;
147 import dmd.errors;
148 import dmd.expression;
149 import dmd.func;
150 import dmd.globals;
151 import dmd.id;
152 import dmd.identifier;
153 import dmd.mtype;
154 import dmd.root.ctfloat;
155 import dmd.common.outbuffer;
156 import dmd.optimize;
157 import dmd.root.aav;
158 import dmd.root.string;
159 import dmd.root.stringtable;
160 import dmd.root.utf;
161 import dmd.target;
162 import dmd.tokens;
163 import dmd.visitor;
165 /************************************************
166 * Append the mangling of type `t` to `buf`.
167 * Params:
168 * t = type to mangle
169 * modMask = mod bits currently applying to t
170 * buf = buffer to append mangling to
171 * backref = state of back references (updated)
173 void mangleType(Type t, ubyte modMask, ref OutBuffer buf, ref Backref backref)
175 void visitWithMask(Type t, ubyte modMask)
177 void mangleSymbol(Dsymbol s)
179 scope Mangler v = new Mangler(buf, &backref);
180 v.mangleSymbol(s);
183 void visitType(Type t)
185 tyToDecoBuffer(buf, t.ty);
188 void visitTypeNext(TypeNext t)
190 visitType(t);
191 visitWithMask(t.next, t.mod);
194 void visitTypeVector(TypeVector t)
196 buf.writestring("Nh");
197 visitWithMask(t.basetype, t.mod);
200 void visitTypeSArray(TypeSArray t)
202 visitType(t);
203 if (t.dim)
204 buf.print(t.dim.toInteger());
205 if (t.next)
206 visitWithMask(t.next, t.mod);
209 void visitTypeDArray(TypeDArray t)
211 visitType(t);
212 if (t.next)
213 visitWithMask(t.next, t.mod);
216 void visitTypeAArray(TypeAArray t)
218 visitType(t);
219 visitWithMask(t.index, 0);
220 visitWithMask(t.next, t.mod);
223 void visitTypeFunction(TypeFunction t)
225 //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
226 //static int nest; if (++nest == 50) *(char*)0=0;
227 mangleFuncType(t, t, t.mod, t.next, buf, backref);
230 void visitTypeIdentifier(TypeIdentifier t)
232 visitType(t);
233 auto name = t.ident.toString();
234 buf.print(cast(int)name.length);
235 buf.writestring(name);
238 void visitTypeEnum(TypeEnum t)
240 visitType(t);
241 mangleSymbol(t.sym);
244 void visitTypeStruct(TypeStruct t)
246 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
247 visitType(t);
248 mangleSymbol(t.sym);
251 void visitTypeClass(TypeClass t)
253 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
254 visitType(t);
255 mangleSymbol(t.sym);
258 void visitTypeTuple(TypeTuple t)
260 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
261 visitType(t);
262 Parameter._foreach(t.arguments, (idx, param) {
263 mangleParameter(param, buf, backref);
264 return 0;
266 buf.writeByte('Z');
269 void visitTypeNull(TypeNull t)
271 visitType(t);
274 void visitTypeNoreturn(TypeNoreturn t)
276 buf.writestring("Nn");
279 if (modMask != t.mod)
281 MODtoDecoBuffer(buf, t.mod);
283 if (backref.addRefToType(buf, t))
284 return;
286 switch (t.ty)
288 case Tpointer:
289 case Treference:
290 case Tdelegate:
291 case Tslice: visitTypeNext (cast(TypeNext)t); break;
293 case Tarray: visitTypeDArray (t.isTypeDArray()); break;
294 case Tsarray: visitTypeSArray (t.isTypeSArray()); break;
295 case Taarray: visitTypeAArray (t.isTypeAArray()); break;
296 case Tfunction: visitTypeFunction (t.isTypeFunction()); break;
297 case Tident: visitTypeIdentifier(t.isTypeIdentifier()); break;
298 case Tclass: visitTypeClass (t.isTypeClass()); break;
299 case Tstruct: visitTypeStruct (t.isTypeStruct()); break;
300 case Tenum: visitTypeEnum (t.isTypeEnum()); break;
301 case Ttuple: visitTypeTuple (t.isTypeTuple()); break;
302 case Tnull: visitTypeNull (t.isTypeNull()); break;
303 case Tvector: visitTypeVector (t.isTypeVector()); break;
304 case Tnoreturn: visitTypeNoreturn (t.isTypeNoreturn); break;
306 case Terror:
307 break; // ignore errors
309 default: visitType(t); break;
313 visitWithMask(t, modMask);
317 /*************************************************************
319 void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret, ref OutBuffer buf, ref Backref backref)
321 //printf("mangleFuncType() %s\n", t.toChars());
322 if (t.inuse && tret)
324 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
325 t.inuse = 2; // flag error to caller
326 return;
328 t.inuse++;
329 if (modMask != t.mod)
330 MODtoDecoBuffer(buf, t.mod);
332 char mc;
333 final switch (t.linkage)
335 case LINK.default_:
336 case LINK.d:
337 mc = 'F';
338 break;
339 case LINK.c:
340 mc = 'U';
341 break;
342 case LINK.windows:
343 mc = 'W';
344 break;
345 case LINK.cpp:
346 mc = 'R';
347 break;
348 case LINK.objc:
349 mc = 'Y';
350 break;
351 case LINK.system:
352 assert(0);
354 buf.writeByte(mc);
356 if (ta.purity)
357 buf.writestring("Na");
358 if (ta.isnothrow)
359 buf.writestring("Nb");
360 if (ta.isref)
361 buf.writestring("Nc");
362 if (ta.isproperty)
363 buf.writestring("Nd");
364 if (ta.isnogc)
365 buf.writestring("Ni");
367 // `return scope` must be in that order
368 if (ta.isreturnscope && !ta.isreturninferred)
370 buf.writestring("NjNl");
372 else
374 // when return ref, the order is `scope return`
375 if (ta.isScopeQual && !ta.isscopeinferred)
376 buf.writestring("Nl");
378 if (ta.isreturn && !ta.isreturninferred)
379 buf.writestring("Nj");
382 if (ta.islive)
383 buf.writestring("Nm");
385 switch (ta.trust)
387 case TRUST.trusted:
388 buf.writestring("Ne");
389 break;
390 case TRUST.safe:
391 buf.writestring("Nf");
392 break;
393 default:
394 break;
397 // Write argument types
398 foreach (idx, param; t.parameterList)
399 mangleParameter(param, buf, backref);
400 //if (buf.data[buf.length - 1] == '@') assert(0);
401 buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
402 if (tret !is null)
403 mangleType(tret, 0, buf, backref);
404 t.inuse--;
407 /*************************************************************
409 void mangleParameter(Parameter p, ref OutBuffer buf, ref Backref backref)
411 // https://dlang.org/spec/abi.html#Parameter
413 auto stc = p.storageClass;
415 // Inferred storage classes don't get mangled in
416 if (stc & STC.scopeinferred)
417 stc &= ~(STC.scope_ | STC.scopeinferred);
418 if (stc & STC.returninferred)
419 stc &= ~(STC.return_ | STC.returninferred);
421 // much like hdrgen.stcToBuffer()
422 string rrs;
423 const isout = (stc & STC.out_) != 0;
424 final switch (buildScopeRef(stc))
426 case ScopeRef.None:
427 case ScopeRef.Scope:
428 case ScopeRef.Ref:
429 case ScopeRef.Return:
430 case ScopeRef.RefScope:
431 break;
433 case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope
434 case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref
435 case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref
436 case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref
438 buf.writestring(rrs);
439 stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
440 break;
443 if (stc & STC.scope_)
444 buf.writeByte('M'); // scope
446 if (stc & STC.return_)
447 buf.writestring("Nk"); // return
449 switch (stc & ((STC.IOR | STC.lazy_) & ~STC.constscoperef))
451 case 0:
452 break;
453 case STC.in_:
454 buf.writeByte('I');
455 break;
456 case STC.in_ | STC.ref_:
457 buf.writestring("IK");
458 break;
459 case STC.out_:
460 buf.writeByte('J');
461 break;
462 case STC.ref_:
463 buf.writeByte('K');
464 break;
465 case STC.lazy_:
466 buf.writeByte('L');
467 break;
468 default:
469 debug
471 printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_));
473 assert(0);
475 mangleType(p.type, (stc & STC.in_) ? MODFlags.const_ : 0, buf, backref);
479 private extern (C++) final class Mangler : Visitor
481 alias visit = Visitor.visit;
482 public:
483 static assert(Key.sizeof == size_t.sizeof);
485 OutBuffer* buf;
486 Backref* backref;
488 extern (D) this(ref OutBuffer buf, Backref* backref) @trusted
490 this.buf = &buf;
491 this.backref = backref;
494 void mangleSymbol(Dsymbol s)
496 s.accept(this);
499 void mangleIdentifier(Identifier id, Dsymbol s)
501 if (!backref.addRefToIdentifier(*buf, id))
502 toBuffer(*buf, id.toString(), s);
505 void mangleInteger(dinteger_t v)
507 if (cast(sinteger_t) v < 0)
509 buf.writeByte('N');
510 buf.print(-v);
512 else
514 buf.writeByte('i');
515 buf.print(v);
519 ////////////////////////////////////////////////////////////////////////////
520 void mangleDecl(Declaration sthis)
522 mangleParent(sthis);
523 assert(sthis.ident);
524 mangleIdentifier(sthis.ident, sthis);
525 if (FuncDeclaration fd = sthis.isFuncDeclaration())
527 mangleFunc(fd, false);
529 else if (sthis.type)
531 mangleType(sthis.type, 0, *buf, *backref);
533 else
534 assert(0);
537 void mangleParent(Dsymbol s)
539 //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
540 Dsymbol p;
541 if (TemplateInstance ti = s.isTemplateInstance())
542 p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
543 else
544 p = s.parent;
545 if (p)
547 uint localNum = s.localNum;
548 mangleParent(p);
549 auto ti = p.isTemplateInstance();
550 if (ti && !ti.isTemplateMixin())
552 localNum = ti.tempdecl.localNum;
553 mangleTemplateInstance(ti);
555 else if (p.getIdent())
557 mangleIdentifier(p.ident, s);
558 if (FuncDeclaration f = p.isFuncDeclaration())
559 mangleFunc(f, true);
561 else
562 buf.writeByte('0');
564 if (localNum)
565 writeLocalParent(*buf, localNum);
569 void mangleFunc(FuncDeclaration fd, bool inParent)
571 //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
572 //printf("fd.type = %s\n", fd.type.toChars());
573 if (fd.needThis() || fd.isNested())
574 buf.writeByte('M');
576 if (!fd.type || fd.type.ty == Terror)
578 // never should have gotten here, but could be the result of
579 // failed speculative compilation
580 buf.writestring("9__error__FZ");
582 //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
583 //assert(0); // don't mangle function until semantic3 done.
585 else if (inParent)
587 TypeFunction tf = fd.type.isTypeFunction();
588 TypeFunction tfo = fd.originalType.isTypeFunction();
589 mangleFuncType(tf, tfo, 0, null, *buf, *backref);
591 else
593 mangleType(fd.type, 0, *buf, *backref);
597 override void visit(Declaration d)
599 //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
600 // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
601 if (const id = externallyMangledIdentifier(d))
603 buf.writestring(id);
604 return;
606 buf.writestring("_D");
607 mangleDecl(d);
608 debug
610 const slice = (*buf)[];
611 assert(slice.length);
612 for (size_t pos; pos < slice.length; )
614 dchar c;
615 auto ppos = pos;
616 const s = utf_decodeChar(slice, pos, c);
617 assert(s is null, s);
618 assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~
619 "contains an invalid character: " ~ slice[ppos..pos]);
624 /******************************************************************************
625 * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
626 * If and only if there is no overloads, mangle() could return
627 * exact mangled name.
629 * module test;
630 * void foo(long) {} // _D4test3fooFlZv
631 * void foo(string) {} // _D4test3fooFAyaZv
633 * // from FuncDeclaration.mangle().
634 * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
635 * // by calling Dsymbol.mangle()
637 * // from FuncAliasDeclaration.mangle()
638 * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
639 * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
641 * If a function has no overloads, .mangleof property still returns exact mangled name.
643 * void bar() {}
644 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
645 * // by calling FuncDeclaration.mangleExact().
647 override void visit(FuncDeclaration fd)
649 if (fd.isUnique())
650 mangleExact(fd);
651 else
652 visit(cast(Dsymbol)fd);
655 // ditto
656 override void visit(FuncAliasDeclaration fd)
658 FuncDeclaration f = fd.toAliasFunc();
659 FuncAliasDeclaration fa = f.isFuncAliasDeclaration();
660 if (!fd.hasOverloads && !fa)
662 mangleExact(f);
663 return;
665 if (fa)
667 mangleSymbol(fa);
668 return;
670 visit(cast(Dsymbol)fd);
673 override void visit(OverDeclaration od)
675 if (od.overnext)
677 visit(cast(Dsymbol)od);
678 return;
680 if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
682 if (fd.isUnique())
684 mangleExact(fd);
685 return;
688 if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
690 if (td.overnext is null)
692 mangleSymbol(td);
693 return;
696 visit(cast(Dsymbol)od);
699 void mangleExact(FuncDeclaration fd)
701 assert(!fd.isFuncAliasDeclaration());
702 if (fd.mangleOverride)
704 buf.writestring(fd.mangleOverride);
705 return;
707 if (fd.isMain())
709 buf.writestring("_Dmain");
710 return;
712 if (fd.isWinMain() || fd.isDllMain())
714 buf.writestring(fd.ident.toString());
715 return;
717 visit(cast(Declaration)fd);
720 override void visit(VarDeclaration vd)
722 if (vd.mangleOverride)
724 buf.writestring(vd.mangleOverride);
725 return;
727 visit(cast(Declaration)vd);
730 override void visit(AggregateDeclaration ad)
732 ClassDeclaration cd = ad.isClassDeclaration();
733 Dsymbol parentsave = ad.parent;
734 if (cd)
736 /* These are reserved to the compiler, so keep simple
737 * names for them.
739 if (cd.ident == Id.Exception && cd.parent.ident == Id.object || cd.ident == Id.TypeInfo || cd.ident == Id.TypeInfo_Struct || cd.ident == Id.TypeInfo_Class || cd.ident == Id.TypeInfo_Tuple || cd == ClassDeclaration.object || cd == Type.typeinfoclass || cd == Module.moduleinfo || strncmp(cd.ident.toChars(), "TypeInfo_", 9) == 0)
741 // Don't mangle parent
742 ad.parent = null;
745 visit(cast(Dsymbol)ad);
746 ad.parent = parentsave;
749 override void visit(TemplateInstance ti)
751 version (none)
753 printf("TemplateInstance.mangle() %p %s", ti, ti.toChars());
754 if (ti.parent)
755 printf(" parent = %s %s", ti.parent.kind(), ti.parent.toChars());
756 printf("\n");
758 if (!ti.tempdecl)
759 error(ti.loc, "%s `%s` is not defined", ti.kind, ti.toPrettyChars);
760 else
761 mangleParent(ti);
763 if (ti.isTemplateMixin() && ti.ident)
764 mangleIdentifier(ti.ident, ti);
765 else
766 mangleTemplateInstance(ti);
769 void mangleTemplateInstance(TemplateInstance ti)
771 TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration();
772 assert(tempdecl);
774 // Use "__U" for the symbols declared inside template constraint.
775 const char T = ti.members ? 'T' : 'U';
776 buf.printf("__%c", T);
777 mangleIdentifier(tempdecl.ident, tempdecl);
779 auto args = ti.tiargs;
780 size_t nparams = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
781 for (size_t i = 0; i < args.length; i++)
783 auto o = (*args)[i];
784 Type ta = isType(o);
785 Expression ea = isExpression(o);
786 Dsymbol sa = isDsymbol(o);
787 Tuple va = isTuple(o);
788 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
789 if (i < nparams && (*tempdecl.parameters)[i].specialization())
790 buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
791 if (ta)
793 buf.writeByte('T');
794 mangleType(ta, 0, *buf, *backref);
796 else if (ea)
798 // Don't interpret it yet, it might actually be an alias template parameter.
799 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
800 enum keepLvalue = true;
801 ea = ea.optimize(WANTvalue, keepLvalue);
802 if (auto ev = ea.isVarExp())
804 sa = ev.var;
805 ea = null;
806 goto Lsa;
808 if (auto et = ea.isThisExp())
810 sa = et.var;
811 ea = null;
812 goto Lsa;
814 if (auto ef = ea.isFuncExp())
816 if (ef.td)
817 sa = ef.td;
818 else
819 sa = ef.fd;
820 ea = null;
821 goto Lsa;
823 buf.writeByte('V');
824 if (ea.op == EXP.tuple)
826 error(ea.loc, "sequence is not a valid template value argument");
827 continue;
829 // Now that we know it is not an alias, we MUST obtain a value
830 uint olderr = global.errors;
831 ea = ea.ctfeInterpret();
832 if (ea.op == EXP.error || olderr != global.errors)
833 continue;
835 /* Use type mangling that matches what it would be for a function parameter
837 mangleType(ea.type, 0, *buf, *backref);
838 ea.accept(this);
840 else if (sa)
842 Lsa:
843 sa = sa.toAlias();
844 if (sa.isDeclaration() && !sa.isOverDeclaration())
846 Declaration d = sa.isDeclaration();
848 if (auto fad = d.isFuncAliasDeclaration())
849 d = fad.toAliasFunc();
850 if (d.mangleOverride)
852 buf.writeByte('X');
853 toBuffer(*buf, d.mangleOverride, d);
854 continue;
856 if (const id = externallyMangledIdentifier(d))
858 buf.writeByte('X');
859 toBuffer(*buf, id, d);
860 continue;
862 if (!d.type || !d.type.deco)
864 error(ti.loc, "%s `%s` forward reference of %s `%s`", ti.kind, ti.toPrettyChars, d.kind(), d.toChars());
865 continue;
868 buf.writeByte('S');
869 mangleSymbol(sa);
871 else if (va)
873 assert(i + 1 == args.length); // must be last one
874 args = &va.objects;
875 i = -cast(size_t)1;
877 else
878 assert(0);
880 buf.writeByte('Z');
883 override void visit(Dsymbol s)
885 version (none)
887 printf("Dsymbol.mangle() '%s'", s.toChars());
888 if (s.parent)
889 printf(" parent = %s %s", s.parent.kind(), s.parent.toChars());
890 printf("\n");
892 if (s.parent && s.ident)
894 if (auto m = s.parent.isModule())
896 if (m.filetype == FileType.c)
898 /* C types at global level get mangled into the __C global namespace
899 * to get the same mangling regardless of which module it
900 * is declared in. This works because types are the same if the mangling
901 * is the same.
903 mangleIdentifier(Id.ImportC, s); // parent
904 mangleIdentifier(s.ident, s);
905 return;
909 mangleParent(s);
910 if (s.ident)
911 mangleIdentifier(s.ident, s);
912 else
913 toBuffer(*buf, s.toString(), s);
914 //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
917 ////////////////////////////////////////////////////////////////////////////
918 override void visit(Expression e)
920 if (!e.type.isTypeError())
921 error(e.loc, "expression `%s` is not a valid template value argument", e.toChars());
924 override void visit(IntegerExp e)
926 mangleInteger(e.toInteger());
929 override void visit(RealExp e)
931 buf.writeByte('e');
932 realToMangleBuffer(*buf, e.value);
935 override void visit(ComplexExp e)
937 buf.writeByte('c');
938 realToMangleBuffer(*buf, e.toReal());
939 buf.writeByte('c'); // separate the two
940 realToMangleBuffer(*buf, e.toImaginary());
943 override void visit(NullExp e)
945 buf.writeByte('n');
948 override void visit(StringExp e)
950 char m;
951 OutBuffer tmp;
952 const(char)[] q;
954 /* Write string in UTF-8 format
956 switch (e.sz)
958 case 1:
959 m = 'a';
960 q = e.peekString();
961 break;
962 case 2:
964 m = 'w';
965 const slice = e.peekWstring();
966 for (size_t u = 0; u < e.len;)
968 dchar c;
969 if (const s = utf_decodeWchar(slice, u, c))
970 error(e.loc, "%.*s", cast(int)s.length, s.ptr);
971 else
972 tmp.writeUTF8(c);
974 q = tmp[];
975 break;
977 case 4:
979 m = 'd';
980 const slice = e.peekDstring();
981 foreach (c; slice)
983 if (!utf_isValidDchar(c))
984 error(e.loc, "invalid UCS-32 char \\U%08x", c);
985 else
986 tmp.writeUTF8(c);
988 q = tmp[];
989 break;
991 case 8:
992 // String of size 8 has to be hexstring cast to long[], mangle as array literal
993 buf.writeByte('A');
994 buf.print(e.len);
995 foreach (i; 0 .. e.len)
997 mangleInteger(e.getIndex(i));
999 return;
1000 default:
1001 assert(0);
1003 buf.reserve(1 + 11 + 2 * q.length);
1004 buf.writeByte(m);
1005 buf.print(q.length);
1006 buf.writeByte('_'); // nbytes <= 11
1007 buf.writeHexString(cast(const(ubyte)[]) q, false);
1010 override void visit(ArrayLiteralExp e)
1012 const dim = e.elements ? e.elements.length : 0;
1013 buf.writeByte('A');
1014 buf.print(dim);
1015 foreach (i; 0 .. dim)
1017 e[i].accept(this);
1021 override void visit(AssocArrayLiteralExp e)
1023 const dim = e.keys.length;
1024 buf.writeByte('A');
1025 buf.print(dim);
1026 foreach (i; 0 .. dim)
1028 (*e.keys)[i].accept(this);
1029 (*e.values)[i].accept(this);
1033 override void visit(StructLiteralExp e)
1035 const dim = e.elements ? e.elements.length : 0;
1036 buf.writeByte('S');
1037 buf.print(dim);
1038 foreach (i; 0 .. dim)
1040 Expression ex = (*e.elements)[i];
1041 if (ex)
1042 ex.accept(this);
1043 else
1044 buf.writeByte('v'); // 'v' for void
1048 override void visit(FuncExp e)
1050 buf.writeByte('f');
1051 if (e.td)
1052 mangleSymbol(e.td);
1053 else
1054 mangleSymbol(e.fd);
1058 /***************************************
1059 * Manage back reference mangling
1061 private struct Backref
1064 * Back references a non-basic type
1066 * The encoded mangling is
1067 * 'Q' <relative position of first occurrence of type>
1069 * Params:
1070 * t = the type to encode via back referencing
1072 * Returns:
1073 * true if the type was found. A back reference has been encoded.
1074 * false if the type was not found. The current position is saved for later back references.
1076 bool addRefToType(ref OutBuffer buf, Type t)
1078 if (t.isTypeBasic())
1079 return false;
1082 * https://issues.dlang.org/show_bug.cgi?id=21591
1084 * Special case for unmerged TypeFunctions: use the generic merged
1085 * function type as backref cache key to avoid missed backrefs.
1087 * Merging is based on mangling, so we need to avoid an infinite
1088 * recursion by excluding the case where `t` is the root type passed to
1089 * `mangleToBuffer()`.
1091 if (t != rootType)
1093 if (t.isFunction_Delegate_PtrToFunction())
1095 import dmd.typesem : merge2;
1096 t = t.merge2();
1100 return backrefImpl(buf, types, t);
1104 * Back references a single identifier
1106 * The encoded mangling is
1107 * 'Q' <relative position of first occurrence of type>
1109 * Params:
1110 * id = the identifier to encode via back referencing
1112 * Returns:
1113 * true if the identifier was found. A back reference has been encoded.
1114 * false if the identifier was not found. The current position is saved for later back references.
1116 bool addRefToIdentifier(ref OutBuffer buf, Identifier id)
1118 return backrefImpl(buf, idents, id);
1121 private:
1123 extern(D) bool backrefImpl(T)(ref OutBuffer buf, ref AssocArray!(T, size_t) aa, T key)
1125 auto p = aa.getLvalue(key);
1126 if (*p)
1128 const offset = *p - 1;
1129 writeBackRef(buf, buf.length - offset);
1130 return true;
1132 *p = buf.length + 1;
1133 return false;
1136 Type rootType; /// avoid infinite recursion
1137 AssocArray!(Type, size_t) types; /// Type => (offset+1) in buf
1138 AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf
1141 /*********************************
1142 * Mangling for mod.
1144 private void MODtoDecoBuffer(ref OutBuffer buf, MOD mod) @safe
1146 switch (mod)
1148 case 0:
1149 break;
1150 case MODFlags.const_:
1151 buf.writeByte('x');
1152 break;
1153 case MODFlags.immutable_:
1154 buf.writeByte('y');
1155 break;
1156 case MODFlags.shared_:
1157 buf.writeByte('O');
1158 break;
1159 case MODFlags.shared_ | MODFlags.const_:
1160 buf.writestring("Ox");
1161 break;
1162 case MODFlags.wild:
1163 buf.writestring("Ng");
1164 break;
1165 case MODFlags.wildconst:
1166 buf.writestring("Ngx");
1167 break;
1168 case MODFlags.shared_ | MODFlags.wild:
1169 buf.writestring("ONg");
1170 break;
1171 case MODFlags.shared_ | MODFlags.wildconst:
1172 buf.writestring("ONgx");
1173 break;
1174 default:
1175 assert(0);
1181 * writes a back reference with the relative position encoded with base 26
1182 * using upper case letters for all digits but the last digit which uses
1183 * a lower case letter.
1184 * The decoder has to look up the referenced position to determine
1185 * whether the back reference is an identifier (starts with a digit)
1186 * or a type (starts with a letter).
1188 * Params:
1189 * buf = buffer to write to
1190 * pos = relative position to encode
1192 private
1193 void writeBackRef(ref OutBuffer buf, size_t pos) @safe
1195 buf.writeByte('Q');
1196 enum base = 26;
1197 size_t mul = 1;
1198 while (pos >= mul * base)
1199 mul *= base;
1200 while (mul >= base)
1202 auto dig = cast(ubyte)(pos / mul);
1203 buf.writeByte('A' + dig);
1204 pos -= dig * mul;
1205 mul /= base;
1207 buf.writeByte('a' + cast(ubyte)pos);
1211 /************************************************************
1212 * Write length prefixed string to buf.
1214 private
1215 extern (D) void toBuffer(ref OutBuffer buf, const(char)[] id, Dsymbol s)
1217 const len = id.length;
1218 if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
1219 error(s.loc, "%s `%s` excessive length %llu for symbol, possible recursive expansion?", s.kind, s.toPrettyChars, cast(ulong)(buf.length + len));
1220 else
1222 buf.print(len);
1223 buf.writestring(id);
1228 /*****
1229 * There can be multiple different declarations in the same
1230 * function that have the same mangled name.
1231 * This results in localNum having a non-zero number, which
1232 * is used to add a fake parent of the form `__Sddd` to make
1233 * the mangled names unique.
1234 * https://issues.dlang.org/show_bug.cgi?id=20565
1235 * Params:
1236 * buf = buffer to write to
1237 * localNum = local symbol number
1239 private
1240 void writeLocalParent(ref OutBuffer buf, uint localNum)
1242 uint ndigits = 1;
1243 auto n = localNum;
1244 while (n >= 10)
1246 n /= 10;
1247 ++ndigits;
1249 buf.printf("%u__S%u", ndigits + 3, localNum);
1252 /*************************
1253 * Write real to buffer.
1254 * Params:
1255 * buf = buffer to write to
1256 * value = real to write
1258 private
1259 void realToMangleBuffer(ref OutBuffer buf, real_t value)
1261 /* Rely on %A to get portable mangling.
1262 * Must munge result to get only identifier characters.
1264 * Possible values from %A => mangled result
1265 * NAN => NAN
1266 * -INF => NINF
1267 * INF => INF
1268 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
1269 * 0X1.9P+2 => 19P2
1271 if (CTFloat.isNaN(value))
1273 buf.writestring("NAN"); // no -NAN bugs
1274 return;
1277 if (value < CTFloat.zero)
1279 buf.writeByte('N');
1280 value = -value;
1283 if (CTFloat.isInfinity(value))
1285 buf.writestring("INF");
1286 return;
1289 char[36] buffer = void;
1290 // 'A' format yields [-]0xh.hhhhp+-d
1291 const n = CTFloat.sprint(buffer.ptr, buffer.length, 'A', value);
1292 assert(n < buffer.length);
1293 foreach (const c; buffer[2 .. n])
1295 switch (c)
1297 case '-':
1298 buf.writeByte('N');
1299 break;
1301 case '+':
1302 case '.':
1303 break;
1305 default:
1306 buf.writeByte(c);
1307 break;
1312 /************************************************************
1313 * Try to obtain an externally mangled identifier from a declaration.
1314 * If the declaration is at global scope or mixed in at global scope,
1315 * the user might want to call it externally, so an externally mangled
1316 * name is returned. Member functions or nested functions can't be called
1317 * externally in C, so in that case null is returned. C++ does support
1318 * namespaces, so extern(C++) always gives a C++ mangled name.
1320 * See also: https://issues.dlang.org/show_bug.cgi?id=20012
1322 * Params:
1323 * d = declaration to mangle
1325 * Returns:
1326 * an externally mangled name or null if the declaration cannot be called externally
1328 private
1329 extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
1331 assert(!d.mangleOverride, "mangle overrides should have been handled earlier");
1333 const linkage = d.resolvedLinkage();
1334 const par = d.toParent(); //toParent() skips over mixin templates
1335 if (!par || par.isModule() || linkage == LINK.cpp ||
1336 (linkage == LINK.c && d.isCsymbol() &&
1337 (d.isFuncDeclaration() ||
1338 (d.isVarDeclaration() && d.isDataseg() && d.storage_class & STC.extern_))))
1340 if (linkage != LINK.d && d.localNum)
1341 error(d.loc, "%s `%s` the same declaration cannot be in multiple scopes with non-D linkage", d.kind, d.toPrettyChars);
1343 final switch (linkage)
1345 case LINK.d:
1346 break;
1347 case LINK.c:
1348 case LINK.windows:
1349 case LINK.objc:
1350 return d.ident.toString();
1351 case LINK.cpp:
1353 const p = target.cpp.toMangle(d);
1354 return p.toDString();
1356 case LINK.default_:
1357 error(d.loc, "%s `%s` forward declaration", d.kind, d.toPrettyChars);
1358 return d.ident.toString();
1359 case LINK.system:
1360 assert(0);
1363 return null;