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/
18 /******************************************************************************
19 * Returns exact mangled name of function.
21 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 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 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 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 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
;
140 import dmd
.basicmangle
;
142 import dmd
.declaration
;
143 import dmd
.dinterpret
;
146 import dmd
.dtemplate
;
148 import dmd
.expression
;
152 import dmd
.identifier
;
154 import dmd
.root
.ctfloat
;
155 import dmd
.common
.outbuffer
;
158 import dmd
.root
.string
;
159 import dmd
.root
.stringtable
;
165 /************************************************
166 * Append the mangling of type `t` to `buf`.
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
);
183 void visitType(Type t
)
185 tyToDecoBuffer(buf
, t
.ty
);
188 void visitTypeNext(TypeNext 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
)
204 buf
.print(t
.dim
.toInteger());
206 visitWithMask(t
.next
, t
.mod
);
209 void visitTypeDArray(TypeDArray t
)
213 visitWithMask(t
.next
, t
.mod
);
216 void visitTypeAArray(TypeAArray 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
)
233 auto name
= t
.ident
.toString();
234 buf
.print(cast(int)name
.length
);
235 buf
.writestring(name
);
238 void visitTypeEnum(TypeEnum t
)
244 void visitTypeStruct(TypeStruct t
)
246 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
251 void visitTypeClass(TypeClass t
)
253 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
258 void visitTypeTuple(TypeTuple t
)
260 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
262 Parameter
._foreach(t
.arguments
, (idx
, param
) {
263 mangleParameter(param
, buf
, backref
);
269 void visitTypeNull(TypeNull 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
))
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;
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());
324 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
325 t
.inuse
= 2; // flag error to caller
329 if (modMask
!= t
.mod
)
330 MODtoDecoBuffer(buf
, t
.mod
);
333 final switch (t
.linkage
)
357 buf
.writestring("Na");
359 buf
.writestring("Nb");
361 buf
.writestring("Nc");
363 buf
.writestring("Nd");
365 buf
.writestring("Ni");
367 // `return scope` must be in that order
368 if (ta
.isreturnscope
&& !ta
.isreturninferred
)
370 buf
.writestring("NjNl");
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");
383 buf
.writestring("Nm");
388 buf
.writestring("Ne");
391 buf
.writestring("Nf");
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
403 mangleType(tret
, 0, buf
, backref
);
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()
423 const isout
= (stc & STC
.out_
) != 0;
424 final switch (buildScopeRef(stc))
429 case ScopeRef
.Return
:
430 case ScopeRef
.RefScope
:
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_
);
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
))
456 case STC
.in_ | STC
.ref_
:
457 buf
.writestring("IK");
471 printf("storageClass = x%llx\n", stc & (STC
.IOR | STC
.lazy_
));
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
;
483 static assert(Key
.sizeof
== size_t
.sizeof
);
488 extern (D
) this(ref OutBuffer buf
, Backref
* backref
) @trusted
491 this.backref
= backref
;
494 void mangleSymbol(Dsymbol s
)
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)
519 ////////////////////////////////////////////////////////////////////////////
520 void mangleDecl(Declaration sthis
)
524 mangleIdentifier(sthis
.ident
, sthis
);
525 if (FuncDeclaration fd
= sthis
.isFuncDeclaration())
527 mangleFunc(fd
, false);
531 mangleType(sthis
.type
, 0, *buf
, *backref
);
537 void mangleParent(Dsymbol s
)
539 //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
541 if (TemplateInstance ti
= s
.isTemplateInstance())
542 p
= ti
.isTemplateMixin() ? ti
.parent
: ti
.tempdecl
.parent
;
547 uint localNum
= s
.localNum
;
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())
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())
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.
587 TypeFunction tf
= fd
.type
.isTypeFunction();
588 TypeFunction tfo
= fd
.originalType
.isTypeFunction();
589 mangleFuncType(tf
, tfo
, 0, null, *buf
, *backref
);
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
))
606 buf
.writestring("_D");
610 const slice
= (*buf
)[];
611 assert(slice
.length
);
612 for (size_t pos
; pos
< slice
.length
; )
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.
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.
644 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
645 * // by calling FuncDeclaration.mangleExact().
647 override void visit(FuncDeclaration fd
)
652 visit(cast(Dsymbol
)fd
);
656 override void visit(FuncAliasDeclaration fd
)
658 FuncDeclaration f
= fd
.toAliasFunc();
659 FuncAliasDeclaration fa
= f
.isFuncAliasDeclaration();
660 if (!fd
.hasOverloads
&& !fa
)
670 visit(cast(Dsymbol
)fd
);
673 override void visit(OverDeclaration od
)
677 visit(cast(Dsymbol
)od
);
680 if (FuncDeclaration fd
= od
.aliassym
.isFuncDeclaration())
688 if (TemplateDeclaration td
= od
.aliassym
.isTemplateDeclaration())
690 if (td
.overnext
is null)
696 visit(cast(Dsymbol
)od
);
699 void mangleExact(FuncDeclaration fd
)
701 assert(!fd
.isFuncAliasDeclaration());
702 if (fd
.mangleOverride
)
704 buf
.writestring(fd
.mangleOverride
);
709 buf
.writestring("_Dmain");
712 if (fd
.isWinMain() || fd
.isDllMain())
714 buf
.writestring(fd
.ident
.toString());
717 visit(cast(Declaration
)fd
);
720 override void visit(VarDeclaration vd
)
722 if (vd
.mangleOverride
)
724 buf
.writestring(vd
.mangleOverride
);
727 visit(cast(Declaration
)vd
);
730 override void visit(AggregateDeclaration ad
)
732 ClassDeclaration cd
= ad
.isClassDeclaration();
733 Dsymbol parentsave
= ad
.parent
;
736 /* These are reserved to the compiler, so keep simple
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
745 visit(cast(Dsymbol
)ad
);
746 ad
.parent
= parentsave
;
749 override void visit(TemplateInstance ti
)
753 printf("TemplateInstance.mangle() %p %s", ti
, ti
.toChars());
755 printf(" parent = %s %s", ti
.parent
.kind(), ti
.parent
.toChars());
759 error(ti
.loc
, "%s `%s` is not defined", ti
.kind
, ti
.toPrettyChars
);
763 if (ti
.isTemplateMixin() && ti
.ident
)
764 mangleIdentifier(ti
.ident
, ti
);
766 mangleTemplateInstance(ti
);
769 void mangleTemplateInstance(TemplateInstance ti
)
771 TemplateDeclaration tempdecl
= ti
.tempdecl
.isTemplateDeclaration();
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
++)
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
794 mangleType(ta
, 0, *buf
, *backref
);
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())
808 if (auto et
= ea
.isThisExp())
814 if (auto ef
= ea
.isFuncExp())
824 if (ea
.op
== EXP
.tuple
)
826 error(ea
.loc
, "sequence is not a valid template value argument");
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
)
835 /* Use type mangling that matches what it would be for a function parameter
837 mangleType(ea
.type
, 0, *buf
, *backref
);
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
)
853 toBuffer(*buf
, d
.mangleOverride
, d
);
856 if (const id
= externallyMangledIdentifier(d
))
859 toBuffer(*buf
, id
, d
);
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());
873 assert(i
+ 1 == args
.length
); // must be last one
883 override void visit(Dsymbol s
)
887 printf("Dsymbol.mangle() '%s'", s
.toChars());
889 printf(" parent = %s %s", s
.parent
.kind(), s
.parent
.toChars());
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
903 mangleIdentifier(Id
.ImportC
, s
); // parent
904 mangleIdentifier(s
.ident
, s
);
911 mangleIdentifier(s
.ident
, s
);
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
)
932 realToMangleBuffer(*buf
, e
.value
);
935 override void visit(ComplexExp e
)
938 realToMangleBuffer(*buf
, e
.toReal());
939 buf
.writeByte('c'); // separate the two
940 realToMangleBuffer(*buf
, e
.toImaginary());
943 override void visit(NullExp e
)
948 override void visit(StringExp e
)
958 foreach (i
; 0 .. e
.len
)
959 mangleInteger(e
.getIndex(i
));
962 /* Write string in UTF-8 format
973 const slice
= e
.peekWstring();
974 for (size_t u
= 0; u
< e
.len
;)
977 if (const s
= utf_decodeWchar(slice
, u
, c
))
978 return mangleAsArray();
988 const slice
= e
.peekDstring();
991 if (!utf_isValidDchar(c
))
992 return mangleAsArray();
1000 // String of size 8 has to be hexstring cast to long[], mangle as array literal
1001 return mangleAsArray();
1005 buf
.reserve(1 + 11 + 2 * q
.length
);
1007 buf
.print(q
.length
);
1008 buf
.writeByte('_'); // nbytes <= 11
1009 buf
.writeHexString(cast(const(ubyte)[]) q
, false);
1012 override void visit(ArrayLiteralExp e
)
1014 const dim
= e
.elements ? e
.elements
.length
: 0;
1017 foreach (i
; 0 .. dim
)
1023 override void visit(AssocArrayLiteralExp e
)
1025 const dim
= e
.keys
.length
;
1028 foreach (i
; 0 .. dim
)
1030 (*e
.keys
)[i
].accept(this);
1031 (*e
.values
)[i
].accept(this);
1035 override void visit(StructLiteralExp e
)
1037 const dim
= e
.elements ? e
.elements
.length
: 0;
1040 foreach (i
; 0 .. dim
)
1042 Expression ex
= (*e
.elements
)[i
];
1046 buf
.writeByte('v'); // 'v' for void
1050 override void visit(FuncExp e
)
1060 /***************************************
1061 * Manage back reference mangling
1063 private struct Backref
1066 * Back references a non-basic type
1068 * The encoded mangling is
1069 * 'Q' <relative position of first occurrence of type>
1072 * t = the type to encode via back referencing
1075 * true if the type was found. A back reference has been encoded.
1076 * false if the type was not found. The current position is saved for later back references.
1078 bool addRefToType(ref OutBuffer buf
, Type t
)
1080 if (t
.isTypeBasic())
1084 * https://issues.dlang.org/show_bug.cgi?id=21591
1086 * Special case for unmerged TypeFunctions: use the generic merged
1087 * function type as backref cache key to avoid missed backrefs.
1089 * Merging is based on mangling, so we need to avoid an infinite
1090 * recursion by excluding the case where `t` is the root type passed to
1091 * `mangleToBuffer()`.
1095 if (t
.isFunction_Delegate_PtrToFunction())
1097 import dmd
.typesem
: merge2
;
1102 return backrefImpl(buf
, types
, t
);
1106 * Back references a single identifier
1108 * The encoded mangling is
1109 * 'Q' <relative position of first occurrence of type>
1112 * id = the identifier to encode via back referencing
1115 * true if the identifier was found. A back reference has been encoded.
1116 * false if the identifier was not found. The current position is saved for later back references.
1118 bool addRefToIdentifier(ref OutBuffer buf
, Identifier id
)
1120 return backrefImpl(buf
, idents
, id
);
1125 extern(D
) bool backrefImpl(T
)(ref OutBuffer buf
, ref AssocArray
!(T
, size_t
) aa
, T key
)
1127 auto p
= aa
.getLvalue(key
);
1130 const offset
= *p
- 1;
1131 writeBackRef(buf
, buf
.length
- offset
);
1134 *p
= buf
.length
+ 1;
1138 Type rootType
; /// avoid infinite recursion
1139 AssocArray
!(Type
, size_t
) types
; /// Type => (offset+1) in buf
1140 AssocArray
!(Identifier
, size_t
) idents
; /// Identifier => (offset+1) in buf
1143 /*********************************
1146 private void MODtoDecoBuffer(ref OutBuffer buf
, MOD mod
) @safe
1152 case MODFlags
.const_
:
1155 case MODFlags
.immutable_
:
1158 case MODFlags
.shared_
:
1161 case MODFlags
.shared_ | MODFlags
.const_
:
1162 buf
.writestring("Ox");
1165 buf
.writestring("Ng");
1167 case MODFlags
.wildconst
:
1168 buf
.writestring("Ngx");
1170 case MODFlags
.shared_ | MODFlags
.wild
:
1171 buf
.writestring("ONg");
1173 case MODFlags
.shared_ | MODFlags
.wildconst
:
1174 buf
.writestring("ONgx");
1183 * writes a back reference with the relative position encoded with base 26
1184 * using upper case letters for all digits but the last digit which uses
1185 * a lower case letter.
1186 * The decoder has to look up the referenced position to determine
1187 * whether the back reference is an identifier (starts with a digit)
1188 * or a type (starts with a letter).
1191 * buf = buffer to write to
1192 * pos = relative position to encode
1195 void writeBackRef(ref OutBuffer buf
, size_t pos
) @safe
1200 while (pos
>= mul * base
)
1204 auto dig
= cast(ubyte)(pos
/ mul);
1205 buf
.writeByte('A' + dig
);
1209 buf
.writeByte('a' + cast(ubyte)pos
);
1213 /************************************************************
1214 * Write length prefixed string to buf.
1217 extern (D
) void toBuffer(ref OutBuffer buf
, const(char)[] id
, Dsymbol s
)
1219 const len
= id
.length
;
1220 if (buf
.length
+ len
>= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
1221 error(s
.loc
, "%s `%s` excessive length %llu for symbol, possible recursive expansion?", s
.kind
, s
.toPrettyChars
, cast(ulong)(buf
.length
+ len
));
1225 buf
.writestring(id
);
1231 * There can be multiple different declarations in the same
1232 * function that have the same mangled name.
1233 * This results in localNum having a non-zero number, which
1234 * is used to add a fake parent of the form `__Sddd` to make
1235 * the mangled names unique.
1236 * https://issues.dlang.org/show_bug.cgi?id=20565
1238 * buf = buffer to write to
1239 * localNum = local symbol number
1242 void writeLocalParent(ref OutBuffer buf
, uint localNum
)
1251 buf
.printf("%u__S%u", ndigits
+ 3, localNum
);
1254 /*************************
1255 * Write real to buffer.
1257 * buf = buffer to write to
1258 * value = real to write
1261 void realToMangleBuffer(ref OutBuffer buf
, real_t value
)
1263 /* Rely on %A to get portable mangling.
1264 * Must munge result to get only identifier characters.
1266 * Possible values from %A => mangled result
1270 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
1273 if (CTFloat
.isNaN(value
))
1275 buf
.writestring("NAN"); // no -NAN bugs
1279 if (value
< CTFloat
.zero
)
1285 if (CTFloat
.isInfinity(value
))
1287 buf
.writestring("INF");
1291 char[36] buffer
= void;
1292 // 'A' format yields [-]0xh.hhhhp+-d
1293 const n
= CTFloat
.sprint(buffer
.ptr
, buffer
.length
, 'A', value
);
1294 assert(n
< buffer
.length
);
1295 foreach (const c
; buffer
[2 .. n
])
1314 /************************************************************
1315 * Try to obtain an externally mangled identifier from a declaration.
1316 * If the declaration is at global scope or mixed in at global scope,
1317 * the user might want to call it externally, so an externally mangled
1318 * name is returned. Member functions or nested functions can't be called
1319 * externally in C, so in that case null is returned. C++ does support
1320 * namespaces, so extern(C++) always gives a C++ mangled name.
1322 * See also: https://issues.dlang.org/show_bug.cgi?id=20012
1325 * d = declaration to mangle
1328 * an externally mangled name or null if the declaration cannot be called externally
1331 extern (D
) const(char)[] externallyMangledIdentifier(Declaration d
)
1333 assert(!d
.mangleOverride
, "mangle overrides should have been handled earlier");
1335 const linkage
= d
.resolvedLinkage();
1336 const par
= d
.toParent(); //toParent() skips over mixin templates
1337 if (!par || par
.isModule() || linkage
== LINK
.cpp ||
1338 (linkage
== LINK
.c
&& d
.isCsymbol() &&
1339 (d
.isFuncDeclaration() ||
1340 (d
.isVarDeclaration() && d
.isDataseg() && d
.storage_class
& STC
.extern_
))))
1342 if (linkage
!= LINK
.d
&& d
.localNum
)
1343 error(d
.loc
, "%s `%s` the same declaration cannot be in multiple scopes with non-D linkage", d
.kind
, d
.toPrettyChars
);
1345 final switch (linkage
)
1352 return d
.ident
.toString();
1355 const p
= target
.cpp
.toMangle(d
);
1356 return p
.toDString();
1359 error(d
.loc
, "%s `%s` forward declaration", d
.kind
, d
.toPrettyChars
);
1360 return d
.ident
.toString();