Skip to content

Commit

Permalink
Fix Issue 15512 - Implement better C++ name mangling feature.
Browse files Browse the repository at this point in the history
  • Loading branch information
look-at-me committed Sep 16, 2018
1 parent 61fe641 commit d974700
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 14 deletions.
5 changes: 4 additions & 1 deletion src/dmd/astbase.d
Expand Up @@ -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)
Expand Down
19 changes: 13 additions & 6 deletions src/dmd/identifier.d
Expand Up @@ -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);
Expand Down
10 changes: 7 additions & 3 deletions src/dmd/nspace.d
Expand Up @@ -30,23 +30,27 @@ 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)
{
ScopeDsymbol.addMember(sc, sds);
if(!ignoreCppSymbols)
ScopeDsymbol.addMember(sc, sds);
if (members)
{
if (!symtab)
Expand Down
49 changes: 45 additions & 4 deletions src/dmd/parse.d
Expand Up @@ -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)
Expand Down Expand Up @@ -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_;
}
Expand Down Expand Up @@ -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_;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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");
Expand Down
25 changes: 25 additions & 0 deletions test/compilable/cppmangle3.d
@@ -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");


0 comments on commit d974700

Please sign in to comment.