[PATCH 2/13] D: The front-end (GDC) implementation.

This patch adds the D front-end implementation, the only part of the compiler that interacts with GCC directly, and being the parts that I maintain, is something that I can talk about more directly.

For the actual code generation pass, that converts the front-end AST to GCC trees, most parts use a separate Visitor interfaces to do a certain kind of lowering, for instance, types.cc builds *_TYPE trees from AST Type's.  The Visitor class is part of the DMD front-end, and is defined in dfrontend/visitor.h.

There are also a few interfaces which have their headers in the DMD frontend, but are implemented here because they do something that requires knowledge of the GCC backend (d-target.cc), does something that may not be portable, or differ between D compilers (d-frontend.cc) or are a thin wrapper around something that is managed by GCC (d-diagnostic.cc).

Many high level operations result in generation of calls to D runtime library functions (runtime.def), all with require some kind of runtime type information (typeinfo.cc).  The compiler also generates functions for registering/deregistering compiled modules with the D runtime library (modules.cc).

As well as the D language having it's own built-in functions (intrinsics.cc), we also expose GCC builtins to D code via a `gcc.builtins' module (d-builtins.cc), and give special treatment to a number of UDAs that could be applied to functions (d-attribs.cc).


That is roughly the high level jist of how things are currently organized.

---

diff --git a/gcc/d/VERSION b/gcc/d/VERSION
new file mode 100644
index 00000000000..d6e15c39442
--- /dev/null
+++ b/gcc/d/VERSION
@@ -0,0 +1 @@
+"2.068.2"
diff --git a/gcc/d/d-attribs.c b/gcc/d/d-attribs.c
new file mode 100644
index 00000000000..4b93d1742e6
--- /dev/null
+++ b/gcc/d/d-attribs.c
@@ -0,0 +1,826 @@
+/* d-attribs.c -- D attributes handling.
+   Copyright (C) 2015-2017 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/>.  */
+
+/* Implementation of attribute handlers for user defined attributes and
+   internal built-in functions.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+
+#include "dfrontend/declaration.h"
+#include "dfrontend/mtype.h"
+
+#include "tree.h"
+#include "diagnostic.h"
+#include "tm.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "stringpool.h"
+#include "varasm.h"
+
+#include "d-tree.h"
+
+
+/* Internal attribute handlers for built-in functions.  */
+static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
+static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
+static tree handle_const_attribute (tree *, tree, tree, int, bool *);
+static tree handle_malloc_attribute (tree *, tree, tree, int, bool *);
+static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_novops_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
+static tree handle_type_generic_attribute (tree *, tree, tree, int, bool *);
+static tree handle_transaction_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+static tree handle_fnspec_attribute (tree *, tree, tree, int, bool *);
+static tree handle_weakref_attribute (tree *, tree, tree, int, bool *);
+
+/* D attribute handlers for user defined attributes.  */
+static tree d_handle_noinline_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_forceinline_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_flatten_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_target_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_noclone_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_section_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_alias_attribute (tree *, tree, tree, int, bool *);
+static tree d_handle_weak_attribute (tree *, tree, tree, int, bool *) ;
+
+
+/* Table of machine-independent attributes.
+   For internal use (marking of builtins) only.  */
+
+const attribute_spec d_langhook_common_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+       affects_type_identity } */
+  { "noreturn",               0, 0, true,  false, false,
+			      handle_noreturn_attribute, false },
+  { "leaf",                   0, 0, true,  false, false,
+			      handle_leaf_attribute, false },
+  { "const",                  0, 0, true,  false, false,
+			      handle_const_attribute, false },
+  { "malloc",                 0, 0, true,  false, false,
+			      handle_malloc_attribute, false },
+  { "returns_twice",          0, 0, true,  false, false,
+			      handle_returns_twice_attribute, false },
+  { "pure",                   0, 0, true,  false, false,
+			      handle_pure_attribute, false },
+  { "nonnull",                0, -1, false, true, true,
+			      handle_nonnull_attribute, false },
+  { "nothrow",                0, 0, true,  false, false,
+			      handle_nothrow_attribute, false },
+  { "transaction_pure",       0, 0, false, true, true,
+			      handle_transaction_pure_attribute, false },
+  { "no vops",                0, 0, true,  false, false,
+			      handle_novops_attribute, false },
+  { "type generic",           0, 0, false, true, true,
+			      handle_type_generic_attribute, false },
+  { "fn spec",                1, 1, false, true, true,
+			      handle_fnspec_attribute, false },
+  { "weakref",                0, 1, true,  false, false,
+			      handle_weakref_attribute, false },
+  { NULL,                     0, 0, false, false, false, NULL, false }
+};
+
+/* Table of D language attributes exposed by `gcc.attribute' UDAs.  */
+
+const attribute_spec d_langhook_attribute_table[] =
+{
+  /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+       affects_type_identity } */
+    { "noinline",               0, 0, true,  false, false,
+				d_handle_noinline_attribute, false },
+    { "forceinline",            0, 0, true,  false, false,
+				d_handle_forceinline_attribute, false },
+    { "flatten",                0, 0, true,  false, false,
+				d_handle_flatten_attribute, false },
+    { "target",                 1, -1, true, false, false,
+				d_handle_target_attribute, false },
+    { "noclone",                0, 0, true, false, false,
+				d_handle_noclone_attribute, false },
+    { "section",                1, 1, true,  false, false,
+				d_handle_section_attribute, false },
+    { "alias",                  1, 1, true,  false, false,
+				d_handle_alias_attribute, false },
+    { "weak",                   0, 0, true,  false, false,
+				d_handle_weak_attribute, false },
+    { NULL,                     0, 0, false, false, false, NULL, false }
+};
+
+
+/* Insert the type attribute ATTRNAME with value VALUE into TYPE.
+   Returns a new variant of the original type declaration.  */
+
+tree
+insert_type_attribute (tree type, const char *attrname, tree value)
+{
+  tree ident = get_identifier (attrname);
+
+  if (value)
+    value = tree_cons (NULL_TREE, value, NULL_TREE);
+
+  tree attribs = merge_attributes (TYPE_ATTRIBUTES (type),
+				   tree_cons (ident, value, NULL_TREE));
+
+  return build_type_attribute_variant (type, attribs);
+}
+
+/* Insert the decl attribute ATTRNAME with value VALUE into DECL.  */
+
+tree
+insert_decl_attribute (tree decl, const char *attrname, tree value)
+{
+  tree ident = get_identifier (attrname);
+
+  if (value)
+    value = tree_cons (NULL_TREE, value, NULL_TREE);
+
+  tree attribs = merge_attributes (DECL_ATTRIBUTES (decl),
+				   tree_cons (ident, value, NULL_TREE));
+
+  return build_decl_attribute_variant (decl, attribs);
+}
+
+/* Returns TRUE if NAME is an attribute recognized as being handled by
+   the `gcc.attribute' module.  */
+
+static bool
+uda_attribute_p (const char* name)
+{
+  Identifier *ident = Identifier::idPool (name);
+
+  /* Search both our language, and target attribute tables.
+     Common and format attributes are kept internal.  */
+  for (const attribute_spec *p = d_langhook_attribute_table; p->name; p++)
+    {
+      if (Identifier::idPool (p->name) == ident)
+	return true;
+    }
+
+  for (const attribute_spec *p = targetm.attribute_table; p->name; p++)
+    {
+      if (Identifier::idPool (p->name) == ident)
+	return true;
+    }
+
+  return false;
+}
+
+/* [attribute/uda]
+
+   User Defined Attributes (UDA) are compile time expressions that can be
+   attached to a declaration.  These attributes can then be queried, extracted,
+   and manipulated at compile time. There is no runtime component to them.
+
+   Expand and merge all UDAs found in the EATTRS list that are of type
+   `gcc.attribute.Attribute'.  This symbol is internally recognized by the
+   compiler and maps them to their equivalent GCC attribute.  */
+
+tree
+build_attributes (Expressions *eattrs)
+{
+  if (!eattrs)
+    return NULL_TREE;
+
+  expandTuples (eattrs);
+
+  tree attribs = NULL_TREE;
+
+  for (size_t i = 0; i < eattrs->dim; i++)
+    {
+      Expression *attr = (*eattrs)[i];
+      Dsymbol *sym = attr->type->toDsymbol (0);
+
+      if (!sym)
+	continue;
+
+      /* Attribute symbol must come from the `gcc.attribute' module.  */
+      Dsymbol *mod = (Dsymbol*) sym->getModule ();
+      if (!(strcmp (mod->toChars (), "attribute") == 0
+          && mod->parent != NULL
+          && strcmp (mod->parent->toChars (), "gcc") == 0
+          && !mod->parent->parent))
+        continue;
+
+      /* Get the result of the attribute if it hasn't already been folded.  */
+      if (attr->op == TOKcall)
+	attr = attr->ctfeInterpret ();
+
+      /* Should now have a struct `Attribute("attrib", "value", ... )'
+	 initializer list.  */
+      gcc_assert (attr->op == TOKstructliteral);
+      Expressions *elems = ((StructLiteralExp*) attr)->elements;
+      Expression *e0 = (*elems)[0];
+
+      if (e0->op != TOKstring)
+	{
+	  error ("expected string attribute, not %qs", e0->toChars());
+	  return error_mark_node;
+	}
+
+      StringExp *se = (StringExp*) e0;
+      gcc_assert (se->sz == 1);
+
+      /* Empty string attribute, just ignore it.  */
+      if (se->len == 0)
+	continue;
+
+      /* Check if the attribute is recognized and handled.
+	 Done here to report the diagnostic at the right location.  */
+      const char* name = (const char*) se->string;
+      if (!uda_attribute_p (name))
+	{
+	  warning_at (get_linemap (e0->loc), OPT_Wattributes,
+		      "unknown attribute %qs", name);
+	  return error_mark_node;
+	}
+
+      /* Chain all attribute arguments together.  */
+      tree args = NULL_TREE;
+
+      for (size_t j = 1; j < elems->dim; j++)
+	{
+	  Expression *e = (*elems)[j];
+	  tree t;
+	  if (e->op == TOKstring && ((StringExp *) e)->sz == 1)
+	    {
+	      StringExp *s = (StringExp *) e;
+	      t = build_string (s->len, (const char *) s->string);
+	    }
+	  else
+	    t = build_expr (e);
+
+	  args = chainon (args, build_tree_list (0, t));
+        }
+
+      tree list = build_tree_list (get_identifier (name), args);
+      attribs =  chainon (attribs, list);
+    }
+
+  return attribs;
+}
+
+/* Built-in attribute handlers.  */
+
+/* Handle a "noreturn" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_noreturn_attribute (tree *node, tree ARG_UNUSED (name),
+			   tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			   bool * ARG_UNUSED (no_add_attrs))
+{
+  tree type = TREE_TYPE (*node);
+
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_THIS_VOLATILE (*node) = 1;
+  else if (TREE_CODE (type) == POINTER_TYPE
+	   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+    TREE_TYPE (*node)
+      = build_pointer_type
+	(build_type_variant (TREE_TYPE (type),
+			     TYPE_READONLY (TREE_TYPE (type)), 1));
+  else
+    gcc_unreachable ();
+
+  return NULL_TREE;
+}
+
+/* Handle a "leaf" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_leaf_attribute (tree *node, tree name,
+		       tree ARG_UNUSED (args),
+		       int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (TREE_CODE (*node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  if (!TREE_PUBLIC (*node))
+    {
+      warning (OPT_Wattributes, "%qE attribute has no effect", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "const" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_const_attribute (tree *node, tree ARG_UNUSED (name),
+			tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			bool * ARG_UNUSED (no_add_attrs))
+{
+  tree type = TREE_TYPE (*node);
+
+  /* See FIXME comment on noreturn in c_common_attribute_table.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_READONLY (*node) = 1;
+  else if (TREE_CODE (type) == POINTER_TYPE
+	   && TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE)
+    TREE_TYPE (*node)
+      = build_pointer_type
+	(build_type_variant (TREE_TYPE (type), 1,
+			     TREE_THIS_VOLATILE (TREE_TYPE (type))));
+  else
+    gcc_unreachable ();
+
+  return NULL_TREE;
+}
+
+/* Handle a "malloc" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_malloc_attribute (tree *node, tree ARG_UNUSED (name),
+			 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			 bool * ARG_UNUSED (no_add_attrs))
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && POINTER_TYPE_P (TREE_TYPE (TREE_TYPE (*node))))
+    DECL_IS_MALLOC (*node) = 1;
+  else
+    gcc_unreachable ();
+
+  return NULL_TREE;
+}
+
+/* Handle a "pure" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_pure_attribute (tree *node, tree ARG_UNUSED (name),
+		       tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+		       bool * ARG_UNUSED (no_add_attrs))
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    DECL_PURE_P (*node) = 1;
+  else
+    gcc_unreachable ();
+
+  return NULL_TREE;
+}
+
+/* Handle a "no vops" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_novops_attribute (tree *node, tree ARG_UNUSED (name),
+			 tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			 bool * ARG_UNUSED (no_add_attrs))
+{
+  gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+  DECL_IS_NOVOPS (*node) = 1;
+  return NULL_TREE;
+}
+
+/* Helper for nonnull attribute handling; fetch the operand number
+   from the attribute argument list.  */
+
+static bool
+get_nonnull_operand (tree arg_num_expr, unsigned HOST_WIDE_INT *valp)
+{
+  /* Verify the arg number is a constant.  */
+  if (!tree_fits_uhwi_p (arg_num_expr))
+    return false;
+
+  *valp = TREE_INT_CST_LOW (arg_num_expr);
+  return true;
+}
+
+/* Handle the "nonnull" attribute.  */
+
+static tree
+handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
+			  tree args, int ARG_UNUSED (flags),
+			  bool * ARG_UNUSED (no_add_attrs))
+{
+  tree type = *node;
+
+  /* If no arguments are specified, all pointer arguments should be
+     non-null.  Verify a full prototype is given so that the arguments
+     will have the correct types when we actually check them later.
+     Avoid diagnosing type-generic built-ins since those have no
+     prototype.  */
+  if (!args)
+    {
+      gcc_assert (prototype_p (type)
+		  || !TYPE_ATTRIBUTES (type)
+		  || lookup_attribute ("type generic", TYPE_ATTRIBUTES (type)));
+
+      return NULL_TREE;
+    }
+
+  /* Argument list specified.  Verify that each argument number references
+     a pointer argument.  */
+  for (; args; args = TREE_CHAIN (args))
+    {
+      tree argument;
+      unsigned HOST_WIDE_INT arg_num = 0, ck_num;
+
+      if (!get_nonnull_operand (TREE_VALUE (args), &arg_num))
+	gcc_unreachable ();
+
+      argument = TYPE_ARG_TYPES (type);
+      if (argument)
+	{
+	  for (ck_num = 1; ; ck_num++)
+	    {
+	      if (!argument || ck_num == arg_num)
+		break;
+	      argument = TREE_CHAIN (argument);
+	    }
+
+	  gcc_assert (argument
+		      && TREE_CODE (TREE_VALUE (argument)) == POINTER_TYPE);
+	}
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "nothrow" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name),
+			  tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			  bool * ARG_UNUSED (no_add_attrs))
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    TREE_NOTHROW (*node) = 1;
+  else
+    gcc_unreachable ();
+
+  return NULL_TREE;
+}
+
+/* Handle a "type_generic" attribute.  */
+
+static tree
+handle_type_generic_attribute (tree *node, tree ARG_UNUSED (name),
+			       tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			       bool * ARG_UNUSED (no_add_attrs))
+{
+  /* Ensure we have a function type.  */
+  gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+  /* Ensure we have a variadic function.  */
+  gcc_assert (!prototype_p (*node) || stdarg_p (*node));
+
+  return NULL_TREE;
+}
+
+/* Handle a "transaction_pure" attribute.  */
+
+static tree
+handle_transaction_pure_attribute (tree *node, tree ARG_UNUSED (name),
+				   tree ARG_UNUSED (args),
+				   int ARG_UNUSED (flags),
+				   bool * ARG_UNUSED (no_add_attrs))
+{
+  /* Ensure we have a function type.  */
+  gcc_assert (TREE_CODE (*node) == FUNCTION_TYPE);
+
+  return NULL_TREE;
+}
+
+/* Handle a "returns_twice" attribute.  */
+
+static tree
+handle_returns_twice_attribute (tree *node, tree ARG_UNUSED (name),
+				tree ARG_UNUSED (args),
+				int ARG_UNUSED (flags),
+				bool * ARG_UNUSED (no_add_attrs))
+{
+  gcc_assert (TREE_CODE (*node) == FUNCTION_DECL);
+
+  DECL_IS_RETURNS_TWICE (*node) = 1;
+
+  return NULL_TREE;
+}
+
+/* Handle a "fn spec" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_fnspec_attribute (tree *node ATTRIBUTE_UNUSED, tree ARG_UNUSED (name),
+			 tree args, int ARG_UNUSED (flags),
+			 bool *no_add_attrs ATTRIBUTE_UNUSED)
+{
+  gcc_assert (args
+	      && TREE_CODE (TREE_VALUE (args)) == STRING_CST
+	      && !TREE_CHAIN (args));
+  return NULL_TREE;
+}
+
+/* Handle a "weakref" attribute; arguments as in struct
+   attribute_spec.handler.  */
+
+static tree
+handle_weakref_attribute (tree *node, tree ARG_UNUSED (name),
+			  tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			  bool *no_add_attrs ATTRIBUTE_UNUSED)
+{
+  gcc_assert (!decl_function_context (*node));
+  gcc_assert (!lookup_attribute ("alias", DECL_ATTRIBUTES (*node)));
+
+  /* Can't call declare_weak because it wants this to be TREE_PUBLIC,
+     and that isn't supported; and because it wants to add it to
+     the list of weak decls, which isn't helpful.  */
+  DECL_WEAK (*node) = 1;
+
+  return NULL_TREE;
+}
+
+/* Language specific attribute handlers.  */
+
+/* Handle a "noinline" attribute.  */
+
+static tree
+d_handle_noinline_attribute (tree *node, tree name,
+			     tree ARG_UNUSED (args),
+			     int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+  if (t->ty == Tfunction)
+    DECL_UNINLINABLE (*node) = 1;
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "forceinline" attribute.  */
+
+static tree
+d_handle_forceinline_attribute (tree *node, tree name,
+				tree ARG_UNUSED (args),
+				int ARG_UNUSED (flags),
+				bool *no_add_attrs)
+{
+  Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+  if (t->ty == Tfunction)
+    {
+      tree attributes = DECL_ATTRIBUTES (*node);
+
+      /* Push attribute always_inline.  */
+      if (! lookup_attribute ("always_inline", attributes))
+	DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("always_inline"),
+					     NULL_TREE, attributes);
+
+      DECL_DECLARED_INLINE_P (*node) = 1;
+      DECL_NO_INLINE_WARNING_P (*node) = 1;
+      DECL_DISREGARD_INLINE_LIMITS (*node) = 1;
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "flatten" attribute.  */
+
+static tree
+d_handle_flatten_attribute (tree *node, tree name,
+			    tree args ATTRIBUTE_UNUSED,
+			    int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
+{
+  Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+  if (t->ty != Tfunction)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "target" attribute.  */
+
+static tree
+d_handle_target_attribute (tree *node, tree name, tree args, int flags,
+			   bool *no_add_attrs)
+{
+  Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+  /* Ensure we have a function type.  */
+  if (t->ty != Tfunction)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+  else if (! targetm.target_option.valid_attribute_p (*node, name, args, flags))
+    *no_add_attrs = true;
+
+  return NULL_TREE;
+}
+
+/* Handle a "noclone" attribute.  */
+
+static tree
+d_handle_noclone_attribute (tree *node, tree name,
+				tree ARG_UNUSED (args),
+				int ARG_UNUSED (flags),
+				bool *no_add_attrs)
+{
+  Type *t = TYPE_LANG_FRONTEND (TREE_TYPE (*node));
+
+  if (t->ty == Tfunction)
+    {
+      tree attributes = DECL_ATTRIBUTES (*node);
+
+      /* Push attribute noclone.  */
+      if (! lookup_attribute ("noclone", attributes))
+	DECL_ATTRIBUTES (*node) = tree_cons (get_identifier ("noclone"),
+					     NULL_TREE, attributes);
+    }
+  else
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle a "section" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+d_handle_section_attribute (tree *node, tree ARG_UNUSED (name), tree args,
+			    int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  tree decl = *node;
+
+  if (targetm_common.have_named_sections)
+    {
+      if (VAR_OR_FUNCTION_DECL_P (decl)
+	  && TREE_CODE (TREE_VALUE (args)) == STRING_CST)
+	{
+	  if (VAR_P (decl)
+	      && current_function_decl != NULL_TREE
+	      && !TREE_STATIC (decl))
+	    {
+	      error_at (DECL_SOURCE_LOCATION (decl),
+			"section attribute cannot be specified for "
+			"local variables");
+	      *no_add_attrs = true;
+	    }
+
+	  /* The decl may have already been given a section attribute
+	     from a previous declaration.  Ensure they match.  */
+	  else if (DECL_SECTION_NAME (decl) != NULL
+		   && strcmp (DECL_SECTION_NAME (decl),
+			      TREE_STRING_POINTER (TREE_VALUE (args))) != 0)
+	    {
+	      error ("section of %q+D conflicts with previous declaration",
+		     *node);
+	      *no_add_attrs = true;
+	    }
+	  else if (VAR_P (decl)
+		   && !targetm.have_tls && targetm.emutls.tmpl_section
+		   && DECL_THREAD_LOCAL_P (decl))
+	    {
+	      error ("section of %q+D cannot be overridden", *node);
+	      *no_add_attrs = true;
+	    }
+	  else
+	    set_decl_section_name (decl,
+				   TREE_STRING_POINTER (TREE_VALUE (args)));
+	}
+      else
+	{
+	  error ("section attribute not allowed for %q+D", *node);
+	  *no_add_attrs = true;
+	}
+    }
+  else
+    {
+      error_at (DECL_SOURCE_LOCATION (*node),
+		"section attributes are not supported for this target");
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
+/* Handle an "alias" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+d_handle_alias_attribute (tree *node, tree ARG_UNUSED (name),
+			  tree args, int ARG_UNUSED (flags),
+			  bool *no_add_attrs ATTRIBUTE_UNUSED)
+{
+  tree decl = *node;
+
+  if (TREE_CODE (decl) != FUNCTION_DECL
+      && TREE_CODE (decl) != VAR_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  else if ((TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+      || (TREE_CODE (decl) != FUNCTION_DECL
+	  && TREE_PUBLIC (decl) && !DECL_EXTERNAL (decl))
+      /* A static variable declaration is always a tentative definition,
+	 but the alias is a non-tentative definition which overrides.  */
+      || (TREE_CODE (decl) != FUNCTION_DECL
+	  && ! TREE_PUBLIC (decl) && DECL_INITIAL (decl)))
+    {
+      error ("%q+D defined both normally and as %qE attribute", decl, name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  else if (decl_function_context (decl))
+    {
+      error ("%q+D alias functions must be global", name);
+      *no_add_attrs = true;
+      return NULL_TREE;
+    }
+  else
+    {
+      tree id;
+
+      id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+	{
+	  error ("attribute %qE argument not a string", name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+      id = get_identifier (TREE_STRING_POINTER (id));
+      /* This counts as a use of the object pointed to.  */
+      TREE_USED (id) = 1;
+
+      if (TREE_CODE (decl) == FUNCTION_DECL)
+	DECL_INITIAL (decl) = error_mark_node;
+      else
+	TREE_STATIC (decl) = 1;
+
+      return NULL_TREE;
+    }
+}
+
+/* Handle a "weak" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+d_handle_weak_attribute (tree *node, tree name,
+		         tree ARG_UNUSED (args),
+		         int ARG_UNUSED (flags),
+		         bool * ARG_UNUSED (no_add_attrs))
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && DECL_DECLARED_INLINE_P (*node))
+    {
+      warning (OPT_Wattributes, "inline function %q+D declared weak", *node);
+      *no_add_attrs = true;
+    }
+  else if (VAR_OR_FUNCTION_DECL_P (*node))
+    {
+      struct symtab_node *n = symtab_node::get (*node);
+      if (n && n->refuse_visibility_changes)
+	error ("%+D declared weak after being used", *node);
+      declare_weak (*node);
+    }
+  else
+    warning (OPT_Wattributes, "%qE attribute ignored", name);
+
+  return NULL_TREE;
+}
+
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
new file mode 100644
index 00000000000..d455d6c862d
--- /dev/null
+++ b/gcc/d/d-builtins.cc
@@ -0,0 +1,1067 @@
+/* d-builtins.cc -- GCC builtins support for D.
+   Copyright (C) 2006-2017 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 "dfrontend/attrib.h"
+#include "dfrontend/aggregate.h"
+#include "dfrontend/declaration.h"
+#include "dfrontend/module.h"
+#include "dfrontend/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "target.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+#include "id.h"
+
+
+static GTY(()) vec<tree, va_gc> *gcc_builtins_functions = NULL;
+static GTY(()) vec<tree, va_gc> *gcc_builtins_libfuncs = NULL;
+static GTY(()) vec<tree, va_gc> *gcc_builtins_types = NULL;
+
+/* Record built-in types and their associated decls for re-use when
+   generating the `gcc.builtins' module.  */
+
+struct builtin_data
+{
+  Type *dtype;
+  tree ctype;
+  Dsymbol *dsym;
+
+  builtin_data (Type *t, tree c, Dsymbol *d = NULL)
+    : dtype(t), ctype(c), dsym(d) { }
+};
+
+static vec<builtin_data> builtin_converted_decls;
+
+/* Build D frontend type from tree TYPE type given.  This will set the backend
+   type symbol directly for complex types to save build_ctype() the work.
+   For other types, it is not useful or will causes errors, such as casting
+   from `C char' to `D char', which also means that `char *` needs to be
+   specially handled.  */
+
+static Type *
+build_frontend_type (tree type)
+{
+  Type *dtype;
+  MOD mod = 0;
+
+  if (TYPE_READONLY (type))
+    mod |= MODconst;
+  if (TYPE_VOLATILE (type))
+    mod |= MODshared;
+
+  /* If we've seen the type before, re-use the converted decl.  */
+  for (size_t i = 0; i < builtin_converted_decls.length (); ++i)
+    {
+      tree t = builtin_converted_decls[i].ctype;
+      if (TYPE_MAIN_VARIANT (t) == TYPE_MAIN_VARIANT (type))
+	return builtin_converted_decls[i].dtype;
+    }
+
+  switch (TREE_CODE (type))
+    {
+    case POINTER_TYPE:
+      dtype = build_frontend_type (TREE_TYPE (type));
+      if (dtype)
+	{
+	  /* Check for char * first. Needs to be done for chars/string.  */
+	  if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node)
+	    return Type::tchar->addMod (dtype->mod)->pointerTo ()->addMod (mod);
+
+	  if (dtype->ty == Tfunction)
+	    return (new TypePointer (dtype))->addMod (mod);
+
+	  return dtype->pointerTo ()->addMod (mod);
+	}
+      break;
+
+    case REFERENCE_TYPE:
+      dtype = build_frontend_type (TREE_TYPE (type));
+      if (dtype)
+	{
+	  /* Want to assign ctype directly so that the REFERENCE_TYPE code
+	     can be turned into as an `inout' argument.  Can't use pointerTo(),
+	     because the returned Type is shared.  */
+	  dtype = (new TypePointer (dtype))->addMod (mod);
+	  dtype->ctype = type;
+	  builtin_converted_decls.safe_push (builtin_data (dtype, type));
+	  return dtype;
+	}
+      break;
+
+    case BOOLEAN_TYPE:
+      /* Should be no need for size checking.  */
+      return Type::tbool->addMod (mod);
+
+    case INTEGER_TYPE:
+    {
+      unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
+      bool unsignedp = TYPE_UNSIGNED (type);
+
+      /* For now, skip support for cent/ucent until the frontend
+	 has better support for handling it.  */
+      for (size_t i = Tint8; i <= Tuns64; i++)
+	{
+	  dtype = Type::basic[i];
+
+	  /* Search for type matching size and signedness.  */
+	  if (unsignedp != dtype->isunsigned ()
+	      || size != dtype->size ())
+	    continue;
+
+	  return dtype->addMod (mod);
+	}
+      break;
+    }
+
+    case REAL_TYPE:
+    {
+      unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
+
+      for (size_t i = Tfloat32; i <= Tfloat80; i++)
+	{
+	  dtype = Type::basic[i];
+
+	  /* Search for type matching size.  */
+	  if (dtype->size () != size)
+	    continue;
+
+	  return dtype->addMod (mod);
+	}
+      break;
+    }
+
+    case COMPLEX_TYPE:
+    {
+      unsigned size = TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
+      for (size_t i = Tcomplex32; i <= Tcomplex80; i++)
+	{
+	  dtype = Type::basic[i];
+
+	  /* Search for type matching size.  */
+	  if (dtype->size () != size)
+	    continue;
+
+	  return dtype->addMod (mod);
+	}
+      break;
+    }
+
+    case VOID_TYPE:
+      return Type::tvoid->addMod (mod);
+
+    case ARRAY_TYPE:
+      dtype = build_frontend_type (TREE_TYPE (type));
+      if (dtype)
+	{
+	  tree index = TYPE_DOMAIN (type);
+	  tree ub = TYPE_MAX_VALUE (index);
+	  tree lb = TYPE_MIN_VALUE (index);
+
+	  tree length = fold_build2 (MINUS_EXPR, TREE_TYPE (lb), ub, lb);
+	  length = size_binop (PLUS_EXPR, size_one_node,
+			       convert (sizetype, length));
+
+	  dtype = dtype->sarrayOf (TREE_INT_CST_LOW (length))->addMod (mod);
+	  builtin_converted_decls.safe_push (builtin_data (dtype, type));
+	  return dtype;
+	}
+      break;
+
+    case VECTOR_TYPE:
+      dtype = build_frontend_type (TREE_TYPE (type));
+      if (dtype)
+	{
+	  dtype = dtype->sarrayOf (TYPE_VECTOR_SUBPARTS (type))->addMod (mod);
+
+	  if (dtype->nextOf ()->isTypeBasic () == NULL)
+	    break;
+
+	  /* Support only 64bit, 128bit, and 256bit vectors for now.  */
+	  unsigned size = dtype->size ();
+	  if (size != 8 && size != 16 && size != 32)
+	    break;
+
+	  dtype = (new TypeVector (Loc (), dtype))->addMod (mod);
+	  builtin_converted_decls.safe_push (builtin_data (dtype, type));
+	  return dtype;
+	}
+      break;
+
+    case RECORD_TYPE:
+      if (TYPE_NAME (type))
+	{
+	  tree structname = DECL_NAME (TYPE_NAME (type));
+	  Identifier *ident
+	    = Identifier::idPool (IDENTIFIER_POINTER (structname));
+
+	  /* Neither the `object' and `gcc.builtins' modules will not exist when
+	     this is called.  Use a stub 'object' module parent in the meantime.
+	     If `gcc.builtins' is later imported, the parent will be overridden
+	     with the correct module symbol.  */
+	  static Module *stubmod = Module::create ("object.d", Id::object, 0, 0);
+
+	  StructDeclaration *sdecl = new StructDeclaration (Loc (), ident);
+	  sdecl->parent = stubmod;
+	  sdecl->structsize = int_size_in_bytes (type);
+	  sdecl->alignsize = TYPE_ALIGN_UNIT (type);
+	  sdecl->sizeok = SIZEOKdone;
+	  sdecl->type = (new TypeStruct (sdecl))->addMod (mod);
+	  sdecl->type->ctype = type;
+	  sdecl->type->merge ();
+
+	  /* Does not seem necessary to convert fields, but the members field
+	     must be non-null for the above size setting to stick.  */
+	  sdecl->members = new Dsymbols;
+	  dtype = sdecl->type;
+	  builtin_converted_decls.safe_push (builtin_data (dtype, type, sdecl));
+	  return dtype;
+	}
+      break;
+
+    case FUNCTION_TYPE:
+      dtype = build_frontend_type (TREE_TYPE (type));
+      if (dtype)
+	{
+	  tree parms = TYPE_ARG_TYPES (type);
+	  int varargs_p = 1;
+
+	  Parameters *args = new Parameters;
+	  args->reserve (list_length (parms));
+
+	  /* Attempt to convert all parameter types.  */
+	  for (tree parm = parms; parm != NULL_TREE; parm = TREE_CHAIN (parm))
+	    {
+	      tree argtype = TREE_VALUE (parm);
+	      if (argtype == void_type_node)
+		{
+		  varargs_p = 0;
+		  break;
+		}
+
+	      StorageClass sc = STCundefined;
+	      if (TREE_CODE (argtype) == REFERENCE_TYPE)
+		{
+		  argtype = TREE_TYPE (argtype);
+		  sc |= STCref;
+		}
+
+	      Type *targ = build_frontend_type (argtype);
+	      if (!targ)
+		{
+		  delete args;
+		  return NULL;
+		}
+
+	      args->push (Parameter::create (sc, targ, NULL, NULL));
+	    }
+
+	  /* GCC generic and placeholder builtins are marked as variadic, yet
+	     have no named parameters, and so can't be represented in D.  */
+	  if (args->dim != 0 || !varargs_p)
+	    {
+	      dtype = TypeFunction::create (args, dtype, varargs_p, LINKc);
+	      return dtype->addMod (mod);
+	    }
+	}
+      break;
+
+    default:
+      break;
+    }
+
+  return NULL;
+}
+
+/* Attempt to convert GCC evaluated CST to a D Frontend Expression.
+   This is used for getting the CTFE value out of a const-folded builtin,
+   returns NULL if it cannot convert CST.  */
+
+Expression *
+d_eval_constant_expression (tree cst)
+{
+  STRIP_TYPE_NOPS (cst);
+  Type *type = build_frontend_type (TREE_TYPE (cst));
+
+  if (type)
+    {
+      /* Convert our GCC CST tree into a D Expression.  This seems like we are
+	 trying too hard, as these will only be converted back to a tree again
+	 later in the codegen pass, but satisfies the need to have GCC builtins
+	 CTFE-able in the frontend.  */
+      tree_code code = TREE_CODE (cst);
+      if (code == COMPLEX_CST)
+	{
+	  real_value re = TREE_REAL_CST (TREE_REALPART (cst));
+	  real_value im = TREE_REAL_CST (TREE_IMAGPART (cst));
+	  complex_t value = complex_t (ldouble (re), ldouble (im));
+	  return new ComplexExp (Loc (), value, type);
+	}
+      else if (code == INTEGER_CST)
+	{
+	  dinteger_t value = TREE_INT_CST_LOW (cst);
+	  return new IntegerExp (Loc (), value, type);
+	}
+      else if (code == REAL_CST)
+	{
+	  real_value value = TREE_REAL_CST (cst);
+	  return new RealExp (Loc (), ldouble (value), type);
+	}
+      else if (code == STRING_CST)
+	{
+	  const void *string = TREE_STRING_POINTER (cst);
+	  size_t len = TREE_STRING_LENGTH (cst);
+	  return new StringExp (Loc (), CONST_CAST (void *, string), len);
+	}
+      else if (code == VECTOR_CST)
+	{
+	  dinteger_t nunits = VECTOR_CST_NELTS (cst);
+	  Expressions *elements = new Expressions;
+	  elements->setDim (nunits);
+
+	  for (size_t i = 0; i < nunits; i++)
+	    {
+	      Expression *elem
+		= d_eval_constant_expression (VECTOR_CST_ELT (cst, i));
+	      if (elem == NULL)
+		return NULL;
+
+	      (*elements)[i] = elem;
+	    }
+
+	  Expression *e = new ArrayLiteralExp (Loc (), elements);
+	  e->type = ((TypeVector *) type)->basetype;
+
+	  return new VectorExp (Loc (), e, type);
+	}
+    }
+
+  return NULL;
+}
+
+/* A helper for d_build_builtins_module.  Return a new ALIAS for TYPE.
+   Analogous to `alias ALIAS = TYPE' in D code.  */
+
+static AliasDeclaration *
+build_alias_declaration (const char *alias, Type *type)
+{
+  return new AliasDeclaration (Loc (), Identifier::idPool (alias), type);
+}
+
+/* A helper function for Target::loadModule.  Generates all code for the
+   `gcc.builtins' module, whose frontend symbol should be M.  */
+
+void
+d_build_builtins_module (Module *m)
+{
+  Dsymbols *members = new Dsymbols;
+  tree decl;
+
+  for (size_t i = 0; vec_safe_iterate (gcc_builtins_functions, i, &decl); ++i)
+    {
+      const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+      TypeFunction *tf = (TypeFunction *) build_frontend_type (TREE_TYPE (decl));
+
+      /* Cannot create built-in function type for DECL.  */
+      if (!tf)
+	continue;
+
+      /* A few notes on D2 attributes applied to builtin functions:
+	 - It is assumed that builtins solely provided by the compiler are
+	   considered @safe and pure.
+	 - Builtins that correspond to `extern(C)' functions in the standard
+	   library that have `__attribute__(nothrow)' are considered `@trusted'.
+	 - The purity of a built-in can vary depending on compiler flags set
+	   upon initialization, or by the `-foptions' passed, such as
+	   flag_unsafe_math_optimizations.
+	 - Builtins never use the GC or raise a D exception, and so are always
+	   marked as `nothrow' and `@nogc'.  */
+      tf->purity = DECL_PURE_P (decl) ?   PUREstrong :
+	TREE_READONLY (decl) ? PUREconst :
+	DECL_IS_NOVOPS (decl) ? PUREweak :
+	!DECL_ASSEMBLER_NAME_SET_P (decl) ? PUREweak :
+	PUREimpure;
+      tf->trust = !DECL_ASSEMBLER_NAME_SET_P (decl) ? TRUSTsafe :
+	TREE_NOTHROW (decl) ? TRUSTtrusted :
+	TRUSTsystem;
+      tf->isnothrow = true;
+      tf->isnogc = true;
+
+      FuncDeclaration *func = new FuncDeclaration (Loc (), Loc (),
+						   Identifier::idPool (name),
+						   STCextern, tf);
+      DECL_LANG_SPECIFIC (decl) = build_lang_decl (func);
+      func->csym = decl;
+      func->builtin = BUILTINyes;
+
+      members->push (func);
+    }
+
+  for (size_t i = 0; vec_safe_iterate (gcc_builtins_types, i, &decl); ++i)
+    {
+      const char *name = IDENTIFIER_POINTER (DECL_NAME (decl));
+      Type *t = build_frontend_type (TREE_TYPE (decl));
+
+      /* Cannot create built-in type for DECL.  */
+      if (!t)
+	continue;
+
+      members->push (build_alias_declaration (name, t));
+    }
+
+  /* Iterate through the target-specific builtin types for va_list.  */
+  if (targetm.enum_va_list_p)
+    {
+      const char *name;
+      tree type;
+
+      for (int i = 0; targetm.enum_va_list_p (i, &name, &type); ++i)
+	{
+	  Type *t = build_frontend_type (type);
+	  /* Cannot create built-in type.  */
+	  if (!t)
+	    continue;
+
+	  members->push (build_alias_declaration (name, t));
+	}
+    }
+
+  /* Push out declarations for any RECORD_TYPE types encountered when building
+     all builtin functions and types.  */
+  for (size_t i = 0; i < builtin_converted_decls.length (); ++i)
+    {
+      /* Currently, there is no need to run semantic, but we do want to output
+	 initializers, typeinfo, and others on demand.  */
+      Dsymbol *dsym = builtin_converted_decls[i].dsym;
+      if (dsym != NULL)
+	{
+	  dsym->parent = m;
+	  members->push (dsym);
+	}
+    }
+
+  /* va_list should already be built, so no need to convert to D type again.  */
+  members->push (build_alias_declaration ("__builtin_va_list", Type::tvalist));
+
+  /* Expose target-specific integer types to the builtins module.  */
+  {
+    Type *t = build_frontend_type (long_integer_type_node);
+    members->push (build_alias_declaration ("__builtin_clong", t));
+
+    t = build_frontend_type (long_unsigned_type_node);
+    members->push (build_alias_declaration ("__builtin_culong", t));
+
+    t = build_frontend_type (lang_hooks.types.type_for_mode (byte_mode, 0));
+    members->push (build_alias_declaration ("__builtin_machine_byte", t));
+
+    t = build_frontend_type (lang_hooks.types.type_for_mode (byte_mode, 1));
+    members->push (build_alias_declaration ("__builtin_machine_ubyte", t));
+
+    t = build_frontend_type (lang_hooks.types.type_for_mode (word_mode, 0));
+    members->push (build_alias_declaration ("__builtin_machine_int", t));
+
+    t = build_frontend_type (lang_hooks.types.type_for_mode (word_mode, 1));
+    members->push (build_alias_declaration ("__builtin_machine_uint", t));
+
+    t = build_frontend_type (lang_hooks.types.type_for_mode (ptr_mode, 0));
+    members->push (build_alias_declaration ("__builtin_pointer_int", t));
+
+    t = build_frontend_type (lang_hooks.types.type_for_mode (ptr_mode, 1));
+    members->push (build_alias_declaration ("__builtin_pointer_uint", t));
+
+    /* _Unwind_Word has it's own target specific mode.  */
+    machine_mode mode = targetm.unwind_word_mode ();
+    t = build_frontend_type (lang_hooks.types.type_for_mode (mode, 0));
+    members->push (build_alias_declaration ("__builtin_unwind_int", t));
+
+    t = build_frontend_type (lang_hooks.types.type_for_mode (mode, 1));
+    members->push (build_alias_declaration ("__builtin_unwind_uint", t));
+  }
+
+  m->members->push (new LinkDeclaration (LINKc, members));
+}
+
+/* Search for any `extern(C)' functions that match any known GCC library builtin
+   function in D and override it's internal backend symbol.  */
+
+static void
+maybe_set_builtin_1 (Dsymbol *d)
+{
+  AttribDeclaration *ad = d->isAttribDeclaration ();
+  FuncDeclaration *fd = d->isFuncDeclaration ();
+
+  if (ad != NULL)
+    {
+      /* Recursively search through attribute decls.  */
+      Dsymbols *decls = ad->include (NULL, NULL);
+      if (decls && decls->dim)
+	{
+	  for (size_t i = 0; i < decls->dim; i++)
+	    {
+	      Dsymbol *sym = (*decls)[i];
+	      maybe_set_builtin_1 (sym);
+	    }
+	}
+    }
+  else if (fd && !fd->fbody)
+    {
+      tree t;
+
+      for (size_t i = 0; vec_safe_iterate (gcc_builtins_libfuncs, i, &t); ++i)
+	{
+	  gcc_assert (DECL_ASSEMBLER_NAME_SET_P (t));
+
+	  const char *name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (t));
+	  if (fd->ident != Identifier::idPool (name))
+	    continue;
+
+	  /* Found a match, tell the frontend this is a builtin.  */
+	  DECL_LANG_SPECIFIC (t) = build_lang_decl (fd);
+	  fd->csym = t;
+	  fd->builtin = BUILTINyes;
+	  return;
+	}
+    }
+}
+
+/* A helper function for Target::loadModule.  Traverse all members in module M
+   to search for any functions that can be mapped to any GCC builtin.  */
+
+void
+d_maybe_set_builtin (Module *m)
+{
+  if (!m || !m->members)
+    return;
+
+  for (size_t i = 0; i < m->members->dim; i++)
+    {
+      Dsymbol *sym = (*m->members)[i];
+      maybe_set_builtin_1 (sym);
+    }
+}
+
+/* Used to help initialize the builtin-types.def table.  When a type of
+   the correct size doesn't exist, use error_mark_node instead of NULL.
+   The later results in segfaults even when a decl using the type doesn't
+   get invoked.  */
+
+static tree
+builtin_type_for_size (int size, bool unsignedp)
+{
+  tree type = lang_hooks.types.type_for_size (size, unsignedp);
+  return type ? type : error_mark_node;
+}
+
+/* Support for DEF_BUILTIN.  */
+
+static void
+do_build_builtin_fn (built_in_function fncode,
+		     const char *name,
+		     built_in_class fnclass,
+		     tree fntype, bool both_p, bool fallback_p,
+		     tree fnattrs, bool implicit_p)
+{
+  tree decl;
+  const char *libname;
+
+  if (fntype == error_mark_node)
+    return;
+
+  gcc_assert ((!both_p && !fallback_p)
+	      || !strncmp (name, "__builtin_",
+			   strlen ("__builtin_")));
+
+  libname = name + strlen ("__builtin_");
+
+  decl = add_builtin_function (name, fntype, fncode, fnclass,
+			       fallback_p ? libname : NULL, fnattrs);
+
+  set_builtin_decl (fncode, decl, implicit_p);
+}
+
+/* Standard data types to be used in builtin argument declarations.  */
+
+static GTY(()) tree string_type_node;
+static GTY(()) tree const_string_type_node;
+static GTY(()) tree wint_type_node;
+static GTY(()) tree intmax_type_node;
+static GTY(()) tree uintmax_type_node;
+static GTY(()) tree signed_size_type_node;
+
+
+/* Build nodes that would have be created by the C front-end; necessary
+   for including builtin-types.def and ultimately builtins.def.  */
+
+static void
+d_build_c_type_nodes (void)
+{
+  void_list_node = build_tree_list (NULL_TREE, void_type_node);
+  string_type_node = build_pointer_type (char_type_node);
+  const_string_type_node
+    = build_pointer_type (build_qualified_type (char_type_node,
+						TYPE_QUAL_CONST));
+
+  if (strcmp (SIZE_TYPE, "unsigned int") == 0)
+    {
+      intmax_type_node = integer_type_node;
+      uintmax_type_node = unsigned_type_node;
+      signed_size_type_node = integer_type_node;
+    }
+  else if (strcmp (SIZE_TYPE, "long unsigned int") == 0)
+    {
+      intmax_type_node = long_integer_type_node;
+      uintmax_type_node = long_unsigned_type_node;
+      signed_size_type_node = long_integer_type_node;
+    }
+  else if (strcmp (SIZE_TYPE, "long long unsigned int") == 0)
+    {
+      intmax_type_node = long_long_integer_type_node;
+      uintmax_type_node = long_long_unsigned_type_node;
+      signed_size_type_node = long_long_integer_type_node;
+    }
+  else
+    gcc_unreachable ();
+
+  wint_type_node = unsigned_type_node;
+  pid_type_node = integer_type_node;
+}
+
+/* Build nodes that are used by the D front-end.
+   These are distinct from C types.  */
+
+static void
+d_build_d_type_nodes (void)
+{
+  /* Integral types.  */
+  byte_type_node = make_signed_type (8);
+  ubyte_type_node = make_unsigned_type (8);
+
+  short_type_node = make_signed_type (16);
+  ushort_type_node = make_unsigned_type (16);
+
+  int_type_node = make_signed_type (32);
+  uint_type_node = make_unsigned_type (32);
+
+  long_type_node = make_signed_type (64);
+  ulong_type_node = make_unsigned_type (64);
+
+  cent_type_node = make_signed_type (128);
+  ucent_type_node = make_unsigned_type (128);
+
+  {
+    /* Re-define size_t as a D type.  */
+    machine_mode type_mode = TYPE_MODE (size_type_node);
+    size_type_node = lang_hooks.types.type_for_mode (type_mode, 1);
+  }
+
+  /* Bool and Character types.  */
+  bool_type_node = make_unsigned_type (1);
+  TREE_SET_CODE (bool_type_node, BOOLEAN_TYPE);
+
+  char8_type_node = make_unsigned_type (8);
+  TYPE_STRING_FLAG (char8_type_node) = 1;
+
+  char16_type_node = make_unsigned_type (16);
+  TYPE_STRING_FLAG (char16_type_node) = 1;
+
+  char32_type_node = make_unsigned_type (32);
+  TYPE_STRING_FLAG (char32_type_node) = 1;
+
+  /* Imaginary types.  */
+  ifloat_type_node = build_distinct_type_copy (float_type_node);
+  TYPE_IMAGINARY_FLOAT (ifloat_type_node) = 1;
+
+  idouble_type_node = build_distinct_type_copy (double_type_node);
+  TYPE_IMAGINARY_FLOAT (idouble_type_node) = 1;
+
+  ireal_type_node = build_distinct_type_copy (long_double_type_node);
+  TYPE_IMAGINARY_FLOAT (ireal_type_node) = 1;
+
+  /* Used for ModuleInfo, ClassInfo, and Interface decls.  */
+  unknown_type_node = make_node (RECORD_TYPE);
+
+  /* Make sure we get a unique function type, so we can give
+     its pointer type a name.  (This wins for gdb).  */
+  {
+    tree vfunc_type = make_node (FUNCTION_TYPE);
+    TREE_TYPE (vfunc_type) = int_type_node;
+    TYPE_ARG_TYPES (vfunc_type) = NULL_TREE;
+    layout_type (vfunc_type);
+
+    vtable_entry_type = build_pointer_type (vfunc_type);
+  }
+
+  vtbl_ptr_type_node = build_pointer_type (vtable_entry_type);
+  layout_type (vtbl_ptr_type_node);
+
+  /* When an object is accessed via an interface, this type appears
+     as the first entry in its vtable.  */
+  {
+    tree domain = build_index_type (size_int (3));
+    vtbl_interface_type_node = build_array_type (ptr_type_node, domain);
+  }
+
+  /* Use `void[]' as a generic dynamic array type.  */
+  array_type_node = make_struct_type ("__builtin_void[]", 2,
+				      get_identifier ("length"), size_type_node,
+				      get_identifier ("ptr"), ptr_type_node);
+
+  null_array_node = d_array_value (array_type_node, size_zero_node,
+				   null_pointer_node);
+}
+
+/* Handle default attributes.  */
+
+enum built_in_attribute
+{
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_STRING(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_STRING
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+  ATTR_LAST
+};
+
+static GTY(()) tree built_in_attributes[(int) ATTR_LAST];
+
+/* Initialize the attribute table for all the supported builtins.  */
+
+static void
+d_init_attributes (void)
+{
+  /* Fill in the built_in_attributes array.  */
+#define DEF_ATTR_NULL_TREE(ENUM)                \
+  built_in_attributes[(int) ENUM] = NULL_TREE;
+# define DEF_ATTR_INT(ENUM, VALUE)                                           \
+  built_in_attributes[(int) ENUM] = build_int_cst (NULL_TREE, VALUE);
+#define DEF_ATTR_STRING(ENUM, VALUE)                                         \
+  built_in_attributes[(int) ENUM] = build_string (strlen (VALUE), VALUE);
+#define DEF_ATTR_IDENT(ENUM, STRING)                            \
+  built_in_attributes[(int) ENUM] = get_identifier (STRING);
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
+  built_in_attributes[(int) ENUM]                       \
+  = tree_cons (built_in_attributes[(int) PURPOSE],    \
+	       built_in_attributes[(int) VALUE],      \
+	       built_in_attributes[(int) CHAIN]);
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_STRING
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+}
+
+/* Builtin types.  */
+
+enum d_builtin_type
+{
+#define DEF_PRIMITIVE_TYPE(NAME, VALUE) NAME,
+#define DEF_FUNCTION_TYPE_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) NAME,
+#define DEF_FUNCTION_TYPE_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6) NAME,
+#define DEF_FUNCTION_TYPE_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_8(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8) NAME,
+#define DEF_FUNCTION_TYPE_9(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8, ARG9) NAME,
+#define DEF_FUNCTION_TYPE_10(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			     ARG6, ARG7, ARG8, ARG9, ARG10) NAME,
+#define DEF_FUNCTION_TYPE_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			     ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
+#define DEF_FUNCTION_TYPE_VAR_0(NAME, RETURN) NAME,
+#define DEF_FUNCTION_TYPE_VAR_1(NAME, RETURN, ARG1) NAME,
+#define DEF_FUNCTION_TYPE_VAR_2(NAME, RETURN, ARG1, ARG2) NAME,
+#define DEF_FUNCTION_TYPE_VAR_3(NAME, RETURN, ARG1, ARG2, ARG3) NAME,
+#define DEF_FUNCTION_TYPE_VAR_4(NAME, RETURN, ARG1, ARG2, ARG3, ARG4) NAME,
+#define DEF_FUNCTION_TYPE_VAR_5(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+				NAME,
+#define DEF_FUNCTION_TYPE_VAR_6(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+				ARG6) NAME,
+#define DEF_FUNCTION_TYPE_VAR_7(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+				ARG6, ARG7) NAME,
+#define DEF_FUNCTION_TYPE_VAR_11(NAME, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+				 ARG6, ARG7, ARG8, ARG9, ARG10, ARG11) NAME,
+#define DEF_POINTER_TYPE(NAME, TYPE) NAME,
+#include "builtin-types.def"
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_0
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_9
+#undef DEF_FUNCTION_TYPE_10
+#undef DEF_FUNCTION_TYPE_11
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_FUNCTION_TYPE_VAR_6
+#undef DEF_FUNCTION_TYPE_VAR_7
+#undef DEF_FUNCTION_TYPE_VAR_11
+#undef DEF_POINTER_TYPE
+  BT_LAST
+};
+
+typedef enum d_builtin_type builtin_type;
+
+/* A temporary array used in communication with def_fn_type.  */
+static GTY(()) tree builtin_types[(int) BT_LAST + 1];
+
+/* A helper function for d_init_builtins.  Build function type for DEF with
+   return type RET and N arguments.  If VAR is true, then the function should
+   be variadic after those N arguments.
+
+   Takes special care not to ICE if any of the types involved are
+   error_mark_node, which indicates that said type is not in fact available
+   (see builtin_type_for_size).  In which case the function type as a whole
+   should be error_mark_node.  */
+
+static void
+def_fn_type (builtin_type def, builtin_type ret, bool var, int n, ...)
+{
+  tree t;
+  tree *args = XALLOCAVEC (tree, n);
+  va_list list;
+  int i;
+
+  va_start (list, n);
+  for (i = 0; i < n; ++i)
+    {
+      builtin_type a = (builtin_type) va_arg (list, int);
+      t = builtin_types[a];
+      if (t == error_mark_node)
+	goto egress;
+      args[i] = t;
+    }
+
+  t = builtin_types[ret];
+  if (t == error_mark_node)
+    goto egress;
+  if (var)
+    t = build_varargs_function_type_array (t, n, args);
+  else
+    t = build_function_type_array (t, n, args);
+
+ egress:
+  builtin_types[def] = t;
+  va_end (list);
+}
+
+/* Create builtin types and functions.  VA_LIST_REF_TYPE_NODE and
+   VA_LIST_ARG_TYPE_NODE are used in builtin-types.def.  */
+
+static void
+d_define_builtins (tree va_list_ref_type_node ATTRIBUTE_UNUSED,
+		   tree va_list_arg_type_node ATTRIBUTE_UNUSED)
+{
+#define DEF_PRIMITIVE_TYPE(ENUM, VALUE) \
+  builtin_types[(int) ENUM] = VALUE;
+#define DEF_FUNCTION_TYPE_0(ENUM, RETURN) \
+  def_fn_type (ENUM, RETURN, 0, 0);
+#define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1) \
+  def_fn_type (ENUM, RETURN, 0, 1, ARG1);
+#define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) \
+  def_fn_type (ENUM, RETURN, 0, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+  def_fn_type (ENUM, RETURN, 0, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+  def_fn_type (ENUM, RETURN, 0, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+  def_fn_type (ENUM, RETURN, 0, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6)                                       \
+  def_fn_type (ENUM, RETURN, 0, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7)                                 \
+  def_fn_type (ENUM, RETURN, 0, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_8(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8)                           \
+  def_fn_type (ENUM, RETURN, 0, 8, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,  \
+	       ARG7, ARG8);
+#define DEF_FUNCTION_TYPE_9(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8, ARG9)                     \
+  def_fn_type (ENUM, RETURN, 0, 9, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,  \
+	       ARG7, ARG8, ARG9);
+#define DEF_FUNCTION_TYPE_10(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8, ARG9, ARG10)              \
+  def_fn_type (ENUM, RETURN, 0, 10, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,  \
+	       ARG7, ARG8, ARG9, ARG10);
+#define DEF_FUNCTION_TYPE_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+			    ARG6, ARG7, ARG8, ARG9, ARG10, ARG11)       \
+  def_fn_type (ENUM, RETURN, 0, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,  \
+	       ARG7, ARG8, ARG9, ARG10, ARG11);
+#define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN) \
+  def_fn_type (ENUM, RETURN, 1, 0);
+#define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1) \
+  def_fn_type (ENUM, RETURN, 1, 1, ARG1);
+#define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2) \
+  def_fn_type (ENUM, RETURN, 1, 2, ARG1, ARG2);
+#define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3) \
+  def_fn_type (ENUM, RETURN, 1, 3, ARG1, ARG2, ARG3);
+#define DEF_FUNCTION_TYPE_VAR_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) \
+  def_fn_type (ENUM, RETURN, 1, 4, ARG1, ARG2, ARG3, ARG4);
+#define DEF_FUNCTION_TYPE_VAR_5(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5) \
+  def_fn_type (ENUM, RETURN, 1, 5, ARG1, ARG2, ARG3, ARG4, ARG5);
+#define DEF_FUNCTION_TYPE_VAR_6(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+				ARG6)                                 \
+  def_fn_type (ENUM, RETURN, 1, 6, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6);
+#define DEF_FUNCTION_TYPE_VAR_7(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+				ARG6, ARG7)                                 \
+  def_fn_type (ENUM, RETURN, 1, 7, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6, ARG7);
+#define DEF_FUNCTION_TYPE_VAR_11(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4, ARG5, \
+				 ARG6, ARG7, ARG8, ARG9, ARG10, ARG11)       \
+  def_fn_type (ENUM, RETURN, 1, 11, ARG1, ARG2, ARG3, ARG4, ARG5, ARG6,      \
+	       ARG7, ARG8, ARG9, ARG10, ARG11);
+#define DEF_POINTER_TYPE(ENUM, TYPE) \
+  builtin_types[(int) ENUM] = build_pointer_type (builtin_types[(int) TYPE]);
+
+#include "builtin-types.def"
+
+#undef DEF_PRIMITIVE_TYPE
+#undef DEF_FUNCTION_TYPE_1
+#undef DEF_FUNCTION_TYPE_2
+#undef DEF_FUNCTION_TYPE_3
+#undef DEF_FUNCTION_TYPE_4
+#undef DEF_FUNCTION_TYPE_5
+#undef DEF_FUNCTION_TYPE_6
+#undef DEF_FUNCTION_TYPE_7
+#undef DEF_FUNCTION_TYPE_8
+#undef DEF_FUNCTION_TYPE_9
+#undef DEF_FUNCTION_TYPE_10
+#undef DEF_FUNCTION_TYPE_11
+#undef DEF_FUNCTION_TYPE_VAR_0
+#undef DEF_FUNCTION_TYPE_VAR_1
+#undef DEF_FUNCTION_TYPE_VAR_2
+#undef DEF_FUNCTION_TYPE_VAR_3
+#undef DEF_FUNCTION_TYPE_VAR_4
+#undef DEF_FUNCTION_TYPE_VAR_5
+#undef DEF_FUNCTION_TYPE_VAR_6
+#undef DEF_FUNCTION_TYPE_VAR_7
+#undef DEF_FUNCTION_TYPE_VAR_11
+#undef DEF_POINTER_TYPE
+  builtin_types[(int) BT_LAST] = NULL_TREE;
+
+  d_init_attributes ();
+
+#define DEF_BUILTIN(ENUM, NAME, CLASS, TYPE, LIBTYPE, BOTH_P, FALLBACK_P,   \
+		    NONANSI_P, ATTRS, IMPLICIT, COND)			    \
+  if (NAME && COND)							    \
+    do_build_builtin_fn (ENUM, NAME, CLASS,				    \
+			 builtin_types[(int) TYPE],			    \
+			 BOTH_P, FALLBACK_P,				    \
+			 built_in_attributes[(int) ATTRS], IMPLICIT);
+#include "builtins.def"
+#undef DEF_BUILTIN
+}
+
+/* Build builtin functions and types for the D language frontend.  */
+
+void
+d_init_builtins (void)
+{
+  /* Build the "standard" abi va_list.  */
+  Type::tvalist = build_frontend_type (va_list_type_node);
+  if (!Type::tvalist)
+    {
+      error ("cannot represent built in va_list type in D");
+      gcc_unreachable ();
+    }
+
+  /* Map the va_list type to the D frontend Type.  This is to prevent both
+     errors in gimplification or an ICE in targetm.canonical_va_list_type.  */
+  Type::tvalist->ctype = va_list_type_node;
+  TYPE_LANG_SPECIFIC (va_list_type_node) = build_lang_type (Type::tvalist);
+
+  d_build_c_type_nodes ();
+  d_build_d_type_nodes ();
+
+  if (TREE_CODE (va_list_type_node) == ARRAY_TYPE)
+    {
+      /* It might seem natural to make the argument type a pointer, but there
+         is no implicit casting from arrays to pointers in D.  */
+      d_define_builtins (va_list_type_node, va_list_type_node);
+    }
+  else
+    {
+      d_define_builtins (build_reference_type (va_list_type_node),
+			 va_list_type_node);
+    }
+
+  targetm.init_builtins ();
+  build_common_builtin_nodes ();
+}
+
+/* Registration of machine- or os-specific builtin types.
+   Add to builtin types list for maybe processing later
+   if `gcc.builtins' was imported into the current module.  */
+
+void
+d_register_builtin_type (tree type, const char *name)
+{
+  tree decl = build_decl (UNKNOWN_LOCATION, TYPE_DECL,
+			  get_identifier (name), type);
+  DECL_ARTIFICIAL (decl) = 1;
+
+  if (!TYPE_NAME (type))
+    TYPE_NAME (type) = decl;
+
+  vec_safe_push (gcc_builtins_types, decl);
+}
+
+/* Add DECL to builtin functions list for maybe processing later
+   if `gcc.builtins' was imported into the current module.  */
+
+tree
+d_builtin_function (tree decl)
+{
+  if (!flag_no_builtin && DECL_ASSEMBLER_NAME_SET_P (decl))
+    vec_safe_push (gcc_builtins_libfuncs, decl);
+
+  vec_safe_push (gcc_builtins_functions, decl);
+  return decl;
+}
+
+
+#include "gt-d-d-builtins.h"
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
new file mode 100644
index 00000000000..ae377131261
--- /dev/null
+++ b/gcc/d/d-codegen.cc
@@ -0,0 +1,2654 @@
+/* d-codegen.cc --  Code generation and routines for manipulation of GCC trees.
+   Copyright (C) 2006-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/ctfe.h"
+#include "dfrontend/declaration.h"
+#include "dfrontend/target.h"
+#include "dfrontend/template.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "target.h"
+#include "stringpool.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "attribs.h"
+#include "function.h"
+
+#include "d-tree.h"
+#include "id.h"
+
+
+/* Return the GCC location for the D frontend location LOC.   */
+
+location_t
+get_linemap (const Loc& loc)
+{
+  location_t gcc_location = input_location;
+
+  if (loc.filename)
+    {
+      linemap_add (line_table, LC_ENTER, 0, loc.filename, loc.linnum);
+      linemap_line_start (line_table, loc.linnum, 0);
+      gcc_location = linemap_position_for_column (line_table, loc.charnum);
+      linemap_add (line_table, LC_LEAVE, 0, NULL, 0);
+    }
+
+  return gcc_location;
+}
+
+/* Return the DECL_CONTEXT for symbol DSYM.  */
+
+tree
+d_decl_context (Dsymbol *dsym)
+{
+  Dsymbol *parent = dsym;
+  Declaration *decl = dsym->isDeclaration ();
+
+  while ((parent = parent->toParent2 ()))
+    {
+      /* We've reached the top-level module namespace.
+	 Set DECL_CONTEXT as the NAMESPACE_DECL of the enclosing module,
+	 but only for extern(D) symbols.  */
+      if (parent->isModule ())
+	{
+	  if (decl != NULL && decl->linkage != LINKd)
+	    return NULL_TREE;
+
+	  return build_import_decl (parent);
+	}
+
+      /* Declarations marked as 'static' or '__gshared' are never
+	 part of any context except at module level.  */
+      if (decl != NULL && decl->isDataseg ())
+	continue;
+
+      /* Nested functions.  */
+      FuncDeclaration *fd = parent->isFuncDeclaration ();
+      if (fd != NULL)
+	return get_symbol_decl (fd);
+
+      /* Methods of classes or structs.  */
+      AggregateDeclaration *ad = parent->isAggregateDeclaration ();
+      if (ad != NULL)
+	{
+	  tree context = build_ctype (ad->type);
+	  /* Want the underlying RECORD_TYPE.  */
+	  if (ad->isClassDeclaration ())
+	    context = TREE_TYPE (context);
+
+	  return context;
+	}
+    }
+
+  return NULL_TREE;
+}
+
+/* Return a copy of record TYPE but safe to modify in any way.  */
+
+tree
+copy_aggregate_type (tree type)
+{
+  tree newtype = build_distinct_type_copy (type);
+  TYPE_FIELDS (newtype) = copy_list (TYPE_FIELDS (type));
+  TYPE_METHODS (newtype) = copy_list (TYPE_METHODS (type));
+
+  for (tree f = TYPE_FIELDS (newtype); f; f = DECL_CHAIN (f))
+    DECL_FIELD_CONTEXT (f) = newtype;
+
+  for (tree m = TYPE_METHODS (newtype); m; m = DECL_CHAIN (m))
+    DECL_CONTEXT (m) = newtype;
+
+  return newtype;
+}
+
+/* Return TRUE if declaration DECL is a reference type.  */
+
+bool
+declaration_reference_p (Declaration *decl)
+{
+  Type *tb = decl->type->toBasetype ();
+
+  /* Declaration is a reference type.  */
+  if (tb->ty == Treference || decl->storage_class & (STCout | STCref))
+    return true;
+
+  return false;
+}
+
+/* Returns the real type for declaration DECL.  */
+
+tree
+declaration_type (Declaration *decl)
+{
+  /* Lazy declarations are converted to delegates.  */
+  if (decl->storage_class & STClazy)
+    {
+      TypeFunction *tf = TypeFunction::create (NULL, decl->type, false, LINKd);
+      TypeDelegate *t = new TypeDelegate (tf);
+      return build_ctype (t->merge ());
+    }
+
+  /* Static array va_list have array->pointer conversions applied.  */
+  if (decl->isParameter () && valist_array_p (decl->type))
+    {
+      Type *valist = decl->type->nextOf ()->pointerTo ();
+      valist = valist->castMod (decl->type->mod);
+      return build_ctype (valist);
+    }
+
+  tree type = build_ctype (decl->type);
+
+  /* Parameter is passed by reference.  */
+  if (declaration_reference_p (decl))
+    return build_reference_type (type);
+
+  /* The 'this' parameter is always const.  */
+  if (decl->isThisDeclaration ())
+    return insert_type_modifiers (type, MODconst);
+
+  return type;
+}
+
+/* These should match the Declaration versions above
+   Return TRUE if parameter ARG is a reference type.  */
+
+bool
+argument_reference_p (Parameter *arg)
+{
+  Type *tb = arg->type->toBasetype ();
+
+  /* Parameter is a reference type.  */
+  if (tb->ty == Treference || arg->storageClass & (STCout | STCref))
+    return true;
+
+  tree type = build_ctype (arg->type);
+  if (TREE_ADDRESSABLE (type))
+    return true;
+
+  return false;
+}
+
+/* Returns the real type for parameter ARG.  */
+
+tree
+type_passed_as (Parameter *arg)
+{
+  /* Lazy parameters are converted to delegates.  */
+  if (arg->storageClass & STClazy)
+    {
+      TypeFunction *tf = TypeFunction::create (NULL, arg->type, false, LINKd);
+      TypeDelegate *t = new TypeDelegate (tf);
+      return build_ctype (t->merge ());
+    }
+
+  /* Static array va_list have array->pointer conversions applied.  */
+  if (valist_array_p (arg->type))
+    {
+      Type *valist = arg->type->nextOf ()->pointerTo ();
+      valist = valist->castMod (arg->type->mod);
+      return build_ctype (valist);
+    }
+
+  tree type = build_ctype (arg->type);
+
+  /* Parameter is passed by reference.  */
+  if (argument_reference_p (arg))
+    return build_reference_type (type);
+
+  return type;
+}
+
+/* Build INTEGER_CST of type TYPE with the value VALUE.  */
+
+tree
+build_integer_cst (dinteger_t value, tree type)
+{
+  /* The type is error_mark_node, we can't do anything.  */
+  if (error_operand_p (type))
+    return type;
+
+  return build_int_cst_type (type, value);
+}
+
+/* Build REAL_CST of type TOTYPE with the value VALUE.  */
+
+tree
+build_float_cst (const real_t& value, Type *totype)
+{
+  real_t new_value;
+  TypeBasic *tb = totype->isTypeBasic ();
+
+  gcc_assert (tb != NULL);
+
+  tree type_node = build_ctype (tb);
+  real_convert (&new_value.rv (), TYPE_MODE (type_node), &value.rv ());
+
+  /* Use original if the value grew as a result of the conversion.  */
+  if (new_value > value)
+    new_value = value;
+
+  return build_real (type_node, new_value.rv ());
+}
+
+/* Returns the .length component from the D dynamic array EXP.  */
+
+tree
+d_array_length (tree exp)
+{
+  if (error_operand_p (exp))
+    return exp;
+
+  /* Get the backend type for the array and pick out the array
+     length field (assumed to be the first field).  */
+  tree len_field = TYPE_FIELDS (TREE_TYPE (exp));
+  return component_ref (exp, len_field);
+}
+
+/* Returns the .ptr component from the D dynamic array EXP.  */
+
+tree
+d_array_ptr (tree exp)
+{
+  if (error_operand_p (exp))
+    return exp;
+
+  /* Get the backend type for the array and pick out the array
+     data pointer field (assumed to be the second field).  */
+  tree ptr_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp)));
+  return component_ref (exp, ptr_field);
+}
+
+/* Returns a constructor for D dynamic array type TYPE of .length LEN
+   and .ptr pointing to DATA.  */
+
+tree
+d_array_value (tree type, tree len, tree data)
+{
+  /* TODO: Assert type is a D array.  */
+  tree len_field, ptr_field;
+  vec<constructor_elt, va_gc> *ce = NULL;
+
+  len_field = TYPE_FIELDS (type);
+  ptr_field = TREE_CHAIN (len_field);
+
+  len = convert (TREE_TYPE (len_field), len);
+  data = convert (TREE_TYPE (ptr_field), data);
+
+  CONSTRUCTOR_APPEND_ELT (ce, len_field, len);
+  CONSTRUCTOR_APPEND_ELT (ce, ptr_field, data);
+
+  return build_constructor (type, ce);
+}
+
+/* Builds a D string value from the C string STR.  */
+
+tree
+d_array_string (const char *str)
+{
+  unsigned len = strlen (str);
+  /* Assumes STR is 0-terminated.  */
+  tree str_tree = build_string (len + 1, str);
+
+  TREE_TYPE (str_tree) = make_array_type (Type::tchar, len);
+
+  return d_array_value (build_ctype (Type::tchar->arrayOf ()),
+			size_int (len), build_address (str_tree));
+}
+
+/* Returns value representing the array length of expression EXP.
+   TYPE could be a dynamic or static array.  */
+
+tree
+get_array_length (tree exp, Type *type)
+{
+  Type *tb = type->toBasetype ();
+
+  switch (tb->ty)
+    {
+    case Tsarray:
+      return size_int (((TypeSArray *) tb)->dim->toUInteger ());
+
+    case Tarray:
+      return d_array_length (exp);
+
+    default:
+      error ("can't determine the length of a %s", type->toChars ());
+      return error_mark_node;
+    }
+}
+
+/* Create BINFO for a ClassDeclaration's inheritance tree.
+   InterfaceDeclaration's are not included.  */
+
+tree
+build_class_binfo (tree super, ClassDeclaration *cd)
+{
+  tree binfo = make_tree_binfo (1);
+  tree ctype = build_ctype (cd->type);
+
+  /* Want RECORD_TYPE, not POINTER_TYPE.  */
+  BINFO_TYPE (binfo) = TREE_TYPE (ctype);
+  BINFO_INHERITANCE_CHAIN (binfo) = super;
+  BINFO_OFFSET (binfo) = integer_zero_node;
+
+  if (cd->baseClass)
+    BINFO_BASE_APPEND (binfo, build_class_binfo (binfo, cd->baseClass));
+
+  return binfo;
+}
+
+/* Create BINFO for an InterfaceDeclaration's inheritance tree.
+   In order to access all inherited methods in the debugger,
+   the entire tree must be described.
+   This function makes assumptions about interface layout.  */
+
+tree
+build_interface_binfo (tree super, ClassDeclaration *cd, unsigned& offset)
+{
+  tree binfo = make_tree_binfo (cd->baseclasses->dim);
+  tree ctype = build_ctype (cd->type);
+
+  /* Want RECORD_TYPE, not POINTER_TYPE.  */
+  BINFO_TYPE (binfo) = TREE_TYPE (ctype);
+  BINFO_INHERITANCE_CHAIN (binfo) = super;
+  BINFO_OFFSET (binfo) = size_int (offset * Target::ptrsize);
+  BINFO_VIRTUAL_P (binfo) = 1;
+
+  for (size_t i = 0; i < cd->baseclasses->dim; i++, offset++)
+    {
+      BaseClass *bc = (*cd->baseclasses)[i];
+      BINFO_BASE_APPEND (binfo, build_interface_binfo (binfo, bc->sym, offset));
+    }
+
+  return binfo;
+}
+
+/* Returns the .funcptr component from the D delegate EXP.  */
+
+tree
+delegate_method (tree exp)
+{
+  /* Get the backend type for the array and pick out the array length
+     field (assumed to be the second field).  */
+  tree method_field = TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (exp)));
+  return component_ref (exp, method_field);
+}
+
+/* Returns the .object component from the delegate EXP.  */
+
+tree
+delegate_object (tree exp)
+{
+  /* Get the backend type for the array and pick out the array data
+     pointer field (assumed to be the first field).  */
+  tree obj_field = TYPE_FIELDS (TREE_TYPE (exp));
+  return component_ref (exp, obj_field);
+}
+
+/* Build a delegate literal of type TYPE whose pointer function is
+   METHOD, and hidden object is OBJECT.  */
+
+tree
+build_delegate_cst (tree method, tree object, Type *type)
+{
+  tree ctor = make_node (CONSTRUCTOR);
+  tree ctype;
+
+  Type *tb = type->toBasetype ();
+  if (tb->ty == Tdelegate)
+    ctype = build_ctype (type);
+  else
+    {
+      /* Convert a function method into an anonymous delegate.  */
+      ctype = make_struct_type ("delegate()", 2,
+				get_identifier ("object"), TREE_TYPE (object),
+				get_identifier ("func"), TREE_TYPE (method));
+    }
+
+  vec<constructor_elt, va_gc> *ce = NULL;
+  CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (ctype), object);
+  CONSTRUCTOR_APPEND_ELT (ce, TREE_CHAIN (TYPE_FIELDS (ctype)), method);
+
+  CONSTRUCTOR_ELTS (ctor) = ce;
+  TREE_TYPE (ctor) = ctype;
+
+  return ctor;
+}
+
+/* Builds a temporary tree to store the CALLEE and OBJECT
+   of a method call expression of type TYPE.  */
+
+tree
+build_method_call (tree callee, tree object, Type *type)
+{
+  tree t = build_delegate_cst (callee, object, type);
+  METHOD_CALL_EXPR (t) = 1;
+  return t;
+}
+
+/* Extract callee and object from T and return in to CALLEE and OBJECT.  */
+
+void
+extract_from_method_call (tree t, tree& callee, tree& object)
+{
+  gcc_assert (METHOD_CALL_EXPR (t));
+  object = CONSTRUCTOR_ELT (t, 0)->value;
+  callee = CONSTRUCTOR_ELT (t, 1)->value;
+}
+
+/* Build a dereference into the virtual table for OBJECT to retrieve
+   a function pointer of type FNTYPE at position INDEX.  */
+
+tree
+build_vindex_ref (tree object, tree fntype, size_t index)
+{
+  /* The vtable is the first field.  Interface methods are also in the class's
+     vtable, so we don't need to convert from a class to an interface.  */
+  tree result = build_deref (object);
+  result = component_ref (result, TYPE_FIELDS (TREE_TYPE (result)));
+
+  gcc_assert (POINTER_TYPE_P (fntype));
+
+  return build_memref (fntype, result, size_int (Target::ptrsize * index));
+}
+
+/* Return TRUE if EXP is a valid lvalue.  Lvalues references cannot be
+   made into temporaries, otherwise any assignments will be lost.  */
+
+static bool
+lvalue_p (tree exp)
+{
+  const enum tree_code code = TREE_CODE (exp);
+
+  switch (code)
+    {
+    case SAVE_EXPR:
+      return false;
+
+    case ARRAY_REF:
+    case INDIRECT_REF:
+    case VAR_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+      return !FUNC_OR_METHOD_TYPE_P (TREE_TYPE (exp));
+
+    case IMAGPART_EXPR:
+    case REALPART_EXPR:
+    case COMPONENT_REF:
+    CASE_CONVERT:
+      return lvalue_p (TREE_OPERAND (exp, 0));
+
+    case COND_EXPR:
+      return (lvalue_p (TREE_OPERAND (exp, 1)
+			? TREE_OPERAND (exp, 1)
+			: TREE_OPERAND (exp, 0))
+	      && lvalue_p (TREE_OPERAND (exp, 2)));
+
+    case TARGET_EXPR:
+      return true;
+
+    case COMPOUND_EXPR:
+      return lvalue_p (TREE_OPERAND (exp, 1));
+
+    default:
+      return false;
+    }
+}
+
+/* Create a SAVE_EXPR if EXP might have unwanted side effects if referenced
+   more than once in an expression.  */
+
+tree
+d_save_expr (tree exp)
+{
+  if (TREE_SIDE_EFFECTS (exp))
+    {
+      if (lvalue_p (exp))
+	return stabilize_reference (exp);
+
+      return save_expr (exp);
+    }
+
+  return exp;
+}
+
+/* VALUEP is an expression we want to pre-evaluate or perform a computation on.
+   The expression returned by this function is the part whose value we don't
+   care about, storing the value in VALUEP.  Callers must ensure that the
+   returned expression is evaluated before VALUEP.  */
+
+tree
+stabilize_expr (tree *valuep)
+{
+  const enum tree_code code = TREE_CODE (*valuep);
+  tree lhs;
+  tree rhs;
+
+  switch (code)
+    {
+    case COMPOUND_EXPR:
+      /* Given ((e1, ...), eN):
+	 Store the last RHS 'eN' expression in VALUEP.  */
+      lhs = TREE_OPERAND (*valuep, 0);
+      rhs = TREE_OPERAND (*valuep, 1);
+      lhs = compound_expr (lhs, stabilize_expr (&rhs));
+      *valuep = rhs;
+      return lhs;
+
+    default:
+      return NULL_TREE;
+    }
+}
+
+/* Return a TARGET_EXPR using EXP to initialize a new temporary.  */
+
+tree
+build_target_expr (tree exp)
+{
+  tree type = TREE_TYPE (exp);
+  tree slot = create_temporary_var (type);
+  tree result = build4 (TARGET_EXPR, type, slot, exp, NULL_TREE, NULL_TREE);
+
+  if (EXPR_HAS_LOCATION (exp))
+    SET_EXPR_LOCATION (result, EXPR_LOCATION (exp));
+
+  /* If slot must always reside in memory.  */
+  if (TREE_ADDRESSABLE (type))
+    d_mark_addressable (slot);
+
+  /* Always set TREE_SIDE_EFFECTS so that expand_expr does not ignore the
+     TARGET_EXPR.  If there really turn out to be no side effects, then the
+     optimizer should be able to remove it.  */
+  TREE_SIDE_EFFECTS (result) = 1;
+
+  return result;
+}
+
+/* Returns the address of the expression EXP.  */
+
+tree
+build_address (tree exp)
+{
+  if (error_operand_p (exp))
+    return exp;
+
+  tree ptrtype;
+  tree type = TREE_TYPE (exp);
+
+  if (TREE_CODE (exp) == STRING_CST)
+    {
+      /* Just convert string literals (char[]) to C-style strings (char *),
+	 otherwise the latter method (char[]*) causes conversion problems
+	 during gimplification.  */
+      ptrtype = build_pointer_type (TREE_TYPE (type));
+    }
+  else if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (va_list_type_node)
+	   && TREE_CODE (TYPE_MAIN_VARIANT (type)) == ARRAY_TYPE)
+    {
+      /* Special case for va_list, allow arrays to decay to a pointer.  */
+      ptrtype = build_pointer_type (TREE_TYPE (type));
+    }
+  else
+    ptrtype = build_pointer_type (type);
+
+  /* Maybe rewrite: &(e1, e2) => (e1, &e2).  */
+  tree init = stabilize_expr (&exp);
+
+  /* Can't take the address of a manifest constant, instead use its value.  */
+  if (TREE_CODE (exp) == CONST_DECL)
+    exp = DECL_INITIAL (exp);
+
+  d_mark_addressable (exp);
+  exp = build_fold_addr_expr_with_type_loc (input_location, exp, ptrtype);
+
+  if (TREE_CODE (exp) == ADDR_EXPR)
+    TREE_NO_TRAMPOLINE (exp) = 1;
+
+  return compound_expr (init, exp);
+}
+
+/* Mark EXP saying that we need to be able to take the
+   address of it; it should not be allocated in a register.  */
+
+tree
+d_mark_addressable (tree exp)
+{
+  switch (TREE_CODE (exp))
+    {
+    case ADDR_EXPR:
+    case COMPONENT_REF:
+    case ARRAY_REF:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+      d_mark_addressable (TREE_OPERAND (exp, 0));
+      break;
+
+    case PARM_DECL:
+    case VAR_DECL:
+    case RESULT_DECL:
+    case CONST_DECL:
+    case FUNCTION_DECL:
+      TREE_ADDRESSABLE (exp) = 1;
+      break;
+
+    case CONSTRUCTOR:
+      TREE_ADDRESSABLE (exp) = 1;
+      break;
+
+    case TARGET_EXPR:
+      TREE_ADDRESSABLE (exp) = 1;
+      d_mark_addressable (TREE_OPERAND (exp, 0));
+      break;
+
+    default:
+      break;
+    }
+
+  return exp;
+}
+
+/* Mark EXP as "used" in the program for the benefit of
+   -Wunused warning purposes.  */
+
+tree
+d_mark_used (tree exp)
+{
+  switch (TREE_CODE (exp))
+    {
+    case VAR_DECL:
+    case CONST_DECL:
+    case PARM_DECL:
+    case RESULT_DECL:
+    case FUNCTION_DECL:
+      TREE_USED (exp) = 1;
+      break;
+
+    case ARRAY_REF:
+    case COMPONENT_REF:
+    case MODIFY_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case ADDR_EXPR:
+      d_mark_used (TREE_OPERAND (exp, 0));
+      break;
+
+    case COMPOUND_EXPR:
+      d_mark_used (TREE_OPERAND (exp, 0));
+      d_mark_used (TREE_OPERAND (exp, 1));
+      break;
+
+    default:
+      break;
+    }
+  return exp;
+}
+
+/* Mark EXP as read, not just set, for set but not used -Wunused
+   warning purposes.  */
+
+tree
+d_mark_read (tree exp)
+{
+  switch (TREE_CODE (exp))
+    {
+    case VAR_DECL:
+    case PARM_DECL:
+      TREE_USED (exp) = 1;
+      DECL_READ_P (exp) = 1;
+      break;
+
+    case ARRAY_REF:
+    case COMPONENT_REF:
+    case MODIFY_EXPR:
+    case REALPART_EXPR:
+    case IMAGPART_EXPR:
+    case NOP_EXPR:
+    case CONVERT_EXPR:
+    case ADDR_EXPR:
+      d_mark_read (TREE_OPERAND (exp, 0));
+      break;
+
+    case COMPOUND_EXPR:
+      d_mark_read (TREE_OPERAND (exp, 1));
+      break;
+
+    default:
+      break;
+    }
+  return exp;
+}
+
+/* Return TRUE if the struct SD is suitable for comparison using memcmp.
+   This is because we don't guarantee that padding is zero-initialized for
+   a stack variable, so we can't use memcmp to compare struct values.  */
+
+bool
+identity_compare_p (StructDeclaration *sd)
+{
+  if (sd->isUnionDeclaration ())
+    return true;
+
+  unsigned offset = 0;
+
+  for (size_t i = 0; i < sd->fields.dim; i++)
+    {
+      VarDeclaration *vd = sd->fields[i];
+
+      /* Check inner data structures.  */
+      if (vd->type->ty == Tstruct)
+	{
+	  TypeStruct *ts = (TypeStruct *) vd->type;
+	  if (!identity_compare_p (ts->sym))
+	    return false;
+	}
+
+      if (offset <= vd->offset)
+	{
+	  /* There's a hole in the struct.  */
+	  if (offset != vd->offset)
+	    return false;
+
+	  offset += vd->type->size ();
+	}
+    }
+
+  /* Any trailing padding may not be zero.  */
+  if (offset < sd->structsize)
+    return false;
+
+  return true;
+}
+
+/* Lower a field-by-field equality expression between T1 and T2 of type SD.
+   CODE is the EQ_EXPR or NE_EXPR comparison.  */
+
+static tree
+lower_struct_comparison (tree_code code, StructDeclaration *sd,
+			 tree t1, tree t2)
+{
+  tree_code tcode = (code == EQ_EXPR) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
+  tree tmemcmp = NULL_TREE;
+
+  /* We can skip the compare if the structs are empty  */
+  if (sd->fields.dim == 0)
+    return build_boolop (code, integer_zero_node, integer_zero_node);
+
+  /* Let backend take care of union comparisons.  */
+  if (sd->isUnionDeclaration ())
+    {
+      tmemcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP), 3,
+				 build_address (t1), build_address (t2),
+				 size_int (sd->structsize));
+
+      return build_boolop (code, tmemcmp, integer_zero_node);
+    }
+
+  for (size_t i = 0; i < sd->fields.dim; i++)
+    {
+      VarDeclaration *vd = sd->fields[i];
+      tree sfield = get_symbol_decl (vd);
+
+      tree t1ref = component_ref (t1, sfield);
+      tree t2ref = component_ref (t2, sfield);
+      tree tcmp;
+
+      if (vd->type->ty == Tstruct)
+	{
+	  /* Compare inner data structures.  */
+	  StructDeclaration *decl = ((TypeStruct *) vd->type)->sym;
+	  tcmp = lower_struct_comparison (code, decl, t1ref, t2ref);
+	}
+      else
+	{
+	  tree stype = build_ctype (vd->type);
+	  machine_mode mode = int_mode_for_mode (TYPE_MODE (stype));
+
+	  if (vd->type->ty != Tvector && vd->type->isintegral ())
+	    {
+	      /* Integer comparison, no special handling required.  */
+	      tcmp = build_boolop (code, t1ref, t2ref);
+	    }
+	  else if (mode != BLKmode)
+	    {
+	      /* Compare field bits as their corresponding integer type.
+		    *((T*) &t1) == *((T*) &t2)  */
+	      tree tmode = lang_hooks.types.type_for_mode (mode, 1);
+
+	      if (tmode == NULL_TREE)
+		tmode = make_unsigned_type (GET_MODE_BITSIZE (mode));
+
+	      t1ref = build_vconvert (tmode, t1ref);
+	      t2ref = build_vconvert (tmode, t2ref);
+
+	      tcmp = build_boolop (code, t1ref, t2ref);
+	    }
+	  else
+	    {
+	      /* Simple memcmp between types.  */
+	      tcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP),
+				      3, build_address (t1ref),
+				      build_address (t2ref),
+				      TYPE_SIZE_UNIT (stype));
+
+	      tcmp = build_boolop (code, tcmp, integer_zero_node);
+	    }
+	}
+
+      tmemcmp = (tmemcmp) ? build_boolop (tcode, tmemcmp, tcmp) : tcmp;
+    }
+
+  return tmemcmp;
+}
+
+
+/* Build an equality expression between two RECORD_TYPES T1 and T2 of type SD.
+   If possible, use memcmp, otherwise field-by-field comparison is done.
+   CODE is the EQ_EXPR or NE_EXPR comparison.  */
+
+tree
+build_struct_comparison (tree_code code, StructDeclaration *sd,
+			 tree t1, tree t2)
+{
+  /* We can skip the compare if the structs are empty.  */
+  if (sd->fields.dim == 0)
+    return build_boolop (code, integer_zero_node, integer_zero_node);
+
+  /* Make temporaries to prevent multiple evaluations.  */
+  tree t1init = stabilize_expr (&t1);
+  tree t2init = stabilize_expr (&t2);
+  tree result;
+
+  t1 = d_save_expr (t1);
+  t2 = d_save_expr (t2);
+
+  /* Bitwise comparison of structs not returned in memory may not work
+     due to data holes loosing its zero padding upon return.
+     As a heuristic, small structs are not compared using memcmp either.  */
+  if (TYPE_MODE (TREE_TYPE (t1)) != BLKmode || !identity_compare_p (sd))
+    result = lower_struct_comparison (code, sd, t1, t2);
+  else
+    {
+      /* Do bit compare of structs.  */
+      tree size = size_int (sd->structsize);
+      tree tmemcmp = build_call_expr (builtin_decl_explicit (BUILT_IN_MEMCMP),
+				      3, build_address (t1),
+				      build_address (t2), size);
+
+      result = build_boolop (code, tmemcmp, integer_zero_node);
+    }
+
+  return compound_expr (compound_expr (t1init, t2init), result);
+}
+
+/* Build an equality expression between two ARRAY_TYPES of size LENGTH.
+   The pointer references are T1 and T2, and the element type is SD.
+   CODE is the EQ_EXPR or NE_EXPR comparison.  */
+
+tree
+build_array_struct_comparison (tree_code code, StructDeclaration *sd,
+			       tree length, tree t1, tree t2)
+{
+  tree_code tcode = (code == EQ_EXPR) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
+
+  /* Build temporary for the result of the comparison.
+     Initialize as either 0 or 1 depending on operation.  */
+  tree result = build_local_temp (bool_type_node);
+  tree init = build_boolop (code, integer_zero_node, integer_zero_node);
+  add_stmt (build_assign (INIT_EXPR, result, init));
+
+  /* Cast pointer-to-array to pointer-to-struct.  */
+  tree ptrtype = build_ctype (sd->type->pointerTo ());
+  tree lentype = TREE_TYPE (length);
+
+  push_binding_level (level_block);
+  push_stmt_list ();
+
+  /* Build temporary locals for length and pointers.  */
+  tree t = build_local_temp (size_type_node);
+  add_stmt (build_assign (INIT_EXPR, t, length));
+  length = t;
+
+  t = build_local_temp (ptrtype);
+  add_stmt (build_assign (INIT_EXPR, t, d_convert (ptrtype, t1)));
+  t1 = t;
+
+  t = build_local_temp (ptrtype);
+  add_stmt (build_assign (INIT_EXPR, t, d_convert (ptrtype, t2)));
+  t2 = t;
+
+  /* Build loop for comparing each element.  */
+  push_stmt_list ();
+
+  /* Exit logic for the loop.
+	if (length == 0 || result OP 0) break;  */
+  t = build_boolop (EQ_EXPR, length, d_convert (lentype, integer_zero_node));
+  t = build_boolop (TRUTH_ORIF_EXPR, t, build_boolop (code, result,
+						      boolean_false_node));
+  t = build1 (EXIT_EXPR, void_type_node, t);
+  add_stmt (t);
+
+  /* Do comparison, caching the value.
+	result = result OP (*t1 == *t2);  */
+  t = build_struct_comparison (code, sd, build_deref (t1), build_deref (t2));
+  t = build_boolop (tcode, result, t);
+  t = modify_expr (result, t);
+  add_stmt (t);
+
+  /* Move both pointers to next element position.
+	t1++, t2++;  */
+  tree size = d_convert (ptrtype, TYPE_SIZE_UNIT (TREE_TYPE (ptrtype)));
+  t = build2 (POSTINCREMENT_EXPR, ptrtype, t1, size);
+  add_stmt (t);
+  t = build2 (POSTINCREMENT_EXPR, ptrtype, t2, size);
+  add_stmt (t);
+
+  /* Decrease loop counter.
+	length -= 1;  */
+  t = build2 (POSTDECREMENT_EXPR, lentype, length,
+	     d_convert (lentype, integer_one_node));
+  add_stmt (t);
+
+  /* Pop statements and finish loop.  */
+  tree body = pop_stmt_list ();
+  add_stmt (build1 (LOOP_EXPR, void_type_node, body));
+
+  /* Wrap it up into a bind expression.  */
+  tree stmt_list = pop_stmt_list ();
+  tree block = pop_binding_level ();
+
+  body = build3 (BIND_EXPR, void_type_node,
+		 BLOCK_VARS (block), stmt_list, block);
+
+  return compound_expr (body, result);
+}
+
+/* Create an anonymous field of type ubyte[T] at OFFSET to fill
+   the alignment hole between OFFSET and FIELDPOS.  */
+
+static tree
+build_alignment_field (HOST_WIDE_INT offset, HOST_WIDE_INT fieldpos)
+{
+  tree type = make_array_type (Type::tuns8, fieldpos - offset);
+  tree field = create_field_decl (type, NULL, 1, 1);
+
+  SET_DECL_OFFSET_ALIGN (field, TYPE_ALIGN (type));
+  DECL_FIELD_OFFSET (field) = size_int (offset);
+  DECL_FIELD_BIT_OFFSET (field) = bitsize_zero_node;
+
+  layout_decl (field, 0);
+
+  return field;
+}
+
+/* Build a constructor for a variable of aggregate type TYPE using the
+   initializer INIT, an ordered flat list of fields and values provided
+   by the frontend.  The returned constructor should be a value that
+   matches the layout of TYPE.  */
+
+tree
+build_struct_literal (tree type, vec<constructor_elt, va_gc> *init)
+{
+  /* If the initializer was empty, use default zero initialization.  */
+  if (vec_safe_is_empty (init))
+    return build_constructor (type, NULL);
+
+  vec<constructor_elt, va_gc> *ve = NULL;
+  HOST_WIDE_INT offset = 0;
+  bool constant_p = true;
+  bool fillholes = true;
+  bool finished = false;
+
+  /* Filling alignment holes this only applies to structs.  */
+  if (TREE_CODE (type) != RECORD_TYPE
+      || CLASS_TYPE_P (type) || TYPE_PACKED (type))
+    fillholes = false;
+
+  /* Walk through each field, matching our initializer list.  */
+  for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+    {
+      bool is_initialized = false;
+      tree value;
+
+      if (DECL_NAME (field) == NULL_TREE
+	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
+	  && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+	{
+	  /* Search all nesting aggregates, if nothing is found, then
+	     this will return an empty initializer to fill the hole.  */
+	  value = build_struct_literal (TREE_TYPE (field), init);
+
+	  if (!initializer_zerop (value))
+	    is_initialized = true;
+	}
+      else
+	{
+	  /* Search for the value to initialize the next field.  Once found,
+	     pop it from the init list so we don't look at it again.  */
+	  unsigned HOST_WIDE_INT idx;
+	  tree index;
+
+	  FOR_EACH_CONSTRUCTOR_ELT (init, idx, index, value)
+	    {
+	      /* If the index is NULL, then just assign it to the next field.
+		 This is expect of layout_typeinfo(), which generates a flat
+		 list of values that we must shape into the record type.  */
+	      if (index == field || index == NULL_TREE)
+		{
+		  init->ordered_remove (idx);
+		  if (!finished)
+		    is_initialized = true;
+		  break;
+		}
+	    }
+	}
+
+      if (is_initialized)
+	{
+	  HOST_WIDE_INT fieldpos = int_byte_position (field);
+	  gcc_assert (value != NULL_TREE);
+
+	  /* Insert anonymous fields in the constructor for padding out
+	     alignment holes in-place between fields.  */
+	  if (fillholes && offset < fieldpos)
+	    {
+	      tree pfield = build_alignment_field (offset, fieldpos);
+	      tree pvalue = build_constructor (TREE_TYPE (pfield), NULL);
+	      CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue);
+	    }
+
+	  /* Must not initialize fields that overlap.  */
+	  if (fieldpos < offset)
+	    {
+	      /* Find the nearest user defined type and field.  */
+	      tree vtype = type;
+	      while (ANON_AGGR_TYPE_P (vtype))
+		vtype = TYPE_CONTEXT (vtype);
+
+	      tree vfield = field;
+	      if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (vfield))
+		  && ANON_AGGR_TYPE_P (TREE_TYPE (vfield)))
+		vfield = TYPE_FIELDS (TREE_TYPE (vfield));
+
+	      /* Must not generate errors for compiler generated fields.  */
+	      gcc_assert (TYPE_NAME (vtype) && DECL_NAME (vfield));
+	      error ("overlapping initializer for field %qT.%qD",
+		     TYPE_NAME (vtype), DECL_NAME (vfield));
+	    }
+
+	  if (!TREE_CONSTANT (value))
+	    constant_p = false;
+
+	  CONSTRUCTOR_APPEND_ELT (ve, field, value);
+
+	  /* For unions, only the first field is initialized, any other field
+	     initializers found for this union are drained and ignored.  */
+	  if (TREE_CODE (type) == UNION_TYPE)
+	    finished = true;
+	}
+
+      /* Move offset to the next position in the struct.  */
+      if (TREE_CODE (type) == RECORD_TYPE)
+	{
+	  offset = int_byte_position (field)
+	    + int_size_in_bytes (TREE_TYPE (field));
+	}
+
+      /* If all initializers have been assigned, there's nothing else to do.  */
+      if (vec_safe_is_empty (init))
+	break;
+    }
+
+  /* Finally pad out the end of the record.  */
+  if (fillholes && offset < int_size_in_bytes (type))
+    {
+      tree pfield = build_alignment_field (offset, int_size_in_bytes (type));
+      tree pvalue = build_constructor (TREE_TYPE (pfield), NULL);
+      CONSTRUCTOR_APPEND_ELT (ve, pfield, pvalue);
+    }
+
+  /* Ensure that we have consumed all values.  */
+  gcc_assert (vec_safe_is_empty (init) || ANON_AGGR_TYPE_P (type));
+
+  tree ctor = build_constructor (type, ve);
+
+  if (constant_p)
+    TREE_CONSTANT (ctor) = 1;
+
+  return ctor;
+}
+
+/* Find the field inside aggregate TYPE identified by IDENT at field OFFSET.  */
+
+static tree
+find_aggregate_field (tree type, tree ident, tree offset)
+{
+  tree fields = TYPE_FIELDS (type);
+
+  for (tree field = fields; field != NULL_TREE; field = TREE_CHAIN (field))
+    {
+      if (DECL_NAME (field) == NULL_TREE
+	  && RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
+	  && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+	{
+	  /* Search nesting anonymous structs and unions.  */
+	  tree vfield = find_aggregate_field (TREE_TYPE (field),
+					      ident, offset);
+	  if (vfield != NULL_TREE)
+	    return vfield;
+	}
+      else if (DECL_NAME (field) == ident
+	       && (offset == NULL_TREE
+		   || DECL_FIELD_OFFSET (field) == offset))
+	{
+	  /* Found matching field at offset.  */
+	  return field;
+	}
+    }
+
+  return NULL_TREE;
+}
+/* Return a constructor that matches the layout of the class expression EXP.  */
+
+tree
+build_class_instance (ClassReferenceExp *exp)
+{
+  ClassDeclaration *cd = exp->originalClass ();
+  tree type = TREE_TYPE (build_ctype (exp->value->stype));
+  vec<constructor_elt, va_gc> *ve = NULL;
+
+  /* The set base vtable field.  */
+  tree vptr = build_address (get_vtable_decl (cd));
+  CONSTRUCTOR_APPEND_ELT (ve, TYPE_FIELDS (type), vptr);
+
+  /* Go through the inheritance graph from top to bottom.  This will add all
+     values to the constructor out of order, however build_struct_literal
+     will re-order all values before returning the finished literal.  */
+  for (ClassDeclaration *bcd = cd; bcd != NULL; bcd = bcd->baseClass)
+    {
+      /* Anonymous vtable interface fields are layed out before the fields of
+	 each class.  The interface offset is used to determine where to put
+	 the classinfo offset reference.  */
+      for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++)
+	{
+	  BaseClass *bc = (*bcd->vtblInterfaces)[i];
+
+	  for (ClassDeclaration *cd2 = cd; 1; cd2 = cd2->baseClass)
+	    {
+	      gcc_assert (cd2 != NULL);
+
+	      unsigned csymoffset = base_vtable_offset (cd2, bc);
+	      if (csymoffset != (unsigned) ~0)
+		{
+		  tree csym = build_address (get_classinfo_decl (cd2));
+		  csym = build_offset (csym, size_int (csymoffset));
+
+		  tree field = find_aggregate_field (type, NULL_TREE,
+						     size_int (bc->offset));
+		  gcc_assert (field != NULL_TREE);
+
+		  CONSTRUCTOR_APPEND_ELT (ve, field, csym);
+		  break;
+		}
+	    }
+	}
+
+      /* Generate initial values of all fields owned by current class.
+	 Use both the name and offset to find the right field.  */
+      for (size_t i = 0; i < bcd->fields.dim; i++)
+	{
+	  VarDeclaration *vfield = bcd->fields[i];
+	  int index = exp->findFieldIndexByName (vfield);
+	  gcc_assert (index != -1);
+
+	  Expression *value = (*exp->value->elements)[index];
+	  if (!value)
+	    continue;
+
+	  /* Use find_aggregate_field to get the overridden field decl,
+	     instead of the field associated with the base class.  */
+	  tree field = get_symbol_decl (bcd->fields[i]);
+	  field = find_aggregate_field (type, DECL_NAME (field),
+					DECL_FIELD_OFFSET (field));
+	  gcc_assert (field != NULL_TREE);
+
+	  CONSTRUCTOR_APPEND_ELT (ve, field, build_expr (value, true));
+	}
+    }
+
+  return build_struct_literal (type, ve);
+}
+
+/* Given the TYPE of an anonymous field inside T, return the
+   FIELD_DECL for the field.  If not found return NULL_TREE.
+   Because anonymous types can nest, we must also search all
+   anonymous fields that are directly reachable.  */
+
+static tree
+lookup_anon_field (tree t, tree type)
+{
+  t = TYPE_MAIN_VARIANT (t);
+
+  for (tree field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
+    {
+      if (DECL_NAME (field) == NULL_TREE)
+	{
+	  /* If we find it directly, return the field.  */
+	  if (type == TYPE_MAIN_VARIANT (TREE_TYPE (field)))
+	    return field;
+
+	  /* Otherwise, it could be nested, search harder.  */
+	  if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (field))
+	      && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
+	    {
+	      tree subfield = lookup_anon_field (TREE_TYPE (field), type);
+	      if (subfield)
+		return subfield;
+	    }
+	}
+    }
+
+  return NULL_TREE;
+}
+
+/* Builds OBJECT.FIELD component reference.  */
+
+tree
+component_ref (tree object, tree field)
+{
+  if (error_operand_p (object) || error_operand_p (field))
+    return error_mark_node;
+
+  gcc_assert (TREE_CODE (field) == FIELD_DECL);
+
+  /* Maybe rewrite: (e1, e2).field => (e1, e2.field)  */
+  tree init = stabilize_expr (&object);
+
+  /* If the FIELD is from an anonymous aggregate, generate a reference
+     to the anonymous data member, and recur to find FIELD.  */
+  if (ANON_AGGR_TYPE_P (DECL_CONTEXT (field)))
+    {
+      tree anonymous_field = lookup_anon_field (TREE_TYPE (object),
+						DECL_CONTEXT (field));
+      object = component_ref (object, anonymous_field);
+    }
+
+  tree result = fold_build3_loc (input_location, COMPONENT_REF,
+				 TREE_TYPE (field), object, field, NULL_TREE);
+
+  return compound_expr (init, result);
+}
+
+/* Build an assignment expression of lvalue LHS from value RHS.
+   CODE is the code for a binary operator that we use to combine
+   the old value of LHS with RHS to get the new value.  */
+
+tree
+build_assign (tree_code code, tree lhs, tree rhs)
+{
+  tree init = stabilize_expr (&lhs);
+  init = compound_expr (init, stabilize_expr (&rhs));
+
+  /* If initializing the LHS using a function that returns via NRVO.  */
+  if (code == INIT_EXPR && TREE_CODE (rhs) == CALL_EXPR
+      && AGGREGATE_TYPE_P (TREE_TYPE (rhs))
+      && aggregate_value_p (TREE_TYPE (rhs), rhs))
+    {
+      /* Mark as addressable here, which should ensure the return slot is the
+	 address of the LHS expression, taken care of by back-end.  */
+      d_mark_addressable (lhs);
+      CALL_EXPR_RETURN_SLOT_OPT (rhs) = true;
+    }
+
+  /* The LHS assignment replaces the temporary in TARGET_EXPR_SLOT.  */
+  if (TREE_CODE (rhs) == TARGET_EXPR)
+    {
+      /* If CODE is not INIT_EXPR, can't initialize LHS directly,
+	 since that would cause the LHS to be constructed twice.
+	 So we force the TARGET_EXPR to be expanded without a target.  */
+      if (code != INIT_EXPR)
+	rhs = compound_expr (rhs, TARGET_EXPR_SLOT (rhs));
+      else
+	{
+	  d_mark_addressable (lhs);
+	  rhs = TARGET_EXPR_INITIAL (rhs);
+	}
+    }
+
+  tree result = fold_build2_loc (input_location, code,
+				 TREE_TYPE (lhs), lhs, rhs);
+  return compound_expr (init, result);
+}
+
+/* Build an assignment expression of lvalue LHS from value RHS.  */
+
+tree
+modify_expr (tree lhs, tree rhs)
+{
+  return build_assign (MODIFY_EXPR, lhs, rhs);
+}
+
+/* Return EXP represented as TYPE.  */
+
+tree
+build_nop (tree type, tree exp)
+{
+  if (error_operand_p (exp))
+    return exp;
+
+  /* Maybe rewrite: cast(TYPE)(e1, e2) => (e1, cast(TYPE) e2)  */
+  tree init = stabilize_expr (&exp);
+  exp = fold_build1_loc (input_location, NOP_EXPR, type, exp);
+
+  return compound_expr (init, exp);
+}
+
+/* Return EXP to be viewed as being another type TYPE.  Same as build_nop,
+   except that EXP is type-punned, rather than a straight-forward cast.  */
+
+tree
+build_vconvert (tree type, tree exp)
+{
+  /* Building *(cast(TYPE *)&e1) directly rather then using VIEW_CONVERT_EXPR
+     makes sure this works for vector-to-array viewing, or if EXP ends up being
+     used as the LHS of a MODIFY_EXPR.  */
+  return indirect_ref (type, build_address (exp));
+}
+
+/* Build a boolean ARG0 op ARG1 expression.  */
+
+tree
+build_boolop (tree_code code, tree arg0, tree arg1)
+{
+  /* Aggregate comparisons may get lowered to a call to builtin memcmp,
+     so need to remove all side effects incase it's address is taken.  */
+  if (AGGREGATE_TYPE_P (TREE_TYPE (arg0)))
+    arg0 = d_save_expr (arg0);
+  if (AGGREGATE_TYPE_P (TREE_TYPE (arg1)))
+    arg1 = d_save_expr (arg1);
+
+  return fold_build2_loc (input_location, code, bool_type_node,
+			  arg0, d_convert (TREE_TYPE (arg0), arg1));
+}
+
+/* Return a COND_EXPR.  ARG0, ARG1, and ARG2 are the three
+   arguments to the conditional expression.  */
+
+tree
+build_condition (tree type, tree arg0, tree arg1, tree arg2)
+{
+  if (arg1 == void_node)
+    arg1 = build_empty_stmt (input_location);
+
+  if (arg2 == void_node)
+    arg2 = build_empty_stmt (input_location);
+
+  return fold_build3_loc (input_location, COND_EXPR,
+			  type, arg0, arg1, arg2);
+}
+
+tree
+build_vcondition (tree arg0, tree arg1, tree arg2)
+{
+  return build_condition (void_type_node, arg0, arg1, arg2);
+}
+
+/* Build a compound expr to join ARG0 and ARG1 together.  */
+
+tree
+compound_expr (tree arg0, tree arg1)
+{
+  if (arg1 == NULL_TREE)
+    return arg0;
+
+  if (arg0 == NULL_TREE || !TREE_SIDE_EFFECTS (arg0))
+    return arg1;
+
+  if (TREE_CODE (arg1) == TARGET_EXPR)
+    {
+      /* If the rhs is a TARGET_EXPR, then build the compound expression
+	 inside the target_expr's initializer.  This helps the compiler
+	 to eliminate unnecessary temporaries.  */
+      tree init = compound_expr (arg0, TARGET_EXPR_INITIAL (arg1));
+      TARGET_EXPR_INITIAL (arg1) = init;
+
+      return arg1;
+    }
+
+  return fold_build2_loc (input_location, COMPOUND_EXPR,
+			  TREE_TYPE (arg1), arg0, arg1);
+}
+
+/* Build a return expression.  */
+
+tree
+return_expr (tree ret)
+{
+  return fold_build1_loc (input_location, RETURN_EXPR,
+			  void_type_node, ret);
+}
+
+/* Return the product of ARG0 and ARG1 as a size_type_node.  */
+
+tree
+size_mult_expr (tree arg0, tree arg1)
+{
+  return fold_build2_loc (input_location, MULT_EXPR, size_type_node,
+			  d_convert (size_type_node, arg0),
+			  d_convert (size_type_node, arg1));
+
+}
+
+/* Return the real part of CE, which should be a complex expression.  */
+
+tree
+real_part (tree ce)
+{
+  return fold_build1_loc (input_location, REALPART_EXPR,
+			  TREE_TYPE (TREE_TYPE (ce)), ce);
+}
+
+/* Return the imaginary part of CE, which should be a complex expression.  */
+
+tree
+imaginary_part (tree ce)
+{
+  return fold_build1_loc (input_location, IMAGPART_EXPR,
+			  TREE_TYPE (TREE_TYPE (ce)), ce);
+}
+
+/* Build a complex expression of type TYPE using RE and IM.  */
+
+tree
+complex_expr (tree type, tree re, tree im)
+{
+  return fold_build2_loc (input_location, COMPLEX_EXPR,
+			  type, re, im);
+}
+
+/* Cast EXP (which should be a pointer) to TYPE* and then indirect.
+   The back-end requires this cast in many cases.  */
+
+tree
+indirect_ref (tree type, tree exp)
+{
+  if (error_operand_p (exp))
+    return exp;
+
+  /* Maybe rewrite: *(e1, e2) => (e1, *e2)  */
+  tree init = stabilize_expr (&exp);
+
+  if (TREE_CODE (TREE_TYPE (exp)) == REFERENCE_TYPE)
+    exp = fold_build1 (INDIRECT_REF, type, exp);
+  else
+    {
+      exp = build_nop (build_pointer_type (type), exp);
+      exp = build_deref (exp);
+    }
+
+  return compound_expr (init, exp);
+}
+
+/* Returns indirect reference of EXP, which must be a pointer type.  */
+
+tree
+build_deref (tree exp)
+{
+  if (error_operand_p (exp))
+    return exp;
+
+  /* Maybe rewrite: *(e1, e2) => (e1, *e2)  */
+  tree init = stabilize_expr (&exp);
+
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (exp)));
+
+  if (TREE_CODE (exp) == ADDR_EXPR)
+    exp = TREE_OPERAND (exp, 0);
+  else
+    exp = build_fold_indirect_ref (exp);
+
+  return compound_expr (init, exp);
+}
+
+/* Builds pointer offset expression PTR[INDEX].  */
+
+tree
+build_array_index (tree ptr, tree index)
+{
+  if (error_operand_p (ptr) || error_operand_p (index))
+    return error_mark_node;
+
+  tree ptr_type = TREE_TYPE (ptr);
+  tree target_type = TREE_TYPE (ptr_type);
+
+  tree type = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype),
+					      TYPE_UNSIGNED (sizetype));
+
+  /* Array element size.  */
+  tree size_exp = size_in_bytes (target_type);
+
+  if (integer_zerop (size_exp))
+    {
+      /* Test for array of void.  */
+      if (TYPE_MODE (target_type) == TYPE_MODE (void_type_node))
+	index = fold_convert (type, index);
+      else
+	{
+	  /* Should catch this earlier.  */
+	  error ("invalid use of incomplete type %qD", TYPE_NAME (target_type));
+	  ptr_type = error_mark_node;
+	}
+    }
+  else if (integer_onep (size_exp))
+    {
+      /* Array of bytes -- No need to multiply.  */
+      index = fold_convert (type, index);
+    }
+  else
+    {
+      index = d_convert (type, index);
+      index = fold_build2 (MULT_EXPR, TREE_TYPE (index),
+			   index, d_convert (TREE_TYPE (index), size_exp));
+      index = fold_convert (type, index);
+    }
+
+  if (integer_zerop (index))
+    return ptr;
+
+  return fold_build2 (POINTER_PLUS_EXPR, ptr_type, ptr, index);
+}
+
+/* Builds pointer offset expression *(PTR OP OFFSET)
+   OP could be a plus or minus expression.  */
+
+tree
+build_offset_op (tree_code op, tree ptr, tree offset)
+{
+  gcc_assert (op == MINUS_EXPR || op == PLUS_EXPR);
+
+  tree type = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype),
+					      TYPE_UNSIGNED (sizetype));
+  offset = fold_convert (type, offset);
+
+  if (op == MINUS_EXPR)
+    offset = fold_build1 (NEGATE_EXPR, type, offset);
+
+  return fold_build2 (POINTER_PLUS_EXPR, TREE_TYPE (ptr), ptr, offset);
+}
+
+/* Builds pointer offset expression *(PTR + OFFSET).  */
+
+tree
+build_offset (tree ptr, tree offset)
+{
+  return build_offset_op (PLUS_EXPR, ptr, offset);
+}
+
+tree
+build_memref (tree type, tree ptr, tree offset)
+{
+  return fold_build2 (MEM_REF, type, ptr, fold_convert (type, offset));
+}
+
+/* Create a tree node to set multiple elements to a single value.  */
+
+tree
+build_array_set (tree ptr, tree length, tree value)
+{
+  tree ptrtype = TREE_TYPE (ptr);
+  tree lentype = TREE_TYPE (length);
+
+  push_binding_level (level_block);
+  push_stmt_list ();
+
+  /* Build temporary locals for length and ptr, and maybe value.  */
+  tree t = build_local_temp (size_type_node);
+  add_stmt (build_assign (INIT_EXPR, t, length));
+  length = t;
+
+  t = build_local_temp (ptrtype);
+  add_stmt (build_assign (INIT_EXPR, t, ptr));
+  ptr = t;
+
+  if (TREE_SIDE_EFFECTS (value))
+    {
+      t = build_local_temp (TREE_TYPE (value));
+      add_stmt (build_assign (INIT_EXPR, t, value));
+      value = t;
+    }
+
+  /* Build loop to initialise { .length=length, .ptr=ptr } with value.  */
+  push_stmt_list ();
+
+  /* Exit logic for the loop.
+	if (length == 0) break;  */
+  t = build_boolop (EQ_EXPR, length, d_convert (lentype, integer_zero_node));
+  t = build1 (EXIT_EXPR, void_type_node, t);
+  add_stmt (t);
+
+  /* Assign value to the current pointer position.
+	*ptr = value;  */
+  t = modify_expr (build_deref (ptr), value);
+  add_stmt (t);
+
+  /* Move pointer to next element position.
+	ptr++;  */
+  tree size = TYPE_SIZE_UNIT (TREE_TYPE (ptrtype));
+  t = build2 (POSTINCREMENT_EXPR, ptrtype, ptr, d_convert (ptrtype, size));
+  add_stmt (t);
+
+  /* Decrease loop counter.
+	length -= 1;  */
+  t = build2 (POSTDECREMENT_EXPR, lentype, length,
+	      d_convert (lentype, integer_one_node));
+  add_stmt (t);
+
+  /* Pop statements and finish loop.  */
+  tree loop_body = pop_stmt_list ();
+  add_stmt (build1 (LOOP_EXPR, void_type_node, loop_body));
+
+  /* Wrap it up into a bind expression.  */
+  tree stmt_list = pop_stmt_list ();
+  tree block = pop_binding_level ();
+
+  return build3 (BIND_EXPR, void_type_node,
+		 BLOCK_VARS (block), stmt_list, block);
+}
+
+
+/* Build an array of type TYPE where all the elements are VAL.  */
+
+tree
+build_array_from_val (Type *type, tree val)
+{
+  gcc_assert (type->ty == Tsarray);
+
+  tree etype = build_ctype (type->nextOf ());
+
+  /* Initializing a multidimensional array.  */
+  if (TREE_CODE (etype) == ARRAY_TYPE && TREE_TYPE (val) != etype)
+    val = build_array_from_val (type->nextOf (), val);
+
+  size_t dims = ((TypeSArray *) type)->dim->toInteger ();
+  vec<constructor_elt, va_gc> *elms = NULL;
+  vec_safe_reserve (elms, dims);
+
+  val = d_convert (etype, val);
+
+  for (size_t i = 0; i < dims; i++)
+    CONSTRUCTOR_APPEND_ELT (elms, size_int (i), val);
+
+  return build_constructor (build_ctype (type), elms);
+}
+
+/* Implicitly converts void* T to byte* as D allows { void[] a; &a[3]; }  */
+
+tree
+void_okay_p (tree t)
+{
+  tree type = TREE_TYPE (t);
+
+  if (VOID_TYPE_P (TREE_TYPE (type)))
+    {
+      tree totype = build_ctype (Type::tuns8->pointerTo ());
+      return fold_convert (totype, t);
+    }
+
+  return t;
+}
+
+/* Builds a bounds condition checking that INDEX is between 0 and LEN.
+   The condition returns the INDEX if true, or throws a RangeError.
+   If INCLUSIVE, we allow INDEX == LEN to return true also.  */
+
+tree
+build_bounds_condition (const Loc& loc, tree index, tree len, bool inclusive)
+{
+  if (!array_bounds_check ())
+    return index;
+
+  /* Prevent multiple evaluations of the index.  */
+  index = d_save_expr (index);
+
+  /* Generate INDEX >= LEN && throw RangeError.
+     No need to check whether INDEX >= 0 as the front-end should
+     have already taken care of implicit casts to unsigned.  */
+  tree condition = fold_build2 (inclusive ? GT_EXPR : GE_EXPR,
+				bool_type_node, index, len);
+  tree boundserr = d_assert_call (loc, LIBCALL_ARRAY_BOUNDS);
+
+  return build_condition (TREE_TYPE (index), condition, boundserr, index);
+}
+
+/* Returns TRUE if array bounds checking code generation is turned on.  */
+
+bool
+array_bounds_check (void)
+{
+  FuncDeclaration *func;
+
+  switch (global.params.useArrayBounds)
+    {
+    case BOUNDSCHECKoff:
+      return false;
+
+    case BOUNDSCHECKon:
+      return true;
+
+    case BOUNDSCHECKsafeonly:
+      /* For D2 safe functions only.  */
+      func = d_function_chain->function;
+      if (func && func->type->ty == Tfunction)
+	{
+	  TypeFunction *tf = (TypeFunction *) func->type;
+	  if (tf->trust == TRUSTsafe)
+	    return true;
+	}
+      return false;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Return an undeclared local temporary of type TYPE
+   for use with BIND_EXPR.  */
+
+tree
+create_temporary_var (tree type)
+{
+  tree decl = build_decl (input_location, VAR_DECL, NULL_TREE, type);
+
+  DECL_CONTEXT (decl) = current_function_decl;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  layout_decl (decl, 0);
+
+  return decl;
+}
+
+/* Return an undeclared local temporary OUT_VAR initialised
+   with result of expression EXP.  */
+
+tree
+maybe_temporary_var (tree exp, tree *out_var)
+{
+  tree t = exp;
+
+  /* Get the base component.  */
+  while (TREE_CODE (t) == COMPONENT_REF)
+    t = TREE_OPERAND (t, 0);
+
+  if (!DECL_P (t) && !REFERENCE_CLASS_P (t))
+    {
+      *out_var = create_temporary_var (TREE_TYPE (exp));
+      DECL_INITIAL (*out_var) = exp;
+      return *out_var;
+    }
+  else
+    {
+      *out_var = NULL_TREE;
+      return exp;
+    }
+}
+
+/* Builds a BIND_EXPR around BODY for the variables VAR_CHAIN.  */
+
+tree
+bind_expr (tree var_chain, tree body)
+{
+  /* Only handles one var.  */
+  gcc_assert (TREE_CHAIN (var_chain) == NULL_TREE);
+
+  if (DECL_INITIAL (var_chain))
+    {
+      tree ini = build_assign (INIT_EXPR, var_chain, DECL_INITIAL (var_chain));
+      DECL_INITIAL (var_chain) = NULL_TREE;
+      body = compound_expr (ini, body);
+    }
+
+  return d_save_expr (build3 (BIND_EXPR, TREE_TYPE (body),
+			      var_chain, body, NULL_TREE));
+}
+
+/* Returns the TypeFunction class for Type T.
+   Assumes T is already ->toBasetype().  */
+
+TypeFunction *
+get_function_type (Type *t)
+{
+  TypeFunction *tf = NULL;
+  if (t->ty == Tpointer)
+    t = t->nextOf ()->toBasetype ();
+  if (t->ty == Tfunction)
+    tf = (TypeFunction *) t;
+  else if (t->ty == Tdelegate)
+    tf = (TypeFunction *) ((TypeDelegate *) t)->next;
+  return tf;
+}
+
+/* Returns TRUE if CALLEE is a plain nested function outside the scope of
+   CALLER.  In which case, CALLEE is being called through an alias that was
+   passed to CALLER.  */
+
+bool
+call_by_alias_p (FuncDeclaration *caller, FuncDeclaration *callee)
+{
+  if (!callee->isNested ())
+    return false;
+
+  if (caller->toParent () == callee->toParent ())
+    return false;
+
+  Dsymbol *dsym = callee;
+
+  while (dsym)
+    {
+      if (dsym->isTemplateInstance ())
+	return false;
+      else if (dsym->isFuncDeclaration () == caller)
+	return false;
+      dsym = dsym->toParent ();
+    }
+
+  return true;
+}
+
+/* Entry point for call routines.  Builds a function call to FD.
+   OBJECT is the 'this' reference passed and ARGS are the arguments to FD.  */
+
+tree
+d_build_call_expr (FuncDeclaration *fd, tree object, Expressions *arguments)
+{
+  return d_build_call (get_function_type (fd->type),
+		       build_address (get_symbol_decl (fd)), object, arguments);
+}
+
+/* Builds a CALL_EXPR of type TF to CALLABLE.  OBJECT holds the 'this' pointer,
+   ARGUMENTS are evaluated in left to right order, saved and promoted
+   before passing.  */
+
+tree
+d_build_call (TypeFunction *tf, tree callable, tree object,
+	      Expressions *arguments)
+{
+  tree ctype = TREE_TYPE (callable);
+  tree callee = callable;
+
+  if (POINTER_TYPE_P (ctype))
+    ctype = TREE_TYPE (ctype);
+  else
+    callee = build_address (callable);
+
+  gcc_assert (FUNC_OR_METHOD_TYPE_P (ctype));
+  gcc_assert (tf != NULL);
+  gcc_assert (tf->ty == Tfunction);
+
+  if (TREE_CODE (ctype) != FUNCTION_TYPE && object == NULL_TREE)
+    {
+      /* Front-end apparently doesn't check this.  */
+      if (TREE_CODE (callable) == FUNCTION_DECL)
+	{
+	  error ("need 'this' to access member %s",
+		 IDENTIFIER_POINTER (DECL_NAME (callable)));
+	  return error_mark_node;
+	}
+
+      /* Probably an internal error.  */
+      gcc_unreachable ();
+    }
+
+  /* Build the argument list for the call.  */
+  vec<tree, va_gc> *args = NULL;
+  tree saved_args = NULL_TREE;
+
+  /* If this is a delegate call or a nested function being called as
+     a delegate, the object should not be NULL.  */
+  if (object != NULL_TREE)
+    vec_safe_push (args, object);
+
+  if (arguments)
+    {
+      /* First pass, evaluated expanded tuples in function arguments.  */
+      for (size_t i = 0; i < arguments->dim; ++i)
+	{
+	Lagain:
+	  Expression *arg = (*arguments)[i];
+	  gcc_assert (arg->op != TOKtuple);
+
+	  if (arg->op == TOKcomma)
+	    {
+	      CommaExp *ce = (CommaExp *) arg;
+	      tree tce = build_expr (ce->e1);
+	      saved_args = compound_expr (saved_args, tce);
+	      (*arguments)[i] = ce->e2;
+	      goto Lagain;
+	    }
+	}
+
+      size_t nparams = Parameter::dim (tf->parameters);
+      /* if _arguments[] is the first argument.  */
+      size_t varargs = (tf->linkage == LINKd && tf->varargs == 1);
+
+      /* Assumes arguments->dim <= formal_args->dim if (!tf->varargs).  */
+      for (size_t i = 0; i < arguments->dim; ++i)
+	{
+	  Expression *arg = (*arguments)[i];
+	  tree targ = build_expr (arg);
+
+	  if (i - varargs < nparams && i >= varargs)
+	    {
+	      /* Actual arguments for declared formal arguments.  */
+	      Parameter *parg = Parameter::getNth (tf->parameters, i - varargs);
+	      targ = convert_for_argument (targ, parg);
+	    }
+
+	  /* Don't pass empty aggregates by value.  */
+	  if (empty_aggregate_p (TREE_TYPE (targ)) && !TREE_ADDRESSABLE (targ)
+	      && TREE_CODE (targ) != CONSTRUCTOR)
+	    {
+	      tree t = build_constructor (TREE_TYPE (targ), NULL);
+	      targ = build2 (COMPOUND_EXPR, TREE_TYPE (t), targ, t);
+	    }
+
+	  vec_safe_push (args, targ);
+	}
+    }
+
+  /* Evaluate the argument before passing to the function.
+     Needed for left to right evaluation.  */
+  if (tf->linkage == LINKd)
+    {
+      size_t nsaved_args = 0;
+      unsigned int ix;
+      tree arg;
+
+      /* First, push left side of comma expressions into the saved args list,
+	 so that only the result is maybe made a temporary.  */
+      FOR_EACH_VEC_SAFE_ELT (args, ix, arg)
+	{
+	  if (TREE_SIDE_EFFECTS (arg))
+	    {
+	      tree expr = stabilize_expr (&arg);
+	      if (expr != NULL_TREE)
+		saved_args = compound_expr (saved_args, expr);
+
+	      /* Argument needs saving.  */
+	      if (TREE_SIDE_EFFECTS (arg))
+		nsaved_args++;
+
+	      (*args)[ix] = arg;
+	    }
+	}
+
+      /* If more than one argument needs saving, then we must enforce the
+	 order of evaluation.  */
+      if (nsaved_args > 1)
+	{
+	  FOR_EACH_VEC_SAFE_ELT (args, ix, arg)
+	    {
+	      if (TREE_SIDE_EFFECTS (arg))
+		{
+		  arg = d_save_expr (arg);
+		  saved_args = compound_expr (saved_args, arg);
+		  (*args)[ix] = arg;
+		}
+	    }
+	}
+    }
+
+  /* Evaluate the callee before calling it.  */
+  if (saved_args != NULL_TREE && TREE_SIDE_EFFECTS (callee))
+    {
+      callee = d_save_expr (callee);
+      saved_args = compound_expr (callee, saved_args);
+    }
+
+  tree result = build_call_vec (TREE_TYPE (ctype), callee, args);
+  result = maybe_expand_intrinsic (result);
+
+  /* Return the value in a temporary slot so that it can be evaluated
+     multiple times by the caller.  */
+  if (TREE_CODE (result) == CALL_EXPR
+      && AGGREGATE_TYPE_P (TREE_TYPE (result))
+      && TREE_ADDRESSABLE (TREE_TYPE (result)))
+    {
+      CALL_EXPR_RETURN_SLOT_OPT (result) = true;
+      result = build_target_expr (result);
+    }
+
+  return compound_expr (saved_args, result);
+}
+
+/* Builds a call to AssertError or AssertErrorMsg.  */
+
+tree
+d_assert_call (const Loc& loc, libcall_fn libcall, tree msg)
+{
+  tree file = d_array_string (loc.filename ? loc.filename : "");
+  tree line = size_int (loc.linnum);
+
+  if (msg != NULL)
+    return build_libcall (libcall, Type::tvoid, 3, msg, file, line);
+  else
+    return build_libcall (libcall, Type::tvoid, 2, file, line);
+}
+
+/* Build and return the correct call to fmod depending on TYPE.
+   ARG0 and ARG1 are the arguments pass to the function.  */
+
+tree
+build_float_modulus (tree type, tree arg0, tree arg1)
+{
+  tree fmodfn = NULL_TREE;
+  tree basetype = type;
+
+  if (COMPLEX_FLOAT_TYPE_P (basetype))
+    basetype = TREE_TYPE (basetype);
+
+  if (TYPE_MAIN_VARIANT (basetype) == double_type_node
+      || TYPE_MAIN_VARIANT (basetype) == idouble_type_node)
+    fmodfn = builtin_decl_explicit (BUILT_IN_FMOD);
+  else if (TYPE_MAIN_VARIANT (basetype) == float_type_node
+	   || TYPE_MAIN_VARIANT (basetype) == ifloat_type_node)
+    fmodfn = builtin_decl_explicit (BUILT_IN_FMODF);
+  else if (TYPE_MAIN_VARIANT (basetype) == long_double_type_node
+	   || TYPE_MAIN_VARIANT (basetype) == ireal_type_node)
+    fmodfn = builtin_decl_explicit (BUILT_IN_FMODL);
+
+  if (!fmodfn)
+    {
+      error ("tried to perform floating-point modulo division on %qT", type);
+      return error_mark_node;
+    }
+
+  if (COMPLEX_FLOAT_TYPE_P (type))
+    {
+      tree re = build_call_expr (fmodfn, 2, real_part (arg0), arg1);
+      tree im = build_call_expr (fmodfn, 2, imaginary_part (arg0), arg1);
+
+      return complex_expr (type, re, im);
+    }
+
+  if (SCALAR_FLOAT_TYPE_P (type))
+    return build_call_expr (fmodfn, 2, arg0, arg1);
+
+  /* Should have caught this above.  */
+  gcc_unreachable ();
+}
+
+/* Build a function type whose first argument is a pointer to BASETYPE,
+   which is to be used for the 'vthis' context parameter for TYPE.
+   The base type may be a record for member functions, or a void for
+   nested functions and delegates.  */
+
+tree
+build_vthis_function (tree basetype, tree type)
+{
+  gcc_assert (TREE_CODE (type) == FUNCTION_TYPE);
+
+  tree argtypes = tree_cons (NULL_TREE, build_pointer_type (basetype),
+			     TYPE_ARG_TYPES (type));
+  tree fntype = build_function_type (TREE_TYPE (type), argtypes);
+
+  if (RECORD_OR_UNION_TYPE_P (basetype))
+    TYPE_METHOD_BASETYPE (fntype) = TYPE_MAIN_VARIANT (basetype);
+  else
+    gcc_assert (VOID_TYPE_P (basetype));
+
+  return fntype;
+}
+
+/* If SYM is a nested function, return the static chain to be
+   used when calling that function from the current function.
+
+   If SYM is a nested class or struct, return the static chain
+   to be used when creating an instance of the class from CFUN.  */
+
+tree
+get_frame_for_symbol (Dsymbol *sym)
+{
+  FuncDeclaration *func = d_function_chain ? d_function_chain->function : NULL;
+  FuncDeclaration *thisfd = sym->isFuncDeclaration ();
+  FuncDeclaration *parentfd = NULL;
+
+  if (thisfd != NULL)
+    {
+      /* Check that the nested function is properly defined.  */
+      if (!thisfd->fbody)
+	{
+	  /* Should instead error on line that references 'thisfd'.  */
+	  thisfd->error ("nested function missing body");
+	  return null_pointer_node;
+	}
+
+      /* Special case for __ensure and __require.  */
+      if (thisfd->ident == Id::ensure || thisfd->ident == Id::require)
+	parentfd = func;
+      else
+	parentfd = thisfd->toParent2 ()->isFuncDeclaration ();
+    }
+  else
+    {
+      /* It's a class (or struct). NewExp codegen has already determined its
+	 outer scope is not another class, so it must be a function.  */
+      while (sym && !sym->isFuncDeclaration ())
+	sym = sym->toParent2 ();
+
+      parentfd = (FuncDeclaration *) sym;
+    }
+
+  gcc_assert (parentfd != NULL);
+
+  if (func != parentfd)
+    {
+      /* If no frame pointer for this function.  */
+      if (!func->vthis)
+	{
+	  sym->error ("is a nested function and cannot be accessed from %s",
+		      func->toChars ());
+	  return null_pointer_node;
+	}
+
+      /* Make sure we can get the frame pointer to the outer function.
+	 Go up each nesting level until we find the enclosing function.  */
+      Dsymbol *dsym = func;
+
+      while (thisfd != dsym)
+	{
+	  /* Check if enclosing function is a function.  */
+	  FuncDeclaration *fd = dsym->isFuncDeclaration ();
+
+	  if (fd != NULL)
+	    {
+	      if (parentfd == fd->toParent2 ())
+		break;
+
+	      gcc_assert (fd->isNested () || fd->vthis);
+	      dsym = dsym->toParent2 ();
+	      continue;
+	    }
+
+	  /* Check if enclosed by an aggregate. That means the current
+	     function must be a member function of that aggregate.  */
+	  AggregateDeclaration *ad = dsym->isAggregateDeclaration ();
+
+	  if (ad == NULL)
+	    goto Lnoframe;
+	  if (ad->isClassDeclaration () && parentfd == ad->toParent2 ())
+	    break;
+	  if (ad->isStructDeclaration () && parentfd == ad->toParent2 ())
+	    break;
+
+	  if (!ad->isNested () || !ad->vthis)
+	    {
+	    Lnoframe:
+	      func->error ("cannot get frame pointer to %s",
+			   sym->toPrettyChars ());
+	      return null_pointer_node;
+	    }
+
+	  dsym = dsym->toParent2 ();
+	}
+    }
+
+  tree ffo = get_frameinfo (parentfd);
+  if (FRAMEINFO_CREATES_FRAME (ffo) || FRAMEINFO_STATIC_CHAIN (ffo))
+    return get_framedecl (func, parentfd);
+
+  return null_pointer_node;
+}
+
+/* Return the parent function of a nested class CD.  */
+
+static FuncDeclaration *
+d_nested_class (ClassDeclaration *cd)
+{
+  FuncDeclaration *fd = NULL;
+  while (cd && cd->isNested ())
+    {
+      Dsymbol *dsym = cd->toParent2 ();
+      if ((fd = dsym->isFuncDeclaration ()))
+	return fd;
+      else
+	cd = dsym->isClassDeclaration ();
+    }
+  return NULL;
+}
+
+/* Return the parent function of a nested struct SD.  */
+
+static FuncDeclaration *
+d_nested_struct (StructDeclaration *sd)
+{
+  FuncDeclaration *fd = NULL;
+  while (sd && sd->isNested ())
+    {
+      Dsymbol *dsym = sd->toParent2 ();
+      if ((fd = dsym->isFuncDeclaration ()))
+	return fd;
+      else
+	sd = dsym->isStructDeclaration ();
+    }
+  return NULL;
+}
+
+
+/* Starting from the current function FUNC, try to find a suitable value of
+   'this' in nested function instances.  A suitable 'this' value is an
+   instance of OCD or a class that has OCD as a base.  */
+
+static tree
+find_this_tree (ClassDeclaration *ocd)
+{
+  FuncDeclaration *func = d_function_chain ? d_function_chain->function : NULL;
+
+  while (func)
+    {
+      AggregateDeclaration *ad = func->isThis ();
+      ClassDeclaration *cd = ad ? ad->isClassDeclaration () : NULL;
+
+      if (cd != NULL)
+	{
+	  if (ocd == cd)
+	    return get_decl_tree (func->vthis);
+	  else if (ocd->isBaseOf (cd, NULL))
+	    return convert_expr (get_decl_tree (func->vthis),
+				 cd->type, ocd->type);
+
+	  func = d_nested_class (cd);
+	}
+      else
+	{
+	  if (func->isNested ())
+	    {
+	      func = func->toParent2 ()->isFuncDeclaration ();
+	      continue;
+	    }
+
+	  func = NULL;
+	}
+    }
+
+  return NULL_TREE;
+}
+
+/* Retrieve the outer class/struct 'this' value of DECL from
+   the current function.  */
+
+tree
+build_vthis (AggregateDeclaration *decl)
+{
+  ClassDeclaration *cd = decl->isClassDeclaration ();
+  StructDeclaration *sd = decl->isStructDeclaration ();
+
+  /* If an aggregate nested in a function has no methods and there are no
+     other nested functions, any static chain created here will never be
+     translated.  Use a null pointer for the link in this case.  */
+  tree vthis_value = null_pointer_node;
+
+  if (cd != NULL || sd != NULL)
+    {
+      Dsymbol *outer = decl->toParent2 ();
+
+      /* If the parent is a templated struct, the outer context is instead
+	 the enclosing symbol of where the instantiation happened.  */
+      if (outer->isStructDeclaration ())
+	{
+	  gcc_assert (outer->parent && outer->parent->isTemplateInstance ());
+	  outer = ((TemplateInstance *) outer->parent)->enclosing;
+	}
+
+      /* For outer classes, get a suitable 'this' value.
+	 For outer functions, get a suitable frame/closure pointer.  */
+      ClassDeclaration *cdo = outer->isClassDeclaration ();
+      FuncDeclaration *fdo = outer->isFuncDeclaration ();
+
+      if (cdo)
+	{
+	  vthis_value = find_this_tree (cdo);
+	  gcc_assert (vthis_value != NULL_TREE);
+	}
+      else if (fdo)
+	{
+	  tree ffo = get_frameinfo (fdo);
+	  if (FRAMEINFO_CREATES_FRAME (ffo) || FRAMEINFO_STATIC_CHAIN (ffo)
+	      || fdo->hasNestedFrameRefs ())
+	    vthis_value = get_frame_for_symbol (decl);
+	  else if (cd != NULL)
+	    {
+	      /* Classes nested in methods are allowed to access any outer
+		 class fields, use the function chain in this case.  */
+	      if (fdo->vthis && fdo->vthis->type != Type::tvoidptr)
+		vthis_value = get_decl_tree (fdo->vthis);
+	    }
+	}
+      else
+	gcc_unreachable ();
+    }
+
+  return vthis_value;
+}
+
+static tree
+build_frame_type (tree ffi, FuncDeclaration *fd)
+{
+  if (FRAMEINFO_TYPE (ffi))
+    return FRAMEINFO_TYPE (ffi);
+
+  tree frame_rec_type = make_node (RECORD_TYPE);
+  char *name = concat (FRAMEINFO_IS_CLOSURE (ffi) ? "CLOSURE." : "FRAME.",
+		       fd->toPrettyChars (), NULL);
+  TYPE_NAME (frame_rec_type) = get_identifier (name);
+  free (name);
+
+  tree ptr_field = build_decl (BUILTINS_LOCATION, FIELD_DECL,
+			       get_identifier ("__chain"), ptr_type_node);
+  DECL_FIELD_CONTEXT (ptr_field) = frame_rec_type;
+  TYPE_READONLY (frame_rec_type) = 1;
+
+  tree fields = chainon (NULL_TREE, ptr_field);
+
+  /* The __ensure and __require are called directly, so never make the outer
+     functions closure, but nevertheless could still be referencing parameters
+     of the calling function non-locally.  So we add all parameters with nested
+     refs to the function frame, this should also mean overriding methods will
+     have the same frame layout when inheriting a contract.  */
+  if ((global.params.useIn && fd->frequire)
+      || (global.params.useOut && fd->fensure))
+    {
+      if (fd->parameters)
+	{
+	  for (size_t i = 0; fd->parameters && i < fd->parameters->dim; i++)
+	    {
+	      VarDeclaration *v = (*fd->parameters)[i];
+	      /* Remove if already in closureVars so can push to front.  */
+	      for (size_t j = i; j < fd->closureVars.dim; j++)
+		{
+		  Dsymbol *s = fd->closureVars[j];
+		  if (s == v)
+		    {
+		      fd->closureVars.remove (j);
+		      break;
+		    }
+		}
+	      fd->closureVars.insert (i, v);
+	    }
+	}
+
+      /* Also add hidden 'this' to outer context.  */
+      if (fd->vthis)
+	{
+	  for (size_t i = 0; i < fd->closureVars.dim; i++)
+	    {
+	      Dsymbol *s = fd->closureVars[i];
+	      if (s == fd->vthis)
+		{
+		  fd->closureVars.remove (i);
+		  break;
+		}
+	    }
+	  fd->closureVars.insert (0, fd->vthis);
+	}
+    }
+
+  for (size_t i = 0; i < fd->closureVars.dim; i++)
+    {
+      VarDeclaration *v = fd->closureVars[i];
+      tree s = get_symbol_decl (v);
+      tree ident =  v->ident
+	? get_identifier (v->ident->toChars ()) : NULL_TREE;
+
+      tree field = build_decl (get_linemap (v->loc), FIELD_DECL, ident,
+			       declaration_type (v));
+      SET_DECL_LANG_FRAME_FIELD (s, field);
+      DECL_FIELD_CONTEXT (field) = frame_rec_type;
+      fields = chainon (fields, field);
+      TREE_USED (s) = 1;
+
+      /* Can't do nrvo if the variable is put in a frame.  */
+      if (fd->nrvo_can && fd->nrvo_var == v)
+	fd->nrvo_can = 0;
+
+      if (FRAMEINFO_IS_CLOSURE (ffi))
+	{
+	  /* Because the value needs to survive the end of the scope.  */
+	  if ((v->edtor && (v->storage_class & STCparameter))
+	      || v->needsScopeDtor ())
+	    v->error ("has scoped destruction, cannot build closure");
+	}
+    }
+
+  TYPE_FIELDS (frame_rec_type) = fields;
+  layout_type (frame_rec_type);
+  d_keep (frame_rec_type);
+
+  return frame_rec_type;
+}
+
+/* Closures are implemented by taking the local variables that
+   need to survive the scope of the function, and copying them
+   into a GC allocated chuck of memory. That chunk, called the
+   closure here, is inserted into the linked list of stack
+   frames instead of the usual stack frame.
+
+   If a closure is not required, but FD still needs a frame to lower
+   nested refs, then instead build custom static chain decl on stack.  */
+
+void
+build_closure (FuncDeclaration *fd)
+{
+  tree ffi = get_frameinfo (fd);
+
+  if (!FRAMEINFO_CREATES_FRAME (ffi))
+    return;
+
+  tree type = FRAMEINFO_TYPE (ffi);
+  gcc_assert (COMPLETE_TYPE_P (type));
+
+  tree decl, decl_ref;
+
+  if (FRAMEINFO_IS_CLOSURE (ffi))
+    {
+      decl = build_local_temp (build_pointer_type (type));
+      DECL_NAME (decl) = get_identifier ("__closptr");
+      decl_ref = build_deref (decl);
+
+      /* Allocate memory for closure.  */
+      tree arg = convert (build_ctype (Type::tsize_t), TYPE_SIZE_UNIT (type));
+      tree init = build_libcall (LIBCALL_ALLOCMEMORY, Type::tvoidptr, 1, arg);
+
+      tree init_exp = build_assign (INIT_EXPR, decl,
+				    build_nop (TREE_TYPE (decl), init));
+      add_stmt (init_exp);
+    }
+  else
+    {
+      decl = build_local_temp (type);
+      DECL_NAME (decl) = get_identifier ("__frame");
+      decl_ref = decl;
+    }
+
+  DECL_IGNORED_P (decl) = 0;
+
+  /* Set the first entry to the parent closure/frame, if any.  */
+  tree chain_field = component_ref (decl_ref, TYPE_FIELDS (type));
+  tree chain_expr = modify_expr (chain_field, d_function_chain->static_chain);
+  add_stmt (chain_expr);
+
+  /* Copy parameters that are referenced nonlocally.  */
+  for (size_t i = 0; i < fd->closureVars.dim; i++)
+    {
+      VarDeclaration *v = fd->closureVars[i];
+
+      if (!v->isParameter ())
+	continue;
+
+      tree vsym = get_symbol_decl (v);
+
+      tree field = component_ref (decl_ref, DECL_LANG_FRAME_FIELD (vsym));
+      tree expr = modify_expr (field, vsym);
+      add_stmt (expr);
+    }
+
+  if (!FRAMEINFO_IS_CLOSURE (ffi))
+    decl = build_address (decl);
+
+  d_function_chain->static_chain = decl;
+}
+
+/* Return the frame of FD.  This could be a static chain or a closure
+   passed via the hidden 'this' pointer.  */
+
+tree
+get_frameinfo (FuncDeclaration *fd)
+{
+  tree fds = get_symbol_decl (fd);
+  if (DECL_LANG_FRAMEINFO (fds))
+    return DECL_LANG_FRAMEINFO (fds);
+
+  tree ffi = make_node (FUNCFRAME_INFO);
+
+  DECL_LANG_FRAMEINFO (fds) = ffi;
+
+  /* Nested functions, or functions with nested refs must create
+     a static frame for local variables to be referenced from.  */
+  if (fd->hasNestedFrameRefs ()
+      || (fd->vthis && fd->vthis->type == Type::tvoidptr))
+    FRAMEINFO_CREATES_FRAME (ffi) = 1;
+
+  /* In checkNestedReference, references from contracts are not added to the
+     closureVars array, so assume all parameters referenced.  Even if they
+     aren't the 'this' parameter may still be needed for the static chain.  */
+  if ((global.params.useIn && fd->frequire)
+      || (global.params.useOut && fd->fensure))
+    FRAMEINFO_CREATES_FRAME (ffi) = 1;
+
+  /* D2 maybe setup closure instead.  */
+  if (fd->needsClosure ())
+    {
+      FRAMEINFO_CREATES_FRAME (ffi) = 1;
+      FRAMEINFO_IS_CLOSURE (ffi) = 1;
+    }
+  else if (fd->closureVars.dim == 0)
+    {
+      /* If fd is nested (deeply) in a function that creates a closure,
+	 then fd inherits that closure via hidden vthis pointer, and
+	 doesn't create a stack frame at all.  */
+      FuncDeclaration *ff = fd;
+
+      while (ff)
+	{
+	  tree ffo = get_frameinfo (ff);
+
+	  if (ff != fd && FRAMEINFO_CREATES_FRAME (ffo))
+	    {
+	      gcc_assert (FRAMEINFO_TYPE (ffo));
+	      FRAMEINFO_CREATES_FRAME (ffi) = 0;
+	      FRAMEINFO_STATIC_CHAIN (ffi) = 1;
+	      FRAMEINFO_IS_CLOSURE (ffi) = FRAMEINFO_IS_CLOSURE (ffo);
+	      gcc_assert (COMPLETE_TYPE_P (FRAMEINFO_TYPE (ffo)));
+	      FRAMEINFO_TYPE (ffi) = FRAMEINFO_TYPE (ffo);
+	      break;
+	    }
+
+	  /* Stop looking if no frame pointer for this function.  */
+	  if (ff->vthis == NULL)
+	    break;
+
+	  AggregateDeclaration *ad = ff->isThis ();
+	  if (ad && ad->isNested ())
+	    {
+	      while (ad->isNested ())
+		{
+		  Dsymbol *d = ad->toParent2 ();
+		  ad = d->isAggregateDeclaration ();
+		  ff = d->isFuncDeclaration ();
+
+		  if (ad == NULL)
+		    break;
+		}
+	    }
+	  else
+	    ff = ff->toParent2 ()->isFuncDeclaration ();
+	}
+    }
+
+  /* Build type now as may be referenced from another module.  */
+  if (FRAMEINFO_CREATES_FRAME (ffi))
+    FRAMEINFO_TYPE (ffi) = build_frame_type (ffi, fd);
+
+  return ffi;
+}
+
+/* Return a pointer to the frame/closure block of OUTER
+   so can be accessed from the function INNER.  */
+
+tree
+get_framedecl (FuncDeclaration *inner, FuncDeclaration *outer)
+{
+  tree result = d_function_chain->static_chain;
+  FuncDeclaration *fd = inner;
+
+  while (fd && fd != outer)
+    {
+      AggregateDeclaration *ad;
+      ClassDeclaration *cd;
+      StructDeclaration *sd;
+
+      /* Parent frame link is the first field.  */
+      if (FRAMEINFO_CREATES_FRAME (get_frameinfo (fd)))
+	result = indirect_ref (ptr_type_node, result);
+
+      if (fd->isNested ())
+	fd = fd->toParent2 ()->isFuncDeclaration ();
+      /* The frame/closure record always points to the outer function's
+	 frame, even if there are intervening nested classes or structs.
+	 So, we can just skip over these.  */
+      else if ((ad = fd->isThis ()) && (cd = ad->isClassDeclaration ()))
+	fd = d_nested_class (cd);
+      else if ((ad = fd->isThis ()) && (sd = ad->isStructDeclaration ()))
+	fd = d_nested_struct (sd);
+      else
+	break;
+    }
+
+  /* Go get our frame record.  */
+  gcc_assert (fd == outer);
+  tree frame_type = FRAMEINFO_TYPE (get_frameinfo (outer));
+
+  if (frame_type != NULL_TREE)
+    {
+      result = build_nop (build_pointer_type (frame_type), result);
+      return result;
+    }
+  else
+    {
+      inner->error ("forward reference to frame of %s", outer->toChars ());
+      return null_pointer_node;
+    }
+}
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
new file mode 100644
index 00000000000..bc1fc65856d
--- /dev/null
+++ b/gcc/d/d-convert.cc
@@ -0,0 +1,804 @@
+/* d-convert.cc -- Data type conversion routines.
+   Copyright (C) 2006-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/expression.h"
+#include "dfrontend/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "target.h"
+#include "convert.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+
+
+/* Build CODE expression with operands OP0 and OP1.
+   Helper function for d_truthvalue_conversion, so assumes bool result.  */
+
+static tree
+d_build_truthvalue_op (tree_code code, tree op0, tree op1)
+{
+  tree type0, type1;
+
+  tree result_type = NULL_TREE;
+
+  type0 = TREE_TYPE (op0);
+  type1 = TREE_TYPE (op1);
+
+  /* Strip NON_LVALUE_EXPRs, etc., since we aren't using as an lvalue.  */
+  STRIP_TYPE_NOPS (op0);
+  STRIP_TYPE_NOPS (op1);
+
+  /* Also need to convert pointer/int comparison.  */
+  if (POINTER_TYPE_P (type0) && TREE_CODE (op1) == INTEGER_CST
+      && integer_zerop (op1))
+    {
+      result_type = type0;
+    }
+  else if (POINTER_TYPE_P (type1) && TREE_CODE (op0) == INTEGER_CST
+	   && integer_zerop (op0))
+    {
+      result_type = type1;
+    }
+  /* If integral, need to convert unsigned/signed comparison.
+     Will also need to convert if type precisions differ.  */
+  else if (INTEGRAL_TYPE_P (type0) && INTEGRAL_TYPE_P (type1))
+    {
+      if (TYPE_PRECISION (type0) > TYPE_PRECISION (type1))
+	result_type = type0;
+      else if (TYPE_PRECISION (type0) < TYPE_PRECISION (type1))
+	result_type = type1;
+      else if (TYPE_UNSIGNED (type0) != TYPE_UNSIGNED (type1))
+	result_type = TYPE_UNSIGNED (type0) ? type0 : type1;
+    }
+
+  if (result_type)
+    {
+      if (TREE_TYPE (op0) != result_type)
+	op0 = convert (result_type, op0);
+      if (TREE_TYPE (op1) != result_type)
+	op1 = convert (result_type, op1);
+    }
+
+  return fold_build2 (code, bool_type_node, op0, op1);
+}
+
+
+/* Convert EXPR to be a truth-value, validating its type for this purpose.  */
+
+tree
+d_truthvalue_conversion (tree expr)
+{
+  switch (TREE_CODE (expr))
+    {
+    case EQ_EXPR:   case NE_EXPR:   case LE_EXPR:
+    case GE_EXPR:   case LT_EXPR:   case GT_EXPR:
+      if (TREE_TYPE (expr) == bool_type_node)
+	return expr;
+      return build2 (TREE_CODE (expr), bool_type_node,
+		     TREE_OPERAND (expr, 0), TREE_OPERAND (expr, 1));
+
+    case TRUTH_ANDIF_EXPR:
+    case TRUTH_ORIF_EXPR:
+    case TRUTH_AND_EXPR:
+    case TRUTH_OR_EXPR:
+    case TRUTH_XOR_EXPR:
+      if (TREE_TYPE (expr) == bool_type_node)
+	return expr;
+      return build2 (TREE_CODE (expr), bool_type_node,
+		     d_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+		     d_truthvalue_conversion (TREE_OPERAND (expr, 1)));
+
+    case TRUTH_NOT_EXPR:
+      if (TREE_TYPE (expr) == bool_type_node)
+	return expr;
+      return build1 (TREE_CODE (expr), bool_type_node,
+		     d_truthvalue_conversion (TREE_OPERAND (expr, 0)));
+
+    case ERROR_MARK:
+      return expr;
+
+    case INTEGER_CST:
+      return integer_zerop (expr) ? boolean_false_node
+				  : boolean_true_node;
+
+    case REAL_CST:
+      return real_compare (NE_EXPR, &TREE_REAL_CST (expr), &dconst0)
+	     ? boolean_true_node
+	     : boolean_false_node;
+
+    case ADDR_EXPR:
+      /* If we are taking the address of a decl that can never be null,
+	 then the return result is always true.  */
+      if (DECL_P (TREE_OPERAND (expr, 0))
+	  && (TREE_CODE (TREE_OPERAND (expr, 0)) == PARM_DECL
+	      || TREE_CODE (TREE_OPERAND (expr, 0)) == LABEL_DECL
+	      || !DECL_WEAK (TREE_OPERAND (expr, 0))))
+	return boolean_true_node;
+      break;
+
+    case COMPLEX_EXPR:
+      return d_build_truthvalue_op ((TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1))
+				     ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
+			d_truthvalue_conversion (TREE_OPERAND (expr, 0)),
+			d_truthvalue_conversion (TREE_OPERAND (expr, 1)));
+
+    case NEGATE_EXPR:
+    case ABS_EXPR:
+    case FLOAT_EXPR:
+      /* These don't change whether an object is nonzero or zero.  */
+      return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+    case LROTATE_EXPR:
+    case RROTATE_EXPR:
+      /* These don't change whether an object is zero or nonzero, but
+	 we can't ignore them if their second arg has side-effects.  */
+      if (TREE_SIDE_EFFECTS (TREE_OPERAND (expr, 1)))
+	{
+	  return build2 (COMPOUND_EXPR, bool_type_node, TREE_OPERAND (expr, 1),
+			 d_truthvalue_conversion (TREE_OPERAND (expr, 0)));
+	}
+      else
+	return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
+
+    case COND_EXPR:
+      /* Distribute the conversion into the arms of a COND_EXPR.  */
+      return fold_build3 (COND_EXPR, bool_type_node, TREE_OPERAND (expr, 0),
+			  d_truthvalue_conversion (TREE_OPERAND (expr, 1)),
+			  d_truthvalue_conversion (TREE_OPERAND (expr, 2)));
+
+    case CONVERT_EXPR:
+      /* Don't cancel the effect of a CONVERT_EXPR from a REFERENCE_TYPE,
+	 since that affects how `default_conversion' will behave.  */
+      if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE
+	  || TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == REFERENCE_TYPE)
+	break;
+      /* Fall through.  */
+
+    case NOP_EXPR:
+      /* If this isn't narrowing the argument, we can ignore it.  */
+      if (TYPE_PRECISION (TREE_TYPE (expr))
+	  >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0))))
+	return d_truthvalue_conversion (TREE_OPERAND (expr, 0));
+      break;
+
+    default:
+      break;
+    }
+
+  if (TREE_CODE (TREE_TYPE (expr)) == COMPLEX_TYPE)
+    {
+      tree t = save_expr (expr);
+      tree type = TREE_TYPE (TREE_TYPE (expr));
+      return d_build_truthvalue_op ((TREE_SIDE_EFFECTS (expr)
+				     ? TRUTH_OR_EXPR : TRUTH_ORIF_EXPR),
+			d_truthvalue_conversion (build1 (REALPART_EXPR, type, t)),
+			d_truthvalue_conversion (build1 (IMAGPART_EXPR, type, t)));
+    }
+  else
+    return d_build_truthvalue_op (NE_EXPR, expr,
+				  build_zero_cst (TREE_TYPE (expr)));
+}
+
+
+/* Creates an expression whose value is that of EXPR, converted to type TYPE.
+   This function implements all reasonable scalar conversions.  */
+
+tree
+convert (tree type, tree expr)
+{
+  tree e = expr;
+  tree_code code = TREE_CODE (type);
+
+  if (type == error_mark_node
+      || expr == error_mark_node
+      || TREE_TYPE (expr) == error_mark_node)
+    return error_mark_node;
+
+  const char *invalid_conv_diag
+    = targetm.invalid_conversion (TREE_TYPE (expr), type);
+
+  if (invalid_conv_diag)
+    {
+      error ("%s", invalid_conv_diag);
+      return error_mark_node;
+    }
+
+  if (type == TREE_TYPE (expr))
+    return expr;
+
+  if (TREE_CODE (type) == ARRAY_TYPE
+      && TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE
+      && TYPE_DOMAIN (type) == TYPE_DOMAIN (TREE_TYPE (expr)))
+    return expr;
+
+  tree ret = targetm.convert_to_type (type, expr);
+  if (ret)
+    return ret;
+
+  STRIP_TYPE_NOPS (e);
+  tree etype = TREE_TYPE (e);
+
+  if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)))
+    return fold_convert (type, expr);
+  if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK)
+    return error_mark_node;
+  if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE)
+    {
+      error ("void value not ignored as it ought to be");
+      return error_mark_node;
+    }
+
+  switch (code)
+    {
+    case VOID_TYPE:
+      return fold_convert (type, e);
+
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+      if (TREE_CODE (etype) == POINTER_TYPE
+	  || TREE_CODE (etype) == REFERENCE_TYPE)
+	{
+	  if (integer_zerop (e))
+	    return build_int_cst (type, 0);
+
+	  /* Convert to an unsigned integer of the correct width first, and
+	     from there widen/truncate to the required type.  */
+	  tree utype = lang_hooks.types.type_for_size (TYPE_PRECISION (etype),
+						       1);
+	  ret = fold_build1 (CONVERT_EXPR, utype, e);
+	  return fold_convert (type, ret);
+	}
+
+      ret = convert_to_integer (type, e);
+      goto maybe_fold;
+
+    case BOOLEAN_TYPE:
+      return fold_convert (type, d_truthvalue_conversion (expr));
+
+    case POINTER_TYPE:
+    case REFERENCE_TYPE:
+      ret = convert_to_pointer (type, e);
+      goto maybe_fold;
+
+    case REAL_TYPE:
+      if (TREE_CODE (etype) == COMPLEX_TYPE && TYPE_IMAGINARY_FLOAT (type))
+	e = build1 (IMAGPART_EXPR, TREE_TYPE (etype), e);
+
+      ret = convert_to_real (type, e);
+      goto maybe_fold;
+
+    case COMPLEX_TYPE:
+      if (TREE_CODE (etype) == REAL_TYPE && TYPE_IMAGINARY_FLOAT (etype))
+	ret = build2 (COMPLEX_EXPR, type,
+		      build_zero_cst (TREE_TYPE (type)),
+		      convert (TREE_TYPE (type), expr));
+      else
+	ret = convert_to_complex (type, e);
+      goto maybe_fold;
+
+    case VECTOR_TYPE:
+      ret = convert_to_vector (type, e);
+      goto maybe_fold;
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+      if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr)))
+	{
+	  ret = build1 (VIEW_CONVERT_EXPR, type, expr);
+	  goto maybe_fold;
+	}
+      break;
+
+    default:
+      break;
+
+    maybe_fold:
+      if (!TREE_CONSTANT (ret))
+	ret = fold (ret);
+      return ret;
+    }
+
+  error ("conversion to non-scalar type requested");
+  return error_mark_node;
+}
+
+/* Return expression EXP, whose type has been converted to TYPE.  */
+
+tree
+d_convert (tree type, tree exp)
+{
+  /* Check this first before retrieving frontend type.  */
+  if (error_operand_p (type) || error_operand_p (exp))
+    return error_mark_node;
+
+  Type *totype = TYPE_LANG_FRONTEND (type);
+  Type *etype = TYPE_LANG_FRONTEND (TREE_TYPE (exp));
+
+  if (totype && etype)
+    return convert_expr (exp, etype, totype);
+
+  return convert (type, exp);
+}
+
+/* Return expression EXP, whose type has been convert from ETYPE to TOTYPE.  */
+
+tree
+convert_expr (tree exp, Type *etype, Type *totype)
+{
+  tree result = NULL_TREE;
+
+  gcc_assert (etype && totype);
+  Type *ebtype = etype->toBasetype ();
+  Type *tbtype = totype->toBasetype ();
+
+  if (same_type_p (etype, totype))
+    return exp;
+
+  if (error_operand_p (exp))
+    return exp;
+
+  switch (ebtype->ty)
+    {
+    case Tdelegate:
+      if (tbtype->ty == Tdelegate)
+	{
+	  exp = d_save_expr (exp);
+	  return build_delegate_cst (delegate_method (exp),
+				     delegate_object (exp), totype);
+	}
+      else if (tbtype->ty == Tpointer)
+	{
+	  /* The front-end converts <delegate>.ptr to cast (void *)<delegate>.
+	     Maybe should only allow void* ?  */
+	  exp = delegate_object (exp);
+	}
+      else
+	{
+	  error ("can't convert a delegate expression to %qs",
+		 totype->toChars ());
+	  return error_mark_node;
+	}
+      break;
+
+    case Tstruct:
+      if (tbtype->ty == Tstruct)
+	{
+	  if (totype->size () == etype->size ())
+	    {
+	      /* Allowed to cast to structs with same type size.  */
+	      result = build_vconvert (build_ctype (totype), exp);
+	    }
+	  else
+	    {
+	      error ("can't convert struct %qs to %qs",
+		     etype->toChars (), totype->toChars ());
+	      return error_mark_node;
+	    }
+	}
+      /* else, default conversion, which should produce an error.  */
+      break;
+
+    case Tclass:
+      if (tbtype->ty == Tclass)
+	{
+	  ClassDeclaration *cdfrom = ebtype->isClassHandle ();
+	  ClassDeclaration *cdto = tbtype->isClassHandle ();
+	  int offset;
+
+	  if (cdto->isBaseOf (cdfrom, &offset) && offset != OFFSET_RUNTIME)
+	    {
+	      /* Casting up the inheritance tree: Don't do anything special.
+		 Cast to an implemented interface: Handle at compile time.  */
+	      if (offset)
+		{
+		  /* Forward references should not leak from the frontend.  */
+		  gcc_assert (offset != OFFSET_FWDREF);
+
+		  tree type = build_ctype (totype);
+		  exp = d_save_expr (exp);
+
+		  tree cond = build_boolop (NE_EXPR, exp, null_pointer_node);
+		  tree object = build_offset (exp, size_int (offset));
+
+		  return build_condition (build_ctype (totype), cond,
+					  build_nop (type, object),
+					  build_nop (type, null_pointer_node));
+		}
+
+	      /* d_convert will make a no-op cast.  */
+	      break;
+	    }
+	  else if (cdfrom->cpp)
+	    {
+	      /* Downcasting in C++ is a no-op.  */
+	      if (cdto->cpp)
+		break;
+
+	      /* Casting from a C++ interface to a class/non-C++ interface
+		 always results in null as there is no runtime information,
+		 and no way one can derive from the other.  */
+	      warning (OPT_Wcast_result, "cast to %qs will produce null result",
+		       totype->toChars ());
+	      result = d_convert (build_ctype (totype), null_pointer_node);
+
+	      /* Make sure the expression is still evaluated if necessary.  */
+	      if (TREE_SIDE_EFFECTS (exp))
+		result = compound_expr (exp, result);
+
+	      break;
+	    }
+
+	  /* The offset can only be determined at runtime, do dynamic cast.  */
+	  libcall_fn libcall = cdfrom->isInterfaceDeclaration ()
+	    ? LIBCALL_INTERFACE_CAST : LIBCALL_DYNAMIC_CAST;
+
+	  return build_libcall (libcall, totype, 2, exp,
+				build_address (get_classinfo_decl (cdto)));
+	}
+      /* else default conversion.  */
+      break;
+
+    case Tsarray:
+      if (tbtype->ty == Tpointer)
+	{
+	  result = build_nop (build_ctype (totype), build_address (exp));
+	}
+      else if (tbtype->ty == Tarray)
+	{
+	  dinteger_t dim = ((TypeSArray *) ebtype)->dim->toInteger ();
+	  dinteger_t esize = ebtype->nextOf ()->size ();
+	  dinteger_t tsize = tbtype->nextOf ()->size ();
+
+	  tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ());
+
+	  if ((dim * esize) % tsize != 0)
+	    {
+	      error ("cannot cast %qs to %qs since sizes don't line up",
+		     etype->toChars (), totype->toChars ());
+	      return error_mark_node;
+	    }
+	  dim = (dim * esize) / tsize;
+
+	  /* Assumes casting to dynamic array of same type or void.  */
+	  return d_array_value (build_ctype (totype), size_int (dim),
+				build_nop (ptrtype, build_address (exp)));
+	}
+      else if (tbtype->ty == Tsarray)
+	{
+	  /* D allows casting a static array to any static array type.  */
+	  return build_nop (build_ctype (totype), exp);
+	}
+      else if (tbtype->ty == Tstruct)
+	{
+	  /* And allows casting a static array to any struct type too.
+	     Type sizes should have already been checked by the frontend.  */
+	  gcc_assert (totype->size () == etype->size ());
+	  result = build_vconvert (build_ctype (totype), exp);
+	}
+      else
+	{
+	  error ("cannot cast expression of type %qs to type %qs",
+		 etype->toChars (), totype->toChars ());
+	  return error_mark_node;
+	}
+      break;
+
+    case Tarray:
+      if (tbtype->ty == Tpointer)
+	{
+	  return d_convert (build_ctype (totype), d_array_ptr (exp));
+	}
+      else if (tbtype->ty == Tarray)
+	{
+	  /* Assume tvoid->size() == 1.  */
+	  d_uns64 fsize = ebtype->nextOf ()->toBasetype ()->size ();
+	  d_uns64 tsize = tbtype->nextOf ()->toBasetype ()->size ();
+
+	  if (fsize != tsize)
+	    {
+	      /* Conversion requires a reinterpret cast of array.  */
+	      return build_libcall (LIBCALL_ARRAYCAST, totype, 3,
+				    size_int (tsize), size_int (fsize), exp);
+	    }
+	  else
+	    {
+	      /* Convert from void[] or elements are the same size
+		 -- don't change length.  */
+	      return build_vconvert (build_ctype (totype), exp);
+	    }
+	}
+      else if (tbtype->ty == Tsarray)
+	{
+	  /* Strings are treated as dynamic arrays D2.  */
+	  if (ebtype->isString () && tbtype->isString ())
+	    return indirect_ref (build_ctype (totype), d_array_ptr (exp));
+	}
+      else
+	{
+	  error ("cannot cast expression of type %qs to %qs",
+		 etype->toChars (), totype->toChars ());
+	  return error_mark_node;
+	}
+      break;
+
+    case Taarray:
+      if (tbtype->ty == Taarray)
+	return build_vconvert (build_ctype (totype), exp);
+      /* Can convert associative arrays to void pointers.  */
+      else if (tbtype->ty == Tpointer && tbtype->nextOf ()->ty == Tvoid)
+	return build_vconvert (build_ctype (totype), exp);
+      /* Else, default conversion, which should product an error.  */
+      break;
+
+    case Tpointer:
+      /* Can convert void pointers to associative arrays too.  */
+      if (tbtype->ty == Taarray && ebtype->nextOf ()->ty == Tvoid)
+	return build_vconvert (build_ctype (totype), exp);
+      break;
+
+    case Tnull:
+      if (tbtype->ty == Tarray)
+	{
+	  tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ());
+	  return d_array_value (build_ctype (totype), size_int (0),
+				build_nop (ptrtype, exp));
+	}
+      else if (tbtype->ty == Taarray)
+	return build_constructor (build_ctype (totype), NULL);
+      else if (tbtype->ty == Tdelegate)
+	return build_delegate_cst (exp, null_pointer_node, totype);
+      break;
+
+    case Tvector:
+      if (tbtype->ty == Tsarray)
+	{
+	  if (tbtype->size () == ebtype->size ())
+	    return build_vconvert (build_ctype (totype), exp);
+	}
+      break;
+
+    default:
+      /* All casts between imaginary and non-imaginary result in 0.0,
+	 except for casts between complex and imaginary types.  */
+      if (!ebtype->iscomplex () && !tbtype->iscomplex ()
+	  && (ebtype->isimaginary () != tbtype->isimaginary ()))
+	{
+	  warning (OPT_Wcast_result,
+		   "cast from %qs to %qs will produce zero result",
+		   ebtype->toChars (), tbtype->toChars ());
+
+	  return compound_expr (exp, build_zero_cst (build_ctype (tbtype)));
+	}
+
+      exp = fold_convert (build_ctype (etype), exp);
+      gcc_assert (TREE_CODE (exp) != STRING_CST);
+      break;
+    }
+
+  return result ? result :
+    convert (build_ctype (totype), exp);
+}
+
+
+/* Apply semantics of assignment to a values of type TOTYPE to EXPR
+   (e.g., pointer = array -> pointer = &array[0])
+
+   Return a TREE representation of EXPR implictly converted to TOTYPE
+   for use in assignment expressions MODIFY_EXPR, INIT_EXPR.  */
+
+tree
+convert_for_assignment (tree expr, Type *etype, Type *totype)
+{
+  Type *ebtype = etype->toBasetype ();
+  Type *tbtype = totype->toBasetype ();
+
+  /* Assuming this only has to handle converting a non Tsarray type to
+     arbitrarily dimensioned Tsarrays.  */
+  if (tbtype->ty == Tsarray)
+    {
+      Type *telem = tbtype->nextOf ()->baseElemOf ();
+
+      if (same_type_p (telem, ebtype))
+	{
+	  TypeSArray *sa_type = (TypeSArray *) tbtype;
+	  uinteger_t count = sa_type->dim->toUInteger ();
+
+	  tree ctor = build_constructor (build_ctype (totype), NULL);
+	  if (count)
+	    {
+	      vec<constructor_elt, va_gc> *ce = NULL;
+	      tree index = build2 (RANGE_EXPR, build_ctype (Type::tsize_t),
+				   size_zero_node, size_int (count - 1));
+	      tree value = convert_for_assignment (expr, etype, sa_type->next);
+
+	      /* Can't use VAR_DECLs in CONSTRUCTORS.  */
+	      if (VAR_P (value))
+		{
+		  value = DECL_INITIAL (value);
+		  gcc_assert (value);
+		}
+
+	      CONSTRUCTOR_APPEND_ELT (ce, index, value);
+	      CONSTRUCTOR_ELTS (ctor) = ce;
+	    }
+	  TREE_READONLY (ctor) = 1;
+	  TREE_CONSTANT (ctor) = 1;
+	  return ctor;
+	}
+    }
+
+  /* D Front end uses IntegerExp(0) to mean zero-init a structure.  */
+  if (tbtype->ty == Tstruct && ebtype->isintegral ())
+    {
+      if (!integer_zerop (expr))
+	gcc_unreachable ();
+
+      return expr;
+    }
+
+  return convert_expr (expr, etype, totype);
+}
+
+/* Return a TREE representation of EXPR converted to represent
+   the parameter type ARG.  */
+
+tree
+convert_for_argument (tree expr, Parameter *arg)
+{
+  /* Lazy arguments: expr should already be a delegate.  */
+  if (arg->storageClass & STClazy)
+    return expr;
+
+  if (valist_array_p (arg->type))
+    {
+      /* Do nothing if the va_list has already been decayed to a pointer.  */
+      if (!POINTER_TYPE_P (TREE_TYPE (expr)))
+	return build_address (expr);
+    }
+  else if (argument_reference_p (arg))
+    {
+      /* Front-end shouldn't automatically take the address.  */
+      return convert (type_passed_as (arg), build_address (expr));
+    }
+
+  return expr;
+}
+
+/* Perform default promotions for data used in expressions.
+   Arrays and functions are converted to pointers;
+   enumeral types or short or char, to int.
+   In addition, manifest constants symbols are replaced by their values.
+
+   Return truth-value conversion of expression EXPR from value type TYPE.  */
+
+tree
+convert_for_condition (tree expr, Type *type)
+{
+  tree result = NULL_TREE;
+
+  switch (type->toBasetype ()->ty)
+    {
+    case Taarray:
+      /* Checks that aa.ptr !is null.  */
+      result = component_ref (expr, TYPE_FIELDS (TREE_TYPE (expr)));
+      break;
+
+    case Tarray:
+      {
+	/* Checks (arr.length || arr.ptr) (i.e arr !is null).  */
+	expr = d_save_expr (expr);
+	tree len = d_array_length (expr);
+	tree ptr = d_array_ptr (expr);
+	if (TYPE_MODE (TREE_TYPE (len)) == TYPE_MODE (TREE_TYPE (ptr)))
+	  {
+	    result = build2 (BIT_IOR_EXPR, TREE_TYPE (len), len,
+			     d_convert (TREE_TYPE (len), ptr));
+	  }
+	else
+	  {
+	    len = d_truthvalue_conversion (len);
+	    ptr = d_truthvalue_conversion (ptr);
+	    /* Probably not worth using TRUTH_OROR here.  */
+	    result = build2 (TRUTH_OR_EXPR, TREE_TYPE (len), len, ptr);
+	  }
+	break;
+      }
+
+    case Tdelegate:
+      {
+	/* Checks (function || object), but what good is it if there is
+	   a null function pointer?  */
+	tree obj, func;
+	if (METHOD_CALL_EXPR (expr))
+	  extract_from_method_call (expr, obj, func);
+	else
+	  {
+	    expr = d_save_expr (expr);
+	    obj = delegate_object (expr);
+	    func = delegate_method (expr);
+	  }
+
+	obj = d_truthvalue_conversion (obj);
+	func = d_truthvalue_conversion (func);
+	/* Probably not worth using TRUTH_ORIF here.  */
+	result = build2 (BIT_IOR_EXPR, TREE_TYPE (obj), obj, func);
+	break;
+      }
+
+    default:
+      result = expr;
+      break;
+    }
+
+  return d_truthvalue_conversion (result);
+}
+
+
+/* Convert EXP to a dynamic array.
+   EXP must be a static array or dynamic array.  */
+
+tree
+d_array_convert (Expression *exp)
+{
+  Type *tb = exp->type->toBasetype ();
+
+  if (tb->ty == Tarray)
+    return build_expr (exp);
+
+  if (tb->ty == Tsarray)
+    {
+      Type *totype = tb->nextOf ()->arrayOf ();
+      return convert_expr (build_expr (exp), exp->type, totype);
+    }
+
+  /* Invalid type passed.  */
+  gcc_unreachable ();
+}
+
+/* Convert EXP to a dynamic array, where ETYPE is the element type.
+   Similar to above, except that EXP is allowed to be an element of an array.
+   Temporary variables that need some kind of BIND_EXPR are pushed to VARS.  */
+
+tree
+d_array_convert (Type *etype, Expression *exp, vec<tree, va_gc> **vars)
+{
+  Type *tb = exp->type->toBasetype ();
+
+  if ((tb->ty != Tarray && tb->ty != Tsarray) || same_type_p (tb, etype))
+    {
+      /* Convert single element to an array.  */
+      tree var = NULL_TREE;
+      tree expr = maybe_temporary_var (build_expr (exp), &var);
+
+      if (var != NULL_TREE)
+	vec_safe_push (*vars, var);
+
+      return d_array_value (build_ctype (exp->type->arrayOf ()),
+			    size_int (1), build_address (expr));
+    }
+  else
+    return d_array_convert (exp);
+}
diff --git a/gcc/d/d-diagnostic.cc b/gcc/d/d-diagnostic.cc
new file mode 100644
index 00000000000..3a09f6211ea
--- /dev/null
+++ b/gcc/d/d-diagnostic.cc
@@ -0,0 +1,224 @@
+/* d-diagnostics.cc -- D frontend interface to gcc diagnostics.
+   Copyright (C) 2017 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 "dfrontend/globals.h"
+#include "dfrontend/errors.h"
+
+#include "tree.h"
+#include "options.h"
+#include "diagnostic.h"
+
+#include "d-tree.h"
+
+
+/* Print a hard error message.  */
+
+void
+error (const Loc& loc, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  verror (loc, format, ap);
+  va_end (ap);
+}
+
+void
+verror (const Loc& loc, const char *format, va_list ap,
+	const char *p1, const char *p2, const char *)
+{
+  if (!global.gag || global.params.showGaggedErrors)
+    {
+      location_t location = get_linemap (loc);
+      char *msg = xvasprintf (format, ap);
+      char *prefix = NULL;
+
+      /* Build string and emit.  */
+      if (p2 != NULL)
+	prefix = xasprintf ("%s %s ", p1, p2);
+      else if (p1 != NULL)
+	prefix = xasprintf ("%s ", p1);
+
+      if (global.gag)
+	emit_diagnostic (DK_ANACHRONISM, location, 0, "(spec:%d) %s%s",
+			 global.gag, prefix ? prefix : "", msg);
+      else
+	error_at (location, "%s%s", prefix ? prefix : "", msg);
+
+      if (prefix)
+	free (prefix);
+      free (msg);
+    }
+
+  if (global.gag)
+    global.gaggedErrors++;
+
+  global.errors++;
+}
+
+/* Print supplementary message about the last error.
+   Doesn't increase error count.  */
+
+void
+errorSupplemental (const Loc& loc, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  verrorSupplemental (loc, format, ap);
+  va_end (ap);
+}
+
+void
+verrorSupplemental (const Loc& loc, const char *format, va_list ap)
+{
+  if (global.gag && !global.params.showGaggedErrors)
+    return;
+
+  location_t location = get_linemap (loc);
+  char *msg = xvasprintf (format, ap);
+
+  inform (location, "%s", msg);
+  free (msg);
+}
+
+/* Print a warning message.  */
+
+void
+warning (const Loc& loc, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  vwarning (loc, format, ap);
+  va_end (ap);
+}
+
+void
+vwarning (const Loc& loc, const char *format, va_list ap)
+{
+  if (global.params.warnings && !global.gag)
+    {
+      location_t location = get_linemap (loc);
+      char *msg = xvasprintf (format, ap);
+
+      warning_at (location, 0, "%s", msg);
+      free (msg);
+
+      /* Warnings don't count if gagged.  */
+      if (global.params.warnings == 1)
+	global.warnings++;
+    }
+}
+
+/* Print supplementary message about the last warning.
+   Doesn't increase warning count.  */
+
+void
+warningSupplemental (const Loc& loc, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  vwarningSupplemental (loc, format, ap);
+  va_end (ap);
+}
+
+void
+vwarningSupplemental (const Loc& loc, const char *format, va_list ap)
+{
+  if (global.params.warnings && !global.gag)
+    {
+      location_t location = get_linemap (loc);
+      char *msg = xvasprintf (format, ap);
+
+      inform (location, "%s", msg);
+      free (msg);
+    }
+}
+
+/* Print a deprecation message.  */
+
+void
+deprecation (const Loc& loc, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  vdeprecation (loc, format, ap);
+  va_end (ap);
+}
+
+void
+vdeprecation (const Loc& loc, const char *format, va_list ap,
+	      const char *p1, const char *p2)
+{
+  if (global.params.useDeprecated == 0)
+    verror (loc, format, ap, p1, p2);
+  else if (global.params.useDeprecated == 2 && !global.gag)
+    {
+      location_t location = get_linemap (loc);
+      char *msg = xvasprintf (format, ap);
+      char *prefix = NULL;
+
+      /* Build prefix for message.  */
+      if (p2 != NULL)
+	prefix = xasprintf ("%s %s ", p1, p2);
+      else if (p1 != NULL)
+	prefix = xasprintf ("%s ", p1);
+
+      warning_at (location, OPT_Wdeprecated, "%s%s", prefix ? prefix : "", msg);
+
+      if (prefix)
+	free (prefix);
+      free (msg);
+    }
+}
+
+/* Print supplementary message about the last deprecation.  */
+
+void
+deprecationSupplemental (const Loc& loc, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  vdeprecationSupplemental (loc, format, ap);
+  va_end (ap);
+}
+
+void
+vdeprecationSupplemental (const Loc& loc, const char *format, va_list ap)
+{
+  if (global.params.useDeprecated == 0)
+    verrorSupplemental (loc, format, ap);
+  else if (global.params.useDeprecated == 2 && !global.gag)
+    {
+      location_t location = get_linemap (loc);
+      char *msg = xvasprintf (format, ap);
+
+      inform (location, "%s", msg);
+      free (msg);
+    }
+}
+
+/* Call this after printing out fatal error messages to clean up and
+   exit the compiler.  */
+
+void
+fatal (void)
+{
+  exit (FATAL_EXIT_CODE);
+}
diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
new file mode 100644
index 00000000000..26804291047
--- /dev/null
+++ b/gcc/d/d-frontend.cc
@@ -0,0 +1,515 @@
+/* d-frontend.cc -- D frontend interface to the gcc backend.
+   Copyright (C) 2013-2017 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 "dfrontend/declaration.h"
+#include "dfrontend/module.h"
+#include "dfrontend/mtype.h"
+#include "dfrontend/scope.h"
+#include "dfrontend/statement.h"
+#include "dfrontend/target.h"
+
+#include "tree.h"
+#include "options.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+#include "id.h"
+
+
+/* Implements the Global interface defined by the frontend.
+   Used for managing the state of the current compilation.  */
+
+Global global;
+
+void
+Global::_init (void)
+{
+  this->mars_ext = "d";
+  this->hdr_ext  = "di";
+  this->doc_ext  = "html";
+  this->ddoc_ext = "ddoc";
+  this->json_ext = "json";
+  this->obj_ext = "o";
+
+  this->run_noext = true;
+  this->version = "v"
+#include "verstr.h"
+    ;
+
+  this->stdmsg = stderr;
+  this->errorLimit = flag_max_errors;
+
+  memset (&this->params, 0, sizeof (Param));
+}
+
+/* Start gagging. Return the current number of gagged errors.  */
+
+unsigned
+Global::startGagging (void)
+{
+  this->gag++;
+  return this->gaggedErrors;
+}
+
+/* End gagging, restoring the old gagged state.  Return true if errors
+   occured while gagged.  */
+
+bool
+Global::endGagging (unsigned oldGagged)
+{
+  bool anyErrs = (this->gaggedErrors != oldGagged);
+  this->gag--;
+
+  /* Restore the original state of gagged errors; set total errors
+     to be original errors + new ungagged errors.  */
+  this->errors -= (this->gaggedErrors - oldGagged);
+  this->gaggedErrors = oldGagged;
+
+  return anyErrs;
+}
+
+/* Increment the error count to record that an error has occured in the
+   current context.  An error message may or may not have been printed.  */
+
+void
+Global::increaseErrorCount (void)
+{
+  if (gag)
+    this->gaggedErrors++;
+
+  this->errors++;
+}
+
+
+/* Implements the Loc interface defined by the frontend.
+   Used for keeping track of current file/line position in code.  */
+
+Loc::Loc (const char *filename, unsigned linnum, unsigned charnum)
+{
+  this->linnum = linnum;
+  this->charnum = charnum;
+  this->filename = filename;
+}
+
+const char *
+Loc::toChars (void) const
+{
+  OutBuffer buf;
+
+  if (this->filename)
+    buf.printf ("%s", this->filename);
+
+  if (this->linnum)
+    {
+      buf.printf (":%u", this->linnum);
+      if (this->charnum)
+	buf.printf (":%u", this->charnum);
+    }
+
+  return buf.extractString ();
+}
+
+bool
+Loc::equals (const Loc& loc)
+{
+  if (this->linnum != loc.linnum || this->charnum != loc.charnum)
+    return false;
+
+  if (!FileName::equals (this->filename, loc.filename))
+    return false;
+
+  return true;
+}
+
+
+/* Implements the Port interface defined by the frontend.
+   A mini library for doing compiler/system specific things.  */
+
+/* Compare the first N bytes of S1 and S2 without regard to the case.  */
+
+int
+Port::memicmp (const char *s1, const char *s2, int n)
+{
+  int result = 0;
+
+  for (int i = 0; i < n; i++)
+    {
+      char c1 = s1[i];
+      char c2 = s2[i];
+
+      result = c1 - c2;
+      if (result)
+	{
+	  result = TOUPPER (c1) - TOUPPER (c2);
+	  if (result)
+	    break;
+	}
+    }
+
+  return result;
+}
+
+/* Convert all characters in S to upper case.  */
+
+char *
+Port::strupr (char *s)
+{
+  char *t = s;
+
+  while (*s)
+    {
+      *s = TOUPPER (*s);
+      s++;
+    }
+
+  return t;
+}
+
+/* Return true a if the real_t value from string BUFFER overflows
+   as a result of rounding down to float mode.  */
+
+bool
+Port::isFloat32LiteralOutOfRange (const char *buffer)
+{
+  real_t r;
+
+  real_from_string3 (&r.rv (), buffer, TYPE_MODE (float_type_node));
+
+  return r == Target::RealProperties::infinity;
+}
+
+/* Return true a if the real_t value from string BUFFER overflows
+   as a result of rounding down to double mode.  */
+
+bool
+Port::isFloat64LiteralOutOfRange (const char *buffer)
+{
+  real_t r;
+
+  real_from_string3 (&r.rv (), buffer, TYPE_MODE (double_type_node));
+
+  return r == Target::RealProperties::infinity;
+}
+
+/* Fetch a little-endian 16-bit value from BUFFER.  */
+
+unsigned
+Port::readwordLE (void *buffer)
+{
+  unsigned char *p = (unsigned char*) buffer;
+
+  return ((unsigned) p[1] << 8) | (unsigned) p[0];
+}
+
+/* Fetch a big-endian 16-bit value from BUFFER.  */
+
+unsigned
+Port::readwordBE (void *buffer)
+{
+  unsigned char *p = (unsigned char*) buffer;
+
+  return ((unsigned) p[0] << 8) | (unsigned) p[1];
+}
+
+/* Write a little-endian 32-bit VALUE to BUFFER.  */
+
+void
+Port::writelongLE (unsigned value, void *buffer)
+{
+    unsigned char *p = (unsigned char*) buffer;
+
+    p[0] = (unsigned) value;
+    p[1] = (unsigned) value >> 8;
+    p[2] = (unsigned) value >> 16;
+    p[3] = (unsigned) value >> 24;
+}
+
+/* Fetch a little-endian 32-bit value from BUFFER.  */
+
+unsigned
+Port::readlongLE (void *buffer)
+{
+  unsigned char *p = (unsigned char*) buffer;
+
+  return (((unsigned) p[3] << 24)
+          | ((unsigned) p[2] << 16)
+          | ((unsigned) p[1] << 8)
+          | (unsigned) p[0]);
+}
+
+/* Write a big-endian 32-bit VALUE to BUFFER.  */
+
+void
+Port::writelongBE (unsigned value, void *buffer)
+{
+    unsigned char *p = (unsigned char*) buffer;
+
+    p[0] = (unsigned) value >> 24;
+    p[1] = (unsigned) value >> 16;
+    p[2] = (unsigned) value >> 8;
+    p[3] = (unsigned) value;
+}
+
+/* Fetch a big-endian 32-bit value from BUFFER.  */
+
+unsigned
+Port::readlongBE (void *buffer)
+{
+  unsigned char *p = (unsigned char*) buffer;
+
+  return (((unsigned) p[0] << 24)
+          | ((unsigned) p[1] << 16)
+          | ((unsigned) p[2] << 8)
+          | (unsigned) p[3]);
+}
+
+/* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness.  */
+
+void
+Port::valcpy (void *buffer, uint64_t value, size_t sz)
+{
+  switch (sz)
+    {
+    case 1:
+      *(uint8_t *) buffer = (uint8_t) value;
+      break;
+
+    case 2:
+      *(uint16_t *) buffer = (uint16_t) value;
+      break;
+
+    case 4:
+      *(uint32_t *) buffer = (uint32_t) value;
+      break;
+
+    case 8:
+      *(uint64_t *) buffer = (uint64_t) value;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+
+/* Implements the CTFloat interface defined by the frontend.
+   Compile-time floating-pointer helper functions.  */
+
+/* Return the absolute value of R.  */
+
+real_t
+CTFloat::fabs (real_t r)
+{
+  real_value x = real_value_abs (&r.rv ());
+  return ldouble (x);
+}
+
+/* Return true if longdouble value X is identical to Y.  */
+
+bool
+CTFloat::isIdentical (real_t x, real_t y)
+{
+  real_value rx = x.rv ();
+  real_value ry = y.rv ();
+  return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry))
+    || real_identical (&rx, &ry);
+}
+
+/* Return true if real_t value R is NaN.  */
+
+bool
+CTFloat::isNaN (real_t r)
+{
+  return REAL_VALUE_ISNAN (r.rv ());
+}
+
+/* Same as isNaN, but also check if is signalling.  */
+
+bool
+CTFloat::isSNaN (real_t r)
+{
+  return REAL_VALUE_ISSIGNALING_NAN (r.rv ());
+}
+
+/* Return true if real_t value is +Inf.  */
+
+bool
+CTFloat::isInfinity (real_t r)
+{
+  return REAL_VALUE_ISINF (r.rv ());
+}
+
+/* Return a real_t value from string BUFFER rounded to long double mode.  */
+
+real_t
+CTFloat::parse (const char *buffer, bool *overflow)
+{
+  real_t r;
+  real_from_string3 (&r.rv (), buffer, TYPE_MODE (long_double_type_node));
+
+  /* Front-end checks overflow to see if the value is representable.  */
+  if (overflow && r == Target::RealProperties::infinity)
+    *overflow = true;
+
+  return r;
+}
+
+/* Format the real_t value R to string BUFFER as a decimal or hexadecimal,
+   converting the result to uppercase if FMT requests it.  */
+
+int
+CTFloat::sprint (char *buffer, char fmt, real_t r)
+{
+  if (fmt == 'a' || fmt == 'A')
+    {
+      /* Converting to a hexadecimal string.  */
+      real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1);
+      int buflen;
+
+      switch (fmt)
+	{
+	case 'A':
+	  buflen = strlen (buffer);
+	  for (int i = 0; i < buflen; i++)
+	    buffer[i] = TOUPPER (buffer[i]);
+
+	  return buflen;
+
+	case 'a':
+	  return strlen (buffer);
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+  else
+    {
+      /* Note: restricting the precision of significant digits to 18.  */
+      real_to_decimal (buffer, &r.rv (), 32, 18, 1);
+      return strlen (buffer);
+    }
+}
+
+
+/* Implements backend-specific interfaces used by the frontend.  */
+
+/* Semantically analyze AsmStatement where SC is the scope.  */
+
+Statement *
+asmSemantic (AsmStatement *s, Scope *sc)
+{
+  sc->func->hasReturnExp |= 8;
+  return s;
+}
+
+/* Determine return style of function - whether in registers or through a
+   hidden pointer to the caller's stack.  */
+
+RET
+retStyle (TypeFunction *)
+{
+  /* Need the backend type to determine this, but this is called from the
+     frontend before semantic processing is finished.  An accurate value
+     is not currently needed anyway.  */
+  return RETstack;
+}
+
+/* Determine if function FD is a builtin one that we can evaluate in CTFE.  */
+
+BUILTIN
+isBuiltin (FuncDeclaration *fd)
+{
+  if (fd->builtin != BUILTINunknown)
+    return fd->builtin;
+
+  fd->builtin = BUILTINno;
+
+  /* Intrinsics have no function body.  */
+  if (fd->fbody)
+    return BUILTINno;
+
+  maybe_set_intrinsic (fd);
+  return fd->builtin;
+}
+
+/* Evaluate builtin D function FD whose argument list is ARGUMENTS.
+   Return result; NULL if cannot evaluate it.  */
+
+Expression *
+eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
+{
+  if (fd->builtin != BUILTINyes)
+    return NULL;
+
+  tree decl = get_symbol_decl (fd);
+  gcc_assert (DECL_BUILT_IN (decl));
+
+  TypeFunction *tf = (TypeFunction *) fd->type;
+  Expression *e = NULL;
+  input_location = get_linemap (loc);
+
+  tree result = d_build_call (tf, decl, NULL, arguments);
+  result = fold (result);
+
+  /* Builtin should be successfully evaluated.
+     Will only return NULL if we can't convert it.  */
+  if (TREE_CONSTANT (result) && TREE_CODE (result) != CALL_EXPR)
+    e = d_eval_constant_expression (result);
+
+  return e;
+}
+
+/* Generate C main() in response to seeing D main().  This used to be in
+   libdruntime, but contained a reference to _Dmain which didn't work when
+   druntime was made into a shared library and was linked to a program, such
+   as a C++ program, that didn't have a _Dmain.  */
+
+void
+genCmain (Scope *sc)
+{
+  static bool initialized = false;
+
+  if (initialized)
+    return;
+
+  /* The D code to be generated is provided by __entrypoint.di.  */
+  Module *m = Module::load (Loc (), NULL, Id::entrypoint);
+  m->importedFrom = m;
+  m->importAll (NULL);
+  m->semantic (NULL);
+  m->semantic2 (NULL);
+  m->semantic3 (NULL);
+
+  d_add_entrypoint_module (m, sc->_module);
+  initialized = true;
+}
+
+/* Build and return typeinfo type for TYPE.  */
+
+Type *
+getTypeInfoType (Type *type, Scope *sc)
+{
+  gcc_assert (type->ty != Terror);
+  create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
+  return type->vtinfo->type;
+}
diff --git a/gcc/d/d-frontend.h b/gcc/d/d-frontend.h
new file mode 100644
index 00000000000..cf4038ea7ba
--- /dev/null
+++ b/gcc/d/d-frontend.h
@@ -0,0 +1,42 @@
+/* d-frontend.h -- D frontend interface to the gcc backend.
+   Copyright (C) 2006-2017 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/>.  */
+
+/* This file contains declarations defined in the D frontend proper,
+   but used in the GDC glue interface.  */
+
+#ifndef GCC_D_FRONTEND_H
+#define GCC_D_FRONTEND_H
+
+/* Forward type declarations to avoid including unnecessary headers.  */
+
+class Dsymbol;
+class FuncDeclaration;
+class StructDeclaration;
+class Type;
+struct OutBuffer;
+
+/* Used in typeinfo.cc.  */
+FuncDeclaration *search_toString (StructDeclaration *);
+const char *cppTypeInfoMangle (Dsymbol *);
+
+/* Used in d-lang.cc.  */
+void initTraitsStringTable (void);
+
+/* Used in intrinsics.cc.  */
+void mangleToBuffer(Type *t, OutBuffer *buf);
+
+#endif  /* ! GCC_D_FRONTEND_H */
diff --git a/gcc/d/d-incpath.cc b/gcc/d/d-incpath.cc
new file mode 100644
index 00000000000..e71cb64f9c9
--- /dev/null
+++ b/gcc/d/d-incpath.cc
@@ -0,0 +1,233 @@
+/* d-incpath.cc -- Set up combined import paths for the D frontend.
+   Copyright (C) 2006-2017 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 "dfrontend/globals.h"
+
+#include "tree.h"
+#include "diagnostic.h"
+#include "options.h"
+#include "cppdefault.h"
+
+#include "d-tree.h"
+
+/* Read ENV_VAR for a PATH_SEPARATOR-separated list of file names; and
+   append all the names to the import search path.  */
+
+static void
+add_environment_paths (const char *env_var)
+{
+  char *q = getenv (env_var);
+  char *path;
+
+  if (!q)
+    return;
+
+  for (char *p = q; *q; p = q + 1)
+    {
+      q = p;
+      while (*q != 0 && *q != PATH_SEPARATOR)
+	q++;
+
+      if (p == q)
+	path = xstrdup (".");
+      else
+	{
+	  path = XNEWVEC (char, q - p + 1);
+	  memcpy (path, p, q - p);
+	  path[q - p] = '\0';
+	}
+
+      global.params.imppath->push (path);
+    }
+}
+
+/* Look for directories that start with the standard prefix.
+   "Translate" them, i.e. replace /usr/local/lib/gcc with
+   IPREFIX and search them first.  Based on incpath.c.  */
+
+static char *
+prefixed_path (const char *path, const char *iprefix)
+{
+  size_t len;
+
+  if (cpp_relocated () && (len = cpp_PREFIX_len) != 0)
+  {
+    if (!strncmp (path, cpp_PREFIX, len))
+      {
+	static const char *relocated_prefix;
+	/* If this path starts with the configure-time prefix,
+	   but the compiler has been relocated, replace it
+	   with the run-time prefix.  */
+	if (!relocated_prefix)
+	  {
+	    /* Make relative prefix expects the first argument
+	       to be a program, not a directory.  */
+	    char *dummy = concat (gcc_exec_prefix, "dummy", NULL);
+	    relocated_prefix
+	      = make_relative_prefix (dummy,
+				      cpp_EXEC_PREFIX,
+				      cpp_PREFIX);
+	    free (dummy);
+	  }
+
+	return concat (relocated_prefix, path + len, NULL);
+      }
+  }
+
+  if (iprefix && (len = cpp_GCC_INCLUDE_DIR_len) != 0)
+    {
+      if (!strncmp (path, cpp_GCC_INCLUDE_DIR, len))
+	return concat (iprefix, path + len, NULL);
+    }
+
+  return xstrdup (path);
+}
+
+/* Add PATHS to the global import lookup path.  */
+
+static void
+add_globalpaths (Strings *paths)
+{
+  if (paths)
+    {
+      if (!global.path)
+	global.path = new Strings ();
+
+      for (size_t i = 0; i < paths->dim; i++)
+	{
+	  const char *path = (*paths)[i];
+	  const char *target = FileName::canonicalName (path);
+
+	  if (!FileName::exists (target))
+	    {
+	      free (CONST_CAST (char *, target));
+	      continue;
+	    }
+
+	  global.path->push (target);
+	}
+    }
+}
+
+/* Add PATHS to the global file import lookup path.  */
+
+static void
+add_filepaths (Strings *paths)
+{
+  if (paths)
+    {
+      if (!global.filePath)
+	global.filePath = new Strings ();
+
+      for (size_t i = 0; i < paths->dim; i++)
+	{
+	  const char *path = (*paths)[i];
+	  const char *target = FileName::canonicalName (path);
+
+	  if (!FileName::exists (target))
+	    {
+	      free (CONST_CAST (char *, target));
+	      continue;
+	    }
+
+	  global.filePath->push (target);
+	}
+    }
+}
+
+/* Add all search directories to compiler runtime.
+   if STDINC, also include standard library paths.  */
+
+void
+add_import_paths (const char *iprefix, const char *imultilib, bool stdinc)
+{
+  if (stdinc)
+    {
+      for (const default_include *p = cpp_include_defaults; p->fname; p++)
+	{
+	  char *path;
+
+	  /* Ignore C++ paths.  */
+	  if (p->cplusplus)
+	    continue;
+
+	  if (!p->add_sysroot)
+	    path = prefixed_path (p->fname, iprefix);
+	  else
+	    path = xstrdup (p->fname);
+
+	  /* Add D-specific suffix.  */
+	  path = concat (path, "/d", NULL);
+
+	  /* Ignore duplicate entries.  */
+	  bool found = false;
+	  for (size_t i = 0; i < global.params.imppath->dim; i++)
+	    {
+	      if (strcmp (path, (*global.params.imppath)[i]) == 0)
+		{
+		  found = true;
+		  break;
+		}
+	    }
+
+	  if (found)
+	    {
+	      free (path);
+	      continue;
+	    }
+
+	  /* Multilib support.  */
+	  if (imultilib)
+	    {
+	      char *target_path = concat (path, "/", imultilib, NULL);
+	      global.params.imppath->shift (target_path);
+	    }
+
+	  global.params.imppath->shift (path);
+	}
+    }
+
+  /* Language-dependent environment variables may add to the include chain.  */
+  add_environment_paths ("D_IMPORT_PATH");
+
+  /* Add import search paths  */
+  if (global.params.imppath)
+    {
+      for (size_t i = 0; i < global.params.imppath->dim; i++)
+	{
+	  const char *path = (*global.params.imppath)[i];
+	  if (path)
+	    add_globalpaths (FileName::splitPath (path));
+	}
+    }
+
+  /* Add string import search paths.  */
+  if (global.params.fileImppath)
+    {
+      for (size_t i = 0; i < global.params.fileImppath->dim; i++)
+	{
+	  const char *path = (*global.params.fileImppath)[i];
+	  if (path)
+	    add_filepaths (FileName::splitPath (path));
+	}
+    }
+}
+
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
new file mode 100644
index 00000000000..126a0bbd7cd
--- /dev/null
+++ b/gcc/d/d-lang.cc
@@ -0,0 +1,1800 @@
+/* d-lang.cc -- Language-dependent hooks for D.
+   Copyright (C) 2006-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/cond.h"
+#include "dfrontend/doc.h"
+#include "dfrontend/hdrgen.h"
+#include "dfrontend/json.h"
+#include "dfrontend/lexer.h"
+#include "dfrontend/module.h"
+#include "dfrontend/mtype.h"
+#include "dfrontend/target.h"
+
+#include "opts.h"
+#include "alias.h"
+#include "tree.h"
+#include "diagnostic.h"
+#include "fold-const.h"
+#include "toplev.h"
+#include "langhooks.h"
+#include "langhooks-def.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "stringpool.h"
+#include "stor-layout.h"
+#include "print-tree.h"
+#include "gimple-expr.h"
+#include "gimplify.h"
+#include "debug.h"
+
+#include "d-tree.h"
+#include "d-frontend.h"
+#include "id.h"
+
+
+/* Array of D frontend type/decl nodes.  */
+tree d_global_trees[DTI_MAX];
+
+/* Options handled by the compiler that are separate from the frontend.  */
+struct d_option_data
+{
+  const char *fonly;                /* -fonly=<arg>  */
+  const char *multilib;             /* -imultilib <dir>  */
+  const char *prefix;               /* -iprefix <dir>  */
+
+  bool deps;                        /* -M  */
+  bool deps_skip_system;            /* -MM  */
+  const char *deps_filename;        /* -M[M]D  */
+  const char *deps_filename_user;   /* -MF <arg>  */
+  OutBuffer *deps_target;           /* -M[QT] <arg> */
+  bool deps_phony;                  /* -MP  */
+
+  bool stdinc;                      /* -nostdinc  */
+}
+d_option;
+
+/* List of modules being compiled.  */
+static Modules builtin_modules;
+
+/* Module where `C main' is defined, compiled in if needed.  */
+static Module *entrypoint_module = NULL;
+static Module *entrypoint_root_module = NULL;
+
+/* The current and global binding level in effect.  */
+struct binding_level *current_binding_level;
+struct binding_level *global_binding_level;
+
+/* The context to be used for global declarations.  */
+static GTY(()) tree global_context;
+
+/* Array of all global declarations to pass back to the middle-end.  */
+static GTY(()) vec<tree, va_gc> *global_declarations;
+
+/* Support for GCC-style command-line make dependency generation.
+   Adds TARGET to the make dependencies target buffer.
+   QUOTED is true if the string should be quoted.  */
+
+static void
+deps_add_target (const char *target, bool quoted)
+{
+  if (!d_option.deps_target)
+    d_option.deps_target = new OutBuffer ();
+  else
+    d_option.deps_target->writeByte (' ');
+
+  d_option.deps_target->reserve (strlen (target));
+
+  if (!quoted)
+    {
+      d_option.deps_target->writestring (target);
+      return;
+    }
+
+  /* Quote characters in target which are significant to Make.  */
+  for (const char *p = target; *p != '\0'; p++)
+    {
+      switch (*p)
+        {
+        case ' ':
+        case '\t':
+          for (const char *q = p - 1; target <= q && *q == '\\';  q--)
+	    d_option.deps_target->writeByte ('\\');
+	  d_option.deps_target->writeByte ('\\');
+          break;
+
+        case '$':
+	  d_option.deps_target->writeByte ('$');
+          break;
+
+        case '#':
+	  d_option.deps_target->writeByte ('\\');
+          break;
+
+        default:
+          break;
+        }
+
+      d_option.deps_target->writeByte (*p);
+    }
+}
+
+/* Write out all dependencies of a given MODULE to the specified BUFFER.
+   COLMAX is the number of columns to word-wrap at (0 means don't wrap).  */
+
+static void
+deps_write (Module *module, OutBuffer *buffer, unsigned colmax = 72)
+{
+  StringTable dependencies;
+  dependencies._init ();
+
+  Modules modlist;
+  modlist.push (module);
+
+  Modules phonylist;
+
+  const char *str;
+  unsigned size;
+  unsigned column = 0;
+
+  /* Write out make target module name.  */
+  if (d_option.deps_target)
+    {
+      size = d_option.deps_target->offset;
+      str = d_option.deps_target->extractString ();
+    }
+  else
+    {
+      str = module->objfile->name->str;
+      size = strlen (str);
+    }
+
+  buffer->writestring (str);
+  column = size;
+  buffer->writestring (":");
+  column++;
+
+  /* Write out all make dependencies.  */
+  while (modlist.dim > 0)
+  {
+    Module *depmod = modlist.pop ();
+
+    str = depmod->srcfile->name->str;
+    size = strlen (str);
+
+    /* Skip dependencies that have already been written.  */
+    if (!dependencies.insert (str, size, NULL))
+      continue;
+
+    column += size;
+
+    if (colmax && column > colmax)
+      {
+	buffer->writestring (" \\\n ");
+	column = size + 1;
+      }
+    else
+      {
+	buffer->writestring (" ");
+	column++;
+      }
+
+    buffer->writestring (str);
+
+    /* Add to list of phony targets if is not being compile.  */
+    if (d_option.deps_phony && !depmod->isRoot ())
+      phonylist.push (depmod);
+
+    /* Search all imports of the written dependency.  */
+    for (size_t i = 0; i < depmod->aimports.dim; i++)
+      {
+	Module *m = depmod->aimports[i];
+
+	/* Ignore compiler-generated modules.  */
+	if (m->ident == Id::entrypoint && m->parent == NULL)
+	  continue;
+
+	/* Don't search system installed modules, this includes
+	   object, core.*, std.*, and gcc.* packages.  */
+	if (d_option.deps_skip_system)
+	  {
+	    if (m->ident == Id::object && m->parent == NULL)
+	      continue;
+
+	    if (m->md && m->md->packages)
+	      {
+		Identifier *package = (*m->md->packages)[0];
+
+		if (package == Id::core || package == Id::std
+		    || package == Identifier::idPool ("gcc"))
+		  continue;
+	      }
+	  }
+
+	modlist.push (m);
+      }
+  }
+
+  buffer->writenl ();
+
+  /* Write out all phony targets.  */
+  for (size_t i = 0; i < phonylist.dim; i++)
+    {
+      Module *m = phonylist[i];
+
+      buffer->writenl ();
+      buffer->writestring (m->srcfile->name->str);
+      buffer->writestring (":\n");
+    }
+}
+
+/* Implements the lang_hooks.init_options routine for language D.
+   This initializes the global state for the D frontend before calling
+   the option handlers.  */
+
+static void
+d_init_options (unsigned int, cl_decoded_option *decoded_options)
+{
+  /* Set default values.  */
+  global._init ();
+
+  global.compiler.vendor = lang_hooks.name;
+
+  global.params.argv0 = xstrdup (decoded_options[0].arg);
+  global.params.link = true;
+  global.params.useAssert = true;
+  global.params.useInvariants = true;
+  global.params.useIn = true;
+  global.params.useOut = true;
+  global.params.useArrayBounds = BOUNDSCHECKdefault;
+  global.params.useSwitchError = true;
+  global.params.useInline = false;
+  global.params.warnings = 0;
+  global.params.obj = true;
+  global.params.useDeprecated = 1;
+  global.params.hdrStripPlainFunctions = true;
+  global.params.betterC = false;
+  global.params.allInst = false;
+
+  global.params.linkswitches = new Strings ();
+  global.params.libfiles = new Strings ();
+  global.params.objfiles = new Strings ();
+  global.params.ddocfiles = new Strings ();
+
+  global.params.imppath = new Strings ();
+  global.params.fileImppath = new Strings ();
+  global.params.modFileAliasStrings = new Strings ();
+
+  /* Extra GDC-specific options.  */
+  d_option.fonly = NULL;
+  d_option.multilib = NULL;
+  d_option.prefix = NULL;
+  d_option.deps = false;
+  d_option.deps_skip_system = false;
+  d_option.deps_filename = NULL;
+  d_option.deps_filename_user = NULL;
+  d_option.deps_target = NULL;
+  d_option.deps_phony = false;
+  d_option.stdinc = true;
+}
+
+/* Implements the lang_hooks.init_options_struct routine for language D.
+   Initializes the options structure OPTS.  */
+
+static void
+d_init_options_struct (gcc_options *opts)
+{
+  /* GCC options.  */
+  opts->x_flag_exceptions = 1;
+
+  /* Avoid range issues for complex multiply and divide.  */
+  opts->x_flag_complex_method = 2;
+
+  /* Unlike C, there is no global 'errno' variable.  */
+  opts->x_flag_errno_math = 0;
+  opts->frontend_set_flag_errno_math = true;
+
+  /* Keep in sync with existing -fbounds-check flag.  */
+  opts->x_flag_bounds_check = global.params.useArrayBounds;
+
+  /* D says that signed overflow is precisely defined.  */
+  opts->x_flag_wrapv = 1;
+}
+
+/* Implements the lang_hooks.lang_mask routine for language D.
+   Returns language mask for option parsing.  */
+
+static unsigned int
+d_option_lang_mask (void)
+{
+  return CL_D;
+}
+
+/* Callback for TARGET_CPU_D_BUILTINS and TARGET_OS_D_BUILTINS.
+   Adds IDENT to the list of predefined version identifiers.  */
+
+static void
+d_add_builtin_version (const char* ident)
+{
+  /* For now, we need to tell the D frontend what platform is being targetted.
+     This should be removed once the frontend has been fixed.  */
+  if (strcmp (ident, "linux") == 0)
+    global.params.isLinux = true;
+  else if (strcmp (ident, "OSX") == 0)
+    global.params.isOSX = true;
+  else if (strcmp (ident, "Windows") == 0)
+    global.params.isWindows = true;
+  else if (strcmp (ident, "FreeBSD") == 0)
+    global.params.isFreeBSD = true;
+  else if (strcmp (ident, "OpenBSD") == 0)
+    global.params.isOpenBSD = true;
+  else if (strcmp (ident, "Solaris") == 0)
+    global.params.isSolaris = true;
+  else if (strcmp (ident, "X86_64") == 0)
+    global.params.is64bit = true;
+
+  VersionCondition::addPredefinedGlobalIdent (ident);
+}
+
+/* Implements the lang_hooks.init routine for language D.  */
+
+static bool
+d_init (void)
+{
+  Lexer::initLexer ();
+  Type::_init ();
+  Id::initialize ();
+  Module::_init ();
+  Expression::_init ();
+  initPrecedence ();
+  initTraitsStringTable ();
+
+  /* Backend init.  */
+  global_binding_level = ggc_cleared_alloc<binding_level> ();
+  current_binding_level = global_binding_level;
+
+  /* This allows the code in d-builtins.cc to not have to worry about
+     converting (C signed char *) to (D char *) for string arguments of
+     built-in functions.  The parameter (signed_char = false) specifies
+     whether char is signed.  */
+  build_common_tree_nodes (false);
+
+  d_init_builtins ();
+
+  if (flag_exceptions)
+    using_eh_for_cleanups ();
+
+  /* This is the C main, not the D main.  */
+  main_identifier_node = get_identifier ("main");
+
+  Target::_init ();
+
+#ifndef TARGET_CPU_D_BUILTINS
+# define TARGET_CPU_D_BUILTINS()
+#endif
+
+#ifndef TARGET_OS_D_BUILTINS
+# define TARGET_OS_D_BUILTINS()
+#endif
+
+# define builtin_define(TXT) d_add_builtin_version (TXT)
+
+  TARGET_CPU_D_BUILTINS ();
+  TARGET_OS_D_BUILTINS ();
+
+  VersionCondition::addPredefinedGlobalIdent ("GNU");
+  VersionCondition::addPredefinedGlobalIdent ("D_Version2");
+
+  if (BYTES_BIG_ENDIAN)
+    VersionCondition::addPredefinedGlobalIdent ("BigEndian");
+  else
+    VersionCondition::addPredefinedGlobalIdent ("LittleEndian");
+
+  if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ)
+    VersionCondition::addPredefinedGlobalIdent ("GNU_SjLj_Exceptions");
+  else if (targetm_common.except_unwind_info (&global_options) == UI_SEH)
+    VersionCondition::addPredefinedGlobalIdent ("GNU_SEH_Exceptions");
+  else if (targetm_common.except_unwind_info (&global_options) == UI_DWARF2)
+    VersionCondition::addPredefinedGlobalIdent ("GNU_DWARF2_Exceptions");
+
+  if (!targetm.have_tls)
+    VersionCondition::addPredefinedGlobalIdent ("GNU_EMUTLS");
+
+#ifdef STACK_GROWS_DOWNWARD
+  VersionCondition::addPredefinedGlobalIdent ("GNU_StackGrowsDown");
+#endif
+
+  /* Should define this anyway to set us apart from the competition. */
+  VersionCondition::addPredefinedGlobalIdent ("GNU_InlineAsm");
+
+  /* LP64 only means 64bit pointers in D. */
+  if (global.params.isLP64)
+    VersionCondition::addPredefinedGlobalIdent ("D_LP64");
+
+  /* Setting `global.params.cov' forces module info generation which is
+     not needed for the GCC coverage implementation.  Instead, just
+     test flag_test_coverage while leaving `global.params.cov' unset. */
+  if (flag_test_coverage)
+    VersionCondition::addPredefinedGlobalIdent ("D_Coverage");
+  if (flag_pic)
+    VersionCondition::addPredefinedGlobalIdent ("D_PIC");
+  if (global.params.doDocComments)
+    VersionCondition::addPredefinedGlobalIdent ("D_Ddoc");
+  if (global.params.useUnitTests)
+    VersionCondition::addPredefinedGlobalIdent ("unittest");
+  if (global.params.useAssert)
+    VersionCondition::addPredefinedGlobalIdent ("assert");
+  if (global.params.useArrayBounds == BOUNDSCHECKoff)
+    VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks");
+
+  VersionCondition::addPredefinedGlobalIdent ("all");
+
+  /* Insert all library-configured identifiers and import paths.  */
+  add_import_paths (d_option.prefix, d_option.multilib, d_option.stdinc);
+
+  return 1;
+}
+
+/* Implements the lang_hooks.init_ts routine for language D.  */
+
+static void
+d_init_ts (void)
+{
+  MARK_TS_TYPED (IASM_EXPR);
+  MARK_TS_TYPED (FLOAT_MOD_EXPR);
+  MARK_TS_TYPED (UNSIGNED_RSHIFT_EXPR);
+}
+
+/* Implements the lang_hooks.handle_option routine for language D.
+   Handles D specific options.  Return false if we didn't do anything.  */
+
+static bool
+d_handle_option (size_t scode, const char *arg, int value,
+		 int kind ATTRIBUTE_UNUSED,
+		 location_t loc ATTRIBUTE_UNUSED,
+		 const cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+  opt_code code = (opt_code) scode;
+  bool result = true;
+
+  switch (code)
+    {
+    case OPT_fall_instantiations:
+      global.params.allInst = value;
+      break;
+
+    case OPT_fassert:
+      global.params.useAssert = value;
+      break;
+
+    case OPT_fbounds_check:
+      global.params.useArrayBounds = value
+	? BOUNDSCHECKon : BOUNDSCHECKoff;
+      break;
+
+    case OPT_fbounds_check_:
+      global.params.useArrayBounds = (value == 2) ? BOUNDSCHECKon
+	: (value == 1) ? BOUNDSCHECKsafeonly : BOUNDSCHECKoff;
+      break;
+
+    case OPT_fdebug:
+      global.params.debuglevel = value ? 1 : 0;
+      break;
+
+    case OPT_fdebug_:
+      if (ISDIGIT (arg[0]))
+	{
+	  int level = integral_argument (arg);
+	  if (level != -1)
+	    {
+	      DebugCondition::setGlobalLevel (level);
+	      break;
+	    }
+	}
+
+      if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
+	{
+	  DebugCondition::addGlobalIdent (arg);
+	  break;
+	}
+
+      error ("bad argument for -fdebug '%s'", arg);
+      break;
+
+    case OPT_fdeps:
+      global.params.moduleDeps = new OutBuffer;
+      break;
+
+    case OPT_fdeps_:
+      global.params.moduleDepsFile = arg;
+      if (!global.params.moduleDepsFile[0])
+	error ("bad argument for -fdeps");
+      global.params.moduleDeps = new OutBuffer;
+      break;
+
+    case OPT_fdoc:
+      global.params.doDocComments = value;
+      break;
+
+    case OPT_fdoc_dir_:
+      global.params.doDocComments = true;
+      global.params.docdir = arg;
+      break;
+
+    case OPT_fdoc_file_:
+      global.params.doDocComments = true;
+      global.params.docname = arg;
+      break;
+
+    case OPT_fdoc_inc_:
+      global.params.ddocfiles->push (arg);
+      break;
+
+    case OPT_fdump_d_original:
+      global.params.vcg_ast = value;
+      break;
+
+    case OPT_fignore_unknown_pragmas:
+      global.params.ignoreUnsupportedPragmas = value;
+      break;
+
+    case OPT_fintfc:
+      global.params.doHdrGeneration = value;
+      break;
+
+    case OPT_fintfc_dir_:
+      global.params.doHdrGeneration = true;
+      global.params.hdrdir = arg;
+      break;
+
+    case OPT_fintfc_file_:
+      global.params.doHdrGeneration = true;
+      global.params.hdrname = arg;
+      break;
+
+    case OPT_finvariants:
+      global.params.useInvariants = value;
+      break;
+
+    case OPT_fmodule_filepath_:
+      global.params.modFileAliasStrings->push (arg);
+      if (!strchr (arg, '='))
+	error ("bad argument for -fmodule-filepath");
+      break;
+
+    case OPT_fmoduleinfo:
+      global.params.betterC = !value;
+      break;
+
+    case OPT_fonly_:
+      d_option.fonly = arg;
+      break;
+
+    case OPT_fpostconditions:
+      global.params.useOut = value;
+      break;
+
+    case OPT_fpreconditions:
+      global.params.useIn = value;
+      break;
+
+    case OPT_fproperty:
+      global.params.enforcePropertySyntax = value;
+      break;
+
+    case OPT_frelease:
+      global.params.release = value;
+      break;
+
+    case OPT_fswitch_errors:
+      global.params.useSwitchError = value;
+      break;
+
+    case OPT_ftransition_all:
+      global.params.vtls = value;
+      global.params.vfield = value;
+      global.params.vcomplex = value;
+      break;
+
+    case OPT_ftransition_checkimports:
+      global.params.check10378 = value;
+      break;
+
+    case OPT_ftransition_complex:
+      global.params.vcomplex = value;
+      break;
+
+    case OPT_ftransition_dip1000:
+      global.params.vsafe = value;
+      global.params.useDIP25 = value;
+      break;
+
+    case OPT_ftransition_dip25:
+      global.params.useDIP25 = value;
+      break;
+
+    case OPT_ftransition_field:
+      global.params.vfield = value;
+      break;
+
+    case OPT_ftransition_import:
+      global.params.bug10378 = value;
+      break;
+
+    case OPT_ftransition_nogc:
+      global.params.vgc = value;
+      break;
+
+    case OPT_ftransition_tls:
+      global.params.vtls = value;
+      break;
+
+    case OPT_funittest:
+      global.params.useUnitTests = value;
+      break;
+
+    case OPT_fversion_:
+      if (ISDIGIT (arg[0]))
+	{
+	  int level = integral_argument (arg);
+	  if (level != -1)
+	    {
+	      VersionCondition::setGlobalLevel (level);
+	      break;
+	    }
+	}
+
+      if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
+	{
+	  VersionCondition::addGlobalIdent (arg);
+	  break;
+	}
+
+      error ("bad argument for -fversion '%s'", arg);
+      break;
+
+    case OPT_imultilib:
+      d_option.multilib = arg;
+      break;
+
+    case OPT_iprefix:
+      d_option.prefix = arg;
+      break;
+
+    case OPT_I:
+      global.params.imppath->push (arg);
+      break;
+
+    case OPT_J:
+      global.params.fileImppath->push (arg);
+      break;
+
+    case OPT_MM:
+      d_option.deps_skip_system = true;
+      /* fall through */
+
+    case OPT_M:
+      d_option.deps = true;
+      break;
+
+    case OPT_MMD:
+    case OPT_fmake_mdeps_:
+      d_option.deps_skip_system = true;
+      /* fall through */
+
+    case OPT_MD:
+    case OPT_fmake_deps_:
+      d_option.deps = true;
+      d_option.deps_filename = arg;
+      break;
+
+    case OPT_MF:
+      /* If specified multiple times, last one wins.  */
+      d_option.deps_filename_user = arg;
+      break;
+
+    case OPT_MP:
+      d_option.deps_phony = true;
+      break;
+
+    case OPT_MQ:
+      deps_add_target (arg, true);
+      break;
+
+    case OPT_MT:
+      deps_add_target (arg, false);
+      break;
+
+    case OPT_nostdinc:
+      d_option.stdinc = false;
+      break;
+
+    case OPT_v:
+      global.params.verbose = value;
+      break;
+
+    case OPT_Wall:
+      if (value)
+	global.params.warnings = 2;
+      break;
+
+    case OPT_Wdeprecated:
+      global.params.useDeprecated = value ? 2 : 1;
+      break;
+
+    case OPT_Werror:
+      if (value)
+	global.params.warnings = 1;
+      break;
+
+    case OPT_Wspeculative:
+      if (value)
+	global.params.showGaggedErrors = 1;
+      break;
+
+    case OPT_Xf:
+      global.params.jsonfilename = arg;
+      /* fall through */
+
+    case OPT_X:
+      global.params.doJsonGeneration = true;
+      break;
+
+    default:
+      break;
+    }
+
+  D_handle_option_auto (&global_options, &global_options_set,
+			scode, arg, value,
+			d_option_lang_mask (), kind,
+			loc, handlers, global_dc);
+
+  return result;
+}
+
+/* Implements the lang_hooks.post_options routine for language D.
+   Deal with any options that imply the turning on/off of features.
+   FN is the main input filename passed on the command line.  */
+
+static bool
+d_post_options (const char ** fn)
+{
+  /* Verify the input file name.  */
+  const char *filename = *fn;
+  if (!filename || strcmp (filename, "-") == 0)
+    filename = "";
+
+  /* The front end considers the first input file to be the main one.  */
+  *fn = filename;
+
+  /* Release mode doesn't turn off bounds checking for safe functions.  */
+  if (global.params.useArrayBounds == BOUNDSCHECKdefault)
+    {
+      global.params.useArrayBounds = global.params.release
+	? BOUNDSCHECKsafeonly : BOUNDSCHECKon;
+      flag_bounds_check = !global.params.release;
+    }
+
+  if (global.params.release)
+    {
+      if (!global_options_set.x_flag_invariants)
+	global.params.useInvariants = false;
+
+      if (!global_options_set.x_flag_preconditions)
+	global.params.useIn = false;
+
+      if (!global_options_set.x_flag_postconditions)
+	global.params.useOut = false;
+
+      if (!global_options_set.x_flag_assert)
+	global.params.useAssert = false;
+
+      if (!global_options_set.x_flag_switch_errors)
+	global.params.useSwitchError = false;
+    }
+
+  /* Error about use of deprecated features.  */
+  if (global.params.useDeprecated == 2 && global.params.warnings == 1)
+    global.params.useDeprecated = 0;
+
+  /* Make -fmax-errors visible to frontend's diagnostic machinery.  */
+  if (global_options_set.x_flag_max_errors)
+    global.errorLimit = flag_max_errors;
+
+  if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT)
+    flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
+
+  if (global.params.useUnitTests)
+    global.params.useAssert = true;
+
+  global.params.symdebug = write_symbols != NO_DEBUG;
+  global.params.useInline = flag_inline_functions;
+
+  if (global.params.useInline)
+    global.params.hdrStripPlainFunctions = false;
+
+  global.params.obj = !flag_syntax_only;
+
+  /* Has no effect yet.  */
+  global.params.pic = flag_pic != 0;
+
+  return false;
+}
+
+/* Return TRUE if an operand OP of a given TYPE being copied has no data.
+   The middle-end does a similar check with zero sized types.  */
+
+static bool
+empty_modify_p (tree type, tree op)
+{
+  tree_code code = TREE_CODE (op);
+  switch (code)
+    {
+    case COMPOUND_EXPR:
+      return empty_modify_p (type, TREE_OPERAND (op, 1));
+
+    case CONSTRUCTOR:
+      /* Non-empty construcors are valid.  */
+      if (CONSTRUCTOR_NELTS (op) != 0 || TREE_CLOBBER_P (op))
+	return false;
+      break;
+
+    case CALL_EXPR:
+      /* Leave nrvo alone because it isn't a copy.  */
+      if (CALL_EXPR_RETURN_SLOT_OPT (op))
+	return false;
+      break;
+
+    default:
+      /* If the operand doesn't have a simple form.  */
+      if (!is_gimple_lvalue (op) && !INDIRECT_REF_P (op))
+	return false;
+      break;
+    }
+
+  return empty_aggregate_p (type);
+}
+
+/* Implements the lang_hooks.gimplify_expr routine for language D.
+   Do gimplification of D specific expression trees in EXPR_P.  */
+
+int
+d_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED,
+		gimple_seq *post_p ATTRIBUTE_UNUSED)
+{
+  tree_code code = TREE_CODE (*expr_p);
+  enum gimplify_status ret = GS_UNHANDLED;
+  tree op0, op1;
+  tree type;
+
+  switch (code)
+    {
+    case INIT_EXPR:
+    case MODIFY_EXPR:
+      op0 = TREE_OPERAND (*expr_p, 0);
+      op1 = TREE_OPERAND (*expr_p, 1);
+
+      if (!error_operand_p (op0) && !error_operand_p (op1)
+	  && (AGGREGATE_TYPE_P (TREE_TYPE (op0))
+	      || AGGREGATE_TYPE_P (TREE_TYPE (op1)))
+	  && !useless_type_conversion_p (TREE_TYPE (op1), TREE_TYPE (op0)))
+	{
+	  /* If the back end isn't clever enough to know that the lhs and rhs
+	     types are the same, add an explicit conversion.  */
+	  TREE_OPERAND (*expr_p, 1) = build1 (VIEW_CONVERT_EXPR,
+					      TREE_TYPE (op0), op1);
+	  ret = GS_OK;
+	}
+      else if (empty_modify_p (TREE_TYPE (op0), op1))
+	{
+	  /* Remove any copies of empty aggregates.  Also drop volatile
+	     loads on the RHS to avoid infinite recursion from
+	     gimplify_expr trying to load the value.  */
+	  gimplify_expr (&TREE_OPERAND (*expr_p, 0), pre_p, post_p,
+			 is_gimple_lvalue, fb_lvalue);
+	  if (TREE_SIDE_EFFECTS (op1))
+	    {
+	      if (TREE_THIS_VOLATILE (op1)
+		  && (REFERENCE_CLASS_P (op1) || DECL_P (op1)))
+		op1 = build_fold_addr_expr (op1);
+
+	      gimplify_and_add (op1, pre_p);
+	    }
+	  *expr_p = TREE_OPERAND (*expr_p, 0);
+	  ret = GS_OK;
+	}
+      break;
+
+    case ADDR_EXPR:
+      op0 = TREE_OPERAND (*expr_p, 0);
+      /* Constructors are not lvalues, so make them one.  */
+      if (TREE_CODE (op0) == CONSTRUCTOR)
+	{
+	  TREE_OPERAND (*expr_p, 0) = build_target_expr (op0);
+	  ret = GS_OK;
+	}
+      break;
+
+    case UNSIGNED_RSHIFT_EXPR:
+      /* Convert op0 to an unsigned type.  */
+      op0 = TREE_OPERAND (*expr_p, 0);
+      op1 = TREE_OPERAND (*expr_p, 1);
+
+      type = d_unsigned_type (TREE_TYPE (op0));
+
+      *expr_p = convert (TREE_TYPE (*expr_p),
+			 build2 (RSHIFT_EXPR, type, convert (type, op0), op1));
+      ret = GS_OK;
+      break;
+
+    case FLOAT_MOD_EXPR:
+    case IASM_EXPR:
+      gcc_unreachable ();
+
+    default:
+      break;
+    }
+
+  return ret;
+}
+
+/* Add the module M to the list of modules that may declare GCC builtins.
+   These are scanned after first semantic and before codegen passes.
+   See d_maybe_set_builtin() for the implementation.  */
+
+void
+d_add_builtin_module (Module *m)
+{
+  builtin_modules.push (m);
+}
+
+/* Record the entrypoint module ENTRY which will be compiled in the current
+   compilation.  ROOT is the module scope where this was requested from.  */
+
+void
+d_add_entrypoint_module (Module *entry, Module *root)
+{
+  /* We are emitting this straight to object file.  */
+  entrypoint_module = entry;
+  entrypoint_root_module = root;
+}
+
+/* Implements the lang_hooks.parse_file routine for language D.  */
+
+void
+d_parse_file (void)
+{
+  if (global.params.verbose)
+    {
+      fprintf (global.stdmsg, "binary    %s\n", global.params.argv0);
+      fprintf (global.stdmsg, "version   %s\n", global.version);
+    }
+
+  /* Start the main input file, if the debug writer wants it.  */
+  if (debug_hooks->start_end_main_source_file)
+    debug_hooks->start_source_file (0, main_input_filename);
+
+  /* Create Module's for all sources we will load.  */
+  Modules modules;
+  modules.reserve (num_in_fnames);
+
+  /* In this mode, the first file name is supposed to be a duplicate
+     of one of the input files.  */
+  if (d_option.fonly && strcmp (d_option.fonly, main_input_filename) != 0)
+    error ("-fonly= argument is different from first input file name");
+
+  for (size_t i = 0; i < num_in_fnames; i++)
+    {
+      if (strcmp (in_fnames[i], "-") == 0)
+	{
+	  /* Handling stdin, generate a unique name for the module.  */
+	  obstack buffer;
+	  gcc_obstack_init (&buffer);
+	  int c;
+
+	  Module *m = Module::create (in_fnames[i],
+				      Identifier::generateId ("__stdin"),
+				      global.params.doDocComments,
+				      global.params.doHdrGeneration);
+	  modules.push (m);
+
+	  /* Load the entire contents of stdin into memory.  */
+	  while ((c = getc (stdin)) != EOF)
+	    obstack_1grow (&buffer, c);
+
+	  if (!obstack_object_size (&buffer))
+	    obstack_1grow (&buffer, '\0');
+
+	  /* Overwrite the source file for the module, the one created by
+	     Module::create would have a forced a `.d' suffix.  */
+	  m->srcfile = File::create ("<stdin>");
+	  m->srcfile->len = obstack_object_size (&buffer);
+	  m->srcfile->buffer = (unsigned char *) obstack_finish (&buffer);
+
+	  /* Tell the front-end not to free the buffer after parsing.  */
+	  m->srcfile->ref = 1;
+	}
+      else
+	{
+	  /* Handling a D source file, strip off the path and extension.  */
+	  const char *basename = FileName::name (in_fnames[i]);
+	  const char *name = FileName::removeExt (basename);
+
+	  Module *m = Module::create (in_fnames[i], Identifier::idPool (name),
+				      global.params.doDocComments,
+				      global.params.doHdrGeneration);
+	  modules.push (m);
+	  FileName::free (name);
+	}
+    }
+
+  /* Read all D source files.  */
+  for (size_t i = 0; i < modules.dim; i++)
+    {
+      Module *m = modules[i];
+      m->read (Loc ());
+    }
+
+  /* Parse all D source files.  */
+  for (size_t i = 0; i < modules.dim; i++)
+    {
+      Module *m = modules[i];
+
+      if (global.params.verbose)
+	fprintf (global.stdmsg, "parse     %s\n", m->toChars ());
+
+      if (!Module::rootModule)
+	Module::rootModule = m;
+
+      m->importedFrom = m;
+      m->parse ();
+      Target::loadModule (m);
+
+      if (m->isDocFile)
+	{
+	  gendocfile (m);
+	  /* Remove M from list of modules.  */
+	  modules.remove (i);
+	  i--;
+	}
+    }
+
+  if (global.errors)
+    goto had_errors;
+
+  if (global.params.doHdrGeneration)
+    {
+      /* Generate 'header' import files.  Since 'header' import files must be
+	 independent of command line switches and what else is imported, they
+	 are generated before any semantic analysis.  */
+      for (size_t i = 0; i < modules.dim; i++)
+	{
+	  Module *m = modules[i];
+	  if (d_option.fonly && m != Module::rootModule)
+	    continue;
+
+	  if (global.params.verbose)
+	    fprintf (global.stdmsg, "import    %s\n", m->toChars ());
+
+	  genhdrfile (m);
+	}
+    }
+
+  if (global.errors)
+    goto had_errors;
+
+  /* Load all unconditional imports for better symbol resolving.  */
+  for (size_t i = 0; i < modules.dim; i++)
+    {
+      Module *m = modules[i];
+
+      if (global.params.verbose)
+	fprintf (global.stdmsg, "importall %s\n", m->toChars ());
+
+      m->importAll (NULL);
+    }
+
+  if (global.errors)
+    goto had_errors;
+
+  /* Do semantic analysis.  */
+  for (size_t i = 0; i < modules.dim; i++)
+    {
+      Module *m = modules[i];
+
+      if (global.params.verbose)
+	fprintf (global.stdmsg, "semantic  %s\n", m->toChars ());
+
+      m->semantic (NULL);
+    }
+
+  /* Do deferred semantic analysis.  */
+  Module::dprogress = 1;
+  Module::runDeferredSemantic ();
+
+  if (Module::deferred.dim)
+    {
+      for (size_t i = 0; i < Module::deferred.dim; i++)
+	{
+	  Dsymbol *sd = Module::deferred[i];
+	  sd->error ("unable to resolve forward reference in definition");
+	}
+    }
+
+  /* Process all built-in modules or functions now for CTFE.  */
+  while (builtin_modules.dim != 0)
+    {
+      Module *m = builtin_modules.pop ();
+      d_maybe_set_builtin (m);
+    }
+
+  /* Do pass 2 semantic analysis.  */
+  for (size_t i = 0; i < modules.dim; i++)
+    {
+      Module *m = modules[i];
+
+      if (global.params.verbose)
+	fprintf (global.stdmsg, "semantic2 %s\n", m->toChars ());
+
+      m->semantic2 (NULL);
+    }
+
+  Module::runDeferredSemantic2 ();
+
+  if (global.errors)
+    goto had_errors;
+
+  /* Do pass 3 semantic analysis.  */
+  for (size_t i = 0; i < modules.dim; i++)
+    {
+      Module *m = modules[i];
+
+      if (global.params.verbose)
+	fprintf (global.stdmsg, "semantic3 %s\n", m->toChars ());
+
+      m->semantic3 (NULL);
+    }
+
+  Module::runDeferredSemantic3 ();
+
+  /* Check again, incase semantic3 pass loaded any more modules.  */
+  while (builtin_modules.dim != 0)
+    {
+      Module *m = builtin_modules.pop ();
+      d_maybe_set_builtin (m);
+    }
+
+  /* Do not attempt to generate output files if errors or warnings occurred.  */
+  if (global.errors || global.warnings)
+    goto had_errors;
+
+  /* Generate output files.  */
+
+  /* Module dependencies (imports, file, version, debug, lib).  */
+  if (global.params.moduleDeps)
+    {
+      OutBuffer *buf = global.params.moduleDeps;
+
+      if (global.params.moduleDepsFile)
+	{
+	  File fdeps (global.params.moduleDepsFile);
+	  fdeps.setbuffer ((void *) buf->data, buf->offset);
+	  fdeps.ref = 1;
+	  writeFile (Loc (), &fdeps);
+	}
+      else
+	fprintf (global.stdmsg, "%.*s", (int) buf->offset, (char *) buf->data);
+    }
+
+  /* Make dependencies.  */
+  if (d_option.deps)
+    {
+      OutBuffer buf;
+
+      for (size_t i = 0; i < modules.dim; i++)
+	deps_write (modules[i], &buf);
+
+      /* -MF <arg> overrides -M[M]D.  */
+      if (d_option.deps_filename_user)
+	d_option.deps_filename = d_option.deps_filename_user;
+
+      if (d_option.deps_filename)
+	{
+	  File fdeps (d_option.deps_filename);
+	  fdeps.setbuffer ((void *) buf.data, buf.offset);
+	  fdeps.ref = 1;
+	  writeFile (Loc (), &fdeps);
+	}
+      else
+	fprintf (global.stdmsg, "%.*s", (int) buf.offset, (char *) buf.data);
+    }
+
+  /* Generate JSON files.  */
+  if (global.params.doJsonGeneration)
+    {
+      OutBuffer buf;
+      json_generate (&buf, &modules);
+
+      const char *name = global.params.jsonfilename;
+
+      if (name && (name[0] != '-' || name[1] != '\0'))
+	{
+	  File fjson (FileName::defaultExt (name, global.json_ext));
+	  fjson.setbuffer ((void *) buf.data, buf.offset);
+	  fjson.ref = 1;
+	  writeFile (Loc (), &fjson);
+	}
+      else
+	fprintf (global.stdmsg, "%.*s", (int) buf.offset, (char *) buf.data);
+    }
+
+  /* Generate Ddoc files.  */
+  if (global.params.doDocComments && !global.errors && !errorcount)
+    {
+      for (size_t i = 0; i < modules.dim; i++)
+	{
+	  Module *m = modules[i];
+	  gendocfile (m);
+	}
+    }
+
+  /* Handle -fdump-d-original.  */
+  if (global.params.vcg_ast)
+    {
+      for (size_t i = 0; i < modules.dim; i++)
+	{
+	  Module *m = modules[i];
+	  OutBuffer buf;
+	  buf.doindent = 1;
+
+	  HdrGenState hgs;
+	  hgs.fullDump = true;
+
+	  toCBuffer (m, &buf, &hgs);
+	  fprintf (global.stdmsg, "%.*s", (int) buf.offset, (char *) buf.data);
+	}
+    }
+
+  for (size_t i = 0; i < modules.dim; i++)
+    {
+      Module *m = modules[i];
+      if (d_option.fonly && m != Module::rootModule)
+	continue;
+
+      if (global.params.verbose)
+	fprintf (global.stdmsg, "code      %s\n", m->toChars ());
+
+      if (!flag_syntax_only)
+	{
+	  if ((entrypoint_module != NULL) && (m == entrypoint_root_module))
+	    build_decl_tree (entrypoint_module);
+
+	  build_decl_tree (m);
+	}
+    }
+
+  /* And end the main input file, if the debug writer wants it.  */
+  if (debug_hooks->start_end_main_source_file)
+    debug_hooks->end_source_file (0);
+
+ had_errors:
+  /* Add the D frontend error count to the GCC error count to correctly
+     exit with an error status.  */
+  errorcount += (global.errors + global.warnings);
+
+  /* Write out globals.  */
+  d_finish_compilation (vec_safe_address (global_declarations),
+			vec_safe_length (global_declarations));
+}
+
+/* Implements the lang_hooks.types.type_for_mode routine for language D.  */
+
+static tree
+d_type_for_mode (machine_mode mode, int unsignedp)
+{
+  if (mode == QImode)
+    return unsignedp ? ubyte_type_node : byte_type_node;
+
+  if (mode == HImode)
+    return unsignedp ? ushort_type_node : short_type_node;
+
+  if (mode == SImode)
+    return unsignedp ? uint_type_node : int_type_node;
+
+  if (mode == DImode)
+    return unsignedp ? ulong_type_node : long_type_node;
+
+  if (mode == TYPE_MODE (cent_type_node))
+    return unsignedp ? ucent_type_node : cent_type_node;
+
+  if (mode == TYPE_MODE (float_type_node))
+    return float_type_node;
+
+  if (mode == TYPE_MODE (double_type_node))
+    return double_type_node;
+
+  if (mode == TYPE_MODE (long_double_type_node))
+    return long_double_type_node;
+
+  if (mode == TYPE_MODE (build_pointer_type (char8_type_node)))
+    return build_pointer_type (char8_type_node);
+
+  if (mode == TYPE_MODE (build_pointer_type (int_type_node)))
+    return build_pointer_type (int_type_node);
+
+  if (COMPLEX_MODE_P (mode))
+    {
+      machine_mode inner_mode;
+      tree inner_type;
+
+      if (mode == TYPE_MODE (complex_float_type_node))
+	return complex_float_type_node;
+      if (mode == TYPE_MODE (complex_double_type_node))
+	return complex_double_type_node;
+      if (mode == TYPE_MODE (complex_long_double_type_node))
+	return complex_long_double_type_node;
+
+      inner_mode = (machine_mode) GET_MODE_INNER (mode);
+      inner_type = d_type_for_mode (inner_mode, unsignedp);
+      if (inner_type != NULL_TREE)
+	return build_complex_type (inner_type);
+    }
+  else if (VECTOR_MODE_P (mode))
+    {
+      machine_mode inner_mode = (machine_mode) GET_MODE_INNER (mode);
+      tree inner_type = d_type_for_mode (inner_mode, unsignedp);
+      if (inner_type != NULL_TREE)
+	return build_vector_type_for_mode (inner_type, mode);
+    }
+
+  return 0;
+}
+
+/* Implements the lang_hooks.types.type_for_size routine for language D.  */
+
+static tree
+d_type_for_size (unsigned bits, int unsignedp)
+{
+  if (bits <= TYPE_PRECISION (byte_type_node))
+    return unsignedp ? ubyte_type_node : byte_type_node;
+
+  if (bits <= TYPE_PRECISION (short_type_node))
+    return unsignedp ? ushort_type_node : short_type_node;
+
+  if (bits <= TYPE_PRECISION (int_type_node))
+    return unsignedp ? uint_type_node : int_type_node;
+
+  if (bits <= TYPE_PRECISION (long_type_node))
+    return unsignedp ? ulong_type_node : long_type_node;
+
+  if (bits <= TYPE_PRECISION (cent_type_node))
+    return unsignedp ? ucent_type_node : cent_type_node;
+
+  return 0;
+}
+
+/* Return the signed or unsigned version of TYPE, an integral type, the
+   signedness being specified by UNSIGNEDP.  */
+
+static tree
+d_signed_or_unsigned_type (int unsignedp, tree type)
+{
+  if (TYPE_UNSIGNED (type) == (unsigned) unsignedp)
+    return type;
+
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (cent_type_node))
+    return unsignedp ? ucent_type_node : cent_type_node;
+
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (long_type_node))
+    return unsignedp ? ulong_type_node : long_type_node;
+
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (int_type_node))
+    return unsignedp ? uint_type_node : int_type_node;
+
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (short_type_node))
+    return unsignedp ? ushort_type_node : short_type_node;
+
+  if (TYPE_PRECISION (type) == TYPE_PRECISION (byte_type_node))
+    return unsignedp ? ubyte_type_node : byte_type_node;
+
+  return signed_or_unsigned_type_for (unsignedp, type);
+}
+
+/* Return the unsigned version of TYPE, an integral type.  */
+
+tree
+d_unsigned_type (tree type)
+{
+  return d_signed_or_unsigned_type (1, type);
+}
+
+/* Return the signed version of TYPE, an integral type.  */
+
+tree
+d_signed_type (tree type)
+{
+  return d_signed_or_unsigned_type (0, type);
+}
+
+/* Implements the lang_hooks.types.type_promotes_to routine for language D.
+   All promotions for variable arguments are handled by the D frontend.  */
+
+static tree
+d_type_promotes_to (tree type)
+{
+  return type;
+}
+
+/* Implements the lang_hooks.decls.global_bindings_p routine for language D.
+   Return true if we are in the global binding level.  */
+
+static bool
+d_global_bindings_p (void)
+{
+  return (current_binding_level == global_binding_level);
+}
+
+/* Return global_context, but create it first if need be.  */
+
+static tree
+get_global_context (void)
+{
+  if (!global_context)
+    {
+      global_context = build_translation_unit_decl (NULL_TREE);
+      debug_hooks->register_main_translation_unit (global_context);
+    }
+
+  return global_context;
+}
+
+/* Implements the lang_hooks.decls.pushdecl routine for language D.
+   Record DECL as belonging to the current lexical scope.  */
+
+tree
+d_pushdecl (tree decl)
+{
+  /* Set the context of the decl.  If current_function_decl did not help in
+     determining the context, use global scope.  */
+  if (!DECL_CONTEXT (decl))
+    {
+      if (current_function_decl)
+	DECL_CONTEXT (decl) = current_function_decl;
+      else
+	DECL_CONTEXT (decl) = get_global_context ();
+    }
+
+  /* Put decls on list in reverse order.  */
+  if (TREE_STATIC (decl) || d_global_bindings_p ())
+    vec_safe_push (global_declarations, decl);
+  else
+    {
+      TREE_CHAIN (decl) = current_binding_level->names;
+      current_binding_level->names = decl;
+    }
+
+  return decl;
+}
+
+/* Implements the lang_hooks.decls.getdecls routine for language D.
+   Return the list of declarations of the current level.  */
+
+static tree
+d_getdecls (void)
+{
+  if (current_binding_level)
+    return current_binding_level->names;
+
+  return NULL_TREE;
+}
+
+
+/* Implements the lang_hooks.get_alias_set routine for language D.
+   Get the alias set corresponding the type or expression T.
+   Return -1 if we don't do anything special.  */
+
+static alias_set_type
+d_get_alias_set (tree t)
+{
+  /* Permit type-punning when accessing a union, provided the access
+     is directly through the union.  */
+  for (tree u = t; handled_component_p (u); u = TREE_OPERAND (u, 0))
+    {
+      if (TREE_CODE (u) == COMPONENT_REF
+	  && TREE_CODE (TREE_TYPE (TREE_OPERAND (u, 0))) == UNION_TYPE)
+	return 0;
+    }
+
+  /* That's all the expressions we handle.  */
+  if (!TYPE_P (t))
+    return get_alias_set (TREE_TYPE (t));
+
+  /* For now in D, assume everything aliases everything else,
+     until we define some solid rules.  */
+  return 0;
+}
+
+/* Implements the lang_hooks.types_compatible_p routine for language D.
+   Compares two types for equivalence in the D programming language.
+   This routine should only return 1 if it is sure, even though the frontend
+   should have already ensured that all types are compatible before handing
+   over the parsed ASTs to the code generator.  */
+
+static int
+d_types_compatible_p (tree x, tree y)
+{
+  Type *tx = TYPE_LANG_FRONTEND (x);
+  Type *ty = TYPE_LANG_FRONTEND (y);
+
+  /* Try validating the types in the frontend first.  */
+  if (tx != NULL && ty != NULL)
+    {
+      if (tx->implicitConvTo (ty) || ty->implicitConvTo (tx))
+	return true;
+    }
+
+  /* Fallback on using type kind and size comparison.  E.g: all dynamic arrays
+     are distinct types in D, but are VIEW_CONVERT compatible.  */
+  return (TREE_CODE (x) == TREE_CODE (y)
+	  && TYPE_SIZE (x) == TYPE_SIZE (y));
+}
+
+/* Implements the lang_hooks.finish_incomplete_decl routine for language D.  */
+
+static void
+d_finish_incomplete_decl (tree decl)
+{
+  if (VAR_P (decl))
+    {
+      /* D allows zero-length declarations.  Such a declaration ends up with
+	 DECL_SIZE (t) == NULL_TREE which is what the backend function
+	 assembler_variable checks.  This could change in later versions, or
+	 maybe all of these variables should be aliased to one symbol. */
+      if (DECL_SIZE (decl) == 0)
+	{
+	  DECL_SIZE (decl) = bitsize_zero_node;
+	  DECL_SIZE_UNIT (decl) = size_zero_node;
+	}
+    }
+}
+
+/* Implements the lang_hooks.types.classify_record routine for language D.
+   Return the true debug type for TYPE.  */
+
+static classify_record
+d_classify_record (tree type)
+{
+  Type *t = TYPE_LANG_FRONTEND (type);
+
+  if (t && t->ty == Tclass)
+    {
+      TypeClass *tc = (TypeClass *) t;
+
+      /* extern(C++) interfaces get emitted as classes.  */
+      if (tc->sym->isInterfaceDeclaration ()
+	  && !tc->sym->isCPPinterface ())
+	return RECORD_IS_INTERFACE;
+
+      return RECORD_IS_CLASS;
+    }
+
+  return RECORD_IS_STRUCT;
+}
+
+/* Implements the lang_hooks.tree_size routine for language D.
+   Determine the size of our tcc_constant or tcc_exceptional nodes.  */
+
+static size_t
+d_tree_size (tree_code code)
+{
+  switch (code)
+    {
+    case FUNCFRAME_INFO:
+      return sizeof (tree_frame_info);
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Implements the lang_hooks.print_xnode routine for language D.  */
+
+static void
+d_print_xnode (FILE *file, tree node, int indent)
+{
+  switch (TREE_CODE (node))
+    {
+    case FUNCFRAME_INFO:
+      print_node (file, "frame_type", FRAMEINFO_TYPE (node), indent + 4);
+      break;
+
+    default:
+      break;
+    }
+}
+
+/* Return which tree structure is used by NODE, or TS_D_GENERIC if NODE
+   is one of the language-independent trees.  */
+
+d_tree_node_structure_enum
+d_tree_node_structure (lang_tree_node *t)
+{
+  switch (TREE_CODE (&t->generic))
+    {
+    case IDENTIFIER_NODE:
+      return TS_D_IDENTIFIER;
+
+    case FUNCFRAME_INFO:
+      return TS_D_FRAMEINFO;
+
+    default:
+      return TS_D_GENERIC;
+    }
+}
+
+/* Allocate and return a lang specific structure for the frontend type.  */
+
+struct lang_type *
+build_lang_type (Type *t)
+{
+  struct lang_type *lt = ggc_cleared_alloc<struct lang_type> ();
+  lt->type = t;
+  return lt;
+}
+
+/* Allocate and return a lang specific structure for the frontend decl.  */
+
+struct lang_decl *
+build_lang_decl (Declaration *d)
+{
+  struct lang_decl *ld = ggc_cleared_alloc<struct lang_decl> ();
+  ld->decl = d;
+  return ld;
+}
+
+/* Implements the lang_hooks.dup_lang_specific_decl routine for language D.
+   Replace the DECL_LANG_SPECIFIC field of NODE with a copy.  */
+
+static void
+d_dup_lang_specific_decl (tree node)
+{
+  if (! DECL_LANG_SPECIFIC (node))
+    return;
+
+  struct lang_decl *ld = ggc_alloc<struct lang_decl> ();
+  memcpy (ld, DECL_LANG_SPECIFIC (node), sizeof (struct lang_decl));
+  DECL_LANG_SPECIFIC (node) = ld;
+}
+
+/* This preserves trees we create from the garbage collector.  */
+
+static GTY(()) tree d_keep_list = NULL_TREE;
+
+void
+d_keep (tree t)
+{
+  d_keep_list = tree_cons (NULL_TREE, t, d_keep_list);
+}
+
+/* Implements the lang_hooks.eh_personality routine for language D.
+   Return the GDC personality function decl.  */
+
+static GTY(()) tree d_eh_personality_decl;
+
+static tree
+d_eh_personality (void)
+{
+  if (!d_eh_personality_decl)
+    {
+      d_eh_personality_decl
+	= build_personality_function ("gdc");
+    }
+  return d_eh_personality_decl;
+}
+
+/* Implements the lang_hooks.eh_runtime_type routine for language D.  */
+
+static tree
+d_build_eh_runtime_type (tree type)
+{
+  Type *t = TYPE_LANG_FRONTEND (type);
+
+  if (t != NULL)
+    t = t->toBasetype ();
+
+  gcc_assert (t != NULL && t->ty == Tclass);
+  ClassDeclaration *cd = ((TypeClass *) t)->sym;
+  tree decl;
+
+  if (cd->cpp)
+    decl = get_cpp_typeinfo_decl (cd);
+  else
+    decl = get_classinfo_decl (cd);
+
+  return convert (ptr_type_node, build_address (decl));
+}
+
+/* Definitions for our language-specific hooks.  */
+
+#undef LANG_HOOKS_NAME
+#undef LANG_HOOKS_INIT
+#undef LANG_HOOKS_INIT_TS
+#undef LANG_HOOKS_INIT_OPTIONS
+#undef LANG_HOOKS_INIT_OPTIONS_STRUCT
+#undef LANG_HOOKS_OPTION_LANG_MASK
+#undef LANG_HOOKS_HANDLE_OPTION
+#undef LANG_HOOKS_POST_OPTIONS
+#undef LANG_HOOKS_PARSE_FILE
+#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
+#undef LANG_HOOKS_ATTRIBUTE_TABLE
+#undef LANG_HOOKS_GET_ALIAS_SET
+#undef LANG_HOOKS_TYPES_COMPATIBLE_P
+#undef LANG_HOOKS_BUILTIN_FUNCTION
+#undef LANG_HOOKS_REGISTER_BUILTIN_TYPE
+#undef LANG_HOOKS_FINISH_INCOMPLETE_DECL
+#undef LANG_HOOKS_GIMPLIFY_EXPR
+#undef LANG_HOOKS_CLASSIFY_RECORD
+#undef LANG_HOOKS_TREE_SIZE
+#undef LANG_HOOKS_PRINT_XNODE
+#undef LANG_HOOKS_DUP_LANG_SPECIFIC_DECL
+#undef LANG_HOOKS_EH_PERSONALITY
+#undef LANG_HOOKS_EH_RUNTIME_TYPE
+#undef LANG_HOOKS_PUSHDECL
+#undef LANG_HOOKS_GETDECLS
+#undef LANG_HOOKS_GLOBAL_BINDINGS_P
+#undef LANG_HOOKS_TYPE_FOR_MODE
+#undef LANG_HOOKS_TYPE_FOR_SIZE
+#undef LANG_HOOKS_TYPE_PROMOTES_TO
+
+#define LANG_HOOKS_NAME			    "GNU D"
+#define LANG_HOOKS_INIT			    d_init
+#define LANG_HOOKS_INIT_TS		    d_init_ts
+#define LANG_HOOKS_INIT_OPTIONS		    d_init_options
+#define LANG_HOOKS_INIT_OPTIONS_STRUCT	    d_init_options_struct
+#define LANG_HOOKS_OPTION_LANG_MASK	    d_option_lang_mask
+#define LANG_HOOKS_HANDLE_OPTION	    d_handle_option
+#define LANG_HOOKS_POST_OPTIONS		    d_post_options
+#define LANG_HOOKS_PARSE_FILE		    d_parse_file
+#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE   d_langhook_common_attribute_table
+#define LANG_HOOKS_ATTRIBUTE_TABLE          d_langhook_attribute_table
+#define LANG_HOOKS_GET_ALIAS_SET	    d_get_alias_set
+#define LANG_HOOKS_TYPES_COMPATIBLE_P	    d_types_compatible_p
+#define LANG_HOOKS_BUILTIN_FUNCTION	    d_builtin_function
+#define LANG_HOOKS_REGISTER_BUILTIN_TYPE    d_register_builtin_type
+#define LANG_HOOKS_FINISH_INCOMPLETE_DECL   d_finish_incomplete_decl
+#define LANG_HOOKS_GIMPLIFY_EXPR	    d_gimplify_expr
+#define LANG_HOOKS_CLASSIFY_RECORD	    d_classify_record
+#define LANG_HOOKS_TREE_SIZE		    d_tree_size
+#define LANG_HOOKS_PRINT_XNODE		    d_print_xnode
+#define LANG_HOOKS_DUP_LANG_SPECIFIC_DECL   d_dup_lang_specific_decl
+#define LANG_HOOKS_EH_PERSONALITY	    d_eh_personality
+#define LANG_HOOKS_EH_RUNTIME_TYPE	    d_build_eh_runtime_type
+#define LANG_HOOKS_PUSHDECL		    d_pushdecl
+#define LANG_HOOKS_GETDECLS		    d_getdecls
+#define LANG_HOOKS_GLOBAL_BINDINGS_P	    d_global_bindings_p
+#define LANG_HOOKS_TYPE_FOR_MODE	    d_type_for_mode
+#define LANG_HOOKS_TYPE_FOR_SIZE	    d_type_for_size
+#define LANG_HOOKS_TYPE_PROMOTES_TO	    d_type_promotes_to
+
+struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
+
+#include "gt-d-d-lang.h"
+#include "gtype-d.h"
diff --git a/gcc/d/d-longdouble.cc b/gcc/d/d-longdouble.cc
new file mode 100644
index 00000000000..2193a512644
--- /dev/null
+++ b/gcc/d/d-longdouble.cc
@@ -0,0 +1,308 @@
+/* d-longdouble.cc -- Software floating point emulation for the frontend.
+   Copyright (C) 2006-2017 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 "dfrontend/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+#include "longdouble.h"
+
+
+/* Constant real values 0, 1, -1 and 0.5.  */
+real_t CTFloat::zero;
+real_t CTFloat::one;
+real_t CTFloat::minusone;
+real_t CTFloat::half;
+
+
+/* Return conversion of signed integer value D to longdouble.
+   Conversion is done at precision mode of TYPE.  */
+
+longdouble
+longdouble::from_int (Type *type, int64_t d)
+{
+  tree t = build_ctype (type);
+  real_from_integer (&this->rv (), TYPE_MODE (t), d, SIGNED);
+  return *this;
+}
+
+/* Return conversion of unsigned integer value D to longdouble.
+   Conversion is done at precision mode of TYPE.  */
+
+longdouble
+longdouble::from_uint (Type *type, uint64_t d)
+{
+  tree t = build_ctype (type);
+  real_from_integer (&this->rv (), TYPE_MODE (t), d, UNSIGNED);
+  return *this;
+}
+
+/* Return conversion of longdouble value to int64_t.
+   Conversion is done at precision mode of TYPE.  */
+
+int64_t
+longdouble::to_int (Type *type) const
+{
+  if (REAL_VALUE_ISNAN (this->rv ()))
+    return 0;
+
+  tree t = fold_build1 (FIX_TRUNC_EXPR, build_ctype (type),
+		       build_float_cst (*this, Type::tfloat64));
+  return TREE_INT_CST_LOW (t);
+}
+
+/* Same as longdouble::to_int, but returns a uint64_t.  */
+
+uint64_t
+longdouble::to_uint (Type *type) const
+{
+  return (uint64_t) to_int (type);
+}
+
+/* Conversion routines between longdouble and real_value.  */
+
+void
+longdouble::set (real_value& d)
+{
+  real_convert (&this->rv (), TYPE_MODE (long_double_type_node), &d);
+}
+
+longdouble::operator
+real_value& (void)
+{
+  return this->rv ();
+}
+
+/* Conversion routines between longdouble and integer types.  */
+
+void
+longdouble::set (int8_t d)
+{
+  from_int (Type::tfloat32, d);
+}
+
+void
+longdouble::set (int16_t d)
+{
+  from_int (Type::tfloat32, d);
+}
+
+void
+longdouble::set (int32_t d)
+{
+  from_int (Type::tfloat64, d);
+}
+
+void
+longdouble::set (int64_t d)
+{
+  from_int (Type::tfloat80, d);
+}
+
+longdouble::operator int8_t (void)
+{
+  return to_int (Type::tint8);
+}
+
+longdouble::operator int16_t (void)
+{
+  return to_int (Type::tint16);
+}
+
+longdouble::operator int32_t (void)
+{
+  return to_int (Type::tint32);
+}
+
+longdouble::operator int64_t (void)
+{
+  return to_int (Type::tint64);
+}
+
+/* Unsigned variants of the same conversion routines.  */
+
+void
+longdouble::set (uint8_t d)
+{
+  from_uint (Type::tfloat32, d);
+}
+
+void
+longdouble::set (uint16_t d)
+{
+  from_uint (Type::tfloat32, d);
+}
+
+void
+longdouble::set (uint32_t d)
+{
+  from_uint (Type::tfloat64, d);
+}
+
+void
+longdouble::set (uint64_t d)
+{
+  from_uint (Type::tfloat80, d);
+}
+
+longdouble::operator uint8_t (void)
+{
+  return to_uint (Type::tuns8);
+}
+
+longdouble::operator uint16_t (void)
+{
+  return to_uint (Type::tuns16);
+}
+
+longdouble::operator uint32_t (void)
+{
+  return to_uint (Type::tuns32);
+}
+
+longdouble::operator uint64_t (void)
+{
+  return to_uint (Type::tuns64);
+}
+
+/* For conversion between boolean, only need to check if is zero.  */
+
+void
+longdouble::set (bool d)
+{
+  this->rv () = (d == false) ? dconst0 : dconst1;
+}
+
+longdouble::operator
+bool (void)
+{
+  return this->rv ().cl != rvc_zero;
+}
+
+/* Overload numeric operators for longdouble types.  */
+
+longdouble
+longdouble::operator + (const longdouble& r)
+{
+  real_value x;
+  real_arithmetic (&x, PLUS_EXPR, &this->rv (), &r.rv ());
+  return ldouble (x);
+}
+
+longdouble
+longdouble::operator - (const longdouble& r)
+{
+  real_value x;
+  real_arithmetic (&x, MINUS_EXPR, &this->rv (), &r.rv ());
+  return ldouble (x);
+}
+
+longdouble
+longdouble::operator * (const longdouble& r)
+{
+  real_value x;
+  real_arithmetic (&x, MULT_EXPR, &this->rv (), &r.rv ());
+  return ldouble (x);
+}
+
+longdouble
+longdouble::operator / (const longdouble& r)
+{
+  real_value x;
+  real_arithmetic (&x, RDIV_EXPR, &this->rv (), &r.rv ());
+  return ldouble (x);
+}
+
+longdouble
+longdouble::operator % (const longdouble& r)
+{
+  real_value q, x;
+
+  if (r.rv ().cl == rvc_zero || REAL_VALUE_ISINF (this->rv ()))
+    {
+      real_value rvt;
+      real_nan (&rvt, "", 1, TYPE_MODE (long_double_type_node));
+      return ldouble (rvt);
+    }
+
+  if (this->rv ().cl == rvc_zero)
+    return *this;
+
+  if (REAL_VALUE_ISINF (r.rv ()))
+    return *this;
+
+  /* Need to check for NaN?  */
+  real_arithmetic (&q, RDIV_EXPR, &this->rv (), &r.rv ());
+  real_arithmetic (&q, FIX_TRUNC_EXPR, &q, NULL);
+  real_arithmetic (&q, MULT_EXPR, &q, &r.rv ());
+  real_arithmetic (&x, MINUS_EXPR, &this->rv (), &q);
+
+  return ldouble (x);
+}
+
+longdouble
+longdouble::operator -(void)
+{
+  real_value x = real_value_negate (&this->rv ());
+  return ldouble (x);
+}
+
+/* Overload equality operators for longdouble types.  */
+
+bool
+longdouble::operator < (const longdouble& r)
+{
+  return real_compare (LT_EXPR, &this->rv (), &r.rv ());
+}
+
+bool
+longdouble::operator > (const longdouble& r)
+{
+  return real_compare (GT_EXPR, &this->rv (), &r.rv ());
+}
+
+bool
+longdouble::operator <= (const longdouble& r)
+{
+  return real_compare (LE_EXPR, &this->rv (), &r.rv ());
+}
+
+bool
+longdouble::operator >= (const longdouble& r)
+{
+  return real_compare (GE_EXPR, &this->rv (), &r.rv ());
+}
+
+bool
+longdouble::operator == (const longdouble& r)
+{
+  return real_compare (EQ_EXPR, &this->rv (), &r.rv ());
+}
+
+bool
+longdouble::operator != (const longdouble& r)
+{
+  return real_compare (NE_EXPR, &this->rv (), &r.rv ());
+}
diff --git a/gcc/d/d-spec.c b/gcc/d/d-spec.c
new file mode 100644
index 00000000000..0c93f9d3e35
--- /dev/null
+++ b/gcc/d/d-spec.c
@@ -0,0 +1,461 @@
+/* d-spec.c -- Specific flags and argument handling of the D front end.
+   Copyright (C) 2006-2017 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 "gcc.h"
+#include "tm.h"
+#include "opts.h"
+
+/* This bit is set if the arguments is a D source file. */
+#define DSOURCE		(1<<1)
+/* this bit is set if they did `-lstdc++'.  */
+#define WITHLIBCXX	(1<<2)
+/* Skip this option.  */
+#define SKIPOPT		(1<<3)
+
+#ifndef LIBSTDCXX
+#define LIBSTDCXX "stdc++"
+#endif
+#ifndef LIBSTDCXX_PROFILE
+#define LIBSTDCXX_PROFILE LIBSTDCXX
+#endif
+
+#ifndef LIBPHOBOS
+#define LIBPHOBOS "gphobos"
+#endif
+#ifndef LIBPHOBOS_PROFILE
+#define LIBPHOBOS_PROFILE LIBPHOBOS
+#endif
+
+#ifndef LIBDRUNTIME
+#define LIBDRUNTIME "gdruntime"
+#endif
+#ifndef LIBDRUNTIME_PROFILE
+#define LIBDRUNTIME_PROFILE LIBDRUNTIME
+#endif
+
+/* What do with libgphobos:
+   -1 means we should not link in libgphobos
+   0  means we should link in libgphobos if it is needed
+   1  means libgphobos is needed and should be linked in.
+   2  means libgphobos is needed and should be linked statically.
+   3  means libgphobos is needed and should be linked dynamically. */
+static int library = 0;
+
+/* If true, use the standard D runtime library when linking with
+   standard libraries. */
+static bool need_phobos = true;
+
+void
+lang_specific_driver (cl_decoded_option **in_decoded_options,
+		      unsigned int *in_decoded_options_count,
+		      int *in_added_libraries)
+{
+  unsigned int i, j;
+
+  /* If nonzero, the user gave us the `-p' or `-pg' flag.  */
+  int saw_profile_flag = 0;
+
+  /* If true, the user gave `-g'.  Used by -debuglib */
+  bool saw_debug_flag = false;
+
+  /* The new argument list will be contained in this.  */
+  cl_decoded_option *new_decoded_options;
+
+  /* "-lstdc++" if it appears on the command line.  */
+  const cl_decoded_option *saw_libcxx = 0;
+
+  /* Whether we need the C++ STD library.  */
+  bool need_stdcxx = false;
+
+  /* True if we saw -static. */
+  bool static_link = false;
+
+  /* True if we should add -shared-libgcc to the command-line.  */
+  bool shared_libgcc = true;
+
+  /* What default library to use instead of phobos */
+  const char *defaultlib = NULL;
+
+  /* What debug library to use instead of phobos */
+  const char *debuglib = NULL;
+
+  /* The total number of arguments with the new stuff.  */
+  unsigned int num_args = 1;
+
+  /* "-fonly" if it appears on the command line.  */
+  const char *only_source_option = 0;
+
+  /* Whether the -o option was used.  */
+  bool saw_opt_o = false;
+
+  /* The first input file with an extension of .d.  */
+  const char *first_d_file = NULL;
+
+  /* The total number of arguments with the new stuff.  */
+  unsigned int argc = *in_decoded_options_count;
+
+  /* The argument list.  */
+  cl_decoded_option *decoded_options = *in_decoded_options;
+
+  /* The number of libraries added in.  */
+  int added_libraries = *in_added_libraries;
+
+  /* An array used to flag each argument that needs a bit set for
+     DSOURCE, MATHLIB, WITHTHREAD, WITHLIBC or WITHLIBCXX.  */
+  int *args = XCNEWVEC (int, argc);
+
+  for (i = 1; i < argc; i++)
+    {
+      const char *arg = decoded_options[i].arg;
+
+      switch (decoded_options[i].opt_index)
+	{
+	case OPT_nostdlib:
+	case OPT_nodefaultlibs:
+	  library = -1;
+	  break;
+
+	case OPT_nophoboslib:
+	  need_phobos = false;
+	  args[i] |= SKIPOPT;
+	  break;
+
+	case OPT_defaultlib_:
+	  if (defaultlib != NULL)
+	    free (CONST_CAST (char *, defaultlib));
+	  if (arg != NULL)
+	    {
+	      need_phobos = false;
+	      args[i] |= SKIPOPT;
+	      defaultlib = XNEWVEC (char, strlen (arg));
+	      strcpy (CONST_CAST (char *, defaultlib), arg);
+	    }
+	  break;
+
+	case OPT_debuglib_:
+	  if (debuglib != NULL)
+	    free (CONST_CAST (char *, debuglib));
+	  if (arg != NULL)
+	    {
+	      need_phobos = false;
+	      args[i] |= SKIPOPT;
+	      debuglib = XNEWVEC (char, strlen (arg));
+	      strcpy (CONST_CAST (char *, debuglib), arg);
+	    }
+	  break;
+
+	case OPT_l:
+	  if ((strcmp (arg, LIBSTDCXX) == 0)
+	      || (strcmp (arg, LIBSTDCXX_PROFILE) == 0))
+	    {
+	      args[i] |= WITHLIBCXX;
+	      need_stdcxx = false;
+	    }
+	  else
+	    /* Unrecognized libraries (e.g. -ltango) may require libphobos.  */
+	    library = (library == 0) ? 1 : library;
+	  break;
+
+	case OPT_pg:
+	case OPT_p:
+	  saw_profile_flag++;
+	  break;
+
+	case OPT_g:
+	  saw_debug_flag = true;
+	  break;
+
+	case OPT_v:
+	  /* If they only gave us `-v', don't try to link in libphobos.  */
+	  if (argc == 2)
+	    library = 0;
+	  break;
+
+	case OPT_x:
+	  if (library == 0
+	      && (strcmp (arg, "d") == 0))
+	    library = 1;
+	  break;
+
+	case OPT_Xlinker:
+	case OPT_Wl_:
+	  /* Arguments that go directly to the linker might be .o files
+	     or something, and so might cause libphobos to be needed.  */
+	  if (library == 0)
+	    library = 1;
+	  break;
+
+	case OPT_c:
+	case OPT_S:
+	case OPT_E:
+	case OPT_M:
+	case OPT_MM:
+	case OPT_fsyntax_only:
+	  /* Don't specify libaries if we won't link, since that would
+	     cause a warning.  */
+	  library = -1;
+	  break;
+
+	case OPT_o:
+	  saw_opt_o = true;
+	  break;
+
+	case OPT_static:
+	  static_link = true;
+	  break;
+
+	case OPT_static_libgcc:
+	  shared_libgcc = false;
+	  break;
+
+	case OPT_static_libphobos:
+	  library = library >= 0 ? 2 : library;
+	  args[i] |= SKIPOPT;
+	  break;
+
+	case OPT_shared_libphobos:
+	  library = library >= 0 ? 3 : library;
+	  args[i] |= SKIPOPT;
+	  break;
+
+	case OPT_fonly_:
+	  args[i] |= SKIPOPT;
+	  only_source_option = decoded_options[i].orig_option_with_args_text;
+
+	  if (arg != NULL)
+	    {
+	      int len = strlen (only_source_option);
+	      if (len <= 2 || only_source_option[len-1] != 'd'
+		  || only_source_option[len-2] != '.')
+		only_source_option = concat (only_source_option, ".d", NULL);
+	    }
+	  break;
+
+	case OPT_SPECIAL_input_file:
+	    {
+	      if (arg[0] == '\0' || arg[1] == '\0')
+		continue;
+
+	      /* Record that this is a D source file.  */
+	      int len = strlen (arg);
+	      if (len <= 2 || strcmp (arg + len - 2, ".d") == 0)
+		{
+		  if (first_d_file == NULL)
+		    first_d_file = arg;
+
+		  args[i] |= DSOURCE;
+		}
+
+	      /* If we don't know that this is a interface file, we might
+		 need to link against libphobos library.  */
+	      if (library == 0)
+		{
+		  if (len <= 3 || strcmp (arg + len - 3, ".di") != 0)
+		    library = 1;
+		}
+
+	      /* If this is a C++ source file, we'll need to link
+		 against libstdc++ library.  */
+	      if ((len <= 3 || strcmp (arg + len - 3, ".cc") == 0)
+		  || (len <= 4 || strcmp (arg + len - 4, ".cpp") == 0)
+		  || (len <= 4 || strcmp (arg + len - 4, ".c++") == 0))
+		need_stdcxx = true;
+
+	      break;
+	    }
+	}
+    }
+
+  /* There's no point adding -shared-libgcc if we don't have a shared
+     libgcc.  */
+#ifndef ENABLE_SHARED_LIBGCC
+  shared_libgcc = false;
+#endif
+
+  /* Make sure to have room for the trailing NULL argument.
+     - needstdcxx might add `-lstdcxx'
+     - libphobos adds `-Bstatic -lphobos -ldruntime -Bdynamic'
+     - only_source adds 1 more arg, also maybe add `-o'.  */
+  num_args = argc + need_stdcxx + shared_libgcc + (library > 0) * 4 + 2;
+  new_decoded_options = XNEWVEC (cl_decoded_option, num_args);
+
+  i = 0;
+  j = 0;
+
+  /* Copy the 0th argument, i.e., the name of the program itself.  */
+  new_decoded_options[j++] = decoded_options[i++];
+
+  /* NOTE: We start at 1 now, not 0.  */
+  while (i < argc)
+    {
+      if (args[i] & SKIPOPT)
+	{
+	  ++i;
+	  continue;
+	}
+
+      new_decoded_options[j] = decoded_options[i];
+
+      if (!saw_libcxx && (args[i] & WITHLIBCXX) && library > 0)
+	{
+	  --j;
+	  saw_libcxx = &decoded_options[i];
+	}
+
+      if (args[i] & DSOURCE)
+	{
+	  if (only_source_option)
+	    --j;
+	}
+
+      i++;
+      j++;
+    }
+
+  if (only_source_option)
+    {
+      const char *only_source_arg = only_source_option + 7;
+      generate_option (OPT_fonly_, only_source_arg, 1, CL_DRIVER,
+		       &new_decoded_options[j]);
+      j++;
+
+      generate_option_input_file (only_source_arg,
+				  &new_decoded_options[j++]);
+    }
+
+  /* If we are not linking, add a -o option.  This is because we need
+     the driver to pass all .d files to cc1d.  Without a -o option the
+     driver will invoke cc1d separately for each input file.  */
+  if (library < 0 && first_d_file != NULL && !saw_opt_o)
+    {
+      const char *base = lbasename (first_d_file);
+      int baselen = strlen (base) - 2;
+      int alen = baselen + 3;
+      char *out = XNEWVEC (char, alen);
+
+      memcpy (out, base, baselen);
+
+      /* The driver will convert .o to some other suffix if appropriate.  */
+      out[baselen] = '.';
+      out[baselen + 1] = 'o';
+      out[baselen + 2] = '\0';
+      generate_option (OPT_o, out, 1, CL_DRIVER,
+		       &new_decoded_options[j]);
+      j++;
+    }
+
+  /* Add `-lgphobos' if we haven't already done so.  */
+  if (library > 0 && need_phobos)
+    {
+      /* Default to static linking.  */
+      if (library == 1)
+        library = 2;
+
+#ifdef HAVE_LD_STATIC_DYNAMIC
+      if (library == 3 && static_link)
+	{
+	  generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER,
+			   &new_decoded_options[j]);
+	  j++;
+	}
+      else if (library == 2 && !static_link)
+	{
+	  generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER,
+			   &new_decoded_options[j]);
+	  j++;
+	}
+#endif
+
+      generate_option (OPT_l,
+		       saw_profile_flag ? LIBPHOBOS_PROFILE : LIBPHOBOS, 1,
+		       CL_DRIVER, &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+      generate_option (OPT_l,
+		       saw_profile_flag ? LIBDRUNTIME_PROFILE : LIBDRUNTIME, 1,
+		       CL_DRIVER, &new_decoded_options[j]);
+      added_libraries++;
+      j++;
+
+#ifdef HAVE_LD_STATIC_DYNAMIC
+      if (library == 3 && static_link)
+	{
+	  generate_option (OPT_Wl_, LD_STATIC_OPTION, 1, CL_DRIVER,
+			   &new_decoded_options[j]);
+	  j++;
+	}
+      else if (library == 2 && !static_link)
+	{
+	  generate_option (OPT_Wl_, LD_DYNAMIC_OPTION, 1, CL_DRIVER,
+			   &new_decoded_options[j]);
+	  j++;
+	}
+#endif
+    }
+  else if (saw_debug_flag && debuglib)
+    {
+      generate_option (OPT_l, debuglib, 1, CL_DRIVER,
+		       &new_decoded_options[j++]);
+      added_libraries++;
+    }
+  else if (defaultlib)
+    {
+      generate_option (OPT_l, defaultlib, 1, CL_DRIVER,
+		       &new_decoded_options[j++]);
+      added_libraries++;
+    }
+
+  if (saw_libcxx)
+    new_decoded_options[j++] = *saw_libcxx;
+  else if (library > 0 && need_stdcxx)
+    {
+      generate_option (OPT_l,
+		       (saw_profile_flag
+			? LIBSTDCXX_PROFILE
+			: LIBSTDCXX),
+		       1, CL_DRIVER, &new_decoded_options[j++]);
+      added_libraries++;
+    }
+
+  if (shared_libgcc && !static_link)
+    {
+      generate_option (OPT_shared_libgcc, NULL, 1, CL_DRIVER,
+		       &new_decoded_options[j++]);
+    }
+
+  *in_decoded_options_count = j;
+  *in_decoded_options = new_decoded_options;
+  *in_added_libraries = added_libraries;
+}
+
+/* Called before linking.  Returns 0 on success and -1 on failure.  */
+
+int lang_specific_pre_link (void)
+{
+  if (library > 0 && need_phobos)
+    do_spec ("%:include(libgphobos.spec)");
+
+  return 0;
+}
+
+/* Number of extra output files that lang_specific_pre_link may generate.  */
+
+int lang_specific_extra_outfiles = 0;  /* Not used for D.  */
+
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
new file mode 100644
index 00000000000..8700547e936
--- /dev/null
+++ b/gcc/d/d-target.cc
@@ -0,0 +1,408 @@
+/* d-target.cc -- Target interface for the D frontend.
+   Copyright (C) 2013-2017 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 "dfrontend/module.h"
+#include "dfrontend/mtype.h"
+#include "dfrontend/target.h"
+
+#include "tree.h"
+#include "memmodel.h"
+#include "fold-const.h"
+#include "stor-layout.h"
+#include "tm.h"
+#include "tm_p.h"
+#include "target.h"
+
+#include "d-tree.h"
+
+
+/* Type size information used by frontend.  */
+int Target::ptrsize;
+int Target::c_longsize;
+int Target::realsize;
+int Target::realpad;
+int Target::realalignsize;
+bool Target::reverseCppOverloads;
+bool Target::cppExceptions;
+int Target::classinfosize;
+unsigned long long Target::maxStaticDataSize;
+
+/* Floating point constants for for .max, .min, and other properties.  */
+template <typename T> real_t Target::FPTypeProperties<T>::max;
+template <typename T> real_t Target::FPTypeProperties<T>::min_normal;
+template <typename T> real_t Target::FPTypeProperties<T>::nan;
+template <typename T> real_t Target::FPTypeProperties<T>::snan;
+template <typename T> real_t Target::FPTypeProperties<T>::infinity;
+template <typename T> real_t Target::FPTypeProperties<T>::epsilon;
+template <typename T> d_int64 Target::FPTypeProperties<T>::dig;
+template <typename T> d_int64 Target::FPTypeProperties<T>::mant_dig;
+template <typename T> d_int64 Target::FPTypeProperties<T>::max_exp;
+template <typename T> d_int64 Target::FPTypeProperties<T>::min_exp;
+template <typename T> d_int64 Target::FPTypeProperties<T>::max_10_exp;
+template <typename T> d_int64 Target::FPTypeProperties<T>::min_10_exp;
+
+
+/* Initialize the floating point constants for TYPE.  */
+
+template <typename T>
+static void
+define_float_constants (tree type)
+{
+  const double log10_2 = 0.30102999566398119521;
+  char buf[128];
+
+  /* Get backend real mode format.  */
+  const machine_mode mode = TYPE_MODE (type);
+  const real_format *fmt = REAL_MODE_FORMAT (mode);
+
+  /* The largest representable value that's not infinity.  */
+  get_max_float (fmt, buf, sizeof (buf));
+  real_from_string (&T::max.rv (), buf);
+
+  /* The smallest representable normalized value that's not 0.  */
+  snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - 1);
+  real_from_string (&T::min_normal.rv (), buf);
+
+  /* Floating-point NaN.  */
+  real_nan (&T::nan.rv (), "", 1, mode);
+
+  /* Signalling floating-point NaN.  */
+  real_nan (&T::snan.rv (), "", 0, mode);
+
+  /* Floating-point +Infinity if the target supports infinities.  */
+  real_inf (&T::infinity.rv ());
+
+  /* The smallest increment to the value 1.  */
+  if (fmt->pnan < fmt->p)
+    snprintf (buf, sizeof (buf), "0x1p%d", fmt->emin - fmt->p);
+  else
+    snprintf (buf, sizeof (buf), "0x1p%d", 1 - fmt->p);
+  real_from_string (&T::epsilon.rv (), buf);
+
+  /* The number of decimal digits of precision.  */
+  T::dig = (fmt->p - 1) * log10_2;
+
+  /* The number of bits in mantissa.  */
+  T::mant_dig = fmt->p;
+
+  /* The maximum int value such that 2** (value-1) is representable.  */
+  T::max_exp = fmt->emax;
+
+  /* The minimum int value such that 2** (value-1) is representable as a
+     normalized value.  */
+  T::min_exp = fmt->emin;
+
+  /* The maximum int value such that 10**value is representable.  */
+  T::max_10_exp = fmt->emax * log10_2;
+
+  /* The minimum int value such that 10**value is representable as a
+     normalized value.  */
+  T::min_10_exp = (fmt->emin - 1) * log10_2;
+}
+
+/* Initialize all variables of the Target structure.  */
+
+void
+Target::_init (void)
+{
+  /* Map D frontend type and sizes to GCC backend types.  */
+  Target::realsize = int_size_in_bytes (long_double_type_node);
+  Target::realpad = (Target::realsize -
+		     (TYPE_PRECISION (long_double_type_node) / BITS_PER_UNIT));
+  Target::realalignsize = TYPE_ALIGN_UNIT (long_double_type_node);
+  Target::reverseCppOverloads = false;
+  Target::cppExceptions = true;
+
+  /* Allow data sizes up to half of the address space.  */
+  Target::maxStaticDataSize = tree_to_shwi (TYPE_MAXVAL (ptrdiff_type_node));
+
+  /* Define what type to use for size_t, ptrdiff_t.  */
+  if (POINTER_SIZE == 64)
+    {
+      global.params.isLP64 = true;
+      Tsize_t = Tuns64;
+      Tptrdiff_t = Tint64;
+    }
+  else
+    {
+      Tsize_t = Tuns32;
+      Tptrdiff_t = Tint32;
+    }
+
+  Type::tsize_t = Type::basic[Tsize_t];
+  Type::tptrdiff_t = Type::basic[Tptrdiff_t];
+  Type::thash_t = Type::tsize_t;
+
+  Target::ptrsize = (POINTER_SIZE / BITS_PER_UNIT);
+  Target::c_longsize = int_size_in_bytes (long_integer_type_node);
+
+  Target::classinfosize = 19 * ptrsize;
+
+  /* Initialize all compile-time properties for floating point types.
+     Should ensure that our real_t type is able to represent real_value.  */
+  gcc_assert (sizeof (real_t) >= sizeof (real_value));
+
+  define_float_constants <Target::FloatProperties> (float_type_node);
+  define_float_constants <Target::DoubleProperties> (double_type_node);
+  define_float_constants <Target::RealProperties> (long_double_type_node);
+
+  /* Commonly used floating point constants.  */
+  CTFloat::zero = dconst0;
+  CTFloat::one = dconst1;
+  CTFloat::minusone = dconstm1;
+  CTFloat::half = dconsthalf;
+}
+
+/* Return GCC memory alignment size for type TYPE.  */
+
+unsigned
+Target::alignsize (Type *type)
+{
+  gcc_assert (type->isTypeBasic ());
+  return TYPE_ALIGN_UNIT (build_ctype (type));
+}
+
+
+/* Return GCC field alignment size for type TYPE.  */
+
+unsigned
+Target::fieldalign (Type *type)
+{
+  /* Work out the correct alignment for the field decl.  */
+  unsigned int align = type->alignsize () * BITS_PER_UNIT;
+
+#ifdef BIGGEST_FIELD_ALIGNMENT
+  align = MIN (align, (unsigned) BIGGEST_FIELD_ALIGNMENT);
+#endif
+
+#ifdef ADJUST_FIELD_ALIGN
+  if (type->isTypeBasic ())
+    align = ADJUST_FIELD_ALIGN (NULL_TREE, build_ctype (type), align);
+#endif
+
+  /* Also controlled by -fpack-struct=  */
+  if (maximum_field_alignment)
+    align = MIN (align, maximum_field_alignment);
+
+  return align / BITS_PER_UNIT;
+}
+
+/* Return size of OS critical section.
+   Can't use the sizeof () calls directly since cross compiling is supported
+   and would end up using the host sizes rather than the target sizes.  */
+
+unsigned
+Target::critsecsize (void)
+{
+  if (global.params.isWindows)
+    {
+      /* sizeof (CRITICAL_SECTION) for Windows.  */
+      return global.params.isLP64 ? 40 : 24;
+    }
+  else if (global.params.isLinux)
+    {
+      /* sizeof(pthread_mutex_t) for Linux.  */
+      if (global.params.is64bit)
+	return global.params.isLP64 ? 40 : 32;
+      else
+	return global.params.isLP64 ? 40 : 24;
+    }
+  else if (global.params.isFreeBSD)
+    {
+      /* sizeof(pthread_mutex_t) for FreeBSD.  */
+      return global.params.isLP64 ? 8 : 4;
+    }
+  else if (global.params.isOpenBSD)
+    {
+      /* sizeof(pthread_mutex_t) for OpenBSD.  */
+      return global.params.isLP64 ? 8 : 4;
+    }
+  else if (global.params.isOSX)
+    {
+      /* sizeof(pthread_mutex_t) for OSX.  */
+      return global.params.isLP64 ? 64 : 44;
+    }
+  else if (global.params.isSolaris)
+    {
+      /* sizeof(pthread_mutex_t) for Solaris.  */
+      return 24;
+    }
+
+  gcc_unreachable ();
+}
+
+/* Returns a Type for the va_list type of the target.  */
+
+Type *
+Target::va_listType (void)
+{
+  return Type::tvalist;
+}
+
+/* Perform a reinterpret cast of EXPR to type TYPE for use in CTFE.
+   The front end should have already ensured that EXPR is a constant,
+   so we just lower the value to GCC and return the converted CST.  */
+
+Expression *
+Target::paintAsType (Expression *expr, Type *type)
+{
+  /* We support up to 512-bit values.  */
+  unsigned char buffer[64];
+  tree cst;
+
+  Type *tb = type->toBasetype ();
+
+  if (expr->type->isintegral ())
+    cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type));
+  else if (expr->type->isfloating ())
+    cst = build_float_cst (expr->toReal (), expr->type);
+  else if (expr->op == TOKarrayliteral)
+    {
+      /* Build array as VECTOR_CST, assumes EXPR is constant.  */
+      Expressions *elements = ((ArrayLiteralExp *) expr)->elements;
+      vec<constructor_elt, va_gc> *elms = NULL;
+
+      vec_safe_reserve (elms, elements->dim);
+      for (size_t i = 0; i < elements->dim; i++)
+	{
+	  Expression *e = (*elements)[i];
+	  if (e->type->isintegral ())
+	    {
+	      tree value = build_integer_cst (e->toInteger (),
+					      build_ctype (e->type));
+	      CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+	    }
+	  else if (e->type->isfloating ())
+	    {
+	      tree value = build_float_cst (e->toReal (), e->type);
+	      CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+	    }
+	  else
+	    gcc_unreachable ();
+	}
+
+      /* Build vector type.  */
+      int nunits = ((TypeSArray *) expr->type)->dim->toUInteger ();
+      Type *telem = expr->type->nextOf ();
+      tree vectype = build_vector_type (build_ctype (telem), nunits);
+
+      cst = build_vector_from_ctor (vectype, elms);
+    }
+  else
+    gcc_unreachable ();
+
+  /* Encode CST to buffer.  */
+  int len = native_encode_expr (cst, buffer, sizeof (buffer));
+
+  if (tb->ty == Tsarray)
+    {
+      /* Interpret value as a vector of the same size,
+	 then return the array literal.  */
+      int nunits = ((TypeSArray *) type)->dim->toUInteger ();
+      Type *elem = type->nextOf ();
+      tree vectype = build_vector_type (build_ctype (elem), nunits);
+
+      cst = native_interpret_expr (vectype, buffer, len);
+
+      Expression *e = d_eval_constant_expression (cst);
+      gcc_assert (e != NULL && e->op == TOKvector);
+
+      return ((VectorExp *) e)->e1;
+    }
+  else
+    {
+      /* Normal interpret cast.  */
+      cst = native_interpret_expr (build_ctype (type), buffer, len);
+
+      Expression *e = d_eval_constant_expression (cst);
+      gcc_assert (e != NULL);
+
+      return e;
+    }
+}
+
+/* Check imported module M for any special processing.
+   Modules we look out for are:
+    - object: For D runtime type information.
+    - gcc.builtins: For all gcc builtins.
+    - core.stdc.*: For all gcc library builtins.  */
+
+void
+Target::loadModule (Module *m)
+{
+  ModuleDeclaration *md = m->md;
+  if (!md || !md->id)
+    return;
+
+  if (!md->packages)
+    {
+      if (!strcmp (md->id->toChars (), "object"))
+	create_tinfo_types (m);
+    }
+  else if (md->packages->dim == 1)
+    {
+      if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
+	  && !strcmp (md->id->toChars (), "builtins"))
+	d_build_builtins_module (m);
+    }
+  else if (md->packages->dim == 2)
+    {
+      if (!strcmp ((*md->packages)[0]->toChars (), "core")
+	  && !strcmp ((*md->packages)[1]->toChars (), "stdc"))
+	d_add_builtin_module (m);
+    }
+}
+
+/* Checks whether the target supports a vector type with total size SZ
+   (in bytes) and element type TYPE.  */
+
+int
+Target::checkVectorType (int sz, Type *type)
+{
+  /* Size must be greater than zero, and a power of two.  */
+  if (sz <= 0 || sz & (sz - 1))
+    return 2;
+
+  /* __vector(void[]) is treated same as __vector(ubyte[])  */
+  if (type == Type::tvoid)
+    type = Type::tuns8;
+
+  /* No support for non-trivial types.  */
+  if (!type->isTypeBasic ())
+    return 3;
+
+  /* If there is no hardware support, check if we an safely emulate it.  */
+  tree ctype = build_ctype (type);
+  machine_mode mode = TYPE_MODE (ctype);
+
+  if (!targetm.vector_mode_supported_p (mode)
+      && !targetm.scalar_mode_supported_p (mode))
+    return 3;
+
+  return 0;
+}
+
+/* Apply any target-specific prefixes based on the given linkage.  */
+
+void
+Target::prefixName (OutBuffer *, LINK)
+{
+}
diff --git a/gcc/d/d-tree.def b/gcc/d/d-tree.def
new file mode 100644
index 00000000000..717fd080387
--- /dev/null
+++ b/gcc/d/d-tree.def
@@ -0,0 +1,34 @@
+/* d-tree.def -- Definitions and documentation for additional tree codes used
+   in the D compiler  (see tree.def for standard codes).
+   Copyright (C) 2006-2017 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/>.  */
+
+/* Used to represent a D inline assembly statement, an intermediate
+   representation of an ASM_EXPR.  Reserved for future use and
+   implementation yet to be defined.  */
+DEFTREECODE (IASM_EXPR, "iasm_expr", tcc_statement, 5)
+
+/* Logical shift done on an unsigned type.  If the first operand is
+   signed, it will be converted to the unsigned equivalent.  The second
+   operand is the number of bits to shift by; it need not be the same
+   type as the first operand and result.  */
+DEFTREECODE (UNSIGNED_RSHIFT_EXPR, "unsigned_rshift_expr", tcc_binary, 2)
+
+/* Floating point modulus that expands to a call to fmod.  */
+DEFTREECODE (FLOAT_MOD_EXPR, "float_mod_expr", tcc_binary, 2)
+
+/* Used to represent information associated with a function closure.  */
+DEFTREECODE (FUNCFRAME_INFO, "funcframe_info", tcc_exceptional, 0)
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
new file mode 100644
index 00000000000..3c07826e48c
--- /dev/null
+++ b/gcc/d/d-tree.h
@@ -0,0 +1,617 @@
+/* d-tree.h -- Definitions and declarations for code generation.
+   Copyright (C) 2006-2017 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/>.  */
+
+#ifndef GCC_D_TREE_H
+#define GCC_D_TREE_H
+
+/* Forward type declarations to avoid including unnecessary headers.  */
+
+class Dsymbol;
+class Declaration;
+class AggregateDeclaration;
+class ClassDeclaration;
+class EnumDeclaration;
+class FuncDeclaration;
+class StructDeclaration;
+class TypeInfoDeclaration;
+class VarDeclaration;
+class UserAttributeDeclaration;
+class Expression;
+class ClassReferenceExp;
+class Module;
+class Statement;
+class Type;
+class TypeFunction;
+class Parameter;
+struct BaseClass;
+struct Scope;
+struct Loc;
+
+template <typename TYPE> struct Array;
+typedef Array<Expression *> Expressions;
+
+/* Usage of TREE_LANG_FLAG_?:
+   0: METHOD_CALL_EXPR
+
+   Usage of TYPE_LANG_FLAG_?:
+   0: TYPE_SHARED
+   1: TYPE_IMAGINARY_FLOAT (in REAL_TYPE).
+      ANON_AGGR_TYPE_P (in RECORD_TYPE, UNION_TYPE).
+   2: CLASS_TYPE_P (in RECORD_TYPE).
+
+   Usage of DECL_LANG_FLAG_?:
+   0: D_DECL_ONE_ONLY
+   1: LABEL_VARIABLE_CASE (in LABEL_DECL).  */
+
+/* The kinds of scopes we recognise.  */
+
+enum level_kind
+{
+  level_block,		/* An ordinary block scope.  */
+  level_try,		/* A try-block.  */
+  level_catch,		/* A catch-block.  */
+  level_finally,	/* A finally-block.  */
+  level_cond,		/* The scope for an if condition.  */
+  level_switch,		/* The scope for a switch statement.  */
+  level_loop,		/* A for, do-while, or unrolled-loop block.  */
+  level_with,		/* The scope for a with statement.  */
+  level_function,	/* The block representing an entire function.  */
+};
+
+/* For use with break and continue statements.  */
+
+enum bc_kind
+{
+  bc_break    = 0,
+  bc_continue = 1,
+};
+
+/* The datatype used to implement D scope.  It is needed primarily to support
+   the backend, but also helps debugging information for local variables.  */
+
+struct GTY((chain_next ("%h.level_chain"))) binding_level
+{
+  /* A chain of declarations for all variables, constants and functions.
+     These are in the reverse of the order supplied.  */
+  tree names;
+
+  /* For each level (except the global one), a chain of BLOCK nodes for
+     all the levels that were entered and exited one level down.  */
+  tree blocks;
+
+  /* The binding level this one is contained in.  */
+  binding_level *level_chain;
+
+  /* The kind of scope this object represents.  */
+  ENUM_BITFIELD (level_kind) kind : 4;
+};
+
+/* The binding level currently in effect.  */
+extern GTY(()) binding_level *current_binding_level;
+extern GTY(()) binding_level *global_binding_level;
+
+/* Used only for jumps to as-yet undefined labels, since jumps to
+   defined labels can have their validity checked immediately.  */
+
+struct GTY((chain_next ("%h.next"))) d_label_use_entry
+{
+  d_label_use_entry *next;
+
+  /* The frontend Statement associated with the jump.  */
+  Statement * GTY((skip)) statement;
+
+  /* The binding level to which this entry is *currently* attached.
+     This is initially the binding level in which the goto appeared,
+     but is modified as scopes are closed.  */
+  binding_level *level;
+};
+
+/* A list of all LABEL_DECLs in the function that have names.  Here so
+   we can clear out their names' definitions at the end of the
+   function, and so we can check the validity of jumps to these labels.  */
+
+struct GTY(()) d_label_entry
+{
+  /* The label decl itself.  */
+  tree label;
+
+  /* The frontend Statement associated with the label.  */
+  Statement * GTY((skip)) statement;
+
+  /* The binding level to which the label is *currently* attached.
+     This is initially set to the binding level in which the label
+     is defined, but is modified as scopes are closed.  */
+  binding_level *level;
+
+  /* A list of forward references of the label.  */
+  d_label_use_entry *fwdrefs;
+
+  /* The following bits are set after the label is defined, and are
+     updated as scopes are popped.  They indicate that a backward jump
+     to the label will illegally enter a scope of the given flavor.  */
+  bool in_try_scope;
+  bool in_catch_scope;
+
+  /* If set, the label we reference represents a break/continue pair.  */
+  bool bc_label;
+};
+
+/* Frame information for a function declaration.  */
+
+struct GTY(()) tree_frame_info
+{
+    struct tree_common common;
+    tree frame_type;
+};
+
+/* True if the function creates a nested frame.  */
+#define FRAMEINFO_CREATES_FRAME(NODE) \
+  (TREE_LANG_FLAG_0 (FUNCFRAME_INFO_CHECK (NODE)))
+
+/* True if the function has a static chain passed in it's DECL_ARGUMENTS.  */
+#define FRAMEINFO_STATIC_CHAIN(NODE) \
+  (TREE_LANG_FLAG_1 (FUNCFRAME_INFO_CHECK (NODE)))
+
+/* True if the function frame is a closure (initialized on the heap).  */
+#define FRAMEINFO_IS_CLOSURE(NODE) \
+  (TREE_LANG_FLAG_2 (FUNCFRAME_INFO_CHECK (NODE)))
+
+#define FRAMEINFO_TYPE(NODE) \
+  (((tree_frame_info *) FUNCFRAME_INFO_CHECK (NODE))->frame_type)
+
+/* Language-dependent contents of an identifier.  */
+
+struct GTY(()) lang_identifier
+{
+  struct tree_identifier common;
+
+  /* The identifier as the user sees it.  */
+  tree pretty_ident;
+
+  /* The frontend Declaration associated with this identifier.  */
+  Declaration * GTY((skip)) dsymbol;
+};
+
+#define IDENTIFIER_LANG_SPECIFIC(NODE) \
+  ((struct lang_identifier *) IDENTIFIER_NODE_CHECK (NODE))
+
+#define IDENTIFIER_PRETTY_NAME(NODE) \
+  (IDENTIFIER_LANG_SPECIFIC (NODE)->pretty_ident)
+
+#define IDENTIFIER_DSYMBOL(NODE) \
+  (IDENTIFIER_LANG_SPECIFIC (NODE)->dsymbol)
+
+/* Global state pertinent to the current function.  */
+
+struct GTY(()) language_function
+{
+  /* Our function and enclosing module.  */
+  FuncDeclaration * GTY((skip)) function;
+  Module * GTY((skip)) module;
+
+  /* Static chain of function, for D2, this is a closure.  */
+  tree static_chain;
+
+  /* Stack of statement lists being collected while we are
+     compiling the function.  */
+  vec<tree, va_gc> *stmt_list;
+
+  /* Variables that are in scope that will need destruction later.  */
+  vec<VarDeclaration *> GTY((skip)) vars_in_scope;
+
+  /* Table of all used or defined labels in the function.  */
+  hash_map<Statement *, d_label_entry> *labels;
+};
+
+/* The D front end types have not been integrated into the GCC garbage
+   collection system.  Handle this by using the "skip" attribute.  */
+
+struct GTY(()) lang_decl
+{
+  Declaration * GTY((skip)) decl;
+
+  /* FIELD_DECL in frame struct that this variable is allocated in.  */
+  tree frame_field;
+
+  /* RESULT_DECL in a function that returns by nrvo.  */
+  tree named_result;
+
+  /* Chain of DECL_LANG_THUNKS in a function.  */
+  tree thunks;
+
+  /* In a FUNCTION_DECL, this is the THUNK_LANG_OFFSET.  */
+  int offset;
+
+  /* FUNCFRAME_INFO in a function that has non-local references.  */
+  tree frame_info;
+};
+
+/* The current D per-function global variables.  */
+
+#define d_function_chain (cfun ? cfun->language : NULL)
+
+/* The D frontend Declaration AST for GCC decl NODE.  */
+#define DECL_LANG_FRONTEND(NODE) \
+  (DECL_LANG_SPECIFIC (NODE) \
+   ? DECL_LANG_SPECIFIC (NODE)->decl : NULL)
+
+#define SET_DECL_LANG_FRAME_FIELD(NODE, VAL) \
+  DECL_LANG_SPECIFIC (NODE)->frame_field = VAL
+
+#define DECL_LANG_FRAME_FIELD(NODE) \
+  (DECL_P (NODE) \
+   ? DECL_LANG_SPECIFIC (NODE)->frame_field : NULL)
+
+#define SET_DECL_LANG_NRVO(NODE, VAL) \
+  DECL_LANG_SPECIFIC (NODE)->named_result = VAL
+
+#define DECL_LANG_NRVO(NODE) \
+  (DECL_P (NODE) \
+   ? DECL_LANG_SPECIFIC (NODE)->named_result : NULL)
+
+#define DECL_LANG_THUNKS(NODE) \
+  DECL_LANG_SPECIFIC (NODE)->thunks
+
+#define THUNK_LANG_OFFSET(NODE) \
+  DECL_LANG_SPECIFIC (NODE)->offset
+
+#define DECL_LANG_FRAMEINFO(NODE) \
+  DECL_LANG_SPECIFIC (NODE)->frame_info
+
+/* The lang_type field is not set for every GCC type.  */
+
+struct GTY(()) lang_type
+{
+  Type * GTY((skip)) type;
+};
+
+/* The D frontend Type AST for GCC type NODE.  */
+#define TYPE_LANG_FRONTEND(NODE) \
+  (TYPE_LANG_SPECIFIC (NODE) \
+   ? TYPE_LANG_SPECIFIC (NODE)->type : NULL)
+
+
+enum d_tree_node_structure_enum
+{
+  TS_D_GENERIC,
+  TS_D_IDENTIFIER,
+  TS_D_FRAMEINFO,
+  LAST_TS_D_ENUM
+};
+
+/* The resulting tree type.  */
+
+union GTY((desc ("d_tree_node_structure (&%h)"),
+	   chain_next ("CODE_CONTAINS_STRUCT (TREE_CODE (&%h.generic), TS_COMMON)"
+		       " ? ((union lang_tree_node *) TREE_CHAIN (&%h.generic)) : NULL")))
+lang_tree_node
+{
+  union tree_node GTY ((tag ("TS_D_GENERIC"),
+			desc ("tree_node_structure (&%h)"))) generic;
+  lang_identifier GTY ((tag ("TS_D_IDENTIFIER"))) identifier;
+  tree_frame_info GTY ((tag ("TS_D_FRAMEINFO"))) frameinfo;
+};
+
+/* True if the Tdelegate typed expression is not really a variable,
+   but a literal function / method reference.  */
+#define METHOD_CALL_EXPR(NODE) \
+  (TREE_LANG_FLAG_0 (NODE))
+
+/* True if the type was declared 'shared'.  */
+#define TYPE_SHARED(NODE) \
+  (TYPE_LANG_FLAG_0 (NODE))
+
+/* True if the type is an imaginary float type.  */
+#define TYPE_IMAGINARY_FLOAT(NODE) \
+  (TYPE_LANG_FLAG_1 (REAL_TYPE_CHECK (NODE)))
+
+/* True if the type is an anonymous record or union.  */
+#define ANON_AGGR_TYPE_P(NODE) \
+  (TYPE_LANG_FLAG_1 (RECORD_OR_UNION_CHECK (NODE)))
+
+/* True if the type is the underlying record for a class.  */
+#define CLASS_TYPE_P(NODE) \
+  (TYPE_LANG_FLAG_2 (RECORD_TYPE_CHECK (NODE)))
+
+/* True if the symbol should be made "link one only".  This is used to
+   defer calling make_decl_one_only() before the decl has been prepared.  */
+#define D_DECL_ONE_ONLY(NODE) \
+  (DECL_LANG_FLAG_0 (NODE))
+
+/* True if the decl is a variable case label decl.  */
+#define LABEL_VARIABLE_CASE(NODE) \
+  (DECL_LANG_FLAG_1 (LABEL_DECL_CHECK (NODE)))
+
+enum d_tree_index
+{
+  DTI_VTABLE_ENTRY_TYPE,
+  DTI_VTBL_PTR_TYPE,
+  DTI_VTBL_INTERFACE_TYPE,
+
+  DTI_BOOL_TYPE,
+  DTI_CHAR_TYPE,
+  DTI_WCHAR_TYPE,
+  DTI_DCHAR_TYPE,
+
+  DTI_BYTE_TYPE,
+  DTI_UBYTE_TYPE,
+  DTI_SHORT_TYPE,
+  DTI_USHORT_TYPE,
+  DTI_INT_TYPE,
+  DTI_UINT_TYPE,
+  DTI_LONG_TYPE,
+  DTI_ULONG_TYPE,
+  DTI_CENT_TYPE,
+  DTI_UCENT_TYPE,
+
+  DTI_IFLOAT_TYPE,
+  DTI_IDOUBLE_TYPE,
+  DTI_IREAL_TYPE,
+
+  DTI_UNKNOWN_TYPE,
+
+  DTI_ARRAY_TYPE,
+  DTI_NULL_ARRAY,
+
+  DTI_MAX
+};
+
+extern GTY(()) tree d_global_trees[DTI_MAX];
+
+#define vtable_entry_type		d_global_trees[DTI_VTABLE_ENTRY_TYPE]
+#define vtbl_ptr_type_node		d_global_trees[DTI_VTBL_PTR_TYPE]
+#define vtbl_interface_type_node	d_global_trees[DTI_VTBL_INTERFACE_TYPE]
+#define bool_type_node			d_global_trees[DTI_BOOL_TYPE]
+#define char8_type_node			d_global_trees[DTI_CHAR_TYPE]
+#define char16_type_node		d_global_trees[DTI_DCHAR_TYPE]
+#define char32_type_node		d_global_trees[DTI_WCHAR_TYPE]
+#define byte_type_node			d_global_trees[DTI_BYTE_TYPE]
+#define ubyte_type_node			d_global_trees[DTI_UBYTE_TYPE]
+#define short_type_node			d_global_trees[DTI_SHORT_TYPE]
+#define ushort_type_node		d_global_trees[DTI_USHORT_TYPE]
+#define int_type_node			d_global_trees[DTI_INT_TYPE]
+#define uint_type_node			d_global_trees[DTI_UINT_TYPE]
+#define long_type_node			d_global_trees[DTI_LONG_TYPE]
+#define ulong_type_node			d_global_trees[DTI_ULONG_TYPE]
+#define cent_type_node			d_global_trees[DTI_CENT_TYPE]
+#define ucent_type_node			d_global_trees[DTI_UCENT_TYPE]
+#define ifloat_type_node		d_global_trees[DTI_IFLOAT_TYPE]
+#define idouble_type_node		d_global_trees[DTI_IDOUBLE_TYPE]
+#define ireal_type_node			d_global_trees[DTI_IREAL_TYPE]
+#define unknown_type_node		d_global_trees[DTI_UNKNOWN_TYPE]
+#define array_type_node			d_global_trees[DTI_ARRAY_TYPE]
+#define null_array_node			d_global_trees[DTI_NULL_ARRAY]
+
+/* A prefix for internal variables, which are not user-visible.  */
+#if !defined (NO_DOT_IN_LABEL)
+# define GDC_PREFIX(x) "gdc." x
+#elif !defined (NO_DOLLAR_IN_LABEL)
+# define GDC_PREFIX(x) "gdc$" x
+#else
+# define GDC_PREFIX(x) "gdc_" x
+#endif
+
+/* Internally recognised D runtime library functions.  */
+
+enum libcall_fn
+{
+#define DEF_D_RUNTIME(CODE, N, T, P, F) LIBCALL_ ## CODE,
+
+#include "runtime.def"
+
+#undef DEF_D_RUNTIME
+  LIBCALL_LAST,
+};
+
+/* In d-attribs.c.  */
+extern tree insert_type_attribute (tree, const char *, tree = NULL_TREE);
+extern tree insert_decl_attribute (tree, const char *, tree = NULL_TREE);
+extern tree build_attributes (Expressions *);
+
+/* In d-builtins.cc.  */
+extern const attribute_spec d_langhook_attribute_table[];
+extern const attribute_spec d_langhook_common_attribute_table[];
+
+extern tree d_builtin_function (tree);
+extern void d_init_builtins (void);
+extern void d_register_builtin_type (tree, const char *);
+extern void d_build_builtins_module (Module *);
+extern void d_maybe_set_builtin (Module *);
+extern Expression *d_eval_constant_expression (tree);
+
+/* In d-codegen.cc.  */
+extern location_t get_linemap (const Loc &);
+extern tree d_decl_context (Dsymbol *);
+extern tree copy_aggregate_type (tree);
+extern bool declaration_reference_p (Declaration *);
+extern tree declaration_type (Declaration *);
+extern bool argument_reference_p (Parameter *);
+extern tree type_passed_as (Parameter *);
+extern tree build_integer_cst (dinteger_t, tree = int_type_node);
+extern tree build_float_cst (const real_t &, Type *);
+extern tree d_array_length (tree);
+extern tree d_array_ptr (tree);
+extern tree d_array_value (tree, tree, tree);
+extern tree d_array_string (const char *);
+extern tree get_array_length (tree, Type *);
+extern tree build_class_binfo (tree, ClassDeclaration *);
+extern tree build_interface_binfo (tree, ClassDeclaration *, unsigned &);
+extern tree delegate_method (tree);
+extern tree delegate_object (tree);
+extern tree build_delegate_cst (tree, tree, Type *);
+extern tree build_method_call (tree, tree, Type *);
+extern void extract_from_method_call (tree, tree &, tree &);
+extern tree build_vindex_ref (tree, tree, size_t);
+extern tree d_save_expr (tree);
+extern tree stabilize_expr (tree *);
+extern tree build_target_expr (tree);
+extern tree build_address (tree);
+extern tree d_mark_addressable (tree);
+extern tree d_mark_used (tree);
+extern tree d_mark_read (tree);
+extern bool identity_compare_p (StructDeclaration *);
+extern tree build_struct_comparison (tree_code, StructDeclaration *,
+				     tree, tree);
+extern tree build_array_struct_comparison (tree_code, StructDeclaration *,
+					   tree, tree, tree);
+extern tree build_struct_literal (tree, vec<constructor_elt, va_gc> *);
+extern tree build_class_instance (ClassReferenceExp *);
+extern tree component_ref (tree, tree);
+extern tree build_assign (tree_code, tree, tree);
+extern tree modify_expr (tree, tree);
+extern tree build_nop (tree, tree);
+extern tree build_vconvert (tree, tree);
+extern tree build_boolop (tree_code, tree, tree);
+extern tree build_condition (tree, tree, tree, tree);
+extern tree build_vcondition (tree, tree, tree);
+extern tree compound_expr (tree, tree);
+extern tree return_expr (tree);
+extern tree size_mult_expr (tree, tree);
+extern tree real_part (tree);
+extern tree imaginary_part (tree);
+extern tree complex_expr (tree, tree, tree);
+extern tree indirect_ref (tree, tree);
+extern tree build_deref (tree);
+extern tree build_array_index (tree, tree);
+extern tree build_offset_op (tree_code, tree, tree);
+extern tree build_offset (tree, tree);
+extern tree build_memref (tree, tree, tree);
+extern tree build_array_set (tree, tree, tree);
+extern tree build_array_from_val (Type *, tree);
+extern tree void_okay_p (tree);
+extern tree build_bounds_condition (const Loc &, tree, tree, bool);
+extern bool array_bounds_check (void);
+extern tree create_temporary_var (tree);
+extern tree maybe_temporary_var (tree, tree *);
+extern tree bind_expr (tree, tree);
+extern TypeFunction *get_function_type (Type *);
+extern bool call_by_alias_p (FuncDeclaration *, FuncDeclaration *);
+extern tree d_build_call_expr (FuncDeclaration *, tree, Expressions *);
+extern tree d_build_call (TypeFunction *, tree, tree, Expressions *);
+extern tree d_assert_call (const Loc &, libcall_fn, tree = NULL_TREE);
+extern tree build_float_modulus (tree, tree, tree);
+extern tree build_vthis_function (tree, tree);
+extern tree get_frame_for_symbol (Dsymbol *);
+extern tree build_vthis (AggregateDeclaration *);
+extern void build_closure (FuncDeclaration *);
+extern tree get_frameinfo (FuncDeclaration *);
+extern tree get_framedecl (FuncDeclaration *, FuncDeclaration *);
+
+/* In d-convert.cc.  */
+extern tree d_truthvalue_conversion (tree);
+extern tree d_convert (tree, tree);
+extern tree convert_expr (tree, Type *, Type *);
+extern tree convert_for_assignment (tree, Type *, Type *);
+extern tree convert_for_argument (tree, Parameter *);
+extern tree convert_for_condition (tree, Type *);
+extern tree d_array_convert (Expression *);
+extern tree d_array_convert (Type *, Expression *, vec<tree, va_gc> **);
+
+/* In d-incpath.cc.  */
+extern void add_import_paths (const char *, const char *, bool);
+
+/* In d-lang.cc.  */
+extern void d_add_builtin_module (Module *);
+extern void d_add_entrypoint_module (Module *, Module *);
+extern d_tree_node_structure_enum d_tree_node_structure (lang_tree_node *);
+extern struct lang_type *build_lang_type (Type *);
+extern struct lang_decl *build_lang_decl (Declaration *);
+extern tree d_pushdecl (tree);
+extern tree d_unsigned_type (tree);
+extern tree d_signed_type (tree);
+extern void d_keep (tree);
+
+/* In decl.cc.  */
+extern tree mangle_internal_decl (Dsymbol *, const char *, const char *);
+extern void build_decl_tree (Dsymbol *);
+extern tree get_symbol_decl (Declaration *);
+extern tree declare_extern_var (tree, tree);
+extern void declare_local_var (VarDeclaration *);
+extern tree build_local_temp (tree);
+extern tree get_decl_tree (Declaration *);
+extern void d_finish_decl (tree);
+extern tree make_thunk (FuncDeclaration *, int);
+extern tree start_function (FuncDeclaration *);
+extern void finish_function (tree);
+extern void mark_needed (tree);
+extern unsigned base_vtable_offset (ClassDeclaration *, BaseClass *);
+extern tree get_vtable_decl (ClassDeclaration *);
+extern tree build_new_class_expr (ClassReferenceExp *);
+extern tree aggregate_initializer_decl (AggregateDeclaration *);
+extern tree layout_struct_initializer (StructDeclaration *);
+extern tree layout_class_initializer (ClassDeclaration *);
+extern tree enum_initializer_decl (EnumDeclaration *);
+extern tree build_artificial_decl (tree, tree, const char * = NULL);
+extern tree create_field_decl (tree, const char *, int, int);
+extern void build_type_decl (tree, Dsymbol *);
+extern void d_comdat_linkage (tree);
+
+/* In expr.cc.  */
+extern tree build_expr (Expression *, bool = false);
+extern tree build_expr_dtor (Expression *);
+extern tree build_return_dtor (Expression *, Type *, TypeFunction *);
+
+/* In imports.cc.  */
+extern tree build_import_decl (Dsymbol *);
+
+/* In intrinsics.cc.  */
+extern void maybe_set_intrinsic (FuncDeclaration *);
+extern tree maybe_expand_intrinsic (tree);
+
+/* In modules.cc.  */
+extern void build_module_tree (Module *);
+extern tree d_module_context (void);
+extern void register_module_decl (Declaration *);
+extern void d_finish_compilation (tree *, int);
+
+/* In runtime.cc.  */
+extern tree build_libcall (libcall_fn, Type *, int ...);
+
+/* In typeinfo.cc.  */
+extern tree layout_typeinfo (TypeInfoDeclaration *);
+extern tree layout_classinfo (ClassDeclaration *);
+extern tree get_typeinfo_decl (TypeInfoDeclaration *);
+extern tree get_classinfo_decl (ClassDeclaration *);
+extern tree build_typeinfo (Type *);
+extern void create_typeinfo (Type *, Module *);
+extern void create_tinfo_types (Module *);
+extern void layout_cpp_typeinfo (ClassDeclaration *);
+extern tree get_cpp_typeinfo_decl (ClassDeclaration *);
+extern bool speculative_type_p (Type *);
+
+/* In toir.cc.  */
+extern void push_binding_level (level_kind);
+extern tree pop_binding_level (void);
+extern void push_stmt_list (void);
+extern tree pop_stmt_list (void);
+extern void add_stmt (tree);
+extern void build_function_body (FuncDeclaration *);
+
+/* In types.cc.  */
+extern bool valist_array_p (Type *);
+extern bool empty_aggregate_p (tree);
+extern bool same_type_p (Type *, Type *);
+extern Type *get_object_type (void);
+extern tree make_array_type (Type *, unsigned HOST_WIDE_INT);
+extern tree make_struct_type (const char *, int n, ...);
+extern tree insert_type_modifiers (tree, unsigned);
+extern void insert_aggregate_field (tree, tree, size_t);
+extern void finish_aggregate_type (unsigned, unsigned, tree,
+				   UserAttributeDeclaration *);
+extern tree build_ctype (Type *);
+
+#endif  /* ! GCC_D_TREE_H */
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
new file mode 100644
index 00000000000..1e6560d99d6
--- /dev/null
+++ b/gcc/d/decl.cc
@@ -0,0 +1,2139 @@
+/* decl.cc -- Lower D frontend declarations to GCC trees.
+   Copyright (C) 2006-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/attrib.h"
+#include "dfrontend/ctfe.h"
+#include "dfrontend/declaration.h"
+#include "dfrontend/enum.h"
+#include "dfrontend/globals.h"
+#include "dfrontend/hdrgen.h"
+#include "dfrontend/identifier.h"
+#include "dfrontend/import.h"
+#include "dfrontend/init.h"
+#include "dfrontend/module.h"
+#include "dfrontend/nspace.h"
+#include "dfrontend/target.h"
+#include "dfrontend/template.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "target.h"
+#include "common/common-target.h"
+#include "cgraph.h"
+#include "toplev.h"
+#include "stringpool.h"
+#include "varasm.h"
+#include "stor-layout.h"
+#include "attribs.h"
+#include "function.h"
+#include "debug.h"
+#include "tree-pretty-print.h"
+
+#include "d-tree.h"
+#include "id.h"
+
+
+/* Return identifier for the external mangled name of DECL.  */
+
+static const char *
+mangle_decl (Dsymbol *decl)
+{
+  if (decl->isFuncDeclaration ())
+    return mangleExact ((FuncDeclaration *)decl);
+  else
+    {
+      OutBuffer buf;
+      mangleToBuffer (decl, &buf);
+      return buf.extractString ();
+    }
+}
+
+/* Generate a mangled identifier using NAME and SUFFIX, prefixed by the
+   assembler name for DECL.  */
+
+tree
+mangle_internal_decl (Dsymbol *decl, const char *name, const char *suffix)
+{
+  const char *prefix = mangle_decl (decl);
+  unsigned namelen = strlen (name);
+  unsigned buflen = (2 + strlen (prefix) + namelen + strlen (suffix)) * 2;
+  char *buf = (char *) alloca (buflen);
+
+  snprintf (buf, buflen, "_D%s%u%s%s", prefix, namelen, name, suffix);
+  tree ident = get_identifier (buf);
+
+  /* Symbol is not found in user code, but generate a readable name for it
+     anyway for debug and diagnostic reporting.  */
+  snprintf (buf, buflen, "%s.%s", decl->toPrettyChars (), name);
+  IDENTIFIER_PRETTY_NAME (ident) = get_identifier (buf);
+
+  return ident;
+}
+
+/* Returns true if DECL is from the gcc.attribute module.  */
+
+static bool
+gcc_attribute_p (Dsymbol *decl)
+{
+  ModuleDeclaration *md = decl->getModule ()->md;
+
+  if (md && md->packages && md->packages->dim == 1)
+    {
+      if (!strcmp ((*md->packages)[0]->toChars (), "gcc")
+	  && !strcmp (md->id->toChars (), "attribute"))
+	return true;
+    }
+
+  return false;
+}
+
+/* Implements the visitor interface to lower all Declaration AST classes
+   emitted from the D Front-end to GCC trees.
+   All visit methods accept one parameter D, which holds the frontend AST
+   of the declaration to compile.  These also don't return any value, instead
+   generated code are appened to global_declarations or added to the
+   current_binding_level by d_pushdecl().  */
+
+class DeclVisitor : public Visitor
+{
+public:
+  DeclVisitor (void) { }
+
+  /* This should be overridden by each declaration class.  */
+
+  void visit (Dsymbol *)
+  {
+  }
+
+  /* Compile a D module, and all members of it.  */
+
+  void visit (Module *d)
+  {
+    if (d->semanticRun >= PASSobj)
+      return;
+
+    /* Set input location, empty DECL_SOURCE_FILE can crash debug generator.  */
+    if (d->loc.filename)
+      input_location = get_linemap (d->loc);
+    else
+      input_location = get_linemap (Loc ("<no_file>", 1, 0));
+
+    build_module_tree (d);
+
+    d->semanticRun = PASSobj;
+  }
+
+  /* Write the imported symbol to debug.  */
+
+  void visit (Import *d)
+  {
+    /* Implements import declarations by telling the debug backend we are
+       importing the NAMESPACE_DECL of the module or IMPORTED_DECL of the
+       declaration into the current lexical scope CONTEXT.  NAME is set if
+       this is a renamed import.  */
+    if (d->isstatic)
+      return;
+
+    input_location = get_linemap (d->loc);
+
+    /* Get the context of this import, this should never be null.  */
+    tree context = d_module_context ();
+
+    if (d->ident == NULL)
+      {
+	/* Importing declaration list.  */
+	for (size_t i = 0; i < d->names.dim; i++)
+	  {
+	    AliasDeclaration *aliasdecl = d->aliasdecls[i];
+	    tree decl = build_import_decl (aliasdecl);
+
+	    /* Skip over unhandled imports.  */
+	    if (decl == NULL_TREE)
+	      continue;
+
+	    Identifier *alias = d->aliases[i];
+	    tree name = (alias != NULL)
+	      ? get_identifier (alias->toChars ()) : NULL_TREE;
+
+	    debug_hooks->imported_module_or_decl (decl, name, context, false);
+	  }
+      }
+    else
+      {
+	/* Importing the entire module.  */
+	tree decl = build_import_decl (d->mod);
+
+	tree name = (d->aliasId != NULL)
+	  ? get_identifier (d->aliasId->toChars ()) : NULL_TREE;
+
+	debug_hooks->imported_module_or_decl (decl, name, context, false);
+      }
+  }
+
+  /* Expand any local variables found in tuples.  */
+
+  void visit (TupleDeclaration *d)
+  {
+    for (size_t i = 0; i < d->objects->dim; i++)
+      {
+	RootObject *o = (*d->objects)[i];
+	if ((o->dyncast () == DYNCAST_EXPRESSION)
+	    && ((Expression *) o)->op == TOKdsymbol)
+	  {
+	    Declaration *d = ((DsymbolExp *) o)->s->isDeclaration ();
+	    if (d)
+	      d->accept (this);
+	  }
+      }
+  }
+
+  /* Walk over all declarations in the attribute scope.  */
+
+  void visit (AttribDeclaration *d)
+  {
+    Dsymbols *ds = d->include (NULL, NULL);
+
+    if (!ds)
+      return;
+
+    for (size_t i = 0; i < ds->dim; i++)
+      {
+	Dsymbol *s = (*ds)[i];
+	s->accept (this);
+      }
+  }
+
+  /* Pragmas are a way to pass special information to the compiler and to add
+     vendor specific extensions to D.  We don't do anything here, yet.  */
+
+  void visit (PragmaDeclaration *d)
+  {
+    if (!global.params.ignoreUnsupportedPragmas)
+      {
+	if (d->ident == Id::lib || d->ident == Id::startaddress)
+	  {
+	    warning_at (get_linemap (d->loc), OPT_Wunknown_pragmas,
+			"pragma(%s) not implemented", d->ident->toChars ());
+	  }
+      }
+
+    visit ((AttribDeclaration *) d);
+  }
+
+  /* Walk over all members in the namespace scope.  */
+
+  void visit (Nspace *d)
+  {
+    if (isError (d) || !d->members)
+      return;
+
+    for (size_t i = 0; i < d->members->dim; i++)
+      {
+	Dsymbol *s = (*d->members)[i];
+	s->accept (this);
+      }
+  }
+
+  /* Walk over all members in the instantiated template.  */
+
+  void visit (TemplateInstance *d)
+  {
+    if (isError (d)|| !d->members)
+      return;
+
+    if (!d->needsCodegen ())
+      return;
+
+    for (size_t i = 0; i < d->members->dim; i++)
+      {
+	Dsymbol *s = (*d->members)[i];
+	s->accept (this);
+      }
+  }
+
+  /* Walk over all members in the mixin template scope.  */
+
+  void visit (TemplateMixin *d)
+  {
+    if (isError (d)|| !d->members)
+      return;
+
+    for (size_t i = 0; i < d->members->dim; i++)
+      {
+	Dsymbol *s = (*d->members)[i];
+	s->accept (this);
+      }
+  }
+
+  /* Write out compiler generated TypeInfo, initializer and functions for the
+     given struct declaration, walking over all static members.  */
+
+  void visit (StructDeclaration *d)
+  {
+    if (d->type->ty == Terror)
+      {
+	d->error ("had semantic errors when compiling");
+	return;
+      }
+
+    /* Add this decl to the current binding level.  */
+    tree ctype = build_ctype (d->type);
+    if (TYPE_NAME (ctype))
+      d_pushdecl (TYPE_NAME (ctype));
+
+    /* Anonymous structs/unions only exist as part of others,
+       do not output forward referenced structs's.  */
+    if (d->isAnonymous () || !d->members)
+      return;
+
+    /* Don't emit any symbols from gcc.attribute module.  */
+    if (gcc_attribute_p (d))
+      return;
+
+    /* Generate TypeInfo.  */
+    create_typeinfo (d->type, NULL);
+
+    /* Generate static initialiser.  */
+    d->sinit = aggregate_initializer_decl (d);
+    DECL_INITIAL (d->sinit) = layout_struct_initializer (d);
+
+    d_finish_decl (d->sinit);
+
+    /* Put out the members.  */
+    for (size_t i = 0; i < d->members->dim; i++)
+      {
+	Dsymbol *member = (*d->members)[i];
+	/* There might be static ctors in the members, and they cannot
+	   be put in separate object files.  */
+	member->accept (this);
+      }
+
+    /* Put out xopEquals, xopCmp and xopHash.  */
+    if (d->xeq && d->xeq != d->xerreq)
+      d->xeq->accept (this);
+
+    if (d->xcmp && d->xcmp != d->xerrcmp)
+      d->xcmp->accept (this);
+
+    if (d->xhash)
+      d->xhash->accept (this);
+  }
+
+  /* Write out compiler generated TypeInfo, initializer and vtables for the
+     given class declaration, walking over all static members.  */
+
+  void visit (ClassDeclaration *d)
+  {
+    if (d->type->ty == Terror)
+      {
+	d->error ("had semantic errors when compiling");
+	return;
+      }
+
+    if (!d->members)
+      return;
+
+    /* Put out the members.  */
+    for (size_t i = 0; i < d->members->dim; i++)
+      {
+	Dsymbol *member = (*d->members)[i];
+	member->accept (this);
+      }
+
+    /* Generate C symbols.  */
+    d->csym = get_classinfo_decl (d);
+    d->vtblsym = get_vtable_decl (d);
+    d->sinit = aggregate_initializer_decl (d);
+
+    /* Generate static initialiser.  */
+    DECL_INITIAL (d->sinit) = layout_class_initializer (d);
+    d_finish_decl (d->sinit);
+
+    /* Put out the TypeInfo.  */
+    create_typeinfo (d->type, NULL);
+    DECL_INITIAL (d->csym) = layout_classinfo (d);
+    d_finish_decl (d->csym);
+
+    /* Put out the vtbl[].  */
+    vec<constructor_elt, va_gc> *elms = NULL;
+
+    /* First entry is ClassInfo reference.  */
+    if (d->vtblOffset ())
+      CONSTRUCTOR_APPEND_ELT (elms, size_zero_node, build_address (d->csym));
+
+    for (size_t i = d->vtblOffset (); i < d->vtbl.dim; i++)
+      {
+	FuncDeclaration *fd = d->vtbl[i]->isFuncDeclaration ();
+
+	if (!fd || (!fd->fbody && d->isAbstract ()))
+	  continue;
+
+	fd->functionSemantic ();
+
+	if (d->isFuncHidden (fd))
+	  {
+	    /* The function fd is hidden from the view of the class.
+	       If it overlaps with any function in the vtbl[], then
+	       issue an error.  */
+	    for (size_t j = 1; j < d->vtbl.dim; j++)
+	      {
+		if (j == i)
+		  continue;
+
+		FuncDeclaration *fd2 = d->vtbl[j]->isFuncDeclaration ();
+		if (!fd2->ident->equals (fd->ident))
+		  continue;
+
+		if (fd->leastAsSpecialized (fd2) || fd2->leastAsSpecialized (fd))
+		  {
+		    TypeFunction *tf = (TypeFunction *) fd->type;
+		    if (tf->ty == Tfunction)
+		      {
+			d->error ("use of %s%s is hidden by %s; "
+				  "use 'alias %s = %s.%s;' "
+				  "to introduce base class overload set.",
+				  fd->toPrettyChars (),
+				  parametersTypeToChars (tf->parameters, tf->varargs),
+				  d->toChars (), fd->toChars (),
+				  fd->parent->toChars (), fd->toChars ());
+		      }
+		    else
+		      {
+			error ("use of %s is hidden by %s",
+			       fd->toPrettyChars (), d->toChars ());
+		      }
+
+		    break;
+		  }
+	      }
+	  }
+
+	CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
+				build_address (get_symbol_decl (fd)));
+      }
+
+    DECL_INITIAL (d->vtblsym)
+      = build_constructor (TREE_TYPE (d->vtblsym), elms);
+    d_finish_decl (d->vtblsym);
+
+    /* Add this decl to the current binding level.  */
+    tree ctype = TREE_TYPE (build_ctype (d->type));
+    if (TYPE_NAME (ctype))
+      d_pushdecl (TYPE_NAME (ctype));
+  }
+
+  /* Write out compiler generated TypeInfo and vtables for the given interface
+     declaration, walking over all static members.  */
+
+  void visit (InterfaceDeclaration *d)
+  {
+    if (d->type->ty == Terror)
+      {
+	d->error ("had semantic errors when compiling");
+	return;
+      }
+
+    if (!d->members)
+      return;
+
+    /* Put out the members.  */
+    for (size_t i = 0; i < d->members->dim; i++)
+      {
+	Dsymbol *member = (*d->members)[i];
+	member->accept (this);
+      }
+
+    /* Generate C symbols.  */
+    d->csym = get_classinfo_decl (d);
+
+    /* Put out the TypeInfo.  */
+    create_typeinfo (d->type, NULL);
+    d->type->vtinfo->accept (this);
+    DECL_INITIAL (d->csym) = layout_classinfo (d);
+    d_finish_decl (d->csym);
+
+    /* Add this decl to the current binding level.  */
+    tree ctype = TREE_TYPE (build_ctype (d->type));
+    if (TYPE_NAME (ctype))
+      d_pushdecl (TYPE_NAME (ctype));
+  }
+
+  /* Write out compiler generated TypeInfo and initializer for the given
+     enum declaration.  */
+
+  void visit (EnumDeclaration *d)
+  {
+    if (d->semanticRun >= PASSobj)
+      return;
+
+    if (d->errors || d->type->ty == Terror)
+      {
+	d->error ("had semantic errors when compiling");
+	return;
+      }
+
+    if (d->isAnonymous ())
+      return;
+
+    /* Generate TypeInfo.  */
+    create_typeinfo (d->type, NULL);
+
+    TypeEnum *tc = (TypeEnum *) d->type;
+    if (tc->sym->members && !d->type->isZeroInit ())
+      {
+	/* Generate static initialiser.  */
+	d->sinit = enum_initializer_decl (d);
+	DECL_INITIAL (d->sinit) = build_expr (tc->sym->defaultval, true);
+	d_finish_decl (d->sinit);
+
+	/* Add this decl to the current binding level.  */
+	tree ctype = build_ctype (d->type);
+	if (TREE_CODE (ctype) == ENUMERAL_TYPE && TYPE_NAME (ctype))
+	  d_pushdecl (TYPE_NAME (ctype));
+      }
+
+    d->semanticRun = PASSobj;
+  }
+
+  /* Finish up a variable declaration and push it into the current scope.
+     This can either be a static, local or manifest constant.  */
+
+  void visit (VarDeclaration *d)
+  {
+    if (d->type->ty == Terror)
+      {
+	d->error ("had semantic errors when compiling");
+	return;
+      }
+
+    if (d->aliassym)
+      {
+	d->toAlias ()->accept (this);
+	return;
+      }
+
+    /* Do not store variables we cannot take the address of,
+       but keep the values for purposes of debugging.  */
+    if (!d->canTakeAddressOf ())
+      {
+	/* Don't know if there is a good way to handle instantiations.  */
+	if (d->isInstantiated ())
+	  return;
+
+	tree decl = get_symbol_decl (d);
+	gcc_assert (d->_init && !d->_init->isVoidInitializer ());
+	Expression *ie = d->_init->toExpression ();
+
+	/* CONST_DECL was initially intended for enumerals and may be used for
+	   scalars in general, but not for aggregates.  Here a non-constant
+	   value is generated anyway so as the CONST_DECL only serves as a
+	   placeholder for the value, however the DECL itself should never be
+	   referenced in any generated code, or passed to the backend.  */
+	if (!d->type->isscalar ())
+	  DECL_INITIAL (decl) = build_expr (ie, false);
+	else
+	  {
+	    DECL_INITIAL (decl) = build_expr (ie, true);
+	    d_pushdecl (decl);
+	    rest_of_decl_compilation (decl, 1, 0);
+	  }
+      }
+    else if (d->isDataseg () && !(d->storage_class & STCextern))
+      {
+	tree s = get_symbol_decl (d);
+
+	/* Duplicated VarDeclarations map to the same symbol. Check if this
+	   is the one declaration which will be emitted.  */
+	tree ident = DECL_ASSEMBLER_NAME (s);
+	if (IDENTIFIER_DSYMBOL (ident) && IDENTIFIER_DSYMBOL (ident) != d)
+	  return;
+
+	/* How big a symbol can be should depend on backend.  */
+	tree size = build_integer_cst (d->type->size (d->loc),
+				       build_ctype (Type::tsize_t));
+	if (!valid_constant_size_p (size))
+	  {
+	    d->error ("size is too large");
+	    return;
+	  }
+
+	if (d->_init && !d->_init->isVoidInitializer ())
+	  {
+	    Expression *e = d->_init->toExpression (d->type);
+	    DECL_INITIAL (s) = build_expr (e, true);
+	  }
+	else
+	  {
+	    if (d->type->ty == Tstruct)
+	      {
+		StructDeclaration *sd = ((TypeStruct *) d->type)->sym;
+		DECL_INITIAL (s) = layout_struct_initializer (sd);
+	      }
+	    else
+	      {
+		Expression *e = d->type->defaultInitLiteral (d->loc);
+		DECL_INITIAL (s) = build_expr (e, true);
+	      }
+	  }
+
+	/* Frontend should have already caught this.  */
+	gcc_assert (!integer_zerop (size)
+		    || d->type->toBasetype ()->ty == Tsarray);
+
+	d_finish_decl (s);
+
+	/* Maybe record the var against the current module.  */
+	register_module_decl (d);
+      }
+    else if (!d->isDataseg () && !d->isMember ())
+      {
+	/* This is needed for VarDeclarations in mixins that are to be local
+	   variables of a function.  Otherwise, it would be enough to make
+	   a check for isVarDeclaration() in DeclarationExp codegen.  */
+	declare_local_var (d);
+
+	if (d->_init)
+	  {
+	    if (!d->_init->isVoidInitializer ())
+	      {
+		ExpInitializer *vinit = d->_init->isExpInitializer ();
+		Expression *ie = vinit->toExpression ();
+		tree exp = build_expr (ie);
+		add_stmt (exp);
+	      }
+	    else if (d->size (d->loc) != 0)
+	      {
+		/* Zero-length arrays do not have an initializer.  */
+		warning (OPT_Wuninitialized, "uninitialized variable '%s'",
+			 d->ident ? d->ident->toChars () : "(no name)");
+	      }
+	  }
+      }
+  }
+
+  /* Generate and compile a static TypeInfo declaration, but only if it is
+     needed in the current compilation.  */
+
+  void visit (TypeInfoDeclaration *d)
+  {
+    if (speculative_type_p (d->tinfo))
+      return;
+
+    tree s = get_typeinfo_decl (d);
+    DECL_INITIAL (s) = layout_typeinfo (d);
+    d_finish_decl (s);
+  }
+
+  /* Finish up a function declaration and compile it all the way
+     down to assembler language output.  */
+
+  void visit (FuncDeclaration *d)
+  {
+    /* Already generated the function.  */
+    if (d->semanticRun >= PASSobj)
+      return;
+
+    /* Don't emit any symbols from gcc.attribute module.  */
+    if (gcc_attribute_p (d))
+      return;
+
+    /* Not emitting unittest functions.  */
+    if (!global.params.useUnitTests && d->isUnitTestDeclaration ())
+      return;
+
+    /* Check if any errors occurred when running semantic.  */
+    if (d->type->ty == Tfunction)
+      {
+	TypeFunction *tf = (TypeFunction *) d->type;
+	if (tf->next == NULL || tf->next->ty == Terror)
+	  return;
+      }
+
+    if (d->semantic3Errors)
+      return;
+
+    if (d->isNested ())
+      {
+	FuncDeclaration *fdp = d;
+	while (fdp && fdp->isNested ())
+	  {
+	    fdp = fdp->toParent2 ()->isFuncDeclaration ();
+
+	    if (fdp == NULL)
+	      break;
+
+	    /* Parent failed to compile, but errors were gagged.  */
+	    if (fdp->semantic3Errors)
+	      return;
+	  }
+      }
+
+    /* Ensure all semantic passes have ran.  */
+    if (d->semanticRun < PASSsemantic3)
+      {
+	d->functionSemantic3 ();
+	Module::runDeferredSemantic3 ();
+      }
+
+    if (global.errors)
+      return;
+
+    /* Duplicated FuncDeclarations map to the same symbol. Check if this
+       is the one declaration which will be emitted.  */
+    tree fndecl = get_symbol_decl (d);
+    tree ident = DECL_ASSEMBLER_NAME (fndecl);
+    if (IDENTIFIER_DSYMBOL (ident) && IDENTIFIER_DSYMBOL (ident) != d)
+      return;
+
+    /* For nested functions in particular, unnest fndecl in the cgraph, as
+       all static chain passing is handled by the front-end.  Do this even
+       if we are not emitting the body.  */
+    struct cgraph_node *node = cgraph_node::get_create (fndecl);
+    if (node->origin)
+      node->unnest ();
+
+    if (!d->fbody)
+      {
+	rest_of_decl_compilation (fndecl, 1, 0);
+	return;
+      }
+
+    if (global.params.verbose)
+      fprintf (global.stdmsg, "function  %s\n", d->toPrettyChars ());
+
+    /* Start generating code for this function.  */
+    gcc_assert (d->semanticRun == PASSsemantic3done);
+    d->semanticRun = PASSobj;
+
+    tree old_context = start_function (d);
+
+    tree parm_decl = NULL_TREE;
+    tree param_list = NULL_TREE;
+
+    /* Special arguments...  */
+
+    /* 'this' parameter:
+       For nested functions, D still generates a vthis, but it
+       should not be referenced in any expression.  */
+    if (d->vthis)
+      {
+	parm_decl = get_symbol_decl (d->vthis);
+	DECL_ARTIFICIAL (parm_decl) = 1;
+	TREE_READONLY (parm_decl) = 1;
+
+	if (d->vthis->type == Type::tvoidptr)
+	  {
+	    /* Replace generic pointer with backend closure type
+	       (this wins for gdb).  */
+	    tree frame_type = FRAMEINFO_TYPE (get_frameinfo (d));
+	    gcc_assert (frame_type != NULL_TREE);
+	    TREE_TYPE (parm_decl) = build_pointer_type (frame_type);
+	  }
+
+	param_list = chainon (param_list, parm_decl);
+	d_function_chain->static_chain = parm_decl;
+      }
+
+    /* _arguments parameter.  */
+    if (d->v_arguments)
+      {
+	parm_decl = get_symbol_decl (d->v_arguments);
+	param_list = chainon (param_list, parm_decl);
+      }
+
+    /* formal function parameters.  */
+    size_t n_parameters = d->parameters ? d->parameters->dim : 0;
+
+    for (size_t i = 0; i < n_parameters; i++)
+      {
+	VarDeclaration *param = (*d->parameters)[i];
+	parm_decl = get_symbol_decl (param);
+	/* Chain them in the correct order.  */
+	param_list = chainon (param_list, parm_decl);
+      }
+
+    DECL_ARGUMENTS (fndecl) = param_list;
+    rest_of_decl_compilation (fndecl, 1, 0);
+    input_location = get_linemap (d->loc);
+
+    /* If this is a member function that nested (possibly indirectly) in another
+       function, construct an expession for this member function's static chain
+       by going through parent link of nested classes.  */
+    if (d->isThis ())
+      {
+	AggregateDeclaration *ad = d->isThis ();
+	tree this_tree = get_symbol_decl (d->vthis);
+
+	while (ad->isNested ())
+	  {
+	    Dsymbol *pd = ad->toParent2 ();
+	    tree vthis_field = get_symbol_decl (ad->vthis);
+	    this_tree = component_ref (build_deref (this_tree), vthis_field);
+
+	    ad = pd->isAggregateDeclaration ();
+	    if (ad == NULL)
+	      {
+		cfun->language->static_chain = this_tree;
+		break;
+	      }
+	  }
+      }
+
+    /* May change cfun->static_chain.  */
+    build_closure (d);
+
+    if (d->vresult)
+      declare_local_var (d->vresult);
+
+    if (d->v_argptr)
+      push_stmt_list ();
+
+    /* The fabled D named return value optimisation.
+       Implemented by overriding all the RETURN_EXPRs and replacing all
+       occurrences of VAR with the RESULT_DECL for the function.
+       This is only worth doing for functions that can return in memory.  */
+    if (d->nrvo_can)
+      {
+	tree restype = TREE_TYPE (DECL_RESULT (fndecl));
+
+	if (!AGGREGATE_TYPE_P (restype))
+	  d->nrvo_can = 0;
+	else
+	  d->nrvo_can = aggregate_value_p (restype, fndecl);
+      }
+
+    if (d->nrvo_can)
+      {
+	tree resdecl = DECL_RESULT (fndecl);
+
+	TREE_TYPE (resdecl)
+	  = build_reference_type (TREE_TYPE (resdecl));
+	DECL_BY_REFERENCE (resdecl) = 1;
+	TREE_ADDRESSABLE (resdecl) = 0;
+	relayout_decl (resdecl);
+
+	if (d->nrvo_var)
+	  {
+	    tree var = get_symbol_decl (d->nrvo_var);
+
+	    /* Copy name from VAR to RESULT.  */
+	    DECL_NAME (resdecl) = DECL_NAME (var);
+	    /* Don't forget that we take it's address.  */
+	    TREE_ADDRESSABLE (var) = 1;
+	    resdecl = build_deref (resdecl);
+
+	    SET_DECL_VALUE_EXPR (var, resdecl);
+	    DECL_HAS_VALUE_EXPR_P (var) = 1;
+	    SET_DECL_LANG_NRVO (var, resdecl);
+	  }
+      }
+
+    build_function_body (d);
+
+    if (d->v_argptr)
+      {
+	tree body = pop_stmt_list ();
+	tree var = get_decl_tree (d->v_argptr);
+	var = build_address (var);
+
+	tree init = build_call_expr (builtin_decl_explicit (BUILT_IN_VA_START),
+				     2, var, parm_decl);
+	declare_local_var (d->v_argptr);
+	add_stmt (init);
+
+	tree cleanup = build_call_expr (builtin_decl_explicit (BUILT_IN_VA_END),
+					1, var);
+	add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, body, cleanup));
+      }
+
+    finish_function (old_context);
+
+    /* Maybe record the function against the current module.  */
+    register_module_decl (d);
+  }
+};
+
+/* Main entry point for the DeclVisitor interface to send
+   the Declaration AST class D to GCC backend.  */
+
+void
+build_decl_tree (Dsymbol *d)
+{
+  DeclVisitor v = DeclVisitor ();
+  d->accept (&v);
+}
+
+/* Return the decl for the symbol, create it if it doesn't already exist.  */
+
+tree
+get_symbol_decl (Declaration *decl)
+{
+  if (decl->csym)
+    return decl->csym;
+
+  /* Deal with placeholder symbols immediately:
+     SymbolDeclaration is used as a shell around an initializer symbol.  */
+  SymbolDeclaration *sd = decl->isSymbolDeclaration ();
+  if (sd)
+    {
+      decl->csym = aggregate_initializer_decl (sd->dsym);
+      return decl->csym;
+    }
+
+  /* Global static TypeInfo declaration.  */
+  if (decl->isTypeInfoDeclaration ())
+    return get_typeinfo_decl ((TypeInfoDeclaration *) decl);
+
+  /* FuncAliasDeclaration is used to import functions from another scope.  */
+  FuncAliasDeclaration *fad = decl->isFuncAliasDeclaration ();
+  if (fad)
+    {
+      decl->csym = get_symbol_decl (fad->funcalias);
+      return decl->csym;
+    }
+
+  /* It is possible for a field declaration symbol to be requested
+     before the parent type has been built.  */
+  if (decl->isField ())
+    {
+      AggregateDeclaration *ad = decl->toParent ()->isAggregateDeclaration ();
+      gcc_assert (ad != NULL);
+
+      /* Finishing off the type should create the associated FIELD_DECL.  */
+      build_ctype (ad->type);
+      gcc_assert (decl->csym != NULL);
+
+      return decl->csym;
+    }
+
+  /* Build the tree for the symbol.  */
+  FuncDeclaration *fd = decl->isFuncDeclaration ();
+  if (fd)
+    {
+      /* Run full semantic on functions we need to know about.  */
+      if (!fd->functionSemantic ())
+	{
+	  decl->csym = error_mark_node;
+	  return decl->csym;
+	}
+
+      decl->csym = build_decl (get_linemap (decl->loc), FUNCTION_DECL,
+			       get_identifier (decl->ident->toChars ()),
+			       NULL_TREE);
+
+      /* Set function type afterwards as there could be self references.  */
+      TREE_TYPE (decl->csym) = build_ctype (fd->type);
+
+      if (!fd->fbody)
+	DECL_EXTERNAL (decl->csym) = 1;
+    }
+  else
+    {
+      /* Build the variable declaration.  */
+      VarDeclaration *vd = decl->isVarDeclaration ();
+      gcc_assert (vd != NULL);
+
+      tree_code code = vd->isParameter () ? PARM_DECL
+	: !vd->canTakeAddressOf () ? CONST_DECL
+	: VAR_DECL;
+      decl->csym = build_decl (get_linemap (decl->loc), code,
+			       get_identifier (decl->ident->toChars ()),
+			       declaration_type (vd));
+
+      /* If any alignment was set on the declaration.  */
+      if (vd->alignment != STRUCTALIGN_DEFAULT)
+	{
+	  SET_DECL_ALIGN (decl->csym, vd->alignment * BITS_PER_UNIT);
+	  DECL_USER_ALIGN (decl->csym) = 1;
+	}
+
+      if (vd->storage_class & STCextern)
+	DECL_EXTERNAL (decl->csym) = 1;
+    }
+
+  /* Set the declaration mangled identifier if static.  */
+  if (decl->isCodeseg () || decl->isDataseg ())
+    {
+      tree mangled_name;
+
+      if (decl->mangleOverride)
+	mangled_name = get_identifier (decl->mangleOverride);
+      else
+	mangled_name = get_identifier (mangle_decl (decl));
+
+      mangled_name = targetm.mangle_decl_assembler_name (decl->csym,
+							 mangled_name);
+      /* The frontend doesn't handle duplicate definitions of unused symbols
+	 with the same mangle.  So a check is done here instead.  */
+      if (!DECL_EXTERNAL (decl->csym))
+	{
+	  if (IDENTIFIER_DSYMBOL (mangled_name))
+	    {
+	      Declaration *other = IDENTIFIER_DSYMBOL (mangled_name);
+
+	      /* Non-templated variables shouldn't be defined twice.  */
+	      if (!decl->isInstantiated ())
+		ScopeDsymbol::multiplyDefined (decl->loc, decl, other);
+
+	      decl->csym = get_symbol_decl (other);
+	      return decl->csym;
+	    }
+
+	  IDENTIFIER_PRETTY_NAME (mangled_name) =
+	    get_identifier (decl->toPrettyChars (true));
+	  IDENTIFIER_DSYMBOL (mangled_name) = decl;
+	}
+
+      SET_DECL_ASSEMBLER_NAME (decl->csym, mangled_name);
+    }
+
+  DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (decl);
+  DECL_CONTEXT (decl->csym) = d_decl_context (decl);
+
+  if (TREE_CODE (decl->csym) == PARM_DECL)
+    {
+      /* Pass non-trivial structs by invisible reference.  */
+      if (TREE_ADDRESSABLE (TREE_TYPE (decl->csym)))
+	{
+	  tree argtype = build_reference_type (TREE_TYPE (decl->csym));
+	  argtype = build_qualified_type (argtype, TYPE_QUAL_RESTRICT);
+	  gcc_assert (!DECL_BY_REFERENCE (decl->csym));
+	  TREE_TYPE (decl->csym) = argtype;
+	  DECL_BY_REFERENCE (decl->csym) = 1;
+	  TREE_ADDRESSABLE (decl->csym) = 0;
+	  relayout_decl (decl->csym);
+	  decl->storage_class |= STCref;
+	}
+
+      DECL_ARG_TYPE (decl->csym) = TREE_TYPE (decl->csym);
+      gcc_assert (TREE_CODE (DECL_CONTEXT (decl->csym)) == FUNCTION_DECL);
+    }
+  else if (TREE_CODE (decl->csym) == CONST_DECL)
+    {
+      /* Manifest constants have no address in memory.  */
+      TREE_CONSTANT (decl->csym) = 1;
+      TREE_READONLY (decl->csym) = 1;
+    }
+  else if (TREE_CODE (decl->csym) == FUNCTION_DECL)
+    {
+      /* The real function type may differ from it's declaration.  */
+      tree fntype = TREE_TYPE (decl->csym);
+      tree newfntype = NULL_TREE;
+
+      if (fd->isNested ())
+	{
+	  /* Add an extra argument for the frame/closure pointer, this is also
+	     required to be compatible with D delegates.  */
+	  newfntype = build_vthis_function (void_type_node, fntype);
+	}
+      else if (fd->isThis ())
+	{
+	  /* Add an extra argument for the 'this' parameter.  The handle type is
+	     used even if there is no debug info.  It is needed to make sure
+	     virtual member functions are not called statically.  */
+	  AggregateDeclaration *ad = fd->isMember2 ();
+	  tree handle = build_ctype (ad->handleType ());
+
+	  /* If handle is a pointer type, get record type.  */
+	  if (!ad->isStructDeclaration ())
+	    handle = TREE_TYPE (handle);
+
+	  newfntype = build_vthis_function (handle, fntype);
+
+	  /* Set the vindex on virtual functions.  */
+	  if (fd->isVirtual () && fd->vtblIndex != -1)
+	    {
+	      DECL_VINDEX (decl->csym) = size_int (fd->vtblIndex);
+	      DECL_VIRTUAL_P (decl->csym) = 1;
+	    }
+	}
+      else if (fd->isMain ())
+	{
+	  /* The main function is named 'D main' to distinguish from C main.  */
+	  DECL_NAME (decl->csym) = get_identifier (fd->toPrettyChars (true));
+
+	  /* 'void main' is implicitly converted to returning an int.  */
+	  newfntype = build_function_type (int_type_node,
+					   TYPE_ARG_TYPES (fntype));
+	}
+
+      if (newfntype != NULL_TREE)
+	{
+	  /* Copy the old attributes from the original type.  */
+	  TYPE_ATTRIBUTES (newfntype) = TYPE_ATTRIBUTES (fntype);
+	  TYPE_LANG_SPECIFIC (newfntype) = TYPE_LANG_SPECIFIC (fntype);
+	  TREE_ADDRESSABLE (newfntype) = TREE_ADDRESSABLE (fntype);
+	  TREE_TYPE (decl->csym) = newfntype;
+	  d_keep (newfntype);
+	}
+
+      /* Miscellaneous function flags.  */
+      if (fd->isMember2 () || fd->isFuncLiteralDeclaration ())
+	{
+	  /* See grokmethod in cp/decl.c.  Maybe we shouldn't be setting inline
+	     flags without reason or proper handling.  */
+	  DECL_DECLARED_INLINE_P (decl->csym) = 1;
+	  DECL_NO_INLINE_WARNING_P (decl->csym) = 1;
+	}
+
+      /* Function was declared 'naked'.  */
+      if (fd->naked)
+	{
+	  DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1;
+	  DECL_UNINLINABLE (decl->csym) = 1;
+	}
+
+      /* Vector array operations are always compiler generated.  */
+      if (fd->isArrayOp)
+	{
+	  DECL_ARTIFICIAL (decl->csym) = 1;
+	  D_DECL_ONE_ONLY (decl->csym) = 1;
+	}
+
+      /* And so are ensure and require contracts.  */
+      if (fd->ident == Id::ensure || fd->ident == Id::require)
+	{
+	  DECL_ARTIFICIAL (decl->csym) = 1;
+	  TREE_PUBLIC (decl->csym) = 1;
+	}
+
+      if (decl->storage_class & STCfinal)
+	DECL_FINAL_P (decl->csym) = 1;
+
+      /* Check whether this function is expanded by the frontend.  */
+      maybe_set_intrinsic (fd);
+    }
+
+  /* Mark compiler generated temporaries as artificial.  */
+  if (decl->storage_class & STCtemp)
+    DECL_ARTIFICIAL (decl->csym) = 1;
+
+  /* Propagate shared on the decl.  */
+  if (TYPE_SHARED (TREE_TYPE (decl->csym)))
+    TREE_ADDRESSABLE (decl->csym) = 1;
+
+  /* Symbol was marked volatile.  */
+  if (decl->storage_class & STCvolatile)
+    TREE_THIS_VOLATILE (decl->csym) = 1;
+
+  /* Protection attributes are used by the debugger.  */
+  if (decl->protection == PROTprivate)
+    TREE_PRIVATE (decl->csym) = 1;
+  else if (decl->protection == PROTprotected)
+    TREE_PROTECTED (decl->csym) = 1;
+
+  /* Likewise, so could the deprecated attribute.  */
+  if (decl->storage_class & STCdeprecated)
+    TREE_DEPRECATED (decl->csym) = 1;
+
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+  /* Have to test for import first.  */
+  if (decl->isImportedSymbol ())
+    {
+      insert_decl_attribute (decl->csym, "dllimport");
+      DECL_DLLIMPORT_P (decl->csym) = 1;
+    }
+  else if (decl->isExport ())
+    insert_decl_attribute (decl->csym, "dllexport");
+#endif
+
+  if (decl->isDataseg () || decl->isCodeseg () || decl->isThreadlocal ())
+    {
+      /* Check if the declaration is a template, and whether it will be emitted
+	 in the current compilation or not.  */
+      TemplateInstance *ti = decl->isInstantiated ();
+      if (ti)
+	{
+	  D_DECL_ONE_ONLY (decl->csym) = 1;
+
+	  if (!DECL_EXTERNAL (decl->csym) && ti->needsCodegen ())
+	    {
+	      /* Warn about templates instantiated in this compilation.  */
+	      if (ti == decl->parent)
+		{
+		  warning (OPT_Wtemplates, "%s %s instantiated",
+			   ti->kind (), ti->toPrettyChars (false));
+		}
+
+	      TREE_STATIC (decl->csym) = 1;
+	    }
+	  else
+	    DECL_EXTERNAL (decl->csym) = 1;
+	}
+      else
+	{
+	  if (!DECL_EXTERNAL (decl->csym)
+	      && decl->getModule () && decl->getModule ()->isRoot ())
+	    TREE_STATIC (decl->csym) = 1;
+	  else
+	    DECL_EXTERNAL (decl->csym) = 1;
+	}
+
+      /* Set TREE_PUBLIC by default, but allow private template to override.  */
+      if (!fd || !fd->isNested ())
+	TREE_PUBLIC (decl->csym) = 1;
+
+      if (D_DECL_ONE_ONLY (decl->csym))
+	d_comdat_linkage (decl->csym);
+    }
+
+  /* Symbol is going in thread local storage.  */
+  if (decl->isThreadlocal () && !DECL_ARTIFICIAL (decl->csym))
+    {
+      if (global.params.vtls)
+	{
+	  const char *p = decl->loc.toChars ();
+	  fprintf (global.stdmsg, "%s: %s is thread local\n",
+		   p ? p : "", decl->toChars ());
+	  if (p)
+	    free (CONST_CAST (char *, p));
+	}
+
+      set_decl_tls_model (decl->csym, decl_default_tls_model (decl->csym));
+    }
+
+  /* Apply any user attributes that may affect semantic meaning.  */
+  if (decl->userAttribDecl)
+    {
+      Expressions *attrs = decl->userAttribDecl->getAttributes ();
+      decl_attributes (&decl->csym, build_attributes (attrs), 0);
+    }
+  else if (DECL_ATTRIBUTES (decl->csym) != NULL)
+    decl_attributes (&decl->csym, DECL_ATTRIBUTES (decl->csym), 0);
+
+  /* %% Probably should be a little more intelligent about setting this.  */
+  TREE_USED (decl->csym) = 1;
+  d_keep (decl->csym);
+
+  return decl->csym;
+}
+
+/* Returns a declaration for a VAR_DECL.  Used to create compiler-generated
+   global variables.  */
+
+tree
+declare_extern_var (tree ident, tree type)
+{
+  tree name = IDENTIFIER_PRETTY_NAME (ident)
+    ? IDENTIFIER_PRETTY_NAME (ident) : ident;
+  tree decl = build_decl (input_location, VAR_DECL, name, type);
+
+  d_keep (decl);
+
+  SET_DECL_ASSEMBLER_NAME (decl, ident);
+  DECL_ARTIFICIAL (decl) = 1;
+  TREE_STATIC (decl) = 1;
+  TREE_PUBLIC (decl) = 1;
+
+  /* The decl has not been defined -- yet.  */
+  DECL_EXTERNAL (decl) = 1;
+
+  return decl;
+}
+
+/* Add local variable VAR into the current function body.  */
+
+void
+declare_local_var (VarDeclaration *var)
+{
+  gcc_assert (!var->isDataseg () && !var->isMember ());
+  gcc_assert (current_function_decl != NULL_TREE);
+
+  FuncDeclaration *fd = cfun->language->function;
+  tree decl = get_symbol_decl (var);
+
+  gcc_assert (!TREE_STATIC (decl));
+
+  input_location = get_linemap (var->loc);
+  d_pushdecl (decl);
+  DECL_CONTEXT (decl) = current_function_decl;
+
+  /* Compiler generated symbols.  */
+  if (var == fd->vresult || var == fd->v_argptr)
+    DECL_ARTIFICIAL (decl) = 1;
+
+  if (DECL_LANG_FRAME_FIELD (decl))
+    {
+      /* Fixes debugging local variables.  */
+      SET_DECL_VALUE_EXPR (decl, get_decl_tree (var));
+      DECL_HAS_VALUE_EXPR_P (decl) = 1;
+    }
+}
+
+/* Return an unnamed local temporary of type TYPE.  */
+
+tree
+build_local_temp (tree type)
+{
+  tree decl = build_decl (input_location, VAR_DECL, NULL_TREE, type);
+
+  DECL_CONTEXT (decl) = current_function_decl;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  d_pushdecl (decl);
+
+  return decl;
+}
+
+/* Return the correct decl to be used for DECL.  For VAR_DECLs, this could
+   instead be a FIELD_DECL from a closure, or a RESULT_DECL from a named return
+   value.  For PARM_DECLs, this could be a FIELD_DECL for a non-local `this'.
+   For all other kinds of decls, this just returns the result of
+   get_symbol_decl().  */
+
+tree
+get_decl_tree (Declaration *decl)
+{
+  tree t = get_symbol_decl (decl);
+  FuncDeclaration *fd = cfun ? cfun->language->function : NULL;
+  VarDeclaration *vd = decl->isVarDeclaration ();
+
+  /* If cfun is NULL, then this is a global static.  */
+  if (vd == NULL || fd == NULL)
+    return t;
+
+  /* Get the named return value.  */
+  if (DECL_LANG_NRVO (t))
+    return DECL_LANG_NRVO (t);
+
+  /* Get the closure holding the var decl.  */
+  if (DECL_LANG_FRAME_FIELD (t))
+    {
+      FuncDeclaration *parent = vd->toParent2 ()->isFuncDeclaration ();
+      tree frame_ref = get_framedecl (fd, parent);
+
+      return component_ref (build_deref (frame_ref),
+			    DECL_LANG_FRAME_FIELD (t));
+    }
+
+  /* Get the non-local 'this' value by going through parent link
+     of nested classes, this routine pretty much undoes what
+     getRightThis in the frontend removes from codegen.  */
+  if (vd->parent != fd && vd->isThisDeclaration ())
+    {
+      AggregateDeclaration *ad = fd->isThis ();
+      gcc_assert (ad != NULL);
+
+      t = get_symbol_decl (fd->vthis);
+      Dsymbol *outer = fd;
+
+      while (outer != vd->parent)
+	{
+	  gcc_assert (ad != NULL);
+	  outer = ad->toParent2 ();
+
+	  /* Get the this->this parent link.  */
+	  tree vfield = get_symbol_decl (ad->vthis);
+	  t = component_ref (build_deref (t), vfield);
+
+	  ad = outer->isAggregateDeclaration ();
+	  if (ad != NULL)
+	    continue;
+
+	  fd = outer->isFuncDeclaration ();
+	  while (fd != NULL)
+	    {
+	      /* If outer function creates a closure, then the 'this'
+		 value would be the closure pointer, and the real
+		 'this' the first field of that closure.  */
+	      tree ff = get_frameinfo (fd);
+	      if (FRAMEINFO_CREATES_FRAME (ff))
+		{
+		  t = build_nop (build_pointer_type (FRAMEINFO_TYPE (ff)), t);
+		  t = indirect_ref (build_ctype (fd->vthis->type), t);
+		}
+
+	      if (fd == vd->parent)
+		break;
+
+	      /* Continue looking for the right `this'.  */
+	      outer = outer->toParent2 ();
+	      fd = outer->isFuncDeclaration ();
+	    }
+
+	  ad = outer->isAggregateDeclaration ();
+	}
+
+      return t;
+    }
+
+  /* Auto variable that the back end will handle for us.  */
+  return t;
+}
+
+/* Finish up a variable declaration and compile it all the way to
+   the assembler language output.  */
+
+void
+d_finish_decl (tree decl)
+{
+  gcc_assert (!error_operand_p (decl));
+
+  /* We are sending this symbol to object file, can't be extern.  */
+  TREE_STATIC (decl) = 1;
+  DECL_EXTERNAL (decl) = 0;
+  relayout_decl (decl);
+
+#ifdef ENABLE_TREE_CHECKING
+  if (DECL_INITIAL (decl) != NULL_TREE)
+    {
+      /* Initialiser must never be bigger than symbol size.  */
+      dinteger_t tsize = int_size_in_bytes (TREE_TYPE (decl));
+      dinteger_t dtsize = int_size_in_bytes (TREE_TYPE (DECL_INITIAL (decl)));
+
+      if (tsize < dtsize)
+	{
+	  tree name = DECL_ASSEMBLER_NAME (decl);
+
+	  internal_error ("Mismatch between declaration '%qE' size (%wd) and "
+			  "it's initializer size (%wd).",
+			  IDENTIFIER_PRETTY_NAME (name)
+			  ? IDENTIFIER_PRETTY_NAME (name) : name,
+			  tsize, dtsize);
+	}
+    }
+#endif
+
+  /* Add this decl to the current binding level.  */
+  d_pushdecl (decl);
+
+  rest_of_decl_compilation (decl, 1, 0);
+}
+
+/* Thunk code is based on g++ */
+
+static int thunk_labelno;
+
+/* Create a static alias to function.  */
+
+static tree
+make_alias_for_thunk (tree function)
+{
+  tree alias;
+  char buf[256];
+
+  /* Thunks may reference extern functions which cannot be aliased.  */
+  if (DECL_EXTERNAL (function))
+    return function;
+
+  targetm.asm_out.generate_internal_label (buf, "LTHUNK", thunk_labelno);
+  thunk_labelno++;
+
+  alias = build_decl (DECL_SOURCE_LOCATION (function), FUNCTION_DECL,
+		      get_identifier (buf), TREE_TYPE (function));
+  DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function);
+  lang_hooks.dup_lang_specific_decl (alias);
+  DECL_CONTEXT (alias) = NULL_TREE;
+  TREE_READONLY (alias) = TREE_READONLY (function);
+  TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function);
+  TREE_PUBLIC (alias) = 0;
+
+  DECL_EXTERNAL (alias) = 0;
+  DECL_ARTIFICIAL (alias) = 1;
+
+  DECL_DECLARED_INLINE_P (alias) = 0;
+  DECL_INITIAL (alias) = error_mark_node;
+  DECL_ARGUMENTS (alias) = copy_list (DECL_ARGUMENTS (function));
+
+  TREE_ADDRESSABLE (alias) = 1;
+  TREE_USED (alias) = 1;
+  SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias));
+
+  if (!flag_syntax_only)
+    {
+      cgraph_node *aliasn;
+      aliasn = cgraph_node::create_same_body_alias (alias, function);
+      gcc_assert (aliasn != NULL);
+    }
+  return alias;
+}
+
+/* Emit the definition of a D vtable thunk.  */
+
+static void
+finish_thunk (tree thunk, tree function)
+{
+  /* Setup how D thunks are outputted.  */
+  int fixed_offset = -THUNK_LANG_OFFSET (thunk);
+  bool this_adjusting = true;
+  tree alias;
+
+  if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function))
+    alias = make_alias_for_thunk (function);
+  else
+    alias = function;
+
+  TREE_ADDRESSABLE (function) = 1;
+  TREE_USED (function) = 1;
+
+  if (flag_syntax_only)
+    {
+      TREE_ASM_WRITTEN (thunk) = 1;
+      return;
+    }
+
+  if (TARGET_USE_LOCAL_THUNK_ALIAS_P (function)
+      && targetm_common.have_named_sections)
+    {
+      tree fn = function;
+      symtab_node *symbol = symtab_node::get (function);
+
+      if (symbol != NULL && symbol->alias)
+	{
+	  if (symbol->analyzed)
+	    fn = symtab_node::get (function)->ultimate_alias_target ()->decl;
+	  else
+	    fn = symtab_node::get (function)->alias_target;
+	}
+      resolve_unique_section (fn, 0, flag_function_sections);
+
+      if (DECL_SECTION_NAME (fn) != NULL && DECL_ONE_ONLY (fn))
+	{
+	  resolve_unique_section (thunk, 0, flag_function_sections);
+
+	  /* Output the thunk into the same section as function.  */
+	  set_decl_section_name (thunk, DECL_SECTION_NAME (fn));
+	  symtab_node::get (thunk)->implicit_section
+	    = symtab_node::get (fn)->implicit_section;
+	}
+    }
+
+  /* Set up cloned argument trees for the thunk.  */
+  tree t = NULL_TREE;
+  for (tree a = DECL_ARGUMENTS (function); a; a = DECL_CHAIN (a))
+    {
+      tree x = copy_node (a);
+      DECL_CHAIN (x) = t;
+      DECL_CONTEXT (x) = thunk;
+      SET_DECL_RTL (x, NULL);
+      DECL_HAS_VALUE_EXPR_P (x) = 0;
+      TREE_ADDRESSABLE (x) = 0;
+      t = x;
+    }
+  DECL_ARGUMENTS (thunk) = nreverse (t);
+  TREE_ASM_WRITTEN (thunk) = 1;
+
+  cgraph_node *funcn, *thunk_node;
+
+  funcn = cgraph_node::get_create (function);
+  gcc_assert (funcn);
+  thunk_node = funcn->create_thunk (thunk, thunk, this_adjusting,
+				    fixed_offset, 0, 0, alias);
+
+  if (DECL_ONE_ONLY (function))
+    thunk_node->add_to_same_comdat_group (funcn);
+
+  /* Target assemble_mi_thunk doesn't work across section boundaries
+     on many targets, instead force thunk to be expanded in gimple.  */
+  if (DECL_EXTERNAL (function))
+    {
+      /* cgraph::expand_thunk writes over current_function_decl, so if this
+	 could ever be in use by the codegen pass, we want to know about it.  */
+      gcc_assert (current_function_decl == NULL_TREE);
+
+      if (!stdarg_p (TREE_TYPE (thunk)))
+	{
+	  /* Put generic thunk into COMDAT.  */
+	  d_comdat_linkage (thunk);
+	  thunk_node->create_edge (funcn, NULL, 0, CGRAPH_FREQ_BASE);
+	  thunk_node->expand_thunk (false, true);
+	}
+
+      /* Tell the backend to not bother inlining the function, this is
+	 assumed not to work as it could be referencing symbols outside
+	 of the current compilation unit.  */
+      DECL_UNINLINABLE (function) = 1;
+    }
+}
+
+/* Return a thunk to DECL.  Thunks adjust the incoming `this' pointer by OFFSET.
+   Adjustor thunks are created and pointers to them stored in the method entries
+   in the vtable in order to set the this pointer to the start of the object
+   instance corresponding to the implementing method.  */
+
+tree
+make_thunk (FuncDeclaration *decl, int offset)
+{
+  tree function = get_symbol_decl (decl);
+
+  if (!DECL_ARGUMENTS (function) || !DECL_RESULT (function))
+    {
+      /* Compile the function body before generating the thunk, this is done
+	 even if the decl is external to the current module.  */
+      if (decl->fbody)
+	build_decl_tree (decl);
+      else
+	{
+	  /* Build parameters for functions that are not being compiled,
+	     so that they can be correctly cloned in finish_thunk.  */
+	  tree fntype = TREE_TYPE (function);
+	  tree params = NULL_TREE;
+
+	  for (tree t = TYPE_ARG_TYPES (fntype); t; t = TREE_CHAIN (t))
+	    {
+	      if (t == void_list_node)
+		break;
+
+	      tree param = build_decl (DECL_SOURCE_LOCATION (function),
+				       PARM_DECL, NULL_TREE, TREE_VALUE (t));
+	      DECL_ARG_TYPE (param) = TREE_TYPE (param);
+	      DECL_ARTIFICIAL (param) = 1;
+	      DECL_IGNORED_P (param) = 1;
+	      DECL_CONTEXT (param) = function;
+	      params = chainon (params, param);
+	    }
+
+	  DECL_ARGUMENTS (function) = params;
+
+	  /* Also build the result decl, which is needed when force creating
+	     the thunk in gimple inside cgraph_node::expand_thunk.  */
+	  tree resdecl = build_decl (DECL_SOURCE_LOCATION (function),
+				     RESULT_DECL, NULL_TREE,
+				     TREE_TYPE (fntype));
+	  DECL_ARTIFICIAL (resdecl) = 1;
+	  DECL_IGNORED_P (resdecl) = 1;
+	  DECL_CONTEXT (resdecl) = function;
+	  DECL_RESULT (function) = resdecl;
+	}
+    }
+
+  /* Don't build the thunk if the compilation step failed.  */
+  if (global.errors)
+    return error_mark_node;
+
+  /* See if we already have the thunk in question.  */
+  for (tree t = DECL_LANG_THUNKS (function); t; t = DECL_CHAIN (t))
+    {
+      if (THUNK_LANG_OFFSET (t) == offset)
+	return t;
+    }
+
+  tree thunk = build_decl (DECL_SOURCE_LOCATION (function),
+			   FUNCTION_DECL, NULL_TREE, TREE_TYPE (function));
+  DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function);
+  lang_hooks.dup_lang_specific_decl (thunk);
+  THUNK_LANG_OFFSET (thunk) = offset;
+
+  TREE_READONLY (thunk) = TREE_READONLY (function);
+  TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function);
+  TREE_NOTHROW (thunk) = TREE_NOTHROW (function);
+
+  DECL_CONTEXT (thunk) = d_decl_context (decl);
+
+  /* Thunks inherit the public access of the function they are targetting.  */
+  TREE_PUBLIC (thunk) = TREE_PUBLIC (function);
+  DECL_EXTERNAL (thunk) = 0;
+
+  /* Thunks are always addressable.  */
+  TREE_ADDRESSABLE (thunk) = 1;
+  TREE_USED (thunk) = 1;
+  DECL_ARTIFICIAL (thunk) = 1;
+  DECL_DECLARED_INLINE_P (thunk) = 0;
+
+  DECL_VISIBILITY (thunk) = DECL_VISIBILITY (function);
+  /* Needed on some targets to avoid "causes a section type conflict".  */
+  D_DECL_ONE_ONLY (thunk) = D_DECL_ONE_ONLY (function);
+  DECL_COMDAT (thunk) = DECL_COMDAT (function);
+  DECL_WEAK (thunk) = DECL_WEAK (function);
+
+  tree target_name = DECL_ASSEMBLER_NAME (function);
+  unsigned identlen = IDENTIFIER_LENGTH (target_name) + 14;
+  const char *ident = XNEWVEC (const char, identlen);
+  snprintf (CONST_CAST (char *, ident), identlen,
+	    "_DT%u%s", offset, IDENTIFIER_POINTER (target_name));
+
+  DECL_NAME (thunk) = get_identifier (ident);
+  SET_DECL_ASSEMBLER_NAME (thunk, DECL_NAME (thunk));
+
+  d_keep (thunk);
+
+  finish_thunk (thunk, function);
+
+  /* Add it to the list of thunks associated with the function.  */
+  DECL_LANG_THUNKS (thunk) = NULL_TREE;
+  DECL_CHAIN (thunk) = DECL_LANG_THUNKS (function);
+  DECL_LANG_THUNKS (function) = thunk;
+
+  return thunk;
+}
+
+/* Create the FUNCTION_DECL for a function definition.
+   This function creates a binding context for the function body
+   as well as setting up the FUNCTION_DECL in current_function_decl.
+   Returns the previous function context if it was already set.  */
+
+tree
+start_function (FuncDeclaration *fd)
+{
+  tree fndecl = get_symbol_decl (fd);
+
+  /* If we are generating the function, but it's really extern.
+     Such as external inlinable functions or thunk aliases.  */
+  if (!fd->isInstantiated () && fd->getModule ()
+      && !fd->getModule ()->isRoot ())
+    {
+      TREE_STATIC (fndecl) = 0;
+      DECL_EXTERNAL (fndecl) = 1;
+    }
+  else
+    {
+      /* This function exists in static storage.  */
+      TREE_STATIC (fndecl) = 1;
+      DECL_EXTERNAL (fndecl) = 0;
+    }
+
+  DECL_INITIAL (fndecl) = error_mark_node;
+
+  /* Add this decl to the current binding level.  */
+  d_pushdecl (fndecl);
+
+  /* Save the current function context.  */
+  tree old_context = current_function_decl;
+
+  if (old_context)
+    push_function_context ();
+
+  /* Let GCC know the current scope is this function.  */
+  current_function_decl = fndecl;
+
+  tree restype = TREE_TYPE (TREE_TYPE (fndecl));
+  tree resdecl = build_decl (get_linemap (fd->loc), RESULT_DECL,
+			     NULL_TREE, restype);
+
+  DECL_RESULT (fndecl) = resdecl;
+  DECL_CONTEXT (resdecl) = fndecl;
+  DECL_ARTIFICIAL (resdecl) = 1;
+  DECL_IGNORED_P (resdecl) = 1;
+
+  /* Initialize the RTL code for the function.  */
+  allocate_struct_function (fndecl, false);
+
+  /* Store the end of the function.  */
+  if (fd->endloc.filename)
+    cfun->function_end_locus = get_linemap (fd->endloc);
+  else
+    cfun->function_end_locus = DECL_SOURCE_LOCATION (fndecl);
+
+  cfun->language = ggc_cleared_alloc<language_function> ();
+  cfun->language->function = fd;
+
+  /* Default chain value is 'null' unless parent found.  */
+  cfun->language->static_chain = null_pointer_node;
+
+  /* Find module for this function.  */
+  for (Dsymbol *p = fd->parent; p != NULL; p = p->parent)
+    {
+      cfun->language->module = p->isModule ();
+      if (cfun->language->module)
+	break;
+    }
+  gcc_assert (cfun->language->module != NULL);
+
+  /* Begin the statement tree for this function.  */
+  push_stmt_list ();
+  push_binding_level (level_function);
+
+  return old_context;
+}
+
+/* Finish up a function declaration and compile that function all
+   the way to assembler language output.  The free the storage for
+   the function definition.  Restores the previous function context.  */
+
+void
+finish_function (tree old_context)
+{
+  tree fndecl = current_function_decl;
+
+  /* Tie off the statement tree for this function.  */
+  tree block = pop_binding_level ();
+  tree body = pop_stmt_list ();
+  tree bind = build3 (BIND_EXPR, void_type_node,
+		      BLOCK_VARS (block), body, block);
+
+  gcc_assert (vec_safe_is_empty (d_function_chain->stmt_list));
+
+  /* Backend expects a statement list to come from somewhere, however
+     pop_stmt_list returns expressions when there is a single statement.
+     So here we create a statement list unconditionally.  */
+  if (TREE_CODE (body) != STATEMENT_LIST)
+    {
+      tree stmtlist = alloc_stmt_list ();
+      append_to_statement_list_force (body, &stmtlist);
+      BIND_EXPR_BODY (bind) = stmtlist;
+    }
+  else if (!STATEMENT_LIST_HEAD (body))
+    {
+      /* For empty functions add a void return.  */
+      append_to_statement_list_force (return_expr (NULL_TREE), &body);
+    }
+
+  DECL_SAVED_TREE (fndecl) = bind;
+
+  if (!errorcount && !global.errors)
+    {
+      /* Dump the D-specific tree IR.  */
+      dump_function (TDI_original, fndecl);
+
+      cgraph_node::finalize_function (fndecl, true);
+    }
+
+  /* We're leaving the context of this function, so free it.  */
+  ggc_free (cfun->language);
+  cfun->language = NULL;
+  set_cfun (NULL);
+
+  if (old_context)
+    pop_function_context ();
+
+  current_function_decl = old_context;
+}
+
+/* Mark DECL, which is a VAR_DECL or FUNCTION_DECL as a symbol that
+   must be emitted in this, output module.  */
+
+void
+mark_needed (tree decl)
+{
+  TREE_USED (decl) = 1;
+
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    {
+      struct cgraph_node *node = cgraph_node::get_create (decl);
+      node->forced_by_abi = true;
+    }
+  else if (VAR_P (decl))
+    {
+      struct varpool_node *node = varpool_node::get_create (decl);
+      node->forced_by_abi = true;
+    }
+}
+
+/* Get offset of base class's vtbl[] initialiser from start of csym.  */
+
+unsigned
+base_vtable_offset (ClassDeclaration *cd, BaseClass *bc)
+{
+  unsigned csymoffset = Target::classinfosize;
+  unsigned interfacesize = int_size_in_bytes (vtbl_interface_type_node);
+  csymoffset += cd->vtblInterfaces->dim * interfacesize;
+
+  for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
+    {
+      BaseClass *b = (*cd->vtblInterfaces)[i];
+      if (b == bc)
+	return csymoffset;
+      csymoffset += b->sym->vtbl.dim * Target::ptrsize;
+    }
+
+  /* Put out the overriding interface vtbl[]s.  */
+  for (ClassDeclaration *cd2 = cd->baseClass; cd2; cd2 = cd2->baseClass)
+    {
+      for (size_t k = 0; k < cd2->vtblInterfaces->dim; k++)
+	{
+	  BaseClass *bs = (*cd2->vtblInterfaces)[k];
+	  if (bs->fillVtbl (cd, NULL, 0))
+	    {
+	      if (bc == bs)
+		return csymoffset;
+	      csymoffset += bs->sym->vtbl.dim * Target::ptrsize;
+	    }
+	}
+    }
+
+  return ~0;
+}
+
+/* Get the VAR_DECL of the vtable symbol for DECL.  If this does not yet exist,
+   create it.  The vtable is accessible via ClassInfo, but since it is needed
+   frequently (like for rtti comparisons), make it directly accessible.  */
+
+tree
+get_vtable_decl (ClassDeclaration *decl)
+{
+  if (decl->vtblsym)
+    return decl->vtblsym;
+
+  tree ident = mangle_internal_decl (decl, "__vtbl", "Z");
+  /* Note: Using a static array type for the VAR_DECL, the DECL_INITIAL value
+     will have a different type.  However the backend seems to accept this.  */
+  tree type = build_ctype (Type::tvoidptr->sarrayOf (decl->vtbl.dim));
+
+  decl->vtblsym = declare_extern_var (ident, type);
+  DECL_LANG_SPECIFIC (decl->vtblsym) = build_lang_decl (NULL);
+
+  /* Class is a reference, want the record type.  */
+  DECL_CONTEXT (decl->vtblsym) = TREE_TYPE (build_ctype (decl->type));
+  TREE_READONLY (decl->vtblsym) = 1;
+  DECL_VIRTUAL_P (decl->vtblsym) = 1;
+
+  SET_DECL_ALIGN (decl->vtblsym, TARGET_VTABLE_ENTRY_ALIGN);
+  DECL_USER_ALIGN (decl->vtblsym) = true;
+
+  /* Could move setting comdat linkage to the caller, who knows whether
+     this vtable is being emitted in this compilation.  */
+  if (decl->isInstantiated ())
+    d_comdat_linkage (decl->vtblsym);
+
+  return decl->vtblsym;
+}
+
+/* Get the VAR_DECL of a class instance representing EXPR as static data.
+   If this does not yet exist, create it.  This is used to support initializing
+   a static variable that is of a class type using values known during CTFE.
+   In user code, it is analogous to the following code snippet.
+
+    enum E = new C(1, 2, 3);
+
+   That we write the contents of `C(1, 2, 3)' to static data is only a compiler
+   implementation detail.  The initialization of these symbols could be done at
+   runtime using during as part of the module initialization or shared static
+   constructors phase of runtime start-up - whichever comes after `gc_init()'.
+   And infact that would be the better thing to do here eventually.  */
+
+tree
+build_new_class_expr (ClassReferenceExp *expr)
+{
+  if (expr->value->sym)
+    return expr->value->sym;
+
+  /* Build the reference symbol.  */
+  tree type = build_ctype (expr->value->stype);
+  expr->value->sym = build_artificial_decl (TREE_TYPE (type), NULL_TREE, "C");
+
+  DECL_INITIAL (expr->value->sym) = build_class_instance (expr);
+  d_pushdecl (expr->value->sym);
+  rest_of_decl_compilation (expr->value->sym, 1, 0);
+
+  return expr->value->sym;
+}
+
+/* Get the VAR_DECL of the static initializer symbol for the struct/class DECL.
+   If this does not yet exist, create it.  The static initializer data is
+   accessible via TypeInfo, and is also used in 'new class' and default
+   initializing struct literals.  */
+
+tree
+aggregate_initializer_decl (AggregateDeclaration *decl)
+{
+  if (decl->sinit)
+    return decl->sinit;
+
+  /* Class is a reference, want the record type.  */
+  tree type = build_ctype (decl->type);
+  StructDeclaration *sd = decl->isStructDeclaration ();
+  if (!sd)
+    type = TREE_TYPE (type);
+
+  tree ident = mangle_internal_decl (decl, "__init", "Z");
+
+  decl->sinit = declare_extern_var (ident, type);
+  DECL_LANG_SPECIFIC (decl->sinit) = build_lang_decl (NULL);
+
+  DECL_CONTEXT (decl->sinit) = type;
+  TREE_READONLY (decl->sinit) = 1;
+
+  /* Honor struct alignment set by user.  */
+  if (sd && sd->alignment != STRUCTALIGN_DEFAULT)
+    {
+      SET_DECL_ALIGN (decl->sinit, sd->alignment * BITS_PER_UNIT);
+      DECL_USER_ALIGN (decl->sinit) = true;
+    }
+
+  /* Could move setting comdat linkage to the caller, who knows whether
+     this initializer is being emitted in this compilation.  */
+  if (decl->isInstantiated ())
+    d_comdat_linkage (decl->sinit);
+
+  return decl->sinit;
+}
+
+/* Generate the data for the static initialiser.  */
+
+tree
+layout_class_initializer (ClassDeclaration *cd)
+{
+  NewExp *ne = new NewExp (cd->loc, NULL, NULL, cd->type, NULL);
+  ne->type = cd->type;
+
+  Expression *e = ne->ctfeInterpret ();
+  gcc_assert (e->op == TOKclassreference);
+
+  return build_class_instance ((ClassReferenceExp *) e);
+}
+
+tree
+layout_struct_initializer (StructDeclaration *sd)
+{
+  StructLiteralExp *sle = StructLiteralExp::create (sd->loc, sd, NULL);
+
+  if (!sd->fill (sd->loc, sle->elements, true))
+    gcc_unreachable ();
+
+  sle->type = sd->type;
+  return build_expr (sle, true);
+}
+
+/* Get the VAR_DECL of the static initializer symbol for the enum DECL.
+   If this does not yet exist, create it.  The static initializer data is
+   accessible via TypeInfo_Enum, but the field member type is a byte[] that
+   requires a pointer to a symbol reference.  */
+
+tree
+enum_initializer_decl (EnumDeclaration *decl)
+{
+  if (decl->sinit)
+    return decl->sinit;
+
+  tree type = build_ctype (decl->type);
+
+  Identifier *ident_save = decl->ident;
+  if (!decl->ident)
+    decl->ident = Identifier::generateId ("__enum");
+  tree ident = mangle_internal_decl (decl, "__init", "Z");
+  decl->ident = ident_save;
+
+  decl->sinit = declare_extern_var (ident, type);
+  DECL_LANG_SPECIFIC (decl->sinit) = build_lang_decl (NULL);
+
+  DECL_CONTEXT (decl->sinit) = d_decl_context (decl);
+  TREE_READONLY (decl->sinit) = 1;
+
+  /* Could move setting comdat linkage to the caller, who knows whether
+     this initializer is being emitted in this compilation.  */
+  if (decl->isInstantiated ())
+    d_comdat_linkage (decl->sinit);
+
+  return decl->sinit;
+}
+
+/* Return an anonymous static variable of type TYPE, initialized with INIT,
+   and optionally prefixing the name with PREFIX.  */
+
+tree
+build_artificial_decl (tree type, tree init, const char *prefix)
+{
+  tree decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, NULL_TREE, type);
+  const char *name = prefix ? prefix : "___s";
+  char *label;
+
+  ASM_FORMAT_PRIVATE_NAME (label, name, DECL_UID (decl));
+  SET_DECL_ASSEMBLER_NAME (decl, get_identifier (label));
+  DECL_NAME (decl) = DECL_ASSEMBLER_NAME (decl);
+
+  TREE_PUBLIC (decl) = 0;
+  TREE_STATIC (decl) = 1;
+  TREE_USED (decl) = 1;
+  DECL_IGNORED_P (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+
+  /* Perhaps at some point the initializer constant should be hashed
+     to remove duplicates.  */
+  DECL_INITIAL (decl) = init;
+
+  return decl;
+}
+
+/* Build TYPE_DECL for the declaration DSYM.  */
+
+void
+build_type_decl (tree type, Dsymbol *dsym)
+{
+  if (TYPE_STUB_DECL (type))
+    return;
+
+  gcc_assert (!POINTER_TYPE_P (type));
+
+  tree decl = build_decl (get_linemap (dsym->loc), TYPE_DECL,
+			  get_identifier (dsym->ident->toChars ()), type);
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_CONTEXT (decl) = d_decl_context (dsym);
+
+  TYPE_CONTEXT (type) = DECL_CONTEXT (decl);
+  TYPE_NAME (type) = decl;
+
+  /* Not sure if there is a need for separate TYPE_DECLs in
+     TYPE_NAME and TYPE_STUB_DECL. */
+  if (TREE_CODE (type) == ENUMERAL_TYPE || RECORD_OR_UNION_TYPE_P (type))
+    TYPE_STUB_DECL (type) = decl;
+
+  rest_of_decl_compilation (decl, SCOPE_FILE_SCOPE_P (decl), 0);
+}
+
+/* Create a declaration for field NAME of a given TYPE, setting the flags
+   for whether the field is ARTIFICIAL and/or IGNORED.  */
+
+tree
+create_field_decl (tree type, const char *name, int artificial, int ignored)
+{
+  tree decl = build_decl (input_location, FIELD_DECL,
+			  name ? get_identifier (name) : NULL_TREE, type);
+  DECL_ARTIFICIAL (decl) = artificial;
+  DECL_IGNORED_P (decl) = ignored;
+
+  return decl;
+}
+
+/* Return the COMDAT group into which DECL should be placed.  */
+
+static tree
+d_comdat_group (tree decl)
+{
+  /* If already part of a comdat group, use that.  */
+  if (DECL_COMDAT_GROUP (decl))
+    return DECL_COMDAT_GROUP (decl);
+
+  return DECL_ASSEMBLER_NAME (decl);
+}
+
+/* Set DECL up to have the closest approximation of "initialized common"
+   linkage available.  */
+
+void
+d_comdat_linkage (tree decl)
+{
+  /* Weak definitions have to be public.  */
+  if (!TREE_PUBLIC (decl))
+    return;
+
+  /* Necessary to allow DECL_ONE_ONLY or DECL_WEAK functions to be inlined.  */
+  if (TREE_CODE (decl) == FUNCTION_DECL)
+    DECL_DECLARED_INLINE_P (decl) = 1;
+
+  if (supports_one_only ())
+    make_decl_one_only (decl, d_comdat_group (decl));
+  else if (TREE_CODE (decl) == FUNCTION_DECL
+	   || (VAR_P (decl) && DECL_ARTIFICIAL (decl)))
+    /* We can just emit function and compiler-generated variables statically;
+       having multiple copies is (for the most part) only a waste of space.  */
+    TREE_PUBLIC (decl) = 0;
+  else if (DECL_INITIAL (decl) == NULL_TREE
+	   || DECL_INITIAL (decl) == error_mark_node)
+    /* Fallback, cannot have multiple copies.  */
+    DECL_COMMON (decl) = 1;
+
+  if (TREE_PUBLIC (decl))
+    DECL_COMDAT (decl) = 1;
+}
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
new file mode 100644
index 00000000000..d7eee486fbd
--- /dev/null
+++ b/gcc/d/expr.cc
@@ -0,0 +1,3177 @@
+/* expr.cc -- Lower D frontend expressions to GCC trees.
+   Copyright (C) 2015-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/ctfe.h"
+#include "dfrontend/declaration.h"
+#include "dfrontend/expression.h"
+#include "dfrontend/init.h"
+#include "dfrontend/module.h"
+#include "dfrontend/mtype.h"
+#include "dfrontend/template.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "langhooks.h"
+#include "tm.h"
+#include "function.h"
+#include "toplev.h"
+#include "varasm.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+#include "id.h"
+
+
+/* Implements the visitor interface to build the GCC trees of all Expression
+   AST classes emitted from the D Front-end.
+   All visit methods accept one parameter E, which holds the frontend AST
+   of the expression to compile.  They also don't return any value, instead
+   generated code is cached in RESULT_ and returned from the caller.  */
+
+class ExprVisitor : public Visitor
+{
+  tree result_;
+  bool constp_;
+
+  /* Determine if type is a struct that has a postblit.  */
+
+  bool needs_postblit (Type *t)
+  {
+    t = t->baseElemOf ();
+
+    if (t->ty == Tstruct)
+      {
+	StructDeclaration *sd = ((TypeStruct *) t)->sym;
+	if (sd->postblit)
+	  return true;
+      }
+
+    return false;
+  }
+
+  /* Determine if type is a struct that has a destructor.  */
+
+  bool needs_dtor (Type *t)
+  {
+    t = t->baseElemOf ();
+
+    if (t->ty == Tstruct)
+      {
+	StructDeclaration *sd = ((TypeStruct *) t)->sym;
+	if (sd->dtor)
+	  return true;
+      }
+
+    return false;
+  }
+
+  /* Determine if expression is suitable lvalue.  */
+
+  bool lvalue_p (Expression *e)
+  {
+    return ((e->op != TOKslice && e->isLvalue ())
+	    || (e->op == TOKslice && ((UnaExp *) e)->e1->isLvalue ())
+	    || (e->op == TOKcast && ((UnaExp *) e)->e1->isLvalue ()));
+  }
+
+  /* Build an expression of code CODE, data type TYPE, and operands ARG0 and
+     ARG1.  Perform relevant conversions needs for correct code operations.  */
+
+  tree binary_op (tree_code code, tree type, tree arg0, tree arg1)
+  {
+    tree t0 = TREE_TYPE (arg0);
+    tree t1 = TREE_TYPE (arg1);
+    tree ret = NULL_TREE;
+
+    bool unsignedp = TYPE_UNSIGNED (t0) || TYPE_UNSIGNED (t1);
+
+    /* Deal with float mod expressions immediately.  */
+    if (code == FLOAT_MOD_EXPR)
+      return build_float_modulus (TREE_TYPE (arg0), arg0, arg1);
+
+    if (POINTER_TYPE_P (t0) && INTEGRAL_TYPE_P (t1))
+      return build_nop (type, build_offset_op (code, arg0, arg1));
+
+    if (INTEGRAL_TYPE_P (t0) && POINTER_TYPE_P (t1))
+      return build_nop (type, build_offset_op (code, arg1, arg0));
+
+    if (POINTER_TYPE_P (t0) && POINTER_TYPE_P (t1))
+      {
+	/* Need to convert pointers to integers because tree-vrp asserts
+	   against (ptr MINUS ptr).  */
+	tree ptrtype = lang_hooks.types.type_for_mode (ptr_mode,
+						       TYPE_UNSIGNED (type));
+	arg0 = d_convert (ptrtype, arg0);
+	arg1 = d_convert (ptrtype, arg1);
+
+	ret = fold_build2 (code, ptrtype, arg0, arg1);
+      }
+    else if (INTEGRAL_TYPE_P (type) && (TYPE_UNSIGNED (type) != unsignedp))
+      {
+	tree inttype = (unsignedp)
+	  ? d_unsigned_type (type) : d_signed_type (type);
+	ret = fold_build2 (code, inttype, arg0, arg1);
+      }
+    else
+      {
+	/* Front-end does not do this conversion and GCC does not
+	   always do it right.  */
+	if (COMPLEX_FLOAT_TYPE_P (t0) && !COMPLEX_FLOAT_TYPE_P (t1))
+	  arg1 = d_convert (t0, arg1);
+	else if (COMPLEX_FLOAT_TYPE_P (t1) && !COMPLEX_FLOAT_TYPE_P (t0))
+	  arg0 = d_convert (t1, arg0);
+
+	ret = fold_build2 (code, type, arg0, arg1);
+      }
+
+    return d_convert (type, ret);
+  }
+
+  /* Build a binary expression of code CODE, assigning the result into E1.  */
+
+  tree binop_assignment (tree_code code, Expression *e1, Expression *e2)
+  {
+    /* Skip casts for lhs assignment.  */
+    Expression *e1b = e1;
+    while (e1b->op == TOKcast)
+      {
+	CastExp *ce = (CastExp *) e1b;
+	gcc_assert (same_type_p (ce->type, ce->to));
+	e1b = ce->e1;
+      }
+
+    /* The LHS expression could be an assignment, to which it's operation gets
+       lost during gimplification.  Stabilize lhs for assignment.  */
+    tree lhs = build_expr (e1b);
+    tree lexpr = stabilize_expr (&lhs);
+
+    lhs = stabilize_reference (lhs);
+
+    tree rhs = build_expr (e2);
+    rhs = this->binary_op (code, build_ctype (e1->type),
+			   convert_expr (lhs, e1b->type, e1->type), rhs);
+
+    tree expr = modify_expr (lhs, convert_expr (rhs, e1->type, e1b->type));
+
+    return compound_expr (lexpr, expr);
+  }
+
+public:
+  ExprVisitor (bool constp)
+  {
+    this->result_ = NULL_TREE;
+    this->constp_ = constp;
+  }
+
+  tree result (void)
+  {
+    return this->result_;
+  }
+
+  /* Visitor interfaces, each Expression class should have
+     overridden the default.  */
+
+  void visit (Expression *e)
+  {
+    input_location = get_linemap (e->loc);
+    gcc_unreachable ();
+  }
+
+  /* Build a conditional expression.  If either the second or third
+     expression is void, then the resulting type is void.  Otherwise
+     they are implicitly converted to a common type.  */
+
+  void visit (CondExp *e)
+  {
+    tree cond = convert_for_condition (build_expr (e->econd),
+				       e->econd->type);
+    tree t1 = build_expr (e->e1);
+    tree t2 = build_expr (e->e2);
+
+    if (e->type->ty != Tvoid)
+      {
+	t1 = convert_expr (t1, e->e1->type, e->type);
+	t2 = convert_expr (t2, e->e2->type, e->type);
+      }
+
+    this->result_ = build_condition (build_ctype (e->type), cond, t1, t2);
+  }
+
+  /* Build an identity comparison expression.  Operands go through the
+     usual conversions to bring them to a common type before comparison.
+     The result type is bool.  */
+
+  void visit (IdentityExp *e)
+  {
+    tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR;
+    Type *tb1 = e->e1->type->toBasetype ();
+    Type *tb2 = e->e2->type->toBasetype ();
+
+    if ((tb1->ty == Tsarray || tb1->ty == Tarray)
+	&& (tb2->ty == Tsarray || tb2->ty == Tarray))
+      {
+	/* For static and dynamic arrays, identity is defined as referring to
+	   the same array elements and the same number of elements.  */
+	tree t1 = d_array_convert (e->e1);
+	tree t2 = d_array_convert (e->e2);
+	this->result_ = d_convert (build_ctype (e->type),
+				   build_boolop (code, t1, t2));
+      }
+    else if (tb1->isfloating ())
+      {
+	/* For floating point values, identity is defined as the bits in the
+	   operands being identical.  */
+	tree t1 = d_save_expr (build_expr (e->e1));
+	tree t2 = d_save_expr (build_expr (e->e2));
+
+	tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP);
+	tree size = size_int (TYPE_PRECISION (TREE_TYPE (t1)) / BITS_PER_UNIT);
+
+	tree result = build_call_expr (tmemcmp, 3, build_address (t1),
+				       build_address (t2), size);
+	this->result_ = build_boolop (code, result, integer_zero_node);
+      }
+    else if (tb1->ty == Tstruct)
+      {
+	/* For struct objects, identity is defined as bits in operands being
+	   identical also.  Alignment holes in structs are ignored.  */
+	StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
+	tree t1 = build_expr (e->e1);
+	tree t2 = build_expr (e->e2);
+
+	gcc_assert (same_type_p (tb1, tb2));
+
+	this->result_ = build_struct_comparison (code, sd, t1, t2);
+      }
+    else
+      {
+	/* For operands of other types, identity is defined as being the
+	   same as equality expressions.  */
+	tree t1 = build_expr (e->e1);
+	tree t2 = build_expr (e->e2);
+	this->result_ = d_convert (build_ctype (e->type),
+				   build_boolop (code, t1, t2));
+      }
+  }
+
+  /* Build an equality expression, which compare the two operands for either
+     equality or inequality.  Operands go through the usual conversions to bring
+     them to a common type before comparison.  The result type is bool.  */
+
+  void visit (EqualExp *e)
+  {
+    Type *tb1 = e->e1->type->toBasetype ();
+    Type *tb2 = e->e2->type->toBasetype ();
+    tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR;
+
+    if ((tb1->ty == Tsarray || tb1->ty == Tarray)
+	&& (tb2->ty == Tsarray || tb2->ty == Tarray))
+      {
+	/* For static and dynamic arrays, equality is defined as the lengths of
+	   the arrays matching, and all the elements are equal.  */
+	Type *t1elem = tb1->nextOf ()->toBasetype ();
+	Type *t2elem = tb1->nextOf ()->toBasetype ();
+
+	/* Check if comparisons of arrays can be optimized using memcmp.
+	   This will inline EQ expressions as:
+		e1.length == e2.length && memcmp(e1.ptr, e2.ptr, size) == 0;
+	    Or when generating a NE expression:
+		e1.length != e2.length || memcmp(e1.ptr, e2.ptr, size) != 0;  */
+	if ((t1elem->isintegral () || t1elem->ty == Tvoid
+	     || (t1elem->ty == Tstruct && !((TypeStruct *)t1elem)->sym->xeq))
+	    && t1elem->ty == t2elem->ty)
+	  {
+	    tree t1 = d_array_convert (e->e1);
+	    tree t2 = d_array_convert (e->e2);
+	    tree result;
+
+	    /* Make temporaries to prevent multiple evaluations.  */
+	    tree t1saved = d_save_expr (t1);
+	    tree t2saved = d_save_expr (t2);
+
+	    /* Length of arrays, for comparisons done before calling memcmp.  */
+	    tree t1len = d_array_length (t1saved);
+	    tree t2len = d_array_length (t2saved);
+
+	    /* Reference to array data.  */
+	    tree t1ptr = d_array_ptr (t1saved);
+	    tree t2ptr = d_array_ptr (t2saved);
+
+	    /* Compare arrays using memcmp if possible, otherwise for structs,
+	       each field is compared inline.  */
+	    if (t1elem->ty != Tstruct
+		|| identity_compare_p (((TypeStruct *) t1elem)->sym))
+	      {
+		tree size = size_mult_expr (t1len, size_int (t1elem->size ()));
+		tree tmemcmp = builtin_decl_explicit (BUILT_IN_MEMCMP);
+
+		result = build_call_expr (tmemcmp, 3, t1ptr, t2ptr, size);
+		result = build_boolop (code, result, integer_zero_node);
+	      }
+	    else
+	      {
+		StructDeclaration *sd = ((TypeStruct *) t1elem)->sym;
+
+		result = build_array_struct_comparison (code, sd, t1len,
+							t1ptr, t2ptr);
+	      }
+
+	    /* Check array length first before passing to memcmp.
+	       For equality expressions, this becomes:
+		    (e1.length == 0 || memcmp);
+	       Otherwise for inequality:
+		    (e1.length != 0 && memcmp);  */
+	    tree tsizecmp = build_boolop (code, t1len, size_zero_node);
+	    if (e->op == TOKequal)
+	      result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result);
+	    else
+	      result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result);
+
+	    /* Finally, check if lengths of both arrays match if dynamic.
+	       The frontend should have already guaranteed that static arrays
+	       have same size.  */
+	    if (tb1->ty == Tsarray && tb2->ty == Tsarray)
+	      gcc_assert (tb1->size () == tb2->size ());
+	    else
+	      {
+		tree tlencmp = build_boolop (code, t1len, t2len);
+		if (e->op == TOKequal)
+		  result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result);
+		else
+		  result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result);
+	      }
+
+	    /* Ensure left-to-right order of evaluation.  */
+	    if (TREE_SIDE_EFFECTS (t2))
+	      result = compound_expr (t2saved, result);
+
+	    if (TREE_SIDE_EFFECTS (t1))
+	      result = compound_expr (t1saved, result);
+
+	    this->result_ = result;
+	  }
+	else
+	  {
+	    /* Use _adEq2() to compare each element.  */
+	    Type *t1array = t1elem->arrayOf ();
+	    tree result = build_libcall (LIBCALL_ADEQ2, e->type, 3,
+					 d_array_convert (e->e1),
+					 d_array_convert (e->e2),
+					 build_typeinfo (t1array));
+
+	    if (e->op == TOKnotequal)
+	      result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
+
+	    this->result_ = result;
+	  }
+      }
+    else if (tb1->ty == Tstruct)
+      {
+	/* Equality for struct objects means the logical product of all
+	   equality results of the corresponding object fields.  */
+	StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
+	tree t1 = build_expr (e->e1);
+	tree t2 = build_expr (e->e2);
+
+	gcc_assert (same_type_p (tb1, tb2));
+
+	this->result_ = build_struct_comparison (code, sd, t1, t2);
+      }
+    else if (tb1->ty == Taarray && tb2->ty == Taarray)
+      {
+	/* Use _aaEqual() for associative arrays.  */
+	TypeAArray *taa1 = (TypeAArray *) tb1;
+	tree result = build_libcall (LIBCALL_AAEQUAL, e->type, 3,
+				     build_typeinfo (taa1),
+				     build_expr (e->e1),
+				     build_expr (e->e2));
+
+	if (e->op == TOKnotequal)
+	  result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
+
+	this->result_ = result;
+      }
+    else
+      {
+	/* For operands of other types, equality is defined as the bit pattern
+	   of the type matches exactly.  */
+	tree t1 = build_expr (e->e1);
+	tree t2 = build_expr (e->e2);
+
+	this->result_ = d_convert (build_ctype (e->type),
+				   build_boolop (code, t1, t2));
+      }
+  }
+
+  /* Build an `in' expression.  This is a condition to see if an element
+     exists in an associative array.  The result is a pointer to the
+     element, or null if false.  */
+
+  void visit (InExp *e)
+  {
+    Type *tb2 = e->e2->type->toBasetype ();
+    gcc_assert (tb2->ty == Taarray);
+
+    Type *tkey = ((TypeAArray *) tb2)->index->toBasetype ();
+    tree key = convert_expr (build_expr (e->e1), e->e1->type, tkey);
+
+    /* Build a call to _aaInX().  */
+    this->result_ = build_libcall (LIBCALL_AAINX, e->type, 3,
+				   build_expr (e->e2),
+				   build_typeinfo (tkey),
+				   build_address (key));
+  }
+
+  /* Build a relational expression.  The result type is bool.  */
+
+  void visit (CmpExp *e)
+  {
+    Type *tb1 = e->e1->type->toBasetype ();
+    Type *tb2 = e->e2->type->toBasetype ();
+
+    tree result;
+    tree_code code;
+
+    switch (e->op)
+      {
+      case TOKue:
+	code = (tb1->isfloating () && tb2->isfloating ())
+	  ? UNEQ_EXPR : EQ_EXPR;
+	break;
+
+      case TOKlg:
+	code = (tb1->isfloating () && tb2->isfloating ())
+	  ? LTGT_EXPR : NE_EXPR;
+	break;
+
+      case TOKule:
+	code = (tb1->isfloating () && tb2->isfloating ())
+	  ? UNLE_EXPR : LE_EXPR;
+	break;
+
+      case TOKul:
+	code = (tb1->isfloating () && tb2->isfloating ())
+	  ? UNLT_EXPR : LT_EXPR;
+	break;
+
+      case TOKuge:
+	code = (tb1->isfloating () && tb2->isfloating ())
+	  ? UNGE_EXPR : GE_EXPR;
+	break;
+
+      case TOKug:
+	code = (tb1->isfloating () && tb2->isfloating ())
+	  ? UNGT_EXPR : GT_EXPR;
+	break;
+
+      case TOKle:
+	code = LE_EXPR;
+	break;
+
+      case TOKlt:
+	code = LT_EXPR;
+	break;
+
+      case TOKge:
+	code = GE_EXPR;
+	break;
+
+      case TOKgt:
+	code = GT_EXPR;
+	break;
+
+      case TOKleg:
+	code = ORDERED_EXPR;
+	break;
+
+      case TOKunord:
+	code = UNORDERED_EXPR;
+	break;
+
+      default:
+	gcc_unreachable ();
+      }
+
+    if ((tb1->ty == Tsarray || tb1->ty == Tarray)
+	&& (tb2->ty == Tsarray || tb2->ty == Tarray))
+      {
+	/* For static and dynamic arrays, the result of the relational op is
+	   the result of the operator applied to the first non-equal element
+	   of the array.  If two arrays compare equal, but are of different
+	   lengths, the shorter array compares as less than the longer.  */
+	Type *telem = tb1->nextOf ()->toBasetype ();
+
+	tree call = build_libcall (LIBCALL_ADCMP2, Type::tint32, 3,
+				   d_array_convert (e->e1),
+				   d_array_convert (e->e2),
+				   build_typeinfo (telem->arrayOf ()));
+	result = build_boolop (code, call, integer_zero_node);
+
+	this->result_ = d_convert (build_ctype (e->type), result);
+      }
+    else
+      {
+	if (!tb1->isfloating () || !tb2->isfloating ())
+	  {
+	    if (code == ORDERED_EXPR)
+	      {
+		this->result_ = convert (bool_type_node, integer_one_node);
+		return;
+	      }
+
+	    if (code == UNORDERED_EXPR)
+	      {
+		this->result_ = convert (bool_type_node, integer_zero_node);
+		return;
+	      }
+	  }
+
+	result = build_boolop (code, build_expr (e->e1), build_expr (e->e2));
+	this->result_ = d_convert (build_ctype (e->type), result);
+      }
+  }
+
+  /* Build an `and if' expression.  If the right operand expression is void,
+     then the resulting type is void.  Otherwise the result is bool.  */
+
+  void visit (AndAndExp *e)
+  {
+    if (e->e2->type->toBasetype ()->ty != Tvoid)
+      {
+	tree t1 = build_expr (e->e1);
+	tree t2 = build_expr (e->e2);
+
+	t1 = convert_for_condition (t1, e->e1->type);
+	t2 = convert_for_condition (t2, e->e2->type);
+
+	this->result_ = d_convert (build_ctype (e->type),
+				   build_boolop (TRUTH_ANDIF_EXPR, t1, t2));
+      }
+    else
+      {
+	tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
+	tree t2 = build_expr_dtor (e->e2);
+
+	this->result_ = build_condition (build_ctype (e->type),
+					 t1, t2, void_node);
+      }
+  }
+
+  /* Build an `or if' expression.  If the right operand expression is void,
+     then the resulting type is void.  Otherwise the result is bool.  */
+
+  void visit (OrOrExp *e)
+  {
+    if (e->e2->type->toBasetype ()->ty != Tvoid)
+      {
+	tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
+	tree t2 = convert_for_condition (build_expr (e->e2), e->e2->type);
+
+	this->result_ = d_convert (build_ctype (e->type),
+				   build_boolop (TRUTH_ORIF_EXPR, t1, t2));
+      }
+    else
+      {
+	tree t1 = convert_for_condition (build_expr (e->e1), e->e1->type);
+	tree t2 = build_expr_dtor (e->e2);
+	tree cond = build1 (TRUTH_NOT_EXPR, bool_type_node, t1);
+
+	this->result_ = build_condition (build_ctype (e->type),
+					 cond, t2, void_node);
+      }
+  }
+
+  /* Build a binary operand expression.  Operands go through usual arithmetic
+     conversions to bring them to a common type before evaluating.  */
+
+  void visit (BinExp *e)
+  {
+    tree_code code;
+
+    switch (e->op)
+      {
+      case TOKadd:
+      case TOKmin:
+	if ((e->e1->type->isreal () && e->e2->type->isimaginary ())
+	    || (e->e1->type->isimaginary () && e->e2->type->isreal ()))
+	  {
+	    /* If the result is complex, then we can shortcut binary_op.
+	       Frontend should have already validated types and sizes.  */
+	    tree t1 = build_expr (e->e1);
+	    tree t2 = build_expr (e->e2);
+
+	    if (e->op == TOKmin)
+	      t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2);
+
+	    if (e->e1->type->isreal ())
+	      this->result_ = complex_expr (build_ctype (e->type), t1, t2);
+	    else
+	      this->result_ = complex_expr (build_ctype (e->type), t2, t1);
+
+	    return;
+	  }
+	else
+	  code = (e->op == TOKadd)
+	    ? PLUS_EXPR : MINUS_EXPR;
+	break;
+
+      case TOKmul:
+	code = MULT_EXPR;
+	break;
+
+      case TOKdiv:
+	code = e->e1->type->isintegral ()
+	  ? TRUNC_DIV_EXPR : RDIV_EXPR;
+	break;
+
+      case TOKmod:
+	code = e->e1->type->isfloating ()
+	  ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
+	break;
+
+      case TOKand:
+	code = BIT_AND_EXPR;
+	break;
+
+      case TOKor:
+	code = BIT_IOR_EXPR;
+	break;
+
+      case TOKxor:
+	code = BIT_XOR_EXPR;
+	break;
+
+      case TOKshl:
+	code = LSHIFT_EXPR;
+	  break;
+
+      case TOKshr:
+	code = RSHIFT_EXPR;
+	break;
+
+      case TOKushr:
+	code = UNSIGNED_RSHIFT_EXPR;
+	break;
+
+      default:
+	gcc_unreachable ();
+      }
+
+    this->result_ = this->binary_op (code, build_ctype (e->type),
+				     build_expr (e->e1), build_expr (e->e2));
+  }
+
+  /* Build a power expression, which raises its left operand to the power of
+     its right operand.   */
+
+  void visit (PowExp *e)
+  {
+    /* Result type determines what version of pow() we call.  */
+    tree powtype = build_ctype (e->type->toBasetype ());
+
+    /* If type is int, implicitly convert to double.  This allows backend
+       to fold the call into a constant return value.  */
+    if (e->type->isintegral ())
+      powtype = double_type_node;
+
+    /* Lookup compatible builtin.  */
+    tree powfn = NULL_TREE;
+    if (TYPE_MAIN_VARIANT (powtype) == double_type_node)
+      powfn = builtin_decl_explicit (BUILT_IN_POW);
+    else if (TYPE_MAIN_VARIANT (powtype) == float_type_node)
+      powfn = builtin_decl_explicit (BUILT_IN_POWF);
+    else if (TYPE_MAIN_VARIANT (powtype) == long_double_type_node)
+      powfn = builtin_decl_explicit (BUILT_IN_POWL);
+
+    if (powfn == NULL_TREE)
+      {
+	Type *tb1 = e->e1->type->toBasetype ();
+
+	if (tb1->ty == Tarray || tb1->ty == Tsarray)
+	  error ("Array operation %s not implemented", e->toChars ());
+	else
+	  error ("%s ^^ %s is not supported",
+		 e->e1->type->toChars (), e->e2->type->toChars ());
+
+	this->result_ = error_mark_node;
+	return;
+      }
+
+    tree t1 = d_convert (powtype, build_expr (e->e1));
+    tree t2 = d_convert (powtype, build_expr (e->e2));
+
+    this->result_ = d_convert (build_ctype (e->type),
+			       build_call_expr (powfn, 2, t1, t2));
+  }
+
+  /* Build a concat expression, which concatenates two or more arrays of the
+     same type, producing a dynamic array with the result.  If one operand
+     is an element type, that element is converted to an array of length 1.  */
+
+  void visit (CatExp *e)
+  {
+    Type *tb1 = e->e1->type->toBasetype ();
+    Type *tb2 = e->e2->type->toBasetype ();
+    Type *etype;
+
+    if (tb1->ty == Tarray || tb1->ty == Tsarray)
+      etype = tb1->nextOf ();
+    else
+      etype = tb2->nextOf ();
+
+    vec<tree, va_gc> *elemvars = NULL;
+    tree result;
+
+    if (e->e1->op == TOKcat)
+      {
+	/* Flatten multiple concatenations to an array.
+	   So the expression ((a ~ b) ~ c) becomes [a, b, c]  */
+	int ndims = 2;
+
+	for (Expression *ex = e->e1; ex->op == TOKcat;)
+	  {
+	    if (ex->op == TOKcat)
+	      {
+		ex = ((CatExp *) ex)->e1;
+		ndims++;
+	      }
+	  }
+
+	/* Store all concatenation args to a temporary byte[][ndims] array.  */
+	Type *targselem = Type::tint8->arrayOf ();
+	tree var = create_temporary_var (make_array_type (targselem, ndims));
+	tree init = build_constructor (TREE_TYPE (var), NULL);
+	vec_safe_push (elemvars, var);
+
+	/* Loop through each concatenation from right to left.  */
+	vec<constructor_elt, va_gc> *elms = NULL;
+	CatExp *ce = e;
+	int dim = ndims - 1;
+
+	for (Expression *oe = ce->e2; oe != NULL;
+	     (ce->e1->op != TOKcat
+	      ? (oe = ce->e1)
+	      : (ce = (CatExp *)ce->e1, oe = ce->e2)))
+	  {
+	    tree arg = d_array_convert (etype, oe, &elemvars);
+	    tree index = size_int (dim);
+	    CONSTRUCTOR_APPEND_ELT (elms, index, d_save_expr (arg));
+
+	    /* Finished pushing all arrays.  */
+	    if (oe == ce->e1)
+	      break;
+
+	    dim -= 1;
+	  }
+
+	/* Check there is no logic bug in constructing byte[][] of arrays.  */
+	gcc_assert (dim == 0);
+	CONSTRUCTOR_ELTS (init) = elms;
+	DECL_INITIAL (var) = init;
+
+	tree arrs = d_array_value (build_ctype (targselem->arrayOf ()),
+				   size_int (ndims), build_address (var));
+
+	result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2,
+				build_typeinfo (e->type), arrs);
+      }
+    else
+      {
+	/* Handle single concatenation (a ~ b).  */
+	result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3,
+				build_typeinfo (e->type),
+				d_array_convert (etype, e->e1, &elemvars),
+				d_array_convert (etype, e->e2, &elemvars));
+      }
+
+    for (size_t i = 0; i < vec_safe_length (elemvars); ++i)
+      result = bind_expr ((*elemvars)[i], result);
+
+    this->result_ = result;
+  }
+
+  /* Build a assignment operator expression.  The right operand is implicitly
+     converted to the type of the left operand, and assigned to it.  */
+
+  void visit (BinAssignExp *e)
+  {
+    tree_code code;
+    Expression *e1b = e->e1;
+
+    switch (e->op)
+      {
+      case TOKaddass:
+	code = PLUS_EXPR;
+	break;
+
+      case TOKminass:
+	code = MINUS_EXPR;
+	break;
+
+      case TOKmulass:
+	code = MULT_EXPR;
+	break;
+
+      case TOKdivass:
+	code = e->e1->type->isintegral ()
+	  ? TRUNC_DIV_EXPR : RDIV_EXPR;
+	break;
+
+      case TOKmodass:
+	code = e->e1->type->isfloating ()
+	  ? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
+	break;
+
+      case TOKandass:
+	code = BIT_AND_EXPR;
+	break;
+
+      case TOKorass:
+	code = BIT_IOR_EXPR;
+	break;
+
+      case TOKxorass:
+	code = BIT_XOR_EXPR;
+	break;
+
+      case TOKpowass:
+	gcc_unreachable ();
+
+      case TOKshlass:
+	code = LSHIFT_EXPR;
+	break;
+
+      case TOKshrass:
+	code = RSHIFT_EXPR;
+	break;
+
+      case TOKushrass:
+	/* The left operand of `>>>=' does not undergo integral promotions
+	   before shifting.  Strip off any just incase.  */
+	while (e1b->op == TOKcast)
+	  {
+	    CastExp *ce = (CastExp *) e1b;
+	    gcc_assert (same_type_p (ce->type, ce->to));
+	    e1b = ce->e1;
+	  }
+	code = UNSIGNED_RSHIFT_EXPR;
+	break;
+
+      default:
+	gcc_unreachable ();
+      }
+
+    tree exp = this->binop_assignment (code, e1b, e->e2);
+    this->result_ = convert_expr (exp, e1b->type, e->type);
+  }
+
+  /* Build a concat assignment expression.  The right operand is appended
+     to the the left operand.  */
+
+  void visit (CatAssignExp *e)
+  {
+    Type *tb1 = e->e1->type->toBasetype ();
+    Type *tb2 = e->e2->type->toBasetype ();
+    Type *etype = tb1->nextOf ()->toBasetype ();
+
+    if (tb1->ty == Tarray && tb2->ty == Tdchar
+	&& (etype->ty == Tchar || etype->ty == Twchar))
+      {
+	/* Append a dchar to a char[] or wchar[]  */
+	libcall_fn libcall = (etype->ty == Tchar)
+	  ? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD;
+
+	this->result_ = build_libcall (libcall, e->type, 2,
+				       build_address (build_expr (e->e1)),
+				       build_expr (e->e2));
+      }
+    else
+      {
+	gcc_assert (tb1->ty == Tarray || tb2->ty == Tsarray);
+
+	tree tinfo = build_typeinfo (e->type);
+	tree ptr = build_address (build_expr (e->e1));
+
+	if ((tb2->ty == Tarray || tb2->ty == Tsarray)
+	    && same_type_p (etype, tb2->nextOf ()->toBasetype ()))
+	  {
+	    /* Append an array.  */
+	    this->result_ = build_libcall (LIBCALL_ARRAYAPPENDT, e->type, 3,
+					   tinfo, ptr, d_array_convert (e->e2));
+
+	  }
+	else if (same_type_p (etype, tb2))
+	  {
+	    /* Append an element.  */
+	    tree result = build_libcall (LIBCALL_ARRAYAPPENDCTX, e->type, 3,
+					 tinfo, ptr, size_one_node);
+	    result = d_save_expr (result);
+
+	    /* Assign e2 to last element.  */
+	    tree offexp = d_array_length (result);
+	    offexp = build2 (MINUS_EXPR, TREE_TYPE (offexp),
+			     offexp, size_one_node);
+	    offexp = d_save_expr (offexp);
+
+	    tree ptrexp = d_array_ptr (result);
+	    ptrexp = void_okay_p (ptrexp);
+	    ptrexp = build_array_index (ptrexp, offexp);
+
+	    /* Evaluate expression before appending.  */
+	    tree t2 = build_expr (e->e2);
+	    tree expr = stabilize_expr (&t2);
+
+	    t2 = d_save_expr (t2);
+	    result = modify_expr (build_deref (ptrexp), t2);
+	    result = compound_expr (t2, result);
+
+	    this->result_ = compound_expr (expr, result);
+	  }
+	else
+	  gcc_unreachable ();
+      }
+  }
+
+  /* Build an assignment expression.  The right operand is implicitly
+     converted to the type of the left operand, and assigned to it.  */
+
+  void visit (AssignExp *e)
+  {
+    /* First, handle special assignment semantics.  */
+
+    /* Look for array.length = n;  */
+    if (e->e1->op == TOKarraylength)
+      {
+	/* Assignment to an array's length property; resize the array.  */
+	ArrayLengthExp *ale = (ArrayLengthExp *) e->e1;
+	tree newlength = convert_expr (build_expr (e->e2), e->e2->type,
+				       Type::tsize_t);
+	tree ptr = build_address (build_expr (ale->e1));
+
+	/* Don't want the basetype for the element type.  */
+	Type *etype = ale->e1->type->toBasetype ()->nextOf ();
+	libcall_fn libcall = etype->isZeroInit ()
+	  ? LIBCALL_ARRAYSETLENGTHT : LIBCALL_ARRAYSETLENGTHIT;
+
+	tree result = build_libcall (libcall, ale->e1->type, 3,
+				     build_typeinfo (ale->e1->type),
+				     newlength, ptr);
+
+	this->result_ = d_array_length (result);
+	return;
+      }
+
+    /* Look for array[] = n;  */
+    if (e->e1->op == TOKslice)
+      {
+	SliceExp *se = (SliceExp *) e->e1;
+	Type *stype = se->e1->type->toBasetype ();
+	Type *etype = stype->nextOf ()->toBasetype ();
+
+	/* Determine if we need to run postblit or dtor.  */
+	bool postblit = this->needs_postblit (etype) && this->lvalue_p (e->e2);
+	bool destructor = this->needs_dtor (etype);
+
+	if (e->memset & blockAssign)
+	  {
+	    /* Set a range of elements to one value.  */
+	    tree t1 = d_save_expr (build_expr (e->e1));
+	    tree t2 = build_expr (e->e2);
+	    tree result;
+
+	    if ((postblit || destructor) && e->op != TOKblit)
+	      {
+		libcall_fn libcall = (e->op == TOKconstruct)
+		  ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN;
+		/* So we can call postblits on const/immutable objects.  */
+		tree ti = build_typeinfo (etype->unSharedOf ()->mutableOf ());
+
+		tree result = build_libcall (libcall, Type::tvoid, 4,
+					     d_array_ptr (t1),
+					     build_address (t2),
+					     d_array_length (t1), ti);
+		this->result_ = compound_expr (result, t1);
+		return;
+	      }
+
+	    if (integer_zerop (t2))
+	      {
+		tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
+		tree size = size_mult_expr (d_array_length (t1),
+					    size_int (etype->size ()));
+
+		result = build_call_expr (tmemset, 3, d_array_ptr (t1),
+					  integer_zero_node, size);
+	      }
+	    else
+	      result = build_array_set (d_array_ptr (t1),
+					d_array_length (t1), t2);
+
+	    this->result_ = compound_expr (result, t1);
+	  }
+	else
+	  {
+	    /* Perform a memcpy operation.  */
+	    gcc_assert (e->e2->type->ty != Tpointer);
+
+	    if (!postblit && !destructor && !array_bounds_check ())
+	      {
+		tree t1 = d_save_expr (d_array_convert (e->e1));
+		tree t2 = d_array_convert (e->e2);
+		tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY);
+		tree size = size_mult_expr (d_array_length (t1),
+					    size_int (etype->size ()));
+
+		tree result = build_call_expr (tmemcpy, 3, d_array_ptr (t1),
+					       d_array_ptr (t2), size);
+		this->result_ = compound_expr (result, t1);
+	      }
+	    else if ((postblit || destructor) && e->op != TOKblit)
+	      {
+		/* Generate: _d_arrayassign(ti, from, to)
+			 or: _d_arrayctor(ti, from, to)  */
+		libcall_fn libcall = (e->op == TOKconstruct)
+		  ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN;
+
+		this->result_ = build_libcall (libcall, e->type, 3,
+					       build_typeinfo (etype),
+					       d_array_convert (e->e2),
+					       d_array_convert (e->e1));
+	      }
+	    else
+	      {
+		/* Generate: _d_arraycopy()  */
+		this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3,
+					       size_int (etype->size ()),
+					       d_array_convert (e->e2),
+					       d_array_convert (e->e1));
+	      }
+	  }
+
+	return;
+      }
+
+    /* Look for reference initializations.  */
+    if (e->memset & referenceInit)
+      {
+	gcc_assert (e->op == TOKconstruct || e->op == TOKblit);
+	gcc_assert (e->e1->op == TOKvar);
+
+	Declaration *decl = ((VarExp *) e->e1)->var;
+	if (decl->storage_class & (STCout | STCref))
+	  {
+	    tree t2 = convert_for_assignment (build_expr (e->e2),
+					      e->e2->type, e->e1->type);
+	    tree t1 = build_expr (e->e1);
+	    /* Want reference to lhs, not indirect ref.  */
+	    t1 = TREE_OPERAND (t1, 0);
+	    t2 = build_address (t2);
+
+	    this->result_ = indirect_ref (build_ctype (e->type),
+					  build_assign (INIT_EXPR, t1, t2));
+	    return;
+	  }
+      }
+
+    /* Other types of assignments that may require post construction.  */
+    Type *tb1 = e->e1->type->toBasetype ();
+    tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR;
+
+    if (tb1->ty == Tstruct)
+      {
+	tree t1 = build_expr (e->e1);
+	tree t2 = convert_for_assignment (build_expr (e->e2),
+					  e->e2->type, e->e1->type);
+
+	if (e->e2->op == TOKint64)
+	  {
+	    /* Use memset to fill struct.  */
+	    StructDeclaration *sd = ((TypeStruct *) tb1)->sym;
+	    gcc_assert (e->op == TOKblit);
+
+	    tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
+	    tree result = build_call_expr (tmemset, 3, build_address (t1),
+					   t2, size_int (sd->structsize));
+
+	    /* Maybe set-up hidden pointer to outer scope context.  */
+	    if (sd->isNested ())
+	      {
+		tree field = get_symbol_decl (sd->vthis);
+		tree value = build_vthis (sd);
+
+		tree vthis_exp = modify_expr (component_ref (t1, field), value);
+		result = compound_expr (result, vthis_exp);
+	      }
+
+	    this->result_ = compound_expr (result, t1);
+	  }
+	else
+	  this->result_ = build_assign (modifycode, t1, t2);
+
+	return;
+      }
+
+    if (tb1->ty == Tsarray)
+      {
+	Type *etype = tb1->nextOf ();
+	gcc_assert (e->e2->type->toBasetype ()->ty == Tsarray);
+
+	/* Determine if we need to run postblit.  */
+	bool postblit = this->needs_postblit (etype);
+	bool destructor = this->needs_dtor (etype);
+	bool lvalue_p = this->lvalue_p (e->e2);
+
+	/* Even if the elements in rhs are all rvalues and don't have
+	   to call postblits, this assignment should call dtors on old
+	   assigned elements.  */
+	if ((!postblit && !destructor)
+	    || (e->op == TOKconstruct && !lvalue_p && postblit)
+	    || (e->op == TOKblit || e->e1->type->size () == 0))
+	  {
+	    tree t1 = build_expr (e->e1);
+	    tree t2 = convert_for_assignment (build_expr (e->e2),
+					      e->e2->type, e->e1->type);
+
+	    this->result_ = build_assign (modifycode, t1, t2);
+	    return;
+	  }
+
+	Type *arrtype = (e->type->ty == Tsarray) ? etype->arrayOf () : e->type;
+	tree result;
+
+	if (e->op == TOKconstruct)
+	  {
+	    /* Generate: _d_arrayctor(ti, from, to)  */
+	    result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3,
+				    build_typeinfo (etype),
+				    d_array_convert (e->e2),
+				    d_array_convert (e->e1));
+	  }
+	else
+	  {
+	    /* Generate: _d_arrayassign_l()
+		     or: _d_arrayassign_r()  */
+	    libcall_fn libcall = (lvalue_p)
+	      ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
+	    tree elembuf = build_local_temp (build_ctype (etype));
+
+	    result = build_libcall (libcall, arrtype, 4,
+				    build_typeinfo (etype),
+				    d_array_convert (e->e2),
+				    d_array_convert (e->e1),
+				    build_address (elembuf));
+	  }
+
+	/* Cast the libcall result back to a static array.  */
+	if (e->type->ty == Tsarray)
+	  result = indirect_ref (build_ctype (e->type),
+				 d_array_ptr (result));
+
+	this->result_ = result;
+	return;
+      }
+
+    /* Simple assignment.  */
+    tree t1 = build_expr (e->e1);
+    tree t2 = convert_for_assignment (build_expr (e->e2),
+				      e->e2->type, e->e1->type);
+
+    this->result_ = build_assign (modifycode, t1, t2);
+  }
+
+  /* Build a postfix expression.  */
+
+  void visit (PostExp *e)
+  {
+    tree result;
+
+    if (e->op == TOKplusplus)
+      {
+	result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type),
+			 build_expr (e->e1), build_expr (e->e2));
+      }
+    else if (e->op == TOKminusminus)
+      {
+	result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type),
+			 build_expr (e->e1), build_expr (e->e2));
+      }
+    else
+      gcc_unreachable ();
+
+    TREE_SIDE_EFFECTS (result) = 1;
+    this->result_ = result;
+  }
+
+  /* Build an index expression.  */
+
+  void visit (IndexExp *e)
+  {
+    Type *tb1 = e->e1->type->toBasetype ();
+
+    if (tb1->ty == Taarray)
+      {
+	/* Get the key for the associative array.  */
+	Type *tkey = ((TypeAArray *) tb1)->index->toBasetype ();
+	tree key = convert_expr (build_expr (e->e2), e->e2->type, tkey);
+	libcall_fn libcall;
+	tree tinfo, ptr;
+
+	if (e->modifiable)
+	  {
+	    libcall = LIBCALL_AAGETY;
+	    ptr = build_address (build_expr (e->e1));
+	    tinfo = build_typeinfo (tb1->unSharedOf ()->mutableOf ());
+	  }
+	else
+	  {
+	    libcall = LIBCALL_AAGETRVALUEX;
+	    ptr = build_expr (e->e1);
+	    tinfo = build_typeinfo (tkey);
+	  }
+
+	/* Index the associative array.  */
+	tree result = build_libcall (libcall, e->type->pointerTo (), 4,
+				     ptr, tinfo,
+				     size_int (tb1->nextOf ()->size ()),
+				     build_address (key));
+
+	if (!e->indexIsInBounds && array_bounds_check ())
+	  {
+	    tree tassert = d_assert_call (e->loc, LIBCALL_ARRAY_BOUNDS);
+	    result = d_save_expr (result);
+	    result = build_condition (TREE_TYPE (result),
+				      d_truthvalue_conversion (result),
+				      result, tassert);
+	  }
+
+	this->result_ = indirect_ref (build_ctype (e->type), result);
+      }
+    else
+      {
+	/* Get the data pointer and length for static and dynamic arrays.  */
+	tree array = d_save_expr (build_expr (e->e1));
+	tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
+
+	tree length = NULL_TREE;
+	if (tb1->ty != Tpointer)
+	  length = get_array_length (array, tb1);
+	else
+	  gcc_assert (e->lengthVar == NULL);
+
+	/* The __dollar variable just becomes a placeholder for the
+	   actual length.  */
+	if (e->lengthVar)
+	  e->lengthVar->csym = length;
+
+	/* Generate the index.  */
+	tree index = build_expr (e->e2);
+
+	/* If it's a static array and the index is constant, the front end has
+	   already checked the bounds.  */
+	if (tb1->ty != Tpointer && !e->indexIsInBounds)
+	  index = build_bounds_condition (e->e2->loc, index, length, false);
+
+	/* Index the .ptr  */
+	ptr = void_okay_p (ptr);
+	this->result_ = indirect_ref (TREE_TYPE (TREE_TYPE (ptr)),
+				      build_array_index (ptr, index));
+      }
+  }
+
+  /* Build a comma expression.  The type is the type of the right operand.  */
+
+  void visit (CommaExp *e)
+  {
+    tree t1 = build_expr (e->e1);
+    tree t2 = build_expr (e->e2);
+    tree type = e->type ? build_ctype (e->type) : void_type_node;
+
+    this->result_ = build2 (COMPOUND_EXPR, type, t1, t2);
+  }
+
+  /* Build an array length expression.  Returns the number of elements
+     in the array.  The result is of type size_t.  */
+
+  void visit (ArrayLengthExp *e)
+  {
+    if (e->e1->type->toBasetype ()->ty == Tarray)
+      this->result_ = d_array_length (build_expr (e->e1));
+    else
+      {
+	/* Static arrays have already been handled by the front-end.  */
+	error ("unexpected type for array length: %s", e->type->toChars ());
+	this->result_ = error_mark_node;
+      }
+  }
+
+  /* Build a delegate pointer expression.  This will return the frame
+     pointer value as a type void*.  */
+
+  void visit (DelegatePtrExp *e)
+  {
+    tree t1 = build_expr (e->e1);
+    this->result_ = delegate_object (t1);
+  }
+
+  /* Build a delegate function pointer expression.  This will return the
+     function pointer value as a function type.  */
+
+  void visit (DelegateFuncptrExp *e)
+  {
+    tree t1 = build_expr (e->e1);
+    this->result_ = delegate_method (t1);
+  }
+
+  /* Build a slice expression.  */
+
+  void visit (SliceExp *e)
+  {
+    Type *tb = e->type->toBasetype ();
+    Type *tb1 = e->e1->type->toBasetype ();
+    gcc_assert (tb->ty == Tarray || tb->ty == Tsarray);
+
+    /* Use convert-to-dynamic-array code if possible.  */
+    if (!e->lwr)
+      {
+	tree result = build_expr (e->e1);
+	if (e->e1->type->toBasetype ()->ty == Tsarray)
+	  result = convert_expr (result, e->e1->type, e->type);
+
+	this->result_ = result;
+	return;
+      }
+    else
+      gcc_assert (e->upr != NULL);
+
+    /* Get the data pointer and length for static and dynamic arrays.  */
+    tree array = d_save_expr (build_expr (e->e1));
+    tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
+    tree length = NULL_TREE;
+
+    /* Our array is already a SAVE_EXPR if necessary, so we don't make length
+       a SAVE_EXPR which is, at most, a COMPONENT_REF on top of array.  */
+    if (tb1->ty != Tpointer)
+      length = get_array_length (array, tb1);
+    else
+      gcc_assert (e->lengthVar == NULL);
+
+    /* The __dollar variable just becomes a placeholder for the
+       actual length.  */
+    if (e->lengthVar)
+      e->lengthVar->csym = length;
+
+    /* Generate lower bound.  */
+    tree lwr_tree = d_save_expr (build_expr (e->lwr));
+
+    if (!integer_zerop (lwr_tree))
+      {
+	/* Adjust the .ptr offset.  */
+	tree ptrtype = TREE_TYPE (ptr);
+	ptr = build_array_index (void_okay_p (ptr), lwr_tree);
+	ptr = build_nop (ptrtype, ptr);
+      }
+    else
+      lwr_tree = NULL_TREE;
+
+    /* Nothing more to do for static arrays.  */
+    if (tb->ty == Tsarray)
+      {
+	this->result_ = indirect_ref (build_ctype (e->type), ptr);
+	return;
+      }
+    else
+      gcc_assert (tb->ty == Tarray);
+
+    /* Generate upper bound with bounds checking.  */
+    tree upr_tree = d_save_expr (build_expr (e->upr));
+    tree newlength;
+
+    if (!e->upperIsInBounds)
+      {
+	if (length)
+	  {
+	    newlength = build_bounds_condition (e->upr->loc, upr_tree,
+						length, true);
+	  }
+	else
+	  {
+	    /* Still need to check bounds lwr <= upr for pointers.  */
+	    gcc_assert (tb1->ty == Tpointer);
+	    newlength = upr_tree;
+	  }
+      }
+    else
+      newlength = upr_tree;
+
+    if (lwr_tree)
+      {
+	/* Enforces lwr <= upr. No need to check lwr <= length as
+	   we've already ensured that upr <= length.  */
+	if (!e->lowerIsLessThanUpper)
+	  {
+	    tree cond = build_bounds_condition (e->lwr->loc, lwr_tree,
+						upr_tree, true);
+
+	    /* When bounds checking is off, the index value is
+	       returned directly.  */
+	    if (cond != lwr_tree)
+	      newlength = compound_expr (cond, newlength);
+	  }
+
+	/* Need to ensure lwr always gets evaluated first, as it may be a
+	   function call.  Generates (lwr, upr) - lwr.  */
+	newlength = fold_build2 (MINUS_EXPR, TREE_TYPE (newlength),
+				 compound_expr (lwr_tree, newlength), lwr_tree);
+      }
+
+    tree result = d_array_value (build_ctype (e->type), newlength, ptr);
+    this->result_ = compound_expr (array, result);
+  }
+
+  /* Build a cast expression, which converts the given unary expression to the
+     type of result.  */
+
+  void visit (CastExp *e)
+  {
+    Type *ebtype = e->e1->type->toBasetype ();
+    Type *tbtype = e->to->toBasetype ();
+    tree result = build_expr (e->e1, this->constp_);
+
+    /* Just evaluate e1 if it has any side effects.  */
+    if (tbtype->ty == Tvoid)
+      this->result_ = build_nop (build_ctype (tbtype), result);
+    else
+      this->result_ = convert_expr (result, ebtype, tbtype);
+  }
+
+  /* Build a delete expression.  */
+
+  void visit (DeleteExp *e)
+  {
+    tree t1 = build_expr (e->e1);
+    Type *tb1 = e->e1->type->toBasetype ();
+
+    if (tb1->ty == Tclass)
+      {
+	/* For class object references, if there is a destructor for that class,
+	   the destructor is called for the object instance.  */
+	libcall_fn libcall;
+
+	if (e->e1->op == TOKvar)
+	  {
+	    VarDeclaration *v = ((VarExp *) e->e1)->var->isVarDeclaration ();
+	    if (v && v->onstack)
+	      {
+		libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
+		  ? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER;
+
+		this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
+		return;
+	      }
+	  }
+
+	/* Otherwise, the garbage collector is called to immediately free the
+	   memory allocated for the class instance.  */
+	libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
+	  ? LIBCALL_DELINTERFACE : LIBCALL_DELCLASS;
+
+	t1 = build_address (t1);
+	this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
+      }
+    else if (tb1->ty == Tarray)
+      {
+	/* For dynamic arrays, the garbage collector is called to immediately
+	   release the memory.  */
+	Type *telem = tb1->nextOf ()->baseElemOf ();
+	tree ti = null_pointer_node;
+
+	if (telem->ty == Tstruct)
+	  {
+	    /* Might need to run destructor on array contents.  */
+	    TypeStruct *ts = (TypeStruct *) telem;
+	    if (ts->sym->dtor)
+	      ti = build_typeinfo (tb1->nextOf ());
+	  }
+
+	/* Generate: _delarray_t (&t1, ti);  */
+	this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2,
+				       build_address (t1), ti);
+      }
+    else if (tb1->ty == Tpointer)
+      {
+	/* For pointers to a struct instance, if the struct has overloaded
+	   operator delete, then that operator is called.  */
+	t1 = build_address (t1);
+	Type *tnext = ((TypePointer *)tb1)->next->toBasetype ();
+
+	if (tnext->ty == Tstruct)
+	  {
+	    TypeStruct *ts = (TypeStruct *)tnext;
+	    if (ts->sym->dtor)
+	      {
+		this->result_ = build_libcall (LIBCALL_DELSTRUCT, Type::tvoid,
+					       2, t1, build_typeinfo (tnext));
+		return;
+	      }
+	  }
+
+	/* Otherwise, the garbage collector is called to immediately free the
+	   memory allocated for the pointer.  */
+	this->result_ = build_libcall (LIBCALL_DELMEMORY, Type::tvoid, 1, t1);
+      }
+    else
+      {
+	error ("don't know how to delete %s", e->e1->toChars ());
+	this->result_ = error_mark_node;
+      }
+  }
+
+  /* Build a remove expression, which removes a particular key from an
+     associative array.  */
+
+  void visit (RemoveExp *e)
+  {
+    /* Check that the array is actually an associative array.  */
+    if (e->e1->type->toBasetype ()->ty == Taarray)
+      {
+	Type *tb = e->e1->type->toBasetype ();
+	Type *tkey = ((TypeAArray *) tb)->index->toBasetype ();
+	tree index = convert_expr (build_expr (e->e2), e->e2->type, tkey);
+
+	this->result_ = build_libcall (LIBCALL_AADELX, Type::tbool, 3,
+				       build_expr (e->e1),
+				       build_typeinfo (tkey),
+				       build_address (index));
+      }
+    else
+      {
+	error ("%s is not an associative array", e->e1->toChars ());
+	this->result_ = error_mark_node;
+      }
+  }
+
+  /* Build an unary not expression.  */
+
+  void visit(NotExp *e)
+  {
+    tree result = convert_for_condition(build_expr(e->e1), e->e1->type);
+    /* Need to convert to boolean type or this will fail.  */
+    result = fold_build1(TRUTH_NOT_EXPR, bool_type_node, result);
+
+    this->result_ = d_convert(build_ctype(e->type), result);
+  }
+
+  /* Build a compliment expression, where all the bits in the value are
+     complemented.  Note: unlike in C, the usual integral promotions
+     are not performed prior to the complement operation.  */
+
+  void visit (ComExp *e)
+  {
+    TY ty1 = e->e1->type->toBasetype ()->ty;
+    gcc_assert (ty1 != Tarray && ty1 != Tsarray);
+
+    this->result_ = fold_build1 (BIT_NOT_EXPR, build_ctype (e->type),
+				 build_expr (e->e1));
+  }
+
+  /* Build an unary negation expression.  */
+
+  void visit (NegExp *e)
+  {
+    TY ty1 = e->e1->type->toBasetype ()->ty;
+    gcc_assert (ty1 != Tarray && ty1 != Tsarray);
+
+    this->result_ = fold_build1 (NEGATE_EXPR, build_ctype (e->type),
+				 build_expr (e->e1));
+  }
+
+  /* Build a pointer index expression.  */
+
+  void visit (PtrExp *e)
+  {
+    Type *tnext = NULL;
+    size_t offset;
+    tree result;
+
+    if (e->e1->op == TOKadd)
+      {
+	BinExp *be = (BinExp *) e->e1;
+	if (be->e1->op == TOKaddress
+	    && be->e2->isConst () && be->e2->type->isintegral ())
+	  {
+	    Expression *ae = ((AddrExp *) be->e1)->e1;
+	    tnext = ae->type->toBasetype ();
+	    result = build_expr (ae);
+	    offset = be->e2->toUInteger ();
+	  }
+      }
+    else if (e->e1->op == TOKsymoff)
+      {
+	SymOffExp *se = (SymOffExp *) e->e1;
+	if (!declaration_reference_p (se->var))
+	  {
+	    tnext = se->var->type->toBasetype ();
+	    result = get_decl_tree (se->var);
+	    offset = se->offset;
+	  }
+      }
+
+    /* Produce better code by converting *(#record + n) to
+       COMPONENT_REFERENCE.  Otherwise, the variable will always be
+       allocated in memory because its address is taken.  */
+    if (tnext && tnext->ty == Tstruct)
+      {
+	StructDeclaration *sd = ((TypeStruct *) tnext)->sym;
+
+	for (size_t i = 0; i < sd->fields.dim; i++)
+	  {
+	    VarDeclaration *field = sd->fields[i];
+
+	    if (field->offset == offset
+		&& same_type_p (field->type, e->type))
+	      {
+		/* Catch errors, backend will ICE otherwise.  */
+		if (error_operand_p (result))
+		  this->result_ = result;
+		else
+		  {
+		    result  = component_ref (result, get_symbol_decl (field));
+		    this->result_ = result;
+		  }
+		return;
+	      }
+	    else if (field->offset > offset)
+	      break;
+	  }
+      }
+
+    this->result_ = indirect_ref (build_ctype (e->type), build_expr (e->e1));
+  }
+
+  /* Build an unary address expression.  */
+
+  void visit (AddrExp *e)
+  {
+    tree type = build_ctype (e->type);
+    tree exp;
+
+    /* The frontend optimizer can convert const symbol into a struct literal.
+       Taking the address of a struct literal is otherwise illegal.  */
+    if (e->e1->op == TOKstructliteral)
+      {
+	StructLiteralExp *sle = ((StructLiteralExp *) e->e1)->origin;
+	gcc_assert (sle != NULL);
+
+	/* Build the reference symbol.  */
+	if (!sle->sym)
+	  {
+	    sle->sym = build_artificial_decl (build_ctype (sle->type),
+					      build_expr (sle, true), "S");
+	    d_pushdecl (sle->sym);
+	    rest_of_decl_compilation (sle->sym, 1, 0);
+	  }
+
+	exp = sle->sym;
+      }
+    else
+      exp = build_expr (e->e1, this->constp_);
+
+    TREE_CONSTANT (exp) = 0;
+    this->result_ = d_convert (type, build_address (exp));
+  }
+
+  /* Build a function call expression.  */
+
+  void visit (CallExp *e)
+  {
+    Type *tb = e->e1->type->toBasetype ();
+    Expression *e1b = e->e1;
+
+    tree callee = NULL_TREE;
+    tree object = NULL_TREE;
+    TypeFunction *tf = NULL;
+
+    /* Calls to delegates can sometimes look like this.  */
+    if (e1b->op == TOKcomma)
+      {
+	e1b = ((CommaExp *) e1b)->e2;
+	gcc_assert (e1b->op == TOKvar);
+
+	Declaration *var = ((VarExp *) e1b)->var;
+	gcc_assert (var->isFuncDeclaration () && !var->needThis ());
+      }
+
+    if (e1b->op == TOKdotvar && tb->ty != Tdelegate)
+      {
+	DotVarExp *dve = (DotVarExp *) e1b;
+
+	/* Don't modify the static initializer for struct literals.  */
+	if (dve->e1->op == TOKstructliteral)
+	  {
+	    StructLiteralExp *sle = (StructLiteralExp *) dve->e1;
+	    sle->useStaticInit = false;
+	  }
+
+	FuncDeclaration *fd = dve->var->isFuncDeclaration ();
+	if (fd != NULL)
+	  {
+	    /* Get the correct callee from the DotVarExp object.  */
+	    tree fndecl = get_symbol_decl (fd);
+	    AggregateDeclaration *ad = fd->isThis ();
+
+	    /* Static method; ignore the object instance.  */
+	    if (!ad)
+	      callee = build_address (fndecl);
+	    else
+	      {
+		tree thisexp = build_expr (dve->e1);
+
+		/* Want reference to 'this' object.  */
+		if (!POINTER_TYPE_P (TREE_TYPE (thisexp)))
+		  thisexp = build_address (thisexp);
+
+		/* Make the callee a virtual call.  */
+		if (fd->isVirtual () && !fd->isFinalFunc () && !e->directcall)
+		  {
+		    tree fntype = build_pointer_type (TREE_TYPE (fndecl));
+		    tree thistype = build_ctype (ad->handleType ());
+		    thisexp = build_nop (thistype, d_save_expr (thisexp));
+		    fndecl = build_vindex_ref (thisexp, fntype, fd->vtblIndex);
+		  }
+		else
+		  fndecl = build_address (fndecl);
+
+		callee = build_method_call (fndecl, thisexp, fd->type);
+	      }
+	  }
+      }
+
+    if (callee == NULL_TREE)
+      callee = build_expr (e1b);
+
+    if (METHOD_CALL_EXPR (callee))
+      {
+	/* This could be a delegate expression (TY == Tdelegate), but not
+	   actually a delegate variable.  */
+	if (e1b->op == TOKdotvar)
+	  {
+	    /* This gets the true function type, getting the function type
+	       from e1->type can sometimes be incorrect, such as when calling
+	       a 'ref' return function.  */
+	    tf = get_function_type (((DotVarExp *) e1b)->var->type);
+	  }
+	else
+	  tf = get_function_type (tb);
+
+	extract_from_method_call (callee, callee, object);
+      }
+    else if (tb->ty == Tdelegate)
+      {
+	/* Delegate call, extract .object and .funcptr from var.  */
+	callee = d_save_expr (callee);
+	tf = get_function_type (tb);
+	object = delegate_object (callee);
+	callee = delegate_method (callee);
+      }
+    else if (e1b->op == TOKvar)
+      {
+	FuncDeclaration *fd = ((VarExp *) e1b)->var->isFuncDeclaration ();
+	gcc_assert (fd != NULL);
+	tf = get_function_type (fd->type);
+
+	if (fd->isNested ())
+	  {
+	    /* Maybe re-evaluate symbol storage treating 'fd' as public.  */
+	    if (call_by_alias_p (d_function_chain->function, fd))
+	      TREE_PUBLIC (callee) = 1;
+
+	    object = get_frame_for_symbol (fd);
+	  }
+	else if (fd->needThis ())
+	  {
+	    e1b->error ("need 'this' to access member %s", fd->toChars ());
+	    /* Continue compiling...  */
+	    object = null_pointer_node;
+	  }
+      }
+    else
+      {
+	/* Normal direct function call.  */
+	tf = get_function_type (tb);
+      }
+
+    gcc_assert (tf != NULL);
+
+    /* Now we have the type, callee and maybe object reference,
+       build the call expression.  */
+    tree exp = d_build_call (tf, callee, object, e->arguments);
+
+    if (tf->isref)
+      exp = build_deref (exp);
+
+    /* Some library calls are defined to return a generic type.
+       this->type is the real type we want to return.  */
+    if (e->type->isTypeBasic ())
+      exp = d_convert (build_ctype (e->type), exp);
+
+    this->result_ = exp;
+  }
+
+  /* Build a delegate expression.  */
+
+  void visit (DelegateExp *e)
+  {
+    if (e->func->semanticRun == PASSsemantic3done)
+      {
+	/* Add the function as nested function if it belongs to this module.
+	   ie: it is a member of this module, or it is a template instance.  */
+	Dsymbol *owner = e->func->toParent ();
+	while (!owner->isTemplateInstance () && owner->toParent ())
+	  owner = owner->toParent ();
+	if (owner->isTemplateInstance () || owner == d_function_chain->module)
+	  build_decl_tree (e->func);
+      }
+
+    tree fndecl;
+    tree object;
+
+    if (e->func->isNested ())
+      {
+	if (e->e1->op == TOKnull)
+	  object = build_expr (e->e1);
+	else
+	  object = get_frame_for_symbol (e->func);
+
+	fndecl = build_address (get_symbol_decl (e->func));
+      }
+    else
+      {
+	if (!e->func->isThis ())
+	  {
+	    error ("delegates are only for non-static functions");
+	    this->result_ = error_mark_node;
+	    return;
+	  }
+
+	object = build_expr (e->e1);
+
+	/* Want reference to 'this' object.  */
+	if (e->e1->type->ty != Tclass && e->e1->type->ty != Tpointer)
+	  object = build_address (object);
+
+	fndecl = get_symbol_decl (e->func);
+
+	/* Get pointer to function out of the virtual table.  */
+	if (e->func->isVirtual () && !e->func->isFinalFunc ()
+	    && e->e1->op != TOKsuper && e->e1->op != TOKdottype)
+	  {
+	    tree fntype = build_pointer_type (TREE_TYPE (fndecl));
+	    object = d_save_expr (object);
+	    fndecl = build_vindex_ref (object, fntype, e->func->vtblIndex);
+	  }
+	else
+	  fndecl = build_address (fndecl);
+      }
+
+    this->result_ = build_method_call (fndecl, object, e->type);
+  }
+
+  /* Build a type component expression.  */
+
+  void visit (DotTypeExp *e)
+  {
+    /* Just a pass through to underlying expression.  */
+    this->result_ = build_expr (e->e1);
+  }
+
+  /* Build a component reference expression.  */
+
+  void visit (DotVarExp *e)
+  {
+    VarDeclaration *vd = e->var->isVarDeclaration ();
+
+    /* This could also be a function, but relying on that being taken
+       care of by the visitor interface for CallExp.  */
+    if (vd != NULL)
+      {
+	if (!vd->isField ())
+	  this->result_ = get_decl_tree (vd);
+	else
+	  {
+	    tree object = build_expr (e->e1);
+
+	    if (e->e1->type->toBasetype ()->ty != Tstruct)
+	      object = build_deref (object);
+
+	    this->result_ = component_ref (object, get_symbol_decl (vd));
+	  }
+      }
+    else
+      {
+	error ("%s is not a field, but a %s",
+	       e->var->toChars (), e->var->kind ());
+	this->result_ = error_mark_node;
+      }
+  }
+
+  /* Build an assert expression, used to declare conditions that must hold at
+     that a given point in the program.  */
+
+  void visit (AssertExp *e)
+  {
+    /* Do nothing if not compiling in assert contracts.  */
+    if (!global.params.useAssert)
+      {
+	this->result_ = void_node;
+	return;
+      }
+
+    /* Build _d_assert() call.  */
+    Type *tb1 = e->e1->type->toBasetype ();
+    tree tmsg = NULL_TREE;
+    libcall_fn libcall;
+
+    if (d_function_chain->function->isUnitTestDeclaration ())
+      {
+	if (e->msg)
+	  {
+	    tmsg = build_expr_dtor (e->msg);
+	    libcall = LIBCALL_UNITTEST_MSG;
+	  }
+	else
+	  libcall = LIBCALL_UNITTEST;
+      }
+    else
+      {
+	if (e->msg)
+	  {
+	    tmsg = build_expr_dtor (e->msg);
+	    libcall = LIBCALL_ASSERT_MSG;
+	  }
+	else
+	  libcall = LIBCALL_ASSERT;
+      }
+
+    tree assert_call = d_assert_call (e->loc, libcall, tmsg);
+
+    /* Build condition that we are asserting in this contract.  */
+    if (tb1->ty == Tclass)
+      {
+	ClassDeclaration *cd = tb1->isClassHandle ();
+	tree arg = build_expr (e->e1);
+	tree invc = void_node;
+
+	if (cd->isCOMclass ())
+	  {
+	    tree cond = build_boolop (NE_EXPR, arg, null_pointer_node);
+	    this->result_ = build_vcondition (cond, void_node, assert_call);
+	    return;
+	  }
+	else if (cd->isInterfaceDeclaration ())
+	  arg = convert_expr (arg, tb1, get_object_type ());
+
+	if (global.params.useInvariants && !cd->isCPPclass ())
+	  {
+	    arg = d_save_expr (arg);
+	    invc = build_libcall (LIBCALL_INVARIANT, Type::tvoid, 1, arg);
+	  }
+
+	/* This does a null pointer check before calling _d_invariant().  */
+	tree cond = build_boolop (NE_EXPR, arg, null_pointer_node);
+	this->result_ = build_vcondition (cond, invc, assert_call);
+      }
+    else
+      {
+	/* Generate: ((bool) e1  ? (void)0 : _d_assert (...))
+		 or: (e1 != null ? e1._invariant() : _d_assert (...))  */
+	tree t1 = build_expr (e->e1);
+	tree invc = void_node;
+
+	if (global.params.useInvariants
+	    && tb1->ty == Tpointer && tb1->nextOf ()->ty == Tstruct)
+	  {
+	    FuncDeclaration *inv = ((TypeStruct *) tb1->nextOf ())->sym->inv;
+	    if (inv != NULL)
+	      {
+		Expressions args;
+		t1 = d_save_expr (t1);
+		invc = d_build_call_expr (inv, t1, &args);
+	      }
+	  }
+
+	tree cond = convert_for_condition (t1, e->e1->type);
+	this->result_ = build_vcondition (cond, invc, assert_call);
+      }
+  }
+
+  /* Build a declaration expression.  */
+
+  void visit (DeclarationExp *e)
+  {
+    /* Compile the declaration.  */
+    push_stmt_list ();
+    build_decl_tree (e->declaration);
+    tree result = pop_stmt_list ();
+
+    /* Construction of an array for typesafe-variadic function arguments
+       can cause an empty STMT_LIST here.  This can causes problems
+       during gimplification.  */
+    if (TREE_CODE (result) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (result))
+      this->result_ = build_empty_stmt (input_location);
+    else
+      this->result_ = result;
+
+    /* Maybe put variable on list of things needing destruction.  */
+    VarDeclaration *vd = e->declaration->isVarDeclaration ();
+    if (vd != NULL)
+      {
+	if (!vd->isStatic () && !(vd->storage_class & STCmanifest)
+	    && !(vd->storage_class & (STCextern | STCtls | STCgshared)))
+	  {
+	    if (vd->needsScopeDtor ())
+	      d_function_chain->vars_in_scope.safe_push (vd);
+	  }
+      }
+
+  }
+
+  /* Build a typeid expression.  Returns an instance of class TypeInfo
+     corresponding to . */
+
+  void visit (TypeidExp *e)
+  {
+    if (Type *tid = isType (e->obj))
+      {
+	tree ti = build_typeinfo (tid);
+
+	/* If the typeinfo is at an offset.  */
+	if (tid->vtinfo->offset)
+	  ti = build_offset (ti, size_int (tid->vtinfo->offset));
+
+	this->result_ = build_nop (build_ctype (e->type), ti);
+      }
+    else if (Expression *tid = isExpression (e->obj))
+      {
+	Type *type = tid->type->toBasetype ();
+	assert (type->ty == Tclass);
+
+	/* Generate **classptr to get the classinfo.  */
+	tree ci = build_expr (tid);
+	ci = indirect_ref (ptr_type_node, ci);
+	ci = indirect_ref (ptr_type_node, ci);
+
+	/* Add extra indirection for interfaces.  */
+	if (((TypeClass *) type)->sym->isInterfaceDeclaration ())
+	  ci = indirect_ref (ptr_type_node, ci);
+
+	this->result_ = build_nop (build_ctype (e->type), ci);
+      }
+    else
+      gcc_unreachable ();
+  }
+
+  /* Build a function/lambda expression.  */
+
+  void visit (FuncExp *e)
+  {
+    Type *ftype = e->type->toBasetype ();
+
+    /* This check is for lambda's, remove 'vthis' as function isn't nested.  */
+    if (e->fd->tok == TOKreserved && ftype->ty == Tpointer)
+      {
+	e->fd->tok = TOKfunction;
+	e->fd->vthis = NULL;
+      }
+
+    /* Compile the function literal body.  */
+    build_decl_tree (e->fd);
+
+    /* If nested, this will be a trampoline.  */
+    if (e->fd->isNested ())
+      {
+	if (this->constp_)
+	  {
+	    e->error ("non-constant nested delegate literal expression %s",
+		      e->toChars ());
+	    this->result_ = error_mark_node;
+	  }
+	else
+	  {
+	    tree func = build_address (get_symbol_decl (e->fd));
+	    tree object = get_frame_for_symbol (e->fd);
+	    this->result_ = build_method_call (func, object, e->fd->type);
+	  }
+      }
+    else
+      {
+	this->result_ = build_nop (build_ctype (e->type),
+				   build_address (get_symbol_decl (e->fd)));
+      }
+  }
+
+  /* Build a halt expression.  */
+
+  void visit (HaltExp *)
+  {
+    /* Should we use trap() or abort()?  */
+    tree ttrap = builtin_decl_explicit (BUILT_IN_TRAP);
+    this->result_ = build_call_expr (ttrap, 0);
+  }
+
+  /* Build a symbol pointer offset expression.  */
+
+  void visit (SymOffExp *e)
+  {
+    /* Build the address and offset of the symbol.  */
+    size_t soffset = ((SymOffExp *) e)->offset;
+    tree result = get_decl_tree (e->var);
+    TREE_USED (result) = 1;
+
+    if (declaration_reference_p (e->var))
+      gcc_assert (POINTER_TYPE_P (TREE_TYPE (result)));
+    else
+      result = build_address (result);
+
+    if (!soffset)
+      result = d_convert (build_ctype (e->type), result);
+    else
+      {
+	tree offset = size_int (soffset);
+	result = build_nop (build_ctype (e->type),
+			    build_offset (result, offset));
+      }
+
+    this->result_ = result;
+  }
+
+  /* Build a variable expression.  */
+
+  void visit (VarExp *e)
+  {
+    if (e->var->needThis ())
+      {
+	error ("need 'this' to access member %s", e->var->ident->toChars ());
+	this->result_ = error_mark_node;
+	return;
+      }
+    else if (e->var->ident == Id::ctfe)
+      {
+	/* __ctfe is always false at runtime.  */
+	this->result_ = integer_zero_node;
+	return;
+      }
+
+    /* This check is same as is done in FuncExp for lambdas.  */
+    FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ();
+    if (fld != NULL)
+      {
+	if (fld->tok == TOKreserved)
+	  {
+	    fld->tok = TOKfunction;
+	    fld->vthis = NULL;
+	  }
+
+	/* Compiler the function literal body.  */
+	build_decl_tree (fld);
+      }
+
+    if (this->constp_)
+      {
+	/* Want the initializer, not the expression.  */
+	VarDeclaration *var = e->var->isVarDeclaration ();
+	SymbolDeclaration *sd = e->var->isSymbolDeclaration ();
+	tree init = NULL_TREE;
+
+	if (var && (var->isConst () || var->isImmutable ())
+	    && e->type->toBasetype ()->ty != Tsarray && var->_init)
+	  {
+	    if (var->inuse)
+	      e->error ("recursive reference %s", e->toChars ());
+	    else
+	      {
+		var->inuse++;
+		init = build_expr (var->_init->toExpression (), true);
+		var->inuse--;
+	      }
+	  }
+	else if (sd && sd->dsym)
+	  init = layout_struct_initializer (sd->dsym);
+	else
+	  e->error ("non-constant expression %s", e->toChars ());
+
+	if (init != NULL_TREE)
+	  this->result_ = init;
+	else
+	  this->result_ = error_mark_node;
+      }
+    else
+      {
+	tree result = get_decl_tree (e->var);
+	TREE_USED (result) = 1;
+
+	/* For variables that are references - currently only out/inout
+	   arguments; objects don't count - evaluating the variable means
+	   we want what it refers to.  */
+	if (declaration_reference_p (e->var))
+	  result = indirect_ref (build_ctype (e->var->type), result);
+
+	this->result_ = result;
+      }
+  }
+
+  /* Build a this variable expression.  */
+
+  void visit (ThisExp *e)
+  {
+    FuncDeclaration *fd = d_function_chain ? d_function_chain->function : NULL;
+    tree result = NULL_TREE;
+
+    if (e->var)
+      result = get_decl_tree (e->var);
+    else
+      {
+	gcc_assert (fd && fd->vthis);
+	result = get_decl_tree (fd->vthis);
+      }
+
+    if (e->type->ty == Tstruct)
+      result = build_deref (result);
+
+    this->result_ = result;
+  }
+
+  /* Build a new expression, which allocates memory either on the garbage
+     collected heap or by using a class or struct specific allocator.  */
+
+  void visit (NewExp *e)
+  {
+    Type *tb = e->type->toBasetype ();
+    tree result;
+
+    if (e->allocator)
+      gcc_assert (e->newargs);
+
+    if (tb->ty == Tclass)
+      {
+	/* Allocating a new class.  */
+	tb = e->newtype->toBasetype ();
+	gcc_assert (tb->ty == Tclass);
+
+	ClassDeclaration *cd = ((TypeClass *) tb)->sym;
+	tree type = build_ctype (tb);
+	tree setup_exp = NULL_TREE;
+	tree new_call;
+
+	if (e->onstack)
+	  {
+	    /* If being used as an initializer for a local variable with scope
+	       storage class, then the instance is allocated on the stack
+	       rather than the heap or using the class specific allocator.  */
+	    tree var = build_local_temp (TREE_TYPE (type));
+	    new_call = build_nop (type, build_address (var));
+	    setup_exp = modify_expr (var, aggregate_initializer_decl (cd));
+	  }
+	else if (e->allocator)
+	  {
+	    /* Call class allocator, and copy the initializer into memory.  */
+	    new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
+	    new_call = d_save_expr (new_call);
+	    new_call = build_nop (type, new_call);
+	    setup_exp = modify_expr (build_deref (new_call),
+				     aggregate_initializer_decl (cd));
+	  }
+	else
+	  {
+	    /* Generate: _d_newclass()  */
+	    tree arg = build_address (get_classinfo_decl (cd));
+	    new_call = build_libcall (LIBCALL_NEWCLASS, tb, 1, arg);
+	  }
+
+	/* Set the context pointer for nested classes.  */
+	if (cd->isNested ())
+	  {
+	    tree field = get_symbol_decl (cd->vthis);
+	    tree value = NULL_TREE;
+
+	    if (e->thisexp)
+	      {
+		ClassDeclaration *tcd = e->thisexp->type->isClassHandle ();
+		Dsymbol *outer = cd->toParent2 ();
+		int offset = 0;
+
+		value = build_expr (e->thisexp);
+		if (outer != tcd)
+		  {
+		    ClassDeclaration *ocd = outer->isClassDeclaration ();
+		    gcc_assert (ocd->isBaseOf (tcd, &offset));
+		    /* Could just add offset...  */
+		    value = convert_expr (value, e->thisexp->type, ocd->type);
+		  }
+	      }
+	    else
+	      value = build_vthis (cd);
+
+	    if (value != NULL_TREE)
+	      {
+		/* Generate: (new())->vthis = this;  */
+		new_call = d_save_expr (new_call);
+		field = component_ref (build_deref (new_call), field);
+		setup_exp = compound_expr (setup_exp,
+					   modify_expr (field, value));
+	      }
+	  }
+	new_call = compound_expr (setup_exp, new_call);
+
+	/* Call the class constructor.  */
+	if (e->member)
+	  result = d_build_call_expr (e->member, new_call, e->arguments);
+	else
+	  result = new_call;
+
+	if (e->argprefix)
+	  result = compound_expr (build_expr (e->argprefix), result);
+      }
+    else if (tb->ty == Tpointer && tb->nextOf ()->toBasetype ()->ty == Tstruct)
+      {
+	/* Allocating memory for a new struct.  */
+	Type *htype = e->newtype->toBasetype ();
+	gcc_assert (htype->ty == Tstruct);
+	gcc_assert (!e->onstack);
+
+	TypeStruct *stype = (TypeStruct *) htype;
+	StructDeclaration *sd = stype->sym;
+	tree new_call;
+
+	/* Cannot new an opaque struct.  */
+	if (sd->size (e->loc) == 0)
+	  {
+	    this->result_ = d_convert (build_ctype (e->type),
+				       integer_zero_node);
+	    return;
+	  }
+
+	if (e->allocator)
+	  {
+	    /* Call struct allocator.  */
+	    new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
+	    new_call = build_nop (build_ctype (tb), new_call);
+	  }
+	else
+	  {
+	    /* Generate: _d_newitemT()  */
+	    libcall_fn libcall = htype->isZeroInit ()
+	      ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
+	    tree arg = build_typeinfo (e->newtype);
+	    new_call = build_libcall (libcall, tb, 1, arg);
+	  }
+
+	if (e->member || !e->arguments)
+	  {
+	    /* Set the context pointer for nested structs.  */
+	    if (sd->isNested ())
+	      {
+		tree value = build_vthis (sd);
+		tree field = get_symbol_decl (sd->vthis);
+		tree type = build_ctype (stype);
+
+		new_call = d_save_expr (new_call);
+		field = component_ref (indirect_ref (type, new_call), field);
+		new_call = compound_expr (modify_expr (field, value), new_call);
+	      }
+
+	    /* Call the struct constructor.  */
+	    if (e->member)
+	      result = d_build_call_expr (e->member, new_call, e->arguments);
+	    else
+	      result = new_call;
+	  }
+	else
+	  {
+	    /* If we have a user supplied initializer, then set-up with a
+	       struct literal.  */
+	    if (e->arguments != NULL && sd->fields.dim != 0)
+	      {
+		StructLiteralExp *se = StructLiteralExp::create (e->loc, sd,
+								 e->arguments,
+								 htype);
+		new_call = d_save_expr (new_call);
+		se->type = sd->type;
+		se->sym = new_call;
+		result = compound_expr (build_expr (se), new_call);
+	      }
+	    else
+	      result = new_call;
+	  }
+
+	if (e->argprefix)
+	  result = compound_expr (build_expr (e->argprefix), result);
+      }
+    else if (tb->ty == Tarray)
+      {
+	/* Allocating memory for a new D array.  */
+	tb = e->newtype->toBasetype ();
+	gcc_assert (tb->ty == Tarray);
+	TypeDArray *tarray = (TypeDArray *) tb;
+
+	gcc_assert (!e->allocator);
+	gcc_assert (e->arguments && e->arguments->dim >= 1);
+
+	if (e->arguments->dim == 1)
+	  {
+	    /* Single dimension array allocations.  */
+	    Expression *arg = (*e->arguments)[0];
+
+	    if (tarray->next->size () == 0)
+	      {
+		/* Array element size is unknown.  */
+		this->result_ = d_array_value (build_ctype (e->type),
+					       size_int (0), null_pointer_node);
+		return;
+	      }
+
+	    libcall_fn libcall = tarray->next->isZeroInit ()
+	      ? LIBCALL_NEWARRAYT : LIBCALL_NEWARRAYIT;
+	    result = build_libcall (libcall, tb, 2,
+				    build_typeinfo (e->type),
+				    build_expr (arg));
+	  }
+	else
+	  {
+	    /* Multidimensional array allocations.  */
+	    vec<constructor_elt, va_gc> *elms = NULL;
+	    Type *telem = e->newtype->toBasetype ();
+	    tree tarray = make_array_type (Type::tsize_t, e->arguments->dim);
+	    tree var = create_temporary_var (tarray);
+	    tree init = build_constructor (TREE_TYPE (var), NULL);
+
+	    for (size_t i = 0; i < e->arguments->dim; i++)
+	      {
+		Expression *arg = (*e->arguments)[i];
+		CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg));
+
+		gcc_assert (telem->ty == Tarray);
+		telem = telem->toBasetype ()->nextOf ();
+		gcc_assert (telem);
+	      }
+
+	    CONSTRUCTOR_ELTS (init) = elms;
+	    DECL_INITIAL (var) = init;
+
+	    /* Generate: _d_newarraymTX(ti, dims)
+		     or: _d_newarraymiTX(ti, dims)  */
+	    libcall_fn libcall = telem->isZeroInit ()
+	      ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX;
+
+	    tree tinfo = build_typeinfo (e->type);
+	    tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()),
+				       size_int (e->arguments->dim),
+				       build_address (var));
+
+	    result = build_libcall (libcall, tb, 2, tinfo, dims);
+	    result = bind_expr (var, result);
+	  }
+
+	if (e->argprefix)
+	  result = compound_expr (build_expr (e->argprefix), result);
+      }
+    else if (tb->ty == Tpointer)
+      {
+	/* Allocating memory for a new pointer.  */
+	TypePointer *tpointer = (TypePointer *) tb;
+
+	if (tpointer->next->size () == 0)
+	  {
+	    /* Pointer element size is unknown.  */
+	    this->result_ = d_convert (build_ctype (e->type),
+				       integer_zero_node);
+	    return;
+	  }
+
+	libcall_fn libcall = tpointer->next->isZeroInit (e->loc)
+	  ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
+
+	tree arg = build_typeinfo (e->newtype);
+	result = build_libcall (libcall, tb, 1, arg);
+
+	if (e->arguments && e->arguments->dim == 1)
+	  {
+	    result = d_save_expr (result);
+	    tree init = modify_expr (build_deref (result),
+				     build_expr ((*e->arguments)[0]));
+	    result = compound_expr (init, result);
+	  }
+
+	if (e->argprefix)
+	  result = compound_expr (build_expr (e->argprefix), result);
+      }
+    else
+      gcc_unreachable ();
+
+    this->result_ = convert_expr (result, tb, e->type);
+  }
+
+  /* Build an integer literal.  */
+
+  void visit (IntegerExp *e)
+  {
+    tree ctype = build_ctype (e->type->toBasetype ());
+    this->result_ = build_integer_cst (e->value, ctype);
+  }
+
+  /* Build a floating point literal.  */
+
+  void visit (RealExp *e)
+  {
+    this->result_ = build_float_cst (e->value, e->type->toBasetype ());
+  }
+
+  /* Build a complex literal.  */
+
+  void visit (ComplexExp *e)
+  {
+    Type *tnext;
+
+    switch (e->type->toBasetype ()->ty)
+      {
+      case Tcomplex32:
+	tnext = (TypeBasic *) Type::tfloat32;
+	break;
+
+      case Tcomplex64:
+	tnext = (TypeBasic *) Type::tfloat64;
+	break;
+
+      case Tcomplex80:
+	tnext = (TypeBasic *) Type::tfloat80;
+	break;
+
+      default:
+	gcc_unreachable ();
+      }
+
+    this->result_ = build_complex (build_ctype (e->type),
+				   build_float_cst (creall (e->value), tnext),
+				   build_float_cst (cimagl (e->value), tnext));
+  }
+
+  /* Build a string literal.  */
+
+  void visit (StringExp *e)
+  {
+    Type *tb = e->type->toBasetype ();
+
+    /* All strings are null terminated except static arrays.  */
+    dinteger_t length = (e->len * e->sz) + (tb->ty != Tsarray);
+    tree value = build_string (length, (char *) e->string);
+    tree type = build_ctype (e->type);
+
+    if (tb->ty == Tsarray)
+      TREE_TYPE (value) = type;
+    else
+      {
+	/* Array type doesn't match string length if null terminated.  */
+	TREE_TYPE (value) = make_array_type (tb->nextOf (), e->len);
+
+	value = build_address (value);
+	if (tb->ty == Tarray)
+	  value = d_array_value (type, size_int (e->len), value);
+      }
+
+    TREE_CONSTANT (value) = 1;
+    this->result_ = d_convert (type, value);
+  }
+
+  /* Build a tuple literal.  Just an argument list that may have
+     side effects that need evaluation.  */
+
+  void visit (TupleExp *e)
+  {
+    tree result = NULL_TREE;
+
+    if (e->e0)
+      result = build_expr (e->e0);
+
+    for (size_t i = 0; i < e->exps->dim; ++i)
+      {
+	Expression *exp = (*e->exps)[i];
+	result = compound_expr (result, build_expr (exp));
+      }
+
+    if (result == NULL_TREE)
+      result = void_node;
+
+    this->result_ = result;
+  }
+
+  /* Build an array literal.   The common type of the all elements is taken to
+     be the type of the array element, and all elements are implicitly
+     converted to that type.  */
+
+  void visit (ArrayLiteralExp *e)
+  {
+    Type *tb = e->type->toBasetype ();
+
+    /* Implicitly convert void[n] to ubyte[n].  */
+    if (tb->ty == Tsarray && tb->nextOf ()->toBasetype ()->ty == Tvoid)
+      tb = Type::tuns8->sarrayOf (((TypeSArray *) tb)->dim->toUInteger ());
+
+    gcc_assert (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tpointer);
+
+    /* Handle empty array literals.  */
+    if (e->elements->dim == 0)
+      {
+	if (tb->ty == Tarray)
+	  this->result_ = d_array_value (build_ctype (e->type),
+					 size_int (0), null_pointer_node);
+	else
+	  this->result_ = build_constructor (make_array_type (tb->nextOf (), 0),
+					     NULL);
+
+	return;
+      }
+
+    /* Build an expression that assigns the expressions in ELEMENTS to
+       a constructor.  */
+    vec<constructor_elt, va_gc> *elms = NULL;
+    vec_safe_reserve (elms, e->elements->dim);
+    bool constant_p = true;
+    tree saved_elems = NULL_TREE;
+
+    Type *etype = tb->nextOf ();
+    tree satype = make_array_type (etype, e->elements->dim);
+
+    for (size_t i = 0; i < e->elements->dim; i++)
+      {
+	Expression *expr = e->getElement (i);
+	tree value = build_expr (expr, this->constp_);
+
+	/* Only append non-zero values, the backend will zero out the rest
+	   of the constructor as we don't set CONSTRUCTOR_NO_CLEARING.  */
+	if (!initializer_zerop (value))
+	  {
+	    if (!TREE_CONSTANT (value))
+	      constant_p = false;
+
+	    /* Split construction of values out of the constructor if there
+	       may be side effects.  */
+	    tree init = stabilize_expr (&value);
+	    if (init != NULL_TREE)
+	      saved_elems = compound_expr (saved_elems, init);
+
+	    CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
+				    convert_expr (value, expr->type, etype));
+	  }
+      }
+
+    /* Now return the constructor as the correct type.  For static arrays there
+       is nothing else to do.  For dynamic arrays, return a two field struct.
+       For pointers, return the address.  */
+    tree ctor = build_constructor (satype, elms);
+    tree type = build_ctype (e->type);
+
+    /* Nothing else to do for static arrays.  */
+    if (tb->ty == Tsarray || this->constp_)
+      {
+	/* Can't take the address of the constructor, so create an anonymous
+	   static symbol, and then refer to it.  */
+	if (tb->ty != Tsarray)
+	  {
+	    tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor, "A");
+	    ctor = build_address (decl);
+	    if (tb->ty == Tarray)
+	      ctor = d_array_value (type, size_int (e->elements->dim), ctor);
+
+	    d_pushdecl (decl);
+	    rest_of_decl_compilation (decl, 1, 0);
+	  }
+
+	/* If the array literal is readonly or static.  */
+	if (constant_p)
+	  TREE_CONSTANT (ctor) = 1;
+	if (constant_p && initializer_constant_valid_p (ctor, TREE_TYPE (ctor)))
+	  TREE_STATIC (ctor) = 1;
+
+	this->result_ = compound_expr (saved_elems, d_convert (type, ctor));
+      }
+    else
+      {
+	/* Allocate space on the memory managed heap.  */
+	tree mem = build_libcall (LIBCALL_ARRAYLITERALTX,
+				  etype->pointerTo (), 2,
+				  build_typeinfo (etype->arrayOf ()),
+				  size_int (e->elements->dim));
+	mem = d_save_expr (mem);
+
+	/* Now copy the constructor into memory.  */
+	tree tmemcpy = builtin_decl_explicit (BUILT_IN_MEMCPY);
+	tree size = size_mult_expr (size_int (e->elements->dim),
+				    size_int (tb->nextOf ()->size ()));
+
+	tree result = build_call_expr (tmemcpy, 3, mem,
+				       build_address (ctor), size);
+
+	/* Return the array pointed to by MEM.   */
+	result = compound_expr (result, mem);
+
+	if (tb->ty == Tarray)
+	  result = d_array_value (type, size_int (e->elements->dim), result);
+
+	this->result_ = compound_expr (saved_elems, result);
+      }
+  }
+
+  /* Build an associative array literal.  The common type of the all keys is
+     taken to be the key type, and common type of all values the value type.
+     All keys and values are then implicitly converted as needed.  */
+
+  void visit (AssocArrayLiteralExp *e)
+  {
+    /* Want the mutable type for typeinfo reference.  */
+    Type *tb = e->type->toBasetype ()->mutableOf ();
+    gcc_assert (tb->ty == Taarray);
+
+    /* Handle empty assoc array literals.  */
+    TypeAArray *ta = (TypeAArray *) tb;
+    if (e->keys->dim == 0)
+      {
+	this->result_ = build_constructor (build_ctype (ta), NULL);
+	return;
+      }
+
+    /* Build an expression that assigns all expressions in KEYS
+       to a constructor.  */
+    vec<constructor_elt, va_gc> *kelts = NULL;
+    vec_safe_reserve (kelts, e->keys->dim);
+    for (size_t i = 0; i < e->keys->dim; i++)
+      {
+	Expression *key = (*e->keys)[i];
+	tree t = build_expr (key);
+	CONSTRUCTOR_APPEND_ELT (kelts, size_int (i),
+				convert_expr (t, key->type, ta->index));
+      }
+    tree tkeys = make_array_type (ta->index, e->keys->dim);
+    tree akeys = build_constructor (tkeys, kelts);
+
+    /* Do the same with all expressions in VALUES.  */
+    vec<constructor_elt, va_gc> *velts = NULL;
+    vec_safe_reserve (velts, e->values->dim);
+    for (size_t i = 0; i < e->values->dim; i++)
+      {
+	Expression *value = (*e->values)[i];
+	tree t = build_expr (value);
+	CONSTRUCTOR_APPEND_ELT (velts, size_int (i),
+				convert_expr (t, value->type, ta->next));
+      }
+    tree tvals = make_array_type (ta->next, e->values->dim);
+    tree avals = build_constructor (tvals, velts);
+
+    /* Generate: _d_assocarrayliteralTX (ti, keys, vals);  */
+    tree keys = d_array_value (build_ctype (ta->index->arrayOf ()),
+			       size_int (e->keys->dim), build_address (akeys));
+    tree vals = d_array_value (build_ctype (ta->next->arrayOf ()),
+			       size_int (e->values->dim),
+			       build_address (avals));
+
+    tree mem = build_libcall (LIBCALL_ASSOCARRAYLITERALTX, Type::tvoidptr, 3,
+			      build_typeinfo (ta), keys, vals);
+
+    /* Return an associative array pointed to by MEM.  */
+    tree aatype = build_ctype (ta);
+    vec<constructor_elt, va_gc> *ce = NULL;
+    CONSTRUCTOR_APPEND_ELT (ce, TYPE_FIELDS (aatype), mem);
+
+    this->result_ = build_nop (build_ctype (e->type),
+			       build_constructor (aatype, ce));
+  }
+
+  /* Build a struct literal.  */
+
+  void visit (StructLiteralExp *e)
+  {
+    /* Handle empty struct literals.  */
+    if (e->elements == NULL || e->sd->fields.dim == 0)
+      {
+	this->result_ = build_constructor (build_ctype (e->type), NULL);
+	return;
+      }
+
+    /* Building sinit trees are delayed until after frontend semantic
+       processing has complete.  Build the static initialiser now.  */
+    if (e->useStaticInit && !this->constp_)
+      {
+	this->result_ = aggregate_initializer_decl (e->sd);
+	return;
+      }
+
+    /* Build a constructor that assigns the expressions in ELEMENTS
+       at each field index that has been filled in.  */
+    vec<constructor_elt, va_gc> *ve = NULL;
+    tree saved_elems = NULL_TREE;
+
+    /* CTFE may fill the hidden pointer by NullExp.  */
+    gcc_assert (e->elements->dim <= e->sd->fields.dim);
+
+    Type *tb = e->type->toBasetype ();
+    gcc_assert (tb->ty == Tstruct);
+
+    for (size_t i = 0; i < e->elements->dim; i++)
+      {
+	Expression *exp = (*e->elements)[i];
+	if (!exp)
+	  continue;
+
+	VarDeclaration *field = e->sd->fields[i];
+	Type *type = exp->type->toBasetype ();
+	Type *ftype = field->type->toBasetype ();
+	tree value = NULL_TREE;
+
+	if (ftype->ty == Tsarray && !same_type_p (type, ftype))
+	  {
+	    /* Initialize a static array with a single element.  */
+	    tree elem = build_expr (exp, this->constp_);
+	    elem = d_save_expr (elem);
+
+	    if (initializer_zerop (elem))
+	      value = build_constructor (build_ctype (ftype), NULL);
+	    else
+	      value = build_array_from_val (ftype, elem);
+	  }
+	else
+	  {
+	    value = convert_expr (build_expr (exp, this->constp_),
+				  exp->type, field->type);
+	  }
+
+	/* Split construction of values out of the constructor.  */
+	tree init = stabilize_expr (&value);
+	if (init != NULL_TREE)
+	  saved_elems = compound_expr (saved_elems, init);
+
+	CONSTRUCTOR_APPEND_ELT (ve, get_symbol_decl (field), value);
+      }
+
+    /* Maybe setup hidden pointer to outer scope context.  */
+    if (e->sd->isNested () && e->elements->dim != e->sd->fields.dim
+	&& this->constp_ == false)
+      {
+	tree field = get_symbol_decl (e->sd->vthis);
+	tree value = build_vthis (e->sd);
+	CONSTRUCTOR_APPEND_ELT (ve, field, value);
+	gcc_assert (e->useStaticInit == false);
+      }
+
+    /* Build a constructor in the correct shape of the aggregate type.  */
+    tree ctor = build_struct_literal (build_ctype (e->type), ve);
+
+    /* Nothing more to do for constant literals.  */
+    if (this->constp_)
+      {
+	/* If the struct literal is a valid for static data.  */
+	if (TREE_CONSTANT (ctor)
+	    && initializer_constant_valid_p (ctor, TREE_TYPE (ctor)))
+	  TREE_STATIC (ctor) = 1;
+
+	this->result_ = compound_expr (saved_elems, ctor);
+	return;
+      }
+
+    if (e->sym != NULL)
+      {
+	tree var = build_deref (e->sym);
+	ctor = compound_expr (modify_expr (var, ctor), var);
+	this->result_ = compound_expr (saved_elems, ctor);
+      }
+    else if (e->sd->isUnionDeclaration ())
+      {
+	/* For unions, use memset to fill holes in the object.  */
+	tree var = build_local_temp (TREE_TYPE (ctor));
+	tree tmemset = builtin_decl_explicit (BUILT_IN_MEMSET);
+	tree init = build_call_expr (tmemset, 3, build_address (var),
+				     size_zero_node,
+				     size_int (e->sd->structsize));
+
+	init = compound_expr (init, saved_elems);
+	init = compound_expr (init, modify_expr (var, ctor));
+	this->result_  = compound_expr (init, var);
+      }
+    else
+      this->result_ = compound_expr (saved_elems, ctor);
+  }
+
+  /* Build a null literal.  */
+
+  void visit (NullExp *e)
+  {
+    Type *tb = e->type->toBasetype();
+    tree value;
+
+    /* Handle certain special case conversions, where the underlying type is an
+       aggregate with a nullable interior pointer.  */
+    if (tb->ty == Tarray)
+      {
+	/* For dynamic arrays, set length and pointer fields to zero.  */
+	value = d_array_value (build_ctype (e->type), size_int (0),
+			       null_pointer_node);
+      }
+    else if (tb->ty == Taarray)
+      {
+	/* For associative arrays, set the pointer field to null.  */
+	value = build_constructor (build_ctype (e->type), NULL);
+      }
+    else if (tb->ty == Tdelegate)
+      {
+	/* For delegates, set the frame and function pointer to null.  */
+	value = build_delegate_cst (null_pointer_node,
+				    null_pointer_node, e->type);
+      }
+    else
+      value = d_convert (build_ctype (e->type), integer_zero_node);
+
+    TREE_CONSTANT (value) = 1;
+    this->result_ = value;
+  }
+
+  /* Build a vector literal.  */
+
+  void visit (VectorExp *e)
+  {
+    tree type = build_ctype (e->type);
+    tree etype = TREE_TYPE (type);
+
+    /* First handle array literal expressions.  */
+    if (e->e1->op == TOKarrayliteral)
+      {
+	ArrayLiteralExp *ale = ((ArrayLiteralExp *) e->e1);
+	vec<constructor_elt, va_gc> *elms = NULL;
+	bool constant_p = true;
+
+	vec_safe_reserve (elms, ale->elements->dim);
+	for (size_t i = 0; i < ale->elements->dim; i++)
+	  {
+	    Expression *expr = ale->getElement (i);
+	    tree value = d_convert (etype, build_expr (expr, this->constp_));
+	    if (!CONSTANT_CLASS_P (value))
+	      constant_p = false;
+
+	    CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+	  }
+
+	/* Build a VECTOR_CST from a constant vector constructor.  */
+	if (constant_p)
+	  this->result_ = build_vector_from_ctor (type, elms);
+	else
+	  this->result_ = build_constructor (type, elms);
+      }
+    else
+      {
+	/* Build constructor from single value.  */
+	tree val = d_convert (etype, build_expr (e->e1, this->constp_));
+	this->result_ = build_vector_from_val (type, val);
+      }
+  }
+
+  /* Build a static class literal, return its reference.  */
+
+  void visit (ClassReferenceExp *e)
+  {
+    /* The result of build_new_class_expr is a RECORD_TYPE, we want
+       the reference.  */
+    tree var = build_address (build_new_class_expr (e));
+
+    /* If the type of this literal is an interface, the we must add the
+       interface offset to symbol.  */
+    if (this->constp_)
+      {
+	TypeClass *tc = (TypeClass *) e->type;
+	InterfaceDeclaration *to = tc->sym->isInterfaceDeclaration ();
+
+	if (to != NULL)
+	  {
+	    ClassDeclaration *from = e->originalClass ();
+	    int offset = 0;
+
+	    gcc_assert (to->isBaseOf (from, &offset) != 0);
+
+	    if (offset != 0)
+	      var = build_offset (var, size_int (offset));
+	  }
+      }
+
+    this->result_ = var;
+  }
+
+  /* These expressions are mainly just a placeholders in the frontend.
+     We shouldn't see them here.  */
+
+  void visit (ScopeExp *e)
+  {
+    e->error ("%s is not an expression", e->toChars ());
+    this->result_ = error_mark_node;
+  }
+
+  void visit (TypeExp *e)
+  {
+    e->error ("type %s is not an expression", e->toChars ());
+    this->result_ = error_mark_node;
+  }
+};
+
+
+/* Main entry point for ExprVisitor interface to generate code for
+   the Expression AST class E.  If CONST_P is true, then E is a
+   constant expression.  */
+
+tree
+build_expr (Expression *e, bool const_p)
+{
+  ExprVisitor v = ExprVisitor (const_p);
+  e->accept (&v);
+  tree expr = v.result ();
+
+  /* Check if initializer expression is valid constant.  */
+  if (const_p && !initializer_constant_valid_p (expr, TREE_TYPE (expr)))
+    {
+      e->error ("non-constant expression %s", e->toChars ());
+      return error_mark_node;
+    }
+
+  return expr;
+}
+
+/* Build an expression that calls the destructors on all the variables
+   going out of the scope between STARTI and ENDI. All destructors are
+   executed in reverse order.  */
+
+static tree
+build_dtor_list (size_t starti, size_t endi)
+{
+  tree dtors = NULL_TREE;
+
+  for (size_t i = starti; i != endi; ++i)
+    {
+      VarDeclaration *vd = d_function_chain->vars_in_scope[i];
+      if (vd)
+	{
+	  d_function_chain->vars_in_scope[i] = NULL;
+	  tree t = build_expr (vd->edtor);
+	  dtors = compound_expr (t, dtors);
+	}
+    }
+
+  return dtors;
+}
+
+/* Same as build_expr, but also calls destructors on any temporaries.  */
+
+tree
+build_expr_dtor (Expression *e)
+{
+  /* Codegen can be improved by determining if no exceptions can be thrown
+     between the ctor and dtor, and eliminating the ctor and dtor.  */
+  size_t starti = d_function_chain->vars_in_scope.length ();
+  tree result = build_expr (e);
+  size_t endi = d_function_chain->vars_in_scope.length ();
+
+  tree dtors = build_dtor_list (starti, endi);
+
+  if (dtors != NULL_TREE)
+    {
+      /* Split comma expressions, so that only the result is maybe saved.  */
+      tree expr = stabilize_expr (&result);
+
+      /* When constructing temporaries, if the constructor throws, then
+	 we don't want to run the destructor on the incomplete object.  */
+      CallExp *ce = (e->op == TOKcall) ? ((CallExp *) e) : NULL;
+      if (ce != NULL && ce->e1->op == TOKdotvar
+	  && ((DotVarExp *) ce->e1)->var->isCtorDeclaration ())
+	{
+	  /* Extract the object from the ctor call, as it will be the same
+	     value as the returned result, just maybe without the side effects.
+	     Rewriting: ctor (&e1) => (ctor (&e1), e1)  */
+	  expr = compound_expr (expr, result);
+
+	  if (INDIRECT_REF_P (result))
+	    result = build_deref (CALL_EXPR_ARG (TREE_OPERAND (result, 0), 0));
+	  else
+	    result = CALL_EXPR_ARG (result, 0);
+
+	  return compound_expr (compound_expr (expr, dtors), result);
+	}
+
+      /* Extract the LHS from the assignment expression.
+	 Rewriting: (e1 = e2) => ((e1 = e2), e1)  */
+      if (TREE_CODE (result) == INIT_EXPR || TREE_CODE (result) == MODIFY_EXPR)
+	{
+	  expr = compound_expr (expr, result);
+	  result = TREE_OPERAND (result, 0);
+	}
+
+      /* If the result has side-effects, save the entire expression.  */
+      if (TREE_SIDE_EFFECTS (result))
+	{
+	  /* Wrap expr and dtors in a try/finally expression.  */
+	  result = d_save_expr (result);
+	  expr = build2 (TRY_FINALLY_EXPR, void_type_node,
+			compound_expr (expr, result), dtors);
+	}
+      else
+	expr = compound_expr (expr, dtors);
+
+      return compound_expr (expr, result);
+    }
+
+  return result;
+}
+
+/* Same as build_expr_dtor, but handles the result of E as a return value.  */
+
+tree
+build_return_dtor (Expression *e, Type *type, TypeFunction *tf)
+{
+  size_t starti = d_function_chain->vars_in_scope.length ();
+  tree result = build_expr (e);
+  size_t endi = d_function_chain->vars_in_scope.length ();
+
+  /* Convert for initialising the DECL_RESULT.  */
+  result = convert_expr (result, e->type, type);
+  tree dtors = build_dtor_list (starti, endi);
+
+  /* If we are returning a reference, take the address.  */
+  if (tf->isref)
+    result = build_address (result);
+
+  /* The decl to store the return expression.  */
+  tree decl = DECL_RESULT (cfun->decl);
+
+  /* Split comma expressions, so that the result is returned directly.  */
+  tree expr = stabilize_expr (&result);
+  result = build_assign (INIT_EXPR, decl, result);
+  result = compound_expr (expr, return_expr (result));
+
+  /* Nest the return expression inside the try/finally expression.  */
+  if (dtors != NULL_TREE)
+    return build2 (TRY_FINALLY_EXPR, void_type_node, result, dtors);
+
+  return result;
+}
+
diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc
new file mode 100644
index 00000000000..3d6c9d7ab33
--- /dev/null
+++ b/gcc/d/imports.cc
@@ -0,0 +1,199 @@
+/* imports.cc -- Build imported modules/declarations.
+   Copyright (C) 2014-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/declaration.h"
+#include "dfrontend/enum.h"
+#include "dfrontend/import.h"
+#include "dfrontend/module.h"
+
+#include "tree.h"
+#include "stringpool.h"
+
+#include "d-tree.h"
+
+
+/* Implements the visitor interface to build debug trees for all
+   module and import declarations, where ISYM holds the cached
+   backend representation to be returned.  */
+class ImportVisitor : public Visitor
+{
+  /* Build the declaration DECL as an imported symbol.  */
+  tree make_import (tree decl)
+  {
+    gcc_assert (decl != NULL_TREE);
+
+    tree import = build_decl (input_location, IMPORTED_DECL,
+			      DECL_NAME (decl), void_type_node);
+    IMPORTED_DECL_ASSOCIATED_DECL (import) = decl;
+    d_keep (import);
+
+    return import;
+  }
+
+public:
+  ImportVisitor (void) {}
+
+  /* This should be overridden by each symbol class.  */
+  void visit (Dsymbol *)
+  {
+    gcc_unreachable ();
+  }
+
+  /* Build the module decl for M, this is considered toplevel, regardless
+     of whether there are any parent packages in the module system.  */
+  void visit (Module *m)
+  {
+    Loc loc = (m->md != NULL) ? m->md->loc
+      : Loc (m->srcfile->toChars (), 1, 0);
+
+    m->isym = build_decl (get_linemap (loc), NAMESPACE_DECL,
+			  get_identifier (m->toPrettyChars ()),
+			  void_type_node);
+    d_keep (m->isym);
+
+    if (!m->isRoot ())
+      DECL_EXTERNAL (m->isym) = 1;
+
+    TREE_PUBLIC (m->isym) = 1;
+    DECL_CONTEXT (m->isym) = NULL_TREE;
+  }
+
+  /* Build an import of another module symbol.  */
+
+  void visit (Import *m)
+  {
+    tree module = build_import_decl (m->mod);
+    m->isym = this->make_import (module);
+  }
+
+  /* Build an import for any kind of user defined type.
+     Use the TYPE_DECL associated with the type symbol.  */
+  void visit (EnumDeclaration *d)
+  {
+    tree type = build_ctype (d->type);
+    /* Not all kinds of D enums create a TYPE_DECL.  */
+    if (TREE_CODE (type) == ENUMERAL_TYPE)
+      d->isym = this->make_import (TYPE_STUB_DECL (type));
+  }
+
+  void visit (AggregateDeclaration *d)
+  {
+    tree type = build_ctype (d->type);
+    d->isym = this->make_import (TYPE_STUB_DECL (type));
+  }
+
+  void visit (ClassDeclaration *d)
+  {
+    /* Want the RECORD_TYPE, not POINTER_TYPE.  */
+    tree type = TREE_TYPE (build_ctype (d->type));
+    d->isym = this->make_import (TYPE_STUB_DECL (type));
+  }
+
+  /* For now, ignore importing other kinds of dsymbols.  */
+  void visit (ScopeDsymbol *)
+  {
+  }
+
+  /* Alias symbols aren't imported, but their targets are.  */
+  void visit (AliasDeclaration *d)
+  {
+    Dsymbol *dsym = d->toAlias ();
+
+    if (dsym == d)
+      {
+	Type *type = d->getType ();
+
+	/* Type imports should really be part of their own visit method.  */
+	if (type != NULL)
+	  {
+	    if (type->ty == Tenum)
+	      dsym = ((TypeEnum *) type)->sym;
+	    else if (type->ty == Tstruct)
+	      dsym = ((TypeStruct *) type)->sym;
+	    else if (type->ty == Tclass)
+	      dsym = ((TypeClass *) type)->sym;
+	  }
+      }
+
+    /* This symbol is really an alias for another, visit the other.  */
+    if (dsym != d)
+      {
+	dsym->accept (this);
+	d->isym = dsym->isym;
+      }
+  }
+
+  /* Visit the underlying alias symbol of overloadable aliases.  */
+  void visit (OverDeclaration *d)
+  {
+    if (d->aliassym != NULL)
+      {
+	d->aliassym->accept (this);
+	d->isym = d->aliassym->isym;
+      }
+  }
+
+  /* Function aliases are the same as alias symbols.  */
+  void visit (FuncAliasDeclaration *d)
+  {
+    FuncDeclaration *fd = d->toAliasFunc ();
+
+    if (fd != NULL)
+      {
+	fd->accept (this);
+	d->isym = fd->isym;
+      }
+  }
+
+  /* Skip over importing templates and tuples.  */
+  void visit (TemplateDeclaration *)
+  {
+  }
+
+  void visit (TupleDeclaration *)
+  {
+  }
+
+  /* Import any other kind of declaration.  If the class does not implement
+     symbol generation routines, the compiler will throw an error.  */
+  void visit (Declaration *d)
+  {
+    d->isym = this->make_import (get_symbol_decl (d));
+  }
+};
+
+
+/* Build a declaration for the symbol D that can be used for the
+   debug_hook imported_module_or_decl.  */
+tree
+build_import_decl (Dsymbol *d)
+{
+  if (!d->isym)
+    {
+      ImportVisitor v;
+      d->accept (&v);
+    }
+
+  /* Not all visitors set 'isym'.  */
+  return d->isym ? d->isym : NULL_TREE;
+}
+
diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc
new file mode 100644
index 00000000000..24746ef2abb
--- /dev/null
+++ b/gcc/d/intrinsics.cc
@@ -0,0 +1,657 @@
+/* intrinsics.cc -- D language compiler intrinsics.
+   Copyright (C) 2006-2017 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 "dfrontend/declaration.h"
+#include "dfrontend/module.h"
+#include "dfrontend/template.h"
+
+#include "tm.h"
+#include "tree.h"
+#include "fold-const.h"
+#include "stringpool.h"
+
+#include "d-tree.h"
+#include "d-frontend.h"
+
+
+/* List of codes for internally recognised compiler intrinsics.  */
+
+enum intrinsic_code
+{
+#define DEF_D_INTRINSIC(CODE, A, N, M, D) INTRINSIC_ ## CODE,
+
+#include "intrinsics.def"
+
+#undef DEF_D_INTRINSIC
+  INTRINSIC_LAST
+};
+
+/* An internal struct used to hold information on D intrinsics.  */
+
+struct intrinsic_decl
+{
+  /* The DECL_FUNCTION_CODE of this decl.  */
+  intrinsic_code code;
+
+  /* The name of the intrinsic.  */
+  const char *name;
+
+  /* The module where the intrinsic is located.  */
+  const char *module;
+
+  /* The mangled signature decoration of the intrinsic.  */
+  const char *deco;
+};
+
+static const intrinsic_decl intrinsic_decls[] =
+{
+#define DEF_D_INTRINSIC(CODE, ALIAS, NAME, MODULE, DECO) \
+    { INTRINSIC_ ## ALIAS, NAME, MODULE, DECO },
+
+#include "intrinsics.def"
+
+#undef DEF_D_INTRINSIC
+};
+
+/* Checks if DECL is an intrinsic or runtime library function that
+   requires special processing.  Marks the generated trees for DECL
+   as BUILT_IN_FRONTEND so can be identified later.  */
+
+void
+maybe_set_intrinsic (FuncDeclaration *decl)
+{
+  if (!decl->ident || decl->builtin == BUILTINyes)
+    return;
+
+  /* Check if it's a compiler intrinsic.  We only require that any
+     internally recognised intrinsics are declared in a module with
+     an explicit module declaration.  */
+  Module *m = decl->getModule ();
+  if (!m || !m->md)
+    return;
+
+  TemplateInstance *ti = decl->isInstantiated ();
+  TemplateDeclaration *td = ti ? ti->tempdecl->isTemplateDeclaration () : NULL;
+
+  const char *tname = decl->ident->toChars ();
+  const char *tmodule = m->md->toChars ();
+  const char *tdeco = (td == NULL) ? decl->type->deco : NULL;
+
+  /* Look through all D intrinsics.  */
+  for (size_t i = 0; i < (int) INTRINSIC_LAST; i++)
+    {
+      if (strcmp (intrinsic_decls[i].name, tname) != 0
+	  || strcmp (intrinsic_decls[i].module, tmodule) != 0)
+	continue;
+
+      /* Instantiated functions would have the wrong type deco, get it from the
+	 template member instead.  */
+      if (tdeco == NULL)
+	{
+	  if (!td || !td->onemember)
+	    return;
+
+	  FuncDeclaration *fd = td->onemember->isFuncDeclaration ();
+	  if (fd == NULL)
+	    return;
+
+	  OutBuffer buf;
+	  mangleToBuffer (fd->type, &buf);
+	  tdeco = buf.extractString ();
+	}
+
+      if (strcmp (intrinsic_decls[i].deco, tdeco) == 0)
+	{
+	  intrinsic_code code = intrinsic_decls[i].code;
+
+	  if (decl->csym == NULL)
+	    {
+	      /* Store a stub BUILT_IN_FRONTEND decl.  */
+	      decl->csym = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+				       get_identifier (tname),
+				       build_ctype (decl->type));
+	      DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (decl);
+	      d_keep (decl->csym);
+	    }
+
+	  DECL_BUILT_IN_CLASS (decl->csym) = BUILT_IN_FRONTEND;
+	  DECL_FUNCTION_CODE (decl->csym) = (built_in_function) code;
+	  decl->builtin = BUILTINyes;
+	  break;
+	}
+    }
+}
+
+/* Clear the DECL_BUILT_IN_CLASS flag on the function in CALLEXP.  */
+
+static void
+clear_intrinsic_flag (tree callexp)
+{
+  tree decl = CALL_EXPR_FN (callexp);
+
+  if (TREE_CODE (decl) == ADDR_EXPR)
+    decl = TREE_OPERAND (decl, 0);
+
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+
+  FuncDeclaration *fd = DECL_LANG_FRONTEND (decl)->isFuncDeclaration ();
+  fd->builtin = BUILTINno;
+  DECL_BUILT_IN_CLASS (decl) = NOT_BUILT_IN;
+  DECL_FUNCTION_CODE (decl) = BUILT_IN_NONE;
+}
+
+/* Construct a function call to the built-in function CODE, N is the number of
+   arguments, and the `...' parameters are the argument expressions.
+   The original call expression is held in CALLEXP.  */
+
+static tree
+call_builtin_fn (tree callexp, built_in_function code, int n, ...)
+{
+  tree *argarray = XALLOCAVEC (tree, n);
+  va_list ap;
+
+  va_start (ap, n);
+  for (int i = 0; i < n; i++)
+    argarray[i] = va_arg (ap, tree);
+  va_end (ap);
+
+  tree exp = build_call_expr_loc_array (EXPR_LOCATION (callexp),
+					builtin_decl_explicit (code),
+					n, argarray);
+  return fold_convert (TREE_TYPE (callexp), fold (exp));
+}
+
+/* Expand a front-end instrinsic call to bsf().  This takes one argument,
+   the signature to which can be either:
+
+	int bsf (uint arg);
+	int bsf (ulong arg);
+
+   This scans all bits in the given argument starting with the first,
+   returning the bit number of the first bit set.  The original call
+   expression is held in CALLEXP.  */
+
+static tree
+expand_intrinsic_bsf (tree callexp)
+{
+  /* The bsr() intrinsic gets turned into __builtin_ctz(arg).
+     The return value is supposed to be undefined if arg is zero.  */
+  tree arg = CALL_EXPR_ARG (callexp, 0);
+  int argsize = TYPE_PRECISION (TREE_TYPE (arg));
+
+  /* Which variant of __builtin_ctz* should we call?  */
+  built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CTZ :
+    (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CTZL :
+    (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CTZLL : END_BUILTINS;
+
+  /* Fallback on runtime implementation, which shouldn't happen as the
+     argument for bsf() is either 32-bit or 64-bit.  */
+  if (code == END_BUILTINS)
+    {
+      clear_intrinsic_flag (callexp);
+      return callexp;
+    }
+
+  return call_builtin_fn (callexp, code, 1, arg);
+}
+
+/* Expand a front-end instrinsic call to bsr().  This takes one argument,
+   the signature to which can be either:
+
+	int bsr (uint arg);
+	int bsr (ulong arg);
+
+   This scans all bits in the given argument from the most significant bit
+   to the least significant, returning the bit number of the first bit set.
+   The original call expression is held in CALLEXP.  */
+
+static tree
+expand_intrinsic_bsr (tree callexp)
+{
+  /* The bsr() intrinsic gets turned into (size - 1) - __builtin_clz(arg).
+     The return value is supposed to be undefined if arg is zero.  */
+  tree arg = CALL_EXPR_ARG (callexp, 0);
+  tree type = TREE_TYPE (arg);
+  int argsize = TYPE_PRECISION (type);
+
+  /* Which variant of __builtin_clz* should we call?  */
+  built_in_function code = (argsize <= INT_TYPE_SIZE) ? BUILT_IN_CLZ :
+    (argsize <= LONG_TYPE_SIZE) ? BUILT_IN_CLZL :
+    (argsize <= LONG_LONG_TYPE_SIZE) ? BUILT_IN_CLZLL : END_BUILTINS;
+
+  /* Fallback on runtime implementation, which shouldn't happen as the
+     argument for bsr() is either 32-bit or 64-bit.  */
+  if (code == END_BUILTINS)
+    {
+      clear_intrinsic_flag (callexp);
+      return callexp;
+    }
+
+  tree result = call_builtin_fn (callexp, code, 1, arg);
+
+  /* Handle int -> long conversions.  */
+  if (TREE_TYPE (result) != type)
+    result = fold_convert (type, result);
+
+  result = fold_build2 (MINUS_EXPR, type,
+			build_integer_cst (argsize - 1, type), result);
+  return fold_convert (TREE_TYPE (callexp), result);
+}
+
+/* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
+   bt(), btc(), btr(), or bts().  These intrinsics expect to take two arguments,
+   the signature to which is:
+
+	int bt (size_t* ptr, size_t bitnum);
+
+   All intrinsics test if a bit is set and return the result of that condition.
+   Variants of `bt' will then update that bit. `btc' compliments the bit, `bts'
+   sets the bit, and `btr' resets the bit.  The original call expression is
+   held in CALLEXP.  */
+
+static tree
+expand_intrinsic_bt (intrinsic_code intrinsic, tree callexp)
+{
+  tree ptr = CALL_EXPR_ARG (callexp, 0);
+  tree bitnum = CALL_EXPR_ARG (callexp, 1);
+  tree type = TREE_TYPE (TREE_TYPE (ptr));
+
+  /* size_t bitsize = sizeof(*ptr) * BITS_PER_UNIT;  */
+  tree bitsize = fold_convert (type, TYPE_SIZE (type));
+
+  /* ptr[bitnum / bitsize]  */
+  ptr = build_array_index (ptr, fold_build2 (TRUNC_DIV_EXPR, type,
+					     bitnum, bitsize));
+  ptr = indirect_ref (type, ptr);
+
+  /* mask = 1 << (bitnum % bitsize);  */
+  bitnum = fold_build2 (TRUNC_MOD_EXPR, type, bitnum, bitsize);
+  bitnum = fold_build2 (LSHIFT_EXPR, type, size_one_node, bitnum);
+
+  /* cond = ptr[bitnum / size] & mask;  */
+  tree cond = fold_build2 (BIT_AND_EXPR, type, ptr, bitnum);
+
+  /* cond ? -1 : 0;  */
+  cond = build_condition (TREE_TYPE (callexp), d_truthvalue_conversion (cond),
+			 integer_minus_one_node, integer_zero_node);
+
+  /* Update the bit as needed, only testing the bit for bt().  */
+  if (intrinsic == INTRINSIC_BT)
+    return cond;
+
+  tree_code code = (intrinsic == INTRINSIC_BTC) ? BIT_XOR_EXPR :
+    (intrinsic == INTRINSIC_BTR) ? BIT_AND_EXPR :
+    (intrinsic == INTRINSIC_BTS) ? BIT_IOR_EXPR : ERROR_MARK;
+  gcc_assert (code != ERROR_MARK);
+
+  /* ptr[bitnum / size] op= mask  */
+  if (intrinsic == INTRINSIC_BTR)
+    bitnum = fold_build1 (BIT_NOT_EXPR, TREE_TYPE (bitnum), bitnum);
+
+  ptr = modify_expr (ptr, fold_build2 (code, TREE_TYPE (ptr), ptr, bitnum));
+
+  /* Store the condition result in a temporary, and return expressions in
+     correct order of evaluation.  */
+  tree tmp = build_local_temp (TREE_TYPE (callexp));
+  cond = modify_expr (tmp, cond);
+
+  return compound_expr (cond, compound_expr (ptr, tmp));
+}
+
+/* Expand a front-end intrinsic call to bswap().  This takes one argument, the
+   signature to which can be either:
+
+	int bswap (uint arg);
+	int bswap (ulong arg);
+
+   This swaps all bytes in an N byte type end-to-end.  The original call
+   expression is held in CALLEXP.  */
+
+static tree
+expand_intrinsic_bswap (tree callexp)
+{
+  tree arg = CALL_EXPR_ARG (callexp, 0);
+  int argsize = TYPE_PRECISION (TREE_TYPE (arg));
+
+  /* Which variant of __builtin_bswap* should we call?  */
+  built_in_function code = (argsize == 32) ? BUILT_IN_BSWAP32 :
+    (argsize == 64) ? BUILT_IN_BSWAP64 : END_BUILTINS;
+
+  /* Fallback on runtime implementation, which shouldn't happen as the
+     argument for bswap() is either 32-bit or 64-bit.  */
+  if (code == END_BUILTINS)
+    {
+      clear_intrinsic_flag (callexp);
+      return callexp;
+    }
+
+  return call_builtin_fn (callexp, code, 1, arg);
+}
+
+/* Expand a front-end intrinsic call to INTRINSIC, which is either a call to
+   sqrt(), sqrtf(), sqrtl().  These intrinsics expect to take one argument,
+   the signature to which can be either:
+
+	float sqrt (float arg);
+	double sqrt (double arg);
+	real sqrt (real arg);
+
+   This computes the square root of the given argument.  The original call
+   expression is held in CALLEXP.  */
+
+static tree
+expand_intrinsic_sqrt (intrinsic_code intrinsic, tree callexp)
+{
+  tree arg = CALL_EXPR_ARG (callexp, 0);
+  tree type = TYPE_MAIN_VARIANT (TREE_TYPE (arg));
+
+  /* arg is an integral type - use double precision.  */
+  if (INTEGRAL_TYPE_P (type))
+    arg = convert (double_type_node, arg);
+
+  /* Which variant of __builtin_sqrt* should we call?  */
+  built_in_function code = (intrinsic == INTRINSIC_SQRT) ? BUILT_IN_SQRT :
+    (intrinsic == INTRINSIC_SQRTF) ? BUILT_IN_SQRTF :
+    (intrinsic == INTRINSIC_SQRTL) ? BUILT_IN_SQRTL : END_BUILTINS;
+
+  gcc_assert (code != END_BUILTINS);
+  return call_builtin_fn (callexp, code, 1, arg);
+}
+
+/* Expand a front-end intrinsic call to va_arg().  These take either one or two
+   arguments, the signature to which can be either:
+
+	T va_arg(T) (ref va_list ap);
+	void va_arg(T) (va_list ap, ref T parmn);
+
+   This retrieves the next variadic parameter that is type T from the given
+   va_list.  If also given, store the value into parmn, otherwise return it.
+   The original call expression is held in CALLEXP.  */
+
+static tree
+expand_intrinsic_vaarg (tree callexp)
+{
+  tree ap = CALL_EXPR_ARG (callexp, 0);
+  tree parmn = NULL_TREE;
+  tree type;
+
+  STRIP_NOPS (ap);
+
+  if (call_expr_nargs (callexp) == 1)
+    type = TREE_TYPE (callexp);
+  else
+    {
+      parmn = CALL_EXPR_ARG (callexp, 1);
+      STRIP_NOPS (parmn);
+      gcc_assert (TREE_CODE (parmn) == ADDR_EXPR);
+      parmn = TREE_OPERAND (parmn, 0);
+      type = TREE_TYPE (parmn);
+    }
+
+  /* (T) VA_ARG_EXP<ap>;  */
+  tree exp = build1 (VA_ARG_EXPR, type, ap);
+
+  /* parmn = (T) VA_ARG_EXP<ap>;  */
+  if (parmn != NULL_TREE)
+    exp = modify_expr (parmn, exp);
+
+  return exp;
+}
+
+/* Expand a front-end intrinsic call to va_start(), which takes two arguments,
+   the signature to which is:
+
+	void va_start(T) (out va_list ap, ref T parmn);
+
+   This initializes the va_list type, where parmn should be the last named
+   parameter.  The original call expression is held in CALLEXP.  */
+
+static tree
+expand_intrinsic_vastart (tree callexp)
+{
+  tree ap = CALL_EXPR_ARG (callexp, 0);
+  tree parmn = CALL_EXPR_ARG (callexp, 1);
+
+  STRIP_NOPS (ap);
+  STRIP_NOPS (parmn);
+
+  /* The va_list argument should already have its address taken.  The second
+     argument, however, is inout and that needs to be fixed to prevent a
+     warning.  Could be casting, so need to check type too?  */
+  gcc_assert (TREE_CODE (ap) == ADDR_EXPR && TREE_CODE (parmn) == ADDR_EXPR);
+
+  /* Assuming nobody tries to change the return type.  */
+  parmn = TREE_OPERAND (parmn, 0);
+
+  return call_builtin_fn (callexp, BUILT_IN_VA_START, 2, ap, parmn);
+}
+
+/* Expand a front-end instrinsic call to INTRINSIC, which is either a call to
+   adds(), addu(), subs(), subu(), negs(), muls(), or mulu().  These intrinsics
+   expect to take two or three arguments, the signature to which can be either:
+
+	int adds (int x, int y, ref bool overflow);
+	long adds (long x, long y, ref bool overflow);
+	int negs (int x, ref bool overflow);
+	long negs (long x, ref bool overflow);
+
+   This performs an operation on two signed or unsigned integers, checking for
+   overflow.  The overflow is sticky, meaning that a sequence of operations
+   can be done and overflow need only be checked at the end.  The original call
+   expression is held in CALLEXP.  */
+
+static tree
+expand_intrinsic_checkedint (intrinsic_code intrinsic, tree callexp)
+{
+  tree type = TREE_TYPE (callexp);
+  tree x;
+  tree y;
+  tree overflow;
+
+  /* The negs() intrinsic gets turned into SUB_OVERFLOW (0, y).  */
+  if (intrinsic == INTRINSIC_NEGS)
+    {
+      x = fold_convert (type, integer_zero_node);
+      y = CALL_EXPR_ARG (callexp, 0);
+      overflow = CALL_EXPR_ARG (callexp, 1);
+    }
+  else
+    {
+      x = CALL_EXPR_ARG (callexp, 0);
+      y = CALL_EXPR_ARG (callexp, 1);
+      overflow = CALL_EXPR_ARG (callexp, 2);
+    }
+
+  /* Which variant of *_OVERFLOW should we generate?  */
+  internal_fn icode = (intrinsic == INTRINSIC_ADDS) ? IFN_ADD_OVERFLOW :
+    (intrinsic == INTRINSIC_SUBS) ? IFN_SUB_OVERFLOW :
+    (intrinsic == INTRINSIC_MULS) ? IFN_MUL_OVERFLOW :
+    (intrinsic == INTRINSIC_NEGS) ? IFN_SUB_OVERFLOW : IFN_LAST;
+  gcc_assert (icode != IFN_LAST);
+
+  tree result
+    = build_call_expr_internal_loc (EXPR_LOCATION (callexp), icode,
+				    build_complex_type (type), 2, x, y);
+
+  STRIP_NOPS (overflow);
+  overflow = build_deref (overflow);
+
+  /* Assign returned result to overflow parameter, however if overflow is
+     already true, maintain it's value.  */
+  type = TREE_TYPE (overflow);
+  result = save_expr (result);
+
+  tree exp = fold_build2 (BIT_IOR_EXPR, type, overflow,
+			  fold_convert (type, imaginary_part (result)));
+  exp = modify_expr (overflow, exp);
+
+  /* Return the value of result.  */
+  return compound_expr (exp, real_part (result));
+}
+
+/* Expand a front-end instrinsic call to volatileLoad().  This takes one
+   argument, the signature to which can be either:
+
+	ubyte volatileLoad (ubyte* ptr);
+	ushort volatileLoad (ushort* ptr);
+	uint volatileLoad (uint* ptr);
+	ulong volatileLoad (ulong* ptr);
+
+   This reads a value from the memory location indicated by ptr.  Calls to
+   them are be guaranteed to not be removed (such as during DCE) or reordered
+   in the same thread.  The original call expression is held in CALLEXP.  */
+
+static tree
+expand_volatile_load (tree callexp)
+{
+  tree ptr = CALL_EXPR_ARG (callexp, 0);
+  tree ptrtype = TREE_TYPE (ptr);
+  gcc_assert (POINTER_TYPE_P (ptrtype));
+
+  /* (T) *(volatile T *) ptr;  */
+  tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE);
+  tree result = indirect_ref (type, ptr);
+  TREE_THIS_VOLATILE (result) = 1;
+
+  return result;
+}
+
+/* Expand a front-end instrinsic call to volatileStore().  This takes two
+   arguments, the signature to which can be either:
+
+	void volatileStore (ubyte* ptr, ubyte value);
+	void volatileStore (ushort* ptr, ushort value);
+	void volatileStore (uint* ptr, uint value);
+	void volatileStore (ulong* ptr, ulong value);
+
+   This writes a value to the memory location indicated by ptr.  Calls to
+   them are be guaranteed to not be removed (such as during DCE) or reordered
+   in the same thread.  The original call expression is held in CALLEXP.  */
+
+static tree
+expand_volatile_store (tree callexp)
+{
+  tree ptr = CALL_EXPR_ARG (callexp, 0);
+  tree ptrtype = TREE_TYPE (ptr);
+  gcc_assert (POINTER_TYPE_P (ptrtype));
+
+  /* (T) *(volatile T *) ptr;  */
+  tree type = build_qualified_type (TREE_TYPE (ptrtype), TYPE_QUAL_VOLATILE);
+  tree result = indirect_ref (type, ptr);
+  TREE_THIS_VOLATILE (result) = 1;
+
+  /* (*(volatile T *) ptr) = value;  */
+  tree value = CALL_EXPR_ARG (callexp, 1);
+  return modify_expr (result, value);
+}
+
+/* If CALLEXP is a BUILT_IN_FRONTEND, expand and return inlined compiler
+   generated instructions.  Most map directly to GCC builtins, others
+   require a little extra work around them.  */
+
+tree
+maybe_expand_intrinsic (tree callexp)
+{
+  tree callee = CALL_EXPR_FN (callexp);
+
+  if (TREE_CODE (callee) == ADDR_EXPR)
+    callee = TREE_OPERAND (callee, 0);
+
+  if (TREE_CODE (callee) == FUNCTION_DECL
+      && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_FRONTEND)
+    {
+      intrinsic_code intrinsic = (intrinsic_code) DECL_FUNCTION_CODE (callee);
+
+      switch (intrinsic)
+	{
+	case INTRINSIC_BSF:
+	  return expand_intrinsic_bsf (callexp);
+
+	case INTRINSIC_BSR:
+	  return expand_intrinsic_bsr (callexp);
+
+	case INTRINSIC_BT:
+	case INTRINSIC_BTC:
+	case INTRINSIC_BTR:
+	case INTRINSIC_BTS:
+	  return expand_intrinsic_bt (intrinsic, callexp);
+
+	case INTRINSIC_BSWAP:
+	  return expand_intrinsic_bswap (callexp);
+
+	case INTRINSIC_COS:
+	  return call_builtin_fn (callexp, BUILT_IN_COSL, 1,
+				  CALL_EXPR_ARG (callexp, 0));
+
+	case INTRINSIC_SIN:
+	  return call_builtin_fn (callexp, BUILT_IN_SINL, 1,
+				  CALL_EXPR_ARG (callexp, 0));
+
+	case INTRINSIC_RNDTOL:
+	  /* Not sure if llroundl stands as a good replacement for the
+	     expected behaviour of rndtol.  */
+	  return call_builtin_fn (callexp, BUILT_IN_LLROUNDL, 1,
+				  CALL_EXPR_ARG (callexp, 0));
+
+	case INTRINSIC_SQRT:
+	case INTRINSIC_SQRTF:
+	case INTRINSIC_SQRTL:
+	  return expand_intrinsic_sqrt (intrinsic, callexp);
+
+	case INTRINSIC_LDEXP:
+	  return call_builtin_fn (callexp, BUILT_IN_LDEXPL, 2,
+				  CALL_EXPR_ARG (callexp, 0),
+				  CALL_EXPR_ARG (callexp, 1));
+
+	case INTRINSIC_FABS:
+	  return call_builtin_fn (callexp, BUILT_IN_FABSL, 1,
+				  CALL_EXPR_ARG (callexp, 0));
+
+	case INTRINSIC_RINT:
+	  return call_builtin_fn (callexp, BUILT_IN_RINTL, 1,
+				  CALL_EXPR_ARG (callexp, 0));
+
+	case INTRINSIC_VA_ARG:
+	case INTRINSIC_C_VA_ARG:
+	  return expand_intrinsic_vaarg (callexp);
+
+	case INTRINSIC_VASTART:
+	  return expand_intrinsic_vastart (callexp);
+
+	case INTRINSIC_ADDS:
+	case INTRINSIC_SUBS:
+	case INTRINSIC_MULS:
+	case INTRINSIC_NEGS:
+	  return expand_intrinsic_checkedint (intrinsic, callexp);
+
+	case INTRINSIC_VLOAD:
+	  return expand_volatile_load (callexp);
+
+	case INTRINSIC_VSTORE:
+	  return expand_volatile_store (callexp);
+
+	default:
+	  gcc_unreachable ();
+	}
+    }
+
+  return callexp;
+}
diff --git a/gcc/d/intrinsics.def b/gcc/d/intrinsics.def
new file mode 100644
index 00000000000..e3e98b2bed5
--- /dev/null
+++ b/gcc/d/intrinsics.def
@@ -0,0 +1,103 @@
+/* intrinsics.def -- Definitions for D compiler intrinsics.
+   Copyright (C) 2014-2017 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/>.  */
+
+/* DEF_D_INTRINSIC (CODE, ALIAS, NAME, MODULE, DECO)
+   CODE	    The enum code used to refer this intrinsic.
+   ALIAS    The enum code used to refer the function DECL_FUNCTION_CODE, if
+	    there are multiple modules or decos for a single intrinsic, they
+	    would all refer to this code.
+   NAME	    The name of this intrinsic as a string.
+   MODULE   The name of the module which the intrinsic belongs to as a string.
+   DECO	    The function signature decoration of the intrinsic.
+
+   Used for declaring internally recognized functions that either map to a
+   GCC builtin, or are specially handled by the compiler.  */
+
+/* core.bitop intrinsics.  */
+
+DEF_D_INTRINSIC (BSF, BSF, "bsf", "core.bitop", "FNaNbNiNfkZi")
+DEF_D_INTRINSIC (BSR, BSR, "bsr", "core.bitop", "FNaNbNiNfkZi")
+DEF_D_INTRINSIC (BT, BT, "bt", "core.bitop", "FNaNbNixPkkZi")
+DEF_D_INTRINSIC (BTC, BTC, "btc", "core.bitop", "FNaNbNiPkkZi")
+DEF_D_INTRINSIC (BTR, BTR, "btr", "core.bitop", "FNaNbNiPkkZi")
+DEF_D_INTRINSIC (BTS, BTS, "bts", "core.bitop", "FNaNbNiPkkZi")
+DEF_D_INTRINSIC (BSF64, BSF, "bsf", "core.bitop", "FNaNbNiNfmZi")
+DEF_D_INTRINSIC (BSR64, BSR, "bsr", "core.bitop", "FNaNbNiNfmZi")
+DEF_D_INTRINSIC (BT64, BT, "bt", "core.bitop", "FNaNbNixPmmZi")
+DEF_D_INTRINSIC (BTC64, BTC, "btc", "core.bitop", "FNaNbNiPmmZi")
+DEF_D_INTRINSIC (BTR64, BTR, "btr", "core.bitop", "FNaNbNiPmmZi")
+DEF_D_INTRINSIC (BTS64, BTS, "bts", "core.bitop", "FNaNbNiPmmZi")
+DEF_D_INTRINSIC (BSWAP, BSWAP, "bswap", "core.bitop", "FNaNbNiNfkZk")
+DEF_D_INTRINSIC (BSWAP64, BSWAP, "bswap", "core.bitop", "FNaNbNiNfmZm")
+DEF_D_INTRINSIC (VLOAD, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPhZh")
+DEF_D_INTRINSIC (VLOAD16, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPtZt")
+DEF_D_INTRINSIC (VLOAD32, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPkZk")
+DEF_D_INTRINSIC (VLOAD64, VLOAD, "volatileLoad", "core.bitop", "FNbNiNfPmZm")
+DEF_D_INTRINSIC (VSTORE, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPhhZv")
+DEF_D_INTRINSIC (VSTORE16, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPttZv")
+DEF_D_INTRINSIC (VSTORE32, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPkkZv")
+DEF_D_INTRINSIC (VSTORE64, VSTORE, "volatileStore", "core.bitop", "FNbNiNfPmmZv")
+
+/* core.checkedint intrinsics.  */
+
+DEF_D_INTRINSIC (ADDS, ADDS, "adds", "core.checkedint", "FNaNbNiNfiiKbZi")
+DEF_D_INTRINSIC (ADDSL, ADDS, "adds", "core.checkedint", "FNaNbNiNfllKbZl")
+DEF_D_INTRINSIC (ADDU, ADDS, "addu", "core.checkedint", "FNaNbNiNfkkKbZk")
+DEF_D_INTRINSIC (ADDUL, ADDS, "addu", "core.checkedint", "FNaNbNiNfmmKbZm")
+DEF_D_INTRINSIC (SUBS, SUBS, "subs", "core.checkedint", "FNaNbNiNfiiKbZi")
+DEF_D_INTRINSIC (SUBSL, SUBS, "subs", "core.checkedint", "FNaNbNiNfllKbZl")
+DEF_D_INTRINSIC (SUBU, SUBS, "subu", "core.checkedint", "FNaNbNiNfkkKbZk")
+DEF_D_INTRINSIC (SUBUL, SUBS, "subu", "core.checkedint", "FNaNbNiNfmmKbZm")
+DEF_D_INTRINSIC (MULS, MULS, "muls", "core.checkedint", "FNaNbNiNfiiKbZi")
+DEF_D_INTRINSIC (MULSL, MULS, "muls", "core.checkedint", "FNaNbNiNfllKbZl")
+DEF_D_INTRINSIC (MULU, MULS, "mulu", "core.checkedint", "FNaNbNiNfkkKbZk")
+DEF_D_INTRINSIC (MULUL, MULS, "mulu", "core.checkedint", "FNaNbNiNfmmKbZm")
+DEF_D_INTRINSIC (NEGS, NEGS, "negs", "core.checkedint", "FNaNbNiNfiKbZi")
+DEF_D_INTRINSIC (NEGSL, NEGS, "negs", "core.checkedint", "FNaNbNiNflKbZl")
+
+/* core.math intrinsics.  */
+
+DEF_D_INTRINSIC (COS, COS, "cos", "core.math", "FNaNbNiNfeZe")
+DEF_D_INTRINSIC (FABS, FABS, "fabs", "core.math", "FNaNbNiNfeZe")
+DEF_D_INTRINSIC (LDEXP, LDEXP, "ldexp", "core.math", "FNaNbNiNfeiZe")
+DEF_D_INTRINSIC (RINT, RINT, "rint", "core.math", "FNaNbNiNfeZe")
+DEF_D_INTRINSIC (RNDTOL, RNDTOL, "rndtol", "core.math", "FNaNbNiNfeZl")
+DEF_D_INTRINSIC (SIN, SIN, "sin", "core.math", "FNaNbNiNfeZe")
+DEF_D_INTRINSIC (SQRTF, SQRTF, "sqrt", "core.math", "FNaNbNiNffZf")
+DEF_D_INTRINSIC (SQRT, SQRT, "sqrt", "core.math", "FNaNbNiNfdZd")
+DEF_D_INTRINSIC (SQRTL, SQRTL, "sqrt", "core.math", "FNaNbNiNfeZe")
+
+/* std.math intrinsics.  */
+
+DEF_D_INTRINSIC (STD_COS, COS, "cos", "std.math", "FNaNbNiNfeZe")
+DEF_D_INTRINSIC (STD_FABS, FABS, "fabs", "std.math", "FNaNbNiNfeZe")
+DEF_D_INTRINSIC (STD_LDEXP, LDEXP, "ldexp", "std.math", "FNaNbNiNfeiZe")
+DEF_D_INTRINSIC (STD_RINT, RINT, "rint", "std.math", "FNaNbNiNfeZe")
+DEF_D_INTRINSIC (STD_RNDTOL, RNDTOL, "rndtol", "std.math", "FNaNbNiNfeZl")
+DEF_D_INTRINSIC (STD_SIN, SIN, "sin", "std.math", "FNaNbNiNfeZe")
+DEF_D_INTRINSIC (STD_SQRTF, SQRTF, "sqrt", "std.math", "FNaNbNiNffZf")
+DEF_D_INTRINSIC (STD_SQRT, SQRT, "sqrt", "std.math", "FNaNbNiNfdZd")
+DEF_D_INTRINSIC (STD_SQRTL, SQRTL, "sqrt", "std.math", "FNaNbNiNfeZe")
+
+/* core.stdc.stdarg intrinsics.  */
+
+DEF_D_INTRINSIC (VA_ARG, VA_ARG, "va_arg", "core.stdc.stdarg",
+		 "FKI7va_listKI1TZv")
+DEF_D_INTRINSIC (C_VA_ARG, C_VA_ARG, "va_arg", "core.stdc.stdarg",
+		 "FKI7va_listZI1T")
+DEF_D_INTRINSIC (VASTART, VASTART, "va_start", "core.stdc.stdarg",
+		 "FJI7va_listKI1TZv")
diff --git a/gcc/d/lang-specs.h b/gcc/d/lang-specs.h
new file mode 100644
index 00000000000..a23b6d27348
--- /dev/null
+++ b/gcc/d/lang-specs.h
@@ -0,0 +1,29 @@
+/* lang-specs.h -- GCC driver specs for D frontend.
+   Copyright (C) 2006-2017 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/>.  */
+
+/* This is the contribution to the `default_compilers' array in gcc.c
+   for the D language.  */
+
+{".d", "@d", 0, 1, 0 },
+{".dd", "@d", 0, 1, 0 },
+{".di", "@d", 0, 1, 0 },
+{"@d",
+  "%{!E:cc1d %i %(cc1_options) %I %{nostdinc*} %{i*} %{I*} %{J*} \
+    %{MD:-MD %b.deps} %{MMD:-MMD %b.deps} \
+    %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} \
+    %{X:-Xf %b.json} %{Xf*} \
+    %{v} %{!fsyntax-only:%(invoke_as)}}", 0, 1, 0 },
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
new file mode 100644
index 00000000000..b307c6856a4
--- /dev/null
+++ b/gcc/d/lang.opt
@@ -0,0 +1,385 @@
+; lang.opt -- Options for the D front end.
+; Copyright (C) 2006-2017 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/>.
+
+; See the GCC internals manual for a description of this file's format.
+
+; Please try to keep this file in ASCII collating order.
+
+Language
+D
+
+-dependencies
+D Alias(M)
+; Documented in C
+
+-print-missing-file-dependencies
+D Alias(MG)
+; Documented in C
+
+-user-dependencies
+D Alias(MM)
+; Documented in C
+
+-write-dependencies
+D NoDriverArg Separate Alias(MD)
+; Documented in C
+
+-write-user-dependencies
+D NoDriverArg Separate Alias(MMD)
+; Documented in C
+
+I
+D Joined Separate
+; Documented in C
+
+J
+D Joined Separate
+; Different from documented use in Fortran.
+
+M
+D
+; Documented in C
+
+MD
+D Separate NoDriverArg
+; Documented in C
+
+MF
+D Joined Separate
+; Documented in C
+
+MG
+D
+; Documented in C
+
+MM
+D
+; Documented in C
+
+MMD
+D Separate NoDriverArg
+; Documented in C
+
+MP
+D
+; Documented in C
+
+MT
+D Joined Separate
+; Documented in C
+
+MQ
+D Joined Separate
+; Documented in C
+
+Wall
+D
+; Documented in C
+
+Wcast-result
+D Warning Var(warn_cast_result)
+Warn about casts that will produce a null result.
+
+Wdeprecated
+D
+; Documented in C
+
+Werror
+D
+; Documented in common.opt
+
+Wspeculative
+D
+Warn from speculative compiles such as __traits(compiles).
+
+Wtemplates
+D
+; Documented in C
+
+Wunknown-pragmas
+D LangEnabledBy(D, Wall)
+; Documented in C
+
+X
+D
+Generate JSON file.
+
+Xf
+D Joined Separate
+-Xf <file>	Write JSON output to the given <file>.
+
+debuglib=
+Driver Joined
+Debug library to use instead of phobos.
+
+defaultlib=
+Driver Joined
+Default library to use instead of phobos.
+
+-verbose
+D Alias(v)
+
+fall-instantiations
+D
+Generate code for all template instantiations.
+
+fassert
+D Var(flag_assert)
+Generate code for assert contracts.
+
+fbounds-check
+D
+; Documented in common.opt
+
+fbounds-check=
+D Joined RejectNegative Enum(bounds_check) Var(flag_bounds_check)
+-fbounds-check=[on|safeonly|off]	Turn array bounds checks on, in @safe code only, or off.
+
+Enum
+Name(bounds_check) Type(int) UnknownError(unknown array bounds setting %qs)
+
+EnumValue
+Enum(bounds_check) String(off) Value(0)
+
+EnumValue
+Enum(bounds_check) String(safeonly) Value(1)
+
+EnumValue
+Enum(bounds_check) String(on) Value(2)
+
+fbuiltin
+D Var(flag_no_builtin, 0)
+; Documented in C
+
+fdebug
+D
+Compile in debug code.
+
+fdebug=
+D Joined RejectNegative
+-fdebug=<level|ident>	Compile in debug code, code <= <level>, or code identified by <ident>.
+
+fdeps
+D
+Print information about module dependencies.
+
+fdeps=
+D Joined RejectNegative
+-fdeps=<file>	Write module dependencies to <file>.
+
+fdoc
+D
+Generate documentation.
+
+fdoc-dir=
+D Joined RejectNegative
+-fdoc-dir=<dir>	Write documentation file to directory <dir>.
+
+fdoc-file=
+D Joined RejectNegative
+-fdoc-file=<file>	Write documentation to <file>.
+
+fdoc-inc=
+D Joined RejectNegative
+-fdoc-inc=<file>	Include a Ddoc macro <file>.
+
+fdump-d-original
+D
+Display the frontend AST after parsing and semantic passes.
+
+fd-vgc
+D Alias(ftransition=nogc)
+; Deprecated in favor of -ftransition=nogc
+
+fd-verbose
+D Alias(v)
+; Deprecated in favor of --verbose
+
+fd-vtls
+D Alias(ftransition=tls)
+; Deprecated in favor of -ftransition=tls.
+
+femit-moduleinfo
+D Alias(fmoduleinfo)
+; Deprecated in favor of -fmoduleinfo.
+
+femit-templates
+D Alias(fall-instantiations)
+; Deprecated in favor of -fall-instantiations.
+
+fignore-unknown-pragmas
+D
+Ignore unsupported pragmas.
+
+fin
+D Alias(fpreconditions)
+; Deprecated in favor of -fpreconditions.
+
+fintfc
+Generate D interface files.
+
+fintfc-dir=
+D Joined RejectNegative
+-fintfc-dir=<dir>	Write D interface files to directory <dir>.
+
+fintfc-file=
+D Joined RejectNegative
+-fintfc-file=<file>	Write D interface to <file>.
+
+finvariants
+D Var(flag_invariants)
+Generate code for class invariant contracts.
+
+fmake-deps
+D Alias(M)
+; Deprecated in favor of -M
+
+fmake-deps=
+D Joined RejectNegative
+Deprecated in favor of -MD
+
+fmake-mdeps
+D Alias(MM)
+; Deprecated in favor of -MM
+
+fmake-mdeps=
+D Joined RejectNegative
+Deprecated in favor of -MMD
+
+fmodule-filepath=
+D Joined RejectNegative
+-fmodule-filepath=<package.module>=<filespec>	use <filespec> as source file for <package.module>
+
+fmoduleinfo
+D
+Generate ModuleInfo struct for output module.
+
+fonly=
+D Joined RejectNegative
+Process all modules specified on the command line, but only generate code for the module specified by the argument.
+
+fout
+D Alias(fpostconditions)
+; Deprecated in favor of -fpostconditions.
+
+fpostconditions
+D Var(flag_postconditions)
+Generate code for postcondition contracts.
+
+fpreconditions
+D Var(flag_preconditions)
+Generate code for precondition contracts.
+
+fproperty
+D
+Enforce property syntax.
+
+frelease
+D
+Compile release version.
+
+fswitch-errors
+D Var(flag_switch_errors)
+Generate code for switches without a default case.
+
+ftransition=all
+D RejectNegative
+List information on all language changes
+
+ftransition=checkimports
+D RejectNegative
+Give deprecation messages about -ftransition=import anomalies
+
+ftransition=complex
+D RejectNegative
+List all usages of complex or imaginary types.
+
+ftransition=dip1000
+D RejectNegative
+Implement http://wiki.dlang.org/DIP1000 (experimental)
+
+ftransition=dip25
+D RejectNegative
+Implement http://wiki.dlang.org/DIP25 (experimental)
+
+ftransition=field
+D RejectNegative
+List all non-mutable fields which occupy an object instance.
+
+ftransition=import
+D RejectNegative
+Revert to single phase name lookup.
+
+ftransition=nogc
+D RejectNegative
+List all hidden GC allocations.
+
+ftransition=safe
+D Alias(ftransition=dip1000)
+; Deprecated in favor of -ftransition=dip1000
+
+ftransition=tls
+D RejectNegative
+List all variables going into thread local storage.
+
+funittest
+D
+Compile in unittest code.
+
+fversion=
+D Joined RejectNegative
+-fversion=<level|ident>	Compile in version code >= <level> or identified by <ident>.
+
+fXf=
+D Joined RejectNegative Alias(Xf)
+; Deprecated in favor of -Xf
+
+imultilib
+D Joined Separate
+; Documented in C
+
+iprefix
+D Joined Separate
+; Documented in C
+
+isysroot
+D Joined Separate
+; Documented in C
+
+isystem
+D Joined Separate
+; Documented in C
+
+nophoboslib
+Driver
+Do not link the standard D library in the compilation.
+
+nostdinc
+D
+; Documented in C
+
+static-libphobos
+Driver
+Link the standard D library statically in the compilation.
+
+shared-libphobos
+Driver
+Link the standard D library dynamically in the compilation.
+
+v
+D
+; Documented in C
diff --git a/gcc/d/longdouble.h b/gcc/d/longdouble.h
new file mode 100644
index 00000000000..aea4f4cf50c
--- /dev/null
+++ b/gcc/d/longdouble.h
@@ -0,0 +1,104 @@
+/* longdouble.h -- Definitions of floating point access for the frontend.
+   Copyright (C) 2015-2017 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/>.  */
+
+#ifndef GCC_D_LONGDOUBLE_H
+#define GCC_D_LONGDOUBLE_H
+
+struct real_value;
+class Type;
+
+struct longdouble
+{
+public:
+   /* Return the hidden real_value from the longdouble type.  */
+  const real_value& rv (void) const
+  { return *(const real_value *) this; }
+
+  real_value& rv (void)
+  { return *(real_value *) this; }
+
+  /* No constructor to be able to use this class in a union.  */
+  template<typename T> longdouble& operator = (T x)
+  { set (x); return *this; }
+
+  /* Lvalue operators.
+     We need to list all basic types to avoid ambiguities.  */
+  void set (real_value& rv);
+  void set (int8_t d);
+  void set (int16_t d);
+  void set (int32_t d);
+  void set (int64_t d);
+  void set (uint8_t d);
+  void set (uint16_t d);
+  void set (uint32_t d);
+  void set (uint64_t d);
+  void set (bool d);
+
+  /* Rvalue operators.  */
+  operator real_value&();
+  operator int8_t (void);
+  operator int16_t (void);
+  operator int32_t (void);
+  operator int64_t (void);
+  operator uint8_t (void);
+  operator uint16_t (void);
+  operator uint32_t (void);
+  operator uint64_t (void);
+  operator bool (void);
+
+  /* Arithmetic operators.  */
+  longdouble operator + (const longdouble& r);
+  longdouble operator - (const longdouble& r);
+  longdouble operator * (const longdouble& r);
+  longdouble operator / (const longdouble& r);
+  longdouble operator % (const longdouble& r);
+
+  longdouble operator -();
+
+  /* Comparison operators.  */
+  bool operator < (const longdouble& r);
+  bool operator <= (const longdouble& r);
+  bool operator > (const longdouble& r);
+  bool operator >= (const longdouble& r);
+  bool operator == (const longdouble& r);
+  bool operator != (const longdouble& r);
+
+private:
+  longdouble from_int (Type *type, int64_t d);
+  longdouble from_uint (Type *type, uint64_t d);
+  int64_t to_int (Type *type) const;
+  uint64_t to_uint (Type *type) const;
+
+  /* Including gcc/real.h presents too many problems, so just
+     statically allocate enough space for REAL_VALUE_TYPE.  */
+  long realvalue[(2 + (16 + sizeof (long)) / sizeof (long))];
+};
+
+/* Declared, but "volatile" is not required.  */
+typedef longdouble volatile_longdouble;
+
+/* Use ldouble() to explicitely create a longdouble value.  */
+template<typename T>
+inline longdouble
+ldouble (T x)
+{
+  longdouble d;
+  d.set (x);
+  return d;
+}
+
+#endif  /* ! GCC_D_LONGDOUBLE_H */
diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc
new file mode 100644
index 00000000000..58355e9aca7
--- /dev/null
+++ b/gcc/d/modules.cc
@@ -0,0 +1,859 @@
+/* modules.cc -- D module initialization and termination.
+   Copyright (C) 2013-2017 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 "dfrontend/declaration.h"
+#include "dfrontend/module.h"
+
+#include "tree.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"
+#include "id.h"
+
+
+/* D generates module information to inform the runtime library which modules
+   needs 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 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;
+
+/* The declaration of the current module being compiled.  */
+
+static Module *current_module_decl;
+
+/* Static constructors and destructors (not D `static this').  */
+
+static vec<tree, va_gc> *static_ctor_list;
+static 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);
+    }
+
+  TypeFunction *tf = TypeFunction::create (0, Type::tvoid, 0, LINKc);
+  FuncDeclaration *fd = new FuncDeclaration (mod->loc, mod->loc,
+					     Identifier::idPool (name),
+					     STCstatic, tf);
+  fd->loc = Loc (mod->srcfile->toChars (), 1, 0);
+  fd->linkage = tf->linkage;
+  fd->parent = mod;
+  fd->protection = 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 (uint_type_node, NULL, 1, 1);
+  DECL_CHAIN (fields) = create_field_decl (uint_type_node, 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 (input_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)
+{
+  gcc_assert (targetm_common.have_named_sections);
+
+  /* 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 layed 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 layed 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);
+
+  finish_aggregate_type (offset, 1, 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, uint_type_node));
+
+  CONSTRUCTOR_APPEND_ELT (minit, NULL_TREE,
+			  build_integer_cst (0, uint_type_node));
+
+  /* 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 backend.  */
+
+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 ();
+
+  current_moduleinfo = &mi;
+  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);
+	}
+    }
+
+  /* Default behaviour is to always generate module info because of templates.
+     Can be switched off for not compiling against runtime library.  */
+  if (!global.params.betterC && decl->ident != Id::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_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);
+
+      /* 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 (current_moduleinfo->sharedctors, decl);
+      else if (fd->isStaticCtorDeclaration ())
+	vec_safe_push (current_moduleinfo->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 (current_moduleinfo->sharedctorgates, gate);
+	    }
+	  vec_safe_insert (current_moduleinfo->shareddtors, 0, decl);
+	}
+      else if (fd->isStaticDtorDeclaration ())
+	{
+	  VarDeclaration *vgate = ((StaticDtorDeclaration *) fd)->vgate;
+	  if (vgate != NULL)
+	    {
+	      tree gate = get_symbol_decl (vgate);
+	      vec_safe_push (current_moduleinfo->ctorgates, gate);
+	    }
+	  vec_safe_insert (current_moduleinfo->dtors, 0, decl);
+	}
+
+      /* If a unittest function.  */
+      if (fd->isUnitTestDeclaration ())
+	vec_safe_push (current_moduleinfo->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);
+
+      /* We want the static symbol to be written.  */
+      if (TREE_PUBLIC (decl) && VAR_OR_FUNCTION_DECL_P (decl))
+	{
+	  if ((VAR_P (decl) && TREE_STATIC (decl)) || !DECL_ARTIFICIAL (decl))
+	    mark_needed (decl);
+	}
+    }
+
+  /* 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);
+    }
+}
diff --git a/gcc/d/runtime.cc b/gcc/d/runtime.cc
new file mode 100644
index 00000000000..8859ac4d68f
--- /dev/null
+++ b/gcc/d/runtime.cc
@@ -0,0 +1,316 @@
+/* runtime.cc -- D runtime functions called by generated code.
+   Copyright (C) 2006-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/mtype.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "stringpool.h"
+
+#include "d-tree.h"
+#include "d-frontend.h"
+
+
+/* During the codegen pass, the compiler may do lowering of expressions to call
+   various runtime library functions.  Most are implemented in the `rt' package.
+   We represent them in the frontend here, however there's no guarantee that
+   the compiler implementation actually matches the actual implementation.  */
+
+enum libcall_type
+{
+  LCT_VOID,		    /* void		    */
+  LCT_BYTE,		    /* byte		    */
+  LCT_INT,		    /* int		    */
+  LCT_UINT,		    /* uint		    */
+  LCT_BOOL,		    /* bool		    */
+  LCT_DCHAR,		    /* dchar		    */
+  LCT_VOIDPTR,		    /* void*		    */
+  LCT_STRING,		    /* string		    */
+  LCT_WSTRING,		    /* wstring		    */
+  LCT_DSTRING,		    /* dstring		    */
+  LCT_SIZE_T,		    /* size_t		    */
+  LCT_ASSOCARRAY,	    /* void[void]	    */
+  LCT_ARRAY_VOID,	    /* void[]		    */
+  LCT_ARRAY_SIZE_T,	    /* size_t[]		    */
+  LCT_ARRAY_BYTE,	    /* byte[]		    */
+  LCT_ARRAY_STRING,	    /* string[]		    */
+  LCT_ARRAY_WSTRING,	    /* wstring[]	    */
+  LCT_ARRAY_DSTRING,	    /* dstring[]	    */
+  LCT_ARRAYARRAY_BYTE,	    /* byte[][]		    */
+  LCT_POINTER_ASSOCARRAY,   /* void[void]*	    */
+  LCT_POINTER_VOIDPTR,	    /* void**		    */
+  LCT_ARRAYPTR_VOID,	    /* void[]*		    */
+  LCT_ARRAYPTR_BYTE,	    /* byte[]*		    */
+  LCT_TYPEINFO,		    /* TypeInfo		    */
+  LCT_CLASSINFO,	    /* TypeInfo_Class	    */
+  LCT_OBJECT,		    /* Object		    */
+  LCT_CONST_TYPEINFO,	    /* const(TypeInfo)	    */
+  LCT_CONST_CLASSINFO,	    /* const(ClassInfo)	    */
+  LCT_END,
+};
+
+/* An array of all types that are used by the runtime functions we need.  */
+
+static Type *libcall_types[LCT_END];
+
+/* Our internal list of library functions.  */
+
+static tree libcall_decls[LIBCALL_LAST];
+
+
+/* Return the frontend Type that is described by TYPE.  Most are readily cached
+   by the frontend proper, and likewise the use of pointerTo(), constOf(), and
+   arrayOf() will return cached types if they have been requested before.  */
+
+static Type *
+get_libcall_type (libcall_type type)
+{
+  if (libcall_types[type])
+    return libcall_types[type];
+
+  switch (type)
+    {
+    case LCT_VOID:
+      libcall_types[type] = Type::tvoid;
+      break;
+
+    case LCT_BYTE:
+      libcall_types[type] = Type::tint8;
+      break;
+
+    case LCT_INT:
+      libcall_types[type] = Type::tint32;
+      break;
+
+    case LCT_UINT:
+      libcall_types[type] = Type::tuns32;
+      break;
+
+    case LCT_BOOL:
+      libcall_types[type] = Type::tbool;
+      break;
+
+    case LCT_DCHAR:
+      libcall_types[type] = Type::tdchar;
+      break;
+
+    case LCT_VOIDPTR:
+      libcall_types[type] = Type::tvoidptr;
+      break;
+
+    case LCT_STRING:
+      libcall_types[type] = Type::tstring;
+      break;
+
+    case LCT_WSTRING:
+      libcall_types[type] = Type::twstring;
+      break;
+
+    case LCT_DSTRING:
+      libcall_types[type] = Type::tdstring;
+      break;
+
+    case LCT_SIZE_T:
+      libcall_types[type] = Type::tsize_t;
+      break;
+
+    case LCT_ASSOCARRAY:
+      libcall_types[type] = TypeAArray::create (Type::tvoid, Type::tvoid);
+      break;
+
+    case LCT_TYPEINFO:
+      libcall_types[type] = Type::dtypeinfo->type;
+      break;
+
+    case LCT_CLASSINFO:
+      libcall_types[type] = Type::typeinfoclass->type;
+      break;
+
+    case LCT_OBJECT:
+      libcall_types[type] = get_object_type ();
+      break;
+
+    case LCT_CONST_TYPEINFO:
+      libcall_types[type] = Type::dtypeinfo->type->constOf ();
+      break;
+
+    case LCT_CONST_CLASSINFO:
+      libcall_types[type] = Type::typeinfoclass->type->constOf ();
+      break;
+
+    case LCT_ARRAY_VOID:
+      libcall_types[type] = Type::tvoid->arrayOf ();
+      break;
+
+    case LCT_ARRAY_SIZE_T:
+      libcall_types[type] = Type::tsize_t->arrayOf ();
+      break;
+
+    case LCT_ARRAY_BYTE:
+      libcall_types[type] = Type::tint8->arrayOf ();
+      break;
+
+    case LCT_ARRAY_STRING:
+      libcall_types[type] = Type::tstring->arrayOf ();
+      break;
+
+    case LCT_ARRAY_WSTRING:
+      libcall_types[type] = Type::twstring->arrayOf ();
+      break;
+
+    case LCT_ARRAY_DSTRING:
+      libcall_types[type] = Type::tdstring->arrayOf ();
+      break;
+
+    case LCT_ARRAYARRAY_BYTE:
+      libcall_types[type] = Type::tint8->arrayOf ()->arrayOf ();
+      break;
+
+    case LCT_POINTER_ASSOCARRAY:
+      libcall_types[type] = get_libcall_type (LCT_ASSOCARRAY)->pointerTo ();
+      break;
+
+    case LCT_POINTER_VOIDPTR:
+      libcall_types[type] = Type::tvoidptr->arrayOf ();
+      break;
+
+    case LCT_ARRAYPTR_VOID:
+      libcall_types[type] = Type::tvoid->arrayOf ()->pointerTo ();
+      break;
+
+    case LCT_ARRAYPTR_BYTE:
+      libcall_types[type] = Type::tint8->arrayOf ()->pointerTo ();
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return libcall_types[type];
+}
+
+/* Builds and returns function declaration named NAME.  The RETURN_TYPE is
+   the type returned, FLAGS are the expression call flags, and NPARAMS is
+   the number of arguments, the types of which are provided in `...'.  */
+
+static tree
+build_libcall_decl (const char *name, libcall_type return_type,
+		    int flags, int nparams, ...)
+{
+  tree *args = XALLOCAVEC (tree, nparams);
+  bool varargs = false;
+  tree fntype;
+
+  /* Add parameter types, using 'void' as the last parameter type
+     to mean this function accepts a variable list of arguments.  */
+  va_list ap;
+  va_start (ap, nparams);
+
+  for (int i = 0; i < nparams; i++)
+    {
+      libcall_type ptype = (libcall_type) va_arg (ap, int);
+      Type *type = get_libcall_type (ptype);
+
+      if (type == Type::tvoid)
+	{
+	  varargs = true;
+	  nparams = i;
+	}
+      else
+	args[i] = build_ctype (type);
+    }
+
+  va_end (ap);
+
+  /* Build the function.  */
+  tree tret = build_ctype (get_libcall_type (return_type));
+  if (varargs)
+    fntype = build_varargs_function_type_array (tret, nparams, args);
+  else
+    fntype = build_function_type_array (tret, nparams, args);
+
+  tree decl = build_decl (input_location, FUNCTION_DECL,
+			  get_identifier (name), fntype);
+  DECL_EXTERNAL (decl) = 1;
+  TREE_PUBLIC (decl) = 1;
+  DECL_ARTIFICIAL (decl) = 1;
+  DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
+  DECL_VISIBILITY_SPECIFIED (decl) = 1;
+
+  /* Set any attributes on the function, such as malloc or noreturn.  */
+  set_call_expr_flags (decl, flags);
+
+  return decl;
+}
+
+/* Return or create the runtime library function declaration for LIBCALL.
+   Library functions are generated as needed.  This could probably be changed in
+   the future to be done in the compiler init stage, like GCC builtin trees are,
+   however we depend on runtime initialization of types whose definitions are
+   in the library such as `Object' or `TypeInfo'.  */
+
+static tree
+get_libcall (libcall_fn libcall)
+{
+  if (libcall_decls[libcall])
+    return libcall_decls[libcall];
+
+  switch (libcall)
+    {
+#define DEF_D_RUNTIME(CODE, NAME, TYPE, PARAMS, FLAGS) \
+    case LIBCALL_ ## CODE:	\
+      libcall_decls[libcall] = build_libcall_decl (NAME, TYPE, FLAGS, PARAMS); \
+      break;
+
+#include "runtime.def"
+
+#undef DEF_D_RUNTIME
+
+    default:
+      gcc_unreachable ();
+    }
+
+  return libcall_decls[libcall];
+}
+
+/* Generate a call to LIBCALL, returning the result as TYPE.  NARGS is the
+   number of call arguments, the expressions of wwhich are provided in `...'.
+   This does not perform conversions or promotions on the arguments.  */
+
+tree
+build_libcall (libcall_fn libcall, Type *type, int nargs, ...)
+{
+  /* Build the call expression to the runtime function.  */
+  tree decl = get_libcall (libcall);
+  tree *args = XALLOCAVEC (tree, nargs);
+  va_list ap;
+
+  va_start (ap, nargs);
+  for (int i = 0; i < nargs; i++)
+    args[i] = va_arg (ap, tree);
+  va_end (ap);
+
+  tree result = build_call_expr_loc_array (input_location, decl, nargs, args);
+
+  /* Assumes caller knows what it is doing.  */
+  return convert (build_ctype (type), result);
+}
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
new file mode 100644
index 00000000000..14b1dcf77c8
--- /dev/null
+++ b/gcc/d/runtime.def
@@ -0,0 +1,224 @@
+/* runtime.def -- Definitions for D runtime functions.
+   Copyright (C) 2014-2017 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/>.  */
+
+/* D runtime library functions.  */
+
+/* DEF_D_RUNTIME (CODE, NAME, FLAGS)
+   CODE	    The enum code used to refer this function.
+   NAME	    The name of this function as a string.
+   FLAGS    ECF flags to describe attributes of the function.
+
+   Used for declaring functions that are called by generated code.  Most are
+   extern(C) - for those that are not, ensure to use correct mangling.  */
+
+/* Helper macros for parameter building.  */
+#define P0()		    0
+#define P1(T1)		    1, LCT_ ## T1
+#define P2(T1, T2)	    2, LCT_ ## T1, LCT_ ## T2
+#define P3(T1, T2, T3)	    3, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3
+#define P4(T1, T2, T3, T4)  4, LCT_ ## T1, LCT_ ## T2, LCT_ ## T3, LCT_ ## T4
+#define RT(T1)		    LCT_ ## T1
+
+/* Used when an assert() contract fails.  */
+DEF_D_RUNTIME (ASSERT, "_d_assert", RT(VOID), P2(STRING, UINT), ECF_NORETURN)
+DEF_D_RUNTIME (ASSERT_MSG, "_d_assert_msg", RT(VOID), P3(STRING, STRING, UINT),
+	       ECF_NORETURN)
+
+/* Used when an assert() contract fails in a unittest function.  */
+DEF_D_RUNTIME (UNITTEST, "_d_unittest", RT(VOID), P2(STRING, UINT),
+	       ECF_NORETURN)
+DEF_D_RUNTIME (UNITTEST_MSG, "_d_unittest_msg", RT(VOID),
+	       P3(STRING, STRING, UINT), ECF_NORETURN)
+
+/* Used when an array index outside the bounds of its range.  */
+DEF_D_RUNTIME (ARRAY_BOUNDS, "_d_arraybounds", RT(VOID), P2(STRING, UINT),
+	       ECF_NORETURN)
+
+/* Used when calling new on a class.  */
+DEF_D_RUNTIME (NEWCLASS, "_d_newclass", RT(OBJECT), P1(CONST_CLASSINFO), 0)
+
+/* Used when calling delete on a class or interface.  */
+DEF_D_RUNTIME (DELCLASS, "_d_delclass", RT(VOID), P1(VOIDPTR), 0)
+DEF_D_RUNTIME (DELINTERFACE, "_d_delinterface", RT(VOID), P1(VOIDPTR), 0)
+
+/* Same as deleting a class, but used for stack-allocated classes.  */
+DEF_D_RUNTIME (CALLFINALIZER, "_d_callfinalizer", RT(VOID), P1(VOIDPTR), 0)
+DEF_D_RUNTIME (CALLINTERFACEFINALIZER, "_d_callinterfacefinalizer", RT(VOID),
+	       P1(VOIDPTR), 0)
+
+/* Used for casting to a class or interface.  */
+DEF_D_RUNTIME (DYNAMIC_CAST, "_d_dynamic_cast", RT(OBJECT),
+	       P2(OBJECT, CLASSINFO), 0)
+DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT),
+	       P2(OBJECT, CLASSINFO), 0)
+
+/* Used when calling new on a pointer.  The `i' variant is for when the
+   initialiser is non-zero.  */
+DEF_D_RUNTIME (NEWITEMT, "_d_newitemT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
+DEF_D_RUNTIME (NEWITEMIT, "_d_newitemiT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
+
+/* Used when calling delete on a pointer.  */
+DEF_D_RUNTIME (DELMEMORY, "_d_delmemory", RT(VOID), P1(POINTER_VOIDPTR), 0)
+DEF_D_RUNTIME (DELSTRUCT, "_d_delstruct", RT(VOID),
+	       P2(POINTER_VOIDPTR, TYPEINFO), 0)
+
+/* Used when calling new on an array.  The `i' variant is for when the
+   initialiser is non-zero, and the `m' variant is when initialising a
+   multi-dimensional array.  */
+DEF_D_RUNTIME (NEWARRAYT, "_d_newarrayT", RT(ARRAY_VOID),
+	       P2(CONST_TYPEINFO, SIZE_T), 0)
+DEF_D_RUNTIME (NEWARRAYIT, "_d_newarrayiT", RT(ARRAY_VOID),
+	       P2(CONST_TYPEINFO, SIZE_T), 0)
+DEF_D_RUNTIME (NEWARRAYMTX, "_d_newarraymTX", RT(ARRAY_VOID),
+	       P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0)
+DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID),
+	       P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0)
+
+/* Used for allocating an array literal on the GC heap.  */
+DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR),
+	       P2(CONST_TYPEINFO, SIZE_T), 0)
+
+/* Used when calling delete on an array.  */
+DEF_D_RUNTIME (DELARRAYT, "_d_delarray_t", RT(VOID),
+	       P2(ARRAYPTR_VOID, CONST_TYPEINFO), 0)
+
+/* Used for value equality (x == y) and comparisons (x < y) of non-trivial
+   arrays.  Such as an array of structs or classes.  */
+DEF_D_RUNTIME (ADEQ2, "_adEq2", RT(INT),
+	       P3(ARRAY_VOID, ARRAY_VOID, CONST_TYPEINFO), 0)
+DEF_D_RUNTIME (ADCMP2, "_adCmp2", RT(INT),
+	       P3(ARRAY_VOID, ARRAY_VOID, CONST_TYPEINFO), 0)
+
+/* Used when casting from one array type to another where the index type
+   sizes differ.  Such as from int[] to short[].  */
+DEF_D_RUNTIME (ARRAYCAST, "_d_arraycast", RT(ARRAY_VOID),
+	       P3(SIZE_T, SIZE_T, ARRAY_VOID), 0)
+
+/* Used for (array.length = n) expressions.  The `i' variant is for when the
+   initialiser is non-zero.  */
+DEF_D_RUNTIME (ARRAYSETLENGTHT, "_d_arraysetlengthT", RT(ARRAY_VOID),
+	       P3(CONST_TYPEINFO, SIZE_T, ARRAYPTR_VOID), 0)
+DEF_D_RUNTIME (ARRAYSETLENGTHIT, "_d_arraysetlengthiT", RT(ARRAY_VOID),
+	       P3(CONST_TYPEINFO, SIZE_T, ARRAYPTR_VOID), 0)
+
+/* Used for allocating closures on the GC heap.  */
+DEF_D_RUNTIME (ALLOCMEMORY, "_d_allocmemory", RT(VOIDPTR), P1(SIZE_T),
+	       ECF_MALLOC)
+
+/* Used for copying an array into a slice, adds an enforcment that the source
+   and destination are equal in size and do not overlap.  */
+DEF_D_RUNTIME (ARRAYCOPY, "_d_arraycopy", RT(ARRAY_VOID),
+	       P3(SIZE_T, ARRAY_VOID, ARRAY_VOID), 0)
+
+/* Used for array assignments from an existing array.  The `set' variant is for
+   when the assignment value is a single element.  */
+DEF_D_RUNTIME (ARRAYASSIGN, "_d_arrayassign", RT(ARRAY_VOID),
+	       P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
+DEF_D_RUNTIME (ARRAYASSIGN_L, "_d_arrayassign_l", RT(ARRAY_VOID),
+	       P4(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID, VOIDPTR), 0)
+DEF_D_RUNTIME (ARRAYASSIGN_R, "_d_arrayassign_r", RT(ARRAY_VOID),
+	       P4(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID, VOIDPTR), 0)
+DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR),
+	       P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0)
+
+/* Used for constructing a new array from an existing array.  The `set' variant
+   is for when the constructor value is a single element.  */
+DEF_D_RUNTIME (ARRAYCTOR, "_d_arrayctor", RT(ARRAY_VOID),
+	       P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
+DEF_D_RUNTIME (ARRAYSETCTOR, "_d_arraysetctor", RT(VOIDPTR),
+	       P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0)
+
+/* Used for concatenating two or more arrays together.  Then `n' variant is
+   for when there is more than two arrays to handle.  */
+DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE),
+	       P3(CONST_TYPEINFO, ARRAY_BYTE, ARRAY_BYTE), 0)
+DEF_D_RUNTIME (ARRAYCATNTX, "_d_arraycatnTX", RT(ARRAY_VOID),
+	       P2(CONST_TYPEINFO, ARRAYARRAY_BYTE), 0)
+
+/* Used for appending a single element to an array.  */
+DEF_D_RUNTIME (ARRAYAPPENDCTX, "_d_arrayappendcTX", RT(ARRAY_BYTE),
+	       P3(CONST_TYPEINFO, ARRAYPTR_BYTE, SIZE_T), 0)
+
+/* Same as appending a single element to an array, but specific for when the
+   source is a UTF-32 character, and the destination is a UTF-8 or 16 array.  */
+DEF_D_RUNTIME (ARRAYAPPENDCD, "_d_arrayappendcd", RT(ARRAY_VOID),
+	       P2(ARRAYPTR_BYTE, DCHAR), 0)
+DEF_D_RUNTIME (ARRAYAPPENDWD, "_d_arrayappendwd", RT(ARRAY_VOID),
+	       P2(ARRAYPTR_BYTE, DCHAR), 0)
+
+/* Used for appending an existing array to another.  */
+DEF_D_RUNTIME (ARRAYAPPENDT, "_d_arrayappendT", RT(ARRAY_VOID),
+	       P3(TYPEINFO, ARRAYPTR_BYTE, ARRAY_BYTE), 0)
+
+/* Used for allocating a new associative array.  */
+DEF_D_RUNTIME (ASSOCARRAYLITERALTX, "_d_assocarrayliteralTX", RT(VOIDPTR),
+	       P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
+
+/* Used for value equality of two associative arrays.  */
+DEF_D_RUNTIME (AAEQUAL, "_aaEqual", RT(INT),
+	       P3(CONST_TYPEINFO, ASSOCARRAY, ASSOCARRAY), 0)
+
+/* Used to determine is a key exists in an associative array.  */
+DEF_D_RUNTIME (AAINX, "_aaInX", RT(VOIDPTR),
+	       P3(ASSOCARRAY, CONST_TYPEINFO, VOIDPTR), 0)
+
+/* Used to retrieve a value from an associative array index by a key.  The
+   `Rvalue' variant returns null if the key is not found, where as aaGetY
+   will create new key entry for assignment.  */
+DEF_D_RUNTIME (AAGETY, "_aaGetY", RT(VOIDPTR),
+	       P4(POINTER_ASSOCARRAY, CONST_TYPEINFO, SIZE_T, VOIDPTR), 0)
+DEF_D_RUNTIME (AAGETRVALUEX, "_aaGetRvalueX", RT(VOIDPTR),
+	       P4(ASSOCARRAY, CONST_TYPEINFO, SIZE_T, VOIDPTR), 0)
+
+/* Used when calling delete on a key entry in an associative array.  */
+DEF_D_RUNTIME (AADELX, "_aaDelX", RT(BOOL),
+	       P3(ASSOCARRAY, CONST_TYPEINFO, VOIDPTR), 0)
+
+/* Used for throw() expressions.  */
+DEF_D_RUNTIME (THROW, "_d_throw", RT(VOID), P1(OBJECT), ECF_NORETURN)
+DEF_D_RUNTIME (BEGIN_CATCH, "__gdc_begin_catch", RT(VOIDPTR), P1(VOIDPTR), 0)
+
+/* C++ exception handlers.  */
+DEF_D_RUNTIME (CXA_BEGIN_CATCH, "__cxa_begin_catch", RT(VOIDPTR), P1(VOIDPTR),
+	       ECF_NOTHROW)
+DEF_D_RUNTIME (CXA_END_CATCH, "__cxa_end_catch", RT(VOID), P0(), 0)
+
+/* When invariant() contracts are turned on, used after testing whether a
+   class != null for validating the state of a class.  */
+DEF_D_RUNTIME (INVARIANT, "_D9invariant12_d_invariantFC6ObjectZv", RT(VOID),
+	       P1(OBJECT), 0)
+
+/* Used when performing a switch/cases on a string.  The `u' and `d' variants
+   are for UTF-16 and UTF-32 strings respectively.  */
+DEF_D_RUNTIME (SWITCH_STRING, "_d_switch_string", RT(INT),
+	       P2(ARRAY_STRING, STRING), 0)
+DEF_D_RUNTIME (SWITCH_USTRING, "_d_switch_ustring", RT(INT),
+	       P2(ARRAY_WSTRING, WSTRING), 0)
+DEF_D_RUNTIME (SWITCH_DSTRING, "_d_switch_dstring", RT(INT),
+	       P2(ARRAY_DSTRING, DSTRING), 0)
+
+/* Used when throwing an error that a switch statement has no default case,
+   and yet none of the existing cases matched.  */
+DEF_D_RUNTIME (SWITCH_ERROR, "_d_switch_error", RT(VOID), P2(STRING, UINT),
+	       ECF_NORETURN)
+
+#undef P0
+#undef P1
+#undef P2
+#undef P3
+#undef P4
+#undef RT
diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc
new file mode 100644
index 00000000000..2a93a379b35
--- /dev/null
+++ b/gcc/d/toir.cc
@@ -0,0 +1,1453 @@
+/* toir.cc -- Lower D frontend statements to GCC trees.
+   Copyright (C) 2006-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/declaration.h"
+#include "dfrontend/init.h"
+#include "dfrontend/statement.h"
+
+#include "tree.h"
+#include "tree-iterator.h"
+#include "options.h"
+#include "stmt.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stringpool.h"
+#include "function.h"
+#include "toplev.h"
+
+#include "d-tree.h"
+#include "id.h"
+
+
+/* Update data for defined and undefined labels when leaving a scope.  */
+
+bool
+pop_binding_label (Statement * const &, d_label_entry *ent, binding_level *bl)
+{
+  binding_level *obl = bl->level_chain;
+
+  if (ent->level == bl)
+    {
+      if (bl->kind == level_try)
+	ent->in_try_scope = true;
+      else if (bl->kind == level_catch)
+	ent->in_catch_scope = true;
+
+      ent->level = obl;
+    }
+  else if (ent->fwdrefs)
+    {
+      for (d_label_use_entry *ref = ent->fwdrefs; ref; ref = ref->next)
+	ref->level = obl;
+    }
+
+  return true;
+}
+
+/* At the end of a function, all labels declared within the function
+   go out of scope.  BLOCK is the top-level block for the function.  */
+
+bool
+pop_label (Statement * const &s, d_label_entry *ent, tree block)
+{
+  if (!ent->bc_label)
+    {
+      /* Put the labels into the "variables" of the top-level block,
+	 so debugger can see them.  */
+      if (DECL_NAME (ent->label))
+	{
+	  gcc_assert (DECL_INITIAL (ent->label) != NULL_TREE);
+	  DECL_CHAIN (ent->label) = BLOCK_VARS (block);
+	  BLOCK_VARS (block) = ent->label;
+	}
+    }
+
+  d_function_chain->labels->remove (s);
+
+  return true;
+}
+
+/* The D front-end does not use the 'binding level' system for a symbol table,
+   however it has been the goto structure for tracking code flow.
+   Primarily it is only needed to get debugging information for local variables
+   and otherwise support the backend.  */
+
+void
+push_binding_level (level_kind kind)
+{
+  /* Add it to the front of currently active scopes stack.  */
+  binding_level *new_level = ggc_cleared_alloc<binding_level> ();
+  new_level->level_chain = current_binding_level;
+  new_level->kind = kind;
+
+  current_binding_level = new_level;
+}
+
+tree
+pop_binding_level (void)
+{
+  binding_level *level = current_binding_level;
+  current_binding_level = level->level_chain;
+
+  tree block = make_node (BLOCK);
+  BLOCK_VARS (block) = level->names;
+  BLOCK_SUBBLOCKS (block) = level->blocks;
+
+  /* In each subblock, record that this is its superior.  */
+  for (tree t = level->blocks; t; t = BLOCK_CHAIN (t))
+    BLOCK_SUPERCONTEXT (t) = block;
+
+  if (level->kind == level_function)
+    {
+      /* Dispose of the block that we just made inside some higher level.  */
+      DECL_INITIAL (current_function_decl) = block;
+      BLOCK_SUPERCONTEXT (block) = current_function_decl;
+
+      /* Pop all the labels declared in the function.  */
+      if (d_function_chain->labels)
+	d_function_chain->labels->traverse<tree, &pop_label> (block);
+    }
+  else
+    {
+      /* Any uses of undefined labels, and any defined labels, now operate
+         under constraints of next binding contour.  */
+      if (d_function_chain && d_function_chain->labels)
+	{
+	  language_function *f = d_function_chain;
+	  f->labels->traverse<binding_level *, &pop_binding_label> (level);
+	}
+
+      current_binding_level->blocks
+	= block_chainon (current_binding_level->blocks, block);
+    }
+
+  TREE_USED (block) = 1;
+  return block;
+}
+
+/* Create an empty statement tree rooted at T.  */
+
+void
+push_stmt_list (void)
+{
+  tree t = alloc_stmt_list ();
+  vec_safe_push (d_function_chain->stmt_list, t);
+  d_keep (t);
+}
+
+/* Finish the statement tree rooted at T.  */
+
+tree
+pop_stmt_list (void)
+{
+  tree t = d_function_chain->stmt_list->pop ();
+
+  /* If the statement list is completely empty, just return it.  This is just
+     as good small as build_empty_stmt, with the advantage that statement
+     lists are merged when they appended to one another.  So using the
+     STATEMENT_LIST avoids pathological buildup of EMPTY_STMT_P statements.  */
+  if (TREE_SIDE_EFFECTS (t))
+    {
+      /* If the statement list contained exactly one statement, then extract
+	 it immediately.  */
+      tree_stmt_iterator i = tsi_start (t);
+
+      if (tsi_one_before_end_p (i))
+	{
+	  tree u = tsi_stmt (i);
+	  tsi_delink (&i);
+	  free_stmt_list (t);
+	  t = u;
+	}
+    }
+
+  return t;
+}
+
+/* T is an expression statement.  Add it to the statement-tree.  */
+
+void
+add_stmt (tree t)
+{
+  /* Ignore (void) 0; expression statements received from the frontend.
+     Likewise void_node is used when contracts become nops in release code.  */
+  if (t == void_node || IS_EMPTY_STMT (t))
+    return;
+
+  /* At this point, we no longer care about the value of expressions,
+     so if there's no side-effects, then don't add it.  */
+  if (!TREE_SIDE_EFFECTS (t))
+    return;
+
+  if (TREE_CODE (t) == COMPOUND_EXPR)
+    {
+      /* Push out each comma expressions as separate statements.  */
+      add_stmt (TREE_OPERAND (t, 0));
+      add_stmt (TREE_OPERAND (t, 1));
+    }
+  else
+    {
+      /* Append the expression to the statement list.
+	 Make sure it has a proper location.  */
+      if (EXPR_P (t) && !EXPR_HAS_LOCATION (t))
+	SET_EXPR_LOCATION (t, input_location);
+
+      tree stmt_list = d_function_chain->stmt_list->last ();
+      append_to_statement_list_force (t, &stmt_list);
+    }
+}
+
+/* Implements the visitor interface to build the GCC trees of all Statement
+   AST classes emitted from the D Front-end.
+   All visit methods accept one parameter S, which holds the frontend AST
+   of the statement to compile.  They also don't return any value, instead
+   generated code are pushed to add_stmt(), which appends them to the
+   statement list in the current_binding_level.  */
+
+class IRVisitor : public Visitor
+{
+  FuncDeclaration *func_;
+
+  /* Stack of labels which are targets for "break" and "continue",
+     linked through TREE_CHAIN.  */
+  tree break_label_;
+  tree continue_label_;
+
+public:
+  IRVisitor (FuncDeclaration *fd)
+  {
+    this->func_ = fd;
+    this->break_label_ = NULL_TREE;
+    this->continue_label_ = NULL_TREE;
+  }
+
+  /* Start a new scope for a KIND statement.
+     Each user-declared variable will have a binding contour that begins
+     where the variable is declared and ends at it's containing scope.  */
+
+  void start_scope (level_kind kind)
+  {
+    push_binding_level (kind);
+    push_stmt_list ();
+  }
+
+  /* Leave scope pushed by start_scope, returning a new bind_expr if
+     any variables where declared in the scope.  */
+
+  tree end_scope (void)
+  {
+    tree block = pop_binding_level ();
+    tree body = pop_stmt_list ();
+
+    if (! BLOCK_VARS (block))
+      return body;
+
+    tree bind = build3 (BIND_EXPR, void_type_node,
+			BLOCK_VARS (block), body, block);
+    TREE_SIDE_EFFECTS (bind) = 1;
+    return bind;
+  }
+
+  /* Like end_scope, but also push it into the outer statement-tree.  */
+
+  void finish_scope (void)
+  {
+    tree scope = this->end_scope ();
+    add_stmt (scope);
+  }
+
+  /* Return TRUE if IDENT is the current function return label.  */
+
+  bool is_return_label (Identifier *ident)
+  {
+    if (this->func_->returnLabel)
+      return this->func_->returnLabel->ident == ident;
+
+    return false;
+  }
+
+  /* Define a label, specifying the location in the source file.
+     Return the LABEL_DECL node for the label.  */
+
+  tree define_label (Statement *s, Identifier *ident = NULL)
+  {
+    tree label = this->lookup_label (s, ident);
+    gcc_assert (DECL_INITIAL (label) == NULL_TREE);
+
+    d_label_entry *ent = d_function_chain->labels->get (s);
+    gcc_assert (ent != NULL);
+
+    /* Mark label as having been defined.  */
+    DECL_INITIAL (label) = error_mark_node;
+
+    ent->level = current_binding_level;
+
+    for (d_label_use_entry *ref = ent->fwdrefs; ref ; ref = ref->next)
+      this->check_previous_goto (ent->statement, ref);
+    ent->fwdrefs = NULL;
+
+    return label;
+  }
+
+  /* Emit a LABEL expression.  */
+
+  void do_label (tree label)
+  {
+    /* Don't write out label unless it is marked as used by the frontend.
+       This makes auto-vectorization possible in conditional loops.
+       The only excemption to this is in the LabelStatement visitor,
+       in which all computed labels are marked regardless.  */
+    if (TREE_USED (label))
+      add_stmt (build1 (LABEL_EXPR, void_type_node, label));
+  }
+
+  /* Emit a goto expression to LABEL.  */
+
+  void do_jump (Statement *stmt, tree label)
+  {
+    if (stmt)
+      input_location = get_linemap (stmt->loc);
+
+    add_stmt (fold_build1 (GOTO_EXPR, void_type_node, label));
+    TREE_USED (label) = 1;
+  }
+
+  /* Check that a new jump at statement scope FROM to a label declared in
+     statement scope TO is valid.  */
+
+  void check_goto (Statement *from, Statement *to)
+  {
+    d_label_entry *ent = d_function_chain->labels->get (to);
+    gcc_assert (ent != NULL);
+
+    /* If the label hasn't been defined yet, defer checking.  */
+    if (! DECL_INITIAL (ent->label))
+      {
+	d_label_use_entry *fwdref = ggc_alloc<d_label_use_entry> ();
+	fwdref->level = current_binding_level;
+	fwdref->statement = from;
+	fwdref->next = ent->fwdrefs;
+	ent->fwdrefs = fwdref;
+	return;
+      }
+
+    if (ent->in_try_scope)
+      from->error ("cannot goto into try block");
+    else if (ent->in_catch_scope)
+      from->error ("cannot goto into catch block");
+  }
+
+  /* Check that a previously seen jump to a newly defined label is valid.
+     S is the label statement; FWDREF is the jump context.  This is called
+     for both user-defined and case labels.  */
+
+  void check_previous_goto (Statement *s, d_label_use_entry *fwdref)
+  {
+    for (binding_level *b = current_binding_level; b ; b = b->level_chain)
+      {
+	if (b == fwdref->level)
+	  break;
+
+	if (b->kind == level_try || b->kind == level_catch)
+	  {
+	    if (s->isLabelStatement ())
+	      {
+		if (b->kind == level_try)
+		  fwdref->statement->error ("cannot goto into try block");
+		else
+		  fwdref->statement->error ("cannot goto into catch block");
+	      }
+	    else if (s->isCaseStatement ())
+	      {
+		s->error ("case cannot be in different "
+			  "try block level from switch");
+	      }
+	    else if (s->isDefaultStatement ())
+	      {
+		s->error ("default cannot be in different "
+			  "try block level from switch");
+	      }
+	    else
+	      gcc_unreachable ();
+	  }
+      }
+  }
+
+  /* Get or build LABEL_DECL using the IDENT and statement block S given.  */
+
+  tree lookup_label (Statement *s, Identifier *ident = NULL)
+  {
+    /* You can't use labels at global scope.  */
+    if (d_function_chain == NULL)
+      {
+	error ("label %s referenced outside of any function",
+	       ident ? ident->toChars () : "(unnamed)");
+	return NULL_TREE;
+      }
+
+    /* Create the label htab for the function on demand.  */
+    if (!d_function_chain->labels)
+      {
+	d_function_chain->labels
+	  = hash_map<Statement *, d_label_entry>::create_ggc (13);
+      }
+
+    d_label_entry *ent = d_function_chain->labels->get (s);
+    if (ent != NULL)
+      return ent->label;
+    else
+      {
+	tree name = ident ? get_identifier (ident->toChars ()) : NULL_TREE;
+	tree decl = build_decl (input_location, LABEL_DECL,
+				name, void_type_node);
+	DECL_CONTEXT (decl) = current_function_decl;
+	DECL_MODE (decl) = VOIDmode;
+
+	/* Create new empty slot.  */
+	ent = ggc_cleared_alloc<d_label_entry> ();
+	ent->statement = s;
+	ent->label = decl;
+
+	bool existed = d_function_chain->labels->put (s, *ent);
+	gcc_assert (!existed);
+
+	return decl;
+      }
+  }
+
+  /* Get the LABEL_DECL to represent a break or continue for the
+     statement S given.  BC indicates which.  */
+
+  tree lookup_bc_label (Statement *s, bc_kind bc)
+  {
+    tree vec = this->lookup_label (s);
+
+    /* The break and continue labels are put into a TREE_VEC.  */
+    if (TREE_CODE (vec) == LABEL_DECL)
+      {
+	d_label_entry *ent = d_function_chain->labels->get (s);
+	gcc_assert (ent != NULL);
+
+	vec = make_tree_vec (2);
+	TREE_VEC_ELT (vec, bc_break) = ent->label;
+
+	/* Build the continue label.  */
+	tree label = build_decl (input_location, LABEL_DECL,
+				 NULL_TREE, void_type_node);
+	DECL_CONTEXT (label) = current_function_decl;
+	DECL_MODE (label) = VOIDmode;
+	TREE_VEC_ELT (vec, bc_continue) = label;
+
+	ent->label = vec;
+	ent->bc_label = true;
+      }
+
+    return TREE_VEC_ELT (vec, bc);
+  }
+
+  /* Set and return the current break label for the current block.  */
+
+  tree push_break_label (Statement *s)
+  {
+    tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_break);
+    DECL_CHAIN (label) = this->break_label_;
+    this->break_label_ = label;
+    return label;
+  }
+
+  /* Finish with the current break label.  */
+
+  void pop_break_label (tree label)
+  {
+    gcc_assert (this->break_label_ == label);
+    this->break_label_ = DECL_CHAIN (this->break_label_);
+    this->do_label (label);
+  }
+
+  /* Set and return the continue label for the current block.  */
+
+  tree push_continue_label (Statement *s)
+  {
+    tree label = this->lookup_bc_label (s->getRelatedLabeled (), bc_continue);
+    DECL_CHAIN (label) = this->continue_label_;
+    this->continue_label_ = label;
+    return label;
+  }
+
+  /* Finish with the current continue label.  */
+
+  void pop_continue_label (tree label)
+  {
+    gcc_assert (this->continue_label_ == label);
+    this->continue_label_ = DECL_CHAIN (this->continue_label_);
+    this->do_label (label);
+  }
+
+  /* Visitor interfaces.  */
+
+
+  /* This should be overridden by each statement class.  */
+
+  void visit (Statement *s)
+  {
+    input_location = get_linemap (s->loc);
+    gcc_unreachable ();
+  }
+
+  /* The frontend lowers `scope (exit/failure/success)' statements as
+     try/catch/finally. At this point, this statement is just an empty
+     placeholder.  Maybe the frontend shouldn't leak these.  */
+
+  void visit (OnScopeStatement *)
+  {
+  }
+
+  /* If statements provide simple conditional execution of statements.  */
+
+  void visit (IfStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    this->start_scope (level_cond);
+
+    /* Build the outer 'if' condition, which may produce temporaries
+       requiring scope destruction.  */
+    tree ifcond = convert_for_condition (build_expr_dtor (s->condition),
+					 s->condition->type);
+    tree ifbody = void_node;
+    tree elsebody = void_node;
+
+    /* Build the 'then' branch.  */
+    if (s->ifbody)
+      {
+	push_stmt_list ();
+	s->ifbody->accept (this);
+	ifbody = pop_stmt_list ();
+      }
+
+    /* Now build the 'else' branch, which may have nested 'else if' parts.  */
+    if (s->elsebody)
+      {
+	push_stmt_list ();
+	s->elsebody->accept (this);
+	elsebody = pop_stmt_list ();
+      }
+
+    /* Wrap up our constructed if condition into a COND_EXPR.  */
+    input_location = get_linemap (s->loc);
+    tree cond = build_vcondition (ifcond, ifbody, elsebody);
+    add_stmt (cond);
+
+    /* Finish the if-then scope.  */
+    this->finish_scope ();
+  }
+
+  /* Should there be any `pragma (...)' statements requiring code generation,
+     here would be the place to do it.  For now, all pragmas are handled
+     by the frontend.  */
+
+  void visit (PragmaStatement *)
+  {
+  }
+
+  /* The frontend lowers `while (...)' statements as `for (...)' loops.
+     This visitor is not strictly required other than to enforce that
+     these kinds of statements never reach here.  */
+
+  void visit (WhileStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    gcc_unreachable ();
+  }
+
+  /* Do while statments implement simple loops.  The body is executed, then
+     the condition is evaluated.  */
+
+  void visit (DoStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    tree lbreak = this->push_break_label (s);
+
+    this->start_scope (level_loop);
+    if (s->_body)
+      {
+	tree lcontinue = this->push_continue_label (s);
+	s->_body->accept (this);
+	this->pop_continue_label (lcontinue);
+      }
+
+    /* Build the outer 'while' condition, which may produce temporaries
+       requiring scope destruction.  */
+    input_location = get_linemap (s->condition->loc);
+    tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
+					   s->condition->type);
+    add_stmt (build_vcondition (exitcond, void_node,
+				build1 (GOTO_EXPR, void_type_node, lbreak)));
+    TREE_USED (lbreak) = 1;
+
+    tree body = this->end_scope ();
+    input_location = get_linemap (s->loc);
+    add_stmt (build1 (LOOP_EXPR, void_type_node, body));
+
+    this->pop_break_label (lbreak);
+  }
+
+  /* For statements implement loops with initialization, test, and
+     increment clauses.  */
+
+  void visit (ForStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    tree lbreak = this->push_break_label (s);
+    this->start_scope (level_loop);
+
+    if (s->_init)
+      s->_init->accept (this);
+
+    if (s->condition)
+      {
+	input_location = get_linemap (s->condition->loc);
+	tree exitcond = convert_for_condition (build_expr_dtor (s->condition),
+					       s->condition->type);
+	add_stmt (build_vcondition (exitcond, void_node,
+				    build1 (GOTO_EXPR, void_type_node,
+					    lbreak)));
+	TREE_USED (lbreak) = 1;
+      }
+
+    if (s->_body)
+      {
+	tree lcontinue = this->push_continue_label (s);
+	s->_body->accept (this);
+	this->pop_continue_label (lcontinue);
+      }
+
+    if (s->increment)
+      {
+	/* Force side effects?  */
+	input_location = get_linemap (s->increment->loc);
+	add_stmt (build_expr_dtor (s->increment));
+      }
+
+    tree body = this->end_scope ();
+    input_location = get_linemap (s->loc);
+    add_stmt (build1 (LOOP_EXPR, void_type_node, body));
+
+    this->pop_break_label (lbreak);
+  }
+
+  /* The frontend lowers `foreach (...)' statements as `for (...)' loops.
+     This visitor is not strictly required other than to enforce that
+     these kinds of statements never reach here.  */
+
+  void visit (ForeachStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    gcc_unreachable ();
+  }
+
+  /* The frontend lowers `foreach (...; [x..y])' statements as `for (...)'
+     loops.  This visitor is not strictly required other than to enforce that
+     these kinds of statements never reach here.  */
+
+  void visit (ForeachRangeStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    gcc_unreachable ();
+  }
+
+  /* Jump to the associated exit label for the current loop.  If IDENT
+     for the Statement is not null, then the label is user defined.  */
+
+  void visit (BreakStatement *s)
+  {
+    if (s->ident)
+      {
+	/* The break label may actually be some levels up.
+	   eg: on a try/finally wrapping a loop.  */
+	LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
+	gcc_assert (label != NULL);
+	Statement *stmt = label->statement->getRelatedLabeled ();
+	this->do_jump (s, this->lookup_bc_label (stmt, bc_break));
+      }
+    else
+      this->do_jump (s, this->break_label_);
+  }
+
+  /* Jump to the associated continue label for the current loop.  If IDENT
+     for the Statement is not null, then the label is user defined.  */
+
+  void visit (ContinueStatement *s)
+  {
+    if (s->ident)
+      {
+	LabelStatement *label = this->func_->searchLabel (s->ident)->statement;
+	gcc_assert (label != NULL);
+	this->do_jump (s, this->lookup_bc_label (label->statement,
+						 bc_continue));
+      }
+    else
+      this->do_jump (s, this->continue_label_);
+  }
+
+  /* A goto statement jumps to the statement identified by the given label.  */
+
+  void visit (GotoStatement *s)
+  {
+    gcc_assert (s->label->statement != NULL);
+    gcc_assert (s->tf == s->label->statement->tf);
+
+    /* This makes the 'undefined label' error show up on the correct line.
+       The extra get_linemap in do_jump shouldn't cause a problem.  */
+    input_location = get_linemap (s->loc);
+
+    /* If no label found, there was an error.  */
+    tree label = this->lookup_label (s->label->statement, s->label->ident);
+    this->do_jump (s, label);
+
+    /* Need to error if the goto is jumping into a try or catch block.  */
+    this->check_goto (s, s->label->statement);
+  }
+
+  /* Statements can be labeled.  A label is an identifier that precedes
+     a statement.  */
+
+  void visit (LabelStatement *s)
+  {
+    LabelDsymbol *sym;
+
+    if (this->is_return_label (s->ident))
+      sym = this->func_->returnLabel;
+    else
+      sym = this->func_->searchLabel (s->ident);
+
+    input_location = get_linemap (s->loc);
+
+    /* If no label found, there was an error.  */
+    tree label = this->define_label (sym->statement, sym->ident);
+    TREE_USED (label) = 1;
+
+    this->do_label (label);
+
+    if (this->is_return_label (s->ident) && this->func_->fensure != NULL)
+      this->func_->fensure->accept (this);
+    else if (s->statement)
+      s->statement->accept (this);
+  }
+
+  /* A switch statement goes to one of a collection of case statements
+     depending on the value of the switch expression.  */
+
+  void visit (SwitchStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    this->start_scope (level_switch);
+    tree lbreak = this->push_break_label (s);
+
+    tree condition = build_expr_dtor (s->condition);
+    Type *condtype = s->condition->type->toBasetype ();
+
+    /* A switch statement on a string gets turned into a library call,
+       which does a binary lookup on list of string cases.  */
+    if (s->condition->type->isString ())
+      {
+	Type *etype = condtype->nextOf ()->toBasetype ();
+	libcall_fn libcall;
+
+	switch (etype->ty)
+	  {
+	  case Tchar:
+	    libcall = LIBCALL_SWITCH_STRING;
+	    break;
+
+	  case Twchar:
+	    libcall = LIBCALL_SWITCH_USTRING;
+	    break;
+
+	  case Tdchar:
+	    libcall = LIBCALL_SWITCH_DSTRING;
+	    break;
+
+	  default:
+	    ::error ("switch statement value must be an array of "
+		     "some character type, not %s", etype->toChars ());
+	    gcc_unreachable ();
+	  }
+
+	/* Apparently the backend is supposed to sort and set the indexes
+	   on the case array, have to change them to be usable.  */
+	Type *satype = condtype->sarrayOf (s->cases->dim);
+	vec<constructor_elt, va_gc> *elms = NULL;
+
+	s->cases->sort ();
+
+	for (size_t i = 0; i < s->cases->dim; i++)
+	  {
+	    CaseStatement *cs = (*s->cases)[i];
+	    cs->index = i;
+
+	    if (cs->exp->op != TOKstring)
+	      s->error ("case '%s' is not a string", cs->exp->toChars ());
+	    else
+	      {
+		tree exp = build_expr (cs->exp, true);
+		CONSTRUCTOR_APPEND_ELT (elms, size_int (i), exp);
+	      }
+	  }
+
+	/* Build static declaration to reference constructor.  */
+	tree ctor = build_constructor (build_ctype (satype), elms);
+	tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
+	TREE_READONLY (decl) = 1;
+	d_pushdecl (decl);
+	rest_of_decl_compilation (decl, 1, 0);
+
+	/* Pass it as a dynamic array.  */
+	decl = d_array_value (build_ctype (condtype->arrayOf ()),
+			      size_int (s->cases->dim),
+			      build_address (decl));
+
+	condition = build_libcall (libcall, Type::tint32, 2, decl, condition);
+      }
+    else if (!condtype->isscalar ())
+      {
+	::error ("cannot handle switch condition of type %s",
+		 condtype->toChars ());
+	gcc_unreachable ();
+      }
+
+    condition = fold (condition);
+
+    /* Build LABEL_DECLs now so they can be refered to by goto case.
+       Also checking the jump from the switch to the label is allowed.  */
+    if (s->cases)
+      {
+	for (size_t i = 0; i < s->cases->dim; i++)
+	  {
+	    CaseStatement *cs = (*s->cases)[i];
+	    tree caselabel = this->lookup_label (cs);
+
+	    /* Write cases as a series of if-then-else blocks.
+	       if (condition == case)
+		 goto caselabel;  */
+	    if (s->hasVars)
+	      {
+		tree ifcase = build2 (EQ_EXPR, build_ctype (condtype),
+				      condition, build_expr_dtor (cs->exp));
+		tree ifbody = fold_build1 (GOTO_EXPR, void_type_node,
+					   caselabel);
+		tree cond = build_vcondition (ifcase, ifbody, void_node);
+		TREE_USED (caselabel) = 1;
+		LABEL_VARIABLE_CASE (caselabel) = 1;
+		add_stmt (cond);
+	      }
+
+	    this->check_goto (s, cs);
+	  }
+
+	if (s->sdefault)
+	  {
+	    tree defaultlabel = this->lookup_label (s->sdefault);
+
+	    /* The default label is the last 'else' block.  */
+	    if (s->hasVars)
+	      {
+		this->do_jump (NULL, defaultlabel);
+		LABEL_VARIABLE_CASE (defaultlabel) = 1;
+	      }
+
+	    this->check_goto (s, s->sdefault);
+	  }
+      }
+
+    /* Switch body goes in its own statement list.  */
+    push_stmt_list ();
+    if (s->_body)
+      s->_body->accept (this);
+
+    tree casebody = pop_stmt_list ();
+
+    /* Wrap up constructed body into a switch_expr, unless it was
+       converted to an if-then-else expression.  */
+    if (s->hasVars)
+      add_stmt (casebody);
+    else
+      {
+	tree switchexpr = build3 (SWITCH_EXPR, TREE_TYPE (condition),
+				  condition, casebody, NULL_TREE);
+	add_stmt (switchexpr);
+      }
+
+    /* If the switch had any 'break' statements, emit the label now.  */
+    this->pop_break_label (lbreak);
+    this->finish_scope ();
+  }
+
+  /* Declare the case label associated with the current SwitchStatement.  */
+
+  void visit (CaseStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+
+    /* Emit the case label.  */
+    tree label = this->define_label (s);
+
+    if (LABEL_VARIABLE_CASE (label))
+      this->do_label (label);
+    else
+      {
+	tree casevalue;
+	if (s->exp->type->isscalar ())
+	  casevalue = build_expr (s->exp);
+	else
+	  casevalue = build_integer_cst (s->index, build_ctype (Type::tint32));
+
+	tree caselabel = build_case_label (casevalue, NULL_TREE, label);
+	add_stmt (caselabel);
+      }
+
+    /* Now do the body.  */
+    if (s->statement)
+      s->statement->accept (this);
+  }
+
+  /* Declare the default label associated with the current SwitchStatement.  */
+
+  void visit (DefaultStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+
+    /* Emit the default case label.  */
+    tree label = this->define_label (s);
+
+    if (LABEL_VARIABLE_CASE (label))
+      this->do_label (label);
+    else
+      {
+	tree caselabel = build_case_label (NULL_TREE, NULL_TREE, label);
+	add_stmt (caselabel);
+      }
+
+    /* Now do the body.  */
+    if (s->statement)
+      s->statement->accept (this);
+  }
+
+  /* Implements 'goto default' by jumping to the label associated with
+     the DefaultStatement in a switch block.  */
+
+  void visit (GotoDefaultStatement *s)
+  {
+    tree label = this->lookup_label (s->sw->sdefault);
+    this->do_jump (s, label);
+  }
+
+  /* Implements 'goto case' by jumping to the label associated with the
+     CaseStatement in a switch block.  */
+
+  void visit (GotoCaseStatement *s)
+  {
+    tree label = this->lookup_label (s->cs);
+    this->do_jump (s, label);
+  }
+
+  /* Throw a SwitchError exception, called when a switch statement has
+     no DefaultStatement, yet none of the cases match.  */
+
+  void visit (SwitchErrorStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    add_stmt (d_assert_call (s->loc, LIBCALL_SWITCH_ERROR));
+  }
+
+  /* A return statement exits the current function and supplies its return
+     value, if the return type is not void.  */
+
+  void visit (ReturnStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+
+    if (s->exp == NULL || s->exp->type->toBasetype ()->ty == Tvoid)
+      {
+	/* Return has no value.  */
+	add_stmt (return_expr (NULL_TREE));
+	return;
+      }
+
+    TypeFunction *tf = (TypeFunction *)this->func_->type;
+    Type *type = this->func_->tintro != NULL
+      ? this->func_->tintro->nextOf () : tf->nextOf ();
+
+    if (this->func_->isMain () && type->toBasetype ()->ty == Tvoid)
+      type = Type::tint32;
+
+    if (this->func_->nrvo_can && this->func_->nrvo_var)
+      {
+	/* Just refer to the DECL_RESULT; this differs from using
+	   NULL_TREE in that it indicates that we care about the value
+	   of the DECL_RESULT.  */
+	tree decl = DECL_RESULT (get_symbol_decl (this->func_));
+	add_stmt (return_expr (decl));
+      }
+    else
+      {
+	/* Convert for initialising the DECL_RESULT.  */
+	tree expr = build_return_dtor (s->exp, type, tf);
+	add_stmt (expr);
+      }
+  }
+
+  /* Evaluate the enclosed expression, and add it to the statement list.  */
+
+  void visit (ExpStatement *s)
+  {
+    if (s->exp)
+      {
+	input_location = get_linemap (s->loc);
+	/* Expression may produce temporaries requiring scope destruction.  */
+	tree exp = build_expr_dtor (s->exp);
+	add_stmt (exp);
+      }
+  }
+
+  /* Evaluate all enclosed statements.  */
+
+  void visit (CompoundStatement *s)
+  {
+    if (s->statements == NULL)
+      return;
+
+    for (size_t i = 0; i < s->statements->dim; i++)
+      {
+	Statement *statement = (*s->statements)[i];
+
+	if (statement != NULL)
+	  statement->accept (this);
+      }
+  }
+
+  /* The frontend lowers `foreach (Tuple!(...))' statements as an unrolled loop.
+     These are compiled down as a `do ... while (0)', where each unrolled loop
+     is nested inside and given their own continue label to jump to.  */
+
+  void visit (UnrolledLoopStatement *s)
+  {
+    if (s->statements == NULL)
+      return;
+
+    tree lbreak = this->push_break_label (s);
+    this->start_scope (level_loop);
+
+    for (size_t i = 0; i < s->statements->dim; i++)
+      {
+	Statement *statement = (*s->statements)[i];
+
+	if (statement != NULL)
+	  {
+	    tree lcontinue = this->push_continue_label (statement);
+	    statement->accept (this);
+	    this->pop_continue_label (lcontinue);
+	  }
+      }
+
+    this->do_jump (NULL, this->break_label_);
+
+    tree body = this->end_scope ();
+    input_location = get_linemap (s->loc);
+    add_stmt (build1 (LOOP_EXPR, void_type_node, body));
+
+    this->pop_break_label (lbreak);
+  }
+
+  /* Start a new scope and visit all nested statements, wrapping
+     them up into a BIND_EXPR at the end of the scope.  */
+
+  void visit (ScopeStatement *s)
+  {
+    if (s->statement == NULL)
+      return;
+
+    this->start_scope (level_block);
+    s->statement->accept (this);
+    this->finish_scope ();
+  }
+
+  /* A with statement is a way to simplify repeated references to the same
+     object, where the handle is either a class or struct instance.  */
+
+  void visit (WithStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    this->start_scope (level_with);
+
+    if (s->wthis)
+      {
+	/* Perform initialisation of the 'with' handle.  */
+	ExpInitializer *ie = s->wthis->_init->isExpInitializer ();
+	gcc_assert (ie != NULL);
+
+	declare_local_var (s->wthis);
+	tree init = build_expr_dtor (ie->exp);
+	add_stmt (init);
+      }
+
+    if (s->_body)
+      s->_body->accept (this);
+
+    this->finish_scope ();
+  }
+
+  /* Implements 'throw Object'.  Frontend already checks that the object
+     thrown is a class type, but does not check if it is derived from
+     Object.  Foreign objects are not currently supported in runtime.  */
+
+  void visit (ThrowStatement *s)
+  {
+    ClassDeclaration *cd = s->exp->type->toBasetype ()->isClassHandle ();
+    InterfaceDeclaration *id = cd->isInterfaceDeclaration ();
+    tree arg = build_expr_dtor (s->exp);
+
+    if (!flag_exceptions)
+      {
+	static int warned = 0;
+	if (!warned)
+	  {
+	    s->error ("exception handling disabled, "
+		      "use -fexceptions to enable");
+	    warned = 1;
+	  }
+      }
+
+    if (cd->cpp || (id != NULL && id->cpp))
+      s->error ("cannot throw C++ classes");
+    else if (cd->com || (id != NULL && id->com))
+      s->error ("cannot throw COM objects");
+    else
+      arg = build_nop (build_ctype (get_object_type ()), arg);
+
+    input_location = get_linemap (s->loc);
+    add_stmt (build_libcall (LIBCALL_THROW, Type::tvoid, 1, arg));
+  }
+
+  /* Build a try-catch statement, one of the building blocks for exception
+     handling generated by the frontend.  This is also used to implement
+     `scope (failure)' statements.  */
+
+  void visit (TryCatchStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+
+    this->start_scope (level_try);
+    if (s->_body)
+      s->_body->accept (this);
+
+    tree trybody = this->end_scope ();
+
+    /* Try handlers go in their own statement list.  */
+    push_stmt_list ();
+
+    if (s->catches)
+      {
+	for (size_t i = 0; i < s->catches->dim; i++)
+	  {
+	    Catch *vcatch = (*s->catches)[i];
+
+	    input_location = get_linemap (vcatch->loc);
+	    this->start_scope (level_catch);
+
+	    tree ehptr = builtin_decl_explicit (BUILT_IN_EH_POINTER);
+	    tree catchtype = build_ctype (vcatch->type);
+	    tree object = NULL_TREE;
+
+	    ehptr = build_call_expr (ehptr, 1, integer_zero_node);
+
+	    /* Retrieve the internal exception object, which could be for a
+	       D or C++ catch handler.  This is different from the generic
+	       exception pointer returned from gcc runtime.  */
+	    Type *tcatch = vcatch->type->toBasetype ();
+	    ClassDeclaration *cd = tcatch->isClassHandle ();
+
+	    libcall_fn libcall = (cd->cpp) ? LIBCALL_CXA_BEGIN_CATCH
+	      : LIBCALL_BEGIN_CATCH;
+	    object = build_libcall (libcall, vcatch->type, 1, ehptr);
+
+	    if (vcatch->var)
+	      {
+		tree var = get_symbol_decl (vcatch->var);
+		tree init = build_assign (INIT_EXPR, var, object);
+
+		declare_local_var (vcatch->var);
+		add_stmt (init);
+	      }
+	    else
+	      {
+		/* Still need to emit a call to __gdc_begin_catch() to
+		   remove the object from the uncaught exceptions list.  */
+		add_stmt (object);
+	      }
+
+	    if (vcatch->handler)
+	      vcatch->handler->accept (this);
+
+	    tree catchbody = this->end_scope ();
+
+	    /* Need to wrap C++ handlers in a try/finally block to signal
+	       the end catch callback.  */
+	    if (cd->cpp)
+	      {
+		tree endcatch = build_libcall (LIBCALL_CXA_END_CATCH,
+					       Type::tvoid, 0);
+		catchbody = build2 (TRY_FINALLY_EXPR, void_type_node,
+				    catchbody, endcatch);
+	      }
+
+	    add_stmt (build2 (CATCH_EXPR, void_type_node,
+			      catchtype, catchbody));
+	  }
+      }
+
+    tree catches = pop_stmt_list ();
+
+    /* Backend expects all catches in a TRY_CATCH_EXPR to be enclosed in a
+       statement list, however pop_stmt_list may optimise away the list
+       if there is only a single catch to push.  */
+    if (TREE_CODE (catches) != STATEMENT_LIST)
+      {
+        tree stmt_list = alloc_stmt_list ();
+        append_to_statement_list_force (catches, &stmt_list);
+        catches = stmt_list;
+      }
+
+    input_location = get_linemap (s->loc);
+    add_stmt (build2 (TRY_CATCH_EXPR, void_type_node, trybody, catches));
+  }
+
+  /* Build a try-finally statement, one of the building blocks for exception
+     handling generated by the frontend.  This is also used to implement
+     `scope (exit)' statements.  */
+
+  void visit (TryFinallyStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    this->start_scope (level_try);
+    if (s->_body)
+      s->_body->accept (this);
+
+    tree trybody = this->end_scope ();
+
+    this->start_scope (level_finally);
+    if (s->finalbody)
+      s->finalbody->accept (this);
+
+    tree finally = this->end_scope ();
+
+    input_location = get_linemap (s->loc);
+    add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, trybody, finally));
+  }
+
+  /* The frontend lowers `synchronized (...)' statements as a call to
+     monitor/critical enter and exit wrapped around try/finally.
+     This visitor is not strictly required other than to enforce that
+     these kinds of statements never reach here.  */
+
+  void visit (SynchronizedStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    gcc_unreachable ();
+  }
+
+  /* D Inline Assembler is not implemented, as would require a writing
+     an assembly parser for each supported target.  Instead we leverage
+     GCC extended assembler using the ExtAsmStatement class.  */
+
+  void visit (AsmStatement *s)
+  {
+    input_location = get_linemap (s->loc);
+    sorry ("D inline assembler statements are not supported in GDC.");
+  }
+
+  /* Build a GCC extended assembler expression, whose components are
+     an INSN string, some OUTPUTS, some INPUTS, and some CLOBBERS.  */
+
+  void visit (ExtAsmStatement *s)
+  {
+    StringExp *insn = (StringExp *)s->insn;
+    tree outputs = NULL_TREE;
+    tree inputs = NULL_TREE;
+    tree clobbers = NULL_TREE;
+    tree labels = NULL_TREE;
+
+    input_location = get_linemap (s->loc);
+
+    /* Collect all arguments, which may be input or output operands.  */
+    if (s->args)
+      {
+	for (size_t i = 0; i < s->args->dim; i++)
+	  {
+	    Identifier *name = (*s->names)[i];
+	    StringExp *constr = (StringExp *)(*s->constraints)[i];
+	    Expression *arg = (*s->args)[i];
+
+	    const char *sname = name ? name->toChars () : NULL;
+	    tree id = name ? build_string (strlen (sname), sname) : NULL_TREE;
+	    tree str = build_string (constr->len, (char *)constr->string);
+	    tree val = build_expr (arg);
+
+	    if (i < s->outputargs)
+	      {
+		tree arg = build_tree_list (id, str);
+		outputs = chainon (outputs, build_tree_list (arg, val));
+	      }
+	    else
+	      {
+		tree arg = build_tree_list (id, str);
+		inputs = chainon (inputs, build_tree_list (arg, val));
+	      }
+	  }
+      }
+
+    /* Collect all clobber arguments.  */
+    if (s->clobbers)
+      {
+	for (size_t i = 0; i < s->clobbers->dim; i++)
+	  {
+	    StringExp *clobber = (StringExp *)(*s->clobbers)[i];
+	    tree val = build_string (clobber->len, (char *)clobber->string);
+	    clobbers = chainon (clobbers, build_tree_list (0, val));
+	  }
+      }
+
+    /* Collect all goto labels, these should have been already checked
+       by the front-end, so pass down the label symbol to the backend.  */
+    if (s->labels)
+      {
+	for (size_t i = 0; i < s->labels->dim; i++)
+	  {
+	    Identifier *ident = (*s->labels)[i];
+	    GotoStatement *gs = (*s->gotos)[i];
+
+	    gcc_assert (gs->label->statement != NULL);
+	    gcc_assert (gs->tf == gs->label->statement->tf);
+
+	    const char *sident = ident->toChars ();
+	    tree name = build_string (strlen (sident), sident);
+	    tree label = this->lookup_label (gs->label->statement,
+					     gs->label->ident);
+	    TREE_USED (label) = 1;
+
+	    labels = chainon (labels, build_tree_list (name, label));
+	  }
+      }
+
+    /* Do some extra validation on all input and output operands.  */
+    tree string = build_string (insn->len, (char *)insn->string);
+    string = resolve_asm_operand_names (string, outputs, inputs, labels);
+
+    if (s->args)
+      {
+	unsigned noutputs = s->outputargs;
+	unsigned ninputs = (s->args->dim - noutputs);
+	const char **oconstraints = XALLOCAVEC (const char *, noutputs);
+	bool allows_mem, allows_reg, is_inout;
+	size_t i;
+	tree t;
+
+	for (i = 0, t = outputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
+	  {
+	    tree output = TREE_VALUE (t);
+	    const char *constraint
+	      = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+
+	    oconstraints[i] = constraint;
+
+	    if (parse_output_constraint (&constraint, i, ninputs, noutputs,
+					 &allows_mem, &allows_reg, &is_inout))
+	      {
+		/* If the output argument is going to end up in memory.  */
+		if (!allows_reg)
+		  d_mark_addressable (output);
+	      }
+	    else
+	      output = error_mark_node;
+
+	    TREE_VALUE (t) = output;
+	  }
+
+	for (i = 0, t = inputs; t != NULL_TREE; t = TREE_CHAIN (t), i++)
+	  {
+	    tree input = TREE_VALUE (t);
+	    const char *constraint
+	      = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (t)));
+
+	    if (parse_input_constraint (&constraint, i, ninputs, noutputs, 0,
+					oconstraints, &allows_mem, &allows_reg))
+	      {
+		/* If the input argument is going to end up in memory.  */
+		if (!allows_reg && allows_mem)
+		  d_mark_addressable (input);
+	      }
+	    else
+	      input = error_mark_node;
+
+	    TREE_VALUE (t) = input;
+	  }
+      }
+
+    tree exp = build5 (ASM_EXPR, void_type_node, string,
+		       outputs, inputs, clobbers, labels);
+    SET_EXPR_LOCATION (exp, input_location);
+
+    /* If the extended syntax was not used, mark the ASM_EXPR.  */
+    if (s->args == NULL && s->clobbers == NULL)
+      ASM_INPUT_P (exp) = 1;
+
+    /* Asm statements without outputs are treated as volatile.  */
+    ASM_VOLATILE_P (exp) = (s->outputargs == 0);
+
+    add_stmt (exp);
+  }
+
+  /* Import symbols from another module.  */
+
+  void visit (ImportStatement *s)
+  {
+    if (s->imports == NULL)
+      return;
+
+    for (size_t i = 0; i < s->imports->dim; i++)
+      {
+	Dsymbol *dsym = (*s->imports)[i];
+
+	if (dsym != NULL)
+	  build_decl_tree (dsym);
+      }
+  }
+};
+
+/* Main entry point for the IRVisitor interface to generate
+   code for the statement AST class S.  */
+
+void
+build_function_body (FuncDeclaration *fd)
+{
+  IRVisitor v = IRVisitor (fd);
+  fd->fbody->accept (&v);
+}
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
new file mode 100644
index 00000000000..5b477ffb761
--- /dev/null
+++ b/gcc/d/typeinfo.cc
@@ -0,0 +1,1647 @@
+/* typeinfo.cc -- D runtime type identification.
+   Copyright (C) 2013-2017 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 "dfrontend/aggregate.h"
+#include "dfrontend/enum.h"
+#include "dfrontend/module.h"
+#include "dfrontend/mtype.h"
+#include "dfrontend/template.h"
+#include "dfrontend/target.h"
+
+#include "tree.h"
+#include "fold-const.h"
+#include "diagnostic.h"
+#include "stringpool.h"
+#include "toplev.h"
+#include "stor-layout.h"
+
+#include "d-tree.h"
+#include "d-frontend.h"
+#include "id.h"
+
+
+/* D returns type information to the user as TypeInfo class objects, and can
+   be retrieved for any type using `typeid()'.  We also use type information
+   to implement many runtime library helpers, including `new', `delete', most
+   dynamic array operations, and all associative array operations.
+
+   Type information for a particular type is indicated with an ABI defined
+   structure derived from TypeInfo.  This would all be very straight forward,
+   but for the fact that the runtime library provides the definitions of the
+   TypeInfo structure and the ABI defined derived classes in `object.d', as
+   well as having specific implementations of TypeInfo for built-in types
+   in `rt/typeinfo`.  We cannot build declarations of these directly in the
+   compiler, but we need to layout objects of their type.
+
+   To get around this, we define layout compatible POD-structs and generate the
+   appropriate initializations for them.  When we have to provide a TypeInfo to
+   the user, we cast the internal compiler type to TypeInfo.
+
+   It is only required that TypeInfo has a definition in `object.d'.  It could
+   happen that we are generating a type information for a TypeInfo object that
+   has no declaration.  We however only need the addresses of such incomplete
+   TypeInfo objects for static initialization.  */
+
+enum tinfo_kind
+{
+  TK_TYPEINFO_TYPE,		/* object.TypeInfo  */
+  TK_CLASSINFO_TYPE,		/* object.TypeInfo_Class  */
+  TK_INTERFACE_TYPE,		/* object.TypeInfo_Interface  */
+  TK_STRUCT_TYPE,		/* object.TypeInfo_Struct  */
+  TK_POINTER_TYPE,		/* object.TypeInfo_Pointer  */
+  TK_ARRAY_TYPE,		/* object.TypeInfo_Array  */
+  TK_STATICARRAY_TYPE,		/* object.TypeInfo_StaticArray  */
+  TK_ASSOCIATIVEARRAY_TYPE,	/* object.TypeInfo_AssociativeArray  */
+  TK_VECTOR_TYPE,		/* object.TypeInfo_Vector  */
+  TK_ENUMERAL_TYPE,		/* object.TypeInfo_Enum  */
+  TK_FUNCTION_TYPE,		/* object.TypeInfo_Function  */
+  TK_DELEGATE_TYPE,		/* object.TypeInfo_Delegate  */
+  TK_TYPELIST_TYPE,		/* object.TypeInfo_Tuple  */
+  TK_CONST_TYPE,		/* object.TypeInfo_Const  */
+  TK_IMMUTABLE_TYPE,		/* object.TypeInfo_Invariant  */
+  TK_SHARED_TYPE,		/* object.TypeInfo_Shared  */
+  TK_INOUT_TYPE,		/* object.TypeInfo_Inout  */
+  TK_CPPTI_TYPE,		/* object.__cpp_type_info_ptr  */
+  TK_END,
+};
+
+/* An array of all internal TypeInfo derived types we need.
+   The TypeInfo and ClassInfo types are created early, the
+   remainder are generated as needed.  */
+
+static GTY(()) tree tinfo_types[TK_END];
+
+/* Return the kind of TypeInfo used to describe TYPE.  */
+
+static tinfo_kind
+get_typeinfo_kind (Type *type)
+{
+  /* Check head shared/const modifiers first.  */
+  if (type->isShared ())
+    return TK_SHARED_TYPE;
+  else if (type->isConst ())
+    return TK_CONST_TYPE;
+  else if (type->isImmutable ())
+    return TK_IMMUTABLE_TYPE;
+  else if (type->isWild ())
+    return TK_INOUT_TYPE;
+
+  switch (type->ty)
+    {
+    case Tpointer:
+      return TK_POINTER_TYPE;
+
+    case  Tarray:
+      return TK_ARRAY_TYPE;
+
+    case Tsarray:
+      return TK_STATICARRAY_TYPE;
+
+    case Taarray:
+      return TK_ASSOCIATIVEARRAY_TYPE;
+
+    case Tstruct:
+      return TK_STRUCT_TYPE;
+
+    case Tvector:
+      return TK_VECTOR_TYPE;
+
+    case Tenum:
+      return TK_ENUMERAL_TYPE;
+
+    case Tfunction:
+      return TK_FUNCTION_TYPE;
+
+    case Tdelegate:
+      return TK_DELEGATE_TYPE;
+
+    case Ttuple:
+      return TK_TYPELIST_TYPE;
+
+    case Tclass:
+      if (((TypeClass *) type)->sym->isInterfaceDeclaration ())
+	return TK_INTERFACE_TYPE;
+      else
+	return TK_CLASSINFO_TYPE;
+
+    default:
+      return TK_TYPEINFO_TYPE;
+    }
+}
+
+/* Generate the RECORD_TYPE containing the data layout of a TypeInfo derivative
+   as used by the runtime.  This layout must be consistent with that defined in
+   the `object.d' module.  */
+
+static void
+make_internal_typeinfo (tinfo_kind tk, Identifier *ident, ...)
+{
+  va_list ap;
+
+  va_start (ap, ident);
+
+  /* First two fields are from the TypeInfo base class.
+     Note, finish_builtin_struct() expects these fields in reverse order.  */
+  tree fields = create_field_decl (ptr_type_node, NULL, 1, 1);
+  DECL_CHAIN (fields) = create_field_decl (vtbl_ptr_type_node, NULL, 1, 1);
+
+  /* Now add the derived fields.  */
+  tree field_type = va_arg (ap, tree);
+  while (field_type != NULL_TREE)
+    {
+      tree field = create_field_decl (field_type, NULL, 1, 1);
+      DECL_CHAIN (field) = fields;
+      fields = field;
+      field_type = va_arg (ap, tree);
+    }
+
+  /* Create the TypeInfo type.  */
+  tree type = make_node (RECORD_TYPE);
+  finish_builtin_struct (type, ident->toChars (), fields, NULL_TREE);
+
+  tinfo_types[tk] = type;
+
+  va_end (ap);
+}
+
+/* Helper for create_tinfo_types.  Creates a typeinfo class declaration
+   incase one wasn't supplied by reading `object.d'.  */
+
+static void
+make_frontend_typeinfo (Module *mod, Identifier *ident,
+			ClassDeclaration *base = NULL)
+{
+  if (!base)
+    base = Type::dtypeinfo;
+
+  gcc_assert (mod->md != NULL);
+
+  /* Create object module in order to complete the semantic.  */
+  if (!mod->_scope)
+    mod->importAll (NULL);
+
+  /* Assignment of global typeinfo variables is managed by the ClassDeclaration
+     constructor, so only need to new the declaration here.  */
+  ClassDeclaration *tinfo = new ClassDeclaration (mod->md->loc, ident,
+						  NULL, true);
+  tinfo->parent = mod;
+  tinfo->semantic (mod->_scope);
+  tinfo->baseClass = base;
+}
+
+/* Make sure the required builtin types exist for generating the TypeInfo
+   variable definitions.  */
+
+void
+create_tinfo_types (Module *mod)
+{
+  /* Build the internal TypeInfo and ClassInfo types.
+     See TypeInfoVisitor for documentation of field layout.  */
+  make_internal_typeinfo (TK_TYPEINFO_TYPE, Id::TypeInfo, NULL);
+
+  make_internal_typeinfo (TK_CLASSINFO_TYPE, Id::TypeInfo_Class,
+			  array_type_node, array_type_node, array_type_node,
+			  array_type_node, ptr_type_node, ptr_type_node,
+			  ptr_type_node, uint_type_node, ptr_type_node,
+			  array_type_node, ptr_type_node, ptr_type_node, NULL);
+
+  /* Create all frontend TypeInfo classes declarations.  We rely on all
+     existing, even if only just as stubs.  */
+  if (!Type::dtypeinfo)
+    make_frontend_typeinfo (mod, Id::TypeInfo, ClassDeclaration::object);
+
+  if (!Type::typeinfoclass)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Class);
+
+  if (!Type::typeinfointerface)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Interface);
+
+  if (!Type::typeinfostruct)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Struct);
+
+  if (!Type::typeinfopointer)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Pointer);
+
+  if (!Type::typeinfoarray)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Array);
+
+  if (!Type::typeinfostaticarray)
+    make_frontend_typeinfo (mod, Id::TypeInfo_StaticArray);
+
+  if (!Type::typeinfoassociativearray)
+    make_frontend_typeinfo (mod, Id::TypeInfo_AssociativeArray);
+
+  if (!Type::typeinfoenum)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Enum);
+
+  if (!Type::typeinfofunction)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Function);
+
+  if (!Type::typeinfodelegate)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Delegate);
+
+  if (!Type::typeinfotypelist)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Tuple);
+
+  if (!Type::typeinfoconst)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Const);
+
+  if (!Type::typeinfoinvariant)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Invariant, Type::typeinfoconst);
+
+  if (!Type::typeinfoshared)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Shared, Type::typeinfoconst);
+
+  if (!Type::typeinfowild)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Wild, Type::typeinfoconst);
+
+  if (!Type::typeinfovector)
+    make_frontend_typeinfo (mod, Id::TypeInfo_Vector);
+
+  if (!ClassDeclaration::cpp_type_info_ptr)
+    make_frontend_typeinfo (mod, Id::cpp_type_info_ptr,
+			    ClassDeclaration::object);
+}
+
+/* Implements the visitor interface to build the TypeInfo layout of all
+   TypeInfoDeclaration AST classes emitted from the D Front-end.
+   All visit methods accept one parameter D, which holds the frontend AST
+   of the TypeInfo class.  They also don't return any value, instead the
+   generated symbol is cached internally and returned from the caller.  */
+
+class TypeInfoVisitor : public Visitor
+{
+  tree type_;
+  vec<constructor_elt, va_gc> *init_;
+
+  /* Add VALUE to the constructor values list.  */
+
+  void layout_field (tree value)
+  {
+    CONSTRUCTOR_APPEND_ELT (this->init_, NULL_TREE, value);
+  }
+
+  /* Write out the __vptr and __monitor fields of class CD.  */
+
+  void layout_base (ClassDeclaration *cd)
+  {
+    gcc_assert (cd != NULL);
+    this->layout_field (build_address (get_vtable_decl (cd)));
+    this->layout_field (null_pointer_node);
+  }
+
+  /* Write out the interfaces field of class CD.
+     Returns the array of interfaces that the field is pointing to.  */
+
+  tree layout_interfaces (ClassDeclaration *cd)
+  {
+    size_t offset = int_size_in_bytes (tinfo_types[TK_CLASSINFO_TYPE]);
+    tree csym = build_address (get_classinfo_decl (cd));
+
+    /* Put out the offset to where vtblInterfaces are written.  */
+    tree value = d_array_value (array_type_node,
+				size_int (cd->vtblInterfaces->dim),
+				build_offset (csym, size_int (offset)));
+    this->layout_field (value);
+
+    /* Internally, the compiler sees Interface as:
+	void*[4] interface;
+
+       The runtime layout of Interface is:
+	TypeInfo_Class classinfo;
+	void*[] vtbl;
+	size_t offset;  */
+    vec<constructor_elt, va_gc> *elms = NULL;
+
+    for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
+      {
+	BaseClass *b = (*cd->vtblInterfaces)[i];
+	ClassDeclaration *id = b->sym;
+	vec<constructor_elt, va_gc> *v = NULL;
+
+	/* Fill in the vtbl[].  */
+	b->fillVtbl (cd, &b->vtbl, 1);
+
+	/* ClassInfo for the interface.  */
+	value = build_address (get_classinfo_decl (id));
+	CONSTRUCTOR_APPEND_ELT (v, size_int (0), value);
+
+	if (!cd->isInterfaceDeclaration ())
+	  {
+	    /* The vtable of the interface length and ptr.  */
+	    size_t voffset = base_vtable_offset (cd, b);
+	    value = build_offset (csym, size_int (voffset));
+
+	    CONSTRUCTOR_APPEND_ELT (v, size_int (1), size_int (id->vtbl.dim));
+	    CONSTRUCTOR_APPEND_ELT (v, size_int (2), value);
+	  }
+
+	/* The 'this' offset.  */
+	CONSTRUCTOR_APPEND_ELT (v, size_int (3), size_int (b->offset));
+
+	/* Add to the array of interfaces.  */
+	value = build_constructor (vtbl_interface_type_node, v);
+	CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+      }
+
+    tree domain = size_int (cd->vtblInterfaces->dim - 1);
+    tree arrtype = build_array_type (vtbl_interface_type_node,
+				     build_index_type (domain));
+    return build_constructor (arrtype, elms);
+  }
+
+  /* Write out the interfacing vtable[] of base class BCD that will be accessed
+     from the overriding class CD.  If both are the same class, then this will
+     be it's own vtable.  INDEX is the offset in the interfaces array of the
+     base class where the Interface reference can be found.
+     This must be mirrored with base_vtable_offset().  */
+
+  void layout_base_vtable (ClassDeclaration *cd, ClassDeclaration *bcd,
+			   size_t index)
+  {
+    BaseClass *bs = (*bcd->vtblInterfaces)[index];
+    ClassDeclaration *id = bs->sym;
+    vec<constructor_elt, va_gc> *elms = NULL;
+    FuncDeclarations bvtbl;
+
+    if (id->vtbl.dim == 0 || base_vtable_offset (cd, bs) == ~0u)
+      return;
+
+    /* Fill bvtbl with the functions we want to put out.  */
+    if (cd != bcd && !bs->fillVtbl (cd, &bvtbl, 0))
+      return;
+
+    /* First entry is struct Interface reference.  */
+    if (id->vtblOffset ())
+      {
+	size_t offset = int_size_in_bytes (tinfo_types[TK_CLASSINFO_TYPE]);
+	offset += (index * int_size_in_bytes (vtbl_interface_type_node));
+	tree value = build_offset (build_address (get_classinfo_decl (bcd)),
+				   size_int (offset));
+	CONSTRUCTOR_APPEND_ELT (elms, size_zero_node, value);
+      }
+
+    for (size_t i = id->vtblOffset () ? 1 : 0; i < id->vtbl.dim; i++)
+      {
+	FuncDeclaration *fd = (cd == bcd) ? bs->vtbl[i] : bvtbl[i];
+	if (fd != NULL)
+	  {
+	    tree value = build_address (make_thunk (fd, bs->offset));
+	    CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
+	  }
+      }
+
+    tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1));
+    tree vtbltype = build_array_type (vtable_entry_type, vtbldomain);
+    tree value = build_constructor (vtbltype, elms);
+    this->layout_field (value);
+  }
+
+
+public:
+  TypeInfoVisitor (tree type)
+  {
+    this->type_ = type;
+    this->init_ = NULL;
+  }
+
+  /* Return the completed constructor for the TypeInfo record.  */
+
+  tree result (void)
+  {
+    return build_struct_literal (this->type_, this->init_);
+  }
+
+  /* Layout of TypeInfo is:
+	void **__vptr;
+	void *__monitor;  */
+
+  void visit (TypeInfoDeclaration *)
+  {
+    /* The vtable for TypeInfo.  */
+    this->layout_base (Type::dtypeinfo);
+  }
+
+  /* Layout of TypeInfo_Const is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo base;  */
+
+  void visit (TypeInfoConstDeclaration *d)
+  {
+    Type *tm = d->tinfo->mutableOf ();
+    tm = tm->merge ();
+
+    /* The vtable for TypeInfo_Const.  */
+    this->layout_base (Type::typeinfoconst);
+
+    /* TypeInfo for the mutable type.  */
+    this->layout_field (build_typeinfo (tm));
+  }
+
+  /* Layout of TypeInfo_Immutable is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo base;  */
+
+  void visit (TypeInfoInvariantDeclaration *d)
+  {
+    Type *tm = d->tinfo->mutableOf ();
+    tm = tm->merge ();
+
+    /* The vtable for TypeInfo_Invariant.  */
+    this->layout_base (Type::typeinfoinvariant);
+
+    /* TypeInfo for the mutable type.  */
+    this->layout_field (build_typeinfo (tm));
+  }
+
+  /* Layout of TypeInfo_Shared is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo base;  */
+
+  void visit (TypeInfoSharedDeclaration *d)
+  {
+    Type *tm = d->tinfo->unSharedOf ();
+    tm = tm->merge ();
+
+    /* The vtable for TypeInfo_Shared.  */
+    this->layout_base (Type::typeinfoshared);
+
+    /* TypeInfo for the unshared type.  */
+    this->layout_field (build_typeinfo (tm));
+  }
+
+  /* Layout of TypeInfo_Inout is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo base;  */
+
+  void visit (TypeInfoWildDeclaration *d)
+  {
+    Type *tm = d->tinfo->mutableOf ();
+    tm = tm->merge ();
+
+    /* The vtable for TypeInfo_Inout.  */
+    this->layout_base (Type::typeinfowild);
+
+    /* TypeInfo for the mutable type.  */
+    this->layout_field (build_typeinfo (tm));
+  }
+
+  /* Layout of TypeInfo_Enum is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo base;
+	string name;
+	void[] m_init;  */
+
+  void visit (TypeInfoEnumDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tenum);
+    TypeEnum *ti = (TypeEnum *) d->tinfo;
+    EnumDeclaration *ed = ti->sym;
+
+    /* The vtable for TypeInfo_Enum.  */
+    this->layout_base (Type::typeinfoenum);
+
+    /* TypeInfo for enum members.  */
+    tree memtype = (ed->memtype) ? build_typeinfo (ed->memtype)
+      : null_pointer_node;
+    this->layout_field (memtype);
+
+    /* Name of the enum declaration.  */
+    this->layout_field (d_array_string (ed->toPrettyChars ()));
+
+    /* Default initializer for enum.  */
+    if (ed->members && !d->tinfo->isZeroInit ())
+      {
+	tree length = size_int (ed->type->size ());
+	tree ptr = build_address (enum_initializer_decl (ed));
+	this->layout_field (d_array_value (array_type_node, length, ptr));
+      }
+    else
+      this->layout_field (null_array_node);
+  }
+
+  /* Layout of TypeInfo_Pointer is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo m_next;  */
+
+  void visit (TypeInfoPointerDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tpointer);
+    TypePointer *ti = (TypePointer *) d->tinfo;
+
+    /* The vtable for TypeInfo_Pointer.  */
+    this->layout_base (Type::typeinfopointer);
+
+    /* TypeInfo for pointer-to type.  */
+    this->layout_field (build_typeinfo (ti->next));
+  }
+
+  /* Layout of TypeInfo_Array is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo value;  */
+
+  void visit (TypeInfoArrayDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tarray);
+    TypeDArray *ti = (TypeDArray *) d->tinfo;
+
+    /* The vtable for TypeInfo_Array.  */
+    this->layout_base (Type::typeinfoarray);
+
+    /* TypeInfo for array of type.  */
+    this->layout_field (build_typeinfo (ti->next));
+  }
+
+  /* Layout of TypeInfo_StaticArray is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo value;
+	size_t len;  */
+
+  void visit (TypeInfoStaticArrayDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tsarray);
+    TypeSArray *ti = (TypeSArray *) d->tinfo;
+
+    /* The vtable for TypeInfo_StaticArray.  */
+    this->layout_base (Type::typeinfostaticarray);
+
+    /* TypeInfo for array of type.  */
+    this->layout_field (build_typeinfo (ti->next));
+
+    /* Static array length.  */
+    this->layout_field (size_int (ti->dim->toInteger ()));
+  }
+
+  /* Layout of TypeInfo_AssociativeArray is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo value;
+	TypeInfo key;  */
+
+  void visit (TypeInfoAssociativeArrayDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Taarray);
+    TypeAArray *ti = (TypeAArray *) d->tinfo;
+
+    /* The vtable for TypeInfo_AssociativeArray.  */
+    this->layout_base (Type::typeinfoassociativearray);
+
+    /* TypeInfo for value of type.  */
+    this->layout_field (build_typeinfo (ti->next));
+
+    /* TypeInfo for index of type.  */
+    this->layout_field (build_typeinfo (ti->index));
+  }
+
+  /* Layout of TypeInfo_Vector is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo base;  */
+
+  void visit (TypeInfoVectorDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tvector);
+    TypeVector *ti = (TypeVector *) d->tinfo;
+
+    /* The vtable for TypeInfo_Vector.  */
+    this->layout_base (Type::typeinfovector);
+
+    /* TypeInfo for equivalent static array.  */
+    this->layout_field (build_typeinfo (ti->basetype));
+  }
+
+  /* Layout of TypeInfo_Function is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo next;
+	string deco;  */
+
+  void visit (TypeInfoFunctionDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tfunction && d->tinfo->deco != NULL);
+    TypeFunction *ti = (TypeFunction *) d->tinfo;
+
+    /* The vtable for TypeInfo_Function.  */
+    this->layout_base (Type::typeinfofunction);
+
+    /* TypeInfo for function return value.  */
+    this->layout_field (build_typeinfo (ti->next));
+
+    /* Mangled name of function declaration.  */
+    this->layout_field (d_array_string (d->tinfo->deco));
+  }
+
+  /* Layout of TypeInfo_Delegate is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo next;
+	string deco;  */
+
+  void visit (TypeInfoDelegateDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tdelegate && d->tinfo->deco != NULL);
+    TypeDelegate *ti = (TypeDelegate *) d->tinfo;
+
+    /* The vtable for TypeInfo_Delegate.  */
+    this->layout_base (Type::typeinfodelegate);
+
+    /* TypeInfo for delegate return value.  */
+    this->layout_field (build_typeinfo (ti->next));
+
+    /* Mangled name of delegate declaration.  */
+    this->layout_field (d_array_string (d->tinfo->deco));
+  }
+
+  /* Layout of ClassInfo/TypeInfo_Class is:
+	void **__vptr;
+	void *__monitor;
+	byte[] m_init;
+	string name;
+	void*[] vtbl;
+	Interface[] interfaces;
+	TypeInfo_Class base;
+	void *destructor;
+	void function(Object) classInvariant;
+	ClassFlags m_flags;
+	void *deallocator;
+	OffsetTypeInfo[] m_offTi;
+	void function(Object) defaultConstructor;
+	immutable(void)* m_RTInfo;
+
+     Information relating to interfaces, and their vtables are layed out
+     immediately after the named fields, if there is anything to write.  */
+
+  void visit (TypeInfoClassDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tclass);
+    TypeClass *ti = (TypeClass *) d->tinfo;
+    ClassDeclaration *cd = ti->sym;
+
+    /* The vtable for ClassInfo.  */
+    this->layout_base (Type::typeinfoclass);
+
+    if (!cd->members)
+      return;
+
+    tree interfaces = NULL_TREE;
+
+    if (!cd->isInterfaceDeclaration ())
+      {
+	/* Default initializer for class.  */
+	tree init = aggregate_initializer_decl (cd);
+	tree value = d_array_value (array_type_node, size_int (cd->structsize),
+				    build_address (init));
+	this->layout_field (value);
+
+	/* Name of the class declaration.  */
+	const char *name = cd->ident->toChars ();
+	if (!(strlen (name) > 9 && memcmp (name, "TypeInfo_", 9) == 0))
+	  name = cd->toPrettyChars ();
+	this->layout_field (d_array_string (name));
+
+	/* The vtable of the class declaration.  */
+	value = d_array_value (array_type_node, size_int (cd->vtbl.dim),
+			       build_address (get_vtable_decl (cd)));
+	this->layout_field (value);
+
+	/* Array of base interfaces that have their own vtable.  */
+	if (cd->vtblInterfaces->dim)
+	  interfaces = this->layout_interfaces (cd);
+	else
+	  this->layout_field (null_array_node);
+
+	/* TypeInfo_Class base;  */
+	tree base = (cd->baseClass)
+	  ? build_address (get_classinfo_decl (cd->baseClass))
+	  : null_pointer_node;
+	this->layout_field (base);
+
+	/* void *destructor;  */
+	tree dtor = (cd->dtor) ? build_address (get_symbol_decl (cd->dtor))
+	  : null_pointer_node;
+	this->layout_field (dtor);
+
+	/* void function(Object) classInvariant;  */
+	tree inv = (cd->inv) ? build_address (get_symbol_decl (cd->inv))
+	  : null_pointer_node;
+	this->layout_field (inv);
+
+	/* ClassFlags m_flags;  */
+	ClassFlags::Type flags = ClassFlags::hasOffTi;
+	if (cd->isCOMclass ())
+	  flags |= ClassFlags::isCOMclass;
+
+	if (cd->isCPPclass ())
+	  flags |= ClassFlags::isCPPclass;
+
+	flags |= ClassFlags::hasGetMembers;
+	flags |= ClassFlags::hasTypeInfo;
+
+	if (cd->ctor)
+	  flags |= ClassFlags::hasCtor;
+
+	for (ClassDeclaration *bcd = cd; bcd; bcd = bcd->baseClass)
+	  {
+	    if (bcd->dtor)
+	      {
+		flags |= ClassFlags::hasDtor;
+		break;
+	      }
+	  }
+
+	if (cd->isabstract)
+	  flags |= ClassFlags::isAbstract;
+
+	for (ClassDeclaration *bcd = cd; bcd; bcd = bcd->baseClass)
+	  {
+	    if (!bcd->members)
+	      continue;
+
+	    for (size_t i = 0; i < cd->members->dim; i++)
+	      {
+		Dsymbol *sm = (*cd->members)[i];
+		if (sm->hasPointers ())
+		  goto Lhaspointers;
+	      }
+	  }
+
+	flags |= ClassFlags::noPointers;
+
+    Lhaspointers:
+	this->layout_field (size_int (flags));
+
+	/* void *deallocator;  */
+	tree ddtor = (cd->aggDelete)
+	  ? build_address (get_symbol_decl (cd->aggDelete))
+	  : null_pointer_node;
+	this->layout_field (ddtor);
+
+	/* OffsetTypeInfo[] m_offTi;  (not implemented)  */
+	this->layout_field (null_array_node);
+
+	/* void function(Object) defaultConstructor;  */
+	if (cd->defaultCtor && !(cd->defaultCtor->storage_class & STCdisable))
+	  {
+	    tree dctor = get_symbol_decl (cd->defaultCtor);
+	    this->layout_field (build_address (dctor));
+	  }
+	else
+	  this->layout_field (null_pointer_node);
+
+	/* immutable(void)* m_RTInfo;  */
+	if (cd->getRTInfo)
+	  this->layout_field (build_expr (cd->getRTInfo, true));
+	else if (!(flags & ClassFlags::noPointers))
+	  this->layout_field (size_one_node);
+      }
+    else
+      {
+	/* No initializer for interface.  */
+	this->layout_field (null_array_node);
+
+	/* Name of the interface declaration.  */
+	this->layout_field (d_array_string (cd->toPrettyChars ()));
+
+	/* No vtable for interface declaration.  */
+	this->layout_field (null_array_node);
+
+	/* Array of base interfaces that have their own vtable.  */
+	if (cd->vtblInterfaces->dim)
+	  interfaces = this->layout_interfaces (cd);
+	else
+	  this->layout_field (null_array_node);
+
+	/* TypeInfo_Class base;
+	   void *destructor;
+	   void function(Object) classInvariant;  */
+	this->layout_field (null_pointer_node);
+	this->layout_field (null_pointer_node);
+	this->layout_field (null_pointer_node);
+
+	/* ClassFlags m_flags;  */
+	ClassFlags::Type flags = ClassFlags::hasOffTi;
+	flags |= ClassFlags::hasTypeInfo;
+	if (cd->isCOMinterface ())
+	  flags |= ClassFlags::isCOMclass;
+
+	this->layout_field (size_int (flags));
+
+	/* void *deallocator;
+	   OffsetTypeInfo[] m_offTi;  (not implemented)
+	   void function(Object) defaultConstructor;  */
+	this->layout_field (null_pointer_node);
+	this->layout_field (null_array_node);
+	this->layout_field (null_pointer_node);
+
+	/* immutable(void)* m_RTInfo;  */
+	if (cd->getRTInfo)
+	  this->layout_field (build_expr (cd->getRTInfo, true));
+	else
+	  this->layout_field (null_pointer_node);
+      }
+
+    /* Put out array of Interfaces.  */
+    if (interfaces != NULL_TREE)
+      this->layout_field (interfaces);
+
+    /* Put out this class' interface vtables[].  */
+    for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
+      this->layout_base_vtable (cd, cd, i);
+
+    /* Put out the overriding interface vtables[].  */
+    for (ClassDeclaration *bcd = cd->baseClass; bcd; bcd = bcd->baseClass)
+      {
+	for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++)
+	  this->layout_base_vtable (cd, bcd, i);
+      }
+  }
+
+  /* Layout of TypeInfo_Interface is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo_Class info;  */
+
+  void visit (TypeInfoInterfaceDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tclass);
+    TypeClass *ti = (TypeClass *) d->tinfo;
+
+    if (!ti->sym->vclassinfo)
+      ti->sym->vclassinfo = TypeInfoClassDeclaration::create (ti);
+
+    /* The vtable for TypeInfo_Interface.  */
+    this->layout_base (Type::typeinfointerface);
+
+    /* TypeInfo for class inheriting the interface.  */
+    tree tidecl = get_typeinfo_decl (ti->sym->vclassinfo);
+    this->layout_field (build_address (tidecl));
+  }
+
+  /* Layout of TypeInfo_Struct is:
+	void **__vptr;
+	void *__monitor;
+	string name;
+	void[] m_init;
+	hash_t function(in void*) xtoHash;
+	bool function(in void*, in void*) xopEquals;
+	int function(in void*, in void*) xopCmp;
+	string function(const(void)*) xtoString;
+	StructFlags m_flags;
+	void function(void*) xdtor;
+	void function(void*) xpostblit;
+	uint m_align;
+	version (X86_64)
+	    TypeInfo m_arg1;
+	    TypeInfo m_arg2;
+	immutable(void)* xgetRTInfo;  */
+
+  void visit (TypeInfoStructDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Tstruct);
+    TypeStruct *ti = (TypeStruct *) d->tinfo;
+    StructDeclaration *sd = ti->sym;
+
+    /* The vtable for TypeInfo_Struct.  */
+    this->layout_base (Type::typeinfostruct);
+
+    if (!sd->members)
+      return;
+
+    /* Send member functions to backend here.  */
+    TemplateInstance *tinst = sd->isInstantiated ();
+    if (tinst && !tinst->needsCodegen ())
+      {
+	gcc_assert (tinst->minst || sd->requestTypeInfo);
+
+	if (sd->xeq && sd->xeq != StructDeclaration::xerreq)
+	  build_decl_tree (sd->xeq);
+
+	if (sd->xcmp && sd->xcmp != StructDeclaration::xerrcmp)
+	  build_decl_tree (sd->xcmp);
+
+	if (FuncDeclaration *ftostr = search_toString (sd))
+	  build_decl_tree (ftostr);
+
+	if (sd->xhash)
+	  build_decl_tree (sd->xhash);
+
+	if (sd->postblit)
+	  build_decl_tree (sd->postblit);
+
+	if (sd->dtor)
+	  build_decl_tree (sd->dtor);
+      }
+
+    /* Name of the struct declaration.  */
+    this->layout_field (d_array_string (sd->toPrettyChars ()));
+
+    /* Default initializer for struct.  */
+    tree ptr = (sd->zeroInit) ? null_pointer_node :
+      build_address (aggregate_initializer_decl (sd));
+    this->layout_field (d_array_value (array_type_node,
+				       size_int (sd->structsize), ptr));
+
+    /* hash_t function (in void*) xtoHash;  */
+    tree xhash = (sd->xhash) ? build_address (get_symbol_decl (sd->xhash))
+      : null_pointer_node;
+    this->layout_field (xhash);
+
+    if (sd->xhash)
+      {
+	TypeFunction *tf = (TypeFunction *) sd->xhash->type;
+	gcc_assert (tf->ty == Tfunction);
+	if (!tf->isnothrow || tf->trust == TRUSTsystem)
+	  {
+	    warning (sd->xhash->loc, "toHash() must be declared as "
+		     "extern (D) size_t toHash() const nothrow @safe, "
+		     "not %s", tf->toChars ());
+	  }
+      }
+
+    /* bool function(in void*, in void*) xopEquals;  */
+    tree xeq = (sd->xeq) ? build_address (get_symbol_decl (sd->xeq))
+      : null_pointer_node;
+    this->layout_field (xeq);
+
+    /* int function(in void*, in void*) xopCmp;  */
+    tree xcmp = (sd->xcmp) ? build_address (get_symbol_decl (sd->xcmp))
+      : null_pointer_node;
+    this->layout_field (xcmp);
+
+    /* string function(const(void)*) xtoString;  */
+    FuncDeclaration *fdx = search_toString (sd);
+    if (fdx)
+      this->layout_field (build_address (get_symbol_decl (fdx)));
+    else
+      this->layout_field (null_pointer_node);
+
+    /* StructFlags m_flags;  */
+    StructFlags::Type m_flags = 0;
+    if (ti->hasPointers ())
+      m_flags |= StructFlags::hasPointers;
+    this->layout_field (size_int (m_flags));
+
+    /* void function(void*) xdtor;  */
+    tree dtor = (sd->dtor) ? build_address (get_symbol_decl (sd->dtor))
+      : null_pointer_node;
+    this->layout_field (dtor);
+
+    /* void function(void*) xpostblit;  */
+    if (sd->postblit && !(sd->postblit->storage_class & STCdisable))
+      this->layout_field (build_address (get_symbol_decl (sd->postblit)));
+    else
+      this->layout_field (null_pointer_node);
+
+    /* uint m_align;  */
+    this->layout_field (size_int (ti->alignsize ()));
+
+    if (global.params.is64bit)
+      {
+	/* TypeInfo m_arg1;  */
+	tree arg1type = (sd->arg1type) ? build_typeinfo (sd->arg1type)
+	  : null_pointer_node;
+	this->layout_field (arg1type);
+
+	/* TypeInfo m_arg2;  */
+	tree arg2type = (sd->arg2type) ? build_typeinfo (sd->arg2type)
+	  : null_pointer_node;
+	this->layout_field (arg2type);
+      }
+
+    /* immutable(void)* xgetRTInfo;  */
+    if (sd->getRTInfo)
+      this->layout_field (build_expr (sd->getRTInfo, true));
+    else if (m_flags & StructFlags::hasPointers)
+      this->layout_field (size_one_node);
+  }
+
+  /* Layout of TypeInfo_Tuple is:
+	void **__vptr;
+	void *__monitor;
+	TypeInfo[] elements;  */
+
+  void visit (TypeInfoTupleDeclaration *d)
+  {
+    gcc_assert (d->tinfo->ty == Ttuple);
+    TypeTuple *ti = (TypeTuple *) d->tinfo;
+
+    /* The vtable for TypeInfo_Tuple.  */
+    this->layout_base (Type::typeinfotypelist);
+
+    /* TypeInfo[] elements;  */
+    Type *satype = Type::tvoidptr->sarrayOf (ti->arguments->dim);
+    vec<constructor_elt, va_gc> *elms = NULL;
+    for (size_t i = 0; i < ti->arguments->dim; i++)
+      {
+	Parameter *arg = (*ti->arguments)[i];
+	CONSTRUCTOR_APPEND_ELT (elms, size_int (i),
+				build_typeinfo (arg->type));
+      }
+    tree ctor = build_constructor (build_ctype (satype), elms);
+    tree decl = build_artificial_decl (TREE_TYPE (ctor), ctor);
+
+    tree length = size_int (ti->arguments->dim);
+    tree ptr = build_address (decl);
+    this->layout_field (d_array_value (array_type_node, length, ptr));
+
+    d_pushdecl (decl);
+    rest_of_decl_compilation (decl, 1, 0);
+  }
+};
+
+
+/* Main entry point for TypeInfoVisitor interface to generate
+   TypeInfo constructor for the TypeInfoDeclaration AST class D.  */
+
+tree
+layout_typeinfo (TypeInfoDeclaration *d)
+{
+  tree type = TREE_TYPE (get_typeinfo_decl (d));
+  TypeInfoVisitor v = TypeInfoVisitor (type);
+  d->accept (&v);
+  return v.result ();
+}
+
+/* Like layout_typeinfo, but generates the TypeInfo_Class for
+   the class or interface declaration CD.  */
+
+tree
+layout_classinfo (ClassDeclaration *cd)
+{
+  /* The classinfo decl initialized here to accomodate both class and interfaces
+     is thrown away immediately after exiting.  So the use of placement new is
+     deliberate to avoid making more heap allocations than necessary.  */
+  char buf[sizeof (TypeInfoClassDeclaration)];
+  TypeInfoClassDeclaration *d = new (buf) TypeInfoClassDeclaration (cd->type);
+
+  tree type = TREE_TYPE (get_classinfo_decl (cd));
+  TypeInfoVisitor v = TypeInfoVisitor (type);
+  d->accept (&v);
+  return v.result ();
+}
+
+/* Layout fields that immediately come after the classinfo type for DECL if
+   there's any interfaces or interface vtables to be added.
+   This must be mirrored with base_vtable_offset().  */
+
+static tree
+layout_classinfo_interfaces (ClassDeclaration *decl)
+{
+  tree type = tinfo_types[TK_CLASSINFO_TYPE];
+  size_t structsize = int_size_in_bytes (type);
+  input_location = get_linemap (decl->loc);
+
+  if (decl->vtblInterfaces->dim)
+    {
+      size_t interfacesize = int_size_in_bytes (vtbl_interface_type_node);
+      tree field;
+
+      type = copy_aggregate_type (type);
+
+      /* First layout the static array of Interface, which provides information
+	 about the vtables that follow.  */
+      tree domain = size_int (decl->vtblInterfaces->dim - 1);
+      tree arrtype = build_array_type (vtbl_interface_type_node,
+				       build_index_type (domain));
+      field = create_field_decl (arrtype, NULL, 1, 1);
+      insert_aggregate_field (type, field, structsize);
+      structsize += decl->vtblInterfaces->dim * interfacesize;
+
+      /* For each interface, layout each vtable.  */
+      for (size_t i = 0; i < decl->vtblInterfaces->dim; i++)
+	{
+	  BaseClass *b = (*decl->vtblInterfaces)[i];
+	  ClassDeclaration *id = b->sym;
+	  unsigned offset = base_vtable_offset (decl, b);
+
+	  if (id->vtbl.dim && offset != ~0u)
+	    {
+	      tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1));
+	      tree vtbltype = build_array_type (vtable_entry_type, vtbldomain);
+
+	      field = create_field_decl (vtbltype, NULL, 1, 1);
+	      insert_aggregate_field (type, field, offset);
+	      structsize += id->vtbl.dim * Target::ptrsize;
+	    }
+	}
+    }
+
+  /* Layout the arrays of overriding interface vtables.  */
+  for (ClassDeclaration *bcd = decl->baseClass; bcd; bcd = bcd->baseClass)
+    {
+      for (size_t i = 0; i < bcd->vtblInterfaces->dim; i++)
+	{
+	  BaseClass *b = (*bcd->vtblInterfaces)[i];
+	  ClassDeclaration *id = b->sym;
+	  unsigned offset = base_vtable_offset (decl, b);
+
+	  if (id->vtbl.dim && offset != ~0u)
+	    {
+	      if (type == tinfo_types[TK_CLASSINFO_TYPE])
+		type = copy_aggregate_type (type);
+
+	      tree vtbldomain = build_index_type (size_int (id->vtbl.dim - 1));
+	      tree vtbltype = build_array_type (vtable_entry_type, vtbldomain);
+
+	      tree field = create_field_decl (vtbltype, NULL, 1, 1);
+	      insert_aggregate_field (type, field, offset);
+	      structsize += id->vtbl.dim * Target::ptrsize;
+	    }
+	}
+    }
+
+  /* Update the type size and record mode for the classinfo type.  */
+  if (type != tinfo_types[TK_CLASSINFO_TYPE])
+    finish_aggregate_type (structsize, TYPE_ALIGN_UNIT (type), type, NULL);
+
+  return type;
+}
+
+/* Implements a visitor interface to create the decl tree for TypeInfo decls.
+   TypeInfo_Class objects differ in that they also have information about
+   the class type packed immediately after the TypeInfo symbol.
+
+   If the frontend had an interface to allow distinguishing being these two
+   AST types, then that would be better for us.  */
+
+class TypeInfoDeclVisitor : public Visitor
+{
+public:
+  TypeInfoDeclVisitor (void) {}
+
+  void visit (TypeInfoDeclaration *tid)
+  {
+    tree ident = get_identifier (tid->ident->toChars ());
+    tree type = tinfo_types[get_typeinfo_kind (tid->tinfo)];
+    gcc_assert (type != NULL_TREE);
+
+    tid->csym = declare_extern_var (ident, type);
+    DECL_LANG_SPECIFIC (tid->csym) = build_lang_decl (tid);
+
+    DECL_CONTEXT (tid->csym) = d_decl_context (tid);
+    TREE_READONLY (tid->csym) = 1;
+
+    /* Built-in typeinfo will be referenced as one-only.  */
+    gcc_assert (!tid->isInstantiated ());
+    d_comdat_linkage (tid->csym);
+  }
+
+  void visit (TypeInfoClassDeclaration *tid)
+  {
+    gcc_assert (tid->tinfo->ty == Tclass);
+    TypeClass *tc = (TypeClass *) tid->tinfo;
+    tid->csym = get_classinfo_decl (tc->sym);
+  }
+};
+
+/* Get the VAR_DECL of the TypeInfo for DECL.  If this does not yet exist,
+   create it.  The TypeInfo decl provides information about the type of a given
+   expression or object.  */
+
+tree
+get_typeinfo_decl (TypeInfoDeclaration *decl)
+{
+  if (decl->csym)
+    return decl->csym;
+
+  gcc_assert (decl->tinfo->ty != Terror);
+
+  TypeInfoDeclVisitor v = TypeInfoDeclVisitor ();
+  decl->accept (&v);
+  gcc_assert (decl->csym != NULL_TREE);
+
+  return decl->csym;
+}
+
+/* Get the VAR_DECL of the ClassInfo for DECL.  If this does not yet exist,
+   create it.  The ClassInfo decl provides information about the dynamic type
+   of a given class type or object.  */
+
+tree
+get_classinfo_decl (ClassDeclaration *decl)
+{
+  if (decl->csym)
+    return decl->csym;
+
+  InterfaceDeclaration *id = decl->isInterfaceDeclaration ();
+  tree ident = mangle_internal_decl (decl, id ? "__Interface" : "__Class", "Z");
+  tree type = layout_classinfo_interfaces (decl);
+
+  decl->csym = declare_extern_var (ident, type);
+  DECL_LANG_SPECIFIC (decl->csym) = build_lang_decl (NULL);
+
+  /* Class is a reference, want the record type.  */
+  DECL_CONTEXT (decl->csym) = TREE_TYPE (build_ctype (decl->type));
+  /* ClassInfo cannot be const data, because we use the monitor on it.  */
+  TREE_READONLY (decl->csym) = 0;
+
+  /* Could move setting comdat linkage to the caller, who knows whether
+     this classinfo is being emitted in this compilation.  */
+  if (decl->isInstantiated ())
+    d_comdat_linkage (decl->csym);
+
+  return decl->csym;
+}
+
+/* Returns typeinfo reference for TYPE.  */
+
+tree
+build_typeinfo (Type *type)
+{
+  gcc_assert (type->ty != Terror);
+  create_typeinfo (type, NULL);
+  return build_address (get_typeinfo_decl (type->vtinfo));
+}
+
+/* Like layout_classinfo, but generates an Object that wraps around a
+   pointer to C++ type_info so it can be distinguished from D TypeInfo.  */
+
+void
+layout_cpp_typeinfo (ClassDeclaration *cd)
+{
+  gcc_assert (cd->isCPPclass ());
+
+  tree decl = get_cpp_typeinfo_decl (cd);
+  vec<constructor_elt, va_gc> *init = NULL;
+
+  /* Use the vtable of __cpp_type_info_ptr, the EH personality routine
+     expects this, as it uses .classinfo identity comparison to test for
+     C++ catch handlers.  */
+  tree vptr = get_vtable_decl (ClassDeclaration::cpp_type_info_ptr);
+  CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, build_address (vptr));
+  CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, null_pointer_node);
+
+  /* Let C++ do the RTTI generation, and just reference the symbol as
+     extern, the knowing the underlying type is not required.  */
+  const char *ident = cppTypeInfoMangle (cd);
+  tree typeinfo = declare_extern_var (get_identifier (ident),
+				      unknown_type_node);
+  TREE_READONLY (typeinfo) = 1;
+  CONSTRUCTOR_APPEND_ELT (init, NULL_TREE, build_address (typeinfo));
+
+  /* Build the initializer and emit.  */
+  DECL_INITIAL (decl) = build_struct_literal (TREE_TYPE (decl), init);
+  DECL_EXTERNAL (decl) = 0;
+  d_pushdecl (decl);
+  rest_of_decl_compilation (decl, 1, 0);
+}
+
+/* Get the VAR_DECL of the __cpp_type_info_ptr for DECL.  If this does not yet
+   exist, create it.  The __cpp_type_info_ptr decl is then initialized with a
+   pointer to the C++ type_info for the given class.  */
+
+tree
+get_cpp_typeinfo_decl (ClassDeclaration *decl)
+{
+  gcc_assert (decl->isCPPclass ());
+
+  if (decl->cpp_type_info_ptr_sym)
+    return decl->cpp_type_info_ptr_sym;
+
+  if (!tinfo_types[TK_CPPTI_TYPE])
+    make_internal_typeinfo (TK_CPPTI_TYPE, Id::cpp_type_info_ptr,
+			    ptr_type_node, NULL);
+
+  tree ident = mangle_internal_decl (decl, "_cpp_type_info_ptr", "");
+  tree type = tinfo_types[TK_CPPTI_TYPE];
+
+  decl->cpp_type_info_ptr_sym = declare_extern_var (ident, type);
+  DECL_LANG_SPECIFIC (decl->cpp_type_info_ptr_sym) = build_lang_decl (NULL);
+
+  /* Class is a reference, want the record type.  */
+  DECL_CONTEXT (decl->cpp_type_info_ptr_sym)
+    = TREE_TYPE (build_ctype (decl->type));
+  TREE_READONLY (decl->cpp_type_info_ptr_sym) = 1;
+
+  d_comdat_linkage (decl->cpp_type_info_ptr_sym);
+
+  /* Layout the initializer and emit the symbol.  */
+  layout_cpp_typeinfo (decl);
+
+  return decl->cpp_type_info_ptr_sym;
+}
+
+/* Returns true if the TypeInfo for type should be placed in
+   the runtime library.  */
+
+static bool
+builtin_typeinfo_p (Type *type)
+{
+  if (type->isTypeBasic () || type->ty == Tclass)
+    return !type->mod;
+
+  if (type->ty == Tarray)
+    {
+      /* Strings are so common, make them builtin.  */
+      Type *next = type->nextOf ();
+      return !type->mod
+	&& ((next->isTypeBasic () != NULL && !next->mod)
+	    || (next->ty == Tchar && next->mod == MODimmutable)
+	    || (next->ty == Tchar && next->mod == MODconst));
+    }
+
+  return false;
+}
+
+/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it.  */
+
+void
+create_typeinfo (Type *type, Module *mod)
+{
+  /* Do this since not all Type's are merged.  */
+  Type *t = type->merge2 ();
+  Identifier *ident;
+
+  if (!t->vtinfo)
+    {
+      tinfo_kind tk = get_typeinfo_kind (t);
+      switch (tk)
+	{
+	case TK_SHARED_TYPE:
+	case TK_CONST_TYPE:
+	case TK_IMMUTABLE_TYPE:
+	case TK_INOUT_TYPE:
+	case TK_POINTER_TYPE:
+	case TK_ARRAY_TYPE:
+	case TK_VECTOR_TYPE:
+	case TK_INTERFACE_TYPE:
+	  /* Kinds of TypeInfo that add one extra pointer field.  */
+	  if (tk == TK_SHARED_TYPE)
+	    {
+	      /* Does both 'shared' and 'shared const'.  */
+	      t->vtinfo = TypeInfoSharedDeclaration::create (t);
+	      ident = Id::TypeInfo_Shared;
+	    }
+	  else if (tk == TK_CONST_TYPE)
+	    {
+	      t->vtinfo = TypeInfoConstDeclaration::create (t);
+	      ident = Id::TypeInfo_Const;
+	    }
+	  else if (tk == TK_IMMUTABLE_TYPE)
+	    {
+	      t->vtinfo = TypeInfoInvariantDeclaration::create (t);
+	      ident = Id::TypeInfo_Invariant;
+	    }
+	  else if (tk == TK_INOUT_TYPE)
+	    {
+	      t->vtinfo = TypeInfoWildDeclaration::create (t);
+	      ident = Id::TypeInfo_Wild;
+	    }
+	  else if (tk == TK_POINTER_TYPE)
+	    {
+	      t->vtinfo = TypeInfoPointerDeclaration::create (t);
+	      ident = Id::TypeInfo_Pointer;
+	    }
+	  else if (tk == TK_ARRAY_TYPE)
+	    {
+	      t->vtinfo = TypeInfoArrayDeclaration::create (t);
+	      ident = Id::TypeInfo_Array;
+	    }
+	  else if (tk == TK_VECTOR_TYPE)
+	    {
+	      t->vtinfo = TypeInfoVectorDeclaration::create (t);
+	      ident = Id::TypeInfo_Vector;
+	    }
+	  else if (tk == TK_INTERFACE_TYPE)
+	    {
+	      t->vtinfo = TypeInfoInterfaceDeclaration::create (t);
+	      ident = Id::TypeInfo_Interface;
+	    }
+	  else
+	    gcc_unreachable ();
+
+	  if (!tinfo_types[tk])
+	    make_internal_typeinfo (tk, ident, ptr_type_node, NULL);
+	  break;
+
+	case TK_STATICARRAY_TYPE:
+	  if (!tinfo_types[tk])
+	    {
+	      make_internal_typeinfo (tk, Id::TypeInfo_StaticArray,
+				      ptr_type_node, size_type_node, NULL);
+	    }
+	  t->vtinfo = TypeInfoStaticArrayDeclaration::create (t);
+	  break;
+
+	case TK_ASSOCIATIVEARRAY_TYPE:
+	  if (!tinfo_types[tk])
+	    {
+	      make_internal_typeinfo (tk, Id::TypeInfo_AssociativeArray,
+				      ptr_type_node, ptr_type_node, NULL);
+	    }
+	  t->vtinfo = TypeInfoAssociativeArrayDeclaration::create (t);
+	  break;
+
+	case TK_STRUCT_TYPE:
+	  if (!tinfo_types[tk])
+	    {
+	      /* Some ABIs add extra TypeInfo fields on the end.  */
+	      tree argtype = global.params.is64bit ? ptr_type_node : NULL_TREE;
+
+	      make_internal_typeinfo (tk, Id::TypeInfo_Struct,
+				      array_type_node, array_type_node,
+				      ptr_type_node, ptr_type_node,
+				      ptr_type_node, ptr_type_node,
+				      size_type_node, ptr_type_node,
+				      ptr_type_node, size_type_node,
+				      ptr_type_node, argtype, argtype, NULL);
+	    }
+	  t->vtinfo = TypeInfoStructDeclaration::create (t);
+	  break;
+
+	case TK_ENUMERAL_TYPE:
+	  if (!tinfo_types[tk])
+	    {
+	      make_internal_typeinfo (tk, Id::TypeInfo_Enum,
+				      ptr_type_node, array_type_node,
+				      array_type_node, NULL);
+	    }
+	  t->vtinfo = TypeInfoEnumDeclaration::create (t);
+	  break;
+
+	case TK_FUNCTION_TYPE:
+	case TK_DELEGATE_TYPE:
+	  /* Functions and delegates share a common TypeInfo layout.  */
+	  if (tk == TK_FUNCTION_TYPE)
+	    {
+	      t->vtinfo = TypeInfoFunctionDeclaration::create (t);
+	      ident = Id::TypeInfo_Function;
+	    }
+	  else if (tk == TK_DELEGATE_TYPE)
+	    {
+	      t->vtinfo = TypeInfoDelegateDeclaration::create (t);
+	      ident = Id::TypeInfo_Delegate;
+	    }
+	  else
+	    gcc_unreachable ();
+
+	  if (!tinfo_types[tk])
+	    {
+	      make_internal_typeinfo (tk, ident, ptr_type_node,
+				      array_type_node, NULL);
+	    }
+	  break;
+
+	case TK_TYPELIST_TYPE:
+	  if (!tinfo_types[tk])
+	    {
+	      make_internal_typeinfo (tk, Id::TypeInfo_Tuple,
+				      array_type_node, NULL);
+	    }
+	  t->vtinfo = TypeInfoTupleDeclaration::create (t);
+	  break;
+
+	case TK_CLASSINFO_TYPE:
+	  t->vtinfo = TypeInfoClassDeclaration::create (t);
+	  break;
+
+	default:
+	  t->vtinfo = TypeInfoDeclaration::create (t);
+	}
+      gcc_assert (t->vtinfo);
+
+      /* If this has a custom implementation in rt/typeinfo, then
+	 do not generate a COMDAT for it.  */
+      if (!builtin_typeinfo_p (t))
+	{
+	  /* Find module that will go all the way to an object file.  */
+	  if (mod)
+	    mod->members->push (t->vtinfo);
+	  else
+	    build_decl_tree (t->vtinfo);
+	}
+    }
+  /* Types aren't merged, but we can share the vtinfo's.  */
+  if (!type->vtinfo)
+    type->vtinfo = t->vtinfo;
+
+  gcc_assert (type->vtinfo != NULL);
+}
+
+/* Implements a visitor interface to check whether a type is speculative.
+   TypeInfo_Struct would refer the members of the struct it is representing
+   (e.g. opEquals via xopEquals field), so if it's instantiated in speculative
+   context, TypeInfo creation should also be stopped to avoid possible
+   `unresolved symbol' linker errors.  */
+
+class SpeculativeTypeVisitor : public Visitor
+{
+  bool result_;
+
+public:
+  SpeculativeTypeVisitor (void)
+  {
+    this->result_ = false;
+  }
+
+  bool result (void)
+  {
+    return this->result_;
+  }
+
+  void visit (Type *t)
+  {
+    Type *tb = t->toBasetype ();
+    if (tb != t)
+      tb->accept (this);
+  }
+
+  void visit (TypeNext *t)
+  {
+    if (t->next)
+      t->next->accept (this);
+  }
+
+  void visit (TypeBasic *)
+  {
+  }
+
+  void visit (TypeVector *t)
+  {
+    t->basetype->accept (this);
+  }
+
+  void visit (TypeAArray *t)
+  {
+    t->index->accept (this);
+    visit ((TypeNext *)t);
+  }
+
+  void visit (TypeFunction *t)
+  {
+    visit ((TypeNext *)t);
+  }
+
+  void visit (TypeStruct *t)
+  {
+    StructDeclaration *sd = t->sym;
+    if (TemplateInstance *ti = sd->isInstantiated ())
+      {
+	if (!ti->needsCodegen ())
+	  {
+	    if (ti->minst || sd->requestTypeInfo)
+	      return;
+
+	    this->result_ |= true;
+	    return;
+	  }
+      }
+  }
+
+  void visit (TypeClass *)
+  {
+  }
+
+  void visit (TypeTuple *t)
+  {
+    if (!t->arguments)
+      return;
+
+    for (size_t i = 0; i < t->arguments->dim; i++)
+      {
+	Type *tprm = (*t->arguments)[i]->type;
+	if (tprm)
+	  tprm->accept (this);
+	if (this->result_)
+	  return;
+      }
+  }
+};
+
+/* Return true if type was instantiated in a speculative context.  */
+
+bool
+speculative_type_p (Type *t)
+{
+  SpeculativeTypeVisitor v = SpeculativeTypeVisitor ();
+  t->accept (&v);
+  return v.result ();
+}
+
+#include "gt-d-typeinfo.h"
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
new file mode 100644
index 00000000000..8fdcbac89d1
--- /dev/null
+++ b/gcc/d/types.cc
@@ -0,0 +1,981 @@
+/* types.cc -- Lower D frontend types to GCC trees.
+   Copyright (C) 2006-2017 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 "dfrontend/attrib.h"
+#include "dfrontend/aggregate.h"
+#include "dfrontend/enum.h"
+#include "dfrontend/mtype.h"
+#include "dfrontend/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->immutableOf ()->equals (tb2->immutableOf ()))
+    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)
+{
+  tree telem = build_ctype (type);
+
+  /* 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 zrange = lang_hooks.types.type_for_size (TYPE_PRECISION (sizetype),
+						    TYPE_UNSIGNED (sizetype));
+      tree zindex = build_range_type (zrange, size_zero_node, NULL_TREE);
+      tree ztype = build_array_type (build_ctype (type), zindex);
+
+      TYPE_SIZE (ztype) = bitsize_zero_node;
+      TYPE_SIZE_UNIT (ztype) = size_zero_node;
+
+      return ztype;
+    }
+
+  return build_array_type (telem, 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 it's 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 it's given offset.  */
+	  if (var->isField ())
+	    {
+	      const char *ident = var->ident ? var->ident->toChars () : NULL;
+	      input_location = get_linemap (var->loc);
+	      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 backend 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);
+	  input_location = get_linemap (ad->loc);
+
+	  /* Build the type declaration.  */
+	  tree decl = build_decl (input_location, 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);
+  input_location = get_linemap (decl->loc);
+
+  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->cpp)
+	    {
+	      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 backend 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 backend representation to be returned.  */
+
+class TypeVisitor : public Visitor
+{
+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 = bool_type_node; break;
+      case Tint8:	  t->ctype = byte_type_node; break;
+      case Tuns8:	  t->ctype = ubyte_type_node; break;
+      case Tint16:	  t->ctype = short_type_node; break;
+      case Tuns16:	  t->ctype = ushort_type_node; break;
+      case Tint32:	  t->ctype = int_type_node; break;
+      case Tuns32:	  t->ctype = uint_type_node; break;
+      case Tint64:	  t->ctype = long_type_node; break;
+      case Tuns64:	  t->ctype = ulong_type_node; break;
+      case Tint128:	  t->ctype = cent_type_node; break;
+      case Tuns128:	  t->ctype = ucent_type_node; 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_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 ();
+	/* In [arrays/void-arrays], void arrays can also be static,
+	   the length is specified in bytes.  */
+	if (t->next->toBasetype ()->ty == Tvoid)
+	  t->ctype = make_array_type (Type::tuns8, size);
+	else
+	  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_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_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 backend
+		   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 a identifier for the enumeration constant.  */
+		tree decl = build_decl (get_linemap (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->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) : NULL_TREE;
+
+	if (method && DECL_CONTEXT (method) == basetype)
+	  {
+	    DECL_CHAIN (method) = TYPE_METHODS (basetype);
+	    TYPE_METHODS (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 backend treats i.e: 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;
+}
