diff --git a/src/ddmd/cppmangle.d b/src/ddmd/cppmangle.d index 210a424da1..45d3a4f860 100644 --- a/src/ddmd/cppmangle.d +++ b/src/ddmd/cppmangle.d @@ -37,657 +37,804 @@ import ddmd.visitor; * ABI has no concept of. These affect every D mangled name, * so nothing would be compatible anyway. */ -static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) + +/* + * Follows Itanium C++ ABI 1.86 + */ +extern (C++) final class CppMangleVisitor : Visitor { - /* - * Follows Itanium C++ ABI 1.86 - */ - extern (C++) final class CppMangleVisitor : Visitor + alias visit = super.visit; + Objects components; + OutBuffer buf; + bool is_top_level; + bool components_on; + + void writeBase36(size_t i) { - alias visit = super.visit; - Objects components; - OutBuffer buf; - bool is_top_level; - bool components_on; - - void writeBase36(size_t i) + if (i >= 36) { - if (i >= 36) + writeBase36(i / 36); + i %= 36; + } + if (i < 10) + buf.writeByte(cast(char)(i + '0')); + else if (i < 36) + buf.writeByte(cast(char)(i - 10 + 'A')); + else + assert(0); + } + + bool substitute(RootObject p) + { + //printf("substitute %s\n", p ? p.toChars() : null); + if (components_on) + for (size_t i = 0; i < components.dim; i++) { - writeBase36(i / 36); - i %= 36; - } - if (i < 10) - buf.writeByte(cast(char)(i + '0')); - else if (i < 36) - buf.writeByte(cast(char)(i - 10 + 'A')); - else - assert(0); - } - - bool substitute(RootObject p) - { - //printf("substitute %s\n", p ? p.toChars() : null); - if (components_on) - for (size_t i = 0; i < components.dim; i++) + //printf(" component[%d] = %s\n", i, components[i] ? components[i].toChars() : null); + if (p == components[i]) { - //printf(" component[%d] = %s\n", i, components[i] ? components[i].toChars() : null); - if (p == components[i]) - { - //printf("\tmatch\n"); - /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... - */ - buf.writeByte('S'); - if (i) - writeBase36(i - 1); - buf.writeByte('_'); - return true; - } - } - return false; - } - - bool exist(RootObject p) - { - //printf("exist %s\n", p ? p.toChars() : null); - if (components_on) - for (size_t i = 0; i < components.dim; i++) - { - if (p == components[i]) - { - return true; - } - } - return false; - } - - void store(RootObject p) - { - //printf("store %s\n", p ? p.toChars() : "null"); - if (components_on) - components.push(p); - } - - void source_name(Dsymbol s, bool skipname = false) - { - //printf("source_name(%s)\n", s.toChars()); - TemplateInstance ti = s.isTemplateInstance(); - if (ti) - { - if (!skipname && !substitute(ti.tempdecl)) - { - store(ti.tempdecl); - const(char)* name = ti.tempdecl.toAlias().ident.toChars(); - buf.printf("%d%s", strlen(name), name); - } - buf.writeByte('I'); - bool is_var_arg = false; - for (size_t i = 0; i < ti.tiargs.dim; i++) - { - RootObject o = cast(RootObject)(*ti.tiargs)[i]; - TemplateParameter tp = null; - TemplateValueParameter tv = null; - TemplateTupleParameter tt = null; - if (!is_var_arg) - { - TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); - assert(td); - tp = (*td.parameters)[i]; - tv = tp.isTemplateValueParameter(); - tt = tp.isTemplateTupleParameter(); - } - /* - * ::= # type or template - * ::= # simple expressions + //printf("\tmatch\n"); + /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... */ - if (tt) - { - buf.writeByte('I'); - is_var_arg = true; - tp = null; - } - if (tv) - { - // ::= L E # integer literal - if (tv.valType.isintegral()) - { - Expression e = isExpression(o); - assert(e); - buf.writeByte('L'); - tv.valType.accept(this); - if (tv.valType.isunsigned()) - { - buf.printf("%llu", e.toUInteger()); - } - else - { - sinteger_t val = e.toInteger(); - if (val < 0) - { - val = -val; - buf.writeByte('n'); - } - buf.printf("%lld", val); - } - buf.writeByte('E'); - } - else - { - s.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); - fatal(); - } - } - else if (!tp || tp.isTemplateTypeParameter()) - { - Type t = isType(o); - assert(t); - t.accept(this); - } - else if (tp.isTemplateAliasParameter()) - { - Dsymbol d = isDsymbol(o); - Expression e = isExpression(o); - if (!d && !e) - { - s.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); - fatal(); - } - if (d && d.isFuncDeclaration()) - { - bool is_nested = d.toParent() && !d.toParent().isModule() && (cast(TypeFunction)d.isFuncDeclaration().type).linkage == LINKcpp; - if (is_nested) - buf.writeByte('X'); - buf.writeByte('L'); - mangle_function(d.isFuncDeclaration()); - buf.writeByte('E'); - if (is_nested) - buf.writeByte('E'); - } - else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) - { - VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); - buf.writeByte('L'); - mangle_variable(vd, true); - buf.writeByte('E'); - } - else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) - { - if (!substitute(d)) - { - cpp_mangle_name(d, false); - } - } - else - { - s.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); - fatal(); - } - } - else - { - s.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); - fatal(); - } + buf.writeByte('S'); + if (i) + writeBase36(i - 1); + buf.writeByte('_'); + return true; } - if (is_var_arg) - { - buf.writeByte('E'); - } - buf.writeByte('E'); - return; } - else - { - const(char)* name = s.ident.toChars(); - buf.printf("%d%s", strlen(name), name); - } - } + return false; + } - void prefix_name(Dsymbol s) - { - //printf("prefix_name(%s)\n", s.toChars()); - if (!substitute(s)) + bool exist(RootObject p) + { + //printf("exist %s\n", p ? p.toChars() : null); + if (components_on) + for (size_t i = 0; i < components.dim; i++) { - Dsymbol p = s.toParent(); - if (p && p.isTemplateInstance()) - { - s = p; - if (exist(p.isTemplateInstance().tempdecl)) - { - p = null; - } - else - { - p = p.toParent(); - } - } - if (p && !p.isModule()) - { - if (p.ident == Id.std && is_initial_qualifier(p)) - buf.writestring("St"); - else - prefix_name(p); - } - if (!(s.ident == Id.std && is_initial_qualifier(s))) - store(s); - source_name(s); - } - } - - /* Is s the initial qualifier? - */ - bool is_initial_qualifier(Dsymbol s) - { - Dsymbol p = s.toParent(); - if (p && p.isTemplateInstance()) - { - if (exist(p.isTemplateInstance().tempdecl)) + if (p == components[i]) { return true; } - p = p.toParent(); } - return !p || p.isModule(); - } + return false; + } - void cpp_mangle_name(Dsymbol s, bool qualified) + void store(RootObject p) + { + //printf("store %s\n", p ? p.toChars() : "null"); + if (components_on) + components.push(p); + } + + void source_name(Dsymbol s, bool skipname = false) + { + //printf("source_name(%s)\n", s.toChars()); + TemplateInstance ti = s.isTemplateInstance(); + if (ti) { - //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); - Dsymbol p = s.toParent(); - Dsymbol se = s; - bool dont_write_prefix = false; - if (p && p.isTemplateInstance()) + if (!skipname && !substitute(ti.tempdecl)) { - se = p; - if (exist(p.isTemplateInstance().tempdecl)) - dont_write_prefix = true; - p = p.toParent(); + store(ti.tempdecl); + const(char)* name = ti.tempdecl.toAlias().ident.toChars(); + buf.printf("%d%s", strlen(name), name); } - if (p && !p.isModule()) + buf.writeByte('I'); + bool is_var_arg = false; + for (size_t i = 0; i < ti.tiargs.dim; i++) { - /* The N..E is not required if: - * 1. the parent is 'std' - * 2. 'std' is the initial qualifier - * 3. there is no CV-qualifier or a ref-qualifier for a member function - * ABI 5.1.8 - */ - if (p.ident == Id.std && is_initial_qualifier(p) && !qualified) + RootObject o = cast(RootObject)(*ti.tiargs)[i]; + TemplateParameter tp = null; + TemplateValueParameter tv = null; + TemplateTupleParameter tt = null; + if (!is_var_arg) { - if (s.ident == Id.allocator) + TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); + assert(td); + tp = (*td.parameters)[i]; + tv = tp.isTemplateValueParameter(); + tt = tp.isTemplateTupleParameter(); + } + /* + * ::= # type or template + * ::= # simple expressions + */ + if (tt) + { + buf.writeByte('I'); + is_var_arg = true; + tp = null; + } + if (tv) + { + // ::= L E # integer literal + if (tv.valType.isintegral()) { - buf.writestring("Sa"); // "Sa" is short for ::std::allocator - source_name(se, true); - } - else if (s.ident == Id.basic_string) - { - components_on = false; // turn off substitutions - buf.writestring("Sb"); // "Sb" is short for ::std::basic_string - size_t off = buf.offset; - source_name(se, true); - components_on = true; - // Replace ::std::basic_string < char, ::std::char_traits, ::std::allocator > - // with Ss - //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); - if (buf.offset - off >= 26 && memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE".ptr, 26) == 0) + Expression e = isExpression(o); + assert(e); + buf.writeByte('L'); + tv.valType.accept(this); + if (tv.valType.isunsigned()) { - buf.remove(off - 2, 28); - buf.insert(off - 2, "Ss"); - return; + buf.printf("%llu", e.toUInteger()); } - buf.setsize(off); - source_name(se, true); - } - else if (s.ident == Id.basic_istream || s.ident == Id.basic_ostream || s.ident == Id.basic_iostream) - { - /* Replace - * ::std::basic_istream > with Si - * ::std::basic_ostream > with So - * ::std::basic_iostream > with Sd - */ - size_t off = buf.offset; - components_on = false; // turn off substitutions - source_name(se, true); - components_on = true; - //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); - if (buf.offset - off >= 21 && memcmp(buf.data + off, "IcSt11char_traitsIcEE".ptr, 21) == 0) + else { - buf.remove(off, 21); - char[2] mbuf; - mbuf[0] = 'S'; - mbuf[1] = 'i'; - if (s.ident == Id.basic_ostream) - mbuf[1] = 'o'; - else if (s.ident == Id.basic_iostream) - mbuf[1] = 'd'; - buf.insert(off, mbuf[]); - return; + sinteger_t val = e.toInteger(); + if (val < 0) + { + val = -val; + buf.writeByte('n'); + } + buf.printf("%lld", val); } - buf.setsize(off); - buf.writestring("St"); - source_name(se); + buf.writeByte('E'); } else { - buf.writestring("St"); - source_name(se); + s.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); + fatal(); + } + } + else if (!tp || tp.isTemplateTypeParameter()) + { + Type t = isType(o); + assert(t); + t.accept(this); + } + else if (tp.isTemplateAliasParameter()) + { + Dsymbol d = isDsymbol(o); + Expression e = isExpression(o); + if (!d && !e) + { + s.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); + fatal(); + } + if (d && d.isFuncDeclaration()) + { + bool is_nested = d.toParent() && !d.toParent().isModule() && (cast(TypeFunction)d.isFuncDeclaration().type).linkage == LINKcpp; + if (is_nested) + buf.writeByte('X'); + buf.writeByte('L'); + mangle_function(d.isFuncDeclaration()); + buf.writeByte('E'); + if (is_nested) + buf.writeByte('E'); + } + else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) + { + VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); + buf.writeByte('L'); + mangle_variable(vd, true); + buf.writeByte('E'); + } + else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) + { + if (!substitute(d)) + { + cpp_mangle_name(d, false); + } + } + else + { + s.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); + fatal(); } } else { - buf.writeByte('N'); - if (!dont_write_prefix) - prefix_name(p); - source_name(se); - buf.writeByte('E'); + s.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + fatal(); } } - else - source_name(se); - store(s); - } - - void mangle_variable(VarDeclaration d, bool is_temp_arg_ref) - { - // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 - if (!(d.storage_class & (STCextern | STCfield | STCgshared))) + if (is_var_arg) { - d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); - fatal(); - } - Dsymbol p = d.toParent(); - if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" - { - buf.writestring("_ZN"); - prefix_name(p); - source_name(d); buf.writeByte('E'); } - else //char beta[6] should mangle as "beta" + buf.writeByte('E'); + return; + } + else + { + const(char)* name = s.ident.toChars(); + buf.printf("%d%s", strlen(name), name); + } + } + + void prefix_name(Dsymbol s) + { + //printf("prefix_name(%s)\n", s.toChars()); + if (!substitute(s)) + { + Dsymbol p = s.toParent(); + if (p && p.isTemplateInstance()) { - if (!is_temp_arg_ref) + s = p; + if (exist(p.isTemplateInstance().tempdecl)) { - buf.writestring(d.ident.toChars()); + p = null; } else { - buf.writestring("_Z"); - source_name(d); + p = p.toParent(); } } + if (p && !p.isModule()) + { + if (p.ident == Id.std && is_initial_qualifier(p)) + buf.writestring("St"); + else + prefix_name(p); + } + if (!(s.ident == Id.std && is_initial_qualifier(s))) + store(s); + source_name(s); } + } - void mangle_function(FuncDeclaration d) + /* Is s the initial qualifier? + */ + bool is_initial_qualifier(Dsymbol s) + { + Dsymbol p = s.toParent(); + if (p && p.isTemplateInstance()) { - //printf("mangle_function(%s)\n", d.toChars()); - /* - * ::= _Z - * ::= - * ::= - * ::= - */ - TypeFunction tf = cast(TypeFunction)d.type; - buf.writestring("_Z"); - Dsymbol p = d.toParent(); - TemplateDeclaration ftd = getFuncTemplateDecl(d); + if (exist(p.isTemplateInstance().tempdecl)) + { + return true; + } + p = p.toParent(); + } + return !p || p.isModule(); + } - if (p && !p.isModule() && tf.linkage == LINKcpp && !ftd) + void cpp_mangle_name(Dsymbol s, bool qualified) + { + //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); + Dsymbol p = s.toParent(); + Dsymbol se = s; + bool dont_write_prefix = false; + if (p && p.isTemplateInstance()) + { + se = p; + if (exist(p.isTemplateInstance().tempdecl)) + dont_write_prefix = true; + p = p.toParent(); + } + if (p && !p.isModule()) + { + /* The N..E is not required if: + * 1. the parent is 'std' + * 2. 'std' is the initial qualifier + * 3. there is no CV-qualifier or a ref-qualifier for a member function + * ABI 5.1.8 + */ + if (p.ident == Id.std && is_initial_qualifier(p) && !qualified) + { + if (s.ident == Id.allocator) + { + buf.writestring("Sa"); // "Sa" is short for ::std::allocator + source_name(se, true); + } + else if (s.ident == Id.basic_string) + { + components_on = false; // turn off substitutions + buf.writestring("Sb"); // "Sb" is short for ::std::basic_string + size_t off = buf.offset; + source_name(se, true); + components_on = true; + // Replace ::std::basic_string < char, ::std::char_traits, ::std::allocator > + // with Ss + //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); + if (buf.offset - off >= 26 && memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE".ptr, 26) == 0) + { + buf.remove(off - 2, 28); + buf.insert(off - 2, "Ss"); + return; + } + buf.setsize(off); + source_name(se, true); + } + else if (s.ident == Id.basic_istream || s.ident == Id.basic_ostream || s.ident == Id.basic_iostream) + { + /* Replace + * ::std::basic_istream > with Si + * ::std::basic_ostream > with So + * ::std::basic_iostream > with Sd + */ + size_t off = buf.offset; + components_on = false; // turn off substitutions + source_name(se, true); + components_on = true; + //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); + if (buf.offset - off >= 21 && memcmp(buf.data + off, "IcSt11char_traitsIcEE".ptr, 21) == 0) + { + buf.remove(off, 21); + char[2] mbuf; + mbuf[0] = 'S'; + mbuf[1] = 'i'; + if (s.ident == Id.basic_ostream) + mbuf[1] = 'o'; + else if (s.ident == Id.basic_iostream) + mbuf[1] = 'd'; + buf.insert(off, mbuf[]); + return; + } + buf.setsize(off); + buf.writestring("St"); + source_name(se); + } + else + { + buf.writestring("St"); + source_name(se); + } + } + else { buf.writeByte('N'); - if (d.type.isConst()) - buf.writeByte('K'); - prefix_name(p); - // See ABI 5.1.8 Compression - // Replace ::std::allocator with Sa - if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator".ptr, 17) == 0) - { - buf.remove(3, 14); - buf.insert(3, "Sa"); - } - // Replace ::std::basic_string with Sb - if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string".ptr, 21) == 0) - { - buf.remove(3, 18); - buf.insert(3, "Sb"); - } - // Replace ::std with St - if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std".ptr, 7) == 0) - { - buf.remove(3, 4); - buf.insert(3, "St"); - } - if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std".ptr, 8) == 0) - { - buf.remove(4, 4); - buf.insert(4, "St"); - } - if (d.isDtorDeclaration()) - { - buf.writestring("D1"); - } - else - { - source_name(d); - } + if (!dont_write_prefix) + prefix_name(p); + source_name(se); buf.writeByte('E'); } - else if (ftd) + } + else + source_name(se); + store(s); + } + + void mangle_variable(VarDeclaration d, bool is_temp_arg_ref) + { + // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 + if (!(d.storage_class & (STCextern | STCfield | STCgshared))) + { + d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); + fatal(); + } + Dsymbol p = d.toParent(); + if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" + { + buf.writestring("_ZN"); + prefix_name(p); + source_name(d); + buf.writeByte('E'); + } + else //char beta[6] should mangle as "beta" + { + if (!is_temp_arg_ref) { - source_name(p); - this.is_top_level = true; - tf.nextOf().accept(this); - this.is_top_level = false; + buf.writestring(d.ident.toChars()); + } + else + { + buf.writestring("_Z"); + source_name(d); + } + } + } + + void mangle_function(FuncDeclaration d) + { + //printf("mangle_function(%s)\n", d.toChars()); + /* + * ::= _Z + * ::= + * ::= + * ::= + */ + TypeFunction tf = cast(TypeFunction)d.type; + buf.writestring("_Z"); + Dsymbol p = d.toParent(); + TemplateDeclaration ftd = getFuncTemplateDecl(d); + + if (p && !p.isModule() && tf.linkage == LINKcpp && !ftd) + { + buf.writeByte('N'); + if (d.type.isConst()) + buf.writeByte('K'); + prefix_name(p); + // See ABI 5.1.8 Compression + // Replace ::std::allocator with Sa + if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator".ptr, 17) == 0) + { + buf.remove(3, 14); + buf.insert(3, "Sa"); + } + // Replace ::std::basic_string with Sb + if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string".ptr, 21) == 0) + { + buf.remove(3, 18); + buf.insert(3, "Sb"); + } + // Replace ::std with St + if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std".ptr, 7) == 0) + { + buf.remove(3, 4); + buf.insert(3, "St"); + } + if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std".ptr, 8) == 0) + { + buf.remove(4, 4); + buf.insert(4, "St"); + } + if (d.isDtorDeclaration()) + { + buf.writestring("D1"); } else { source_name(d); } - if (tf.linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling - { - assert(tf.ty == Tfunction); - argsCppMangle(tf.parameters, tf.varargs); - } + buf.writeByte('E'); } - - void argsCppMangle(Parameters* parameters, int varargs) + else if (ftd) { - int paramsCppMangleDg(size_t n, Parameter fparam) - { - Type t = fparam.type.merge2(); - if (fparam.storageClass & (STCout | STCref)) - t = t.referenceTo(); - else if (fparam.storageClass & STClazy) - { - // Mangle as delegate - Type td = new TypeFunction(null, t, 0, LINKd); - td = new TypeDelegate(td); - t = t.merge(); - } - if (t.ty == Tsarray) - { - // Mangle static arrays as pointers - t.error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function."); - t.error(Loc(), "Use pointer instead."); - fatal(); - //t = t.nextOf().pointerTo(); - } - /* If it is a basic, enum or struct type, - * then don't mark it const - */ - this.is_top_level = true; - if ((t.ty == Tenum || t.ty == Tstruct || t.ty == Tpointer || t.isTypeBasic()) && t.isConst()) - t.mutableOf().accept(this); - else - t.accept(this); - this.is_top_level = false; - return 0; - } - - if (parameters) - Parameter._foreach(parameters, ¶msCppMangleDg); - if (varargs) - buf.writestring("z"); - else if (!parameters || !parameters.dim) - buf.writeByte('v'); // encode ( ) parameters + source_name(p); + this.is_top_level = true; + tf.nextOf().accept(this); + this.is_top_level = false; } - - public: - extern (D) this() + else { - this.components_on = true; + source_name(d); } - - const(char)* mangleOf(Dsymbol s) + if (tf.linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling { - VarDeclaration vd = s.isVarDeclaration(); - FuncDeclaration fd = s.isFuncDeclaration(); - if (vd) - { - mangle_variable(vd, false); - } - else if (fd) - { - mangle_function(fd); - } - else - { - assert(0); - } - Target.prefixName(&buf, LINKcpp); - return buf.extractString(); + assert(tf.ty == Tfunction); + argsCppMangle(tf.parameters, tf.varargs); } + } - override void visit(Type t) + void argsCppMangle(Parameters* parameters, int varargs) + { + int paramsCppMangleDg(size_t n, Parameter fparam) { - if (t.isImmutable() || t.isShared()) + Type t = fparam.type.merge2(); + if (fparam.storageClass & (STCout | STCref)) + t = t.referenceTo(); + else if (fparam.storageClass & STClazy) { - t.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", t.toChars()); + // Mangle as delegate + Type td = new TypeFunction(null, t, 0, LINKd); + td = new TypeDelegate(td); + t = t.merge(); } - else + if (t.ty == Tsarray) { - t.error(Loc(), "Internal Compiler Error: unsupported type %s\n", t.toChars()); + // Mangle static arrays as pointers + t.error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function."); + t.error(Loc(), "Use pointer instead."); + fatal(); + //t = t.nextOf().pointerTo(); } - fatal(); //Fatal, because this error should be handled in frontend - } - - override void visit(TypeBasic t) - { - /* ABI spec says: - * v void - * w wchar_t - * b bool - * c char - * a signed char - * h unsigned char - * s short - * t unsigned short - * i int - * j unsigned int - * l long - * m unsigned long - * x long long, __int64 - * y unsigned long long, __int64 - * n __int128 - * o unsigned __int128 - * f float - * d double - * e long double, __float80 - * g __float128 - * z ellipsis - * u # vendor extended type + /* If it is a basic, enum or struct type, + * then don't mark it const */ - char c; - char p = 0; - switch (t.ty) + this.is_top_level = true; + if ((t.ty == Tenum || t.ty == Tstruct || t.ty == Tpointer || t.isTypeBasic()) && t.isConst()) + t.mutableOf().accept(this); + else + t.accept(this); + this.is_top_level = false; + return 0; + } + + if (parameters) + Parameter._foreach(parameters, ¶msCppMangleDg); + if (varargs) + buf.writestring("z"); + else if (!parameters || !parameters.dim) + buf.writeByte('v'); // encode ( ) parameters + } + +public: + extern (D) this() + { + this.components_on = true; + } + + const(char)* mangleOf(Dsymbol s) + { + VarDeclaration vd = s.isVarDeclaration(); + FuncDeclaration fd = s.isFuncDeclaration(); + if (vd) + { + mangle_variable(vd, false); + } + else if (fd) + { + mangle_function(fd); + } + else + { + assert(0); + } + Target.prefixName(&buf, LINKcpp); + return buf.extractString(); + } + + override void visit(Type t) + { + if (t.isImmutable() || t.isShared()) + { + t.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", t.toChars()); + } + else + { + t.error(Loc(), "Internal Compiler Error: unsupported type %s\n", t.toChars()); + } + fatal(); //Fatal, because this error should be handled in frontend + } + + override void visit(TypeBasic t) + { + /* ABI spec says: + * v void + * w wchar_t + * b bool + * c char + * a signed char + * h unsigned char + * s short + * t unsigned short + * i int + * j unsigned int + * l long + * m unsigned long + * x long long, __int64 + * y unsigned long long, __int64 + * n __int128 + * o unsigned __int128 + * f float + * d double + * e long double, __float80 + * g __float128 + * z ellipsis + * u # vendor extended type + */ + char c; + char p = 0; + switch (t.ty) + { + case Tvoid: + c = 'v'; + break; + case Tint8: + c = 'a'; + break; + case Tuns8: + c = 'h'; + break; + case Tint16: + c = 's'; + break; + case Tuns16: + c = 't'; + break; + case Tint32: + c = 'i'; + break; + case Tuns32: + c = 'j'; + break; + case Tfloat32: + c = 'f'; + break; + case Tint64: + c = (Target.c_longsize == 8 ? 'l' : 'x'); + break; + case Tuns64: + c = (Target.c_longsize == 8 ? 'm' : 'y'); + break; + case Tint128: + c = 'n'; + break; + case Tuns128: + c = 'o'; + break; + case Tfloat64: + c = 'd'; + break; + case Tfloat80: + c = Target.realislongdouble ? 'e' : 'g'; + break; + case Tbool: + c = 'b'; + break; + case Tchar: + c = 'c'; + break; + case Twchar: + c = 't'; + break; + // unsigned short + case Tdchar: + c = 'w'; + break; + // wchar_t (UTF-32) + case Timaginary32: + p = 'G'; + c = 'f'; + break; + case Timaginary64: + p = 'G'; + c = 'd'; + break; + case Timaginary80: + p = 'G'; + c = 'e'; + break; + case Tcomplex32: + p = 'C'; + c = 'f'; + break; + case Tcomplex64: + p = 'C'; + c = 'd'; + break; + case Tcomplex80: + p = 'C'; + c = 'e'; + break; + default: + visit(cast(Type)t); + return; + } + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); + } + if (p || t.isConst()) + { + if (substitute(t)) { - case Tvoid: - c = 'v'; - break; - case Tint8: - c = 'a'; - break; - case Tuns8: - c = 'h'; - break; - case Tint16: - c = 's'; - break; - case Tuns16: - c = 't'; - break; - case Tint32: - c = 'i'; - break; - case Tuns32: - c = 'j'; - break; - case Tfloat32: - c = 'f'; - break; - case Tint64: - c = (Target.c_longsize == 8 ? 'l' : 'x'); - break; - case Tuns64: - c = (Target.c_longsize == 8 ? 'm' : 'y'); - break; - case Tint128: - c = 'n'; - break; - case Tuns128: - c = 'o'; - break; - case Tfloat64: - c = 'd'; - break; - case Tfloat80: - c = Target.realislongdouble ? 'e' : 'g'; - break; - case Tbool: - c = 'b'; - break; - case Tchar: - c = 'c'; - break; - case Twchar: - c = 't'; - break; - // unsigned short - case Tdchar: - c = 'w'; - break; - // wchar_t (UTF-32) - case Timaginary32: - p = 'G'; - c = 'f'; - break; - case Timaginary64: - p = 'G'; - c = 'd'; - break; - case Timaginary80: - p = 'G'; - c = 'e'; - break; - case Tcomplex32: - p = 'C'; - c = 'f'; - break; - case Tcomplex64: - p = 'C'; - c = 'd'; - break; - case Tcomplex80: - p = 'C'; - c = 'e'; - break; - default: - visit(cast(Type)t); return; } + else + { + store(t); + } + } + if (t.isConst()) + buf.writeByte('K'); + if (p) + buf.writeByte(p); + buf.writeByte(c); + } + + override void visit(TypeVector t) + { + is_top_level = false; + if (substitute(t)) + return; + store(t); + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); + } + if (t.isConst()) + buf.writeByte('K'); + assert(t.basetype && t.basetype.ty == Tsarray); + assert((cast(TypeSArray)t.basetype).dim); + //buf.printf("Dv%llu_", ((TypeSArray *)t.basetype).dim.toInteger());// -- Gnu ABI v.4 + buf.writestring("U8__vector"); //-- Gnu ABI v.3 + t.basetype.nextOf().accept(this); + } + + override void visit(TypeSArray t) + { + is_top_level = false; + if (!substitute(t)) + store(t); + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); + } + if (t.isConst()) + buf.writeByte('K'); + buf.printf("A%llu_", t.dim ? t.dim.toInteger() : 0); + t.next.accept(this); + } + + override void visit(TypeDArray t) + { + visit(cast(Type)t); + } + + override void visit(TypeAArray t) + { + visit(cast(Type)t); + } + + override void visit(TypePointer t) + { + is_top_level = false; + if (substitute(t)) + return; + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); + } + if (t.isConst()) + buf.writeByte('K'); + buf.writeByte('P'); + t.next.accept(this); + store(t); + } + + override void visit(TypeReference t) + { + is_top_level = false; + if (substitute(t)) + return; + buf.writeByte('R'); + t.next.accept(this); + store(t); + } + + override void visit(TypeFunction t) + { + is_top_level = false; + /* + * ::= F [Y] E + * ::= + + * # types are possible return type, then parameter types + */ + /* ABI says: + "The type of a non-static member function is considered to be different, + for the purposes of substitution, from the type of a namespace-scope or + static member function whose type appears similar. The types of two + non-static member functions are considered to be different, for the + purposes of substitution, if the functions are members of different + classes. In other words, for the purposes of substitution, the class of + which the function is a member is considered part of the type of + function." + + BUG: Right now, types of functions are never merged, so our simplistic + component matcher always finds them to be different. + We should use Type.equals on these, and use different + TypeFunctions for non-static member functions, and non-static + member functions of different classes. + */ + if (substitute(t)) + return; + buf.writeByte('F'); + if (t.linkage == LINKc) + buf.writeByte('Y'); + Type tn = t.next; + if (t.isref) + tn = tn.referenceTo(); + tn.accept(this); + argsCppMangle(t.parameters, t.varargs); + buf.writeByte('E'); + store(t); + } + + override void visit(TypeDelegate t) + { + visit(cast(Type)t); + } + + override void visit(TypeStruct t) + { + const id = t.sym.ident; + //printf("struct id = '%s'\n", id.toChars()); + char c; + if (id == Id.__c_long) + c = 'l'; + else if (id == Id.__c_ulong) + c = 'm'; + else + c = 0; + if (c) + { if (t.isImmutable() || t.isShared()) { visit(cast(Type)t); } - if (p || t.isConst()) + if (t.isConst()) { if (substitute(t)) { @@ -700,311 +847,418 @@ static if (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TAR } if (t.isConst()) buf.writeByte('K'); - if (p) - buf.writeByte(p); buf.writeByte(c); + return; } - - override void visit(TypeVector t) - { - is_top_level = false; - if (substitute(t)) - return; - store(t); - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - assert(t.basetype && t.basetype.ty == Tsarray); - assert((cast(TypeSArray)t.basetype).dim); - //buf.printf("Dv%llu_", ((TypeSArray *)t.basetype).dim.toInteger());// -- Gnu ABI v.4 - buf.writestring("U8__vector"); //-- Gnu ABI v.3 - t.basetype.nextOf().accept(this); - } - - override void visit(TypeSArray t) - { - is_top_level = false; - if (!substitute(t)) - store(t); - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - buf.printf("A%llu_", t.dim ? t.dim.toInteger() : 0); - t.next.accept(this); - } - - override void visit(TypeDArray t) + is_top_level = false; + if (substitute(t)) + return; + if (t.isImmutable() || t.isShared()) { visit(cast(Type)t); } - - override void visit(TypeAArray t) + if (t.isConst()) + buf.writeByte('K'); + if (!substitute(t.sym)) + { + cpp_mangle_name(t.sym, t.isConst()); + } + if (t.isImmutable() || t.isShared()) { visit(cast(Type)t); } - - override void visit(TypePointer t) - { - is_top_level = false; - if (substitute(t)) - return; - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - buf.writeByte('P'); - t.next.accept(this); + if (t.isConst()) store(t); - } - - override void visit(TypeReference t) - { - is_top_level = false; - if (substitute(t)) - return; - buf.writeByte('R'); - t.next.accept(this); - store(t); - } - - override void visit(TypeFunction t) - { - is_top_level = false; - /* - * ::= F [Y] E - * ::= + - * # types are possible return type, then parameter types - */ - /* ABI says: - "The type of a non-static member function is considered to be different, - for the purposes of substitution, from the type of a namespace-scope or - static member function whose type appears similar. The types of two - non-static member functions are considered to be different, for the - purposes of substitution, if the functions are members of different - classes. In other words, for the purposes of substitution, the class of - which the function is a member is considered part of the type of - function." - - BUG: Right now, types of functions are never merged, so our simplistic - component matcher always finds them to be different. - We should use Type.equals on these, and use different - TypeFunctions for non-static member functions, and non-static - member functions of different classes. - */ - if (substitute(t)) - return; - buf.writeByte('F'); - if (t.linkage == LINKc) - buf.writeByte('Y'); - Type tn = t.next; - if (t.isref) - tn = tn.referenceTo(); - tn.accept(this); - argsCppMangle(t.parameters, t.varargs); - buf.writeByte('E'); - store(t); - } - - override void visit(TypeDelegate t) - { - visit(cast(Type)t); - } - - override void visit(TypeStruct t) - { - const id = t.sym.ident; - //printf("struct id = '%s'\n", id.toChars()); - char c; - if (id == Id.__c_long) - c = 'l'; - else if (id == Id.__c_ulong) - c = 'm'; - else - c = 0; - if (c) - { - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - { - if (substitute(t)) - { - return; - } - else - { - store(t); - } - } - if (t.isConst()) - buf.writeByte('K'); - buf.writeByte(c); - return; - } - is_top_level = false; - if (substitute(t)) - return; - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - buf.writeByte('K'); - if (!substitute(t.sym)) - { - cpp_mangle_name(t.sym, t.isConst()); - } - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - store(t); - } - - override void visit(TypeEnum t) - { - is_top_level = false; - if (substitute(t)) - return; - if (t.isConst()) - buf.writeByte('K'); - if (!substitute(t.sym)) - { - cpp_mangle_name(t.sym, t.isConst()); - } - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst()) - store(t); - } - - override void visit(TypeClass t) - { - if (substitute(t)) - return; - if (t.isImmutable() || t.isShared()) - { - visit(cast(Type)t); - } - if (t.isConst() && !is_top_level) - buf.writeByte('K'); - is_top_level = false; - buf.writeByte('P'); - if (t.isConst()) - buf.writeByte('K'); - if (!substitute(t.sym)) - { - cpp_mangle_name(t.sym, t.isConst()); - } - if (t.isConst()) - store(null); - store(t); - } - - final const(char)* mangle_typeinfo(Dsymbol s) - { - buf.writestring("_ZTI"); - cpp_mangle_name(s, false); - return buf.extractString(); - } } - extern (C++) const(char)* toCppMangle(Dsymbol s) + override void visit(TypeEnum t) { - //printf("toCppMangle(%s)\n", s.toChars()); - scope CppMangleVisitor v = new CppMangleVisitor(); - return v.mangleOf(s); + is_top_level = false; + if (substitute(t)) + return; + if (t.isConst()) + buf.writeByte('K'); + if (!substitute(t.sym)) + { + cpp_mangle_name(t.sym, t.isConst()); + } + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); + } + if (t.isConst()) + store(t); } - extern (C++) const(char)* cppTypeInfoMangle(Dsymbol s) + override void visit(TypeClass t) { - //printf("cppTypeInfoMangle(%s)\n", s.toChars()); - scope CppMangleVisitor v = new CppMangleVisitor(); - return v.mangle_typeinfo(s); + if (substitute(t)) + return; + if (t.isImmutable() || t.isShared()) + { + visit(cast(Type)t); + } + if (t.isConst() && !is_top_level) + buf.writeByte('K'); + is_top_level = false; + buf.writeByte('P'); + if (t.isConst()) + buf.writeByte('K'); + if (!substitute(t.sym)) + { + cpp_mangle_name(t.sym, t.isConst()); + } + if (t.isConst()) + store(null); + store(t); + } + + final const(char)* mangle_typeinfo(Dsymbol s) + { + buf.writestring("_ZTI"); + cpp_mangle_name(s, false); + return buf.extractString(); } } -else static if (TARGET_WINDOS) + +extern (C++) const(char)* toCppMangleItanium(Dsymbol s) { - // Windows DMC and Microsoft Visual C++ mangling - enum VC_SAVED_TYPE_CNT = 10u; - enum VC_SAVED_IDENT_CNT = 10u; + //printf("toCppMangleItanium(%s)\n", s.toChars()); + scope CppMangleVisitor v = new CppMangleVisitor(); + return v.mangleOf(s); +} - extern (C++) final class VisualCPPMangler : Visitor +extern (C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s) +{ + //printf("cppTypeInfoMangle(%s)\n", s.toChars()); + scope CppMangleVisitor v = new CppMangleVisitor(); + return v.mangle_typeinfo(s); +} + +// Windows DMC and Microsoft Visual C++ mangling +enum VC_SAVED_TYPE_CNT = 10u; +enum VC_SAVED_IDENT_CNT = 10u; + +extern (C++) final class VisualCPPMangler : Visitor +{ + alias visit = super.visit; + const(char)*[VC_SAVED_IDENT_CNT] saved_idents; + Type[VC_SAVED_TYPE_CNT] saved_types; + + // IS_NOT_TOP_TYPE: when we mangling one argument, we can call visit several times (for base types of arg type) + // but we must save only arg type: + // For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int" + // This flag is set up by the visit(NextType, ) function and should be reset when the arg type output is finished. + // MANGLE_RETURN_TYPE: return type shouldn't be saved and substituted in arguments + // IGNORE_CONST: in some cases we should ignore CV-modifiers. + + enum Flags : int { - alias visit = super.visit; - const(char)*[VC_SAVED_IDENT_CNT] saved_idents; - Type[VC_SAVED_TYPE_CNT] saved_types; + IS_NOT_TOP_TYPE = 0x1, + MANGLE_RETURN_TYPE = 0x2, + IGNORE_CONST = 0x4, + IS_DMC = 0x8, + } - // IS_NOT_TOP_TYPE: when we mangling one argument, we can call visit several times (for base types of arg type) - // but we must save only arg type: - // For example: if we have an int** argument, we should save "int**" but visit will be called for "int**", "int*", "int" - // This flag is set up by the visit(NextType, ) function and should be reset when the arg type output is finished. - // MANGLE_RETURN_TYPE: return type shouldn't be saved and substituted in arguments - // IGNORE_CONST: in some cases we should ignore CV-modifiers. + alias IS_NOT_TOP_TYPE = Flags.IS_NOT_TOP_TYPE; + alias MANGLE_RETURN_TYPE = Flags.MANGLE_RETURN_TYPE; + alias IGNORE_CONST = Flags.IGNORE_CONST; + alias IS_DMC = Flags.IS_DMC; - enum Flags : int + int flags; + OutBuffer buf; + + extern (D) this(VisualCPPMangler rvl) + { + flags |= (rvl.flags & IS_DMC); + memcpy(&saved_idents, &rvl.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); + memcpy(&saved_types, &rvl.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT); + } + +public: + extern (D) this(bool isdmc) + { + if (isdmc) { - IS_NOT_TOP_TYPE = 0x1, - MANGLE_RETURN_TYPE = 0x2, - IGNORE_CONST = 0x4, - IS_DMC = 0x8, + flags |= IS_DMC; } + memset(&saved_idents, 0, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); + memset(&saved_types, 0, Type.sizeof * VC_SAVED_TYPE_CNT); + } - alias IS_NOT_TOP_TYPE = Flags.IS_NOT_TOP_TYPE; - alias MANGLE_RETURN_TYPE = Flags.MANGLE_RETURN_TYPE; - alias IGNORE_CONST = Flags.IGNORE_CONST; - alias IS_DMC = Flags.IS_DMC; - - int flags; - OutBuffer buf; - - extern (D) this(VisualCPPMangler rvl) + override void visit(Type type) + { + if (type.isImmutable() || type.isShared()) { - flags |= (rvl.flags & IS_DMC); - memcpy(&saved_idents, &rvl.saved_idents, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); - memcpy(&saved_types, &rvl.saved_types, Type.sizeof * VC_SAVED_TYPE_CNT); + type.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", type.toChars()); } - - public: - extern (D) this(bool isdmc) + else { - if (isdmc) + type.error(Loc(), "Internal Compiler Error: unsupported type %s\n", type.toChars()); + } + fatal(); //Fatal, because this error should be handled in frontend + } + + override void visit(TypeBasic type) + { + //printf("visit(TypeBasic); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (type.isImmutable() || type.isShared()) + { + visit(cast(Type)type); + return; + } + if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) + { + if (checkTypeSaved(type)) + return; + } + if ((type.ty == Tbool) && checkTypeSaved(type)) // try to replace long name with number + { + return; + } + if (!(flags & IS_DMC)) + { + switch (type.ty) { - flags |= IS_DMC; + case Tint64: + case Tuns64: + case Tint128: + case Tuns128: + case Tfloat80: + case Twchar: + if (checkTypeSaved(type)) + return; + break; + + default: + break; } - memset(&saved_idents, 0, (const(char)*).sizeof * VC_SAVED_IDENT_CNT); - memset(&saved_types, 0, Type.sizeof * VC_SAVED_TYPE_CNT); } - - override void visit(Type type) + mangleModifier(type); + switch (type.ty) { - if (type.isImmutable() || type.isShared()) + case Tvoid: + buf.writeByte('X'); + break; + case Tint8: + buf.writeByte('C'); + break; + case Tuns8: + buf.writeByte('E'); + break; + case Tint16: + buf.writeByte('F'); + break; + case Tuns16: + buf.writeByte('G'); + break; + case Tint32: + buf.writeByte('H'); + break; + case Tuns32: + buf.writeByte('I'); + break; + case Tfloat32: + buf.writeByte('M'); + break; + case Tint64: + buf.writestring("_J"); + break; + case Tuns64: + buf.writestring("_K"); + break; + case Tint128: + buf.writestring("_L"); + break; + case Tuns128: + buf.writestring("_M"); + break; + case Tfloat64: + buf.writeByte('N'); + break; + case Tbool: + buf.writestring("_N"); + break; + case Tchar: + buf.writeByte('D'); + break; + case Tdchar: + buf.writeByte('I'); + break; + // unsigned int + case Tfloat80: + if (flags & IS_DMC) + buf.writestring("_Z"); // DigitalMars long double + else + buf.writestring("_T"); // Intel long double + break; + case Twchar: + if (flags & IS_DMC) + buf.writestring("_Y"); // DigitalMars wchar_t + else + buf.writestring("_W"); // Visual C++ wchar_t + break; + default: + visit(cast(Type)type); + return; + } + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } + + override void visit(TypeVector type) + { + //printf("visit(TypeVector); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (checkTypeSaved(type)) + return; + buf.writestring("T__m128@@"); // may be better as __m128i or __m128d? + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } + + override void visit(TypeSArray type) + { + // This method can be called only for static variable type mangling. + //printf("visit(TypeSArray); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (checkTypeSaved(type)) + return; + // first dimension always mangled as const pointer + if (flags & IS_DMC) + buf.writeByte('Q'); + else + buf.writeByte('P'); + flags |= IS_NOT_TOP_TYPE; + assert(type.next); + if (type.next.ty == Tsarray) + { + mangleArray(cast(TypeSArray)type.next); + } + else + { + type.next.accept(this); + } + } + + // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation) + // There is not way to map int C++ (*arr)[2][1] to D + override void visit(TypePointer type) + { + //printf("visit(TypePointer); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (type.isImmutable() || type.isShared()) + { + visit(cast(Type)type); + return; + } + assert(type.next); + if (type.next.ty == Tfunction) + { + const(char)* arg = mangleFunctionType(cast(TypeFunction)type.next); // compute args before checking to save; args should be saved before function type + // If we've mangled this function early, previous call is meaningless. + // However we should do it before checking to save types of function arguments before function type saving. + // If this function was already mangled, types of all it arguments are save too, thus previous can't save + // anything if function is saved. + if (checkTypeSaved(type)) + return; + if (type.isConst()) + buf.writeByte('Q'); // const + else + buf.writeByte('P'); // mutable + buf.writeByte('6'); // pointer to a function + buf.writestring(arg); + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + return; + } + else if (type.next.ty == Tsarray) + { + if (checkTypeSaved(type)) + return; + mangleModifier(type); + if (type.isConst() || !(flags & IS_DMC)) + buf.writeByte('Q'); // const + else + buf.writeByte('P'); // mutable + if (global.params.is64bit) + buf.writeByte('E'); + flags |= IS_NOT_TOP_TYPE; + mangleArray(cast(TypeSArray)type.next); + return; + } + else + { + if (checkTypeSaved(type)) + return; + mangleModifier(type); + if (type.isConst()) { - type.error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", type.toChars()); + buf.writeByte('Q'); // const } else { - type.error(Loc(), "Internal Compiler Error: unsupported type %s\n", type.toChars()); + buf.writeByte('P'); // mutable } - fatal(); //Fatal, because this error should be handled in frontend + if (global.params.is64bit) + buf.writeByte('E'); + flags |= IS_NOT_TOP_TYPE; + type.next.accept(this); } + } - override void visit(TypeBasic type) + override void visit(TypeReference type) + { + //printf("visit(TypeReference); type = %s\n", type.toChars()); + if (checkTypeSaved(type)) + return; + if (type.isImmutable() || type.isShared()) + { + visit(cast(Type)type); + return; + } + buf.writeByte('A'); // mutable + if (global.params.is64bit) + buf.writeByte('E'); + flags |= IS_NOT_TOP_TYPE; + assert(type.next); + if (type.next.ty == Tsarray) + { + mangleArray(cast(TypeSArray)type.next); + } + else + { + type.next.accept(this); + } + } + + override void visit(TypeFunction type) + { + const(char)* arg = mangleFunctionType(type); + if ((flags & IS_DMC)) + { + if (checkTypeSaved(type)) + return; + } + else + { + buf.writestring("$$A6"); + } + buf.writestring(arg); + flags &= ~(IS_NOT_TOP_TYPE | IGNORE_CONST); + } + + override void visit(TypeStruct type) + { + const id = type.sym.ident; + char c; + if (id == Id.__c_long_double) + c = 'O'; // VC++ long double + else if (id == Id.__c_long) + c = 'J'; // VC++ long + else if (id == Id.__c_ulong) + c = 'K'; // VC++ unsigned long + else + c = 0; + if (c) { - //printf("visit(TypeBasic); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); if (type.isImmutable() || type.isShared()) { visit(cast(Type)type); @@ -1015,966 +1269,704 @@ else static if (TARGET_WINDOS) if (checkTypeSaved(type)) return; } - if ((type.ty == Tbool) && checkTypeSaved(type)) // try to replace long name with number - { + mangleModifier(type); + buf.writeByte(c); + } + else + { + if (checkTypeSaved(type)) return; - } - if (!(flags & IS_DMC)) - { - switch (type.ty) - { - case Tint64: - case Tuns64: - case Tint128: - case Tuns128: - case Tfloat80: - case Twchar: - if (checkTypeSaved(type)) - return; - break; + //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + mangleModifier(type); + if (type.sym.isUnionDeclaration()) + buf.writeByte('T'); + else + buf.writeByte(type.cppmangle == CPPMANGLE.asClass ? 'V' : 'U'); + mangleIdent(type.sym); + } + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } + override void visit(TypeEnum type) + { + //printf("visit(TypeEnum); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (checkTypeSaved(type)) + return; + mangleModifier(type); + buf.writeByte('W'); + switch (type.sym.memtype.ty) + { + case Tchar: + case Tint8: + buf.writeByte('0'); + break; + case Tuns8: + buf.writeByte('1'); + break; + case Tint16: + buf.writeByte('2'); + break; + case Tuns16: + buf.writeByte('3'); + break; + case Tint32: + buf.writeByte('4'); + break; + case Tuns32: + buf.writeByte('5'); + break; + case Tint64: + buf.writeByte('6'); + break; + case Tuns64: + buf.writeByte('7'); + break; + default: + visit(cast(Type)type); + break; + } + mangleIdent(type.sym); + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } + + // D class mangled as pointer to C++ class + // const(Object) mangled as Object const* const + override void visit(TypeClass type) + { + //printf("visit(TypeClass); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); + if (checkTypeSaved(type)) + return; + if (flags & IS_NOT_TOP_TYPE) + mangleModifier(type); + if (type.isConst()) + buf.writeByte('Q'); + else + buf.writeByte('P'); + if (global.params.is64bit) + buf.writeByte('E'); + flags |= IS_NOT_TOP_TYPE; + mangleModifier(type); + buf.writeByte(type.cppmangle == CPPMANGLE.asStruct ? 'U' : 'V'); + mangleIdent(type.sym); + flags &= ~IS_NOT_TOP_TYPE; + flags &= ~IGNORE_CONST; + } + + const(char)* mangleOf(Dsymbol s) + { + VarDeclaration vd = s.isVarDeclaration(); + FuncDeclaration fd = s.isFuncDeclaration(); + if (vd) + { + mangleVariable(vd); + } + else if (fd) + { + mangleFunction(fd); + } + else + { + assert(0); + } + return buf.extractString(); + } + +private: + void mangleFunction(FuncDeclaration d) + { + // ? + assert(d); + buf.writeByte('?'); + mangleIdent(d); + if (d.needThis()) // ::= + { + // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ + //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", + //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); + if (d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) + { + switch (d.protection.kind) + { + case PROTprivate: + buf.writeByte('E'); + break; + case PROTprotected: + buf.writeByte('M'); + break; default: + buf.writeByte('U'); break; } } - mangleModifier(type); - switch (type.ty) + else { - case Tvoid: - buf.writeByte('X'); - break; - case Tint8: + switch (d.protection.kind) + { + case PROTprivate: + buf.writeByte('A'); + break; + case PROTprotected: + buf.writeByte('I'); + break; + default: + buf.writeByte('Q'); + break; + } + } + if (global.params.is64bit) + buf.writeByte('E'); + if (d.type.isConst()) + { + buf.writeByte('B'); + } + else + { + buf.writeByte('A'); + } + } + else if (d.isMember2()) // static function + { + // ::= + switch (d.protection.kind) + { + case PROTprivate: buf.writeByte('C'); break; - case Tuns8: - buf.writeByte('E'); - break; - case Tint16: - buf.writeByte('F'); - break; - case Tuns16: - buf.writeByte('G'); - break; - case Tint32: - buf.writeByte('H'); - break; - case Tuns32: - buf.writeByte('I'); - break; - case Tfloat32: - buf.writeByte('M'); - break; - case Tint64: - buf.writestring("_J"); - break; - case Tuns64: - buf.writestring("_K"); - break; - case Tint128: - buf.writestring("_L"); - break; - case Tuns128: - buf.writestring("_M"); - break; - case Tfloat64: - buf.writeByte('N'); - break; - case Tbool: - buf.writestring("_N"); - break; - case Tchar: - buf.writeByte('D'); - break; - case Tdchar: - buf.writeByte('I'); - break; - // unsigned int - case Tfloat80: - if (flags & IS_DMC) - buf.writestring("_Z"); // DigitalMars long double - else - buf.writestring("_T"); // Intel long double - break; - case Twchar: - if (flags & IS_DMC) - buf.writestring("_Y"); // DigitalMars wchar_t - else - buf.writestring("_W"); // Visual C++ wchar_t + case PROTprotected: + buf.writeByte('K'); break; default: - visit(cast(Type)type); - return; - } - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - override void visit(TypeVector type) - { - //printf("visit(TypeVector); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - buf.writestring("T__m128@@"); // may be better as __m128i or __m128d? - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - override void visit(TypeSArray type) - { - // This method can be called only for static variable type mangling. - //printf("visit(TypeSArray); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - // first dimension always mangled as const pointer - if (flags & IS_DMC) - buf.writeByte('Q'); - else - buf.writeByte('P'); - flags |= IS_NOT_TOP_TYPE; - assert(type.next); - if (type.next.ty == Tsarray) - { - mangleArray(cast(TypeSArray)type.next); - } - else - { - type.next.accept(this); + buf.writeByte('S'); + break; } } - - // attention: D int[1][2]* arr mapped to C++ int arr[][2][1]; (because it's more typical situation) - // There is not way to map int C++ (*arr)[2][1] to D - override void visit(TypePointer type) + else // top-level function { - //printf("visit(TypePointer); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - assert(type.next); - if (type.next.ty == Tfunction) - { - const(char)* arg = mangleFunctionType(cast(TypeFunction)type.next); // compute args before checking to save; args should be saved before function type - // If we've mangled this function early, previous call is meaningless. - // However we should do it before checking to save types of function arguments before function type saving. - // If this function was already mangled, types of all it arguments are save too, thus previous can't save - // anything if function is saved. - if (checkTypeSaved(type)) - return; - if (type.isConst()) - buf.writeByte('Q'); // const - else - buf.writeByte('P'); // mutable - buf.writeByte('6'); // pointer to a function - buf.writestring(arg); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - return; - } - else if (type.next.ty == Tsarray) - { - if (checkTypeSaved(type)) - return; - mangleModifier(type); - if (type.isConst() || !(flags & IS_DMC)) - buf.writeByte('Q'); // const - else - buf.writeByte('P'); // mutable - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - mangleArray(cast(TypeSArray)type.next); - return; - } - else - { - if (checkTypeSaved(type)) - return; - mangleModifier(type); - if (type.isConst()) - { - buf.writeByte('Q'); // const - } - else - { - buf.writeByte('P'); // mutable - } - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - type.next.accept(this); - } + // ::= Y + buf.writeByte('Y'); } + const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration()); + buf.writestring(args); + } - override void visit(TypeReference type) + void mangleVariable(VarDeclaration d) + { + // ::= ? + assert(d); + // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 + if (!(d.storage_class & (STCextern | STCfield | STCgshared))) { - //printf("visit(TypeReference); type = %s\n", type.toChars()); - if (checkTypeSaved(type)) - return; - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - buf.writeByte('A'); // mutable - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - assert(type.next); - if (type.next.ty == Tsarray) - { - mangleArray(cast(TypeSArray)type.next); - } - else - { - type.next.accept(this); - } + d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); + fatal(); } - - override void visit(TypeFunction type) + buf.writeByte('?'); + mangleIdent(d); + assert((d.storage_class & STCfield) || !d.needThis()); + Dsymbol parent = d.toParent(); + while (parent && parent.isNspace()) { - const(char)* arg = mangleFunctionType(type); - if ((flags & IS_DMC)) - { - if (checkTypeSaved(type)) - return; - } - else - { - buf.writestring("$$A6"); - } - buf.writestring(arg); - flags &= ~(IS_NOT_TOP_TYPE | IGNORE_CONST); + parent = parent.toParent(); } - - override void visit(TypeStruct type) + if (parent && parent.isModule()) // static member { - const id = type.sym.ident; - char c; - if (id == Id.__c_long_double) - c = 'O'; // VC++ long double - else if (id == Id.__c_long) - c = 'J'; // VC++ long - else if (id == Id.__c_ulong) - c = 'K'; // VC++ unsigned long - else - c = 0; - if (c) - { - if (type.isImmutable() || type.isShared()) - { - visit(cast(Type)type); - return; - } - if (type.isConst() && ((flags & IS_NOT_TOP_TYPE) || (flags & IS_DMC))) - { - if (checkTypeSaved(type)) - return; - } - mangleModifier(type); - buf.writeByte(c); - } - else - { - if (checkTypeSaved(type)) - return; - //printf("visit(TypeStruct); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - mangleModifier(type); - if (type.sym.isUnionDeclaration()) - buf.writeByte('T'); - else - buf.writeByte(type.cppmangle == CPPMANGLE.asClass ? 'V' : 'U'); - mangleIdent(type.sym); - } - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; + buf.writeByte('3'); } - - override void visit(TypeEnum type) + else { - //printf("visit(TypeEnum); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - mangleModifier(type); - buf.writeByte('W'); - switch (type.sym.memtype.ty) + switch (d.protection.kind) { - case Tchar: - case Tint8: + case PROTprivate: buf.writeByte('0'); break; - case Tuns8: + case PROTprotected: buf.writeByte('1'); break; - case Tint16: + default: buf.writeByte('2'); break; - case Tuns16: - buf.writeByte('3'); - break; - case Tint32: - buf.writeByte('4'); - break; - case Tuns32: - buf.writeByte('5'); - break; - case Tint64: - buf.writeByte('6'); - break; - case Tuns64: - buf.writeByte('7'); - break; - default: - visit(cast(Type)type); - break; } - mangleIdent(type.sym); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; } - - // D class mangled as pointer to C++ class - // const(Object) mangled as Object const* const - override void visit(TypeClass type) + char cv_mod = 0; + Type t = d.type; + if (t.isImmutable() || t.isShared()) { - //printf("visit(TypeClass); is_not_top_type = %d\n", (int)(flags & IS_NOT_TOP_TYPE)); - if (checkTypeSaved(type)) - return; - if (flags & IS_NOT_TOP_TYPE) - mangleModifier(type); - if (type.isConst()) - buf.writeByte('Q'); - else - buf.writeByte('P'); - if (global.params.is64bit) - buf.writeByte('E'); - flags |= IS_NOT_TOP_TYPE; - mangleModifier(type); - buf.writeByte(type.cppmangle == CPPMANGLE.asStruct ? 'U' : 'V'); - mangleIdent(type.sym); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; + visit(t); + return; } - - const(char)* mangleOf(Dsymbol s) + if (t.isConst()) { - VarDeclaration vd = s.isVarDeclaration(); - FuncDeclaration fd = s.isFuncDeclaration(); - if (vd) - { - mangleVariable(vd); - } - else if (fd) - { - mangleFunction(fd); - } - else - { - assert(0); - } - return buf.extractString(); + cv_mod = 'B'; // const } - - private: - void mangleFunction(FuncDeclaration d) + else { - // ? - assert(d); - buf.writeByte('?'); - mangleIdent(d); - if (d.needThis()) // ::= - { - // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ - //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", - //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); - if (d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) - { - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('E'); - break; - case PROTprotected: - buf.writeByte('M'); - break; - default: - buf.writeByte('U'); - break; - } - } - else - { - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('A'); - break; - case PROTprotected: - buf.writeByte('I'); - break; - default: - buf.writeByte('Q'); - break; - } - } - if (global.params.is64bit) - buf.writeByte('E'); - if (d.type.isConst()) - { - buf.writeByte('B'); - } - else - { - buf.writeByte('A'); - } - } - else if (d.isMember2()) // static function - { - // ::= - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('C'); - break; - case PROTprotected: - buf.writeByte('K'); - break; - default: - buf.writeByte('S'); - break; - } - } - else // top-level function - { - // ::= Y - buf.writeByte('Y'); - } - const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration()); - buf.writestring(args); + cv_mod = 'A'; // mutable } - - void mangleVariable(VarDeclaration d) + if (t.ty != Tpointer) + t = t.mutableOf(); + t.accept(this); + if ((t.ty == Tpointer || t.ty == Treference || t.ty == Tclass) && global.params.is64bit) { - // ::= ? - assert(d); - // fake mangling for fields to fix https://issues.dlang.org/show_bug.cgi?id=16525 - if (!(d.storage_class & (STCextern | STCfield | STCgshared))) - { - d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); - fatal(); - } - buf.writeByte('?'); - mangleIdent(d); - assert((d.storage_class & STCfield) || !d.needThis()); - Dsymbol parent = d.toParent(); - while (parent && parent.isNspace()) - { - parent = parent.toParent(); - } - if (parent && parent.isModule()) // static member - { - buf.writeByte('3'); - } - else - { - switch (d.protection.kind) - { - case PROTprivate: - buf.writeByte('0'); - break; - case PROTprotected: - buf.writeByte('1'); - break; - default: - buf.writeByte('2'); - break; - } - } - char cv_mod = 0; - Type t = d.type; - if (t.isImmutable() || t.isShared()) - { - visit(t); - return; - } - if (t.isConst()) - { - cv_mod = 'B'; // const - } - else - { - cv_mod = 'A'; // mutable - } - if (t.ty != Tpointer) - t = t.mutableOf(); - t.accept(this); - if ((t.ty == Tpointer || t.ty == Treference || t.ty == Tclass) && global.params.is64bit) - { - buf.writeByte('E'); - } - buf.writeByte(cv_mod); + buf.writeByte('E'); } + buf.writeByte(cv_mod); + } - void mangleName(Dsymbol sym, bool dont_use_back_reference = false) + void mangleName(Dsymbol sym, bool dont_use_back_reference = false) + { + //printf("mangleName('%s')\n", sym.toChars()); + const(char)* name = null; + bool is_dmc_template = false; + if (sym.isDtorDeclaration()) { - //printf("mangleName('%s')\n", sym.toChars()); - const(char)* name = null; - bool is_dmc_template = false; - if (sym.isDtorDeclaration()) + buf.writestring("?1"); + return; + } + if (TemplateInstance ti = sym.isTemplateInstance()) + { + scope VisualCPPMangler tmp = new VisualCPPMangler((flags & IS_DMC) ? true : false); + tmp.buf.writeByte('?'); + tmp.buf.writeByte('$'); + tmp.buf.writestring(ti.name.toChars()); + tmp.saved_idents[0] = ti.name.toChars(); + tmp.buf.writeByte('@'); + if (flags & IS_DMC) { - buf.writestring("?1"); - return; + tmp.mangleIdent(sym.parent, true); + is_dmc_template = true; } - if (TemplateInstance ti = sym.isTemplateInstance()) + bool is_var_arg = false; + for (size_t i = 0; i < ti.tiargs.dim; i++) { - scope VisualCPPMangler tmp = new VisualCPPMangler((flags & IS_DMC) ? true : false); - tmp.buf.writeByte('?'); - tmp.buf.writeByte('$'); - tmp.buf.writestring(ti.name.toChars()); - tmp.saved_idents[0] = ti.name.toChars(); - tmp.buf.writeByte('@'); - if (flags & IS_DMC) + RootObject o = (*ti.tiargs)[i]; + TemplateParameter tp = null; + TemplateValueParameter tv = null; + TemplateTupleParameter tt = null; + if (!is_var_arg) { - tmp.mangleIdent(sym.parent, true); - is_dmc_template = true; + TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); + assert(td); + tp = (*td.parameters)[i]; + tv = tp.isTemplateValueParameter(); + tt = tp.isTemplateTupleParameter(); } - bool is_var_arg = false; - for (size_t i = 0; i < ti.tiargs.dim; i++) + if (tt) { - RootObject o = (*ti.tiargs)[i]; - TemplateParameter tp = null; - TemplateValueParameter tv = null; - TemplateTupleParameter tt = null; - if (!is_var_arg) + is_var_arg = true; + tp = null; + } + if (tv) + { + if (tv.valType.isintegral()) { - TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration(); - assert(td); - tp = (*td.parameters)[i]; - tv = tp.isTemplateValueParameter(); - tt = tp.isTemplateTupleParameter(); - } - if (tt) - { - is_var_arg = true; - tp = null; - } - if (tv) - { - if (tv.valType.isintegral()) + tmp.buf.writeByte('$'); + tmp.buf.writeByte('0'); + Expression e = isExpression(o); + assert(e); + if (tv.valType.isunsigned()) { - tmp.buf.writeByte('$'); - tmp.buf.writeByte('0'); - Expression e = isExpression(o); - assert(e); - if (tv.valType.isunsigned()) - { - tmp.mangleNumber(e.toUInteger()); - } - else if (is_dmc_template) - { - // NOTE: DMC mangles everything based on - // unsigned int - tmp.mangleNumber(e.toInteger()); - } - else - { - sinteger_t val = e.toInteger(); - if (val < 0) - { - val = -val; - tmp.buf.writeByte('?'); - } - tmp.mangleNumber(val); - } + tmp.mangleNumber(e.toUInteger()); + } + else if (is_dmc_template) + { + // NOTE: DMC mangles everything based on + // unsigned int + tmp.mangleNumber(e.toInteger()); } else { - sym.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); - fatal(); + sinteger_t val = e.toInteger(); + if (val < 0) + { + val = -val; + tmp.buf.writeByte('?'); + } + tmp.mangleNumber(val); } } - else if (!tp || tp.isTemplateTypeParameter()) + else { - Type t = isType(o); - assert(t); - t.accept(tmp); + sym.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); + fatal(); } - else if (tp.isTemplateAliasParameter()) + } + else if (!tp || tp.isTemplateTypeParameter()) + { + Type t = isType(o); + assert(t); + t.accept(tmp); + } + else if (tp.isTemplateAliasParameter()) + { + Dsymbol d = isDsymbol(o); + Expression e = isExpression(o); + if (!d && !e) { - Dsymbol d = isDsymbol(o); - Expression e = isExpression(o); - if (!d && !e) - { - sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); - fatal(); - } - if (d && d.isFuncDeclaration()) - { - tmp.buf.writeByte('$'); + sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); + fatal(); + } + if (d && d.isFuncDeclaration()) + { + tmp.buf.writeByte('$'); + tmp.buf.writeByte('1'); + tmp.mangleFunction(d.isFuncDeclaration()); + } + else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) + { + tmp.buf.writeByte('$'); + if (flags & IS_DMC) tmp.buf.writeByte('1'); - tmp.mangleFunction(d.isFuncDeclaration()); - } - else if (e && e.op == TOKvar && (cast(VarExp)e).var.isVarDeclaration()) + else + tmp.buf.writeByte('E'); + tmp.mangleVariable((cast(VarExp)e).var.isVarDeclaration()); + } + else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) + { + Dsymbol ds = d.isTemplateDeclaration().onemember; + if (flags & IS_DMC) { - tmp.buf.writeByte('$'); - if (flags & IS_DMC) - tmp.buf.writeByte('1'); - else - tmp.buf.writeByte('E'); - tmp.mangleVariable((cast(VarExp)e).var.isVarDeclaration()); + tmp.buf.writeByte('V'); } - else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) + else { - Dsymbol ds = d.isTemplateDeclaration().onemember; - if (flags & IS_DMC) + if (ds.isUnionDeclaration()) + { + tmp.buf.writeByte('T'); + } + else if (ds.isStructDeclaration()) + { + tmp.buf.writeByte('U'); + } + else if (ds.isClassDeclaration()) { tmp.buf.writeByte('V'); } else { - if (ds.isUnionDeclaration()) - { - tmp.buf.writeByte('T'); - } - else if (ds.isStructDeclaration()) - { - tmp.buf.writeByte('U'); - } - else if (ds.isClassDeclaration()) - { - tmp.buf.writeByte('V'); - } - else - { - sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); - fatal(); - } + sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + fatal(); } - tmp.mangleIdent(d); - } - else - { - sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); - fatal(); } + tmp.mangleIdent(d); } else { - sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); fatal(); } } - name = tmp.buf.extractString(); + else + { + sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + fatal(); + } + } + name = tmp.buf.extractString(); + } + else + { + name = sym.ident.toChars(); + } + assert(name); + if (is_dmc_template) + { + if (checkAndSaveIdent(name)) + return; + } + else + { + if (dont_use_back_reference) + { + saveIdent(name); } else - { - name = sym.ident.toChars(); - } - assert(name); - if (is_dmc_template) { if (checkAndSaveIdent(name)) return; } - else - { - if (dont_use_back_reference) - { - saveIdent(name); - } - else - { - if (checkAndSaveIdent(name)) - return; - } - } - buf.writestring(name); - buf.writeByte('@'); } + buf.writestring(name); + buf.writeByte('@'); + } - // returns true if name already saved - bool checkAndSaveIdent(const(char)* name) + // returns true if name already saved + bool checkAndSaveIdent(const(char)* name) + { + foreach (i; 0 .. VC_SAVED_IDENT_CNT) { - foreach (i; 0 .. VC_SAVED_IDENT_CNT) + if (!saved_idents[i]) // no saved same name { - if (!saved_idents[i]) // no saved same name - { - saved_idents[i] = name; - break; - } - if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name - { - buf.writeByte(i + '0'); - return true; - } + saved_idents[i] = name; + break; } - return false; - } - - void saveIdent(const(char)* name) - { - foreach (i; 0 .. VC_SAVED_IDENT_CNT) + if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name { - if (!saved_idents[i]) // no saved same name - { - saved_idents[i] = name; - break; - } - if (!strcmp(saved_idents[i], name)) // ok, we've found same name. use index instead of name - { - return; - } + buf.writeByte(i + '0'); + return true; } } + return false; + } - void mangleIdent(Dsymbol sym, bool dont_use_back_reference = false) + void saveIdent(const(char)* name) + { + foreach (i; 0 .. VC_SAVED_IDENT_CNT) { - // ::= @ - // ::= - // ::= - // ::= @ - // ::= ?$ @