[committed,1/4] d: Merge upstream dmd 568496d5b

Message ID 20211208235624.3251697-1-ibuclaw@gdcproject.org
State Committed
Headers
Series [committed,1/4] d: Merge upstream dmd 568496d5b |

Commit Message

Iain Buclaw Dec. 8, 2021, 11:56 p.m. UTC
  Hi,

This patch merges the D front-end implementation with upstream dmd
568496d5b, bumping the internal version to 2.098.0.

D front-end changes:

    - Import dmd v2.098.0
    - New ImportC module for compiling preprocessed C11 code into D.
    - New -ftransition=in switch.
    - Improved handling of new 'noreturn' type.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and
committed to mainline.

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 568496d5b.
	* Make-lang.in (D_FRONTEND_OBJS): Add d/common-file.o,
	d/common-outbuffer.o, d/common-string.o, d/file_manager.o,
	d/importc.o.  Remove d/root-outbuffer.o.
	(d/common-%.o): New recipe.
	* d-builtins.cc (build_frontend_type): Update for new front-end
	interface.
	(d_build_d_type_nodes): Set noreturn_type_node.
	* d-codegen.cc (d_build_call): Don't call function if one of the
	arguments is type 'noreturn'.
	(build_vthis_function): Propagate TYPE_QUAL_VOLATILE from original
	function type.
	* d-frontend.cc (eval_builtin): Update signature.
	(getTypeInfoType): Likewise.
	(toObjFile): New function.
	* d-gimplify.cc (d_gimplify_call_expr): Always evaluate arguments from
	left to right.
	* d-lang.cc (d_handle_option): Handle OPT_ftransition_in.
	(d_parse_file): Don't generate D main if it is declared in user code.
	* d-tree.h (CALL_EXPR_ARGS_ORDERED): Remove.
	(enum d_tree_index): Add DTI_BOTTOM_TYPE.
	(noreturn_type_node): New.
	* decl.cc (apply_pragma_crt): Remove.
	(DeclVisitor::visit): Update for new front-end interface.
	(DeclVisitor::visit (PragmaDeclaration *)): Don't handle
	crt_constructor and crt_destructor pragmas.
	(DeclVisitor::visit (VarDeclaration *)): Don't generate declarations
	of type 'noreturn'.
	(DeclVisitor::visit (FuncDeclaration *)): Stop adding parameters when
	'noreturn' type has been encountered.
	(get_symbol_decl): Set DECL_STATIC_CONSTRUCTOR and
	DECL_STATIC_DESTRUCTOR on decl node if requested.
	(aggregate_initializer_decl): Update for new front-end interface.
	* expr.cc (ExprVisitor::visit (CallExp *)): Always use the 'this'
	object as the result of calling any constructor function.
	(ExprVisitor::visit): Update for new front-end interface.
	* gdc.texi (Runtime Options): Document -fmain and -ftransition=in.
	* lang.opt (ftransition=in): New option.
	* modules.cc (get_internal_fn): Update for new front-end interface.
	* types.cc (TypeVisitor::visit): Likewise.
	(TypeVisitor::visit (TypeNoreturn *)): Return noreturn_type_node.
	(TypeVisitor::visit (TypeFunction *)): Stop adding parameters when
	'notreturn' type has been encountered.  Qualify function types that
	return 'noreturn' as TYPE_QUAL_VOLATILE.
---
 gcc/d/Make-lang.in                            |  10 +-
 gcc/d/d-builtins.cc                           |   7 +-
 gcc/d/d-codegen.cc                            |  36 +-
 gcc/d/d-frontend.cc                           |  11 +-
 gcc/d/d-gimplify.cc                           |  65 +-
 gcc/d/d-lang.cc                               |  16 +
 gcc/d/d-tree.h                                |   9 +-
 gcc/d/decl.cc                                 | 155 ++--
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/expr.cc                                 |   9 +-
 gcc/d/gdc.texi                                |   9 +
 gcc/d/lang.opt                                |   4 +
 gcc/d/modules.cc                              |   2 +-
 gcc/d/types.cc                                |  19 +-
 111 files changed, 4199 insertions(+), 2920 deletions(-)
  

Patch

diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 4ce11e3cada..d7f714760f7 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -89,6 +89,9 @@  D_FRONTEND_OBJS = \
 	d/canthrow.o \
 	d/chkformat.o \
 	d/clone.o \
+	d/common-file.o \
+	d/common-outbuffer.o \
+	d/common-string.o \
 	d/compiler.o \
 	d/complex.o \
 	d/cond.o \
@@ -120,6 +123,7 @@  D_FRONTEND_OBJS = \
 	d/escape.o \
 	d/expression.o \
 	d/expressionsem.o \
+	d/file_manager.o \
 	d/foreachvar.o \
 	d/func.o \
 	d/globals.o \
@@ -131,6 +135,7 @@  D_FRONTEND_OBJS = \
 	d/identifier.o \
 	d/impcnvtab.o \
 	d/imphint.o \
+	d/importc.o \
 	d/init.o \
 	d/initsem.o \
 	d/inline.o \
@@ -157,7 +162,6 @@  D_FRONTEND_OBJS = \
 	d/root-filename.o \
 	d/root-hash.o \
 	d/root-longdouble.o \
-	d/root-outbuffer.o \
 	d/root-port.o \
 	d/root-region.o \
 	d/root-rmem.o \
@@ -393,6 +397,10 @@  d/%.o: d/dmd/%.d
 	$(DCOMPILE) $(D_INCLUDES) $<
 	$(DPOSTCOMPILE)
 
+d/common-%.o: d/dmd/common/%.d
+	$(DCOMPILE) $(D_INCLUDES) $<
+	$(DPOSTCOMPILE)
+
 d/root-%.o: d/dmd/root/%.d
 	$(DCOMPILE) $(D_INCLUDES) $<
 	$(DPOSTCOMPILE)
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index ab3a950689f..ea8e1eda244 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -236,7 +236,7 @@  build_frontend_type (tree type)
       sdecl->parent = stubmod;
       sdecl->structsize = int_size_in_bytes (type);
       sdecl->alignsize = TYPE_ALIGN_UNIT (type);
-      sdecl->alignment = STRUCTALIGN_DEFAULT;
+      sdecl->alignment.setDefault ();
       sdecl->sizeok = Sizeok::done;
       sdecl->type = (TypeStruct::create (sdecl))->addMod (mod);
       sdecl->type->ctype = type;
@@ -275,7 +275,7 @@  build_frontend_type (tree type)
 						       NULL);
 	  vd->parent = sdecl;
 	  vd->offset = tree_to_uhwi (byte_position (field));
-	  vd->semanticRun = PASSsemanticdone;
+	  vd->semanticRun = PASS::semanticdone;
 	  vd->csym = field;
 	  sdecl->members->push (vd);
 	  sdecl->fields.push (vd);
@@ -856,6 +856,9 @@  d_build_d_type_nodes (void)
   ireal_type_node = build_distinct_type_copy (long_double_type_node);
   TYPE_IMAGINARY_FLOAT (ireal_type_node) = 1;
 
+  /* Noreturn type.  */
+  noreturn_type_node = build_distinct_type_copy (void_type_node);
+
   /* Calling build_ctype() links the front-end Type to the GCC node,
      and sets the TYPE_NAME to the D language type.  */
   for (unsigned ty = 0; ty < (unsigned) TY::TMAX; ty++)
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 403e3c74377..c082ac5ab80 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -2140,6 +2140,7 @@  d_build_call (TypeFunction *tf, tree callable, tree object,
   /* Build the argument list for the call.  */
   vec <tree, va_gc> *args = NULL;
   tree saved_args = NULL_TREE;
+  bool noreturn_call = false;
 
   /* If this is a delegate call or a nested function being called as
      a delegate, the object should not be NULL.  */
@@ -2165,9 +2166,9 @@  d_build_call (TypeFunction *tf, tree callable, tree object,
 	    }
 	}
 
-      size_t nparams = tf->parameterList.length ();
+      const size_t nparams = tf->parameterList.length ();
       /* if _arguments[] is the first argument.  */
-      size_t varargs = tf->isDstyleVariadic ();
+      const size_t varargs = tf->isDstyleVariadic ();
 
       /* Assumes arguments->length <= formal_args->length if (!tf->varargs).  */
       for (size_t i = 0; i < arguments->length; ++i)
@@ -2206,6 +2207,11 @@  d_build_call (TypeFunction *tf, tree callable, tree object,
 			      build_address (targ));
 	    }
 
+  	  /* Type `noreturn` is a terminator, as no other arguments can possibly
+  	     be evaluated after it.  */
+  	  if (TREE_TYPE (targ) == noreturn_type_node)
+	    noreturn_call = true;
+
 	  vec_safe_push (args, targ);
 	}
     }
@@ -2217,13 +2223,27 @@  d_build_call (TypeFunction *tf, tree callable, tree object,
       saved_args = compound_expr (callee, saved_args);
     }
 
+  /* If we saw a `noreturn` parameter, any unreachable argument evaluations
+     after it are discarded, as well as the function call itself.  */
+  if (noreturn_call)
+    {
+      if (TREE_SIDE_EFFECTS (callee))
+	saved_args = compound_expr (callee, saved_args);
+
+      tree arg;
+      unsigned int ix;
+
+      FOR_EACH_VEC_SAFE_ELT (args, ix, arg)
+	saved_args = compound_expr (saved_args, arg);
+
+      /* Add a stub result type for the expression.  */
+      tree result = build_zero_cst (TREE_TYPE (ctype));
+      return compound_expr (saved_args, result);
+    }
+
   tree result = build_call_vec (TREE_TYPE (ctype), callee, args);
   SET_EXPR_LOCATION (result, input_location);
 
-  /* Enforce left to right evaluation.  */
-  if (tf->linkage == LINK::d)
-    CALL_EXPR_ARGS_ORDERED (result) = 1;
-
   result = maybe_expand_intrinsic (result);
 
   /* Return the value in a temporary slot so that it can be evaluated
@@ -2296,6 +2316,10 @@  build_vthis_function (tree basetype, tree type)
 			     TYPE_ARG_TYPES (type));
   tree fntype = build_function_type (TREE_TYPE (type), argtypes);
 
+  /* Copy volatile qualifiers from the original function type.  */
+  if (TYPE_QUALS (type) & TYPE_QUAL_VOLATILE)
+    fntype = build_qualified_type (fntype, TYPE_QUAL_VOLATILE);
+
   if (RECORD_OR_UNION_TYPE_P (basetype))
     TYPE_METHOD_BASETYPE (fntype) = TYPE_MAIN_VARIANT (basetype);
   else
diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
index 522095f12c5..b2e52c0c5e7 100644
--- a/gcc/d/d-frontend.cc
+++ b/gcc/d/d-frontend.cc
@@ -31,6 +31,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "diagnostic.h"
 
 #include "d-tree.h"
+#include "d-frontend.h"
 
 /* Implements back-end specific interfaces used by the frontend.  */
 
@@ -51,7 +52,7 @@  isBuiltin (FuncDeclaration *fd)
    Return result; NULL if cannot evaluate it.  */
 
 Expression *
-eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
+eval_builtin (const Loc &loc, FuncDeclaration *fd, Expressions *arguments)
 {
   if (fd->builtin == BUILTIN::unimp)
     return NULL;
@@ -78,10 +79,16 @@  eval_builtin (Loc loc, FuncDeclaration *fd, Expressions *arguments)
 /* Build and return typeinfo type for TYPE.  */
 
 Type *
-getTypeInfoType (Loc loc, Type *type, Scope *sc)
+getTypeInfoType (const Loc &loc, Type *type, Scope *sc)
 {
   gcc_assert (type->ty != TY::Terror);
   check_typeinfo_type (loc, sc);
   create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
   return type->vtinfo->type;
 }
+
+void
+toObjFile (Dsymbol *ds, bool)
+{
+  build_decl_tree (ds);
+}
diff --git a/gcc/d/d-gimplify.cc b/gcc/d/d-gimplify.cc
index 0fa744247ff..e3668815731 100644
--- a/gcc/d/d-gimplify.cc
+++ b/gcc/d/d-gimplify.cc
@@ -120,52 +120,47 @@  d_gimplify_addr_expr (tree *expr_p)
 static gimplify_status
 d_gimplify_call_expr (tree *expr_p, gimple_seq *pre_p)
 {
-  if (CALL_EXPR_ARGS_ORDERED (*expr_p))
-    {
-      /* Strictly evaluate all arguments from left to right.  */
-      int nargs = call_expr_nargs (*expr_p);
-      location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
+  /* Strictly evaluate all arguments from left to right.  */
+  int nargs = call_expr_nargs (*expr_p);
+  location_t loc = EXPR_LOC_OR_LOC (*expr_p, input_location);
 
-      /* No need to enforce evaluation order if only one argument.  */
-      if (nargs < 2)
-	return GS_UNHANDLED;
+  /* No need to enforce evaluation order if only one argument.  */
+  if (nargs < 2)
+    return GS_UNHANDLED;
 
-      /* Or if all arguments are already free of side-effects.  */
-      bool has_side_effects = false;
-      for (int i = 0; i < nargs; i++)
+  /* Or if all arguments are already free of side-effects.  */
+  bool has_side_effects = false;
+  for (int i = 0; i < nargs; i++)
+    {
+      if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i)))
 	{
-	  if (TREE_SIDE_EFFECTS (CALL_EXPR_ARG (*expr_p, i)))
-	    {
-	      has_side_effects = true;
-	      break;
-	    }
+	  has_side_effects = true;
+	  break;
 	}
+    }
 
-      if (!has_side_effects)
-	return GS_UNHANDLED;
-
-      /* Leave the last argument for gimplify_call_expr.  */
-      for (int i = 0; i < nargs - 1; i++)
-	{
-	  tree new_arg = CALL_EXPR_ARG (*expr_p, i);
+  if (!has_side_effects)
+    return GS_UNHANDLED;
 
-	  /* If argument has a side-effect, gimplify_arg will handle it.  */
-	  if (gimplify_arg (&new_arg, pre_p, loc) == GS_ERROR)
-	    return GS_ERROR;
+  /* Leave the last argument for gimplify_call_expr.  */
+  for (int i = 0; i < nargs - 1; i++)
+    {
+      tree new_arg = CALL_EXPR_ARG (*expr_p, i);
 
-	  /* Even if an argument itself doesn't have any side-effects, it
-	     might be altered by another argument in the list.  */
-	  if (new_arg == CALL_EXPR_ARG (*expr_p, i)
-	      && !really_constant_p (new_arg))
-	    new_arg = get_formal_tmp_var (new_arg, pre_p);
+      /* If argument has a side-effect, gimplify_arg will handle it.  */
+      if (gimplify_arg (&new_arg, pre_p, loc) == GS_ERROR)
+	return GS_ERROR;
 
-	  CALL_EXPR_ARG (*expr_p, i) = new_arg;
-	}
+      /* Even if an argument itself doesn't have any side-effects, it
+	 might be altered by another argument in the list.  */
+      if (new_arg == CALL_EXPR_ARG (*expr_p, i)
+	  && !really_constant_p (new_arg))
+	new_arg = get_formal_tmp_var (new_arg, pre_p);
 
-      return GS_OK;
+      CALL_EXPR_ARG (*expr_p, i) = new_arg;
     }
 
-  return GS_UNHANDLED;
+  return GS_OK;
 }
 
 /* Gimplify an UNSIGNED_RSHIFT_EXPR node.  */
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index dbf7a8b60b9..576eefcc01f 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -674,6 +674,7 @@  d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
     case OPT_ftransition_all:
       global.params.vfield = value;
       global.params.vgc = value;
+      global.params.vin = value;
       global.params.vmarkdown= value;
       global.params.vtls = value;
       break;
@@ -682,6 +683,10 @@  d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.vfield = value;
       break;
 
+    case OPT_ftransition_in:
+      global.params.vin = value;
+      break;
+
     case OPT_ftransition_nogc:
       global.params.vgc = value;
       break;
@@ -1176,6 +1181,14 @@  d_parse_file (void)
     {
       Module *m = modules[i];
 
+      /* If this is the `__main` module, check that `D main` hasn't already
+	 been declared in user code before running semantic on it.  */
+      if (m == main_module && global.hasMainFunction)
+	{
+	  modules.remove (i);
+	  continue;
+	}
+
       if (global.params.verbose)
 	message ("semantic  %s", m->toChars ());
 
@@ -1357,6 +1370,9 @@  d_parse_file (void)
   for (size_t i = 0; i < modules.length; i++)
     {
       Module *m = modules[i];
+
+      /* Skip generating code for header files, or when the module wasn't
+	 specified by `-fonly=`.  */
       if ((m->isHdrFile && m != main_module)
 	  || (d_option.fonly && m != Module::rootModule))
 	continue;
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
index 328b6b861d2..a5970d8a2e3 100644
--- a/gcc/d/d-tree.h
+++ b/gcc/d/d-tree.h
@@ -47,7 +47,6 @@  typedef Array <Expression *> Expressions;
 
 /* Usage of TREE_LANG_FLAG_?:
    0: METHOD_CALL_EXPR
-   1: CALL_EXPR_ARGS_ORDERED (in CALL_EXPR).
 
    Usage of TYPE_LANG_FLAG_?:
    0: TYPE_SHARED
@@ -351,11 +350,6 @@  lang_tree_node
 #define METHOD_CALL_EXPR(NODE) \
   (TREE_LANG_FLAG_0 (NODE))
 
-/* True if all arguments in a call expression should be evaluated in the
-   order they are given (left to right).  */
-#define CALL_EXPR_ARGS_ORDERED(NODE) \
-  (TREE_LANG_FLAG_1 (CALL_EXPR_CHECK (NODE)))
-
 /* True if the type was declared 'shared'.  */
 #define TYPE_SHARED(NODE) \
   (TYPE_LANG_FLAG_0 (NODE))
@@ -430,6 +424,7 @@  enum d_tree_index
 
   DTI_ARRAY_TYPE,
   DTI_NULL_ARRAY,
+  DTI_BOTTOM_TYPE,
 
   DTI_MAX
 };
@@ -465,6 +460,8 @@  extern GTY(()) tree d_global_trees[DTI_MAX];
 #define array_type_node			d_global_trees[DTI_ARRAY_TYPE]
 /* Null initializer for dynamic arrays.  */
 #define null_array_node			d_global_trees[DTI_NULL_ARRAY]
+/* The bottom type, referred to as `noreturn` in code.  */
+#define noreturn_type_node		d_global_trees[DTI_BOTTOM_TYPE]
 
 /* A prefix for internal variables, which are not user-visible.  */
 #if !defined (NO_DOT_IN_LABEL)
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index e28a581a7ec..a4976b68bf0 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -116,59 +116,6 @@  gcc_attribute_p (Dsymbol *decl)
   return false;
 }
 
-/* Subroutine of pragma declaration visitor for marking the function in the
-   defined in SYM as a global constructor or destructor.  If ISCTOR is true,
-   then we're applying pragma(crt_constructor).  */
-
-static int
-apply_pragma_crt (Dsymbol *sym, bool isctor)
-{
-  AttribDeclaration *ad = sym->isAttribDeclaration ();
-  if (ad != NULL)
-    {
-      int nested = 0;
-
-      /* Walk all declarations of the attribute scope.  */
-      Dsymbols *ds = ad->include (NULL);
-      if (ds)
-	{
-	  for (size_t i = 0; i < ds->length; i++)
-	    nested += apply_pragma_crt ((*ds)[i], isctor);
-	}
-
-      return nested;
-    }
-
-  FuncDeclaration *fd = sym->isFuncDeclaration ();
-  if (fd != NULL)
-    {
-      tree decl = get_decl_tree (fd);
-
-      /* Apply flags to the function.  */
-      if (isctor)
-	{
-	  DECL_STATIC_CONSTRUCTOR (decl) = 1;
-	  decl_init_priority_insert (decl, DEFAULT_INIT_PRIORITY);
-	}
-      else
-	{
-	  DECL_STATIC_DESTRUCTOR (decl) = 1;
-	  decl_fini_priority_insert (decl, DEFAULT_INIT_PRIORITY);
-	}
-
-      if (fd->linkage != LINK::c)
-	{
-	  error_at (make_location_t (fd->loc),
-		    "must be %<extern(C)%> for %<pragma(%s)%>",
-		    isctor ? "crt_constructor" : "crt_destructor");
-	}
-
-      return 1;
-    }
-
-  return 0;
-}
-
 /* 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
@@ -210,18 +157,18 @@  public:
 
   void visit (Module *d)
   {
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     build_module_tree (d);
-    d->semanticRun = PASSobj;
+    d->semanticRun = PASS::obj;
   }
 
   /* Write the imported symbol to debug.  */
 
   void visit (Import *d)
   {
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     /* Implements import declarations by telling the debug back-end we are
@@ -266,7 +213,7 @@  public:
 					      false, false);
       }
 
-    d->semanticRun = PASSobj;
+    d->semanticRun = PASS::obj;
   }
 
   /* Expand any local variables found in tuples.  */
@@ -312,18 +259,6 @@  public:
 			"pragma(%s) not implemented", d->ident->toChars ());
 	  }
       }
-    else if (d->ident == Identifier::idPool ("crt_constructor")
-	     || d->ident == Identifier::idPool ("crt_destructor"))
-      {
-	/* Handle pragma(crt_constructor) and pragma(crt_destructor).  Apply
-	   flag to indicate that the functions enclosed should run automatically
-	   at the beginning or end of execution.  */
-	bool isctor = (d->ident == Identifier::idPool ("crt_constructor"));
-
-	if (apply_pragma_crt (d, isctor) > 1)
-	  error_at (make_location_t (d->loc),
-		    "can only apply to a single declaration");
-      }
 
     visit ((AttribDeclaration *) d);
   }
@@ -422,7 +357,7 @@  public:
 
   void visit (StructDeclaration *d)
   {
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     if (d->type->ty == TY::Terror)
@@ -470,7 +405,7 @@  public:
     if (d->xhash)
       this->build_dsymbol (d->xhash);
 
-    d->semanticRun = PASSobj;
+    d->semanticRun = PASS::obj;
   }
 
   /* Finish semantic analysis of functions in vtbl for class CD.  */
@@ -537,7 +472,7 @@  public:
 
   void visit (ClassDeclaration *d)
   {
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     if (d->type->ty == TY::Terror)
@@ -603,7 +538,7 @@  public:
     if (TYPE_NAME (ctype))
       d_pushdecl (TYPE_NAME (ctype));
 
-    d->semanticRun = PASSobj;
+    d->semanticRun = PASS::obj;
   }
 
   /* Write out compiler generated TypeInfo and vtables for the given interface
@@ -611,7 +546,7 @@  public:
 
   void visit (InterfaceDeclaration *d)
   {
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     if (d->type->ty == TY::Terror)
@@ -646,7 +581,7 @@  public:
     if (TYPE_NAME (ctype))
       d_pushdecl (TYPE_NAME (ctype));
 
-    d->semanticRun = PASSobj;
+    d->semanticRun = PASS::obj;
   }
 
   /* Write out compiler generated TypeInfo and initializer for the given
@@ -654,7 +589,7 @@  public:
 
   void visit (EnumDeclaration *d)
   {
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     if (d->errors || d->type->ty == TY::Terror)
@@ -685,7 +620,7 @@  public:
     if (TYPE_NAME (ctype))
       d_pushdecl (TYPE_NAME (ctype));
 
-    d->semanticRun = PASSobj;
+    d->semanticRun = PASS::obj;
   }
 
   /* Finish up a variable declaration and push it into the current scope.
@@ -693,7 +628,7 @@  public:
 
   void visit (VarDeclaration *d)
   {
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     if (d->type->ty == TY::Terror)
@@ -703,6 +638,21 @@  public:
 	return;
       }
 
+    /* Variables of type `noreturn` are just placeholders, and evaluate to
+       `assert(0)` if ever read.  */
+    if (d->type->isTypeNoreturn ())
+      {
+	if (!d->isDataseg () && !d->isMember ()
+	    && d->_init && !d->_init->isVoidInitializer ())
+	  {
+	    Expression *e = d->type->defaultInitLiteral (d->loc);
+	    tree exp = build_expr (e);
+	    add_stmt (exp);
+	  }
+
+	return;
+      }
+
     if (d->aliassym)
       {
 	this->build_dsymbol (d->toAlias ());
@@ -762,7 +712,7 @@  public:
 
 	/* Frontend should have already caught this.  */
 	gcc_assert (!integer_zerop (size)
-		    || d->type->toBasetype ()->ty == TY::Tsarray);
+		    || d->type->toBasetype ()->isTypeSArray ());
 
 	d_finish_decl (decl);
 
@@ -797,7 +747,7 @@  public:
 	  }
       }
 
-    d->semanticRun = PASSobj;
+    d->semanticRun = PASS::obj;
   }
 
   /* Generate and compile a static TypeInfo declaration, but only if it is
@@ -805,7 +755,7 @@  public:
 
   void visit (TypeInfoDeclaration *d)
   {
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     if (speculative_type_p (d->tinfo))
@@ -814,7 +764,7 @@  public:
     tree t = get_typeinfo_decl (d);
     DECL_INITIAL (t) = layout_typeinfo (d);
     d_finish_decl (t);
-    d->semanticRun = PASSobj;
+    d->semanticRun = PASS::obj;
   }
 
   /* Finish up a function declaration and compile it all the way
@@ -823,7 +773,7 @@  public:
   void visit (FuncDeclaration *d)
   {
     /* Already generated the function.  */
-    if (d->semanticRun >= PASSobj)
+    if (d->semanticRun >= PASS::obj)
       return;
 
     /* Don't emit any symbols from gcc.attribute module.  */
@@ -861,7 +811,7 @@  public:
       }
 
     /* Ensure all semantic passes have run.  */
-    if (d->semanticRun < PASSsemantic3)
+    if (d->semanticRun < PASS::semantic3)
       {
 	d->functionSemantic3 ();
 	Module::runDeferredSemantic3 ();
@@ -887,8 +837,8 @@  public:
       message ("function  %s", d->toPrettyChars ());
 
     /* Start generating code for this function.  */
-    gcc_assert (d->semanticRun == PASSsemantic3done);
-    d->semanticRun = PASSobj;
+    gcc_assert (d->semanticRun == PASS::semantic3done);
+    d->semanticRun = PASS::obj;
 
     tree old_context = start_function (d);
 
@@ -927,12 +877,19 @@  public:
       }
 
     /* formal function parameters.  */
-    size_t n_parameters = d->parameters ? d->parameters->length : 0;
+    const size_t n_parameters = d->parameters ? d->parameters->length : 0;
 
     for (size_t i = 0; i < n_parameters; i++)
       {
 	VarDeclaration *param = (*d->parameters)[i];
+
 	parm_decl = get_symbol_decl (param);
+
+	/* Type `noreturn` is a terminator, as no other arguments can possibly
+	   be evaluated after it.  */
+	if (TREE_TYPE (parm_decl) == noreturn_type_node)
+	  break;
+
 	/* Chain them in the correct order.  */
 	param_list = chainon (param_list, parm_decl);
       }
@@ -1136,9 +1093,9 @@  get_symbol_decl (Declaration *decl)
 			       declaration_type (vd));
 
       /* If any alignment was set on the declaration.  */
-      if (vd->alignment != STRUCTALIGN_DEFAULT)
+      if (!vd->alignment.isDefault ())
 	{
-	  SET_DECL_ALIGN (decl->csym, vd->alignment * BITS_PER_UNIT);
+	  SET_DECL_ALIGN (decl->csym, vd->alignment.get () * BITS_PER_UNIT);
 	  DECL_USER_ALIGN (decl->csym) = 1;
 	}
 
@@ -1321,6 +1278,20 @@  get_symbol_decl (Declaration *decl)
       else if (fd->inlining == PINLINE::never)
 	DECL_UNINLINABLE (decl->csym) = 1;
 
+      /* In [pragma/crtctor], Annotates a function so it is run after the C
+	 runtime library is initialized and before the D runtime library is
+	 initialized.  */
+      if (fd->isCrtCtorDtor == 1)
+	{
+	  DECL_STATIC_CONSTRUCTOR (decl->csym) = 1;
+	  decl_init_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
+	}
+      else if (fd->isCrtCtorDtor == 2)
+	{
+	  DECL_STATIC_DESTRUCTOR (decl->csym) = 1;
+	  decl_fini_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
+       	}
+
       /* Function was declared `naked'.  */
       if (fd->naked)
 	{
@@ -1342,7 +1313,7 @@  get_symbol_decl (Declaration *decl)
 	DECL_FINAL_P (decl->csym) = 1;
 
       /* Function is of type `noreturn' or `typeof(*null)'.  */
-      if (fd->type->nextOf ()->ty == TY::Tnoreturn)
+      if (fd->type->nextOf ()->isTypeNoreturn ())
 	TREE_THIS_VOLATILE (decl->csym) = 1;
 
       /* Check whether this function is expanded by the frontend.  */
@@ -2246,9 +2217,9 @@  aggregate_initializer_decl (AggregateDeclaration *decl)
   TREE_READONLY (sinit) = 1;
 
   /* Honor struct alignment set by user.  */
-  if (sd && sd->alignment != STRUCTALIGN_DEFAULT)
+  if (sd && !sd->alignment.isDefault ())
     {
-      SET_DECL_ALIGN (sinit, sd->alignment * BITS_PER_UNIT);
+      SET_DECL_ALIGN (sinit, sd->alignment.get () * BITS_PER_UNIT);
       DECL_USER_ALIGN (sinit) = true;
     }
 
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 129050b6780..d23e1fedba4 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-b8384668f28741ad5884fc055a2bdb9c05fd95ec
+568496d5b6ed02d577dfa86f73c7bb4edee05813
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md
index 720d25683af..3cb7e127bb6 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -20,6 +20,7 @@ 
 |--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
 | [dmd/](https://github.com/dlang/dmd/tree/master/src/dmd)                 | The dmd driver and front-end                                                                                                                                                                                  |
 | [dmd/backend/](https://github.com/dlang/dmd/tree/master/src/dmd/backend) | Code generation for x86 or x86-64. Shared by the [Digital Mars C compiler](https://github.com/DigitalMars/Compiler/), but not [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). |
+| [dmd/common/](https://github.com/dlang/dmd/tree/master/src/dmd/common)   | Code shared by the front-end and back-end                                                                                                                                                                     |
 | [dmd/root/](https://github.com/dlang/dmd/tree/master/src/dmd/root)       | Meant as a portable utility library, but ["it wasn't very good and the only project left using it is dmd"](https://github.com/dlang/dmd/pull/9844#issuecomment-498479516).                                    |
 
 DMD has a mostly flat directory structure, so this section aims to divide all source files into logical groups for easier navigation.
@@ -126,6 +127,7 @@ 
 | [optimize.d](https://github.com/dlang/dmd/blob/master/src/dmd/optimize.d)     | Do constant folding more generally                                                         |
 | [dcast.d](https://github.com/dlang/dmd/blob/master/src/dmd/dcast.d)           | Implicit or explicit cast(), finding common types e.g. in `x ? a : b`, integral promotions |
 | [impcnvtab.d](https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d)   | Define an implicit conversion table for basic types                                        |
+| [importc.d](https://github.com/dlang/dmd/blob/master/src/dmd/importc.d)       | Helpers specific to ImportC                                                                |
 | [sideeffect.d](https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings.                                 |
 
 **Compile Time Function Execution (CTFE)**
@@ -243,14 +245,14 @@ 
 
 Note: many other utilities are in [dmd/root](https://github.com/dlang/dmd/tree/master/src/dmd/root).
 
-| File                                                                        | Purpose                                           |
-|-----------------------------------------------------------------------------|---------------------------------------------------|
-| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/env.d)             | Modify environment variables                      |
-| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d)     | Print error messages in color                     |
-| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/utf.d)             | Encoding/decoding Unicode text                    |
-| [filecache.d](https://github.com/dlang/dmd/blob/master/src/dmd/filecache.d) | Keep file contents in memory                      |
-| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d)         | Utility functions related to files and file paths |
-| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/complex.d)     | A complex number type                             |
+| File                                                                              | Purpose                                           |
+|-----------------------------------------------------------------------------------|---------------------------------------------------|
+| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/env.d)                   | Modify environment variables                      |
+| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d)           | Print error messages in color                     |
+| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/utf.d)                   | Encoding/decoding Unicode text                    |
+| [file_manager.d](https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d) | Keep file contents in memory                      |
+| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d)               | Utility functions related to files and file paths |
+| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/complex.d)           | A complex number type                             |
 
 | File                                                                            | Purpose                                                       |
 |---------------------------------------------------------------------------------|---------------------------------------------------------------|
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 64ce79a7c45..fa5940ed249 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@ 
-v2.097.2
+v2.098.0
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index cff4b9feb45..1fe8e809aa5 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -21,6 +21,7 @@  import dmd.aliasthis;
 import dmd.apply;
 import dmd.arraytypes;
 import dmd.astenums;
+import dmd.attrib;
 import dmd.declaration;
 import dmd.dscope;
 import dmd.dstruct;
@@ -115,11 +116,12 @@  extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
 
     AliasThis aliasthis;    /// forward unresolved lookups to aliasthis
 
-    DtorDeclarations dtors;     /// Array of destructors
-    DtorDeclaration dtor;       /// aggregate destructor calling dtors and member constructors
-    DtorDeclaration primaryDtor;/// non-deleting C++ destructor, same as dtor for D
+    DtorDeclarations userDtors; /// user-defined destructors (`~this()`) - mixins can yield multiple ones
+    DtorDeclaration aggrDtor;   /// aggregate destructor calling userDtors and fieldDtor (and base class aggregate dtor for C++ classes)
+    DtorDeclaration dtor;       /// the aggregate destructor exposed as `__xdtor` alias
+                                /// (same as aggrDtor, except for C++ classes with virtual dtor on Windows)
     DtorDeclaration tidtor;     /// aggregate destructor used in TypeInfo (must have extern(D) ABI)
-    FuncDeclaration fieldDtor;  /// aggregate destructor for just the fields
+    DtorDeclaration fieldDtor;  /// function destructing (non-inherited) fields
 
     Expression getRTInfo;   /// pointer to GC info generated by object.RTInfo(this)
 
@@ -177,7 +179,7 @@  extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
      * Returns:
      *      false if failed to determine the size.
      */
-    final bool determineSize(Loc loc)
+    final bool determineSize(const ref Loc loc)
     {
         //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
 
@@ -331,7 +333,7 @@  extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
      *      false if any errors occur.
      *      Otherwise, returns true and the missing arguments will be pushed in elements[].
      */
-    final bool fill(Loc loc, Expressions* elements, bool ctorinit)
+    final bool fill(const ref Loc loc, Expressions* elements, bool ctorinit)
     {
         //printf("AggregateDeclaration::fill() %s\n", toChars());
         assert(sizeok == Sizeok.done);
@@ -482,45 +484,52 @@  extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
      * Align sizes of 0, as we may not know array sizes yet.
      * Params:
      *   alignment = struct alignment that is in effect
-     *   size = alignment requirement of field
+     *   memalignsize = natural alignment of field
      *   poffset = pointer to offset to be aligned
      */
-    extern (D) static void alignmember(structalign_t alignment, uint size, uint* poffset) pure nothrow @safe
+    extern (D) static void alignmember(structalign_t alignment, uint memalignsize, uint* poffset) pure nothrow @safe
     {
-        //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
-        switch (alignment)
-        {
-        case cast(structalign_t)1:
-            // No alignment
-            break;
+        //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, *poffset);
+        uint alignvalue;
 
-        case cast(structalign_t)STRUCTALIGN_DEFAULT:
+        if (alignment.isDefault())
+        {
             // Alignment in Target::fieldalignsize must match what the
             // corresponding C compiler's default alignment behavior is.
-            assert(size > 0 && !(size & (size - 1)));
-            *poffset = (*poffset + size - 1) & ~(size - 1);
-            break;
-
-        default:
+            alignvalue = memalignsize;
+        }
+        else if (alignment.isPack())    // #pragma pack semantics
+        {
+            alignvalue = alignment.get();
+            if (memalignsize < alignvalue)
+                alignvalue = memalignsize;      // align to min(memalignsize, alignment)
+        }
+        else if (alignment.get() > 1)
+        {
             // Align on alignment boundary, which must be a positive power of 2
-            assert(alignment > 0 && !(alignment & (alignment - 1)));
-            *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
-            break;
+            alignvalue = alignment.get();
         }
+        else
+            return;
+
+        assert(alignvalue > 0 && !(alignvalue & (alignvalue - 1)));
+        *poffset = (*poffset + alignvalue - 1) & ~(alignvalue - 1);
     }
 
     /****************************************
-     * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
+     * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
+     * Params:
+     *    nextoffset    = location just past the end of the previous field in the aggregate.
+     *                    Updated to be just past the end of this field to be placed, i.e. the future nextoffset
+     *    memsize       = size of field
+     *    memalignsize  = natural alignment of field
+     *    alignment     = alignment in effect for this field
+     *    paggsize      = size of aggregate (updated)
+     *    paggalignsize = alignment of aggregate (updated)
+     *    isunion       = the aggregate is a union
      * Returns:
-     *      offset to place field at
+     *    aligned offset to place field at
      *
-     * nextoffset:    next location in aggregate
-     * memsize:       size of member
-     * memalignsize:  natural alignment of member
-     * alignment:     alignment in effect for this member
-     * paggsize:      size of aggregate (updated)
-     * paggalignsize: alignment of aggregate (updated)
-     * isunion:       the aggregate is a union
      */
     extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
         structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
@@ -528,7 +537,8 @@  extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         uint ofs = *nextoffset;
 
         const uint actualAlignment =
-            alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
+            alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get()
+                        ? memalignsize : alignment.get();
 
         // Ensure no overflow
         bool overflow;
@@ -536,7 +546,10 @@  extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         addu(ofs, sz, overflow);
         if (overflow) assert(0);
 
-        alignmember(alignment, memalignsize, &ofs);
+        // Skip no-op for noreturn without custom aligment
+        if (memsize != 0 || !alignment.isDefault())
+            alignmember(alignment, memalignsize, &ofs);
+
         uint memoffset = ofs;
         ofs += memsize;
         if (ofs > *paggsize)
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index f8d2f45706a..48e5f4a8062 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -105,11 +105,12 @@  public:
 
     AliasThis *aliasthis;       // forward unresolved lookups to aliasthis
 
-    DtorDeclarations dtors;     // Array of destructors
-    DtorDeclaration *dtor;      // aggregate destructor
-    DtorDeclaration *primaryDtor; // non-deleting C++ destructor, same as dtor for D
+    DtorDeclarations userDtors; // user-defined destructors (`~this()`) - mixins can yield multiple ones
+    DtorDeclaration *aggrDtor;  // aggregate destructor calling userDtors and fieldDtor (and base class aggregate dtor for C++ classes)
+    DtorDeclaration *dtor;      // the aggregate destructor exposed as `__xdtor` alias
+                                // (same as aggrDtor, except for C++ classes with virtual dtor on Windows)
     DtorDeclaration *tidtor;    // aggregate destructor used in TypeInfo (must have extern(D) ABI)
-    FuncDeclaration *fieldDtor;   // aggregate destructor for just the fields
+    DtorDeclaration *fieldDtor; // function destructing (non-inherited) fields
 
     Expression *getRTInfo;      // pointer to GC info generated by object.RTInfo(this)
 
@@ -121,10 +122,10 @@  public:
     virtual Scope *newScope(Scope *sc);
     void setScope(Scope *sc);
     size_t nonHiddenFields();
-    bool determineSize(Loc loc);
+    bool determineSize(const Loc &loc);
     virtual void finalizeSize() = 0;
     d_uns64 size(const Loc &loc);
-    bool fill(Loc loc, Expressions *elements, bool ctorinit);
+    bool fill(const Loc &loc, Expressions *elements, bool ctorinit);
     Type *getType();
     bool isDeprecated() const;         // is aggregate deprecated?
     void setDeprecated();
@@ -184,7 +185,7 @@  public:
     // ABI-specific type(s) if the struct can be passed in registers
     TypeTuple *argTypes;
 
-    static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
+    static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject);
     StructDeclaration *syntaxCopy(Dsymbol *s);
     Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
     const char *kind() const;
@@ -277,7 +278,7 @@  public:
     ObjcClassDeclaration objc;          // Data for a class declaration that is needed for the Objective-C integration
     Symbol *cpp_type_info_ptr_sym;      // cached instance of class Id.cpp_type_info_ptr
 
-    static ClassDeclaration *create(Loc loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
+    static ClassDeclaration *create(const Loc &loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
     const char *toPrettyChars(bool QualifyTypes = false);
     ClassDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d
index 81e0d7e64be..e048cdc2e1b 100644
--- a/gcc/d/dmd/aliasthis.d
+++ b/gcc/d/dmd/aliasthis.d
@@ -72,17 +72,32 @@  extern (C++) final class AliasThis : Dsymbol
     }
 }
 
-Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false)
+/*************************************
+ * Find the `alias this` symbol of e's type.
+ * Params:
+ *      sc = context
+ *      e = expression forming the `this`
+ *      gag = if true do not print errors, return null instead
+ *      findOnly = don't do further processing like resolving properties,
+ *                 i.e. just return plain dotExp() result.
+ * Returns:
+ *      Expression that is `e.aliasthis`
+ */
+Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
 {
+    import dmd.typesem : dotExp;
     for (AggregateDeclaration ad = isAggregate(e.type); ad;)
     {
         if (ad.aliasthis)
         {
-            uint olderrors = gag ? global.startGagging() : 0;
             Loc loc = e.loc;
             Type tthis = (e.op == TOK.type ? e.type : null);
-            e = new DotIdExp(loc, e, ad.aliasthis.ident);
-            e = e.expressionSemantic(sc);
+            const flags = DotExpFlag.noAliasThis | (gag ? DotExpFlag.gag : 0);
+            uint olderrors = gag ? global.startGagging() : 0;
+            e = dotExp(e.type, sc, e, ad.aliasthis.ident, flags);
+            if (!e || findOnly)
+                return gag && global.endGagging(olderrors) ? null : e;
+
             if (tthis && ad.aliasthis.sym.needThis())
             {
                 if (e.op == TOK.variable)
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index 66be73ea21f..e2b33194f06 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -26,7 +26,7 @@  import dmd.globals;
 import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.statement;
 import dmd.tokens;
 import dmd.visitor;
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index ae8f65b6daa..0bf40ef9a72 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -42,7 +42,7 @@  import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
 import dmd.objc; // for objc.addSymbols
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.target; // for target.systemLinkage
 import dmd.tokens;
 import dmd.visitor;
@@ -696,12 +696,9 @@  extern (C++) final class AlignDeclaration : AttribDeclaration
 {
     Expressions* exps;                              /// Expression(s) yielding the desired alignment,
                                                     /// the largest value wins
-    enum structalign_t UNKNOWN = 0;                 /// alignment not yet computed
-    static assert(STRUCTALIGN_DEFAULT != UNKNOWN);
-
-    /// the actual alignment, `UNKNOWN` until it's either set to the value of `ealign`
-    /// or `STRUCTALIGN_DEFAULT` if `ealign` is null ( / an error ocurred)
-    structalign_t salign = UNKNOWN;
+    /// the actual alignment is Unknown until it's either set to the value of `ealign`
+    /// or the default if `ealign` is null ( / an error ocurred)
+    structalign_t salign;
 
 
     extern (D) this(const ref Loc loc, Expression exp, Dsymbols* decl)
@@ -709,8 +706,7 @@  extern (C++) final class AlignDeclaration : AttribDeclaration
         super(loc, null, decl);
         if (exp)
         {
-            if (!exps)
-                exps = new Expressions();
+            exps = new Expressions();
             exps.push(exp);
         }
     }
@@ -721,6 +717,12 @@  extern (C++) final class AlignDeclaration : AttribDeclaration
         this.exps = exps;
     }
 
+    extern (D) this(const ref Loc loc, structalign_t salign, Dsymbols* decl)
+    {
+        super(loc, null, decl);
+        this.salign = salign;
+    }
+
     override AlignDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
@@ -1196,7 +1198,7 @@  extern (C++) final class StaticForeachDeclaration : AttribDeclaration
 
         // expand static foreach
         import dmd.statementsem: makeTupleForeach;
-        Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion);
+        Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion).decl;
         if (d) // process generated declarations
         {
             // Add members lazily.
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index 1fd90051830..0ecd6351f7d 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -108,7 +108,7 @@  int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
                         return;
                     }
                 }
-                if (s.exp.type.toBasetype().isTypeNoreturn())
+                if (s.exp.type && s.exp.type.toBasetype().isTypeNoreturn())
                     result = BE.halt;
                 if (canThrow(s.exp, func, mustNotThrow))
                     result |= BE.throw_;
@@ -146,7 +146,7 @@  int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
                             else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
                             {
                             }
-                            else
+                            else if (!func.getModule().isCFile)
                             {
                                 const(char)* gototype = s.isCaseStatement() ? "case" : "default";
                                 s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
diff --git a/gcc/d/dmd/builtin.d b/gcc/d/dmd/builtin.d
index b99f690e156..c4f84b12968 100644
--- a/gcc/d/dmd/builtin.d
+++ b/gcc/d/dmd/builtin.d
@@ -30,4 +30,4 @@  public extern (C++) BUILTIN isBuiltin(FuncDeclaration fd);
  * Evaluate builtin function.
  * Return result; NULL if cannot evaluate it.
  */
-public extern (C++) Expression eval_builtin(Loc loc, FuncDeclaration fd, Expressions* arguments);
+public extern (C++) Expression eval_builtin(const ref Loc loc, FuncDeclaration fd, Expressions* arguments);
diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d
index 97adc5ad8ac..b168b4f7e0a 100644
--- a/gcc/d/dmd/chkformat.d
+++ b/gcc/d/dmd/chkformat.d
@@ -690,8 +690,8 @@  Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
                 return error();
             while ('0' <= format[i] && format[i] <= '9')
             {
-               ++i;
-               if (i == length)
+                ++i;
+                if (i == length)
                     return error();
             }
         }
@@ -720,8 +720,8 @@  Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
                 return error();
             while ('0' <= format[i] && format[i] <= '9')
             {
-               ++i;
-               if (i == length)
+                ++i;
+                if (i == length)
                     return error();
             }
         }
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index d3006170be7..da66812b954 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -794,6 +794,19 @@  FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
     if (!needToHash(sd))
         return null;
 
+    /* The trouble is that the following code relies on .tupleof, but .tupleof
+     * is not allowed for C files. If we allow it for C files, then that turns on
+     * the other D properties, too, such as .dup which will then conflict with allowed
+     * field names.
+     * One way to fix it is to replace the following foreach and .tupleof with C
+     * statements and expressions.
+     * But, it's debatable whether C structs should even need toHash().
+     * Note that it would only be necessary if it has floating point fields.
+     * For now, we'll just not generate a toHash() for C files.
+     */
+    if (sc.flags & SCOPE.Cfile)
+        return null;
+
     //printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars());
     Loc declLoc; // loc is unnecessary so __xtoHash is never called directly
     Loc loc; // internal code should have no loc to prevent coverage
@@ -831,31 +844,31 @@  FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
 }
 
 /*****************************************
- * Create inclusive destructor for struct/class by aggregating
- * all the destructors in dtors[] with the destructors for
+ * Create aggregate destructor for struct/class by aggregating
+ * all the destructors in userDtors[] with the destructors for
  * all the members.
+ * Sets ad's fieldDtor, aggrDtor, dtor and tidtor fields.
  * Params:
  *      ad = struct or class to build destructor for
  *      sc = context
- * Returns:
- *      generated function, null if none needed
  * Note:
  * Close similarity with StructDeclaration::buildPostBlit(),
  * and the ordering changes (runs backward instead of forwards).
  */
-DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
+void buildDtors(AggregateDeclaration ad, Scope* sc)
 {
     //printf("AggregateDeclaration::buildDtor() %s\n", ad.toChars());
     if (ad.isUnionDeclaration())
-        return null;                    // unions don't have destructors
+        return;                    // unions don't have destructors
 
     StorageClass stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
-    Loc declLoc = ad.dtors.dim ? ad.dtors[0].loc : ad.loc;
+    Loc declLoc = ad.userDtors.dim ? ad.userDtors[0].loc : ad.loc;
     Loc loc; // internal code should have no loc to prevent coverage
     FuncDeclaration xdtor_fwd = null;
 
-    // if the dtor is an extern(C++) prototype, then we expect it performs a full-destruction; we don't need to build a full-dtor
-    const bool dtorIsCppPrototype = ad.dtors.dim == 1 && ad.dtors[0].linkage == LINK.cpp && !ad.dtors[0].fbody;
+    // Build the field destructor (`ad.fieldDtor`), if needed.
+    // If the user dtor is an extern(C++) prototype, then we expect it performs a full-destruction and skip building.
+    const bool dtorIsCppPrototype = ad.userDtors.dim && ad.userDtors[0].linkage == LINK.cpp && !ad.userDtors[0].fbody;
     if (!dtorIsCppPrototype)
     {
         Expression e = null;
@@ -936,36 +949,6 @@  DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
             e = Expression.combine(ex, e); // combine in reverse order
         }
 
-        /* extern(C++) destructors call into super to destruct the full hierarchy
-        */
-        ClassDeclaration cldec = ad.isClassDeclaration();
-        if (cldec && cldec.classKind == ClassKind.cpp && cldec.baseClass && cldec.baseClass.primaryDtor)
-        {
-            // WAIT BUT: do I need to run `cldec.baseClass.dtor` semantic? would it have been run before?
-            cldec.baseClass.dtor.functionSemantic();
-
-            stc = mergeFuncAttrs(stc, cldec.baseClass.primaryDtor);
-            if (!(stc & STC.disable))
-            {
-                // super.__xdtor()
-
-                Expression ex = new SuperExp(loc);
-
-                // This is a hack so we can call destructors on const/immutable objects.
-                // Do it as a type 'paint'.
-                ex = new CastExp(loc, ex, cldec.baseClass.type.mutableOf());
-                if (stc & STC.safe)
-                    stc = (stc & ~STC.safe) | STC.trusted;
-
-                ex = new DotVarExp(loc, ex, cldec.baseClass.primaryDtor, false);
-                ex = new CallExp(loc, ex);
-
-                e = Expression.combine(e, ex); // super dtor last
-            }
-        }
-
-        /* Build our own "destructor" which executes e
-         */
         if (e || (stc & STC.disable))
         {
             //printf("Building __fieldDtor(), %s\n", e.toChars());
@@ -973,29 +956,45 @@  DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
             dd.generated = true;
             dd.storage_class |= STC.inference;
             dd.fbody = new ExpStatement(loc, e);
-            ad.dtors.shift(dd);
             ad.members.push(dd);
             dd.dsymbolSemantic(sc);
             ad.fieldDtor = dd;
         }
     }
 
-    DtorDeclaration xdtor = null;
-    switch (ad.dtors.dim)
+    // Generate list of dtors to call in that order
+    DtorDeclarations dtors;
+    foreach_reverse (userDtor; ad.userDtors[])
+        dtors.push(userDtor);
+    if (ad.fieldDtor)
+        dtors.push(ad.fieldDtor);
+    if (!dtorIsCppPrototype)
+    {
+        // extern(C++) destructors call into super to destruct the full hierarchy
+        ClassDeclaration cldec = ad.isClassDeclaration();
+        if (cldec && cldec.classKind == ClassKind.cpp && cldec.baseClass && cldec.baseClass.aggrDtor)
+            dtors.push(cldec.baseClass.aggrDtor);
+    }
+
+    // Set/build `ad.aggrDtor`
+    switch (dtors.dim)
     {
     case 0:
         break;
 
     case 1:
-        xdtor = ad.dtors[0];
+        // Use the single existing dtor directly as aggregate dtor.
+        // Note that this might be `cldec.baseClass.aggrDtor`.
+        ad.aggrDtor = dtors[0];
         break;
 
     default:
+        // Build the aggregate destructor, calling all dtors in order.
         assert(!dtorIsCppPrototype);
         Expression e = null;
         e = null;
         stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
-        foreach (FuncDeclaration fd; ad.dtors)
+        foreach (FuncDeclaration fd; dtors)
         {
             stc = mergeFuncAttrs(stc, fd);
             if (stc & STC.disable)
@@ -1005,8 +1004,9 @@  DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
             }
             Expression ex = new ThisExp(loc);
             ex = new DotVarExp(loc, ex, fd, false);
-            ex = new CallExp(loc, ex);
-            e = Expression.combine(ex, e);
+            CallExp ce = new CallExp(loc, ex);
+            ce.directcall = true;
+            e = Expression.combine(e, ce);
         }
         auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor);
         dd.generated = true;
@@ -1014,19 +1014,20 @@  DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
         dd.fbody = new ExpStatement(loc, e);
         ad.members.push(dd);
         dd.dsymbolSemantic(sc);
-        xdtor = dd;
+        ad.aggrDtor = dd;
         break;
     }
 
-    ad.primaryDtor = xdtor;
-
-    if (xdtor && xdtor.linkage == LINK.cpp && !target.cpp.twoDtorInVtable)
-        xdtor = buildWindowsCppDtor(ad, xdtor, sc);
+    // Set/build `ad.dtor`.
+    // On Windows, the dtor in the vtable is a shim with different signature.
+    ad.dtor = (ad.aggrDtor && ad.aggrDtor.linkage == LINK.cpp && !target.cpp.twoDtorInVtable)
+        ? buildWindowsCppDtor(ad, ad.aggrDtor, sc)
+        : ad.aggrDtor;
 
-    // Add an __xdtor alias to make the inclusive dtor accessible
-    if (xdtor)
+    // Add an __xdtor alias to make `ad.dtor` accessible
+    if (ad.dtor)
     {
-        auto _alias = new AliasDeclaration(Loc.initial, Id.__xdtor, xdtor);
+        auto _alias = new AliasDeclaration(Loc.initial, Id.__xdtor, ad.dtor);
         _alias.dsymbolSemantic(sc);
         ad.members.push(_alias);
         if (xdtor_fwd)
@@ -1035,7 +1036,8 @@  DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
             _alias.addMember(sc, ad); // add to symbol table
     }
 
-    return xdtor;
+    // Set/build `ad.tidtor`
+    ad.tidtor = buildExternDDtor(ad, sc);
 }
 
 /**
@@ -1069,17 +1071,16 @@  private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
     auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, dtor.storage_class);
     auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.cppdtor);
     func.type = ftype;
-    if (dtor.fbody)
-    {
-        const loc = dtor.loc;
-        auto stmts = new Statements;
-        auto call = new CallExp(loc, dtor, null);
-        call.directcall = true;
-        stmts.push(new ExpStatement(loc, call));
-        stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
-        func.fbody = new CompoundStatement(loc, stmts);
-        func.generated = true;
-    }
+
+    // Always generate the function with body, because it is not exported from DLLs.
+    const loc = dtor.loc;
+    auto stmts = new Statements;
+    auto call = new CallExp(loc, dtor, null);
+    call.directcall = true;
+    stmts.push(new ExpStatement(loc, call));
+    stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
+    func.fbody = new CompoundStatement(loc, stmts);
+    func.generated = true;
 
     auto sc2 = sc.push();
     sc2.stc &= ~STC.static_; // not a static destructor
@@ -1094,7 +1095,7 @@  private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
 }
 
 /**
- * build a shim function around the compound dtor that translates
+ * build a shim function around the aggregate dtor that translates
  *  a C++ destructor to a destructor with extern(D) calling convention
  *
  * Params:
@@ -1104,9 +1105,9 @@  private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara
  * Returns:
  *  the shim destructor, semantically analyzed and added to the class as a member
  */
-DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
+private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
 {
-    auto dtor = ad.primaryDtor;
+    auto dtor = ad.aggrDtor;
     if (!dtor)
         return null;
 
diff --git a/gcc/d/dmd/common/README.md b/gcc/d/dmd/common/README.md
new file mode 100644
index 00000000000..a9b65c3dd8d
--- /dev/null
+++ b/gcc/d/dmd/common/README.md
@@ -0,0 +1,7 @@ 
+# Table of contents
+
+| File                                                                               | Purpose                                                         |
+|------------------------------------------------------------------------------------|-----------------------------------------------------------------|
+| [file.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d)           | Functions and objects dedicated to file I/O and management      |
+| [outbuffer.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data |
+| [string.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d)       | Common string functions including filename manipulation         |
diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d
new file mode 100644
index 00000000000..b8cde375736
--- /dev/null
+++ b/gcc/d/dmd/common/file.d
@@ -0,0 +1,576 @@ 
+/**
+ * File utilities.
+ *
+ * Functions and objects dedicated to file I/O and management. TODO: Move here artifacts
+ * from places such as root/ so both the frontend and the backend have access to them.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors:   Walter Bright, http://www.digitalmars.com
+ * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d, common/_file.d)
+ * Documentation: https://dlang.org/phobos/dmd_common_file.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/file.d
+ */
+
+module dmd.common.file;
+
+import core.stdc.errno : errno;
+import core.stdc.stdio : fprintf, remove, rename, stderr;
+import core.stdc.stdlib : exit;
+import core.stdc.string : strerror;
+import core.sys.windows.winbase;
+import core.sys.windows.winnt;
+import core.sys.posix.fcntl;
+import core.sys.posix.unistd;
+
+import dmd.common.string;
+
+/**
+Encapsulated management of a memory-mapped file.
+
+Params:
+Datum = the mapped data type: Use a POD of size 1 for read/write mapping
+and a `const` version thereof for read-only mapping. Other primitive types
+should work, but have not been yet tested.
+*/
+struct FileMapping(Datum)
+{
+    static assert(__traits(isPOD, Datum) && Datum.sizeof == 1,
+        "Not tested with other data types yet. Add new types with care.");
+
+    version(Posix) enum invalidHandle = -1;
+    else version(Windows) enum invalidHandle = INVALID_HANDLE_VALUE;
+
+    // state {
+    /// Handle of underlying file
+    private auto handle = invalidHandle;
+    /// File mapping object needed on Windows
+    version(Windows) private HANDLE fileMappingObject = invalidHandle;
+    /// Memory-mapped array
+    private Datum[] data;
+    /// Name of underlying file, zero-terminated
+    private const(char)* name;
+    // state }
+
+    /**
+    Open `filename` and map it in memory. If `Datum` is `const`, opens for
+    read-only and maps the content in memory; no error is issued if the file
+    does not exist. This makes it easy to treat a non-existing file as empty.
+
+    If `Datum` is mutable, opens for read/write (creates file if it does not
+    exist) and fails fatally on any error.
+
+    Due to quirks in `mmap`, if the file is empty, `handle` is valid but `data`
+    is `null`. This state is valid and accounted for.
+
+    Params:
+    filename = the name of the file to be mapped in memory
+    */
+    this(const char* filename)
+    {
+        version (Posix)
+        {
+            import core.sys.posix.sys.mman;
+            import core.sys.posix.fcntl : open, O_CREAT, O_RDONLY, O_RDWR, S_IRGRP, S_IROTH, S_IRUSR, S_IWUSR;
+
+            handle = open(filename, is(Datum == const) ? O_RDONLY : (O_CREAT | O_RDWR),
+                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+            if (handle == invalidHandle)
+            {
+                static if (is(Datum == const))
+                {
+                    // No error, nonexisting file in read mode behaves like an empty file.
+                    return;
+                }
+                else
+                {
+                    fprintf(stderr, "open(\"%s\") failed: %s\n", filename, strerror(errno));
+                    exit(1);
+                }
+            }
+
+            const size = fileSize(handle);
+
+            if (size > 0 && size != ulong.max && size <= size_t.max)
+            {
+                auto p = mmap(null, cast(size_t) size, is(Datum == const) ? PROT_READ : PROT_WRITE, MAP_SHARED, handle, 0);
+                if (p == MAP_FAILED)
+                {
+                    fprintf(stderr, "mmap(null, %zu) for \"%s\" failed: %s\n", cast(size_t) size, filename, strerror(errno));
+                    exit(1);
+                }
+                // The cast below will always work because it's gated by the `size <= size_t.max` condition.
+                data = cast(Datum[]) p[0 .. cast(size_t) size];
+            }
+        }
+        else version(Windows)
+        {
+            static if (is(Datum == const))
+            {
+                enum createFileMode = GENERIC_READ;
+                enum openFlags = OPEN_EXISTING;
+            }
+            else
+            {
+                enum createFileMode = GENERIC_READ | GENERIC_WRITE;
+                enum openFlags = CREATE_ALWAYS;
+            }
+
+            handle = filename.asDString.extendedPathThen!(p => CreateFileW(p.ptr, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null));
+            if (handle == invalidHandle)
+            {
+                static if (is(Datum == const))
+                {
+                    return;
+                }
+                else
+                {
+                    fprintf(stderr, "CreateFileW() failed for \"%s\": %d\n", filename, GetLastError());
+                    exit(1);
+                }
+            }
+            createMapping(filename, fileSize(handle));
+        }
+        else static assert(0);
+
+        // Save the name for later. Technically there's no need: on Linux one can use readlink on /proc/self/fd/NNN.
+        // On BSD and OSX one can use fcntl with F_GETPATH. On Windows one can use GetFileInformationByHandleEx.
+        // But just saving the name is simplest, fastest, and most portable...
+        import core.stdc.string : strlen;
+        import core.stdc.stdlib : malloc;
+        import core.stdc.string : memcpy;
+        auto totalNameLength = filename.strlen() + 1;
+        name = cast(char*) memcpy(malloc(totalNameLength), filename, totalNameLength);
+        name || assert(0, "FileMapping: Out of memory.");
+    }
+
+    /**
+    Common code factored opportunistically. Windows only. Assumes `handle` is
+    already pointing to an opened file. Initializes the `fileMappingObject`
+    and `data` members.
+
+    Params:
+    filename = the file to be mapped
+    size = the size of the file in bytes
+    */
+    version(Windows) private void createMapping(const char* filename, ulong size)
+    {
+        assert(size <= size_t.max || size == ulong.max);
+        assert(handle != invalidHandle);
+        assert(data is null);
+        assert(fileMappingObject == invalidHandle);
+
+        if (size == 0 || size == ulong.max)
+            return;
+
+        static if (is(Datum == const))
+        {
+            enum fileMappingFlags = PAGE_READONLY;
+            enum mapViewFlags = FILE_MAP_READ;
+        }
+        else
+        {
+            enum fileMappingFlags = PAGE_READWRITE;
+            enum mapViewFlags = FILE_MAP_WRITE;
+        }
+
+        fileMappingObject = CreateFileMappingW(handle, null, fileMappingFlags, 0, 0, null);
+        if (!fileMappingObject)
+        {
+            fprintf(stderr, "CreateFileMappingW(%p) failed for %llu bytes of \"%s\": %d\n",
+                handle, size, filename, GetLastError());
+            fileMappingObject = invalidHandle;  // by convention always use invalidHandle, not null
+            exit(1);
+        }
+        auto p = MapViewOfFile(fileMappingObject, mapViewFlags, 0, 0, 0);
+        if (!p)
+        {
+            fprintf(stderr, "MapViewOfFile() failed for \"%s\": %d\n", filename, GetLastError());
+            exit(1);
+        }
+        data = cast(Datum[]) p[0 .. cast(size_t) size];
+    }
+
+    // Not copyable or assignable (for now).
+    @disable this(const FileMapping!Datum rhs);
+    @disable void opAssign(const ref FileMapping!Datum rhs);
+
+    /**
+    Frees resources associated with this mapping. However, it does not deallocate the name.
+    */
+    ~this() pure nothrow
+    {
+        if (!active)
+            return;
+        fakePure({
+            version (Posix)
+            {
+                import core.sys.posix.sys.mman : munmap;
+                import core.sys.posix.unistd : close;
+
+                // Cannot call fprintf from inside a destructor, so exiting silently.
+
+                if (data.ptr && munmap(cast(void*) data.ptr, data.length) != 0)
+                {
+                    exit(1);
+                }
+                data = null;
+                if (handle != invalidHandle && close(handle) != 0)
+                {
+                    exit(1);
+                }
+                handle = invalidHandle;
+            }
+            else version(Windows)
+            {
+                if (data.ptr !is null && UnmapViewOfFile(cast(void*) data.ptr) == 0)
+                {
+                    exit(1);
+                }
+                data = null;
+                if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
+                {
+                    exit(1);
+                }
+                fileMappingObject = invalidHandle;
+                if (handle != invalidHandle && CloseHandle(handle) == 0)
+                {
+                    exit(1);
+                }
+                handle = invalidHandle;
+            }
+            else static assert(0);
+        });
+    }
+
+    /**
+    Returns the zero-terminated file name associated with the mapping. Can NOT
+    be saved beyond the lifetime of `this`.
+    */
+    private const(char)* filename() const pure @nogc @safe nothrow { return name; }
+
+    /**
+    Frees resources associated with this mapping. However, it does not deallocate the name.
+    Reinitializes `this` as a fresh object that can be reused.
+    */
+    void close()
+    {
+        __dtor();
+        handle = invalidHandle;
+        version(Windows) fileMappingObject = invalidHandle;
+        data = null;
+        name = null;
+    }
+
+    /**
+    Deletes the underlying file and frees all resources associated.
+    Reinitializes `this` as a fresh object that can be reused.
+
+    This function does not abort if the file cannot be deleted, but does print
+    a message on `stderr` and returns `false` to the caller. The underlying
+    rationale is to give the caller the option to continue execution if
+    deleting the file is not important.
+
+    Returns: `true` iff the file was successfully deleted. If the file was not
+    deleted, prints a message to `stderr` and returns `false`.
+    */
+    static if (!is(Datum == const))
+    bool discard()
+    {
+        // Truncate file to zero so unflushed buffers are not flushed unnecessarily.
+        resize(0);
+        auto deleteme = name;
+        close();
+        // In-memory resource freed, now get rid of the underlying temp file.
+        version(Posix)
+        {
+            import core.sys.posix.unistd : unlink;
+            if (unlink(deleteme) != 0)
+            {
+                fprintf(stderr, "unlink(\"%s\") failed: %s\n", filename, strerror(errno));
+                return false;
+            }
+        }
+        else version(Windows)
+        {
+            import core.sys.windows.winbase;
+            if (deleteme.asDString.extendedPathThen!(p => DeleteFileW(p.ptr)) == 0)
+            {
+                fprintf(stderr, "DeleteFileW error %d\n", GetLastError());
+                return false;
+            }
+        }
+        else static assert(0);
+        return true;
+    }
+
+    /**
+    Queries whether `this` is currently associated with a file.
+
+    Returns: `true` iff there is an active mapping.
+    */
+    bool active() const pure @nogc nothrow
+    {
+        return handle !is invalidHandle;
+    }
+
+    /**
+    Queries the length of the file associated with this mapping.  If not
+    active, returns 0.
+
+    Returns: the length of the file, or 0 if no file associated.
+    */
+    size_t length() const pure @nogc @safe nothrow { return data.length; }
+
+    /**
+    Get a slice to the contents of the entire file.
+
+    Returns: the contents of the file. If not active, returns the `null` slice.
+    */
+    auto opSlice() pure @nogc @safe nothrow { return data; }
+
+    /**
+    Resizes the file and mapping to the specified `size`.
+
+    Params:
+    size = new length requested
+    */
+    static if (!is(Datum == const))
+    void resize(size_t size) pure
+    {
+        assert(handle != invalidHandle);
+        fakePure({
+            version(Posix)
+            {
+                import core.sys.posix.unistd : ftruncate;
+                import core.sys.posix.sys.mman;
+
+                if (data.length)
+                {
+                    assert(data.ptr, "Corrupt memory mapping");
+                    // assert(0) here because it would indicate an internal error
+                    munmap(cast(void*) data.ptr, data.length) == 0 || assert(0);
+                    data = null;
+                }
+                if (ftruncate(handle, size) != 0)
+                {
+                    fprintf(stderr, "ftruncate() failed for \"%s\": %s\n", filename, strerror(errno));
+                    exit(1);
+                }
+                if (size > 0)
+                {
+                    auto p = mmap(null, size, PROT_WRITE, MAP_SHARED, handle, 0);
+                    if (cast(ssize_t) p == -1)
+                    {
+                        fprintf(stderr, "mmap() failed for \"%s\": %s\n", filename, strerror(errno));
+                        exit(1);
+                    }
+                    data = cast(Datum[]) p[0 .. size];
+                }
+            }
+            else version(Windows)
+            {
+                // Per documentation, must unmap first.
+                if (data.length > 0 && UnmapViewOfFile(cast(void*) data.ptr) == 0)
+                {
+                    fprintf(stderr, "UnmapViewOfFile(%p) failed for memory mapping of \"%s\": %d\n",
+                        data.ptr, filename, GetLastError());
+                    exit(1);
+                }
+                data = null;
+                if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
+                {
+                    fprintf(stderr, "CloseHandle() failed for memory mapping of \"%s\": %d\n", filename, GetLastError());
+                    exit(1);
+                }
+                fileMappingObject = invalidHandle;
+                LARGE_INTEGER biggie;
+                biggie.QuadPart = size;
+                if (SetFilePointerEx(handle, biggie, null, FILE_BEGIN) == 0 || SetEndOfFile(handle) == 0)
+                {
+                    fprintf(stderr, "SetFilePointer() failed for \"%s\": %d\n", filename, GetLastError());
+                    exit(1);
+                }
+                createMapping(name, size);
+            }
+            else static assert(0);
+        });
+    }
+
+    /**
+    Unconditionally and destructively moves the underlying file to `filename`.
+    If the operation succeeds, returns true. Upon failure, prints a message to
+    `stderr` and returns `false`. In all cases it closes the underlying file.
+
+    Params: filename = zero-terminated name of the file to move to.
+
+    Returns: `true` iff the operation was successful.
+    */
+    bool moveToFile(const char* filename)
+    {
+        assert(name !is null);
+
+        // Fetch the name and then set it to `null` so it doesn't get deallocated
+        auto oldname = name;
+        import core.stdc.stdlib;
+        scope(exit) free(cast(void*) oldname);
+        name = null;
+        close();
+
+        // Rename the underlying file to the target, no copy necessary.
+        version(Posix)
+        {
+            if (.rename(oldname, filename) != 0)
+            {
+                fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", oldname, filename, strerror(errno));
+                return false;
+            }
+        }
+        else version(Windows)
+        {
+            import core.sys.windows.winbase;
+            auto r = oldname.asDString.extendedPathThen!(
+                p1 => filename.asDString.extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING))
+            );
+            if (r == 0)
+            {
+                fprintf(stderr, "MoveFileExW(\"%s\", \"%s\") failed: %d\n", oldname, filename, GetLastError());
+                return false;
+            }
+        }
+        else static assert(0);
+        return true;
+    }
+}
+
+/// Write a file, returning `true` on success.
+extern(D) static bool writeFile(const(char)* name, const void[] data) nothrow
+{
+    version (Posix)
+    {
+        int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
+        if (fd == -1)
+            goto err;
+        if (.write(fd, data.ptr, data.length) != data.length)
+            goto err2;
+        if (close(fd) == -1)
+            goto err;
+        return true;
+    err2:
+        close(fd);
+        .remove(name);
+    err:
+        return false;
+    }
+    else version (Windows)
+    {
+        DWORD numwritten; // here because of the gotos
+        const nameStr = name.asDString;
+        // work around Windows file path length limitation
+        // (see documentation for extendedPathThen).
+        HANDLE h = nameStr.extendedPathThen!
+            (p => CreateFileW(p.ptr,
+                                GENERIC_WRITE,
+                                0,
+                                null,
+                                CREATE_ALWAYS,
+                                FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+                                null));
+        if (h == INVALID_HANDLE_VALUE)
+            goto err;
+
+        if (WriteFile(h, data.ptr, cast(DWORD)data.length, &numwritten, null) != TRUE)
+            goto err2;
+        if (numwritten != data.length)
+            goto err2;
+        if (!CloseHandle(h))
+            goto err;
+        return true;
+    err2:
+        CloseHandle(h);
+        nameStr.extendedPathThen!(p => DeleteFileW(p.ptr));
+    err:
+        return false;
+    }
+    else
+    {
+        static assert(0);
+    }
+}
+
+/// Touch a file to current date
+bool touchFile(const char* namez)
+{
+    version (Windows)
+    {
+        FILETIME ft = void;
+        SYSTEMTIME st = void;
+        GetSystemTime(&st);
+        SystemTimeToFileTime(&st, &ft);
+
+        import core.stdc.string : strlen;
+
+        // get handle to file
+        HANDLE h = namez[0 .. namez.strlen()].extendedPathThen!(p => CreateFile(p.ptr,
+            FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE,
+            null, OPEN_EXISTING,
+            FILE_ATTRIBUTE_NORMAL, null));
+        if (h == INVALID_HANDLE_VALUE)
+            return false;
+
+        const f = SetFileTime(h, null, null, &ft); // set last write time
+
+        if (!CloseHandle(h))
+            return false;
+
+        return f != 0;
+    }
+    else version (Posix)
+    {
+        import core.sys.posix.utime;
+        return utime(namez, null) == 0;
+    }
+    else
+        static assert(0);
+}
+
+// Feel free to make these public if used elsewhere.
+/**
+Size of a file in bytes.
+Params: fd = file handle
+Returns: file size in bytes, or `ulong.max` on any error.
+*/
+version (Posix)
+private ulong fileSize(int fd)
+{
+    import core.sys.posix.sys.stat;
+    stat_t buf;
+    if (fstat(fd, &buf) == 0)
+        return buf.st_size;
+    return ulong.max;
+}
+
+/// Ditto
+version (Windows)
+private ulong fileSize(HANDLE fd)
+{
+    ulong result;
+    if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
+        return result;
+    return ulong.max;
+}
+
+/**
+Runs a non-pure function or delegate as pure code. Use with caution.
+
+Params:
+fun = the delegate to run, usually inlined: `fakePure({ ... });`
+
+Returns: whatever `fun` returns.
+*/
+private auto ref fakePure(F)(scope F fun) pure
+{
+    mixin("alias PureFun = " ~ F.stringof ~ " pure;");
+    return (cast(PureFun) fun)();
+}
diff --git a/gcc/d/dmd/root/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
similarity index 77%
rename from gcc/d/dmd/root/outbuffer.d
rename to gcc/d/dmd/common/outbuffer.d
index e756917b88d..c5a84375aaa 100644
--- a/gcc/d/dmd/root/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -9,14 +9,21 @@ 
  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/outbuffer.d
  */
 
-module dmd.root.outbuffer;
+module dmd.common.outbuffer;
 
 import core.stdc.stdarg;
 import core.stdc.stdio;
 import core.stdc.string;
-import dmd.root.rmem;
-import dmd.root.rootobject;
-import dmd.root.string;
+import core.stdc.stdlib;
+
+// In theory these functions should also restore errno, but we don't care because
+// we abort application on error anyway.
+extern (C) private pure @system @nogc nothrow
+{
+    pragma(mangle, "malloc") void* pureMalloc(size_t);
+    pragma(mangle, "realloc") void* pureRealloc(void* ptr, size_t size);
+    pragma(mangle, "free") void pureFree(void* ptr);
+}
 
 debug
 {
@@ -29,7 +36,7 @@  a contiguous array or a memory-mapped file.
 */
 struct OutBuffer
 {
-    import dmd.root.file : FileMapping;
+    import dmd.common.file : FileMapping, touchFile, writeFile;
 
     // IMPORTANT: PLEASE KEEP STATE AND DESTRUCTOR IN SYNC WITH DEFINITION IN ./outbuffer.h.
     // state {
@@ -47,6 +54,14 @@  struct OutBuffer
     int level;
     // state }
 
+    /**
+    Construct given size.
+    */
+    this(size_t initialSize) nothrow
+    {
+        reserve(initialSize);
+    }
+
     /**
     Construct from filename. Will map the file into memory (or create it anew
     if necessary) and start writing at the beginning of it.
@@ -56,14 +71,36 @@  struct OutBuffer
     */
     @trusted this(const(char)* filename)
     {
-        fileMapping = new FileMapping!ubyte(filename);
+        FileMapping!ubyte model;
+        fileMapping = cast(FileMapping!ubyte*) malloc(model.sizeof);
+        memcpy(fileMapping, &model, model.sizeof);
+        fileMapping.__ctor(filename);
+        //fileMapping = new FileMapping!ubyte(filename);
         data = (*fileMapping)[];
     }
 
+    /**
+    Frees resources associated.
+    */
+    extern (C++) void dtor() nothrow @trusted
+    {
+        if (fileMapping)
+        {
+            if (fileMapping.active)
+                fileMapping.close();
+            fileMapping = null;
+        }
+        else
+        {
+            debug (stomp) memset(data.ptr, 0xFF, data.length);
+            free(data.ptr);
+        }
+    }
+
     /**
     Frees resources associated automatically.
     */
-    extern (C++) ~this() pure nothrow
+    extern (C++) ~this() pure nothrow @trusted
     {
         if (fileMapping)
         {
@@ -74,10 +111,23 @@  struct OutBuffer
         else
         {
             debug (stomp) memset(data.ptr, 0xFF, data.length);
-            mem.xfree(data.ptr);
+            pureFree(data.ptr);
         }
     }
 
+    /// For porting with ease from dmd.backend.outbuf.Outbuffer
+    ubyte* buf() nothrow {
+        return data.ptr;
+    }
+
+    /// For porting with ease from dmd.backend.outbuf.Outbuffer
+    ubyte** bufptr() nothrow {
+        static struct Array { size_t length; ubyte* ptr; }
+        auto a = cast(Array*) &data;
+        assert(a.length == data.length && a.ptr == data.ptr);
+        return &a.ptr;
+    }
+
     extern (C++) size_t length() const pure @nogc @safe nothrow { return offset; }
 
     /**********************
@@ -109,7 +159,7 @@  struct OutBuffer
         else
         {
             debug (stomp) memset(data.ptr, 0xFF, data.length);
-            mem.xfree(extractData());
+            pureFree(extractData());
         }
     }
 
@@ -141,17 +191,18 @@  struct OutBuffer
         {
             debug (stomp)
             {
-                auto p = cast(ubyte*)mem.xmalloc(size);
+                auto p = cast(ubyte*) pureMalloc(size);
+                p || assert(0, "OutBuffer: out of memory.");
                 memcpy(p, data.ptr, offset);
                 memset(data.ptr, 0xFF, data.length);  // stomp old location
-                mem.xfree(data.ptr);
+                pureFree(data.ptr);
                 memset(p + offset, 0xff, size - offset); // stomp unused data
             }
             else
             {
-                auto p = cast(ubyte*)mem.xrealloc(data.ptr, size);
-                if (mem.isGCEnabled) // clear currently unused data to avoid false pointers
-                    memset(p + offset + nbytes, 0xff, size - offset - nbytes);
+                auto p = cast(ubyte*) pureRealloc(data.ptr, size);
+                p || assert(0, "OutBuffer: out of memory.");
+                memset(p + offset + nbytes, 0xff, size - offset - nbytes);
             }
             data = p[0 .. size];
         }
@@ -164,7 +215,7 @@  struct OutBuffer
      */
     extern (C++) void setsize(size_t size) pure nothrow @nogc @safe
     {
-        assert(size <= offset);
+        assert(size <= data.length);
         offset = size;
     }
 
@@ -185,6 +236,14 @@  struct OutBuffer
         notlinehead = true;
     }
 
+    // Write an array to the buffer, no reserve check
+    @trusted nothrow
+    void writen(const void *b, size_t len)
+    {
+        memcpy(data.ptr + offset, b, len);
+        offset += len;
+    }
+
     extern (C++) void write(const(void)* data, size_t nbytes) pure nothrow
     {
         write(data[0 .. nbytes]);
@@ -199,27 +258,90 @@  struct OutBuffer
         offset += buf.length;
     }
 
-    extern (C++) void writestring(const(char)* string) pure nothrow
+    /**
+     * Writes a 16 bit value, no reserve check.
+     */
+    @trusted nothrow
+    void write16n(int v)
     {
-        write(string.toDString);
+        auto x = cast(ushort) v;
+        data[offset] = x & 0x00FF;
+        data[offset + 1] = x >> 8u;
+        offset += 2;
     }
 
+    /**
+     * Writes a 16 bit value.
+     */
+    void write16(int v) nothrow
+    {
+        auto u = cast(ushort) v;
+        write(&u, u.sizeof);
+    }
+
+    /**
+     * Writes a 32 bit int.
+     */
+    void write32(int v) nothrow @trusted
+    {
+        write(&v, v.sizeof);
+    }
+
+    /**
+     * Writes a 64 bit int.
+     */
+    @trusted void write64(long v) nothrow
+    {
+        write(&v, v.sizeof);
+    }
+
+    /// NOT zero-terminated
+    extern (C++) void writestring(const(char)* s) pure nothrow
+    {
+        if (!s)
+            return;
+        import core.stdc.string : strlen;
+        write(s[0 .. strlen(s)]);
+    }
+
+    /// ditto
     void writestring(const(char)[] s) pure nothrow
     {
         write(s);
     }
 
+    /// ditto
     void writestring(string s) pure nothrow
     {
         write(s);
     }
 
+    /// NOT zero-terminated, followed by newline
     void writestringln(const(char)[] s) pure nothrow
     {
         writestring(s);
         writenl();
     }
 
+    // Zero-terminated
+    void writeString(const(char)* s) pure nothrow @trusted
+    {
+        write(s[0 .. strlen(s)+1]);
+    }
+
+    /// ditto
+    void writeString(const(char)[] s) pure nothrow
+    {
+        write(s);
+        writeByte(0);
+    }
+
+    /// ditto
+    void writeString(string s) pure nothrow
+    {
+        writeString(cast(const(char)[])(s));
+    }
+
     extern (C++) void prependstring(const(char)* string) pure nothrow
     {
         size_t len = strlen(string);
@@ -244,6 +366,38 @@  struct OutBuffer
             notlinehead = false;
     }
 
+    // Write n zeros; return pointer to start of zeros
+    @trusted
+    void *writezeros(size_t n) nothrow
+    {
+        reserve(n);
+        auto result = memset(data.ptr + offset, 0, n);
+        offset += n;
+        return result;
+    }
+
+    // Position buffer to accept the specified number of bytes at offset
+    @trusted
+    void position(size_t where, size_t nbytes) nothrow
+    {
+        if (where + nbytes > data.length)
+        {
+            reserve(where + nbytes - offset);
+        }
+        offset = where;
+
+        debug assert(offset + nbytes <= data.length);
+    }
+
+    /**
+     * Writes an 8 bit byte, no reserve check.
+     */
+    extern (C++) @trusted nothrow
+    void writeByten(int b)
+    {
+        this.data[offset++] = cast(ubyte) b;
+    }
+
     extern (C++) void writeByte(uint b) pure nothrow
     {
         if (doindent && !notlinehead && b != '\n')
@@ -369,14 +523,6 @@  struct OutBuffer
         }
     }
 
-    extern (C++) void write(RootObject obj) /*nothrow*/
-    {
-        if (obj)
-        {
-            writestring(obj.toChars());
-        }
-    }
-
     extern (C++) void fill0(size_t nbytes) pure nothrow
     {
         reserve(nbytes);
@@ -428,8 +574,8 @@  struct OutBuffer
                 break;
         }
         offset += count;
-        if (mem.isGCEnabled)
-            memset(data.ptr + offset, 0xff, psize - count);
+        // if (mem.isGCEnabled)
+             memset(data.ptr + offset, 0xff, psize - count);
     }
 
     static if (__VERSION__ < 2092)
@@ -460,7 +606,6 @@  struct OutBuffer
      */
     extern (C++) void print(ulong u) pure nothrow
     {
-        //import core.internal.string;  // not available
         UnsignedStringBuf buf = void;
         writestring(unsignedToTempString(u, buf));
     }
@@ -558,6 +703,11 @@  struct OutBuffer
         return extractData()[0 .. length];
     }
 
+    extern (D) byte[] extractUbyteSlice(bool nullTerminate = false) pure nothrow
+    {
+        return cast(byte[]) extractSlice(nullTerminate);
+    }
+
     // Append terminating null if necessary and get view of internal buffer
     extern (C++) char* peekChars() pure nothrow
     {
@@ -577,6 +727,36 @@  struct OutBuffer
         return extractData();
     }
 
+    void writesLEB128(int value) pure nothrow
+    {
+        while (1)
+        {
+            ubyte b = value & 0x7F;
+
+            value >>= 7;            // arithmetic right shift
+            if ((value == 0 && !(b & 0x40)) ||
+                (value == -1 && (b & 0x40)))
+            {
+                 writeByte(b);
+                 break;
+            }
+            writeByte(b | 0x80);
+        }
+    }
+
+    void writeuLEB128(uint value) pure nothrow
+    {
+        do
+        {
+            ubyte b = value & 0x7F;
+
+            value >>= 7;
+            if (value)
+                b |= 0x80;
+            writeByte(b);
+        } while (value);
+    }
+
     /**
     Destructively saves the contents of `this` to `filename`. As an
     optimization, if the file already has identical contents with the buffer,
@@ -591,7 +771,6 @@  struct OutBuffer
     */
     extern(D) bool moveToFile(const char* filename)
     {
-        import dmd.root.file;
         bool result = true;
         const bool identical = this[] == FileMapping!(const ubyte)(filename)[];
 
@@ -615,12 +794,12 @@  struct OutBuffer
         else
         {
             if (!identical)
-                File.write(filename, this[]);
+                writeFile(filename, this[]);
             destroy();
         }
 
         return identical
-            ? result && File.touch(filename)
+            ? result && touchFile(filename)
             : result;
     }
 }
@@ -645,7 +824,7 @@  char[] unsignedToTempString(ulong value, char[] buf, uint radix = 10) @safe pure
         else
         {
             ubyte x = cast(ubyte)(value % radix);
-            value = value / radix;
+            value /= radix;
             buf[--i] = cast(char)((x < 10) ? x + '0' : x - 10 + 'a');
         }
     } while (value);
diff --git a/gcc/d/dmd/root/outbuffer.h b/gcc/d/dmd/common/outbuffer.h
similarity index 90%
rename from gcc/d/dmd/root/outbuffer.h
rename to gcc/d/dmd/common/outbuffer.h
index b635373c183..a5e3f9c541d 100644
--- a/gcc/d/dmd/root/outbuffer.h
+++ b/gcc/d/dmd/common/outbuffer.h
@@ -4,14 +4,14 @@ 
  * http://www.digitalmars.com
  * Distributed under the Boost Software License, Version 1.0.
  * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/common/outbuffer.h
  */
 
 #pragma once
 
-#include "dsystem.h"
-#include "dcompat.h"
-#include "rmem.h"
+#include "../root/dsystem.h"
+#include "../root/dcompat.h"
+#include "../root/rmem.h"
 
 class RootObject;
 
@@ -22,7 +22,7 @@  private:
     DArray<unsigned char> data;
     d_size_t offset;
     bool notlinehead;
-    void* fileMapping;  // pointer to a file mapping object not used on the C++ side
+    void *fileMapping;  // pointer to a file mapping object not used on the C++ side
 public:
     bool doindent;
     bool spaces;
diff --git a/gcc/d/dmd/common/string.d b/gcc/d/dmd/common/string.d
new file mode 100644
index 00000000000..026374af89d
--- /dev/null
+++ b/gcc/d/dmd/common/string.d
@@ -0,0 +1,209 @@ 
+/**
+ * Common string functions including filename manipulation.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors:   Walter Bright, http://www.digitalmars.com
+ * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d, common/_string.d)
+ * Documentation: https://dlang.org/phobos/dmd_common_string.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/string.d
+ */
+module dmd.common.string;
+
+/**
+Defines a temporary array using a fixed-length buffer as back store. If the length
+of the buffer suffices, it is readily used. Otherwise, `malloc` is used to
+allocate memory for the array and `free` is used for deallocation in the
+destructor.
+
+This type is meant to use exclusively as an automatic variable. It is not
+default constructible or copyable.
+*/
+struct SmallBuffer(T)
+{
+    import core.stdc.stdlib : malloc, free;
+
+    private T[] _extent;
+    private bool needsFree;
+
+    @disable this(); // no default ctor
+    @disable this(ref const SmallBuffer!T); // noncopyable, nonassignable
+
+    this(size_t len, T[] buffer)
+    {
+        if (len <= buffer.length)
+        {
+            _extent = buffer[0 .. len];
+        }
+        else
+        {
+            _extent = (cast(typeof(_extent.ptr)) malloc(len * _extent[0].sizeof))[0 .. len];
+            _extent.ptr || assert(0, "Out of memory.");
+            needsFree = true;
+        }
+        assert(this.length == len);
+    }
+
+    ~this()
+    {
+        if (needsFree)
+            free(_extent.ptr);
+    }
+
+    void create(size_t len)
+    {
+        if (len <= _extent.length)
+        {
+            _extent = _extent[0 .. len];
+        }
+        else
+        {
+            __dtor();
+            _extent = (cast(typeof(_extent.ptr)) malloc(len * _extent[0].sizeof))[0 .. len];
+            _extent.ptr || assert(0, "Out of memory.");
+            needsFree = true;
+        }
+        assert(this.length == len);
+    }
+
+    // Force accesses to extent to be scoped.
+    scope inout extent()
+    {
+        return _extent;
+    }
+
+    alias extent this;
+}
+
+/// ditto
+unittest
+{
+    char[230] buf = void;
+    auto a = SmallBuffer!char(10, buf);
+    assert(a[] is buf[0 .. 10]);
+    auto b = SmallBuffer!char(1000, buf);
+    assert(b[] !is buf[]);
+    b.create(1000);
+    assert(b.length == 1000);
+    assert(b[] !is buf[]);
+}
+
+/**
+Converts a zero-terminated C string to a D slice. Takes linear time and allocates no memory.
+
+Params:
+stringz = the C string to be converted
+
+Returns:
+a slice comprehending the string. The terminating 0 is not part of the slice.
+*/
+auto asDString(C)(C* stringz) pure @nogc nothrow
+{
+    import core.stdc.string : strlen;
+    return stringz[0 .. strlen(stringz)];
+}
+
+///
+unittest
+{
+    const char* p = "123".ptr;
+    assert(p.asDString == "123");
+}
+
+/**
+(Windows only) Converts a narrow string to a wide string using `buffer` as strorage. Returns a slice managed by
+`buffer` containing the converted string. The terminating zero is not part of the returned slice,
+but is guaranteed to follow it.
+*/
+version(Windows) wchar[] toWStringz(const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow
+{
+    import core.sys.windows.winnls : CP_ACP, MultiByteToWideChar;
+    // assume filenames encoded in system default Windows ANSI code page
+    enum CodePage = CP_ACP;
+
+    if (narrow is null)
+        return null;
+
+    const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
+    if (requiredLength < cast(int) buffer.length)
+    {
+        buffer[requiredLength] = 0;
+        return buffer[0 .. requiredLength];
+    }
+
+    buffer.create(requiredLength + 1);
+    const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, requiredLength);
+    assert(length == requiredLength);
+    buffer[length] = 0;
+    return buffer[0 .. length];
+}
+
+/**************************************
+* Converts a path to one suitable to be passed to Win32 API
+* functions that can deal with paths longer than 248
+* characters then calls the supplied function on it.
+*
+* Params:
+*  path = The Path to call F on.
+*
+* Returns:
+*  The result of calling F on path.
+*
+* References:
+*  https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
+*/
+version(Windows) auto extendedPathThen(alias F)(const(char)[] path)
+{
+    import core.sys.windows.winbase;
+    import core.sys.windows.winnt;
+
+    if (!path.length)
+        return F((wchar[]).init);
+
+    wchar[1024] buf = void;
+    auto store = SmallBuffer!wchar(buf.length, buf);
+    auto wpath = toWStringz(path, store);
+
+    // GetFullPathNameW expects a sized buffer to store the result in. Since we don't
+    // know how large it has to be, we pass in null and get the needed buffer length
+    // as the return code.
+    const pathLength = GetFullPathNameW(&wpath[0],
+                                        0 /*length8*/,
+                                        null /*output buffer*/,
+                                        null /*filePartBuffer*/);
+    if (pathLength == 0)
+    {
+        return F((wchar[]).init);
+    }
+
+    // wpath is the UTF16 version of path, but to be able to use
+    // extended paths, we need to prefix with `\\?\` and the absolute
+    // path.
+    static immutable prefix = `\\?\`w;
+
+    // prefix only needed for long names and non-UNC names
+    const needsPrefix = pathLength >= MAX_PATH && (wpath[0] != '\\' || wpath[1] != '\\');
+    const prefixLength = needsPrefix ? prefix.length : 0;
+
+    // +1 for the null terminator
+    const bufferLength = pathLength + prefixLength + 1;
+
+    wchar[1024] absBuf = void;
+    auto absPath = SmallBuffer!wchar(bufferLength, absBuf);
+
+    absPath[0 .. prefixLength] = prefix[0 .. prefixLength];
+
+    const absPathRet = GetFullPathNameW(&wpath[0],
+        cast(uint)(absPath.length - prefixLength - 1),
+        &absPath[prefixLength],
+        null /*filePartBuffer*/);
+
+    if (absPathRet == 0 || absPathRet > absPath.length - prefixLength)
+    {
+        return F((wchar[]).init);
+    }
+
+    absPath[$ - 1] = '\0';
+    // Strip null terminator from the slice
+    return F(absPath[0 .. $ - 1]);
+}
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index d4a8b136d43..05bd4bd550d 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -28,7 +28,7 @@  import dmd.globals;
 import dmd.identifier;
 import dmd.mtype;
 import dmd.typesem;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.tokens;
@@ -452,7 +452,6 @@  extern (C++) final class StaticForeach : RootObject
             sc = sc.startCTFE();
             aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
             sc = sc.endCTFE();
-            aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
         }
 
         if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror)
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index bb40649dc0b..7d8ab67ee6a 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -23,7 +23,7 @@  import dmd.lexer;
 import dmd.parse;
 import dmd.errors;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.rootobject;
 import dmd.root.string;
@@ -72,6 +72,7 @@  final class CParser(AST) : Parser!AST
     {
         //printf("cparseTranslationUnit()\n");
         symbols = new AST.Dsymbols();
+        addBuiltinDeclarations();
         while (1)
         {
             if (token.value == TOK.endOfFile)
@@ -756,7 +757,6 @@  final class CParser(AST) : Parser!AST
             switch (token.value)
             {
             case TOK.dot:
-            case TOK.arrow:
                 nextToken();
                 if (token.value == TOK.identifier)
                 {
@@ -767,6 +767,19 @@  final class CParser(AST) : Parser!AST
                 error("identifier expected following `.`, not `%s`", token.toChars());
                 break;
 
+            case TOK.arrow:
+                nextToken();
+                if (token.value == TOK.identifier)
+                {
+                    Identifier id = token.ident;
+                    auto die = new AST.DotIdExp(loc, e, id);
+                    die.arrow = true;
+                    e = die;
+                    break;
+                }
+                error("identifier expected following `->`, not `%s`", token.toChars());
+                break;
+
             case TOK.plusPlus:
                 e = new AST.PostExp(TOK.plusPlus, loc, e);
                 break;
@@ -949,6 +962,7 @@  final class CParser(AST) : Parser!AST
                 nextToken();
                 auto t = cparseTypeName();
                 check(TOK.rightParenthesis);
+                pt = &token;
 
                 if (token.value == TOK.leftCurly)
                 {
@@ -957,6 +971,17 @@  final class CParser(AST) : Parser!AST
                     auto ce = new AST.CompoundLiteralExp(loc, t, ci);
                     return cparsePostfixOperators(ce);
                 }
+                else if (t.isTypeIdentifier() &&
+                         token.value == TOK.leftParenthesis &&
+                         !isCastExpression(pt))
+                {
+                    /* this might actually be a function
+                     * call that looks like `(a)(b)` or even `(a)(b,c)`
+                     */
+                    auto ie = new AST.IdentifierExp(loc, t.isTypeIdentifier().ident);
+                    ie.parens = true;    // disambiguate it from being a declaration
+                    return new AST.CallExp(loc, ie, cparseArguments());
+                }
                 else
                 {
                     // ( type-name ) cast-expression
@@ -1451,6 +1476,7 @@  final class CParser(AST) : Parser!AST
 
         auto symbolsSave = symbols;
         Specifier specifier;
+        specifier.packalign = this.packalign;
         auto tspec = cparseDeclarationSpecifiers(level, specifier);
 
         /* If a declarator does not follow, it is unnamed
@@ -1459,7 +1485,8 @@  final class CParser(AST) : Parser!AST
         {
             nextToken();
             auto tt = tspec.isTypeTag();
-            if (!tt || !tt.id)
+            if (!tt ||
+                !tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_))
                 return; // legal but meaningless empty declaration, ignore it
 
             /* `struct tag;` and `struct tag { ... };`
@@ -1493,7 +1520,7 @@  final class CParser(AST) : Parser!AST
         {
             Identifier id;
             AST.Expression asmname;
-            auto dt = cparseDeclarator(DTR.xdirect, tspec, id);
+            auto dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
             if (!dt)
             {
                 panic();
@@ -1674,6 +1701,8 @@  final class CParser(AST) : Parser!AST
                     return;
 
                 case TOK.comma:
+                    if (!symbolsSave)
+                        symbolsSave = symbols;
                     nextToken();
                     break;
 
@@ -1720,8 +1749,9 @@  final class CParser(AST) : Parser!AST
              */
             auto pl = ft.parameterList;
             pl.hasIdentifierList = true;        // semantic needs to know to adjust parameter types
-            if (pl.varargs != AST.VarArg.none)
+            if (pl.varargs != AST.VarArg.none && pl.length)
                 error("function identifier-list cannot end with `...`");
+            ft.parameterList.varargs = AST.VarArg.variadic;     // but C11 allows extra arguments
             auto plLength = pl.length;
             if (symbols.length != plLength)
                 error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length);
@@ -1756,7 +1786,10 @@  final class CParser(AST) : Parser!AST
                     }
                 }
                 if (!p.type)
+                {
                     error("no declaration for identifier `%s`", p.ident.toChars());
+                    p.type = AST.Type.terror;
+                }
             }
         }
 
@@ -2240,14 +2273,14 @@  final class CParser(AST) : Parser!AST
      *  declarator   = declarator kind
      *  t            = base type to start with
      *  pident       = set to Identifier if there is one, null if not
-     *  storageClass = any storage classes seen so far that apply to a function
+     *  specifier    = specifiers in and out
      * Returns:
      *  type declared. If a TypeFunction is returned, this.symbols is the
      *  symbol table for the parameter-type-list, which will contain any
      *  declared struct, union or enum tags.
      */
     private AST.Type cparseDeclarator(DTR declarator, AST.Type t,
-        out Identifier pident, StorageClass storageClass = 0)
+        out Identifier pident, ref Specifier specifier)
     {
         //printf("cparseDeclarator(%d)\n", declarator);
         AST.Types constTypes; // all the Types that will need `const` applied to them
@@ -2285,6 +2318,8 @@  final class CParser(AST) : Parser!AST
                     const mod = cparseTypeQualifierList();
                     if (mod & MOD.xconst)
                         constTypes.push(t);
+                    if (token.value == TOK.__attribute__)
+                        cparseGnuAttributes(specifier);
                     continue;
 
                 default:
@@ -2352,8 +2387,9 @@  final class CParser(AST) : Parser!AST
                         }
                         else
                         {
-                            // An array of unknown size, fake it with a DArray
-                            ta = new AST.TypeDArray(t); // []
+                            /* C11 6.7.6.2-4 An [ ] array is an incomplete array type
+                             */
+                            ta = new AST.TypeSArray(t);
                         }
                         check(TOK.rightBracket);
 
@@ -2388,7 +2424,7 @@  final class CParser(AST) : Parser!AST
                             /* C11 6.7.6.2-1: the element type shall not be an incomplete or
                              * function type.
                              */
-                            if (ta.isTypeDArray() && !isVLA)
+                            if (ta.isTypeSArray() && ta.isTypeSArray().isIncomplete() && !isVLA)
                                 error("array type has incomplete element type `%s`", ta.toChars());
                         }
 
@@ -2489,9 +2525,10 @@  final class CParser(AST) : Parser!AST
     AST.Type cparseTypeName()
     {
         Specifier specifier;
+        specifier.packalign.setDefault();
         auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
         Identifier id;
-        return cparseDeclarator(DTR.xabstract, tspec, id);
+        return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
     }
 
     /***********************************
@@ -2525,13 +2562,19 @@  final class CParser(AST) : Parser!AST
         StorageClass varargsStc;
 
         check(TOK.leftParenthesis);
-        if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis)
+        if (token.value == TOK.void_ && peekNext() == TOK.rightParenthesis) // func(void)
         {
             nextToken();
             nextToken();
             return AST.ParameterList(parameters, varargs, varargsStc);
         }
 
+        if (token.value == TOK.rightParenthesis)        // func()
+        {
+            nextToken();
+            return AST.ParameterList(parameters, AST.VarArg.variadic, varargsStc);
+        }
+
         /* The check for identifier-list comes later,
          * when doing the trailing declaration-list (opt)
          */
@@ -2541,6 +2584,8 @@  final class CParser(AST) : Parser!AST
                 break;
             if (token.value == TOK.dotDotDot)
             {
+                if (parameters.length == 0)     // func(...)
+                    error("named parameter required before `...`");
                 varargs = AST.VarArg.variadic;  // C-style variadics
                 nextToken();
                 check(TOK.rightParenthesis);
@@ -2548,10 +2593,16 @@  final class CParser(AST) : Parser!AST
             }
 
             Specifier specifier;
+            specifier.packalign.setDefault();
             auto tspec = cparseDeclarationSpecifiers(LVL.prototype, specifier);
+            if (tspec && specifier.mod & MOD.xconst)
+            {
+                tspec = toConst(tspec);
+                specifier.mod = MOD.xnone;      // 'used' it
+            }
 
             Identifier id;
-            auto t = cparseDeclarator(DTR.xparameter, tspec, id);
+            auto t = cparseDeclarator(DTR.xparameter, tspec, id, specifier);
             if (specifier.mod & MOD.xconst)
                 t = toConst(t);
             auto param = new AST.Parameter(STC.parameter, t, id, null, null);
@@ -2920,6 +2971,7 @@  final class CParser(AST) : Parser!AST
          *    enum gnu-attributes (opt) identifier
          */
         Specifier specifier;
+        specifier.packalign.setDefault();
         if (token.value == TOK.__attribute__)
             cparseGnuAttributes(specifier);
 
@@ -2950,6 +3002,16 @@  final class CParser(AST) : Parser!AST
                 nextToken();
                 auto mloc = token.loc;
 
+                if (token.value == TOK.__attribute__)
+                {
+                    /* gnu-attributes can appear here, but just scan and ignore them
+                     * https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
+                     */
+                    Specifier specifierx;
+                    specifierx.packalign.setDefault();
+                    cparseGnuAttributes(specifierx);
+                }
+
                 AST.Expression value;
                 if (token.value == TOK.assign)
                 {
@@ -2958,6 +3020,16 @@  final class CParser(AST) : Parser!AST
                     // TODO C11 6.7.2.2-2 value must fit into an int
                 }
 
+                if (token.value == TOK.__attribute__)
+                {
+                    /* gnu-attributes can appear here, but just scan and ignore them
+                     * https://gcc.gnu.org/onlinedocs/gcc/Enumerator-Attributes.html
+                     */
+                    Specifier specifierx;
+                    specifierx.packalign.setDefault();
+                    cparseGnuAttributes(specifierx);
+                }
+
                 auto em = new AST.EnumMember(mloc, ident, value, null, 0, null, null);
                 members.push(em);
 
@@ -3037,14 +3109,12 @@  final class CParser(AST) : Parser!AST
             check(TOK.rightCurly);
 
             if ((*members).length == 0) // C11 6.7.2.1-8
-                /* TODO: not strict enough, should really be contains "no named members",
-                 * not just "no members".
-                 * I.e. an unnamed bit field, _Static_assert, etc, are not named members,
-                 * but will pass this check.
-                 * Be careful to detect named members that come anonymous structs.
-                 * Correctly doing this will likely mean moving it to typesem.d.
+            {
+                /* allow empty structs as an extension
+                 *  struct-declarator-list:
+                 *    struct-declarator (opt)
                  */
-                error("empty struct-declaration-list for `%s %s`", Token.toChars(structOrUnion), tag ? tag.toChars() : "Anonymous".ptr);
+            }
         }
         else if (!tag)
             error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
@@ -3083,7 +3153,13 @@  final class CParser(AST) : Parser!AST
 
         auto symbolsSave = symbols;
         Specifier specifier;
+        specifier.packalign = this.packalign;
         auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
+        if (tspec && specifier.mod & MOD.xconst)
+        {
+            tspec = toConst(tspec);
+            specifier.mod = MOD.xnone;          // 'used' it
+        }
 
         /* If a declarator does not follow, it is unnamed
          */
@@ -3139,12 +3215,14 @@  final class CParser(AST) : Parser!AST
                 dt = tspec;
             }
             else
-                dt = cparseDeclarator(DTR.xdirect, tspec, id);
-            if (!dt)
             {
-                panic();
-                nextToken();
-                break;          // error recovery
+                dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
+                if (!dt)
+                {
+                    panic();
+                    nextToken();
+                    break;          // error recovery
+                }
             }
 
             AST.Expression width;
@@ -3155,9 +3233,6 @@  final class CParser(AST) : Parser!AST
                 width = cparseConstantExp();
             }
 
-            if (specifier.mod & MOD.xconst)
-                dt = toConst(dt);
-
             /* GNU Extensions
              * struct-declarator:
              *    declarator gnu-attributes (opt)
@@ -3234,8 +3309,8 @@  final class CParser(AST) : Parser!AST
      */
     private bool isCDeclaration(ref Token* pt)
     {
-        //printf("isCDeclaration()\n");
         auto t = pt;
+        //printf("isCDeclaration() %s\n", t.toChars());
         if (!isDeclarationSpecifiers(t))
             return false;
 
@@ -3360,8 +3435,8 @@  final class CParser(AST) : Parser!AST
      */
     private bool isAssignmentExpression(ref Token* pt)
     {
-        //printf("isAssignmentExpression()\n");
         auto t = pt;
+        //printf("isAssignmentExpression() %s\n", t.toChars());
 
         /* This doesn't actually check for grammar matching an
          * assignment-expression. It just matches ( ) [ ] looking for
@@ -3384,6 +3459,15 @@  final class CParser(AST) : Parser!AST
                 case TOK.leftParenthesis:
                     if (!skipParens(t, &t))
                         return false;
+                    /*
+                        https://issues.dlang.org/show_bug.cgi?id=22267
+                        Fix issue 22267: If the parser encounters the following
+                            `identifier variableName = (expression);`
+                        the initializer is not identified as such since the parentheses
+                        cause the parser to keep walking indefinitely
+                        (whereas `(1) + 1` would not be affected.).
+                    */
+                    any = true;
                     continue;
 
                 case TOK.leftBracket:
@@ -3391,6 +3475,11 @@  final class CParser(AST) : Parser!AST
                         return false;
                     continue;
 
+                case TOK.leftCurly:
+                    if (!skipBraces(t))
+                        return false;
+                    continue;
+
                 default:
                     any = true;   // assume token was part of an a-e
                     t = peek(t);
@@ -3427,6 +3516,7 @@  final class CParser(AST) : Parser!AST
 
         auto t = pt;
 
+        bool seenType;
         bool any;
         while (1)
         {
@@ -3445,9 +3535,19 @@  final class CParser(AST) : Parser!AST
                 case TOK._Bool:
                 //case TOK._Imaginary:
                 case TOK._Complex:
-                case TOK.identifier: // typedef-name
                     t = peek(t);
+                    seenType = true;
                     any = true;
+                    continue;
+
+                case TOK.identifier: // typedef-name
+                    if (!seenType)
+                    {
+                        t = peek(t);
+                        seenType = true;
+                        any = true;
+                        continue;
+                    }
                     break;
 
                 case TOK.struct_:
@@ -3878,6 +3978,10 @@  final class CParser(AST) : Parser!AST
                     t = tk;
                     break;
                 }
+
+                if (tk.value == TOK.leftParenthesis && peek(tk).value == TOK.rightParenthesis)
+                    return false;    // (type-name)() is not a cast (it might be a function call)
+
                 if (!isCastExpression(tk, true))
                 {
                     if (afterParenType) // could be ( type-name ) ( unary-expression )
@@ -4071,6 +4175,7 @@  final class CParser(AST) : Parser!AST
         SCW scw;        /// storage-class specifiers
         MOD mod;        /// type qualifiers
         AST.Expressions*  alignExps;  /// alignment
+        structalign_t packalign;  /// #pragma pack alignment value
     }
 
     /***********************
@@ -4089,19 +4194,19 @@  final class CParser(AST) : Parser!AST
             if (level == LVL.global)
             {
                 if (specifier.scw & SCW.xextern)
-                   stc = AST.STC.extern_;
+                    stc = AST.STC.extern_;
             }
             else if (level == LVL.local)
             {
                 if (specifier.scw & SCW.xextern)
-                   stc = AST.STC.extern_;
+                    stc = AST.STC.extern_;
                 else if (specifier.scw & SCW.xstatic)
                     stc = AST.STC.static_;
             }
             else if (level == LVL.member)
             {
                 if (specifier.scw & SCW.xextern)
-                   stc = AST.STC.extern_;
+                    stc = AST.STC.extern_;
                 else if (specifier.scw & SCW.xstatic)
                     stc = AST.STC.static_;
             }
@@ -4111,21 +4216,23 @@  final class CParser(AST) : Parser!AST
             if (level == LVL.global)
             {
                 if (specifier.scw & SCW.xextern)
-                   stc = AST.STC.extern_ | AST.STC.gshared;
+                    stc = AST.STC.extern_ | AST.STC.gshared;
+                else if (specifier.scw & SCW.xstatic)
+                    stc = AST.STC.gshared | AST.STC.static_;
                 else
                     stc = AST.STC.gshared;
             }
             else if (level == LVL.local)
             {
                 if (specifier.scw & SCW.xextern)
-                   stc = AST.STC.extern_ | AST.STC.gshared;
+                    stc = AST.STC.extern_ | AST.STC.gshared;
                 else if (specifier.scw & SCW.xstatic)
                     stc = AST.STC.gshared;
             }
             else if (level == LVL.member)
             {
                 if (specifier.scw & SCW.xextern)
-                   stc = AST.STC.extern_ | AST.STC.gshared;
+                    stc = AST.STC.extern_ | AST.STC.gshared;
                 else if (specifier.scw & SCW.xstatic)
                     stc = AST.STC.gshared;
             }
@@ -4235,15 +4342,59 @@  final class CParser(AST) : Parser!AST
      */
     private AST.Dsymbol applySpecifier(AST.Dsymbol s, ref Specifier specifier)
     {
+        //printf("applySpecifier() %s\n", s.toChars());
         if (specifier.alignExps)
         {
+            //printf("  applying _Alignas %s, packalign %d\n", (*specifier.alignExps)[0].toChars(), cast(int)specifier.packalign);
             // Wrap declaration in an AlignDeclaration
             auto decls = new AST.Dsymbols(1);
             (*decls)[0] = s;
             s = new AST.AlignDeclaration(s.loc, specifier.alignExps, decls);
         }
+        else if (!specifier.packalign.isDefault())
+        {
+            //printf("  applying packalign %d\n", cast(int)specifier.packalign);
+            // Wrap #pragma pack in an AlignDeclaration
+            auto decls = new AST.Dsymbols(1);
+            (*decls)[0] = s;
+            s = new AST.AlignDeclaration(s.loc, specifier.packalign, decls);
+        }
         return s;
     }
 
+    /***********************************
+     * Add global target-dependent builtin declarations.
+     */
+    private void addBuiltinDeclarations()
+    {
+        void genBuiltinFunc(Identifier id, AST.VarArg va)
+        {
+            auto tva_list = new AST.TypeIdentifier(Loc.initial, Id.builtin_va_list);
+            auto parameters = new AST.Parameters();
+            parameters.push(new AST.Parameter(STC.parameter | STC.ref_, tva_list, null, null, null));
+            auto pl = AST.ParameterList(parameters, va, 0);
+            auto tf = new AST.TypeFunction(pl, AST.Type.tvoid, LINK.c, 0);
+            auto s = new AST.FuncDeclaration(Loc.initial, Loc.initial, id, AST.STC.static_, tf, false);
+            symbols.push(s);
+        }
+
+        /* void __builtin_va_start(__builtin_va_list, ...);
+         * The second argument is supposed to be of any type, so fake it with the ...
+         */
+        genBuiltinFunc(Id.builtin_va_start, AST.VarArg.variadic);
+
+        /* void __builtin_va_end(__builtin_va_list);
+         */
+        genBuiltinFunc(Id.builtin_va_end, AST.VarArg.none);
+
+        /* struct __va_list_tag
+         * {
+         *    uint, uint, void*, void*
+         * }
+         */
+        auto s = new AST.StructDeclaration(Loc.initial, Id.va_list_tag, false);
+        symbols.push(s);
+    }
+
     //}
 }
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 0381f9ad6a4..df742c0bd8f 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -41,7 +41,7 @@  import dmd.identifier;
 import dmd.mtype;
 import dmd.nspace;
 import dmd.root.array;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.target;
@@ -98,21 +98,20 @@  extern(C++) const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
 }
 
 /******************************
- * Determine if sym is the 'primary' destructor, that is,
- * the most-aggregate destructor (the one that is defined as __xdtor)
+ * Determine if sym is a full aggregate destructor.
  * Params:
  *      sym = Dsymbol
  * Returns:
- *      true if sym is the primary destructor for an aggregate
+ *      true if sym is an aggregate destructor
  */
-bool isPrimaryDtor(const Dsymbol sym)
+bool isAggregateDtor(const Dsymbol sym)
 {
     const dtor = sym.isDtorDeclaration();
     if (!dtor)
         return false;
     const ad = dtor.isMember();
     assert(ad);
-    return dtor == ad.primaryDtor;
+    return dtor == ad.aggrDtor;
 }
 
 /// Context used when processing pre-semantic AST
@@ -1069,7 +1068,7 @@  private final class CppMangleVisitor : Visitor
 
             if (auto ctor = d.isCtorDeclaration())
                 buf.writestring(ctor.isCpCtor ? "C2" : "C1");
-            else if (d.isPrimaryDtor())
+            else if (d.isAggregateDtor())
                 buf.writestring("D1");
             else if (d.ident && d.ident == Id.assign)
                 buf.writestring("aS");
@@ -1184,7 +1183,7 @@  private final class CppMangleVisitor : Visitor
             mangleFunctionParameters(tf.parameterList);
             return;
         }
-        else if (d.isPrimaryDtor())
+        else if (d.isAggregateDtor())
         {
             buf.writestring("D1");
             mangleFunctionParameters(tf.parameterList);
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 22633a869d4..7f76d7565e0 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -685,6 +685,11 @@  bool isSafePointerCast(Type srcPointee, Type destPointee)
     // It's OK if both are the same (modulo const)
     if (srcPointee.constConv(destPointee))
         return true;
+
+    // It's ok to cast from/to shared because CTFE is single threaded anyways
+    if (srcPointee.unSharedOf() == destPointee.unSharedOf())
+        return true;
+
     // It's OK if function pointers differ only in safe/pure/nothrow
     if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
         return srcPointee.covariant(destPointee) == Covariant.yes ||
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 4c70565e5c2..87c3adae9e6 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -31,12 +31,13 @@  import dmd.func;
 import dmd.globals;
 import dmd.impcnvtab;
 import dmd.id;
+import dmd.importc;
 import dmd.init;
 import dmd.intrange;
 import dmd.mtype;
 import dmd.opover;
 import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.tokens;
 import dmd.typesem;
@@ -1445,6 +1446,29 @@  MATCH implicitConvTo(Expression e, Type t)
             if (tb.ty == Tpointer && e.e1.op == TOK.string_)
                 e.e1.accept(this);
         }
+
+        override void visit(TupleExp e)
+        {
+            result = e.type.implicitConvTo(t);
+            if (result != MATCH.nomatch)
+                return;
+
+            /* If target type is a tuple of same length, test conversion of
+             * each expression to the corresponding type in the tuple.
+             */
+            TypeTuple totuple = t.isTypeTuple();
+            if (totuple && e.exps.length == totuple.arguments.length)
+            {
+                result = MATCH.exact;
+                foreach (i, ex; *e.exps)
+                {
+                    auto to = (*totuple.arguments)[i].type;
+                    MATCH mi = ex.implicitConvTo(to);
+                    if (mi < result)
+                        result = mi;
+                }
+            }
+        }
     }
 
     scope ImplicitConvTo v = new ImplicitConvTo(t);
@@ -1476,12 +1500,8 @@  MATCH cimplicitConvTo(Expression e, Type t)
         return MATCH.convert;
     if (tb.isintegral() && typeb.ty == Tpointer) // C11 6.3.2.3-6
         return MATCH.convert;
-    if (tb.ty == Tpointer && typeb.ty == Tpointer)
-    {
-        if (tb.isTypePointer().next.ty == Tvoid ||
-            typeb.isTypePointer().next.ty == Tvoid)
-            return MATCH.convert;       // convert to/from void* C11 6.3.2.3-1
-    }
+    if (tb.ty == Tpointer && typeb.ty == Tpointer) // C11 6.3.2.3-7
+        return MATCH.convert;
 
     return implicitConvTo(e, t);
 }
@@ -2189,13 +2209,20 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 return;
             }
 
+            /* If target type is a tuple of same length, cast each expression to
+             * the corresponding type in the tuple.
+             */
+            TypeTuple totuple;
+            if (auto tt = t.isTypeTuple())
+                totuple = e.exps.length == tt.arguments.length ? tt : null;
+
             TupleExp te = e.copy().isTupleExp();
             te.e0 = e.e0 ? e.e0.copy() : null;
             te.exps = e.exps.copy();
             for (size_t i = 0; i < te.exps.dim; i++)
             {
                 Expression ex = (*te.exps)[i];
-                ex = ex.castTo(sc, t);
+                ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t);
                 (*te.exps)[i] = ex;
             }
             result = te;
@@ -2821,6 +2848,13 @@  Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
     Expression e1 = pe1;
     Expression e2 = pe2;
 
+    // ImportC: do array/function conversions
+    if (sc)
+    {
+        e1 = e1.arrayFuncConv(sc);
+        e2 = e2.arrayFuncConv(sc);
+    }
+
     Type Lret(Type result)
     {
         pe1 = e1;
@@ -2838,7 +2872,7 @@  Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
         return result;
     }
 
-    /// Converts one of the expression too the other
+    /// Converts one of the expression to the other
     Type convert(ref Expression from, Type to)
     {
         from = from.castTo(sc, to);
@@ -2856,6 +2890,22 @@  Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
     Type t1b = e1.type.toBasetype();
     Type t2b = e2.type.toBasetype();
 
+    if (sc && sc.flags & SCOPE.Cfile)
+    {
+        // Integral types can be implicitly converted to pointers
+        if ((t1b.ty == Tpointer) != (t2b.ty == Tpointer))
+        {
+            if (t1b.isintegral())
+            {
+                return convert(e1, t2b);
+            }
+            else if (t2b.isintegral())
+            {
+                return convert(e2, t1b);
+            }
+        }
+    }
+
     if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
     {
         if (op == TOK.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar())
@@ -3132,6 +3182,14 @@  Lagain:
     Lcc:
         while (1)
         {
+            MATCH i1woat = MATCH.exact;
+            MATCH i2woat = MATCH.exact;
+
+            if (auto t2c = t2.isTypeClass())
+                i1woat = t2c.implicitConvToWithoutAliasThis(t1);
+            if (auto t1c = t1.isTypeClass())
+                i2woat = t1c.implicitConvToWithoutAliasThis(t2);
+
             MATCH i1 = e2.implicitConvTo(t1);
             MATCH i2 = e1.implicitConvTo(t2);
 
@@ -3144,11 +3202,26 @@  Lagain:
                     i2 = MATCH.nomatch;
             }
 
-            if (i2)
+            // Match but without 'alias this' on classes
+            if (i2 && i2woat)
                 return coerce(t2);
-            if (i1)
+            if (i1 && i1woat)
                 return coerce(t1);
 
+            // Here use implicitCastTo() instead of castTo() to try 'alias this' on classes
+            Type coerceImplicit(Type towards)
+            {
+                e1 = e1.implicitCastTo(sc, towards);
+                e2 = e2.implicitCastTo(sc, towards);
+                return Lret(towards);
+            }
+
+            // Implicit conversion with 'alias this'
+            if (i2)
+                return coerceImplicit(t2);
+            if (i1)
+                return coerceImplicit(t1);
+
             if (t1.ty == Tclass && t2.ty == Tclass)
             {
                 TypeClass tc1 = t1.isTypeClass();
@@ -3257,29 +3330,26 @@  Lagain:
         }
     }
 
-    if (t1.ty == Tstruct || t2.ty == Tstruct)
+    if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
     {
-        if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
-        {
-            if (isRecursiveAliasThis(att1, e1.type))
-                return null;
-            //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
-            e1 = resolveAliasThis(sc, e1);
-            t1 = e1.type;
-            t = t1;
-            goto Lagain;
-        }
-        if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
-        {
-            if (isRecursiveAliasThis(att2, e2.type))
-                return null;
-            //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
-            e2 = resolveAliasThis(sc, e2);
-            t2 = e2.type;
-            t = t2;
-            goto Lagain;
-        }
-        return null;
+        if (isRecursiveAliasThis(att1, e1.type))
+            return null;
+        //printf("att tmerge(s || s) e1 = %s\n", e1.type.toChars());
+        e1 = resolveAliasThis(sc, e1);
+        t1 = e1.type;
+        t = t1;
+        goto Lagain;
+    }
+
+    if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
+    {
+        if (isRecursiveAliasThis(att2, e2.type))
+            return null;
+        //printf("att tmerge(s || s) e2 = %s\n", e2.type.toChars());
+        e2 = resolveAliasThis(sc, e2);
+        t2 = e2.type;
+        t = t2;
+        goto Lagain;
     }
 
     if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2))
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index b065251e652..34a236ba26e 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -20,6 +20,7 @@  import dmd.aggregate;
 import dmd.apply;
 import dmd.arraytypes;
 import dmd.astenums;
+import dmd.attrib;
 import dmd.gluelayer;
 import dmd.declaration;
 import dmd.dscope;
@@ -367,7 +368,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
         baseok = Baseok.none;
     }
 
-    static ClassDeclaration create(Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
+    static ClassDeclaration create(const ref Loc loc, Identifier id, BaseClasses* baseclasses, Dsymbols* members, bool inObject)
     {
         return new ClassDeclaration(loc, id, baseclasses, members, inObject);
     }
@@ -607,7 +608,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
 
                 if (!b.sym.alignsize)
                     b.sym.alignsize = target.ptrsize;
-                alignmember(b.sym.alignsize, b.sym.alignsize, &offset);
+                alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, &offset);
                 assert(bi < vtblInterfaces.dim);
 
                 BaseClass* bv = (*vtblInterfaces)[bi];
@@ -725,6 +726,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
 
         void searchVtbl(ref Dsymbols vtbl)
         {
+            bool seenInterfaceVirtual;
             foreach (s; vtbl)
             {
                 auto fd = s.isFuncDeclaration();
@@ -748,6 +750,23 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
                 if (fd == fdmatch)
                     continue;
 
+                /* Functions overriding interface functions for extern(C++) with VC++
+                 * are not in the normal vtbl, but in vtblFinal. If the implementation
+                 * is again overridden in a child class, both would be found here.
+                 * The function in the child class should override the function
+                 * in the base class, which is done here, because searchVtbl is first
+                 * called for the child class. Checking seenInterfaceVirtual makes
+                 * sure, that the compared functions are not in the same vtbl.
+                 */
+                if (fd.interfaceVirtual &&
+                    fd.interfaceVirtual is fdmatch.interfaceVirtual &&
+                    !seenInterfaceVirtual &&
+                    fdmatch.type.covariant(fd.type) == Covariant.yes)
+                {
+                    seenInterfaceVirtual = true;
+                    continue;
+                }
+
                 {
                 // Function type matching: exact > covariant
                 MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 0f40c1142c7..e3f135a03d8 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -16,6 +16,7 @@  import core.stdc.stdio;
 import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
+import dmd.attrib;
 import dmd.ctorflow;
 import dmd.dclass;
 import dmd.delegatize;
@@ -34,7 +35,7 @@  import dmd.init;
 import dmd.initsem;
 import dmd.intrange;
 import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.target;
 import dmd.tokens;
@@ -705,7 +706,7 @@  extern (C++) final class AliasDeclaration : Declaration
         assert(s);
     }
 
-    static AliasDeclaration create(Loc loc, Identifier id, Type type)
+    static AliasDeclaration create(const ref Loc loc, Identifier id, Type type)
     {
         return new AliasDeclaration(loc, id, type);
     }
@@ -1192,14 +1193,7 @@  extern (C++) class VarDeclaration : Declaration
         /* If coming after a bit field in progress,
          * advance past the field
          */
-        if (fieldState.inFlight)
-        {
-            fieldState.inFlight = false;
-            if (0 && target.os & Target.OS.Posix)
-                fieldState.offset += (fieldState.bitOffset + 7) / 8;
-            else if (0 &&target.os == Target.OS.Windows)
-                fieldState.offset += fieldState.fieldSize;
-        }
+        fieldState.inFlight = false;
 
         const sz = t.size(loc);
         assert(sz != SIZE_INVALID && sz < uint.max);
@@ -1743,13 +1737,23 @@  extern (C++) class BitFieldDeclaration : VarDeclaration
 
     override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
     {
-        //printf("BitFieldDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
+        //printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
+        static void print(const ref FieldState fieldState)
+        {
+            printf("FieldState.offset      = %d bytes\n",   fieldState.offset);
+            printf("          .fieldOffset = %d bytes\n",   fieldState.fieldOffset);
+            printf("          .bitOffset   = %d bits\n",    fieldState.bitOffset);
+            printf("          .fieldSize   = %d bytes\n",   fieldState.fieldSize);
+            printf("          .inFlight    = %d\n\n", fieldState.inFlight);
+        }
+        //print(fieldState);
 
         Type t = type.toBasetype();
+        const bool anon = isAnonymous();
 
         // List in ad.fields. Even if the type is error, it's necessary to avoid
         // pointless error diagnostic "more initializers than fields" on struct literal.
-        if (!isAnonymous())
+        if (!anon)
             ad.fields.push(this);
 
         if (t.ty == Terror)
@@ -1760,17 +1764,36 @@  extern (C++) class BitFieldDeclaration : VarDeclaration
         uint memsize = cast(uint)sz;                // size of member
         uint memalignsize = target.fieldalign(t);   // size of member for alignment purposes
 
-        if (fieldWidth == 0 && !isAnonymous())
+        if (fieldWidth == 0 && !anon)
             error(loc, "named bit fields cannot have 0 width");
         if (fieldWidth > memsize * 8)
             error(loc, "bit field width %d is larger than type", fieldWidth);
 
+        const style = target.c.bitFieldStyle;
+
         void startNewField()
         {
+            uint alignsize;
+            if (style == TargetC.BitFieldStyle.Gcc_Clang)
+            {
+                if (fieldWidth > 32)
+                    alignsize = memalignsize;
+                else if (fieldWidth > 16)
+                    alignsize = 4;
+                else if (fieldWidth > 8)
+                    alignsize = 2;
+                else
+                    alignsize = 1;
+            }
+            else
+                alignsize = memsize; // not memalignsize
+
+            uint dummy;
             offset = AggregateDeclaration.placeField(
                 &fieldState.offset,
-                memsize, memalignsize, alignment,
-                &ad.structsize, &ad.alignsize,
+                memsize, alignsize, alignment,
+                &ad.structsize,
+                (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? &dummy : &ad.alignsize,
                 isunion);
 
             fieldState.inFlight = true;
@@ -1779,19 +1802,92 @@  extern (C++) class BitFieldDeclaration : VarDeclaration
             fieldState.fieldSize = memsize;
         }
 
-        if (!fieldState.inFlight || fieldWidth == 0)
+        if (style == TargetC.BitFieldStyle.Gcc_Clang)
         {
-            startNewField();
+            if (fieldWidth == 0)
+            {
+                if (!isunion)
+                {
+                    // Use type of zero width field to align to next field
+                    fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
+                    ad.structsize = fieldState.offset;
+                }
+
+                fieldState.inFlight = false;
+                return;
+            }
+
+            if (ad.alignsize == 0)
+                ad.alignsize = 1;
+            if (!anon &&
+                  ad.alignsize < memalignsize)
+                ad.alignsize = memalignsize;
+        }
+        else if (style == TargetC.BitFieldStyle.MS)
+        {
+            if (ad.alignsize == 0)
+                ad.alignsize = 1;
+            if (fieldWidth == 0)
+            {
+                if (fieldState.inFlight && !isunion)
+                {
+                    // documentation says align to next int
+                    //const alsz = cast(uint)Type.tint32.size();
+                    const alsz = memsize; // but it really does this
+                    fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+                    ad.structsize = fieldState.offset;
+                }
+
+                fieldState.inFlight = false;
+                return;
+            }
+        }
+        else if (style == TargetC.BitFieldStyle.DM)
+        {
+            if (anon && fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
+                return;  // this probably should be a bug in DMC
+            if (ad.alignsize == 0)
+                ad.alignsize = 1;
+            if (fieldWidth == 0)
+            {
+                if (fieldState.inFlight && !isunion)
+                {
+                    const alsz = memsize;
+                    fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+                    ad.structsize = fieldState.offset;
+                }
+
+                fieldState.inFlight = false;
+                return;
+            }
         }
 
-        if (0 && target.os & Target.OS.Posix)
+        if (!fieldState.inFlight)
+        {
+            startNewField();
+        }
+        else if (style == TargetC.BitFieldStyle.Gcc_Clang)
         {
-            if ((fieldState.offset%4 * 8) + fieldState.bitOffset + fieldWidth > int.sizeof * 8)
+            if (fieldState.bitOffset + fieldWidth > memsize * 8)
             {
+                //printf("start1 fieldState.bitOffset:%u fieldWidth:%u memsize:%u\n", fieldState.bitOffset, fieldWidth, memsize);
                 startNewField();
             }
+            else
+            {
+                // if alignment boundary is crossed
+                uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
+                uint end   = start + fieldWidth;
+                //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
+                if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
+                {
+                    //printf("alignment is crossed\n");
+                    startNewField();
+                }
+            }
         }
-        else if (1 || target.os == Target.OS.Windows)
+        else if (style == TargetC.BitFieldStyle.DM ||
+                 style == TargetC.BitFieldStyle.MS)
         {
             if (memsize != fieldState.fieldSize ||
                 fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
@@ -1799,22 +1895,29 @@  extern (C++) class BitFieldDeclaration : VarDeclaration
                 startNewField();
             }
         }
+        else
+            assert(0);
 
         offset = fieldState.fieldOffset;
         bitOffset = fieldState.bitOffset;
-        if (0 && target.os & Target.OS.Posix)
+
+        const pastField = bitOffset + fieldWidth;
+        if (style == TargetC.BitFieldStyle.Gcc_Clang)
         {
-            while (bitOffset > memsize * 8)
-            {
-                bitOffset -= 8;
-                offset += 1;
-            }
+            auto size = (pastField + 7) / 8;
+            fieldState.fieldSize = size;
+            //printf(" offset: %d, size: %d\n", offset, size);
+            ad.structsize = offset + size;
         }
+        else
+            fieldState.fieldSize = memsize;
+        //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
+        //print(fieldState);
 
-        //fieldState.fieldSize = memsize;
         if (!isunion)
         {
-            fieldState.bitOffset += fieldWidth;
+            fieldState.offset = offset + fieldState.fieldSize;
+            fieldState.bitOffset = pastField;
         }
 
         //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
@@ -1861,7 +1964,7 @@  extern (C++) class TypeInfoDeclaration : VarDeclaration
         storage_class = STC.static_ | STC.gshared;
         visibility = Visibility(Visibility.Kind.public_);
         linkage = LINK.c;
-        alignment = target.ptrsize;
+        alignment.set(target.ptrsize);
     }
 
     static TypeInfoDeclaration create(Type tinfo)
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 1c56defd3ee..4a4c3530417 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -188,7 +188,7 @@  public:
     Dsymbol *overnext;          // next in overload list
     Dsymbol *_import;           // !=NULL if unresolved internal alias for selective import
 
-    static AliasDeclaration *create(Loc loc, Identifier *id, Type *type);
+    static AliasDeclaration *create(const Loc &loc, Identifier *id, Type *type);
     AliasDeclaration *syntaxCopy(Dsymbol *);
     bool overloadInsert(Dsymbol *s);
     const char *kind() const;
@@ -511,7 +511,7 @@  enum class BUILTIN : unsigned char
     toPrecReal
 };
 
-Expression *eval_builtin(Loc loc, FuncDeclaration *fd, Expressions *arguments);
+Expression *eval_builtin(const Loc &loc, FuncDeclaration *fd, Expressions *arguments);
 BUILTIN isBuiltin(FuncDeclaration *fd);
 
 class FuncDeclaration : public Declaration
@@ -535,6 +535,8 @@  public:
     VarDeclaration *vresult;            // result variable for out contracts
     LabelDsymbol *returnLabel;          // where the return goes
 
+    void *isTypeIsolatedCache;          // An AA on the D side to cache an expensive check result
+
     // used to prevent symbols in different
     // scopes from having the same name
     DsymbolTable *localsymtab;
@@ -839,9 +841,6 @@  public:
 class NewDeclaration : public FuncDeclaration
 {
 public:
-    Parameters *parameters;
-    VarArg varargs;
-
     NewDeclaration *syntaxCopy(Dsymbol *);
     const char *kind() const;
     bool isVirtual() const;
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 541fac7dfb4..a1f36c0c48f 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -42,6 +42,7 @@  import dmd.mtype;
 import dmd.printast;
 import dmd.root.rmem;
 import dmd.root.array;
+import dmd.root.ctfloat;
 import dmd.root.region;
 import dmd.root.rootobject;
 import dmd.statement;
@@ -75,6 +76,7 @@  public Expression ctfeInterpret(Expression e)
         case TOK.template_:              // non-eponymous template/instance
         case TOK.scope_:                 // ditto
         case TOK.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
+        case TOK.dotTemplateInstance:    // ditto
         case TOK.dot:                    // ditto
              if (e.type.ty == Terror)
                 return ErrorExp.get();
@@ -2167,26 +2169,20 @@  public:
             return;
         }
 
-        // Note: This is a workaround for
-        // https://issues.dlang.org/show_bug.cgi?id=17351
-        // The aforementioned bug triggers when passing manifest constant by `ref`.
-        // If there was not a previous reference to them, they are
-        // not cached and trigger a "cannot be read at compile time".
-        // This fix is a crude solution to get it to work. A more proper
-        // approach would be to resolve the forward reference, but that is
-        // much more involved.
-        if (goal == CTFEGoal.LValue && e.var.type.isMutable())
+        if (goal == CTFEGoal.LValue)
         {
             if (auto v = e.var.isVarDeclaration())
             {
-                if (!v.isDataseg() && !v.isCTFE() && !istate)
-                {
-                    e.error("variable `%s` cannot be read at compile time", v.toChars());
-                    result = CTFEExp.cantexp;
-                    return;
-                }
                 if (!hasValue(v))
                 {
+                    // Compile-time known non-CTFE variable from an outer context
+                    // e.g. global or from a ref argument
+                    if (v.isConst() || v.isImmutable())
+                    {
+                        result = getVarExp(e.loc, istate, v, goal);
+                        return;
+                    }
+
                     if (!v.isCTFE() && v.isDataseg())
                         e.error("static variable `%s` cannot be read at compile time", v.toChars());
                     else // CTFE initiated from inside a function
@@ -2201,7 +2197,7 @@  public:
                     Expression ev = getValue(v);
                     if (ev.op == TOK.variable ||
                         ev.op == TOK.index ||
-                        ev.op == TOK.slice ||
+                        (ev.op == TOK.slice && ev.type.toBasetype().ty == Tsarray) ||
                         ev.op == TOK.dotVariable)
                     {
                         result = interpret(pue, ev, istate, goal);
@@ -2836,8 +2832,7 @@  public:
             auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
             se.origin = se;
             se.ownedByCtfe = OwnedBy.ctfe;
-            emplaceExp!(ClassReferenceExp)(pue, e.loc, se, e.type);
-            Expression eref = pue.exp();
+            Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
             if (e.member)
             {
                 // Call constructor
@@ -6024,12 +6019,23 @@  public:
         }
         if (e.to.ty == Tsarray)
             e1 = resolveSlice(e1);
-        if (e.to.toBasetype().ty == Tbool && e1.type.ty == Tpointer)
+
+        auto tobt = e.to.toBasetype();
+        if (tobt.ty == Tbool && e1.type.ty == Tpointer)
         {
             emplaceExp!(IntegerExp)(pue, e.loc, e1.op != TOK.null_, e.to);
             result = pue.exp();
             return;
         }
+        else if (tobt.isTypeBasic() && e1.op == TOK.null_)
+        {
+            if (tobt.isintegral())
+                emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
+            else if (tobt.isreal())
+                emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
+            result = pue.exp();
+            return;
+        }
         result = ctfeCast(pue, e.loc, e.type, e.to, e1);
     }
 
@@ -6306,7 +6312,7 @@  public:
             auto tsa = cast(TypeSArray)v.type;
             auto len = cast(size_t)tsa.dim.toInteger();
             UnionExp ue = void;
-            result = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
+            result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
             if (result == ue.exp())
                 result = ue.copy();
             (*se.elements)[i] = result;
diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d
index ddfee2ccab0..357f7bdcd9f 100644
--- a/gcc/d/dmd/dmacro.d
+++ b/gcc/d/dmd/dmacro.d
@@ -16,7 +16,7 @@  import core.stdc.string;
 import dmd.doc;
 import dmd.errors;
 import dmd.globals;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 
 extern (C++) struct MacroTable
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index 71b8c7a6098..c417f93c353 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -139,7 +139,7 @@  import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
 import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.aav;
 import dmd.root.string;
 import dmd.root.stringtable;
@@ -1259,14 +1259,49 @@  public:
 
     override void visit(Parameter p)
     {
-        if (p.storageClass & STC.scope_ && !(p.storageClass & STC.scopeinferred))
-            buf.writeByte('M');
+        // https://dlang.org/spec/abi.html#Parameter
+
+        auto stc = p.storageClass;
+
+        // Inferred storage classes don't get mangled in
+        if (stc & STC.scopeinferred)
+            stc &= ~(STC.scope_ | STC.scopeinferred);
+        if (stc & STC.returninferred)
+            stc &= ~(STC.return_ | STC.returninferred);
 
         // 'return inout ref' is the same as 'inout ref'
-        if ((p.storageClass & (STC.return_ | STC.wild)) == STC.return_ &&
-            !(p.storageClass & STC.returninferred))
-            buf.writestring("Nk");
-        switch (p.storageClass & (STC.IOR | STC.lazy_))
+        if ((stc & (STC.return_ | STC.wild)) == (STC.return_ | STC.wild))
+            stc &= ~STC.return_;
+
+        // much like hdrgen.stcToBuffer()
+        string rrs;
+        const isout = (stc & STC.out_) != 0;
+        final switch (buildScopeRef(stc))
+        {
+            case ScopeRef.None:
+            case ScopeRef.Scope:
+            case ScopeRef.Ref:
+            case ScopeRef.Return:
+            case ScopeRef.RefScope:
+                break;
+
+            case ScopeRef.ReturnScope:     rrs = "NkM";                  goto L1;  // return scope
+            case ScopeRef.ReturnRef:       rrs = isout ? "NkJ"  : "NkK"; goto L1;  // return ref
+            case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref
+            case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref
+            L1:
+                buf.writestring(rrs);
+                stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_);
+                break;
+        }
+
+        if (stc & STC.scope_)
+            buf.writeByte('M');  // scope
+
+        if (stc & STC.return_)
+            buf.writestring("Nk"); // return
+
+        switch (stc & (STC.IOR | STC.lazy_))
         {
         case 0:
             break;
@@ -1288,10 +1323,10 @@  public:
         default:
             debug
             {
-                printf("storageClass = x%llx\n", p.storageClass & (STC.IOR | STC.lazy_));
+                printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_));
             }
             assert(0);
         }
-        visitWithMask(p.type, (p.storageClass & STC.in_) ? MODFlags.const_ : 0);
+        visitWithMask(p.type, (stc & STC.in_) ? MODFlags.const_ : 0);
     }
 }
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 768eaa05a08..4e0071304e4 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -31,6 +31,7 @@  import dmd.dsymbolsem;
 import dmd.errors;
 import dmd.expression;
 import dmd.expressionsem;
+import dmd.file_manager;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
@@ -39,7 +40,7 @@  import dmd.cparse;
 import dmd.root.array;
 import dmd.root.file;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.port;
 import dmd.root.rmem;
 import dmd.root.rootobject;
@@ -50,113 +51,6 @@  import dmd.target;
 import dmd.utils;
 import dmd.visitor;
 
-enum package_d  = "package." ~ mars_ext;
-enum package_di = "package." ~ hdr_ext;
-
-/********************************************
- * Look for the source file if it's different from filename.
- * Look for .di, .d, directory, and along global.path.
- * Does not open the file.
- * Params:
- *      filename = as supplied by the user
- *      path = path to look for filename
- * Returns:
- *      the found file name or
- *      `null` if it is not different from filename.
- */
-private const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
-{
-    //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
-    /* Search along path[] for .di file, then .d file, then .i file, then .c file.
-     */
-    const sdi = FileName.forceExt(filename, hdr_ext);
-    if (FileName.exists(sdi) == 1)
-        return sdi;
-    scope(exit) FileName.free(sdi.ptr);
-
-    const sd = FileName.forceExt(filename, mars_ext);
-    if (FileName.exists(sd) == 1)
-        return sd;
-    scope(exit) FileName.free(sd.ptr);
-
-    const si = FileName.forceExt(filename, i_ext);
-    if (FileName.exists(si) == 1)
-        return si;
-    scope(exit) FileName.free(si.ptr);
-
-    const sc = FileName.forceExt(filename, c_ext);
-    if (FileName.exists(sc) == 1)
-        return sc;
-    scope(exit) FileName.free(sc.ptr);
-
-    if (FileName.exists(filename) == 2)
-    {
-        /* The filename exists and it's a directory.
-         * Therefore, the result should be: filename/package.d
-         * iff filename/package.d is a file
-         */
-        const ni = FileName.combine(filename, package_di);
-        if (FileName.exists(ni) == 1)
-            return ni;
-        FileName.free(ni.ptr);
-
-        const n = FileName.combine(filename, package_d);
-        if (FileName.exists(n) == 1)
-            return n;
-        FileName.free(n.ptr);
-    }
-    if (FileName.absolute(filename))
-        return null;
-    if (!path.length)
-        return null;
-    foreach (entry; path)
-    {
-        const p = entry.toDString();
-
-        const(char)[] n = FileName.combine(p, sdi);
-        if (FileName.exists(n) == 1) {
-            return n;
-        }
-        FileName.free(n.ptr);
-
-        n = FileName.combine(p, sd);
-        if (FileName.exists(n) == 1) {
-            return n;
-        }
-        FileName.free(n.ptr);
-
-        n = FileName.combine(p, si);
-        if (FileName.exists(n) == 1) {
-            return n;
-        }
-        FileName.free(n.ptr);
-
-        n = FileName.combine(p, sc);
-        if (FileName.exists(n) == 1) {
-            return n;
-        }
-        FileName.free(n.ptr);
-
-        const b = FileName.removeExt(filename);
-        n = FileName.combine(p, b);
-        FileName.free(b.ptr);
-        if (FileName.exists(n) == 2)
-        {
-            const n2i = FileName.combine(n, package_di);
-            if (FileName.exists(n2i) == 1)
-                return n2i;
-            FileName.free(n2i.ptr);
-            const n2 = FileName.combine(n, package_d);
-            if (FileName.exists(n2) == 1) {
-                return n2;
-            }
-            FileName.free(n2.ptr);
-        }
-        FileName.free(n.ptr);
-    }
-    return null;
-}
-
 // function used to call semantic3 on a module's dependencies
 void semantic3OnDependencies(Module m)
 {
@@ -414,8 +308,8 @@  extern (C++) class Package : ScopeDsymbol
             packages ~= s.ident;
         reverse(packages);
 
-        if (lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null))
-            Module.load(Loc(), packages, this.ident);
+        if (FileManager.lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null))
+            Module.load(Loc.initial, packages, this.ident);
         else
             isPkgMod = PKG.package_;
     }
@@ -598,12 +492,12 @@  extern (C++) final class Module : Package
         return new Module(Loc.initial, filename, ident, doDocComment, doHdrGen);
     }
 
-    extern (C++) static Module load(Loc loc, Identifiers* packages, Identifier ident)
+    extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident)
     {
         return load(loc, packages ? (*packages)[] : null, ident);
     }
 
-    extern (D) static Module load(Loc loc, Identifier[] packages, Identifier ident)
+    extern (D) static Module load(const ref Loc loc, Identifier[] packages, Identifier ident)
     {
         //printf("Module::load(ident = '%s')\n", ident.toChars());
         // Build module filename by turning:
@@ -612,7 +506,7 @@  extern (C++) final class Module : Package
         //  foo\bar\baz
         const(char)[] filename = getFilename(packages, ident);
         // Look for the source file
-        if (const result = lookForSourceFile(filename, global.path ? (*global.path)[] : null))
+        if (const result = FileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null))
             filename = result; // leaks
 
         auto m = new Module(loc, filename, ident, 0, 0);
@@ -737,7 +631,12 @@  extern (C++) final class Module : Package
             if (isPackageMod)
                 .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars());
             else
-                error(loc, "is in file '%s' which cannot be read", srcfile.toChars());
+            {
+                .error(loc, "unable to read module `%s`", toChars());
+                const pkgfile = FileName.combine(FileName.removeExt(srcfile.toString()), package_d);
+                .errorSupplemental(loc, "Expected '%s' or '%s' in one of the following import paths:",
+                    srcfile.toChars(), pkgfile.ptr);
+            }
         }
         if (!global.gag)
         {
@@ -776,14 +675,25 @@  extern (C++) final class Module : Package
             return true; // already read
 
         //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
-        auto readResult = File.read(srcfile.toChars());
 
         if (global.params.emitMakeDeps)
         {
             global.params.makeDeps.push(srcfile.toChars());
         }
 
-        return loadSourceBuffer(loc, readResult);
+        if (auto readResult = FileManager.fileManager.lookup(srcfile))
+        {
+            srcBuffer = readResult;
+            return true;
+        }
+
+        auto readResult = File.read(srcfile.toChars());
+        if (loadSourceBuffer(loc, readResult))
+        {
+            FileManager.fileManager.add(srcfile, srcBuffer);
+            return true;
+        }
+        return false;
     }
 
     /// syntactic parse
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index 9b4329b8b0a..f9b765c521c 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -45,7 +45,7 @@  import dmd.mtype;
 import dmd.root.array;
 import dmd.root.file;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.port;
 import dmd.root.rmem;
 import dmd.root.string;
@@ -3995,8 +3995,8 @@  private size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const r
     const iDelimiterRowEnd = parseTableDelimiterRow(buf, iEnd + 1, inQuote, columnAlignments);
     if (iDelimiterRowEnd)
     {
-        const delta = replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, true);
-        if (delta)
+        size_t delta;
+        if (replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, true, delta))
         {
             buf.remove(iEnd + delta, iDelimiterRowEnd - iEnd);
             buf.insert(iEnd + delta, "$(TBODY ");
@@ -4023,12 +4023,15 @@  private size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const r
  *  headerRow = if `true` then the number of columns will be enforced to match
  *              `columnAlignments.length` and the row will be surrounded by a
  *              `THEAD` macro
- * Returns: the number of characters added by replacing the row, or `0` if unchanged
+ *  delta     = the number of characters added by replacing the row, or `0` if unchanged
+ * Returns: `true` if a table row was found and replaced
  */
-private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow)
+private bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow, out size_t delta)
 {
+    delta = 0;
+
     if (!columnAlignments.length || iStart == iEnd)
-        return 0;
+        return false;
 
     iStart = skipChars(buf, iStart, " \t");
     int cellCount = 0;
@@ -4045,7 +4048,7 @@  private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, co
         ++cellCount;
 
     if (headerRow && cellCount != columnAlignments.length)
-        return 0;
+        return false;
 
     if (headerRow && global.params.vmarkdown)
     {
@@ -4053,8 +4056,6 @@  private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, co
         message(loc, "Ddoc: formatting table '%.*s'", cast(int)s.length, s.ptr);
     }
 
-    size_t delta = 0;
-
     void replaceTableCell(size_t iCellStart, size_t iCellEnd, int cellIndex, int di)
     {
         const eDelta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, di);
@@ -4146,7 +4147,7 @@  private size_t replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, co
         delta += 9;
     }
 
-    return delta;
+    return true;
 }
 
 /****************************************************
@@ -4182,7 +4183,8 @@  private size_t endTable(ref OutBuffer buf, size_t i, ref TableColumnAlignment[]
  */
 private size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments)
 {
-    size_t delta = replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, false);
+    size_t delta;
+    replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, false, delta);
     delta += endTable(buf, iEnd + delta, columnAlignments);
     return delta;
 }
@@ -4263,8 +4265,8 @@  private void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, s
                 i += startTable(buf, iLineStart, i, loc, lineQuoted, inlineDelimiters, columnAlignments);
             else if (columnAlignments.length)
             {
-                const delta = replaceTableRow(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments, false);
-                if (delta)
+                size_t delta;
+                if (replaceTableRow(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments, false, delta))
                     i += delta;
                 else
                     i += endTable(buf, i, columnAlignments);
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 638fc7e5295..42c0d18b2db 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -33,7 +33,7 @@  import dmd.func;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.speller;
 import dmd.statement;
@@ -730,12 +730,21 @@  struct Scope
         }
     }
 
+    /******************************
+     */
     structalign_t alignment()
     {
         if (aligndecl)
-            return aligndecl.getAlignment(&this);
+        {
+            auto ad = aligndecl.getAlignment(&this);
+            return ad.salign;
+        }
         else
-            return STRUCTALIGN_DEFAULT;
+        {
+            structalign_t sa;
+            sa.setDefault();
+            return sa;
+        }
     }
 
     /**********************************
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 80ecd361135..0925e7cd38a 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -16,6 +16,7 @@  module dmd.dstruct;
 import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
+import dmd.attrib;
 import dmd.declaration;
 import dmd.dmodule;
 import dmd.dscope;
@@ -127,7 +128,7 @@  extern (C++) void semanticTypeInfo(Scope* sc, Type t)
          */
         if (!sd.members)
             return; // opaque struct
-        if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd))
+        if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.tidtor && !sd.xhash && !search_toString(sd))
             return; // none of TypeInfo-specific members
 
         // If the struct is in a non-root module, run semantic3 to get
@@ -232,7 +233,7 @@  extern (C++) class StructDeclaration : AggregateDeclaration
         }
     }
 
-    static StructDeclaration create(Loc loc, Identifier id, bool inObject)
+    static StructDeclaration create(const ref Loc loc, Identifier id, bool inObject)
     {
         return new StructDeclaration(loc, id, inObject);
     }
@@ -297,22 +298,46 @@  extern (C++) class StructDeclaration : AggregateDeclaration
             return;
         }
 
-        // 0 sized struct's are set to 1 byte
         if (structsize == 0)
         {
             hasNoFields = true;
             alignsize = 1;
-            if (classKind != classKind.c) // C gets a struct size of 0
-                structsize = 1;
+
+            // A fine mess of what size a zero sized struct should be
+            final switch (classKind)
+            {
+                case ClassKind.d:
+                case ClassKind.cpp:
+                    structsize = 1;
+                    break;
+
+                case ClassKind.c:
+                case ClassKind.objc:
+                    if (target.c.bitFieldStyle == TargetC.BitFieldStyle.MS)
+                    {
+                        /* Undocumented MS behavior for:
+                         *   struct S { int :0; };
+                         */
+                        structsize = 4;
+                    }
+                    else if (target.c.bitFieldStyle == TargetC.BitFieldStyle.DM)
+                    {
+                        structsize = 0;
+                        alignsize = 0;
+                    }
+                    else
+                        structsize = 0;
+                    break;
+            }
         }
 
         // Round struct size up to next alignsize boundary.
         // This will ensure that arrays of structs will get their internals
         // aligned properly.
-        if (alignment == STRUCTALIGN_DEFAULT)
+        if (alignment.isDefault() || alignment.isPack())
             structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
         else
-            structsize = (structsize + alignment - 1) & ~(alignment - 1);
+            structsize = (structsize + alignment.get() - 1) & ~(alignment.get() - 1);
 
         sizeok = Sizeok.done;
 
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 3a6dff2d44f..9aa435d6463 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -187,7 +187,7 @@  struct Visibility
     }
 }
 
-enum PASS : int
+enum PASS : ubyte
 {
     init,           // initial state
     semantic,       // semantic() started
@@ -225,11 +225,13 @@  enum : int
  */
 struct FieldState
 {
-    uint offset;        /// offset for next field
+    uint offset;        /// byte offset for next field
 
-    uint fieldOffset;   /// offset for the start of the bit field
+    uint fieldOffset;   /// byte offset for the start of the bit field
+    uint fieldSize;     /// byte size of field
+    uint fieldAlign;    /// byte alignment of field
     uint bitOffset;     /// bit offset for field
-    uint fieldSize;     /// size of field in bytes
+
     bool inFlight;      /// bit field is in flight
 }
 
@@ -793,10 +795,18 @@  extern (C++) class Dsymbol : ASTNode
             Dsymbol s2 = sds.symtabLookup(this,ident);
 
             // If using C tag/prototype/forward declaration rules
-            if (sc.flags & SCOPE.Cfile &&
-                handleTagSymbols(*sc, this, s2, sds))
+            if (sc.flags & SCOPE.Cfile)
+            {
+                if (handleTagSymbols(*sc, this, s2, sds))
+                    return;
+                if (handleSymbolRedeclarations(*sc, this, s2, sds))
                     return;
 
+                sds.multiplyDefined(Loc.initial, this, s2);  // ImportC doesn't allow overloading
+                errors = true;
+                return;
+            }
+
             if (!s2.overloadInsert(this))
             {
                 sds.multiplyDefined(Loc.initial, this, s2);
@@ -2384,3 +2394,91 @@  Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
 }
 
 
+/**********************************************
+ * ImportC allows redeclarations of C variables, functions and typedefs.
+ *    extern int x;
+ *    int x = 3;
+ * and:
+ *    extern void f();
+ *    void f() { }
+ * Attempt to merge them.
+ * Params:
+ *      sc = context
+ *      s = symbol to add to symbol table
+ *      s2 = existing declaration
+ *      sds = symbol table
+ * Returns:
+ *      if s and s2 are successfully put in symbol table then return the merged symbol,
+ *      null if they conflict
+ */
+Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
+{
+    enum log = false;
+    if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
+
+    static Dsymbol collision()
+    {
+        if (log) printf(" collision\n");
+        return null;
+    }
+
+    auto vd = s.isVarDeclaration(); // new declaration
+    auto vd2 = s2.isVarDeclaration(); // existing declaration
+    if (vd && vd2)
+    {
+        // if one is `static` and the other isn't
+        if ((vd.storage_class ^ vd2.storage_class) & STC.static_)
+            return collision();
+
+        const i1 =  vd._init && ! vd._init.isVoidInitializer();
+        const i2 = vd2._init && !vd2._init.isVoidInitializer();
+
+        if (i1 && i2)
+            return collision();         // can't both have initializers
+
+        if (i1)
+            return vd;
+
+        /* BUG: the types should match, which needs semantic() to be run on it
+         *    extern int x;
+         *    int x;  // match
+         *    typedef int INT;
+         *    INT x;  // match
+         *    long x; // collision
+         * We incorrectly ignore these collisions
+         */
+        return vd2;
+    }
+
+    auto fd = s.isFuncDeclaration(); // new declaration
+    auto fd2 = s2.isFuncDeclaration(); // existing declaration
+    if (fd && fd2)
+    {
+        // if one is `static` and the other isn't
+        if ((fd.storage_class ^ fd2.storage_class) & STC.static_)
+            return collision();
+
+        if (fd.fbody && fd2.fbody)
+            return collision();         // can't both have bodies
+
+        if (fd.fbody)
+            return fd;
+
+        /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
+         * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
+         */
+        return fd2;
+    }
+
+    auto td  = s.isAliasDeclaration();  // new declaration
+    auto td2 = s2.isAliasDeclaration(); // existing declaration
+    if (td && td2)
+    {
+        /* BUG: just like with variables and functions, the types should match, which needs semantic() to be run on it.
+         * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
+         */
+        return td2;
+    }
+
+    return collision();
+}
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index f43bc837992..02252fd13e5 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -108,7 +108,21 @@  struct Visibility
 
 /* State of symbol in winding its way through the passes of the compiler
  */
-enum PASS
+enum class PASS : uint8_t
+{
+    init,           // initial state
+    semantic,       // semantic() started
+    semanticdone,   // semantic() done
+    semantic2,      // semantic2() started
+    semantic2done,  // semantic2() done
+    semantic3,      // semantic3() started
+    semantic3done,  // semantic3() done
+    inline_,         // inline started
+    inlinedone,     // inline done
+    obj             // toObjFile() run
+};
+
+enum
 {
     PASSinit,           // initial state
     PASSsemantic,       // semantic() started
@@ -145,8 +159,10 @@  struct FieldState
     unsigned offset;
 
     unsigned fieldOffset;
+    unsigned fieldSize;
+    unsigned fieldAlign;
     unsigned bitOffset;
-    unsigned fieldSice;
+
     bool inFlight;
 };
 
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index eac20952eb5..047c1eb6f69 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -56,7 +56,7 @@  import dmd.objc;
 import dmd.opover;
 import dmd.parse;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.rootobject;
 import dmd.semantic2;
@@ -109,17 +109,18 @@  extern(C++) void dsymbolSemantic(Dsymbol dsym, Scope* sc)
  *      ad = AlignmentDeclaration
  *      sc = context
  * Returns:
- *      alignment as numerical value that is never 0.
- *      STRUCTALIGN_DEFAULT is used instead.
- *      STRUCTALIGN_DEFAULT is returned for errors
+ *      ad with alignment value determined
  */
-structalign_t getAlignment(AlignDeclaration ad, Scope* sc)
+AlignDeclaration getAlignment(AlignDeclaration ad, Scope* sc)
 {
-    if (ad.salign != ad.UNKNOWN)   // UNKNOWN is 0
-        return ad.salign;
+    if (!ad.salign.isUnknown())   // UNKNOWN is 0
+        return ad;
 
     if (!ad.exps)
-        return ad.salign = STRUCTALIGN_DEFAULT;
+    {
+        ad.salign.setDefault();
+        return ad;
+    }
 
     dinteger_t strictest = 0;   // strictest alignment
     bool errors;
@@ -140,7 +141,7 @@  structalign_t getAlignment(AlignDeclaration ad, Scope* sc)
             if (sc.flags & SCOPE.Cfile && n == 0)       // C11 6.7.5-6 allows 0 for alignment
                 continue;
 
-            if (n < 1 || n & (n - 1) || structalign_t.max < n || !e.type.isintegral())
+            if (n < 1 || n & (n - 1) || ushort.max < n || !e.type.isintegral())
             {
                 error(ad.loc, "alignment must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
                 errors = true;
@@ -150,10 +151,12 @@  structalign_t getAlignment(AlignDeclaration ad, Scope* sc)
         }
     }
 
-    ad.salign = (errors || strictest == 0)  // C11 6.7.5-6 says alignment of 0 means no effect
-                ? STRUCTALIGN_DEFAULT
-                : cast(structalign_t) strictest;
-    return ad.salign;
+    if (errors || strictest == 0)  // C11 6.7.5-6 says alignment of 0 means no effect
+        ad.salign.setDefault();
+    else
+        ad.salign.set(cast(uint) strictest);
+
+    return ad;
 }
 
 const(char)* getMessage(DeprecatedDeclaration dd)
@@ -365,16 +368,31 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         dsym.semanticRun = PASS.semantic;
 
-        /* Pick up storage classes from context, but except synchronized,
-         * override, abstract, and final.
-         */
-        dsym.storage_class |= (sc.stc & ~(STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_));
+        // 'static foreach' variables should not inherit scope properties
+        // https://issues.dlang.org/show_bug.cgi?id=19482
+        if ((dsym.storage_class & (STC.foreach_ | STC.local)) == (STC.foreach_ | STC.local))
+        {
+            dsym.linkage = LINK.d;
+            dsym.visibility = Visibility(Visibility.Kind.public_);
+            dsym.overlapped = false; // unset because it is modified early on this function
+            dsym.userAttribDecl = null; // unset because it is set by Dsymbol.setScope()
+        }
+        else
+        {
+            /* Pick up storage classes from context, but except synchronized,
+             * override, abstract, and final.
+             */
+            dsym.storage_class |= (sc.stc & ~(STC.synchronized_ | STC.override_ | STC.abstract_ | STC.final_));
+            dsym.userAttribDecl = sc.userAttribDecl;
+            dsym.cppnamespace = sc.namespace;
+            dsym.linkage = sc.linkage;
+            dsym.visibility = sc.visibility;
+            dsym.alignment = sc.alignment();
+        }
+
         if (dsym.storage_class & STC.extern_ && dsym._init)
             dsym.error("extern symbols cannot have initializers");
 
-        dsym.userAttribDecl = sc.userAttribDecl;
-        dsym.cppnamespace = sc.namespace;
-
         AggregateDeclaration ad = dsym.isThis();
         if (ad)
             dsym.storage_class |= ad.storage_class & STC.TYPECTOR;
@@ -431,16 +449,13 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             dsym.errors = true;
 
         dsym.type.checkDeprecated(dsym.loc, sc);
-        dsym.linkage = sc.linkage;
         dsym.parent = sc.parent;
         //printf("this = %p, parent = %p, '%s'\n", dsym, dsym.parent, dsym.parent.toChars());
-        dsym.visibility = sc.visibility;
 
         /* If scope's alignment is the default, use the type's alignment,
          * otherwise the scope overrrides.
          */
-        dsym.alignment = sc.alignment();
-        if (dsym.alignment == STRUCTALIGN_DEFAULT)
+        if (dsym.alignment.isDefault())
             dsym.alignment = dsym.type.alignment(); // use type's alignment
 
         //printf("sc.stc = %x\n", sc.stc);
@@ -935,6 +950,15 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             sc = sc.push();
             sc.stc &= ~(STC.TYPECTOR | STC.pure_ | STC.nothrow_ | STC.nogc | STC.ref_ | STC.disable);
 
+            if (sc.flags & SCOPE.Cfile &&
+                dsym.type.isTypeSArray() &&
+                dsym.type.isTypeSArray().isIncomplete() &&
+                dsym._init.isVoidInitializer() &&
+                !(dsym.storage_class & STC.field))
+            {
+                dsym.error("incomplete array type must have initializer");
+            }
+
             ExpInitializer ei = dsym._init.isExpInitializer();
 
             if (ei) // https://issues.dlang.org/show_bug.cgi?id=13424
@@ -971,6 +995,13 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                         ei = new ExpInitializer(dsym._init.loc, e);
                         dsym._init = ei;
                     }
+                    else if (sc.flags & SCOPE.Cfile && dsym.type.isTypeSArray() &&
+                             dsym.type.isTypeSArray().isIncomplete())
+                    {
+                        // C11 6.7.9-22 determine the size of the incomplete array,
+                        // or issue an error that the initializer is invalid.
+                        dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret);
+                    }
 
                     Expression exp = ei.exp;
                     Expression e1 = new VarExp(dsym.loc, dsym);
@@ -1056,18 +1087,29 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     // could crash (inf. recursion) on a mod/pkg referencing itself
                     if (ei && (ei.exp.op != TOK.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage()))
                     {
-                        Expression exp = ei.exp.syntaxCopy();
-
-                        bool needctfe = dsym.isDataseg() || (dsym.storage_class & STC.manifest);
-                        if (needctfe)
-                            sc = sc.startCTFE();
-                        exp = exp.expressionSemantic(sc);
-                        exp = resolveProperties(sc, exp);
-                        if (needctfe)
-                            sc = sc.endCTFE();
+                        if (ei.exp.type)
+                        {
+                            // If exp is already resolved we are done, our original init exp
+                            // could have a type painting that we need to respect
+                            // e.g.  ['a'] typed as string, or [['z'], ""] as string[]
+                            // See https://issues.dlang.org/show_bug.cgi?id=15711
+                        }
+                        else
+                        {
+                            Expression exp = ei.exp.syntaxCopy();
+
+                            bool needctfe = dsym.isDataseg() || (dsym.storage_class & STC.manifest);
+                            if (needctfe)
+                                sc = sc.startCTFE();
+                            exp = exp.expressionSemantic(sc);
+                            exp = resolveProperties(sc, exp);
+                            if (needctfe)
+                                sc = sc.endCTFE();
+                            ei.exp = exp;
+                        }
 
                         Type tb2 = dsym.type.toBasetype();
-                        Type ti = exp.type.toBasetype();
+                        Type ti = ei.exp.type.toBasetype();
 
                         /* The problem is the following code:
                          *  struct CopyTest {
@@ -1091,11 +1133,10 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                             if (sd.postblit && tb2.toDsymbol(null) == sd)
                             {
                                 // The only allowable initializer is a (non-copy) constructor
-                                if (exp.isLvalue())
+                                if (ei.exp.isLvalue())
                                     dsym.error("of type struct `%s` uses `this(this)`, which is not allowed in static initialization", tb2.toChars());
                             }
                         }
-                        ei.exp = exp;
                     }
 
                     dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITinterpret);
@@ -1708,6 +1749,36 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         {
             if (pd.args && pd.args.dim != 0)
                 pd.error("takes no argument");
+            else
+            {
+                immutable isCtor = pd.ident == Id.crt_constructor;
+
+                static uint recurse(Dsymbol s, bool isCtor)
+                {
+                    if (auto ad = s.isAttribDeclaration())
+                    {
+                        uint nestedCount;
+                        auto decls = ad.include(null);
+                        if (decls)
+                        {
+                            for (size_t i = 0; i < decls.dim; ++i)
+                                nestedCount += recurse((*decls)[i], isCtor);
+                        }
+                        return nestedCount;
+                    }
+                    else if (auto f = s.isFuncDeclaration())
+                    {
+                        f.isCrtCtorDtor |= isCtor ? 1 : 2;
+                        return 1;
+                    }
+                    else
+                        return 0;
+                    assert(0);
+                }
+
+                if (recurse(pd, isCtor) > 1)
+                    pd.error("can only apply to a single declaration");
+            }
             return declarations();
         }
         else if (pd.ident == Id.printf || pd.ident == Id.scanf)
@@ -2445,6 +2516,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         tempdecl.parent = sc.parent;
         tempdecl.visibility = sc.visibility;
+        tempdecl.userAttribDecl = sc.userAttribDecl;
         tempdecl.cppnamespace = sc.namespace;
         tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_);
         tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_);
@@ -2973,6 +3045,16 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         if (auto pragmadecl = sc.inlining)
             funcdecl.inlining = pragmadecl.evalPragmaInline(sc);
 
+        // check pragma(crt_constructor)
+        if (funcdecl.isCrtCtorDtor)
+        {
+            if (funcdecl.linkage != LINK.c)
+            {
+                funcdecl.error("must be `extern(C)` for `pragma(%s)`",
+                    funcdecl.isCrtCtorDtor == 1 ? "crt_constructor".ptr : "crt_destructor".ptr);
+            }
+        }
+
         funcdecl.visibility = sc.visibility;
         funcdecl.userAttribDecl = sc.userAttribDecl;
         UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl.linkage);
@@ -3799,6 +3881,10 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
         }
 
+        if (funcdecl.fbody && sc._module.isRoot() &&
+            (funcdecl.isMain() || funcdecl.isWinMain() || funcdecl.isDllMain() || funcdecl.isCMain()))
+            global.hasMainFunction = true;
+
         if (funcdecl.fbody && funcdecl.isMain() && sc._module.isRoot())
         {
             // check if `_d_cmain` is defined
@@ -3995,7 +4081,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             return;
         }
         if (dd.ident == Id.dtor && dd.semanticRun < PASS.semantic)
-            ad.dtors.push(dd);
+            ad.userDtors.push(dd);
         if (!dd.type)
         {
             dd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, dd.storage_class);
@@ -4417,8 +4503,8 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         // Look for the constructor
         sd.ctor = sd.searchCtor();
 
-        sd.dtor = buildDtor(sd, sc2);
-        sd.tidtor = buildExternDDtor(sd, sc2);
+        buildDtors(sd, sc2);
+
         sd.hasCopyCtor = buildCopyCtor(sd, sc2);
         sd.postblit = buildPostBlit(sd, sc2);
 
@@ -5057,8 +5143,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
         }
 
-        cldec.dtor = buildDtor(cldec, sc2);
-        cldec.tidtor = buildExternDDtor(cldec, sc2);
+        buildDtors(cldec, sc2);
 
         if (cldec.classKind == ClassKind.cpp && cldec.cppDtorVtblIndex != -1)
         {
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index c3503bbf7d6..9d7957a975d 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -67,7 +67,7 @@  import dmd.initsem;
 import dmd.mtype;
 import dmd.opover;
 import dmd.root.array;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.semantic2;
 import dmd.semantic3;
@@ -985,9 +985,9 @@  extern (C++) final class TemplateDeclaration : ScopeDsymbol
                 buf.writenl();
                 buf.writestring("       ");
             }
-            buf.write((*parameters)[i]);
+            write(buf, (*parameters)[i]);
             buf.writestring(" = ");
-            buf.write(tiargs[i]);
+            write(buf, tiargs[i]);
         }
         // write remaining variadic arguments on the last line
         if (variadic)
@@ -998,16 +998,16 @@  extern (C++) final class TemplateDeclaration : ScopeDsymbol
                 buf.writenl();
                 buf.writestring("       ");
             }
-            buf.write((*parameters)[end]);
+            write(buf, (*parameters)[end]);
             buf.writestring(" = ");
             buf.writeByte('(');
             if (cast(int)tiargs.length - end > 0)
             {
-                buf.write(tiargs[end]);
+                write(buf, tiargs[end]);
                 foreach (j; parameters.length .. tiargs.length)
                 {
                     buf.writestring(", ");
-                    buf.write(tiargs[j]);
+                    write(buf, tiargs[j]);
                 }
             }
             buf.writeByte(')');
@@ -1919,8 +1919,15 @@  extern (C++) final class TemplateDeclaration : ScopeDsymbol
                             /* If a semantic error occurs while doing alias this,
                              * eg purity(https://issues.dlang.org/show_bug.cgi?id=7295),
                              * just regard it as not a match.
-                             */
-                            if (auto e = resolveAliasThis(sc, farg, true))
+                             *
+                             * We also save/restore sc.func.flags to avoid messing up
+                             * attribute inference in the evaluation.
+                            */
+                            const oldflags = sc.func ? sc.func.flags : 0;
+                            auto e = resolveAliasThis(sc, farg, true);
+                            if (sc.func)
+                                sc.func.flags = oldflags;
+                            if (e)
                             {
                                 farg = e;
                                 goto Lretry;
@@ -5340,7 +5347,7 @@  extern (C++) class TemplateParameter : ASTNode
 
     abstract RootObject specialization();
 
-    abstract RootObject defaultArg(Loc instLoc, Scope* sc);
+    abstract RootObject defaultArg(const ref Loc instLoc, Scope* sc);
 
     abstract bool hasDefaultArg();
 
@@ -5422,7 +5429,7 @@  extern (C++) class TemplateTypeParameter : TemplateParameter
         return specType;
     }
 
-    override final RootObject defaultArg(Loc instLoc, Scope* sc)
+    override final RootObject defaultArg(const ref Loc instLoc, Scope* sc)
     {
         Type t = defaultType;
         if (t)
@@ -5541,7 +5548,7 @@  extern (C++) final class TemplateValueParameter : TemplateParameter
         return specValue;
     }
 
-    override RootObject defaultArg(Loc instLoc, Scope* sc)
+    override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
     {
         Expression e = defaultValue;
         if (e)
@@ -5640,7 +5647,7 @@  extern (C++) final class TemplateAliasParameter : TemplateParameter
         return specAlias;
     }
 
-    override RootObject defaultArg(Loc instLoc, Scope* sc)
+    override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
     {
         RootObject da = defaultAlias;
         Type ta = isType(defaultAlias);
@@ -5741,7 +5748,7 @@  extern (C++) final class TemplateTupleParameter : TemplateParameter
         return null;
     }
 
-    override RootObject defaultArg(Loc instLoc, Scope* sc)
+    override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
     {
         return null;
     }
@@ -8413,3 +8420,11 @@  private struct MATCHpair
         this.mfa = mfa;
     }
 }
+
+private void write(ref OutBuffer buf, RootObject obj)
+{
+    if (obj)
+    {
+        buf.writestring(obj.toChars());
+    }
+}
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 28054d02904..e19adfc4b14 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -17,6 +17,7 @@  import core.stdc.ctype;
 
 import dmd.astcodegen;
 import dmd.arraytypes;
+import dmd.attrib;
 import dmd.dsymbol;
 import dmd.errors;
 import dmd.globals;
@@ -25,7 +26,7 @@  import dmd.root.filename;
 import dmd.visitor;
 import dmd.tokens;
 
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.utils;
 
 //debug = Debug_DtoH;
@@ -254,7 +255,7 @@  public:
         Identifier ident;
 
         /// Original type of the currently visited declaration
-        AST.Type* origType;
+        AST.Type origType;
 
         /// Last written visibility level applying to the current scope
         AST.Visibility.Kind currentVisibility;
@@ -706,6 +707,10 @@  public:
         // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars());
         visited[cast(void*)fd] = true;
 
+        // silently ignore non-user-defined destructors
+        if (fd.generated && fd.isDtorDeclaration())
+            return;
+
         // Note that tf might be null for templated (member) functions
         auto tf = cast(AST.TypeFunction)fd.type;
         if ((tf && tf.linkage != LINK.c && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
@@ -841,12 +846,12 @@  public:
             return;
 
         if (vd.originalType && vd.type == AST.Type.tsize_t)
-            origType = &vd.originalType;
+            origType = vd.originalType;
         scope(exit) origType = null;
 
-        if (vd.alignment != STRUCTALIGN_DEFAULT)
+        if (!vd.alignment.isDefault())
         {
-            buf.printf("// Ignoring var %s alignment %u", vd.toChars(), vd.alignment);
+            buf.printf("// Ignoring var %s alignment %d", vd.toChars(), vd.alignment.get());
             buf.writenl();
         }
 
@@ -1008,12 +1013,12 @@  public:
             if (ad.originalType && ad.type.ty == AST.Tpointer &&
                 (cast(AST.TypePointer)t).nextOf.ty == AST.Tfunction)
             {
-                origType = &ad.originalType;
+                origType = ad.originalType;
             }
             scope(exit) origType = null;
 
             buf.writestring("typedef ");
-            typeToBuffer(origType ? *origType : t, ad);
+            typeToBuffer(origType !is null ? origType : t, ad);
             writeDeclEnd();
             return;
         }
@@ -1346,7 +1351,7 @@  public:
 
     /// Starts a custom alignment section using `#pragma pack` if
     /// `alignment` specifies a custom alignment
-    private void pushAlignToBuffer(uint alignment)
+    private void pushAlignToBuffer(structalign_t alignment)
     {
         // DMD ensures alignment is a power of two
         //assert(alignment > 0 && ((alignment & (alignment - 1)) == 0),
@@ -1354,20 +1359,20 @@  public:
 
         // When no alignment is specified, `uint.max` is the default
         // FIXME: alignment is 0 for structs templated members
-        if (alignment == STRUCTALIGN_DEFAULT || (tdparent && alignment == 0))
+        if (alignment.isDefault() || (tdparent && alignment.isUnknown()))
         {
             return;
         }
 
-        buf.printf("#pragma pack(push, %d)", alignment);
+        buf.printf("#pragma pack(push, %d)", alignment.get());
         buf.writenl();
     }
 
     /// Ends a custom alignment section using `#pragma pack` if
     /// `alignment` specifies a custom alignment
-    private void popAlignToBuffer(uint alignment)
+    private void popAlignToBuffer(structalign_t alignment)
     {
-        if (alignment == STRUCTALIGN_DEFAULT || (tdparent && alignment == 0))
+        if (alignment.isDefault() || (tdparent && alignment.isUnknown()))
             return;
 
         buf.writestringln("#pragma pack(pop)");
@@ -1645,7 +1650,7 @@  public:
         }
 
         this.ident = s.ident;
-        auto type = origType ? *origType : t;
+        auto type = origType !is null ? origType : t;
         AST.Dsymbol customLength;
 
         // Check for quirks that are usually resolved during semantic
diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d
index 0dff754bee5..49ee4b3b3ec 100644
--- a/gcc/d/dmd/dversion.d
+++ b/gcc/d/dmd/dversion.d
@@ -22,7 +22,7 @@  import dmd.dsymbol;
 import dmd.dsymbolsem;
 import dmd.globals;
 import dmd.identifier;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.visitor;
 
 /***********************************************************
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 0d6fa1e88f3..2a623324454 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -59,7 +59,7 @@  import dmd.opover;
 import dmd.optimize;
 import dmd.root.ctfloat;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.rootobject;
 import dmd.root.string;
@@ -1201,20 +1201,14 @@  extern (C++) abstract class Expression : ASTNode
         // DtorDeclaration without parents should fail at an earlier stage
         auto ad = cast(AggregateDeclaration) f.toParent2();
         assert(ad);
-        assert(ad.dtors.length);
 
-        // Search for the user-defined destructor (if any)
-        foreach(dtor; ad.dtors)
+        if (ad.userDtors.dim)
         {
-            if (dtor.generated)
-                continue;
-
-            if (!check(dtor)) // doesn't match check (e.g. is impure as well)
+            if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well)
                 return;
 
             // Sanity check
-            assert(!check(cast(DtorDeclaration) ad.fieldDtor));
-            break;
+            assert(!check(ad.fieldDtor));
         }
 
         dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
@@ -1781,13 +1775,13 @@  extern (C++) final class IntegerExp : Expression
         this.value = cast(d_int32)value;
     }
 
-    static IntegerExp create(Loc loc, dinteger_t value, Type type)
+    static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
     {
         return new IntegerExp(loc, value, type);
     }
 
     // Same as create, but doesn't allocate memory.
-    static void emplace(UnionExp* pue, Loc loc, dinteger_t value, Type type)
+    static void emplace(UnionExp* pue, const ref Loc loc, dinteger_t value, Type type)
     {
         emplaceExp!(IntegerExp)(pue, loc, value, type);
     }
@@ -2052,13 +2046,13 @@  extern (C++) final class RealExp : Expression
         this.type = type;
     }
 
-    static RealExp create(Loc loc, real_t value, Type type)
+    static RealExp create(const ref Loc loc, real_t value, Type type)
     {
         return new RealExp(loc, value, type);
     }
 
     // Same as create, but doesn't allocate memory.
-    static void emplace(UnionExp* pue, Loc loc, real_t value, Type type)
+    static void emplace(UnionExp* pue, const ref Loc loc, real_t value, Type type)
     {
         emplaceExp!(RealExp)(pue, loc, value, type);
     }
@@ -2127,13 +2121,13 @@  extern (C++) final class ComplexExp : Expression
         //printf("ComplexExp::ComplexExp(%s)\n", toChars());
     }
 
-    static ComplexExp create(Loc loc, complex_t value, Type type)
+    static ComplexExp create(const ref Loc loc, complex_t value, Type type)
     {
         return new ComplexExp(loc, value, type);
     }
 
     // Same as create, but doesn't allocate memory.
-    static void emplace(UnionExp* pue, Loc loc, complex_t value, Type type)
+    static void emplace(UnionExp* pue, const ref Loc loc, complex_t value, Type type)
     {
         emplaceExp!(ComplexExp)(pue, loc, value, type);
     }
@@ -2203,7 +2197,7 @@  extern (C++) class IdentifierExp : Expression
         this.ident = ident;
     }
 
-    static IdentifierExp create(Loc loc, Identifier ident)
+    static IdentifierExp create(const ref Loc loc, Identifier ident)
     {
         return new IdentifierExp(loc, ident);
     }
@@ -2421,28 +2415,28 @@  extern (C++) final class StringExp : Expression
         this.postfix = postfix;
     }
 
-    static StringExp create(Loc loc, char* s)
+    static StringExp create(const ref Loc loc, const(char)* s)
     {
         return new StringExp(loc, s.toDString());
     }
 
-    static StringExp create(Loc loc, void* string, size_t len)
+    static StringExp create(const ref Loc loc, const(void)* string, size_t len)
     {
         return new StringExp(loc, string[0 .. len]);
     }
 
     // Same as create, but doesn't allocate memory.
-    static void emplace(UnionExp* pue, Loc loc, char* s)
+    static void emplace(UnionExp* pue, const ref Loc loc, const(char)* s)
     {
         emplaceExp!(StringExp)(pue, loc, s.toDString());
     }
 
-    extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string)
+    extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string)
     {
         emplaceExp!(StringExp)(pue, loc, string);
     }
 
-    extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
+    extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
     {
         emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
     }
@@ -2863,7 +2857,7 @@  extern (C++) final class TupleExp : Expression
         }
     }
 
-    static TupleExp create(Loc loc, Expressions* exps)
+    static TupleExp create(const ref Loc loc, Expressions* exps)
     {
         return new TupleExp(loc, exps);
     }
@@ -2946,13 +2940,13 @@  extern (C++) final class ArrayLiteralExp : Expression
         this.elements = elements;
     }
 
-    static ArrayLiteralExp create(Loc loc, Expressions* elements)
+    static ArrayLiteralExp create(const ref Loc loc, Expressions* elements)
     {
         return new ArrayLiteralExp(loc, null, elements);
     }
 
     // Same as create, but doesn't allocate memory.
-    static void emplace(UnionExp* pue, Loc loc, Expressions* elements)
+    static void emplace(UnionExp* pue, const ref Loc loc, Expressions* elements)
     {
         emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
     }
@@ -3188,7 +3182,7 @@  extern (C++) final class StructLiteralExp : Expression
         //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
     }
 
-    static StructLiteralExp create(Loc loc, StructDeclaration sd, void* elements, Type stype = null)
+    static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
     {
         return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
     }
@@ -3532,7 +3526,7 @@  extern (C++) final class NewExp : Expression
         this.arguments = arguments;
     }
 
-    static NewExp create(Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
+    static NewExp create(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
     {
         return new NewExp(loc, thisexp, newargs, newtype, arguments);
     }
@@ -3653,7 +3647,7 @@  extern (C++) final class VarExp : SymbolExp
         this.type = var.type;
     }
 
-    static VarExp create(Loc loc, Declaration var, bool hasOverloads = true)
+    static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true)
     {
         return new VarExp(loc, var, hasOverloads);
     }
@@ -3965,6 +3959,7 @@  extern (C++) final class FuncExp : Expression
             auto tfy = new TypeFunction(tfx.parameterList, tof.next,
                         tfx.linkage, STC.undefined_);
             tfy.mod = tfx.mod;
+            tfy.trust = tfx.trust;
             tfy.isnothrow = tfx.isnothrow;
             tfy.isnogc = tfx.isnogc;
             tfy.purity = tfx.purity;
@@ -4688,6 +4683,7 @@  extern (C++) final class DotIdExp : UnaExp
     Identifier ident;
     bool noderef;       // true if the result of the expression will never be dereferenced
     bool wantsym;       // do not replace Symbol with its initializer during semantic()
+    bool arrow;         // ImportC: if -> instead of .
 
     extern (D) this(const ref Loc loc, Expression e, Identifier ident)
     {
@@ -4695,7 +4691,7 @@  extern (C++) final class DotIdExp : UnaExp
         this.ident = ident;
     }
 
-    static DotIdExp create(Loc loc, Expression e, Identifier ident)
+    static DotIdExp create(const ref Loc loc, Expression e, Identifier ident)
     {
         return new DotIdExp(loc, e, ident);
     }
@@ -4889,6 +4885,31 @@  extern (C++) final class DotTemplateInstanceExp : UnaExp
         return ti.updateTempDecl(sc, s);
     }
 
+    override bool checkType()
+    {
+        // Same logic as ScopeExp.checkType()
+        if (ti.tempdecl &&
+            ti.semantictiargsdone &&
+            ti.semanticRun == PASS.init)
+        {
+            error("partial %s `%s` has no type", ti.kind(), toChars());
+            return true;
+        }
+        return false;
+    }
+
+    override bool checkValue()
+    {
+        if (ti.tempdecl &&
+            ti.semantictiargsdone &&
+            ti.semanticRun == PASS.init)
+
+            error("partial %s `%s` has no value", ti.kind(), toChars());
+        else
+            error("%s `%s` has no value", ti.kind(), ti.toChars());
+        return true;
+    }
+
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4987,17 +5008,17 @@  extern (C++) final class CallExp : UnaExp
         this.f = fd;
     }
 
-    static CallExp create(Loc loc, Expression e, Expressions* exps)
+    static CallExp create(const ref Loc loc, Expression e, Expressions* exps)
     {
         return new CallExp(loc, e, exps);
     }
 
-    static CallExp create(Loc loc, Expression e)
+    static CallExp create(const ref Loc loc, Expression e)
     {
         return new CallExp(loc, e);
     }
 
-    static CallExp create(Loc loc, Expression e, Expression earg1)
+    static CallExp create(const ref Loc loc, Expression e, Expression earg1)
     {
         return new CallExp(loc, e, earg1);
     }
@@ -5009,7 +5030,7 @@  extern (C++) final class CallExp : UnaExp
     *       fd    = the declaration of the function to call
     *       earg1 = the function argument
     */
-    static CallExp create(Loc loc, FuncDeclaration fd, Expression earg1)
+    static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
     {
         return new CallExp(loc, fd, earg1);
     }
@@ -5167,6 +5188,19 @@  extern (C++) final class PtrExp : UnaExp
     override Expression modifiableLvalue(Scope* sc, Expression e)
     {
         //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
+        Declaration var;
+        if (auto se = e1.isSymOffExp())
+            var = se.var;
+        else if (auto ve = e1.isVarExp())
+            var = ve.var;
+        if (var && var.type.isFunction_Delegate_PtrToFunction())
+        {
+            if (var.type.isTypeFunction())
+                error("function `%s` is not an lvalue and cannot be modified", var.toChars());
+            else
+                error("function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
+            return ErrorExp.get();
+        }
         return Expression.modifiableLvalue(sc, e);
     }
 
@@ -5331,13 +5365,13 @@  extern (C++) final class VectorExp : UnaExp
         to = cast(TypeVector)t;
     }
 
-    static VectorExp create(Loc loc, Expression e, Type t)
+    static VectorExp create(const ref Loc loc, Expression e, Type t)
     {
         return new VectorExp(loc, e, t);
     }
 
     // Same as create, but doesn't allocate memory.
-    static void emplace(UnionExp* pue, Loc loc, Expression e, Type type)
+    static void emplace(UnionExp* pue, const ref Loc loc, Expression e, Type type)
     {
         emplaceExp!(VectorExp)(pue, loc, e, type);
     }
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index dec3713b676..691364cb265 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -57,6 +57,9 @@  enum
     OWNEDcache      // constant value cached for CTFE
 };
 
+#define WANTvalue  0 // default
+#define WANTexpand 1 // expand const/immutable variables if possible
+
 /**
  * Specifies how the checkModify deals with certain situations
  */
@@ -239,8 +242,8 @@  class IntegerExp : public Expression
 public:
     dinteger_t value;
 
-    static IntegerExp *create(Loc loc, dinteger_t value, Type *type);
-    static void emplace(UnionExp *pue, Loc loc, dinteger_t value, Type *type);
+    static IntegerExp *create(const Loc &loc, dinteger_t value, Type *type);
+    static void emplace(UnionExp *pue, const Loc &loc, dinteger_t value, Type *type);
     bool equals(const RootObject *o) const;
     dinteger_t toInteger();
     real_t toReal();
@@ -269,8 +272,8 @@  class RealExp : public Expression
 public:
     real_t value;
 
-    static RealExp *create(Loc loc, real_t value, Type *type);
-    static void emplace(UnionExp *pue, Loc loc, real_t value, Type *type);
+    static RealExp *create(const Loc &loc, real_t value, Type *type);
+    static void emplace(UnionExp *pue, const Loc &loc, real_t value, Type *type);
     bool equals(const RootObject *o) const;
     dinteger_t toInteger();
     uinteger_t toUInteger();
@@ -286,8 +289,8 @@  class ComplexExp : public Expression
 public:
     complex_t value;
 
-    static ComplexExp *create(Loc loc, complex_t value, Type *type);
-    static void emplace(UnionExp *pue, Loc loc, complex_t value, Type *type);
+    static ComplexExp *create(const Loc &loc, complex_t value, Type *type);
+    static void emplace(UnionExp *pue, const Loc &loc, complex_t value, Type *type);
     bool equals(const RootObject *o) const;
     dinteger_t toInteger();
     uinteger_t toUInteger();
@@ -303,7 +306,7 @@  class IdentifierExp : public Expression
 public:
     Identifier *ident;
 
-    static IdentifierExp *create(Loc loc, Identifier *ident);
+    static IdentifierExp *create(const Loc &loc, Identifier *ident);
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *e);
     void accept(Visitor *v) { v->visit(this); }
@@ -365,10 +368,9 @@  public:
     utf8_t postfix;      // 'c', 'w', 'd'
     OwnedBy ownedByCtfe;
 
-    static StringExp *create(Loc loc, char *s);
-    static StringExp *create(Loc loc, void *s, size_t len);
-    static void emplace(UnionExp *pue, Loc loc, char *s);
-    static void emplace(UnionExp *pue, Loc loc, void *s, size_t len);
+    static StringExp *create(const Loc &loc, const char *s);
+    static StringExp *create(const Loc &loc, const void *s, size_t len);
+    static void emplace(UnionExp *pue, const Loc &loc, const char *s);
     bool equals(const RootObject *o) const;
     StringExp *toStringExp();
     StringExp *toUTF8(Scope *sc);
@@ -397,7 +399,7 @@  public:
      */
     Expressions *exps;
 
-    static TupleExp *create(Loc loc, Expressions *exps);
+    static TupleExp *create(const Loc &loc, Expressions *exps);
     TupleExp *toTupleExp();
     TupleExp *syntaxCopy();
     bool equals(const RootObject *o) const;
@@ -412,8 +414,8 @@  public:
     Expressions *elements;
     OwnedBy ownedByCtfe;
 
-    static ArrayLiteralExp *create(Loc loc, Expressions *elements);
-    static void emplace(UnionExp *pue, Loc loc, Expressions *elements);
+    static ArrayLiteralExp *create(const Loc &loc, Expressions *elements);
+    static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements);
     ArrayLiteralExp *syntaxCopy();
     bool equals(const RootObject *o) const;
     Expression *getElement(d_size_t i); // use opIndex instead
@@ -468,7 +470,7 @@  public:
     bool isOriginal;            // used when moving instances to indicate `this is this.origin`
     OwnedBy ownedByCtfe;
 
-    static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
+    static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
     bool equals(const RootObject *o) const;
     StructLiteralExp *syntaxCopy();
     Expression *getField(Type *type, unsigned offset);
@@ -528,7 +530,7 @@  public:
     bool onstack;               // allocate on stack
     bool thrownew;              // this NewExp is the expression of a ThrowStatement
 
-    static NewExp *create(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
+    static NewExp *create(const Loc &loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
     NewExp *syntaxCopy();
 
     void accept(Visitor *v) { v->visit(this); }
@@ -576,7 +578,7 @@  class VarExp : public SymbolExp
 {
 public:
     bool delegateWasExtracted;
-    static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true);
+    static VarExp *create(const Loc &loc, Declaration *var, bool hasOverloads = true);
     bool equals(const RootObject *o) const;
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *e);
@@ -746,8 +748,9 @@  public:
     Identifier *ident;
     bool noderef;       // true if the result of the expression will never be dereferenced
     bool wantsym;       // do not replace Symbol with its initializer during semantic()
+    bool arrow;         // ImportC: if -> instead of .
 
-    static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
+    static DotIdExp *create(const Loc &loc, Expression *e, Identifier *ident);
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -780,6 +783,8 @@  public:
 
     DotTemplateInstanceExp *syntaxCopy();
     bool findTempDecl(Scope *sc);
+    bool checkType();
+    bool checkValue();
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -812,10 +817,10 @@  public:
     bool ignoreAttributes;      // don't enforce attributes (e.g. call @gc function in @nogc code)
     VarDeclaration *vthis2;     // container for multi-context
 
-    static CallExp *create(Loc loc, Expression *e, Expressions *exps);
-    static CallExp *create(Loc loc, Expression *e);
-    static CallExp *create(Loc loc, Expression *e, Expression *earg1);
-    static CallExp *create(Loc loc, FuncDeclaration *fd, Expression *earg1);
+    static CallExp *create(const Loc &loc, Expression *e, Expressions *exps);
+    static CallExp *create(const Loc &loc, Expression *e);
+    static CallExp *create(const Loc &loc, Expression *e, Expression *earg1);
+    static CallExp *create(const Loc &loc, FuncDeclaration *fd, Expression *earg1);
 
     CallExp *syntaxCopy();
     bool isLvalue();
@@ -893,8 +898,8 @@  public:
     unsigned dim;               // number of elements in the vector
     OwnedBy ownedByCtfe;
 
-    static VectorExp *create(Loc loc, Expression *e, Type *t);
-    static void emplace(UnionExp *pue, Loc loc, Expression *e, Type *t);
+    static VectorExp *create(const Loc &loc, Expression *e, Type *t);
+    static void emplace(UnionExp *pue, const Loc &loc, Expression *e, Type *t);
     VectorExp *syntaxCopy();
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -1272,7 +1277,7 @@  public:
 
 class GenericExp : Expression
 {
-    Expression cntlExp;
+    Expression *cntlExp;
     Types *types;
     Expressions *exps;
 
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 3b604af53b9..8e152d6a1fc 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -43,12 +43,14 @@  import dmd.dtemplate;
 import dmd.errors;
 import dmd.escape;
 import dmd.expression;
+import dmd.file_manager;
 import dmd.func;
 import dmd.globals;
 import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.imphint;
+import dmd.importc;
 import dmd.init;
 import dmd.initsem;
 import dmd.inline;
@@ -62,7 +64,7 @@  import dmd.printast;
 import dmd.root.ctfloat;
 import dmd.root.file;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.semantic2;
@@ -1239,6 +1241,10 @@  private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         tthis = dve.e1.type;
         goto Lfd;
     }
+    else if (sc && sc.flags & SCOPE.Cfile && e1.op == TOK.variable && !e2)
+    {
+        // ImportC: do not implicitly call function if no ( ) are present
+    }
     else if (e1.op == TOK.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
     {
         s = (cast(VarExp)e1).var;
@@ -1388,7 +1394,6 @@  private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
 
     Type t0 = null;
     Expression e0 = null;
-    size_t j0 = ~0;
     bool foundType;
 
     for (size_t i = 0; i < exps.dim; i++)
@@ -1441,17 +1446,16 @@  private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
             {
                 // https://issues.dlang.org/show_bug.cgi?id=21285
                 // Functions and delegates don't convert correctly with castTo below
-                exps[j0] = condexp.e1;
+                exps[i] = condexp.e1;
                 e = condexp.e2;
             }
             else
             {
                 // Convert to common type
-                exps[j0] = condexp.e1.castTo(sc, condexp.type);
+                exps[i] = condexp.e1.castTo(sc, condexp.type);
                 e = condexp.e2.castTo(sc, condexp.type);
             }
         }
-        j0 = i;
         e0 = e;
         t0 = e.type;
         if (e.op != TOK.error)
@@ -1599,6 +1603,7 @@  private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool repo
         {
             Expression arg = (*exps)[i];
             arg = resolveProperties(sc, arg);
+            arg = arg.arrayFuncConv(sc);
             if (arg.op == TOK.type)
             {
                 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
@@ -4297,7 +4302,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
          *  expr.foo!(tiargs)(funcargs)
          */
     Ldotti:
-        if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type)
+        if (exp.e1.op == TOK.dotTemplateInstance)
         {
             DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1;
             TemplateInstance ti = se.ti;
@@ -4352,7 +4357,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  * We handle such earlier, so go back.
                  * Note that in the rewrite, we carefully did not run semantic() on e1
                  */
-                if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type)
+                if (exp.e1.op == TOK.dotTemplateInstance)
                 {
                     goto Ldotti;
                 }
@@ -4419,6 +4424,26 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             else if (exp.e1.op == TOK.type && (sc && sc.flags & SCOPE.Cfile))
             {
+                const numArgs = exp.arguments ? exp.arguments.length : 0;
+                if (e1org.parens && numArgs >= 1)
+                {
+                    /* Ambiguous cases arise from CParser where there is not enough
+                     * information to determine if we have a function call or a cast.
+                     *   ( type-name ) ( identifier ) ;
+                     *   ( identifier ) ( identifier ) ;
+                     * If exp.e1 is a type-name, then this is a cast.
+                     */
+                    Expression arg;
+                    foreach (a; (*exp.arguments)[])
+                    {
+                        arg = arg ? new CommaExp(a.loc, arg, a) : a;
+                    }
+                    auto t = exp.e1.isTypeExp().type;
+                    auto e = new CastExp(exp.loc, arg, t);
+                    result = e.expressionSemantic(sc);
+                    return;
+                }
+
                 /* Ambiguous cases arise from CParser where there is not enough
                  * information to determine if we have a function call or declaration.
                  *   type-name ( identifier ) ;
@@ -4426,7 +4451,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  * If exp.e1 is a type-name, then this is a declaration. C11 does not
                  * have type construction syntax, so don't convert this to a cast().
                  */
-                if (exp.arguments && exp.arguments.dim == 1)
+                if (numArgs == 1)
                 {
                     Expression arg = (*exp.arguments)[0];
                     if (auto ie = (*exp.arguments)[0].isIdentifierExp())
@@ -4638,15 +4663,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             UnaExp ue = cast(UnaExp)exp.e1;
 
-            Expression ue1 = ue.e1;
-            Expression ue1old = ue1; // need for 'right this' check
-            VarDeclaration v;
-            if (ue1.op == TOK.variable && (v = (cast(VarExp)ue1).var.isVarDeclaration()) !is null && v.needThis())
-            {
-                ue.e1 = new TypeExp(ue1.loc, ue1.type);
-                ue1 = null;
-            }
-
+            Expression ue1old = ue.e1; // need for 'right this' check
             DotVarExp dve;
             DotTemplateExp dte;
             Dsymbol s;
@@ -4665,7 +4682,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
 
             // Do overload resolution
-            exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue1 ? ue1.type : null, exp.arguments, FuncResolveFlag.standard);
+            exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.arguments, FuncResolveFlag.standard);
             if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
                 return setError();
 
@@ -4677,7 +4694,6 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 auto ad2 = b.sym;
                 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
                 ue.e1 = ue.e1.expressionSemantic(sc);
-                ue1 = ue.e1;
                 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.dim);
                 assert(vi >= 0);
                 exp.f = ad2.vtbl[vi].isFuncDeclaration();
@@ -6036,17 +6052,29 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         {
-            auto readResult = File.read(name);
-            if (!readResult.success)
+            auto fileName = FileName(name.toDString);
+            if (auto fmResult = FileManager.fileManager.lookup(fileName))
             {
-                e.error("cannot read file `%s`", name);
-                return setError();
+                se = new StringExp(e.loc, fmResult.data);
             }
             else
             {
-                // take ownership of buffer (probably leaking)
-                auto data = readResult.extractSlice();
-                se = new StringExp(e.loc, data);
+                auto readResult = File.read(name);
+                if (!readResult.success)
+                {
+                    e.error("cannot read file `%s`", name);
+                    return setError();
+                }
+                else
+                {
+                    // take ownership of buffer (probably leaking)
+                    auto data = readResult.extractSlice();
+                    se = new StringExp(e.loc, data);
+
+                    FileBuffer* fileBuffer = FileBuffer.create();
+                    fileBuffer.data = data;
+                    FileManager.fileManager.add(fileName, fileBuffer);
+                }
             }
         }
         result = se.expressionSemantic(sc);
@@ -6357,7 +6385,11 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 result = e;
                 return;
             }
-            exp.type = Type.tnoreturn;
+
+            // Only override the type when it isn't already some flavour of noreturn,
+            // e.g. when this assert was generated by defaultInitLiteral
+            if (!exp.type || !exp.type.isTypeNoreturn())
+                exp.type = Type.tnoreturn;
         }
         else
             exp.type = Type.tvoid;
@@ -6374,12 +6406,53 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
             //printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op));
         }
+        if (exp.arrow) // ImportC only
+            exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
+
+        if (sc.flags & SCOPE.Cfile)
+        {
+            if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
+            {
+                // C11 6.5.3 says _Alignof only applies to types
+                Expression e;
+                Type t;
+                Dsymbol s;
+                dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
+                if (e)
+                {
+                    exp.e1.error("argument to `_Alignof` must be a type");
+                    return setError();
+                }
+                else if (t)
+                {
+                    result = new IntegerExp(exp.loc, t.alignsize, Type.tsize_t);
+                }
+                else if (s)
+                {
+                    exp.e1.error("argument to `_Alignof` must be a type");
+                    return setError();
+                }
+                else
+                    assert(0);
+                return;
+            }
+        }
+
+        if (sc.flags & SCOPE.Cfile && exp.ident != Id.__sizeof)
+        {
+            result = fieldLookup(exp.e1, sc, exp.ident);
+            return;
+        }
+
         Expression e = exp.semanticY(sc, 1);
+
         if (e && isDotOpDispatch(e))
         {
+            auto ode = e;
             uint errors = global.startGagging();
             e = resolvePropertiesX(sc, e);
-            if (global.endGagging(errors))
+            // Any error or if 'e' is not resolved, go to UFCS
+            if (global.endGagging(errors) || e is ode)
                 e = null; /* fall down to UFCS */
             else
             {
@@ -6580,10 +6653,17 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
         }
+        if (exp.type)
+        {
+            result = exp;
+            return;
+        }
         // Indicate we need to resolve by UFCS.
         Expression e = exp.semanticY(sc, 1);
         if (!e)
             e = resolveUFCSProperties(sc, exp);
+        if (e is exp)
+            e.type = Type.tvoid; // Unresolved type, because it needs inference
         result = e;
     }
 
@@ -7908,6 +7988,16 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     dinteger_t length = el.toInteger();
                     auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
                     exp.upperIsInBounds = bounds.contains(uprRange);
+                    if (exp.lwr.op == TOK.int64 && exp.upr.op == TOK.int64 && exp.lwr.toInteger() > exp.upr.toInteger())
+                    {
+                        exp.error("in slice `%s[%llu .. %llu]`, lower bound is greater than upper bound", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger());
+                        return setError();
+                    }
+                    if (exp.upr.op == TOK.int64 && exp.upr.toInteger() > length)
+                    {
+                        exp.error("in slice `%s[%llu .. %llu]`, upper bound is greater than array length `%llu`", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger(), length);
+                        return setError();
+                    }
                 }
                 else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0)
                 {
@@ -7965,6 +8055,11 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             printf("ArrayExp::semantic('%s')\n", exp.toChars());
         }
         assert(!exp.type);
+
+        result = exp.carraySemantic(sc);  // C semantics
+        if (result)
+            return;
+
         Expression e = exp.op_overload(sc);
         if (e)
         {
@@ -8019,6 +8114,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
     override void visit(CommaExp e)
     {
+        //printf("Semantic.CommaExp() %s\n", e.toChars());
         if (e.type)
         {
             result = e;
@@ -8042,10 +8138,13 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (checkNonAssignmentArrayOp(e.e1))
             return setError();
 
+        // Comma expressions trigger this conversion
+        e.e2 = e.e2.arrayFuncConv(sc);
+
         e.type = e.e2.type;
         if (e.type is Type.tvoid)
             discardValue(e.e1);
-        else if (!e.allowCommaExp && !e.isGenerated)
+        else if (!e.allowCommaExp && !e.isGenerated && !(sc.flags & SCOPE.Cfile))
             e.error("Using the result of a comma expression is not allowed");
         result = e;
     }
@@ -8143,7 +8242,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         // operator overloading should be handled in ArrayExp already.
         if (!exp.e1.type)
-            exp.e1 = exp.e1.expressionSemantic(sc);
+            exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
         assert(exp.e1.type); // semantic() should already be run on it
         if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
         {
@@ -8191,7 +8290,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         if (t1b.ty == Ttuple)
             sc = sc.startCTFE();
-        exp.e2 = exp.e2.expressionSemantic(sc);
+        exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
         exp.e2 = resolveProperties(sc, exp.e2);
         if (t1b.ty == Ttuple)
             sc = sc.endCTFE();
@@ -8515,7 +8614,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         if (auto e2comma = exp.e2.isCommaExp())
         {
-            if (!e2comma.isGenerated)
+            if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
                 exp.error("Using the result of a comma expression is not allowed");
 
             /* Rewrite to get rid of the comma from rvalue
@@ -8659,6 +8758,11 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                 e1x = e;
             }
+            else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
+            {
+                auto die = e1x.isDotIdExp();
+                e1x = fieldLookup(die.e1, sc, die.ident);
+            }
             else if (auto die = e1x.isDotIdExp())
             {
                 Expression e = die.semanticY(sc, 1);
@@ -8672,10 +8776,12 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                      * In order to make sure that UFCS is tried with correct parameters, e2
                      * needs to have semantic ran on it.
                      */
+                    auto ode = e;
                     exp.e2 = exp.e2.expressionSemantic(sc);
                     uint errors = global.startGagging();
                     e = resolvePropertiesX(sc, e, exp.e2);
-                    if (global.endGagging(errors))
+                    // Any error or if 'e' is not resolved, go to UFCS
+                    if (global.endGagging(errors) || e is ode)
                         e = null; /* fall down to UFCS */
                     else
                         return setResult(e);
@@ -8717,12 +8823,14 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             Expression e2x = inferType(exp.e2, t1.baseElemOf());
             e2x = e2x.expressionSemantic(sc);
+            if (!t1.isTypeSArray())
+                e2x = e2x.arrayFuncConv(sc);
             e2x = resolveProperties(sc, e2x);
             if (e2x.op == TOK.type)
                 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
             if (e2x.op == TOK.error)
                 return setResult(e2x);
-            // We skip checking the value for structs/classes as these might have
+            // We delay checking the value for structs/classes as these might have
             // an opAssign defined.
             if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
                 e2x.checkSharedAccess(sc))
@@ -9208,6 +9316,9 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             else
                 assert(exp.op == TOK.blit);
 
+            if (e2x.checkValue())
+                return setError();
+
             exp.e1 = e1x;
             exp.e2 = e2x;
         }
@@ -9223,6 +9334,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return;
                 }
             }
+            if (exp.e2.checkValue())
+                return setError();
         }
         else if (t1.ty == Tsarray)
         {
@@ -9672,7 +9785,13 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         exp.type = exp.e1.type;
         assert(exp.type);
         auto res = exp.op == TOK.assign ? exp.reorderSettingAAElem(sc) : exp;
-        checkAssignEscape(sc, res, false);
+        Expression tmp;
+        /* https://issues.dlang.org/show_bug.cgi?id=22366
+         *
+         * `reorderSettingAAElem` creates a tree of comma expressions, however,
+         * `checkAssignExp` expects only AssignExps.
+         */
+        checkAssignEscape(sc, Expression.extractLast(res, tmp), false);
         return setResult(res);
     }
 
@@ -9944,6 +10063,11 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
+        /* ImportC: convert arrays to pointers, functions to pointers to functions
+         */
+        exp.e1 = exp.e1.arrayFuncConv(sc);
+        exp.e2 = exp.e2.arrayFuncConv(sc);
+
         Type tb1 = exp.e1.type.toBasetype();
         Type tb2 = exp.e2.type.toBasetype();
 
@@ -10045,6 +10169,11 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
+        /* ImportC: convert arrays to pointers, functions to pointers to functions
+         */
+        exp.e1 = exp.e1.arrayFuncConv(sc);
+        exp.e2 = exp.e2.arrayFuncConv(sc);
+
         Type t1 = exp.e1.type.toBasetype();
         Type t2 = exp.e2.type.toBasetype();
 
@@ -11539,12 +11668,12 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         ec = ec.toBoolean(sc);
 
         CtorFlow ctorflow_root = sc.ctorflow.clone();
-        Expression e1x = exp.e1.expressionSemantic(sc);
+        Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
         e1x = resolveProperties(sc, e1x);
 
         CtorFlow ctorflow1 = sc.ctorflow;
         sc.ctorflow = ctorflow_root;
-        Expression e2x = exp.e2.expressionSemantic(sc);
+        Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
         e2x = resolveProperties(sc, e2x);
 
         sc.merge(exp.loc, ctorflow1);
@@ -11894,95 +12023,84 @@  Expression semanticX(DotIdExp exp, Scope* sc)
     if (exp.ident == Id._mangleof)
     {
         // symbol.mangleof
-        Dsymbol ds;
-        switch (exp.e1.op)
+
+        // return mangleof as an Expression
+        static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
         {
-        case TOK.scope_:
-            ds = (cast(ScopeExp)exp.e1).sds;
-            goto L1;
-        case TOK.variable:
-            ds = (cast(VarExp)exp.e1).var;
-            goto L1;
-        case TOK.dotVariable:
-            ds = (cast(DotVarExp)exp.e1).var;
-            goto L1;
-        case TOK.overloadSet:
-            ds = (cast(OverExp)exp.e1).vars;
-            goto L1;
-        case TOK.template_:
-            {
-                TemplateExp te = cast(TemplateExp)exp.e1;
-                ds = te.fd ? cast(Dsymbol)te.fd : te.td;
-            }
-        L1:
+            assert(ds);
+            if (auto f = ds.isFuncDeclaration())
             {
-                assert(ds);
-                if (auto f = ds.isFuncDeclaration())
+                if (f.checkForwardRef(loc))
+                    return ErrorExp.get();
+
+                if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess |
+                               FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess))
                 {
-                    if (f.checkForwardRef(exp.loc))
-                    {
-                        return ErrorExp.get();
-                    }
-                    if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess |
-                                   FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess))
-                    {
-                        f.error(exp.loc, "cannot retrieve its `.mangleof` while inferring attributes");
-                        return ErrorExp.get();
-                    }
+                    f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes");
+                    return ErrorExp.get();
                 }
-                OutBuffer buf;
-                mangleToBuffer(ds, &buf);
-                Expression e = new StringExp(exp.loc, buf.extractSlice());
-                e = e.expressionSemantic(sc);
-                return e;
             }
-        default:
-            break;
+            OutBuffer buf;
+            mangleToBuffer(ds, &buf);
+            Expression e = new StringExp(loc, buf.extractSlice());
+            return e.expressionSemantic(sc);
+        }
+
+        Dsymbol ds;
+        switch (exp.e1.op)
+        {
+            case TOK.scope_:      return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
+            case TOK.variable:    return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
+            case TOK.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
+            case TOK.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
+            case TOK.template_:
+            {
+                TemplateExp te = exp.e1.isTemplateExp();
+                return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
+            }
+
+            default:
+                break;
         }
     }
 
-    if (exp.e1.op == TOK.variable && exp.e1.type.toBasetype().ty == Tsarray && exp.ident == Id.length)
+    if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
     {
         // bypass checkPurity
         return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0);
     }
 
-    if (exp.e1.op == TOK.dot)
-    {
-    }
-    else
+    if (!exp.e1.isDotExp())
     {
         exp.e1 = resolvePropertiesX(sc, exp.e1);
     }
-    if (exp.e1.op == TOK.tuple && exp.ident == Id.offsetof)
+
+    if (auto te = exp.e1.isTupleExp())
     {
-        /* 'distribute' the .offsetof to each of the tuple elements.
-         */
-        TupleExp te = cast(TupleExp)exp.e1;
-        auto exps = new Expressions(te.exps.dim);
-        for (size_t i = 0; i < exps.dim; i++)
+        if (exp.ident == Id.offsetof)
         {
-            Expression e = (*te.exps)[i];
+            /* 'distribute' the .offsetof to each of the tuple elements.
+             */
+            auto exps = new Expressions(te.exps.dim);
+            foreach (i, e; (*te.exps)[])
+            {
+                (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
+            }
+            // Don't evaluate te.e0 in runtime
+            Expression e = new TupleExp(exp.loc, null, exps);
             e = e.expressionSemantic(sc);
-            e = new DotIdExp(e.loc, e, Id.offsetof);
-            (*exps)[i] = e;
+            return e;
+        }
+        if (exp.ident == Id.length)
+        {
+            // Don't evaluate te.e0 in runtime
+            return new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t);
         }
-        // Don't evaluate te.e0 in runtime
-        Expression e = new TupleExp(exp.loc, null, exps);
-        e = e.expressionSemantic(sc);
-        return e;
-    }
-    if (exp.e1.op == TOK.tuple && exp.ident == Id.length)
-    {
-        TupleExp te = cast(TupleExp)exp.e1;
-        // Don't evaluate te.e0 in runtime
-        Expression e = new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t);
-        return e;
     }
 
     // https://issues.dlang.org/show_bug.cgi?id=14416
     // Template has no built-in properties except for 'stringof'.
-    if ((exp.e1.op == TOK.dotTemplateDeclaration || exp.e1.op == TOK.template_) && exp.ident != Id.stringof)
+    if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
     {
         exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
         return ErrorExp.get();
@@ -11996,8 +12114,15 @@  Expression semanticX(DotIdExp exp, Scope* sc)
     return exp;
 }
 
-// Resolve e1.ident without seeing UFCS.
-// If flag == 1, stop "not a property" error and return NULL.
+/******************************
+ * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
+ * Params:
+ *      exp = expression to resolve
+ *      sc = context
+ *      flag = if 1 then do not emit error messages, just return null
+ * Returns:
+ *      resolved expression, null if error
+ */
 Expression semanticY(DotIdExp exp, Scope* sc, int flag)
 {
     //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
@@ -12008,32 +12133,35 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
      * to be classtype.id and baseclasstype.id
      * if we have no this pointer.
      */
-    if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && !hasThis(sc))
+    if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
     {
         if (AggregateDeclaration ad = sc.getStructClassScope())
         {
-            if (exp.e1.op == TOK.this_)
+            if (exp.e1.isThisExp())
             {
                 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
             }
             else
             {
-                ClassDeclaration cd = ad.isClassDeclaration();
-                if (cd && cd.baseClass)
-                    exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
+                if (auto cd = ad.isClassDeclaration())
+                {
+                    if (cd.baseClass)
+                        exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
+                }
             }
         }
     }
 
-    Expression e = semanticX(exp, sc);
-    if (e != exp)
-        return e;
+    {
+        Expression e = semanticX(exp, sc);
+        if (e != exp)
+            return e;
+    }
 
     Expression eleft;
     Expression eright;
-    if (exp.e1.op == TOK.dot)
+    if (auto de = exp.e1.isDotExp())
     {
-        DotExp de = cast(DotExp)exp.e1;
         eleft = de.e1;
         eright = de.e2;
     }
@@ -12045,11 +12173,9 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
 
     Type t1b = exp.e1.type.toBasetype();
 
-    if (eright.op == TOK.scope_) // also used for template alias's
+    if (auto ie = eright.isScopeExp()) // also used for template alias's
     {
-        ScopeExp ie = cast(ScopeExp)eright;
-
-        int flags = SearchLocalsOnly;
+        auto flags = SearchLocalsOnly;
         /* Disable access to another module's private imports.
          * The check for 'is sds our current module' is because
          * the current module should have access to its own imports.
@@ -12082,13 +12208,11 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
             exp.checkDeprecated(sc, s);
             exp.checkDisabled(sc, s);
 
-            EnumMember em = s.isEnumMember();
-            if (em)
+            if (auto em = s.isEnumMember())
             {
                 return em.getVarExp(exp.loc, sc);
             }
-            VarDeclaration v = s.isVarDeclaration();
-            if (v)
+            if (auto v = s.isVarDeclaration())
             {
                 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
                 if (!v.type ||
@@ -12100,7 +12224,7 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
                         exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
                     return ErrorExp.get();
                 }
-                if (v.type.ty == Terror)
+                if (v.type.isTypeError())
                     return ErrorExp.get();
 
                 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
@@ -12114,13 +12238,14 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
                         error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
                         return ErrorExp.get();
                     }
-                    e = v.expandInitializer(exp.loc);
+                    auto e = v.expandInitializer(exp.loc);
                     v.inuse++;
                     e = e.expressionSemantic(sc);
                     v.inuse--;
                     return e;
                 }
 
+                Expression e;
                 if (v.needThis())
                 {
                     if (!eleft)
@@ -12141,12 +12266,12 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
                 return e.expressionSemantic(sc);
             }
 
-            FuncDeclaration f = s.isFuncDeclaration();
-            if (f)
+            if (auto f = s.isFuncDeclaration())
             {
                 //printf("it's a function\n");
                 if (!f.functionSemantic())
                     return ErrorExp.get();
+                Expression e;
                 if (f.needThis())
                 {
                     if (!eleft)
@@ -12167,6 +12292,7 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
             }
             if (auto td = s.isTemplateDeclaration())
             {
+                Expression e;
                 if (eleft)
                     e = new DotTemplateExp(exp.loc, eleft, td);
                 else
@@ -12176,7 +12302,7 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
             }
             if (OverDeclaration od = s.isOverDeclaration())
             {
-                e = new VarExp(exp.loc, od, true);
+                Expression e = new VarExp(exp.loc, od, true);
                 if (eleft)
                 {
                     e = new CommaExp(exp.loc, eleft, e);
@@ -12184,8 +12310,7 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
                 }
                 return e;
             }
-            OverloadSet o = s.isOverloadSet();
-            if (o)
+            if (auto o = s.isOverloadSet())
             {
                 //printf("'%s' is an overload set\n", o.toChars());
                 return new OverExp(exp.loc, o);
@@ -12196,36 +12321,33 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
                 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
             }
 
-            TupleDeclaration tup = s.isTupleDeclaration();
-            if (tup)
+            if (auto tup = s.isTupleDeclaration())
             {
                 if (eleft)
                 {
-                    e = new DotVarExp(exp.loc, eleft, tup);
+                    Expression e = new DotVarExp(exp.loc, eleft, tup);
                     e = e.expressionSemantic(sc);
                     return e;
                 }
-                e = new TupleExp(exp.loc, tup);
+                Expression e = new TupleExp(exp.loc, tup);
                 e = e.expressionSemantic(sc);
                 return e;
             }
 
-            ScopeDsymbol sds = s.isScopeDsymbol();
-            if (sds)
+            if (auto sds = s.isScopeDsymbol())
             {
                 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
-                e = new ScopeExp(exp.loc, sds);
+                Expression e = new ScopeExp(exp.loc, sds);
                 e = e.expressionSemantic(sc);
                 if (eleft)
                     e = new DotExp(exp.loc, eleft, e);
                 return e;
             }
 
-            Import imp = s.isImport();
-            if (imp)
+            if (auto imp = s.isImport())
             {
-                ie = new ScopeExp(exp.loc, imp.pkg);
-                return ie.expressionSemantic(sc);
+                Expression se = new ScopeExp(exp.loc, imp.pkg);
+                return se.expressionSemantic(sc);
             }
             // BUG: handle other cases like in IdentifierExp::semantic()
             debug
@@ -12236,7 +12358,7 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
         }
         else if (exp.ident == Id.stringof)
         {
-            e = new StringExp(exp.loc, ie.toString());
+            Expression e = new StringExp(exp.loc, ie.toString());
             e = e.expressionSemantic(sc);
             return e;
         }
@@ -12263,9 +12385,11 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
         Type t1bn = t1b.nextOf();
         if (flag)
         {
-            AggregateDeclaration ad = isAggregate(t1bn);
-            if (ad && !ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
-                return null;
+            if (AggregateDeclaration ad = isAggregate(t1bn))
+            {
+                if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
+                    return null;
+            }
         }
 
         /* Rewrite:
@@ -12275,27 +12399,27 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
          */
         if (flag && t1bn.ty == Tvoid)
             return null;
-        e = new PtrExp(exp.loc, exp.e1);
+        Expression e = new PtrExp(exp.loc, exp.e1);
         e = e.expressionSemantic(sc);
         return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
     }
     else if (exp.ident == Id.__xalignof &&
              exp.e1.isVarExp() &&
              exp.e1.isVarExp().var.isVarDeclaration() &&
-             exp.e1.isVarExp().var.isVarDeclaration().alignment)
+             !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
     {
         // For `x.alignof` get the alignment of the variable, not the alignment of its type
         const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
         const naturalAlignment = exp.e1.type.alignsize();
-        const actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment);
-        e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
+        const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
+        Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
         return e;
     }
     else
     {
-        if (exp.e1.op == TOK.type || exp.e1.op == TOK.template_)
+        if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
             flag = 0;
-        e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
+        Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
         if (e)
             e = e.expressionSemantic(sc);
         return e;
@@ -12875,7 +12999,7 @@  private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
         const hasPointers = tb.hasPointers();
         if (hasPointers)
         {
-            if ((stype.alignment() < target.ptrsize ||
+            if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
                  (v.offset & (target.ptrsize - 1))) &&
                 (sc.func && sc.func.setUnsafe()))
             {
diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d
new file mode 100644
index 00000000000..05aeb7df5dc
--- /dev/null
+++ b/gcc/d/dmd/file_manager.d
@@ -0,0 +1,301 @@ 
+/**
+ * Read a file from disk and store it in memory.
+ *
+ * Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
+ * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d, _file_manager.d)
+ * Documentation:  https://dlang.org/phobos/dmd_file_manager.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/file_manager.d
+ */
+
+module dmd.file_manager;
+
+import dmd.root.stringtable : StringTable;
+import dmd.root.file : File, FileBuffer;
+import dmd.root.filename : FileName;
+import dmd.root.string : toDString;
+import dmd.globals;
+import dmd.identifier;
+
+enum package_d  = "package." ~ mars_ext;
+enum package_di = "package." ~ hdr_ext;
+
+extern(C++) struct FileManager
+{
+    private StringTable!(FileBuffer*) files;
+    private __gshared bool initialized = false;
+
+nothrow:
+    extern(D) private FileBuffer* readToFileBuffer(const(char)[] filename)
+    {
+        if (!initialized)
+            FileManager._init();
+
+        auto readResult = File.read(filename);
+        if (readResult.success)
+        {
+            FileBuffer* fb;
+            if (auto val = files.lookup(filename))
+                fb = val.value;
+
+            if (!fb)
+                fb = FileBuffer.create();
+
+            fb.data = readResult.extractSlice();
+
+            return files.insert(filename, fb) == null ? null : fb;
+        }
+        else
+        {
+            return null;
+        }
+
+    }
+
+    /********************************************
+    * Look for the source file if it's different from filename.
+    * Look for .di, .d, directory, and along global.path.
+    * Does not open the file.
+    * Params:
+    *      filename = as supplied by the user
+    *      path = path to look for filename
+    * Returns:
+    *      the found file name or
+    *      `null` if it is not different from filename.
+    */
+    extern(D) static const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
+    {
+        //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
+        /* Search along path[] for .di file, then .d file, then .i file, then .c file.
+        */
+        const sdi = FileName.forceExt(filename, hdr_ext);
+        if (FileName.exists(sdi) == 1)
+            return sdi;
+        scope(exit) FileName.free(sdi.ptr);
+
+        const sd = FileName.forceExt(filename, mars_ext);
+        if (FileName.exists(sd) == 1)
+            return sd;
+        scope(exit) FileName.free(sd.ptr);
+
+        const si = FileName.forceExt(filename, i_ext);
+        if (FileName.exists(si) == 1)
+            return si;
+        scope(exit) FileName.free(si.ptr);
+
+        const sc = FileName.forceExt(filename, c_ext);
+        if (FileName.exists(sc) == 1)
+            return sc;
+        scope(exit) FileName.free(sc.ptr);
+
+        if (FileName.exists(filename) == 2)
+        {
+            /* The filename exists and it's a directory.
+            * Therefore, the result should be: filename/package.d
+            * iff filename/package.d is a file
+            */
+            const ni = FileName.combine(filename, package_di);
+            if (FileName.exists(ni) == 1)
+                return ni;
+            FileName.free(ni.ptr);
+
+            const n = FileName.combine(filename, package_d);
+            if (FileName.exists(n) == 1)
+                return n;
+            FileName.free(n.ptr);
+        }
+        if (FileName.absolute(filename))
+            return null;
+        if (!path.length)
+            return null;
+        foreach (entry; path)
+        {
+            const p = entry.toDString();
+
+            const(char)[] n = FileName.combine(p, sdi);
+            if (FileName.exists(n) == 1) {
+                return n;
+            }
+            FileName.free(n.ptr);
+
+            n = FileName.combine(p, sd);
+            if (FileName.exists(n) == 1) {
+                return n;
+            }
+            FileName.free(n.ptr);
+
+            n = FileName.combine(p, si);
+            if (FileName.exists(n) == 1) {
+                return n;
+            }
+            FileName.free(n.ptr);
+
+            n = FileName.combine(p, sc);
+            if (FileName.exists(n) == 1) {
+                return n;
+            }
+            FileName.free(n.ptr);
+
+            const b = FileName.removeExt(filename);
+            n = FileName.combine(p, b);
+            FileName.free(b.ptr);
+            if (FileName.exists(n) == 2)
+            {
+                const n2i = FileName.combine(n, package_di);
+                if (FileName.exists(n2i) == 1)
+                    return n2i;
+                FileName.free(n2i.ptr);
+                const n2 = FileName.combine(n, package_d);
+                if (FileName.exists(n2) == 1) {
+                    return n2;
+                }
+                FileName.free(n2.ptr);
+            }
+            FileName.free(n.ptr);
+        }
+        return null;
+    }
+
+    /**
+     * Looks up the given filename from the internal file buffer table.
+     * If the file does not already exist within the table, it will be read from the filesystem.
+     * If it has been read before,
+     *
+     * Returns: the loaded source file if it was found in memory,
+     *      otherwise `null`
+     */
+    extern(D) FileBuffer* lookup(FileName filename)
+    {
+        if (!initialized)
+            FileManager._init();
+
+        if (auto val = files.lookup(filename.toString))
+        {
+            // There is a chance that the buffer could've been
+            // stolen by a reader with extractSlice, so we should
+            // try and do our reading logic if that happens.
+            if (val !is null && val.value.data !is null)
+            {
+                return val.value;
+            }
+        }
+
+        const name = filename.toString;
+        auto res = FileName.exists(name);
+        if (res == 1)
+            return readToFileBuffer(name);
+
+        const fullName = lookForSourceFile(name, global.path ? (*global.path)[] : null);
+        if (!fullName)
+            return null;
+
+        return readToFileBuffer(fullName);
+    }
+
+    extern(C++) FileBuffer* lookup(const(char)* filename)
+    {
+        return lookup(FileName(filename.toDString));
+    }
+
+    /**
+     * Looks up the given filename from the internal file buffer table, and returns the lines within the file.
+     * If the file does not already exist within the table, it will be read from the filesystem.
+     * If it has been read before,
+     *
+     * Returns: the loaded source file if it was found in memory,
+     *      otherwise `null`
+     */
+    extern(D) const(char)[][] getLines(FileName file)
+    {
+        if (!initialized)
+            FileManager._init();
+
+        const(char)[][] lines;
+        if (FileBuffer* buffer = lookup(file))
+        {
+            ubyte[] slice = buffer.data[0 .. buffer.data.length];
+            size_t start, end;
+            ubyte c;
+            for (auto i = 0; i < slice.length; i++)
+            {
+                c = slice[i];
+                if (c == '\n' || c == '\r')
+                {
+                    if (i != 0)
+                    {
+                        end = i;
+                        lines ~= cast(const(char)[])slice[start .. end];
+                    }
+                    // Check for Windows-style CRLF newlines
+                    if (c == '\r')
+                    {
+                        if (slice.length > i + 1 && slice[i + 1] == '\n')
+                        {
+                            // This is a CRLF sequence, skip over two characters
+                            start = i + 2;
+                            i++;
+                        }
+                        else
+                        {
+                            // Just a CR sequence
+                            start = i + 1;
+                        }
+                    }
+                    else
+                    {
+                        // The next line should start after the LF sequence
+                        start = i + 1;
+                    }
+                }
+            }
+
+            if (slice[$ - 1] != '\r' && slice[$ - 1] != '\n')
+            {
+                end = slice.length;
+                lines ~= cast(const(char)[])slice[start .. end];
+            }
+        }
+
+        return lines;
+    }
+
+    /**
+     * Adds a FileBuffer to the table.
+     *
+     * Returns: The FileBuffer added, or null
+     */
+    extern(D) FileBuffer* add(FileName filename, FileBuffer* filebuffer)
+    {
+        if (!initialized)
+            FileManager._init();
+
+        auto val = files.insert(filename.toString, filebuffer);
+        return val == null ? null : val.value;
+    }
+
+    extern(C++) FileBuffer* add(const(char)* filename, FileBuffer* filebuffer)
+    {
+        if (!initialized)
+            FileManager._init();
+
+        auto val = files.insert(filename.toDString, filebuffer);
+        return val == null ? null : val.value;
+    }
+
+    __gshared fileManager = FileManager();
+
+    // Initialize the global FileManager singleton
+    extern(C++) static __gshared void _init()
+    {
+        if (!initialized)
+        {
+            fileManager.initialize();
+            initialized = true;
+        }
+    }
+
+    void initialize()
+    {
+        files._init();
+    }
+}
diff --git a/gcc/d/dmd/root/root.h b/gcc/d/dmd/file_manager.h
similarity index 50%
rename from gcc/d/dmd/root/root.h
rename to gcc/d/dmd/file_manager.h
index 667ce67fb7c..7488fab17fc 100644
--- a/gcc/d/dmd/root/root.h
+++ b/gcc/d/dmd/file_manager.h
@@ -4,17 +4,16 @@ 
  * http://www.digitalmars.com
  * Distributed under the Boost Software License, Version 1.0.
  * http://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/dmd/root/root.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.h
  */
 
 #pragma once
 
-#include "object.h"
+#include "root/file.h"
 
-#include "filename.h"
-
-#include "file.h"
-
-#include "outbuffer.h"
-
-#include "array.h"
+struct FileManager
+{
+    static void _init();
+    FileBuffer* lookup(const char* filename);
+    FileBuffer* add(const char* filename, FileBuffer* filebuffer);
+};
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 7f0b0bb9a28..2d6a756178e 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -45,7 +45,8 @@  import dmd.identifier;
 import dmd.init;
 import dmd.mtype;
 import dmd.objc;
-import dmd.root.outbuffer;
+import dmd.root.aav;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.root.stringtable;
@@ -261,6 +262,8 @@  extern (C++) class FuncDeclaration : Declaration
     VarDeclaration vresult;             /// result variable for out contracts
     LabelDsymbol returnLabel;           /// where the return goes
 
+    bool[size_t] isTypeIsolatedCache;   /// cache for the potentially very expensive isTypeIsolated check
+
     // used to prevent symbols in different
     // scopes from having the same name
     DsymbolTable localsymtab;
@@ -740,7 +743,7 @@  extern (C++) class FuncDeclaration : Declaration
      */
     final BaseClass* overrideInterface()
     {
-        if (ClassDeclaration cd = toParent2().isClassDeclaration())
+        for (ClassDeclaration cd = toParent2().isClassDeclaration(); cd; cd = cd.baseClass)
         {
             foreach (b; cd.interfaces)
             {
@@ -1529,8 +1532,23 @@  extern (C++) class FuncDeclaration : Declaration
     extern (D) final bool isTypeIsolated(Type t)
     {
         StringTable!Type parentTypes;
-        parentTypes._init();
-        return isTypeIsolated(t, parentTypes);
+        const uniqueTypeID = t.getUniqueID();
+        if (uniqueTypeID)
+        {
+            const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
+            if (cacheResultPtr !is null)
+                return *cacheResultPtr;
+
+            parentTypes._init();
+            const isIsolated = isTypeIsolated(t, parentTypes);
+            isTypeIsolatedCache[uniqueTypeID] = isIsolated;
+            return isIsolated;
+        }
+        else
+        {
+            parentTypes._init();
+            return isTypeIsolated(t, parentTypes);
+        }
     }
 
     ///ditto
@@ -2593,9 +2611,10 @@  extern (C++) class FuncDeclaration : Declaration
         }
 
         if (!tf.nextOf())
-            error("must return `int` or `void`");
-        else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid)
-            error("must return `int` or `void`, not `%s`", tf.nextOf().toChars());
+            // auto main(), check after semantic
+            assert(this.inferRetType);
+        else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid && tf.nextOf().ty != Tnoreturn)
+            error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars());
         else if (tf.parameterList.varargs || nparams >= 2 || argerr)
             error("parameters must be `main()` or `main(string[] args)`");
     }
@@ -3054,7 +3073,11 @@  FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
         return null;
 
     bool hasOverloads = fd.overnext !is null;
-    auto tf = fd.type.toTypeFunction();
+    auto tf = fd.type.isTypeFunction();
+    // if type is an error, the original type should be there for better diagnostics
+    if (!tf)
+        tf = fd.originalType.toTypeFunction();
+
     if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
     {
         OutBuffer thisBuf, funcBuf;
@@ -3253,17 +3276,7 @@  private bool traverseIndirections(Type ta, Type tb)
 {
     //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
 
-    /* Threaded list of aggregate types already examined,
-     * used to break cycles.
-     * Cycles in type graphs can only occur with aggregates.
-     */
-    static struct Ctxt
-    {
-        Ctxt* prev;
-        Type type;      // an aggregate type
-    }
-
-    static bool traverse(Type ta, Type tb, Ctxt* ctxt, bool reversePass)
+    static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
     {
         //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
         ta = ta.baseElemOf();
@@ -3293,28 +3306,27 @@  private bool traverseIndirections(Type ta, Type tb)
 
         if (tb.ty == Tclass || tb.ty == Tstruct)
         {
-            for (Ctxt* c = ctxt; c; c = c.prev)
-                if (tb == c.type)
-                    return true;
-            Ctxt c;
-            c.prev = ctxt;
-            c.type = tb;
-
             /* Traverse the type of each field of the aggregate
              */
+            bool* found = table.getLvalue(tb.deco);
+            if (*found == true)
+                return true; // We have already seen this symbol, break the cycle
+            else
+                *found = true;
+
             AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
             foreach (v; sym.fields)
             {
                 Type tprmi = v.type.addMod(tb.mod);
                 //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
-                if (!traverse(ta, tprmi, &c, reversePass))
+                if (!traverse(ta, tprmi, table, reversePass))
                     return false;
             }
         }
         else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
         {
             Type tind = tb.nextOf();
-            if (!traverse(ta, tind, ctxt, reversePass))
+            if (!traverse(ta, tind, table, reversePass))
                 return false;
         }
         else if (tb.hasPointers())
@@ -3325,7 +3337,10 @@  private bool traverseIndirections(Type ta, Type tb)
 
         // Still no match, so try breaking up ta if we have not done so yet.
         if (!reversePass)
-            return traverse(tb, ta, ctxt, true);
+        {
+            scope newTable = AssocArray!(const(char)*, bool)();
+            return traverse(tb, ta, newTable, true);
+        }
 
         return true;
     }
@@ -3333,7 +3348,8 @@  private bool traverseIndirections(Type ta, Type tb)
     // To handle arbitrary levels of indirections in both parameters, we
     // recursively descend into aggregate members/levels of indirection in both
     // `ta` and `tb` while avoiding cycles. Start with the original types.
-    const result = traverse(ta, tb, null, false);
+    scope table = AssocArray!(const(char)*, bool)();
+    const result = traverse(ta, tb, table, false);
     //printf("  returns %d\n", result);
     return result;
 }
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index 9b65d024b97..747a1138905 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -14,7 +14,7 @@  module dmd.globals;
 import core.stdc.stdint;
 import dmd.root.array;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.identifier;
 
 /// Defines a setting for how compiler warnings and deprecations are handled
@@ -118,6 +118,7 @@  extern (C++) struct Param
     bool vgc;               // identify gc usage
     bool vfield;            // identify non-mutable field variables
     bool vcomplex = true;   // identify complex/imaginary type usage
+    bool vin;               // identify 'in' parameters
     ubyte symdebug;         // insert debug symbolic information
     bool symdebugref;       // insert debug information for all referenced types, too
     bool optimize;          // run optimizer
@@ -261,11 +262,29 @@  extern (C++) struct Param
     const(char)[] mapfile;
 }
 
-alias structalign_t = uint;
+extern (C++) struct structalign_t
+{
+  private:
+    ushort value = 0;  // unknown
+    enum STRUCTALIGN_DEFAULT = 1234;   // default = match whatever the corresponding C compiler does
+    bool pack;         // use #pragma pack semantics
+
+  public:
+  pure @safe @nogc nothrow:
+    bool isDefault() const { return value == STRUCTALIGN_DEFAULT; }
+    void setDefault()      { value = STRUCTALIGN_DEFAULT; }
+    bool isUnknown() const { return value == 0; }  // value is not set
+    void setUnknown()      { value = 0; }
+    void set(uint value)   { this.value = cast(ushort)value; }
+    uint get() const       { return value; }
+    bool isPack() const    { return pack; }
+    void setPack(bool pack) { this.pack = pack; }
+}
+//alias structalign_t = uint;
 
 // magic value means "match whatever the underlying C compiler does"
 // other values are all powers of 2
-enum STRUCTALIGN_DEFAULT = (cast(structalign_t)~0);
+//enum STRUCTALIGN_DEFAULT = (cast(structalign_t)~0);
 
 enum mars_ext = "d";        // for D source files
 enum doc_ext  = "html";     // for Ddoc generated files
@@ -307,6 +326,8 @@  extern (C++) struct Global
     Array!Identifier* versionids; /// command line versions and predefined versions
     Array!Identifier* debugids;   /// command line debug versions and predefined versions
 
+    bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch)
+
     enum recursionLimit = 500; /// number of recursive template expansions before abort
 
   nothrow:
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 6e794748bee..2275ec517e5 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -12,7 +12,7 @@ 
 
 #include "root/dcompat.h"
 #include "root/ctfloat.h"
-#include "root/outbuffer.h"
+#include "common/outbuffer.h"
 #include "root/filename.h"
 #include "compiler.h"
 
@@ -107,6 +107,7 @@  struct Param
     bool vgc;           // identify gc usage
     bool vfield;        // identify non-mutable field variables
     bool vcomplex;      // identify complex/imaginary type usage
+    bool vin;           // identify 'in' parameters
     unsigned char symdebug;  // insert debug symbolic information
     bool symdebugref;   // insert debug information for all referenced types, too
     bool optimize;      // run optimizer
@@ -238,10 +239,24 @@  struct Param
     DString mapfile;
 };
 
-typedef unsigned structalign_t;
+struct structalign_t
+{
+    unsigned short value;
+    bool pack;
+
+    bool isDefault() const;
+    void setDefault();
+    bool isUnknown() const;
+    void setUnknown();
+    void set(unsigned value);
+    unsigned get() const;
+    bool isPack() const;
+    void setPack(bool pack);
+};
+
 // magic value means "match whatever the underlying C compiler does"
 // other values are all powers of 2
-#define STRUCTALIGN_DEFAULT ((structalign_t) ~0)
+//#define STRUCTALIGN_DEFAULT ((structalign_t) ~0)
 
 const DString mars_ext = "d";
 const DString doc_ext  = "html";     // for Ddoc generated files
@@ -274,6 +289,8 @@  struct Global
     Array<class Identifier*>* versionids; // command line versions and predefined versions
     Array<class Identifier*>* debugids;   // command line debug versions and predefined versions
 
+    bool hasMainFunction;
+
     /* Start gagging. Return the current number of gagged errors
      */
     unsigned startGagging();
diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d
index debb9ca62d4..4018126cb26 100644
--- a/gcc/d/dmd/gluelayer.d
+++ b/gcc/d/dmd/gluelayer.d
@@ -78,6 +78,7 @@  else version (IN_GCC)
     extern (C++)
     {
         Statement asmSemantic(AsmStatement s, Scope* sc);
+        void toObjFile(Dsymbol ds, bool multiobj);
     }
 
     // stubs
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 8c31590a311..4ff07b5de32 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -44,7 +44,7 @@  import dmd.mtype;
 import dmd.nspace;
 import dmd.parse;
 import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.statement;
@@ -909,6 +909,12 @@  public:
 
     override void visit(AttribDeclaration d)
     {
+        bool hasSTC;
+        if (auto stcd = d.isStorageClassDeclaration)
+        {
+            hasSTC = stcToBuffer(buf, stcd.stc);
+        }
+
         if (!d.decl)
         {
             buf.writeByte(';');
@@ -918,10 +924,12 @@  public:
         if (d.decl.dim == 0 || (hgs.hdrgen && d.decl.dim == 1 && (*d.decl)[0].isUnitTestDeclaration()))
         {
             // hack for bugzilla 8081
+            if (hasSTC) buf.writeByte(' ');
             buf.writestring("{}");
         }
         else if (d.decl.dim == 1)
         {
+            if (hasSTC) buf.writeByte(' ');
             (*d.decl)[0].accept(this);
             return;
         }
@@ -941,8 +949,6 @@  public:
 
     override void visit(StorageClassDeclaration d)
     {
-        if (stcToBuffer(buf, d.stc))
-            buf.writeByte(' ');
         visit(cast(AttribDeclaration)d);
     }
 
@@ -1324,11 +1330,10 @@  public:
         if (d.ident)
         {
             buf.writestring(d.ident.toString());
-            buf.writeByte(' ');
         }
         if (d.memtype)
         {
-            buf.writestring(": ");
+            buf.writestring(" : ");
             typeToBuffer(d.memtype, null, buf, hgs);
         }
         if (!d.members)
@@ -2362,7 +2367,10 @@  public:
     override void visit(DotIdExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
-        buf.writeByte('.');
+        if (e.arrow)
+            buf.writestring("->");
+        else
+            buf.writeByte('.');
         buf.writestring(e.ident.toString());
     }
 
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
index e61fb23eb5d..3ff0e894e2a 100644
--- a/gcc/d/dmd/iasmgcc.d
+++ b/gcc/d/dmd/iasmgcc.d
@@ -300,7 +300,7 @@  Ldone:
  * Returns:
  *      the completed gcc asm statement, or null if errors occurred
  */
-public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
+extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
 {
     //printf("GccAsmStatement.semantic()\n");
     scope p = new Parser!ASTCodegen(sc._module, ";", false);
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index 1f04dcfbc11..1ee51533b53 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -500,6 +500,17 @@  immutable Msgtable[] msgtable =
     { "vector_size" },
     { "__func__" },
     { "noreturn" },
+    { "__pragma", "pragma" },
+    { "builtin_va_list", "__builtin_va_list" },
+    { "builtin_va_start", "__builtin_va_start" },
+    { "builtin_va_arg", "__builtin_va_arg" },
+    { "builtin_va_copy", "__builtin_va_copy" },
+    { "builtin_va_end", "__builtin_va_end" },
+    { "va_list_tag", "__va_list_tag" },
+    { "pack" },
+    { "show" },
+    { "push" },
+    { "pop" },
 ];
 
 
diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d
index 43a1435cd10..8add74a1427 100644
--- a/gcc/d/dmd/identifier.d
+++ b/gcc/d/dmd/identifier.d
@@ -16,7 +16,7 @@  import core.stdc.stdio;
 import core.stdc.string;
 import dmd.globals;
 import dmd.id;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.root.stringtable;
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
new file mode 100644
index 00000000000..0dad1a83a8b
--- /dev/null
+++ b/gcc/d/dmd/importc.d
@@ -0,0 +1,171 @@ 
+/**
+ * Contains semantic routines specific to ImportC
+ *
+ * Specification: C11
+ *
+ * Copyright:   Copyright (C) 2021 by The D Language Foundation, All Rights Reserved
+ * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/importc.d, _importc.d)
+ * Documentation:  https://dlang.org/phobos/dmd_importc.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/importc.d
+ */
+
+module dmd.importc;
+
+import core.stdc.stdio;
+
+import dmd.dcast;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.identifier;
+import dmd.mtype;
+
+/**************************************
+ * C11 does not allow array or function parameters.
+ * Hence, adjust those types per C11 6.7.6.3 rules.
+ * Params:
+ *      t = parameter type to adjust
+ *      sc = context
+ * Returns:
+ *      adjusted type
+ */
+Type cAdjustParamType(Type t, Scope* sc)
+{
+    if (!(sc.flags & SCOPE.Cfile))
+        return t;
+
+    Type tb = t.toBasetype();
+
+    /* C11 6.7.6.3-7 array of T is converted to pointer to T
+     */
+    if (auto ta = tb.isTypeDArray())
+    {
+        t = ta.next.pointerTo();
+    }
+    else if (auto ts = tb.isTypeSArray())
+    {
+        t = ts.next.pointerTo();
+    }
+    /* C11 6.7.6.3-8 function is converted to pointer to function
+     */
+    else if (tb.isTypeFunction())
+    {
+        t = tb.pointerTo();
+    }
+    return t;
+}
+
+/***********************************************
+ * C11 6.3.2.1-3 Convert expression that is an array of type to a pointer to type.
+ * C11 6.3.2.1-4 Convert expression that is a function to a pointer to a function.
+ * Params:
+ *  e = ImportC expression to possibly convert
+ *  sc = context
+ * Returns:
+ *  converted expression
+ */
+Expression arrayFuncConv(Expression e, Scope* sc)
+{
+    //printf("arrayFuncConv() %s\n", e.toChars());
+    if (!(sc.flags & SCOPE.Cfile))
+        return e;
+
+    auto t = e.type.toBasetype();
+    if (auto ta = t.isTypeDArray())
+    {
+        e = e.castTo(sc, ta.next.pointerTo());
+    }
+    else if (auto ts = t.isTypeSArray())
+    {
+        e = e.castTo(sc, ts.next.pointerTo());
+    }
+    else if (t.isTypeFunction())
+    {
+        e = e.addressOf();
+    }
+    else
+        return e;
+    return e.expressionSemantic(sc);
+}
+
+/****************************************
+ * Run semantic on `e`.
+ * Expression `e` evaluates to an instance of a struct.
+ * Look up `ident` as a field of that struct.
+ * Params:
+ *   e = evaluates to an instance of a struct
+ *   sc = context
+ *   id = identifier of a field in that struct
+ * Returns:
+ *   if successful `e.ident`
+ *   if not then `ErrorExp` and message is printed
+ */
+Expression fieldLookup(Expression e, Scope* sc, Identifier id)
+{
+    e = e.expressionSemantic(sc);
+    if (e.isErrorExp())
+        return e;
+
+    Dsymbol s;
+    auto t = e.type;
+    if (t.isTypePointer())
+    {
+        t = t.isTypePointer().next;
+        e = new PtrExp(e.loc, e);
+    }
+    if (auto ts = t.isTypeStruct())
+        s = ts.sym.search(e.loc, id, 0);
+    if (!s)
+    {
+        e.error("`%s` is not a member of `%s`", id.toChars(), t.toChars());
+        return ErrorExp.get();
+    }
+    Expression ef = new DotVarExp(e.loc, e, s.isDeclaration());
+    return ef.expressionSemantic(sc);
+}
+
+/****************************************
+ * C11 6.5.2.1-2
+ * Apply C semantics to `E[I]` expression.
+ * E1[E2] is lowered to *(E1 + E2)
+ * Params:
+ *      ae = ArrayExp to run semantics on
+ *      sc = context
+ * Returns:
+ *      Expression if this was a C expression with completed semantic, null if not
+ */
+Expression carraySemantic(ArrayExp ae, Scope* sc)
+{
+    if (!(sc.flags & SCOPE.Cfile))
+        return null;
+
+    auto e1 = ae.e1.expressionSemantic(sc);
+
+    assert(ae.arguments.length == 1);
+    Expression e2 = (*ae.arguments)[0];
+
+    /* CTFE cannot do pointer arithmetic, but it can index arrays.
+     * So, rewrite as an IndexExp if we can.
+     */
+    auto t1 = e1.type.toBasetype();
+    if (t1.isTypeDArray() || t1.isTypeSArray())
+    {
+        e2 = e2.expressionSemantic(sc).arrayFuncConv(sc);
+        return new IndexExp(ae.loc, e1, e2).expressionSemantic(sc);
+    }
+
+    e1 = e1.arrayFuncConv(sc);   // e1 might still be a function call
+    e2 = e2.expressionSemantic(sc);
+    auto t2 = e2.type.toBasetype();
+    if (t2.isTypeDArray() || t2.isTypeSArray())
+    {
+        return new IndexExp(ae.loc, e2, e1).expressionSemantic(sc); // swap operands
+    }
+
+    e2 = e2.arrayFuncConv(sc);
+    auto ep = new PtrExp(ae.loc, new AddExp(ae.loc, e1, e2));
+    return ep.expressionSemantic(sc);
+}
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index 45e101b903a..d036ee1635b 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -23,7 +23,7 @@  import dmd.globals;
 import dmd.hdrgen;
 import dmd.identifier;
 import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.tokens;
 import dmd.visitor;
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index ae8bde2ff57..5828486c6fe 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -31,6 +31,7 @@  import dmd.func;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
+import dmd.importc;
 import dmd.init;
 import dmd.mtype;
 import dmd.opover;
@@ -176,30 +177,35 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                             break;
                     }
                 }
-                else if (fieldi >= nfields)
+                if (j >= nfields)
                 {
-                    error(i.loc, "too many initializers for `%s`", sd.toChars());
+                    error(i.value[j].loc, "too many initializers for `%s`", sd.toChars());
                     return err();
                 }
 
                 VarDeclaration vd = sd.fields[fieldi];
                 if (elems[fieldi])
                 {
-                    error(i.loc, "duplicate initializer for field `%s`", vd.toChars());
+                    error(i.value[j].loc, "duplicate initializer for field `%s`", vd.toChars());
                     errors = true;
+                    elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+                    ++fieldi;
                     continue;
                 }
 
                 // Check for @safe violations
                 if (vd.type.hasPointers)
                 {
-                    if ((t.alignment() < target.ptrsize ||
+                    if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize ||
                          (vd.offset & (target.ptrsize - 1))) &&
                         sc.func && sc.func.setUnsafe())
                     {
-                        error(i.loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
+                        error(i.value[j].loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
                             sd.toChars(), vd.toChars());
                         errors = true;
+                        elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+                        ++fieldi;
+                        continue;
                     }
                 }
 
@@ -208,7 +214,7 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 {
                     if (vd.isOverlappedWith(v2) && elems[k])
                     {
-                        error(i.loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+                        error(elems[k].loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
                         errors = true;
                         continue;
                     }
@@ -222,6 +228,8 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 if (ex.op == TOK.error)
                 {
                     errors = true;
+                    elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
+                    ++fieldi;
                     continue;
                 }
 
@@ -363,10 +371,10 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             if (length > i.dim)
                 i.dim = length;
         }
-        if (t.ty == Tsarray)
+        if (auto tsa = t.isTypeSArray())
         {
-            uinteger_t edim = (cast(TypeSArray)t).dim.toInteger();
-            if (i.dim > edim)
+            uinteger_t edim = tsa.dim.toInteger();
+            if (i.dim > edim && !(tsa.isIncomplete() && (sc.flags & SCOPE.Cfile)))
             {
                 error(i.loc, "array initializer has %u elements, but array length is %llu", i.dim, edim);
                 return err();
@@ -398,6 +406,13 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         if (i.exp.op == TOK.error)
             return err();
         uint olderrors = global.errors;
+
+        /* ImportC: convert arrays to pointers, functions to pointers to functions
+         */
+        Type tb = t.toBasetype();
+        if (tb.isTypePointer())
+            i.exp = i.exp.arrayFuncConv(sc);
+
         /* Save the expression before ctfe
          * Otherwise the error message would contain for example "&[0][0]" instead of "new int"
          * Regression: https://issues.dlang.org/show_bug.cgi?id=21687
@@ -408,7 +423,7 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             // If the result will be implicitly cast, move the cast into CTFE
             // to avoid premature truncation of polysemous types.
             // eg real [] x = [1.1, 2.2]; should use real precision.
-            if (i.exp.implicitConvTo(t))
+            if (i.exp.implicitConvTo(t) && !(sc.flags & SCOPE.Cfile))
             {
                 i.exp = i.exp.implicitCastTo(sc, t);
             }
@@ -416,6 +431,11 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             {
                 return i;
             }
+            if (sc.flags & SCOPE.Cfile)
+                /* the interpreter turns (char*)"string" into &"string"[0] which then
+                 * it cannot interpret. Resolve that case by doing optimize() first
+                 */
+                i.exp = i.exp.optimize(WANTvalue);
             i.exp = i.exp.ctfeInterpret();
             if (i.exp.op == TOK.voidExpression)
                 error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
@@ -424,6 +444,7 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         {
             i.exp = i.exp.optimize(WANTvalue);
         }
+
         if (!global.gag && olderrors != global.errors)
         {
             return i; // Failed, suppress duplicate error messages
@@ -445,7 +466,6 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             i.exp.error("cannot use non-constant CTFE pointer in an initializer `%s`", currExp.toChars());
             return err();
         }
-        Type tb = t.toBasetype();
         Type ti = i.exp.type.toBasetype();
         if (i.exp.op == TOK.tuple && i.expandTuples && !i.exp.implicitConvTo(t))
         {
@@ -470,13 +490,12 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 goto L1;
             }
         }
-
         /* C11 6.7.9-14..15
          * Initialize an array of unknown size with a string.
-         * ImportC regards Tarray as an array of unknown size.
          * Change to static array of known size
          */
-        if (sc.flags & SCOPE.Cfile && i.exp.op == TOK.string_ && tb.ty == Tarray)
+        if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
+            tb.isTypeSArray() && tb.isTypeSArray().isIncomplete())
         {
             StringExp se = i.exp.isStringExp();
             auto ts = new TypeSArray(tb.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t));
@@ -683,8 +702,7 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         }
 
         auto tsa = t.isTypeSArray();
-        auto ta = t.isTypeDArray();
-        if (!(tsa || ta))
+        if (!tsa)
         {
             /* Not an array. See if it is `{ exp }` which can be
              * converted to an ExpInitializer
@@ -722,19 +740,32 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         {
             //printf(" type %s i %d dim %d dil.length = %d\n", t.toChars(), cast(int)i, cast(int)dim, cast(int)dil.length);
             auto tn = t.nextOf().toBasetype();
-            if (auto tna = tn.isTypeDArray())
+            auto tnsa = tn.isTypeSArray();
+            if (tnsa && tnsa.isIncomplete())
             {
                 // C11 6.2.5-20 "element type shall be complete whenever the array type is specified"
-                error(ci.loc, "incomplete element type `%s` not allowed", tna.toChars());
+                error(ci.loc, "incomplete element type `%s` not allowed", tnsa.toChars());
                 errors = true;
                 return 1;
             }
             if (i == dil.length)
                 return 0;
             size_t n;
-            auto tnsa = tn.isTypeSArray();
             const nelems = tnsa ? cast(size_t)tnsa.dim.toInteger() : 0;
 
+            /* Run initializerSemantic on a single element.
+             */
+            Initializer elem(Initializer ie)
+            {
+                ++i;
+                auto tnx = tn; // in case initializerSemantic tries to change it
+                ie = ie.initializerSemantic(sc, tnx, needInterpret);
+                if (ie.isErrorInitializer())
+                    errors = true;
+                assert(tnx == tn); // sub-types should not be modified
+                return ie;
+            }
+
             foreach (j; 0 .. dim)
             {
                 auto di = dil[i];
@@ -751,16 +782,17 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 }
                 else if (auto tns = tn.isTypeStruct())
                 {
-                    dil[n].initializer = structs(tns);
+                    if (di.initializer.isExpInitializer())
+                    {
+                        // no braces enclosing struct initializer
+                        dil[n].initializer = structs(tns);
+                    }
+                    else
+                        dil[n].initializer = elem(di.initializer);
                 }
                 else
                 {
-                    ++i;
-                    auto tnx = tn; // in case initializerSemantic tries to change it
-                    di.initializer = di.initializer.initializerSemantic(sc, tnx, needInterpret);
-                    if (di.initializer.isErrorInitializer())
-                        errors = true;
-                    assert(tnx == tn); // sub-types should not be modified
+                    di.initializer = elem(di.initializer);
                 }
                 ++n;
                 if (i == dil.length)
@@ -770,16 +802,16 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             return n;
         }
 
-        size_t dim = ta ? dil.length : cast(size_t)tsa.dim.toInteger();
-        auto n = array(t, dim);
+        size_t dim = tsa.isIncomplete() ? dil.length : cast(size_t)tsa.dim.toInteger();
+        auto newdim = array(t, dim);
 
         if (errors)
             return err();
 
-        if (ta) // array of unknown length
+        if (tsa.isIncomplete()) // array of unknown length
         {
             // Change to array of known length
-            tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, n, Type.tsize_t));
+            tsa = new TypeSArray(tn, new IntegerExp(Loc.initial, newdim, Type.tsize_t));
             tx = tsa;       // rewrite caller's type
             ci.type = tsa;  // remember for later passes
         }
@@ -799,6 +831,39 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             return err();
         }
 
+        /* If an array of simple elements, replace with an ArrayInitializer
+         */
+        auto tnb = tn.toBasetype();
+        if (!(tnb.isTypeSArray() || tnb.isTypeStruct()))
+        {
+            auto ai = new ArrayInitializer(ci.loc);
+            ai.dim = cast(uint) dil.length;
+            ai.index.setDim(dil.length);
+            ai.value.setDim(dil.length);
+            foreach (const j; 0 .. dil.length)
+            {
+                ai.index[j] = null;
+                ai.value[j] = dil[j].initializer;
+            }
+            auto ty = tx;
+            return ai.initializerSemantic(sc, ty, needInterpret);
+        }
+
+        if (newdim < ci.initializerList.length && tnb.isTypeStruct())
+        {
+            // https://issues.dlang.org/show_bug.cgi?id=22375
+            // initializerList can be bigger than the number of actual elements
+            // to initialize for array of structs because it is not required
+            // for values to have proper bracing.
+            // i.e: These are all valid initializers for `struct{int a,b;}[3]`:
+            //      {1,2,3,4}, {{1,2},3,4}, {1,2,{3,4}}, {{1,2},{3,4}}
+            // In all examples above, the new length of the initializer list
+            // has been shortened from four elements to two. This is important,
+            // because `dil` is written back to directly, making the lowered
+            // initializer `{{1,2},{3,4}}` and not `{{1,2},{3,4},3,4}`.
+            ci.initializerList.length = newdim;
+        }
+
         return ci;
     }
 
@@ -1263,6 +1328,3 @@  private bool hasNonConstPointers(Expression e)
     }
     return false;
 }
-
-
-
diff --git a/gcc/d/dmd/intrange.h b/gcc/d/dmd/intrange.h
deleted file mode 100644
index fd6153205c9..00000000000
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
index bfd31bc1d13..fef515071f9 100644
--- a/gcc/d/dmd/json.d
+++ b/gcc/d/dmd/json.d
@@ -33,7 +33,7 @@  import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.target;
@@ -794,8 +794,8 @@  public:
             property("init", d._init.toString());
         if (d.isField())
             property("offset", d.offset);
-        if (d.alignment && d.alignment != STRUCTALIGN_DEFAULT)
-            property("align", d.alignment);
+        if (!d.alignment.isUnknown() && !d.alignment.isDefault())
+            property("align", d.alignment.get());
         objectEnd();
     }
 
diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d
index d29bdc13806..44a6c066507 100644
--- a/gcc/d/dmd/lambdacomp.d
+++ b/gcc/d/dmd/lambdacomp.d
@@ -27,7 +27,7 @@  import dmd.expression;
 import dmd.func;
 import dmd.dmangle;
 import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.stringtable;
 import dmd.dscope;
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index afffc2dcf30..e2b4199b80a 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -26,8 +26,9 @@  import dmd.errors;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
+import dmd.root.array;
 import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.port;
 import dmd.root.rmem;
 import dmd.root.string;
@@ -229,6 +230,8 @@  class Lexer
     ubyte long_doublesize;      /// size of C long double, 8 or D real.sizeof
     ubyte wchar_tsize;          /// size of C wchar_t, 2 or 4
 
+    structalign_t packalign;    /// current state of #pragma pack alignment (ImportC)
+
     private
     {
         const(char)* base;      // pointer to start of buffer
@@ -242,6 +245,10 @@  class Lexer
         int lastDocLine;        // last line of previous doc comment
 
         Token* tokenFreelist;
+
+        // ImportC #pragma pack stack
+        Array!Identifier* records;      // identifers (or null)
+        Array!structalign_t* packs;     // parallel alignment values
     }
 
   nothrow:
@@ -273,6 +280,7 @@  class Lexer
         this.commentToken = commentToken;
         this.inTokenStringConstant = 0;
         this.lastDocLine = 0;
+        this.packalign.setDefault();
         //initKeywords();
         /* If first line starts with '#!', ignore the line
          */
@@ -1146,6 +1154,11 @@  class Lexer
                             poundLine(n, false);
                             continue;
                         }
+                        else if (n.ident == Id.__pragma && Ccompile)
+                        {
+                            pragmaDirective(scanloc);
+                            continue;
+                        }
                         else
                         {
                             const locx = loc();
@@ -2162,7 +2175,7 @@  class Lexer
             case '.':
                 if (p[1] == '.')
                     goto Ldone; // if ".."
-                if (base == 10 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
+                if (base <= 10 && n > 0 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
                     goto Ldone; // if ".identifier" or ".unicode"
                 if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80))
                     goto Ldone; // if ".identifier" or ".unicode"
@@ -2911,6 +2924,220 @@  class Lexer
             error(loc, "#line integer [\"filespec\"]\\n expected");
     }
 
+    /*********************************************
+     * C11 6.10.6 Pragma directive
+     * # pragma pp-tokens(opt) new-line
+     * The C preprocessor sometimes leaves pragma directives in
+     * the preprocessed output. Ignore them.
+     * Upon return, p is at start of next line.
+     */
+    private void pragmaDirective(const ref Loc loc)
+    {
+        Token n;
+        scan(&n);
+        if (n.value == TOK.identifier && n.ident == Id.pack)
+            return pragmaPack(loc);
+        skipToNextLine();
+    }
+
+    /*********
+     * ImportC
+     * # pragma pack
+     * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
+     * https://docs.microsoft.com/en-us/cpp/preprocessor/pack
+     * Scanner is on the `pack`
+     * Params:
+     *  startloc = location to use for error messages
+     */
+    private void pragmaPack(const ref Loc startloc)
+    {
+        const loc = startloc;
+        Token n;
+        scan(&n);
+        if (n.value != TOK.leftParenthesis)
+        {
+            error(loc, "left parenthesis expected to follow `#pragma pack`");
+            skipToNextLine();
+            return;
+        }
+
+        void closingParen()
+        {
+            if (n.value != TOK.rightParenthesis)
+            {
+                error(loc, "right parenthesis expected to close `#pragma pack(`");
+            }
+            skipToNextLine();
+        }
+
+        void setPackAlign(ref const Token t)
+        {
+            const n = t.unsvalue;
+            if (n < 1 || n & (n - 1) || ushort.max < n)
+                error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
+            packalign.set(cast(uint)n);
+            packalign.setPack(true);
+        }
+
+        scan(&n);
+
+        if (!records)
+        {
+            records = new Array!Identifier;
+            packs = new Array!structalign_t;
+        }
+
+        /* # pragma pack ( show )
+         */
+        if (n.value == TOK.identifier && n.ident == Id.show)
+        {
+            if (packalign.isDefault())
+                warning(startloc, "current pack attribute is default");
+            else
+                warning(startloc, "current pack attribute is %d", packalign.get());
+            scan(&n);
+            return closingParen();
+        }
+        /* # pragma pack ( push )
+         * # pragma pack ( push , identifier )
+         * # pragma pack ( push , integer )
+         * # pragma pack ( push , identifier , integer )
+         */
+        if (n.value == TOK.identifier && n.ident == Id.push)
+        {
+            scan(&n);
+            Identifier record = null;
+            if (n.value == TOK.comma)
+            {
+                scan(&n);
+                if (n.value == TOK.identifier)
+                {
+                    record = n.ident;
+                    scan(&n);
+                    if (n.value == TOK.comma)
+                    {
+                        scan(&n);
+                        if (n.value == TOK.int32Literal)
+                        {
+                            setPackAlign(n);
+                            scan(&n);
+                        }
+                        else
+                            error(loc, "alignment value expected, not `%s`", n.toChars());
+                    }
+                }
+                else if (n.value == TOK.int32Literal)
+                {
+                    setPackAlign(n);
+                    scan(&n);
+                }
+                else
+                    error(loc, "alignment value expected, not `%s`", n.toChars());
+            }
+            this.records.push(record);
+            this.packs.push(packalign);
+            return closingParen();
+        }
+        /* # pragma pack ( pop )
+         * # pragma pack ( pop PopList )
+         * PopList :
+         *    , IdentifierOrInteger
+         *    , IdentifierOrInteger PopList
+         * IdentifierOrInteger:
+         *      identifier
+         *      integer
+         */
+        if (n.value == TOK.identifier && n.ident == Id.pop)
+        {
+            scan(&n);
+            while (n.value == TOK.comma)
+            {
+                scan(&n);
+                if (n.value == TOK.identifier)
+                {
+                    for (size_t len = this.records.length; len; --len)
+                    {
+                        if ((*this.records)[len - 1] == n.ident)
+                        {
+                            packalign = (*this.packs)[len - 1];
+                            this.records.setDim(len - 1);
+                            this.packs.setDim(len - 1);
+                            break;
+                        }
+                    }
+                    scan(&n);
+                }
+                else if (n.value == TOK.int32Literal)
+                {
+                    setPackAlign(n);
+                    this.records.push(null);
+                    this.packs.push(packalign);
+                    scan(&n);
+                }
+            }
+            return closingParen();
+        }
+        /* # pragma pack ( integer )
+         */
+        if (n.value == TOK.int32Literal)
+        {
+            setPackAlign(n);
+            scan(&n);
+            return closingParen();
+        }
+        /* # pragma pack ( )
+         */
+        if (n.value == TOK.rightParenthesis)
+        {
+            packalign.setDefault();
+            return closingParen();
+        }
+
+        error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
+        skipToNextLine();
+    }
+
+    /***************************************
+     * Scan forward to start of next line.
+     */
+    private void skipToNextLine()
+    {
+        while (1)
+        {
+            switch (*p)
+            {
+            case 0:
+            case 0x1A:
+                return; // do not advance p
+
+            case '\n':
+                ++p;
+                break;
+
+            case '\r':
+                ++p;
+                if (p[0] == '\n')
+                   ++p;
+                break;
+
+            default:
+                if (*p & 0x80)
+                {
+                    const u = decodeUTF();
+                    if (u == PS || u == LS)
+                    {
+                        ++p;
+                        break;
+                    }
+                }
+                ++p;
+                continue;
+            }
+            break;
+        }
+        endOfLine();
+    }
+
     /********************************************
      * Decode UTF character.
      * Issue error messages for invalid sequences.
@@ -3106,8 +3333,10 @@  class Lexer
         return p;
     }
 
-private:
-    void endOfLine() pure @nogc @safe
+    /**************************
+     * `p` should be at start of next line
+     */
+    private void endOfLine() pure @nogc @safe
     {
         scanloc.linnum++;
         line = p;
diff --git a/gcc/d/dmd/lexer.h b/gcc/d/dmd/lexer.h
deleted file mode 100644
index b36e7f7bdaf..00000000000
diff --git a/gcc/d/dmd/macro.h b/gcc/d/dmd/macro.h
deleted file mode 100644
index 80ec36e00e6..00000000000
diff --git a/gcc/d/dmd/mars.h b/gcc/d/dmd/mars.h
deleted file mode 100644
index 9b9c278c8a7..00000000000
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index 969290c476c..fe4c73a021c 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -119,7 +119,7 @@  public:
 
     static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen);
 
-    static Module *load(Loc loc, Identifiers *packages, Identifier *ident);
+    static Module *load(const Loc &loc, Identifiers *packages, Identifier *ident);
 
     const char *kind() const;
     bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise.
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 80e47918f2d..a21924b3aac 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -43,7 +43,7 @@  import dmd.identifier;
 import dmd.init;
 import dmd.opover;
 import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.rootobject;
 import dmd.root.stringtable;
@@ -237,6 +237,7 @@  enum DotExpFlag
 {
     gag     = 1,    // don't report "not a property" error and just return null
     noDeref = 2,    // the use of the expression will not attempt a dereference
+    noAliasThis = 4, // don't do 'alias this' resolution
 }
 
 /// Result of a check whether two types are covariant
@@ -426,6 +427,13 @@  extern (C++) abstract class Type : ASTNode
         return DYNCAST.type;
     }
 
+    /// Returns a non-zero unique ID for this Type, or returns 0 if the Type does not (yet) have a unique ID.
+    /// If `semantic()` has not been run, 0 is returned.
+    final size_t getUniqueID() const
+    {
+        return cast(size_t) deco;
+    }
+
     extern (D)
     final Mcache* getMcache()
     {
@@ -2298,7 +2306,9 @@  extern (C++) abstract class Type : ASTNode
      */
     structalign_t alignment()
     {
-        return STRUCTALIGN_DEFAULT;
+        structalign_t s;
+        s.setDefault();
+        return s;
     }
 
     /***************************************
@@ -3532,6 +3542,13 @@  extern (C++) final class TypeSArray : TypeArray
         this.dim = dim;
     }
 
+    extern (D) this(Type t)  // for incomplete type
+    {
+        super(Tsarray, t);
+        //printf("TypeSArray()\n");
+        this.dim = new IntegerExp(0);
+    }
+
     override const(char)* kind() const
     {
         return "sarray";
@@ -3546,6 +3563,15 @@  extern (C++) final class TypeSArray : TypeArray
         return result;
     }
 
+    /***
+     * C11 6.7.6.2-4 incomplete array type
+     * Returns: true if incomplete type
+     */
+    bool isIncomplete()
+    {
+        return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0;
+    }
+
     override d_uns64 size(const ref Loc loc)
     {
         //printf("TypeSArray::size()\n");
@@ -3952,65 +3978,37 @@  extern (C++) final class TypePointer : TypeNext
         if (equals(to))
             return MATCH.exact;
 
-        if (next.ty == Tfunction)
-        {
-            if (auto tp = to.isTypePointer())
-            {
-                if (tp.next.ty == Tfunction)
-                {
-                    if (next.equals(tp.next))
-                        return MATCH.constant;
-
-                    if (next.covariant(tp.next) == Covariant.yes)
-                    {
-                        Type tret = this.next.nextOf();
-                        Type toret = tp.next.nextOf();
-                        if (tret.ty == Tclass && toret.ty == Tclass)
-                        {
-                            /* https://issues.dlang.org/show_bug.cgi?id=10219
-                             * Check covariant interface return with offset tweaking.
-                             * interface I {}
-                             * class C : Object, I {}
-                             * I function() dg = function C() {}    // should be error
-                             */
-                            int offset = 0;
-                            if (toret.isBaseOf(tret, &offset) && offset != 0)
-                                return MATCH.nomatch;
-                        }
-                        return MATCH.convert;
-                    }
-                }
-                else if (tp.next.ty == Tvoid)
-                {
-                    // Allow conversions to void*
-                    return MATCH.convert;
-                }
-            }
+        // Only convert between pointers
+        auto tp = to.isTypePointer();
+        if (!tp)
             return MATCH.nomatch;
-        }
-        else if (auto tp = to.isTypePointer())
+
+        assert(this.next);
+        assert(tp.next);
+
+        // Conversion to void*
+        if (tp.next.ty == Tvoid)
         {
-            assert(tp.next);
+            // Function pointer conversion doesn't check constness?
+            if (this.next.ty == Tfunction)
+                return MATCH.convert;
 
             if (!MODimplicitConv(next.mod, tp.next.mod))
                 return MATCH.nomatch; // not const-compatible
 
-            /* Alloc conversion to void*
-             */
-            if (next.ty != Tvoid && tp.next.ty == Tvoid)
-            {
-                return MATCH.convert;
-            }
-
-            MATCH m = next.constConv(tp.next);
-            if (m > MATCH.nomatch)
-            {
-                if (m == MATCH.exact && mod != to.mod)
-                    m = MATCH.constant;
-                return m;
-            }
+            return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
         }
-        return MATCH.nomatch;
+
+        // Conversion between function pointers
+        if (auto thisTf = this.next.isTypeFunction())
+            return thisTf.implicitPointerConv(tp.next);
+
+        // Default, no implicit conversion between the pointer targets
+        MATCH m = next.constConv(tp.next);
+
+        if (m == MATCH.exact && mod != to.mod)
+            m = MATCH.constant;
+        return m;
     }
 
     override MATCH constConv(Type to)
@@ -4760,7 +4758,10 @@  extern (C++) final class TypeFunction : TypeNext
                             }
                         }
                         else
-                            m = arg.implicitConvTo(tprm);
+                        {
+                            import dmd.dcast : cimplicitConvTo;
+                            m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
+                        }
                     }
                     //printf("match %d\n", m);
                 }
@@ -4971,6 +4972,47 @@  extern (C++) final class TypeFunction : TypeNext
         return MATCH.nomatch;
     }
 
+    /+
+     + Checks whether this function type is convertible to ` to`
+     + when used in a function pointer / delegate.
+     +
+     + Params:
+     +   to = target type
+     +
+     + Returns:
+     +   MATCH.nomatch: `to` is not a covaraint function
+     +   MATCH.convert: `to` is a covaraint function
+     +   MATCH.exact:   `to` is identical to this function
+     +/
+    private MATCH implicitPointerConv(Type to)
+    {
+        assert(to);
+
+        if (this == to)
+            return MATCH.constant;
+
+        if (this.covariant(to) == Covariant.yes)
+        {
+            Type tret = this.nextOf();
+            Type toret = to.nextOf();
+            if (tret.ty == Tclass && toret.ty == Tclass)
+            {
+                /* https://issues.dlang.org/show_bug.cgi?id=10219
+                 * Check covariant interface return with offset tweaking.
+                 * interface I {}
+                 * class C : Object, I {}
+                 * I function() dg = function C() {}    // should be error
+                 */
+                int offset = 0;
+                if (toret.isBaseOf(tret, &offset) && offset != 0)
+                    return MATCH.nomatch;
+            }
+            return MATCH.convert;
+        }
+
+        return MATCH.nomatch;
+    }
+
     /** Extends TypeNext.constConv by also checking for matching attributes **/
     override MATCH constConv(Type to)
     {
@@ -5262,27 +5304,16 @@  extern (C++) final class TypeDelegate : TypeNext
         if (this == to)
             return MATCH.exact;
 
-        version (all)
+        if (auto toDg = to.isTypeDelegate())
         {
-            // not allowing covariant conversions because it interferes with overriding
-            if (to.ty == Tdelegate && this.nextOf().covariant(to.nextOf()) == Covariant.yes)
-            {
-                Type tret = this.next.nextOf();
-                Type toret = (cast(TypeDelegate)to).next.nextOf();
-                if (tret.ty == Tclass && toret.ty == Tclass)
-                {
-                    /* https://issues.dlang.org/show_bug.cgi?id=10219
-                     * Check covariant interface return with offset tweaking.
-                     * interface I {}
-                     * class C : Object, I {}
-                     * I delegate() dg = delegate C() {}    // should be error
-                     */
-                    int offset = 0;
-                    if (toret.isBaseOf(tret, &offset) && offset != 0)
-                        return MATCH.nomatch;
-                }
-                return MATCH.convert;
-            }
+            MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next);
+
+            // Retain the old behaviour for this refactoring
+            // Should probably be changed to constant to match function pointers
+            if (m > MATCH.convert)
+                m = MATCH.convert;
+
+            return m;
         }
 
         return MATCH.nomatch;
@@ -5516,6 +5547,11 @@  extern (C++) final class TypeIdentifier : TypeQualified
         this.ident = ident;
     }
 
+    static TypeIdentifier create(const ref Loc loc, Identifier ident)
+    {
+        return new TypeIdentifier(loc, ident);
+    }
+
     override const(char)* kind() const
     {
         return "identifier";
@@ -5737,7 +5773,7 @@  extern (C++) final class TypeStruct : Type
 
     override structalign_t alignment()
     {
-        if (sym.alignment == 0)
+        if (sym.alignment.isUnknown())
             sym.size(sym.loc);
         return sym.alignment;
     }
@@ -6519,6 +6555,29 @@  extern (C++) final class TypeTuple : Type
         return false;
     }
 
+    override MATCH implicitConvTo(Type to)
+    {
+        if (this == to)
+            return MATCH.exact;
+        if (auto tt = to.isTypeTuple())
+        {
+            if (arguments.dim == tt.arguments.dim)
+            {
+                MATCH m = MATCH.exact;
+                for (size_t i = 0; i < tt.arguments.dim; i++)
+                {
+                    Parameter arg1 = (*arguments)[i];
+                    Parameter arg2 = (*tt.arguments)[i];
+                    MATCH mi = arg1.type.implicitConvTo(arg2.type);
+                    if (mi < m)
+                        m = mi;
+                }
+                return m;
+            }
+        }
+        return MATCH.nomatch;
+    }
+
     override void accept(Visitor v)
     {
         v.visit(this);
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index cdf221f55f7..430b39b205c 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -224,6 +224,7 @@  public:
     bool equivalent(Type *t);
     // kludge for template.isType()
     DYNCAST dyncast() const { return DYNCAST_TYPE; }
+    size_t getUniqueID() const;
     Covariant covariant(Type *t, StorageClass *pstc = NULL);
     const char *toChars() const;
     char *toPrettyChars(bool QualifyTypes = false);
@@ -446,6 +447,7 @@  public:
 
     const char *kind();
     TypeSArray *syntaxCopy();
+    bool isIncomplete();
     d_uns64 size(const Loc &loc);
     unsigned alignsize();
     bool isString();
@@ -582,6 +584,7 @@  struct ParameterList
     Parameters* parameters;
     StorageClass stc;
     VarArg varargs;
+    bool hasIdentifierList; // true if C identifier-list style
 
     size_t length();
     Parameter *operator[](size_t i) { return Parameter::getNth(parameters, i); }
@@ -711,6 +714,7 @@  public:
     Identifier *ident;
     Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution
 
+    static TypeIdentifier *create(const Loc &loc, Identifier *ident);
     const char *kind();
     TypeIdentifier *syntaxCopy();
     Dsymbol *toDsymbol(Scope *sc);
diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d
index 7719ccfe297..605e9f3bfdd 100644
--- a/gcc/d/dmd/ob.d
+++ b/gcc/d/dmd/ob.d
@@ -43,7 +43,7 @@  import dmd.tokens;
 import dmd.visitor;
 
 import dmd.root.bitarray;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 
 /**********************************
  * Perform ownership/borrowing checks for funcdecl.
diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d
index 85e371e6e63..eb4ba1db20d 100644
--- a/gcc/d/dmd/objc.d
+++ b/gcc/d/dmd/objc.d
@@ -38,7 +38,7 @@  import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
 import dmd.root.array;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.stringtable;
 import dmd.target;
 import dmd.tokens;
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index 4ef55f3acc9..ff03a6e0d3c 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -213,9 +213,13 @@  private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE
     if (isRecursiveAliasThis(e.att1, e.e1.type))
         return null;
     //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
-    Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident);
     BinExp be = cast(BinExp)e.copy();
-    be.e1 = e1;
+    // Resolve 'alias this' but in case of assigment don't resolve properties yet
+    // because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2'
+    bool findOnly = (e.op == TOK.assign);
+    be.e1 = resolveAliasThis(sc, e.e1, true, findOnly);
+    if (!be.e1)
+        return null;
 
     Expression result;
     if (be.op == TOK.concatenateAssign)
@@ -237,9 +241,10 @@  private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
     if (isRecursiveAliasThis(e.att2, e.e2.type))
         return null;
     //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
-    Expression e2 = new DotIdExp(e.loc, e.e2, ad.aliasthis.ident);
     BinExp be = cast(BinExp)e.copy();
-    be.e2 = e2;
+    be.e2 = resolveAliasThis(sc, e.e2, true);
+    if (!be.e2)
+        return null;
 
     Expression result;
     if (be.op == TOK.concatenateAssign)
@@ -1744,11 +1749,31 @@  private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration f
         else if (m == match && m > MATCH.nomatch)
         {
             assert(fd_best);
-            /* Ignore covariant matches, as later on it can be redone
-             * after the opApply delegate has its attributes inferred.
-             */
-            if (tf.covariant(fd_best.type) != Covariant.yes &&
-                fd_best.type.covariant(tf) != Covariant.yes)
+            auto bestTf = fd_best.type.isTypeFunction();
+            assert(bestTf);
+
+            // Found another overload with different attributes?
+            // e.g. @system vs. @safe opApply
+            bool ambig = tf.attributesEqual(bestTf);
+
+            // opApplies with identical attributes could still accept
+            // different function bodies as delegate
+            // => different parameters or attributes
+            if (ambig)
+            {
+                // Fetch the delegates that receive the function body
+                auto tfBody = tf.parameterList[0].type.isTypeDelegate().next;
+                assert(tfBody);
+
+                auto bestBody = bestTf.parameterList[0].type.isTypeDelegate().next;
+                assert(bestBody);
+
+                // Ignore covariant matches, as later on it can be redone
+                // after the opApply delegate has its attributes inferred.
+                ambig = !(tfBody.covariant(bestBody) == Covariant.yes || bestBody.covariant(tfBody) == Covariant.yes);
+            }
+
+            if (ambig)
                 fd_ambig = f;                           // not covariant, so ambiguous
         }
         return 0;               // continue
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 3ae30619a20..9f116fe8509 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -697,6 +697,8 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                 // See if we can remove an unnecessary cast
                 ClassDeclaration cdfrom = e.e1.type.isClassHandle();
                 ClassDeclaration cdto = e.type.isClassHandle();
+                if (cdfrom.errors || cdto.errors)
+                    return error();
                 if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
                     goto L1;    // can always convert a class to Object
                 // Need to determine correct offset before optimizing away the cast.
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 21042dd80ea..f00ceb6cc93 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -22,7 +22,7 @@  import dmd.identifier;
 import dmd.lexer;
 import dmd.errors;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.rootobject;
 import dmd.root.string;
@@ -556,6 +556,9 @@  class Parser(AST) : Lexer
                     {
                     case TOK.leftParenthesis:
                         {
+                            // MixinType
+                            if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
+                                goto Ldeclaration;
                             // mixin(string)
                             nextToken();
                             auto exps = parseArguments();
@@ -2954,6 +2957,8 @@  class Parser(AST) : Lexer
                         // Don't call nextToken again.
                     }
                 case TOK.in_:
+                    if (global.params.vin)
+                        message(scanloc, "Usage of 'in' on parameter");
                     stc = STC.in_;
                     goto L2;
 
@@ -5408,6 +5413,11 @@  class Parser(AST) : Lexer
                     stc = STC.scope_;
                     goto Lagain;
 
+                case TOK.out_:
+                    error("cannot declare `out` loop variable, use `ref` instead");
+                    stc = STC.out_;
+                    goto Lagain;
+
                 case TOK.enum_:
                     stc = STC.manifest;
                     goto Lagain;
diff --git a/gcc/d/dmd/parse.h b/gcc/d/dmd/parse.h
deleted file mode 100644
index a2ad47882ef..00000000000
diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d
index 3f12b173357..414d6f665f5 100644
--- a/gcc/d/dmd/printast.d
+++ b/gcc/d/dmd/printast.d
@@ -59,7 +59,7 @@  extern (C++) final class PrintASTVisitor : Visitor
         printIndent(indent);
 
         import dmd.hdrgen : floatToBuffer;
-        import dmd.root.outbuffer : OutBuffer;
+        import dmd.common.outbuffer : OutBuffer;
         OutBuffer buf;
         floatToBuffer(e.type, e.value, &buf, false);
         printf("Real %s %s\n", buf.peekChars(), e.type ? e.type.toChars() : "");
diff --git a/gcc/d/dmd/root/README.md b/gcc/d/dmd/root/README.md
index 539b940d6fb..e062d93da46 100644
--- a/gcc/d/dmd/root/README.md
+++ b/gcc/d/dmd/root/README.md
@@ -11,7 +11,6 @@ 
 | [hash.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/hash.d)               | Calculate a hash for a byte array                                                          |
 | [longdouble.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/longdouble.d)   | 80-bit floating point number implementation in case they are not natively supported        |
 | [man.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/man.d)                 | Opens an online manual page                                                                |
-| [outbuffer.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/outbuffer.d)     | An expandable buffer in which you can write text or binary data.                           |
 | [port.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d)               | Portable routines for functions that have different implementations on different platforms |
 | [region.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/region.d)           | A region allocator                                                                         |
 | [response.d](https://github.com/dlang/dmd/blob/master/src/dmd/root/response.d)       | Parse command line arguments from response files                                           |
diff --git a/gcc/d/dmd/root/aav.h b/gcc/d/dmd/root/aav.h
deleted file mode 100644
index c65b674a7f5..00000000000
diff --git a/gcc/d/dmd/root/checkedint.h b/gcc/d/dmd/root/checkedint.h
deleted file mode 100644
index 8a7d9c90d9f..00000000000
diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d
index ef6056cfed0..64e95716322 100644
--- a/gcc/d/dmd/root/file.d
+++ b/gcc/d/dmd/root/file.d
@@ -23,410 +23,8 @@  import dmd.root.filename;
 import dmd.root.rmem;
 import dmd.root.string;
 
-/**
-Encapsulated management of a memory-mapped file.
-
-Params:
-Datum = the mapped data type: Use a POD of size 1 for read/write mapping
-and a `const` version thereof for read-only mapping. Other primitive types
-should work, but have not been yet tested.
-*/
-struct FileMapping(Datum)
-{
-    static assert(__traits(isPOD, Datum) && Datum.sizeof == 1,
-        "Not tested with other data types yet. Add new types with care.");
-
-    version(Posix) enum invalidHandle = -1;
-    else version(Windows) enum invalidHandle = INVALID_HANDLE_VALUE;
-
-    // state {
-    /// Handle of underlying file
-    private auto handle = invalidHandle;
-    /// File mapping object needed on Windows
-    version(Windows) private HANDLE fileMappingObject = invalidHandle;
-    /// Memory-mapped array
-    private Datum[] data;
-    /// Name of underlying file, zero-terminated
-    private const(char)* name;
-    // state }
-
-    /**
-    Open `filename` and map it in memory. If `Datum` is `const`, opens for
-    read-only and maps the content in memory; no error is issued if the file
-    does not exist. This makes it easy to treat a non-existing file as empty.
-
-    If `Datum` is mutable, opens for read/write (creates file if it does not
-    exist) and fails fatally on any error.
-
-    Due to quirks in `mmap`, if the file is empty, `handle` is valid but `data`
-    is `null`. This state is valid and accounted for.
-
-    Params:
-    filename = the name of the file to be mapped in memory
-    */
-    this(const char* filename)
-    {
-        version (Posix)
-        {
-            import core.sys.posix.sys.mman;
-            import core.sys.posix.fcntl;
-
-            handle = .open(filename, is(Datum == const) ? O_RDONLY : (O_CREAT | O_RDWR),
-                S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-            if (handle == invalidHandle)
-            {
-                static if (is(Datum == const))
-                {
-                    // No error, nonexisting file in read mode behaves like an empty file.
-                    return;
-                }
-                else
-                {
-                    fprintf(stderr, "open(\"%s\") failed: %s\n", filename, strerror(errno));
-                    exit(1);
-                }
-            }
-
-            const size = File.size(handle);
-
-            if (size > 0 && size != ulong.max && size <= size_t.max)
-            {
-                auto p = mmap(null, cast(size_t) size, is(Datum == const) ? PROT_READ : PROT_WRITE, MAP_SHARED, handle, 0);
-                if (p == MAP_FAILED)
-                {
-                    fprintf(stderr, "mmap(null, %zu) for \"%s\" failed: %s\n", cast(size_t) size, filename, strerror(errno));
-                    exit(1);
-                }
-                // The cast below will always work because it's gated by the `size <= size_t.max` condition.
-                data = cast(Datum[]) p[0 .. cast(size_t) size];
-            }
-        }
-        else version(Windows)
-        {
-            static if (is(Datum == const))
-            {
-                enum createFileMode = GENERIC_READ;
-                enum openFlags = OPEN_EXISTING;
-            }
-            else
-            {
-                enum createFileMode = GENERIC_READ | GENERIC_WRITE;
-                enum openFlags = CREATE_ALWAYS;
-            }
-
-            handle = CreateFileA(filename, createFileMode, 0, null, openFlags, FILE_ATTRIBUTE_NORMAL, null);
-            if (handle == invalidHandle)
-            {
-                static if (is(Datum == const))
-                {
-                    return;
-                }
-                else
-                {
-                    fprintf(stderr, "CreateFileA() failed for \"%s\": %d\n", filename, GetLastError());
-                    exit(1);
-                }
-            }
-            createMapping(filename, File.size(handle));
-        }
-        else static assert(0);
-
-        // Save the name for later. Technically there's no need: on Linux one can use readlink on /proc/self/fd/NNN.
-        // On BSD and OSX one can use fcntl with F_GETPATH. On Windows one can use GetFileInformationByHandleEx.
-        // But just saving the name is simplest, fastest, and most portable...
-        import core.stdc.string : strlen;
-        name = filename[0 .. filename.strlen() + 1].idup.ptr;
-    }
-
-    /**
-    Common code factored opportunistically. Windows only. Assumes `handle` is
-    already pointing to an opened file. Initializes the `fileMappingObject`
-    and `data` members.
-
-    Params:
-    filename = the file to be mapped
-    size = the size of the file in bytes
-    */
-    version(Windows) private void createMapping(const char* filename, ulong size)
-    {
-        assert(size <= size_t.max || size == ulong.max);
-        assert(handle != invalidHandle);
-        assert(data is null);
-        assert(fileMappingObject == invalidHandle);
-
-        if (size == 0 || size == ulong.max)
-            return;
-
-        static if (is(Datum == const))
-        {
-            enum fileMappingFlags = PAGE_READONLY;
-            enum mapViewFlags = FILE_MAP_READ;
-        }
-        else
-        {
-            enum fileMappingFlags = PAGE_READWRITE;
-            enum mapViewFlags = FILE_MAP_WRITE;
-        }
-
-        fileMappingObject = CreateFileMappingA(handle, null, fileMappingFlags, 0, 0, null);
-        if (!fileMappingObject)
-        {
-            fprintf(stderr, "CreateFileMappingA(%p) failed for %llu bytes of \"%s\": %d\n",
-                handle, size, filename, GetLastError());
-            fileMappingObject = invalidHandle;  // by convention always use invalidHandle, not null
-            exit(1);
-        }
-        auto p = MapViewOfFile(fileMappingObject, mapViewFlags, 0, 0, 0);
-        if (!p)
-        {
-            fprintf(stderr, "MapViewOfFile() failed for \"%s\": %d\n", filename, GetLastError());
-            exit(1);
-        }
-        data = cast(Datum[]) p[0 .. cast(size_t) size];
-    }
-
-    // Not copyable or assignable (for now).
-    @disable this(const FileMapping!Datum rhs);
-    @disable void opAssign(const ref FileMapping!Datum rhs);
-
-    /**
-    Frees resources associated with this mapping. However, it does not deallocate the name.
-    */
-    ~this() pure nothrow
-    {
-        if (!active)
-            return;
-        fakePure({
-            version (Posix)
-            {
-                import core.sys.posix.sys.mman : munmap;
-
-                // Cannot call fprintf from inside a destructor, so exiting silently.
-
-                if (data.ptr && munmap(cast(void*) data.ptr, data.length) != 0)
-                {
-                    exit(1);
-                }
-                data = null;
-                if (handle != invalidHandle && .close(handle) != 0)
-                {
-                    exit(1);
-                }
-                handle = invalidHandle;
-            }
-            else version(Windows)
-            {
-                if (data.ptr !is null && UnmapViewOfFile(cast(void*) data.ptr) == 0)
-                {
-                    exit(1);
-                }
-                data = null;
-                if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
-                {
-                    exit(1);
-                }
-                fileMappingObject = invalidHandle;
-                if (handle != invalidHandle && CloseHandle(handle) == 0)
-                {
-                    exit(1);
-                }
-                handle = invalidHandle;
-            }
-            else static assert(0);
-        });
-    }
-
-    /**
-    Returns the zero-terminated file name associated with the mapping. Can
-    be saved beyond the lifetime of `this`.
-    */
-    const(char)* filename() const pure @nogc @safe nothrow { return name; }
-
-    /**
-    Frees resources associated with this mapping. However, it does not deallocate the name.
-    Reinitializes `this` as a fresh object that can be reused.
-    */
-    void close()
-    {
-        __dtor();
-        handle = invalidHandle;
-        version(Windows) fileMappingObject = invalidHandle;
-        data = null;
-        name = null;
-    }
-
-    /**
-    Deletes the underlying file and frees all resources associated.
-    Reinitializes `this` as a fresh object that can be reused.
-
-    This function does not abort if the file cannot be deleted, but does print
-    a message on `stderr` and returns `false` to the caller. The underlying
-    rationale is to give the caller the option to continue execution if
-    deleting the file is not important.
-
-    Returns: `true` iff the file was successfully deleted. If the file was not
-    deleted, prints a message to `stderr` and returns `false`.
-    */
-    static if (!is(Datum == const))
-    bool discard()
-    {
-        // Truncate file to zero so unflushed buffers are not flushed unnecessarily.
-        resize(0);
-        auto deleteme = name;
-        close();
-        // In-memory resource freed, now get rid of the underlying temp file.
-        version(Posix)
-        {
-            import core.sys.posix.unistd;
-            if (unlink(deleteme) != 0)
-            {
-                fprintf(stderr, "unlink(\"%s\") failed: %s\n", filename, strerror(errno));
-                return false;
-            }
-        }
-        else version(Windows)
-        {
-            import core.sys.windows.winbase;
-            if (DeleteFileA(deleteme) == 0)
-            {
-                fprintf(stderr, "DeleteFileA error %d\n", GetLastError());
-                return false;
-            }
-        }
-        else static assert(0);
-        return true;
-    }
-
-    /**
-    Queries whether `this` is currently associated with a file.
-
-    Returns: `true` iff there is an active mapping.
-    */
-    bool active() const pure @nogc nothrow
-    {
-        return handle !is invalidHandle;
-    }
-
-    /**
-    Queries the length of the file associated with this mapping.  If not
-    active, returns 0.
-
-    Returns: the length of the file, or 0 if no file associated.
-    */
-    size_t length() const pure @nogc @safe nothrow { return data.length; }
-
-    /**
-    Get a slice to the contents of the entire file.
-
-    Returns: the contents of the file. If not active, returns the `null` slice.
-    */
-    auto opSlice() pure @nogc @safe nothrow { return data; }
-
-    /**
-    Resizes the file and mapping to the specified `size`.
-
-    Params:
-    size = new length requested
-    */
-    static if (!is(Datum == const))
-    void resize(size_t size) pure
-    {
-        assert(handle != invalidHandle);
-        fakePure({
-            version(Posix)
-            {
-                import core.sys.posix.unistd : ftruncate;
-                import core.sys.posix.sys.mman;
-
-                if (data.length)
-                {
-                    assert(data.ptr, "Corrupt memory mapping");
-                    // assert(0) here because it would indicate an internal error
-                    munmap(cast(void*) data.ptr, data.length) == 0 || assert(0);
-                    data = null;
-                }
-                if (ftruncate(handle, size) != 0)
-                {
-                    fprintf(stderr, "ftruncate() failed for \"%s\": %s\n", filename, strerror(errno));
-                    exit(1);
-                }
-                if (size > 0)
-                {
-                    auto p = mmap(null, size, PROT_WRITE, MAP_SHARED, handle, 0);
-                    if (cast(ssize_t) p == -1)
-                    {
-                        fprintf(stderr, "mmap() failed for \"%s\": %s\n", filename, strerror(errno));
-                        exit(1);
-                    }
-                    data = cast(Datum[]) p[0 .. size];
-                }
-            }
-            else version(Windows)
-            {
-                // Per documentation, must unmap first.
-                if (data.length > 0 && UnmapViewOfFile(cast(void*) data.ptr) == 0)
-                {
-                    fprintf(stderr, "UnmapViewOfFile(%p) failed for memory mapping of \"%s\": %d\n",
-                        data.ptr, filename, GetLastError());
-                    exit(1);
-                }
-                data = null;
-                if (fileMappingObject != invalidHandle && CloseHandle(fileMappingObject) == 0)
-                {
-                    fprintf(stderr, "CloseHandle() failed for memory mapping of \"%s\": %d\n", filename, GetLastError());
-                    exit(1);
-                }
-                fileMappingObject = invalidHandle;
-                LARGE_INTEGER biggie;
-                biggie.QuadPart = size;
-                if (SetFilePointerEx(handle, biggie, null, FILE_BEGIN) == 0 || SetEndOfFile(handle) == 0)
-                {
-                    fprintf(stderr, "SetFilePointer() failed for \"%s\": %d\n", filename, GetLastError());
-                    exit(1);
-                }
-                createMapping(name, size);
-            }
-            else static assert(0);
-        });
-    }
-
-    /**
-    Unconditionally and destructively moves the underlying file to `filename`.
-    If the operation succeds, returns true. Upon failure, prints a message to
-    `stderr` and returns `false`.
-
-    Params: filename = zero-terminated name of the file to move to.
-
-    Returns: `true` iff the operation was successful.
-    */
-    bool moveToFile(const char* filename)
-    {
-        auto oldname = name;
-
-        close();
-        // Rename the underlying file to the target, no copy necessary.
-        version(Posix)
-        {
-            if (.rename(oldname, filename) != 0)
-            {
-                fprintf(stderr, "rename(\"%s\", \"%s\") failed: %s\n", oldname, filename, strerror(errno));
-                return false;
-            }
-        }
-        else version(Windows)
-        {
-            import core.sys.windows.winbase;
-            if (MoveFileExA(oldname, filename, MOVEFILE_REPLACE_EXISTING) == 0)
-            {
-                fprintf(stderr, "MoveFileExA(\"%s\", \"%s\") failed: %d\n", oldname, filename, GetLastError());
-                return false;
-            }
-        }
-        else static assert(0);
-        return true;
-    }
-}
+import dmd.common.file;
+import dmd.common.string;
 
 /// Owns a (rmem-managed) file buffer.
 struct FileBuffer
@@ -585,58 +183,8 @@  nothrow:
     /// Write a file, returning `true` on success.
     extern (D) static bool write(const(char)* name, const void[] data)
     {
-        version (Posix)
-        {
-            ssize_t numwritten;
-            int fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, (6 << 6) | (4 << 3) | 4);
-            if (fd == -1)
-                goto err;
-            numwritten = .write(fd, data.ptr, data.length);
-            if (numwritten != data.length)
-                goto err2;
-            if (close(fd) == -1)
-                goto err;
-            return true;
-        err2:
-            close(fd);
-            .remove(name);
-        err:
-            return false;
-        }
-        else version (Windows)
-        {
-            DWORD numwritten; // here because of the gotos
-            const nameStr = name.toDString;
-            // work around Windows file path length limitation
-            // (see documentation for extendedPathThen).
-            HANDLE h = nameStr.extendedPathThen!
-                (p => CreateFileW(p.ptr,
-                                  GENERIC_WRITE,
-                                  0,
-                                  null,
-                                  CREATE_ALWAYS,
-                                  FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
-                                  null));
-            if (h == INVALID_HANDLE_VALUE)
-                goto err;
-
-            if (WriteFile(h, data.ptr, cast(DWORD)data.length, &numwritten, null) != TRUE)
-                goto err2;
-            if (numwritten != data.length)
-                goto err2;
-            if (!CloseHandle(h))
-                goto err;
-            return true;
-        err2:
-            CloseHandle(h);
-            nameStr.extendedPathThen!(p => DeleteFileW(p.ptr));
-        err:
-            return false;
-        }
-        else
-        {
-            static assert(0);
-        }
+        import dmd.common.file : writeFile;
+        return writeFile(name, data);
     }
 
     ///ditto
@@ -717,42 +265,6 @@  nothrow:
         return update(name, data[0 .. size]);
     }
 
-    /// Touch a file to current date
-    static bool touch(const char* namez)
-    {
-        version (Windows)
-        {
-            FILETIME ft = void;
-            SYSTEMTIME st = void;
-            GetSystemTime(&st);
-            SystemTimeToFileTime(&st, &ft);
-
-            import core.stdc.string : strlen;
-
-            // get handle to file
-            HANDLE h = namez[0 .. namez.strlen()].extendedPathThen!(p => CreateFile(p.ptr,
-                FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE,
-                null, OPEN_EXISTING,
-                FILE_ATTRIBUTE_NORMAL, null));
-            if (h == INVALID_HANDLE_VALUE)
-                return false;
-
-            const f = SetFileTime(h, null, null, &ft); // set last write time
-
-            if (!CloseHandle(h))
-                return false;
-
-            return f != 0;
-        }
-        else version (Posix)
-        {
-            import core.sys.posix.utime;
-            return utime(namez, null) == 0;
-        }
-        else
-            static assert(0);
-    }
-
     /// Size of a file in bytes.
     /// Params: namez = null-terminated filename
     /// Returns: `ulong.max` on any error, the length otherwise.
@@ -777,38 +289,5 @@  nothrow:
         // Error cases go here.
         return ulong.max;
     }
-
-    /// Ditto
-    version (Posix)
-    static ulong size(int fd)
-    {
-        stat_t buf;
-        if (fstat(fd, &buf) == 0)
-            return buf.st_size;
-        return ulong.max;
-    }
-
-    /// Ditto
-    version (Windows)
-    static ulong size(HANDLE fd)
-    {
-        ulong result;
-        if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
-            return result;
-        return ulong.max;
-    }
 }
 
-/**
-Runs a non-pure function or delegate as pure code. Use with caution.
-
-Params:
-fun = the delegate to run, usually inlined: `fakePure({ ... });`
-
-Returns: whatever `fun` returns.
-*/
-private auto ref fakePure(F)(scope F fun) pure
-{
-    mixin("alias PureFun = " ~ F.stringof ~ " pure;");
-    return (cast(PureFun) fun)();
-}
diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d
index 1e4ccb5d344..d1500c8953b 100644
--- a/gcc/d/dmd/root/filename.d
+++ b/gcc/d/dmd/root/filename.d
@@ -16,7 +16,8 @@  import core.stdc.errno;
 import core.stdc.string;
 import dmd.root.array;
 import dmd.root.file;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
+import dmd.common.file;
 import dmd.root.port;
 import dmd.root.rmem;
 import dmd.root.rootobject;
@@ -1123,78 +1124,13 @@  version(Windows)
      */
     private int _mkdir(const(char)[] path) nothrow
     {
+        import dmd.common.string : extendedPathThen;
         const createRet = path.extendedPathThen!(
             p => CreateDirectoryW(&p[0], null /*securityAttributes*/));
         // different conventions for CreateDirectory and mkdir
         return createRet == 0 ? 1 : 0;
     }
 
-    /**************************************
-     * Converts a path to one suitable to be passed to Win32 API
-     * functions that can deal with paths longer than 248
-     * characters then calls the supplied function on it.
-     *
-     * Params:
-     *  path = The Path to call F on.
-     *
-     * Returns:
-     *  The result of calling F on path.
-     *
-     * References:
-     *  https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
-     */
-    package auto extendedPathThen(alias F)(const(char)[] path)
-    {
-        if (!path.length)
-            return F((wchar[]).init);
-        return path.toWStringzThen!((wpath)
-        {
-            // GetFullPathNameW expects a sized buffer to store the result in. Since we don't
-            // know how large it has to be, we pass in null and get the needed buffer length
-            // as the return code.
-            const pathLength = GetFullPathNameW(&wpath[0],
-                                                0 /*length8*/,
-                                                null /*output buffer*/,
-                                                null /*filePartBuffer*/);
-            if (pathLength == 0)
-            {
-                return F((wchar[]).init);
-            }
-
-            // wpath is the UTF16 version of path, but to be able to use
-            // extended paths, we need to prefix with `\\?\` and the absolute
-            // path.
-            static immutable prefix = `\\?\`w;
-
-            // prefix only needed for long names and non-UNC names
-            const needsPrefix = pathLength >= MAX_PATH && (wpath[0] != '\\' || wpath[1] != '\\');
-            const prefixLength = needsPrefix ? prefix.length : 0;
-
-            // +1 for the null terminator
-            const bufferLength = pathLength + prefixLength + 1;
-
-            wchar[1024] absBuf = void;
-            wchar[] absPath = bufferLength > absBuf.length
-                ? new wchar[bufferLength] : absBuf[0 .. bufferLength];
-
-            absPath[0 .. prefixLength] = prefix[0 .. prefixLength];
-
-            const absPathRet = GetFullPathNameW(&wpath[0],
-                cast(uint)(absPath.length - prefixLength - 1),
-                &absPath[prefixLength],
-                null /*filePartBuffer*/);
-
-            if (absPathRet == 0 || absPathRet > absPath.length - prefixLength)
-            {
-                return F((wchar[]).init);
-            }
-
-            absPath[$ - 1] = '\0';
-            // Strip null terminator from the slice
-            return F(absPath[0 .. $ - 1]);
-        });
-    }
-
     /**********************************
      * Converts a UTF-16 string to a (null-terminated) narrow string.
      * Returns:
@@ -1222,33 +1158,6 @@  version(Windows)
         return newBuffer[0 .. length];
     }
 
-    /**********************************
-     * Converts a narrow string to a (null-terminated) UTF-16 string.
-     * Returns:
-     *  If `buffer` is specified and the result fits, a slice of that buffer,
-     *  otherwise a new buffer which can be released via `mem.xfree()`.
-     *  Nulls are propagated, i.e., if `narrow` is null, the returned slice is
-     *  null too.
-     */
-    wchar[] toWStringz(const(char)[] narrow, wchar[] buffer = null) nothrow
-    {
-        if (narrow is null)
-            return null;
-
-        const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
-        if (requiredLength < buffer.length)
-        {
-            buffer[requiredLength] = 0;
-            return buffer[0 .. requiredLength];
-        }
-
-        wchar* newBuffer = cast(wchar*) mem.xmalloc_noscan((requiredLength + 1) * wchar.sizeof);
-        const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, newBuffer, requiredLength);
-        assert(length == requiredLength);
-        newBuffer[length] = 0;
-        return newBuffer[0 .. length];
-    }
-
     /**********************************
      * Converts a slice of UTF-8 characters to an array of wchar that's null
      * terminated so it can be passed to Win32 APIs then calls the supplied
@@ -1262,9 +1171,12 @@  version(Windows)
      */
     private auto toWStringzThen(alias F)(const(char)[] str) nothrow
     {
+        import dmd.common.string : SmallBuffer, toWStringz;
+
         if (!str.length) return F(""w.ptr);
 
-        wchar[1024] buf = void;
+        wchar[1024] support = void;
+        auto buf = SmallBuffer!wchar(support.length, support);
         wchar[] wide = toWStringz(str, buf);
         scope(exit) wide.ptr != buf.ptr && mem.xfree(wide.ptr);
 
diff --git a/gcc/d/dmd/root/hash.h b/gcc/d/dmd/root/hash.h
deleted file mode 100644
index 6a322006213..00000000000
diff --git a/gcc/d/dmd/root/rootobject.d b/gcc/d/dmd/root/rootobject.d
index 854ec1a65bc..64104b823d1 100644
--- a/gcc/d/dmd/root/rootobject.d
+++ b/gcc/d/dmd/root/rootobject.d
@@ -13,7 +13,7 @@  module dmd.root.rootobject;
 
 import core.stdc.stdio;
 
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 
 /***********************************************************
  */
diff --git a/gcc/d/dmd/root/speller.h b/gcc/d/dmd/root/speller.h
deleted file mode 100644
index bd53fc452c9..00000000000
diff --git a/gcc/d/dmd/root/stringtable.h b/gcc/d/dmd/root/stringtable.h
deleted file mode 100644
index 51304d32c3f..00000000000
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index 35734b2caa5..89049599dac 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -89,7 +89,7 @@  bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
 
         if (hasPointers && v.type.toBasetype().ty != Tstruct)
         {
-            if ((ad.type.alignment() < target.ptrsize ||
+            if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize ||
                  (v.offset & (target.ptrsize - 1))) &&
                 sc.func.setUnsafe())
             {
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index 7b2fa5e93cd..993db905523 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -53,7 +53,7 @@  import dmd.objc;
 import dmd.opover;
 import dmd.parse;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.rootobject;
 import dmd.sideeffect;
@@ -363,7 +363,7 @@  private extern(C++) final class Semantic2Visitor : Visitor
         assert(fd.semanticRun <= PASS.semantic2);
         fd.semanticRun = PASS.semantic2;
 
-        //printf("FuncDeclaration::semantic2 [%s] fd0 = %s %s\n", loc.toChars(), toChars(), type.toChars());
+        //printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr);
 
         // Only check valid functions which have a body to avoid errors
         // for multiple declarations, e.g.
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index ac2b239efaf..3852d0b2693 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -55,7 +55,7 @@  import dmd.objc;
 import dmd.opover;
 import dmd.parse;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.rootobject;
 import dmd.sideeffect;
@@ -407,7 +407,8 @@  private extern(C++) final class Semantic3Visitor : Visitor
                     sc2.insert(_arguments);
                     _arguments.parent = funcdecl;
                 }
-                if (f.linkage == LINK.d || f.parameterList.length)
+                if ((f.linkage == LINK.d || f.parameterList.length) &&
+                    !(sc.flags & SCOPE.Cfile))  // don't want to require importing stdarg for C files
                 {
                     // Declare _argptr
                     Type t = target.va_listType(funcdecl.loc, sc);
@@ -598,7 +599,10 @@  private extern(C++) final class Semantic3Visitor : Visitor
                         f.next = Type.tvoid;
                     if (f.checkRetType(funcdecl.loc))
                         funcdecl.fbody = new ErrorStatement();
+                    else if (funcdecl.isMain())
+                        funcdecl.checkDmain();       // Check main() parameters and return type
                 }
+
                 if (global.params.vcomplex && f.next !is null)
                     f.next.checkComplexTransition(funcdecl.loc, sc);
 
@@ -777,8 +781,14 @@  private extern(C++) final class Semantic3Visitor : Visitor
                     }
                     assert(!funcdecl.returnLabel);
                 }
-                else if (f.next.ty == Tnoreturn)
+                else if (f.next.toBasetype().ty == Tnoreturn)
                 {
+                    // Fallthrough despite being declared as noreturn? return is already rejected when evaluating the ReturnStatement
+                    if (blockexit & BE.fallthru)
+                    {
+                        funcdecl.error("is typed as `%s` but does return", f.next.toChars());
+                        funcdecl.loc.errorSupplemental("`noreturn` functions must either throw, abort or loop indefinitely");
+                    }
                 }
                 else
                 {
@@ -1571,7 +1581,7 @@  private struct FuncDeclSem3
     }
 }
 
-private void semanticTypeInfoMembers(StructDeclaration sd)
+extern (C++) void semanticTypeInfoMembers(StructDeclaration sd)
 {
     if (sd.xeq &&
         sd.xeq._scope &&
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index b49c9035d3f..91e3fe7bfeb 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -39,7 +39,7 @@  import dmd.id;
 import dmd.identifier;
 import dmd.dinterpret;
 import dmd.mtype;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.sapply;
 import dmd.sideeffect;
@@ -463,7 +463,7 @@  extern (C++) class ExpStatement : Statement
         this.exp = new DeclarationExp(loc, declaration);
     }
 
-    static ExpStatement create(Loc loc, Expression exp)
+    static ExpStatement create(const ref Loc loc, Expression exp)
     {
         return new ExpStatement(loc, exp);
     }
@@ -577,7 +577,7 @@  extern (C++) class CompoundStatement : Statement
             statements.push(s);
     }
 
-    static CompoundStatement create(Loc loc, Statement s1, Statement s2)
+    static CompoundStatement create(const ref Loc loc, Statement s1, Statement s2)
     {
         return new CompoundStatement(loc, s1, s2);
     }
@@ -1635,7 +1635,7 @@  extern (C++) final class TryFinallyStatement : Statement
         this.bodyFallsThru = true;      // assume true until statementSemantic()
     }
 
-    static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody)
+    static TryFinallyStatement create(const ref Loc loc, Statement _body, Statement finalbody)
     {
         return new TryFinallyStatement(loc, _body, finalbody);
     }
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index 7825762db9e..98b7bd318eb 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -186,7 +186,7 @@  class ExpStatement : public Statement
 public:
     Expression *exp;
 
-    static ExpStatement *create(Loc loc, Expression *exp);
+    static ExpStatement *create(const Loc &loc, Expression *exp);
     ExpStatement *syntaxCopy();
 
     void accept(Visitor *v) { v->visit(this); }
@@ -218,7 +218,7 @@  class CompoundStatement : public Statement
 public:
     Statements *statements;
 
-    static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2);
+    static CompoundStatement *create(const Loc &loc, Statement *s1, Statement *s2);
     CompoundStatement *syntaxCopy();
     ReturnStatement *endsWithReturnStatement();
     Statement *last();
@@ -615,7 +615,7 @@  public:
     Statement *tryBody;   // set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
     bool bodyFallsThru;   // true if _body falls through to finally
 
-    static TryFinallyStatement *create(Loc loc, Statement *body, Statement *finalbody);
+    static TryFinallyStatement *create(const Loc &loc, Statement *body, Statement *finalbody);
     TryFinallyStatement *syntaxCopy();
     bool hasBreak() const;
     bool hasContinue() const;
diff --git a/gcc/d/dmd/statement_rewrite_walker.h b/gcc/d/dmd/statement_rewrite_walker.h
deleted file mode 100644
index 28a930a28bc..00000000000
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index f067c91b316..9eba2ffaed2 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -54,7 +54,7 @@  import dmd.nogc;
 import dmd.opover;
 import dmd.parse;
 import dmd.printast;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.string;
 import dmd.semantic2;
 import dmd.sideeffect;
@@ -659,20 +659,6 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
         result = fs;
     }
 
-    /*******************
-     * Determines the return type of makeTupleForeach.
-     */
-    private static template MakeTupleForeachRet(bool isDecl)
-    {
-        static if(isDecl)
-        {
-            alias MakeTupleForeachRet = Dsymbols*;
-        }
-        else
-        {
-            alias MakeTupleForeachRet = void;
-        }
-    }
 
     /*******************
      * Type check and unroll `foreach` over an expression tuple as well
@@ -696,29 +682,24 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
      * expands the tuples into multiple `STC.local` `static foreach`
      * variables.
      */
-    MakeTupleForeachRet!isDecl makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, TupleForeachArgs!(isStatic, isDecl) args)
+    auto makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
     {
-        auto returnEarly()
-        {
-            static if (isDecl)
-            {
-                return null;
-            }
-            else
-            {
-                result = new ErrorStatement();
-                return;
-            }
-        }
-        static if(isDecl)
+        // Voldemort return type
+        union U
         {
-            static assert(isStatic);
-            auto dbody = args[0];
+            Statement statement;
+            Dsymbols* decl;
         }
-        static if(isStatic)
+
+        U result;
+
+        auto returnEarly()
         {
-            auto needExpansion = args[$-1];
-            assert(sc);
+            if (isDecl)
+                result.decl = null;
+            else
+                result.statement = new ErrorStatement();
+            return result;
         }
 
         auto loc = fs.loc;
@@ -827,7 +808,7 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
                 }
                 Initializer ie = new ExpInitializer(Loc.initial, new IntegerExp(k));
                 auto var = new VarDeclaration(loc, p.type, p.ident, ie);
-                var.storage_class |= STC.manifest;
+                var.storage_class |= STC.foreach_ | STC.manifest;
                 static if(isStatic) var.storage_class |= STC.local;
                 static if(!isDecl)
                 {
@@ -919,8 +900,9 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
                         e = resolveProperties(sc, e);
                         Initializer ie = new ExpInitializer(Loc.initial, e);
                         auto v = new VarDeclaration(loc, type, ident, ie, storageClass);
+                        v.storage_class |= STC.foreach_;
                         if (storageClass & STC.ref_)
-                            v.storage_class |= STC.ref_ | STC.foreach_;
+                            v.storage_class |= STC.ref_;
                         if (isStatic || storageClass&STC.manifest || e.isConst() ||
                             e.op == TOK.string_ ||
                             e.op == TOK.structLiteral ||
@@ -1057,23 +1039,17 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
                 ls.gotoTarget = res;
             if (te && te.e0)
                 res = new CompoundStatement(loc, new ExpStatement(te.e0.loc, te.e0), res);
+            result.statement = res;
         }
         else static if (!isDecl)
         {
-            Statement res = new CompoundStatement(loc, statements);
-        }
-        else
-        {
-            auto res = declarations;
-        }
-        static if (!isDecl)
-        {
-            result = res;
+            result.statement = new CompoundStatement(loc, statements);
         }
         else
         {
-            return res;
+            result.decl = declarations;
         }
+        return result;
     }
 
     override void visit(ForeachStatement fs)
@@ -1202,10 +1178,10 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
 
         if (tab.ty == Ttuple) // don't generate new scope for tuple loops
         {
-            makeTupleForeach!(false,false)(fs);
+            Statement s = makeTupleForeach!(false,false)(fs, null, false).statement;
             if (vinit)
-                result = new CompoundStatement(loc, new ExpStatement(loc, vinit), result);
-            result = result.statementSemantic(sc);
+                s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s);
+            result = s.statementSemantic(sc);
             return;
         }
 
@@ -2727,7 +2703,8 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
                 needswitcherror = true;
         }
 
-        if (!sc.sw.sdefault && (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
+        if (!sc.sw.sdefault && !(sc.flags & SCOPE.Cfile) &&
+            (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
         {
             ss.hasNoDefault = 1;
 
@@ -3061,7 +3038,7 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
 
         if (lval - fval > 256)
         {
-            crs.error("had %llu cases which is more than 256 cases in case range", lval - fval);
+            crs.error("had %llu cases which is more than 257 cases in case range", 1 + lval - fval);
             errors = true;
             lval = fval + 256;
         }
@@ -3295,12 +3272,14 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
             if (e0)
                 e0 = e0.optimize(WANTvalue);
 
-            /* Void-return function can have void typed expression
+            /* Void-return function can have void / noreturn typed expression
              * on return statement.
              */
-            if (tbret && tbret.ty == Tvoid || rs.exp.type.ty == Tvoid)
+            const convToVoid = rs.exp.type.ty == Tvoid || rs.exp.type.ty == Tnoreturn;
+
+            if (tbret && tbret.ty == Tvoid || convToVoid)
             {
-                if (rs.exp.type.ty != Tvoid)
+                if (!convToVoid)
                 {
                     rs.error("cannot return non-void from `void` function");
                     errors = true;
@@ -3345,7 +3324,7 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
                     }
                     else if (rs.exp.op != TOK.error)
                     {
-                        rs.error("Expected return type of `%s`, not `%s`:",
+                        rs.error("expected return type of `%s`, not `%s`:",
                                  tret.toChars(),
                                  rs.exp.type.toChars());
                         errorSupplemental((fd.returns) ? (*fd.returns)[0].loc : fd.loc,
@@ -3409,10 +3388,20 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
         }
         else
         {
+            // Type of the returned expression (if any), might've been moved to e0
+            auto resType = e0 ? e0.type : Type.tvoid;
+
             // infer return type
             if (fd.inferRetType)
             {
-                if (tf.next && tf.next.ty != Tvoid)
+                // 1. First `return <noreturn exp>?`
+                // 2. Potentially found a returning branch, update accordingly
+                if (!tf.next || tf.next.toBasetype().isTypeNoreturn())
+                {
+                    tf.next = resType; // infer void or noreturn
+                }
+                // Found an actual return value before
+                else if (tf.next.ty != Tvoid && !resType.toBasetype().isTypeNoreturn())
                 {
                     if (tf.next.ty != Terror)
                     {
@@ -3421,20 +3410,23 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
                     errors = true;
                     tf.next = Type.terror;
                 }
-                else
-                    tf.next = Type.tvoid;
 
-                    tret = tf.next;
+                tret = tf.next;
                 tbret = tret.toBasetype();
             }
 
             if (inferRef) // deduce 'auto ref'
                 tf.isref = false;
 
-            if (tbret.ty != Tvoid) // if non-void return
+            if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return
             {
                 if (tbret.ty != Terror)
-                    rs.error("`return` expression expected");
+                {
+                    if (e0)
+                        rs.error("expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars());
+                    else
+                        rs.error("`return` expression expected");
+                }
                 errors = true;
             }
             else if (fd.isMain())
@@ -3522,7 +3514,12 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
             }
             else
             {
-                result = new CompoundStatement(rs.loc, new ExpStatement(rs.loc, e0), rs);
+                auto es = new ExpStatement(rs.loc, e0);
+                if (e0.type.isTypeNoreturn())
+                    result = es; // Omit unreachable return;
+                else
+                    result = new CompoundStatement(rs.loc, es, rs);
+
                 return;
             }
         }
@@ -4014,7 +4011,7 @@  private extern (C++) final class StatementSemanticVisitor : Visitor
                 /* If catch exception type is derived from Exception
                  */
                 if (c.type.toBasetype().implicitConvTo(ClassDeclaration.exception.type) &&
-                    (!c.handler || !c.handler.comeFrom()))
+                    (!c.handler || !c.handler.comeFrom()) && !(sc.flags & SCOPE.debug_))
                 {
                     // Remove c from the array of catches
                     tcs.catches.remove(i);
@@ -4569,45 +4566,14 @@  Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out St
 }
 
 
-/*******************
- * Determines additional argument types for makeTupleForeach.
- */
-static template TupleForeachArgs(bool isStatic, bool isDecl)
-{
-    alias Seq(T...)=T;
-    static if(isStatic) alias T = Seq!(bool);
-    else alias T = Seq!();
-    static if(!isDecl) alias TupleForeachArgs = T;
-    else alias TupleForeachArgs = Seq!(Dsymbols*,T);
-}
-
-/*******************
- * Determines the return type of makeTupleForeach.
- */
-static template TupleForeachRet(bool isStatic, bool isDecl)
-{
-    alias Seq(T...)=T;
-    static if(!isDecl) alias TupleForeachRet = Statement;
-    else alias TupleForeachRet = Dsymbols*;
-}
-
-
 /*******************
  * See StatementSemanticVisitor.makeTupleForeach.  This is a simple
  * wrapper that returns the generated statements/declarations.
  */
-TupleForeachRet!(isStatic, isDecl) makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, TupleForeachArgs!(isStatic, isDecl) args)
+auto makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
 {
     scope v = new StatementSemanticVisitor(sc);
-    static if(!isDecl)
-    {
-        v.makeTupleForeach!(isStatic, isDecl)(fs, args);
-        return v.result;
-    }
-    else
-    {
-        return v.makeTupleForeach!(isStatic, isDecl)(fs, args);
-    }
+    return v.makeTupleForeach!(isStatic, isDecl)(fs, dbody, needExpansion);
 }
 
 /*********************************
@@ -4731,7 +4697,7 @@  private Statements* flatten(Statement statement, Scope* sc)
             sfs.sfe.prepare(sc);
             if (sfs.sfe.ready())
             {
-                auto s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, sfs.sfe.needExpansion);
+                Statement s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, null, sfs.sfe.needExpansion).statement;
                 auto result = s.flatten(sc);
                 if (result)
                 {
diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d
index 2f27414a56c..d1578ec3a12 100644
--- a/gcc/d/dmd/staticcond.d
+++ b/gcc/d/dmd/staticcond.d
@@ -22,7 +22,7 @@  import dmd.globals;
 import dmd.identifier;
 import dmd.mtype;
 import dmd.root.array;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.tokens;
 
 
diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d
index d5b3de2c522..16739addf57 100644
--- a/gcc/d/dmd/target.d
+++ b/gcc/d/dmd/target.d
@@ -316,7 +316,8 @@  struct TargetC
     enum BitFieldStyle : ubyte
     {
         Unspecified,
-        Dm_Ms,                /// Digital Mars and Microsoft C compilers
+        DM,                   /// Digital Mars 32 bit C compiler
+        MS,                   /// Microsoft 32 and 64 bit C compilers
                               /// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
                               /// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
         Gcc_Clang,            /// gcc and clang
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index 83281a6358f..6a75ccc5ebd 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -63,7 +63,8 @@  struct TargetC
     enum class BitFieldStyle : unsigned char
     {
         Unspecified,
-        Dm_Ms,                // Digital Mars and Microsoft C compilers
+        DM,                   // Digital Mars 32 bit C compiler
+        MS,                   // Microsoft 32 and 64 bit C compilers
                               // https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160
                               // https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160
         Gcc_Clang,            // gcc and clang
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 08ce9acef99..69cc84f6573 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -131,7 +131,7 @@  public:
     virtual bool declareParameter(Scope *sc) = 0;
     virtual void print(RootObject *oarg, RootObject *oded) = 0;
     virtual RootObject *specialization() = 0;
-    virtual RootObject *defaultArg(Loc instLoc, Scope *sc) = 0;
+    virtual RootObject *defaultArg(const Loc &instLoc, Scope *sc) = 0;
     virtual bool hasDefaultArg() = 0;
 
     /* Create dummy argument based on parameter.
@@ -154,7 +154,7 @@  public:
     bool declareParameter(Scope *sc);
     void print(RootObject *oarg, RootObject *oded);
     RootObject *specialization();
-    RootObject *defaultArg(Loc instLoc, Scope *sc);
+    RootObject *defaultArg(const Loc &instLoc, Scope *sc);
     bool hasDefaultArg();
     RootObject *dummyArg();
     void accept(Visitor *v) { v->visit(this); }
@@ -186,7 +186,7 @@  public:
     bool declareParameter(Scope *sc);
     void print(RootObject *oarg, RootObject *oded);
     RootObject *specialization();
-    RootObject *defaultArg(Loc instLoc, Scope *sc);
+    RootObject *defaultArg(const Loc &instLoc, Scope *sc);
     bool hasDefaultArg();
     RootObject *dummyArg();
     void accept(Visitor *v) { v->visit(this); }
@@ -207,7 +207,7 @@  public:
     bool declareParameter(Scope *sc);
     void print(RootObject *oarg, RootObject *oded);
     RootObject *specialization();
-    RootObject *defaultArg(Loc instLoc, Scope *sc);
+    RootObject *defaultArg(const Loc &instLoc, Scope *sc);
     bool hasDefaultArg();
     RootObject *dummyArg();
     void accept(Visitor *v) { v->visit(this); }
@@ -224,7 +224,7 @@  public:
     bool declareParameter(Scope *sc);
     void print(RootObject *oarg, RootObject *oded);
     RootObject *specialization();
-    RootObject *defaultArg(Loc instLoc, Scope *sc);
+    RootObject *defaultArg(const Loc &instLoc, Scope *sc);
     bool hasDefaultArg();
     RootObject *dummyArg();
     void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
index 7680fb8500b..1ea51a89bff 100644
--- a/gcc/d/dmd/tokens.d
+++ b/gcc/d/dmd/tokens.d
@@ -19,7 +19,7 @@  import core.stdc.string;
 import dmd.globals;
 import dmd.identifier;
 import dmd.root.ctfloat;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.utf;
 
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
index 0fd6634f2ce..d14d0aab593 100644
--- a/gcc/d/dmd/tokens.h
+++ b/gcc/d/dmd/tokens.h
@@ -187,6 +187,7 @@  enum
         TOKarrow,
         TOKcolonColon,
         TOKwchar_tLiteral,
+        TOKcompoundLiteral,
 
         TOKinline,
         TOKregister,
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 8f968ed0dc2..cc1d2e351e6 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -49,7 +49,7 @@  import dmd.tokens;
 import dmd.typesem;
 import dmd.visitor;
 import dmd.root.rootobject;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.string;
 
 enum LOGSEMANTIC = false;
@@ -1410,19 +1410,30 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
         auto o = (*e.args)[0];
         auto o1 = (*e.args)[1];
 
-        FuncDeclaration fd;
-        TypeFunction tf = toTypeFunction(o, fd);
-
         ParameterList fparams;
-        if (tf)
-            fparams = tf.parameterList;
-        else if (fd)
-            fparams = fd.getParameterList();
+
+        CallExp ce;
+        if (auto exp = isExpression(o))
+            ce = exp.isCallExp();
+
+        if (ce)
+        {
+            fparams = ce.f.getParameterList();
+        }
         else
         {
-            e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function",
-                o.toChars(), o1.toChars());
-            return ErrorExp.get();
+            FuncDeclaration fd;
+            auto tf = toTypeFunction(o, fd);
+            if (tf)
+                fparams = tf.parameterList;
+            else if (fd)
+                fparams = fd.getParameterList();
+            else
+            {
+                e.error("first argument to `__traits(getParameterStorageClasses, %s, %s)` is not a function or a function call",
+                    o.toChars(), o1.toChars());
+                return ErrorExp.get();
+            }
         }
 
         // Avoid further analysis for invalid functions leading to misleading error messages
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index ace4e423bcc..f75ae0e0b5a 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -44,6 +44,7 @@  import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.imphint;
+import dmd.importc;
 import dmd.init;
 import dmd.initsem;
 import dmd.visitor;
@@ -53,7 +54,7 @@  import dmd.opover;
 import dmd.parse;
 import dmd.root.ctfloat;
 import dmd.root.rmem;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.root.stringtable;
@@ -1334,6 +1335,8 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                         continue;
                 }
 
+                fparam.type = fparam.type.cAdjustParamType(sc); // adjust C array and function parameter types
+
                 Type t = fparam.type.toBasetype();
 
                 /* If fparam after semantic() turns out to be a tuple, the number of parameters may
@@ -1378,6 +1381,7 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                                 stc, narg.type, narg.ident, narg.defaultArg, narg.userAttribDecl);
                         }
                         fparam.type = new TypeTuple(newparams);
+                        fparam.type = fparam.type.typeSemantic(loc, argsc);
                     }
                     fparam.storageClass = STC.parameter;
 
@@ -1627,7 +1631,8 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             errors = true;
         }
 
-        if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0)
+        if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
+            !(sc.flags & SCOPE.Cfile))
         {
             .error(loc, "variadic functions with non-D linkage must have at least one parameter");
             errors = true;
@@ -1750,10 +1755,10 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             {
                 // if there was an error evaluating the symbol, it might actually
                 // be a type. Avoid misleading error messages.
-               .error(loc, "`%s` had previous errors", mtype.toChars());
+                .error(loc, "`%s` had previous errors", mtype.toChars());
             }
             else
-               .error(loc, "`%s` is used as a type", mtype.toChars());
+                .error(loc, "`%s` is used as a type", mtype.toChars());
             return error();
         }
         return t;
@@ -2133,6 +2138,15 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                      * struct S { int a; } *s;
                      */
                     sd.members = mtype.members;
+                    if (sd.semanticRun == PASS.semanticdone)
+                    {
+                        /* The first semantic pass marked `sd` as an opaque struct.
+                         * Re-run semantic so that all newly assigned members are
+                         * picked up and added to the symtab.
+                         */
+                        sd.semanticRun = PASS.semantic;
+                        sd.dsymbolSemantic(sc);
+                    }
                 }
                 else
                 {
@@ -2264,7 +2278,7 @@  RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
  * Returns:
  *      the type that was merged
  */
-Type merge(Type type)
+extern (C++) Type merge(Type type)
 {
     switch (type.ty)
     {
@@ -2361,7 +2375,7 @@  Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
         {
             const explicitAlignment = mt.alignment();
             const naturalAlignment = mt.alignsize();
-            const actualAlignment = (explicitAlignment == STRUCTALIGN_DEFAULT ? naturalAlignment : explicitAlignment);
+            const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
             e = new IntegerExp(loc, actualAlignment, Type.tsize_t);
         }
         else if (ident == Id._init)
@@ -3734,10 +3748,18 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
     }
 
     /***************************************
-     * Figures out what to do with an undefined member reference
-     * for classes and structs.
-     *
-     * If flag & 1, don't report "not a property" error and just return NULL.
+     * `ident` was not found as a member of `mt`.
+     * Attempt to use overloaded opDot(), overloaded opDispatch(), or `alias this`.
+     * If that fails, forward to visitType().
+     * Params:
+     *  mt = class or struct
+     *  sc = context
+     *  e = `this` for `ident`
+     *  ident = name of member
+     *  flag = flag & 1, don't report "not a property" error and just return NULL.
+     *         flag & DotExpFlag.noAliasThis, don't do 'alias this' resolution.
+     * Returns:
+     *  resolved expression if found, otherwise null
      */
     Expression noMember(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
     {
@@ -3828,7 +3850,8 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
 
             /* See if we should forward to the alias this.
              */
-            auto alias_e = resolveAliasThis(sc, e, gagError);
+            auto alias_e = flag & DotExpFlag.noAliasThis ? null
+                                                         : resolveAliasThis(sc, e, gagError);
             if (alias_e && alias_e != e)
             {
                 /* Rewrite e.ident as:
@@ -4611,7 +4634,7 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
  * Returns:
  *  The initialization expression for the type.
  */
-Expression defaultInit(Type mt, const ref Loc loc)
+extern (C++) Expression defaultInit(Type mt, const ref Loc loc)
 {
     Expression visitBasic(TypeBasic mt)
     {
@@ -4744,6 +4767,7 @@  Expression defaultInit(Type mt, const ref Loc loc)
         }
         auto cond = IntegerExp.createBool(false);
         auto msg = new StringExp(loc, "Accessed expression of type `noreturn`");
+        msg.type = Type.tstring;
         auto ae = new AssertExp(loc, cond, msg);
         ae.type = mt;
         return ae;
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index d8160f0d633..d05af61ce6f 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -1,5 +1,5 @@ 
 /**
- * Generate `TypeInfo` objects, which are needed for run-time introspection of classes.
+ * Generate `TypeInfo` objects, which are needed for run-time introspection of types.
  *
  * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
@@ -11,9 +11,87 @@ 
 
 module dmd.typinf;
 
+import dmd.astenums;
+import dmd.declaration;
+import dmd.dmodule;
 import dmd.dscope;
+import dmd.dclass;
+import dmd.dstruct;
+import dmd.errors;
 import dmd.globals;
+import dmd.gluelayer;
 import dmd.mtype;
+import dmd.visitor;
+import core.stdc.stdio;
+
+/****************************************************
+ * Generates the `TypeInfo` object associated with `torig` if it
+ * hasn't already been generated
+ * Params:
+ *      loc   = the location for reporting line numbers in errors
+ *      torig = the type to generate the `TypeInfo` object for
+ *      sc    = the scope
+ */
+extern (C++) void genTypeInfo(const ref Loc loc, Type torig, Scope* sc)
+{
+    // printf("genTypeInfo() %s\n", torig.toChars());
+
+    // Even when compiling without `useTypeInfo` (e.g. -betterC) we should
+    // still be able to evaluate `TypeInfo` at compile-time, just not at runtime.
+    // https://issues.dlang.org/show_bug.cgi?id=18472
+    if (!sc || !(sc.flags & SCOPE.ctfe))
+    {
+        if (!global.params.useTypeInfo)
+        {
+            .error(loc, "`TypeInfo` cannot be used with -betterC");
+            fatal();
+        }
+    }
+
+    if (!Type.dtypeinfo)
+    {
+        .error(loc, "`object.TypeInfo` could not be found, but is implicitly used");
+        fatal();
+    }
+
+    Type t = torig.merge2(); // do this since not all Type's are merge'd
+    if (!t.vtinfo)
+    {
+        if (t.isShared()) // does both 'shared' and 'shared const'
+            t.vtinfo = TypeInfoSharedDeclaration.create(t);
+        else if (t.isConst())
+            t.vtinfo = TypeInfoConstDeclaration.create(t);
+        else if (t.isImmutable())
+            t.vtinfo = TypeInfoInvariantDeclaration.create(t);
+        else if (t.isWild())
+            t.vtinfo = TypeInfoWildDeclaration.create(t);
+        else
+            t.vtinfo = getTypeInfoDeclaration(t);
+        assert(t.vtinfo);
+
+        // ClassInfos are generated as part of ClassDeclaration codegen
+        const isUnqualifiedClassInfo = (t.ty == Tclass && !t.mod);
+
+        // generate a COMDAT for other TypeInfos not available as builtins in
+        // druntime
+        if (!isUnqualifiedClassInfo && !builtinTypeInfo(t))
+        {
+            if (sc) // if in semantic() pass
+            {
+                // Find module that will go all the way to an object file
+                Module m = sc._module.importedFrom;
+                m.members.push(t.vtinfo);
+            }
+            else // if in obj generation pass
+            {
+                toObjFile(t.vtinfo, global.params.multiobj);
+            }
+        }
+    }
+    if (!torig.vtinfo)
+        torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
+    assert(torig.vtinfo);
+}
 
 /****************************************************
  * Gets the type of the `TypeInfo` object associated with `t`
@@ -24,5 +102,161 @@  import dmd.mtype;
  * Returns:
  *      The type of the `TypeInfo` object associated with `t`
  */
-extern (C++) Type getTypeInfoType(Loc loc, Type t, Scope* sc);
+extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc);
+
+private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
+{
+    //printf("Type::getTypeInfoDeclaration() %s\n", t.toChars());
+    switch (t.ty)
+    {
+    case Tpointer:
+        return TypeInfoPointerDeclaration.create(t);
+    case Tarray:
+        return TypeInfoArrayDeclaration.create(t);
+    case Tsarray:
+        return TypeInfoStaticArrayDeclaration.create(t);
+    case Taarray:
+        return TypeInfoAssociativeArrayDeclaration.create(t);
+    case Tstruct:
+        return TypeInfoStructDeclaration.create(t);
+    case Tvector:
+        return TypeInfoVectorDeclaration.create(t);
+    case Tenum:
+        return TypeInfoEnumDeclaration.create(t);
+    case Tfunction:
+        return TypeInfoFunctionDeclaration.create(t);
+    case Tdelegate:
+        return TypeInfoDelegateDeclaration.create(t);
+    case Ttuple:
+        return TypeInfoTupleDeclaration.create(t);
+    case Tclass:
+        if ((cast(TypeClass)t).sym.isInterfaceDeclaration())
+            return TypeInfoInterfaceDeclaration.create(t);
+        else
+            return TypeInfoClassDeclaration.create(t);
+
+    default:
+        return TypeInfoDeclaration.create(t);
+    }
+}
+
+/**************************************************
+ * Returns:
+ *      true if any part of type t is speculative.
+ *      if t is null, returns false.
+ */
+bool isSpeculativeType(Type t)
+{
+    static bool visitVector(TypeVector t)
+    {
+        return isSpeculativeType(t.basetype);
+    }
+
+    static bool visitAArray(TypeAArray t)
+    {
+        return isSpeculativeType(t.index) ||
+               isSpeculativeType(t.next);
+    }
+
+    static bool visitStruct(TypeStruct t)
+    {
+        StructDeclaration sd = t.sym;
+        if (auto ti = sd.isInstantiated())
+        {
+            if (!ti.needsCodegen())
+            {
+                if (ti.minst || sd.requestTypeInfo)
+                    return false;
+
+                /* https://issues.dlang.org/show_bug.cgi?id=14425
+                 * TypeInfo_Struct would refer the members of
+                 * struct (e.g. opEquals via xopEquals field), so if it's instantiated
+                 * in speculative context, TypeInfo creation should also be
+                 * stopped to avoid 'unresolved symbol' linker errors.
+                 */
+                /* When -debug/-unittest is specified, all of non-root instances are
+                 * automatically changed to speculative, and here is always reached
+                 * from those instantiated non-root structs.
+                 * Therefore, if the TypeInfo is not auctually requested,
+                 * we have to elide its codegen.
+                 */
+                return true;
+            }
+        }
+        else
+        {
+            //assert(!sd.inNonRoot() || sd.requestTypeInfo);    // valid?
+        }
+        return false;
+    }
+
+    static bool visitClass(TypeClass t)
+    {
+        ClassDeclaration sd = t.sym;
+        if (auto ti = sd.isInstantiated())
+        {
+            if (!ti.needsCodegen() && !ti.minst)
+            {
+                return true;
+            }
+        }
+        return false;
+    }
 
+
+    static bool visitTuple(TypeTuple t)
+    {
+        if (t.arguments)
+        {
+            foreach (arg; *t.arguments)
+            {
+                if (isSpeculativeType(arg.type))
+                    return true;
+            }
+        }
+        return false;
+    }
+
+    if (!t)
+        return false;
+    Type tb = t.toBasetype();
+    switch (tb.ty)
+    {
+        case Tvector:   return visitVector(tb.isTypeVector());
+        case Taarray:   return visitAArray(tb.isTypeAArray());
+        case Tstruct:   return visitStruct(tb.isTypeStruct());
+        case Tclass:    return visitClass(tb.isTypeClass());
+        case Ttuple:    return visitTuple(tb.isTypeTuple());
+        case Tenum:     return false;
+        default:
+        return isSpeculativeType(tb.nextOf());
+
+        /* For TypeFunction, TypeInfo_Function doesn't store parameter types,
+         * so only the .next (the return type) is checked here.
+         */
+    }
+}
+
+/* ========================================================================= */
+
+/* Indicates whether druntime already contains an appropriate TypeInfo instance
+ * for the specified type (in module rt.util.typeinfo).
+ */
+extern (C++) bool builtinTypeInfo(Type t)
+{
+    if (!t.mod) // unqualified types only
+    {
+        // unqualified basic types + typeof(null)
+        if (t.isTypeBasic() || t.ty == Tnull)
+            return true;
+        // some unqualified arrays
+        if (t.ty == Tarray)
+        {
+            Type next = t.nextOf();
+            return (next.isTypeBasic() && !next.mod)                     // of unqualified basic types
+                || (next.ty == Tchar && next.mod == MODFlags.immutable_) // string
+                || (next.ty == Tchar && next.mod == MODFlags.const_);    // const(char)[]
+        }
+    }
+    return false;
+}
diff --git a/gcc/d/dmd/utf.h b/gcc/d/dmd/utf.h
deleted file mode 100644
index b3782afe78b..00000000000
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
index 600521fbd49..6cd5d20f6f7 100644
--- a/gcc/d/dmd/utils.d
+++ b/gcc/d/dmd/utils.d
@@ -16,7 +16,7 @@  import dmd.errors;
 import dmd.globals;
 import dmd.root.file;
 import dmd.root.filename;
-import dmd.root.outbuffer;
+import dmd.common.outbuffer;
 import dmd.root.string;
 
 
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 31680564bdd..2831eefc4ba 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -1757,7 +1757,7 @@  public:
 		/* C++ constructors return void, even though front-end semantic
 		   treats them as implicitly returning `this'.  Set returnvalue
 		   to override the result of this expression.  */
-		if (fd->isCtorDeclaration () && fd->linkage == LINK::cpp)
+		if (fd->isCtorDeclaration ())
 		  {
 		    thisexp = d_save_expr (thisexp);
 		    returnvalue = thisexp;
@@ -1846,6 +1846,11 @@  public:
       {
 	tree init = TARGET_EXPR_INITIAL (cleanup);
 	TARGET_EXPR_INITIAL (cleanup) = compound_expr (init, exp);
+
+	/* Keep the return value outside the TARGET_EXPR.  */
+	if (returnvalue != NULL_TREE)
+	  cleanup = compound_expr (cleanup, TREE_OPERAND (exp, 1));
+
 	exp = cleanup;
       }
 
@@ -1856,7 +1861,7 @@  public:
 
   void visit (DelegateExp *e)
   {
-    if (e->func->semanticRun == PASSsemantic3done)
+    if (e->func->semanticRun == PASS::semantic3done)
       {
 	/* 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.  */
diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi
index c98eb1f45d9..d37d205e870 100644
--- a/gcc/d/gdc.texi
+++ b/gcc/d/gdc.texi
@@ -283,6 +283,13 @@  Sets @code{__traits(getTargetInfo "cppStd")} to @code{202002}.
 @cindex @option{-fno-invariants}
 Turns off code generation for class @code{invariant} contracts.
 
+@item -fmain
+@cindex @option{-fmain}
+Generates a default @code{main()} function when compiling.  This is useful when
+unittesting a library, as it enables running the unittests in a library without
+having to manually define an entry-point function.  This option does nothing
+when @code{main} is already defined in user code.
+
 @item -fno-moduleinfo
 @cindex @option{-fmoduleinfo}
 @cindex @option{-fno-moduleinfo}
@@ -742,6 +749,8 @@  List information on all D language transitions.
 List all usages of complex or imaginary types.
 @item field
 List all non-mutable fields which occupy an object instance.
+@item in
+List all usages of @code{in} on parameter.
 @item nogc
 List all hidden GC allocations.
 @item templates
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index f7f90fb08c3..d0a5e2f6859 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -436,6 +436,10 @@  ftransition=field
 D RejectNegative
 List all non-mutable fields which occupy an object instance.
 
+ftransition=in
+D RejectNegative
+List all usages of 'in' on parameter.
+
 ftransition=nogc
 D RejectNegative
 List all hidden GC allocations.
diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc
index 06eb5ae3424..cb5c4a7b1e7 100644
--- a/gcc/d/modules.cc
+++ b/gcc/d/modules.cc
@@ -145,7 +145,7 @@  get_internal_fn (tree ident, const Visibility &visibility)
   fd->loc = Loc (mod->srcfile.toChars (), 1, 0);
   fd->parent = mod;
   fd->visibility = visibility;
-  fd->semanticRun = PASSsemantic3done;
+  fd->semanticRun = PASS::semantic3done;
 
   return fd;
 }
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index db500ee2efe..b39b92eb822 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -610,7 +610,8 @@  public:
 
   void visit (TypeNoreturn *t)
   {
-    t->ctype = void_type_node;
+    t->ctype = noreturn_type_node;
+    TYPE_NAME (t->ctype) = get_identifier (t->toChars ());
   }
 
   /* Basic Data Types.  */
@@ -770,11 +771,17 @@  public:
 	fnparams = chainon (fnparams, build_tree_list (0, type));
       }
 
-    size_t n_args = t->parameterList.length ();
+    const size_t n_args = t->parameterList.length ();
 
     for (size_t i = 0; i < n_args; i++)
       {
 	tree type = parameter_type (t->parameterList[i]);
+
+	/* Type `noreturn` is a terminator, as no other arguments can possibly
+	   be evaluated after it.  */
+	if (type == noreturn_type_node)
+	  break;
+
 	fnparams = chainon (fnparams, build_tree_list (0, type));
       }
 
@@ -797,6 +804,10 @@  public:
     TYPE_LANG_SPECIFIC (t->ctype) = build_lang_type (t);
     d_keep (t->ctype);
 
+    /* Qualify function types that have the type `noreturn` as volatile.  */
+    if (fntype == noreturn_type_node)
+      t->ctype = build_qualified_type (t->ctype, TYPE_QUAL_VOLATILE);
+
     /* Handle any special support for calling conventions.  */
     switch (t->linkage)
       {
@@ -995,8 +1006,8 @@  public:
 	   the context or laying out fields as those types may make
 	   recursive references to this type.  */
 	unsigned structsize = t->sym->structsize;
-	unsigned alignsize = (t->sym->alignment != STRUCTALIGN_DEFAULT)
-	  ? t->sym->alignment : t->sym->alignsize;
+	unsigned alignsize = t->sym->alignment.isDefault ()
+	  ? t->sym->alignsize : t->sym->alignment.get ();
 
 	TYPE_SIZE (t->ctype) = bitsize_int (structsize * BITS_PER_UNIT);
 	TYPE_SIZE_UNIT (t->ctype) = size_int (structsize);