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-2023 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/
18 /******************************************************************************
19 * Returns exact mangled name of function.
21 extern (C
++) const(char)* mangleExact(FuncDeclaration fd
)
23 //printf("mangleExact()\n");
27 auto backref
= Backref(null);
28 scope Mangler v
= new Mangler(buf
, &backref
);
30 fd
.mangleString
= buf
.extractChars();
32 return fd
.mangleString
;
35 extern (C
++) void mangleToBuffer(Type t
, ref OutBuffer buf
)
37 //printf("mangleToBuffer t()\n");
39 buf
.writestring(t
.deco
);
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
);
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
);
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
76 c
>= 'A' && c
<= 'Z' ||
77 c
>= 'a' && c
<= 'z' ||
78 c
>= '0' && c
<= '9' ||
79 c
!= 0 && strchr("$%().:?@[]_", c
) ||
83 // valid mangled characters
86 assert('a'.isValidMangling
);
87 assert('B'.isValidMangling
);
88 assert('2'.isValidMangling
);
89 assert('@'.isValidMangling
);
90 assert('_'.isValidMangling
);
93 // invalid mangled characters
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.
106 * deco = string containing the deco
108 * null for failed to convert
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
))
119 Type t
= cast(Type
)sv
.value
;
128 /***************************************** private ***************************************/
133 import core
.stdc
.ctype
;
134 import core
.stdc
.stdio
;
135 import core
.stdc
.string
;
137 import dmd
.aggregate
;
138 import dmd
.arraytypes
;
141 import dmd
.declaration
;
144 import dmd
.dtemplate
;
146 import dmd
.expression
;
150 import dmd
.identifier
;
152 import dmd
.root
.ctfloat
;
153 import dmd
.common
.outbuffer
;
155 import dmd
.root
.string
;
156 import dmd
.root
.stringtable
;
162 private immutable char[TMAX
] mangleChar
=
197 Tfunction
: 'F', // D function
204 // M // has this, or scope
205 // N // Nh:vector Ng:wild Nn:noreturn
208 // Q // Type/symbol/identifier backward reference
213 // W // Windows function
214 // X // variadic T t...)
215 // Y // variadic T t,...)
216 // Z // not variadic, end of parameters
218 // '@' shouldn't appear anywhere in the deco'd names
230 Tnoreturn
: '@', // becomes 'Nn'
235 foreach (i
, mangle
; mangleChar
)
237 if (mangle
== char.init
)
239 fprintf(stderr
, "ty = %u\n", cast(uint)i
);
245 /************************************************
246 * Append the mangling of type `t` to `buf`.
249 * modMask = mod bits currently applying to t
250 * buf = buffer to append mangling to
251 * backref = state of back references (updated)
253 void mangleType(Type t
, ubyte modMask
, ref OutBuffer buf
, ref Backref backref
)
255 void visitWithMask(Type t
, ubyte modMask
)
257 void mangleSymbol(Dsymbol s
)
259 scope Mangler v
= new Mangler(buf
, &backref
);
263 void visitType(Type t
)
265 tyToDecoBuffer(buf
, t
.ty
);
268 void visitTypeNext(TypeNext t
)
271 visitWithMask(t
.next
, t
.mod
);
274 void visitTypeVector(TypeVector t
)
276 buf
.writestring("Nh");
277 visitWithMask(t
.basetype
, t
.mod
);
280 void visitTypeSArray(TypeSArray t
)
284 buf
.print(t
.dim
.toInteger());
286 visitWithMask(t
.next
, t
.mod
);
289 void visitTypeDArray(TypeDArray t
)
293 visitWithMask(t
.next
, t
.mod
);
296 void visitTypeAArray(TypeAArray t
)
299 visitWithMask(t
.index
, 0);
300 visitWithMask(t
.next
, t
.mod
);
303 void visitTypeFunction(TypeFunction t
)
305 //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
306 //static int nest; if (++nest == 50) *(char*)0=0;
307 mangleFuncType(t
, t
, t
.mod
, t
.next
, buf
, backref
);
310 void visitTypeIdentifier(TypeIdentifier t
)
313 auto name
= t
.ident
.toString();
314 buf
.print(cast(int)name
.length
);
315 buf
.writestring(name
);
318 void visitTypeEnum(TypeEnum t
)
324 void visitTypeStruct(TypeStruct t
)
326 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
331 void visitTypeClass(TypeClass t
)
333 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
338 void visitTypeTuple(TypeTuple t
)
340 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
342 Parameter
._foreach(t
.arguments
, (idx
, param
) {
343 mangleParameter(param
, buf
, backref
);
349 void visitTypeNull(TypeNull t
)
354 void visitTypeNoreturn(TypeNoreturn t
)
356 buf
.writestring("Nn");
359 if (modMask
!= t
.mod
)
361 MODtoDecoBuffer(buf
, t
.mod
);
363 if (backref
.addRefToType(buf
, t
))
371 case Tslice
: visitTypeNext (cast(TypeNext
)t
); break;
373 case Tarray
: visitTypeDArray (t
.isTypeDArray()); break;
374 case Tsarray
: visitTypeSArray (t
.isTypeSArray()); break;
375 case Taarray
: visitTypeAArray (t
.isTypeAArray()); break;
376 case Tfunction
: visitTypeFunction (t
.isTypeFunction()); break;
377 case Tident
: visitTypeIdentifier(t
.isTypeIdentifier()); break;
378 case Tclass
: visitTypeClass (t
.isTypeClass()); break;
379 case Tstruct
: visitTypeStruct (t
.isTypeStruct()); break;
380 case Tenum
: visitTypeEnum (t
.isTypeEnum()); break;
381 case Ttuple
: visitTypeTuple (t
.isTypeTuple()); break;
382 case Tnull
: visitTypeNull (t
.isTypeNull()); break;
383 case Tvector
: visitTypeVector (t
.isTypeVector()); break;
384 case Tnoreturn
: visitTypeNoreturn (t
.isTypeNoreturn
); break;
387 break; // ignore errors
389 default: visitType(t
); break;
393 visitWithMask(t
, modMask
);
397 /*************************************************************
399 void mangleFuncType(TypeFunction t
, TypeFunction ta
, ubyte modMask
, Type tret
, ref OutBuffer buf
, ref Backref backref
)
401 //printf("mangleFuncType() %s\n", t.toChars());
404 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
405 t
.inuse
= 2; // flag error to caller
409 if (modMask
!= t
.mod
)
410 MODtoDecoBuffer(buf
, t
.mod
);
413 final switch (t
.linkage
)
437 buf
.writestring("Na");
439 buf
.writestring("Nb");
441 buf
.writestring("Nc");
443 buf
.writestring("Nd");
445 buf
.writestring("Ni");
447 // `return scope` must be in that order
448 if (ta
.isreturnscope
&& !ta
.isreturninferred
)
450 buf
.writestring("NjNl");
454 // when return ref, the order is `scope return`
455 if (ta
.isScopeQual
&& !ta
.isscopeinferred
)
456 buf
.writestring("Nl");
458 if (ta
.isreturn
&& !ta
.isreturninferred
)
459 buf
.writestring("Nj");
463 buf
.writestring("Nm");
468 buf
.writestring("Ne");
471 buf
.writestring("Nf");
477 // Write argument types
478 foreach (idx
, param
; t
.parameterList
)
479 mangleParameter(param
, buf
, backref
);
480 //if (buf.data[buf.length - 1] == '@') assert(0);
481 buf
.writeByte('Z' - t
.parameterList
.varargs
); // mark end of arg list
483 mangleType(tret
, 0, buf
, backref
);
487 /*************************************************************
489 void mangleParameter(Parameter p
, ref OutBuffer buf
, ref Backref backref
)
491 // https://dlang.org/spec/abi.html#Parameter
493 auto stc = p
.storageClass
;
495 // Inferred storage classes don't get mangled in
496 if (stc & STC
.scopeinferred
)
497 stc &= ~(STC
.scope_ | STC
.scopeinferred
);
498 if (stc & STC
.returninferred
)
499 stc &= ~(STC
.return_ | STC
.returninferred
);
501 // much like hdrgen.stcToBuffer()
503 const isout
= (stc & STC
.out_
) != 0;
504 final switch (buildScopeRef(stc))
509 case ScopeRef
.Return
:
510 case ScopeRef
.RefScope
:
513 case ScopeRef
.ReturnScope
: rrs
= "NkM"; goto L1
; // return scope
514 case ScopeRef
.ReturnRef
: rrs
= isout ?
"NkJ" : "NkK"; goto L1
; // return ref
515 case ScopeRef
.ReturnRef_Scope
: rrs
= isout ?
"MNkJ" : "MNkK"; goto L1
; // scope return ref
516 case ScopeRef
.Ref_ReturnScope
: rrs
= isout ?
"NkMJ" : "NkMK"; goto L1
; // return scope ref
518 buf
.writestring(rrs
);
519 stc &= ~(STC
.out_ | STC
.scope_ | STC
.ref_ | STC
.return_
);
523 if (stc & STC
.scope_
)
524 buf
.writeByte('M'); // scope
526 if (stc & STC
.return_
)
527 buf
.writestring("Nk"); // return
529 switch (stc & (STC
.IOR | STC
.lazy_
))
536 case STC
.in_ | STC
.ref_
:
537 buf
.writestring("IK");
551 printf("storageClass = x%llx\n", stc & (STC
.IOR | STC
.lazy_
));
555 mangleType(p
.type
, (stc & STC
.in_
) ? MODFlags
.const_
: 0, buf
, backref
);
559 private extern (C
++) final class Mangler
: Visitor
561 alias visit
= Visitor
.visit
;
563 static assert(Key
.sizeof
== size_t
.sizeof
);
568 extern (D
) this(ref OutBuffer buf
, Backref
* backref
) @trusted
571 this.backref
= backref
;
574 void mangleSymbol(Dsymbol s
)
579 void mangleIdentifier(Identifier id
, Dsymbol s
)
581 if (!backref
.addRefToIdentifier(*buf
, id
))
582 toBuffer(*buf
, id
.toString(), s
);
585 ////////////////////////////////////////////////////////////////////////////
586 void mangleDecl(Declaration sthis
)
590 mangleIdentifier(sthis
.ident
, sthis
);
591 if (FuncDeclaration fd
= sthis
.isFuncDeclaration())
593 mangleFunc(fd
, false);
597 mangleType(sthis
.type
, 0, *buf
, *backref
);
603 void mangleParent(Dsymbol s
)
605 //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
607 if (TemplateInstance ti
= s
.isTemplateInstance())
608 p
= ti
.isTemplateMixin() ? ti
.parent
: ti
.tempdecl
.parent
;
613 uint localNum
= s
.localNum
;
615 auto ti
= p
.isTemplateInstance();
616 if (ti
&& !ti
.isTemplateMixin())
618 localNum
= ti
.tempdecl
.localNum
;
619 mangleTemplateInstance(ti
);
621 else if (p
.getIdent())
623 mangleIdentifier(p
.ident
, s
);
624 if (FuncDeclaration f
= p
.isFuncDeclaration())
631 writeLocalParent(*buf
, localNum
);
635 void mangleFunc(FuncDeclaration fd
, bool inParent
)
637 //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
638 //printf("fd.type = %s\n", fd.type.toChars());
639 if (fd
.needThis() || fd
.isNested())
642 if (!fd
.type || fd
.type
.ty
== Terror
)
644 // never should have gotten here, but could be the result of
645 // failed speculative compilation
646 buf
.writestring("9__error__FZ");
648 //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
649 //assert(0); // don't mangle function until semantic3 done.
653 TypeFunction tf
= fd
.type
.isTypeFunction();
654 TypeFunction tfo
= fd
.originalType
.isTypeFunction();
655 mangleFuncType(tf
, tfo
, 0, null, *buf
, *backref
);
659 mangleType(fd
.type
, 0, *buf
, *backref
);
663 override void visit(Declaration d
)
665 //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
666 // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
667 if (const id
= externallyMangledIdentifier(d
))
672 buf
.writestring("_D");
676 const slice
= (*buf
)[];
677 assert(slice
.length
);
678 for (size_t pos
; pos
< slice
.length
; )
682 const s
= utf_decodeChar(slice
, pos
, c
);
683 assert(s
is null, s
);
684 assert(c
.isValidMangling
, "The mangled name '" ~ slice
~ "' " ~
685 "contains an invalid character: " ~ slice
[ppos
..pos
]);
690 /******************************************************************************
691 * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
692 * If and only if there is no overloads, mangle() could return
693 * exact mangled name.
696 * void foo(long) {} // _D4test3fooFlZv
697 * void foo(string) {} // _D4test3fooFAyaZv
699 * // from FuncDeclaration.mangle().
700 * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
701 * // by calling Dsymbol.mangle()
703 * // from FuncAliasDeclaration.mangle()
704 * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
705 * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
707 * If a function has no overloads, .mangleof property still returns exact mangled name.
710 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
711 * // by calling FuncDeclaration.mangleExact().
713 override void visit(FuncDeclaration fd
)
718 visit(cast(Dsymbol
)fd
);
722 override void visit(FuncAliasDeclaration fd
)
724 FuncDeclaration f
= fd
.toAliasFunc();
725 FuncAliasDeclaration fa
= f
.isFuncAliasDeclaration();
726 if (!fd
.hasOverloads
&& !fa
)
736 visit(cast(Dsymbol
)fd
);
739 override void visit(OverDeclaration od
)
743 visit(cast(Dsymbol
)od
);
746 if (FuncDeclaration fd
= od
.aliassym
.isFuncDeclaration())
754 if (TemplateDeclaration td
= od
.aliassym
.isTemplateDeclaration())
756 if (td
.overnext
is null)
762 visit(cast(Dsymbol
)od
);
765 void mangleExact(FuncDeclaration fd
)
767 assert(!fd
.isFuncAliasDeclaration());
768 if (fd
.mangleOverride
)
770 buf
.writestring(fd
.mangleOverride
);
775 buf
.writestring("_Dmain");
778 if (fd
.isWinMain() || fd
.isDllMain())
780 buf
.writestring(fd
.ident
.toString());
783 visit(cast(Declaration
)fd
);
786 override void visit(VarDeclaration vd
)
788 if (vd
.mangleOverride
)
790 buf
.writestring(vd
.mangleOverride
);
793 visit(cast(Declaration
)vd
);
796 override void visit(AggregateDeclaration ad
)
798 ClassDeclaration cd
= ad
.isClassDeclaration();
799 Dsymbol parentsave
= ad
.parent
;
802 /* These are reserved to the compiler, so keep simple
805 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)
807 // Don't mangle parent
811 visit(cast(Dsymbol
)ad
);
812 ad
.parent
= parentsave
;
815 override void visit(TemplateInstance ti
)
819 printf("TemplateInstance.mangle() %p %s", ti
, ti
.toChars());
821 printf(" parent = %s %s", ti
.parent
.kind(), ti
.parent
.toChars());
825 error(ti
.loc
, "%s `%s` is not defined", ti
.kind
, ti
.toPrettyChars
);
829 if (ti
.isTemplateMixin() && ti
.ident
)
830 mangleIdentifier(ti
.ident
, ti
);
832 mangleTemplateInstance(ti
);
835 void mangleTemplateInstance(TemplateInstance ti
)
837 TemplateDeclaration tempdecl
= ti
.tempdecl
.isTemplateDeclaration();
840 // Use "__U" for the symbols declared inside template constraint.
841 const char T
= ti
.members ?
'T' : 'U';
842 buf
.printf("__%c", T
);
843 mangleIdentifier(tempdecl
.ident
, tempdecl
);
845 auto args
= ti
.tiargs
;
846 size_t nparams
= tempdecl
.parameters
.length
- (tempdecl
.isVariadic() ?
1 : 0);
847 for (size_t i
= 0; i
< args
.length
; i
++)
851 Expression ea
= isExpression(o
);
852 Dsymbol sa
= isDsymbol(o
);
853 Tuple va
= isTuple(o
);
854 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
855 if (i
< nparams
&& (*tempdecl
.parameters
)[i
].specialization())
856 buf
.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
860 mangleType(ta
, 0, *buf
, *backref
);
864 // Don't interpret it yet, it might actually be an alias template parameter.
865 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
866 enum keepLvalue
= true;
867 ea
= ea
.optimize(WANTvalue
, keepLvalue
);
868 if (auto ev
= ea
.isVarExp())
874 if (auto et
= ea
.isThisExp())
880 if (auto ef
= ea
.isFuncExp())
890 if (ea
.op
== EXP
.tuple
)
892 error(ea
.loc
, "sequence is not a valid template value argument");
895 // Now that we know it is not an alias, we MUST obtain a value
896 uint olderr
= global
.errors
;
897 ea
= ea
.ctfeInterpret();
898 if (ea
.op
== EXP
.error || olderr
!= global
.errors
)
901 /* Use type mangling that matches what it would be for a function parameter
903 mangleType(ea
.type
, 0, *buf
, *backref
);
910 if (sa
.isDeclaration() && !sa
.isOverDeclaration())
912 Declaration d
= sa
.isDeclaration();
914 if (auto fad
= d
.isFuncAliasDeclaration())
915 d
= fad
.toAliasFunc();
916 if (d
.mangleOverride
)
919 toBuffer(*buf
, d
.mangleOverride
, d
);
922 if (const id
= externallyMangledIdentifier(d
))
925 toBuffer(*buf
, id
, d
);
928 if (!d
.type ||
!d
.type
.deco
)
930 error(ti
.loc
, "%s `%s` forward reference of %s `%s`", ti
.kind
, ti
.toPrettyChars
, d
.kind(), d
.toChars());
939 assert(i
+ 1 == args
.length
); // must be last one
949 override void visit(Dsymbol s
)
953 printf("Dsymbol.mangle() '%s'", s
.toChars());
955 printf(" parent = %s %s", s
.parent
.kind(), s
.parent
.toChars());
958 if (s
.parent
&& s
.ident
)
960 if (auto m
= s
.parent
.isModule())
962 if (m
.filetype
== FileType
.c
)
964 /* C types at global level get mangled into the __C global namespace
965 * to get the same mangling regardless of which module it
966 * is declared in. This works because types are the same if the mangling
969 mangleIdentifier(Id
.ImportC
, s
); // parent
970 mangleIdentifier(s
.ident
, s
);
977 mangleIdentifier(s
.ident
, s
);
979 toBuffer(*buf
, s
.toString(), s
);
980 //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
983 ////////////////////////////////////////////////////////////////////////////
984 override void visit(Expression e
)
986 if (!e
.type
.isTypeError())
987 error(e
.loc
, "expression `%s` is not a valid template value argument", e
.toChars());
990 override void visit(IntegerExp e
)
992 const v
= e
.toInteger();
993 if (cast(sinteger_t
)v
< 0)
1005 override void visit(RealExp e
)
1008 realToMangleBuffer(*buf
, e
.value
);
1011 override void visit(ComplexExp e
)
1014 realToMangleBuffer(*buf
, e
.toReal());
1015 buf
.writeByte('c'); // separate the two
1016 realToMangleBuffer(*buf
, e
.toImaginary());
1019 override void visit(NullExp e
)
1024 override void visit(StringExp e
)
1029 /* Write string in UTF-8 format
1040 const slice
= e
.peekWstring();
1041 for (size_t u
= 0; u
< e
.len
;)
1044 if (const s
= utf_decodeWchar(slice
, u
, c
))
1045 error(e
.loc
, "%.*s", cast(int)s
.length
, s
.ptr
);
1055 const slice
= e
.peekDstring();
1058 if (!utf_isValidDchar(c
))
1059 error(e
.loc
, "invalid UCS-32 char \\U%08x", c
);
1070 buf
.reserve(1 + 11 + 2 * q
.length
);
1072 buf
.print(q
.length
);
1073 buf
.writeByte('_'); // nbytes <= 11
1074 auto slice
= buf
.allocate(2 * q
.length
);
1077 char hi
= (c
>> 4) & 0xF;
1078 slice
[i
* 2] = cast(char)(hi
< 10 ? hi
+ '0' : hi
- 10 + 'a');
1080 slice
[i
* 2 + 1] = cast(char)(lo
< 10 ? lo
+ '0' : lo
- 10 + 'a');
1084 override void visit(ArrayLiteralExp e
)
1086 const dim
= e
.elements ? e
.elements
.length
: 0;
1089 foreach (i
; 0 .. dim
)
1095 override void visit(AssocArrayLiteralExp e
)
1097 const dim
= e
.keys
.length
;
1100 foreach (i
; 0 .. dim
)
1102 (*e
.keys
)[i
].accept(this);
1103 (*e
.values
)[i
].accept(this);
1107 override void visit(StructLiteralExp e
)
1109 const dim
= e
.elements ? e
.elements
.length
: 0;
1112 foreach (i
; 0 .. dim
)
1114 Expression ex
= (*e
.elements
)[i
];
1118 buf
.writeByte('v'); // 'v' for void
1122 override void visit(FuncExp e
)
1132 /***************************************
1133 * Manage back reference mangling
1135 private struct Backref
1138 * Back references a non-basic type
1140 * The encoded mangling is
1141 * 'Q' <relative position of first occurrence of type>
1144 * t = the type to encode via back referencing
1147 * true if the type was found. A back reference has been encoded.
1148 * false if the type was not found. The current position is saved for later back references.
1150 bool addRefToType(ref OutBuffer buf
, Type t
)
1152 if (t
.isTypeBasic())
1156 * https://issues.dlang.org/show_bug.cgi?id=21591
1158 * Special case for unmerged TypeFunctions: use the generic merged
1159 * function type as backref cache key to avoid missed backrefs.
1161 * Merging is based on mangling, so we need to avoid an infinite
1162 * recursion by excluding the case where `t` is the root type passed to
1163 * `mangleToBuffer()`.
1167 if (t
.isFunction_Delegate_PtrToFunction())
1173 return backrefImpl(buf
, types
, t
);
1177 * Back references a single identifier
1179 * The encoded mangling is
1180 * 'Q' <relative position of first occurrence of type>
1183 * id = the identifier to encode via back referencing
1186 * true if the identifier was found. A back reference has been encoded.
1187 * false if the identifier was not found. The current position is saved for later back references.
1189 bool addRefToIdentifier(ref OutBuffer buf
, Identifier id
)
1191 return backrefImpl(buf
, idents
, id
);
1196 extern(D
) bool backrefImpl(T
)(ref OutBuffer buf
, ref AssocArray
!(T
, size_t
) aa
, T key
)
1198 auto p
= aa
.getLvalue(key
);
1201 const offset
= *p
- 1;
1202 writeBackRef(buf
, buf
.length
- offset
);
1205 *p
= buf
.length
+ 1;
1209 Type rootType
; /// avoid infinite recursion
1210 AssocArray
!(Type
, size_t
) types
; /// Type => (offset+1) in buf
1211 AssocArray
!(Identifier
, size_t
) idents
; /// Identifier => (offset+1) in buf
1215 /***********************
1216 * Mangle basic type ty to buf.
1219 private void tyToDecoBuffer(ref OutBuffer buf
, int ty
) @safe
1221 const c
= mangleChar
[ty
];
1224 buf
.writeByte(ty
== Tint128 ?
'i' : 'k');
1227 /*********************************
1230 private void MODtoDecoBuffer(ref OutBuffer buf
, MOD mod
) @safe
1236 case MODFlags
.const_
:
1239 case MODFlags
.immutable_
:
1242 case MODFlags
.shared_
:
1245 case MODFlags
.shared_ | MODFlags
.const_
:
1246 buf
.writestring("Ox");
1249 buf
.writestring("Ng");
1251 case MODFlags
.wildconst
:
1252 buf
.writestring("Ngx");
1254 case MODFlags
.shared_ | MODFlags
.wild
:
1255 buf
.writestring("ONg");
1257 case MODFlags
.shared_ | MODFlags
.wildconst
:
1258 buf
.writestring("ONgx");
1267 * writes a back reference with the relative position encoded with base 26
1268 * using upper case letters for all digits but the last digit which uses
1269 * a lower case letter.
1270 * The decoder has to look up the referenced position to determine
1271 * whether the back reference is an identifier (starts with a digit)
1272 * or a type (starts with a letter).
1275 * buf = buffer to write to
1276 * pos = relative position to encode
1279 void writeBackRef(ref OutBuffer buf
, size_t pos
) @safe
1284 while (pos
>= mul * base
)
1288 auto dig
= cast(ubyte)(pos
/ mul);
1289 buf
.writeByte('A' + dig
);
1293 buf
.writeByte('a' + cast(ubyte)pos
);
1297 /************************************************************
1298 * Write length prefixed string to buf.
1301 extern (D
) void toBuffer(ref OutBuffer buf
, const(char)[] id
, Dsymbol s
)
1303 const len
= id
.length
;
1304 if (buf
.length
+ len
>= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
1305 error(s
.loc
, "%s `%s` excessive length %llu for symbol, possible recursive expansion?", s
.kind
, s
.toPrettyChars
, cast(ulong)(buf
.length
+ len
));
1309 buf
.writestring(id
);
1315 * There can be multiple different declarations in the same
1316 * function that have the same mangled name.
1317 * This results in localNum having a non-zero number, which
1318 * is used to add a fake parent of the form `__Sddd` to make
1319 * the mangled names unique.
1320 * https://issues.dlang.org/show_bug.cgi?id=20565
1322 * buf = buffer to write to
1323 * localNum = local symbol number
1326 void writeLocalParent(ref OutBuffer buf
, uint localNum
)
1335 buf
.printf("%u__S%u", ndigits
+ 3, localNum
);
1338 /*************************
1339 * Write real to buffer.
1341 * buf = buffer to write to
1342 * value = real to write
1345 void realToMangleBuffer(ref OutBuffer buf
, real_t value
)
1347 /* Rely on %A to get portable mangling.
1348 * Must munge result to get only identifier characters.
1350 * Possible values from %A => mangled result
1354 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
1357 if (CTFloat
.isNaN(value
))
1359 buf
.writestring("NAN"); // no -NAN bugs
1363 if (value
< CTFloat
.zero
)
1369 if (CTFloat
.isInfinity(value
))
1371 buf
.writestring("INF");
1375 char[36] buffer
= void;
1376 // 'A' format yields [-]0xh.hhhhp+-d
1377 const n
= CTFloat
.sprint(buffer
.ptr
, buffer
.length
, 'A', value
);
1378 assert(n
< buffer
.length
);
1379 foreach (const c
; buffer
[2 .. n
])
1398 /************************************************************
1399 * Try to obtain an externally mangled identifier from a declaration.
1400 * If the declaration is at global scope or mixed in at global scope,
1401 * the user might want to call it externally, so an externally mangled
1402 * name is returned. Member functions or nested functions can't be called
1403 * externally in C, so in that case null is returned. C++ does support
1404 * namespaces, so extern(C++) always gives a C++ mangled name.
1406 * See also: https://issues.dlang.org/show_bug.cgi?id=20012
1409 * d = declaration to mangle
1412 * an externally mangled name or null if the declaration cannot be called externally
1415 extern (D
) const(char)[] externallyMangledIdentifier(Declaration d
)
1417 assert(!d
.mangleOverride
, "mangle overrides should have been handled earlier");
1419 const linkage
= d
.resolvedLinkage();
1420 const par
= d
.toParent(); //toParent() skips over mixin templates
1421 if (!par || par
.isModule() || linkage
== LINK
.cpp ||
1422 (linkage
== LINK
.c
&& d
.isCsymbol() &&
1423 (d
.isFuncDeclaration() ||
1424 (d
.isVarDeclaration() && d
.isDataseg() && d
.storage_class
& STC
.extern_
))))
1426 if (linkage
!= LINK
.d
&& d
.localNum
)
1427 error(d
.loc
, "%s `%s` the same declaration cannot be in multiple scopes with non-D linkage", d
.kind
, d
.toPrettyChars
);
1429 final switch (linkage
)
1436 return d
.ident
.toString();
1439 const p
= target
.cpp
.toMangle(d
);
1440 return p
.toDString();
1443 error(d
.loc
, "%s `%s` forward declaration", d
.kind
, d
.toPrettyChars
);
1444 return d
.ident
.toString();