blob: a6a41cb54d06591a38249c2210df309b2810c128 [file] [log] [blame]
/* Compiler implementation of the D programming language
* Copyright (C) 1999-2019 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 "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[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:
OutBuffer *buf;
Mangler(OutBuffer *buf)
{
this->buf = buf;
}
////////////////////////////////////////////////////////////////////////////
/**************************************************
* Type mangling
*/
void visitWithMask(Type *t, unsigned char modMask)
{
if (modMask != t->mod)
{
MODtoDecoBuffer(buf, t->mod);
}
t->accept(this);
}
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)
{
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 LINKpascal: mc = 'V'; 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->parameters);
//if (buf->data[buf->offset - 1] == '@') halt();
buf->writeByte('Z' - t->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);
t->sym->accept(this);
}
void visit(TypeStruct *t)
{
//printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", t->toChars(), name);
visit((Type *)t);
t->sym->accept(this);
}
void visit(TypeClass *t)
{
//printf("TypeClass::toDecoBuffer('%s' mod=%x) = '%s'\n", t->toChars(), mod, name);
visit((Type *)t);
t->sym->accept(this);
}
void visit(TypeTuple *t)
{
//printf("TypeTuple::toDecoBuffer() t = %p, %s\n", t, t->toChars());
visit((Type *)t);
OutBuffer buf2;
buf2.reserve(32);
Mangler v(&buf2);
v.paramsToDecoBuffer(t->arguments);
const char *s = buf2.peekString();
int len = (int)buf2.offset;
buf->printf("%d%.*s", len, len, s);
}
void visit(TypeNull *t)
{
visit((Type *)t);
}
////////////////////////////////////////////////////////////////////////////
void mangleDecl(Declaration *sthis)
{
mangleParent(sthis);
assert(sthis->ident);
const char *id = sthis->ident->toChars();
toBuffer(id, sthis);
if (FuncDeclaration *fd = sthis->isFuncDeclaration())
{
mangleFunc(fd, false);
}
else if (sthis->type->deco)
{
buf->writestring(sthis->type->deco);
}
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);
if (p->getIdent())
{
const char *id = p->ident->toChars();
toBuffer(id, 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->deco)
{
buf->writestring(fd->type->deco);
}
else
{
printf("[%s] %s %s\n", fd->loc.toChars(), fd->toChars(), fd->type->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 (len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
s->error("excessive length %llu for symbol, possible recursive expansion?", len);
else
{
buf->print(len);
buf->write(id, len);
}
}
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 (!d->parent || d->parent->isModule() || d->linkage == LINKcpp) // if at global scope
{
switch (d->linkage)
{
case LINKd:
break;
case LINKc:
case LINKwindows:
case LINKpascal:
case LINKobjc:
buf->writestring(d->ident->toChars());
return;
case LINKcpp:
buf->writestring(Target::toCppMangle(d));
return;
case LINKdefault:
d->error("forward declaration");
buf->writestring(d->ident->toChars());
return;
default:
fprintf(stderr, "'%s', linkage = %d\n", d->toChars(), d->linkage);
assert(0);
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)
{
fa->accept(this);
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)
{
td->accept(this);
return;
}
}
visit((Dsymbol *)od);
}
void mangleExact(FuncDeclaration *fd)
{
assert(!fd->isFuncAliasDeclaration());
if (fd->mangleOverride)
{
buf->writestring(fd->mangleOverride);
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)
{
buf->writestring(vd->mangleOverride);
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);
ti->getIdent();
const char *id = ti->ident ? ti->ident->toChars() : ti->toChars();
toBuffer(id, ti);
//printf("TemplateInstance::mangle() %s = %s\n", ti->toChars(), ti->id);
}
void visit(Dsymbol *s)
{
mangleParent(s);
const char *id = s->ident ? s->ident->toChars() : s->toChars();
toBuffer(id, 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.data;
qlen = tmp.offset;
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.data;
qlen = tmp.offset;
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->data + buf->offset, *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->offset += 2 * qlen;
}
void visit(ArrayLiteralExp *e)
{
size_t dim = e->elements ? e->elements->dim : 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->dim;
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->dim : 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, &paramsToDecoBufferDg, (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.extractString();
}
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);
}