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
;
145 import dmd
.expression
;
149 import dmd
.identifier
;
151 import dmd
.root
.ctfloat
;
152 import dmd
.common
.outbuffer
;
154 import dmd
.root
.string
;
155 import dmd
.root
.stringtable
;
161 private immutable char[TMAX
] mangleChar
=
196 Tfunction
: 'F', // D function
203 // M // has this, or scope
204 // N // Nh:vector Ng:wild Nn:noreturn
207 // Q // Type/symbol/identifier backward reference
212 // W // Windows function
213 // X // variadic T t...)
214 // Y // variadic T t,...)
215 // Z // not variadic, end of parameters
217 // '@' shouldn't appear anywhere in the deco'd names
229 Tnoreturn
: '@', // becomes 'Nn'
234 foreach (i
, mangle
; mangleChar
)
236 if (mangle
== char.init
)
238 fprintf(stderr
, "ty = %u\n", cast(uint)i
);
244 /************************************************
245 * Append the mangling of type `t` to `buf`.
248 * modMask = mod bits currently applying to t
249 * buf = buffer to append mangling to
250 * backref = state of back references (updated)
252 void mangleType(Type t
, ubyte modMask
, ref OutBuffer buf
, ref Backref backref
)
254 void visitWithMask(Type t
, ubyte modMask
)
256 void mangleSymbol(Dsymbol s
)
258 scope Mangler v
= new Mangler(buf
, &backref
);
262 void visitType(Type t
)
264 tyToDecoBuffer(buf
, t
.ty
);
267 void visitTypeNext(TypeNext t
)
270 visitWithMask(t
.next
, t
.mod
);
273 void visitTypeVector(TypeVector t
)
275 buf
.writestring("Nh");
276 visitWithMask(t
.basetype
, t
.mod
);
279 void visitTypeSArray(TypeSArray t
)
283 buf
.print(t
.dim
.toInteger());
285 visitWithMask(t
.next
, t
.mod
);
288 void visitTypeDArray(TypeDArray t
)
292 visitWithMask(t
.next
, t
.mod
);
295 void visitTypeAArray(TypeAArray t
)
298 visitWithMask(t
.index
, 0);
299 visitWithMask(t
.next
, t
.mod
);
302 void visitTypeFunction(TypeFunction t
)
304 //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
305 //static int nest; if (++nest == 50) *(char*)0=0;
306 mangleFuncType(t
, t
, t
.mod
, t
.next
, buf
, backref
);
309 void visitTypeIdentifier(TypeIdentifier t
)
312 auto name
= t
.ident
.toString();
313 buf
.print(cast(int)name
.length
);
314 buf
.writestring(name
);
317 void visitTypeEnum(TypeEnum t
)
323 void visitTypeStruct(TypeStruct t
)
325 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
330 void visitTypeClass(TypeClass t
)
332 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
337 void visitTypeTuple(TypeTuple t
)
339 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
341 Parameter
._foreach(t
.arguments
, (idx
, param
) {
342 mangleParameter(param
, buf
, backref
);
348 void visitTypeNull(TypeNull t
)
353 void visitTypeNoreturn(TypeNoreturn t
)
355 buf
.writestring("Nn");
358 if (modMask
!= t
.mod
)
360 MODtoDecoBuffer(buf
, t
.mod
);
362 if (backref
.addRefToType(buf
, t
))
370 case Tslice
: visitTypeNext (cast(TypeNext
)t
); break;
372 case Tarray
: visitTypeDArray (t
.isTypeDArray()); break;
373 case Tsarray
: visitTypeSArray (t
.isTypeSArray()); break;
374 case Taarray
: visitTypeAArray (t
.isTypeAArray()); break;
375 case Tfunction
: visitTypeFunction (t
.isTypeFunction()); break;
376 case Tident
: visitTypeIdentifier(t
.isTypeIdentifier()); break;
377 case Tclass
: visitTypeClass (t
.isTypeClass()); break;
378 case Tstruct
: visitTypeStruct (t
.isTypeStruct()); break;
379 case Tenum
: visitTypeEnum (t
.isTypeEnum()); break;
380 case Ttuple
: visitTypeTuple (t
.isTypeTuple()); break;
381 case Tnull
: visitTypeNull (t
.isTypeNull()); break;
382 case Tvector
: visitTypeVector (t
.isTypeVector()); break;
383 case Tnoreturn
: visitTypeNoreturn (t
.isTypeNoreturn
); break;
386 break; // ignore errors
388 default: visitType(t
); break;
392 visitWithMask(t
, modMask
);
396 /*************************************************************
398 void mangleFuncType(TypeFunction t
, TypeFunction ta
, ubyte modMask
, Type tret
, ref OutBuffer buf
, ref Backref backref
)
400 //printf("mangleFuncType() %s\n", t.toChars());
403 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
404 t
.inuse
= 2; // flag error to caller
408 if (modMask
!= t
.mod
)
409 MODtoDecoBuffer(buf
, t
.mod
);
412 final switch (t
.linkage
)
436 buf
.writestring("Na");
438 buf
.writestring("Nb");
440 buf
.writestring("Nc");
442 buf
.writestring("Nd");
444 buf
.writestring("Ni");
446 // `return scope` must be in that order
447 if (ta
.isreturnscope
&& !ta
.isreturninferred
)
449 buf
.writestring("NjNl");
453 // when return ref, the order is `scope return`
454 if (ta
.isScopeQual
&& !ta
.isscopeinferred
)
455 buf
.writestring("Nl");
457 if (ta
.isreturn
&& !ta
.isreturninferred
)
458 buf
.writestring("Nj");
462 buf
.writestring("Nm");
467 buf
.writestring("Ne");
470 buf
.writestring("Nf");
476 // Write argument types
477 foreach (idx
, param
; t
.parameterList
)
478 mangleParameter(param
, buf
, backref
);
479 //if (buf.data[buf.length - 1] == '@') assert(0);
480 buf
.writeByte('Z' - t
.parameterList
.varargs
); // mark end of arg list
482 mangleType(tret
, 0, buf
, backref
);
486 /*************************************************************
488 void mangleParameter(Parameter p
, ref OutBuffer buf
, ref Backref backref
)
490 // https://dlang.org/spec/abi.html#Parameter
492 auto stc = p
.storageClass
;
494 // Inferred storage classes don't get mangled in
495 if (stc & STC
.scopeinferred
)
496 stc &= ~(STC
.scope_ | STC
.scopeinferred
);
497 if (stc & STC
.returninferred
)
498 stc &= ~(STC
.return_ | STC
.returninferred
);
500 // much like hdrgen.stcToBuffer()
502 const isout
= (stc & STC
.out_
) != 0;
503 final switch (buildScopeRef(stc))
508 case ScopeRef
.Return
:
509 case ScopeRef
.RefScope
:
512 case ScopeRef
.ReturnScope
: rrs
= "NkM"; goto L1
; // return scope
513 case ScopeRef
.ReturnRef
: rrs
= isout ?
"NkJ" : "NkK"; goto L1
; // return ref
514 case ScopeRef
.ReturnRef_Scope
: rrs
= isout ?
"MNkJ" : "MNkK"; goto L1
; // scope return ref
515 case ScopeRef
.Ref_ReturnScope
: rrs
= isout ?
"NkMJ" : "NkMK"; goto L1
; // return scope ref
517 buf
.writestring(rrs
);
518 stc &= ~(STC
.out_ | STC
.scope_ | STC
.ref_ | STC
.return_
);
522 if (stc & STC
.scope_
)
523 buf
.writeByte('M'); // scope
525 if (stc & STC
.return_
)
526 buf
.writestring("Nk"); // return
528 switch (stc & (STC
.IOR | STC
.lazy_
))
535 case STC
.in_ | STC
.ref_
:
536 buf
.writestring("IK");
550 printf("storageClass = x%llx\n", stc & (STC
.IOR | STC
.lazy_
));
554 mangleType(p
.type
, (stc & STC
.in_
) ? MODFlags
.const_
: 0, buf
, backref
);
558 private extern (C
++) final class Mangler
: Visitor
560 alias visit
= Visitor
.visit
;
562 static assert(Key
.sizeof
== size_t
.sizeof
);
567 extern (D
) this(ref OutBuffer buf
, Backref
* backref
) @trusted
570 this.backref
= backref
;
573 void mangleSymbol(Dsymbol s
)
578 void mangleIdentifier(Identifier id
, Dsymbol s
)
580 if (!backref
.addRefToIdentifier(*buf
, id
))
581 toBuffer(*buf
, id
.toString(), s
);
584 ////////////////////////////////////////////////////////////////////////////
585 void mangleDecl(Declaration sthis
)
589 mangleIdentifier(sthis
.ident
, sthis
);
590 if (FuncDeclaration fd
= sthis
.isFuncDeclaration())
592 mangleFunc(fd
, false);
596 mangleType(sthis
.type
, 0, *buf
, *backref
);
602 void mangleParent(Dsymbol s
)
604 //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
606 if (TemplateInstance ti
= s
.isTemplateInstance())
607 p
= ti
.isTemplateMixin() ? ti
.parent
: ti
.tempdecl
.parent
;
612 uint localNum
= s
.localNum
;
614 auto ti
= p
.isTemplateInstance();
615 if (ti
&& !ti
.isTemplateMixin())
617 localNum
= ti
.tempdecl
.localNum
;
618 mangleTemplateInstance(ti
);
620 else if (p
.getIdent())
622 mangleIdentifier(p
.ident
, s
);
623 if (FuncDeclaration f
= p
.isFuncDeclaration())
630 writeLocalParent(*buf
, localNum
);
634 void mangleFunc(FuncDeclaration fd
, bool inParent
)
636 //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
637 //printf("fd.type = %s\n", fd.type.toChars());
638 if (fd
.needThis() || fd
.isNested())
641 if (!fd
.type || fd
.type
.ty
== Terror
)
643 // never should have gotten here, but could be the result of
644 // failed speculative compilation
645 buf
.writestring("9__error__FZ");
647 //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
648 //assert(0); // don't mangle function until semantic3 done.
652 TypeFunction tf
= fd
.type
.isTypeFunction();
653 TypeFunction tfo
= fd
.originalType
.isTypeFunction();
654 mangleFuncType(tf
, tfo
, 0, null, *buf
, *backref
);
658 mangleType(fd
.type
, 0, *buf
, *backref
);
662 override void visit(Declaration d
)
664 //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
665 // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
666 if (const id
= externallyMangledIdentifier(d
))
671 buf
.writestring("_D");
675 const slice
= (*buf
)[];
676 assert(slice
.length
);
677 for (size_t pos
; pos
< slice
.length
; )
681 const s
= utf_decodeChar(slice
, pos
, c
);
682 assert(s
is null, s
);
683 assert(c
.isValidMangling
, "The mangled name '" ~ slice
~ "' " ~
684 "contains an invalid character: " ~ slice
[ppos
..pos
]);
689 /******************************************************************************
690 * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
691 * If and only if there is no overloads, mangle() could return
692 * exact mangled name.
695 * void foo(long) {} // _D4test3fooFlZv
696 * void foo(string) {} // _D4test3fooFAyaZv
698 * // from FuncDeclaration.mangle().
699 * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
700 * // by calling Dsymbol.mangle()
702 * // from FuncAliasDeclaration.mangle()
703 * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
704 * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
706 * If a function has no overloads, .mangleof property still returns exact mangled name.
709 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
710 * // by calling FuncDeclaration.mangleExact().
712 override void visit(FuncDeclaration fd
)
717 visit(cast(Dsymbol
)fd
);
721 override void visit(FuncAliasDeclaration fd
)
723 FuncDeclaration f
= fd
.toAliasFunc();
724 FuncAliasDeclaration fa
= f
.isFuncAliasDeclaration();
725 if (!fd
.hasOverloads
&& !fa
)
735 visit(cast(Dsymbol
)fd
);
738 override void visit(OverDeclaration od
)
742 visit(cast(Dsymbol
)od
);
745 if (FuncDeclaration fd
= od
.aliassym
.isFuncDeclaration())
753 if (TemplateDeclaration td
= od
.aliassym
.isTemplateDeclaration())
755 if (td
.overnext
is null)
761 visit(cast(Dsymbol
)od
);
764 void mangleExact(FuncDeclaration fd
)
766 assert(!fd
.isFuncAliasDeclaration());
767 if (fd
.mangleOverride
)
769 buf
.writestring(fd
.mangleOverride
);
774 buf
.writestring("_Dmain");
777 if (fd
.isWinMain() || fd
.isDllMain())
779 buf
.writestring(fd
.ident
.toString());
782 visit(cast(Declaration
)fd
);
785 override void visit(VarDeclaration vd
)
787 if (vd
.mangleOverride
)
789 buf
.writestring(vd
.mangleOverride
);
792 visit(cast(Declaration
)vd
);
795 override void visit(AggregateDeclaration ad
)
797 ClassDeclaration cd
= ad
.isClassDeclaration();
798 Dsymbol parentsave
= ad
.parent
;
801 /* These are reserved to the compiler, so keep simple
804 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)
806 // Don't mangle parent
810 visit(cast(Dsymbol
)ad
);
811 ad
.parent
= parentsave
;
814 override void visit(TemplateInstance ti
)
818 printf("TemplateInstance.mangle() %p %s", ti
, ti
.toChars());
820 printf(" parent = %s %s", ti
.parent
.kind(), ti
.parent
.toChars());
824 ti
.error("is not defined");
828 if (ti
.isTemplateMixin() && ti
.ident
)
829 mangleIdentifier(ti
.ident
, ti
);
831 mangleTemplateInstance(ti
);
834 void mangleTemplateInstance(TemplateInstance ti
)
836 TemplateDeclaration tempdecl
= ti
.tempdecl
.isTemplateDeclaration();
839 // Use "__U" for the symbols declared inside template constraint.
840 const char T
= ti
.members ?
'T' : 'U';
841 buf
.printf("__%c", T
);
842 mangleIdentifier(tempdecl
.ident
, tempdecl
);
844 auto args
= ti
.tiargs
;
845 size_t nparams
= tempdecl
.parameters
.length
- (tempdecl
.isVariadic() ?
1 : 0);
846 for (size_t i
= 0; i
< args
.length
; i
++)
850 Expression ea
= isExpression(o
);
851 Dsymbol sa
= isDsymbol(o
);
852 Tuple va
= isTuple(o
);
853 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
854 if (i
< nparams
&& (*tempdecl
.parameters
)[i
].specialization())
855 buf
.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
859 mangleType(ta
, 0, *buf
, *backref
);
863 // Don't interpret it yet, it might actually be an alias template parameter.
864 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
865 enum keepLvalue
= true;
866 ea
= ea
.optimize(WANTvalue
, keepLvalue
);
867 if (auto ev
= ea
.isVarExp())
873 if (auto et
= ea
.isThisExp())
879 if (auto ef
= ea
.isFuncExp())
889 if (ea
.op
== EXP
.tuple
)
891 ea
.error("sequence is not a valid template value argument");
894 // Now that we know it is not an alias, we MUST obtain a value
895 uint olderr
= global
.errors
;
896 ea
= ea
.ctfeInterpret();
897 if (ea
.op
== EXP
.error || olderr
!= global
.errors
)
900 /* Use type mangling that matches what it would be for a function parameter
902 mangleType(ea
.type
, 0, *buf
, *backref
);
909 if (sa
.isDeclaration() && !sa
.isOverDeclaration())
911 Declaration d
= sa
.isDeclaration();
913 if (auto fad
= d
.isFuncAliasDeclaration())
914 d
= fad
.toAliasFunc();
915 if (d
.mangleOverride
)
918 toBuffer(*buf
, d
.mangleOverride
, d
);
921 if (const id
= externallyMangledIdentifier(d
))
924 toBuffer(*buf
, id
, d
);
927 if (!d
.type ||
!d
.type
.deco
)
929 ti
.error("forward reference of %s `%s`", d
.kind(), d
.toChars());
938 assert(i
+ 1 == args
.length
); // must be last one
948 override void visit(Dsymbol s
)
952 printf("Dsymbol.mangle() '%s'", s
.toChars());
954 printf(" parent = %s %s", s
.parent
.kind(), s
.parent
.toChars());
957 if (s
.parent
&& s
.ident
)
959 if (auto m
= s
.parent
.isModule())
961 if (m
.filetype
== FileType
.c
)
963 /* C types at global level get mangled into the __C global namespace
964 * to get the same mangling regardless of which module it
965 * is declared in. This works because types are the same if the mangling
968 mangleIdentifier(Id
.ImportC
, s
); // parent
969 mangleIdentifier(s
.ident
, s
);
976 mangleIdentifier(s
.ident
, s
);
978 toBuffer(*buf
, s
.toString(), s
);
979 //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
982 ////////////////////////////////////////////////////////////////////////////
983 override void visit(Expression e
)
985 e
.error("expression `%s` is not a valid template value argument", e
.toChars());
988 override void visit(IntegerExp e
)
990 const v
= e
.toInteger();
991 if (cast(sinteger_t
)v
< 0)
1003 override void visit(RealExp e
)
1006 realToMangleBuffer(*buf
, e
.value
);
1009 override void visit(ComplexExp e
)
1012 realToMangleBuffer(*buf
, e
.toReal());
1013 buf
.writeByte('c'); // separate the two
1014 realToMangleBuffer(*buf
, e
.toImaginary());
1017 override void visit(NullExp e
)
1022 override void visit(StringExp e
)
1027 /* Write string in UTF-8 format
1038 const slice
= e
.peekWstring();
1039 for (size_t u
= 0; u
< e
.len
;)
1042 if (const s
= utf_decodeWchar(slice
, u
, c
))
1043 e
.error("%.*s", cast(int)s
.length
, s
.ptr
);
1053 const slice
= e
.peekDstring();
1056 if (!utf_isValidDchar(c
))
1057 e
.error("invalid UCS-32 char \\U%08x", c
);
1068 buf
.reserve(1 + 11 + 2 * q
.length
);
1070 buf
.print(q
.length
);
1071 buf
.writeByte('_'); // nbytes <= 11
1072 auto slice
= buf
.allocate(2 * q
.length
);
1075 char hi
= (c
>> 4) & 0xF;
1076 slice
[i
* 2] = cast(char)(hi
< 10 ? hi
+ '0' : hi
- 10 + 'a');
1078 slice
[i
* 2 + 1] = cast(char)(lo
< 10 ? lo
+ '0' : lo
- 10 + 'a');
1082 override void visit(ArrayLiteralExp e
)
1084 const dim
= e
.elements ? e
.elements
.length
: 0;
1087 foreach (i
; 0 .. dim
)
1093 override void visit(AssocArrayLiteralExp e
)
1095 const dim
= e
.keys
.length
;
1098 foreach (i
; 0 .. dim
)
1100 (*e
.keys
)[i
].accept(this);
1101 (*e
.values
)[i
].accept(this);
1105 override void visit(StructLiteralExp e
)
1107 const dim
= e
.elements ? e
.elements
.length
: 0;
1110 foreach (i
; 0 .. dim
)
1112 Expression ex
= (*e
.elements
)[i
];
1116 buf
.writeByte('v'); // 'v' for void
1120 override void visit(FuncExp e
)
1130 /***************************************
1131 * Manage back reference mangling
1133 private struct Backref
1136 * Back references a non-basic type
1138 * The encoded mangling is
1139 * 'Q' <relative position of first occurrence of type>
1142 * t = the type to encode via back referencing
1145 * true if the type was found. A back reference has been encoded.
1146 * false if the type was not found. The current position is saved for later back references.
1148 bool addRefToType(ref OutBuffer buf
, Type t
)
1150 if (t
.isTypeBasic())
1154 * https://issues.dlang.org/show_bug.cgi?id=21591
1156 * Special case for unmerged TypeFunctions: use the generic merged
1157 * function type as backref cache key to avoid missed backrefs.
1159 * Merging is based on mangling, so we need to avoid an infinite
1160 * recursion by excluding the case where `t` is the root type passed to
1161 * `mangleToBuffer()`.
1165 if (t
.isFunction_Delegate_PtrToFunction())
1171 return backrefImpl(buf
, types
, t
);
1175 * Back references a single identifier
1177 * The encoded mangling is
1178 * 'Q' <relative position of first occurrence of type>
1181 * id = the identifier to encode via back referencing
1184 * true if the identifier was found. A back reference has been encoded.
1185 * false if the identifier was not found. The current position is saved for later back references.
1187 bool addRefToIdentifier(ref OutBuffer buf
, Identifier id
)
1189 return backrefImpl(buf
, idents
, id
);
1194 extern(D
) bool backrefImpl(T
)(ref OutBuffer buf
, ref AssocArray
!(T
, size_t
) aa
, T key
)
1196 auto p
= aa
.getLvalue(key
);
1199 const offset
= *p
- 1;
1200 writeBackRef(buf
, buf
.length
- offset
);
1203 *p
= buf
.length
+ 1;
1207 Type rootType
; /// avoid infinite recursion
1208 AssocArray
!(Type
, size_t
) types
; /// Type => (offset+1) in buf
1209 AssocArray
!(Identifier
, size_t
) idents
; /// Identifier => (offset+1) in buf
1213 /***********************
1214 * Mangle basic type ty to buf.
1217 private void tyToDecoBuffer(ref OutBuffer buf
, int ty
) @safe
1219 const c
= mangleChar
[ty
];
1222 buf
.writeByte(ty
== Tint128 ?
'i' : 'k');
1225 /*********************************
1228 private void MODtoDecoBuffer(ref OutBuffer buf
, MOD mod
) @safe
1234 case MODFlags
.const_
:
1237 case MODFlags
.immutable_
:
1240 case MODFlags
.shared_
:
1243 case MODFlags
.shared_ | MODFlags
.const_
:
1244 buf
.writestring("Ox");
1247 buf
.writestring("Ng");
1249 case MODFlags
.wildconst
:
1250 buf
.writestring("Ngx");
1252 case MODFlags
.shared_ | MODFlags
.wild
:
1253 buf
.writestring("ONg");
1255 case MODFlags
.shared_ | MODFlags
.wildconst
:
1256 buf
.writestring("ONgx");
1265 * writes a back reference with the relative position encoded with base 26
1266 * using upper case letters for all digits but the last digit which uses
1267 * a lower case letter.
1268 * The decoder has to look up the referenced position to determine
1269 * whether the back reference is an identifier (starts with a digit)
1270 * or a type (starts with a letter).
1273 * buf = buffer to write to
1274 * pos = relative position to encode
1277 void writeBackRef(ref OutBuffer buf
, size_t pos
) @safe
1282 while (pos
>= mul * base
)
1286 auto dig
= cast(ubyte)(pos
/ mul);
1287 buf
.writeByte('A' + dig
);
1291 buf
.writeByte('a' + cast(ubyte)pos
);
1295 /************************************************************
1296 * Write length prefixed string to buf.
1299 extern (D
) void toBuffer(ref OutBuffer buf
, const(char)[] id
, Dsymbol s
)
1301 const len
= id
.length
;
1302 if (buf
.length
+ len
>= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
1303 s
.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf
.length
+ len
));
1307 buf
.writestring(id
);
1313 * There can be multiple different declarations in the same
1314 * function that have the same mangled name.
1315 * This results in localNum having a non-zero number, which
1316 * is used to add a fake parent of the form `__Sddd` to make
1317 * the mangled names unique.
1318 * https://issues.dlang.org/show_bug.cgi?id=20565
1320 * buf = buffer to write to
1321 * localNum = local symbol number
1324 void writeLocalParent(ref OutBuffer buf
, uint localNum
)
1333 buf
.printf("%u__S%u", ndigits
+ 3, localNum
);
1336 /*************************
1337 * Write real to buffer.
1339 * buf = buffer to write to
1340 * value = real to write
1343 void realToMangleBuffer(ref OutBuffer buf
, real_t value
)
1345 /* Rely on %A to get portable mangling.
1346 * Must munge result to get only identifier characters.
1348 * Possible values from %A => mangled result
1352 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
1355 if (CTFloat
.isNaN(value
))
1357 buf
.writestring("NAN"); // no -NAN bugs
1361 if (value
< CTFloat
.zero
)
1367 if (CTFloat
.isInfinity(value
))
1369 buf
.writestring("INF");
1373 char[36] buffer
= void;
1374 // 'A' format yields [-]0xh.hhhhp+-d
1375 const n
= CTFloat
.sprint(buffer
.ptr
, buffer
.length
, 'A', value
);
1376 assert(n
< buffer
.length
);
1377 foreach (const c
; buffer
[2 .. n
])
1396 /************************************************************
1397 * Try to obtain an externally mangled identifier from a declaration.
1398 * If the declaration is at global scope or mixed in at global scope,
1399 * the user might want to call it externally, so an externally mangled
1400 * name is returned. Member functions or nested functions can't be called
1401 * externally in C, so in that case null is returned. C++ does support
1402 * namespaces, so extern(C++) always gives a C++ mangled name.
1404 * See also: https://issues.dlang.org/show_bug.cgi?id=20012
1407 * d = declaration to mangle
1410 * an externally mangled name or null if the declaration cannot be called externally
1413 extern (D
) const(char)[] externallyMangledIdentifier(Declaration d
)
1415 assert(!d
.mangleOverride
, "mangle overrides should have been handled earlier");
1417 const linkage
= d
.resolvedLinkage();
1418 const par
= d
.toParent(); //toParent() skips over mixin templates
1419 if (!par || par
.isModule() || linkage
== LINK
.cpp ||
1420 (linkage
== LINK
.c
&& d
.isCsymbol() &&
1421 (d
.isFuncDeclaration() ||
1422 (d
.isVarDeclaration() && d
.isDataseg() && d
.storage_class
& STC
.extern_
))))
1424 if (linkage
!= LINK
.d
&& d
.localNum
)
1425 d
.error("the same declaration cannot be in multiple scopes with non-D linkage");
1427 final switch (linkage
)
1434 return d
.ident
.toString();
1437 const p
= target
.cpp
.toMangle(d
);
1438 return p
.toDString();
1441 d
.error("forward declaration");
1442 return d
.ident
.toString();