diff options
author | Iain Buclaw <ibuclaw@gcc.gnu.org> | 2018-10-28 19:51:47 +0000 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gcc.gnu.org> | 2018-10-28 19:51:47 +0000 |
commit | b4c522fabd0df7be08882d2207df8b2765026110 (patch) | |
tree | b5ffc312b0a441c1ba24323152aec463fdbe5e9f /gcc/d/dmd/cppmangle.c | |
parent | 01ce9e31a02c8039d88e90f983735104417bf034 (diff) | |
download | gcc-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.c | 1103 |
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(); +} |