diff --git a/gcc.version b/gcc.version index adcdbbd2e..d31312091 100644 --- a/gcc.version +++ b/gcc.version @@ -1 +1 @@ -gcc-9-20180729 +gcc-9-20180826 diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog index 9b8944ff0..4f8233e76 100644 --- a/gcc/d/ChangeLog +++ b/gcc/d/ChangeLog @@ -1,4 +1,18 @@ +2018-08-29 Iain Buclaw + + * d-target.cc (Target::prefixName): Remove function. + (Target::cppParameterType): New function. + +2018-08-25 Iain Buclaw + + * Make-lang.in (D_FRONTEND_OBJS): Add iasm.o, iasmgcc.o + * lang.opt (fproperty): Remove option. + * d-lang.cc (d_handle_option): Remove case for OPT_fproperty. + * toir.cc (IRVisitor::visit(ExtAsmStatement)): Rename override to + GccAsmStatement. + 2018-07-23 Eugene Wissner + * d-lang.cc (d_handle_option): Change function argument to HOST_WIDE_INT. * lang.opt (Walloca-larger-than=, Wno-alloca-larger-than): New options. * opt.texi (Walloca-larger-than=, Wno-alloca-larger-than): Likewise. diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index 1b87e0ac4..a224a2bdc 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -94,6 +94,8 @@ D_FRONTEND_OBJS = \ d/filename.o \ d/func.o \ d/hdrgen.o \ + d/iasm.o \ + d/iasmgcc.o \ d/identifier.o \ d/imphint.o \ d/init.o \ diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 8ff428449..2363552ac 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -430,12 +430,16 @@ d_init_versions (void) VersionCondition::addPredefinedGlobalIdent ("D_Coverage"); if (flag_pic) VersionCondition::addPredefinedGlobalIdent ("D_PIC"); + if (global.params.doDocComments) VersionCondition::addPredefinedGlobalIdent ("D_Ddoc"); + if (global.params.useUnitTests) VersionCondition::addPredefinedGlobalIdent ("unittest"); + if (global.params.useAssert) VersionCondition::addPredefinedGlobalIdent ("assert"); + if (global.params.useArrayBounds == BOUNDSCHECKoff) VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks"); diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc index 512bf1dda..63dfda9b4 100644 --- a/gcc/d/d-frontend.cc +++ b/gcc/d/d-frontend.cc @@ -428,15 +428,6 @@ CTFloat::hash (real_t r) /* Implements backend-specific interfaces used by the frontend. */ -/* Semantically analyze AsmStatement where SC is the scope. */ - -Statement * -asmSemantic (AsmStatement *s, Scope *sc) -{ - sc->func->hasReturnExp |= 8; - return s; -} - /* Determine return style of function - whether in registers or through a hidden pointer to the caller's stack. */ diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 0d908b2ec..a0d28246b 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -514,10 +514,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.useIn = value; break; - case OPT_fproperty: - global.params.enforcePropertySyntax = value; - break; - case OPT_frelease: global.params.release = value; break; diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index a178564ef..0c0be1822 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -431,13 +431,6 @@ Target::isVectorOpSupported (Type *type, TOK op, Type *) return true; } -/* Apply any target-specific prefixes based on the given linkage. */ - -void -Target::prefixName (OutBuffer *, LINK) -{ -} - /* Return the symbol mangling of S for C++ linkage. */ const char * @@ -469,6 +462,37 @@ Target::cppTypeMangle (Type *type) return NULL; } +/* Return the type that will really be used for passing the given parameter + ARG to an extern(C++) function. */ + +Type * +Target::cppParameterType (Parameter *arg) +{ + Type *t = arg->type->merge2 (); + if (arg->storageClass & (STCout | STCref)) + t = t->referenceTo (); + else if (arg->storageClass & STClazy) + { + /* Mangle as delegate. */ + Type *td = TypeFunction::create (NULL, t, 0, LINKd); + td = TypeDelegate::create (td); + t = t->merge2 (); + } + + /* Could be a va_list, which we mangle as a pointer. */ + if (t->ty == Tsarray && Type::tvalist->ty == Tsarray) + { + Type *tb = t->toBasetype ()->mutableOf (); + if (tb == Type::tvalist) + { + tb = t->nextOf ()->pointerTo (); + t = tb->castMod (t->mod); + } + } + + return t; +} + /* Return the default system linkage for the target. */ LINK diff --git a/gcc/d/dfrontend/cppmangle.c b/gcc/d/dfrontend/cppmangle.c index bd548105a..dc1705cca 100644 --- a/gcc/d/dfrontend/cppmangle.c +++ b/gcc/d/dfrontend/cppmangle.c @@ -9,6 +9,19 @@ * https://github.com/D-Programming-Language/dmd/blob/master/src/cppmangle.c */ +/** + * Do mangling for C++ linkage. + * + * References: + * Follows Itanium C++ ABI 1.86 section 5.1 + * http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling + * which is where the grammar comments come from. + * + * Bugs: + * https://issues.dlang.org/query.cgi + * enter `C++, mangling` as the keywords. + */ + #include #include #include @@ -31,269 +44,387 @@ typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param); int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL); -/* Do mangling for C++ linkage. - * No attempt is made to support mangling of templates, operator - * overloading, or special functions. - * - * So why don't we use the C++ ABI for D name mangling? - * Because D supports a lot of things (like modules) that the C++ - * ABI has no concept of. These affect every D mangled name, - * so nothing would be compatible anyway. - */ - -/* - * Follows Itanium C++ ABI 1.86 - */ - class CppMangleVisitor : public Visitor { - Objects components; - OutBuffer buf; - bool is_top_level; - bool components_on; + Objects components; // array of components available for substitution + OutBuffer *buf; // append the mangling to buf[] + Loc loc; // location for use in error messages - void writeBase36(size_t i) + public: + // Write to buf + void write_seq_id(size_t i) { if (i >= 36) { - writeBase36(i / 36); + write_seq_id(i / 36); i %= 36; } - if (i < 10) - buf.writeByte((char)(i + '0')); - else if (i < 36) - buf.writeByte((char)(i - 10 + 'A')); - else - assert(0); + i += (i < 10) ? '0' : 'A' - 10; + buf->writeByte((char)i); } bool substitute(RootObject *p) { //printf("substitute %s\n", p ? p->toChars() : NULL); - if (components_on) - for (size_t i = 0; i < components.dim; i++) + int i = find(p); + if (i >= 0) + { + //printf("\tmatch\n"); + /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... + */ + buf->writeByte('S'); + if (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; - } + write_seq_id(i - 1); } + buf->writeByte('_'); + return true; + } return false; } - bool exist(RootObject *p) + /****** + * See if `p` exists in components[] + * Returns: + * index if found, -1 if not + */ + int find(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; + //printf("find %p %d %s\n", p, p.dyncast(), p ? p.toChars() : NULL); + for (size_t i = 0; i < components.dim; i++) + { + if (p == components[i]) + return (int)i; + } + return -1; } - void store(RootObject *p) + /********************* + * Append p to components[] + */ + void append(RootObject *p) { - //printf("store %s\n", p ? p->toChars() : NULL); - if (components_on) - components.push(p); + //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null"); + components.push(p); } - void source_name(Dsymbol *s, bool skipname = false) + /************************ + * Determine if symbol is indeed the global ::std namespace. + * Params: + * s = symbol to check + * Returns: + * true if it is ::std + */ + static bool isStd(Dsymbol *s) { - //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 = (RootObject *)(*ti->tiargs)[i]; + return (s && + s->ident == Id::std && // the right name + s->isNspace() && // g++ disallows global "std" for other than a namespace + !getQualifier(s)); // at global level + } - 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 - */ + /****************************** + * Write the mangled representation of the template arguments. + * Params: + * ti = the template instance + */ + void template_args(TemplateInstance *ti) + { + /* ::= I + E + */ + if (!ti) // could happen if std::basic_string is not a template + return; + buf->writeByte('I'); + for (size_t i = 0; i < ti->tiargs->dim; i++) + { + RootObject *o = (*ti->tiargs)[i]; + TemplateDeclaration *td = ti->tempdecl->isTemplateDeclaration(); + assert(td); + TemplateParameter *tp = (*td->parameters)[i]; + + /* + * ::= # type or template + * ::= X E # expression + * ::= # simple expressions + * ::= I * E # argument pack + */ + if (tp->isTemplateTupleParameter()) + { + buf->writeByte('I'); // argument pack - if (tt) + // mangle the rest of the arguments as types + for (size_t j = i; j < ti->tiargs->dim; j++) { - buf.writeByte('I'); - is_var_arg = true; - tp = NULL; + Type *t = isType((*ti->tiargs)[j]); + assert(t); + t->accept(this); } - if (tv) + buf->writeByte('E'); + break; + } + if (tp->isTemplateTypeParameter()) + { + Type *t = isType(o); + assert(t); + t->accept(this); + } + else if (TemplateValueParameter *tv = tp->isTemplateValueParameter()) + { + // ::= L E # integer literal + if (tv->valType->isintegral()) { - // ::= 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 + Expression *e = isExpression(o); + assert(e); + buf->writeByte('L'); + tv->valType->accept(this); + uinteger_t val = e->toUInteger(); + if (!tv->valType->isunsigned() && (sinteger_t)val < 0) { - s->error("Internal Compiler Error: C++ %s template value parameter is not supported", tv->valType->toChars()); - fatal(); + val = -val; + buf->writeByte('n'); } + buf->printf("%llu", val); + buf->writeByte('E'); } - else if (!tp || tp->isTemplateTypeParameter()) + else { - Type *t = isType(o); - assert(t); - t->accept(this); + ti->error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv->valType->toChars()); + fatal(); } - else if (tp->isTemplateAliasParameter()) + } + else if (tp->isTemplateAliasParameter()) + { + Dsymbol *d = isDsymbol(o); + Expression *e = isExpression(o); + if (d && d->isFuncDeclaration()) { - 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() && ((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 && ((VarExp*)e)->var->isVarDeclaration()) - { - VarDeclaration *vd = ((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 + bool is_nested = d->toParent() && + !d->toParent()->isModule() && + ((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 && ((VarExp*)e)->var->isVarDeclaration()) + { + VarDeclaration *vd = ((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)) { - s->error("Internal Compiler Error: %s is unsupported parameter for C++ template", o->toChars()); - fatal(); + cpp_mangle_name(d, false); } - } else { - s->error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); + ti->error("Internal Compiler Error: `%s` is unsupported parameter for C++ template", o->toChars()); fatal(); } } - if (is_var_arg) + else if(tp->isTemplateThisParameter()) { - buf.writeByte('E'); + ti->error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o->toChars()); + fatal(); } - buf.writeByte('E'); - return; + else + { + assert(0); + } + } + buf->writeByte('E'); + } + + void source_name(Dsymbol *s) + { + //printf("source_name(%s)\n", s->toChars()); + if (TemplateInstance *ti = s->isTemplateInstance()) + { + if (!substitute(ti->tempdecl)) + { + append(ti->tempdecl); + const char *name = ti->tempdecl->toAlias()->ident->toChars(); + buf->printf("%d", strlen(name)); + buf->writestring(name); + } + template_args(ti); } else { const char *name = s->ident->toChars(); - buf.printf("%d%s", strlen(name), name); + buf->printf("%d", strlen(name)); + buf->writestring(name); + } + } + + /******** + * See if s is actually an instance of a template + * Params: + * s = symbol + * Returns: + * if s is instance of a template, return the instance, otherwise return s + */ + Dsymbol *getInstance(Dsymbol *s) + { + Dsymbol *p = s->toParent(); + if (p) + { + if (TemplateInstance *ti = p->isTemplateInstance()) + return ti; + } + return s; + } + + /******** + * Get qualifier for `s`, meaning the symbol + * that s is in the symbol table of. + * The module does not count as a qualifier, because C++ + * does not have modules. + * Params: + * s = symbol that may have a qualifier + * Returns: + * qualifier, NULL if none + */ + static Dsymbol *getQualifier(Dsymbol *s) + { + Dsymbol *p = s->toParent(); + return (p && !p->isModule()) ? p : NULL; + } + + // Detect type char + static bool isChar(RootObject *o) + { + Type *t = isType(o); + return (t && t->equals(Type::tchar)); + } + + // Detect type ::std::char_traits + static bool isChar_traits_char(RootObject *o) + { + return isIdent_char(Id::char_traits, o); + } + + // Detect type ::std::allocator + static bool isAllocator_char(RootObject *o) + { + return isIdent_char(Id::allocator, o); + } + + // Detect type ::std::ident + static bool isIdent_char(Identifier *ident, RootObject *o) + { + Type *t = isType(o); + if (!t || t->ty != Tstruct) + return false; + Dsymbol *s = ((TypeStruct*)t)->toDsymbol(NULL); + if (s->ident != ident) + return false; + Dsymbol *p = s->toParent(); + if (!p) + return false; + TemplateInstance *ti = p->isTemplateInstance(); + if (!ti) + return false; + Dsymbol *q = getQualifier(ti); + return isStd(q) && ti->tiargs->dim == 1 && isChar((*ti->tiargs)[0]); + } + + /*** + * Detect template args > + * and write st if found. + * Returns: + * true if found + */ + bool char_std_char_traits_char(TemplateInstance *ti, const char *st) + { + if (ti->tiargs->dim == 2 && + isChar((*ti->tiargs)[0]) && + isChar_traits_char((*ti->tiargs)[1])) + { + buf->writestring(st); + return true; } + return false; } + void prefix_name(Dsymbol *s) { //printf("prefix_name(%s)\n", s->toChars()); if (!substitute(s)) { - Dsymbol *p = s->toParent(); - if (p && p->isTemplateInstance()) + Dsymbol *si = getInstance(s); + Dsymbol *p = getQualifier(si); + if (p) { - s = p; - if (exist(p->isTemplateInstance()->tempdecl)) + if (isStd(p)) { - p = NULL; - } - else - { - p = p->toParent(); - } - } + TemplateInstance *ti = si->isTemplateInstance(); + if (ti) + { + if (s->ident == Id::allocator) + { + buf->writestring("Sa"); + template_args(ti); + append(ti); + return; + } + if (s->ident == Id::basic_string) + { + // ::std::basic_string, ::std::allocator> + if (ti->tiargs->dim == 3 && + isChar((*ti->tiargs)[0]) && + isChar_traits_char((*ti->tiargs)[1]) && + isAllocator_char((*ti->tiargs)[2])) - if (p && !p->isModule()) - { - if (p->ident == Id::std && is_initial_qualifier(p)) - buf.writestring("St"); + { + buf->writestring("Ss"); + return; + } + buf->writestring("Sb"); // ::std::basic_string + template_args(ti); + append(ti); + return; + } + + // ::std::basic_istream> + if (s->ident == Id::basic_istream && + char_std_char_traits_char(ti, "Si")) + return; + + // ::std::basic_ostream> + if (s->ident == Id::basic_ostream && + char_std_char_traits_char(ti, "So")) + return; + + // ::std::basic_iostream> + if (s->ident == Id::basic_iostream && + char_std_char_traits_char(ti, "Sd")) + return; + } + 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)) + source_name(si); + if (!isStd(si)) { - return true; + /* Do this after the source_name() call to keep components[] + * in the right order. + * https://issues.dlang.org/show_bug.cgi?id=17947 + */ + append(si); } - p = p->toParent(); } - - return !p || p->isModule(); } void cpp_mangle_name(Dsymbol *s, bool qualified) @@ -301,12 +432,12 @@ class CppMangleVisitor : public Visitor //printf("cpp_mangle_name(%s, %d)\n", s->toChars(), qualified); Dsymbol *p = s->toParent(); Dsymbol *se = s; - bool dont_write_prefix = false; + bool write_prefix = true; if (p && p->isTemplateInstance()) { se = p; - if (exist(p->isTemplateInstance()->tempdecl)) - dont_write_prefix = true; + if (find(p->isTemplateInstance()->tempdecl) >= 0) + write_prefix = false; p = p->toParent(); } @@ -318,87 +449,70 @@ class CppMangleVisitor : public Visitor * 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 (isStd(p) && !qualified) { + TemplateInstance *ti = se->isTemplateInstance(); if (s->ident == Id::allocator) { - buf.writestring("Sa"); // "Sa" is short for ::std::allocator - source_name(se, true); + buf->writestring("Sa"); // "Sa" is short for ::std::allocator + template_args(ti); } 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", 26) == 0) + // ::std::basic_string, ::std::allocator> + if (ti->tiargs->dim == 3 && + isChar((*ti->tiargs)[0]) && + isChar_traits_char((*ti->tiargs)[1]) && + isAllocator_char((*ti->tiargs)[2])) + { - buf.remove(off - 2, 28); - buf.insert(off - 2, (const char *)"Ss", 2); + buf->writestring("Ss"); return; } - buf.setsize(off); - source_name(se, true); + buf->writestring("Sb"); // ::std::basic_string + template_args(ti); } - else if (s->ident == Id::basic_istream || - s->ident == Id::basic_ostream || - s->ident == Id::basic_iostream) + else { - /* 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", 21) == 0) + // ::std::basic_istream> + if (s->ident == Id::basic_istream) { - buf.remove(off, 21); - char mbuf[2]; - 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, 2); - return; + if (char_std_char_traits_char(ti, "Si")) + return; } - buf.setsize(off); - buf.writestring("St"); - source_name(se); - } - else - { - buf.writestring("St"); + else if (s->ident == Id::basic_ostream) + { + if (char_std_char_traits_char(ti, "So")) + return; + } + else if (s->ident == Id::basic_iostream) + { + if (char_std_char_traits_char(ti, "Sd")) + return; + } + buf->writestring("St"); source_name(se); } } else { - buf.writeByte('N'); - if (!dont_write_prefix) + buf->writeByte('N'); + if (write_prefix) prefix_name(p); source_name(se); - buf.writeByte('E'); + buf->writeByte('E'); } } else source_name(se); - store(s); + append(s); + } + + void CV_qualifiers(Type *t) + { + // CV-qualifiers are 'r': restrict, 'V': volatile, 'K': const + if (t->isConst()) + buf->writeByte('K'); } void mangle_variable(VarDeclaration *d, bool is_temp_arg_ref) @@ -406,27 +520,27 @@ class CppMangleVisitor : public Visitor // 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"); + 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"); + buf->writestring("_ZN"); prefix_name(p); source_name(d); - buf.writeByte('E'); + buf->writeByte('E'); } else //char beta[6] should mangle as "beta" { if (!is_temp_arg_ref) { - buf.writestring(d->ident->toChars()); + buf->writestring(d->ident->toChars()); } else { - buf.writestring("_Z"); + buf->writestring("_Z"); source_name(d); } } @@ -438,153 +552,140 @@ class CppMangleVisitor : public Visitor /* * ::= _Z * ::= - * ::= - * ::= + * ::= + * ::= */ TypeFunction *tf = (TypeFunction *)d->type; - buf.writestring("_Z"); - Dsymbol *p = d->toParent(); - TemplateDeclaration *ftd = getFuncTemplateDecl(d); - - if (p && !p->isModule() && tf->linkage == LINKcpp && !ftd) + buf->writestring("_Z"); + if (getFuncTemplateDecl(d)) { - 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", 17) == 0) - { - buf.remove(3, 14); - buf.insert(3, (const char *)"Sa", 2); - } - - // Replace ::std::basic_string with Sb - if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string", 21) == 0) - { - buf.remove(3, 18); - buf.insert(3, (const char *)"Sb", 2); - } - - // Replace ::std with St - if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std", 7) == 0) + /* It's an instance of a function template + */ + TemplateInstance *ti = d->parent->isTemplateInstance(); + assert(ti); + Dsymbol *p = ti->toParent(); + if (p && !p->isModule() && tf->linkage == LINKcpp) { - buf.remove(3, 4); - buf.insert(3, (const char *)"St", 2); + buf->writeByte('N'); + CV_qualifiers(d->type); + prefix_name(p); + if (d->isCtorDeclaration()) + buf->writestring("C1"); + else if (d->isDtorDeclaration()) + buf->writestring("D1"); + else + source_name(ti); + buf->writeByte('E'); } - if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std", 8) == 0) + else + source_name(ti); + headOfType(tf->nextOf()); // mangle return type + } + else + { + Dsymbol *p = d->toParent(); + if (p && !p->isModule() && tf->linkage == LINKcpp) { - buf.remove(4, 4); - buf.insert(4, (const char *)"St", 2); - } + /* ::= N [] E + * ::= N [] E + */ + buf->writeByte('N'); + CV_qualifiers(d->type); + + /* ::= + * ::= + * ::= + * ::= # empty + * ::= + * ::= + */ + prefix_name(p); + //printf("p: %s\n", buf.peekString()); - if (d->isDtorDeclaration()) - { - buf.writestring("D1"); + if (d->isCtorDeclaration()) + { + buf->writestring("C1"); + } + else if (d->isDtorDeclaration()) + { + buf->writestring("D1"); + } + else + { + source_name(d); + } + buf->writeByte('E'); } else { source_name(d); } - buf.writeByte('E'); - } - else if (ftd) - { - source_name(p); - this->is_top_level = true; - tf->nextOf()->accept(this); - this->is_top_level = false; - } - 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); + mangleFunctionParameters(tf->parameters, tf->varargs); } } - static int paramsCppMangleDg(void *ctx, size_t, Parameter *fparam) + void mangleFunctionParameters(Parameters *parameters, int varargs) { - CppMangleVisitor *mangler = (CppMangleVisitor *)ctx; - - 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(); - } -#ifdef IN_GCC - if (t->ty == Tsarray && Type::tvalist->ty == Tsarray) + struct ParamsCppMangle { - // Could be a va_list, which we mangle as a pointer. - Type *tb = t->toBasetype()->mutableOf(); - if (tb == Type::tvalist) + int numparams; + CppMangleVisitor *mangler; + + static int dg(void *ctx, size_t, Parameter *fparam) { - tb = t->nextOf()->pointerTo(); - t = tb->castMod(t->mod); + ParamsCppMangle *p = (ParamsCppMangle *)ctx; + CppMangleVisitor *mangler = p->mangler; + Type *t = Target::cppParameterType(fparam); + if (t->ty == Tsarray) + { + // Static arrays in D are passed by value; no counterpart in C++ + t->error(mangler->loc, "Internal Compiler Error: unable to pass static array `%s` to extern(C++) function, use pointer instead", + t->toChars()); + fatal(); + } + mangler->headOfType(t); + p->numparams++; + return 0; } - } -#else - 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(); - } -#endif + }; - /* If it is a basic, enum or struct type, - * then don't mark it const - */ - mangler->is_top_level = true; - if ((t->ty == Tenum || t->ty == Tstruct || t->ty == Tpointer || t->isTypeBasic()) && t->isConst()) - t->mutableOf()->accept(mangler); - else - t->accept(mangler); - mangler->is_top_level = false; - return 0; - } + ParamsCppMangle p; + p.numparams = 0; + p.mangler = this; - void argsCppMangle(Parameters *parameters, int varargs) - { if (parameters) - Parameter_foreach(parameters, ¶msCppMangleDg, (void*)this); + Parameter_foreach(parameters, &ParamsCppMangle::dg, (void*)&p); if (varargs) - buf.writestring("z"); - else if (!parameters || !parameters->dim) - buf.writeByte('v'); // encode ( ) parameters + buf->writeByte('z'); + else if (!p.numparams) + buf->writeByte('v'); // encode (void) parameters } public: - CppMangleVisitor() - : components(), buf(), is_top_level(false), components_on(true) + CppMangleVisitor(OutBuffer *buf, Loc loc) + : components(), buf(buf), loc(loc) { } - char *mangleOf(Dsymbol *s) + /***** + * Entry point. Append mangling to buf[] + * Params: + * s = symbol to mangle + */ + void mangleOf(Dsymbol *s) { - VarDeclaration *vd = s->isVarDeclaration(); - FuncDeclaration *fd = s->isFuncDeclaration(); - if (vd) + if (VarDeclaration *vd = s->isVarDeclaration()) { mangle_variable(vd, false); } - else if (fd) + else if (FuncDeclaration *fd = s->isFuncDeclaration()) { mangle_function(fd); } @@ -592,45 +693,91 @@ class CppMangleVisitor : public Visitor { assert(0); } - Target::prefixName(&buf, LINKcpp); - return buf.extractString(); } - void visit(Type *t) + /****** The rest is type mangling ************/ + + void error(Type *t) { -#ifdef IN_GCC - /* Make this the 'vendor extended type' when there is no - * C++ analog. - * u - */ - if (substitute(t)) - return; - assert(t->deco); - buf.printf("u%d%s", strlen(t->deco), t->deco); - store(t); -#else - if (t->isImmutable() || t->isShared()) + const char *p; + if (t->isImmutable()) + p = "`immutable` "; + else if (t->isShared()) + p = "`shared` "; + else + p = ""; + t->error(loc, "Internal Compiler Error: %stype `%s` can not be mapped to C++", p, t->toChars()); + fatal(); //Fatal, because this error should be handled in frontend + } + + /**************************** + * Mangle a type, + * treating it as a Head followed by a Tail. + * Params: + * t = Head of a type + */ + void headOfType(Type *t) + { + if (t->ty == Tclass) { - t->error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", t->toChars()); + mangleTypeClass((TypeClass*)t, true); } else { - t->error(Loc(), "Internal Compiler Error: type %s can not be mapped to C++\n", t->toChars()); + // For value types, strip const/immutable/shared from the head of the type + t->mutableOf()->unSharedOf()->accept(this); } - fatal(); //Fatal, because this error should be handled in frontend -#endif } - void visit(TypeBasic *t) + void visit(Type *t) { - /* ABI spec says: - * v void - * w wchar_t - * b bool - * c char - * a signed char - * h unsigned char - * s short + error(t); + } + + /****** + * Write out 1 or 2 character basic type mangling. + * Handle const and substitutions. + * Params: + * t = type to mangle + * p = if not 0, then character prefix + * c = mangling character + */ + void writeBasicType(Type *t, char p, char c) + { + if (p || t->isConst()) + { + if (substitute(t)) + return; + else + append(t); + } + CV_qualifiers(t); + if (p) + buf->writeByte(p); + buf->writeByte(c); + } + + void visit(TypeNull *t) + { + if (t->isImmutable() || t->isShared()) + return error(t); + + writeBasicType(t, 'D', 'n'); + } + + void visit(TypeBasic *t) + { + if (t->isImmutable() || t->isShared()) + return error(t); + + /* : + * 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 @@ -645,6 +792,12 @@ class CppMangleVisitor : public Visitor * e long double, __float80 * g __float128 * z ellipsis + * Dd 64 bit IEEE 754r decimal floating point + * De 128 bit IEEE 754r decimal floating point + * Df 32 bit IEEE 754r decimal floating point + * Dh 16 bit IEEE 754r half-precision floating point + * Di char32_t + * Ds char16_t * u # vendor extended type */ @@ -652,149 +805,121 @@ class CppMangleVisitor : public Visitor 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 = 'e'; 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((Type *)t); return; - } - if (t->isImmutable() || t->isShared()) - { - visit((Type *)t); - } - if (p || t->isConst()) - { - if (substitute(t)) - { - return; - } - else - { - store(t); - } - } - - if (t->isConst()) - buf.writeByte('K'); + 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 = 'e'; break; + case Tbool: c = 'b'; break; + case Tchar: c = 'c'; break; + case Twchar: c = 't'; break; // unsigned short (perhaps use 'Ds' ? + case Tdchar: c = 'w'; break; // wchar_t (UTF-32) (perhaps use 'Di' ? + case Timaginary32: p = 'G'; c = 'f'; break; // 'G' means imaginary + case Timaginary64: p = 'G'; c = 'd'; break; + case Timaginary80: p = 'G'; c = 'e'; break; + case Tcomplex32: p = 'C'; c = 'f'; break; // 'C' means complex + case Tcomplex64: p = 'C'; c = 'd'; break; + case Tcomplex80: p = 'C'; c = 'e'; break; - // Handle any target-specific basic types. - if (const char *tm = Target::cppTypeMangle(t)) - { - buf.writestring(tm); - } - else - { - if (p) - buf.writeByte(p); - buf.writeByte(c); + default: + // Handle any target-specific basic types. + if (const char *tm = Target::cppTypeMangle(t)) + { + if (substitute(t)) + return; + else + append(t); + CV_qualifiers(t); + buf->writestring(tm); + return; + } + return error(t); } + writeBasicType(t, p, c); } - void visit(TypeVector *t) { - is_top_level = false; + if (t->isImmutable() || t->isShared()) + return error(t); + if (substitute(t)) return; - store(t); - if (t->isImmutable() || t->isShared()) - { - visit((Type *)t); - } - if (t->isConst()) - buf.writeByte('K'); + append(t); + CV_qualifiers(t); // Handle any target-specific vector types. if (const char *tm = Target::cppTypeMangle(t)) { - buf.writestring(tm); + buf->writestring(tm); } else { assert(t->basetype && t->basetype->ty == Tsarray); assert(((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 +#if 0 + buf->writestring("Dv"); + buf->printf("%llu", ((TypeSArray *)t->basetype)->dim->toInteger()); // -- Gnu ABI v.4 + buf->writeByte('_'); +#else + buf->writestring("U8__vector"); //-- Gnu ABI v.3 +#endif t->basetype->nextOf()->accept(this); } } void visit(TypeSArray *t) { - is_top_level = false; - if (!substitute(t)) - store(t); if (t->isImmutable() || t->isShared()) - { - visit((Type *)t); - } - if (t->isConst()) - buf.writeByte('K'); - buf.printf("A%llu_", t->dim ? t->dim->toInteger() : 0); - t->next->accept(this); - } - - void visit(TypeDArray *t) - { - visit((Type *)t); - } + return error(t); - void visit(TypeAArray *t) - { - visit((Type *)t); + if (!substitute(t)) + append(t); + CV_qualifiers(t); + buf->writeByte('A'); + buf->printf("%llu", t->dim ? t->dim->toInteger() : 0); + buf->writeByte('_'); + t->next->accept(this); } void visit(TypePointer *t) { - is_top_level = false; + if (t->isImmutable() || t->isShared()) + return error(t); + if (substitute(t)) return; - if (t->isImmutable() || t->isShared()) - { - visit((Type *)t); - } - if (t->isConst()) - buf.writeByte('K'); - buf.writeByte('P'); + CV_qualifiers(t); + buf->writeByte('P'); t->next->accept(this); - store(t); + append(t); } void visit(TypeReference *t) { - is_top_level = false; + //printf("TypeReference %s\n", t->toChars()); if (substitute(t)) return; - buf.writeByte('R'); + buf->writeByte('R'); t->next->accept(this); - store(t); + append(t); } void visit(TypeFunction *t) { - is_top_level = false; /* * ::= F [Y] E * ::= + @@ -819,1198 +944,167 @@ class CppMangleVisitor : public Visitor */ if (substitute(t)) return; - buf.writeByte('F'); + buf->writeByte('F'); if (t->linkage == LINKc) - buf.writeByte('Y'); + 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); - } - - void visit(TypeDelegate *t) - { - visit((Type *)t); + mangleFunctionParameters(t->parameters, t->varargs); + buf->writeByte('E'); + append(t); } void visit(TypeStruct *t) { + if (t->isImmutable() || t->isShared()) + return error(t); + + /* __c_long and __c_ulong get special mangling + */ Identifier *id = t->sym->ident; //printf("struct id = '%s'\n", id->toChars()); - char c; if (id == Id::__c_long) - c = 'l'; + return writeBasicType(t, 0, 'l'); else if (id == Id::__c_ulong) - c = 'm'; - else - c = 0; - if (c) - { - if (t->isImmutable() || t->isShared()) - { - visit((Type *)t); - } - if (t->isConst()) - { - if (substitute(t)) - { - return; - } - else - { - store(t); - } - } + return writeBasicType(t, 0, 'm'); - if (t->isConst()) - buf.writeByte('K'); + //printf("TypeStruct %s\n", t->toChars()); + doSymbol(t); + } - buf.writeByte(c); - return; - } - is_top_level = false; + void visit(TypeEnum *t) + { + if (t->isImmutable() || t->isShared()) + return error(t); + + /* __c_(u)long(long) get special mangling + */ + Identifier *id = t->sym->ident; + //printf("enum id = '%s'\n", id->toChars()); + if (id == Id::__c_long) + return writeBasicType(t, 0, 'l'); + else if (id == Id::__c_ulong) + return writeBasicType(t, 0, 'm'); + else if (id == Id::__c_longlong) + return writeBasicType(t, 0, 'x'); + else if (id == Id::__c_ulonglong) + return writeBasicType(t, 0, 'y'); + + doSymbol(t); + } + /**************** + * Write structs and enums. + * Params: + * t = TypeStruct or TypeEnum + */ + void doSymbol(Type *t) + { if (substitute(t)) return; - if (t->isImmutable() || t->isShared()) - { - visit((Type *)t); - } - if (t->isConst()) - buf.writeByte('K'); + CV_qualifiers(t); // Handle any target-specific struct types. if (const char *tm = Target::cppTypeMangle(t)) { - buf.writestring(tm); + buf->writestring(tm); } else { - if (!substitute(t->sym)) + Dsymbol *s = t->toDsymbol(NULL); + Dsymbol *p = s->toParent(); + if (p && p->isTemplateInstance()) { - cpp_mangle_name(t->sym, t->isConst()); + /* https://issues.dlang.org/show_bug.cgi?id=17947 + * Substitute the template instance symbol, not the struct/enum symbol + */ + if (substitute(p)) + return; } - - if (t->isImmutable() || t->isShared()) + if (!substitute(s)) { - visit((Type *)t); + cpp_mangle_name(s, t->isConst()); } } - if (t->isConst()) - store(t); + append(t); } - void visit(TypeEnum *t) + void visit(TypeClass *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((Type *)t); - } - - if (t->isConst()) - store(t); + mangleTypeClass(t, false); } - void visit(TypeClass *t) + /************************ + * Mangle a class type. + * If it's the head, treat the initial pointer as a value type. + * Params: + * t = class type + * head = true for head of a type + */ + void mangleTypeClass(TypeClass *t, bool head) { + if (t->isImmutable() || t->isShared()) + return error(t); + + /* Mangle as a + */ if (substitute(t)) return; - if (t->isImmutable() || t->isShared()) + if (!head) + CV_qualifiers(t); + buf->writeByte('P'); + + CV_qualifiers(t); + { - visit((Type *)t); + Dsymbol *s = t->toDsymbol(NULL); + Dsymbol *p = s->toParent(); + if (p && p->isTemplateInstance()) + { + /* https://issues.dlang.org/show_bug.cgi?id=17947 + * Substitute the template instance symbol, not the class symbol + */ + if (substitute(p)) + return; + } } - 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); + append(NULL); // C++ would have an extra type here + append(t); } const char *mangle_typeinfo(Dsymbol *s) { - buf.writestring("_ZTI"); + buf->writestring("_ZTI"); cpp_mangle_name(s, false); - return buf.extractString(); + return buf->extractString(); } }; const char *toCppMangleItanium(Dsymbol *s) { //printf("toCppMangleItanium(%s)\n", s->toChars()); - CppMangleVisitor v; - return v.mangleOf(s); + OutBuffer buf; + CppMangleVisitor v(&buf, s->loc); + v.mangleOf(s); + return buf.extractString(); } const char *cppTypeInfoMangleItanium(Dsymbol *s) { //printf("cppTypeInfoMangleItanium(%s)\n", s->toChars()); - CppMangleVisitor v; - return v.mangle_typeinfo(s); -} - -// Windows DMC and Microsoft Visual C++ mangling -#define VC_SAVED_TYPE_CNT 10 -#define VC_SAVED_IDENT_CNT 10 - -class VisualCPPMangler : public Visitor -{ - const char *saved_idents[VC_SAVED_IDENT_CNT]; - Type *saved_types[VC_SAVED_TYPE_CNT]; - - // 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 - { - IS_NOT_TOP_TYPE = 0x1, - MANGLE_RETURN_TYPE = 0x2, - IGNORE_CONST = 0x4, - IS_DMC = 0x8 - }; - - int flags; OutBuffer buf; - - VisualCPPMangler(VisualCPPMangler *rvl) - : flags(0), buf() - { - flags |= (rvl->flags & IS_DMC); - memcpy(&saved_idents, &rvl->saved_idents, sizeof(const char*) * VC_SAVED_IDENT_CNT); - memcpy(&saved_types, &rvl->saved_types, sizeof(Type*) * VC_SAVED_TYPE_CNT); - } - -public: - VisualCPPMangler(bool isdmc) - : flags(0), buf() - { - if (isdmc) - { - flags |= IS_DMC; - } - memset(&saved_idents, 0, sizeof(const char*) * VC_SAVED_IDENT_CNT); - memset(&saved_types, 0, sizeof(Type*) * VC_SAVED_TYPE_CNT); - } - - void visit(Type *type) - { - if (type->isImmutable() || type->isShared()) - { - type->error(Loc(), "Internal Compiler Error: shared or immutable types can not be mapped to C++ (%s)", type->toChars()); - } - else - { - type->error(Loc(), "Internal Compiler Error: type %s can not be mapped to C++\n", type->toChars()); - } - fatal(); // Fatal, because this error should be handled in frontend - } - - 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((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; - } - mangleModifier(type); - switch (type->ty) - { - 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((Type*)type); return; - } - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - 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; - } - - 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((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 - 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((Type*)type); - return; - } - - assert(type->next); - if (type->next->ty == Tfunction) - { - const char *arg = mangleFunctionType((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((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); - } - } - - void visit(TypeReference *type) - { - //printf("visit(TypeReference); type = %s\n", type->toChars()); - if (checkTypeSaved(type)) - return; - - if (type->isImmutable() || type->isShared()) - { - visit((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((TypeSArray*)type->next); - } - else - { - type->next->accept(this); - } - } - - 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); - } - - void visit(TypeStruct *type) - { - Identifier *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((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 == CPPMANGLEclass ? 'V' : 'U'); - mangleIdent(type->sym); - } - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_CONST; - } - - 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((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 - 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 == CPPMANGLEstruct ? 'U' : 'V'); - - mangleIdent(type->sym); - flags &= ~IS_NOT_TOP_TYPE; - flags &= ~IGNORE_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(), (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((TypeFunction *)d->type, (bool)d->needThis(), d->isCtorDeclaration() || d->isDtorDeclaration()); - buf.writestring(args); - } - - 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))) - { - 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((Type*)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); - } - - 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()) - { - buf.writestring("?1"); - return; - } - if (TemplateInstance *ti = sym->isTemplateInstance()) - { - VisualCPPMangler tmp((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) - { - tmp.mangleIdent(sym->parent, true); - is_dmc_template = true; - } - - bool is_var_arg = false; - for (size_t i = 0; i < ti->tiargs->dim; i++) - { - RootObject *o = (*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(); - } - - 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.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); - } - } - else - { - sym->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(&tmp); - } - else if (tp->isTemplateAliasParameter()) - { - 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('$'); - tmp.buf.writeByte('1'); - tmp.mangleFunction(d->isFuncDeclaration()); - } - else if (e && e->op == TOKvar && ((VarExp*)e)->var->isVarDeclaration()) - { - tmp.buf.writeByte('$'); - if (flags & IS_DMC) - tmp.buf.writeByte('1'); - else - tmp.buf.writeByte('E'); - tmp.mangleVariable(((VarExp*)e)->var->isVarDeclaration()); - } - else if (d && d->isTemplateDeclaration() && d->isTemplateDeclaration()->onemember) - { - - Dsymbol *ds = d->isTemplateDeclaration()->onemember; - if (flags & IS_DMC) - { - 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(); - } - } - tmp.mangleIdent(d); - } - else - { - sym->error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o->toChars()); - fatal(); - } - - } - 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 - { - if (checkAndSaveIdent(name)) - return; - } - } - buf.writestring(name); - buf.writeByte('@'); - } - - // returns true if name already saved - bool checkAndSaveIdent(const char *name) - { - for (size_t i = 0; i < VC_SAVED_IDENT_CNT; i++) - { - 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; - } - } - return false; - } - - void saveIdent(const char *name) - { - for (size_t i = 0; i < VC_SAVED_IDENT_CNT; i++) - { - 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; - } - } - } - - void mangleIdent(Dsymbol *sym, bool dont_use_back_reference = false) - { - // ::= @ - // ::= - // ::= - - // ::= @ - // ::= ?$ @