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 (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); super(ident);
this.loc = loc; this.loc = loc;
this.members = members; this.members = members;
this.ignoreCppSymbols = ignoreCppSymbols;
} }
override void accept(Visitor v) override void accept(Visitor v)

View file

@ -273,15 +273,22 @@ nothrow:
*/ */
static bool isValidIdentifier(const(char)* p) static bool isValidIdentifier(const(char)* p)
{ {
size_t len;
size_t idx;
if (!p || !*p) 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 if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars
goto Linvalid; goto Linvalid;
len = strlen(p); while (idx < len)
idx = 0;
while (p[idx])
{ {
dchar dc; dchar dc;
const q = utf_decodeChar(p, len, idx, dc); const q = utf_decodeChar(p, len, idx, dc);

View file

@ -30,23 +30,27 @@ private enum LOG = false;
*/ */
extern (C++) final class Nspace : ScopeDsymbol 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); super(ident);
//printf("Nspace::Nspace(ident = %s)\n", ident.toChars()); //printf("Nspace::Nspace(ident = %s)\n", ident.toChars());
this.loc = loc; this.loc = loc;
this.members = members; this.members = members;
this.ignoreCppSymbols = ignoreCppSymbols;
} }
override Dsymbol syntaxCopy(Dsymbol s) override Dsymbol syntaxCopy(Dsymbol s)
{ {
auto ns = new Nspace(loc, ident, null); auto ns = new Nspace(loc, ident, null, ignoreCppSymbols);
return ScopeDsymbol.syntaxCopy(ns); return ScopeDsymbol.syntaxCopy(ns);
} }
override void addMember(Scope* sc, ScopeDsymbol sds) override void addMember(Scope* sc, ScopeDsymbol sds)
{ {
ScopeDsymbol.addMember(sc, sds); if(!ignoreCppSymbols)
ScopeDsymbol.addMember(sc, sds);
if (members) if (members)
{ {
if (!symtab) if (!symtab)

View file

@ -870,7 +870,8 @@ final class Parser(AST) : Lexer
const linkLoc = token.loc; const linkLoc = token.loc;
AST.Identifiers* idents = null; AST.Identifiers* idents = null;
CPPMANGLE cppmangle; 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.default_)
{ {
if (pAttrs.link != link) if (pAttrs.link != link)
@ -902,7 +903,7 @@ final class Parser(AST) : Lexer
a = new AST.Dsymbols(); a = new AST.Dsymbols();
a.push(s); a.push(s);
} }
s = new AST.Nspace(linkLoc, id, a); s = new AST.Nspace(linkLoc, id, a, ignoreCppSymbols);
} }
pAttrs.link = LINK.default_; pAttrs.link = LINK.default_;
} }
@ -2117,10 +2118,13 @@ final class Parser(AST) : Lexer
* Parse: * Parse:
* extern (linkage) * extern (linkage)
* extern (C++, namespaces) * extern (C++, namespaces)
* extern (C++, "namespace", "namespaces", ...)
* The parser is on the 'extern' token. * 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; AST.Identifiers* idents = null;
cppmangle = CPPMANGLE.def; cppmangle = CPPMANGLE.def;
LINK link = LINK.default_; LINK link = LINK.default_;
@ -2152,6 +2156,42 @@ final class Parser(AST) : Lexer
cppmangle = token.value == TOK.class_ ? CPPMANGLE.asClass : CPPMANGLE.asStruct; cppmangle = token.value == TOK.class_ ? CPPMANGLE.asClass : CPPMANGLE.asStruct;
nextToken(); 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 else
{ {
idents = new AST.Identifiers(); idents = new AST.Identifiers();
@ -4212,7 +4252,8 @@ final class Parser(AST) : Lexer
sawLinkage = true; sawLinkage = true;
AST.Identifiers* idents = null; AST.Identifiers* idents = null;
CPPMANGLE cppmangle; CPPMANGLE cppmangle;
link = parseLinkage(&idents, cppmangle); bool ignoreCppSymbols = false;
link = parseLinkage(&idents, cppmangle, ignoreCppSymbols);
if (idents) if (idents)
{ {
error("C++ name spaces not allowed here"); 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");