/* Compiler implementation of the D programming language * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved * written by Walter Bright * http://www.digitalmars.com * Distributed under the Boost Software License, Version 1.0. * http://www.boost.org/LICENSE_1_0.txt * https://github.com/D-Programming-Language/dmd/blob/master/src/mangle.c */ #include "root/dsystem.h" #include "root/root.h" #include "root/aav.h" #include "mangle.h" #include "init.h" #include "declaration.h" #include "aggregate.h" #include "mtype.h" #include "attrib.h" #include "target.h" #include "template.h" #include "id.h" #include "module.h" #include "enum.h" #include "expression.h" #include "utf.h" typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param); int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL); static const char *mangleChar[TMAX]; void initTypeMangle() { mangleChar[Tarray] = "A"; mangleChar[Tsarray] = "G"; mangleChar[Taarray] = "H"; mangleChar[Tpointer] = "P"; mangleChar[Treference] = "R"; mangleChar[Tfunction] = "F"; mangleChar[Tident] = "I"; mangleChar[Tclass] = "C"; mangleChar[Tstruct] = "S"; mangleChar[Tenum] = "E"; mangleChar[Tdelegate] = "D"; mangleChar[Tnone] = "n"; mangleChar[Tvoid] = "v"; mangleChar[Tint8] = "g"; mangleChar[Tuns8] = "h"; mangleChar[Tint16] = "s"; mangleChar[Tuns16] = "t"; mangleChar[Tint32] = "i"; mangleChar[Tuns32] = "k"; mangleChar[Tint64] = "l"; mangleChar[Tuns64] = "m"; mangleChar[Tint128] = "zi"; mangleChar[Tuns128] = "zk"; mangleChar[Tfloat32] = "f"; mangleChar[Tfloat64] = "d"; mangleChar[Tfloat80] = "e"; mangleChar[Timaginary32] = "o"; mangleChar[Timaginary64] = "p"; mangleChar[Timaginary80] = "j"; mangleChar[Tcomplex32] = "q"; mangleChar[Tcomplex64] = "r"; mangleChar[Tcomplex80] = "c"; mangleChar[Tbool] = "b"; mangleChar[Tchar] = "a"; mangleChar[Twchar] = "u"; mangleChar[Tdchar] = "w"; // '@' shouldn't appear anywhere in the deco'd names mangleChar[Tinstance] = "@"; mangleChar[Terror] = "@"; mangleChar[Ttypeof] = "@"; mangleChar[Ttuple] = "B"; mangleChar[Tslice] = "@"; mangleChar[Treturn] = "@"; mangleChar[Tvector] = "@"; mangleChar[Ttraits] = "@"; mangleChar[Tmixin] = "@"; mangleChar[Tnoreturn] = "@"; // becomes 'Nn' mangleChar[Tnull] = "n"; // same as TypeNone for (size_t i = 0; i < TMAX; i++) { if (!mangleChar[i]) fprintf(stderr, "ty = %llu\n", (ulonglong)i); assert(mangleChar[i]); } } /********************************* * Mangling for mod. */ void MODtoDecoBuffer(OutBuffer *buf, MOD mod) { switch (mod) { case 0: break; case MODconst: buf->writeByte('x'); break; case MODimmutable: buf->writeByte('y'); break; case MODshared: buf->writeByte('O'); break; case MODshared | MODconst: buf->writestring("Ox"); break; case MODwild: buf->writestring("Ng"); break; case MODwildconst: buf->writestring("Ngx"); break; case MODshared | MODwild: buf->writestring("ONg"); break; case MODshared | MODwildconst: buf->writestring("ONgx"); break; default: assert(0); } } class Mangler : public Visitor { public: AA *types; AA *idents; OutBuffer *buf; Mangler(OutBuffer *buf) { this->types = NULL; this->idents = NULL; this->buf = buf; } /** * writes a back reference with the relative position encoded with base 26 * using upper case letters for all digits but the last digit which uses * a lower case letter. * The decoder has to look up the referenced position to determine * whether the back reference is an identifier (starts with a digit) * or a type (starts with a letter). * * Params: * pos = relative position to encode */ void writeBackRef(size_t pos) { buf->writeByte('Q'); const size_t base = 26; size_t mul = 1; while (pos >= mul * base) mul *= base; while (mul >= base) { unsigned char dig = (unsigned char)(pos / mul); buf->writeByte('A' + dig); pos -= dig * mul; mul /= base; } buf->writeByte('a' + (unsigned char)pos); } /** * Back references a non-basic type * * The encoded mangling is * 'Q' * * Params: * t = the type to encode via back referencing * * Returns: * true if the type was found. A back reference has been encoded. * false if the type was not found. The current position is saved for later back references. */ bool backrefType(Type *t) { if (!t->isTypeBasic()) { size_t *p = (size_t *)dmd_aaGet(&types, (void *)t); if (*p) { writeBackRef(buf->length() - *p); return true; } *p = buf->length(); } return false; } /** * Back references a single identifier * * The encoded mangling is * 'Q' * * Params: * id = the identifier to encode via back referencing * * Returns: * true if the identifier was found. A back reference has been encoded. * false if the identifier was not found. The current position is saved for later back references. */ bool backrefIdentifier(Identifier *id) { size_t *p = (size_t *)dmd_aaGet(&idents, (void *)id); if (*p) { writeBackRef(buf->length() - *p); return true; } *p = buf->length(); return false; } void mangleSymbol(Dsymbol *s) { s->accept(this); } void mangleType(Type *t) { if (!backrefType(t)) t->accept(this); } void mangleIdentifier(Identifier *id, Dsymbol *s) { if (!backrefIdentifier(id)) toBuffer(id->toChars(), s); } //////////////////////////////////////////////////////////////////////////// /************************************************** * Type mangling */ void visitWithMask(Type *t, unsigned char modMask) { if (modMask != t->mod) { MODtoDecoBuffer(buf, t->mod); } mangleType(t); } void visit(Type *t) { buf->writestring(mangleChar[t->ty]); } void visit(TypeNext *t) { visit((Type *)t); visitWithMask(t->next, t->mod); } void visit(TypeVector *t) { buf->writestring("Nh"); visitWithMask(t->basetype, t->mod); } void visit(TypeSArray *t) { visit((Type *)t); if (t->dim) buf->print(t->dim->toInteger()); if (t->next) visitWithMask(t->next, t->mod); } void visit(TypeDArray *t) { visit((Type *)t); if (t->next) visitWithMask(t->next, t->mod); } void visit(TypeAArray *t) { visit((Type *)t); visitWithMask(t->index, 0); visitWithMask(t->next, t->mod); } void visit(TypeFunction *t) { //printf("TypeFunction::toDecoBuffer() t = %p %s\n", t, t->toChars()); //static int nest; if (++nest == 50) *(char*)0=0; mangleFuncType(t, t, t->mod, t->next); } void mangleFuncType(TypeFunction *t, TypeFunction *ta, unsigned char modMask, Type *tret) { //printf("mangleFuncType() %s\n", t->toChars()); if (t->inuse && tret) { // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t->toChars()); t->inuse = 2; // flag error to caller return; } t->inuse++; if (modMask != t->mod) MODtoDecoBuffer(buf, t->mod); unsigned char mc; switch (t->linkage) { case LINKd: mc = 'F'; break; case LINKc: mc = 'U'; break; case LINKwindows: mc = 'W'; break; case LINKcpp: mc = 'R'; break; case LINKobjc: mc = 'Y'; break; default: assert(0); } buf->writeByte(mc); if (ta->purity || ta->isnothrow || ta->isnogc || ta->isproperty || ta->isref || ta->trust || ta->isreturn || ta->isscope) { if (ta->purity) buf->writestring("Na"); if (ta->isnothrow) buf->writestring("Nb"); if (ta->isref) buf->writestring("Nc"); if (ta->isproperty) buf->writestring("Nd"); if (ta->isnogc) buf->writestring("Ni"); if (ta->isreturn) buf->writestring("Nj"); if (ta->isscope && !ta->isreturn && !ta->isscopeinferred) buf->writestring("Nl"); switch (ta->trust) { case TRUSTtrusted: buf->writestring("Ne"); break; case TRUSTsafe: buf->writestring("Nf"); break; default: break; } } // Write argument types paramsToDecoBuffer(t->parameterList.parameters); //if (buf->slice().ptr[buf->length() - 1] == '@') halt(); buf->writeByte('Z' - t->parameterList.varargs); // mark end of arg list if (tret != NULL) visitWithMask(tret, 0); t->inuse--; } void visit(TypeIdentifier *t) { visit((Type *)t); const char *name = t->ident->toChars(); size_t len = strlen(name); buf->print(len); buf->writestring(name); } void visit(TypeEnum *t) { visit((Type *)t); mangleSymbol(t->sym); } void visit(TypeStruct *t) { //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), name); visit((Type *)t); mangleSymbol(t->sym); } void visit(TypeClass *t) { //printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", t->toChars(), mod, name); visit((Type *)t); mangleSymbol(t->sym); } void visit(TypeTuple *t) { //printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars()); visit((Type *)t); paramsToDecoBuffer(t->arguments); buf->writeByte('Z'); } void visit(TypeNull *t) { visit((Type *)t); } void visit(TypeNoreturn *) { buf->writestring("Nn"); } //////////////////////////////////////////////////////////////////////////// void mangleDecl(Declaration *sthis) { mangleParent(sthis); assert(sthis->ident); mangleIdentifier(sthis->ident, sthis); if (FuncDeclaration *fd = sthis->isFuncDeclaration()) { mangleFunc(fd, false); } else if (sthis->type) { visitWithMask(sthis->type, 0); } else assert(0); } void mangleParent(Dsymbol *s) { Dsymbol *p; if (TemplateInstance *ti = s->isTemplateInstance()) p = ti->isTemplateMixin() ? ti->parent : ti->tempdecl->parent; else p = s->parent; if (p) { mangleParent(p); TemplateInstance *ti = p->isTemplateInstance(); if (ti && !ti->isTemplateMixin()) { mangleTemplateInstance(ti); } else if (p->getIdent()) { mangleIdentifier(p->ident, s); if (FuncDeclaration *f = p->isFuncDeclaration()) mangleFunc(f, true); } else buf->writeByte('0'); } } void mangleFunc(FuncDeclaration *fd, bool inParent) { //printf("deco = '%s'\n", fd->type->deco ? fd->type->deco : "null"); //printf("fd->type = %s\n", fd->type->toChars()); if (fd->needThis() || fd->isNested()) buf->writeByte('M'); if (inParent) { TypeFunction *tf = (TypeFunction *)fd->type; TypeFunction *tfo = (TypeFunction *)fd->originalType; mangleFuncType(tf, tfo, 0, NULL); } else if (fd->type) { visitWithMask(fd->type, 0); } else { printf("[%s] %s no type\n", fd->loc.toChars(), fd->toChars()); assert(0); // don't mangle function until semantic3 done. } } /************************************************************ * Write length prefixed string to buf. */ void toBuffer(const char *id, Dsymbol *s) { size_t len = strlen(id); if (buf->length() + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone s->error("excessive length %llu for symbol, possible recursive expansion?", buf->length() + len); else { buf->print(len); buf->write(id, len); } } static const char *externallyMangledIdentifier(Declaration *d) { if (!d->parent || d->parent->isModule() || d->linkage == LINKcpp) // if at global scope { switch (d->linkage) { case LINKd: break; case LINKc: case LINKwindows: case LINKobjc: return d->ident->toChars(); case LINKcpp: return target.cpp.toMangle(d); case LINKdefault: d->error("forward declaration"); return d->ident->toChars(); default: fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), d->linkage); assert(0); } } return NULL; } void visit(Declaration *d) { //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", // d, d->toChars(), d->parent ? d->parent->toChars() : "null", d->linkage); if (const char *id = externallyMangledIdentifier(d)) { buf->writestring(id); return; } buf->writestring("_D"); mangleDecl(d); } /****************************************************************************** * Normally FuncDeclaration and FuncAliasDeclaration have overloads. * If and only if there is no overloads, mangle() could return * exact mangled name. * * module test; * void foo(long) {} // _D4test3fooFlZv * void foo(string) {} // _D4test3fooFAyaZv * * // from FuncDeclaration::mangle(). * pragma(msg, foo.mangleof); // prints unexact mangled name "4test3foo" * // by calling Dsymbol::mangle() * * // from FuncAliasDeclaration::mangle() * pragma(msg, __traits(getOverloads, test, "foo")[0].mangleof); // "_D4test3fooFlZv" * pragma(msg, __traits(getOverloads, test, "foo")[1].mangleof); // "_D4test3fooFAyaZv" * * If a function has no overloads, .mangleof property still returns exact mangled name. * * void bar() {} * pragma(msg, bar.mangleof); // still prints "_D4test3barFZv" * // by calling FuncDeclaration::mangleExact(). */ void visit(FuncDeclaration *fd) { if (fd->isUnique()) mangleExact(fd); else visit((Dsymbol *)fd); } // ditto void visit(FuncAliasDeclaration *fd) { FuncDeclaration *f = fd->toAliasFunc(); FuncAliasDeclaration *fa = f->isFuncAliasDeclaration(); if (!fd->hasOverloads && !fa) { mangleExact(f); return; } if (fa) { mangleSymbol(fa); return; } visit((Dsymbol *)fd); } void visit(OverDeclaration *od) { if (od->overnext) { visit((Dsymbol *)od); return; } if (FuncDeclaration *fd = od->aliassym->isFuncDeclaration()) { if (!od->hasOverloads || fd->isUnique()) { mangleExact(fd); return; } } if (TemplateDeclaration *td = od->aliassym->isTemplateDeclaration()) { if (!od->hasOverloads || td->overnext == NULL) { mangleSymbol(td); return; } } visit((Dsymbol *)od); } void mangleExact(FuncDeclaration *fd) { assert(!fd->isFuncAliasDeclaration()); if (fd->mangleOverride.length) { buf->writestring(fd->mangleOverride.ptr); return; } if (fd->isMain()) { buf->writestring("_Dmain"); return; } if (fd->isWinMain() || fd->isDllMain() || fd->ident == Id::tls_get_addr) { buf->writestring(fd->ident->toChars()); return; } visit((Declaration *)fd); } void visit(VarDeclaration *vd) { if (vd->mangleOverride.length) { buf->writestring(vd->mangleOverride.ptr); return; } visit((Declaration *)vd); } void visit(AggregateDeclaration *ad) { ClassDeclaration *cd = ad->isClassDeclaration(); Dsymbol *parentsave = ad->parent; if (cd) { /* These are reserved to the compiler, so keep simple * names for them. */ 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) { // Don't mangle parent ad->parent = NULL; } } visit((Dsymbol *)ad); ad->parent = parentsave; } void visit(TemplateInstance *ti) { if (!ti->tempdecl) ti->error("is not defined"); else mangleParent(ti); if (ti->isTemplateMixin() && ti->ident) mangleIdentifier(ti->ident, ti); else mangleTemplateInstance(ti); } void mangleTemplateInstance(TemplateInstance *ti) { TemplateDeclaration *tempdecl = ti->tempdecl->isTemplateDeclaration(); assert(tempdecl); // Use "__U" for the symbols declared inside template constraint. const char T = ti->members ? 'T' : 'U'; buf->printf("__%c", T); mangleIdentifier(tempdecl->ident, tempdecl); Objects *args = ti->tiargs; size_t nparams = tempdecl->parameters->length - (tempdecl->isVariadic() ? 1 : 0); for (size_t i = 0; i < args->length; i++) { RootObject *o = (*args)[i]; Type *ta = isType(o); Expression *ea = isExpression(o); Dsymbol *sa = isDsymbol(o); Tuple *va = isTuple(o); //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); if (i < nparams && (*tempdecl->parameters)[i]->specialization()) buf->writeByte('H'); // https://issues.dlang.org/show_bug.cgi?id=6574 if (ta) { buf->writeByte('T'); visitWithMask(ta, 0); } else if (ea) { // Don't interpret it yet, it might actually be an alias template parameter. // Only constfold manifest constants, not const/immutable lvalues, see https://issues.dlang.org/show_bug.cgi?id=17339. const bool keepLvalue = true; ea = ea->optimize(WANTvalue, keepLvalue); if (ea->op == TOKvar) { sa = ((VarExp *)ea)->var; ea = NULL; goto Lsa; } if (ea->op == TOKthis) { sa = ((ThisExp *)ea)->var; ea = NULL; goto Lsa; } if (ea->op == TOKfunction) { if (((FuncExp *)ea)->td) sa = ((FuncExp *)ea)->td; else sa = ((FuncExp *)ea)->fd; ea = NULL; goto Lsa; } buf->writeByte('V'); if (ea->op == TOKtuple) { ea->error("tuple is not a valid template value argument"); continue; } // Now that we know it is not an alias, we MUST obtain a value unsigned olderr = global.errors; ea = ea->ctfeInterpret(); if (ea->op == TOKerror || olderr != global.errors) continue; /* Use type mangling that matches what it would be for a function parameter */ visitWithMask(ea->type, 0); ea->accept(this); } else if (sa) { Lsa: sa = sa->toAlias(); if (Declaration *d = sa->isDeclaration()) { if (FuncAliasDeclaration *fad = d->isFuncAliasDeclaration()) d = fad->toAliasFunc(); if (d->mangleOverride.length) { buf->writeByte('X'); toBuffer(d->mangleOverride.ptr, d); continue; } if (const char *id = externallyMangledIdentifier(d)) { buf->writeByte('X'); toBuffer(id, d); continue; } if (!d->type || !d->type->deco) { ti->error("forward reference of %s %s", d->kind(), d->toChars()); continue; } } buf->writeByte('S'); mangleSymbol(sa); } else if (va) { assert(i + 1 == args->length); // must be last one args = &va->objects; i = -(size_t)1; } else assert(0); } buf->writeByte('Z'); } void visit(Dsymbol *s) { mangleParent(s); if (s->ident) mangleIdentifier(s->ident, s); else toBuffer(s->toChars(), s); //printf("Dsymbol::mangle() %s = %s\n", s->toChars(), id); } //////////////////////////////////////////////////////////////////////////// void visit(Expression *e) { e->error("expression %s is not a valid template value argument", e->toChars()); } void visit(IntegerExp *e) { if ((sinteger_t)e->value < 0) { buf->writeByte('N'); buf->print(-e->value); } else { buf->writeByte('i'); buf->print(e->value); } } void visit(RealExp *e) { buf->writeByte('e'); realToMangleBuffer(e->value); } void realToMangleBuffer(real_t value) { /* Rely on %A to get portable mangling. * Must munge result to get only identifier characters. * * Possible values from %A => mangled result * NAN => NAN * -INF => NINF * INF => INF * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 * 0X1.9P+2 => 19P2 */ if (CTFloat::isNaN(value)) buf->writestring("NAN"); // no -NAN bugs else if (CTFloat::isInfinity(value)) buf->writestring(value < CTFloat::zero ? "NINF" : "INF"); else { const size_t BUFFER_LEN = 36; char buffer[BUFFER_LEN]; size_t n = CTFloat::sprint(buffer, 'A', value); assert(n < BUFFER_LEN); for (size_t i = 0; i < n; i++) { char c = buffer[i]; switch (c) { case '-': buf->writeByte('N'); break; case '+': case 'X': case '.': break; case '0': if (i < 2) break; // skip leading 0X /* fall through */ default: buf->writeByte(c); break; } } } } void visit(ComplexExp *e) { buf->writeByte('c'); realToMangleBuffer(e->toReal()); buf->writeByte('c'); // separate the two realToMangleBuffer(e->toImaginary()); } void visit(NullExp *) { buf->writeByte('n'); } void visit(StringExp *e) { char m; OutBuffer tmp; utf8_t *q; size_t qlen; /* Write string in UTF-8 format */ switch (e->sz) { case 1: m = 'a'; q = (utf8_t *)e->string; qlen = e->len; break; case 2: m = 'w'; for (size_t u = 0; u < e->len; ) { unsigned c; const char *p = utf_decodeWchar((unsigned short *)e->string, e->len, &u, &c); if (p) e->error("%s", p); else tmp.writeUTF8(c); } q = (utf8_t *)tmp.slice().ptr; qlen = tmp.length(); break; case 4: m = 'd'; for (size_t u = 0; u < e->len; u++) { unsigned c = ((unsigned *)e->string)[u]; if (!utf_isValidDchar(c)) e->error("invalid UCS-32 char \\U%08x", c); else tmp.writeUTF8(c); } q = (utf8_t *)tmp.slice().ptr; qlen = tmp.length(); break; default: assert(0); } buf->reserve(1 + 11 + 2 * qlen); buf->writeByte(m); buf->print(qlen); buf->writeByte('_'); // nbytes <= 11 for (utf8_t *p = (utf8_t *)buf->slice().ptr + buf->length(), *pend = p + 2 * qlen; p < pend; p += 2, ++q) { utf8_t hi = *q >> 4 & 0xF; p[0] = (utf8_t)(hi < 10 ? hi + '0' : hi - 10 + 'a'); utf8_t lo = *q & 0xF; p[1] = (utf8_t)(lo < 10 ? lo + '0' : lo - 10 + 'a'); } buf->setsize(buf->length() + 2 * qlen); } void visit(ArrayLiteralExp *e) { size_t dim = e->elements ? e->elements->length : 0; buf->writeByte('A'); buf->print(dim); for (size_t i = 0; i < dim; i++) { e->getElement(i)->accept(this); } } void visit(AssocArrayLiteralExp *e) { size_t dim = e->keys->length; buf->writeByte('A'); buf->print(dim); for (size_t i = 0; i < dim; i++) { (*e->keys)[i]->accept(this); (*e->values)[i]->accept(this); } } void visit(StructLiteralExp *e) { size_t dim = e->elements ? e->elements->length : 0; buf->writeByte('S'); buf->print(dim); for (size_t i = 0; i < dim; i++) { Expression *ex = (*e->elements)[i]; if (ex) ex->accept(this); else buf->writeByte('v'); // 'v' for void } } //////////////////////////////////////////////////////////////////////////// void paramsToDecoBuffer(Parameters *parameters) { //printf("Parameter::paramsToDecoBuffer()\n"); Parameter_foreach(parameters, ¶msToDecoBufferDg, (void *)this); } static int paramsToDecoBufferDg(void *ctx, size_t, Parameter *p) { p->accept((Visitor *)ctx); return 0; } void visit(Parameter *p) { if (p->storageClass & STCscope && !(p->storageClass & STCscopeinferred)) buf->writeByte('M'); // 'return inout ref' is the same as 'inout ref' if ((p->storageClass & (STCreturn | STCwild)) == STCreturn) buf->writestring("Nk"); switch (p->storageClass & (STCin | STCout | STCref | STClazy)) { case 0: case STCin: break; case STCout: buf->writeByte('J'); break; case STCref: buf->writeByte('K'); break; case STClazy: buf->writeByte('L'); break; default: assert(0); } visitWithMask(p->type, 0); } }; /****************************************************************************** * Returns exact mangled name of function. */ const char *mangleExact(FuncDeclaration *fd) { if (!fd->mangleString) { OutBuffer buf; Mangler v(&buf); v.mangleExact(fd); fd->mangleString = buf.extractChars(); } return fd->mangleString; } void mangleToBuffer(Type *t, OutBuffer *buf) { Mangler v(buf); v.visitWithMask(t, 0); } void mangleToBuffer(Expression *e, OutBuffer *buf) { Mangler v(buf); e->accept(&v); } void mangleToBuffer(Dsymbol *s, OutBuffer *buf) { Mangler v(buf); s->accept(&v); } void mangleToBuffer(TemplateInstance *ti, OutBuffer *buf) { Mangler v(buf); v.mangleTemplateInstance(ti); } /********************************************** * Convert a string representing a type (the deco) and * return its equivalent Type. * Params: * deco = string containing the deco * Returns: * null for failed to convert * Type for succeeded */ Type *decoToType(const char *deco) { if (!deco) return NULL; //printf("decoToType(): %s\n", deco) if (StringValue *sv = Type::stringtable.lookup(deco, strlen(deco))) { if (sv->ptrvalue) { Type *t = (Type *)sv->ptrvalue; assert(t->deco); return t; } } return NULL; }