diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index d379ef14f80..eaea6e039cf 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -104,6 +104,7 @@ D_FRONTEND_OBJS = \
 	d/cppmangle.o \
 	d/ctfeexpr.o \
 	d/ctorflow.o \
+	d/cxxfrontend.o \
 	d/dcast.o \
 	d/dclass.o \
 	d/declaration.o \
diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index 36a139b4ec4..0f7ca10e017 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -320,14 +320,14 @@ build_attributes (Expressions *eattrs)
   if (!eattrs)
     return NULL_TREE;
 
-  expandTuples (eattrs);
+  dmd::expandTuples (eattrs);
 
   tree attribs = NULL_TREE;
 
   for (size_t i = 0; i < eattrs->length; i++)
     {
       Expression *attr = (*eattrs)[i];
-      Dsymbol *sym = toDsymbol (attr->type, NULL);
+      Dsymbol *sym = dmd::toDsymbol (attr->type, NULL);
 
       if (!sym)
 	{
@@ -354,7 +354,7 @@ build_attributes (Expressions *eattrs)
 
       /* Get the result of the attribute if it hasn't already been folded.  */
       if (attr->op == EXP::call)
-	attr = ctfeInterpret (attr);
+	attr = dmd::ctfeInterpret (attr);
 
       if (attr->op != EXP::structLiteral)
 	{
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 24ac456e23d..dc50df4252c 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -98,14 +98,14 @@ build_frontend_type (tree type)
 	  /* Check for char * first.  Needs to be done for chars/string.  */
 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node)
 	    {
-	      dtype = addMod (Type::tchar, dtype->mod);
-	      return addMod (dtype->pointerTo (), mod);
+	      dtype = dmd::addMod (Type::tchar, dtype->mod);
+	      return dmd::addMod (dmd::pointerTo (dtype), mod);
 	    }
 
 	  if (dtype->ty == TY::Tfunction)
-	    return addMod (TypePointer::create (dtype), mod);
+	    return dmd::addMod (TypePointer::create (dtype), mod);
 
-	  return addMod (dtype->pointerTo (), mod);
+	  return dmd::addMod (dmd::pointerTo (dtype), mod);
 	}
       break;
 
@@ -116,7 +116,7 @@ build_frontend_type (tree type)
 	  /* Want to assign ctype directly so that the REFERENCE_TYPE code
 	     can be turned into as an `inout' argument.  Can't use pointerTo(),
 	     because the returned Type is shared.  */
-	  dtype = addMod (TypePointer::create (dtype), mod);
+	  dtype = dmd::addMod (TypePointer::create (dtype), mod);
 	  dtype->ctype = type;
 	  builtin_converted_decls.safe_push (builtin_data (dtype, type));
 	  return dtype;
@@ -125,7 +125,7 @@ build_frontend_type (tree type)
 
     case BOOLEAN_TYPE:
       /* Should be no need for size checking.  */
-      return addMod (Type::tbool, mod);
+      return dmd::addMod (Type::tbool, mod);
 
     case INTEGER_TYPE:
     {
@@ -143,7 +143,7 @@ build_frontend_type (tree type)
 	      || size != dtype->size ())
 	    continue;
 
-	  return addMod (dtype, mod);
+	  return dmd::addMod (dtype, mod);
 	}
       break;
     }
@@ -160,7 +160,7 @@ build_frontend_type (tree type)
 	  if (dtype->size () != size)
 	    continue;
 
-	  return addMod (dtype, mod);
+	  return dmd::addMod (dtype, mod);
 	}
       break;
     }
@@ -177,13 +177,13 @@ build_frontend_type (tree type)
 	  if (dtype->size () != size)
 	    continue;
 
-	  return addMod (dtype, mod);
+	  return dmd::addMod (dtype, mod);
 	}
       break;
     }
 
     case VOID_TYPE:
-      return addMod (Type::tvoid, mod);
+      return dmd::addMod (Type::tvoid, mod);
 
     case ARRAY_TYPE:
       dtype = build_frontend_type (TREE_TYPE (type));
@@ -197,7 +197,8 @@ build_frontend_type (tree type)
 	  length = size_binop (PLUS_EXPR, size_one_node,
 			       convert (sizetype, length));
 
-	  dtype = addMod (dtype->sarrayOf (TREE_INT_CST_LOW (length)), mod);
+	  dtype =
+	    dmd::addMod (dtype->sarrayOf (TREE_INT_CST_LOW (length)), mod);
 	  builtin_converted_decls.safe_push (builtin_data (dtype, type));
 	  return dtype;
 	}
@@ -213,11 +214,11 @@ build_frontend_type (tree type)
       if (!dtype)
 	break;
 
-      dtype = addMod (dtype->sarrayOf (nunits), mod);
+      dtype = dmd::addMod (dtype->sarrayOf (nunits), mod);
       if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ()))
 	break;
 
-      dtype = addMod (TypeVector::create (dtype), mod);
+      dtype = dmd::addMod (TypeVector::create (dtype), mod);
       builtin_converted_decls.safe_push (builtin_data (dtype, type));
       return dtype;
     }
@@ -241,9 +242,9 @@ build_frontend_type (tree type)
       sdecl->alignsize = TYPE_ALIGN_UNIT (type);
       sdecl->alignment.setDefault ();
       sdecl->sizeok = Sizeok::done;
-      sdecl->type = addMod (TypeStruct::create (sdecl), mod);
+      sdecl->type = dmd::addMod (TypeStruct::create (sdecl), mod);
       sdecl->type->ctype = type;
-      merge2 (sdecl->type);
+      dmd::merge2 (sdecl->type);
 
       /* Add both named and anonymous fields as members of the struct.
 	 Anonymous fields still need a name in D, so call them "__pad%u".  */
@@ -334,7 +335,7 @@ build_frontend_type (tree type)
 	  if (args->length != 0 || varargs_p == VARARGnone)
 	    {
 	      dtype = TypeFunction::create (args, dtype, varargs_p, LINK::c);
-	      return addMod (dtype, mod);
+	      return dmd::addMod (dtype, mod);
 	    }
 	}
       break;
@@ -690,10 +691,10 @@ strip_type_modifiers (Type *type)
   if (type->ty == TY::Tpointer)
     {
       Type *tnext = strip_type_modifiers (type->nextOf ());
-      return tnext->pointerTo ();
+      return dmd::pointerTo (tnext);
     }
 
-  return castMod (type, 0);
+  return dmd::castMod (type, 0);
 }
 
 /* Returns true if types T1 and T2 representing return types or types of
@@ -727,7 +728,7 @@ static bool
 covariant_with_builtin_type_p (Type *t1, Type *t2)
 {
   /* Check whether the declared function matches the built-in.  */
-  if (same_type_p (t1, t2) || covariant (t1, t2) == Covariant::yes)
+  if (same_type_p (t1, t2) || dmd::covariant (t1, t2) == Covariant::yes)
     return true;
 
   /* May not be covariant because of D attributes applied on t1.
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index dc528164aaf..5bc233928aa 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -150,14 +150,14 @@ declaration_type (Declaration *decl)
       TypeFunction *tf = TypeFunction::create (NULL, decl->type,
 					       VARARGnone, LINK::d);
       TypeDelegate *t = TypeDelegate::create (tf);
-      return build_ctype (merge2 (t));
+      return build_ctype (dmd::merge2 (t));
     }
 
   /* Static array va_list have array->pointer conversions applied.  */
   if (decl->isParameter () && valist_array_p (decl->type))
     {
-      Type *valist = decl->type->nextOf ()->pointerTo ();
-      valist = castMod (valist, decl->type->mod);
+      Type *valist = dmd::pointerTo (decl->type->nextOf ());
+      valist = dmd::castMod (valist, decl->type->mod);
       return build_ctype (valist);
     }
 
@@ -200,14 +200,14 @@ parameter_type (Parameter *arg)
       TypeFunction *tf = TypeFunction::create (NULL, arg->type,
 					       VARARGnone, LINK::d);
       TypeDelegate *t = TypeDelegate::create (tf);
-      return build_ctype (merge2 (t));
+      return build_ctype (dmd::merge2 (t));
     }
 
   /* Static array va_list have array->pointer conversions applied.  */
   if (valist_array_p (arg->type))
     {
-      Type *valist = arg->type->nextOf ()->pointerTo ();
-      valist = castMod (valist, arg->type->mod);
+      Type *valist = dmd::pointerTo (arg->type->nextOf ());
+      valist = dmd::castMod (valist, arg->type->mod);
       return build_ctype (valist);
     }
 
@@ -1089,7 +1089,7 @@ build_array_struct_comparison (tree_code code, StructDeclaration *sd,
   add_stmt (build_assign (INIT_EXPR, result, init));
 
   /* Cast pointer-to-array to pointer-to-struct.  */
-  tree ptrtype = build_ctype (sd->type->pointerTo ());
+  tree ptrtype = build_ctype (dmd::pointerTo (sd->type));
   tree lentype = TREE_TYPE (length);
 
   push_binding_level (level_block);
@@ -1859,7 +1859,7 @@ void_okay_p (tree t)
 
   if (VOID_TYPE_P (TREE_TYPE (type)))
     {
-      tree totype = build_ctype (Type::tuns8->pointerTo ());
+      tree totype = build_ctype (dmd::pointerTo (Type::tuns8));
       return fold_convert (totype, t);
     }
 
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index 011b22ec28c..4ccbf0908b5 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -470,7 +470,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	  dinteger_t esize = ebtype->nextOf ()->size ();
 	  dinteger_t tsize = tbtype->nextOf ()->size ();
 
-	  tree ptrtype = build_ctype (tbtype->nextOf ()->pointerTo ());
+	  tree ptrtype = build_ctype (dmd::pointerTo (tbtype->nextOf ()));
 
 	  if (esize != tsize)
 	    {
@@ -727,12 +727,12 @@ check_valist_conversion (Expression *expr, Type *totype, bool in_assignment)
   if (VarExp *ve = expr->isVarExp ())
     {
       decl = ve->var;
-      type = ve->var->type->nextOf ()->pointerTo ();
+      type = dmd::pointerTo (ve->var->type->nextOf ());
     }
   else if (SymOffExp *se = expr->isSymOffExp ())
     {
       decl = se->var;
-      type = se->var->type->nextOf ()->pointerTo ()->pointerTo ();
+      type = dmd::pointerTo (dmd::pointerTo (se->var->type->nextOf ()));
     }
 
   /* Should not be called unless is_valist_parameter_type also matched.  */
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 138a7f9d0f9..89ffa7e61ea 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -1029,8 +1029,8 @@ d_generate_ddoc_file (Module *m, OutBuffer &ddocbuf)
   d_read_ddoc_files (global.params.ddoc.files, ddocbuf);
 
   OutBuffer ddocbuf_out;
-  gendocfile (m, ddocbuf.peekChars (), ddocbuf.length (), global.datetime,
-	      global.errorSink, ddocbuf_out);
+  dmd::gendocfile (m, ddocbuf.peekChars (), ddocbuf.length (), global.datetime,
+		   global.errorSink, ddocbuf_out);
 
   d_write_file (m->docfile.toChars (), ddocbuf_out.peekChars ());
 }
@@ -1205,7 +1205,7 @@ d_parse_file (void)
 	    message ("import    %s", m->toChars ());
 
 	  OutBuffer buf;
-	  genhdrfile (m, global.params.dihdr.fullOutput, buf);
+	  dmd::genhdrfile (m, global.params.dihdr.fullOutput, buf);
 	  d_write_file (m->hdrfile.toChars (), buf.peekChars ());
 	}
 
@@ -1223,7 +1223,7 @@ d_parse_file (void)
       if (global.params.v.verbose)
 	message ("importall %s", m->toChars ());
 
-      importAll (m, NULL);
+      dmd::importAll (m, NULL);
     }
 
   if (global.errors)
@@ -1247,7 +1247,7 @@ d_parse_file (void)
       if (global.params.v.verbose)
 	message ("semantic  %s", m->toChars ());
 
-      dsymbolSemantic (m, NULL);
+      dmd::dsymbolSemantic (m, NULL);
     }
 
   /* Do deferred semantic analysis.  */
@@ -1278,7 +1278,7 @@ d_parse_file (void)
       if (global.params.v.verbose)
 	message ("semantic2 %s", m->toChars ());
 
-      semantic2 (m, NULL);
+      dmd::semantic2 (m, NULL);
     }
 
   Module::runDeferredSemantic2 ();
@@ -1294,7 +1294,7 @@ d_parse_file (void)
       if (global.params.v.verbose)
 	message ("semantic3 %s", m->toChars ());
 
-      semantic3 (m, NULL);
+      dmd::semantic3 (m, NULL);
     }
 
   Module::runDeferredSemantic3 ();
@@ -1318,7 +1318,7 @@ d_parse_file (void)
       /* Declare the name of the root module as the first global name in order
 	 to make the middle-end fully deterministic.  */
       OutBuffer buf;
-      mangleToBuffer (Module::rootModule, buf);
+      dmd::mangleToBuffer (Module::rootModule, buf);
       first_global_object_name = buf.extractChars ();
     }
 
@@ -1341,15 +1341,15 @@ d_parse_file (void)
 
   if (global.params.v.templates)
     {
-      printTemplateStats (global.params.v.templatesListInstances,
-			  global.errorSink);
+      dmd::printTemplateStats (global.params.v.templatesListInstances,
+			       global.errorSink);
     }
 
   /* Generate JSON files.  */
   if (global.params.json.doOutput)
     {
       OutBuffer buf;
-      json_generate (modules, buf);
+      dmd::json_generate (modules, buf);
       d_write_file (global.params.json.name.ptr, buf.peekChars ());
     }
 
@@ -1372,14 +1372,14 @@ d_parse_file (void)
 	  OutBuffer buf;
 	  buf.doindent = 1;
 
-	  moduleToBuffer (buf, true, m);
+	  dmd::moduleToBuffer (buf, true, m);
 	  message ("%s", buf.peekChars ());
 	}
     }
 
   /* Generate C++ header files.  */
   if (global.params.cxxhdr.doOutput)
-    genCppHdrFiles (modules);
+    dmd::genCppHdrFiles (modules);
 
   if (global.errors)
     goto had_errors;
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index ff3489c6cf4..b9d124422b7 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -335,7 +335,7 @@ Target::isVectorOpSupported (Type *type, EXP op, Type *)
 const char *
 TargetCPP::toMangle (Dsymbol *s)
 {
-  return toCppMangleItanium (s);
+  return dmd::toCppMangleItanium (s);
 }
 
 /* Return the symbol mangling of CD for C++ linkage.  */
@@ -343,7 +343,7 @@ TargetCPP::toMangle (Dsymbol *s)
 const char *
 TargetCPP::typeInfoMangle (ClassDeclaration *cd)
 {
-  return cppTypeInfoMangleItanium (cd);
+  return dmd::cppTypeInfoMangleItanium (cd);
 }
 
 /* Get mangle name of a this-adjusting thunk to the function declaration FD
@@ -352,7 +352,7 @@ TargetCPP::typeInfoMangle (ClassDeclaration *cd)
 const char *
 TargetCPP::thunkMangle (FuncDeclaration *fd, int offset)
 {
-  return cppThunkMangleItanium (fd, offset);
+  return dmd::cppThunkMangleItanium (fd, offset);
 }
 
 /* For a vendor-specific type, return a string containing the C++ mangling.
@@ -381,11 +381,11 @@ TargetCPP::parameterType (Type *type)
   Type *tvalist = target.va_listType (Loc (), NULL);
   if (type->ty == TY::Tsarray && tvalist->ty == TY::Tsarray)
     {
-      Type *tb = mutableOf (type->toBasetype ());
+      Type *tb = dmd::mutableOf (type->toBasetype ());
       if (tb == tvalist)
 	{
-	  tb = type->nextOf ()->pointerTo ();
-	  type = castMod (tb, type->mod);
+	  tb = dmd::pointerTo (type->nextOf ());
+	  type = dmd::castMod (tb, type->mod);
 	}
     }
 
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 827495b3e30..25398a32381 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -69,11 +69,11 @@ const char *
 d_mangle_decl (Dsymbol *decl)
 {
   if (decl->isFuncDeclaration ())
-    return mangleExact ((FuncDeclaration *) decl);
+    return dmd::mangleExact ((FuncDeclaration *) decl);
   else
     {
       OutBuffer buf;
-      mangleToBuffer (decl, buf);
+      dmd::mangleToBuffer (decl, buf);
       return buf.extractChars ();
     }
 }
@@ -332,6 +332,14 @@ public:
     d->semanticRun = PASS::obj;
   }
 
+  /* Finish a top-level `asm` definition.  */
+
+  void visit (CAsmDeclaration *d) final override
+  {
+    tree asm_str = build_expr (d->code);
+    symtab->finalize_toplevel_asm (asm_str);
+  }
+
   /* Expand any local variables found in tuples.  */
 
   void visit (TupleDeclaration *d) final override
@@ -402,7 +410,7 @@ public:
 
   void visit (Nspace *d) final override
   {
-    if (isError (d) || !d->members)
+    if (dmd::isError (d) || !d->members)
       return;
 
     for (size_t i = 0; i < d->members->length; i++)
@@ -447,7 +455,7 @@ public:
 
   void visit (TemplateInstance *d) final override
   {
-    if (isError (d)|| !d->members)
+    if (dmd::isError (d)|| !d->members)
       return;
 
     if (!d->needsCodegen ())
@@ -461,7 +469,7 @@ public:
 
   void visit (TemplateMixin *d) final override
   {
-    if (isError (d)|| !d->members)
+    if (dmd::isError (d)|| !d->members)
       return;
 
     for (size_t i = 0; i < d->members->length; i++)
@@ -539,7 +547,7 @@ public:
 	  continue;
 
 	/* Ensure function has a return value.  */
-	if (!functionSemantic (fd))
+	if (!dmd::functionSemantic (fd))
 	  has_errors = true;
 
 	/* No name hiding to check for.  */
@@ -765,7 +773,7 @@ public:
 	    && d->_init && !d->_init->isVoidInitializer ())
 	  {
 	    /* Evaluate RHS for side effects first.  */
-	    Expression *ie = initializerToExpression (d->_init);
+	    Expression *ie = dmd::initializerToExpression (d->_init);
 	    add_stmt (build_expr (ie));
 
 	    Expression *e = d->type->defaultInitLiteral (d->loc);
@@ -785,7 +793,7 @@ public:
       {
 	/* Do not store variables we cannot take the address of,
 	   but keep the values for purposes of debugging.  */
-	if (d->type->isscalar () && !hasPointers (d->type))
+	if (d->type->isscalar () && !dmd::hasPointers (d->type))
 	  {
 	    tree decl = get_symbol_decl (d);
 	    d_pushdecl (decl);
@@ -820,7 +828,8 @@ public:
 	    /* Use the explicit initializer, this includes `void`.  */
 	    if (!d->_init->isVoidInitializer ())
 	      {
-		Expression *e = initializerToExpression (d->_init, d->type);
+		Expression *e =
+		  dmd::initializerToExpression (d->_init, d->type);
 		DECL_INITIAL (decl) = build_expr (e, true);
 	      }
 	  }
@@ -857,7 +866,7 @@ public:
 	    tree decl = get_symbol_decl (d);
 
 	    ExpInitializer *vinit = d->_init->isExpInitializer ();
-	    Expression *ie = initializerToExpression (vinit);
+	    Expression *ie = dmd::initializerToExpression (vinit);
 	    tree exp = build_expr (ie);
 
 	    /* Maybe put variable on list of things needing destruction.  */
@@ -964,7 +973,7 @@ public:
 	gcc_assert (!doing_semantic_analysis_p);
 
 	doing_semantic_analysis_p = true;
-	functionSemantic3 (d);
+	dmd::functionSemantic3 (d);
 	Module::runDeferredSemantic3 ();
 	doing_semantic_analysis_p = false;
       }
@@ -1241,7 +1250,7 @@ get_symbol_decl (Declaration *decl)
       if (!vd->canTakeAddressOf () && !vd->type->isscalar ())
 	{
 	  gcc_assert (vd->_init && !vd->_init->isVoidInitializer ());
-	  Expression *ie = initializerToExpression (vd->_init);
+	  Expression *ie = dmd::initializerToExpression (vd->_init);
 	  decl->csym = build_expr (ie, false);
 	  return decl->csym;
 	}
@@ -1252,7 +1261,7 @@ get_symbol_decl (Declaration *decl)
   if (fd)
     {
       /* Run full semantic on functions we need to know about.  */
-      if (!functionSemantic (fd))
+      if (!dmd::functionSemantic (fd))
 	{
 	  decl->csym = error_mark_node;
 	  return decl->csym;
@@ -1301,7 +1310,7 @@ get_symbol_decl (Declaration *decl)
 	  /* Non-scalar manifest constants have already been dealt with.  */
 	  gcc_assert (vd->type->isscalar ());
 
-	  Expression *ie = initializerToExpression (vd->_init);
+	  Expression *ie = dmd::initializerToExpression (vd->_init);
 	  DECL_INITIAL (decl->csym) = build_expr (ie, true);
 	}
 
@@ -2398,7 +2407,7 @@ layout_class_initializer (ClassDeclaration *cd)
   NewExp *ne = NewExp::create (cd->loc, NULL, cd->type, NULL);
   ne->type = cd->type;
 
-  Expression *e = ctfeInterpret (ne);
+  Expression *e = dmd::ctfeInterpret (ne);
   gcc_assert (e->op == EXP::classReference);
 
   return build_class_instance (e->isClassReferenceExp ());
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 74c194508f7..021149aabc7 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-11240a96635074b2f79d908b9348e9c0fbc3c7dc
+9471b25db9ed44d71e0e27956430c0c6a09c16db
 
 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/VERSION b/gcc/d/dmd/VERSION
index 8463aee451c..1880c9808c5 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.107.0
+v2.107.1-rc.1
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index 6a864002e08..c972f0a6631 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -41,8 +41,11 @@ enum class Baseok : uint8_t
     semanticdone  // all base classes semantic done
 };
 
-FuncDeclaration *search_toString(StructDeclaration *sd);
-void semanticTypeInfoMembers(StructDeclaration *sd);
+namespace dmd
+{
+    FuncDeclaration *search_toString(StructDeclaration *sd);
+    void semanticTypeInfoMembers(StructDeclaration *sd);
+}
 
 enum class ClassKind : uint8_t
 {
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index d4623505816..536a212536d 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -136,6 +136,23 @@ final class CParser(AST) : Parser!AST
                 return wrap;
             }
 
+            /* GNU Extensions
+             * external-declaration:
+             *    simple-asm-expr ;
+             */
+            if (token.value == TOK.asm_)
+            {
+                nextToken();     // move past asm
+                check(TOK.leftParenthesis);
+                if (token.value != TOK.string_)
+                    error("string literal expected for Asm Definition, not `%s`", token.toChars());
+                auto code = cparsePrimaryExp();
+                check(TOK.rightParenthesis);
+                symbols.push(new AST.CAsmDeclaration(code));
+                check(TOK.semicolon);
+                continue;
+            }
+
             cparseDeclaration(LVL.global);
         }
     }
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 90b6295ab2f..0116aa35c8c 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -65,7 +65,7 @@ package CppOperator isCppOperator(Identifier id)
 }
 
 ///
-extern(C++) const(char)* toCppMangleItanium(Dsymbol s)
+const(char)* toCppMangleItanium(Dsymbol s)
 {
     //printf("toCppMangleItanium(%s)\n", s.toChars());
     OutBuffer buf;
@@ -75,7 +75,7 @@ extern(C++) const(char)* toCppMangleItanium(Dsymbol s)
 }
 
 ///
-extern(C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s)
+const(char)* cppTypeInfoMangleItanium(Dsymbol s)
 {
     //printf("cppTypeInfoMangle(%s)\n", s.toChars());
     OutBuffer buf;
@@ -86,7 +86,7 @@ extern(C++) const(char)* cppTypeInfoMangleItanium(Dsymbol s)
 }
 
 ///
-extern(C++) const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
+const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
 {
     //printf("cppThunkMangleItanium(%s)\n", fd.toChars());
     OutBuffer buf;
diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d
new file mode 100644
index 00000000000..1b94a69da23
--- /dev/null
+++ b/gcc/d/dmd/cxxfrontend.d
@@ -0,0 +1,623 @@
+/**
+ * Contains C++ interfaces for interacting with DMD as a library.
+ *
+ * Copyright:   Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
+ * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/cxxfrontend.d, _cxxfrontend.d)
+ * Documentation:  https://dlang.org/phobos/dmd_cxxfrontend.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/cxxfrontend.d
+ */
+module dmd.cxxfrontend;
+
+import dmd.aggregate : AggregateDeclaration;
+import dmd.arraytypes;
+import dmd.astenums;
+import dmd.common.outbuffer : OutBuffer;
+import dmd.dmodule /*: Module*/;
+import dmd.dscope : Scope;
+import dmd.dstruct /*: StructDeclaration*/;
+import dmd.dsymbol : Dsymbol, ScopeDsymbol, CAsmDeclaration, SearchOpt, SearchOptFlags;
+import dmd.dtemplate /*: TemplateInstance, TemplateParameter, Tuple*/;
+import dmd.errorsink : ErrorSink;
+import dmd.expression /*: Expression*/;
+import dmd.func : FuncDeclaration;
+import dmd.globals;
+import dmd.identifier : Identifier;
+import dmd.init : Initializer, NeedInterpret;
+import dmd.location : Loc;
+import dmd.mtype /*: Covariant, Type, Parameter, ParameterList*/;
+import dmd.rootobject : RootObject;
+import dmd.statement : Statement, AsmStatement, GccAsmStatement;
+
+// NB: At some point in the future, we can switch to shortened function syntax.
+extern (C++, "dmd"):
+
+/***********************************************************
+ * cppmangle.d
+ */
+const(char)* toCppMangleItanium(Dsymbol s)
+{
+    import dmd.cppmangle;
+    return dmd.cppmangle.toCppMangleItanium(s);
+}
+
+const(char)* cppTypeInfoMangleItanium(Dsymbol s)
+{
+    import dmd.cppmangle;
+    return dmd.cppmangle.cppTypeInfoMangleItanium(s);
+}
+
+const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
+{
+    import dmd.cppmangle;
+    return dmd.cppmangle.cppThunkMangleItanium(fd, offset);
+}
+
+/***********************************************************
+ * dinterpret.d
+ */
+Expression ctfeInterpret(Expression e)
+{
+    import dmd.dinterpret;
+    return dmd.dinterpret.ctfeInterpret(e);
+}
+
+/***********************************************************
+ * dmangle.d
+ */
+const(char)* mangleExact(FuncDeclaration fd)
+{
+    import dmd.dmangle;
+    return dmd.dmangle.mangleExact(fd);
+}
+
+void mangleToBuffer(Type t, ref OutBuffer buf)
+{
+    import dmd.dmangle;
+    return dmd.dmangle.mangleToBuffer(t, buf);
+}
+
+void mangleToBuffer(Expression e, ref OutBuffer buf)
+{
+    import dmd.dmangle;
+    return dmd.dmangle.mangleToBuffer(e, buf);
+}
+
+void mangleToBuffer(Dsymbol s, ref OutBuffer buf)
+{
+    import dmd.dmangle;
+    return dmd.dmangle.mangleToBuffer(s, buf);
+}
+
+void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
+{
+    import dmd.dmangle;
+    return dmd.dmangle.mangleToBuffer(ti, buf);
+}
+
+/***********************************************************
+ * dmodule.d
+ */
+void getLocalClasses(Module mod, ref ClassDeclarations aclasses)
+{
+    return dmd.dmodule.getLocalClasses(mod, aclasses);
+}
+
+FuncDeclaration findGetMembers(ScopeDsymbol dsym)
+{
+    return dmd.dmodule.findGetMembers(dsym);
+}
+
+/***********************************************************
+ * doc.d
+ */
+void gendocfile(Module m, const char* ddoctext_ptr, size_t ddoctext_length,
+                const char* datetime, ErrorSink eSink, ref OutBuffer outbuf)
+{
+    import dmd.doc;
+    return dmd.doc.gendocfile(m, ddoctext_ptr, ddoctext_length, datetime, eSink, outbuf);
+}
+
+/***********************************************************
+ * dstruct.d
+ */
+FuncDeclaration search_toString(StructDeclaration sd)
+{
+    return dmd.dstruct.search_toString(sd);
+}
+
+/***********************************************************
+ * dsymbolsem.d
+ */
+void dsymbolSemantic(Dsymbol dsym, Scope* sc)
+{
+    import dmd.dsymbolsem;
+    return dmd.dsymbolsem.dsymbolSemantic(dsym, sc);
+}
+
+void addMember(Dsymbol dsym, Scope* sc, ScopeDsymbol sds)
+{
+    import dmd.dsymbolsem;
+    return dmd.dsymbolsem.addMember(dsym, sc, sds);
+}
+
+Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags
+               flags = SearchOpt.all)
+{
+    import dmd.dsymbolsem;
+    return dmd.dsymbolsem.search(d, loc, ident, flags);
+}
+
+void setScope(Dsymbol d, Scope* sc)
+{
+    import dmd.dsymbolsem;
+    return dmd.dsymbolsem.setScope(d, sc);
+}
+
+void importAll(Dsymbol d, Scope* sc)
+{
+    import dmd.dsymbolsem;
+    return dmd.dsymbolsem.importAll(d, sc);
+}
+
+/***********************************************************
+ * dtemplate.d
+ */
+inout(Expression) isExpression(inout RootObject o)
+{
+    return dmd.dtemplate.isExpression(o);
+}
+
+inout(Dsymbol) isDsymbol(inout RootObject o)
+{
+    return dmd.dtemplate.isDsymbol(o);
+}
+
+inout(Type) isType(inout RootObject o)
+{
+    return dmd.dtemplate.isType(o);
+}
+
+inout(Tuple) isTuple(inout RootObject o)
+{
+    return dmd.dtemplate.isTuple(o);
+}
+
+inout(Parameter) isParameter(inout RootObject o)
+{
+    return dmd.dtemplate.isParameter(o);
+}
+
+inout(TemplateParameter) isTemplateParameter(inout RootObject o)
+{
+    return dmd.dtemplate.isTemplateParameter(o);
+}
+
+bool isError(const RootObject o)
+{
+    return dmd.dtemplate.isError(o);
+}
+
+void printTemplateStats(bool listInstances, ErrorSink eSink)
+{
+    return dmd.dtemplate.printTemplateStats(listInstances, eSink);
+}
+
+/***********************************************************
+ * dtoh.d
+ */
+void genCppHdrFiles(ref Modules ms)
+{
+    import dmd.dtoh;
+    return dmd.dtoh.genCppHdrFiles(ms);
+}
+
+/***********************************************************
+ * expression.d
+ */
+void expandTuples(Expressions* exps, Identifiers* names = null)
+{
+    return dmd.expression.expandTuples(exps, names);
+}
+
+/***********************************************************
+ * expressionsem.d
+ */
+Expression expressionSemantic(Expression e, Scope* sc)
+{
+    import dmd.expressionsem;
+    return dmd.expressionsem.expressionSemantic(e, sc);
+}
+
+/***********************************************************
+ * funcsem.d
+ */
+bool functionSemantic(FuncDeclaration fd)
+{
+    import dmd.funcsem;
+    return dmd.funcsem.functionSemantic(fd);
+}
+
+bool functionSemantic3(FuncDeclaration fd)
+{
+    import dmd.funcsem;
+    return dmd.funcsem.functionSemantic3(fd);
+}
+
+/***********************************************************
+ * hdrgen.d
+ */
+void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf)
+{
+    import dmd.hdrgen;
+    return dmd.hdrgen.genhdrfile(m, doFuncBodies, buf);
+}
+
+const(char)* toChars(const Statement s)
+{
+    import dmd.hdrgen;
+    return dmd.hdrgen.toChars(s);
+}
+
+const(char)* toChars(const Expression e)
+{
+    import dmd.hdrgen;
+    return dmd.hdrgen.toChars(e);
+}
+
+const(char)* toChars(const Initializer i)
+{
+    import dmd.hdrgen;
+    return dmd.hdrgen.toChars(i);
+}
+
+const(char)* toChars(const Type t)
+{
+    import dmd.hdrgen;
+    return dmd.hdrgen.toChars(t);
+}
+
+void moduleToBuffer(ref OutBuffer buf, bool vcg_ast, Module m)
+{
+    import dmd.hdrgen;
+    return dmd.hdrgen.moduleToBuffer(buf, vcg_ast, m);
+}
+
+const(char)* parametersTypeToChars(ParameterList pl)
+{
+    import dmd.hdrgen;
+    return dmd.hdrgen.parametersTypeToChars(pl);
+}
+
+/***********************************************************
+ * iasm.d
+ */
+Statement asmSemantic(AsmStatement s, Scope *sc)
+{
+    import dmd.iasm;
+    return dmd.iasm.asmSemantic(s, sc);
+}
+
+void asmSemantic(CAsmDeclaration d, Scope *sc)
+{
+    import dmd.iasm;
+    return dmd.iasm.asmSemantic(d, sc);
+}
+
+/***********************************************************
+ * iasmgcc.d
+ */
+Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
+{
+    import dmd.iasmgcc;
+    return dmd.iasmgcc.gccAsmSemantic(s, sc);
+}
+
+void gccAsmSemantic(CAsmDeclaration d, Scope *sc)
+{
+    import dmd.iasmgcc;
+    return dmd.iasmgcc.gccAsmSemantic(d, sc);
+}
+
+/***********************************************************
+ * initsem.d
+ */
+Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx,
+                                NeedInterpret needInterpret)
+{
+    import dmd.initsem;
+    return dmd.initsem.initializerSemantic(init, sc, tx, needInterpret);
+}
+
+Expression initializerToExpression(Initializer init, Type itype = null, const
+                                   bool isCfile = false)
+{
+    import dmd.initsem;
+    return dmd.initsem.initializerToExpression(init, itype, isCfile);
+}
+
+/***********************************************************
+ * json.d
+ */
+void json_generate(ref Modules modules, ref OutBuffer buf)
+{
+    import dmd.json;
+    return dmd.json.json_generate(modules, buf);
+}
+
+JsonFieldFlags tryParseJsonField(const(char)* fieldName)
+{
+    import dmd.json;
+    return dmd.json.tryParseJsonField(fieldName);
+}
+
+/***********************************************************
+ * mtype.d
+ */
+AggregateDeclaration isAggregate(Type t)
+{
+    return dmd.mtype.isAggregate(t);
+}
+
+/***********************************************************
+ * optimize.d
+ */
+Expression optimize(Expression e, int result, bool keepLvalue = false)
+{
+    import dmd.optimize;
+    return dmd.optimize.optimize(e, result, keepLvalue);
+}
+
+/***********************************************************
+ * semantic2.d
+ */
+void semantic2(Dsymbol dsym, Scope* sc)
+{
+    import dmd.semantic2;
+    return dmd.semantic2.semantic2(dsym, sc);
+}
+
+/***********************************************************
+ * semantic3.d
+ */
+void semantic3(Dsymbol dsym, Scope* sc)
+{
+    import dmd.semantic3;
+    return dmd.semantic3.semantic3(dsym, sc);
+}
+
+void semanticTypeInfoMembers(StructDeclaration sd)
+{
+    import dmd.semantic3;
+    return dmd.semantic3.semanticTypeInfoMembers(sd);
+}
+
+/***********************************************************
+ * statementsem.d
+ */
+Statement statementSemantic(Statement s, Scope* sc)
+{
+    import dmd.statementsem;
+    return dmd.statementsem.statementSemantic(s, sc);
+}
+
+/***********************************************************
+ * templateparamsem.d
+ */
+bool tpsemantic(TemplateParameter tp, Scope* sc, TemplateParameters* parameters)
+{
+    import dmd.templateparamsem;
+    return dmd.templateparamsem.tpsemantic(tp, sc, parameters);
+}
+
+/***********************************************************
+ * typesem.d
+ */
+bool hasPointers(Type t)
+{
+    import dmd.typesem;
+    return dmd.typesem.hasPointers(t);
+}
+
+Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
+{
+    import dmd.typesem;
+    return dmd.typesem.typeSemantic(type, loc, sc);
+}
+
+Type trySemantic(Type type, const ref Loc loc, Scope* sc)
+{
+    import dmd.typesem;
+    return dmd.typesem.trySemantic(type, loc, sc);
+}
+
+Type merge(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.merge(type);
+}
+
+Type merge2(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.merge2(type);
+}
+
+Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
+{
+    import dmd.typesem;
+    return dmd.typesem.defaultInit(mt, loc, isCfile);
+}
+
+Dsymbol toDsymbol(Type type, Scope* sc)
+{
+    import dmd.typesem;
+    return dmd.typesem.toDsymbol(type, sc);
+}
+
+Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool
+                    cppCovariant = false)
+{
+    import dmd.typesem;
+    return dmd.typesem.covariant(src, t, pstc, cppCovariant);
+}
+
+bool isBaseOf(Type tthis, Type t, int* poffset)
+{
+    import dmd.typesem;
+    return dmd.typesem.isBaseOf(tthis, t, poffset);
+}
+
+bool equivalent(Type src, Type t)
+{
+    import dmd.typesem;
+    return dmd.typesem.equivalent(src, t);
+}
+
+Type constOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.constOf(type);
+}
+
+Type immutableOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.immutableOf(type);
+}
+
+Type mutableOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.mutableOf(type);
+}
+
+Type sharedOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.sharedOf(type);
+}
+
+Type sharedConstOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.sharedConstOf(type);
+}
+
+Type unSharedOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.unSharedOf(type);
+}
+
+Type wildOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.wildOf(type);
+}
+
+Type wildConstOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.wildConstOf(type);
+}
+
+Type sharedWildOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.sharedWildOf(type);
+}
+
+Type sharedWildConstOf(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.sharedWildConstOf(type);
+}
+
+Type castMod(Type type, MOD mod)
+{
+    import dmd.typesem;
+    return dmd.typesem.castMod(type, mod);
+}
+
+Type addMod(Type type, MOD mod)
+{
+    import dmd.typesem;
+    return dmd.typesem.addMod(type, mod);
+}
+
+Type addStorageClass(Type type, StorageClass stc)
+{
+    import dmd.typesem;
+    return dmd.typesem.addStorageClass(type, stc);
+}
+
+Type pointerTo(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.pointerTo(type);
+}
+
+Type referenceTo(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.referenceTo(type);
+}
+
+/***********************************************************
+ * typinf.d
+ */
+bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
+{
+    import dmd.typinf;
+    return dmd.typinf.genTypeInfo(e, loc, torig, sc);
+}
+
+bool isSpeculativeType(Type t)
+{
+    import dmd.typinf;
+    return dmd.typinf.isSpeculativeType(t);
+}
+
+bool builtinTypeInfo(Type t)
+{
+    import dmd.typinf;
+    return dmd.typinf.builtinTypeInfo(t);
+}
+
+version (IN_LLVM)
+{
+    /***********************************************************
+     * argtypes_aarch64.d
+     */
+    TypeTuple toArgTypes_aarch64(Type t)
+    {
+        import dmd.argtypes_aarch64;
+        return dmd.argtypes_aarch64.toArgTypes_aarch64(t);
+    }
+
+    bool isHFVA(Type t, int maxNumElements = 4, Type* rewriteType = null)
+    {
+        import dmd.argtypes_aarch64;
+        return dmd.argtypes_aarch64.isHFVA(t, maxNumElements, rewriteType);
+    }
+
+    /***********************************************************
+     * argtypes_sysv_x64.d
+     */
+    TypeTuple toArgTypes_sysv_x64(Type t)
+    {
+        import dmd.argtypes_sysv_x64;
+        return dmd.argtypes_sysv_x64.toArgTypes_sysv_x64(t);
+    }
+
+    /***********************************************************
+     * argtypes_x86.d
+     */
+    TypeTuple toArgTypes_x86(Type t)
+    {
+        import dmd.argtypes_x86;
+        return dmd.argtypes_x86.toArgTypes_x86(t);
+    }
+}
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index a393da80c09..998beba97dd 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -30,8 +30,11 @@ class StructDeclaration;
 struct IntRange;
 struct AttributeViolation;
 
-bool functionSemantic(FuncDeclaration* fd);
-bool functionSemantic3(FuncDeclaration* fd);
+namespace dmd
+{
+    bool functionSemantic(FuncDeclaration* fd);
+    bool functionSemantic3(FuncDeclaration* fd);
+}
 
 //enum STC : ulong from astenums.d:
 
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index c3395a584e2..467e29f3c3c 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -50,7 +50,7 @@ import dmd.rootobject;
 import dmd.root.utf;
 import dmd.statement;
 import dmd.tokens;
-import dmd.typesem : mutableOf, equivalent;
+import dmd.typesem : mutableOf, equivalent, pointerTo;
 import dmd.utils : arrayCastBigEndian;
 import dmd.visitor;
 
@@ -63,7 +63,7 @@ import dmd.visitor;
  * functions and may invoke a function that contains `ErrorStatement` in its body.
  * If that, the "CTFE failed because of previous errors" error is raised.
  */
-extern(C++) public Expression ctfeInterpret(Expression e)
+public Expression ctfeInterpret(Expression e)
 {
     switch (e.op)
     {
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index 1d016479e1d..33428ded2d1 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -18,7 +18,7 @@ module dmd.dmangle;
 /******************************************************************************
  * Returns exact mangled name of function.
  */
-extern (C++) const(char)* mangleExact(FuncDeclaration fd)
+const(char)* mangleExact(FuncDeclaration fd)
 {
     //printf("mangleExact()\n");
     if (!fd.mangleString)
@@ -32,7 +32,7 @@ extern (C++) const(char)* mangleExact(FuncDeclaration fd)
     return fd.mangleString;
 }
 
-extern (C++) void mangleToBuffer(Type t, ref OutBuffer buf)
+void mangleToBuffer(Type t, ref OutBuffer buf)
 {
     //printf("mangleToBuffer t()\n");
     if (t.deco)
@@ -45,7 +45,7 @@ extern (C++) void mangleToBuffer(Type t, ref OutBuffer buf)
     }
 }
 
-extern (C++) void mangleToBuffer(Expression e, ref OutBuffer buf)
+void mangleToBuffer(Expression e, ref OutBuffer buf)
 {
     //printf("mangleToBuffer e()\n");
     auto backref = Backref(null);
@@ -53,7 +53,7 @@ extern (C++) void mangleToBuffer(Expression e, ref OutBuffer buf)
     e.accept(v);
 }
 
-extern (C++) void mangleToBuffer(Dsymbol s, ref OutBuffer buf)
+void mangleToBuffer(Dsymbol s, ref OutBuffer buf)
 {
     //printf("mangleToBuffer s(%s)\n", s.toChars());
     auto backref = Backref(null);
@@ -61,7 +61,7 @@ extern (C++) void mangleToBuffer(Dsymbol s, ref OutBuffer buf)
     s.accept(v);
 }
 
-extern (C++) void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
+void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
 {
     //printf("mangleToBuffer ti()\n");
     auto backref = Backref(null);
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 6167e2a7486..07d5077ee49 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -1300,7 +1300,7 @@ extern (C++) struct ModuleDeclaration
  *      aclasses = array to fill in
  * Returns: array of local classes
  */
-extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses)
+void getLocalClasses(Module mod, ref ClassDeclarations aclasses)
 {
     //printf("members.length = %d\n", mod.members.length);
     int pushAddClassDg(size_t n, Dsymbol sm)
@@ -1565,7 +1565,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
  *      const(MemberInfo)[] getMembers(string);
  * Returns NULL if not found
  */
-extern(C++) FuncDeclaration findGetMembers(ScopeDsymbol dsym)
+FuncDeclaration findGetMembers(ScopeDsymbol dsym)
 {
     import dmd.opover : search_function;
     Dsymbol s = search_function(dsym, Id.getmembers);
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index bcf358cb5e9..c00c1cc8f40 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -382,7 +382,7 @@ immutable ddoc_decl_dd_e = ")\n";
  *      outbuf = append the Ddoc text to this
  */
 public
-extern(C++) void gendocfile(Module m, const char* ddoctext_ptr, size_t ddoctext_length, const char* datetime, ErrorSink eSink, ref OutBuffer outbuf)
+void gendocfile(Module m, const char* ddoctext_ptr, size_t ddoctext_length, const char* datetime, ErrorSink eSink, ref OutBuffer outbuf)
 {
     gendocfile(m, ddoctext_ptr[0 .. ddoctext_length], datetime, eSink, outbuf);
 }
diff --git a/gcc/d/dmd/doc.h b/gcc/d/dmd/doc.h
index 71a66b90cb8..1775e354e00 100644
--- a/gcc/d/dmd/doc.h
+++ b/gcc/d/dmd/doc.h
@@ -15,5 +15,8 @@
 class Module;
 class ErrorSink;
 
-void gendocfile(Module *m, const char *ddoctext_ptr, d_size_t ddoctext_length,
-                const char *datetime, ErrorSink *eSink, OutBuffer &outbuf);
+namespace dmd
+{
+    void gendocfile(Module *m, const char *ddoctext_ptr, d_size_t ddoctext_length,
+                    const char *datetime, ErrorSink *eSink, OutBuffer &outbuf);
+}
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index e02ba9a873b..76a26a245fb 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -34,6 +34,7 @@ import dmd.func;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
+import dmd.importc;
 import dmd.location;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 7546fb6146b..df4d07a81d9 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -48,7 +48,7 @@ import dmd.visitor;
  * Returns:
  *   FuncDeclaration of `toString()` if found, `null` if not
  */
-extern (C++) FuncDeclaration search_toString(StructDeclaration sd)
+FuncDeclaration search_toString(StructDeclaration sd)
 {
     Dsymbol s = search_function(sd, Id.tostring);
     FuncDeclaration fd = s ? s.isFuncDeclaration() : null;
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 5e7922ea11d..b831c32c28b 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -1105,6 +1105,7 @@ extern (C++) class Dsymbol : ASTNode
     inout(MixinDeclaration)            isMixinDeclaration()            inout { return null; }
     inout(StaticAssert)                isStaticAssert()                inout { return null; }
     inout(StaticIfDeclaration)         isStaticIfDeclaration()         inout { return null; }
+    inout(CAsmDeclaration)             isCAsmDeclaration()             inout { return null; }
 }
 
 /***********************************************************
@@ -1700,275 +1701,25 @@ extern (C++) final class DsymbolTable : RootObject
     }
 }
 
-/**********************************************
- * ImportC tag symbols sit in a parallel symbol table,
- * so that this C code works:
- * ---
- * struct S { a; };
- * int S;
- * struct S s;
- * ---
- * But there are relatively few such tag symbols, so that would be
- * a waste of memory and complexity. An additional problem is we'd like the D side
- * to find the tag symbols with ordinary lookup, not lookup in both
- * tables, if the tag symbol is not conflicting with an ordinary symbol.
- * The solution is to put the tag symbols that conflict into an associative
- * array, indexed by the address of the ordinary symbol that conflicts with it.
- * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
- * A side effect of our approach is that D code cannot access a tag symbol that is
- * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
- * has mentioned it when importing C headers. If someone wants to do it,
- * too bad so sad. Change the C code.
- * This function fixes up the symbol table when faced with adding a new symbol
- * `s` when there is an existing symbol `s2` with the same name.
- * C also allows forward and prototype declarations of tag symbols,
- * this function merges those.
- * 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 handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
-{
-    enum log = false;
-    if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
-    if (log) printf("  add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
-    auto sd = s.isScopeDsymbol(); // new declaration
-    auto sd2 = s2.isScopeDsymbol(); // existing declaration
-
-    static if (log) void print(EnumDeclaration sd)
-    {
-        printf("members: %p\n", sd.members);
-        printf("symtab: %p\n", sd.symtab);
-        printf("endlinnum: %d\n", sd.endlinnum);
-        printf("type: %s\n", sd.type.toChars());
-        printf("memtype: %s\n", sd.memtype.toChars());
-    }
-
-    if (!sd2)
-    {
-        /* Look in tag table
-         */
-        if (log) printf(" look in tag table\n");
-        if (auto p = cast(void*)s2 in sc._module.tagSymTab)
-        {
-            Dsymbol s2tag = *p;
-            sd2 = s2tag.isScopeDsymbol();
-            assert(sd2);        // only tags allowed in tag symbol table
-        }
-    }
-
-    if (sd && sd2) // `s` is a tag, `sd2` is the same tag
-    {
-        if (log) printf(" tag is already defined\n");
-
-        if (sd.kind() != sd2.kind())  // being enum/struct/union must match
-            return null;              // conflict
-
-        /* Not a redeclaration if one is a forward declaration.
-         * Move members to the first declared type, which is sd2.
-         */
-        if (sd2.members)
-        {
-            if (!sd.members)
-                return sd2;  // ignore the sd redeclaration
-        }
-        else if (sd.members)
-        {
-            sd2.members = sd.members; // transfer definition to sd2
-            sd.members = null;
-            if (auto ed2 = sd2.isEnumDeclaration())
-            {
-                auto ed = sd.isEnumDeclaration();
-                if (ed.memtype != ed2.memtype)
-                    return null;        // conflict
-
-                // transfer ed's members to sd2
-                ed2.members.foreachDsymbol( (s)
-                {
-                    if (auto em = s.isEnumMember())
-                        em.ed = ed2;
-                });
-
-                ed2.type = ed.type;
-                ed2.memtype = ed.memtype;
-                ed2.added = false;
-            }
-            return sd2;
-        }
-        else
-            return sd2; // ignore redeclaration
-    }
-    else if (sd) // `s` is a tag, `s2` is not
-    {
-        if (log) printf(" s is tag, s2 is not\n");
-        /* add `s` as tag indexed by s2
-         */
-        sc._module.tagSymTab[cast(void*)s2] = s;
-        return s;
-    }
-    else if (s2 is sd2) // `s2` is a tag, `s` is not
-    {
-        if (log) printf(" s2 is tag, s is not\n");
-        /* replace `s2` in symbol table with `s`,
-         * then add `s2` as tag indexed by `s`
-         */
-        sds.symtab.update(s);
-        sc._module.tagSymTab[cast(void*)s] = s2;
-        return s;
-    }
-    // neither s2 nor s is a tag
-    if (log) printf(" collision\n");
-    return null;
-}
-
-
-/**********************************************
- * 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
+/**
+ * ImportC global `asm` definition.
  */
-Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
+extern (C++) final class CAsmDeclaration : Dsymbol
 {
-    enum log = false;
-    if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
-    if (log) printf("  add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
-
-    static Dsymbol collision()
+    Expression code;
+    extern (D) this(Expression e) nothrow @safe
     {
-        if (log) printf(" collision\n");
-        return null;
-    }
-    /*
-    Handle merging declarations with asm("foo") and their definitions
-    */
-    static void mangleWrangle(Declaration oldDecl, Declaration newDecl)
-    {
-        if (oldDecl && newDecl)
-        {
-            newDecl.mangleOverride = oldDecl.mangleOverride ? oldDecl.mangleOverride : null;
-        }
+        super();
+        this.code = e;
     }
 
-    auto vd = s.isVarDeclaration(); // new declaration
-    auto vd2 = s2.isVarDeclaration(); // existing declaration
-
-    if (vd && vd.isCmacro())
-        return vd2;
-
-    assert(!(vd2 && vd2.isCmacro()));
-
-    if (vd && vd2)
+    override inout(CAsmDeclaration) isCAsmDeclaration() inout nothrow
     {
-        /* if one is `static` and the other isn't, the result is undefined
-         * behavior, C11 6.2.2.7
-         */
-        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
-
-        mangleWrangle(vd2, vd);
-
-        if (i1)                         // vd is the definition
-        {
-            vd2.storage_class |= STC.extern_;  // so toObjFile() won't emit it
-            sds.symtab.update(vd);      // replace vd2 with the definition
-            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, the result is undefined
-         * behavior, C11 6.2.2.7
-         * However, match what gcc allows:
-         *    static int sun1(); int sun1() { return 0; }
-         * and:
-         *    static int sun2() { return 0; } int sun2();
-         * Both produce a static function.
-         *
-         * Both of these should fail:
-         *    int sun3(); static int sun3() { return 0; }
-         * and:
-         *    int sun4() { return 0; } static int sun4();
-         */
-        // if adding `static`
-        if (   fd.storage_class & STC.static_ &&
-            !(fd2.storage_class & STC.static_))
-        {
-            return collision();
-        }
-
-        if (fd.fbody && fd2.fbody)
-            return collision();         // can't both have bodies
-
-        mangleWrangle(fd2, fd);
-
-        if (fd.fbody)                   // fd is the definition
-        {
-            if (log) printf(" replace existing with new\n");
-            sds.symtab.update(fd);      // replace fd2 in symbol table with fd
-            fd.overnext = fd2;
-
-            /* If fd2 is covering a tag symbol, then fd has to cover the same one
-             */
-            auto ps = cast(void*)fd2 in sc._module.tagSymTab;
-            if (ps)
-                sc._module.tagSymTab[cast(void*)fd] = *ps;
-
-            return fd;
-        }
-
-        /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
-         * FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
-         */
-        fd2.overloadInsert(fd);
-
-        return fd2;
+        return this;
     }
 
-    auto td  = s.isAliasDeclaration();  // new declaration
-    auto td2 = s2.isAliasDeclaration(); // existing declaration
-    if (td && td2)
+    override void accept(Visitor v)
     {
-        /* 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;
+        v.visit(this);
     }
-
-    return collision();
 }
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index db236275570..f8454354fed 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -73,6 +73,7 @@ class AliasAssign;
 class OverloadSet;
 class StaticAssert;
 class StaticIfDeclaration;
+class CAsmDeclaration;
 struct AA;
 #ifdef IN_GCC
 typedef union tree_node Symbol;
@@ -95,9 +96,16 @@ enum class ThreeState : uint8_t
     yes,          // value is true
 };
 
-void dsymbolSemantic(Dsymbol *dsym, Scope *sc);
-void semantic2(Dsymbol *dsym, Scope *sc);
-void semantic3(Dsymbol *dsym, Scope* sc);
+namespace dmd
+{
+    void dsymbolSemantic(Dsymbol *dsym, Scope *sc);
+    void semantic2(Dsymbol *dsym, Scope *sc);
+    void semantic3(Dsymbol *dsym, Scope* sc);
+    // in iasm.d
+    void asmSemantic(CAsmDeclaration *ad, Scope *sc);
+    // in iasmgcc.d
+    void gccAsmSemantic(CAsmDeclaration *ad, Scope *sc);
+}
 
 struct Visibility
 {
@@ -315,6 +323,7 @@ public:
     virtual MixinDeclaration *isMixinDeclaration() { return NULL; }
     virtual StaticAssert *isStaticAssert() { return NULL; }
     virtual StaticIfDeclaration *isStaticIfDeclaration() { return NULL; }
+    virtual CAsmDeclaration *isCAsmDeclaration() { return NULL; }
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -404,6 +413,15 @@ public:
     ExpressionDsymbol *isExpressionDsymbol() override { return this; }
 };
 
+class CAsmDeclaration final : public Dsymbol
+{
+public:
+    Expression *code;   // string expression
+
+    CAsmDeclaration *isCAsmDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
+};
+
 // Table of Dsymbol's
 
 class DsymbolTable final : public RootObject
@@ -425,7 +443,10 @@ public:
     size_t length() const;
 };
 
-void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
-Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
-void setScope(Dsymbol *d, Scope *sc);
-void importAll(Dsymbol *d, Scope *sc);
+namespace dmd
+{
+    void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
+    Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
+    void setScope(Dsymbol *d, Scope *sc);
+    void importAll(Dsymbol *d, Scope *sc);
+}
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 4a4d82ff5c0..c15d925ce0a 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -85,7 +85,7 @@ enum LOG = false;
 /*************************************
  * Does semantic analysis on the public face of declarations.
  */
-extern(C++) void dsymbolSemantic(Dsymbol dsym, Scope* sc)
+void dsymbolSemantic(Dsymbol dsym, Scope* sc)
 {
     scope v = new DsymbolSemanticVisitor(sc);
     dsym.accept(v);
@@ -1440,6 +1440,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         assert(dsym._linkage == LINK.c);
     }
 
+    override void visit(CAsmDeclaration dsym)
+    {
+        if (dsym.semanticRun >= PASS.semanticdone)
+            return;
+        import dmd.iasm : asmSemantic;
+        asmSemantic(dsym, sc);
+        dsym.semanticRun = PASS.semanticdone;
+    }
+
     override void visit(BitFieldDeclaration dsym)
     {
         //printf("BitField::semantic('%s')\n", dsym.toChars());
@@ -4059,7 +4068,7 @@ Params:
     sc = scope where the dsymbol is declared
     sds = ScopeDsymbol where dsym is inserted
 */
-extern(C++) void addMember(Dsymbol dsym, Scope* sc, ScopeDsymbol sds)
+void addMember(Dsymbol dsym, Scope* sc, ScopeDsymbol sds)
 {
     auto addMemberVisitor = new AddMemberVisitor(sc, sds);
     dsym.accept(addMemberVisitor);
@@ -5979,7 +5988,7 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope*
  * Returns:
  *  null if not found
  */
-extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all)
+Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all)
 {
     scope v = new SearchVisitor(loc, ident, flags);
     d.accept(v);
@@ -6621,7 +6630,7 @@ private extern(C++) class SearchVisitor : Visitor
  *   d = dsymbol for which the scope is set
  *   sc = scope that is used to set the value
  */
-extern(C++) void setScope(Dsymbol d, Scope* sc)
+void setScope(Dsymbol d, Scope* sc)
 {
     scope setScopeVisitor = new SetScopeVisitor(sc);
     d.accept(setScopeVisitor);
@@ -6764,7 +6773,7 @@ private extern(C++) class SetScopeVisitor : Visitor
     }
 }
 
-extern(C++) void importAll(Dsymbol d, Scope* sc)
+void importAll(Dsymbol d, Scope* sc)
 {
     scope iav = new ImportAllVisitor(sc);
     d.accept(iav);
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 4a195e3e7c2..165a010059f 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -96,7 +96,7 @@ pure nothrow @nogc @safe
  * These functions substitute for dynamic_cast. dynamic_cast does not work
  * on earlier versions of gcc.
  */
-extern (C++) inout(Expression) isExpression(inout RootObject o)
+inout(Expression) isExpression(inout RootObject o)
 {
     //return dynamic_cast<Expression *>(o);
     if (!o || o.dyncast() != DYNCAST.expression)
@@ -104,7 +104,7 @@ extern (C++) inout(Expression) isExpression(inout RootObject o)
     return cast(inout(Expression))o;
 }
 
-extern (C++) inout(Dsymbol) isDsymbol(inout RootObject o)
+inout(Dsymbol) isDsymbol(inout RootObject o)
 {
     //return dynamic_cast<Dsymbol *>(o);
     if (!o || o.dyncast() != DYNCAST.dsymbol)
@@ -112,7 +112,7 @@ extern (C++) inout(Dsymbol) isDsymbol(inout RootObject o)
     return cast(inout(Dsymbol))o;
 }
 
-extern (C++) inout(Type) isType(inout RootObject o)
+inout(Type) isType(inout RootObject o)
 {
     //return dynamic_cast<Type *>(o);
     if (!o || o.dyncast() != DYNCAST.type)
@@ -120,7 +120,7 @@ extern (C++) inout(Type) isType(inout RootObject o)
     return cast(inout(Type))o;
 }
 
-extern (C++) inout(Tuple) isTuple(inout RootObject o)
+inout(Tuple) isTuple(inout RootObject o)
 {
     //return dynamic_cast<Tuple *>(o);
     if (!o || o.dyncast() != DYNCAST.tuple)
@@ -128,7 +128,7 @@ extern (C++) inout(Tuple) isTuple(inout RootObject o)
     return cast(inout(Tuple))o;
 }
 
-extern (C++) inout(Parameter) isParameter(inout RootObject o)
+inout(Parameter) isParameter(inout RootObject o)
 {
     //return dynamic_cast<Parameter *>(o);
     if (!o || o.dyncast() != DYNCAST.parameter)
@@ -136,7 +136,7 @@ extern (C++) inout(Parameter) isParameter(inout RootObject o)
     return cast(inout(Parameter))o;
 }
 
-extern (C++) inout(TemplateParameter) isTemplateParameter(inout RootObject o)
+inout(TemplateParameter) isTemplateParameter(inout RootObject o)
 {
     if (!o || o.dyncast() != DYNCAST.templateparameter)
         return null;
@@ -146,7 +146,7 @@ extern (C++) inout(TemplateParameter) isTemplateParameter(inout RootObject o)
 /**************************************
  * Is this Object an error?
  */
-extern (C++) bool isError(const RootObject o)
+bool isError(const RootObject o)
 {
     if (const t = isType(o))
         return (t.ty == Terror);
@@ -6311,7 +6311,7 @@ struct TemplateStats
  *      listInstances = list instances of templates
  *      eSink = where the print is sent
  */
-extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink)
+void printTemplateStats(bool listInstances, ErrorSink eSink)
 {
     static struct TemplateDeclarationStats
     {
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 4a1ff055157..2e2ced4b0d1 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -54,7 +54,7 @@ import dmd.utils;
  *  - ignored declarations are mentioned in a comment if `global.params.doCxxHdrGeneration`
  *    is set to `CxxHeaderMode.verbose`
  */
-extern(C++) void genCppHdrFiles(ref Modules ms)
+void genCppHdrFiles(ref Modules ms)
 {
     initialize();
 
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 82de837ef75..bc907cfd2f4 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -108,7 +108,7 @@ inout(Expression) lastComma(inout Expression e)
  *     exps  = array of Expressions
  *     names = optional array of names corresponding to Expressions
  */
-extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null)
+void expandTuples(Expressions* exps, Identifiers* names = null)
 {
     //printf("expandTuples()\n");
     if (exps is null)
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 8dbb4a63c7e..3bd8ca7568e 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -46,16 +46,19 @@ typedef union tree_node Symbol;
 struct Symbol;          // back end symbol
 #endif
 
-// in expressionsem.d
-Expression *expressionSemantic(Expression *e, Scope *sc);
-// in typesem.d
-Expression *defaultInit(Type *mt, const Loc &loc, const bool isCfile = false);
-
-// Entry point for CTFE.
-// A compile-time result is required. Give an error if not possible
-Expression *ctfeInterpret(Expression *e);
-void expandTuples(Expressions *exps, Identifiers *names = nullptr);
-Expression *optimize(Expression *exp, int result, bool keepLvalue = false);
+namespace dmd
+{
+    // in expressionsem.d
+    Expression *expressionSemantic(Expression *e, Scope *sc);
+    // in typesem.d
+    Expression *defaultInit(Type *mt, const Loc &loc, const bool isCfile = false);
+
+    // Entry point for CTFE.
+    // A compile-time result is required. Give an error if not possible
+    Expression *ctfeInterpret(Expression *e);
+    void expandTuples(Expressions *exps, Identifiers *names = nullptr);
+    Expression *optimize(Expression *exp, int result, bool keepLvalue = false);
+}
 
 typedef unsigned char OwnedBy;
 enum
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 9028ba1b191..cc589b991d1 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -5023,7 +5023,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return setError();
 
                 checkFunctionAttributes(exp, sc, f);
-                checkAccess(cd, exp.loc, sc, f);
+                if (!checkSymbolAccess(sc, f))
+                {
+                    error(exp.loc, "%s `%s` is not accessible from module `%s`",
+                        f.kind(), f.toPrettyChars(), sc._module.toChars);
+                    return setError();
+                }
 
                 TypeFunction tf = f.type.isTypeFunction();
                 if (!exp.arguments)
@@ -6463,7 +6468,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return setError();
 
             checkFunctionAttributes(exp, sc, exp.f);
-            checkAccess(exp.loc, sc, null, exp.f);
+            if (!checkSymbolAccess(sc, exp.f))
+            {
+                error(exp.loc, "%s `%s` is not accessible from module `%s`",
+                    exp.f.kind(), exp.f.toPrettyChars(), sc._module.toChars);
+                return setError();
+            }
 
             exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
             exp.e1 = exp.e1.expressionSemantic(sc);
@@ -6649,7 +6659,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             assert(exp.f);
             tiargs = null;
 
-            if (exp.f.overnext)
+            if (ve.hasOverloads && exp.f.overnext)
                 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
             else
             {
@@ -14193,7 +14203,7 @@ Expression binSemanticProp(BinExp e, Scope* sc)
 }
 
 // entrypoint for semantic ExpressionSemanticVisitor
-extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
+Expression expressionSemantic(Expression e, Scope* sc)
 {
     scope v = new ExpressionSemanticVisitor(sc);
     e.accept(v);
@@ -14211,8 +14221,10 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
         // symbol.mangleof
 
         // return mangleof as an Expression
-        static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
+        static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds, bool hasOverloads)
         {
+            Expression e;
+
             assert(ds);
             if (auto f = ds.isFuncDeclaration())
             {
@@ -14224,24 +14236,40 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
                     error(loc, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f.kind, f.toPrettyChars);
                     return ErrorExp.get();
                 }
+
+                if (!hasOverloads)
+                    e = StringExp.create(loc, mangleExact(f));
             }
-            OutBuffer buf;
-            mangleToBuffer(ds, buf);
-            Expression e = new StringExp(loc, buf.extractSlice());
+
+            if (!e)
+            {
+                OutBuffer buf;
+                mangleToBuffer(ds, buf);
+                e = new StringExp(loc, buf.extractSlice());
+            }
+
             return e.expressionSemantic(sc);
         }
 
         Dsymbol ds;
         switch (exp.e1.op)
         {
-            case EXP.scope_:      return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
-            case EXP.variable:    return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
-            case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
-            case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
+            case EXP.scope_:      return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds, false);
+            case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars, false);
+            case EXP.variable:
+            {
+                VarExp ve = exp.e1.isVarExp();
+                return dotMangleof(exp.loc, sc, ve.var, ve.hasOverloads);
+            }
+            case EXP.dotVariable:
+            {
+                DotVarExp dve = exp.e1.isDotVarExp();
+                return dotMangleof(exp.loc, sc, dve.var, dve.hasOverloads);
+            }
             case EXP.template_:
             {
                 TemplateExp te = exp.e1.isTemplateExp();
-                return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
+                return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td, false);
             }
 
             default:
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
index 9e706ee80d9..49da6b20136 100644
--- a/gcc/d/dmd/funcsem.d
+++ b/gcc/d/dmd/funcsem.d
@@ -1042,7 +1042,6 @@ Ldone:
  *  false if any errors exist in the signature.
  */
 public
-extern (C++)
 bool functionSemantic(FuncDeclaration fd)
 {
     //printf("functionSemantic() %p %s\n", this, toChars());
@@ -1101,7 +1100,6 @@ bool functionSemantic(FuncDeclaration fd)
  * Returns false if any errors exist in the body.
  */
 public
-extern (C++)
 bool functionSemantic3(FuncDeclaration fd)
 {
     if (fd.semanticRun < PASS.semantic3 && fd._scope)
diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d
index b3980eb7930..a3a3bd01f13 100644
--- a/gcc/d/dmd/gluelayer.d
+++ b/gcc/d/dmd/gluelayer.d
@@ -30,19 +30,9 @@ version (NoBackend)
     struct TYPE;
     alias type = TYPE;
 
-    extern (C++)
+    extern(C++) abstract class ObjcGlue
     {
-        // iasm
-        Statement asmSemantic(AsmStatement s, Scope* sc)
-        {
-            sc.func.hasReturnExp = 8;
-            return null;
-        }
-
-        extern(C++) abstract class ObjcGlue
-        {
-            static void initialize() {}
-        }
+        static void initialize() {}
     }
 }
 else version (IN_GCC)
@@ -53,11 +43,6 @@ else version (IN_GCC)
     alias code = tree_node;
     alias type = tree_node;
 
-    extern (C++)
-    {
-        Statement asmSemantic(AsmStatement s, Scope* sc);
-    }
-
     // stubs
     extern(C++) abstract class ObjcGlue
     {
@@ -70,6 +55,5 @@ else
     public import dmd.backend.type : type;
     public import dmd.backend.el : elem;
     public import dmd.backend.code_x86 : code;
-    public import dmd.iasm : asmSemantic;
     public import dmd.objc_glue : ObjcGlue;
 }
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index e4cbcc5f0b9..8eef7992e2a 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -83,7 +83,7 @@ enum TEST_EMIT_ALL = 0;
  *      doFuncBodies = generate function definitions rather than just declarations
  *      buf = buffer to write the data to
  */
-extern (C++) void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf)
+void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf)
 {
     buf.doindent = 1;
     buf.printf("// D import file generated from '%s'", m.srcfile.toChars());
@@ -103,7 +103,7 @@ extern (C++) void genhdrfile(Module m, bool doFuncBodies, ref OutBuffer buf)
  * Returns:
  *      0-terminated string
  */
-public extern (C++) const(char)* toChars(const Statement s)
+public const(char)* toChars(const Statement s)
 {
     HdrGenState hgs;
     OutBuffer buf;
@@ -112,7 +112,7 @@ public extern (C++) const(char)* toChars(const Statement s)
     return buf.extractSlice().ptr;
 }
 
-public extern (C++) const(char)* toChars(const Expression e)
+public const(char)* toChars(const Expression e)
 {
     HdrGenState hgs;
     OutBuffer buf;
@@ -120,7 +120,7 @@ public extern (C++) const(char)* toChars(const Expression e)
     return buf.extractChars();
 }
 
-public extern (C++) const(char)* toChars(const Initializer i)
+public const(char)* toChars(const Initializer i)
 {
     OutBuffer buf;
     HdrGenState hgs;
@@ -128,7 +128,7 @@ public extern (C++) const(char)* toChars(const Initializer i)
     return buf.extractChars();
 }
 
-public extern (C++) const(char)* toChars(const Type t)
+public const(char)* toChars(const Type t)
 {
     OutBuffer buf;
     buf.reserve(16);
@@ -154,7 +154,7 @@ public const(char)[] toString(const Initializer i)
  *   vcg_ast = write out codegen ast
  *   m = module to visit all members of.
  */
-extern (C++) void moduleToBuffer(ref OutBuffer buf, bool vcg_ast, Module m)
+void moduleToBuffer(ref OutBuffer buf, bool vcg_ast, Module m)
 {
     HdrGenState hgs;
     hgs.fullDump = true;
@@ -3418,7 +3418,7 @@ void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects)
  *  pl = parameter list to print
  * Returns: Null-terminated string representing parameters.
  */
-extern (C++) const(char)* parametersTypeToChars(ParameterList pl)
+const(char)* parametersTypeToChars(ParameterList pl)
 {
     OutBuffer buf;
     HdrGenState hgs;
diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h
index e0a20461d45..14793ad23a8 100644
--- a/gcc/d/dmd/hdrgen.h
+++ b/gcc/d/dmd/hdrgen.h
@@ -18,12 +18,15 @@ class Initializer;
 class Module;
 class Statement;
 
-void genhdrfile(Module *m, bool doFuncBodies, OutBuffer &buf);
-void genCppHdrFiles(Modules &ms);
-void moduleToBuffer(OutBuffer& buf, bool vcg_ast, Module *m);
-const char *parametersTypeToChars(ParameterList pl);
+namespace dmd
+{
+    void genhdrfile(Module *m, bool doFuncBodies, OutBuffer &buf);
+    void genCppHdrFiles(Modules &ms);
+    void moduleToBuffer(OutBuffer& buf, bool vcg_ast, Module *m);
+    const char *parametersTypeToChars(ParameterList pl);
 
-const char* toChars(const Expression* const e);
-const char* toChars(const Initializer* const i);
-const char* toChars(const Statement* const s);
-const char* toChars(const Type* const t);
+    const char* toChars(const Expression* const e);
+    const char* toChars(const Initializer* const i);
+    const char* toChars(const Statement* const s);
+    const char* toChars(const Type* const t);
+}
diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d
index 24a45136cd5..1399ac27fae 100644
--- a/gcc/d/dmd/iasm.d
+++ b/gcc/d/dmd/iasm.d
@@ -16,6 +16,7 @@ module dmd.iasm;
 import core.stdc.stdio;
 
 import dmd.dscope;
+import dmd.dsymbol;
 import dmd.expression;
 import dmd.func;
 import dmd.mtype;
@@ -23,7 +24,10 @@ import dmd.tokens;
 import dmd.statement;
 import dmd.statementsem;
 
-version (IN_GCC)
+version (NoBackend)
+{
+}
+else version (IN_GCC)
 {
     import dmd.iasmgcc;
 }
@@ -35,7 +39,7 @@ else
 
 /************************ AsmStatement ***************************************/
 
-extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc)
+Statement asmSemantic(AsmStatement s, Scope *sc)
 {
     //printf("AsmStatement.semantic()\n");
 
@@ -48,7 +52,11 @@ extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc)
     // Assume assembler code takes care of setting the return value
     sc.func.hasReturnExp |= 8;
 
-    version (MARS)
+    version (NoBackend)
+    {
+        return null;
+    }
+    else version (MARS)
     {
         /* If it starts with a string literal, it's gcc inline asm
          */
@@ -78,3 +86,21 @@ extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc)
         return new ErrorStatement();
     }
 }
+
+/************************ CAsmDeclaration ************************************/
+
+void asmSemantic(CAsmDeclaration ad, Scope *sc)
+{
+    version (NoBackend)
+    {
+    }
+    else version (IN_GCC)
+    {
+        return gccAsmSemantic(ad, sc);
+    }
+    else
+    {
+        import dmd.errors : error;
+        error(ad.code.loc, "Gnu Asm not supported - compile this file with gcc or clang");
+    }
+}
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
index db51e734155..4b1b2e78c69 100644
--- a/gcc/d/dmd/iasmgcc.d
+++ b/gcc/d/dmd/iasmgcc.d
@@ -16,6 +16,7 @@ import core.stdc.string;
 import dmd.arraytypes;
 import dmd.astcodegen;
 import dmd.dscope;
+import dmd.dsymbol;
 import dmd.errors;
 import dmd.errorsink;
 import dmd.expression;
@@ -299,7 +300,7 @@ Ldone:
  * Returns:
  *      the completed gcc asm statement, or null if errors occurred
  */
-extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
+public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
 {
     //printf("GccAsmStatement.semantic()\n");
     const bool doUnittests = global.params.parsingUnittestsRequired();
@@ -382,6 +383,26 @@ extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
     return s;
 }
 
+/***********************************
+ * Run semantic analysis on an CAsmDeclaration.
+ * Params:
+ *      ad  = asm declaration
+ *      sc = the scope where the asm declaration is located
+ */
+public void gccAsmSemantic(CAsmDeclaration ad, Scope *sc)
+{
+    import dmd.typesem : pointerTo;
+    ad.code = semanticString(sc, ad.code, "asm definition");
+    ad.code.type = ad.code.type.nextOf().pointerTo();
+
+    // Asm definition always needs emitting into the root module.
+    import dmd.dmodule : Module;
+    if (sc._module && sc._module.isRoot())
+        return;
+    if (Module m = Module.rootModule)
+        m.members.push(ad);
+}
+
 unittest
 {
     import dmd.mtype : TypeBasic;
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
index 69a85ceec93..e4d5aa2cae1 100644
--- a/gcc/d/dmd/importc.d
+++ b/gcc/d/dmd/importc.d
@@ -366,3 +366,276 @@ bool cTypeEquivalence(Type t1, Type t2)
 
     return false;
 }
+
+/**********************************************
+ * ImportC tag symbols sit in a parallel symbol table,
+ * so that this C code works:
+ * ---
+ * struct S { a; };
+ * int S;
+ * struct S s;
+ * ---
+ * But there are relatively few such tag symbols, so that would be
+ * a waste of memory and complexity. An additional problem is we'd like the D side
+ * to find the tag symbols with ordinary lookup, not lookup in both
+ * tables, if the tag symbol is not conflicting with an ordinary symbol.
+ * The solution is to put the tag symbols that conflict into an associative
+ * array, indexed by the address of the ordinary symbol that conflicts with it.
+ * C has no modules, so this associative array is tagSymTab[] in ModuleDeclaration.
+ * A side effect of our approach is that D code cannot access a tag symbol that is
+ * hidden by an ordinary symbol. This is more of a theoretical problem, as nobody
+ * has mentioned it when importing C headers. If someone wants to do it,
+ * too bad so sad. Change the C code.
+ * This function fixes up the symbol table when faced with adding a new symbol
+ * `s` when there is an existing symbol `s2` with the same name.
+ * C also allows forward and prototype declarations of tag symbols,
+ * this function merges those.
+ * 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 handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
+{
+    enum log = false;
+    if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
+    if (log) printf("  add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
+    auto sd = s.isScopeDsymbol(); // new declaration
+    auto sd2 = s2.isScopeDsymbol(); // existing declaration
+
+    static if (log) void print(EnumDeclaration sd)
+    {
+        printf("members: %p\n", sd.members);
+        printf("symtab: %p\n", sd.symtab);
+        printf("endlinnum: %d\n", sd.endlinnum);
+        printf("type: %s\n", sd.type.toChars());
+        printf("memtype: %s\n", sd.memtype.toChars());
+    }
+
+    if (!sd2)
+    {
+        /* Look in tag table
+         */
+        if (log) printf(" look in tag table\n");
+        if (auto p = cast(void*)s2 in sc._module.tagSymTab)
+        {
+            Dsymbol s2tag = *p;
+            sd2 = s2tag.isScopeDsymbol();
+            assert(sd2);        // only tags allowed in tag symbol table
+        }
+    }
+
+    if (sd && sd2) // `s` is a tag, `sd2` is the same tag
+    {
+        if (log) printf(" tag is already defined\n");
+
+        if (sd.kind() != sd2.kind())  // being enum/struct/union must match
+            return null;              // conflict
+
+        /* Not a redeclaration if one is a forward declaration.
+         * Move members to the first declared type, which is sd2.
+         */
+        if (sd2.members)
+        {
+            if (!sd.members)
+                return sd2;  // ignore the sd redeclaration
+        }
+        else if (sd.members)
+        {
+            sd2.members = sd.members; // transfer definition to sd2
+            sd.members = null;
+            if (auto ed2 = sd2.isEnumDeclaration())
+            {
+                auto ed = sd.isEnumDeclaration();
+                if (ed.memtype != ed2.memtype)
+                    return null;        // conflict
+
+                // transfer ed's members to sd2
+                ed2.members.foreachDsymbol( (s)
+                {
+                    if (auto em = s.isEnumMember())
+                        em.ed = ed2;
+                });
+
+                ed2.type = ed.type;
+                ed2.memtype = ed.memtype;
+                ed2.added = false;
+            }
+            return sd2;
+        }
+        else
+            return sd2; // ignore redeclaration
+    }
+    else if (sd) // `s` is a tag, `s2` is not
+    {
+        if (log) printf(" s is tag, s2 is not\n");
+        /* add `s` as tag indexed by s2
+         */
+        sc._module.tagSymTab[cast(void*)s2] = s;
+        return s;
+    }
+    else if (s2 is sd2) // `s2` is a tag, `s` is not
+    {
+        if (log) printf(" s2 is tag, s is not\n");
+        /* replace `s2` in symbol table with `s`,
+         * then add `s2` as tag indexed by `s`
+         */
+        sds.symtab.update(s);
+        sc._module.tagSymTab[cast(void*)s] = s2;
+        return s;
+    }
+    // neither s2 nor s is a tag
+    if (log) printf(" collision\n");
+    return null;
+}
+
+
+/**********************************************
+ * 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());
+    if (log) printf("  add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
+
+    static Dsymbol collision()
+    {
+        if (log) printf(" collision\n");
+        return null;
+    }
+    /*
+    Handle merging declarations with asm("foo") and their definitions
+    */
+    static void mangleWrangle(Declaration oldDecl, Declaration newDecl)
+    {
+        if (oldDecl && newDecl)
+        {
+            newDecl.mangleOverride = oldDecl.mangleOverride ? oldDecl.mangleOverride : null;
+        }
+    }
+
+    auto vd = s.isVarDeclaration(); // new declaration
+    auto vd2 = s2.isVarDeclaration(); // existing declaration
+
+    if (vd && vd.isCmacro())
+        return vd2;
+
+    assert(!(vd2 && vd2.isCmacro()));
+
+    if (vd && vd2)
+    {
+        /* if one is `static` and the other isn't, the result is undefined
+         * behavior, C11 6.2.2.7
+         */
+        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
+
+        mangleWrangle(vd2, vd);
+
+        if (i1)                         // vd is the definition
+        {
+            vd2.storage_class |= STC.extern_;  // so toObjFile() won't emit it
+            sds.symtab.update(vd);      // replace vd2 with the definition
+            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, the result is undefined
+         * behavior, C11 6.2.2.7
+         * However, match what gcc allows:
+         *    static int sun1(); int sun1() { return 0; }
+         * and:
+         *    static int sun2() { return 0; } int sun2();
+         * Both produce a static function.
+         *
+         * Both of these should fail:
+         *    int sun3(); static int sun3() { return 0; }
+         * and:
+         *    int sun4() { return 0; } static int sun4();
+         */
+        // if adding `static`
+        if (   fd.storage_class & STC.static_ &&
+            !(fd2.storage_class & STC.static_))
+        {
+            return collision();
+        }
+
+        if (fd.fbody && fd2.fbody)
+            return collision();         // can't both have bodies
+
+        mangleWrangle(fd2, fd);
+
+        if (fd.fbody)                   // fd is the definition
+        {
+            if (log) printf(" replace existing with new\n");
+            sds.symtab.update(fd);      // replace fd2 in symbol table with fd
+            fd.overnext = fd2;
+
+            /* If fd2 is covering a tag symbol, then fd has to cover the same one
+             */
+            auto ps = cast(void*)fd2 in sc._module.tagSymTab;
+            if (ps)
+                sc._module.tagSymTab[cast(void*)fd] = *ps;
+
+            return fd;
+        }
+
+        /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
+         * FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
+         */
+        fd2.overloadInsert(fd);
+
+        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/init.h b/gcc/d/dmd/init.h
index cccd3c97f2c..2485d78bb59 100644
--- a/gcc/d/dmd/init.h
+++ b/gcc/d/dmd/init.h
@@ -124,5 +124,8 @@ public:
     void accept(Visitor *v) override { v->visit(this); }
 };
 
-Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
-Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *&tx, NeedInterpret needInterpret);
+namespace dmd
+{
+    Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
+    Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *&tx, NeedInterpret needInterpret);
+}
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 79d7902fc9b..b07699e19fe 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -103,7 +103,7 @@ Expression toAssocArrayLiteral(ArrayInitializer ai)
  *      `Initializer` with completed semantic analysis, `ErrorInitializer` if errors
  *      were encountered
  */
-extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret)
+Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret)
 {
     //printf("initializerSemantic() tx: %p %s\n", tx, tx.toChars());
     Type t = tx;
@@ -1224,7 +1224,7 @@ Initializer inferType(Initializer init, Scope* sc)
  * Returns:
  *      `Expression` created, `null` if cannot, `ErrorExp` for other errors
  */
-extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
+Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
 {
     //printf("initializerToExpression() isCfile: %d\n", isCfile);
 
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
index 7c6506712fc..f20b3d4b38a 100644
--- a/gcc/d/dmd/json.d
+++ b/gcc/d/dmd/json.d
@@ -978,7 +978,7 @@ public:
  *      modules = array of Modules
  *      buf = write json output to buf
  */
-extern (C++) void json_generate(ref Modules modules, ref OutBuffer buf)
+void json_generate(ref Modules modules, ref OutBuffer buf)
 {
     scope ToJsonVisitor json = new ToJsonVisitor(&buf);
     // write trailing newline
@@ -1047,7 +1047,7 @@ Params:
 Returns: JsonFieldFlags.none on error, otherwise the JsonFieldFlags value
          corresponding to the given fieldName.
 */
-extern (C++) JsonFieldFlags tryParseJsonField(const(char)* fieldName)
+JsonFieldFlags tryParseJsonField(const(char)* fieldName)
 {
     auto fieldNameString = fieldName.toDString();
     foreach (idx, enumName; __traits(allMembers, JsonFieldFlags))
diff --git a/gcc/d/dmd/json.h b/gcc/d/dmd/json.h
index 8a949114feb..b119c9ede4e 100644
--- a/gcc/d/dmd/json.h
+++ b/gcc/d/dmd/json.h
@@ -15,5 +15,8 @@
 
 struct OutBuffer;
 
-void json_generate(Modules &, OutBuffer &);
-JsonFieldFlags tryParseJsonField(const char *fieldName);
+namespace dmd
+{
+    void json_generate(Modules &, OutBuffer &);
+    JsonFieldFlags tryParseJsonField(const char *fieldName);
+}
diff --git a/gcc/d/dmd/mangle.h b/gcc/d/dmd/mangle.h
index 68064a9210a..de6fa55f777 100644
--- a/gcc/d/dmd/mangle.h
+++ b/gcc/d/dmd/mangle.h
@@ -17,18 +17,21 @@ class TemplateInstance;
 class Type;
 struct OutBuffer;
 
-// In cppmangle.d
-const char *toCppMangleItanium(Dsymbol *s);
-const char *cppTypeInfoMangleItanium(Dsymbol *s);
-const char *cppThunkMangleItanium(FuncDeclaration *fd, int offset);
+namespace dmd
+{
+    // In cppmangle.d
+    const char *toCppMangleItanium(Dsymbol *s);
+    const char *cppTypeInfoMangleItanium(Dsymbol *s);
+    const char *cppThunkMangleItanium(FuncDeclaration *fd, int offset);
 
-// In cppmanglewin.d
-const char *toCppMangleMSVC(Dsymbol *s);
-const char *cppTypeInfoMangleMSVC(Dsymbol *s);
+    // In cppmanglewin.d
+    const char *toCppMangleMSVC(Dsymbol *s);
+    const char *cppTypeInfoMangleMSVC(Dsymbol *s);
 
-// In dmangle.d
-const char *mangleExact(FuncDeclaration *fd);
-void mangleToBuffer(Type *s, OutBuffer& buf);
-void mangleToBuffer(Expression *s, OutBuffer& buf);
-void mangleToBuffer(Dsymbol *s, OutBuffer& buf);
-void mangleToBuffer(TemplateInstance *s, OutBuffer& buf);
+    // In dmangle.d
+    const char *mangleExact(FuncDeclaration *fd);
+    void mangleToBuffer(Type *s, OutBuffer& buf);
+    void mangleToBuffer(Expression *s, OutBuffer& buf);
+    void mangleToBuffer(Dsymbol *s, OutBuffer& buf);
+    void mangleToBuffer(TemplateInstance *s, OutBuffer& buf);
+}
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index d09e873c495..379e8e6973a 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -167,5 +167,8 @@ struct ModuleDeclaration
     const char *toChars() const;
 };
 
-extern void getLocalClasses(Module* mod, Array<ClassDeclaration* >& aclasses);
-FuncDeclaration *findGetMembers(ScopeDsymbol *dsym);
+namespace dmd
+{
+    void getLocalClasses(Module* mod, Array<ClassDeclaration* >& aclasses);
+    FuncDeclaration *findGetMembers(ScopeDsymbol *dsym);
+}
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 4f8ed7594c7..09ed630fe8b 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -1186,58 +1186,6 @@ extern (C++) abstract class Type : ASTNode
         return t;
     }
 
-    /************************************
-     * Add storage class modifiers to type.
-     */
-    Type addStorageClass(StorageClass stc)
-    {
-        /* Just translate to MOD bits and let addMod() do the work
-         */
-        MOD mod = 0;
-        if (stc & STC.immutable_)
-            mod = MODFlags.immutable_;
-        else
-        {
-            if (stc & (STC.const_ | STC.in_))
-                mod |= MODFlags.const_;
-            if (stc & STC.wild)
-                mod |= MODFlags.wild;
-            if (stc & STC.shared_)
-                mod |= MODFlags.shared_;
-        }
-        return this.addMod(mod);
-    }
-
-    final Type pointerTo()
-    {
-        if (ty == Terror)
-            return this;
-        if (!pto)
-        {
-            Type t = new TypePointer(this);
-            if (ty == Tfunction)
-            {
-                t.deco = t.merge().deco;
-                pto = t;
-            }
-            else
-                pto = t.merge();
-        }
-        return pto;
-    }
-
-    final Type referenceTo()
-    {
-        if (ty == Terror)
-            return this;
-        if (!rto)
-        {
-            Type t = new TypeReference(this);
-            rto = t.merge();
-        }
-        return rto;
-    }
-
     final Type arrayOf()
     {
         if (ty == Terror)
@@ -3449,56 +3397,6 @@ extern (C++) final class TypeFunction : TypeNext
         return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
     }
 
-    override Type addStorageClass(StorageClass stc)
-    {
-        //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
-        TypeFunction t = Type.addStorageClass(stc).toTypeFunction();
-        if ((stc & STC.pure_ && !t.purity) ||
-            (stc & STC.nothrow_ && !t.isnothrow) ||
-            (stc & STC.nogc && !t.isnogc) ||
-            (stc & STC.scope_ && !t.isScopeQual) ||
-            (stc & STC.safe && t.trust < TRUST.trusted))
-        {
-            // Klunky to change these
-            auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0);
-            tf.mod = t.mod;
-            tf.fargs = fargs;
-            tf.purity = t.purity;
-            tf.isnothrow = t.isnothrow;
-            tf.isnogc = t.isnogc;
-            tf.isproperty = t.isproperty;
-            tf.isref = t.isref;
-            tf.isreturn = t.isreturn;
-            tf.isreturnscope = t.isreturnscope;
-            tf.isScopeQual = t.isScopeQual;
-            tf.isreturninferred = t.isreturninferred;
-            tf.isscopeinferred = t.isscopeinferred;
-            tf.trust = t.trust;
-            tf.isInOutParam = t.isInOutParam;
-            tf.isInOutQual = t.isInOutQual;
-            tf.isctor = t.isctor;
-
-            if (stc & STC.pure_)
-                tf.purity = PURE.fwdref;
-            if (stc & STC.nothrow_)
-                tf.isnothrow = true;
-            if (stc & STC.nogc)
-                tf.isnogc = true;
-            if (stc & STC.safe)
-                tf.trust = TRUST.safe;
-            if (stc & STC.scope_)
-            {
-                tf.isScopeQual = true;
-                if (stc & STC.scopeinferred)
-                    tf.isscopeinferred = true;
-            }
-
-            tf.deco = tf.merge().deco;
-            t = tf;
-        }
-        return t;
-    }
-
     override Type substWildTo(uint)
     {
         if (!iswild && !(mod & MODFlags.wild))
@@ -3800,12 +3698,6 @@ extern (C++) final class TypeDelegate : TypeNext
         return result;
     }
 
-    override Type addStorageClass(StorageClass stc)
-    {
-        TypeDelegate t = cast(TypeDelegate)Type.addStorageClass(stc);
-        return t;
-    }
-
     override uinteger_t size(const ref Loc loc)
     {
         return target.ptrsize * 2;
@@ -5673,7 +5565,7 @@ void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTforma
  * If the type is a class or struct, returns the symbol for it,
  * else null.
  */
-extern (C++) AggregateDeclaration isAggregate(Type t)
+AggregateDeclaration isAggregate(Type t)
 {
     t = t.toBasetype();
     if (t.ty == Tclass)
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index df8cc4dd6b6..57f4ec6e0d2 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -39,8 +39,11 @@ typedef union tree_node type;
 typedef struct TYPE type;
 #endif
 
-Type *typeSemantic(Type *t, const Loc &loc, Scope *sc);
-Type *merge(Type *type);
+namespace dmd
+{
+    Type *typeSemantic(Type *t, const Loc &loc, Scope *sc);
+    Type *merge(Type *type);
+}
 
 enum class TY : uint8_t
 {
@@ -251,9 +254,6 @@ public:
     bool isSharedWild() const  { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); }
     bool isNaked() const       { return mod == 0; }
     Type *nullAttributes() const;
-    virtual Type *addStorageClass(StorageClass stc);
-    Type *pointerTo();
-    Type *referenceTo();
     Type *arrayOf();
     Type *sarrayOf(dinteger_t dim);
     bool hasDeprecatedAliasThis();
@@ -579,7 +579,6 @@ public:
     TypeFunction *syntaxCopy() override;
     bool hasLazyParameters();
     bool isDstyleVariadic() const;
-    Type *addStorageClass(StorageClass stc) override;
 
     Type *substWildTo(unsigned mod) override;
     MATCH constConv(Type *to) override;
@@ -623,7 +622,6 @@ public:
     static TypeDelegate *create(TypeFunction *t);
     const char *kind() override;
     TypeDelegate *syntaxCopy() override;
-    Type *addStorageClass(StorageClass stc) override;
     uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
     MATCH implicitConvTo(Type *to) override;
@@ -880,26 +878,31 @@ public:
 
 /**************************************************************/
 
-
-// If the type is a class or struct, returns the symbol for it, else null.
-AggregateDeclaration *isAggregate(Type *t);
-bool hasPointers(Type *t);
-// return the symbol to which type t resolves
-Dsymbol *toDsymbol(Type *t, Scope *sc);
-bool equivalent(Type *src, Type *t);
-Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);
-bool isBaseOf(Type *tthis, Type *t, int *poffset);
-Type *trySemantic(Type *type, const Loc &loc, Scope *sc);
-Type *merge2(Type *type);
-Type *constOf(Type *type);
-Type *immutableOf(Type *type);
-Type *mutableOf(Type *type);
-Type *sharedOf(Type *type);
-Type *sharedConstOf(Type *type);
-Type *unSharedOf(Type *type);
-Type *wildOf(Type *type);
-Type *wildConstOf(Type *type);
-Type *sharedWildOf(Type *type);
-Type *sharedWildConstOf(Type *type);
-Type *castMod(Type *type, MOD mod);
-Type *addMod(Type *type, MOD mod);
+namespace dmd
+{
+    // If the type is a class or struct, returns the symbol for it, else null.
+    AggregateDeclaration *isAggregate(Type *t);
+    bool hasPointers(Type *t);
+    // return the symbol to which type t resolves
+    Dsymbol *toDsymbol(Type *t, Scope *sc);
+    bool equivalent(Type *src, Type *t);
+    Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);
+    bool isBaseOf(Type *tthis, Type *t, int *poffset);
+    Type *trySemantic(Type *type, const Loc &loc, Scope *sc);
+    Type *pointerTo(Type *type);
+    Type *referenceTo(Type *type);
+    Type *merge2(Type *type);
+    Type *constOf(Type *type);
+    Type *immutableOf(Type *type);
+    Type *mutableOf(Type *type);
+    Type *sharedOf(Type *type);
+    Type *sharedConstOf(Type *type);
+    Type *unSharedOf(Type *type);
+    Type *wildOf(Type *type);
+    Type *wildConstOf(Type *type);
+    Type *sharedWildOf(Type *type);
+    Type *sharedWildConstOf(Type *type);
+    Type *castMod(Type *type, MOD mod);
+    Type *addMod(Type *type, MOD mod);
+    Type *addStorageClass(Type *type, StorageClass stc);
+}
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 5c0ef67787c..dd6b117e0ac 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -273,7 +273,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type)
  * Returns:
  *      Constant folded version of `e`
  */
-extern (C++) Expression optimize(Expression e, int result, bool keepLvalue = false)
+Expression optimize(Expression e, int result, bool keepLvalue = false)
 {
     //printf("optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue);
     Expression ret = e;
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 2d2e6fde323..9c446eb1bf3 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -7180,6 +7180,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         }
         if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != NeedDeclaratorId.mustIfDstyle))
             goto Lisnot;
+        // needed for `__traits(compiles, arr[0] = 0)`
+        if (!haveId && t.value == TOK.assign)
+            goto Lisnot;
         if ((needId == NeedDeclaratorId.no && !haveId) ||
             (needId == NeedDeclaratorId.opt) ||
             (needId == NeedDeclaratorId.must && haveId) ||
diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d
index 422c1c8c0ec..c03f78d4de9 100644
--- a/gcc/d/dmd/parsetimevisitor.d
+++ b/gcc/d/dmd/parsetimevisitor.d
@@ -36,6 +36,7 @@ public:
     void visit(AST.DebugSymbol s) { visit(cast(AST.Dsymbol)s); }
     void visit(AST.VersionSymbol s) { visit(cast(AST.Dsymbol)s); }
     void visit(AST.AliasAssign s) { visit(cast(AST.Dsymbol)s); }
+    void visit(AST.CAsmDeclaration s) { visit(cast(AST.Dsymbol)s); }
 
     // ScopeDsymbols
     void visit(AST.Package s) { visit(cast(AST.ScopeDsymbol)s); }
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index b4f91ac7cf0..f5ce0c0ada6 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -73,7 +73,7 @@ enum LOG = false;
 /*************************************
  * Does semantic analysis on initializers and members of aggregates.
  */
-extern(C++) void semantic2(Dsymbol dsym, Scope* sc)
+void semantic2(Dsymbol dsym, Scope* sc)
 {
     scope v = new Semantic2Visitor(sc);
     dsym.accept(v);
@@ -876,7 +876,7 @@ private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor
         hookFunc = new DotIdExp(aaExp.loc, hookFunc, Id.object);
         hookFunc = new DotIdExp(aaExp.loc, hookFunc, Id._aaAsStruct);
         auto arguments = new Expressions();
-        arguments.push(aaExp.syntaxCopy());
+        arguments.push(aaExp);
         Expression loweredExp = new CallExp(aaExp.loc, hookFunc, arguments);
 
         sc = sc.startCTFE();
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 125a39d179f..882d1a9a355 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -79,7 +79,7 @@ enum LOG = false;
 /*************************************
  * Does semantic analysis on function bodies.
  */
-extern(C++) void semantic3(Dsymbol dsym, Scope* sc)
+void semantic3(Dsymbol dsym, Scope* sc)
 {
     scope v = new Semantic3Visitor(sc);
     dsym.accept(v);
@@ -1636,7 +1636,7 @@ private struct FuncDeclSem3
     }
 }
 
-extern (C++) void semanticTypeInfoMembers(StructDeclaration sd)
+void semanticTypeInfoMembers(StructDeclaration sd)
 {
     if (sd.xeq &&
         sd.xeq._scope &&
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index 8a6bf3d0d1c..ea80e510c52 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -701,12 +701,15 @@ public:
     void accept(Visitor *v) override { v->visit(this); }
 };
 
-// in statementsem.d
-Statement* statementSemantic(Statement *s, Scope *sc);
-// in iasm.d
-Statement* asmSemantic(AsmStatement *s, Scope *sc);
-// in iasmgcc.d
-Statement *gccAsmSemantic(GccAsmStatement *s, Scope *sc);
+namespace dmd
+{
+    // in statementsem.d
+    Statement* statementSemantic(Statement *s, Scope *sc);
+    // in iasm.d
+    Statement* asmSemantic(AsmStatement *s, Scope *sc);
+    // in iasmgcc.d
+    Statement *gccAsmSemantic(GccAsmStatement *s, Scope *sc);
+}
 
 class AsmStatement : public Statement
 {
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index a431d5c0922..5013c569933 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -41,8 +41,8 @@ import dmd.expressionsem;
 import dmd.func;
 import dmd.funcsem;
 import dmd.globals;
-import dmd.gluelayer;
 import dmd.hdrgen;
+import dmd.iasm;
 import dmd.id;
 import dmd.identifier;
 import dmd.importc;
@@ -135,7 +135,7 @@ private Expression checkAssignmentAsCondition(Expression e, Scope* sc)
 }
 
 // Performs semantic analysis in Statement AST nodes
-extern(C++) Statement statementSemantic(Statement s, Scope* sc)
+Statement statementSemantic(Statement s, Scope* sc)
 {
     import dmd.compiler;
 
diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d
index e63bf17a5f7..cff1d2e9bec 100644
--- a/gcc/d/dmd/target.d
+++ b/gcc/d/dmd/target.d
@@ -110,7 +110,7 @@ extern (C++) struct Target
 
     /// Architecture name
     const(char)[] architectureName;
-    CPU cpu = CPU.baseline; // CPU instruction set to target
+    CPU cpu;                // CPU instruction set to target
     bool isX86_64;          // generate 64 bit code for x86_64; true by default for 64 bit dmd
     bool isLP64;            // pointers are 64 bits
 
@@ -119,7 +119,7 @@ extern (C++) struct Target
     const(char)[] lib_ext;    /// extension for static library files
     const(char)[] dll_ext;    /// extension for dynamic library files
     bool run_noext;           /// allow -run sources without extensions
-    bool omfobj = false;      // for Win32: write OMF object files instead of MsCoff
+    bool omfobj;              // for Win32: write OMF object files instead of MsCoff
     /**
      * Values representing all properties for floating point types
      */
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index c80f28bf807..6f12ac3eb1f 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -317,14 +317,17 @@ public:
     void accept(Visitor *v) override { v->visit(this); }
 };
 
-// in templateparamsem.d
-bool tpsemantic(TemplateParameter *tp, Scope *sc, TemplateParameters *parameters);
-
-Expression *isExpression(RootObject *o);
-Dsymbol *isDsymbol(RootObject *o);
-Type *isType(RootObject *o);
-Tuple *isTuple(RootObject *o);
-Parameter *isParameter(RootObject *o);
-TemplateParameter *isTemplateParameter(RootObject *o);
-bool isError(const RootObject *const o);
-void printTemplateStats(bool listInstances, ErrorSink* eSink);
+namespace dmd
+{
+    // in templateparamsem.d
+    bool tpsemantic(TemplateParameter *tp, Scope *sc, TemplateParameters *parameters);
+
+    Expression *isExpression(RootObject *o);
+    Dsymbol *isDsymbol(RootObject *o);
+    Type *isType(RootObject *o);
+    Tuple *isTuple(RootObject *o);
+    Parameter *isParameter(RootObject *o);
+    TemplateParameter *isTemplateParameter(RootObject *o);
+    bool isError(const RootObject *const o);
+    void printTemplateStats(bool listInstances, ErrorSink* eSink);
+}
diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d
index 89749d6b7f3..f2dc50ebb70 100644
--- a/gcc/d/dmd/templateparamsem.d
+++ b/gcc/d/dmd/templateparamsem.d
@@ -35,7 +35,7 @@ import dmd.visitor;
  * Returns:
  *      `true` if no errors
  */
-extern(C++) bool tpsemantic(TemplateParameter tp, Scope* sc, TemplateParameters* parameters)
+bool tpsemantic(TemplateParameter tp, Scope* sc, TemplateParameters* parameters)
 {
     scope v = new TemplateParameterSemanticVisitor(sc, parameters);
     tp.accept(v);
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 19c6912eeaf..61272ea344c 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1222,7 +1222,7 @@ private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
  * Return !=0 if type has pointers that need to
  * be scanned by the GC during a collection cycle.
  */
-extern(C++) bool hasPointers(Type t)
+bool hasPointers(Type t)
 {
     bool visitType(Type _)              { return false; }
     bool visitDArray(TypeDArray _)      { return true; }
@@ -1292,7 +1292,7 @@ extern(C++) bool hasPointers(Type t)
  *      `Type` with completed semantic analysis, `Terror` if errors
  *      were encountered
  */
-extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
+Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
 {
     static Type error()
     {
@@ -2821,7 +2821,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
     }
 }
 
-extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc)
+Type trySemantic(Type type, const ref Loc loc, Scope* sc)
 {
     //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
 
@@ -2855,7 +2855,7 @@ extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc)
  * Returns:
  *      the type that was merged
  */
-extern (C++) Type merge(Type type)
+Type merge(Type type)
 {
     switch (type.ty)
     {
@@ -2925,7 +2925,7 @@ extern (C++) Type merge(Type type)
  * This version does a merge even if the deco is already computed.
  * Necessary for types that have a deco, but are not merged.
  */
-extern(C++) Type merge2(Type type)
+Type merge2(Type type)
 {
     //printf("merge2(%s)\n", toChars());
     Type t = type;
@@ -5365,7 +5365,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
  * Returns:
  *  The initialization expression for the type.
  */
-extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
+Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false)
 {
     Expression visitBasic(TypeBasic mt)
     {
@@ -5545,7 +5545,7 @@ Returns:
   if the type does resolve to any symbol (for example,
   in the case of basic types).
 */
-extern(C++) Dsymbol toDsymbol(Type type, Scope* sc)
+Dsymbol toDsymbol(Type type, Scope* sc)
 {
     Dsymbol visitType(Type _)            { return null; }
     Dsymbol visitStruct(TypeStruct type) { return type.sym; }
@@ -5644,6 +5644,94 @@ extern(C++) Dsymbol toDsymbol(Type type, Scope* sc)
     }
 }
 
+/************************************
+ * Add storage class modifiers to type.
+ */
+Type addStorageClass(Type type, StorageClass stc)
+{
+    Type visitType(Type t)
+    {
+        /* Just translate to MOD bits and let addMod() do the work
+         */
+        MOD mod = 0;
+        if (stc & STC.immutable_)
+            mod = MODFlags.immutable_;
+        else
+        {
+            if (stc & (STC.const_ | STC.in_))
+                mod |= MODFlags.const_;
+            if (stc & STC.wild)
+                mod |= MODFlags.wild;
+            if (stc & STC.shared_)
+                mod |= MODFlags.shared_;
+        }
+        return t.addMod(mod);
+    }
+
+    Type visitFunction(TypeFunction tf_src)
+    {
+        //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
+        TypeFunction t = visitType(tf_src).toTypeFunction();
+        if ((stc & STC.pure_ && !t.purity) ||
+            (stc & STC.nothrow_ && !t.isnothrow) ||
+            (stc & STC.nogc && !t.isnogc) ||
+            (stc & STC.scope_ && !t.isScopeQual) ||
+            (stc & STC.safe && t.trust < TRUST.trusted))
+        {
+            // Klunky to change these
+            auto tf = new TypeFunction(t.parameterList, t.next, t.linkage, 0);
+            tf.mod = t.mod;
+            tf.fargs = tf_src.fargs;
+            tf.purity = t.purity;
+            tf.isnothrow = t.isnothrow;
+            tf.isnogc = t.isnogc;
+            tf.isproperty = t.isproperty;
+            tf.isref = t.isref;
+            tf.isreturn = t.isreturn;
+            tf.isreturnscope = t.isreturnscope;
+            tf.isScopeQual = t.isScopeQual;
+            tf.isreturninferred = t.isreturninferred;
+            tf.isscopeinferred = t.isscopeinferred;
+            tf.trust = t.trust;
+            tf.isInOutParam = t.isInOutParam;
+            tf.isInOutQual = t.isInOutQual;
+            tf.isctor = t.isctor;
+
+            if (stc & STC.pure_)
+                tf.purity = PURE.fwdref;
+            if (stc & STC.nothrow_)
+                tf.isnothrow = true;
+            if (stc & STC.nogc)
+                tf.isnogc = true;
+            if (stc & STC.safe)
+                tf.trust = TRUST.safe;
+            if (stc & STC.scope_)
+            {
+                tf.isScopeQual = true;
+                if (stc & STC.scopeinferred)
+                    tf.isscopeinferred = true;
+            }
+
+            tf.deco = tf.merge().deco;
+            t = tf;
+        }
+        return t;
+    }
+
+    Type visitDelegate(TypeDelegate tdg)
+    {
+        TypeDelegate t = visitType(tdg).isTypeDelegate();
+        return t;
+    }
+
+    switch(type.ty)
+    {
+        default:            return visitType(type);
+        case Tfunction:     return visitFunction(type.isTypeFunction());
+        case Tdelegate:     return visitDelegate(type.isTypeDelegate());
+    }
+}
+
 /**********************************************
  * Extract complex type from core.stdc.config
  * Params:
@@ -5722,7 +5810,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
  * Returns:
  *     An enum value of either `Covariant.yes` or a reason it's not covariant.
  */
-extern(C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
+Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
 {
     version (none)
     {
@@ -6085,7 +6173,7 @@ StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, Var
         return stc | STC.scope_;
 }
 
-extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset)
+bool isBaseOf(Type tthis, Type t, int* poffset)
 {
     auto tc = tthis.isTypeClass();
     if (!tc)
@@ -6106,15 +6194,45 @@ extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset)
     return false;
 }
 
-extern(C++) bool equivalent(Type src, Type t)
+bool equivalent(Type src, Type t)
 {
     return immutableOf(src).equals(t.immutableOf());
 }
 
+Type pointerTo(Type type)
+{
+    if (type.ty == Terror)
+        return type;
+    if (!type.pto)
+    {
+        Type t = new TypePointer(type);
+        if (type.ty == Tfunction)
+        {
+            t.deco = t.merge().deco;
+            type.pto = t;
+        }
+        else
+            type.pto = t.merge();
+    }
+    return type.pto;
+}
+
+Type referenceTo(Type type)
+{
+    if (type.ty == Terror)
+        return type;
+    if (!type.rto)
+    {
+        Type t = new TypeReference(type);
+        type.rto = t.merge();
+    }
+    return type.rto;
+}
+
 /********************************
  * Convert to 'const'.
  */
-extern(C++) Type constOf(Type type)
+Type constOf(Type type)
 {
     //printf("Type::constOf() %p %s\n", type, type.toChars());
     if (type.mod == MODFlags.const_)
@@ -6134,7 +6252,7 @@ extern(C++) Type constOf(Type type)
 /********************************
  * Convert to 'immutable'.
  */
-extern(C++) Type immutableOf(Type type)
+Type immutableOf(Type type)
 {
     //printf("Type::immutableOf() %p %s\n", this, toChars());
     if (type.isImmutable())
@@ -6154,7 +6272,7 @@ extern(C++) Type immutableOf(Type type)
 /********************************
  * Make type mutable.
  */
-extern(C++) Type mutableOf(Type type)
+Type mutableOf(Type type)
 {
     //printf("Type::mutableOf() %p, %s\n", type, type.toChars());
     Type t = type;
@@ -6204,7 +6322,7 @@ extern(C++) Type mutableOf(Type type)
     return t;
 }
 
-extern(C++) Type sharedOf(Type type)
+Type sharedOf(Type type)
 {
     //printf("Type::sharedOf() %p, %s\n", type, type.toChars());
     if (type.mod == MODFlags.shared_)
@@ -6221,7 +6339,7 @@ extern(C++) Type sharedOf(Type type)
     return t;
 }
 
-extern(C++) Type sharedConstOf(Type type)
+Type sharedConstOf(Type type)
 {
     //printf("Type::sharedConstOf() %p, %s\n", type, type.toChars());
     if (type.mod == (MODFlags.shared_ | MODFlags.const_))
@@ -6250,7 +6368,7 @@ extern(C++) Type sharedConstOf(Type type)
  *      shared wild  => wild
  *      shared wild const => wild const
  */
-extern(C++) Type unSharedOf(Type type)
+Type unSharedOf(Type type)
 {
     //printf("Type::unSharedOf() %p, %s\n", type, type.toChars());
     Type t = type;
@@ -6292,7 +6410,7 @@ extern(C++) Type unSharedOf(Type type)
 /********************************
  * Convert to 'wild'.
  */
-extern(C++) Type wildOf(Type type)
+Type wildOf(Type type)
 {
     //printf("Type::wildOf() %p %s\n", type, type.toChars());
     if (type.mod == MODFlags.wild)
@@ -6309,7 +6427,7 @@ extern(C++) Type wildOf(Type type)
     return t;
 }
 
-extern(C++) Type wildConstOf(Type type)
+Type wildConstOf(Type type)
 {
     //printf("Type::wildConstOf() %p %s\n", type, type.toChars());
     if (type.mod == MODFlags.wildconst)
@@ -6326,7 +6444,7 @@ extern(C++) Type wildConstOf(Type type)
     return t;
 }
 
-extern(C++) Type sharedWildOf(Type type)
+Type sharedWildOf(Type type)
 {
     //printf("Type::sharedWildOf() %p, %s\n", type, type.toChars());
     if (type.mod == (MODFlags.shared_ | MODFlags.wild))
@@ -6343,7 +6461,7 @@ extern(C++) Type sharedWildOf(Type type)
     return t;
 }
 
-extern(C++) Type sharedWildConstOf(Type type)
+Type sharedWildConstOf(Type type)
 {
     //printf("Type::sharedWildConstOf() %p, %s\n", type, type.toChars());
     if (type.mod == (MODFlags.shared_ | MODFlags.wildconst))
@@ -6363,7 +6481,7 @@ extern(C++) Type sharedWildConstOf(Type type)
 /************************************
  * Apply MODxxxx bits to existing type.
  */
-extern(C++) Type castMod(Type type, MOD mod)
+Type castMod(Type type, MOD mod)
 {
     Type t;
     switch (mod)
@@ -6415,7 +6533,7 @@ extern(C++) Type castMod(Type type, MOD mod)
  * We're adding, not replacing, so adding const to
  * a shared type => "shared const"
  */
-extern(C++) Type addMod(Type type, MOD mod)
+Type addMod(Type type, MOD mod)
 {
     /* Add anything to immutable, and it remains immutable
      */
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index 6ae6df0e9b5..a3198327fb2 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -35,7 +35,7 @@ import core.stdc.stdio;
  * Returns:
  *      true if `TypeInfo` was generated and needs compiling to object file
  */
-extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
+bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
 {
     // printf("genTypeInfo() %s\n", torig.toChars());
 
@@ -147,7 +147,7 @@ private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
  *      true if any part of type t is speculative.
  *      if t is null, returns false.
  */
-extern (C++) bool isSpeculativeType(Type t)
+bool isSpeculativeType(Type t)
 {
     static bool visitVector(TypeVector t)
     {
@@ -244,7 +244,7 @@ extern (C++) bool isSpeculativeType(Type t)
 /* Indicates whether druntime already contains an appropriate TypeInfo instance
  * for the specified type (in module rt.util.typeinfo).
  */
-extern (C++) bool builtinTypeInfo(Type t)
+bool builtinTypeInfo(Type t)
 {
     if (!t.mod) // unqualified types only
     {
diff --git a/gcc/d/dmd/typinf.h b/gcc/d/dmd/typinf.h
index fe80b94b4e1..dd9572aab42 100644
--- a/gcc/d/dmd/typinf.h
+++ b/gcc/d/dmd/typinf.h
@@ -16,7 +16,10 @@ class Expression;
 class Type;
 struct Scope;
 
-bool genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc);
+namespace dmd
+{
+    bool genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc);
+    bool isSpeculativeType(Type *t);
+    bool builtinTypeInfo(Type *t);
+}
 Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc, bool genObjCode = true);
-bool isSpeculativeType(Type *t);
-bool builtinTypeInfo(Type *t);
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index 6e3d3151888..ab5cba6f7d0 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -126,6 +126,7 @@ class WithScopeSymbol;
 class ArrayScopeSymbol;
 class Nspace;
 class AliasAssign;
+class CAsmDeclaration;
 
 class AggregateDeclaration;
 class StructDeclaration;
@@ -339,6 +340,7 @@ public:
     virtual void visit(DebugSymbol *s) { visit((Dsymbol *)s); }
     virtual void visit(VersionSymbol *s) { visit((Dsymbol *)s); }
     virtual void visit(AliasAssign *s) { visit((Dsymbol *)s); }
+    virtual void visit(CAsmDeclaration *s) { visit((Dsymbol *)s); }
 
     // ScopeDsymbols
     virtual void visit(Package *s) { visit((ScopeDsymbol *)s); }
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index a05058834af..7fbabbe185f 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -1178,7 +1178,7 @@ public:
 	  {
 	    libcall = LIBCALL_AAGETY;
 	    ptr = build_address (build_expr (e->e1));
-	    tinfo = build_typeinfo (e, mutableOf (unSharedOf (tb1)));
+	    tinfo = build_typeinfo (e, dmd::mutableOf (dmd::unSharedOf (tb1)));
 	  }
 	else
 	  {
@@ -1188,7 +1188,7 @@ public:
 	  }
 
 	/* Index the associative array.  */
-	tree result = build_libcall (libcall, e->type->pointerTo (), 4,
+	tree result = build_libcall (libcall, dmd::pointerTo (e->type), 4,
 				     ptr, tinfo,
 				     size_int (tb1->nextOf ()->size ()),
 				     build_address (key));
@@ -1253,7 +1253,8 @@ public:
 	else
 	  {
 	    /* Generate `array.ptr[index]'.  */
-	    tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
+	    tree ptr = convert_expr (array, tb1,
+				     dmd::pointerTo (tb1->nextOf ()));
 	    ptr = void_okay_p (ptr);
 	    this->result_ = indirect_ref (TREE_TYPE (TREE_TYPE (ptr)),
 					  build_pointer_index (ptr, index));
@@ -1328,7 +1329,7 @@ public:
 
     /* Get the data pointer and length for static and dynamic arrays.  */
     tree array = d_save_expr (build_expr (e->e1));
-    tree ptr = convert_expr (array, tb1, tb1->nextOf ()->pointerTo ());
+    tree ptr = convert_expr (array, tb1, dmd::pointerTo (tb1->nextOf ()));
     tree length = NULL_TREE;
 
     /* Our array is already a SAVE_EXPR if necessary, so we don't make length
@@ -1994,7 +1995,7 @@ public:
 
   void visit (TypeidExp *e) final override
   {
-    if (Type *tid = isType (e->obj))
+    if (Type *tid = dmd::isType (e->obj))
       {
 	tree ti = build_typeinfo (e, tid);
 
@@ -2004,7 +2005,7 @@ public:
 
 	this->result_ = build_nop (build_ctype (e->type), ti);
       }
-    else if (Expression *tid = isExpression (e->obj))
+    else if (Expression *tid = dmd::isExpression (e->obj))
       {
 	Type *type = tid->type->toBasetype ();
 	assert (type->ty == TY::Tclass);
@@ -2136,7 +2137,8 @@ public:
 	    else
 	      {
 		var->inuse++;
-		init = build_expr (initializerToExpression (var->_init), true);
+		Expression *vinit = dmd::initializerToExpression (var->_init);
+		init = build_expr (vinit, true);
 		var->inuse--;
 	      }
 	  }
@@ -2170,7 +2172,7 @@ public:
 	      {
 		/* Generate a slice for non-zero initialized aggregates,
 		   otherwise create an empty array.  */
-		gcc_assert (e->type == constOf (Type::tvoid->arrayOf ()));
+		gcc_assert (e->type == dmd::constOf (Type::tvoid->arrayOf ()));
 
 		tree type = build_ctype (e->type);
 		tree length = size_int (sd->dsym->structsize);
@@ -2682,7 +2684,7 @@ public:
       {
 	/* Allocate space on the memory managed heap.  */
 	tree mem = build_libcall (LIBCALL_ARRAYLITERALTX,
-				  etype->pointerTo (), 2,
+				  dmd::pointerTo (etype), 2,
 				  build_typeinfo (e, etype->arrayOf ()),
 				  size_int (e->elements->length));
 	mem = d_save_expr (mem);
@@ -2718,7 +2720,7 @@ public:
       }
 
     /* Want the mutable type for typeinfo reference.  */
-    Type *tb = mutableOf (e->type->toBasetype ());
+    Type *tb = dmd::mutableOf (e->type->toBasetype ());
 
     /* Handle empty assoc array literals.  */
     TypeAArray *ta = tb->isTypeAArray ();
diff --git a/gcc/d/intrinsics.cc b/gcc/d/intrinsics.cc
index 8adbbeede70..8bbcdc164ee 100644
--- a/gcc/d/intrinsics.cc
+++ b/gcc/d/intrinsics.cc
@@ -126,7 +126,7 @@ maybe_set_intrinsic (FuncDeclaration *decl)
 	    return;
 
 	  OutBuffer buf;
-	  mangleToBuffer (fd->type, buf);
+	  dmd::mangleToBuffer (fd->type, buf);
 	  tdeco = buf.extractChars ();
 	}
 
@@ -719,7 +719,7 @@ expand_intrinsic_rotate (intrinsic_code intrinsic, tree callexp)
       TemplateInstance *ti = DECL_LANG_FRONTEND (callee)->isInstantiated ();
       gcc_assert (ti && ti->tiargs && ti->tiargs->length == 2);
 
-      Expression *e = isExpression ((*ti->tiargs)[0]);
+      Expression *e = dmd::isExpression ((*ti->tiargs)[0]);
       gcc_assert (e && e->op == EXP::int64);
       count = build_expr (e, true);
     }
diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc
index 58b15beba34..b111ee90cea 100644
--- a/gcc/d/modules.cc
+++ b/gcc/d/modules.cc
@@ -504,7 +504,7 @@ layout_moduleinfo_fields (Module *decl, tree type)
   if (decl->sshareddtor)
     layout_moduleinfo_field (ptr_type_node, type, offset);
 
-  if (findGetMembers (decl))
+  if (dmd::findGetMembers (decl))
     layout_moduleinfo_field (ptr_type_node, type, offset);
 
   if (decl->sictor)
@@ -532,7 +532,7 @@ layout_moduleinfo_fields (Module *decl, tree type)
 
   /* Array of local ClassInfo decls are laid out in the same way.  */
   ClassDeclarations aclasses;
-  getLocalClasses (decl, aclasses);
+  dmd::getLocalClasses (decl, aclasses);
 
   if (aclasses.length)
     {
@@ -562,7 +562,7 @@ layout_moduleinfo (Module *decl)
   ClassDeclarations aclasses;
   FuncDeclaration *sgetmembers;
 
-  getLocalClasses (decl, aclasses);
+  dmd::getLocalClasses (decl, aclasses);
 
   size_t aimports_dim = decl->aimports.length;
   for (size_t i = 0; i < decl->aimports.length; i++)
@@ -572,7 +572,7 @@ layout_moduleinfo (Module *decl)
 	aimports_dim--;
     }
 
-  sgetmembers = findGetMembers (decl);
+  sgetmembers = dmd::findGetMembers (decl);
 
   size_t flags = 0;
   if (decl->sctor)
diff --git a/gcc/d/runtime.cc b/gcc/d/runtime.cc
index 9d11e7e132a..e5988c721ca 100644
--- a/gcc/d/runtime.cc
+++ b/gcc/d/runtime.cc
@@ -150,11 +150,11 @@ get_libcall_type (d_libcall_type type)
       break;
 
     case LCT_CONST_TYPEINFO:
-      libcall_types[type] = constOf (Type::dtypeinfo->type);
+      libcall_types[type] = dmd::constOf (Type::dtypeinfo->type);
       break;
 
     case LCT_CONST_CLASSINFO:
-      libcall_types[type] = constOf (Type::typeinfoclass->type);
+      libcall_types[type] = dmd::constOf (Type::typeinfoclass->type);
       break;
 
     case LCT_ARRAY_VOID:
@@ -186,7 +186,7 @@ get_libcall_type (d_libcall_type type)
       break;
 
     case LCT_POINTER_ASSOCARRAY:
-      libcall_types[type] = get_libcall_type (LCT_ASSOCARRAY)->pointerTo ();
+      libcall_types[type] = dmd::pointerTo (get_libcall_type (LCT_ASSOCARRAY));
       break;
 
     case LCT_POINTER_VOIDPTR:
@@ -194,15 +194,15 @@ get_libcall_type (d_libcall_type type)
       break;
 
     case LCT_ARRAYPTR_VOID:
-      libcall_types[type] = Type::tvoid->arrayOf ()->pointerTo ();
+      libcall_types[type] = dmd::pointerTo (Type::tvoid->arrayOf ());
       break;
 
     case LCT_ARRAYPTR_BYTE:
-      libcall_types[type] = Type::tint8->arrayOf ()->pointerTo ();
+      libcall_types[type] = dmd::pointerTo (Type::tint8->arrayOf ());
       break;
 
     case LCT_IMMUTABLE_CHARPTR:
-      libcall_types[type] = immutableOf (Type::tchar->pointerTo ());
+      libcall_types[type] = dmd::immutableOf (dmd::pointerTo (Type::tchar));
       break;
 
     default:
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index 3dbda55ad2b..794737b3b0b 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -206,7 +206,7 @@ make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL)
 
   /* Create object module in order to complete the semantic.  */
   if (!object_module->_scope)
-    importAll (object_module, NULL);
+    dmd::importAll (object_module, NULL);
 
   /* Object class doesn't exist, create a stub one that will cause an error if
      used.  */
@@ -232,7 +232,7 @@ make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL)
 						      true);
   tinfo->parent = object_module;
   tinfo->members = d_gc_malloc<Dsymbols> ();
-  dsymbolSemantic (tinfo, object_module->_scope);
+  dmd::dsymbolSemantic (tinfo, object_module->_scope);
   tinfo->baseClass = base;
   /* This is a compiler generated class, and shouldn't be mistaken for being
      the type declared in the runtime library.  */
@@ -577,8 +577,8 @@ public:
 
   void visit (TypeInfoConstDeclaration *d) final override
   {
-    Type *tm = mutableOf (d->tinfo);
-    tm = merge2 (tm);
+    Type *tm = dmd::mutableOf (d->tinfo);
+    tm = dmd::merge2 (tm);
 
     /* The vtable for TypeInfo_Const.  */
     this->layout_base (Type::typeinfoconst);
@@ -594,8 +594,8 @@ public:
 
   void visit (TypeInfoInvariantDeclaration *d) final override
   {
-    Type *tm = mutableOf (d->tinfo);
-    tm = merge2 (tm);
+    Type *tm = dmd::mutableOf (d->tinfo);
+    tm = dmd::merge2 (tm);
 
     /* The vtable for TypeInfo_Invariant.  */
     this->layout_base (Type::typeinfoinvariant);
@@ -611,8 +611,8 @@ public:
 
   void visit (TypeInfoSharedDeclaration *d) final override
   {
-    Type *tm = unSharedOf (d->tinfo);
-    tm = merge2 (tm);
+    Type *tm = dmd::unSharedOf (d->tinfo);
+    tm = dmd::merge2 (tm);
 
     /* The vtable for TypeInfo_Shared.  */
     this->layout_base (Type::typeinfoshared);
@@ -628,8 +628,8 @@ public:
 
   void visit (TypeInfoWildDeclaration *d) final override
   {
-    Type *tm = mutableOf (d->tinfo);
-    tm = merge2 (tm);
+    Type *tm = dmd::mutableOf (d->tinfo);
+    tm = dmd::merge2 (tm);
 
     /* The vtable for TypeInfo_Inout.  */
     this->layout_base (Type::typeinfowild);
@@ -1091,7 +1091,7 @@ public:
     this->layout_field (xcmp);
 
     /* string function(const(void)*) xtoString;  */
-    FuncDeclaration *fdx = search_toString (sd);
+    FuncDeclaration *fdx = dmd::search_toString (sd);
     if (fdx)
       this->layout_field (build_address (get_symbol_decl (fdx)));
     else
@@ -1099,7 +1099,7 @@ public:
 
     /* StructFlags m_flags;  */
     int m_flags = StructFlags::none;
-    if (hasPointers (ti))
+    if (dmd::hasPointers (ti))
       m_flags |= StructFlags::hasPointers;
     this->layout_field (build_integer_cst (m_flags, d_uint_type));
 
@@ -1551,7 +1551,7 @@ create_typeinfo (Type *type, Module *mod, bool generate)
     create_frontend_tinfo_types ();
 
   /* Do this since not all Type's are merged.  */
-  Type *t = merge2 (type);
+  Type *t = dmd::merge2 (type);
   Identifier *ident;
 
   if (!t->vtinfo)
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index ed97aa39cc5..9fa2f888cb2 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -144,7 +144,7 @@ same_type_p (Type *t1, Type *t2)
     return true;
 
   /* Types are mutably the same type.  */
-  if (tb1->ty == tb2->ty && equivalent (tb1, tb2))
+  if (tb1->ty == tb2->ty && dmd::equivalent (tb1, tb2))
     return true;
 
   return false;
@@ -1334,7 +1334,7 @@ build_ctype (Type *t)
 	t->accept (&v);
       else
 	{
-	  Type *tb = castMod (t, 0);
+	  Type *tb = dmd::castMod (t, 0);
 	  if (!tb->ctype)
 	    tb->accept (&v);
 	  t->ctype = insert_type_modifiers (tb->ctype, t->mod);
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test24390a.d b/gcc/testsuite/gdc.test/compilable/imports/test24390a.d
new file mode 100644
index 00000000000..0792c67426f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test24390a.d
@@ -0,0 +1,2 @@
+module imports.test24390a;
+public import imports.test24390b;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test24390b.d b/gcc/testsuite/gdc.test/compilable/imports/test24390b.d
new file mode 100644
index 00000000000..914553efdb0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test24390b.d
@@ -0,0 +1,9 @@
+module imports.test24390b;
+static if (__traits(compiles, __vector(int[4])) && __traits(compiles, __vector(byte[16])))
+{
+    __vector(int[4]) _mm_set1_epi8 (byte a)
+    {
+        __vector(byte[16]) b = a;
+        return cast(__vector(int[4]))b;
+    }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/interpret3.d b/gcc/testsuite/gdc.test/compilable/interpret3.d
index 14142630454..69f65b1cbdf 100644
--- a/gcc/testsuite/gdc.test/compilable/interpret3.d
+++ b/gcc/testsuite/gdc.test/compilable/interpret3.d
@@ -2326,7 +2326,7 @@ struct Bug10840
     Data10840* _data;
 }
 
-bool bug10840(int n)
+enum bug10840 = (int n)
 {
     Bug10840 stack;
     if (n == 1)
@@ -2336,7 +2336,7 @@ bool bug10840(int n)
     }
     // Wrong-code for ?:
     return stack._data ? false : true;
-}
+};
 
 static assert(bug10840(0));
 static assert(!is(typeof(Compileable!(bug10840(1)))));
@@ -5910,13 +5910,13 @@ struct Bug7527
     char[] data;
 }
 
-int bug7527()
+enum bug7527 = ()
 {
     auto app = Bug7527();
 
     app.data.ptr[0 .. 1] = "x";
     return 1;
-}
+};
 
 static assert(!is(typeof(compiles!(bug7527()))));
 
diff --git a/gcc/testsuite/gdc.test/compilable/test24390.d b/gcc/testsuite/gdc.test/compilable/test24390.d
new file mode 100644
index 00000000000..f02054dac0f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test24390.d
@@ -0,0 +1,26 @@
+// PERMUTE_ARGS: -O -inline
+// EXTRA_SOURCES: imports/test24390a.d imports/test24390b.d
+static if (__traits(compiles, __vector(int[4])) && __traits(compiles, __vector(byte[16])))
+{
+    import imports.test24390a;
+
+    void main()
+    {
+        __vector(int[4]) mmA ;
+        __vector(int[4]) mmB ;
+        auto mask = _mm_cmpestrm(mmA, mmB);
+    }
+
+    __vector(int[4]) _mm_cmpestrm(__vector(int[4]) mmA, __vector(int[4]) mmB)
+    {
+        __vector(int[4]) R;
+        for (int pos ; pos < 16; ++pos)
+        {
+            byte charK = (cast(__vector(byte[16]))mmA).array[pos];
+            __vector(int[4]) eqMask = _mm_set1_epi8(charK);
+            R = R & eqMask;
+
+        }
+        return R;
+    }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/traits.d b/gcc/testsuite/gdc.test/compilable/traits.d
index 3c65dac0932..d5e2cb0f220 100644
--- a/gcc/testsuite/gdc.test/compilable/traits.d
+++ b/gcc/testsuite/gdc.test/compilable/traits.d
@@ -316,3 +316,7 @@ extern(C++, `inst`)
 mixin GetNamespaceTestTemplatedMixin!() GNTT;
 
 static assert (__traits(getCppNamespaces, GNTT.foo) == Seq!(`inst`,/*`decl`,*/ `f`));
+
+int[1] arr;
+// test that index assignment parses as an expression, not a type
+enum _ = __traits(compiles, arr[0] = 0);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/imports/issue21685.d b/gcc/testsuite/gdc.test/fail_compilation/imports/issue21685.d
index eef95bf9ade..cfc39dee378 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/imports/issue21685.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/imports/issue21685.d
@@ -3,4 +3,5 @@ module issue21685;
 class E
 {
     private this() {}
+    public this(int) {}
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue21685_main.d b/gcc/testsuite/gdc.test/fail_compilation/issue21685_main.d
index c6e29c3eb17..5b95d9be764 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/issue21685_main.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue21685_main.d
@@ -1,7 +1,8 @@
 /* REQUIRED_ARGS: -preview=dip1000 -Ifail_compilation/imports
 TEST_OUTPUT:
 ---
-fail_compilation/issue21685_main.d(11): Error: class `issue21685.E` constructor `this` is not accessible
+fail_compilation/issue21685_main.d(12): Error: constructor `issue21685.E.this` is not accessible from module `issue21685_main`
+fail_compilation/issue21685_main.d(19): Error: constructor `issue21685.E.this` is not accessible from module `issue21685_main`
 ---
 */
 import issue21685;
@@ -10,3 +11,11 @@ void main()
 {
     new E;
 }
+
+class F : E
+{
+    this()
+    {
+        super();
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23786.d b/gcc/testsuite/gdc.test/fail_compilation/test23786.d
new file mode 100644
index 00000000000..11fe5d4cc17
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test23786.d
@@ -0,0 +1,39 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test23786.d(22): Error: function `foo` is not callable using argument types `(double)`
+fail_compilation/test23786.d(22):        cannot pass argument `1.0` of type `double` to parameter `int i`
+fail_compilation/test23786.d(19):        `test23786.foo(int i)` declared here
+fail_compilation/test23786.d(29): Error: function `bar` is not callable using argument types `(int*)`
+fail_compilation/test23786.d(29):        cannot pass argument `& i` of type `int*` to parameter `int i`
+fail_compilation/test23786.d(26):        `test23786.bar(int i)` declared here
+fail_compilation/test23786.d(37): Error: function `baz` is not callable using argument types `(int*)`
+fail_compilation/test23786.d(37):        cannot pass argument `& i` of type `int*` to parameter `int i`
+fail_compilation/test23786.d(34):        `test23786.baz(int i)` declared here
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=23786
+
+module test23786;
+
+void foo(int i)
+{
+    static assert(__traits(parent, {}).mangleof == "_D9test237863fooFiZv");
+    __traits(parent, {})(1.0);
+}
+void foo(int* p) {}
+
+void bar(int i)
+{
+    static assert(__traits(parent, {}).mangleof == "_D9test237863barFiZv");
+    __traits(parent, {})(&i);
+}
+void bar(int* p) {}
+
+void baz(int* p) {}
+void baz(int i)
+{
+    static assert(__traits(parent, {}).mangleof == "_D9test237863bazFiZv");
+    __traits(parent, {})(&i);
+}
+void baz(float* p) {}
diff --git a/gcc/testsuite/gdc.test/runnable/link15021.d b/gcc/testsuite/gdc.test/runnable/link15021.d
index 2e82610148d..1c136fcffc2 100644
--- a/gcc/testsuite/gdc.test/runnable/link15021.d
+++ b/gcc/testsuite/gdc.test/runnable/link15021.d
@@ -13,7 +13,7 @@ class AliasDecl {}
 
 void aliasDecl(AliasDecl ad)
 {
-    AliasDecl* zis;
+    AliasDecl* zis = &ad;
 
     static if (is(typeof(to!string(*zis))))
     {
diff --git a/gcc/testsuite/gdc.test/runnable/mars1.d b/gcc/testsuite/gdc.test/runnable/mars1.d
index b24eced9f7f..f493eac181d 100644
--- a/gcc/testsuite/gdc.test/runnable/mars1.d
+++ b/gcc/testsuite/gdc.test/runnable/mars1.d
@@ -2478,6 +2478,19 @@ void test21835()
     if (arr[0].r != 0.0) assert(0);
 }
 
+////////////////////////////////////////////////////////////////////////
+// https://github.com/dlang/dmd/pull/16187#issuecomment-1946534649
+
+void testDoWhileContinue()
+{
+    int i = 10;
+    do
+    {
+        continue;
+    }
+    while(--i > 0);
+}
+
 ////////////////////////////////////////////////////////////////////////
 
 int main()
@@ -2578,6 +2591,7 @@ int main()
     test21256();
     test21816();
     test21835();
+    testDoWhileContinue();
 
     printf("Success\n");
     return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/staticaa.d b/gcc/testsuite/gdc.test/runnable/staticaa.d
index e5b25d1f66a..089144c4fb5 100644
--- a/gcc/testsuite/gdc.test/runnable/staticaa.d
+++ b/gcc/testsuite/gdc.test/runnable/staticaa.d
@@ -165,6 +165,22 @@ void testEnumInit()
 
 /////////////////////////////////////////////
 
+// https://issues.dlang.org/show_bug.cgi?id=24370
+immutable uint[3][string] test = [
+	"oneTwoThree": [1,2,3],
+	"fourFiveSix": [4,5,6],
+	"sevenEightNine": [7,8,9],
+];
+
+void testStaticArray()
+{
+	assert(test["oneTwoThree"] == [1, 2, 3]);
+	assert(test["fourFiveSix"] == [4, 5, 6]);
+	assert(test["sevenEightNine"] == [7, 8, 9]);
+}
+
+/////////////////////////////////////////////
+
 void main()
 {
     testSimple();
@@ -175,4 +191,5 @@ void main()
     testImmutable();
     testLocalStatic();
     testEnumInit();
+    testStaticArray();
 }
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test7925.d b/gcc/testsuite/gdc.test/runnable_cxx/test7925.d
index 2f52826bc4f..f05aac916e2 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/test7925.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test7925.d
@@ -1,10 +1,10 @@
 // EXTRA_CPP_SOURCES: cpp7925.cpp
 
 /*
-Exclude -O due to a codegen bug on OSX:
+Exclude -O/-inline due to a codegen bug on OSX:
 https://issues.dlang.org/show_bug.cgi?id=22556
 
-PERMUTE_ARGS(osx): -inline -release -g
+PERMUTE_ARGS(osx): -release -g
 */
 
 import core.vararg;
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 74c194508f7..021149aabc7 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-11240a96635074b2f79d908b9348e9c0fbc3c7dc
+9471b25db9ed44d71e0e27956430c0c6a09c16db
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/libphobos/libdruntime/core/interpolation.d b/libphobos/libdruntime/core/interpolation.d
index 0d45fe79088..530602580f1 100644
--- a/libphobos/libdruntime/core/interpolation.d
+++ b/libphobos/libdruntime/core/interpolation.d
@@ -91,6 +91,14 @@
 +/
 module core.interpolation;
 
+/++
+    Common implementation for returning an empty string, to avoid storing
+    multiple versions of the same function based on templated types below.
++/
+public string __getEmptyString() @nogc pure nothrow @safe {
+    return "";
+}
+
 /++
     Sentinel values to indicate the beginning and end of an
     interpolated expression sequence.
@@ -104,9 +112,7 @@ struct InterpolationHeader {
         Returns `null` for easy compatibility with existing functions
         like `std.stdio.writeln` and `std.conv.text`.
     +/
-    string toString() const @nogc pure nothrow @safe {
-        return null;
-    }
+    alias toString = __getEmptyString;
 }
 
 /// ditto
@@ -115,9 +121,7 @@ struct InterpolationFooter {
         Returns `null` for easy compatibility with existing functions
         like `std.stdio.writeln` and `std.conv.text`.
     +/
-    string toString() const @nogc pure nothrow @safe {
-        return null;
-    }
+    alias toString = __getEmptyString;
 }
 
 /++
@@ -130,7 +134,7 @@ struct InterpolatedLiteral(string text) {
         segment of the tuple, for easy access and compatibility with
         existing functions like `std.stdio.writeln` and `std.conv.text`.
     +/
-    string toString() const @nogc pure nothrow @safe {
+    static string toString() @nogc pure nothrow @safe {
         return text;
     }
 }
@@ -150,7 +154,5 @@ struct InterpolatedExpression(string text) {
         Returns `null` for easy compatibility with existing functions
         like `std.stdio.writeln` and `std.conv.text`.
     +/
-    string toString() const @nogc pure nothrow @safe {
-        return null;
-    }
+    alias toString = __getEmptyString;
 }
diff --git a/libphobos/libdruntime/core/thread/fiber.d b/libphobos/libdruntime/core/thread/fiber.d
index 50253b09512..dd2462fbca1 100644
--- a/libphobos/libdruntime/core/thread/fiber.d
+++ b/libphobos/libdruntime/core/thread/fiber.d
@@ -14,7 +14,7 @@
  */
 module core.thread.fiber;
 
-import core.thread.osthread;
+import core.thread.threadbase;
 import core.thread.threadgroup;
 import core.thread.types;
 import core.thread.context;
@@ -220,8 +220,8 @@ private
         Fiber   obj = Fiber.getThis();
         assert( obj );
 
-        assert( Thread.getThis().m_curr is obj.m_ctxt );
-        atomicStore!(MemoryOrder.raw)(*cast(shared)&Thread.getThis().m_lock, false);
+        assert( ThreadBase.getThis().m_curr is obj.m_ctxt );
+        atomicStore!(MemoryOrder.raw)(*cast(shared)&ThreadBase.getThis().m_lock, false);
         obj.m_ctxt.tstack = obj.m_ctxt.bstack;
         obj.m_state = Fiber.State.EXEC;
 
@@ -1106,7 +1106,7 @@ private:
             }
         }
 
-        Thread.add( m_ctxt );
+        ThreadBase.add( m_ctxt );
     }
 
 
@@ -1119,9 +1119,9 @@ private:
     {
         // NOTE: m_ctxt is guaranteed to be alive because it is held in the
         //       global context list.
-        Thread.slock.lock_nothrow();
-        scope(exit) Thread.slock.unlock_nothrow();
-        Thread.remove( m_ctxt );
+        ThreadBase.slock.lock_nothrow();
+        scope(exit) ThreadBase.slock.unlock_nothrow();
+        ThreadBase.remove( m_ctxt );
 
         version (Windows)
         {
@@ -1623,7 +1623,7 @@ private:
     //
     final void switchIn() nothrow @nogc
     {
-        Thread  tobj = Thread.getThis();
+        ThreadBase  tobj = ThreadBase.getThis();
         void**  oldp = &tobj.m_curr.tstack;
         void*   newp = m_ctxt.tstack;
 
@@ -1657,7 +1657,7 @@ private:
     //
     final void switchOut() nothrow @nogc
     {
-        Thread  tobj = Thread.getThis();
+        ThreadBase  tobj = ThreadBase.getThis();
         void**  oldp = &m_ctxt.tstack;
         void*   newp = tobj.m_curr.within.tstack;
 
@@ -1682,7 +1682,7 @@ private:
         // NOTE: If use of this fiber is multiplexed across threads, the thread
         //       executing here may be different from the one above, so get the
         //       current thread handle before unlocking, etc.
-        tobj = Thread.getThis();
+        tobj = ThreadBase.getThis();
         atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
         tobj.m_curr.tstack = tobj.m_curr.bstack;
     }
@@ -2027,6 +2027,7 @@ unittest
 unittest
 {
     import core.memory;
+    import core.thread.osthread : Thread;
     import core.time : dur;
 
     static void unreferencedThreadObject()
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index 295ca52e350..a9fcf96254b 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -1625,7 +1625,7 @@ extern (C) @nogc nothrow
 }
 
 
-package extern(D) void* getStackTop() nothrow @nogc
+private extern(D) void* getStackTop() nothrow @nogc
 {
     version (D_InlineAsm_X86)
         asm pure nothrow @nogc { naked; mov EAX, ESP; ret; }
@@ -1638,7 +1638,7 @@ package extern(D) void* getStackTop() nothrow @nogc
 }
 
 
-package extern(D) void* getStackBottom() nothrow @nogc
+private extern(D) void* getStackBottom() nothrow @nogc
 {
     version (Windows)
     {
diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d
index 84f9203f23b..f593387c755 100644
--- a/libphobos/libdruntime/core/thread/threadbase.d
+++ b/libphobos/libdruntime/core/thread/threadbase.d
@@ -84,7 +84,10 @@ private
     enum mutexClassInstanceSize = __traits(classInstanceSize, Mutex);
 
     alias swapContext = externDFunc!("core.thread.osthread.swapContext", void* function(void*) nothrow @nogc);
+}
 
+package
+{
     alias getStackBottom = externDFunc!("core.thread.osthread.getStackBottom", void* function() nothrow @nogc);
     alias getStackTop = externDFunc!("core.thread.osthread.getStackTop", void* function() nothrow @nogc);
 }
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index ff182d9da42..4125fd717f4 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-37796e783ba438a0bedfb435dbbcc7aeaf06ce2a
+5478868465ae1ad743ff76ac5bb92691463ffec5
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d
index ef1170600b3..1453d2b64b9 100644
--- a/libphobos/src/std/algorithm/iteration.d
+++ b/libphobos/src/std/algorithm/iteration.d
@@ -2027,7 +2027,7 @@ private struct ChunkByGroup(alias eq, Range, bool eqEquivalenceAssured)
     }
 
     // Cannot be a copy constructor due to https://issues.dlang.org/show_bug.cgi?id=22239
-    this(this) @trusted
+    this(this) scope @trusted
     {
         import core.lifetime : emplace;
         // since mothership has to be in a union, we have to manually trigger
@@ -2129,7 +2129,7 @@ if (isForwardRange!Range)
     }
 
     // Cannot be a copy constructor due to https://issues.dlang.org/show_bug.cgi?id=22239
-    this(this) @trusted
+    this(this) scope @trusted
     {
         import core.lifetime : emplace;
         // since _impl has to be in a union, we have to manually trigger
diff --git a/libphobos/src/std/algorithm/mutation.d b/libphobos/src/std/algorithm/mutation.d
index 61b6a5e4eff..fbef28e5d56 100644
--- a/libphobos/src/std/algorithm/mutation.d
+++ b/libphobos/src/std/algorithm/mutation.d
@@ -1813,22 +1813,28 @@ range.
 
 For example, here is how to remove a single element from an array:
 
+$(RUNNABLE_EXAMPLE
 ----
+import std.algorithm.mutation;
 string[] a = [ "a", "b", "c", "d" ];
 a = a.remove(1); // remove element at offset 1
 assert(a == [ "a", "c", "d"]);
 ----
+)
 
 Note that `remove` does not change the length of the original range directly;
 instead, it returns the shortened range. If its return value is not assigned to
 the original range, the original range will retain its original length, though
 its contents will have changed:
 
+$(RUNNABLE_EXAMPLE
 ----
+import std.algorithm.mutation;
 int[] a = [ 3, 5, 7, 8 ];
 assert(remove(a, 1) == [ 3, 7, 8 ]);
 assert(a == [ 3, 7, 8, 8 ]);
 ----
+)
 
 The element at offset `1` has been removed and the rest of the elements have
 shifted up to fill its place, however, the original array remains of the same
@@ -1838,25 +1844,34 @@ invoked to rearrange elements, and on integers `move` simply copies the source
 to the destination.  To replace `a` with the effect of the removal, simply
 assign the slice returned by `remove` to it, as shown in the first example.
 
+$(H3 $(LNAME2 remove-multiple, Removing multiple elements))
+
 Multiple indices can be passed into `remove`. In that case,
 elements at the respective indices are all removed. The indices must
 be passed in increasing order, otherwise an exception occurs.
 
+$(RUNNABLE_EXAMPLE
 ----
+import std.algorithm.mutation;
 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
 assert(remove(a, 1, 3, 5) ==
     [ 0, 2, 4, 6, 7, 8, 9, 10 ]);
 ----
+)
 
-(Note that all indices refer to slots in the $(I original) array, not
-in the array as it is being progressively shortened.)
+Note that all indices refer to slots in the $(I original) array, not
+in the array as it is being progressively shortened.
 
-Tuples of two integral offsets can be used to remove an indices range:
+Tuples of two integral offsets can be supplied to remove a range of indices:
 
+$(RUNNABLE_EXAMPLE
 ----
+import std.algorithm.mutation, std.typecons;
 int[] a = [ 3, 4, 5, 6, 7];
-assert(remove(a, 1, tuple(1, 3), 9) == [ 3, 6, 7 ]);
+// remove elements at indices 1 and 2
+assert(remove(a, tuple(1, 3)) == [ 3, 6, 7 ]);
 ----
+)
 
 The tuple passes in a range closed to the left and open to
 the right (consistent with built-in slices), e.g. `tuple(1, 3)`
@@ -1865,22 +1880,31 @@ means indices `1` and `2` but not `3`.
 Finally, any combination of integral offsets and tuples composed of two integral
 offsets can be passed in:
 
+$(RUNNABLE_EXAMPLE
 ----
+import std.algorithm.mutation, std.typecons;
 int[] a = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
-assert(remove(a, 1, tuple(3, 5), 9) == [ 0, 2, 5, 6, 7, 8, 10 ]);
+a = remove(a, 1, tuple(3, 5), 9);
+assert(a == [ 0, 2, 5, 6, 7, 8, 10 ]);
 ----
+)
 
 In this case, the slots at positions 1, 3, 4, and 9 are removed from
 the array.
 
+$(H3 $(LNAME2 remove-moving, Moving strategy))
+
 If the need is to remove some elements in the range but the order of
 the remaining elements does not have to be preserved, you may want to
 pass `SwapStrategy.unstable` to `remove`.
 
+$(RUNNABLE_EXAMPLE
 ----
+import std.algorithm.mutation;
 int[] a = [ 0, 1, 2, 3 ];
 assert(remove!(SwapStrategy.unstable)(a, 1) == [ 0, 3, 2 ]);
 ----
+)
 
 In the case above, the element at slot `1` is removed, but replaced
 with the last element of the range. Taking advantage of the relaxation
@@ -1888,7 +1912,7 @@ of the stability requirement, `remove` moved elements from the end
 of the array over the slots to be removed. This way there is less data
 movement to be done which improves the execution time of the function.
 
-The function `remove` works on bidirectional ranges that have assignable
+`remove` works on bidirectional ranges that have assignable
 lvalue elements. The moving strategy is (listed from fastest to slowest):
 
 $(UL
@@ -1914,7 +1938,7 @@ Params:
     offset = which element(s) to remove
 
 Returns:
-    A range containing all of the elements of range with offset removed.
+    A range containing elements of `range` with 1 or more elements removed.
 */
 Range remove
 (SwapStrategy s = SwapStrategy.stable, Range, Offset ...)
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index c985015a7af..30f6ffb9f44 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -2427,7 +2427,14 @@ if (Rs.length > 1 && allSatisfy!(isInputRange, staticMap!(Unqual, Rs)))
         }
     }
 
-    return Result(rs, 0);
+    size_t firstNonEmpty = size_t.max;
+    static foreach (i; 0 .. Rs.length)
+    {
+        if (firstNonEmpty == size_t.max && !rs[i].empty)
+            firstNonEmpty = i;
+    }
+
+    return Result(rs, firstNonEmpty);
 }
 
 ///
@@ -2489,6 +2496,14 @@ pure @safe nothrow unittest
     assert(equal(r, [ S(1), S(10), S(2), S(20) ]));
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24384
+@safe unittest
+{
+    auto r = roundRobin("", "a");
+    assert(!r.empty);
+    auto e = r.front;
+}
+
 /**
 Iterates a random-access range starting from a given point and
 progressively extending left and right from that point. If no initial
@@ -10167,10 +10182,18 @@ public:
 private struct OnlyResult(Values...)
 if (Values.length > 1)
 {
+    import std.meta : ApplyRight;
+    import std.traits : isAssignable;
+
     private enum arity = Values.length;
 
     private alias UnqualValues = staticMap!(Unqual, Values);
 
+    private enum canAssignElements = allSatisfy!(
+        ApplyRight!(isAssignable, CommonType!Values),
+        Values
+    );
+
     private this(return scope ref Values values)
     {
         ref @trusted unqual(T)(ref T x){return cast() x;}
@@ -10195,6 +10218,15 @@ if (Values.length > 1)
         return this[0];
     }
 
+    static if (canAssignElements)
+    {
+        void front(CommonType!Values value) @property
+        {
+            assert(!empty, "Attempting to assign the front of an empty Only range");
+            this[0] = value;
+        }
+    }
+
     void popFront()
     {
         assert(!empty, "Attempting to popFront an empty Only range");
@@ -10207,6 +10239,15 @@ if (Values.length > 1)
         return this[$ - 1];
     }
 
+    static if (canAssignElements)
+    {
+        void back(CommonType!Values value) @property
+        {
+            assert(!empty, "Attempting to assign the back of an empty Only range");
+            this[$ - 1] = value;
+        }
+    }
+
     void popBack()
     {
         assert(!empty, "Attempting to popBack an empty Only range");
@@ -10236,6 +10277,18 @@ if (Values.length > 1)
                 return cast(T) values[i];
     }
 
+    static if (canAssignElements)
+    {
+        void opIndexAssign(CommonType!Values value, size_t idx)
+        {
+            assert(idx < length, "Attempting to assign to an out of bounds index of an Only range");
+            final switch (frontIndex + idx)
+                static foreach (i; 0 .. Values.length)
+                case i:
+                    values[i] = value;
+        }
+    }
+
     OnlyResult opSlice()
     {
         return this;
@@ -10279,16 +10332,34 @@ if (Values.length > 1)
 // Specialize for single-element results
 private struct OnlyResult(T)
 {
+    import std.traits : isAssignable;
+
     @property T front()
     {
         assert(!empty, "Attempting to fetch the front of an empty Only range");
         return fetchFront();
     }
+    static if (isAssignable!T)
+    {
+        @property void front(T value)
+        {
+            assert(!empty, "Attempting to assign the front of an empty Only range");
+            assignFront(value);
+        }
+    }
     @property T back()
     {
         assert(!empty, "Attempting to fetch the back of an empty Only range");
         return fetchFront();
     }
+    static if (isAssignable!T)
+    {
+        @property void back(T value)
+        {
+            assert(!empty, "Attempting to assign the front of an empty Only range");
+            assignFront(value);
+        }
+    }
     @property bool empty() const { return _empty; }
     @property size_t length() const { return !_empty; }
     @property auto save() { return this; }
@@ -10319,6 +10390,15 @@ private struct OnlyResult(T)
         return fetchFront();
     }
 
+    static if (isAssignable!T)
+    {
+        void opIndexAssign(T value, size_t i)
+        {
+            assert(!_empty && i == 0, "Attempting to assign an out of bounds index of an Only range");
+            assignFront(value);
+        }
+    }
+
     OnlyResult opSlice()
     {
         return this;
@@ -10348,6 +10428,13 @@ private struct OnlyResult(T)
     {
         return *cast(T*)&_value;
     }
+    static if (isAssignable!T)
+    {
+        private @trusted void assignFront(T newValue)
+        {
+            *cast(T*) &_value = newValue;
+        }
+    }
 }
 
 /**
@@ -10368,6 +10455,9 @@ Params:
 Returns:
     A `RandomAccessRange` of the assembled values.
 
+    The returned range can be sliced. Its elements can be assigned to if every
+    type in `Values` supports assignment from the range's element type.
+
 See_Also: $(LREF chain) to chain ranges
  */
 auto only(Values...)(return scope Values values)
@@ -10629,6 +10719,32 @@ auto only()()
     auto r1 = arr.chain(x.only, only(x, x));
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24382
+@safe unittest
+{
+    auto r1 = only(123);
+    r1.front = 456;
+    r1.back = 456;
+    r1[0] = 456;
+
+    auto r2 = only(123, 456);
+    r2.front = 789;
+    r2.back = 789;
+    r2[0] = 789;
+
+    auto r3 = only(1.23, 456);
+    // Can't assign double to int
+    static assert(!__traits(compiles, r3.front = 7.89));
+    static assert(!__traits(compiles, r3.back = 7.89));
+    // Workaround https://issues.dlang.org/show_bug.cgi?id=24383
+    static assert(!__traits(compiles, () { r3[0] = 7.89; }));
+    // Can't assign type other than element type (even if compatible)
+    static assert(!__traits(compiles, r3.front = 789));
+    static assert(!__traits(compiles, r3.back = 789));
+    // Workaround https://issues.dlang.org/show_bug.cgi?id=24383
+    static assert(!__traits(compiles, () { r3[0] = 789; }));
+}
+
 /**
 Iterate over `range` with an attached index variable.
 
