From 68d36fe54a8066667f038b40761226fd29095aac Mon Sep 17 00:00:00 2001 From: Jacob Carlborg Date: Thu, 14 Dec 2017 17:53:39 +0100 Subject: [PATCH] Fix issue 18095 - Add support for pragma(mangle) on alias declarations This allows to override the mangling of a type in an alias declaration as follows: ```d pragma(mangle, "foo") alias foo = int; static assert(foo.mangleof == "foo"); static assert(int.mangleof == "i"); ``` Overriding the mangling of a type in an alias allows for more generic solution to get the correct mangling of `c_long/c_ulong` for C++ functions. With the current solution the compiler is looking for a struct with the name `__c_long/__c_ulong` and special cases the mangling for that particular struct. Since D doesn't have implicit conversions to structs one are also forced cast/explicitly construct a `__c_long` struct when calling a function which uses the `__c_long` type as a parameter. With an alias that's not necessary anymore. --- src/dmd/cppmangle.d | 7 +++- src/dmd/dmangle.d | 8 +++- src/dmd/dsymbolsem.d | 16 ++++--- src/dmd/expressionsem.d | 29 +++++++++---- src/dmd/mtype.d | 10 +++++ src/dmd/mtype.h | 2 + src/dmd/semantic2.d | 13 ++++++ src/dmd/typesem.d | 7 ++++ test/compilable/cppmangle.d | 37 +++++++++++++++++ test/runnable/mangle.d | 83 +++++++++++++++++++++++++++++++++++++ 10 files changed, 196 insertions(+), 16 deletions(-) diff --git a/src/dmd/cppmangle.d b/src/dmd/cppmangle.d index a66e3646fb6a..289065724e93 100644 --- a/src/dmd/cppmangle.d +++ b/src/dmd/cppmangle.d @@ -748,7 +748,12 @@ public: else { // For value types, strip const/immutable/shared from the head of the type - t.mutableOf().unSharedOf().accept(this); + auto unqualified = t.mutableOf().unSharedOf(); + + if (unqualified.mangleOverride) + buf.writestring(unqualified.mangleOverride); + else + unqualified.accept(this); } } diff --git a/src/dmd/dmangle.d b/src/dmd/dmangle.d index 0178c118003f..4b6f56fef7f4 100644 --- a/src/dmd/dmangle.d +++ b/src/dmd/dmangle.d @@ -268,7 +268,9 @@ public: final void mangleType(Type t) { - if (!backrefType(t)) + if (t.mangleOverride) + buf.writestring(t.mangleOverride); + else if (!backrefType(t)) t.accept(this); } @@ -1106,7 +1108,9 @@ extern (C++) const(char)* mangleExact(FuncDeclaration fd) extern (C++) void mangleToBuffer(Type t, OutBuffer* buf) { - if (t.deco) + if (t.mangleOverride) + buf.writestring(t.mangleOverride); + else if (t.deco) buf.writestring(t.deco); else { diff --git a/src/dmd/dsymbolsem.d b/src/dmd/dsymbolsem.d index c048b280b241..cd371dce8f3f 100644 --- a/src/dmd/dsymbolsem.d +++ b/src/dmd/dsymbolsem.d @@ -73,7 +73,7 @@ import dmd.visitor; enum LOG = false; -private uint setMangleOverride(Dsymbol s, char* sym) +private uint setMangleOverride(Dsymbol s, char* sym, Scope* sc) { AttribDeclaration ad = s.isAttribDeclaration(); if (ad) @@ -82,12 +82,16 @@ private uint setMangleOverride(Dsymbol s, char* sym) uint nestedCount = 0; if (decls && decls.dim) for (size_t i = 0; i < decls.dim; ++i) - nestedCount += setMangleOverride((*decls)[i], sym); + nestedCount += setMangleOverride((*decls)[i], sym, sc); return nestedCount; } - else if (s.isFuncDeclaration() || s.isVarDeclaration()) + else if (s.isFuncDeclaration() || s.isVarDeclaration() || s.isAliasDeclaration) { s.isDeclaration().mangleOverride = sym; + + if (s.isAliasDeclaration) + semantic2(s, sc); + return 1; } else @@ -1307,7 +1311,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(PragmaDeclaration pd) { // Should be merged with PragmaStatement - //printf("\tPragmaDeclaration::semantic '%s'\n", pd.toChars()); + //printf("PragmaDeclaration::semantic '%s'\n", pd.toChars()); if (pd.ident == Id.msg) { if (pd.args) @@ -1518,7 +1522,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor char* name = cast(char*)mem.xmalloc(se.len + 1); memcpy(name, se.string, se.len); name[se.len] = 0; - uint cnt = setMangleOverride(s, name); + uint cnt = setMangleOverride(s, name, sc2); if (cnt > 1) pd.error("can only apply to a single declaration"); } @@ -5414,7 +5418,7 @@ Laftersemantic: // function used to perform semantic on AliasDeclaration void aliasSemantic(AliasDeclaration ds, Scope* sc) { - //printf("AliasDeclaration::semantic() %s\n", toChars()); + //printf("AliasDeclaration::semantic() %s\n", ds.toChars()); if (ds.aliassym) { auto fd = ds.aliassym.isFuncLiteralDeclaration(); diff --git a/src/dmd/expressionsem.d b/src/dmd/expressionsem.d index e7dd7f81f626..bd070933d42f 100644 --- a/src/dmd/expressionsem.d +++ b/src/dmd/expressionsem.d @@ -9429,7 +9429,17 @@ extern (C++) Expression expressionSemantic(Expression e, Scope* sc) Expression semanticX(DotIdExp exp, Scope* sc) { - //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars()); + static Expression mangleToBuffer(Node)(Node node, DotIdExp exp, Scope* sc) + if (is(Node == Type) || is(Node == Dsymbol)) + { + OutBuffer buf; + .mangleToBuffer(node, &buf); + const s = buf.peekSlice(); + auto e = new StringExp(exp.loc, buf.extractString(), s.length); + return e.expressionSemantic(sc); + } + + //printf("DotIdExp::semanticX(this = %p, '%s')\n", exp, exp.toChars()); if (Expression ex = unaSemantic(exp, sc)) return ex; @@ -9455,7 +9465,17 @@ Expression semanticX(DotIdExp exp, Scope* sc) { TemplateExp te = cast(TemplateExp)exp.e1; ds = te.fd ? cast(Dsymbol)te.fd : te.td; + goto L1; } + case TOKtype: + { + auto type = (cast(TypeExp)exp.e1).type; + + if (type.mangleOverride) + return mangleToBuffer(type, exp, sc); + else + break; + } L1: { assert(ds); @@ -9466,12 +9486,7 @@ Expression semanticX(DotIdExp exp, Scope* sc) return new ErrorExp(); } } - OutBuffer buf; - mangleToBuffer(ds, &buf); - const s = buf.peekSlice(); - Expression e = new StringExp(exp.loc, buf.extractString(), s.length); - e = e.expressionSemantic(sc); - return e; + return mangleToBuffer(ds, exp, sc); } default: break; diff --git a/src/dmd/mtype.d b/src/dmd/mtype.d index 6d70558041fe..187b199c5eb9 100644 --- a/src/dmd/mtype.d +++ b/src/dmd/mtype.d @@ -512,6 +512,9 @@ extern (C++) abstract class Type : RootObject type* ctype; // for back end + /// Overridden symbol with `pragma(mangle, "...")`. + const(char)* mangleOverride; + extern (C++) static __gshared Type tvoid; extern (C++) static __gshared Type tint8; extern (C++) static __gshared Type tuns8; @@ -1052,8 +1055,15 @@ extern (C++) abstract class Type : RootObject StringValue* sv = stringtable.lookup(t.deco, strlen(t.deco)); if (sv && sv.ptrvalue) { + auto mangleOverride = t.mangleOverride; t = cast(Type)sv.ptrvalue; assert(t.deco); + + if (mangleOverride) + { + t = t.copy(); + t.mangleOverride = mangleOverride; + } } else assert(0); diff --git a/src/dmd/mtype.h b/src/dmd/mtype.h index 526efbe120a6..57910a21ed87 100644 --- a/src/dmd/mtype.h +++ b/src/dmd/mtype.h @@ -163,6 +163,8 @@ class Type : public RootObject type *ctype; // for back end + const char *mangleOverride; // overridden symbol with pragma(mangle, "...") + static Type *tvoid; static Type *tint8; static Type *tuns8; diff --git a/src/dmd/semantic2.d b/src/dmd/semantic2.d index 5dea977ef74c..bdc2a1b6d81b 100644 --- a/src/dmd/semantic2.d +++ b/src/dmd/semantic2.d @@ -357,6 +357,19 @@ private extern(C++) final class Semantic2Visitor : Visitor } } + override void visit(AliasDeclaration ad) + { + //printf("AliasDeclaration.semantic2 %s\n", ad.toChars); + + if (!ad.mangleOverride || ad.type.mangleOverride) + return; + + // make a copy to make sure the mangling of the original type isn't + // overwritten + ad.type = ad.type.copy(); + ad.type.mangleOverride = ad.mangleOverride; + } + override void visit(Import i) { //printf("Import::semantic2('%s')\n", toChars()); diff --git a/src/dmd/typesem.d b/src/dmd/typesem.d index 945a8e39a9c9..1b7af8802b37 100644 --- a/src/dmd/typesem.d +++ b/src/dmd/typesem.d @@ -1400,6 +1400,7 @@ static Type merge(Type type) StringValue* sv = type.stringtable.update(cast(char*)buf.data, buf.offset); if (sv.ptrvalue) { + auto mangleOverride = t.mangleOverride; t = cast(Type)sv.ptrvalue; debug { @@ -1409,6 +1410,12 @@ static Type merge(Type type) } assert(t.deco); //printf("old value, deco = '%s' %p\n", t.deco, t.deco); + + if (mangleOverride) + { + t = t.copy(); + t.mangleOverride = mangleOverride; + } } else { diff --git a/test/compilable/cppmangle.d b/test/compilable/cppmangle.d index c6343e90196f..647f192f655f 100644 --- a/test/compilable/cppmangle.d +++ b/test/compilable/cppmangle.d @@ -444,3 +444,40 @@ version (linux) { static assert(test36.mangleof == "_Z6test36PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPiPS12_"); } + +// test overriding mangling for alias declaration +version (Posix) extern (C++) struct TestOverridingManglingAlias +{ + version (OSX) + enum prefix = "_"; + else + enum prefix = ""; + + enum baseMangling = prefix ~ "_ZN27TestOverridingManglingAlias"; + + // basic type + + // override mangling + pragma(mangle, "bar") alias a = int; + static assert(a.mangleof == "bar"); + + // alias without overriding + alias b = int; + static assert(b.mangleof == "i"); + + // default mangling of basic type + static assert(int.mangleof == "i"); + + + + // function + + // type of parameter is an alias" + pragma(mangle, "foo") alias c = int; + void d(c); + static assert(d.mangleof == baseMangling ~ "1dEfoo"); + + // default mangling of function" + void e(int); + static assert(e.mangleof == baseMangling ~ "1eEi"); +} diff --git a/test/runnable/mangle.d b/test/runnable/mangle.d index 883d58ac07c2..6a03dcfa0157 100644 --- a/test/runnable/mangle.d +++ b/test/runnable/mangle.d @@ -589,6 +589,89 @@ void fooB(void delegate (void delegate()) scope dg) //pragma(msg, fooB.mangleof); static assert(typeof(fooA).mangleof != typeof(fooB).mangleof); +/***************************************************/ + +// test overriding mangling for alias declaration +struct TestOverridingManglingAlias +{ + enum baseMangling = "6mangle27TestOverridingManglingAlias"; + + // basic type + + // override mangling + pragma(mangle, "bar") alias a = int; + static assert(a.mangleof == "bar"); + + // alias without overriding + alias b = int; + static assert(b.mangleof == "i"); + + // default mangling of basic type + static assert(int.mangleof == "i"); + + // verify that the alias and the aliased type is the same type + pragma(mangle, "bar") alias c = int; + static assert(is(int == c)); + + // override mangling at intermediate step + alias d = int; + pragma(mangle, "foo") alias e = d; + alias f = e; + f g; + static assert(g.mangleof == "_D" ~ baseMangling ~ "1g" ~ e.mangleof); + + + + // struct + + struct Struct + { + enum defaultMangling = "S" ~ baseMangling ~"6Struct"; + } + + // override mangling + pragma(mangle, "Bar") alias h = Struct; + static assert(h.mangleof == "Bar"); + + // alias without overriding + alias i = Struct; + static assert(i.mangleof == Struct.defaultMangling); + + // default mangling of struct + static assert(Struct.mangleof == Struct.defaultMangling); + + + + // class + struct Class + { + enum defaultMangling = "S" ~ baseMangling ~ "5Class"; + } + + // override mangling + pragma(mangle, "Bar") alias j = Struct; + static assert(j.mangleof == "Bar"); + + // alias without overriding + alias k = Class; + static assert(k.mangleof == Class.defaultMangling); + + // default mangling of class + static assert(Class.mangleof == Class.defaultMangling); + + + + // function + + // type of parameter is an alias" + pragma(mangle, "foo") alias l = int; + void m(l); + static assert(m.mangleof == "_D" ~ baseMangling ~ "1mMFfooZv"); + + // default mangling of function" + void n(int); + static assert(n.mangleof == "_D" ~ baseMangling ~ "1nMFiZv"); +} /***************************************************/