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/types.cc | |
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/types.cc')
-rw-r--r-- | gcc/d/types.cc | 986 |
1 files changed, 986 insertions, 0 deletions
diff --git a/gcc/d/types.cc b/gcc/d/types.cc new file mode 100644 index 0000000..d5eac2d --- /dev/null +++ b/gcc/d/types.cc @@ -0,0 +1,986 @@ +/* types.cc -- Lower D frontend types to GCC trees. + Copyright (C) 2006-2018 Free Software Foundation, Inc. + +GCC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 3, or (at your option) +any later version. + +GCC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GCC; see the file COPYING3. If not see +<http://www.gnu.org/licenses/>. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" + +#include "dmd/attrib.h" +#include "dmd/aggregate.h" +#include "dmd/enum.h" +#include "dmd/expression.h" +#include "dmd/identifier.h" +#include "dmd/mtype.h" +#include "dmd/target.h" + +#include "tree.h" +#include "fold-const.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "tm.h" +#include "function.h" +#include "toplev.h" +#include "target.h" +#include "stringpool.h" +#include "stor-layout.h" +#include "attribs.h" + +#include "d-tree.h" + + +/* Return TRUE if TYPE is a static array va_list. This is for compatibility + with the C ABI, where va_list static arrays are passed by reference. + However for every other case in D, static arrays are passed by value. */ + +bool +valist_array_p (Type *type) +{ + if (Type::tvalist->ty == Tsarray) + { + Type *tb = type->toBasetype (); + if (same_type_p (tb, Type::tvalist)) + return true; + } + + return false; +} + +/* Returns true if TYPE contains no actual data, just various + possible combinations of empty aggregates. */ + +bool +empty_aggregate_p (tree type) +{ + if (!AGGREGATE_TYPE_P (type)) + return false; + + /* Want the element type for arrays. */ + if (TREE_CODE (type) == ARRAY_TYPE) + return empty_aggregate_p (TREE_TYPE (type)); + + /* Recursively check all fields. */ + for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) + { + if (TREE_CODE (field) == FIELD_DECL + && !empty_aggregate_p (TREE_TYPE (field))) + return false; + } + + return true; +} + +/* Returns true if T1 and T2 are related to each other. */ + +bool +same_type_p (Type *t1, Type *t2) +{ + /* Types are equal. */ + if (t1 == t2) + return true; + + /* Types derive from the same base. */ + Type *tb1 = t1->toBasetype (); + Type *tb2 = t2->toBasetype (); + if (tb1 == tb2) + return true; + + /* Types are mutably the same type. */ + if (tb1->ty == tb2->ty && tb1->equivalent (tb2)) + return true; + + return false; +} + +/* Returns 'Object' type which all D classes are derived from. */ + +Type * +get_object_type (void) +{ + if (ClassDeclaration::object) + return ClassDeclaration::object->type; + + error ("missing or corrupt object.d"); + return Type::terror; +} + + +/* Returns a static array of TYPE which has SIZE number of elements. */ + +tree +make_array_type (Type *type, unsigned HOST_WIDE_INT size) +{ + /* In [arrays/void-arrays], void arrays can also be static, the length is + specified in bytes. */ + if (type->toBasetype ()->ty == Tvoid) + type = Type::tuns8; + + /* In [arrays/static-arrays], a static array with a dimension of 0 is allowed, + but no space is allocated for it. */ + if (size == 0) + { + tree range = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype), + TYPE_UNSIGNED (sizetype)); + tree index = build_range_type (range, size_zero_node, NULL_TREE); + + tree t = build_array_type (build_ctype (type), index); + TYPE_SIZE (t) = bitsize_zero_node; + TYPE_SIZE_UNIT (t) = size_zero_node; + return t; + } + + return build_array_type (build_ctype (type), + build_index_type (size_int (size - 1))); +} + +/* Builds a record type whose name is NAME. NFIELDS is the number of fields, + provided as field ident/type pairs. */ + +tree +make_struct_type (const char *name, int nfields, ...) +{ + tree fields = NULL_TREE; + va_list ap; + + va_start (ap, nfields); + + for (int i = 0; i < nfields; i++) + { + tree ident = va_arg (ap, tree); + tree type = va_arg (ap, tree); + tree field = build_decl (BUILTINS_LOCATION, FIELD_DECL, ident, type); + DECL_CHAIN (field) = fields; + fields = field; + } + + va_end (ap); + + tree type = make_node (RECORD_TYPE); + finish_builtin_struct (type, name, fields, NULL_TREE); + + return type; +} + +/* Return qualified type variant of TYPE determined by modifier value MOD. */ + +tree +insert_type_modifiers (tree type, unsigned mod) +{ + int quals = 0; + + switch (mod) + { + case MODconst: + case MODwild: + case MODwildconst: + case MODimmutable: + case MODshared | MODconst: + case MODshared | MODwild: + case MODshared | MODwildconst: + quals |= TYPE_QUAL_CONST; + break; + + case 0: + case MODshared: + break; + + default: + gcc_unreachable (); + } + + tree qualtype = build_qualified_type (type, quals); + + /* Mark whether the type is qualified 'shared'. */ + if (mod & MODshared) + TYPE_SHARED (qualtype) = 1; + + return qualtype; +} + +/* Adds FIELD into the aggregate TYPE at OFFSET. */ + +void +insert_aggregate_field (tree type, tree field, size_t offset) +{ + DECL_FIELD_CONTEXT (field) = type; + SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (TREE_TYPE (field))); + DECL_FIELD_OFFSET (field) = size_int (offset); + DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node; + + TREE_ADDRESSABLE (field) = TYPE_SHARED (TREE_TYPE (field)); + + layout_decl (field, 0); + TYPE_FIELDS (type) = chainon (TYPE_FIELDS (type), field); +} + +/* For all decls in the FIELDS chain, adjust their field offset by OFFSET. + This is done as the frontend puts fields into the outer struct, and so + their offset is from the beginning of the aggregate. + We want the offset to be from the beginning of the anonymous aggregate. */ + +static void +fixup_anonymous_offset (tree fields, tree offset) +{ + while (fields != NULL_TREE) + { + /* Traverse all nested anonymous aggregates to update their offset. + Set the anonymous decl offset to its first member. */ + tree ftype = TREE_TYPE (fields); + if (TYPE_NAME (ftype) && anon_aggrname_p (TYPE_IDENTIFIER (ftype))) + { + tree vfields = TYPE_FIELDS (ftype); + fixup_anonymous_offset (vfields, offset); + DECL_FIELD_OFFSET (fields) = DECL_FIELD_OFFSET (vfields); + } + else + { + tree voffset = DECL_FIELD_OFFSET (fields); + DECL_FIELD_OFFSET (fields) = size_binop (MINUS_EXPR, voffset, offset); + } + + fields = DECL_CHAIN (fields); + } +} + +/* Iterate over all MEMBERS of an aggregate, and add them as fields to CONTEXT. + If INHERITED_P is true, then the members derive from a base class. + Returns the number of fields found. */ + +static size_t +layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) +{ + size_t fields = 0; + + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *sym = (*members)[i]; + VarDeclaration *var = sym->isVarDeclaration (); + if (var != NULL) + { + /* Skip fields that have already been added. */ + if (!inherited_p && var->csym != NULL) + continue; + + /* If this variable was really a tuple, add all tuple fields. */ + if (var->aliassym) + { + TupleDeclaration *td = var->aliassym->isTupleDeclaration (); + Dsymbols tmembers; + /* No other way to coerce the underlying type out of the tuple. + Frontend should have already validated this. */ + for (size_t j = 0; j < td->objects->dim; j++) + { + RootObject *ro = (*td->objects)[j]; + gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION); + Expression *e = (Expression *) ro; + gcc_assert (e->op == TOKdsymbol); + DsymbolExp *se = (DsymbolExp *) e; + + tmembers.push (se->s); + } + + fields += layout_aggregate_members (&tmembers, context, + inherited_p); + continue; + } + + /* Insert the field declaration at its given offset. */ + if (var->isField ()) + { + const char *ident = var->ident ? var->ident->toChars () : NULL; + tree field = create_field_decl (declaration_type (var), ident, + inherited_p, inherited_p); + insert_aggregate_field (context, field, var->offset); + + /* Because the front-end shares field decls across classes, don't + create the corresponding back-end symbol unless we are adding + it to the aggregate it is defined in. */ + if (!inherited_p) + { + DECL_LANG_SPECIFIC (field) = build_lang_decl (var); + var->csym = field; + } + + fields += 1; + continue; + } + } + + /* Anonymous struct/union are flattened by the frontend. However, we + want to keep the record layout in-tact when building the type. */ + AnonDeclaration *ad = sym->isAnonDeclaration (); + if (ad != NULL) + { + /* Use a counter to create anonymous type names. */ + static int anon_cnt = 0; + char buf[32]; + sprintf (buf, anon_aggrname_format (), anon_cnt++); + + tree ident = get_identifier (buf); + tree type = make_node (ad->isunion ? UNION_TYPE : RECORD_TYPE); + ANON_AGGR_TYPE_P (type) = 1; + d_keep (type); + + /* Build the type declaration. */ + tree decl = build_decl (make_location_t (ad->loc), + TYPE_DECL, ident, type); + DECL_CONTEXT (decl) = context; + DECL_ARTIFICIAL (decl) = 1; + + TYPE_CONTEXT (type) = context; + TYPE_NAME (type) = decl; + TYPE_STUB_DECL (type) = decl; + + /* Recursively iterator over the anonymous members. */ + fields += layout_aggregate_members (ad->decl, type, inherited_p); + + /* Remove from the anon fields the base offset of this anonymous + aggregate. Undoes what is set-up in setFieldOffset, but doesn't + affect field accesses. */ + tree offset = size_int (ad->anonoffset); + fixup_anonymous_offset (TYPE_FIELDS (type), offset); + + finish_aggregate_type (ad->anonstructsize, ad->anonalignsize, + type, NULL); + + /* And make the corresponding data member. */ + tree field = create_field_decl (type, NULL, 0, 0); + insert_aggregate_field (context, field, ad->anonoffset); + continue; + } + + /* Other kinds of attributes don't create a scope. */ + AttribDeclaration *attrib = sym->isAttribDeclaration (); + if (attrib != NULL) + { + Dsymbols *decls = attrib->include (NULL, NULL); + if (decls != NULL) + { + fields += layout_aggregate_members (decls, context, inherited_p); + continue; + } + } + + /* Same with template mixins and namespaces. */ + if (sym->isTemplateMixin () || sym->isNspace ()) + { + ScopeDsymbol *scopesym = sym->isScopeDsymbol (); + if (scopesym->members) + { + fields += layout_aggregate_members (scopesym->members, context, + inherited_p); + continue; + } + } + } + + return fields; +} + +/* Write out all fields for aggregate BASE. For classes, write out all + interfaces first, then the base class fields. */ + +static void +layout_aggregate_type (AggregateDeclaration *decl, tree type, + AggregateDeclaration *base) +{ + ClassDeclaration *cd = base->isClassDeclaration (); + bool inherited_p = (decl != base); + + if (cd != NULL) + { + if (cd->baseClass) + layout_aggregate_type (decl, type, cd->baseClass); + else + { + /* This is the base class (Object) or interface. */ + tree objtype = TREE_TYPE (build_ctype (cd->type)); + + /* Add the vtable pointer, and optionally the monitor fields. */ + InterfaceDeclaration *id = cd->isInterfaceDeclaration (); + if (!id || id->vtblInterfaces->dim == 0) + { + tree field = create_field_decl (vtbl_ptr_type_node, "__vptr", 1, + inherited_p); + DECL_VIRTUAL_P (field) = 1; + TYPE_VFIELD (type) = field; + DECL_FCONTEXT (field) = objtype; + insert_aggregate_field (type, field, 0); + } + + if (!id && !cd->isCPPclass ()) + { + tree field = create_field_decl (ptr_type_node, "__monitor", 1, + inherited_p); + insert_aggregate_field (type, field, Target::ptrsize); + } + } + + if (cd->vtblInterfaces) + { + for (size_t i = 0; i < cd->vtblInterfaces->dim; i++) + { + BaseClass *bc = (*cd->vtblInterfaces)[i]; + tree field = create_field_decl (vtbl_ptr_type_node, NULL, 1, 1); + insert_aggregate_field (type, field, bc->offset); + } + } + } + + if (base->members) + { + size_t fields = layout_aggregate_members (base->members, type, + inherited_p); + gcc_assert (fields == base->fields.dim); + + /* Make sure that all fields have been created. */ + if (!inherited_p) + { + for (size_t i = 0; i < base->fields.dim; i++) + { + VarDeclaration *var = base->fields[i]; + gcc_assert (var->csym != NULL); + } + } + } +} + +/* Given a record type TYPE, whose size and alignment are determined by + STRUCTSIZE and ALIGNSIZE. Apply any type attributes ATTRS and compute + the finalized record mode. */ + +void +finish_aggregate_type (unsigned structsize, unsigned alignsize, + tree type, UserAttributeDeclaration *attrs) +{ + TYPE_SIZE (type) = NULL_TREE; + + /* Write out any GCC attributes that were applied to the type declaration. */ + if (attrs) + { + Expressions *eattrs = attrs->getAttributes (); + decl_attributes (&type, build_attributes (eattrs), + ATTR_FLAG_TYPE_IN_PLACE); + } + + /* Set size and alignment as requested by frontend. */ + TYPE_SIZE (type) = bitsize_int (structsize * BITS_PER_UNIT); + TYPE_SIZE_UNIT (type) = size_int (structsize); + SET_TYPE_ALIGN (type, alignsize * BITS_PER_UNIT); + TYPE_PACKED (type) = (alignsize == 1); + + /* Set the back-end type mode. */ + compute_record_mode (type); + + /* Fix up all variants of this aggregate type. */ + for (tree t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t)) + { + if (t == type) + continue; + + TYPE_FIELDS (t) = TYPE_FIELDS (type); + TYPE_LANG_SPECIFIC (t) = TYPE_LANG_SPECIFIC (type); + SET_TYPE_ALIGN (t, TYPE_ALIGN (type)); + TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type); + gcc_assert (TYPE_MODE (t) == TYPE_MODE (type)); + } +} + + +/* Implements the visitor interface to build the GCC trees of all + Type AST classes emitted from the D Front-end, where CTYPE holds + the cached back-end representation to be returned. */ + +class TypeVisitor : public Visitor +{ + using Visitor::visit; + +public: + TypeVisitor (void) + { + } + + /* This should be overridden by each type class. */ + + void visit (Type *) + { + gcc_unreachable (); + } + + /* Type assigned to erroneous expressions or constructs that + failed during the semantic stage. */ + + void visit (TypeError *t) + { + t->ctype = error_mark_node; + } + + /* Type assigned to generic nullable types. */ + + void visit (TypeNull *t) + { + t->ctype = ptr_type_node; + } + + + /* Basic Data Types. */ + + void visit (TypeBasic *t) + { + /* [type/basic-data-types] + + void no type. + bool 8-bit boolean value. + byte 8-bit signed value. + ubyte 8-bit unsigned value. + short 16-bit signed value. + ushort 16-bit unsigned value. + int 32-bit signed value. + uint 32-bit unsigned value. + long 64-bit signed value. + ulong 64-bit unsigned value. + cent 128-bit signed value. + ucent 128-bit unsigned value. + float 32-bit IEEE 754 floating-point value. + double 64-bit IEEE 754 floating-point value. + real largest FP size implemented in hardware. + ifloat imaginary float. + idouble imaginary double. + ireal imaginary real. + cfloat complex float. + cdouble complex double. + creal complex real. + char UTF-8 code unit. + wchar UTF-16 code unit. + dchar UTF-32 code unit. */ + + switch (t->ty) + { + case Tvoid: t->ctype = void_type_node; break; + case Tbool: t->ctype = d_bool_type; break; + case Tint8: t->ctype = d_byte_type; break; + case Tuns8: t->ctype = d_ubyte_type; break; + case Tint16: t->ctype = d_short_type; break; + case Tuns16: t->ctype = d_ushort_type; break; + case Tint32: t->ctype = d_int_type; break; + case Tuns32: t->ctype = d_uint_type; break; + case Tint64: t->ctype = d_long_type; break; + case Tuns64: t->ctype = d_ulong_type; break; + case Tint128: t->ctype = d_cent_type; break; + case Tuns128: t->ctype = d_ucent_type; break; + case Tfloat32: t->ctype = float_type_node; break; + case Tfloat64: t->ctype = double_type_node; break; + case Tfloat80: t->ctype = long_double_type_node; break; + case Timaginary32: t->ctype = ifloat_type_node; break; + case Timaginary64: t->ctype = idouble_type_node; break; + case Timaginary80: t->ctype = ireal_type_node; break; + case Tcomplex32: t->ctype = complex_float_type_node; break; + case Tcomplex64: t->ctype = complex_double_type_node; break; + case Tcomplex80: t->ctype = complex_long_double_type_node; break; + case Tchar: t->ctype = char8_type_node; break; + case Twchar: t->ctype = char16_type_node; break; + case Tdchar: t->ctype = char32_type_node; break; + default: gcc_unreachable (); + } + + TYPE_NAME (t->ctype) = get_identifier (t->toChars ()); + } + + + /* Derived Data Types. */ + + /* Build a simple pointer to data type, analogous to C pointers. */ + + void visit (TypePointer *t) + { + t->ctype = build_pointer_type (build_ctype (t->next)); + } + + /* Build a dynamic array type, consisting of a length and a pointer + to the array data. */ + + void visit (TypeDArray *t) + { + /* In [abi/arrays], dynamic array layout is: + .length array dimension. + .ptr pointer to array data. */ + t->ctype = make_struct_type (t->toChars (), 2, + get_identifier ("length"), + build_ctype (Type::tsize_t), + get_identifier ("ptr"), + build_pointer_type (build_ctype (t->next))); + TYPE_DYNAMIC_ARRAY (t->ctype) = 1; + TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); + d_keep (t->ctype); + } + + /* Build a static array type, distinguished from dynamic arrays by + having a length fixed at compile-time, analogous to C arrays. */ + + void visit (TypeSArray *t) + { + if (t->dim->isConst () && t->dim->type->isintegral ()) + { + uinteger_t size = t->dim->toUInteger (); + t->ctype = make_array_type (t->next, size); + } + else + { + error ("invalid expression for static array dimension: %s", + t->dim->toChars ()); + gcc_unreachable (); + } + } + + /* Build a vector type, a fixed array of floating or integer types. */ + + void visit (TypeVector *t) + { + int nunits = ((TypeSArray *) t->basetype)->dim->toUInteger (); + tree inner = build_ctype (t->elementType ()); + + /* Same rationale as void static arrays. */ + if (inner == void_type_node) + inner = build_ctype (Type::tuns8); + + t->ctype = build_vector_type (inner, nunits); + TYPE_NAME (t->ctype) = get_identifier (t->toChars ()); + layout_type (t->ctype); + } + + /* Build an associative array type, distinguished from arrays by having an + index that's not necessarily an integer, and can be sparsely populated. */ + + void visit (TypeAArray *t) + { + /* In [abi/associative-arrays], associative arrays are a struct that only + consist of a pointer to an opaque, implementation defined type. */ + t->ctype = make_struct_type (t->toChars (), 1, + get_identifier ("ptr"), ptr_type_node); + TYPE_ASSOCIATIVE_ARRAY (t->ctype) = 1; + TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); + d_keep (t->ctype); + } + + /* Build type for a function declaration, which consists of a return type, + and a list of parameter types, and a linkage attribute. */ + + void visit (TypeFunction *t) + { + tree fnparams = NULL_TREE; + tree fntype; + + /* [function/variadic] + + Variadic functions with D linkage have an additional hidden argument + with the name _arguments passed to the function. */ + if (t->varargs == 1 && t->linkage == LINKd) + { + tree type = build_ctype (Type::typeinfotypelist->type); + fnparams = chainon (fnparams, build_tree_list (0, type)); + } + + if (t->parameters) + { + size_t n_args = Parameter::dim (t->parameters); + + for (size_t i = 0; i < n_args; i++) + { + tree type = type_passed_as (Parameter::getNth (t->parameters, i)); + fnparams = chainon (fnparams, build_tree_list (0, type)); + } + } + + /* When the last parameter is void_list_node, that indicates a fixed length + parameter list, otherwise function is treated as variadic. */ + if (t->varargs != 1) + fnparams = chainon (fnparams, void_list_node); + + if (t->next != NULL) + { + fntype = build_ctype (t->next); + if (t->isref) + fntype = build_reference_type (fntype); + } + else + fntype = void_type_node; + + /* Could the function type be self referenced by parameters? */ + t->ctype = build_function_type (fntype, fnparams); + TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); + d_keep (t->ctype); + + /* Handle any special support for calling conventions. */ + switch (t->linkage) + { + case LINKpascal: + case LINKwindows: + /* [attribute/linkage] + + The Windows convention is distinct from the C convention only + on Win32, where it is equivalent to the stdcall convention. */ + if (!global.params.is64bit) + t->ctype = insert_type_attribute (t->ctype, "stdcall"); + break; + + case LINKc: + case LINKcpp: + case LINKd: + case LINKobjc: + /* [abi/function-calling-conventions] + + The extern (C) and extern (D) calling convention matches + the C calling convention used by the supported C compiler + on the host system. */ + break; + + default: + gcc_unreachable (); + } + } + + /* Build a delegate type, an aggregate of two pieces of data, an object + reference and a pointer to a non-static member function, or a pointer + to a closure and a pointer to a nested function. */ + + void visit (TypeDelegate *t) + { + /* In [abi/delegates], delegate layout is: + .ptr context pointer. + .funcptr pointer to function. */ + tree fntype = build_ctype (t->next); + tree dgtype = build_vthis_function (void_type_node, fntype); + + TYPE_ATTRIBUTES (dgtype) = TYPE_ATTRIBUTES (fntype); + TYPE_LANG_SPECIFIC (dgtype) = TYPE_LANG_SPECIFIC (fntype); + + t->ctype = make_struct_type (t->toChars (), 2, + get_identifier ("ptr"), + build_ctype (Type::tvoidptr), + get_identifier ("funcptr"), + build_pointer_type (dgtype)); + TYPE_DELEGATE (t->ctype) = 1; + TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); + d_keep (t->ctype); + } + + + /* User Defined Types. */ + + /* Build a named enum type, a distinct value whose values are restrict to + a group of constants of the same underlying base type. */ + + void visit (TypeEnum *t) + { + tree basetype = (t->sym->memtype) + ? build_ctype (t->sym->memtype) : void_type_node; + + if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE) + { + /* Enums in D2 can have a base type that is not necessarily integral. + For these, we simplify this a little by using the base type directly + instead of building an ENUMERAL_TYPE. */ + t->ctype = build_variant_type_copy (basetype); + } + else + { + t->ctype = make_node (ENUMERAL_TYPE); + ENUM_IS_SCOPED (t->ctype) = 1; + TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); + d_keep (t->ctype); + + if (flag_short_enums) + TYPE_PACKED (t->ctype) = 1; + + TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8; + TYPE_SIZE (t->ctype) = 0; + + TYPE_MIN_VALUE (t->ctype) = TYPE_MIN_VALUE (basetype); + TYPE_MAX_VALUE (t->ctype) = TYPE_MAX_VALUE (basetype); + layout_type (t->ctype); + + tree values = NULL_TREE; + if (t->sym->members) + { + for (size_t i = 0; i < t->sym->members->dim; i++) + { + EnumMember *member = (*t->sym->members)[i]->isEnumMember (); + /* Templated functions can seep through to the back-end + just ignore for now. */ + if (member == NULL) + continue; + + tree ident = get_identifier (member->ident->toChars ()); + tree value = build_integer_cst (member->value ()->toInteger (), + basetype); + + /* Build an identifier for the enumeration constant. */ + tree decl = build_decl (make_location_t (member->loc), + CONST_DECL, ident, basetype); + DECL_CONTEXT (decl) = t->ctype; + TREE_CONSTANT (decl) = 1; + TREE_READONLY (decl) = 1; + DECL_INITIAL (decl) = value; + + /* Add this enumeration constant to the list for this type. */ + values = chainon (values, build_tree_list (ident, decl)); + } + } + + TYPE_VALUES (t->ctype) = values; + TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype); + build_type_decl (t->ctype, t->sym); + } + + if (t->sym->userAttribDecl) + { + Expressions *eattrs = t->sym->userAttribDecl->getAttributes (); + decl_attributes (&t->ctype, build_attributes (eattrs), + ATTR_FLAG_TYPE_IN_PLACE); + } + } + + /* Build a struct or union type. Layout should be exactly represented + as an equivalent C struct, except for non-POD or nested structs. */ + + void visit (TypeStruct *t) + { + /* Need to set this right away in case of self-references. */ + t->ctype = make_node (t->sym->isUnionDeclaration () + ? UNION_TYPE : RECORD_TYPE); + d_keep (t->ctype); + + TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); + + if (t->sym->members) + { + /* Must set up the overall size and alignment before determining + the context or laying out fields as those types may make + recursive references to this type. */ + unsigned structsize = t->sym->structsize; + unsigned alignsize = (t->sym->alignment != STRUCTALIGN_DEFAULT) + ? t->sym->alignment : t->sym->alignsize; + + TYPE_SIZE (t->ctype) = bitsize_int (structsize * BITS_PER_UNIT); + TYPE_SIZE_UNIT (t->ctype) = size_int (structsize); + SET_TYPE_ALIGN (t->ctype, alignsize * BITS_PER_UNIT); + TYPE_PACKED (t->ctype) = (alignsize == 1); + compute_record_mode (t->ctype); + + /* Put out all fields. */ + layout_aggregate_type (t->sym, t->ctype, t->sym); + finish_aggregate_type (structsize, alignsize, t->ctype, + t->sym->userAttribDecl); + } + + TYPE_CONTEXT (t->ctype) = d_decl_context (t->sym); + build_type_decl (t->ctype, t->sym); + + /* For structs with a user defined postblit or a destructor, + also set TREE_ADDRESSABLE on the type and all variants. + This will make the struct be passed around by reference. */ + if (t->sym->postblit || t->sym->dtor) + { + for (tree tv = t->ctype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv)) + TREE_ADDRESSABLE (tv) = 1; + } + } + + /* Build a class type. Whereas structs are value types, classes are + reference types, with all the object-orientated features. */ + + void visit (TypeClass *t) + { + /* Need to set ctype right away in case of self-references to + the type during this call. */ + tree basetype = make_node (RECORD_TYPE); + t->ctype = build_pointer_type (basetype); + d_keep (t->ctype); + + /* Note that lang_specific data is assigned to both the reference + and the underlying record type. */ + TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t); + TYPE_LANG_SPECIFIC (basetype) = TYPE_LANG_SPECIFIC (t->ctype); + CLASS_TYPE_P (basetype) = 1; + + /* Put out all fields, including from each base class. */ + layout_aggregate_type (t->sym, basetype, t->sym); + finish_aggregate_type (t->sym->structsize, t->sym->alignsize, + basetype, t->sym->userAttribDecl); + + /* Classes only live in memory, so always set the TREE_ADDRESSABLE bit. */ + for (tree tv = basetype; tv != NULL_TREE; tv = TYPE_NEXT_VARIANT (tv)) + TREE_ADDRESSABLE (tv) = 1; + + /* Type is final, there are no derivations. */ + if (t->sym->storage_class & STCfinal) + TYPE_FINAL_P (basetype) = 1; + + /* Create BINFO even if debugging is off. This is needed to keep + references to inherited types. */ + if (!t->sym->isInterfaceDeclaration ()) + TYPE_BINFO (basetype) = build_class_binfo (NULL_TREE, t->sym); + else + { + unsigned offset = 0; + + TYPE_BINFO (basetype) = build_interface_binfo (NULL_TREE, t->sym, + offset); + } + + /* Associate all virtual methods with the class too. */ + for (size_t i = 0; i < t->sym->vtbl.dim; i++) + { + FuncDeclaration *fd = t->sym->vtbl[i]->isFuncDeclaration (); + tree method = fd ? get_symbol_decl (fd) : error_mark_node; + + if (!error_operand_p (method) + && DECL_CONTEXT (method) == basetype + && !chain_member (method, TYPE_FIELDS (basetype))) + TYPE_FIELDS (basetype) = chainon (TYPE_FIELDS (basetype), method); + } + + TYPE_CONTEXT (basetype) = d_decl_context (t->sym); + build_type_decl (basetype, t->sym); + } +}; + + +/* Build a tree from a frontend Type. */ + +tree +build_ctype (Type *t) +{ + if (!t->ctype) + { + TypeVisitor v; + + /* Strip const modifiers from type before building. This is done + to ensure that back-end treats e.g: const (T) as a variant of T, + and not as two distinct types. */ + if (t->isNaked ()) + t->accept (&v); + else + { + Type *tb = t->castMod (0); + if (!tb->ctype) + tb->accept (&v); + t->ctype = insert_type_modifiers (tb->ctype, t->mod); + } + } + + return t->ctype; +} |