mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-30 07:00:46 +03:00
381 lines
8.9 KiB
C
381 lines
8.9 KiB
C
|
|
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2007 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 <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 DMDV2
|
|
|
|
/* 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.
|
|
*/
|
|
|
|
struct CppMangleState
|
|
{
|
|
static Array components;
|
|
|
|
int substitute(OutBuffer *buf, void *p);
|
|
};
|
|
|
|
Array CppMangleState::components;
|
|
|
|
|
|
void writeBase36(OutBuffer *buf, unsigned i)
|
|
{
|
|
if (i >= 36)
|
|
{
|
|
writeBase36(buf, i / 36);
|
|
i %= 36;
|
|
}
|
|
if (i < 10)
|
|
buf->writeByte(i + '0');
|
|
else if (i < 36)
|
|
buf->writeByte(i - 10 + 'A');
|
|
else
|
|
assert(0);
|
|
}
|
|
|
|
int CppMangleState::substitute(OutBuffer *buf, void *p)
|
|
{
|
|
for (size_t i = 0; i < components.dim; i++)
|
|
{
|
|
if (p == components.data[i])
|
|
{
|
|
/* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
|
|
*/
|
|
buf->writeByte('S');
|
|
if (i)
|
|
writeBase36(buf, i - 1);
|
|
buf->writeByte('_');
|
|
return 1;
|
|
}
|
|
}
|
|
components.push(p);
|
|
return 0;
|
|
}
|
|
|
|
void source_name(OutBuffer *buf, Dsymbol *s)
|
|
{
|
|
char *name = s->ident->toChars();
|
|
buf->printf("%d%s", strlen(name), name);
|
|
}
|
|
|
|
void prefix_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s)
|
|
{
|
|
if (!cms->substitute(buf, s))
|
|
{
|
|
Dsymbol *p = s->toParent();
|
|
if (p && !p->isModule())
|
|
{
|
|
prefix_name(buf, cms, p);
|
|
}
|
|
source_name(buf, s);
|
|
}
|
|
}
|
|
|
|
void cpp_mangle_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s)
|
|
{
|
|
Dsymbol *p = s->toParent();
|
|
if (p && !p->isModule())
|
|
{
|
|
buf->writeByte('N');
|
|
|
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
|
if (fd->isConst())
|
|
buf->writeByte('K');
|
|
|
|
prefix_name(buf, cms, p);
|
|
source_name(buf, s);
|
|
|
|
buf->writeByte('E');
|
|
}
|
|
else
|
|
source_name(buf, s);
|
|
}
|
|
|
|
|
|
char *cpp_mangle(Dsymbol *s)
|
|
{
|
|
/*
|
|
* <mangled-name> ::= _Z <encoding>
|
|
* <encoding> ::= <function name> <bare-function-type>
|
|
* ::= <data name>
|
|
* ::= <special-name>
|
|
*/
|
|
|
|
CppMangleState cms;
|
|
memset(&cms, 0, sizeof(cms));
|
|
cms.components.setDim(0);
|
|
|
|
OutBuffer buf;
|
|
#if MACHOBJ
|
|
buf.writestring("__Z");
|
|
#else
|
|
buf.writestring("_Z");
|
|
#endif
|
|
|
|
cpp_mangle_name(&buf, &cms, s);
|
|
|
|
FuncDeclaration *fd = s->isFuncDeclaration();
|
|
if (fd)
|
|
{ // add <bare-function-type>
|
|
TypeFunction *tf = (TypeFunction *)fd->type;
|
|
assert(tf->ty == Tfunction);
|
|
Argument::argsCppMangle(&buf, &cms, tf->parameters, tf->varargs);
|
|
}
|
|
buf.writeByte(0);
|
|
return (char *)buf.extractData();
|
|
}
|
|
|
|
/* ============= Type Encodings ============================================= */
|
|
|
|
void Type::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
/* Make this the 'vendor extended type' when there is no
|
|
* C++ analog.
|
|
* u <source-name>
|
|
*/
|
|
if (!cms->substitute(buf, this))
|
|
{ assert(deco);
|
|
buf->printf("u%d%s", strlen(deco), deco);
|
|
}
|
|
}
|
|
|
|
void TypeBasic::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{ char c;
|
|
char p = 0;
|
|
|
|
/* 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
|
|
*/
|
|
|
|
switch (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)
|
|
{
|
|
if (cms->substitute(buf, this))
|
|
return;
|
|
buf->writeByte(p);
|
|
}
|
|
buf->writeByte(c);
|
|
}
|
|
|
|
|
|
void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
if (!cms->substitute(buf, this))
|
|
{ buf->printf("A%ju_", dim ? dim->toInteger() : 0);
|
|
next->toCppMangle(buf, cms);
|
|
}
|
|
}
|
|
|
|
void TypeDArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
Type::toCppMangle(buf, cms);
|
|
}
|
|
|
|
|
|
void TypeAArray::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
Type::toCppMangle(buf, cms);
|
|
}
|
|
|
|
|
|
void TypePointer::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
if (!cms->substitute(buf, this))
|
|
{ buf->writeByte('P');
|
|
next->toCppMangle(buf, cms);
|
|
}
|
|
}
|
|
|
|
|
|
void TypeReference::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
if (!cms->substitute(buf, this))
|
|
{ buf->writeByte('R');
|
|
next->toCppMangle(buf, cms);
|
|
}
|
|
}
|
|
|
|
|
|
void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{ /*
|
|
* <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 (!cms->substitute(buf, this))
|
|
{
|
|
buf->writeByte('F');
|
|
if (linkage == LINKc)
|
|
buf->writeByte('Y');
|
|
next->toCppMangle(buf, cms);
|
|
Argument::argsCppMangle(buf, cms, parameters, varargs);
|
|
buf->writeByte('E');
|
|
}
|
|
}
|
|
|
|
|
|
void TypeDelegate::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
Type::toCppMangle(buf, cms);
|
|
}
|
|
|
|
|
|
void TypeStruct::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
if (!cms->substitute(buf, sym))
|
|
cpp_mangle_name(buf, cms, sym);
|
|
}
|
|
|
|
|
|
void TypeEnum::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
if (!cms->substitute(buf, sym))
|
|
cpp_mangle_name(buf, cms, sym);
|
|
}
|
|
|
|
|
|
void TypeTypedef::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
Type::toCppMangle(buf, cms);
|
|
}
|
|
|
|
|
|
void TypeClass::toCppMangle(OutBuffer *buf, CppMangleState *cms)
|
|
{
|
|
if (!cms->substitute(buf, this))
|
|
{ buf->writeByte('P');
|
|
if (!cms->substitute(buf, sym))
|
|
cpp_mangle_name(buf, cms, sym);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void Argument::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Arguments *arguments, int varargs)
|
|
{ int n = 0;
|
|
if (arguments)
|
|
{
|
|
for (size_t i = 0; i < arguments->dim; i++)
|
|
{ Argument *arg = (Argument *)arguments->data[i];
|
|
Type *t = arg->type;
|
|
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();
|
|
}
|
|
t->toCppMangle(buf, cms);
|
|
|
|
n++;
|
|
}
|
|
}
|
|
if (varargs)
|
|
buf->writestring("z");
|
|
else if (!n)
|
|
buf->writeByte('v'); // encode ( ) arguments
|
|
}
|
|
|
|
|
|
#endif
|
|
|