summaryrefslogtreecommitdiff
path: root/gcc/d/dmd/dmangle.d
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/dmangle.d')
-rw-r--r--gcc/d/dmd/dmangle.d626
1 files changed, 331 insertions, 295 deletions
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index ad305f966d4..1e6799f63a1 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -231,168 +231,19 @@ unittest
}
}
-/***********************
- * Mangle basic type ty to buf.
- */
-
-private void tyToDecoBuffer(OutBuffer* buf, int ty)
-{
- const c = mangleChar[ty];
- buf.writeByte(c);
- if (c == 'z')
- buf.writeByte(ty == Tint128 ? 'i' : 'k');
-}
-
-/*********************************
- * Mangling for mod.
- */
-private void MODtoDecoBuffer(OutBuffer* buf, MOD mod)
-{
- switch (mod)
- {
- case 0:
- break;
- case MODFlags.const_:
- buf.writeByte('x');
- break;
- case MODFlags.immutable_:
- buf.writeByte('y');
- break;
- case MODFlags.shared_:
- buf.writeByte('O');
- break;
- case MODFlags.shared_ | MODFlags.const_:
- buf.writestring("Ox");
- break;
- case MODFlags.wild:
- buf.writestring("Ng");
- break;
- case MODFlags.wildconst:
- buf.writestring("Ngx");
- break;
- case MODFlags.shared_ | MODFlags.wild:
- buf.writestring("ONg");
- break;
- case MODFlags.shared_ | MODFlags.wildconst:
- buf.writestring("ONgx");
- break;
- default:
- assert(0);
- }
-}
-
private extern (C++) final class Mangler : Visitor
{
alias visit = Visitor.visit;
public:
static assert(Key.sizeof == size_t.sizeof);
- AssocArray!(Type, size_t) types; // Type => (offset+1) in buf
- AssocArray!(Identifier, size_t) idents; // Identifier => (offset+1) in buf
+
OutBuffer* buf;
- Type rootType;
+ Backref backref;
extern (D) this(OutBuffer* buf, Type rootType = null)
{
this.buf = buf;
- this.rootType = rootType;
- }
-
- /**
- * 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');
- enum base = 26;
- size_t mul = 1;
- while (pos >= mul * base)
- mul *= base;
- while (mul >= base)
- {
- auto dig = cast(ubyte)(pos / mul);
- buf.writeByte('A' + dig);
- pos -= dig * mul;
- mul /= base;
- }
- buf.writeByte('a' + cast(ubyte)pos);
- }
-
- /**
- * Back references a non-basic type
- *
- * The encoded mangling is
- * 'Q' <relative position of first occurrence of type>
- *
- * 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())
- return false;
-
- /**
- * https://issues.dlang.org/show_bug.cgi?id=21591
- *
- * Special case for unmerged TypeFunctions: use the generic merged
- * function type as backref cache key to avoid missed backrefs.
- *
- * Merging is based on mangling, so we need to avoid an infinite
- * recursion by excluding the case where `t` is the root type passed to
- * `mangleToBuffer()`.
- */
- if (t != rootType)
- {
- if (t.isFunction_Delegate_PtrToFunction())
- {
- t = t.merge2();
- }
- }
-
- return backrefImpl(types, t);
- }
-
- /**
- * Back references a single identifier
- *
- * The encoded mangling is
- * 'Q' <relative position of first occurrence of type>
- *
- * 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)
- {
- return backrefImpl(idents, id);
- }
-
- private extern(D) bool backrefImpl(T)(ref AssocArray!(T, size_t) aa, T key)
- {
- auto p = aa.getLvalue(key);
- if (*p)
- {
- const offset = *p - 1;
- writeBackRef(buf.length - offset);
- return true;
- }
- *p = buf.length + 1;
- return false;
+ this.backref = Backref(rootType);
}
void mangleSymbol(Dsymbol s)
@@ -402,14 +253,14 @@ public:
void mangleType(Type t)
{
- if (!backrefType(t))
+ if (!backref.addRefToType(buf, t))
t.accept(this);
}
void mangleIdentifier(Identifier id, Dsymbol s)
{
- if (!backrefIdentifier(id))
- toBuffer(id.toString(), s);
+ if (!backref.addRefToIdentifier(buf, id))
+ toBuffer(buf, id.toString(), s);
}
////////////////////////////////////////////////////////////////////////////
@@ -541,7 +392,7 @@ public:
// Write argument types
foreach (idx, param; t.parameterList)
- param.accept(this);
+ mangleParameter(param);
//if (buf.data[buf.length - 1] == '@') assert(0);
buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list
if (tret !is null)
@@ -582,7 +433,7 @@ public:
//printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars());
visit(cast(Type)t);
Parameter._foreach(t.arguments, (idx, param) {
- param.accept(this);
+ mangleParameter(param);
return 0;
});
buf.writeByte('Z');
@@ -643,24 +494,8 @@ public:
else
buf.writeByte('0');
- /* There can be multiple different declarations in the same
- * function that have the same mangled name.
- * This results in localNum having a non-zero number, which
- * is used to add a fake parent of the form `__Sddd` to make
- * the mangled names unique.
- * https://issues.dlang.org/show_bug.cgi?id=20565
- */
if (localNum)
- {
- uint ndigits = 1;
- auto n = localNum;
- while (n >= 10)
- {
- n /= 10;
- ++ndigits;
- }
- buf.printf("%u__S%u", ndigits + 3, localNum);
- }
+ writeLocalParent(buf, localNum);
}
}
@@ -692,67 +527,6 @@ public:
}
}
- /************************************************************
- * Write length prefixed string to buf.
- */
- extern (D) void toBuffer(const(char)[] id, Dsymbol s)
- {
- const len = id.length;
- if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
- s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.length + len));
- else
- {
- buf.print(len);
- buf.writestring(id);
- }
- }
-
- /************************************************************
- * Try to obtain an externally mangled identifier from a declaration.
- * If the declaration is at global scope or mixed in at global scope,
- * the user might want to call it externally, so an externally mangled
- * name is returned. Member functions or nested functions can't be called
- * externally in C, so in that case null is returned. C++ does support
- * namespaces, so extern(C++) always gives a C++ mangled name.
- *
- * See also: https://issues.dlang.org/show_bug.cgi?id=20012
- *
- * Params:
- * d = declaration to mangle
- *
- * Returns:
- * an externally mangled name or null if the declaration cannot be called externally
- */
- extern (D) static const(char)[] externallyMangledIdentifier(Declaration d)
- {
- const par = d.toParent(); //toParent() skips over mixin templates
- if (!par || par.isModule() || d.linkage == LINK.cpp ||
- (d.linkage == LINK.c && d.isCsymbol() && d.isFuncDeclaration()))
- {
- if (d.linkage != LINK.d && d.localNum)
- d.error("the same declaration cannot be in multiple scopes with non-D linkage");
- final switch (d.linkage)
- {
- case LINK.d:
- break;
- case LINK.c:
- case LINK.windows:
- case LINK.objc:
- return d.ident.toString();
- case LINK.cpp:
- {
- const p = target.cpp.toMangle(d);
- return p.toDString();
- }
- case LINK.default_:
- case LINK.system:
- d.error("forward declaration");
- return d.ident.toString();
- }
- }
- return null;
- }
-
override void visit(Declaration d)
{
//printf("Declaration.mangle(this = %p, '%s', parent = '%s', linkage = %d)\n",
@@ -1009,13 +783,13 @@ public:
if (d.mangleOverride)
{
buf.writeByte('X');
- toBuffer(d.mangleOverride, d);
+ toBuffer(buf, d.mangleOverride, d);
continue;
}
if (const id = externallyMangledIdentifier(d))
{
buf.writeByte('X');
- toBuffer(id, d);
+ toBuffer(buf, id, d);
continue;
}
if (!d.type || !d.type.deco)
@@ -1052,7 +826,7 @@ public:
if (s.ident)
mangleIdentifier(s.ident, s);
else
- toBuffer(s.toString(), s);
+ toBuffer(buf, s.toString(), s);
//printf("Dsymbol.mangle() %s = %s\n", s.toChars(), id);
}
@@ -1080,68 +854,15 @@ public:
override 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
- return;
- }
-
- if (value < CTFloat.zero)
- {
- buf.writeByte('N');
- value = -value;
- }
-
- if (CTFloat.isInfinity(value))
- {
- buf.writestring("INF");
- return;
- }
-
- char[36] buffer = void;
- // 'A' format yields [-]0xh.hhhhp+-d
- const n = CTFloat.sprint(buffer.ptr, 'A', value);
- assert(n < buffer.length);
- foreach (const c; buffer[2 .. n])
- {
- switch (c)
- {
- case '-':
- buf.writeByte('N');
- break;
-
- case '+':
- case '.':
- break;
-
- default:
- buf.writeByte(c);
- break;
- }
- }
+ realToMangleBuffer(buf, e.value);
}
override void visit(ComplexExp e)
{
buf.writeByte('c');
- realToMangleBuffer(e.toReal());
+ realToMangleBuffer(buf, e.toReal());
buf.writeByte('c'); // separate the two
- realToMangleBuffer(e.toImaginary());
+ realToMangleBuffer(buf, e.toImaginary());
}
override void visit(NullExp e)
@@ -1258,7 +979,7 @@ public:
////////////////////////////////////////////////////////////////////////////
- override void visit(Parameter p)
+ void mangleParameter(Parameter p)
{
// https://dlang.org/spec/abi.html#Parameter
@@ -1331,3 +1052,318 @@ public:
visitWithMask(p.type, (stc & STC.in_) ? MODFlags.const_ : 0);
}
}
+
+/***************************************
+ * Manage back reference mangling
+ */
+private struct Backref
+{
+ /**
+ * Back references a non-basic type
+ *
+ * The encoded mangling is
+ * 'Q' <relative position of first occurrence of type>
+ *
+ * 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 addRefToType(OutBuffer* buf, Type t)
+ {
+ if (t.isTypeBasic())
+ return false;
+
+ /**
+ * https://issues.dlang.org/show_bug.cgi?id=21591
+ *
+ * Special case for unmerged TypeFunctions: use the generic merged
+ * function type as backref cache key to avoid missed backrefs.
+ *
+ * Merging is based on mangling, so we need to avoid an infinite
+ * recursion by excluding the case where `t` is the root type passed to
+ * `mangleToBuffer()`.
+ */
+ if (t != rootType)
+ {
+ if (t.isFunction_Delegate_PtrToFunction())
+ {
+ t = t.merge2();
+ }
+ }
+
+ return backrefImpl(buf, types, t);
+ }
+
+ /**
+ * Back references a single identifier
+ *
+ * The encoded mangling is
+ * 'Q' <relative position of first occurrence of type>
+ *
+ * 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 addRefToIdentifier(OutBuffer* buf, Identifier id)
+ {
+ return backrefImpl(buf, idents, id);
+ }
+
+ private:
+
+ extern(D) bool backrefImpl(T)(OutBuffer* buf, ref AssocArray!(T, size_t) aa, T key)
+ {
+ auto p = aa.getLvalue(key);
+ if (*p)
+ {
+ const offset = *p - 1;
+ writeBackRef(buf, buf.length - offset);
+ return true;
+ }
+ *p = buf.length + 1;
+ return false;
+ }
+
+ Type rootType; /// avoid infinite recursion
+ AssocArray!(Type, size_t) types; /// Type => (offset+1) in buf
+ AssocArray!(Identifier, size_t) idents; /// Identifier => (offset+1) in buf
+}
+
+
+/***********************
+ * Mangle basic type ty to buf.
+ */
+
+private void tyToDecoBuffer(OutBuffer* buf, int ty)
+{
+ const c = mangleChar[ty];
+ buf.writeByte(c);
+ if (c == 'z')
+ buf.writeByte(ty == Tint128 ? 'i' : 'k');
+}
+
+/*********************************
+ * Mangling for mod.
+ */
+private void MODtoDecoBuffer(OutBuffer* buf, MOD mod)
+{
+ switch (mod)
+ {
+ case 0:
+ break;
+ case MODFlags.const_:
+ buf.writeByte('x');
+ break;
+ case MODFlags.immutable_:
+ buf.writeByte('y');
+ break;
+ case MODFlags.shared_:
+ buf.writeByte('O');
+ break;
+ case MODFlags.shared_ | MODFlags.const_:
+ buf.writestring("Ox");
+ break;
+ case MODFlags.wild:
+ buf.writestring("Ng");
+ break;
+ case MODFlags.wildconst:
+ buf.writestring("Ngx");
+ break;
+ case MODFlags.shared_ | MODFlags.wild:
+ buf.writestring("ONg");
+ break;
+ case MODFlags.shared_ | MODFlags.wildconst:
+ buf.writestring("ONgx");
+ break;
+ default:
+ assert(0);
+ }
+}
+
+
+/**
+ * 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:
+ * buf = buffer to write to
+ * pos = relative position to encode
+ */
+private
+void writeBackRef(OutBuffer* buf, size_t pos)
+{
+ buf.writeByte('Q');
+ enum base = 26;
+ size_t mul = 1;
+ while (pos >= mul * base)
+ mul *= base;
+ while (mul >= base)
+ {
+ auto dig = cast(ubyte)(pos / mul);
+ buf.writeByte('A' + dig);
+ pos -= dig * mul;
+ mul /= base;
+ }
+ buf.writeByte('a' + cast(ubyte)pos);
+}
+
+
+/************************************************************
+ * Write length prefixed string to buf.
+ */
+private
+extern (D) void toBuffer(OutBuffer* buf, const(char)[] id, Dsymbol s)
+{
+ const len = id.length;
+ if (buf.length + len >= 8 * 1024 * 1024) // 8 megs ought be enough for anyone
+ s.error("excessive length %llu for symbol, possible recursive expansion?", cast(ulong)(buf.length + len));
+ else
+ {
+ buf.print(len);
+ buf.writestring(id);
+ }
+}
+
+
+/*****
+ * There can be multiple different declarations in the same
+ * function that have the same mangled name.
+ * This results in localNum having a non-zero number, which
+ * is used to add a fake parent of the form `__Sddd` to make
+ * the mangled names unique.
+ * https://issues.dlang.org/show_bug.cgi?id=20565
+ * Params:
+ * buf = buffer to write to
+ * localNum = local symbol number
+ */
+private
+void writeLocalParent(OutBuffer* buf, uint localNum)
+{
+ uint ndigits = 1;
+ auto n = localNum;
+ while (n >= 10)
+ {
+ n /= 10;
+ ++ndigits;
+ }
+ buf.printf("%u__S%u", ndigits + 3, localNum);
+}
+
+/*************************
+ * Write real to buffer.
+ * Params:
+ * buf = buffer to write to
+ * value = real to write
+ */
+private
+void realToMangleBuffer(OutBuffer* buf, 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
+ return;
+ }
+
+ if (value < CTFloat.zero)
+ {
+ buf.writeByte('N');
+ value = -value;
+ }
+
+ if (CTFloat.isInfinity(value))
+ {
+ buf.writestring("INF");
+ return;
+ }
+
+ char[36] buffer = void;
+ // 'A' format yields [-]0xh.hhhhp+-d
+ const n = CTFloat.sprint(buffer.ptr, 'A', value);
+ assert(n < buffer.length);
+ foreach (const c; buffer[2 .. n])
+ {
+ switch (c)
+ {
+ case '-':
+ buf.writeByte('N');
+ break;
+
+ case '+':
+ case '.':
+ break;
+
+ default:
+ buf.writeByte(c);
+ break;
+ }
+ }
+}
+
+/************************************************************
+ * Try to obtain an externally mangled identifier from a declaration.
+ * If the declaration is at global scope or mixed in at global scope,
+ * the user might want to call it externally, so an externally mangled
+ * name is returned. Member functions or nested functions can't be called
+ * externally in C, so in that case null is returned. C++ does support
+ * namespaces, so extern(C++) always gives a C++ mangled name.
+ *
+ * See also: https://issues.dlang.org/show_bug.cgi?id=20012
+ *
+ * Params:
+ * d = declaration to mangle
+ *
+ * Returns:
+ * an externally mangled name or null if the declaration cannot be called externally
+ */
+private
+extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
+{
+ const par = d.toParent(); //toParent() skips over mixin templates
+ if (!par || par.isModule() || d.linkage == LINK.cpp ||
+ (d.linkage == LINK.c && d.isCsymbol() && d.isFuncDeclaration()))
+ {
+ if (d.linkage != LINK.d && d.localNum)
+ d.error("the same declaration cannot be in multiple scopes with non-D linkage");
+ final switch (d.linkage)
+ {
+ case LINK.d:
+ break;
+ case LINK.c:
+ case LINK.windows:
+ case LINK.objc:
+ return d.ident.toString();
+ case LINK.cpp:
+ {
+ const p = target.cpp.toMangle(d);
+ return p.toDString();
+ }
+ case LINK.default_:
+ case LINK.system:
+ d.error("forward declaration");
+ return d.ident.toString();
+ }
+ }
+ return null;
+}
+
+