1
2/* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/mangle.c
9 */
10
11#include "root/dsystem.h"
12#include "root/root.h"
13
14#include "mangle.h"
15#include "init.h"
16#include "declaration.h"
17#include "aggregate.h"
18#include "mtype.h"
19#include "attrib.h"
20#include "target.h"
21#include "template.h"
22#include "id.h"
23#include "module.h"
24#include "enum.h"
25#include "expression.h"
26#include "utf.h"
27
28typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
29int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
30
31static const char *mangleChar[TMAX];
32
33void initTypeMangle()
34{
35    mangleChar[Tarray] = "A";
36    mangleChar[Tsarray] = "G";
37    mangleChar[Taarray] = "H";
38    mangleChar[Tpointer] = "P";
39    mangleChar[Treference] = "R";
40    mangleChar[Tfunction] = "F";
41    mangleChar[Tident] = "I";
42    mangleChar[Tclass] = "C";
43    mangleChar[Tstruct] = "S";
44    mangleChar[Tenum] = "E";
45    mangleChar[Tdelegate] = "D";
46
47    mangleChar[Tnone] = "n";
48    mangleChar[Tvoid] = "v";
49    mangleChar[Tint8] = "g";
50    mangleChar[Tuns8] = "h";
51    mangleChar[Tint16] = "s";
52    mangleChar[Tuns16] = "t";
53    mangleChar[Tint32] = "i";
54    mangleChar[Tuns32] = "k";
55    mangleChar[Tint64] = "l";
56    mangleChar[Tuns64] = "m";
57    mangleChar[Tint128] = "zi";
58    mangleChar[Tuns128] = "zk";
59    mangleChar[Tfloat32] = "f";
60    mangleChar[Tfloat64] = "d";
61    mangleChar[Tfloat80] = "e";
62
63    mangleChar[Timaginary32] = "o";
64    mangleChar[Timaginary64] = "p";
65    mangleChar[Timaginary80] = "j";
66    mangleChar[Tcomplex32] = "q";
67    mangleChar[Tcomplex64] = "r";
68    mangleChar[Tcomplex80] = "c";
69
70    mangleChar[Tbool] = "b";
71    mangleChar[Tchar] = "a";
72    mangleChar[Twchar] = "u";
73    mangleChar[Tdchar] = "w";
74
75    // '@' shouldn't appear anywhere in the deco'd names
76    mangleChar[Tinstance] = "@";
77    mangleChar[Terror] = "@";
78    mangleChar[Ttypeof] = "@";
79    mangleChar[Ttuple] = "B";
80    mangleChar[Tslice] = "@";
81    mangleChar[Treturn] = "@";
82    mangleChar[Tvector] = "@";
83    mangleChar[Ttraits] = "@";
84
85    mangleChar[Tnull] = "n";    // same as TypeNone
86
87    for (size_t i = 0; i < TMAX; i++)
88    {
89        if (!mangleChar[i])
90            fprintf(stderr, "ty = %llu\n", (ulonglong)i);
91        assert(mangleChar[i]);
92    }
93}
94
95/*********************************
96 * Mangling for mod.
97 */
98void MODtoDecoBuffer(OutBuffer *buf, MOD mod)
99{
100    switch (mod)
101    {
102        case 0:
103            break;
104        case MODconst:
105            buf->writeByte('x');
106            break;
107        case MODimmutable:
108            buf->writeByte('y');
109            break;
110        case MODshared:
111            buf->writeByte('O');
112            break;
113        case MODshared | MODconst:
114            buf->writestring("Ox");
115            break;
116        case MODwild:
117            buf->writestring("Ng");
118            break;
119        case MODwildconst:
120            buf->writestring("Ngx");
121            break;
122        case MODshared | MODwild:
123            buf->writestring("ONg");
124            break;
125        case MODshared | MODwildconst:
126            buf->writestring("ONgx");
127            break;
128        default:
129            assert(0);
130    }
131}
132
133class Mangler : public Visitor
134{
135public:
136    OutBuffer *buf;
137
138    Mangler(OutBuffer *buf)
139    {
140        this->buf = buf;
141    }
142
143
144    ////////////////////////////////////////////////////////////////////////////
145
146    /**************************************************
147     * Type mangling
148     */
149
150    void visitWithMask(Type *t, unsigned char modMask)
151    {
152        if (modMask != t->mod)
153        {
154            MODtoDecoBuffer(buf, t->mod);
155        }
156        t->accept(this);
157    }
158
159    void visit(Type *t)
160    {
161        buf->writestring(mangleChar[t->ty]);
162    }
163
164    void visit(TypeNext *t)
165    {
166        visit((Type *)t);
167        visitWithMask(t->next, t->mod);
168    }
169
170    void visit(TypeVector *t)
171    {
172        buf->writestring("Nh");
173        visitWithMask(t->basetype, t->mod);
174    }
175
176    void visit(TypeSArray *t)
177    {
178        visit((Type *)t);
179        if (t->dim)
180            buf->print(t->dim->toInteger());
181        if (t->next)
182            visitWithMask(t->next, t->mod);
183    }
184
185    void visit(TypeDArray *t)
186    {
187        visit((Type *)t);
188        if (t->next)
189            visitWithMask(t->next, t->mod);
190    }
191
192    void visit(TypeAArray *t)
193    {
194        visit((Type *)t);
195        visitWithMask(t->index, 0);
196        visitWithMask(t->next, t->mod);
197    }
198
199    void visit(TypeFunction *t)
200    {
201        //printf("TypeFunction::toDecoBuffer() t = %p %s\n", t, t->toChars());
202        //static int nest; if (++nest == 50) *(char*)0=0;
203
204        mangleFuncType(t, t, t->mod, t->next);
205    }
206
207    void mangleFuncType(TypeFunction *t, TypeFunction *ta, unsigned char modMask, Type *tret)
208    {
209        //printf("mangleFuncType() %s\n", t->toChars());
210        if (t->inuse)
211        {
212            t->inuse = 2;       // flag error to caller
213            return;
214        }
215        t->inuse++;
216
217        if (modMask != t->mod)
218            MODtoDecoBuffer(buf, t->mod);
219
220        unsigned char mc;
221        switch (t->linkage)
222        {
223            case LINKd:             mc = 'F';       break;
224            case LINKc:             mc = 'U';       break;
225            case LINKwindows:       mc = 'W';       break;
226            case LINKpascal:        mc = 'V';       break;
227            case LINKcpp:           mc = 'R';       break;
228            case LINKobjc:          mc = 'Y';       break;
229            default:
230                assert(0);
231        }
232        buf->writeByte(mc);
233
234        if (ta->purity || ta->isnothrow || ta->isnogc || ta->isproperty || ta->isref || ta->trust || ta->isreturn || ta->isscope)
235        {
236            if (ta->purity)
237                buf->writestring("Na");
238            if (ta->isnothrow)
239                buf->writestring("Nb");
240            if (ta->isref)
241                buf->writestring("Nc");
242            if (ta->isproperty)
243                buf->writestring("Nd");
244            if (ta->isnogc)
245                buf->writestring("Ni");
246            if (ta->isreturn)
247                buf->writestring("Nj");
248            if (ta->isscope && !ta->isreturn && !ta->isscopeinferred)
249                buf->writestring("Nl");
250            switch (ta->trust)
251            {
252                case TRUSTtrusted:
253                    buf->writestring("Ne");
254                    break;
255                case TRUSTsafe:
256                    buf->writestring("Nf");
257                    break;
258                default:
259                    break;
260            }
261        }
262
263        // Write argument types
264        paramsToDecoBuffer(t->parameters);
265        //if (buf->data[buf->offset - 1] == '@') halt();
266        buf->writeByte('Z' - t->varargs);   // mark end of arg list
267        if (tret != NULL)
268            visitWithMask(tret, 0);
269
270        t->inuse--;
271    }
272
273    void visit(TypeIdentifier *t)
274    {
275        visit((Type *)t);
276        const char *name = t->ident->toChars();
277        size_t len = strlen(name);
278        buf->print(len);
279        buf->writestring(name);
280    }
281
282    void visit(TypeEnum *t)
283    {
284        visit((Type *)t);
285        t->sym->accept(this);
286    }
287
288    void visit(TypeStruct *t)
289    {
290        //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), name);
291        visit((Type *)t);
292        t->sym->accept(this);
293    }
294
295    void visit(TypeClass *t)
296    {
297        //printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", t->toChars(), mod, name);
298        visit((Type *)t);
299        t->sym->accept(this);
300    }
301
302    void visit(TypeTuple *t)
303    {
304        //printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars());
305        visit((Type *)t);
306
307        OutBuffer buf2;
308        buf2.reserve(32);
309        Mangler v(&buf2);
310        v.paramsToDecoBuffer(t->arguments);
311        const char *s = buf2.peekString();
312        int len = (int)buf2.offset;
313        buf->printf("%d%.*s", len, len, s);
314    }
315
316    void visit(TypeNull *t)
317    {
318        visit((Type *)t);
319    }
320
321    ////////////////////////////////////////////////////////////////////////////
322
323    void mangleDecl(Declaration *sthis)
324    {
325        mangleParent(sthis);
326
327        assert(sthis->ident);
328        const char *id = sthis->ident->toChars();
329        toBuffer(id, sthis);
330
331        if (FuncDeclaration *fd = sthis->isFuncDeclaration())
332        {
333            mangleFunc(fd, false);
334        }
335        else if (sthis->type->deco)
336        {
337            buf->writestring(sthis->type->deco);
338        }
339        else
340            assert(0);
341    }
342
343    void mangleParent(Dsymbol *s)
344    {
345        Dsymbol *p;
346        if (TemplateInstance *ti = s->isTemplateInstance())
347            p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent;
348        else
349            p = s->parent;
350
351        if (p)
352        {
353            mangleParent(p);
354
355            if (p->getIdent())
356            {
357                const char *id = p->ident->toChars();
358                toBuffer(id, s);
359
360                if (FuncDeclaration *f = p->isFuncDeclaration())
361                    mangleFunc(f, true);
362            }
363            else
364                buf->writeByte('0');
365        }
366    }
367
368    void mangleFunc(FuncDeclaration *fd, bool inParent)
369    {
370        //printf("deco = '%s'\n", fd->type->deco ? fd->type->deco : "null");
371        //printf("fd->type = %s\n", fd->type->toChars());
372        if (fd->needThis() || fd->isNested())
373            buf->writeByte('M');
374        if (inParent)
375        {
376            TypeFunction *tf = (TypeFunction *)fd->type;
377            TypeFunction *tfo = (TypeFunction *)fd->originalType;
378            mangleFuncType(tf, tfo, 0, NULL);
379        }
380        else if (fd->type->deco)
381        {
382            buf->writestring(fd->type->deco);
383        }
384        else
385        {
386            printf("[%s] %s %s\n", fd->loc.toChars(), fd->toChars(), fd->type->toChars());
387            assert(0);  // don't mangle function until semantic3 done.
388        }
389    }
390
391    /************************************************************
392     * Write length prefixed string to buf.
393     */
394    void toBuffer(const char *id, Dsymbol *s)
395    {
396        size_t len = strlen(id);
397        if (len >= 8 * 1024 * 1024)         // 8 megs ought be enough for anyone
398            s->error("excessive length %llu for symbol, possible recursive expansion?", len);
399        else
400        {
401            buf->print(len);
402            buf->write(id, len);
403        }
404    }
405
406    void visit(Declaration *d)
407    {
408        //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
409        //        d, d->toChars(), d->parent ? d->parent->toChars() : "null", d->linkage);
410        if (!d->parent || d->parent->isModule() || d->linkage == LINKcpp) // if at global scope
411        {
412            switch (d->linkage)
413            {
414                case LINKd:
415                    break;
416
417                case LINKc:
418                case LINKwindows:
419                case LINKpascal:
420                case LINKobjc:
421                    buf->writestring(d->ident->toChars());
422                    return;
423
424                case LINKcpp:
425                    buf->writestring(Target::toCppMangle(d));
426                    return;
427
428                case LINKdefault:
429                    d->error("forward declaration");
430                    buf->writestring(d->ident->toChars());
431                    return;
432
433                default:
434                    fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), d->linkage);
435                    assert(0);
436                    return;
437            }
438        }
439
440        buf->writestring("_D");
441        mangleDecl(d);
442    }
443
444    /******************************************************************************
445     * Normally FuncDeclaration and FuncAliasDeclaration have overloads.
446     * If and only if there is no overloads, mangle() could return
447     * exact mangled name.
448     *
449     *      module test;
450     *      void foo(long) {}           // _D4test3fooFlZv
451     *      void foo(string) {}         // _D4test3fooFAyaZv
452     *
453     *      // from FuncDeclaration::mangle().
454     *      pragma(msg, foo.mangleof);  // prints unexact mangled name "4test3foo"
455     *                                  // by calling Dsymbol::mangle()
456     *
457     *      // from FuncAliasDeclaration::mangle()
458     *      pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof);  // "_D4test3fooFlZv"
459     *      pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof);  // "_D4test3fooFAyaZv"
460     *
461     * If a function has no overloads, .mangleof property still returns exact mangled name.
462     *
463     *      void bar() {}
464     *      pragma(msg, bar.mangleof);  // still prints "_D4test3barFZv"
465     *                                  // by calling FuncDeclaration::mangleExact().
466     */
467    void visit(FuncDeclaration *fd)
468    {
469        if (fd->isUnique())
470            mangleExact(fd);
471        else
472            visit((Dsymbol *)fd);
473    }
474
475    // ditto
476    void visit(FuncAliasDeclaration *fd)
477    {
478        FuncDeclaration *f = fd->toAliasFunc();
479        FuncAliasDeclaration *fa = f->isFuncAliasDeclaration();
480        if (!fd->hasOverloads && !fa)
481        {
482            mangleExact(f);
483            return;
484        }
485        if (fa)
486        {
487            fa->accept(this);
488            return;
489        }
490        visit((Dsymbol *)fd);
491    }
492
493    void visit(OverDeclaration *od)
494    {
495        if (od->overnext)
496        {
497            visit((Dsymbol *)od);
498            return;
499        }
500
501        if (FuncDeclaration *fd = od->aliassym->isFuncDeclaration())
502        {
503            if (!od->hasOverloads || fd->isUnique())
504            {
505                mangleExact(fd);
506                return;
507            }
508        }
509        if (TemplateDeclaration *td = od->aliassym->isTemplateDeclaration())
510        {
511            if (!od->hasOverloads || td->overnext == NULL)
512            {
513                td->accept(this);
514                return;
515            }
516        }
517        visit((Dsymbol *)od);
518    }
519
520    void mangleExact(FuncDeclaration *fd)
521    {
522        assert(!fd->isFuncAliasDeclaration());
523
524        if (fd->mangleOverride)
525        {
526            buf->writestring(fd->mangleOverride);
527            return;
528        }
529
530        if (fd->isMain())
531        {
532            buf->writestring("_Dmain");
533            return;
534        }
535
536        if (fd->isWinMain() || fd->isDllMain() || fd->ident == Id::tls_get_addr)
537        {
538            buf->writestring(fd->ident->toChars());
539            return;
540        }
541
542        visit((Declaration *)fd);
543    }
544
545    void visit(VarDeclaration *vd)
546    {
547        if (vd->mangleOverride)
548        {
549            buf->writestring(vd->mangleOverride);
550            return;
551        }
552
553        visit((Declaration *)vd);
554    }
555
556    void visit(AggregateDeclaration *ad)
557    {
558        ClassDeclaration *cd = ad->isClassDeclaration();
559        Dsymbol *parentsave = ad->parent;
560        if (cd)
561        {
562            /* These are reserved to the compiler, so keep simple
563             * names for them.
564             */
565            if ((cd->ident == Id::Exception && cd->parent->ident == Id::object) ||
566                cd->ident == Id::TypeInfo ||
567                cd->ident == Id::TypeInfo_Struct ||
568                cd->ident == Id::TypeInfo_Class ||
569                cd->ident == Id::TypeInfo_Tuple ||
570                cd == ClassDeclaration::object ||
571                cd == Type::typeinfoclass ||
572                cd == Module::moduleinfo ||
573                strncmp(cd->ident->toChars(), "TypeInfo_", 9) == 0)
574            {
575                // Don't mangle parent
576                ad->parent = NULL;
577            }
578        }
579
580        visit((Dsymbol *)ad);
581
582        ad->parent = parentsave;
583    }
584
585    void visit(TemplateInstance *ti)
586    {
587        if (!ti->tempdecl)
588            ti->error("is not defined");
589        else
590            mangleParent(ti);
591
592        ti->getIdent();
593        const char *id = ti->ident ? ti->ident->toChars() : ti->toChars();
594        toBuffer(id, ti);
595
596        //printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), ti->id);
597    }
598
599    void visit(Dsymbol *s)
600    {
601        mangleParent(s);
602
603        const char *id = s->ident ? s->ident->toChars() : s->toChars();
604        toBuffer(id, s);
605
606        //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id);
607    }
608
609    ////////////////////////////////////////////////////////////////////////////
610
611    void visit(Expression *e)
612    {
613        e->error("expression %s is not a valid template value argument", e->toChars());
614    }
615
616    void visit(IntegerExp *e)
617    {
618        if ((sinteger_t)e->value < 0)
619        {
620            buf->writeByte('N');
621            buf->print(-e->value);
622        }
623        else
624        {
625            buf->writeByte('i');
626            buf->print(e->value);
627        }
628    }
629
630    void visit(RealExp *e)
631    {
632        buf->writeByte('e');
633        realToMangleBuffer(e->value);
634    }
635
636    void realToMangleBuffer(real_t value)
637    {
638        /* Rely on %A to get portable mangling.
639         * Must munge result to get only identifier characters.
640         *
641         * Possible values from %A  => mangled result
642         * NAN                      => NAN
643         * -INF                     => NINF
644         * INF                      => INF
645         * -0X1.1BC18BA997B95P+79   => N11BC18BA997B95P79
646         * 0X1.9P+2                 => 19P2
647         */
648
649        if (CTFloat::isNaN(value))
650            buf->writestring("NAN");        // no -NAN bugs
651        else if (CTFloat::isInfinity(value))
652            buf->writestring(value < CTFloat::zero ? "NINF" : "INF");
653        else
654        {
655            const size_t BUFFER_LEN = 36;
656            char buffer[BUFFER_LEN];
657            size_t n = CTFloat::sprint(buffer, 'A', value);
658            assert(n < BUFFER_LEN);
659            for (size_t i = 0; i < n; i++)
660            {
661                char c = buffer[i];
662                switch (c)
663                {
664                    case '-':
665                        buf->writeByte('N');
666                        break;
667
668                    case '+':
669                    case 'X':
670                    case '.':
671                        break;
672
673                    case '0':
674                        if (i < 2)
675                            break;          // skip leading 0X
676                        /* fall through */
677                    default:
678                        buf->writeByte(c);
679                        break;
680                }
681            }
682        }
683    }
684
685    void visit(ComplexExp *e)
686    {
687        buf->writeByte('c');
688        realToMangleBuffer(e->toReal());
689        buf->writeByte('c');        // separate the two
690        realToMangleBuffer(e->toImaginary());
691    }
692
693    void visit(NullExp *)
694    {
695        buf->writeByte('n');
696    }
697
698    void visit(StringExp *e)
699    {
700        char m;
701        OutBuffer tmp;
702        utf8_t *q;
703        size_t qlen;
704
705        /* Write string in UTF-8 format
706         */
707        switch (e->sz)
708        {
709            case 1:
710                m = 'a';
711                q = (utf8_t *)e->string;
712                qlen = e->len;
713                break;
714
715            case 2:
716                m = 'w';
717                for (size_t u = 0; u < e->len; )
718                {
719                    unsigned c;
720                    const char *p = utf_decodeWchar((unsigned short *)e->string, e->len, &u, &c);
721                    if (p)
722                        e->error("%s", p);
723                    else
724                        tmp.writeUTF8(c);
725                }
726                q = (utf8_t *)tmp.data;
727                qlen = tmp.offset;
728                break;
729
730            case 4:
731                m = 'd';
732                for (size_t u = 0; u < e->len; u++)
733                {
734                    unsigned c = ((unsigned *)e->string)[u];
735                    if (!utf_isValidDchar(c))
736                        e->error("invalid UCS-32 char \\U%08x", c);
737                    else
738                        tmp.writeUTF8(c);
739                }
740                q = (utf8_t *)tmp.data;
741                qlen = tmp.offset;
742                break;
743
744            default:
745                assert(0);
746        }
747        buf->reserve(1 + 11 + 2 * qlen);
748        buf->writeByte(m);
749        buf->print(qlen);
750        buf->writeByte('_');    // nbytes <= 11
751
752        for (utf8_t *p = (utf8_t *)buf->data + buf->offset, *pend = p + 2 * qlen;
753             p < pend; p += 2, ++q)
754        {
755            utf8_t hi = *q >> 4 & 0xF;
756            p[0] = (utf8_t)(hi < 10 ? hi + '0' : hi - 10 + 'a');
757            utf8_t lo = *q & 0xF;
758            p[1] = (utf8_t)(lo < 10 ? lo + '0' : lo - 10 + 'a');
759        }
760        buf->offset += 2 * qlen;
761    }
762
763    void visit(ArrayLiteralExp *e)
764    {
765        size_t dim = e->elements ? e->elements->dim : 0;
766        buf->writeByte('A');
767        buf->print(dim);
768        for (size_t i = 0; i < dim; i++)
769        {
770            e->getElement(i)->accept(this);
771        }
772    }
773
774    void visit(AssocArrayLiteralExp *e)
775    {
776        size_t dim = e->keys->dim;
777        buf->writeByte('A');
778        buf->print(dim);
779        for (size_t i = 0; i < dim; i++)
780        {
781            (*e->keys)[i]->accept(this);
782            (*e->values)[i]->accept(this);
783        }
784    }
785
786    void visit(StructLiteralExp *e)
787    {
788        size_t dim = e->elements ? e->elements->dim : 0;
789        buf->writeByte('S');
790        buf->print(dim);
791        for (size_t i = 0; i < dim; i++)
792        {
793            Expression *ex = (*e->elements)[i];
794            if (ex)
795                ex->accept(this);
796            else
797                buf->writeByte('v');        // 'v' for void
798        }
799    }
800
801    ////////////////////////////////////////////////////////////////////////////
802
803    void paramsToDecoBuffer(Parameters *parameters)
804    {
805        //printf("Parameter::paramsToDecoBuffer()\n");
806        Parameter_foreach(parameters, &paramsToDecoBufferDg, (void *)this);
807    }
808
809    static int paramsToDecoBufferDg(void *ctx, size_t, Parameter *p)
810    {
811        p->accept((Visitor *)ctx);
812        return 0;
813    }
814
815    void visit(Parameter *p)
816    {
817        if (p->storageClass & STCscope && !(p->storageClass & STCscopeinferred))
818            buf->writeByte('M');
819        // 'return inout ref' is the same as 'inout ref'
820        if ((p->storageClass & (STCreturn | STCwild)) == STCreturn)
821            buf->writestring("Nk");
822        switch (p->storageClass & (STCin | STCout | STCref | STClazy))
823        {
824            case 0:
825            case STCin:
826                break;
827            case STCout:
828                buf->writeByte('J');
829                break;
830            case STCref:
831                buf->writeByte('K');
832                break;
833            case STClazy:
834                buf->writeByte('L');
835                break;
836            default:
837                assert(0);
838        }
839        visitWithMask(p->type, 0);
840    }
841};
842
843/******************************************************************************
844 * Returns exact mangled name of function.
845 */
846const char *mangleExact(FuncDeclaration *fd)
847{
848    if (!fd->mangleString)
849    {
850        OutBuffer buf;
851        Mangler v(&buf);
852        v.mangleExact(fd);
853        fd->mangleString = buf.extractString();
854    }
855    return fd->mangleString;
856}
857
858void mangleToBuffer(Type *t, OutBuffer *buf)
859{
860    Mangler v(buf);
861    v.visitWithMask(t, 0);
862}
863
864void mangleToBuffer(Expression *e, OutBuffer *buf)
865{
866    Mangler v(buf);
867    e->accept(&v);
868}
869
870void mangleToBuffer(Dsymbol *s, OutBuffer *buf)
871{
872    Mangler v(buf);
873    s->accept(&v);
874}
875