mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 07:00:46 +03:00

The new visitor class is used for IR generation. This removes some modifications from DMD source.
480 lines
12 KiB
C
480 lines
12 KiB
C
|
|
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2012 by Digital Mars
|
|
// All Rights Reserved
|
|
// written by Walter Bright
|
|
// http://www.digitalmars.com
|
|
// License for redistribution is by either the Artistic License
|
|
// in artistic.txt, or the GNU General Public License in gnu.txt.
|
|
// See the included readme.txt for details.
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include "mars.h"
|
|
#include "dsymbol.h"
|
|
#include "mtype.h"
|
|
#include "scope.h"
|
|
#include "init.h"
|
|
#include "expression.h"
|
|
#include "attrib.h"
|
|
#include "declaration.h"
|
|
#include "template.h"
|
|
#include "id.h"
|
|
#include "enum.h"
|
|
#include "import.h"
|
|
#include "aggregate.h"
|
|
|
|
#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
|
|
|
|
/* Do mangling for C++ linkage.
|
|
* Follows Itanium C++ ABI 1.86
|
|
* No attempt is made to support mangling of templates, operator
|
|
* overloading, or special functions.
|
|
*
|
|
* So why don't we use the C++ ABI for D name mangling?
|
|
* Because D supports a lot of things (like modules) that the C++
|
|
* ABI has no concept of. These affect every D mangled name,
|
|
* so nothing would be compatible anyway.
|
|
*/
|
|
|
|
class CppMangleVisitor : public Visitor
|
|
{
|
|
Objects components;
|
|
OutBuffer buf;
|
|
|
|
void writeBase36(size_t i)
|
|
{
|
|
if (i >= 36)
|
|
{
|
|
writeBase36(i / 36);
|
|
i %= 36;
|
|
}
|
|
if (i < 10)
|
|
buf.writeByte((char)(i + '0'));
|
|
else if (i < 36)
|
|
buf.writeByte((char)(i - 10 + 'A'));
|
|
else
|
|
assert(0);
|
|
}
|
|
|
|
int substitute(RootObject *p)
|
|
{
|
|
for (size_t i = 0; i < components.dim; i++)
|
|
{
|
|
if (p == components[i])
|
|
{
|
|
/* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
|
|
*/
|
|
buf.writeByte('S');
|
|
if (i)
|
|
writeBase36(i - 1);
|
|
buf.writeByte('_');
|
|
return 1;
|
|
}
|
|
}
|
|
components.push(p);
|
|
return 0;
|
|
}
|
|
|
|
int exist(RootObject *p)
|
|
{
|
|
for (size_t i = 0; i < components.dim; i++)
|
|
{
|
|
if (p == components[i])
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void store(RootObject *p)
|
|
{
|
|
components.push(p);
|
|
}
|
|
|
|
void source_name(Dsymbol *s)
|
|
{
|
|
char *name = s->ident->toChars();
|
|
buf.printf("%d%s", strlen(name), name);
|
|
}
|
|
|
|
void prefix_name(Dsymbol *s)
|
|
{
|
|
if (!substitute(s))
|
|
{
|
|
Dsymbol *p = s->toParent();
|
|
if (p && !p->isModule())
|
|
{
|
|
prefix_name(p);
|
|
}
|
|
source_name(s);
|
|
}
|
|
}
|
|
|
|
public:
|
|
CppMangleVisitor(const char *prefix)
|
|
: buf(), components()
|
|
{
|
|
buf.writestring(prefix);
|
|
}
|
|
|
|
char *finish()
|
|
{
|
|
buf.writeByte(0);
|
|
return (char *)buf.extractData();
|
|
}
|
|
|
|
void cpp_mangle_name(Dsymbol *s)
|
|
{
|
|
Dsymbol *p = s->toParent();
|
|
if (p && !p->isModule())
|
|
{
|
|
buf.writeByte('N');
|
|
|
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
|
VarDeclaration *vd = s->isVarDeclaration();
|
|
if (fd && fd->type->isConst())
|
|
{
|
|
buf.writeByte('K');
|
|
}
|
|
if (vd && !(vd->storage_class & (STCextern | STCgshared)))
|
|
{
|
|
s->error("C++ static non- __gshared non-extern variables not supported");
|
|
}
|
|
if (vd || fd)
|
|
{
|
|
prefix_name(p);
|
|
source_name(s);
|
|
}
|
|
else
|
|
{
|
|
assert(0);
|
|
}
|
|
buf.writeByte('E');
|
|
}
|
|
else
|
|
source_name(s);
|
|
}
|
|
|
|
void visit(Type *t)
|
|
{
|
|
/* Make this the 'vendor extended type' when there is no
|
|
* C++ analog.
|
|
* u <source-name>
|
|
*/
|
|
if (!substitute(t))
|
|
{ assert(t->deco);
|
|
buf.printf("u%d%s", strlen(t->deco), t->deco);
|
|
}
|
|
}
|
|
|
|
void visit(TypeBasic *t)
|
|
{
|
|
/* ABI spec says:
|
|
* v void
|
|
* w wchar_t
|
|
* b bool
|
|
* c char
|
|
* a signed char
|
|
* h unsigned char
|
|
* s short
|
|
* t unsigned short
|
|
* i int
|
|
* j unsigned int
|
|
* l long
|
|
* m unsigned long
|
|
* x long long, __int64
|
|
* y unsigned long long, __int64
|
|
* n __int128
|
|
* o unsigned __int128
|
|
* f float
|
|
* d double
|
|
* e long double, __float80
|
|
* g __float128
|
|
* z ellipsis
|
|
* u <source-name> # vendor extended type
|
|
*/
|
|
|
|
char c;
|
|
char p = 0;
|
|
switch (t->ty)
|
|
{
|
|
case Tvoid: c = 'v'; break;
|
|
case Tint8: c = 'a'; break;
|
|
case Tuns8: c = 'h'; break;
|
|
case Tint16: c = 's'; break;
|
|
case Tuns16: c = 't'; break;
|
|
case Tint32: c = 'i'; break;
|
|
case Tuns32: c = 'j'; break;
|
|
case Tfloat32: c = 'f'; break;
|
|
case Tint64: c = 'x'; break;
|
|
case Tuns64: c = 'y'; break;
|
|
case Tfloat64: c = 'd'; break;
|
|
case Tfloat80: c = 'e'; break;
|
|
case Tbool: c = 'b'; break;
|
|
case Tchar: c = 'c'; break;
|
|
case Twchar: c = 't'; break;
|
|
case Tdchar: c = 'w'; break;
|
|
|
|
case Timaginary32: p = 'G'; c = 'f'; break;
|
|
case Timaginary64: p = 'G'; c = 'd'; break;
|
|
case Timaginary80: p = 'G'; c = 'e'; break;
|
|
case Tcomplex32: p = 'C'; c = 'f'; break;
|
|
case Tcomplex64: p = 'C'; c = 'd'; break;
|
|
case Tcomplex80: p = 'C'; c = 'e'; break;
|
|
|
|
default: assert(0);
|
|
}
|
|
if (p || t->isConst())
|
|
{
|
|
if (substitute(t))
|
|
return;
|
|
}
|
|
|
|
if (t->isConst())
|
|
buf.writeByte('K');
|
|
|
|
if (p)
|
|
buf.writeByte(p);
|
|
|
|
buf.writeByte(c);
|
|
}
|
|
|
|
|
|
void visit(TypeVector *t)
|
|
{
|
|
if (!substitute(t))
|
|
{
|
|
buf.writestring("U8__vector");
|
|
t->basetype->accept(this);
|
|
}
|
|
}
|
|
|
|
void visit(TypeSArray *t)
|
|
{
|
|
if (!substitute(t))
|
|
{
|
|
buf.printf("A%llu_", t->dim ? t->dim->toInteger() : 0);
|
|
t->next->accept(this);
|
|
}
|
|
}
|
|
|
|
void visit(TypeDArray *t)
|
|
{
|
|
visit((Type *)t);
|
|
}
|
|
|
|
void visit(TypeAArray *t)
|
|
{
|
|
visit((Type *)t);
|
|
}
|
|
|
|
void visit(TypePointer *t)
|
|
{
|
|
if (!exist(t))
|
|
{
|
|
buf.writeByte('P');
|
|
t->next->accept(this);
|
|
store(t);
|
|
}
|
|
else
|
|
substitute(t);
|
|
}
|
|
|
|
void visit(TypeReference *t)
|
|
{
|
|
if (!exist(t))
|
|
{
|
|
buf.writeByte('R');
|
|
t->next->accept(this);
|
|
store(t);
|
|
}
|
|
else
|
|
substitute(t);
|
|
}
|
|
|
|
void visit(TypeFunction *t)
|
|
{
|
|
/*
|
|
* <function-type> ::= F [Y] <bare-function-type> E
|
|
* <bare-function-type> ::= <signature type>+
|
|
* # types are possible return type, then parameter types
|
|
*/
|
|
|
|
/* ABI says:
|
|
"The type of a non-static member function is considered to be different,
|
|
for the purposes of substitution, from the type of a namespace-scope or
|
|
static member function whose type appears similar. The types of two
|
|
non-static member functions are considered to be different, for the
|
|
purposes of substitution, if the functions are members of different
|
|
classes. In other words, for the purposes of substitution, the class of
|
|
which the function is a member is considered part of the type of
|
|
function."
|
|
|
|
BUG: Right now, types of functions are never merged, so our simplistic
|
|
component matcher always finds them to be different.
|
|
We should use Type::equals on these, and use different
|
|
TypeFunctions for non-static member functions, and non-static
|
|
member functions of different classes.
|
|
*/
|
|
if (!exist(t))
|
|
{
|
|
buf.writeByte('F');
|
|
if (t->linkage == LINKc)
|
|
buf.writeByte('Y');
|
|
t->next->accept(this);
|
|
argsCppMangle(t->parameters, t->varargs);
|
|
buf.writeByte('E');
|
|
store(t);
|
|
}
|
|
else
|
|
substitute(t);
|
|
}
|
|
|
|
void visit(TypeDelegate *t)
|
|
{
|
|
visit((Type *)t);
|
|
}
|
|
|
|
void visit(TypeStruct *t)
|
|
{
|
|
if (!exist(t))
|
|
{
|
|
if (t->isConst())
|
|
buf.writeByte('K');
|
|
|
|
if (!substitute(t->sym))
|
|
cpp_mangle_name(t->sym);
|
|
|
|
if (t->isConst())
|
|
store(t);
|
|
}
|
|
else
|
|
substitute(t);
|
|
}
|
|
|
|
void visit(TypeEnum *t)
|
|
{
|
|
if (!exist(t))
|
|
{
|
|
if (t->isConst())
|
|
buf.writeByte('K');
|
|
|
|
if (!substitute(t->sym))
|
|
cpp_mangle_name(t->sym);
|
|
|
|
if (t->isConst())
|
|
store(t);
|
|
}
|
|
else
|
|
substitute(t);
|
|
}
|
|
|
|
void visit(TypeTypedef *t)
|
|
{
|
|
visit((Type *)t);
|
|
}
|
|
|
|
void visit(TypeClass *t)
|
|
{
|
|
if (!exist(t))
|
|
{
|
|
buf.writeByte('P');
|
|
|
|
if (!substitute(t->sym))
|
|
cpp_mangle_name(t->sym);
|
|
|
|
store(t);
|
|
}
|
|
else
|
|
substitute(t);
|
|
}
|
|
|
|
struct ArgsCppMangleCtx
|
|
{
|
|
CppMangleVisitor *v;
|
|
size_t cnt;
|
|
};
|
|
|
|
void argsCppMangle(Parameters *arguments, int varargs)
|
|
{
|
|
size_t n = 0;
|
|
if (arguments)
|
|
{
|
|
ArgsCppMangleCtx ctx = { this, 0 };
|
|
Parameter::foreach(arguments, &argsCppMangleDg, &ctx);
|
|
n = ctx.cnt;
|
|
}
|
|
if (varargs)
|
|
buf.writestring("z");
|
|
else if (!n)
|
|
buf.writeByte('v'); // encode ( ) arguments
|
|
}
|
|
|
|
static int argsCppMangleDg(void *ctx, size_t n, Parameter *arg)
|
|
{
|
|
ArgsCppMangleCtx *p = (ArgsCppMangleCtx *)ctx;
|
|
|
|
Type *t = arg->type->merge2();
|
|
if (arg->storageClass & (STCout | STCref))
|
|
t = t->referenceTo();
|
|
else if (arg->storageClass & STClazy)
|
|
{ // Mangle as delegate
|
|
Type *td = new TypeFunction(NULL, t, 0, LINKd);
|
|
td = new TypeDelegate(td);
|
|
t = t->merge();
|
|
}
|
|
if (t->ty == Tsarray)
|
|
{ // Mangle static arrays as pointers
|
|
t = t->pointerTo();
|
|
}
|
|
|
|
/* If it is a basic, enum or struct type,
|
|
* then don't mark it const
|
|
*/
|
|
if ((t->ty == Tenum || t->ty == Tstruct || t->isTypeBasic()) && t->isConst())
|
|
t->mutableOf()->accept(p->v);
|
|
else
|
|
t->accept(p->v);
|
|
|
|
p->cnt++;
|
|
return 0;
|
|
}
|
|
};
|
|
|
|
char *toCppMangle(Dsymbol *s)
|
|
{
|
|
/*
|
|
* <mangled-name> ::= _Z <encoding>
|
|
* <encoding> ::= <function name> <bare-function-type>
|
|
* ::= <data name>
|
|
* ::= <special-name>
|
|
*/
|
|
|
|
CppMangleVisitor v(global.params.isOSX ? "__Z" : "_Z");
|
|
|
|
v.cpp_mangle_name(s);
|
|
|
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
|
if (fd)
|
|
{ // add <bare-function-type>
|
|
assert(fd->type->ty == Tfunction);
|
|
TypeFunction *tf = (TypeFunction *)fd->type;
|
|
v.argsCppMangle(tf->parameters, tf->varargs);
|
|
}
|
|
return v.finish();
|
|
}
|
|
|
|
#else
|
|
|
|
char *toCppMangle(Dsymbol *s)
|
|
{
|
|
// Windows C++ mangling is done by C++ back end
|
|
return s->ident->toChars();
|
|
}
|
|
|
|
#endif
|
|
|