diff gcc/d/modules.cc @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/d/modules.cc	Thu Feb 13 11:34:05 2020 +0900
@@ -0,0 +1,925 @@
+/* modules.cc -- D module initialization and termination.
+   Copyright (C) 2013-2020 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/declaration.h"
+#include "dmd/identifier.h"
+#include "dmd/module.h"
+
+#include "tree.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "tm.h"
+#include "function.h"
+#include "cgraph.h"
+#include "stor-layout.h"
+#include "toplev.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "stringpool.h"
+
+#include "d-tree.h"
+
+
+/* D generates module information to inform the runtime library which modules
+   need some kind of special handling.  All `static this()', `static ~this()',
+   and `unittest' functions for a given module are aggregated into a single
+   function - one for each kind - and a pointer to that function is inserted
+   into the ModuleInfo instance for that module.
+
+   Module information for a particular module is indicated with an ABI defined
+   structure derived from ModuleInfo.  ModuleInfo is a variably sized struct
+   with two fixed base fields.  The first field `flags' determines what
+   information is packed immediately after the record type.
+
+   Like TypeInfo, the runtime library provides the definitions of the ModuleInfo
+   structure, as well as accessors for the variadic fields.  So we only define
+   layout compatible POD_structs for ModuleInfo.  */
+
+/* The internally represented ModuleInfo and CompilerDSO types.  */
+static tree moduleinfo_type;
+static tree compiler_dso_type;
+static tree dso_registry_fn;
+
+/* The DSO slot for use by the druntime implementation.  */
+static tree dso_slot_node;
+
+/* For registering and deregistering DSOs with druntime, we have one global
+   constructor and destructor per object that calls _d_dso_registry with the
+   respective DSO record.  To ensure that this is only done once, a
+   `dso_initialized' variable is introduced to guard repeated calls.  */
+static tree dso_initialized_node;
+
+/* The beginning and end of the `minfo' section.  */
+static tree start_minfo_node;
+static tree stop_minfo_node;
+
+/* Record information about module initialization, termination,
+   unit testing, and thread local storage in the compilation.  */
+
+struct GTY(()) module_info
+{
+  vec<tree, va_gc> *ctors;
+  vec<tree, va_gc> *dtors;
+  vec<tree, va_gc> *ctorgates;
+
+  vec<tree, va_gc> *sharedctors;
+  vec<tree, va_gc> *shareddtors;
+  vec<tree, va_gc> *sharedctorgates;
+
+  vec<tree, va_gc> *unitTests;
+};
+
+/* These must match the values in libdruntime/object_.d.  */
+
+enum module_info_flags
+{
+  MIctorstart	    = 0x1,
+  MIctordone	    = 0x2,
+  MIstandalone	    = 0x4,
+  MItlsctor	    = 0x8,
+  MItlsdtor	    = 0x10,
+  MIctor	    = 0x20,
+  MIdtor	    = 0x40,
+  MIxgetMembers	    = 0x80,
+  MIictor	    = 0x100,
+  MIunitTest	    = 0x200,
+  MIimportedModules = 0x400,
+  MIlocalClasses    = 0x800,
+  MIname	    = 0x1000
+};
+
+/* The ModuleInfo information structure for the module currently being compiled.
+   Assuming that only ever process one at a time.  */
+
+static module_info *current_moduleinfo;
+
+/* When compiling with -fbuilding-libphobos-tests, this contains information
+   about the module that gets compiled in only when unittests are enabled.  */
+
+static module_info *current_testing_module;
+
+/* The declaration of the current module being compiled.  */
+
+static Module *current_module_decl;
+
+/* Static constructors and destructors (not D `static this').  */
+
+static GTY(()) vec<tree, va_gc> *static_ctor_list;
+static GTY(()) vec<tree, va_gc> *static_dtor_list;
+
+/* Returns an internal function identified by IDENT.  This is used
+   by both module initialization and dso handlers.  */
+
+static FuncDeclaration *
+get_internal_fn (tree ident)
+{
+  Module *mod = current_module_decl;
+  const char *name = IDENTIFIER_POINTER (ident);
+
+  if (!mod)
+    mod = Module::rootModule;
+
+  if (name[0] == '*')
+    {
+      tree s = mangle_internal_decl (mod, name + 1, "FZv");
+      name = IDENTIFIER_POINTER (s);
+    }
+
+  FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid,
+						   Identifier::idPool (name));
+  fd->loc = Loc (mod->srcfile->toChars (), 1, 0);
+  fd->parent = mod;
+  fd->protection.kind = PROTprivate;
+  fd->semanticRun = PASSsemantic3done;
+
+  return fd;
+}
+
+/* Generate an internal function identified by IDENT.
+   The function body to add is in EXPR.  */
+
+static tree
+build_internal_fn (tree ident, tree expr)
+{
+  FuncDeclaration *fd = get_internal_fn (ident);
+  tree decl = get_symbol_decl (fd);
+
+  tree old_context = start_function (fd);
+  rest_of_decl_compilation (decl, 1, 0);
+  add_stmt (expr);
+  finish_function (old_context);
+
+  /* D static ctors, static dtors, unittests, and the ModuleInfo
+     chain function are always private.  */
+  TREE_PUBLIC (decl) = 0;
+  TREE_USED (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+
+  return decl;
+}
+
+/* Build and emit a function identified by IDENT that increments (in order)
+   all variables in GATES, then calls the list of functions in FUNCTIONS.  */
+
+static tree
+build_funcs_gates_fn (tree ident, vec<tree, va_gc> *functions,
+		      vec<tree, va_gc> *gates)
+{
+  tree expr_list = NULL_TREE;
+
+  /* Increment gates first.  */
+  for (size_t i = 0; i < vec_safe_length (gates); i++)
+    {
+      tree decl = (*gates)[i];
+      tree value = build2 (PLUS_EXPR, TREE_TYPE (decl),
+			   decl, integer_one_node);
+      tree var_expr = modify_expr (decl, value);
+      expr_list = compound_expr (expr_list, var_expr);
+    }
+
+  /* Call Functions.  */
+  for (size_t i = 0; i < vec_safe_length (functions); i++)
+    {
+      tree decl = (*functions)[i];
+      tree call_expr = build_call_expr (decl, 0);
+      expr_list = compound_expr (expr_list, call_expr);
+    }
+
+  if (expr_list)
+    return build_internal_fn (ident, expr_list);
+
+  return NULL_TREE;
+}
+
+/* Return the type for ModuleInfo, create it if it doesn't already exist.  */
+
+static tree
+get_moduleinfo_type (void)
+{
+  if (moduleinfo_type)
+    return moduleinfo_type;
+
+  /* Layout of ModuleInfo is:
+	uint flags;
+	uint index;  */
+  tree fields = create_field_decl (d_uint_type, NULL, 1, 1);
+  DECL_CHAIN (fields) = create_field_decl (d_uint_type, NULL, 1, 1);
+
+  moduleinfo_type = make_node (RECORD_TYPE);
+  finish_builtin_struct (moduleinfo_type, "ModuleInfo", fields, NULL_TREE);
+
+  return moduleinfo_type;
+}
+
+/* Get the VAR_DECL of the ModuleInfo for DECL.  If this does not yet exist,
+   create it.  The ModuleInfo decl is used to keep track of constructors,
+   destructors, unittests, members, classes, and imports for the given module.
+   This is used by the D runtime for module initialization and termination.  */
+
+static tree
+get_moduleinfo_decl (Module *decl)
+{
+  if (decl->csym)
+    return decl->csym;
+
+  tree ident = mangle_internal_decl (decl, "__ModuleInfo", "Z");
+  tree type = get_moduleinfo_type ();
+
+  decl->csym = declare_extern_var (ident, type);
+  DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (NULL);
+
+  DECL_CONTEXT (decl->csym) = build_import_decl (decl);
+  /* Not readonly, moduleinit depends on this.  */
+  TREE_READONLY (decl->csym) = 0;
+
+  return decl->csym;
+}
+
+/* Return the type for CompilerDSOData, create it if it doesn't exist.  */
+
+static tree
+get_compiler_dso_type (void)
+{
+  if (compiler_dso_type)
+    return compiler_dso_type;
+
+  /* Layout of CompilerDSOData is:
+	size_t version;
+	void** slot;
+	ModuleInfo** _minfo_beg;
+	ModuleInfo** _minfo_end;
+	FuncTable* _deh_beg;
+	FuncTable* _deh_end;
+
+     Note, finish_builtin_struct() expects these fields in reverse order.  */
+  tree fields = create_field_decl (ptr_type_node, NULL, 1, 1);
+  tree field = create_field_decl (ptr_type_node, NULL, 1, 1);
+  DECL_CHAIN (field) = fields;
+  fields = field;
+
+  field = create_field_decl (build_pointer_type (get_moduleinfo_type ()),
+			     NULL, 1, 1);
+  DECL_CHAIN (field) = fields;
+  fields = field;
+  field = create_field_decl (build_pointer_type (get_moduleinfo_type ()),
+			     NULL, 1, 1);
+  DECL_CHAIN (field) = fields;
+  fields = field;
+
+  field = create_field_decl (build_pointer_type (ptr_type_node), NULL, 1, 1);
+  DECL_CHAIN (field) = fields;
+  fields = field;
+
+  field = create_field_decl (size_type_node, NULL, 1, 1);
+  DECL_CHAIN (field) = fields;
+  fields = field;
+
+  compiler_dso_type = make_node (RECORD_TYPE);
+  finish_builtin_struct (compiler_dso_type, "CompilerDSOData",
+			 fields, NULL_TREE);
+
+  return compiler_dso_type;
+}
+
+/* Returns the _d_dso_registry FUNCTION_DECL.  */
+
+static tree
+get_dso_registry_fn (void)
+{
+  if (dso_registry_fn)
+    return dso_registry_fn;
+
+  tree dso_type = get_compiler_dso_type ();
+  tree fntype = build_function_type_list (void_type_node,
+					  build_pointer_type (dso_type),
+					  NULL_TREE);
+  dso_registry_fn = build_decl (UNKNOWN_LOCATION, FUNCTION_DECL,
+				get_identifier ("_d_dso_registry"), fntype);
+  TREE_PUBLIC (dso_registry_fn) = 1;
+  DECL_EXTERNAL (dso_registry_fn) = 1;
+
+  return dso_registry_fn;
+}
+
+/* Depending on CTOR_P, builds and emits eiter a constructor or destructor
+   calling _d_dso_registry if `dso_initialized' is `false' in a constructor
+   or `true' in a destructor.  */
+
+static tree
+build_dso_cdtor_fn (bool ctor_p)
+{
+  const char *name = ctor_p ? GDC_PREFIX ("dso_ctor") : GDC_PREFIX ("dso_dtor");
+  tree condition = ctor_p ? boolean_true_node : boolean_false_node;
+
+  /* Declaration of dso_ctor/dso_dtor is:
+
+     extern(C) void dso_{c,d}tor (void)
+     {
+	if (dso_initialized != condition)
+	{
+	    dso_initialized = condition;
+	    CompilerDSOData dso = {1, &dsoSlot, &__start_minfo, &__stop_minfo};
+	    _d_dso_registry (&dso);
+	}
+    }
+   */
+  FuncDeclaration *fd = get_internal_fn (get_identifier (name));
+  tree decl = get_symbol_decl (fd);
+
+  TREE_PUBLIC (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
+  DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+  d_comdat_linkage (decl);
+
+  /* Start laying out the body.  */
+  tree old_context = start_function (fd);
+  rest_of_decl_compilation (decl, 1, 0);
+
+  /* if (dso_initialized != condition).  */
+  tree if_cond = build_boolop (NE_EXPR, dso_initialized_node, condition);
+
+  /* dso_initialized = condition;  */
+  tree expr_list = modify_expr (dso_initialized_node, condition);
+
+  /* CompilerDSOData dso = {1, &dsoSlot, &__start_minfo, &__stop_minfo};  */
+  tree dso_type = get_compiler_dso_type ();
+  tree dso = build_local_temp (dso_type);
+
+  vec<constructor_elt, va_gc> *ve = NULL;
+  CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_integer_cst (1, size_type_node));
+  CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (dso_slot_node));
+  CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (start_minfo_node));
+  CONSTRUCTOR_APPEND_ELT (ve, NULL_TREE, build_address (stop_minfo_node));
+
+  tree assign_expr = modify_expr (dso, build_struct_literal (dso_type, ve));
+  expr_list = compound_expr (expr_list, assign_expr);
+
+  /* _d_dso_registry (&dso);  */
+  tree call_expr = build_call_expr (get_dso_registry_fn (), 1,
+				    build_address (dso));
+  expr_list = compound_expr (expr_list, call_expr);
+
+  add_stmt (build_vcondition (if_cond, expr_list, void_node));
+  finish_function (old_context);
+
+  return decl;
+}
+
+/* Build a variable used in the dso_registry code identified by NAME,
+   and data type TYPE.  The variable always has VISIBILITY_HIDDEN and
+   TREE_PUBLIC flags set.  */
+
+static tree
+build_dso_registry_var (const char * name, tree type)
+{
+  tree var = declare_extern_var (get_identifier (name), type);
+  DECL_VISIBILITY (var) = VISIBILITY_HIDDEN;
+  DECL_VISIBILITY_SPECIFIED (var) = 1;
+  return var;
+}
+
+/* Place a reference to the ModuleInfo symbol MINFO for DECL into the
+   `minfo' section.  Then create the global ctors/dtors to call the
+   _d_dso_registry function if necessary.  */
+
+static void
+register_moduleinfo (Module *decl, tree minfo)
+{
+  if (!targetm_common.have_named_sections)
+    sorry ("%<-fmoduleinfo%> is not supported on this target");
+
+  /* Build the ModuleInfo reference, this is done once for every Module.  */
+  tree ident = mangle_internal_decl (decl, "__moduleRef", "Z");
+  tree mref = declare_extern_var (ident, ptr_type_node);
+
+  /* Build the initializer and emit.  Do not start section with a `.' character
+     so that the linker will provide a __start_ and __stop_ symbol to indicate
+     the start and end address of the section respectively.
+     https://sourceware.org/binutils/docs-2.26/ld/Orphan-Sections.html.  */
+  DECL_INITIAL (mref) = build_address (minfo);
+  DECL_EXTERNAL (mref) = 0;
+  DECL_PRESERVE_P (mref) = 1;
+
+  set_decl_section_name (mref, "minfo");
+  d_pushdecl (mref);
+  rest_of_decl_compilation (mref, 1, 0);
+
+  /* Only for the first D module being emitted do we need to generate a static
+     constructor and destructor for.  These are only required once per shared
+     library, so it's safe to emit them only once per object file.  */
+  static bool first_module = true;
+  if (!first_module)
+    return;
+
+  start_minfo_node = build_dso_registry_var ("__start_minfo", ptr_type_node);
+  rest_of_decl_compilation (start_minfo_node, 1, 0);
+
+  stop_minfo_node = build_dso_registry_var ("__stop_minfo", ptr_type_node);
+  rest_of_decl_compilation (stop_minfo_node, 1, 0);
+
+  /* Declare dso_slot and dso_initialized.  */
+  dso_slot_node = build_dso_registry_var (GDC_PREFIX ("dso_slot"),
+					  ptr_type_node);
+  DECL_EXTERNAL (dso_slot_node) = 0;
+  d_comdat_linkage (dso_slot_node);
+  rest_of_decl_compilation (dso_slot_node, 1, 0);
+
+  dso_initialized_node = build_dso_registry_var (GDC_PREFIX ("dso_initialized"),
+						 boolean_type_node);
+  DECL_EXTERNAL (dso_initialized_node) = 0;
+  d_comdat_linkage (dso_initialized_node);
+  rest_of_decl_compilation (dso_initialized_node, 1, 0);
+
+  /* Declare dso_ctor() and dso_dtor().  */
+  tree dso_ctor = build_dso_cdtor_fn (true);
+  vec_safe_push (static_ctor_list, dso_ctor);
+
+  tree dso_dtor = build_dso_cdtor_fn (false);
+  vec_safe_push (static_dtor_list, dso_dtor);
+
+  first_module = false;
+}
+
+/* Convenience function for layout_moduleinfo_fields.  Adds a field of TYPE to
+   the moduleinfo record at OFFSET, incrementing the offset to the next field
+   position.  No alignment is taken into account, all fields are packed.  */
+
+static void
+layout_moduleinfo_field (tree type, tree rec_type, HOST_WIDE_INT& offset)
+{
+  tree field = create_field_decl (type, NULL, 1, 1);
+  insert_aggregate_field (rec_type, field, offset);
+  offset += int_size_in_bytes (type);
+}
+
+/* Layout fields that immediately come after the moduleinfo TYPE for DECL.
+   Data relating to the module is packed into the type on an as-needed
+   basis, this is done to keep its size to a minimum.  */
+
+static tree
+layout_moduleinfo_fields (Module *decl, tree type)
+{
+  HOST_WIDE_INT offset = int_size_in_bytes (type);
+  type = copy_aggregate_type (type);
+
+  /* First fields added are all the function pointers.  */
+  if (decl->sctor)
+    layout_moduleinfo_field (ptr_type_node, type, offset);
+
+  if (decl->sdtor)
+    layout_moduleinfo_field (ptr_type_node, type, offset);
+
+  if (decl->ssharedctor)
+    layout_moduleinfo_field (ptr_type_node, type, offset);
+
+  if (decl->sshareddtor)
+    layout_moduleinfo_field (ptr_type_node, type, offset);
+
+  if (decl->findGetMembers ())
+    layout_moduleinfo_field (ptr_type_node, type, offset);
+
+  if (decl->sictor)
+    layout_moduleinfo_field (ptr_type_node, type, offset);
+
+  if (decl->stest)
+    layout_moduleinfo_field (ptr_type_node, type, offset);
+
+  /* Array of module imports is laid out as a length field, followed by
+     a static array of ModuleInfo pointers.  */
+  size_t aimports_dim = decl->aimports.dim;
+  for (size_t i = 0; i < decl->aimports.dim; i++)
+    {
+      Module *mi = decl->aimports[i];
+      if (!mi->needmoduleinfo)
+	aimports_dim--;
+    }
+
+  if (aimports_dim)
+    {
+      layout_moduleinfo_field (size_type_node, type, offset);
+      layout_moduleinfo_field (make_array_type (Type::tvoidptr, aimports_dim),
+			       type, offset);
+    }
+
+  /* Array of local ClassInfo decls are laid out in the same way.  */
+  ClassDeclarations aclasses;
+  for (size_t i = 0; i < decl->members->dim; i++)
+    {
+      Dsymbol *member = (*decl->members)[i];
+      member->addLocalClass (&aclasses);
+    }
+
+  if (aclasses.dim)
+    {
+      layout_moduleinfo_field (size_type_node, type, offset);
+      layout_moduleinfo_field (make_array_type (Type::tvoidptr, aclasses.dim),
+			       type, offset);
+    }
+
+  /* Lastly, the name of the module is a static char array.  */
+  size_t namelen = strlen (decl->toPrettyChars ()) + 1;
+  layout_moduleinfo_field (make_array_type (Type::tchar, namelen),
+			   type, offset);
+
+  size_t alignsize = MAX (TYPE_ALIGN_UNIT (type),
+			  TYPE_ALIGN_UNIT (ptr_type_node));
+  finish_aggregate_type (offset, alignsize, type, NULL);
+
+  return type;
+}
+
+/* Output the ModuleInfo for module DECL and register it with druntime.  */
+
+static void
+layout_moduleinfo (Module *decl)
+{
+  ClassDeclarations aclasses;
+  FuncDeclaration *sgetmembers;
+
+  for (size_t i = 0; i < decl->members->dim; i++)
+    {
+      Dsymbol *member = (*decl->members)[i];
+      member->addLocalClass (&aclasses);
+    }
+
+  size_t aimports_dim = decl->aimports.dim;
+  for (size_t i = 0; i < decl->aimports.dim; i++)
+    {
+      Module *mi = decl->aimports[i];
+      if (!mi->needmoduleinfo)
+	aimports_dim--;
+    }
+
+  sgetmembers = decl->findGetMembers ();
+
+  size_t flags = 0;
+  if (decl->sctor)
+    flags |= MItlsctor;
+  if (decl->sdtor)
+    flags |= MItlsdtor;
+  if (decl->ssharedctor)
+    flags |= MIctor;
+  if (decl->sshareddtor)
+    flags |= MIdtor;
+  if (sgetmembers)
+    flags |= MIxgetMembers;
+  if (decl->sictor)
+    flags |= MIictor;
+  if (decl->stest)
+    flags |= MIunitTest;
+  if (aimports_dim)
+    flags |= MIimportedModules;
+  if (aclasses.dim)
+    flags |= MIlocalClasses;
+  if (!decl->needmoduleinfo)
+    flags |= MIstandalone;
+
+  flags |= MIname;
+
+  tree minfo = get_moduleinfo_decl (decl);
+  tree type = layout_moduleinfo_fields (decl, TREE_TYPE (minfo));
+
+  /* Put out the two named fields in a ModuleInfo decl:
+	uint flags;
+	uint index;  */
+  vec<constructor_elt, va_gc> *minit = NULL;
+
+  CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+			  build_integer_cst (flags, d_uint_type));
+
+  CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+			  build_integer_cst (0, d_uint_type));
+
+  /* Order of appearance, depending on flags:
+	void function() tlsctor;
+	void function() tlsdtor;
+	void* function() xgetMembers;
+	void function() ctor;
+	void function() dtor;
+	void function() ictor;
+	void function() unitTest;
+	ModuleInfo*[] importedModules;
+	TypeInfo_Class[] localClasses;
+	char[N] name;
+   */
+  if (flags & MItlsctor)
+    CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sctor));
+
+  if (flags & MItlsdtor)
+    CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sdtor));
+
+  if (flags & MIctor)
+    CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+			    build_address (decl->ssharedctor));
+
+  if (flags & MIdtor)
+    CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+			    build_address (decl->sshareddtor));
+
+  if (flags & MIxgetMembers)
+    CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+			    build_address (get_symbol_decl (sgetmembers)));
+
+  if (flags & MIictor)
+    CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->sictor));
+
+  if (flags & MIunitTest)
+    CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, build_address (decl->stest));
+
+  if (flags & MIimportedModules)
+    {
+      vec<constructor_elt, va_gc> *elms = NULL;
+      tree satype = make_array_type (Type::tvoidptr, aimports_dim);
+      size_t idx = 0;
+
+      for (size_t i = 0; i < decl->aimports.dim; i++)
+	{
+	  Module *mi = decl->aimports[i];
+	  if (mi->needmoduleinfo)
+	    {
+	      CONSTRUCTOR_APPEND_ELT (elms, size_int (idx),
+				      build_address (get_moduleinfo_decl (mi)));
+	      idx++;
+	    }
+	}
+
+      CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aimports_dim));
+      CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+			      build_constructor (satype, elms));
+    }
+
+  if (flags & MIlocalClasses)
+    {
+      vec<constructor_elt, va_gc> *elms = NULL;
+      tree satype = make_array_type (Type::tvoidptr, aclasses.dim);
+
+      for (size_t i = 0; i < aclasses.dim; i++)
+	{
+	  ClassDeclaration *cd = aclasses[i];
+	  CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
+				  build_address (get_classinfo_decl (cd)));
+	}
+
+      CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, size_int (aclasses.dim));
+      CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+			      build_constructor (satype, elms));
+    }
+
+  if (flags & MIname)
+    {
+      /* Put out module name as a 0-terminated C-string, to save bytes.  */
+      const char *name = decl->toPrettyChars ();
+      size_t namelen = strlen (name) + 1;
+      tree strtree = build_string (namelen, name);
+      TREE_TYPE (strtree) = make_array_type (Type::tchar, namelen);
+      CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE, strtree);
+    }
+
+  TREE_TYPE (minfo) = type;
+  DECL_INITIAL (minfo) = build_struct_literal (type, minit);
+  d_finish_decl (minfo);
+
+  /* Register the module against druntime.  */
+  register_moduleinfo (decl, minfo);
+}
+
+/* Send the Module AST class DECL to GCC back-end.  */
+
+void
+build_module_tree (Module *decl)
+{
+  /* There may be more than one module per object file, but should only
+     ever compile them one at a time.  */
+  assert (!current_moduleinfo && !current_module_decl);
+
+  module_info mi = module_info ();
+  module_info mitest = module_info ();
+
+  current_moduleinfo = &mi;
+  current_testing_module = &mitest;
+  current_module_decl = decl;
+
+  /* Layout module members.  */
+  if (decl->members)
+    {
+      for (size_t i = 0; i < decl->members->dim; i++)
+	{
+	  Dsymbol *s = (*decl->members)[i];
+	  build_decl_tree (s);
+	}
+    }
+
+  /* For libphobos-internal use only.  Generate a separate module info symbol
+     that references all compiled in unittests, this allows compiling library
+     modules and linking to libphobos without having run-time conflicts because
+     of two ModuleInfo records with the same name being present in two DSOs.  */
+  if (flag_building_libphobos_tests)
+    {
+      /* Associate the module info symbol with a mock module.  */
+      const char *name = concat (GDC_PREFIX ("modtest__"),
+				 decl->ident->toChars (), NULL);
+      Module *tm = Module::create (decl->arg, Identifier::idPool (name), 0, 0);
+      Dsymbols members;
+
+      /* Setting parent puts module in the same package as the current, to
+	 avoid any symbol conflicts.  */
+      tm->parent = decl->parent;
+      tm->needmoduleinfo = decl->needmoduleinfo;
+      tm->members = &members;
+      /* Register the current module as being imported by the mock module.
+	 This informs run-time that there is a dependency between the two.  */
+      tm->aimports.push (decl);
+
+      if (mitest.ctors || mitest.ctorgates)
+	tm->sctor = build_funcs_gates_fn (get_identifier ("*__modtestctor"),
+					  mitest.ctors, mitest.ctorgates);
+
+      if (mitest.dtors)
+	tm->sdtor = build_funcs_gates_fn (get_identifier ("*__modtestdtor"),
+					  mitest.dtors, NULL);
+
+      if (mitest.sharedctors || mitest.sharedctorgates)
+	tm->ssharedctor
+	  = build_funcs_gates_fn (get_identifier ("*__modtestsharedctor"),
+				  mitest.sharedctors, mitest.sharedctorgates);
+
+      if (mitest.shareddtors)
+	tm->sshareddtor
+	  = build_funcs_gates_fn (get_identifier ("*__modtestshareddtor"),
+				  mitest.shareddtors, NULL);
+
+      if (mi.unitTests)
+	tm->stest = build_funcs_gates_fn (get_identifier ("*__modtest"),
+					  mi.unitTests, NULL);
+
+      mi.unitTests = NULL;
+      layout_moduleinfo (tm);
+    }
+
+  /* Default behavior is to always generate module info because of templates.
+     Can be switched off for not compiling against runtime library.  */
+  if (global.params.useModuleInfo
+      && Module::moduleinfo != NULL
+      && decl->ident != Identifier::idPool ("__entrypoint"))
+    {
+      if (mi.ctors || mi.ctorgates)
+	decl->sctor = build_funcs_gates_fn (get_identifier ("*__modctor"),
+					    mi.ctors, mi.ctorgates);
+
+      if (mi.dtors)
+	decl->sdtor = build_funcs_gates_fn (get_identifier ("*__moddtor"),
+					    mi.dtors, NULL);
+
+      if (mi.sharedctors || mi.sharedctorgates)
+	decl->ssharedctor
+	  = build_funcs_gates_fn (get_identifier ("*__modsharedctor"),
+				  mi.sharedctors, mi.sharedctorgates);
+
+      if (mi.shareddtors)
+	decl->sshareddtor
+	  = build_funcs_gates_fn (get_identifier ("*__modshareddtor"),
+				  mi.shareddtors, NULL);
+
+      if (mi.unitTests)
+	decl->stest = build_funcs_gates_fn (get_identifier ("*__modtest"),
+					    mi.unitTests, NULL);
+
+      layout_moduleinfo (decl);
+    }
+
+  current_moduleinfo = NULL;
+  current_testing_module = NULL;
+  current_module_decl = NULL;
+}
+
+/* Returns the current function or module context for the purpose
+   of imported_module_or_decl.  */
+
+tree
+d_module_context (void)
+{
+  if (cfun != NULL)
+    return current_function_decl;
+
+  gcc_assert (current_module_decl != NULL);
+  return build_import_decl (current_module_decl);
+}
+
+/* Maybe record declaration D against our module information structure.  */
+
+void
+register_module_decl (Declaration *d)
+{
+  FuncDeclaration *fd = d->isFuncDeclaration ();
+  if (fd != NULL)
+    {
+      tree decl = get_symbol_decl (fd);
+
+      /* Any module constructors or destructors that are only present when
+	 compiling in unittests are kept track of separately so they are
+	 not omitted when compiling with -fbuilding-libphobos-tests.  */
+      module_info *minfo;
+      if (flag_building_libphobos_tests && !fd->isUnitTestDeclaration ()
+	  && DECL_IN_UNITTEST_CONDITION_P (decl))
+	minfo = current_testing_module;
+      else
+	minfo = current_moduleinfo;
+
+      gcc_assert (minfo != NULL);
+
+      /* If a static constructor, push into the current ModuleInfo.
+	 Checks for `shared' first because it derives from the non-shared
+	 constructor type in the front-end.  */
+      if (fd->isSharedStaticCtorDeclaration ())
+	vec_safe_push (minfo->sharedctors, decl);
+      else if (fd->isStaticCtorDeclaration ())
+	vec_safe_push (minfo->ctors, decl);
+
+      /* If a static destructor, do same as with constructors, but also
+	 increment the destructor's vgate at construction time.  */
+      if (fd->isSharedStaticDtorDeclaration ())
+	{
+	  VarDeclaration *vgate = ((SharedStaticDtorDeclaration *) fd)->vgate;
+	  if (vgate != NULL)
+	    {
+	      tree gate = get_symbol_decl (vgate);
+	      vec_safe_push (minfo->sharedctorgates, gate);
+	    }
+	  vec_safe_insert (minfo->shareddtors, 0, decl);
+	}
+      else if (fd->isStaticDtorDeclaration ())
+	{
+	  VarDeclaration *vgate = ((StaticDtorDeclaration *) fd)->vgate;
+	  if (vgate != NULL)
+	    {
+	      tree gate = get_symbol_decl (vgate);
+	      vec_safe_push (minfo->ctorgates, gate);
+	    }
+	  vec_safe_insert (minfo->dtors, 0, decl);
+	}
+
+      /* If a unittest function.  */
+      if (fd->isUnitTestDeclaration ())
+	vec_safe_push (minfo->unitTests, decl);
+    }
+}
+
+/* Wrapup all global declarations and start the final compilation.  */
+
+void
+d_finish_compilation (tree *vec, int len)
+{
+  /* Complete all generated thunks.  */
+  symtab->process_same_body_aliases ();
+
+  /* Process all file scopes in this compilation, and the external_scope,
+     through wrapup_global_declarations.  */
+  for (int i = 0; i < len; i++)
+    {
+      tree decl = vec[i];
+      wrapup_global_declarations (&decl, 1);
+    }
+
+  /* If the target does not directly support static constructors,
+     static_ctor_list contains a list of all static constructors defined
+     so far.  This routine will create a function to call all of those
+     and is picked up by collect2.  */
+  if (static_ctor_list)
+    {
+      tree decl = build_funcs_gates_fn (get_file_function_name ("I"),
+					static_ctor_list, NULL);
+      DECL_STATIC_CONSTRUCTOR (decl) = 1;
+      decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY);
+    }
+
+  if (static_dtor_list)
+    {
+      tree decl = build_funcs_gates_fn (get_file_function_name ("D"),
+					static_dtor_list, NULL);
+      DECL_STATIC_DESTRUCTOR (decl) = 1;
+      decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
+    }
+}
+
+
+#include "gt-d-modules.h"