]> gcc.gnu.org Git - gcc.git/blob - gcc/d/dmd/dmangle.d
d: Merge upstream dmd d579c467c1, phobos 88aa69b14.
[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-2022 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/
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.common.outbuffer;
143 import dmd.root.aav;
144 import dmd.root.string;
145 import dmd.root.stringtable;
146 import dmd.root.utf;
147 import dmd.target;
148 import dmd.tokens;
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 private extern (C++) final class Mangler : Visitor
235 {
236 alias visit = Visitor.visit;
237 public:
238 static assert(Key.sizeof == size_t.sizeof);
239
240 OutBuffer* buf;
241 Backref backref;
242
243 extern (D) this(OutBuffer* buf, Type rootType = null)
244 {
245 this.buf = buf;
246 this.backref = Backref(rootType);
247 }
248
249 void mangleSymbol(Dsymbol s)
250 {
251 s.accept(this);
252 }
253
254 void mangleType(Type t)
255 {
256 if (!backref.addRefToType(buf, t))
257 t.accept(this);
258 }
259
260 void mangleIdentifier(Identifier id, Dsymbol s)
261 {
262 if (!backref.addRefToIdentifier(buf, id))
263 toBuffer(buf, id.toString(), s);
264 }
265
266 ////////////////////////////////////////////////////////////////////////////
267 /**************************************************
268 * Type mangling
269 */
270 void visitWithMask(Type t, ubyte modMask)
271 {
272 if (modMask != t.mod)
273 {
274 MODtoDecoBuffer(buf, t.mod);
275 }
276 mangleType(t);
277 }
278
279 override void visit(Type t)
280 {
281 tyToDecoBuffer(buf, t.ty);
282 }
283
284 override void visit(TypeNext t)
285 {
286 visit(cast(Type)t);
287 visitWithMask(t.next, t.mod);
288 }
289
290 override void visit(TypeVector t)
291 {
292 buf.writestring("Nh");
293 visitWithMask(t.basetype, t.mod);
294 }
295
296 override void visit(TypeSArray t)
297 {
298 visit(cast(Type)t);
299 if (t.dim)
300 buf.print(t.dim.toInteger());
301 if (t.next)
302 visitWithMask(t.next, t.mod);
303 }
304
305 override void visit(TypeDArray t)
306 {
307 visit(cast(Type)t);
308 if (t.next)
309 visitWithMask(t.next, t.mod);
310 }
311
312 override void visit(TypeAArray t)
313 {
314 visit(cast(Type)t);
315 visitWithMask(t.index, 0);
316 visitWithMask(t.next, t.mod);
317 }
318
319 override void visit(TypeFunction t)
320 {
321 //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars());
322 //static int nest; if (++nest == 50) *(char*)0=0;
323 mangleFuncType(t, t, t.mod, t.next);
324 }
325
326 void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret)
327 {
328 //printf("mangleFuncType() %s\n", t.toChars());
329 if (t.inuse && tret)
330 {
331 // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars());
332 t.inuse = 2; // flag error to caller
333 return;
334 }
335 t.inuse++;
336 if (modMask != t.mod)
337 MODtoDecoBuffer(buf, t.mod);
338
339 char mc;
340 final switch (t.linkage)
341 {
342 case LINK.default_:
343 case LINK.d:
344 mc = 'F';
345 break;
346 case LINK.c:
347 mc = 'U';
348 break;
349 case LINK.windows:
350 mc = 'W';
351 break;
352 case LINK.cpp:
353 mc = 'R';
354 break;
355 case LINK.objc:
356 mc = 'Y';
357 break;
358 case LINK.system:
359 assert(0);
360 }
361 buf.writeByte(mc);
362
363 if (ta.purity)
364 buf.writestring("Na");
365 if (ta.isnothrow)
366 buf.writestring("Nb");
367 if (ta.isref)
368 buf.writestring("Nc");
369 if (ta.isproperty)
370 buf.writestring("Nd");
371 if (ta.isnogc)
372 buf.writestring("Ni");
373
374 // `return scope` must be in that order
375 if (ta.isreturnscope && !ta.isreturninferred)
376 {
377 buf.writestring("NjNl");
378 }
379 else
380 {
381 // when return ref, the order is `scope return`
382 if (ta.isScopeQual && !ta.isscopeinferred)
383 buf.writestring("Nl");
384
385 if (ta.isreturn && !ta.isreturninferred)
386 buf.writestring("Nj");
387 }
388
389 if (ta.islive)
390 buf.writestring("Nm");
391
392 switch (ta.trust)
393 {
394 case TRUST.trusted:
395 buf.writestring("Ne");
396 break;
397 case TRUST.safe:
398 buf.writestring("Nf");
399 break;
400 default:
401 break;
402 }
403
404 // Write argument types
405 foreach (idx, param; t.parameterList)
406 mangleParameter(param);
407 //if (buf.data[buf.length - 1] == '@') assert(0);
408 buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
409 if (tret !is null)
410 visitWithMask(tret, 0);
411 t.inuse--;
412 }
413
414 override void visit(TypeIdentifier t)
415 {
416 visit(cast(Type)t);
417 auto name = t.ident.toString();
418 buf.print(cast(int)name.length);
419 buf.writestring(name);
420 }
421
422 override void visit(TypeEnum t)
423 {
424 visit(cast(Type)t);
425 mangleSymbol(t.sym);
426 }
427
428 override void visit(TypeStruct t)
429 {
430 //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name);
431 visit(cast(Type)t);
432 mangleSymbol(t.sym);
433 }
434
435 override void visit(TypeClass t)
436 {
437 //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name);
438 visit(cast(Type)t);
439 mangleSymbol(t.sym);
440 }
441
442 override void visit(TypeTuple t)
443 {
444 //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
445 visit(cast(Type)t);
446 Parameter._foreach(t.arguments, (idx, param) {
447 mangleParameter(param);
448 return 0;
449 });
450 buf.writeByte('Z');
451 }
452
453 override void visit(TypeNull t)
454 {
455 visit(cast(Type)t);
456 }
457
458 override void visit(TypeNoreturn t)
459 {
460 buf.writestring("Nn");
461 }
462
463 ////////////////////////////////////////////////////////////////////////////
464 void mangleDecl(Declaration sthis)
465 {
466 mangleParent(sthis);
467 assert(sthis.ident);
468 mangleIdentifier(sthis.ident, sthis);
469 if (FuncDeclaration fd = sthis.isFuncDeclaration())
470 {
471 mangleFunc(fd, false);
472 }
473 else if (sthis.type)
474 {
475 visitWithMask(sthis.type, 0);
476 }
477 else
478 assert(0);
479 }
480
481 void mangleParent(Dsymbol s)
482 {
483 //printf("mangleParent() %s %s\n", s.kind(), s.toChars());
484 Dsymbol p;
485 if (TemplateInstance ti = s.isTemplateInstance())
486 p = ti.isTemplateMixin() ? ti.parent : ti.tempdecl.parent;
487 else
488 p = s.parent;
489 if (p)
490 {
491 uint localNum = s.localNum;
492 mangleParent(p);
493 auto ti = p.isTemplateInstance();
494 if (ti && !ti.isTemplateMixin())
495 {
496 localNum = ti.tempdecl.localNum;
497 mangleTemplateInstance(ti);
498 }
499 else if (p.getIdent())
500 {
501 mangleIdentifier(p.ident, s);
502 if (FuncDeclaration f = p.isFuncDeclaration())
503 mangleFunc(f, true);
504 }
505 else
506 buf.writeByte('0');
507
508 if (localNum)
509 writeLocalParent(buf, localNum);
510 }
511 }
512
513 void mangleFunc(FuncDeclaration fd, bool inParent)
514 {
515 //printf("deco = '%s'\n", fd.type.deco ? fd.type.deco : "null");
516 //printf("fd.type = %s\n", fd.type.toChars());
517 if (fd.needThis() || fd.isNested())
518 buf.writeByte('M');
519
520 if (!fd.type || fd.type.ty == Terror)
521 {
522 // never should have gotten here, but could be the result of
523 // failed speculative compilation
524 buf.writestring("9__error__FZ");
525
526 //printf("[%s] %s no type\n", fd.loc.toChars(), fd.toChars());
527 //assert(0); // don't mangle function until semantic3 done.
528 }
529 else if (inParent)
530 {
531 TypeFunction tf = fd.type.isTypeFunction();
532 TypeFunction tfo = fd.originalType.isTypeFunction();
533 mangleFuncType(tf, tfo, 0, null);
534 }
535 else
536 {
537 visitWithMask(fd.type, 0);
538 }
539 }
540
541 override void visit(Declaration d)
542 {
543 //printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
544 // d, d.toChars(), d.parent ? d.parent.toChars() : "null", d.linkage);
545 if (const id = externallyMangledIdentifier(d))
546 {
547 buf.writestring(id);
548 return;
549 }
550 buf.writestring("_D");
551 mangleDecl(d);
552 debug
553 {
554 const slice = (*buf)[];
555 assert(slice.length);
556 for (size_t pos; pos < slice.length; )
557 {
558 dchar c;
559 auto ppos = pos;
560 const s = utf_decodeChar(slice, pos, c);
561 assert(s is null, s);
562 assert(c.isValidMangling, "The mangled name '" ~ slice ~ "' " ~
563 "contains an invalid character: " ~ slice[ppos..pos]);
564 }
565 }
566 }
567
568 /******************************************************************************
569 * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
570 * If and only if there is no overloads, mangle() could return
571 * exact mangled name.
572 *
573 * module test;
574 * void foo(long) {} // _D4test3fooFlZv
575 * void foo(string) {} // _D4test3fooFAyaZv
576 *
577 * // from FuncDeclaration.mangle().
578 * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo"
579 * // by calling Dsymbol.mangle()
580 *
581 * // from FuncAliasDeclaration.mangle()
582 * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv"
583 * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv"
584 *
585 * If a function has no overloads, .mangleof property still returns exact mangled name.
586 *
587 * void bar() {}
588 * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv"
589 * // by calling FuncDeclaration.mangleExact().
590 */
591 override void visit(FuncDeclaration fd)
592 {
593 if (fd.isUnique())
594 mangleExact(fd);
595 else
596 visit(cast(Dsymbol)fd);
597 }
598
599 // ditto
600 override void visit(FuncAliasDeclaration fd)
601 {
602 FuncDeclaration f = fd.toAliasFunc();
603 FuncAliasDeclaration fa = f.isFuncAliasDeclaration();
604 if (!fd.hasOverloads && !fa)
605 {
606 mangleExact(f);
607 return;
608 }
609 if (fa)
610 {
611 mangleSymbol(fa);
612 return;
613 }
614 visit(cast(Dsymbol)fd);
615 }
616
617 override void visit(OverDeclaration od)
618 {
619 if (od.overnext)
620 {
621 visit(cast(Dsymbol)od);
622 return;
623 }
624 if (FuncDeclaration fd = od.aliassym.isFuncDeclaration())
625 {
626 if (fd.isUnique())
627 {
628 mangleExact(fd);
629 return;
630 }
631 }
632 if (TemplateDeclaration td = od.aliassym.isTemplateDeclaration())
633 {
634 if (td.overnext is null)
635 {
636 mangleSymbol(td);
637 return;
638 }
639 }
640 visit(cast(Dsymbol)od);
641 }
642
643 void mangleExact(FuncDeclaration fd)
644 {
645 assert(!fd.isFuncAliasDeclaration());
646 if (fd.mangleOverride)
647 {
648 buf.writestring(fd.mangleOverride);
649 return;
650 }
651 if (fd.isMain())
652 {
653 buf.writestring("_Dmain");
654 return;
655 }
656 if (fd.isWinMain() || fd.isDllMain())
657 {
658 buf.writestring(fd.ident.toString());
659 return;
660 }
661 visit(cast(Declaration)fd);
662 }
663
664 override void visit(VarDeclaration vd)
665 {
666 if (vd.mangleOverride)
667 {
668 buf.writestring(vd.mangleOverride);
669 return;
670 }
671 visit(cast(Declaration)vd);
672 }
673
674 override void visit(AggregateDeclaration ad)
675 {
676 ClassDeclaration cd = ad.isClassDeclaration();
677 Dsymbol parentsave = ad.parent;
678 if (cd)
679 {
680 /* These are reserved to the compiler, so keep simple
681 * names for them.
682 */
683 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)
684 {
685 // Don't mangle parent
686 ad.parent = null;
687 }
688 }
689 visit(cast(Dsymbol)ad);
690 ad.parent = parentsave;
691 }
692
693 override void visit(TemplateInstance ti)
694 {
695 version (none)
696 {
697 printf("TemplateInstance.mangle() %p %s", ti, ti.toChars());
698 if (ti.parent)
699 printf(" parent = %s %s", ti.parent.kind(), ti.parent.toChars());
700 printf("\n");
701 }
702 if (!ti.tempdecl)
703 ti.error("is not defined");
704 else
705 mangleParent(ti);
706
707 if (ti.isTemplateMixin() && ti.ident)
708 mangleIdentifier(ti.ident, ti);
709 else
710 mangleTemplateInstance(ti);
711 }
712
713 void mangleTemplateInstance(TemplateInstance ti)
714 {
715 TemplateDeclaration tempdecl = ti.tempdecl.isTemplateDeclaration();
716 assert(tempdecl);
717
718 // Use "__U" for the symbols declared inside template constraint.
719 const char T = ti.members ? 'T' : 'U';
720 buf.printf("__%c", T);
721 mangleIdentifier(tempdecl.ident, tempdecl);
722
723 auto args = ti.tiargs;
724 size_t nparams = tempdecl.parameters.dim - (tempdecl.isVariadic() ? 1 : 0);
725 for (size_t i = 0; i < args.dim; i++)
726 {
727 auto o = (*args)[i];
728 Type ta = isType(o);
729 Expression ea = isExpression(o);
730 Dsymbol sa = isDsymbol(o);
731 Tuple va = isTuple(o);
732 //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va);
733 if (i < nparams && (*tempdecl.parameters)[i].specialization())
734 buf.writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574
735 if (ta)
736 {
737 buf.writeByte('T');
738 visitWithMask(ta, 0);
739 }
740 else if (ea)
741 {
742 // Don't interpret it yet, it might actually be an alias template parameter.
743 // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339.
744 enum keepLvalue = true;
745 ea = ea.optimize(WANTvalue, keepLvalue);
746 if (auto ev = ea.isVarExp())
747 {
748 sa = ev.var;
749 ea = null;
750 goto Lsa;
751 }
752 if (auto et = ea.isThisExp())
753 {
754 sa = et.var;
755 ea = null;
756 goto Lsa;
757 }
758 if (auto ef = ea.isFuncExp())
759 {
760 if (ef.td)
761 sa = ef.td;
762 else
763 sa = ef.fd;
764 ea = null;
765 goto Lsa;
766 }
767 buf.writeByte('V');
768 if (ea.op == EXP.tuple)
769 {
770 ea.error("tuple is not a valid template value argument");
771 continue;
772 }
773 // Now that we know it is not an alias, we MUST obtain a value
774 uint olderr = global.errors;
775 ea = ea.ctfeInterpret();
776 if (ea.op == EXP.error || olderr != global.errors)
777 continue;
778
779 /* Use type mangling that matches what it would be for a function parameter
780 */
781 visitWithMask(ea.type, 0);
782 ea.accept(this);
783 }
784 else if (sa)
785 {
786 Lsa:
787 sa = sa.toAlias();
788 if (sa.isDeclaration() && !sa.isOverDeclaration())
789 {
790 Declaration d = sa.isDeclaration();
791
792 if (auto fad = d.isFuncAliasDeclaration())
793 d = fad.toAliasFunc();
794 if (d.mangleOverride)
795 {
796 buf.writeByte('X');
797 toBuffer(buf, d.mangleOverride, d);
798 continue;
799 }
800 if (const id = externallyMangledIdentifier(d))
801 {
802 buf.writeByte('X');
803 toBuffer(buf, id, d);
804 continue;
805 }
806 if (!d.type || !d.type.deco)
807 {
808 ti.error("forward reference of %s `%s`", d.kind(), d.toChars());
809 continue;
810 }
811 }
812 buf.writeByte('S');
813 mangleSymbol(sa);
814 }
815 else if (va)
816 {
817 assert(i + 1 == args.dim); // must be last one
818 args = &va.objects;
819 i = -cast(size_t)1;
820 }
821 else
822 assert(0);
823 }
824 buf.writeByte('Z');
825 }
826
827 override void visit(Dsymbol s)
828 {
829 version (none)
830 {
831 printf("Dsymbol.mangle() '%s'", s.toChars());
832 if (s.parent)
833 printf(" parent = %s %s", s.parent.kind(), s.parent.toChars());
834 printf("\n");
835 }
836 if (s.parent && s.ident)
837 {
838 if (auto m = s.parent.isModule())
839 {
840 if (m.filetype == FileType.c)
841 {
842 /* C types at global level get mangled into the __C global namespace
843 * to get the same mangling regardless of which module it
844 * is declared in. This works because types are the same if the mangling
845 * is the same.
846 */
847 mangleIdentifier(Id.ImportC, s); // parent
848 mangleIdentifier(s.ident, s);
849 return;
850 }
851 }
852 }
853 mangleParent(s);
854 if (s.ident)
855 mangleIdentifier(s.ident, s);
856 else
857 toBuffer(buf, s.toString(), s);
858 //printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
859 }
860
861 ////////////////////////////////////////////////////////////////////////////
862 override void visit(Expression e)
863 {
864 e.error("expression `%s` is not a valid template value argument", e.toChars());
865 }
866
867 override void visit(IntegerExp e)
868 {
869 const v = e.toInteger();
870 if (cast(sinteger_t)v < 0)
871 {
872 buf.writeByte('N');
873 buf.print(-v);
874 }
875 else
876 {
877 buf.writeByte('i');
878 buf.print(v);
879 }
880 }
881
882 override void visit(RealExp e)
883 {
884 buf.writeByte('e');
885 realToMangleBuffer(buf, e.value);
886 }
887
888 override void visit(ComplexExp e)
889 {
890 buf.writeByte('c');
891 realToMangleBuffer(buf, e.toReal());
892 buf.writeByte('c'); // separate the two
893 realToMangleBuffer(buf, e.toImaginary());
894 }
895
896 override void visit(NullExp e)
897 {
898 buf.writeByte('n');
899 }
900
901 override void visit(StringExp e)
902 {
903 char m;
904 OutBuffer tmp;
905 const(char)[] q;
906 /* Write string in UTF-8 format
907 */
908 switch (e.sz)
909 {
910 case 1:
911 m = 'a';
912 q = e.peekString();
913 break;
914 case 2:
915 {
916 m = 'w';
917 const slice = e.peekWstring();
918 for (size_t u = 0; u < e.len;)
919 {
920 dchar c;
921 if (const s = utf_decodeWchar(slice, u, c))
922 e.error("%.*s", cast(int)s.length, s.ptr);
923 else
924 tmp.writeUTF8(c);
925 }
926 q = tmp[];
927 break;
928 }
929 case 4:
930 {
931 m = 'd';
932 const slice = e.peekDstring();
933 foreach (c; slice)
934 {
935 if (!utf_isValidDchar(c))
936 e.error("invalid UCS-32 char \\U%08x", c);
937 else
938 tmp.writeUTF8(c);
939 }
940 q = tmp[];
941 break;
942 }
943
944 default:
945 assert(0);
946 }
947 buf.reserve(1 + 11 + 2 * q.length);
948 buf.writeByte(m);
949 buf.print(q.length);
950 buf.writeByte('_'); // nbytes <= 11
951 auto slice = buf.allocate(2 * q.length);
952 foreach (i, c; q)
953 {
954 char hi = (c >> 4) & 0xF;
955 slice[i * 2] = cast(char)(hi < 10 ? hi + '0' : hi - 10 + 'a');
956 char lo = c & 0xF;
957 slice[i * 2 + 1] = cast(char)(lo < 10 ? lo + '0' : lo - 10 + 'a');
958 }
959 }
960
961 override void visit(ArrayLiteralExp e)
962 {
963 const dim = e.elements ? e.elements.dim : 0;
964 buf.writeByte('A');
965 buf.print(dim);
966 foreach (i; 0 .. dim)
967 {
968 e[i].accept(this);
969 }
970 }
971
972 override void visit(AssocArrayLiteralExp e)
973 {
974 const dim = e.keys.dim;
975 buf.writeByte('A');
976 buf.print(dim);
977 foreach (i; 0 .. dim)
978 {
979 (*e.keys)[i].accept(this);
980 (*e.values)[i].accept(this);
981 }
982 }
983
984 override void visit(StructLiteralExp e)
985 {
986 const dim = e.elements ? e.elements.dim : 0;
987 buf.writeByte('S');
988 buf.print(dim);
989 foreach (i; 0 .. dim)
990 {
991 Expression ex = (*e.elements)[i];
992 if (ex)
993 ex.accept(this);
994 else
995 buf.writeByte('v'); // 'v' for void
996 }
997 }
998
999 override void visit(FuncExp e)
1000 {
1001 buf.writeByte('f');
1002 if (e.td)
1003 mangleSymbol(e.td);
1004 else
1005 mangleSymbol(e.fd);
1006 }
1007
1008 ////////////////////////////////////////////////////////////////////////////
1009
1010 void mangleParameter(Parameter p)
1011 {
1012 // https://dlang.org/spec/abi.html#Parameter
1013
1014 auto stc = p.storageClass;
1015
1016 // Inferred storage classes don't get mangled in
1017 if (stc & STC.scopeinferred)
1018 stc &= ~(STC.scope_ | STC.scopeinferred);
1019 if (stc & STC.returninferred)
1020 stc &= ~(STC.return_ | STC.returninferred);
1021
1022 // much like hdrgen.stcToBuffer()
1023 string rrs;
1024 const isout = (stc & STC.out_) != 0;
1025 final switch (buildScopeRef(stc))
1026 {
1027 case ScopeRef.None:
1028 case ScopeRef.Scope:
1029 case ScopeRef.Ref:
1030 case ScopeRef.Return:
1031 case ScopeRef.RefScope:
1032 break;
1033
1034 case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope
1035 case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref
1036 case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref
1037 case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref
1038 L1:
1039 buf.writestring(rrs);
1040 stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
1041 break;
1042 }
1043
1044 if (stc & STC.scope_)
1045 buf.writeByte('M'); // scope
1046
1047 if (stc & STC.return_)
1048 buf.writestring("Nk"); // return
1049
1050 switch (stc & (STC.IOR | STC.lazy_))
1051 {
1052 case 0:
1053 break;
1054 case STC.in_:
1055 buf.writeByte('I');
1056 break;
1057 case STC.in_ | STC.ref_:
1058 buf.writestring("IK");
1059 break;
1060 case STC.out_:
1061 buf.writeByte('J');
1062 break;
1063 case STC.ref_:
1064 buf.writeByte('K');
1065 break;
1066 case STC.lazy_:
1067 buf.writeByte('L');
1068 break;
1069 default:
1070 debug
1071 {
1072 printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_));
1073 }
1074 assert(0);
1075 }
1076 visitWithMask(p.type, (stc & STC.in_) ? MODFlags.const_ : 0);
1077 }
1078 }
1079
1080 /***************************************
1081 * Manage back reference mangling
1082 */
1083 private struct Backref
1084 {
1085 /**
1086 * Back references a non-basic type
1087 *
1088 * The encoded mangling is
1089 * 'Q' <relative position of first occurrence of type>
1090 *
1091 * Params:
1092 * t = the type to encode via back referencing
1093 *
1094 * Returns:
1095 * true if the type was found. A back reference has been encoded.
1096 * false if the type was not found. The current position is saved for later back references.
1097 */
1098 bool addRefToType(OutBuffer* buf, Type t)
1099 {
1100 if (t.isTypeBasic())
1101 return false;
1102
1103 /**
1104 * https://issues.dlang.org/show_bug.cgi?id=21591
1105 *
1106 * Special case for unmerged TypeFunctions: use the generic merged
1107 * function type as backref cache key to avoid missed backrefs.
1108 *
1109 * Merging is based on mangling, so we need to avoid an infinite
1110 * recursion by excluding the case where `t` is the root type passed to
1111 * `mangleToBuffer()`.
1112 */
1113 if (t != rootType)
1114 {
1115 if (t.isFunction_Delegate_PtrToFunction())
1116 {
1117 t = t.merge2();
1118 }
1119 }
1120
1121 return backrefImpl(buf, types, t);
1122 }
1123
1124 /**
1125 * Back references a single identifier
1126 *
1127 * The encoded mangling is
1128 * 'Q' <relative position of first occurrence of type>
1129 *
1130 * Params:
1131 * id = the identifier to encode via back referencing
1132 *
1133 * Returns:
1134 * true if the identifier was found. A back reference has been encoded.
1135 * false if the identifier was not found. The current position is saved for later back references.
1136 */
1137 bool addRefToIdentifier(OutBuffer* buf, Identifier id)
1138 {
1139 return backrefImpl(buf, idents, id);
1140 }
1141
1142 private:
1143
1144 extern(D) bool backrefImpl(T)(OutBuffer* buf, ref AssocArray!(T, size_t) aa, T key)
1145 {
1146 auto p = aa.getLvalue(key);
1147 if (*p)
1148 {
1149 const offset = *p - 1;
1150 writeBackRef(buf, buf.length - offset);
1151 return true;
1152 }
1153 *p = buf.length + 1;
1154 return false;
1155 }
1156
1157 Type rootType; /// avoid infinite recursion
1158 AssocArray!(Type, size_t) types; /// Type => (offset+1) in buf
1159 AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf
1160 }
1161
1162
1163 /***********************
1164 * Mangle basic type ty to buf.
1165 */
1166
1167 private void tyToDecoBuffer(OutBuffer* buf, int ty)
1168 {
1169 const c = mangleChar[ty];
1170 buf.writeByte(c);
1171 if (c == 'z')
1172 buf.writeByte(ty == Tint128 ? 'i' : 'k');
1173 }
1174
1175 /*********************************
1176 * Mangling for mod.
1177 */
1178 private void MODtoDecoBuffer(OutBuffer* buf, MOD mod)
1179 {
1180 switch (mod)
1181 {
1182 case 0:
1183 break;
1184 case MODFlags.const_:
1185 buf.writeByte('x');
1186 break;
1187 case MODFlags.immutable_:
1188 buf.writeByte('y');
1189 break;
1190 case MODFlags.shared_:
1191 buf.writeByte('O');
1192 break;
1193 case MODFlags.shared_ | MODFlags.const_:
1194 buf.writestring("Ox");
1195 break;
1196 case MODFlags.wild:
1197 buf.writestring("Ng");
1198 break;
1199 case MODFlags.wildconst:
1200 buf.writestring("Ngx");
1201 break;
1202 case MODFlags.shared_ | MODFlags.wild:
1203 buf.writestring("ONg");
1204 break;
1205 case MODFlags.shared_ | MODFlags.wildconst:
1206 buf.writestring("ONgx");
1207 break;
1208 default:
1209 assert(0);
1210 }
1211 }
1212
1213
1214 /**
1215 * writes a back reference with the relative position encoded with base 26
1216 * using upper case letters for all digits but the last digit which uses
1217 * a lower case letter.
1218 * The decoder has to look up the referenced position to determine
1219 * whether the back reference is an identifier (starts with a digit)
1220 * or a type (starts with a letter).
1221 *
1222 * Params:
1223 * buf = buffer to write to
1224 * pos = relative position to encode
1225 */
1226 private
1227 void writeBackRef(OutBuffer* buf, size_t pos)
1228 {
1229 buf.writeByte('Q');
1230 enum base = 26;
1231 size_t mul = 1;
1232 while (pos >= mul * base)
1233 mul *= base;
1234 while (mul >= base)
1235 {
1236 auto dig = cast(ubyte)(pos / mul);
1237 buf.writeByte('A' + dig);
1238 pos -= dig * mul;
1239 mul /= base;
1240 }
1241 buf.writeByte('a' + cast(ubyte)pos);
1242 }
1243
1244
1245 /************************************************************
1246 * Write length prefixed string to buf.
1247 */
1248 private
1249 extern (D) void toBuffer(OutBuffer* buf, const(char)[] id, Dsymbol s)
1250 {
1251 const len = id.length;
1252 if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
1253 s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.length + len));
1254 else
1255 {
1256 buf.print(len);
1257 buf.writestring(id);
1258 }
1259 }
1260
1261
1262 /*****
1263 * There can be multiple different declarations in the same
1264 * function that have the same mangled name.
1265 * This results in localNum having a non-zero number, which
1266 * is used to add a fake parent of the form `__Sddd` to make
1267 * the mangled names unique.
1268 * https://issues.dlang.org/show_bug.cgi?id=20565
1269 * Params:
1270 * buf = buffer to write to
1271 * localNum = local symbol number
1272 */
1273 private
1274 void writeLocalParent(OutBuffer* buf, uint localNum)
1275 {
1276 uint ndigits = 1;
1277 auto n = localNum;
1278 while (n >= 10)
1279 {
1280 n /= 10;
1281 ++ndigits;
1282 }
1283 buf.printf("%u__S%u", ndigits + 3, localNum);
1284 }
1285
1286 /*************************
1287 * Write real to buffer.
1288 * Params:
1289 * buf = buffer to write to
1290 * value = real to write
1291 */
1292 private
1293 void realToMangleBuffer(OutBuffer* buf, real_t value)
1294 {
1295 /* Rely on %A to get portable mangling.
1296 * Must munge result to get only identifier characters.
1297 *
1298 * Possible values from %A => mangled result
1299 * NAN => NAN
1300 * -INF => NINF
1301 * INF => INF
1302 * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
1303 * 0X1.9P+2 => 19P2
1304 */
1305 if (CTFloat.isNaN(value))
1306 {
1307 buf.writestring("NAN"); // no -NAN bugs
1308 return;
1309 }
1310
1311 if (value < CTFloat.zero)
1312 {
1313 buf.writeByte('N');
1314 value = -value;
1315 }
1316
1317 if (CTFloat.isInfinity(value))
1318 {
1319 buf.writestring("INF");
1320 return;
1321 }
1322
1323 char[36] buffer = void;
1324 // 'A' format yields [-]0xh.hhhhp+-d
1325 const n = CTFloat.sprint(buffer.ptr, 'A', value);
1326 assert(n < buffer.length);
1327 foreach (const c; buffer[2 .. n])
1328 {
1329 switch (c)
1330 {
1331 case '-':
1332 buf.writeByte('N');
1333 break;
1334
1335 case '+':
1336 case '.':
1337 break;
1338
1339 default:
1340 buf.writeByte(c);
1341 break;
1342 }
1343 }
1344 }
1345
1346 /************************************************************
1347 * Try to obtain an externally mangled identifier from a declaration.
1348 * If the declaration is at global scope or mixed in at global scope,
1349 * the user might want to call it externally, so an externally mangled
1350 * name is returned. Member functions or nested functions can't be called
1351 * externally in C, so in that case null is returned. C++ does support
1352 * namespaces, so extern(C++) always gives a C++ mangled name.
1353 *
1354 * See also: https://issues.dlang.org/show_bug.cgi?id=20012
1355 *
1356 * Params:
1357 * d = declaration to mangle
1358 *
1359 * Returns:
1360 * an externally mangled name or null if the declaration cannot be called externally
1361 */
1362 private
1363 extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
1364 {
1365 assert(!d.mangleOverride, "mangle overrides should have been handled earlier");
1366
1367 const linkage = d.resolvedLinkage();
1368 const par = d.toParent(); //toParent() skips over mixin templates
1369 if (!par || par.isModule() || linkage == LINK.cpp ||
1370 (linkage == LINK.c && d.isCsymbol() &&
1371 (d.isFuncDeclaration() ||
1372 (d.isVarDeclaration() && d.isDataseg() && d.storage_class & STC.extern_))))
1373 {
1374 if (linkage != LINK.d && d.localNum)
1375 d.error("the same declaration cannot be in multiple scopes with non-D linkage");
1376
1377 final switch (linkage)
1378 {
1379 case LINK.d:
1380 break;
1381 case LINK.c:
1382 case LINK.windows:
1383 case LINK.objc:
1384 return d.ident.toString();
1385 case LINK.cpp:
1386 {
1387 const p = target.cpp.toMangle(d);
1388 return p.toDString();
1389 }
1390 case LINK.default_:
1391 d.error("forward declaration");
1392 return d.ident.toString();
1393 case LINK.system:
1394 assert(0);
1395 }
1396 }
1397 return null;
1398 }
This page took 0.099751 seconds and 5 git commands to generate.