aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/cppmangle.c
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gcc.gnu.org>2018-10-28 19:51:47 +0000
committerIain Buclaw <ibuclaw@gcc.gnu.org>2018-10-28 19:51:47 +0000
commitb4c522fabd0df7be08882d2207df8b2765026110 (patch)
treeb5ffc312b0a441c1ba24323152aec463fdbe5e9f /gcc/d/dmd/cppmangle.c
parent01ce9e31a02c8039d88e90f983735104417bf034 (diff)
downloadgcc-b4c522fabd0df7be08882d2207df8b2765026110.zip
gcc-b4c522fabd0df7be08882d2207df8b2765026110.tar.gz
gcc-b4c522fabd0df7be08882d2207df8b2765026110.tar.bz2
Add D front-end, libphobos library, and D2 testsuite.
ChangeLog: * Makefile.def (target_modules): Add libphobos. (flags_to_pass): Add GDC, GDCFLAGS, GDC_FOR_TARGET and GDCFLAGS_FOR_TARGET. (dependencies): Make libphobos depend on libatomic, libbacktrace configure, and zlib configure. (language): Add language d. * Makefile.in: Rebuild. * Makefile.tpl (BUILD_EXPORTS): Add GDC and GDCFLAGS. (HOST_EXPORTS): Add GDC. (POSTSTAGE1_HOST_EXPORTS): Add GDC and GDC_FOR_BUILD. (BASE_TARGET_EXPORTS): Add GDC. (GDC_FOR_BUILD, GDC, GDCFLAGS): New variables. (GDC_FOR_TARGET, GDC_FLAGS_FOR_TARGET): New variables. (EXTRA_HOST_FLAGS): Add GDC. (STAGE1_FLAGS_TO_PASS): Add GDC. (EXTRA_TARGET_FLAGS): Add GDC and GDCFLAGS. * config-ml.in: Treat GDC and GDCFLAGS like other compiler/flag environment variables. * configure: Rebuild. * configure.ac: Add target-libphobos to target_libraries. Set and substitute GDC_FOR_BUILD and GDC_FOR_TARGET. config/ChangeLog: * multi.m4: Set GDC. gcc/ChangeLog: * Makefile.in (tm_d_file_list, tm_d_include_list): New variables. (TM_D_H, D_TARGET_DEF, D_TARGET_H, D_TARGET_OBJS): New variables. (tm_d.h, cs-tm_d.h, default-d.o): New rules. (d/d-target-hooks-def.h, s-d-target-hooks-def-h): New rules. (s-tm-texi): Also check timestamp on d-target.def. (generated_files): Add TM_D_H and d-target-hooks-def.h. (build/genhooks.o): Also depend on D_TARGET_DEF. * config.gcc (tm_d_file, d_target_objs, target_has_targetdm): New variables. * config/aarch64/aarch64-d.c: New file. * config/aarch64/aarch64-linux.h (GNU_USER_TARGET_D_CRITSEC_SIZE): Define. * config/aarch64/aarch64-protos.h (aarch64_d_target_versions): New prototype. * config/aarch64/aarch64.h (TARGET_D_CPU_VERSIONS): Define. * config/aarch64/t-aarch64 (aarch64-d.o): New rule. * config/arm/arm-d.c: New file. * config/arm/arm-protos.h (arm_d_target_versions): New prototype. * config/arm/arm.h (TARGET_D_CPU_VERSIONS): Define. * config/arm/linux-eabi.h (EXTRA_TARGET_D_OS_VERSIONS): Define. * config/arm/t-arm (arm-d.o): New rule. * config/default-d.c: New file. * config/glibc-d.c: New file. * config/gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/i386/i386-d.c: New file. * config/i386/i386-protos.h (ix86_d_target_versions): New prototype. * config/i386/i386.h (TARGET_D_CPU_VERSIONS): Define. * config/i386/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define. (GNU_USER_TARGET_D_CRITSEC_SIZE): Define. * config/i386/t-i386 (i386-d.o): New rule. * config/kfreebsd-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/kopensolaris-gnu.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/linux-android.h (ANDROID_TARGET_D_OS_VERSIONS): Define. * config/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/mips/linux-common.h (EXTRA_TARGET_D_OS_VERSIONS): Define. * config/mips/mips-d.c: New file. * config/mips/mips-protos.h (mips_d_target_versions): New prototype. * config/mips/mips.h (TARGET_D_CPU_VERSIONS): Define. * config/mips/t-mips (mips-d.o): New rule. * config/powerpcspe/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/powerpcspe/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/powerpcspe/powerpcspe-d.c: New file. * config/powerpcspe/powerpcspe-protos.h (rs6000_d_target_versions): New prototype. * config/powerpcspe/powerpcspe.c (rs6000_output_function_epilogue): Support GNU D by using 0 as the language type. * config/powerpcspe/powerpcspe.h (TARGET_D_CPU_VERSIONS): Define. * config/powerpcspe/t-powerpcspe (powerpcspe-d.o): New rule. * config/riscv/riscv-d.c: New file. * config/riscv/riscv-protos.h (riscv_d_target_versions): New prototype. * config/riscv/riscv.h (TARGET_D_CPU_VERSIONS): Define. * config/riscv/t-riscv (riscv-d.o): New rule. * config/rs6000/linux.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/rs6000/linux64.h (GNU_USER_TARGET_D_OS_VERSIONS): Define. * config/rs6000/rs6000-d.c: New file. * config/rs6000/rs6000-protos.h (rs6000_d_target_versions): New prototype. * config/rs6000/rs6000.c (rs6000_output_function_epilogue): Support GNU D by using 0 as the language type. * config/rs6000/rs6000.h (TARGET_D_CPU_VERSIONS): Define. * config/rs6000/t-rs6000 (rs6000-d.o): New rule. * config/s390/s390-d.c: New file. * config/s390/s390-protos.h (s390_d_target_versions): New prototype. * config/s390/s390.h (TARGET_D_CPU_VERSIONS): Define. * config/s390/t-s390 (s390-d.o): New rule. * config/sparc/sparc-d.c: New file. * config/sparc/sparc-protos.h (sparc_d_target_versions): New prototype. * config/sparc/sparc.h (TARGET_D_CPU_VERSIONS): Define. * config/sparc/t-sparc (sparc-d.o): New rule. * config/t-glibc (glibc-d.o): New rule. * configure: Regenerated. * configure.ac (tm_d_file): New variable. (tm_d_file_list, tm_d_include_list, d_target_objs): Add substitutes. * doc/contrib.texi (Contributors): Add self for the D frontend. * doc/frontends.texi (G++ and GCC): Mention D as a supported language. * doc/install.texi (Configuration): Mention libphobos as an option for --enable-shared. Mention d as an option for --enable-languages. (Testing): Mention check-d as a target. * doc/invoke.texi (Overall Options): Mention .d, .dd, and .di as file name suffixes. Mention d as a -x option. * doc/sourcebuild.texi (Top Level): Mention libphobos. * doc/standards.texi (Standards): Add section on D language. * doc/tm.texi: Regenerated. * doc/tm.texi.in: Add @node for D language and ABI, and @hook for TARGET_CPU_VERSIONS, TARGET_D_OS_VERSIONS, and TARGET_D_CRITSEC_SIZE. * dwarf2out.c (is_dlang): New function. (gen_compile_unit_die): Use DW_LANG_D for D. (declare_in_namespace): Return module die for D, instead of adding extra declarations into the namespace. (gen_namespace_die): Generate DW_TAG_module for D. (gen_decl_die): Handle CONST_DECLSs for D. (dwarf2out_decl): Likewise. (prune_unused_types_walk_local_classes): Handle DW_tag_interface_type. (prune_unused_types_walk): Handle DW_tag_interface_type same as other kinds of aggregates. * gcc.c (default_compilers): Add entries for .d, .dd and .di. * genhooks.c: Include d/d-target.def. gcc/po/ChangeLog: * EXCLUDES: Add sources from d/dmd. gcc/testsuite/ChangeLog: * gcc.misc-tests/help.exp: Add D to option descriptions check. * gdc.dg/asan/asan.exp: New file. * gdc.dg/asan/gdc272.d: New test. * gdc.dg/compilable.d: New test. * gdc.dg/dg.exp: New file. * gdc.dg/gdc254.d: New test. * gdc.dg/gdc260.d: New test. * gdc.dg/gdc270a.d: New test. * gdc.dg/gdc270b.d: New test. * gdc.dg/gdc282.d: New test. * gdc.dg/gdc283.d: New test. * gdc.dg/imports/gdc170.d: New test. * gdc.dg/imports/gdc231.d: New test. * gdc.dg/imports/gdc239.d: New test. * gdc.dg/imports/gdc241a.d: New test. * gdc.dg/imports/gdc241b.d: New test. * gdc.dg/imports/gdc251a.d: New test. * gdc.dg/imports/gdc251b.d: New test. * gdc.dg/imports/gdc253.d: New test. * gdc.dg/imports/gdc254a.d: New test. * gdc.dg/imports/gdc256.d: New test. * gdc.dg/imports/gdc27.d: New test. * gdc.dg/imports/gdcpkg256/package.d: New test. * gdc.dg/imports/runnable.d: New test. * gdc.dg/link.d: New test. * gdc.dg/lto/lto.exp: New file. * gdc.dg/lto/ltotests_0.d: New test. * gdc.dg/lto/ltotests_1.d: New test. * gdc.dg/runnable.d: New test. * gdc.dg/simd.d: New test. * gdc.test/gdc-test.exp: New file. * lib/gdc-dg.exp: New file. * lib/gdc.exp: New file. libphobos/ChangeLog: * Makefile.am: New file. * Makefile.in: New file. * acinclude.m4: New file. * aclocal.m4: New file. * config.h.in: New file. * configure: New file. * configure.ac: New file. * d_rules.am: New file. * libdruntime/Makefile.am: New file. * libdruntime/Makefile.in: New file. * libdruntime/__entrypoint.di: New file. * libdruntime/__main.di: New file. * libdruntime/gcc/attribute.d: New file. * libdruntime/gcc/backtrace.d: New file. * libdruntime/gcc/builtins.d: New file. * libdruntime/gcc/config.d.in: New file. * libdruntime/gcc/deh.d: New file. * libdruntime/gcc/libbacktrace.d.in: New file. * libdruntime/gcc/unwind/arm.d: New file. * libdruntime/gcc/unwind/arm_common.d: New file. * libdruntime/gcc/unwind/c6x.d: New file. * libdruntime/gcc/unwind/generic.d: New file. * libdruntime/gcc/unwind/package.d: New file. * libdruntime/gcc/unwind/pe.d: New file. * m4/autoconf.m4: New file. * m4/druntime.m4: New file. * m4/druntime/cpu.m4: New file. * m4/druntime/libraries.m4: New file. * m4/druntime/os.m4: New file. * m4/gcc_support.m4: New file. * m4/gdc.m4: New file. * m4/libtool.m4: New file. * src/Makefile.am: New file. * src/Makefile.in: New file. * src/libgphobos.spec.in: New file. * testsuite/Makefile.am: New file. * testsuite/Makefile.in: New file. * testsuite/config/default.exp: New file. * testsuite/lib/libphobos-dg.exp: New file. * testsuite/lib/libphobos.exp: New file. * testsuite/testsuite_flags.in: New file. From-SVN: r265573
Diffstat (limited to 'gcc/d/dmd/cppmangle.c')
-rw-r--r--gcc/d/dmd/cppmangle.c1103
1 files changed, 1103 insertions, 0 deletions
diff --git a/gcc/d/dmd/cppmangle.c b/gcc/d/dmd/cppmangle.c
new file mode 100644
index 0000000..bb919a5
--- /dev/null
+++ b/gcc/d/dmd/cppmangle.c
@@ -0,0 +1,1103 @@
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2018 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ * 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 <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "mars.h"
+#include "dsymbol.h"
+#include "mtype.h"
+#include "scope.h"
+#include "init.h"
+#include "expression.h"
+#include "attrib.h"
+#include "declaration.h"
+#include "template.h"
+#include "id.h"
+#include "enum.h"
+#include "import.h"
+#include "aggregate.h"
+#include "target.h"
+
+typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param);
+int Parameter_foreach(Parameters *parameters, ForeachDg dg, void *ctx, size_t *pn = NULL);
+
+class CppMangleVisitor : public Visitor
+{
+ Objects components; // array of components available for substitution
+ OutBuffer *buf; // append the mangling to buf[]
+ Loc loc; // location for use in error messages
+
+ public:
+ // Write <seq-id> to buf
+ void write_seq_id(size_t i)
+ {
+ if (i >= 36)
+ {
+ write_seq_id(i / 36);
+ i %= 36;
+ }
+ i += (i < 10) ? '0' : 'A' - 10;
+ buf->writeByte((char)i);
+ }
+
+ bool substitute(RootObject *p)
+ {
+ //printf("substitute %s\n", p ? p->toChars() : NULL);
+ int i = find(p);
+ if (i >= 0)
+ {
+ //printf("\tmatch\n");
+ /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ...
+ */
+ buf->writeByte('S');
+ if (i)
+ {
+ write_seq_id(i - 1);
+ }
+ buf->writeByte('_');
+ return true;
+ }
+ return false;
+ }
+
+ /******
+ * See if `p` exists in components[]
+ * Returns:
+ * index if found, -1 if not
+ */
+ int find(RootObject *p)
+ {
+ //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;
+ }
+
+ /*********************
+ * Append p to components[]
+ */
+ void append(RootObject *p)
+ {
+ //printf("append %p %d %s\n", p, p.dyncast(), p ? p.toChars() : "null");
+ components.push(p);
+ }
+
+ /************************
+ * 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)
+ {
+ 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
+ }
+
+ /******************************
+ * Write the mangled representation of the template arguments.
+ * Params:
+ * ti = the template instance
+ */
+ void template_args(TemplateInstance *ti)
+ {
+ /* <template-args> ::= I <template-arg>+ 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];
+
+ /*
+ * <template-arg> ::= <type> # type or template
+ * ::= X <expression> E # expression
+ * ::= <expr-primary> # simple expressions
+ * ::= I <template-arg>* E # argument pack
+ */
+ if (tp->isTemplateTupleParameter())
+ {
+ buf->writeByte('I'); // argument pack
+
+ // mangle the rest of the arguments as types
+ for (size_t j = i; j < ti->tiargs->dim; j++)
+ {
+ Type *t = isType((*ti->tiargs)[j]);
+ assert(t);
+ t->accept(this);
+ }
+
+ buf->writeByte('E');
+ break;
+ }
+ if (tp->isTemplateTypeParameter())
+ {
+ Type *t = isType(o);
+ assert(t);
+ t->accept(this);
+ }
+ else if (TemplateValueParameter *tv = tp->isTemplateValueParameter())
+ {
+ // <expr-primary> ::= L <type> <value number> E # integer literal
+ if (tv->valType->isintegral())
+ {
+ 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)
+ {
+ val = -val;
+ buf->writeByte('n');
+ }
+ buf->printf("%llu", val);
+ buf->writeByte('E');
+ }
+ else
+ {
+ ti->error("Internal Compiler Error: C++ `%s` template value parameter is not supported", tv->valType->toChars());
+ fatal();
+ }
+ }
+ else if (tp->isTemplateAliasParameter())
+ {
+ Dsymbol *d = isDsymbol(o);
+ Expression *e = isExpression(o);
+ 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
+ {
+ ti->error("Internal Compiler Error: `%s` is unsupported parameter for C++ template", o->toChars());
+ fatal();
+ }
+ }
+ else if(tp->isTemplateThisParameter())
+ {
+ ti->error("Internal Compiler Error: C++ `%s` template this parameter is not supported", o->toChars());
+ fatal();
+ }
+ 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", 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<char>
+ static bool isChar_traits_char(RootObject *o)
+ {
+ return isIdent_char(Id::char_traits, o);
+ }
+
+ // Detect type ::std::allocator<char>
+ static bool isAllocator_char(RootObject *o)
+ {
+ return isIdent_char(Id::allocator, o);
+ }
+
+ // Detect type ::std::ident<char>
+ 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 <char, ::std::char_traits<char>>
+ * 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 *si = getInstance(s);
+ Dsymbol *p = getQualifier(si);
+ if (p)
+ {
+ if (isStd(p))
+ {
+ 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<char, ::std::char_traits<char>, ::std::allocator<char>>
+ if (ti->tiargs->dim == 3 &&
+ isChar((*ti->tiargs)[0]) &&
+ isChar_traits_char((*ti->tiargs)[1]) &&
+ isAllocator_char((*ti->tiargs)[2]))
+
+ {
+ buf->writestring("Ss");
+ return;
+ }
+ buf->writestring("Sb"); // ::std::basic_string
+ template_args(ti);
+ append(ti);
+ return;
+ }
+
+ // ::std::basic_istream<char, ::std::char_traits<char>>
+ if (s->ident == Id::basic_istream &&
+ char_std_char_traits_char(ti, "Si"))
+ return;
+
+ // ::std::basic_ostream<char, ::std::char_traits<char>>
+ if (s->ident == Id::basic_ostream &&
+ char_std_char_traits_char(ti, "So"))
+ return;
+
+ // ::std::basic_iostream<char, ::std::char_traits<char>>
+ if (s->ident == Id::basic_iostream &&
+ char_std_char_traits_char(ti, "Sd"))
+ return;
+ }
+ buf->writestring("St");
+ }
+ else
+ prefix_name(p);
+ }
+ source_name(si);
+ if (!isStd(si))
+ {
+ /* 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);
+ }
+ }
+ }
+
+ 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 write_prefix = true;
+ if (p && p->isTemplateInstance())
+ {
+ se = p;
+ if (find(p->isTemplateInstance()->tempdecl) >= 0)
+ write_prefix = false;
+ 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 (isStd(p) && !qualified)
+ {
+ TemplateInstance *ti = se->isTemplateInstance();
+ if (s->ident == Id::allocator)
+ {
+ buf->writestring("Sa"); // "Sa" is short for ::std::allocator
+ template_args(ti);
+ }
+ else if (s->ident == Id::basic_string)
+ {
+ // ::std::basic_string<char, ::std::char_traits<char>, ::std::allocator<char>>
+ if (ti->tiargs->dim == 3 &&
+ isChar((*ti->tiargs)[0]) &&
+ isChar_traits_char((*ti->tiargs)[1]) &&
+ isAllocator_char((*ti->tiargs)[2]))
+
+ {
+ buf->writestring("Ss");
+ return;
+ }
+ buf->writestring("Sb"); // ::std::basic_string
+ template_args(ti);
+ }
+ else
+ {
+ // ::std::basic_istream<char, ::std::char_traits<char>>
+ if (s->ident == Id::basic_istream)
+ {
+ if (char_std_char_traits_char(ti, "Si"))
+ return;
+ }
+ 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 (write_prefix)
+ prefix_name(p);
+ source_name(se);
+ buf->writeByte('E');
+ }
+ }
+ else
+ source_name(se);
+ 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)
+ {
+ // 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)
+ {
+ buf->writestring(d->ident->toChars());
+ }
+ else
+ {
+ buf->writestring("_Z");
+ source_name(d);
+ }
+ }
+ }
+
+ void mangle_function(FuncDeclaration *d)
+ {
+ //printf("mangle_function(%s)\n", d->toChars());
+ /*
+ * <mangled-name> ::= _Z <encoding>
+ * <encoding> ::= <function name> <bare-function-type>
+ * ::= <data name>
+ * ::= <special-name>
+ */
+ TypeFunction *tf = (TypeFunction *)d->type;
+
+ buf->writestring("_Z");
+ if (getFuncTemplateDecl(d))
+ {
+ /* 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->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');
+ }
+ else
+ source_name(ti);
+ headOfType(tf->nextOf()); // mangle return type
+ }
+ else
+ {
+ Dsymbol *p = d->toParent();
+ if (p && !p->isModule() && tf->linkage == LINKcpp)
+ {
+ /* <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
+ * ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
+ */
+ buf->writeByte('N');
+ CV_qualifiers(d->type);
+
+ /* <prefix> ::= <prefix> <unqualified-name>
+ * ::= <template-prefix> <template-args>
+ * ::= <template-param>
+ * ::= # empty
+ * ::= <substitution>
+ * ::= <prefix> <data-member-prefix>
+ */
+ prefix_name(p);
+ //printf("p: %s\n", buf.peekString());
+
+ if (d->isCtorDeclaration())
+ {
+ buf->writestring("C1");
+ }
+ else if (d->isDtorDeclaration())
+ {
+ buf->writestring("D1");
+ }
+ else
+ {
+ source_name(d);
+ }
+ buf->writeByte('E');
+ }
+ else
+ {
+ source_name(d);
+ }
+ }
+
+ if (tf->linkage == LINKcpp) //Template args accept extern "C" symbols with special mangling
+ {
+ assert(tf->ty == Tfunction);
+ mangleFunctionParameters(tf->parameters, tf->varargs);
+ }
+ }
+
+ void mangleFunctionParameters(Parameters *parameters, int varargs)
+ {
+ struct ParamsCppMangle
+ {
+ int numparams;
+ CppMangleVisitor *mangler;
+
+ static int dg(void *ctx, size_t, Parameter *fparam)
+ {
+ 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;
+ }
+ };
+
+ ParamsCppMangle p;
+ p.numparams = 0;
+ p.mangler = this;
+
+ if (parameters)
+ Parameter_foreach(parameters, &ParamsCppMangle::dg, (void*)&p);
+
+ if (varargs)
+ buf->writeByte('z');
+ else if (!p.numparams)
+ buf->writeByte('v'); // encode (void) parameters
+ }
+
+public:
+ CppMangleVisitor(OutBuffer *buf, Loc loc)
+ : components(), buf(buf), loc(loc)
+ {
+ }
+
+ /*****
+ * Entry point. Append mangling to buf[]
+ * Params:
+ * s = symbol to mangle
+ */
+ void mangleOf(Dsymbol *s)
+ {
+ if (VarDeclaration *vd = s->isVarDeclaration())
+ {
+ mangle_variable(vd, false);
+ }
+ else if (FuncDeclaration *fd = s->isFuncDeclaration())
+ {
+ mangle_function(fd);
+ }
+ else
+ {
+ assert(0);
+ }
+ }
+
+ /****** The rest is type mangling ************/
+
+ void error(Type *t)
+ {
+ 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)
+ {
+ mangleTypeClass((TypeClass*)t, true);
+ }
+ else
+ {
+ // For value types, strip const/immutable/shared from the head of the type
+ t->mutableOf()->unSharedOf()->accept(this);
+ }
+ }
+
+ void visit(Type *t)
+ {
+ 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);
+
+ /* <builtin-type>:
+ * 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
+ * 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 <source-name> # 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 = '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;
+
+ 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)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ if (substitute(t))
+ return;
+ append(t);
+ CV_qualifiers(t);
+
+ // Handle any target-specific vector types.
+ if (const char *tm = Target::cppTypeMangle(t))
+ {
+ buf->writestring(tm);
+ }
+ else
+ {
+ assert(t->basetype && t->basetype->ty == Tsarray);
+ assert(((TypeSArray *)t->basetype)->dim);
+ buf->writestring("U8__vector"); //-- Gnu ABI v.3
+ t->basetype->nextOf()->accept(this);
+ }
+ }
+
+ void visit(TypeSArray *t)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(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)
+ {
+ if (t->isImmutable() || t->isShared())
+ return error(t);
+
+ if (substitute(t))
+ return;
+ CV_qualifiers(t);
+ buf->writeByte('P');
+ t->next->accept(this);
+ append(t);
+ }
+
+ void visit(TypeReference *t)
+ {
+ //printf("TypeReference %s\n", t->toChars());
+ if (substitute(t))
+ return;
+ buf->writeByte('R');
+ t->next->accept(this);
+ append(t);
+ }
+
+ void visit(TypeFunction *t)
+ {
+ /*
+ * <function-type> ::= F [Y] <bare-function-type> E
+ * <bare-function-type> ::= <signature type>+
+ * # 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);
+ 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());
+ if (id == Id::__c_long)
+ return writeBasicType(t, 0, 'l');
+ else if (id == Id::__c_ulong)
+ return writeBasicType(t, 0, 'm');
+
+ //printf("TypeStruct %s\n", t->toChars());
+ doSymbol(t);
+ }
+
+
+ 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;
+ CV_qualifiers(t);
+
+ // Handle any target-specific struct types.
+ if (const char *tm = Target::cppTypeMangle(t))
+ {
+ buf->writestring(tm);
+ }
+ else
+ {
+ 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 struct/enum symbol
+ */
+ if (substitute(p))
+ return;
+ }
+ if (!substitute(s))
+ {
+ cpp_mangle_name(s, t->isConst());
+ }
+ }
+ if (t->isConst())
+ append(t);
+ }
+
+ void visit(TypeClass *t)
+ {
+ mangleTypeClass(t, false);
+ }
+
+ /************************
+ * 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 <pointer to><struct>
+ */
+ if (substitute(t))
+ return;
+ if (!head)
+ CV_qualifiers(t);
+ buf->writeByte('P');
+
+ CV_qualifiers(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 (!substitute(t->sym))
+ {
+ cpp_mangle_name(t->sym, t->isConst());
+ }
+ if (t->isConst())
+ append(NULL); // C++ would have an extra type here
+ append(t);
+ }
+
+ const char *mangle_typeinfo(Dsymbol *s)
+ {
+ buf->writestring("_ZTI");
+ cpp_mangle_name(s, false);
+ return buf->extractString();
+ }
+};
+
+const char *toCppMangleItanium(Dsymbol *s)
+{
+ //printf("toCppMangleItanium(%s)\n", s->toChars());
+ OutBuffer buf;
+ CppMangleVisitor v(&buf, s->loc);
+ v.mangleOf(s);
+ return buf.extractString();
+}
+
+const char *cppTypeInfoMangleItanium(Dsymbol *s)
+{
+ //printf("cppTypeInfoMangleItanium(%s)\n", s->toChars());
+ OutBuffer buf;
+ buf.writestring("_ZTI"); // "TI" means typeinfo structure
+ CppMangleVisitor v(&buf, s->loc);
+ v.cpp_mangle_name(s, false);
+ return buf.extractString();
+}