Fix Issue 15512 - Implement better C++ name mangling feature.

This commit is contained in:
look-at-me 2018-09-06 22:24:34 -04:00
parent 61fe641e9a
commit d9747003d4
5 changed files with 94 additions and 14 deletions

View file

@ -1159,11 +1159,14 @@ struct ASTBase
extern (C++) final class Nspace : ScopeDsymbol
{
extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* members)
bool ignoreCppSymbols;
extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* members, bool ignoreCppSymbols)
{
super(ident);
this.loc = loc;
this.members = members;
this.ignoreCppSymbols = ignoreCppSymbols;
}
override void accept(Visitor v)

View file

@ -273,15 +273,22 @@ nothrow:
*/
static bool isValidIdentifier(const(char)* p)
{
size_t len;
size_t idx;
if (!p || !*p)
goto Linvalid;
return false;
return isValidIdentifier(p[0 .. strlen(p)]);
}
/**********************************
* ditto
*/
extern (D) static bool isValidIdentifier(const(char)[] str)
{
const(char)* p = str.ptr;
size_t len = str.length;
size_t idx = 0;
if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars
goto Linvalid;
len = strlen(p);
idx = 0;
while (p[idx])
while (idx < len)
{
dchar dc;
const q = utf_decodeChar(p, len, idx, dc);

View file

@ -30,22 +30,26 @@ private enum LOG = false;
*/
extern (C++) final class Nspace : ScopeDsymbol
{
extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* members)
bool ignoreCppSymbols;
extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* members, bool ignoreCppSymbols)
{
super(ident);
//printf("Nspace::Nspace(ident = %s)\n", ident.toChars());
this.loc = loc;
this.members = members;
this.ignoreCppSymbols = ignoreCppSymbols;
}
override Dsymbol syntaxCopy(Dsymbol s)
{
auto ns = new Nspace(loc, ident, null);
auto ns = new Nspace(loc, ident, null, ignoreCppSymbols);
return ScopeDsymbol.syntaxCopy(ns);
}
override void addMember(Scope* sc, ScopeDsymbol sds)
{
if(!ignoreCppSymbols)
ScopeDsymbol.addMember(sc, sds);
if (members)
{

View file

@ -870,7 +870,8 @@ final class Parser(AST) : Lexer
const linkLoc = token.loc;
AST.Identifiers* idents = null;
CPPMANGLE cppmangle;
const link = parseLinkage(&idents, cppmangle);
bool ignoreCppSymbols = false;
const link = parseLinkage(&idents, cppmangle, ignoreCppSymbols);
if (pAttrs.link != LINK.default_)
{
if (pAttrs.link != link)
@ -902,7 +903,7 @@ final class Parser(AST) : Lexer
a = new AST.Dsymbols();
a.push(s);
}
s = new AST.Nspace(linkLoc, id, a);
s = new AST.Nspace(linkLoc, id, a, ignoreCppSymbols);
}
pAttrs.link = LINK.default_;
}
@ -2117,10 +2118,13 @@ final class Parser(AST) : Lexer
* Parse:
* extern (linkage)
* extern (C++, namespaces)
* extern (C++, "namespace", "namespaces", ...)
* The parser is on the 'extern' token.
*/
LINK parseLinkage(AST.Identifiers** pidents, out CPPMANGLE cppmangle)
LINK parseLinkage(AST.Identifiers** pidents, out CPPMANGLE cppmangle, out bool ignoreCppSymbols)
{
import std.string : toStringz;
AST.Identifiers* idents = null;
cppmangle = CPPMANGLE.def;
LINK link = LINK.default_;
@ -2152,6 +2156,42 @@ final class Parser(AST) : Lexer
cppmangle = token.value == TOK.class_ ? CPPMANGLE.asClass : CPPMANGLE.asStruct;
nextToken();
}
else if (token.value == TOK.string_) // extern(C++, "namespace", "namespaces")
{
ignoreCppSymbols = true;
idents = new AST.Identifiers();
while(1)
{
AST.StringExp stringExp = cast(AST.StringExp)parsePrimaryExp();
const(char)[] name = stringExp.toStringz();
if(name.length == 0)
{
error("invalid zero length C++ namespace");
idents = null;
break;
}
else if(!Identifier.isValidIdentifier(name))
{
error("C++ namespace `%s` is invalid", name.ptr);
idents = null;
break;
}
idents.push(Identifier.idPool(name));
if(token.value == TOK.comma)
{
nextToken();
if(token.value != TOK.string_)
{
error("string expected following `,` for C++ namespace");
idents = null;
break;
}
}
else
break;
}
}
else
{
idents = new AST.Identifiers();
@ -4212,7 +4252,8 @@ final class Parser(AST) : Lexer
sawLinkage = true;
AST.Identifiers* idents = null;
CPPMANGLE cppmangle;
link = parseLinkage(&idents, cppmangle);
bool ignoreCppSymbols = false;
link = parseLinkage(&idents, cppmangle, ignoreCppSymbols);
if (idents)
{
error("C++ name spaces not allowed here");

View file

@ -0,0 +1,25 @@
extern(C++, "true")
{
}
extern(C++, "__traits")
{
}
extern(C++, "foo")
{
}
int foo; // no name clashing with above namespace
extern(C++, "std", "chrono")
{
void func();
}
version(Windows) static assert(func.mangleof == "?func@chrono@std@@YAXXZ");
else static assert(func.mangleof == "_ZNSt6chrono4funcEv");