]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/dmangle.d
d: Import dmd b8384668f, druntime e6caaab9, phobos 5ab9ad256 (v2.098.0-beta.1)
[thirdparty/gcc.git] / gcc / d / dmd / dmangle.d
1 /**
2 * Does name mangling for `extern(D)` symbols.
3 *
4 * Specification: $(LINK2 https://dlang.org/spec/abi.html#name_mangling, Name Mangling)
5 *
6 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
7 * Authors: Walter Bright, http://www.digitalmars.com
8 * License: $(LINK2 http://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/
13 */
14
15 module dmd.dmangle;
16
17 import dmd.astenums;
18
19 /******************************************************************************
20 * Returns exact mangled name of function.
21 */
22 extern (C++) const(char)* mangleExact(FuncDeclaration fd)
23 {
24 if (!fd.mangleString)
25 {
26 OutBuffer buf;
27 scope Mangler v = new Mangler(&buf);
28 v.mangleExact(fd);
29 fd.mangleString = buf.extractChars();
30 }
31 return fd.mangleString;
32 }
33
34 extern (C++) void mangleToBuffer(Type t, OutBuffer* buf)
35 {
36 if (t.deco)
37 buf.writestring(t.deco);
38 else
39 {
40 scope Mangler v = new Mangler(buf, t);
41 v.visitWithMask(t, 0);
42 }
43 }
44
45 extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf)
46 {
47 scope Mangler v = new Mangler(buf);
48 e.accept(v);
49 }
50
51 extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf)
52 {
53 scope Mangler v = new Mangler(buf);
54 s.accept(v);
55 }
56
57 extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf)
58 {
59 scope Mangler v = new Mangler(buf);
60 v.mangleTemplateInstance(ti);
61 }
62
63 /// Returns: `true` if the given character is a valid mangled character
64 package bool isValidMangling(dchar c) nothrow
65 {
66 return
67 c >= 'A' && c <= 'Z' ||
68 c >= 'a' && c <= 'z' ||
69 c >= '0' && c <= '9' ||
70 c != 0 && strchr("$%().:?@[]_", c) ||
71 isUniAlpha(c);
72 }
73
74 // valid mangled characters
75 unittest
76 {
77 assert('a'.isValidMangling);
78 assert('B'.isValidMangling);
79 assert('2'.isValidMangling);
80 assert('@'.isValidMangling);
81 assert('_'.isValidMangling);
82 }
83
84 // invalid mangled characters
85 unittest
86 {
87 assert(!'-'.isValidMangling);
88 assert(!0.isValidMangling);
89 assert(!'/'.isValidMangling);
90 assert(!'\\'.isValidMangling);
91 }
92
93 /**********************************************
94 * Convert a string representing a type (the deco) and
95 * return its equivalent Type.
96 * Params:
97 * deco = string containing the deco
98 * Returns:
99 * null for failed to convert
100 * Type for succeeded
101 */
102
103 public Type decoToType(const(char)[] deco)
104 {
105 //printf("decoToType(): %.*s\n", cast(int)deco.length, deco.ptr);
106 if (auto sv = Type.stringtable.lookup(deco))
107 {
108 if (sv.value)
109 {
110 Type t = cast(Type)sv.value;
111 assert(t.deco);
112 return t;
113 }
114 }
115 return null;
116 }
117
118
119 /***************************************** private ***************************************/
120
121 private:
122
123
124 import core.stdc.ctype;
125 import core.stdc.stdio;
126 import core.stdc.string;
127
128 import dmd.aggregate;
129 import dmd.arraytypes;
130 import dmd.dclass;
131 import dmd.declaration;
132 import dmd.dmodule;
133 import dmd.dsymbol;
134 import dmd.dtemplate;
135 import dmd.expression;
136 import dmd.func;
137 import dmd.globals;
138 import dmd.id;
139 import dmd.identifier;
140 import dmd.mtype;
141 import dmd.root.ctfloat;
142 import dmd.root.outbuffer;
143 import dmd.root.aav;
144 import dmd.root.string;
145 import dmd.root.stringtable;
146 import dmd.target;
147 import dmd.tokens;
148 import dmd.utf;
149 import dmd.visitor;
150
151 private immutable char[TMAX] mangleChar =
152 [
153 Tchar : 'a',
154 Tbool : 'b',
155 Tcomplex80 : 'c',
156 Tfloat64 : 'd',
157 Tfloat80 : 'e',
158 Tfloat32 : 'f',
159 Tint8 : 'g',
160 Tuns8 : 'h',
161 Tint32 : 'i',
162 Timaginary80 : 'j',
163 Tuns32 : 'k',
164 Tint64 : 'l',
165 Tuns64 : 'm',
166 Tnull : 'n',
167 Timaginary32 : 'o',
168 Timaginary64 : 'p',
169 Tcomplex32 : 'q',
170 Tcomplex64 : 'r',
171 Tint16 : 's',
172 Tuns16 : 't',
173 Twchar : 'u',
174 Tvoid : 'v',
175 Tdchar : 'w',
176 // x // const
177 // y // immutable
178 Tint128 : 'z', // zi
179 Tuns128 : 'z', // zk
180
181 Tarray : 'A',
182 Ttuple : 'B',
183 Tclass : 'C',
184 Tdelegate : 'D',
185 Tenum : 'E',
186 Tfunction : 'F', // D function
187 Tsarray : 'G',
188 Taarray : 'H',
189 // I // in
190 // J // out
191 // K // ref
192 // L // lazy
193 // M // has this, or scope
194 // N // Nh:vector Ng:wild Nn:noreturn
195 // O // shared
196 Tpointer : 'P',
197 // Q // Type/symbol/identifier backward reference
198 Treference : 'R',
199 Tstruct : 'S',
200 // T // Ttypedef
201 // U // C function
202 // W // Windows function
203 // X // variadic T t...)
204 // Y // variadic T t,...)
205 // Z // not variadic, end of parameters
206
207 // '@' shouldn't appear anywhere in the deco'd names
208 Tnone : '@',
209 Tident : '@',
210 Tinstance : '@',
211 Terror : '@',
212 Ttypeof : '@',
213 Tslice : '@',
214 Treturn : '@',
215 Tvector : '@',
216 Ttraits : '@',
217 Tmixin : '@',
218 Ttag : '@',
219 Tnoreturn : '@', // becomes 'Nn'
220 ];
221
222 unittest
223 {
224 foreach (i, mangle; mangleChar)
225 {
226 if (mangle == char.init)
227 {
228 fprintf(stderr, "ty = %u\n", cast(uint)i);
229 assert(0);
230 }
231 }
232 }
233
234 /***********************
235 * Mangle basic type ty to buf.
236 */
237
238 private void tyToDecoBuffer(OutBuffer* buf, int ty)
239 {
240 const c = mangleChar[ty];
241 buf.writeByte(c);
242 if (c == 'z')
243 buf.writeByte(ty == Tint128 ? 'i' : 'k');
244 }
245
246 /*********************************
247 * Mangling for mod.
248 */
249 private void MODtoDecoBuffer(OutBuffer* buf, MOD mod)
250 {
251 switch (mod)
252 {
253 case 0:
254 break;
255 case MODFlags.const_:
256 buf.writeByte('x');
257 break;
258 case MODFlags.immutable_:
259 buf.writeByte('y');
260 break;
261 case MODFlags.shared_:
262 buf.writeByte('O');
263 break;
264 case MODFlags.shared_ | MODFlags.const_:
265 buf.writestring("Ox");
266 break;
267 case MODFlags.wild:
268 buf.writestring("Ng");
269 break;
270 case MODFlags.wildconst:
271 buf.writestring("Ngx");
272 break;
273 case MODFlags.shared_ | MODFlags.wild:
274 buf.writestring("ONg");
275 break;
276 case MODFlags.shared_ | MODFlags.wildconst:
277 buf.writestring("ONgx");
278 break;
279 default:
280 assert(0);
281 }
282 }
283
284 private extern (C++) final class Mangler : Visitor
285 {
286 alias visit = Visitor.visit;
287 public:
288 static assert(Key.sizeof == size_t.sizeof);
289 AssocArray!(Type, size_t) types; // Type => (offset+1) in buf
290 AssocArray!(Identifier, size_t) idents; // Identifier => (offset+1) in buf
291 OutBuffer* buf;
292 Type rootType;
293
294 extern (D) this(OutBuffer* buf, Type rootType = null)
295 {
296 this.buf = buf;
297 this.rootType = rootType;
298 }
299
300 /**
301 * writes a back reference with the relative position encoded with base 26
302 * using upper case letters for all digits but the last digit which uses
303 * a lower case letter.
304 * The decoder has to look up the referenced position to determine
305 * whether the back reference is an identifier (starts with a digit)
306 * or a type (starts with a letter).
307 *
308 * Params:
309 * pos = relative position to encode
310 */
311 void writeBackRef(size_t pos)
312 {
313 buf.writeByte('Q');
314 enum base = 26;
315 size_t mul = 1;
316 while (pos >= mul * base)
317 mul *= base;
318 while (mul >= base)
319 {
320 auto dig = cast(ubyte)(pos / mul);
321 buf.writeByte('A' + dig);
322 pos -= dig * mul;
323 mul /= base;
324 }
325 buf.writeByte('a' + cast(ubyte)pos);
326 }
327
328 /**
329 * Back references a non-basic type
330 *
331 * The encoded mangling is
332 * 'Q' <relative position of first occurrence of type>
333 *
334 * Params:
335 * t = the type to encode via back referencing
336 *
337 * Returns:
338 * true if the type was found. A back reference has been encoded.
339 * false if the type was not found. The current position is saved for later back references.
340 */
341 bool backrefType(Type t)
342 {
343 if (t.isTypeBasic())
344 return false;
345
346 /**
347 * https://issues.dlang.org/show_bug.cgi?id=21591
348 *
349 * Special case for unmerged TypeFunctions: use the generic merged
350 * function type as backref cache key to avoid missed backrefs.
351 *
352 * Merging is based on mangling, so we need to avoid an infinite
353 * recursion by excluding the case where `t` is the root type passed to
354 * `mangleToBuffer()`.
355 */
356 if (t != rootType)
357 {
358 if (t.isFunction_Delegate_PtrToFunction())
359 {
360 t = t.merge2();
361 }
362 }
363
364 return backrefImpl(types, t);
365 }
366
367 /**
368 * Back references a single identifier
369 *
370 * The encoded mangling is
371 * 'Q' <relative position of first occurrence of type>
372 *
373 * Params:
374 * id = the identifier to encode via back referencing
375 *
376 * Returns:
377 * true if the identifier was found. A back reference has been encoded.
378 * false if the identifier was not found. The current position is saved for later back references.
379 */
380 bool backrefIdentifier(Identifier id)
381 {
382 return backrefImpl(idents, id);
383 }
384
385 private extern(D) bool backrefImpl(T)(ref AssocArray!(T, size_t) aa, T key)
386 {
387 auto p = aa.getLvalue(key);
388 if (*p)
389 {
390 const offset = *p - 1;
391 writeBackRef(buf.length - offset);
392 return true;
393 }
394 *p = buf.length + 1;
395 return false;
396 }
397
398 void mangleSymbol(Dsymbol s)
399 {
400 s.accept(this);
401 }
402
403 void mangleType(Type t)
404 {
405 if (!backrefType(t))
406 t.accept(this);
407 }
408
409 void mangleIdentifier(Identifier id, Dsymbol s)
410 {
411 if (!backrefIdentifier(id))
412 toBuffer(id.toString(), s);
413 }
414
415 ////////////////////////////////////////////////////////////////////////////
416 /**************************************************
417 * Type mangling
418 */
419 void visitWithMask(Type t, ubyte modMask)
420 {
421 if (modMask != t.mod)
422 {
423 MODtoDecoBuffer(buf, t.mod);
424 }
425 mangleType(t);
426 }
427
428 override void visit(Type t)
429 {
430 tyToDecoBuffer(buf, t.ty);
431 }
432
433 override void visit(TypeNext t)
434 {
435 visit(cast(Type)t);
436 visitWithMask(t.next, t.mod);
437 }
438
439 override void visit(TypeVector t)
440 {
441 buf.writestring("Nh");
442 visitWithMask(t.basetype, t.mod);
443 }
444
445 override void visit(TypeSArray t)
446 {
447 visit(cast(Type)t);
448 if (t.dim)
449 buf.print(t.dim.toInteger());
450 if (t.next)
451 visitWithMask(t.next, t.mod);
452 }
453
454 override void visit(TypeDArray t)
455 {
456 visit(cast(Type)t);
457 if (t.next)
458 visitWithMask(t.next, t.mod);
459 }
460
461 override void visit(TypeAArray t)
462 {
463 visit(cast(Type)t);
464 visitWithMask(t.index, 0);
465 visitWithMask(t.next, t.mod);
466 }
467
468 override void visit(TypeFunction t)
469 {
470 //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
471 //static int nest; if (++nest == 50) *(char*)0=0;
472 mangleFuncType(t, t, t.mod, t.next);
473 }
474
475 void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret)
476 {
477 //printf("mangleFuncType() %s\n", t.toChars());
478 if (t.inuse && tret)
479 {
480 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
481 t.inuse = 2; // flag error to caller
482 return;
483 }
484 t.inuse++;
485 if (modMask != t.mod)
486 MODtoDecoBuffer(buf, t.mod);
487
488 char mc;
489 final switch (t.linkage)
490 {
491 case LINK.default_:
492 case LINK.system:
493 case LINK.d:
494 mc = 'F';
495 break;
496 case LINK.c:
497 mc = 'U';
498 break;
499 case LINK.windows:
500 mc = 'W';
501 break;
502 case LINK.cpp:
503 mc = 'R';
504 break;
505 case LINK.objc:
506 mc = 'Y';
507 break;
508 }
509 buf.writeByte(mc);
510
511 if (ta.purity)
512 buf.writestring("Na");
513 if (ta.isnothrow)
514 buf.writestring("Nb");
515 if (ta.isref)
516 buf.writestring("Nc");
517 if (ta.isproperty)
518 buf.writestring("Nd");
519 if (ta.isnogc)
520 buf.writestring("Ni");
521
522 if (ta.isreturn && !ta.isreturninferred)
523 buf.writestring("Nj");
524 else if (ta.isScopeQual && !ta.isscopeinferred)
525 buf.writestring("Nl");
526
527 if (ta.islive)
528 buf.writestring("Nm");
529
530 switch (ta.trust)
531 {
532 case TRUST.trusted:
533 buf.writestring("Ne");
534 break;
535 case TRUST.safe:
536 buf.writestring("Nf");
537 break;
538 default:
539 break;
540 }
541
542 // Write argument types
543 foreach (idx, param; t.parameterList)
544 param.accept(this);
545 //if (buf.data[buf.length - 1] == '@') assert(0);
546 buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
547 if (tret !is null)
548 visitWithMask(tret, 0);
549 t.inuse--;
550 }
551
552 override void visit(TypeIdentifier t)
553 {
554 visit(cast(Type)t);
555 auto name = t.ident.toString();
556 buf.print(cast(int)name.length);
557 buf.writestring(name);
558 }
559
560 override void visit(TypeEnum t)
561 {
562 visit(cast(Type)t);
563 mangleSymbol(t.sym);
564 }
565
566 override void visit(TypeStruct t)
567 {
568 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
569 visit(cast(Type)t);
570 mangleSymbol(t.sym);
571 }
572
573 override void visit(TypeClass t)
574 {
575 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
576 visit(cast(Type)t);
577 mangleSymbol(t.sym);
578 }
579
580 override void visit(TypeTuple t)
581 {
582 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
583 visit(cast(Type)t);
584 Parameter._foreach(t.arguments, (idx, param) {
585 param.accept(this);
586 return 0;
587 });
588 buf.writeByte('Z');
589 }
590
591 override void visit(TypeNull t)
592 {
593 visit(cast(Type)t);
594 }
595
596 override void visit(TypeNoreturn t)
597 {
598 buf.writestring("Nn");
599 }
600
601 ////////////////////////////////////////////////////////////////////////////
602 void mangleDecl(Declaration sthis)
603 {
604 mangleParent(sthis);
605 assert(sthis.ident);
606 mangleIdentifier(sthis.ident, sthis);
607 if (FuncDeclaration fd = sthis.isFuncDeclaration())
608 {
609 mangleFunc(fd, false);
610 }
611 else if (sthis.type)
612 {
613 visitWithMask(sthis.type, 0);
614 }
615 else
616 assert(0);
617 }
618
619 void mangleParent(Dsymbol s)
620 {
621 //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
622 Dsymbol p;
623 if (TemplateInstance ti = s.isTemplateInstance())
624 p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
625 else
626 p = s.parent;
627 if (p)
628 {
629 uint localNum = s.localNum;
630 mangleParent(p);
631 auto ti = p.isTemplateInstance();
632 if (ti && !ti.isTemplateMixin())
633 {
634 localNum = ti.tempdecl.localNum;
635 mangleTemplateInstance(ti);
636 }
637 else if (p.getIdent())
638 {
639 mangleIdentifier(p.ident, s);
640 if (FuncDeclaration f = p.isFuncDeclaration())
641 mangleFunc(f, true);
642 }
643 else
644 buf.writeByte('0');
645
646 /* There can be multiple different declarations in the same
647 * function that have the same mangled name.
648 * This results in localNum having a non-zero number, which
649 * is used to add a fake parent of the form `__Sddd` to make
650 * the mangled names unique.
651 * https://issues.dlang.org/show_bug.cgi?id=20565
652 */
653 if (localNum)
654 {
655 uint ndigits = 1;
656 auto n = localNum;
657 while (n >= 10)
658 {
659 n /= 10;
660 ++ndigits;
661 }
662 buf.printf("%u__S%u", ndigits + 3, localNum);
663 }
664 }
665 }
666
667 void mangleFunc(FuncDeclaration fd, bool inParent)
668 {
669 //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
670 //printf("fd.type = %s\n", fd.type.toChars());
671 if (fd.needThis() || fd.isNested())
672 buf.writeByte('M');
673
674 if (!fd.type || fd.type.ty == Terror)
675 {
676 // never should have gotten here, but could be the result of
677 // failed speculative compilation
678 buf.writestring("9__error__FZ");
679
680 //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
681 //assert(0); // don't mangle function until semantic3 done.
682 }
683 else if (inParent)
684 {
685 TypeFunction tf = fd.type.isTypeFunction();
686 TypeFunction tfo = fd.originalType.isTypeFunction();
687 mangleFuncType(tf, tfo, 0, null);
688 }
689 else
690 {
691 visitWithMask(fd.type, 0);
692 }
693 }
694
695 /************************************************************
696 * Write length prefixed string to buf.
697 */
698 extern (D) void toBuffer(const(char)[] id, Dsymbol s)
699 {
700 const len = id.length;
701 if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
702 s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.length + len));
703 else
704 {
705 buf.print(len);
706 buf.writestring(id);
707 }
708 }
709
710 /************************************************************
711 * Try to obtain an externally mangled identifier from a declaration.
712 * If the declaration is at global scope or mixed in at global scope,
713 * the user might want to call it externally, so an externally mangled
714 * name is returned. Member functions or nested functions can't be called
715 * externally in C, so in that case null is returned. C++ does support
716 * namespaces, so extern(C++) always gives a C++ mangled name.
717 *
718 * See also: https://issues.dlang.org/show_bug.cgi?id=20012
719 *
720 * Params:
721 * d = declaration to mangle
722 *
723 * Returns:
724 * an externally mangled name or null if the declaration cannot be called externally
725 */
726 extern (D) static const(char)[] externallyMangledIdentifier(Declaration d)
727 {
728 const par = d.toParent(); //toParent() skips over mixin templates
729 if (!par || par.isModule() || d.linkage == LINK.cpp)
730 {
731 if (d.linkage != LINK.d && d.localNum)
732 d.error("the same declaration cannot be in multiple scopes with non-D linkage");
733 final switch (d.linkage)
734 {
735 case LINK.d:
736 break;
737 case LINK.c:
738 case LINK.windows:
739 case LINK.objc:
740 return d.ident.toString();
741 case LINK.cpp:
742 {
743 const p = target.cpp.toMangle(d);
744 return p.toDString();
745 }
746 case LINK.default_:
747 case LINK.system:
748 d.error("forward declaration");
749 return d.ident.toString();
750 }
751 }
752 return null;
753 }
754
755 override void visit(Declaration d)
756 {
757 //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
758 // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
759 if (const id = externallyMangledIdentifier(d))
760 {
761 buf.writestring(id);
762 return;
763 }
764 buf.writestring("_D");
765 mangleDecl(d);
766 debug
767 {
768 const slice = (*buf)[];
769 assert(slice.length);
770 for (size_t pos; pos < slice.length; )
771 {
772 dchar c;
773 auto ppos = pos;
774 const s = utf_decodeChar(slice, pos, c);
775 assert(s is null, s);
776 assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~
777 "contains an invalid character: " ~ slice[ppos..pos]);
778 }
779 }
780 }
781
782 /******************************************************************************
783 * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
784 * If and only if there is no overloads, mangle() could return
785 * exact mangled name.
786 *
787 * module test;
788 * void foo(long) {} // _D4test3fooFlZv
789 * void foo(string) {} // _D4test3fooFAyaZv
790 *
791 * // from FuncDeclaration.mangle().
792 * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
793 * // by calling Dsymbol.mangle()
794 *
795 * // from FuncAliasDeclaration.mangle()
796 * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
797 * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
798 *
799 * If a function has no overloads, .mangleof property still returns exact mangled name.
800 *
801 * void bar() {}
802 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
803 * // by calling FuncDeclaration.mangleExact().
804 */
805 override void visit(FuncDeclaration fd)
806 {
807 if (fd.isUnique())
808 mangleExact(fd);
809 else
810 visit(cast(Dsymbol)fd);
811 }
812
813 // ditto
814 override void visit(FuncAliasDeclaration fd)
815 {
816 FuncDeclaration f = fd.toAliasFunc();
817 FuncAliasDeclaration fa = f.isFuncAliasDeclaration();
818 if (!fd.hasOverloads && !fa)
819 {
820 mangleExact(f);
821 return;
822 }
823 if (fa)
824 {
825 mangleSymbol(fa);
826 return;
827 }
828 visit(cast(Dsymbol)fd);
829 }
830
831 override void visit(OverDeclaration od)
832 {
833 if (od.overnext)
834 {
835 visit(cast(Dsymbol)od);
836 return;
837 }
838 if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
839 {
840 if (fd.isUnique())
841 {
842 mangleExact(fd);
843 return;
844 }
845 }
846 if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
847 {
848 if (td.overnext is null)
849 {
850 mangleSymbol(td);
851 return;
852 }
853 }
854 visit(cast(Dsymbol)od);
855 }
856
857 void mangleExact(FuncDeclaration fd)
858 {
859 assert(!fd.isFuncAliasDeclaration());
860 if (fd.mangleOverride)
861 {
862 buf.writestring(fd.mangleOverride);
863 return;
864 }
865 if (fd.isMain())
866 {
867 buf.writestring("_Dmain");
868 return;
869 }
870 if (fd.isWinMain() || fd.isDllMain())
871 {
872 buf.writestring(fd.ident.toString());
873 return;
874 }
875 visit(cast(Declaration)fd);
876 }
877
878 override void visit(VarDeclaration vd)
879 {
880 if (vd.mangleOverride)
881 {
882 buf.writestring(vd.mangleOverride);
883 return;
884 }
885 visit(cast(Declaration)vd);
886 }
887
888 override void visit(AggregateDeclaration ad)
889 {
890 ClassDeclaration cd = ad.isClassDeclaration();
891 Dsymbol parentsave = ad.parent;
892 if (cd)
893 {
894 /* These are reserved to the compiler, so keep simple
895 * names for them.
896 */
897 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)
898 {
899 // Don't mangle parent
900 ad.parent = null;
901 }
902 }
903 visit(cast(Dsymbol)ad);
904 ad.parent = parentsave;
905 }
906
907 override void visit(TemplateInstance ti)
908 {
909 version (none)
910 {
911 printf("TemplateInstance.mangle() %p %s", ti, ti.toChars());
912 if (ti.parent)
913 printf(" parent = %s %s", ti.parent.kind(), ti.parent.toChars());
914 printf("\n");
915 }
916 if (!ti.tempdecl)
917 ti.error("is not defined");
918 else
919 mangleParent(ti);
920
921 if (ti.isTemplateMixin() && ti.ident)
922 mangleIdentifier(ti.ident, ti);
923 else
924 mangleTemplateInstance(ti);
925 }
926
927 void mangleTemplateInstance(TemplateInstance ti)
928 {
929 TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration();
930 assert(tempdecl);
931
932 // Use "__U" for the symbols declared inside template constraint.
933 const char T = ti.members ? 'T' : 'U';
934 buf.printf("__%c", T);
935 mangleIdentifier(tempdecl.ident, tempdecl);
936
937 auto args = ti.tiargs;
938 size_t nparams = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0);
939 for (size_t i = 0; i < args.dim; i++)
940 {
941 auto o = (*args)[i];
942 Type ta = isType(o);
943 Expression ea = isExpression(o);
944 Dsymbol sa = isDsymbol(o);
945 Tuple va = isTuple(o);
946 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
947 if (i < nparams && (*tempdecl.parameters)[i].specialization())
948 buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
949 if (ta)
950 {
951 buf.writeByte('T');
952 visitWithMask(ta, 0);
953 }
954 else if (ea)
955 {
956 // Don't interpret it yet, it might actually be an alias template parameter.
957 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
958 enum keepLvalue = true;
959 ea = ea.optimize(WANTvalue, keepLvalue);
960 if (auto ev = ea.isVarExp())
961 {
962 sa = ev.var;
963 ea = null;
964 goto Lsa;
965 }
966 if (auto et = ea.isThisExp())
967 {
968 sa = et.var;
969 ea = null;
970 goto Lsa;
971 }
972 if (auto ef = ea.isFuncExp())
973 {
974 if (ef.td)
975 sa = ef.td;
976 else
977 sa = ef.fd;
978 ea = null;
979 goto Lsa;
980 }
981 buf.writeByte('V');
982 if (ea.op == TOK.tuple)
983 {
984 ea.error("tuple is not a valid template value argument");
985 continue;
986 }
987 // Now that we know it is not an alias, we MUST obtain a value
988 uint olderr = global.errors;
989 ea = ea.ctfeInterpret();
990 if (ea.op == TOK.error || olderr != global.errors)
991 continue;
992
993 /* Use type mangling that matches what it would be for a function parameter
994 */
995 visitWithMask(ea.type, 0);
996 ea.accept(this);
997 }
998 else if (sa)
999 {
1000 Lsa:
1001 sa = sa.toAlias();
1002 if (sa.isDeclaration() && !sa.isOverDeclaration())
1003 {
1004 Declaration d = sa.isDeclaration();
1005
1006 if (auto fad = d.isFuncAliasDeclaration())
1007 d = fad.toAliasFunc();
1008 if (d.mangleOverride)
1009 {
1010 buf.writeByte('X');
1011 toBuffer(d.mangleOverride, d);
1012 continue;
1013 }
1014 if (const id = externallyMangledIdentifier(d))
1015 {
1016 buf.writeByte('X');
1017 toBuffer(id, d);
1018 continue;
1019 }
1020 if (!d.type || !d.type.deco)
1021 {
1022 ti.error("forward reference of %s `%s`", d.kind(), d.toChars());
1023 continue;
1024 }
1025 }
1026 buf.writeByte('S');
1027 mangleSymbol(sa);
1028 }
1029 else if (va)
1030 {
1031 assert(i + 1 == args.dim); // must be last one
1032 args = &va.objects;
1033 i = -cast(size_t)1;
1034 }
1035 else
1036 assert(0);
1037 }
1038 buf.writeByte('Z');
1039 }
1040
1041 override void visit(Dsymbol s)
1042 {
1043 version (none)
1044 {
1045 printf("Dsymbol.mangle() '%s'", s.toChars());
1046 if (s.parent)
1047 printf(" parent = %s %s", s.parent.kind(), s.parent.toChars());
1048 printf("\n");
1049 }
1050 mangleParent(s);
1051 if (s.ident)
1052 mangleIdentifier(s.ident, s);
1053 else
1054 toBuffer(s.toString(), s);
1055 //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
1056 }
1057
1058 ////////////////////////////////////////////////////////////////////////////
1059 override void visit(Expression e)
1060 {
1061 e.error("expression `%s` is not a valid template value argument", e.toChars());
1062 }
1063
1064 override void visit(IntegerExp e)
1065 {
1066 const v = e.toInteger();
1067 if (cast(sinteger_t)v < 0)
1068 {
1069 buf.writeByte('N');
1070 buf.print(-v);
1071 }
1072 else
1073 {
1074 buf.writeByte('i');
1075 buf.print(v);
1076 }
1077 }
1078
1079 override void visit(RealExp e)
1080 {
1081 buf.writeByte('e');
1082 realToMangleBuffer(e.value);
1083 }
1084
1085 void realToMangleBuffer(real_t value)
1086 {
1087 /* Rely on %A to get portable mangling.
1088 * Must munge result to get only identifier characters.
1089 *
1090 * Possible values from %A => mangled result
1091 * NAN => NAN
1092 * -INF => NINF
1093 * INF => INF
1094 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
1095 * 0X1.9P+2 => 19P2
1096 */
1097 if (CTFloat.isNaN(value))
1098 {
1099 buf.writestring("NAN"); // no -NAN bugs
1100 return;
1101 }
1102
1103 if (value < CTFloat.zero)
1104 {
1105 buf.writeByte('N');
1106 value = -value;
1107 }
1108
1109 if (CTFloat.isInfinity(value))
1110 {
1111 buf.writestring("INF");
1112 return;
1113 }
1114
1115 char[36] buffer = void;
1116 // 'A' format yields [-]0xh.hhhhp+-d
1117 const n = CTFloat.sprint(buffer.ptr, 'A', value);
1118 assert(n < buffer.length);
1119 foreach (const c; buffer[2 .. n])
1120 {
1121 switch (c)
1122 {
1123 case '-':
1124 buf.writeByte('N');
1125 break;
1126
1127 case '+':
1128 case '.':
1129 break;
1130
1131 default:
1132 buf.writeByte(c);
1133 break;
1134 }
1135 }
1136 }
1137
1138 override void visit(ComplexExp e)
1139 {
1140 buf.writeByte('c');
1141 realToMangleBuffer(e.toReal());
1142 buf.writeByte('c'); // separate the two
1143 realToMangleBuffer(e.toImaginary());
1144 }
1145
1146 override void visit(NullExp e)
1147 {
1148 buf.writeByte('n');
1149 }
1150
1151 override void visit(StringExp e)
1152 {
1153 char m;
1154 OutBuffer tmp;
1155 const(char)[] q;
1156 /* Write string in UTF-8 format
1157 */
1158 switch (e.sz)
1159 {
1160 case 1:
1161 m = 'a';
1162 q = e.peekString();
1163 break;
1164 case 2:
1165 {
1166 m = 'w';
1167 const slice = e.peekWstring();
1168 for (size_t u = 0; u < e.len;)
1169 {
1170 dchar c;
1171 if (const s = utf_decodeWchar(slice, u, c))
1172 e.error("%.*s", cast(int)s.length, s.ptr);
1173 else
1174 tmp.writeUTF8(c);
1175 }
1176 q = tmp[];
1177 break;
1178 }
1179 case 4:
1180 {
1181 m = 'd';
1182 const slice = e.peekDstring();
1183 foreach (c; slice)
1184 {
1185 if (!utf_isValidDchar(c))
1186 e.error("invalid UCS-32 char \\U%08x", c);
1187 else
1188 tmp.writeUTF8(c);
1189 }
1190 q = tmp[];
1191 break;
1192 }
1193
1194 default:
1195 assert(0);
1196 }
1197 buf.reserve(1 + 11 + 2 * q.length);
1198 buf.writeByte(m);
1199 buf.print(q.length);
1200 buf.writeByte('_'); // nbytes <= 11
1201 auto slice = buf.allocate(2 * q.length);
1202 foreach (i, c; q)
1203 {
1204 char hi = (c >> 4) & 0xF;
1205 slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a');
1206 char lo = c & 0xF;
1207 slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a');
1208 }
1209 }
1210
1211 override void visit(ArrayLiteralExp e)
1212 {
1213 const dim = e.elements ? e.elements.dim : 0;
1214 buf.writeByte('A');
1215 buf.print(dim);
1216 foreach (i; 0 .. dim)
1217 {
1218 e[i].accept(this);
1219 }
1220 }
1221
1222 override void visit(AssocArrayLiteralExp e)
1223 {
1224 const dim = e.keys.dim;
1225 buf.writeByte('A');
1226 buf.print(dim);
1227 foreach (i; 0 .. dim)
1228 {
1229 (*e.keys)[i].accept(this);
1230 (*e.values)[i].accept(this);
1231 }
1232 }
1233
1234 override void visit(StructLiteralExp e)
1235 {
1236 const dim = e.elements ? e.elements.dim : 0;
1237 buf.writeByte('S');
1238 buf.print(dim);
1239 foreach (i; 0 .. dim)
1240 {
1241 Expression ex = (*e.elements)[i];
1242 if (ex)
1243 ex.accept(this);
1244 else
1245 buf.writeByte('v'); // 'v' for void
1246 }
1247 }
1248
1249 override void visit(FuncExp e)
1250 {
1251 buf.writeByte('f');
1252 if (e.td)
1253 mangleSymbol(e.td);
1254 else
1255 mangleSymbol(e.fd);
1256 }
1257
1258 ////////////////////////////////////////////////////////////////////////////
1259
1260 override void visit(Parameter p)
1261 {
1262 if (p.storageClass & STC.scope_ && !(p.storageClass & STC.scopeinferred))
1263 buf.writeByte('M');
1264
1265 // 'return inout ref' is the same as 'inout ref'
1266 if ((p.storageClass & (STC.return_ | STC.wild)) == STC.return_ &&
1267 !(p.storageClass & STC.returninferred))
1268 buf.writestring("Nk");
1269 switch (p.storageClass & (STC.IOR | STC.lazy_))
1270 {
1271 case 0:
1272 break;
1273 case STC.in_:
1274 buf.writeByte('I');
1275 break;
1276 case STC.in_ | STC.ref_:
1277 buf.writestring("IK");
1278 break;
1279 case STC.out_:
1280 buf.writeByte('J');
1281 break;
1282 case STC.ref_:
1283 buf.writeByte('K');
1284 break;
1285 case STC.lazy_:
1286 buf.writeByte('L');
1287 break;
1288 default:
1289 debug
1290 {
1291 printf("storageClass = x%llx\n", p.storageClass & (STC.IOR | STC.lazy_));
1292 }
1293 assert(0);
1294 }
1295 visitWithMask(p.type, (p.storageClass & STC.in_) ? MODFlags.const_ : 0);
1296 }
1297 }