diff mbox series

[committed,1/3] d: Merge upstream dmd 3b808e838

Message ID 20210403232828.1822347-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed,1/3] d: Merge upstream dmd 3b808e838 | expand

Commit Message

Iain Buclaw April 3, 2021, 11:28 p.m. UTC
Hi,

This patch series merges the D front-end implementation with upstream
dmd 3b808e838, and the Phobos standard library with druntime 483bc129
and phobos f89dc217a.

These changes are specific to the front-end implementation part.

D front-end changes:

 - Explicit package visibility attribute is now always applied to
   introducing scopes.

 - Added `__traits(totype, string)' to convert mangled type string to an
   existing type.

 - Printf-like and scanf-like functions are now detected by prefixing
   them with `pragma(printf)' for printf-like functions or
   `pragma(scanf)' for scanf-like functions.

 - Added `__c_wchar_t', `__c_complex_float', `__c_complex_double', and
   `__c_complex_real' types for interfacing with C and C++.

 - Template alias parameters can now be instantiated with basic types,
   such as `int` or `void function()`.

 - Mixins can now be used as types in the form `mixin(string) var'.

 - Mixin expressions can take an argument list, same as `pragma(msg)'.

 - Implement DIP1034, add `typeof(*null)' types to represent `noreturn'.

 - `pragma(msg)' can print expressions of type `void'.

 - It is now an error to use private variables selectively imported from
   other modules.  Due to a bug, some imported private members were
   visible from other modules, violating the specification.

 - Added new syntax to declare an alias to a function type using the
   `alias' syntax based on the assignment operator.

 - Function literals can now return a value by reference.


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

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 3b808e838.
	* Make-lang.in (D_FRONTEND_OBJS): Add d/chkformat.o.
	* d-codegen.cc (build_struct_literal): Handle special enums.
	* d-convert.cc (convert_expr): Handle noreturn type.
	(convert_for_condition): Likewise.
	* d-target.cc (Target::_init): Set type for wchar_t.
	(TargetCPP::derivedClassOffset): New method.
	(Target::libraryObjectMonitors): New method.
	* decl.cc (get_symbol_decl): Set TREE_THIS_VOLATILE for functions of
	type noreturn.
	* toir.cc (IRVisitor::visit (ReturnStatement *)): Handle returning
	noreturn types.
	* types.cc (TypeVisitor::visit (TypeNoreturn *)): New method.
	(TypeVisitor::visit (TypeEnum *)): Handle special enums.
---
 gcc/d/Make-lang.in           |    1 +
 gcc/d/d-codegen.cc           |    8 +
 gcc/d/d-convert.cc           |   14 +-
 gcc/d/d-target.cc            |   28 +
 gcc/d/decl.cc                |    4 +
 gcc/d/dmd/MERGE              |    2 +-
 gcc/d/dmd/attrib.c           |   39 +-
 gcc/d/dmd/attrib.h           |    4 +-
 gcc/d/dmd/blockexit.c        |    2 +
 gcc/d/dmd/chkformat.c        |  975 +++++++++++++++
 gcc/d/dmd/cppmangle.c        |   18 +-
 gcc/d/dmd/ctfeexpr.c         |    2 +-
 gcc/d/dmd/dcast.c            |    5 +-
 gcc/d/dmd/dclass.c           |   20 +-
 gcc/d/dmd/declaration.h      |    4 +-
 gcc/d/dmd/denum.c            |   19 +-
 gcc/d/dmd/dimport.c          |   80 +-
 gcc/d/dmd/dmangle.c          |   37 +-
 gcc/d/dmd/dmodule.c          |   33 +-
 gcc/d/dmd/dscope.c           |    6 +-
 gcc/d/dmd/dsymbol.c          |   32 +-
 gcc/d/dmd/dsymbol.h          |    3 +-
 gcc/d/dmd/dsymbolsem.c       |  139 ++-
 gcc/d/dmd/dtemplate.c        |  210 ++--
 gcc/d/dmd/expression.c       | 2218 ++++------------------------------
 gcc/d/dmd/expression.h       |    9 +-
 gcc/d/dmd/expressionsem.c    | 2091 ++++++++++++++++++++++++++++++--
 gcc/d/dmd/func.c             |   18 +-
 gcc/d/dmd/hdrgen.c           |   57 +-
 gcc/d/dmd/hdrgen.h           |    1 +
 gcc/d/dmd/idgen.c            |    8 +-
 gcc/d/dmd/import.h           |    1 +
 gcc/d/dmd/module.h           |    1 +
 gcc/d/dmd/mtype.c            |  282 ++++-
 gcc/d/dmd/mtype.h            |   38 +-
 gcc/d/dmd/parse.c            |  217 +++-
 gcc/d/dmd/parse.h            |    1 +
 gcc/d/dmd/scope.h            |    4 +
 gcc/d/dmd/semantic2.c        |   20 +
 gcc/d/dmd/semantic3.c        |   34 +-
 gcc/d/dmd/statement.c        |   36 +-
 gcc/d/dmd/statement.h        |    3 +-
 gcc/d/dmd/statementsem.c     |    2 +-
 gcc/d/dmd/target.h           |    4 +
 gcc/d/dmd/template.h         |    1 +
 gcc/d/dmd/templateparamsem.c |    2 +-
 gcc/d/dmd/traits.c           |  103 +-
 gcc/d/dmd/typesem.c          |   77 +-
 gcc/d/dmd/visitor.h          |    4 +
 gcc/d/toir.cc                |    7 +
 gcc/d/types.cc               |   47 +-
 51 files changed, 4517 insertions(+), 2454 deletions(-)
 create mode 100644 gcc/d/dmd/chkformat.c
diff mbox series

Patch

diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 75857d81ec7..b3c77a08f46 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -64,6 +64,7 @@  D_FRONTEND_OBJS = \
 	d/blockexit.o \
 	d/canthrow.o \
 	d/checkedint.o \
+	d/chkformat.o \
 	d/clone.o \
 	d/cond.o \
 	d/constfold.o \
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 5e6f240cb90..608abcd94f5 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -1153,6 +1153,14 @@  build_struct_literal (tree type, vec <constructor_elt, va_gc> *init)
   if (vec_safe_is_empty (init))
     return build_constructor (type, NULL);
 
+  /* Struct literals can be seen for special enums representing `_Complex',
+     make sure to reinterpret the literal as the correct type.  */
+  if (COMPLEX_FLOAT_TYPE_P (type))
+    {
+      gcc_assert (vec_safe_length (init) == 2);
+      return build_complex (type, (*init)[0].value, (*init)[1].value);
+    }
+
   vec <constructor_elt, va_gc> *ve = NULL;
   HOST_WIDE_INT offset = 0;
   bool constant_p = true;
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index f407a46da6e..3073edaae9f 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -559,7 +559,9 @@  convert_expr (tree exp, Type *etype, Type *totype)
       break;
 
     case Tnull:
-      /* Casting from typeof(null) is represented as all zeros.  */
+    case Tnoreturn:
+      /* Casting from `typeof(null)' for `null' expressions, or `typeof(*null)'
+	 for `noreturn' expressions is represented as all zeros.  */
       result = build_typeof_null_value (totype);
 
       /* Make sure the expression is still evaluated if necessary.  */
@@ -742,6 +744,16 @@  convert_for_condition (tree expr, Type *type)
 	break;
       }
 
+    case Tnoreturn:
+      /* Front-end allows conditionals that never return, represent the
+	 conditional result value as all zeros.  */
+      result = build_zero_cst (d_bool_type);
+
+      /* Make sure the expression is still evaluated if necessary.  */
+      if (TREE_SIDE_EFFECTS (expr))
+	result = compound_expr (expr, result);
+      break;
+
     default:
       result = expr;
       break;
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index d50fcef22e2..a1dc2ee286f 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -164,6 +164,15 @@  Target::_init (const Param &)
   this->c.longsize = int_size_in_bytes (long_integer_type_node);
   this->c.long_doublesize = int_size_in_bytes (long_double_type_node);
 
+  /* Define what type to use for wchar_t.  We don't want to support wide
+     characters less than "short" in D.  */
+  if (WCHAR_TYPE_SIZE == 32)
+    this->c.twchar_t = Type::basic[Tdchar];
+  else if (WCHAR_TYPE_SIZE == 16)
+    this->c.twchar_t = Type::basic[Twchar];
+  else
+    sorry ("D does not support wide characters on this target.");
+
   /* Set-up target C++ ABI.  */
   this->cpp.reverseOverloads = false;
   this->cpp.exceptions = true;
@@ -417,6 +426,15 @@  TargetCPP::fundamentalType (const Type *, bool &)
   return false;
 }
 
+/* Get the starting offset position for fields of an `extern(C++)` class
+   that is derived from the given BASE_CLASS.  */
+
+unsigned
+TargetCPP::derivedClassOffset(ClassDeclaration *base_class)
+{
+  return base_class->structsize;
+}
+
 /* Return the default system linkage for the target.  */
 
 LINK
@@ -517,3 +535,13 @@  Target::getTargetInfo (const char *key, const Loc &loc)
 
   return NULL;
 }
+
+/**
+ * Returns true if the implementation for object monitors is always defined
+ * in the D runtime library (rt/monitor_.d).  */
+
+bool
+Target::libraryObjectMonitors (FuncDeclaration *, Statement *)
+{
+  return true;
+}
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 042abbfc48a..0ec19345272 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -1277,6 +1277,10 @@  get_symbol_decl (Declaration *decl)
       if (decl->storage_class & STCfinal)
 	DECL_FINAL_P (decl->csym) = 1;
 
+      /* Function is of type `noreturn' or `typeof(*null)'.  */
+      if (fd->type->nextOf ()->ty == Tnoreturn)
+	TREE_THIS_VOLATILE (decl->csym) = 1;
+
       /* Check whether this function is expanded by the frontend.  */
       DECL_INTRINSIC_CODE (decl->csym) = INTRINSIC_NONE;
       maybe_set_intrinsic (fd);
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 78b454c1c64..86475c80d35 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-a3c9bf422e7ff54d45846b8c577ee82da4234db1
+3b808e838bb00f527eb4ed5281cd985756237b8f
 
 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/attrib.c b/gcc/d/dmd/attrib.c
index 56b8ce816be..a808b8a6c3f 100644
--- a/gcc/d/dmd/attrib.c
+++ b/gcc/d/dmd/attrib.c
@@ -80,8 +80,8 @@  Scope *AttribDeclaration::createNewScope(Scope *sc,
     if (stc != sc->stc ||
         linkage != sc->linkage ||
         cppmangle != sc->cppmangle ||
-        !protection.isSubsetOf(sc->protection) ||
         explicitProtection != sc->explicitProtection ||
+        !(protection == sc->protection) ||
         aligndecl != sc->aligndecl ||
         inlining != sc->inlining)
     {
@@ -552,10 +552,21 @@  void ProtDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
     if (protection.kind == Prot::package_ && protection.pkg && sc->_module)
     {
         Module *m = sc->_module;
-        Package* pkg = m->parent ? m->parent->isPackage() : NULL;
-        if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
-            error("does not bind to one of ancestor packages of module `%s`",
-               m->toPrettyChars(true));
+
+        // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
+        // each package's .isModule() properites are equal.
+        //
+        // Properties generated from `package(foo)` i.e. protection.pkg have .isModule() == null.
+        // This breaks package declarations of the package in question if they are declared in
+        // the same package.d file, which _do_ have a module associated with them, and hence a non-null
+        // isModule()
+        if (!m->isPackage() || !protection.pkg->ident->equals(m->isPackage()->ident))
+        {
+            Package* pkg = m->parent ? m->parent->isPackage() : NULL;
+            if (!pkg || !protection.pkg->isAncestorPackageOf(pkg))
+                error("does not bind to one of ancestor packages of module `%s`",
+                      m->toPrettyChars(true));
+        }
     }
 
     return AttribDeclaration::addMember(sc, sds);
@@ -795,6 +806,18 @@  Scope *PragmaDeclaration::newScope(Scope *sc)
             sc->protection, sc->explicitProtection, sc->aligndecl,
             inlining);
     }
+    if (ident == Id::printf || ident == Id::scanf)
+    {
+        Scope *sc2 = sc->push();
+
+        if (ident == Id::printf)
+            // Override previous setting, never let both be set
+            sc2->flags = (sc2->flags & ~SCOPEscanf) | SCOPEprintf;
+        else
+            sc2->flags = (sc2->flags & ~SCOPEprintf) | SCOPEscanf;
+
+        return sc2;
+    }
     return sc;
 }
 
@@ -1164,12 +1187,12 @@  void ForwardingAttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sds)
 
 // These are mixin declarations, like mixin("int x");
 
-CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
+CompileDeclaration::CompileDeclaration(Loc loc, Expressions *exps)
     : AttribDeclaration(NULL)
 {
     //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
     this->loc = loc;
-    this->exp = exp;
+    this->exps = exps;
     this->scopesym = NULL;
     this->compiled = false;
 }
@@ -1177,7 +1200,7 @@  CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp)
 Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *)
 {
     //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
-    return new CompileDeclaration(loc, exp->syntaxCopy());
+    return new CompileDeclaration(loc, Expression::arraySyntaxCopy(exps));
 }
 
 void CompileDeclaration::addMember(Scope *, ScopeDsymbol *sds)
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index 74364176128..174d3c1ad5b 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -234,12 +234,12 @@  public:
 class CompileDeclaration : public AttribDeclaration
 {
 public:
-    Expression *exp;
+    Expressions *exps;
 
     ScopeDsymbol *scopesym;
     bool compiled;
 
-    CompileDeclaration(Loc loc, Expression *exp);
+    CompileDeclaration(Loc loc, Expressions *exps);
     Dsymbol *syntaxCopy(Dsymbol *s);
     void addMember(Scope *sc, ScopeDsymbol *sds);
     void setScope(Scope *sc);
diff --git a/gcc/d/dmd/blockexit.c b/gcc/d/dmd/blockexit.c
index 44e3cc13bd3..1895d36fb1e 100644
--- a/gcc/d/dmd/blockexit.c
+++ b/gcc/d/dmd/blockexit.c
@@ -62,6 +62,8 @@  int blockExit(Statement *s, FuncDeclaration *func, bool mustNotThrow)
                         return;
                     }
                 }
+                if (s->exp->type->toBasetype()->isTypeNoreturn())
+                    result = BEhalt;
                 if (canThrow(s->exp, func, mustNotThrow))
                     result |= BEthrow;
             }
diff --git a/gcc/d/dmd/chkformat.c b/gcc/d/dmd/chkformat.c
new file mode 100644
index 00000000000..d00b658ca00
--- /dev/null
+++ b/gcc/d/dmd/chkformat.c
@@ -0,0 +1,975 @@ 
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * http://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * http://www.boost.org/LICENSE_1_0.txt
+ */
+
+// Check the arguments to `printf` and `scanf` against the `format` string.
+
+#include "root/dsystem.h"
+#include "root/dcompat.h"
+
+#include "arraytypes.h"
+#include "cond.h"
+#include "errors.h"
+#include "expression.h"
+#include "globals.h"
+#include "identifier.h"
+#include "mtype.h"
+#include "target.h"
+
+
+/* Different kinds of formatting specifications, variations we don't
+   care about are merged. (Like we don't care about the difference between
+   f, e, g, a, etc.)
+
+   For `scanf`, every format is a pointer.
+ */
+enum Format
+{
+    Format_d,          // int
+    Format_hhd,        // signed char
+    Format_hd,         // short int
+    Format_ld,         // long int
+    Format_lld,        // long long int
+    Format_jd,         // intmax_t
+    Format_zd,         // size_t
+    Format_td,         // ptrdiff_t
+    Format_u,          // unsigned int
+    Format_hhu,        // unsigned char
+    Format_hu,         // unsigned short int
+    Format_lu,         // unsigned long int
+    Format_llu,        // unsigned long long int
+    Format_ju,         // uintmax_t
+    Format_g,          // float (scanf) / double (printf)
+    Format_lg,         // double (scanf)
+    Format_Lg,         // long double (both)
+    Format_s,          // char string (both)
+    Format_ls,         // wchar_t string (both)
+    Format_c,          // char (printf)
+    Format_lc,         // wint_t (printf)
+    Format_p,          // pointer
+    Format_n,          // pointer to int
+    Format_hhn,        // pointer to signed char
+    Format_hn,         // pointer to short
+    Format_ln,         // pointer to long int
+    Format_lln,        // pointer to long long int
+    Format_jn,         // pointer to intmax_t
+    Format_zn,         // pointer to size_t
+    Format_tn,         // pointer to ptrdiff_t
+    Format_GNU_a,      // GNU ext. : address to a string with no maximum size (scanf)
+    Format_GNU_m,      // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
+    Format_percent,    // %% (i.e. no argument)
+    Format_error,      // invalid format specification
+};
+
+/**************************************
+ * Parse the *length specifier* and the *specifier* of the following form:
+ * `[length]specifier`
+ *
+ * Params:
+ *      format = format string
+ *      idx = index of of start of format specifier,
+ *          which gets updated to index past the end of it,
+ *          even if `Format_error` is returned
+ *      genSpecifier = Generic specifier. For instance, it will be set to `d` if the
+ *           format is `hdd`.
+ * Returns:
+ *      Format
+ */
+static Format parseGenericFormatSpecifier(const char *format,
+            size_t &idx, char &genSpecifier, bool useGNUExts =
+            findCondition(global.versionids, Identifier::idPool("CRuntime_Glibc")))
+{
+    genSpecifier = 0;
+
+    const size_t length = strlen(format);
+
+    /* Read the `length modifier`
+     */
+    const char lm = format[idx];
+    bool lm1= false;        // if jztL
+    bool lm2= false;        // if `hh` or `ll`
+    if (lm == 'j' ||
+        lm == 'z' ||
+        lm == 't' ||
+        lm == 'L')
+    {
+        ++idx;
+        if (idx == length)
+            return Format_error;
+        lm1 = true;
+    }
+    else if (lm == 'h' || lm == 'l')
+    {
+        ++idx;
+        if (idx == length)
+            return Format_error;
+        lm2 = lm == format[idx];
+        if (lm2)
+        {
+            ++idx;
+            if (idx == length)
+                return Format_error;
+        }
+    }
+
+    /* Read the `specifier`
+     */
+    Format specifier;
+    const char sc = format[idx];
+    genSpecifier = sc;
+    switch (sc)
+    {
+        case 'd':
+        case 'i':
+            if (lm == 'L')
+                specifier = Format_error;
+            else
+                specifier = lm == 'h' && lm2 ? Format_hhd :
+                            lm == 'h'        ? Format_hd  :
+                            lm == 'l' && lm2 ? Format_lld :
+                            lm == 'l'        ? Format_ld  :
+                            lm == 'j'        ? Format_jd  :
+                            lm == 'z'        ? Format_zd  :
+                            lm == 't'        ? Format_td  :
+                                               Format_d;
+            break;
+
+        case 'u':
+        case 'o':
+        case 'x':
+        case 'X':
+            if (lm == 'L')
+                specifier = Format_error;
+            else
+                specifier = lm == 'h' && lm2 ? Format_hhu :
+                            lm == 'h'        ? Format_hu  :
+                            lm == 'l' && lm2 ? Format_llu :
+                            lm == 'l'        ? Format_lu  :
+                            lm == 'j'        ? Format_ju  :
+                            lm == 'z'        ? Format_zd  :
+                            lm == 't'        ? Format_td  :
+                                               Format_u;
+            break;
+
+        case 'a':
+            if (useGNUExts)
+            {
+                // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
+                specifier = Format_GNU_a;
+                break;
+            }
+            /* fall through */
+
+        case 'f':
+        case 'F':
+        case 'e':
+        case 'E':
+        case 'g':
+        case 'G':
+        case 'A':
+            if (lm == 'L')
+                specifier = Format_Lg;
+            else if (lm1 || lm2 || lm == 'h')
+                specifier = Format_error;
+            else
+                specifier = lm == 'l' ? Format_lg : Format_g;
+            break;
+
+        case 'c':
+            if (lm1 || lm2 || lm == 'h')
+                specifier = Format_error;
+            else
+                specifier = lm == 'l' ? Format_lc : Format_c;
+            break;
+
+        case 's':
+            if (lm1 || lm2 || lm == 'h')
+                specifier = Format_error;
+            else
+                specifier = lm == 'l' ? Format_ls : Format_s;
+            break;
+
+        case 'p':
+            if (lm1 || lm2 || lm == 'h' || lm == 'l')
+                specifier = Format_error;
+            else
+                specifier = Format_p;
+            break;
+
+        case 'n':
+            if (lm == 'L')
+                specifier = Format_error;
+            else
+                specifier = lm == 'l' && lm2 ? Format_lln :
+                            lm == 'l'        ? Format_ln  :
+                            lm == 'h' && lm2 ? Format_hhn :
+                            lm == 'h'        ? Format_hn  :
+                            lm == 'j'        ? Format_jn  :
+                            lm == 'z'        ? Format_zn  :
+                            lm == 't'        ? Format_tn  :
+                                               Format_n;
+            break;
+
+        case 'm':
+            if (useGNUExts)
+            {
+                // http://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
+                specifier = Format_GNU_m;
+                break;
+            }
+            goto Ldefault;
+
+        default:
+        Ldefault:
+            specifier = Format_error;
+            break;
+    }
+
+    ++idx;
+    return specifier; // success
+}
+
+Format formatError(size_t &idx, size_t i)
+{
+    idx = i;
+    return Format_error;
+}
+
+/**************************************
+ * Parse the *format specifier* which is of the form:
+ *
+ * `%[*][width][length]specifier`
+ *
+ * Params:
+ *      format = format string
+ *      idx = index of `%` of start of format specifier,
+ *          which gets updated to index past the end of it,
+ *          even if `Format_error` is returned
+ *      asterisk = set if there is a `*` sub-specifier
+ * Returns:
+ *      Format
+ */
+static Format parseScanfFormatSpecifier(const char *format, size_t &idx,
+                bool &asterisk)
+{
+    asterisk = false;
+
+    size_t i = idx;
+    assert(format[i] == '%');
+    const size_t length = strlen(format);
+
+    ++i;
+    if (i == length)
+        return formatError(idx, i);
+
+    if (format[i] == '%')
+    {
+        idx = i + 1;
+        return Format_percent;
+    }
+
+    // * sub-specifier
+    if (format[i] == '*')
+    {
+        ++i;
+        if (i == length)
+            return formatError(idx, i);
+        asterisk = true;
+    }
+
+    // fieldWidth
+    while (isdigit(format[i]))
+    {
+        i++;
+        if (i == length)
+            return formatError(idx, i);
+    }
+
+    /* Read the scanset
+     * A scanset can be anything, so we just check that it is paired
+     */
+    if (format[i] == '[')
+    {
+        while (i < length)
+        {
+            if (format[i] == ']')
+                break;
+            ++i;
+        }
+
+        // no `]` found
+        if (i == length)
+            return formatError(idx, i);
+
+        ++i;
+        // no specifier after `]`
+        // it could be mixed with the one above, but then idx won't have the right index
+        if (i == length)
+            return formatError(idx, i);
+    }
+
+    /* Read the specifier
+     */
+    char genSpec;
+    Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
+    if (specifier == Format_error)
+        return formatError(idx, i);
+
+    idx = i;
+    return specifier;  // success
+}
+
+/**************************************
+ * Parse the *format specifier* which is of the form:
+ *
+ * `%[flags][field width][.precision][length modifier]specifier`
+ *
+ * Params:
+ *      format = format string
+ *      idx = index of `%` of start of format specifier,
+ *          which gets updated to index past the end of it,
+ *          even if `Format_error` is returned
+ *      widthStar = set if * for width
+ *      precisionStar = set if * for precision
+ * Returns:
+ *      Format
+ */
+static Format parsePrintfFormatSpecifier(const char *format, size_t &idx,
+                bool &widthStar, bool &precisionStar)
+{
+    widthStar = false;
+    precisionStar = false;
+
+    size_t i = idx;
+    assert(format[i] == '%');
+    const size_t format_length = strlen(format);
+    const size_t length = format_length;
+    bool hash = false;
+    bool zero = false;
+    bool flags = false;
+    bool width = false;
+    bool precision = false;
+
+    ++i;
+    if (i == length)
+        return formatError(idx, i);
+
+    if (format[i] == '%')
+    {
+        idx = i + 1;
+        return Format_percent;
+    }
+
+    /* Read the `flags`
+     */
+    while (1)
+    {
+        const char c = format[i];
+        if (c == '-' ||
+            c == '+' ||
+            c == ' ')
+        {
+            flags = true;
+        }
+        else if (c == '#')
+        {
+            hash = true;
+        }
+        else if (c == '0')
+        {
+            zero = true;
+        }
+        else
+            break;
+        ++i;
+        if (i == length)
+            return formatError(idx, i);
+    }
+
+    /* Read the `field width`
+     */
+    {
+        const char c = format[i];
+        if (c == '*')
+        {
+            width = true;
+            widthStar = true;
+            ++i;
+            if (i == length)
+                return formatError(idx, i);
+        }
+        else if ('1' <= c && c <= '9')
+        {
+            width = true;
+            ++i;
+            if (i == length)
+                return formatError(idx, i);
+            while ('0' <= format[i] && format[i] <= '9')
+            {
+               ++i;
+               if (i == length)
+                    return formatError(idx, i);
+            }
+        }
+    }
+
+    /* Read the `precision`
+     */
+    if (format[i] == '.')
+    {
+        precision = true;
+        ++i;
+        if (i == length)
+            return formatError(idx, i);
+        const char c = format[i];
+        if (c == '*')
+        {
+            precisionStar = true;
+            ++i;
+            if (i == length)
+                return formatError(idx, i);
+        }
+        else if ('0' <= c && c <= '9')
+        {
+            ++i;
+            if (i == length)
+                return formatError(idx, i);
+            while ('0' <= format[i] && format[i] <= '9')
+            {
+               ++i;
+               if (i == length)
+                    return formatError(idx, i);
+            }
+        }
+    }
+
+    /* Read the specifier
+     */
+    char genSpec;
+    Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
+    if (specifier == Format_error)
+        return formatError(idx, i);
+
+    switch (genSpec)
+    {
+        case 'c':
+        case 's':
+            if (hash || zero)
+                return formatError(idx, i);
+            break;
+
+        case 'd':
+        case 'i':
+            if (hash)
+                return formatError(idx, i);
+            break;
+
+        case 'n':
+            if (hash || zero || precision || width || flags)
+                return formatError(idx, i);
+            break;
+
+        default:
+            break;
+    }
+
+    idx = i;
+    return specifier;  // success
+}
+
+/*******************************************/
+
+static Expression *getNextPrintfArg(const Loc &loc, Expressions &args, size_t &n,
+                size_t gnu_m_count, bool &skip)
+{
+    if (n == args.length)
+    {
+        if (args.length < (n + 1) - gnu_m_count)
+            deprecation(loc, "more format specifiers than %d arguments", (int)n);
+        else
+            skip = true;
+        return NULL;
+    }
+    return args[n++];
+}
+
+static void errorPrintfFormat(const char *prefix, DString &slice, Expression *arg,
+                const char *texpect, Type *tactual)
+{
+    deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
+                prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
+}
+
+/******************************************
+ * Check that arguments to a printf format string are compatible
+ * with that string. Issue errors for incompatibilities.
+ *
+ * Follows the C99 specification for printf.
+ *
+ * Takes a generous, rather than strict, view of compatiblity.
+ * For example, an unsigned value can be formatted with a signed specifier.
+ *
+ * Diagnosed incompatibilities are:
+ *
+ * 1. incompatible sizes which will cause argument misalignment
+ * 2. deferencing arguments that are not pointers
+ * 3. insufficient number of arguments
+ * 4. struct arguments
+ * 5. array and slice arguments
+ * 6. non-pointer arguments to `s` specifier
+ * 7. non-standard formats
+ * 8. undefined behavior per C99
+ *
+ * Per the C Standard, extra arguments are ignored.
+ *
+ * No attempt is made to fix the arguments or the format string.
+ *
+ * Params:
+ *      loc = location for error messages
+ *      format = format string
+ *      args = arguments to match with format string
+ *      isVa_list = if a "v" function (format check only)
+ *
+ * Returns:
+ *      `true` if errors occurred
+ * References:
+ * C99 7.19.6.1
+ * http://www.cplusplus.com/reference/cstdio/printf/
+ */
+bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
+{
+    //printf("checkPrintFormat('%s')\n", format);
+    size_t n = 0;             // index in args
+    size_t gnu_m_count = 0;   // number of Format_GNU_m
+    const size_t format_length = strlen(format);
+    for (size_t i = 0; i < format_length;)
+    {
+        if (format[i] != '%')
+        {
+            ++i;
+            continue;
+        }
+        bool widthStar = false;
+        bool precisionStar = false;
+        size_t j = i;
+        const Format fmt = parsePrintfFormatSpecifier(format, j, widthStar, precisionStar);
+        DString slice = DString(j - i, format + i);
+        i = j;
+
+        if (fmt == Format_percent)
+            continue;                   // "%%", no arguments
+
+        if (isVa_list)
+        {
+            // format check only
+            if (fmt == Format_error)
+                deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
+            continue;
+        }
+
+        if (fmt == Format_GNU_m)
+            ++gnu_m_count;
+
+        if (widthStar)
+        {
+            bool skip = false;
+            Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
+            if (skip)
+                continue;
+            if (!e)
+                return true;
+            Type *t = e->type->toBasetype();
+            if (t->ty != Tint32 && t->ty != Tuns32)
+                errorPrintfFormat("width ", slice, e, "int", t);
+        }
+
+        if (precisionStar)
+        {
+            bool skip = false;
+            Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
+            if (skip)
+                continue;
+            if (!e)
+                return true;
+            Type *t = e->type->toBasetype();
+            if (t->ty != Tint32 && t->ty != Tuns32)
+                errorPrintfFormat("precision ", slice, e, "int", t);
+        }
+
+        bool skip = false;
+        Expression *e = getNextPrintfArg(loc, args, n, gnu_m_count, skip);
+        if (skip)
+            continue;
+        if (!e)
+            return true;
+        Type *t = e->type->toBasetype();
+        Type *tnext = t->nextOf();
+        const unsigned c_longsize = target.c.longsize;
+        const bool is64bit = global.params.is64bit;
+
+        // Types which are promoted to int are allowed.
+        // Spec: C99 6.5.2.2.7
+        switch (fmt)
+        {
+            case Format_u:      // unsigned int
+            case Format_d:      // int
+                if (t->ty != Tint32 && t->ty != Tuns32)
+                    errorPrintfFormat(NULL, slice, e, "int", t);
+                break;
+
+            case Format_hhu:    // unsigned char
+            case Format_hhd:    // signed char
+                if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint8 && t->ty != Tuns8)
+                    errorPrintfFormat(NULL, slice, e, "byte", t);
+                break;
+
+            case Format_hu:     // unsigned short int
+            case Format_hd:     // short int
+                if (t->ty != Tint32 && t->ty != Tuns32 && t->ty != Tint16 && t->ty != Tuns16)
+                    errorPrintfFormat(NULL, slice, e, "short", t);
+                break;
+
+            case Format_lu:     // unsigned long int
+            case Format_ld:     // long int
+                if (!(t->isintegral() && t->size() == c_longsize))
+                    errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int" : "long"), t);
+                break;
+
+            case Format_llu:    // unsigned long long int
+            case Format_lld:    // long long int
+                if (t->ty != Tint64 && t->ty != Tuns64)
+                    errorPrintfFormat(NULL, slice, e, "long", t);
+                break;
+
+            case Format_ju:     // uintmax_t
+            case Format_jd:     // intmax_t
+                if (t->ty != Tint64 && t->ty != Tuns64)
+                    errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t", t);
+                break;
+
+            case Format_zd:     // size_t
+                if (!(t->isintegral() && t->size() == (is64bit ? 8 : 4)))
+                    errorPrintfFormat(NULL, slice, e, "size_t", t);
+                break;
+
+            case Format_td:     // ptrdiff_t
+                if (!(t->isintegral() && t->size() == (is64bit ? 8 : 4)))
+                    errorPrintfFormat(NULL, slice, e, "ptrdiff_t", t);
+                break;
+
+            case Format_GNU_a:  // Format_GNU_a is only for scanf
+            case Format_lg:
+            case Format_g:      // double
+                if (t->ty != Tfloat64 && t->ty != Timaginary64)
+                    errorPrintfFormat(NULL, slice, e, "double", t);
+                break;
+
+            case Format_Lg:     // long double
+                if (t->ty != Tfloat80 && t->ty != Timaginary80)
+                    errorPrintfFormat(NULL, slice, e, "real", t);
+                break;
+
+            case Format_p:      // pointer
+                if (t->ty != Tpointer && t->ty != Tnull && t->ty != Tclass && t->ty != Tdelegate && t->ty != Taarray)
+                    errorPrintfFormat(NULL, slice, e, "void*", t);
+                break;
+
+            case Format_n:      // pointer to int
+                if (!(t->ty == Tpointer && tnext->ty == Tint32))
+                    errorPrintfFormat(NULL, slice, e, "int*", t);
+                break;
+
+            case Format_ln:     // pointer to long int
+                if (!(t->ty == Tpointer && tnext->isintegral() && tnext->size() == c_longsize))
+                    errorPrintfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
+                break;
+
+            case Format_lln:    // pointer to long long int
+                if (!(t->ty == Tpointer && tnext->ty == Tint64))
+                    errorPrintfFormat(NULL, slice, e, "long*", t);
+                break;
+
+            case Format_hn:     // pointer to short
+                if (!(t->ty == Tpointer && tnext->ty == Tint16))
+                    errorPrintfFormat(NULL, slice, e, "short*", t);
+                break;
+
+            case Format_hhn:    // pointer to signed char
+                if (!(t->ty == Tpointer && tnext->ty == Tint16))
+                    errorPrintfFormat(NULL, slice, e, "byte*", t);
+                break;
+
+            case Format_jn:     // pointer to intmax_t
+                if (!(t->ty == Tpointer && tnext->ty == Tint64))
+                    errorPrintfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
+                break;
+
+            case Format_zn:     // pointer to size_t
+                if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
+                    errorPrintfFormat(NULL, slice, e, "size_t*", t);
+                break;
+
+            case Format_tn:     // pointer to ptrdiff_t
+                if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tint64 : Tint32)))
+                    errorPrintfFormat(NULL, slice, e, "ptrdiff_t*", t);
+                break;
+
+            case Format_c:      // char
+                if (t->ty != Tint32 && t->ty != Tuns32)
+                    errorPrintfFormat(NULL, slice, e, "char", t);
+                break;
+
+            case Format_lc:     // wint_t
+                if (t->ty != Tint32 && t->ty != Tuns32)
+                    errorPrintfFormat(NULL, slice, e, "wchar_t", t);
+                break;
+
+            case Format_s:      // pointer to char string
+                if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
+                    errorPrintfFormat(NULL, slice, e, "char*", t);
+                break;
+
+            case Format_ls:     // pointer to wchar_t string
+            {
+                if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
+                    errorPrintfFormat(NULL, slice, e, "wchar_t*", t);
+                break;
+            }
+            case Format_error:
+                deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
+                break;
+
+            case Format_GNU_m:
+                break;  // not assert(0) because it may go through it if there are extra arguments
+
+            case Format_percent:
+            default:
+                assert(0);
+        }
+    }
+    return false;
+}
+
+/*******************************************/
+
+static Expression *getNextScanfArg(const Loc &loc, Expressions &args, size_t &n, bool asterisk)
+{
+    if (n == args.length)
+    {
+        if (!asterisk)
+            deprecation(loc, "more format specifiers than %d arguments", (int)n);
+        return NULL;
+    }
+    return args[n++];
+}
+
+static void errorScanfFormat(const char *prefix, DString &slice,
+                Expression *arg, const char *texpect, Type *tactual)
+{
+    deprecation(arg->loc, "%sargument `%s` for format specification `\"%.*s\"` must be `%s`, not `%s`",
+                prefix ? prefix : "", arg->toChars(), (int)slice.length, slice.ptr, texpect, tactual->toChars());
+}
+
+/******************************************
+ * Check that arguments to a scanf format string are compatible
+ * with that string. Issue errors for incompatibilities.
+ *
+ * Follows the C99 specification for scanf.
+ *
+ * Takes a generous, rather than strict, view of compatiblity.
+ * For example, an unsigned value can be formatted with a signed specifier.
+ *
+ * Diagnosed incompatibilities are:
+ *
+ * 1. incompatible sizes which will cause argument misalignment
+ * 2. deferencing arguments that are not pointers
+ * 3. insufficient number of arguments
+ * 4. struct arguments
+ * 5. array and slice arguments
+ * 6. non-standard formats
+ * 7. undefined behavior per C99
+ *
+ * Per the C Standard, extra arguments are ignored.
+ *
+ * No attempt is made to fix the arguments or the format string.
+ *
+ * Params:
+ *      loc = location for error messages
+ *      format = format string
+ *      args = arguments to match with format string
+ *      isVa_list = if a "v" function (format check only)
+ *
+ * Returns:
+ *      `true` if errors occurred
+ * References:
+ * C99 7.19.6.2
+ * http://www.cplusplus.com/reference/cstdio/scanf/
+ */
+bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list)
+{
+    size_t n = 0;
+    const size_t format_length = strlen(format);
+    for (size_t i = 0; i < format_length;)
+    {
+        if (format[i] != '%')
+        {
+            ++i;
+            continue;
+        }
+        bool asterisk = false;
+        size_t j = i;
+        const Format fmt = parseScanfFormatSpecifier(format, j, asterisk);
+        DString slice = DString(j - i, format + i);
+        i = j;
+
+        if (fmt == Format_percent || asterisk)
+            continue;   // "%%", "%*": no arguments
+
+        if (isVa_list)
+        {
+            // format check only
+            if (fmt == Format_error)
+                deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
+            continue;
+        }
+
+        Expression *e = getNextScanfArg(loc, args, n, asterisk);
+        if (!e)
+            return true;
+
+        Type *t = e->type->toBasetype();
+        Type *tnext = t->nextOf();
+        const unsigned c_longsize = target.c.longsize;
+        const bool is64bit = global.params.is64bit;
+
+        switch (fmt)
+        {
+            case Format_n:
+            case Format_d:      // pointer to int
+                if (!(t->ty == Tpointer && tnext->ty == Tint32))
+                    errorScanfFormat(NULL, slice, e, "int*", t);
+                break;
+
+            case Format_hhn:
+            case Format_hhd:    // pointer to signed char
+                if (!(t->ty == Tpointer && tnext->ty == Tint16))
+                    errorScanfFormat(NULL, slice, e, "byte*", t);
+                break;
+
+            case Format_hn:
+            case Format_hd:     // pointer to short
+                if (!(t->ty == Tpointer && tnext->ty == Tint16))
+                    errorScanfFormat(NULL, slice, e, "short*", t);
+                break;
+
+            case Format_ln:
+            case Format_ld:     // pointer to long int
+                if (!(t->ty == Tpointer && tnext->isintegral() && tnext->size() == c_longsize))
+                    errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "int*" : "long*"), t);
+                break;
+
+            case Format_lln:
+            case Format_lld:    // pointer to long long int
+                if (!(t->ty == Tpointer && tnext->ty == Tint64))
+                    errorScanfFormat(NULL, slice, e, "long*", t);
+                break;
+
+            case Format_jn:
+            case Format_jd:     // pointer to intmax_t
+                if (!(t->ty == Tpointer && tnext->ty == Tint64))
+                    errorScanfFormat(NULL, slice, e, "core.stdc.stdint.intmax_t*", t);
+                break;
+
+            case Format_zn:
+            case Format_zd:     // pointer to size_t
+                if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
+                    errorScanfFormat(NULL, slice, e, "size_t*", t);
+                break;
+
+            case Format_tn:
+            case Format_td:     // pointer to ptrdiff_t
+                if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tint64 : Tint32)))
+                    errorScanfFormat(NULL, slice, e, "ptrdiff_t*", t);
+                break;
+
+            case Format_u:      // pointer to unsigned int
+                if (!(t->ty == Tpointer && tnext->ty == Tuns32))
+                    errorScanfFormat(NULL, slice, e, "uint*", t);
+                break;
+
+            case Format_hhu:    // pointer to unsigned char
+                if (!(t->ty == Tpointer && tnext->ty == Tuns8))
+                    errorScanfFormat(NULL, slice, e, "ubyte*", t);
+                break;
+
+            case Format_hu:     // pointer to unsigned short int
+                if (!(t->ty == Tpointer && tnext->ty == Tuns16))
+                    errorScanfFormat(NULL, slice, e, "ushort*", t);
+                break;
+
+            case Format_lu:     // pointer to unsigned long int
+                if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
+                    errorScanfFormat(NULL, slice, e, (c_longsize == 4 ? "uint*" : "ulong*"), t);
+                break;
+
+            case Format_llu:    // pointer to unsigned long long int
+                if (!(t->ty == Tpointer && tnext->ty == Tuns64))
+                    errorScanfFormat(NULL, slice, e, "ulong*", t);
+                break;
+
+            case Format_ju:     // pointer to uintmax_t
+                if (!(t->ty == Tpointer && tnext->ty == (is64bit ? Tuns64 : Tuns32)))
+                    errorScanfFormat(NULL, slice, e, "ulong*", t);
+                break;
+
+            case Format_g:      // pointer to float
+                if (!(t->ty == Tpointer && tnext->ty == Tfloat32))
+                    errorScanfFormat(NULL, slice, e, "float*", t);
+                break;
+
+            case Format_lg:     // pointer to double
+                if (!(t->ty == Tpointer && tnext->ty == Tfloat64))
+                    errorScanfFormat(NULL, slice, e, "double*", t);
+                break;
+
+            case Format_Lg:     // pointer to long double
+                if (!(t->ty == Tpointer && tnext->ty == Tfloat80))
+                    errorScanfFormat(NULL, slice, e, "real*", t);
+                break;
+
+            case Format_GNU_a:
+            case Format_GNU_m:
+            case Format_c:
+            case Format_s:      // pointer to char string
+                if (!(t->ty == Tpointer && (tnext->ty == Tchar || tnext->ty == Tint8 || tnext->ty == Tuns8)))
+                    errorScanfFormat(NULL, slice, e, "char*", t);
+                break;
+
+            case Format_lc:
+            case Format_ls:     // pointer to wchar_t string
+            {
+                if (!(t->ty == Tpointer && tnext == target.c.twchar_t))
+                    errorScanfFormat(NULL, slice, e, "wchar_t*", t);
+                break;
+            }
+            case Format_p:      // double pointer
+                if (!(t->ty == Tpointer && tnext->ty == Tpointer))
+                    errorScanfFormat(NULL, slice, e, "void**", t);
+                break;
+
+            case Format_error:
+                deprecation(loc, "format specifier `\"%.*s\"` is invalid", (int)slice.length, slice.ptr);
+                break;
+
+            case Format_percent:
+            default:
+                assert(0);
+        }
+    }
+    return false;
+}
diff --git a/gcc/d/dmd/cppmangle.c b/gcc/d/dmd/cppmangle.c
index a0e0b5fb993..baf64c5653e 100644
--- a/gcc/d/dmd/cppmangle.c
+++ b/gcc/d/dmd/cppmangle.c
@@ -806,6 +806,14 @@  public:
         writeBasicType(t, 'D', 'n');
     }
 
+    void visit(TypeNoreturn *t)
+    {
+        if (t->isImmutable() || t->isShared())
+            return error(t);
+
+        writeBasicType(t, 0, 'v');      // mangle like `void`
+    }
+
     void visit(TypeBasic *t)
     {
         if (t->isImmutable() || t->isShared())
@@ -1012,7 +1020,7 @@  public:
         if (t->isImmutable() || t->isShared())
             return error(t);
 
-        /* __c_(u)long(long) get special mangling
+        /* __c_(u)long(long) and others get special mangling
          */
         Identifier *id = t->sym->ident;
         //printf("enum id = '%s'\n", id->toChars());
@@ -1020,10 +1028,18 @@  public:
             return writeBasicType(t, 0, 'l');
         else if (id == Id::__c_ulong)
             return writeBasicType(t, 0, 'm');
+        else if (id == Id::__c_wchar_t)
+            return writeBasicType(t, 0, 'w');
         else if (id == Id::__c_longlong)
             return writeBasicType(t, 0, 'x');
         else if (id == Id::__c_ulonglong)
             return writeBasicType(t, 0, 'y');
+        else if (id == Id::__c_complex_float)
+            return writeBasicType(t, 'C', 'f');
+        else if (id == Id::__c_complex_double)
+            return writeBasicType(t, 'C', 'd');
+        else if (id == Id::__c_complex_real)
+            return writeBasicType(t, 'C', 'e');
 
         doSymbol(t);
     }
diff --git a/gcc/d/dmd/ctfeexpr.c b/gcc/d/dmd/ctfeexpr.c
index 1d669e595e5..a8e97833ad0 100644
--- a/gcc/d/dmd/ctfeexpr.c
+++ b/gcc/d/dmd/ctfeexpr.c
@@ -162,7 +162,7 @@  const char *CTFEExp::toChars()
     switch (op)
     {
         case TOKcantexp:    return "<cant>";
-        case TOKvoidexp:    return "<void>";
+        case TOKvoidexp:    return "cast(void)0";
         case TOKbreak:      return "<break>";
         case TOKcontinue:   return "<continue>";
         case TOKgoto:       return "<goto>";
diff --git a/gcc/d/dmd/dcast.c b/gcc/d/dmd/dcast.c
index 61e28fe8d13..4dd648bcc48 100644
--- a/gcc/d/dmd/dcast.c
+++ b/gcc/d/dmd/dcast.c
@@ -26,6 +26,7 @@ 
 FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
 bool isCommutative(TOK op);
 MOD MODmerge(MOD mod1, MOD mod2);
+void toAutoQualChars(const char **result, Type *t1, Type *t2);
 
 /* ==================== implicitCast ====================== */
 
@@ -90,8 +91,10 @@  Expression *implicitCastTo(Expression *e, Scope *sc, Type *t)
                     //printf("type %p ty %d deco %p\n", type, type->ty, type->deco);
                     //type = type->semantic(loc, sc);
                     //printf("type %s t %s\n", type->deco, t->deco);
+                    const char *ts[2];
+                    toAutoQualChars(ts, e->type, t);
                     e->error("cannot implicitly convert expression (%s) of type %s to %s",
-                        e->toChars(), e->type->toChars(), t->toChars());
+                        e->toChars(), ts[0], ts[1]);
                 }
             }
             result = new ErrorExp();
diff --git a/gcc/d/dmd/dclass.c b/gcc/d/dmd/dclass.c
index c7dbbbea5d3..3f33014da9f 100644
--- a/gcc/d/dmd/dclass.c
+++ b/gcc/d/dmd/dclass.c
@@ -277,15 +277,10 @@  Scope *ClassDeclaration::newScope(Scope *sc)
     Scope *sc2 = AggregateDeclaration::newScope(sc);
     if (isCOMclass())
     {
-        if (global.params.isWindows)
-            sc2->linkage = LINKwindows;
-        else
-        {
-            /* This enables us to use COM objects under Linux and
-             * work with things like XPCOM
-             */
-            sc2->linkage = LINKc;
-        }
+        /* This enables us to use COM objects under Linux and
+         * work with things like XPCOM
+         */
+        sc2->linkage = target.systemLinkage();
     }
     return sc2;
 }
@@ -491,9 +486,10 @@  void ClassDeclaration::finalizeSize()
         assert(baseClass->sizeok == SIZEOKdone);
 
         alignsize = baseClass->alignsize;
-        structsize = baseClass->structsize;
-        if (isCPPclass() && global.params.isWindows)
-            structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
+        if (classKind == ClassKind::cpp)
+            structsize = target.cpp.derivedClassOffset(baseClass);
+        else
+            structsize = baseClass->structsize;
     }
     else if (isInterfaceDeclaration())
     {
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 81b563f4b0f..55c814288e0 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -118,7 +118,7 @@  struct Match
     FuncDeclaration *anyf;      // pick a func, any func, to use for error recovery
 };
 
-void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs);
+void functionResolve(Match *m, Dsymbol *fd, Loc loc, Scope *sc, Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage = NULL);
 int overloadApply(Dsymbol *fstart, void *param, int (*fp)(void *, Dsymbol *));
 void aliasSemantic(AliasDeclaration *ds, Scope *sc);
 
@@ -551,6 +551,8 @@  void builtin_init();
 #define FUNCFLAGreturnInprocess 0x10    // working on inferring 'return' for parameters
 #define FUNCFLAGinlineScanned   0x20    // function has been scanned for inline possibilities
 #define FUNCFLAGinferScope      0x40    // infer 'scope' for parameters
+#define FUNCFLAGprintf          0x200   // is a printf-like function
+#define FUNCFLAGscanf           0x400   // is a scanf-like function
 
 class FuncDeclaration : public Declaration
 {
diff --git a/gcc/d/dmd/denum.c b/gcc/d/dmd/denum.c
index ca1d3bb771c..bfd3b7274f4 100644
--- a/gcc/d/dmd/denum.c
+++ b/gcc/d/dmd/denum.c
@@ -22,6 +22,19 @@ 
 #include "declaration.h"
 #include "init.h"
 
+bool isSpecialEnumIdent(const Identifier *ident)
+{
+    return  ident == Id::__c_long ||
+            ident == Id::__c_ulong ||
+            ident == Id::__c_longlong ||
+            ident == Id::__c_ulonglong ||
+            ident == Id::__c_long_double ||
+            ident == Id::__c_wchar_t ||
+            ident == Id::__c_complex_float ||
+            ident == Id::__c_complex_double ||
+            ident == Id::__c_complex_real;
+}
+
 /********************************* EnumDeclaration ****************************/
 
 EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype)
@@ -187,11 +200,7 @@  Lerrors:
  */
 bool EnumDeclaration::isSpecial() const
 {
-    return (ident == Id::__c_long ||
-            ident == Id::__c_ulong ||
-            ident == Id::__c_longlong ||
-            ident == Id::__c_ulonglong ||
-            ident == Id::__c_long_double) && memtype;
+    return isSpecialEnumIdent(ident) && memtype;
 }
 
 Expression *EnumDeclaration::getDefaultValue(Loc loc)
diff --git a/gcc/d/dmd/dimport.c b/gcc/d/dmd/dimport.c
index 0d93ed80e58..7b63a186552 100644
--- a/gcc/d/dmd/dimport.c
+++ b/gcc/d/dmd/dimport.c
@@ -161,37 +161,75 @@  void Import::load(Scope *sc)
     if (mod && !mod->importedFrom)
         mod->importedFrom = sc ? sc->_module->importedFrom : Module::rootModule;
     if (!pkg)
-        pkg = mod;
+    {
+        if (mod && mod->isPackageFile)
+        {
+            // one level depth package.d file (import pkg; ./pkg/package.d)
+            // it's necessary to use the wrapping Package already created
+            pkg = mod->pkg;
+        }
+        else
+            pkg = mod;
+    }
 
     //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg);
 }
 
 void Import::importAll(Scope *sc)
 {
-    if (!mod)
+    if (mod) return; // Already done
+    load(sc);
+    if (!mod) return; // Failed
+
+    if (sc->stc & STCstatic)
+        isstatic = true;
+    mod->importAll(NULL);
+    if (mod->md && mod->md->isdeprecated)
     {
-        load(sc);
-        if (mod)                // if successfully loaded module
-        {
-            mod->importAll(NULL);
-
-            if (mod->md && mod->md->isdeprecated)
-            {
-                Expression *msg = mod->md->msg;
-                if (StringExp *se = msg ? msg->toStringExp() : NULL)
-                    mod->deprecation(loc, "is deprecated - %s", se->string);
-                else
-                    mod->deprecation(loc, "is deprecated");
-            }
+        Expression *msg = mod->md->msg;
+        if (StringExp *se = msg ? msg->toStringExp() : NULL)
+            mod->deprecation(loc, "is deprecated - %s", se->string);
+        else
+            mod->deprecation(loc, "is deprecated");
+    }
+    if (sc->explicitProtection)
+        protection = sc->protection;
+    if (!isstatic && !aliasId && !names.length)
+        sc->scopesym->importScope(mod, protection);
+    // Enable access to pkgs/mod as soon as posible, because compiler
+    // can traverse them before the import gets semantic (Issue: 21501)
+    if (!aliasId && !names.length)
+        addPackageAccess(sc->scopesym);
+}
 
-            if (sc->explicitProtection)
-                protection = sc->protection;
-            if (!isstatic && !aliasId && !names.length)
-            {
-                sc->scopesym->importScope(mod, protection);
-            }
+/*******************************
+ * Mark the imported packages as accessible from the current
+ * scope. This access check is necessary when using FQN b/c
+ * we're using a single global package tree.
+ * https://issues.dlang.org/show_bug.cgi?id=313
+ */
+void Import::addPackageAccess(ScopeDsymbol *scopesym)
+{
+    //printf("Import::addPackageAccess('%s') %p\n", toPrettyChars(), this);
+    if (packages)
+    {
+        // import a.b.c.d;
+        Package *p = pkg; // a
+        scopesym->addAccessiblePackage(p, protection);
+        for (size_t i = 1; i < packages->length; i++) // [b, c]
+        {
+            Identifier *id = (*packages)[i];
+            p = (Package *) p->symtab->lookup(id);
+            // https://issues.dlang.org/show_bug.cgi?id=17991
+            // An import of truly empty file/package can happen
+            // https://issues.dlang.org/show_bug.cgi?id=20151
+            // Package in the path conflicts with a module name
+            if (p == NULL)
+                return;
+            scopesym->addAccessiblePackage(p, protection);
         }
     }
+    scopesym->addAccessiblePackage(mod, protection); // d
 }
 
 Dsymbol *Import::toAlias()
diff --git a/gcc/d/dmd/dmangle.c b/gcc/d/dmd/dmangle.c
index 303ae617874..83f4c18bee8 100644
--- a/gcc/d/dmd/dmangle.c
+++ b/gcc/d/dmd/dmangle.c
@@ -82,6 +82,8 @@  void initTypeMangle()
     mangleChar[Treturn] = "@";
     mangleChar[Tvector] = "@";
     mangleChar[Ttraits] = "@";
+    mangleChar[Tmixin] = "@";
+    mangleChar[Tnoreturn] = "@";    // becomes 'Nn'
 
     mangleChar[Tnull] = "n";    // same as TypeNone
 
@@ -150,7 +152,7 @@  public:
     *  using upper case letters for all digits but the last digit which uses
     *  a lower case letter.
     * The decoder has to look up the referenced position to determine
-    *  whether the back reference is an identifer (starts with a digit)
+    *  whether the back reference is an identifier (starts with a digit)
     *  or a type (starts with a letter).
     *
     * Params:
@@ -414,6 +416,11 @@  public:
         visit((Type *)t);
     }
 
+    void visit(TypeNoreturn *)
+    {
+        buf->writestring("Nn");
+    }
+
     ////////////////////////////////////////////////////////////////////////////
 
     void mangleDecl(Declaration *sthis)
@@ -1085,3 +1092,31 @@  void mangleToBuffer(TemplateInstance *ti, OutBuffer *buf)
     Mangler v(buf);
     v.mangleTemplateInstance(ti);
 }
+
+/**********************************************
+ * Convert a string representing a type (the deco) and
+ * return its equivalent Type.
+ * Params:
+ *      deco = string containing the deco
+ * Returns:
+ *      null for failed to convert
+ *      Type for succeeded
+ */
+
+Type *decoToType(const char *deco)
+{
+    if (!deco)
+        return NULL;
+
+    //printf("decoToType(): %s\n", deco)
+    if (StringValue *sv = Type::stringtable.lookup(deco, strlen(deco)))
+    {
+        if (sv->ptrvalue)
+        {
+            Type *t = (Type *)sv->ptrvalue;
+            assert(t->deco);
+            return t;
+        }
+    }
+    return NULL;
+}
diff --git a/gcc/d/dmd/dmodule.c b/gcc/d/dmd/dmodule.c
index ed01858f06b..472b2b9e7f8 100644
--- a/gcc/d/dmd/dmodule.c
+++ b/gcc/d/dmd/dmodule.c
@@ -52,6 +52,7 @@  Module::Module(const char *filename, Identifier *ident, int doDocComment, int do
     members = NULL;
     isDocFile = 0;
     isPackageFile = false;
+    pkg = NULL;
     needmoduleinfo = 0;
     selfimports = 0;
     rootimports = 0;
@@ -685,15 +686,27 @@  Module *Module::parse()
          *
          * To avoid the conflict:
          * 1. If preceding package name insertion had occurred by Package::resolve,
-         *    later package.d loading will change Package::isPkgMod to PKGmodule and set Package::mod.
+         *    reuse the previous wrapping 'Package' if it exists
          * 2. Otherwise, 'package.d' wrapped by 'Package' is inserted to the internal tree in here.
+         *
+         * Then change Package::isPkgMod to PKGmodule and set Package::mod.
+         *
+         * Note that the 'wrapping Package' is the Package that contains package.d and other submodules,
+         * the one inserted to the symbol table.
          */
-        Package *p = new Package(ident);
+        Dsymbol *ps = dst->lookup(ident);
+        Package *p = ps ? ps->isPackage() : NULL;
+        if (p == NULL)
+        {
+            p = new Package(ident);
+            p->tag = this->tag; // reuse the same package tag
+            p->symtab = new DsymbolTable();
+        }
+        this->tag= p->tag; // reuse the 'older' package tag
+        this->pkg = p;
         p->parent = this->parent;
         p->isPkgMod = PKGmodule;
         p->mod = this;
-        p->tag = this->tag; // reuse the same package tag
-        p->symtab = new DsymbolTable();
         s = p;
     }
     if (!dst->insert(s))
@@ -720,15 +733,9 @@  Module *Module::parse()
         }
         else if (Package *pkg = prev->isPackage())
         {
-            if (pkg->isPkgMod == PKGunknown && isPackageFile)
-            {
-                /* If the previous inserted Package is not yet determined as package.d,
-                 * link it to the actual module.
-                 */
-                pkg->isPkgMod = PKGmodule;
-                pkg->mod = this;
-                pkg->tag = this->tag; // reuse the same package tag
-            }
+            // 'package.d' loaded after a previous 'Package' insertion
+            if (isPackageFile)
+                amodules.push(this); // Add to global array of all modules
             else
                 error(md ? md->loc : loc, "from file %s conflicts with package name %s",
                     srcname, pkg->toChars());
diff --git a/gcc/d/dmd/dscope.c b/gcc/d/dmd/dscope.c
index 65e6734b035..e56f3936ee0 100644
--- a/gcc/d/dmd/dscope.c
+++ b/gcc/d/dmd/dscope.c
@@ -24,6 +24,7 @@ 
 #include "aggregate.h"
 #include "module.h"
 #include "id.h"
+#include "target.h"
 #include "template.h"
 
 Scope *Scope::freelist = NULL;
@@ -155,7 +156,8 @@  Scope *Scope::push()
     s->nofree = 0;
     s->fieldinit = saveFieldInit();
     s->flags = (flags & (SCOPEcontract | SCOPEdebug | SCOPEctfe | SCOPEcompile | SCOPEconstraint |
-                         SCOPEnoaccesscheck | SCOPEignoresymbolvisibility));
+                         SCOPEnoaccesscheck | SCOPEignoresymbolvisibility |
+                         SCOPEprintf | SCOPEscanf));
     s->lastdc = NULL;
 
     assert(this != s);
@@ -637,7 +639,7 @@  const char *Scope::search_correct_C(Identifier *ident)
     else if (ident == Id::C_unsigned)
         tok = TOKuns32;
     else if (ident == Id::C_wchar_t)
-        tok = global.params.isWindows ? TOKwchar : TOKdchar;
+        tok = target.c.twchar_t->ty == Twchar ? TOKwchar : TOKdchar;
     else
         return NULL;
     return Token::toChars(tok);
diff --git a/gcc/d/dmd/dsymbol.c b/gcc/d/dmd/dsymbol.c
index 89c55576a55..f0c1cf6d93c 100644
--- a/gcc/d/dmd/dsymbol.c
+++ b/gcc/d/dmd/dsymbol.c
@@ -515,7 +515,7 @@  Dsymbol *Dsymbol::search_correct(Identifier *ident)
  * Returns:
  *      symbol found, NULL if not
  */
-Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
+Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id, int flags)
 {
     //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars());
     Dsymbol *s = toAlias();
@@ -533,7 +533,7 @@  Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, RootObject *id)
     switch (id->dyncast())
     {
         case DYNCAST_IDENTIFIER:
-            sm = s->search(loc, (Identifier *)id);
+            sm = s->search(loc, (Identifier *)id, flags);
             break;
 
         case DYNCAST_DSYMBOL:
@@ -1801,31 +1801,3 @@  bool Prot::operator==(const Prot& other) const
     }
     return false;
 }
-
-/**
- * Checks if parent defines different access restrictions than this one.
- *
- * Params:
- *  parent = protection attribute for scope that hosts this one
- *
- * Returns:
- *  'true' if parent is already more restrictive than this one and thus
- *  no differentiation is needed.
- */
-bool Prot::isSubsetOf(const Prot& parent) const
-{
-    if (this->kind != parent.kind)
-        return false;
-
-    if (this->kind == Prot::package_)
-    {
-        if (!this->pkg)
-            return true;
-        if (!parent.pkg)
-            return false;
-        if (parent.pkg->isAncestorPackageOf(this->pkg))
-            return true;
-    }
-
-    return true;
-}
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 1ddfe06e6a1..4aabb5d3c6c 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -107,7 +107,6 @@  struct Prot
 
     bool isMoreRestrictiveThan(const Prot other) const;
     bool operator==(const Prot& other) const;
-    bool isSubsetOf(const Prot& other) const;
 };
 
 // in hdrgen.c
@@ -207,7 +206,7 @@  public:
     virtual void importAll(Scope *sc);
     virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
     Dsymbol *search_correct(Identifier *id);
-    Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id);
+    Dsymbol *searchX(Loc loc, Scope *sc, RootObject *id, int flags);
     virtual bool overloadInsert(Dsymbol *s);
     virtual d_uns64 size(Loc loc);
     virtual bool isforwardRef();
diff --git a/gcc/d/dmd/dsymbolsem.c b/gcc/d/dmd/dsymbolsem.c
index 5d5c9fca769..26e23e98587 100644
--- a/gcc/d/dmd/dsymbolsem.c
+++ b/gcc/d/dmd/dsymbolsem.c
@@ -42,6 +42,8 @@  VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
 Initializer *inferType(Initializer *init, Scope *sc);
 void MODtoBuffer(OutBuffer *buf, MOD mod);
 bool reliesOnTident(Type *t, TemplateParameters *tparams = NULL, size_t iStart = 0);
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
+bool symbolIsVisible(Scope *sc, Dsymbol *s);
 Objc *objc();
 
 static unsigned setMangleOverride(Dsymbol *s, char *sym)
@@ -1098,22 +1100,7 @@  public:
                     scopesym->importScope(imp->mod, imp->protection);
                 }
 
-                // Mark the imported packages as accessible from the current
-                // scope. This access check is necessary when using FQN b/c
-                // we're using a single global package tree. See Bugzilla 313.
-                if (imp->packages)
-                {
-                    // import a.b.c.d;
-                    Package *p = imp->pkg; // a
-                    scopesym->addAccessiblePackage(p, imp->protection);
-                    for (size_t i = 1; i < imp->packages->length; i++) // [b, c]
-                    {
-                        Identifier *id = (*imp->packages)[i];
-                        p = (Package *) p->symtab->lookup(id);
-                        scopesym->addAccessiblePackage(p, imp->protection);
-                    }
-                }
-                scopesym->addAccessiblePackage(imp->mod, imp->protection); // d
+                imp->addPackageAccess(scopesym);
             }
 
             dsymbolSemantic(imp->mod, NULL);
@@ -1130,8 +1117,12 @@  public:
             {
                 AliasDeclaration *ad = imp->aliasdecls[i];
                 //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), imp->aliases[i]->toChars(), imp->names[i]->toChars(), ad->_scope);
-                if (imp->mod->search(imp->loc, imp->names[i]))
+                Dsymbol *sym = imp->mod->search(imp->loc, imp->names[i], IgnorePrivateImports);
+                if (sym)
                 {
+                    if (!symbolIsVisible(sc, sym))
+                        imp->mod->error(imp->loc, "member `%s` is not visible from module `%s`",
+                            imp->names[i]->toChars(), sc->_module->toChars());
                     dsymbolSemantic(ad, sc);
                     // If the import declaration is in non-root module,
                     // analysis of the aliased symbol is deferred.
@@ -1141,7 +1132,7 @@  public:
                 {
                     Dsymbol *s = imp->mod->search_correct(imp->names[i]);
                     if (s)
-                        imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toChars());
+                        imp->mod->error(imp->loc, "import `%s` not found, did you mean %s `%s`?", imp->names[i]->toChars(), s->kind(), s->toPrettyChars());
                     else
                         imp->mod->error(imp->loc, "import `%s` not found", imp->names[i]->toChars());
                     ad->type = Type::terror;
@@ -1312,8 +1303,6 @@  public:
                     e = expressionSemantic(e, sc);
                     e = resolveProperties(sc, e);
                     sc = sc->endCTFE();
-
-                    // pragma(msg) is allowed to contain types as well as expressions
                     e = ctfeInterpretForPragmaMsg(e);
                     if (e->op == TOKerror)
                     {
@@ -1458,6 +1447,12 @@  public:
                 }
             }
         }
+        else if (pd->ident == Id::printf || pd->ident == Id::scanf)
+        {
+            if (pd->args && pd->args->length != 0)
+                pd->error("takes no argument");
+            goto Ldecl;
+        }
         else if (global.params.ignoreUnsupportedPragmas)
         {
             if (global.params.verbose)
@@ -1547,13 +1542,14 @@  public:
     Dsymbols *compileIt(CompileDeclaration *cd)
     {
         //printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd->loc.linnum, cd->exp->toChars());
-        StringExp *se = semanticString(sc, cd->exp, "argument to mixin");
-        if (!se)
+        OutBuffer buf;
+        if (expressionsToString(buf, sc, cd->exps))
             return NULL;
-        se = se->toUTF8(sc);
 
         unsigned errors = global.errors;
-        Parser p(cd->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+        const size_t len = buf.length();
+        const char *str = buf.extractChars();
+        Parser p(cd->loc, sc->_module, (const utf8_t *)str, len, false);
         p.nextToken();
 
         Dsymbols *d = p.parseDeclDefs(0);
@@ -1562,7 +1558,7 @@  public:
 
         if (p.token.value != TOKeof)
         {
-            cd->exp->error("incomplete mixin declaration (%s)", se->toChars());
+            cd->error("incomplete mixin declaration (%s)", str);
             return NULL;
         }
         return d;
@@ -1637,7 +1633,7 @@  public:
         Scope *sc = m->_scope;                  // see if already got one from importAll()
         if (!sc)
         {
-            Scope::createGlobal(m);      // create root scope
+            sc = Scope::createGlobal(m);      // create root scope
         }
 
         //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage);
@@ -1735,7 +1731,7 @@  public:
                     // memtype is forward referenced, so try again later
                     ed->_scope = scx ? scx : sc->copy();
                     ed->_scope->setNoFree();
-                    ed->_scope->_module->addDeferredSemantic(ed);
+                    Module::addDeferredSemantic(ed);
                     Module::dprogress = dprogress_save;
                     //printf("\tdeferring %s\n", ed->toChars());
                     ed->semanticRun = PASSinit;
@@ -2233,7 +2229,7 @@  public:
                 //printf("forward reference - deferring\n");
                 tm->_scope = scx ? scx : sc->copy();
                 tm->_scope->setNoFree();
-                tm->_scope->_module->addDeferredSemantic(tm);
+                Module::addDeferredSemantic(tm);
                 return;
             }
 
@@ -2457,6 +2453,23 @@  public:
         ns->semanticRun = PASSsemanticdone;
     }
 
+
+private:
+    static bool isPointerToChar(Parameter *p)
+    {
+        if (TypePointer *tptr = p->type->isTypePointer())
+        {
+            return tptr->next->ty == Tchar;
+        }
+        return false;
+    }
+
+    static bool isVa_list(Parameter *p, FuncDeclaration *funcdecl, Scope *sc)
+    {
+        return p->type->equals(target.va_listType(funcdecl->loc, sc));
+    }
+
+public:
     void funcDeclarationSemantic(FuncDeclaration *funcdecl)
     {
         TypeFunction *f;
@@ -2771,6 +2784,45 @@  public:
         if (funcdecl->isAbstract() && funcdecl->isFinalFunc())
             funcdecl->error("cannot be both final and abstract");
 
+        if (const unsigned pors = sc->flags & (SCOPEprintf | SCOPEscanf))
+        {
+            /* printf/scanf-like functions must be of the form:
+             *    extern (C/C++) T printf([parameters...], const(char)* format, ...);
+             * or:
+             *    extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
+             */
+            const size_t nparams = f->parameterList.length();
+            if ((f->linkage == LINKc || f->linkage == LINKcpp) &&
+
+                ((f->parameterList.varargs == VARARGvariadic &&
+                  nparams >= 1 &&
+                  isPointerToChar(f->parameterList[nparams - 1])) ||
+                 (f->parameterList.varargs == VARARGnone &&
+                  nparams >= 2 &&
+                  isPointerToChar(f->parameterList[nparams - 2]) &&
+                  isVa_list(f->parameterList[nparams - 1], funcdecl, sc))
+                )
+               )
+            {
+                funcdecl->flags |= (pors == SCOPEprintf) ? FUNCFLAGprintf : FUNCFLAGscanf;
+            }
+            else
+            {
+                const char *p = (pors == SCOPEprintf ? Id::printf : Id::scanf)->toChars();
+                if (f->parameterList.varargs == VARARGvariadic)
+                {
+                    funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`"
+                                    " not `%s`",
+                        p, f->next->toChars(), funcdecl->toChars(), funcdecl->type->toChars());
+                }
+                else
+                {
+                    funcdecl->error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, va_list)`",
+                        p, f->next->toChars(), funcdecl->toChars());
+                }
+            }
+        }
+
         id = parent->isInterfaceDeclaration();
         if (id)
         {
@@ -3831,7 +3883,7 @@  public:
 
             sd->_scope = scx ? scx : sc->copy();
             sd->_scope->setNoFree();
-            sd->_scope->_module->addDeferredSemantic(sd);
+            Module::addDeferredSemantic(sd);
 
             //printf("\tdeferring %s\n", sd->toChars());
             return;
@@ -4079,7 +4131,7 @@  public:
                 {
                     //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars());
                     if (tc->sym->_scope)
-                        tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+                        Module::addDeferredSemantic(tc->sym);
                     cldec->baseok = BASEOKnone;
                 }
              L7: ;
@@ -4131,7 +4183,7 @@  public:
                 {
                     //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
                     if (tc->sym->_scope)
-                        tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+                        Module::addDeferredSemantic(tc->sym);
                     cldec->baseok = BASEOKnone;
                 }
                 i++;
@@ -4141,7 +4193,7 @@  public:
                 // Forward referencee of one or more bases, try again later
                 cldec->_scope = scx ? scx : sc->copy();
                 cldec->_scope->setNoFree();
-                cldec->_scope->_module->addDeferredSemantic(cldec);
+                Module::addDeferredSemantic(cldec);
                 //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
                 return;
             }
@@ -4254,8 +4306,8 @@  public:
                 cldec->_scope = scx ? scx : sc->copy();
                 cldec->_scope->setNoFree();
                 if (tc->sym->_scope)
-                    tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
-                cldec->_scope->_module->addDeferredSemantic(cldec);
+                    Module::addDeferredSemantic(tc->sym);
+                Module::addDeferredSemantic(cldec);
                 //printf("\tL%d semantic('%s') failed due to forward references\n", __LINE__, cldec->toChars());
                 return;
             }
@@ -4359,7 +4411,7 @@  public:
 
             cldec->_scope = scx ? scx : sc->copy();
             cldec->_scope->setNoFree();
-            cldec->_scope->_module->addDeferredSemantic(cldec);
+            Module::addDeferredSemantic(cldec);
             //printf("\tdeferring %s\n", cldec->toChars());
             return;
         }
@@ -4628,7 +4680,7 @@  public:
                 {
                     //printf("\ttry later, forward reference of base %s\n", tc->sym->toChars());
                     if (tc->sym->_scope)
-                        tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
+                        Module::addDeferredSemantic(tc->sym);
                     idec->baseok = BASEOKnone;
                 }
                 i++;
@@ -4638,7 +4690,7 @@  public:
                 // Forward referencee of one or more bases, try again later
                 idec->_scope = scx ? scx : sc->copy();
                 idec->_scope->setNoFree();
-                idec->_scope->_module->addDeferredSemantic(idec);
+                Module::addDeferredSemantic(idec);
                 return;
             }
             idec->baseok = BASEOKdone;
@@ -4682,8 +4734,8 @@  public:
                 idec->_scope = scx ? scx : sc->copy();
                 idec->_scope->setNoFree();
                 if (tc->sym->_scope)
-                    tc->sym->_scope->_module->addDeferredSemantic(tc->sym);
-                idec->_scope->_module->addDeferredSemantic(idec);
+                    Module::addDeferredSemantic(tc->sym);
+                Module::addDeferredSemantic(idec);
                 return;
             }
         }
@@ -5335,6 +5387,7 @@  void aliasSemantic(AliasDeclaration *ds, Scope *sc)
     ds->userAttribDecl = sc->userAttribDecl;
 
     // TypeTraits needs to know if it's located in an AliasDeclaration
+    const unsigned oldflags = sc->flags;
     sc->flags |= SCOPEalias;
 
     if (ds->aliassym)
@@ -5345,7 +5398,7 @@  void aliasSemantic(AliasDeclaration *ds, Scope *sc)
         {
             if (fd && fd->semanticRun >= PASSsemanticdone)
             {
-                sc->flags &= ~SCOPEalias;
+                sc->flags = oldflags;
                 return;
             }
 
@@ -5361,13 +5414,13 @@  void aliasSemantic(AliasDeclaration *ds, Scope *sc)
                 ds->aliassym = NULL;
                 ds->type = Type::terror;
             }
-            sc->flags &= ~SCOPEalias;
+            sc->flags = oldflags;
             return;
         }
 
         if (ds->aliassym->isTemplateInstance())
             dsymbolSemantic(ds->aliassym, sc);
-        sc->flags &= ~SCOPEalias;
+        sc->flags = oldflags;
         return;
     }
     ds->inuse = 1;
@@ -5472,7 +5525,7 @@  void aliasSemantic(AliasDeclaration *ds, Scope *sc)
         if (!ds->overloadInsert(sx))
             ScopeDsymbol::multiplyDefined(Loc(), sx, ds);
     }
-    sc->flags &= ~SCOPEalias;
+    sc->flags = oldflags;
 }
 
 
diff --git a/gcc/d/dmd/dtemplate.c b/gcc/d/dmd/dtemplate.c
index b868e9ad388..208b064aafb 100644
--- a/gcc/d/dmd/dtemplate.c
+++ b/gcc/d/dmd/dtemplate.c
@@ -156,17 +156,14 @@  Dsymbol *getDsymbol(RootObject *oarg)
     if (ea)
     {
         // Try to convert Expression to symbol
-        if (ea->op == TOKvar)
-            sa = ((VarExp *)ea)->var;
-        else if (ea->op == TOKfunction)
-        {
-            if (((FuncExp *)ea)->td)
-                sa = ((FuncExp *)ea)->td;
-            else
-                sa = ((FuncExp *)ea)->fd;
-        }
-        else if (ea->op == TOKtemplate)
-            sa = ((TemplateExp *)ea)->td;
+        if (VarExp *ve = ea->isVarExp())
+            sa = ve->var;
+        else if (FuncExp *fe = ea->isFuncExp())
+            sa = fe->td ? (Dsymbol *)fe->td : (Dsymbol *)fe->fd;
+        else if (TemplateExp *te = ea->isTemplateExp())
+            sa = te->td;
+        else if (ScopeExp *se = ea->isScopeExp())
+            sa = se->sds;
         else
             sa = NULL;
     }
@@ -536,6 +533,7 @@  TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id,
     this->isstatic = true;
     this->previous = NULL;
     this->protection = Prot(Prot::undefined);
+    this->inuse = 0;
     this->instances = NULL;
 
     // Compute in advance for Ddoc's use
@@ -770,7 +768,9 @@  MATCH TemplateDeclaration::matchWithInstance(Scope *sc, TemplateInstance *ti,
         Declaration *sparam;
 
         //printf("\targument [%d]\n", i);
+        inuse++;
         m2 = tp->matchArg(ti->loc, paramscope, ti->tiargs, i, parameters, dedtypes, &sparam);
+        inuse--;
         //printf("\tm2 = %d\n", m2);
 
         if (m2 == MATCHnomatch)
@@ -1397,7 +1397,9 @@  MATCH TemplateDeclaration::deduceFunctionTemplateMatch(
                         }
                         else
                         {
+                            inuse++;
                             oded = tparam->defaultArg(instLoc, paramscope);
+                            inuse--;
                             if (oded)
                                 (*dedargs)[i] = declareParameter(paramscope, tparam, oded);
                         }
@@ -1771,7 +1773,9 @@  Lmatch:
             }
             else
             {
+                inuse++;
                 oded = tparam->defaultArg(instLoc, paramscope);
+                inuse--;
                 if (!oded)
                 {
                     // if tuple parameter and
@@ -1997,18 +2001,19 @@  bool TemplateDeclaration::isOverloadable()
 /*************************************************
  * Given function arguments, figure out which template function
  * to expand, and return matching result.
- * Input:
- *      m               matching result
- *      dstart          the root of overloaded function templates
- *      loc             instantiation location
- *      sc              instantiation scope
- *      tiargs          initial list of template arguments
- *      tthis           if !NULL, the 'this' pointer argument
- *      fargs           arguments to function
+ * Params:
+ *      m           = matching result
+ *      dstart      = the root of overloaded function templates
+ *      loc         = instantiation location
+ *      sc          = instantiation scope
+ *      tiargs      = initial list of template arguments
+ *      tthis       = if !NULL, the 'this' pointer argument
+ *      fargs       = arguments to function
+ *      pMessage    = address to store error message, or null
  */
 
 void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
-        Objects *tiargs, Type *tthis, Expressions *fargs)
+    Objects *tiargs, Type *tthis, Expressions *fargs, const char **pMessage)
 {
     struct ParamDeduce
     {
@@ -2018,6 +2023,7 @@  void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
         Type *tthis;
         Objects *tiargs;
         Expressions *fargs;
+        const char **pMessage;
         // result
         Match *m;
         int property;   // 0: unintialized
@@ -2093,7 +2099,7 @@  void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
                 else
                     return 0;   // MATCHnomatch
             }
-            MATCH mfa = tf->callMatch(tthis_fd, fargs);
+            MATCH mfa = tf->callMatch(tthis_fd, fargs, 0, pMessage);
             //printf("test1: mfa = %d\n", mfa);
             if (mfa > MATCHnomatch)
             {
@@ -2180,8 +2186,12 @@  void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
         int applyTemplate(TemplateDeclaration *td)
         {
             //printf("applyTemplate()\n");
-            // skip duplicates
-            if (td == td_best)
+            if (td->inuse)
+            {
+                td->error(loc, "recursive template expansion");
+                return 1;
+            }
+            if (td == td_best)  // skip duplicates
                 return 0;
 
             if (!sc)
@@ -2431,6 +2441,7 @@  void functionResolve(Match *m, Dsymbol *dstart, Loc loc, Scope *sc,
     p.tthis  = tthis;
     p.tiargs = tiargs;
     p.fargs  = fargs;
+    p.pMessage = pMessage;
 
     // result
     p.m          = m;
@@ -5165,6 +5176,16 @@  MATCH TemplateAliasParameter::matchArg(Scope *sc, RootObject *oarg,
              *  template X(T) {}        // T => sa
              */
         }
+        else if (ta && ta->ty != Tident)
+        {
+            /* Match any type that's not a TypeIdentifier to alias parameters,
+             * but prefer type parameter.
+             * template X(alias a) { }  // a == ta
+             *
+             * TypeIdentifiers are excluded because they might be not yet resolved aliases.
+             */
+            m = MATCHconvert;
+        }
         else
             goto Lnomatch;
     }
@@ -5485,12 +5506,15 @@  RootObject *TemplateValueParameter::defaultArg(Loc instLoc, Scope *sc)
     if (e)
     {
         e = e->syntaxCopy();
+        unsigned olderrs = global.errors;
         if ((e = expressionSemantic(e, sc)) == NULL)
             return NULL;
         if ((e = resolveProperties(sc, e)) == NULL)
             return NULL;
         e = e->resolveLoc(instLoc, sc);     // use the instantiated loc
         e = e->optimize(WANTvalue);
+        if (global.errors != olderrs)
+            e = new ErrorExp();
     }
     return e;
 }
@@ -6049,6 +6073,7 @@  bool TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f
         if (ta)
         {
             //printf("type %s\n", ta->toChars());
+
             // It might really be an Expression or an Alias
             ta->resolve(loc, sc, &ea, &ta, &sa, (flags & 1) != 0);
             if (ea) goto Lexpr;
@@ -6270,6 +6295,7 @@  bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
     }
 
     unsigned errs = global.errors;
+    TemplateDeclaration *td_last = NULL;
 
   struct ParamBest
   {
@@ -6291,7 +6317,11 @@  bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
         TemplateDeclaration *td = s->isTemplateDeclaration();
         if (!td)
             return 0;
-
+        if (td->inuse)
+        {
+            td->error(ti->loc, "recursive template expansion");
+            return 1;
+        }
         if (td == td_best)          // skip duplicates
             return 0;
 
@@ -6349,8 +6379,6 @@  bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
     /* Since there can be multiple TemplateDeclaration's with the same
      * name, look for the best match.
      */
-    TemplateDeclaration *td_last = NULL;
-
     OverloadSet *tovers = tempdecl->isOverloadSet();
     size_t overs_dim = tovers ? tovers->a.length : 1;
     for (size_t oi = 0; oi < overs_dim; oi++)
@@ -6359,7 +6387,9 @@  bool TemplateInstance::findBestMatch(Scope *sc, Expressions *fargs)
         p.td_best  = NULL;
         p.td_ambig = NULL;
         p.m_best   = MATCHnomatch;
-        overloadApply(tovers ? tovers->a[oi] : tempdecl, &p, &ParamBest::fp);
+
+        Dsymbol *dstart = tovers ? tovers->a[oi] : tempdecl;
+        overloadApply(dstart, &p, &ParamBest::fp);
 
         if (p.td_ambig)
         {
@@ -6481,8 +6511,11 @@  bool TemplateInstance::needsTypeInference(Scope *sc, int flag)
     {
         TemplateDeclaration *td = s->isTemplateDeclaration();
         if (!td)
-        {
             return 0;
+        if (td->inuse)
+        {
+            td->error(ti->loc, "recursive template expansion");
+            return 1;
         }
 
         /* If any of the overloaded template declarations need inference,
@@ -7128,6 +7161,68 @@  void unSpeculative(Scope *sc, RootObject *o)
         unSpeculative(sc, ti);
 }
 
+/**
+    Returns: true if the instances' innards are discardable.
+
+    The idea of this function is to see if the template instantiation
+    can be 100% replaced with its eponymous member. All other members
+    can be discarded, even in the compiler to free memory (for example,
+    the template could be expanded in a region allocator, deemed trivial,
+    the end result copied back out independently and the entire region freed),
+    and can be elided entirely from the binary.
+
+    The current implementation affects code that generally looks like:
+
+    ---
+    template foo(args...) {
+        some_basic_type_or_string helper() { .... }
+        enum foo = helper();
+    }
+    ---
+
+    since it was the easiest starting point of implementation but it can and
+    should be expanded more later.
+*/
+static bool isDiscardable(TemplateInstance *ti)
+{
+    if (ti->aliasdecl == NULL)
+        return false;
+
+    VarDeclaration *v = ti->aliasdecl->isVarDeclaration();
+    if (v == NULL)
+        return false;
+
+    if (!(v->storage_class & STCmanifest))
+        return false;
+
+    // Currently only doing basic types here because it is the easiest proof-of-concept
+    // implementation with minimal risk of side effects, but it could likely be
+    // expanded to any type that already exists outside this particular instance.
+    if (!(v->type->equals(Type::tstring) || (v->type->isTypeBasic() != NULL)))
+        return false;
+
+    // Static ctors and dtors, even in an eponymous enum template, are still run,
+    // so if any of them are in here, we'd better not assume it is trivial lest
+    // we break useful code
+    for (size_t i = 0; i < ti->members->length; i++)
+    {
+        Dsymbol *member = (*ti->members)[i];
+        if (member->hasStaticCtorOrDtor())
+            return false;
+        if (member->isStaticDtorDeclaration())
+            return false;
+        if (member->isStaticCtorDeclaration())
+            return false;
+    }
+
+    // but if it passes through this gauntlet... it should be fine. D code will
+    // see only the eponymous member, outside stuff can never access it, even through
+    // reflection; the outside world ought to be none the wiser. Even dmd should be
+    // able to simply free the memory of everything except the final result.
+
+    return true;
+}
+
 /***********************************************
  * Returns true if this is not instantiated in non-root module, and
  * is a part of non-speculative instantiatiation.
@@ -7137,38 +7232,6 @@  void unSpeculative(Scope *sc, RootObject *o)
  */
 bool TemplateInstance::needsCodegen()
 {
-    // Now -allInst is just for the backward compatibility.
-    if (global.params.allInst)
-    {
-        //printf("%s minst = %s, enclosing (%s)->isNonRoot = %d\n",
-        //    toPrettyChars(), minst ? minst->toChars() : NULL,
-        //    enclosing ? enclosing->toPrettyChars() : NULL, enclosing && enclosing->inNonRoot());
-        if (enclosing)
-        {
-            // Bugzilla 14588: If the captured context is not a function
-            // (e.g. class), the instance layout determination is guaranteed,
-            // because the semantic/semantic2 pass will be executed
-            // even for non-root instances.
-            if (!enclosing->isFuncDeclaration())
-                return true;
-
-            // Bugzilla 14834: If the captured context is a function,
-            // this excessive instantiation may cause ODR violation, because
-            // -allInst and others doesn't guarantee the semantic3 execution
-            // for that function.
-
-            // If the enclosing is also an instantiated function,
-            // we have to rely on the ancestor's needsCodegen() result.
-            if (TemplateInstance *ti = enclosing->isInstantiated())
-                return ti->needsCodegen();
-
-            // Bugzilla 13415: If and only if the enclosing scope needs codegen,
-            // this nested templates would also need code generation.
-            return !enclosing->inNonRoot();
-        }
-        return true;
-    }
-
     if (!minst)
     {
         // If this is a speculative instantiation,
@@ -7185,6 +7248,10 @@  bool TemplateInstance::needsCodegen()
         if (tinst && tinst->needsCodegen())
         {
             minst = tinst->minst;   // cache result
+            if (global.params.allInst && minst)
+            {
+                return true;
+            }
             assert(minst);
             assert(minst->isRoot() || minst->rootImports());
             return true;
@@ -7192,6 +7259,10 @@  bool TemplateInstance::needsCodegen()
         if (tnext && (tnext->needsCodegen() || tnext->minst))
         {
             minst = tnext->minst;   // cache result
+            if (global.params.allInst && minst)
+            {
+                return true;
+            }
             assert(minst);
             return minst->isRoot() || minst->rootImports();
         }
@@ -7200,6 +7271,16 @@  bool TemplateInstance::needsCodegen()
         return false;
     }
 
+    if (global.params.allInst)
+    {
+        return true;
+    }
+
+    if (isDiscardable(this))
+    {
+        return false;
+    }
+
     /* Even when this is reached to the codegen pass,
      * a non-root nested template should not generate code,
      * due to avoid ODR violation.
@@ -7221,14 +7302,7 @@  bool TemplateInstance::needsCodegen()
         return false;
     }
 
-    /* The issue is that if the importee is compiled with a different -debug
-     * setting than the importer, the importer may believe it exists
-     * in the compiled importee when it does not, when the instantiation
-     * is behind a conditional debug declaration.
-     */
-    // workaround for Bugzilla 11239
-    if (global.params.useUnitTests ||
-        global.params.debuglevel)
+    if (global.params.useUnitTests)
     {
         // Prefer instantiations from root modules, to maximize link-ability.
         if (minst->isRoot())
diff --git a/gcc/d/dmd/expression.c b/gcc/d/dmd/expression.c
index c90392d16a2..2592b38d961 100644
--- a/gcc/d/dmd/expression.c
+++ b/gcc/d/dmd/expression.c
@@ -43,110 +43,10 @@  VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
 Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
 char *MODtoChars(MOD mod);
 bool MODimplicitConv(MOD modfrom, MOD modto);
-MOD MODmerge(MOD mod1, MOD mod2);
 void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
 Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
 bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
-
-/*************************************************************
- * Given var, we need to get the
- * right 'this' pointer if var is in an outer class, but our
- * existing 'this' pointer is in an inner class.
- * Input:
- *      e1      existing 'this'
- *      ad      struct or class we need the correct 'this' for
- *      var     the specific member of ad we're accessing
- */
-
-Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
-        Expression *e1, Declaration *var, int flag = 0)
-{
-    //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
- L1:
-    Type *t = e1->type->toBasetype();
-    //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
-
-    /* If e1 is not the 'this' pointer for ad
-     */
-    if (ad &&
-        !(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
-          ((TypeStruct *)t->nextOf())->sym == ad)
-        &&
-        !(t->ty == Tstruct &&
-          ((TypeStruct *)t)->sym == ad)
-       )
-    {
-        ClassDeclaration *cd = ad->isClassDeclaration();
-        ClassDeclaration *tcd = t->isClassHandle();
-
-        /* e1 is the right this if ad is a base class of e1
-         */
-        if (!cd || !tcd ||
-            !(tcd == cd || cd->isBaseOf(tcd, NULL))
-           )
-        {
-            /* Only classes can be inner classes with an 'outer'
-             * member pointing to the enclosing class instance
-             */
-            if (tcd && tcd->isNested())
-            {
-                /* e1 is the 'this' pointer for an inner class: tcd.
-                 * Rewrite it as the 'this' pointer for the outer class.
-                 */
-
-                e1 = new DotVarExp(loc, e1, tcd->vthis);
-                e1->type = tcd->vthis->type;
-                e1->type = e1->type->addMod(t->mod);
-                // Do not call checkNestedRef()
-                //e1 = expressionSemantic(e1, sc);
-
-                // Skip up over nested functions, and get the enclosing
-                // class type.
-                int n = 0;
-                Dsymbol *s;
-                for (s = tcd->toParent();
-                     s && s->isFuncDeclaration();
-                     s = s->toParent())
-                {
-                    FuncDeclaration *f = s->isFuncDeclaration();
-                    if (f->vthis)
-                    {
-                        //printf("rewriting e1 to %s's this\n", f->toChars());
-                        n++;
-                        e1 = new VarExp(loc, f->vthis);
-                    }
-                    else
-                    {
-                        e1->error("need `this` of type %s to access member %s"
-                                  " from static function %s",
-                            ad->toChars(), var->toChars(), f->toChars());
-                        e1 = new ErrorExp();
-                        return e1;
-                    }
-                }
-                if (s && s->isClassDeclaration())
-                {
-                    e1->type = s->isClassDeclaration()->type;
-                    e1->type = e1->type->addMod(t->mod);
-                    if (n > 1)
-                        e1 = expressionSemantic(e1, sc);
-                }
-                else
-                    e1 = expressionSemantic(e1, sc);
-                goto L1;
-            }
-
-            /* Can't find a path from e1 to ad
-             */
-            if (flag)
-                return NULL;
-            e1->error("this for %s needs to be type %s not type %s",
-                var->toChars(), ad->toChars(), t->toChars());
-            return new ErrorExp();
-        }
-    }
-    return e1;
-}
+void toAutoQualChars(const char **result, Type *t1, Type *t2);
 
 /*****************************************
  * Determine if 'this' is available.
@@ -230,817 +130,112 @@  bool isNeedThisScope(Scope *sc, Declaration *d)
     return true;
 }
 
-/***************************************
- * Pull out any properties.
+/******************************
+ * check e is exp.opDispatch!(tiargs) or not
+ * It's used to switch to UFCS the semantic analysis path
  */
 
-Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
+bool isDotOpDispatch(Expression *e)
 {
-    //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL);
-    Loc loc = e1->loc;
-
-    OverloadSet *os;
-    Dsymbol *s;
-    Objects *tiargs;
-    Type *tthis;
-    if (e1->op == TOKdot)
-    {
-        DotExp *de = (DotExp *)e1;
-        if (de->e2->op == TOKoverloadset)
-        {
-            tiargs = NULL;
-            tthis  = de->e1->type;
-            os = ((OverExp *)de->e2)->vars;
-            goto Los;
-        }
-    }
-    else if (e1->op == TOKoverloadset)
-    {
-        tiargs = NULL;
-        tthis  = NULL;
-        os = ((OverExp *)e1)->vars;
-    Los:
-        assert(os);
-        FuncDeclaration *fd = NULL;
-        if (e2)
-        {
-            e2 = expressionSemantic(e2, sc);
-            if (e2->op == TOKerror)
-                return new ErrorExp();
-            e2 = resolveProperties(sc, e2);
+    return e->op == TOKdotti &&
+           ((DotTemplateInstanceExp *)e)->ti->name == Id::opDispatch;
+}
 
-            Expressions a;
-            a.push(e2);
+/****************************************
+ * Expand tuples.
+ * Input:
+ *      exps    aray of Expressions
+ * Output:
+ *      exps    rewritten in place
+ */
 
-            for (size_t i = 0; i < os->a.length; i++)
-            {
-                FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, &a, 1);
-                if (f)
-                {
-                    if (f->errors)
-                        return new ErrorExp();
-                    fd = f;
-                    assert(fd->type->ty == Tfunction);
-                }
-            }
-            if (fd)
-            {
-                Expression *e = new CallExp(loc, e1, e2);
-                return expressionSemantic(e, sc);
-            }
-        }
-        {
-            for (size_t i = 0; i < os->a.length; i++)
-            {
-                FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, NULL, 1);
-                if (f)
-                {
-                    if (f->errors)
-                        return new ErrorExp();
-                    fd = f;
-                    assert(fd->type->ty == Tfunction);
-                    TypeFunction *tf = (TypeFunction *)fd->type;
-                    if (!tf->isref && e2)
-                        goto Leproplvalue;
-                }
-            }
-            if (fd)
-            {
-                Expression *e = new CallExp(loc, e1);
-                if (e2)
-                    e = new AssignExp(loc, e, e2);
-                return expressionSemantic(e, sc);
-            }
-        }
-        if (e2)
-            goto Leprop;
-    }
-    else if (e1->op == TOKdotti)
-    {
-        DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
-        if (!dti->findTempDecl(sc))
-            goto Leprop;
-        if (!dti->ti->semanticTiargs(sc))
-            goto Leprop;
-        tiargs = dti->ti->tiargs;
-        tthis  = dti->e1->type;
-        if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL)
-            goto Los;
-        if ((s = dti->ti->tempdecl) != NULL)
-            goto Lfd;
-    }
-    else if (e1->op == TOKdottd)
-    {
-        DotTemplateExp *dte = (DotTemplateExp *)e1;
-        s      = dte->td;
-        tiargs = NULL;
-        tthis  = dte->e1->type;
-        goto Lfd;
-    }
-    else if (e1->op == TOKscope)
-    {
-        s = ((ScopeExp *)e1)->sds;
-        TemplateInstance *ti = s->isTemplateInstance();
-        if (ti && !ti->semanticRun && ti->tempdecl)
-        {
-            //assert(ti->needsTypeInference(sc));
-            if (!ti->semanticTiargs(sc))
-                goto Leprop;
-            tiargs = ti->tiargs;
-            tthis  = NULL;
-            if ((os = ti->tempdecl->isOverloadSet()) != NULL)
-                goto Los;
-            if ((s = ti->tempdecl) != NULL)
-                goto Lfd;
-        }
-    }
-    else if (e1->op == TOKtemplate)
-    {
-        s      = ((TemplateExp *)e1)->td;
-        tiargs = NULL;
-        tthis  = NULL;
-        goto Lfd;
-    }
-    else if (e1->op == TOKdotvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
-    {
-        DotVarExp *dve = (DotVarExp *)e1;
-        s      = dve->var->isFuncDeclaration();
-        tiargs = NULL;
-        tthis  = dve->e1->type;
-        goto Lfd;
-    }
-    else if (e1->op == TOKvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+void expandTuples(Expressions *exps)
+{
+    //printf("expandTuples()\n");
+    if (exps)
     {
-        s      = ((VarExp *)e1)->var->isFuncDeclaration();
-        tiargs = NULL;
-        tthis  = NULL;
-    Lfd:
-        assert(s);
-        if (e2)
+        for (size_t i = 0; i < exps->length; i++)
         {
-            e2 = expressionSemantic(e2, sc);
-            if (e2->op == TOKerror)
-                return new ErrorExp();
-            e2 = resolveProperties(sc, e2);
-
-            Expressions a;
-            a.push(e2);
+            Expression *arg = (*exps)[i];
+            if (!arg)
+                continue;
 
-            FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1);
-            if (fd && fd->type)
-            {
-                if (fd->errors)
-                    return new ErrorExp();
-                assert(fd->type->ty == Tfunction);
-                Expression *e = new CallExp(loc, e1, e2);
-                return expressionSemantic(e, sc);
-            }
-        }
-        {
-            FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1);
-            if (fd && fd->type)
+            // Look for tuple with 0 members
+            if (arg->op == TOKtype)
             {
-                if (fd->errors)
-                    return new ErrorExp();
-                assert(fd->type->ty == Tfunction);
-                TypeFunction *tf = (TypeFunction *)fd->type;
-                if (!e2 || tf->isref)
+                TypeExp *e = (TypeExp *)arg;
+                if (e->type->toBasetype()->ty == Ttuple)
                 {
-                    Expression *e = new CallExp(loc, e1);
-                    if (e2)
-                        e = new AssignExp(loc, e, e2);
-                    return expressionSemantic(e, sc);
-                }
-            }
-        }
-        if (FuncDeclaration *fd = s->isFuncDeclaration())
-        {
-            // Keep better diagnostic message for invalid property usage of functions
-            assert(fd->type->ty == Tfunction);
-            Expression *e = new CallExp(loc, e1, e2);
-            return expressionSemantic(e, sc);
-        }
-        if (e2)
-            goto Leprop;
-    }
-    if (e1->op == TOKvar)
-    {
-        VarExp *ve = (VarExp *)e1;
-        VarDeclaration *v = ve->var->isVarDeclaration();
-        if (v && ve->checkPurity(sc, v))
-            return new ErrorExp();
-    }
-    if (e2)
-        return NULL;
-
-    if (e1->type &&
-        e1->op != TOKtype)      // function type is not a property
-    {
-        /* Look for e1 being a lazy parameter; rewrite as delegate call
-         */
-        if (e1->op == TOKvar)
-        {
-            VarExp *ve = (VarExp *)e1;
+                    TypeTuple *tt = (TypeTuple *)e->type->toBasetype();
 
-            if (ve->var->storage_class & STClazy)
-            {
-                Expression *e = new CallExp(loc, e1);
-                return expressionSemantic(e, sc);
+                    if (!tt->arguments || tt->arguments->length == 0)
+                    {
+                        exps->remove(i);
+                        if (i == exps->length)
+                            return;
+                        i--;
+                        continue;
+                    }
+                }
             }
-        }
-        else if (e1->op == TOKdotvar)
-        {
-            // Check for reading overlapped pointer field in @safe code.
-            if (checkUnsafeAccess(sc, e1, true, true))
-                return new ErrorExp();
-        }
-        else if (e1->op == TOKdot)
-        {
-            e1->error("expression has no value");
-            return new ErrorExp();
-        }
-        else if (e1->op == TOKcall)
-        {
-            CallExp *ce = (CallExp *)e1;
-            // Check for reading overlapped pointer field in @safe code.
-            if (checkUnsafeAccess(sc, ce->e1, true, true))
-                return new ErrorExp();
-        }
-    }
-
-    if (!e1->type)
-    {
-        error(loc, "cannot resolve type for %s", e1->toChars());
-        e1 = new ErrorExp();
-    }
-    return e1;
-
-Leprop:
-    error(loc, "not a property %s", e1->toChars());
-    return new ErrorExp();
-
-Leproplvalue:
-    error(loc, "%s is not an lvalue", e1->toChars());
-    return new ErrorExp();
-}
-
-Expression *resolveProperties(Scope *sc, Expression *e)
-{
-    //printf("resolveProperties(%s)\n", e->toChars());
-
-    e = resolvePropertiesX(sc, e);
-    if (e->checkRightThis(sc))
-        return new ErrorExp();
-    return e;
-}
-
-/******************************
- * Check the tail CallExp is really property function call.
- */
-static bool checkPropertyCall(Expression *e)
-{
-    while (e->op == TOKcomma)
-        e = ((CommaExp *)e)->e2;
 
-    if (e->op == TOKcall)
-    {
-        CallExp *ce = (CallExp *)e;
-        TypeFunction *tf;
-        if (ce->f)
-        {
-            tf = (TypeFunction *)ce->f->type;
-            /* If a forward reference to ce->f, try to resolve it
-             */
-            if (!tf->deco && ce->f->semanticRun < PASSsemanticdone)
+            // Inline expand all the tuples
+            while (arg->op == TOKtuple)
             {
-                dsymbolSemantic(ce->f, NULL);
-                tf = (TypeFunction *)ce->f->type;
+                TupleExp *te = (TupleExp *)arg;
+                exps->remove(i);                // remove arg
+                exps->insert(i, te->exps);      // replace with tuple contents
+                if (i == exps->length)
+                    return;             // empty tuple, no more arguments
+                (*exps)[i] = Expression::combine(te->e0, (*exps)[i]);
+                arg = (*exps)[i];
             }
         }
-        else if (ce->e1->type->ty == Tfunction)
-            tf = (TypeFunction *)ce->e1->type;
-        else if (ce->e1->type->ty == Tdelegate)
-            tf = (TypeFunction *)ce->e1->type->nextOf();
-        else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction)
-            tf = (TypeFunction *)ce->e1->type->nextOf();
-        else
-            assert(0);
     }
-    return false;
 }
 
-/******************************
- * If e1 is a property function (template), resolve it.
+/****************************************
+ * Expand alias this tuples.
  */
 
-Expression *resolvePropertiesOnly(Scope *sc, Expression *e1)
+TupleDeclaration *isAliasThisTuple(Expression *e)
 {
-    //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars());
-    OverloadSet *os;
-    FuncDeclaration *fd;
-    TemplateDeclaration *td;
+    if (!e->type)
+        return NULL;
 
-    if (e1->op == TOKdot)
-    {
-        DotExp *de = (DotExp *)e1;
-        if (de->e2->op == TOKoverloadset)
-        {
-            os = ((OverExp *)de->e2)->vars;
-            goto Los;
-        }
-    }
-    else if (e1->op == TOKoverloadset)
-    {
-        os = ((OverExp *)e1)->vars;
-    Los:
-        assert(os);
-        for (size_t i = 0; i < os->a.length; i++)
-        {
-            Dsymbol *s = os->a[i];
-            fd = s->isFuncDeclaration();
-            td = s->isTemplateDeclaration();
-            if (fd)
-            {
-                if (((TypeFunction *)fd->type)->isproperty)
-                    return resolveProperties(sc, e1);
-            }
-            else if (td && td->onemember &&
-                     (fd = td->onemember->isFuncDeclaration()) != NULL)
-            {
-                if (((TypeFunction *)fd->type)->isproperty ||
-                    (fd->storage_class2 & STCproperty) ||
-                    (td->_scope->stc & STCproperty))
-                {
-                    return resolveProperties(sc, e1);
-                }
-            }
-        }
-    }
-    else if (e1->op == TOKdotti)
-    {
-        DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
-        if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL)
-            goto Ltd;
-    }
-    else if (e1->op == TOKdottd)
-    {
-        td = ((DotTemplateExp *)e1)->td;
-        goto Ltd;
-    }
-    else if (e1->op == TOKscope)
-    {
-        Dsymbol *s = ((ScopeExp *)e1)->sds;
-        TemplateInstance *ti = s->isTemplateInstance();
-        if (ti && !ti->semanticRun && ti->tempdecl)
-        {
-            if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL)
-                goto Ltd;
-        }
-    }
-    else if (e1->op == TOKtemplate)
+    Type *t = e->type->toBasetype();
+Lagain:
+    if (Dsymbol *s = t->toDsymbol(NULL))
     {
-        td = ((TemplateExp *)e1)->td;
-    Ltd:
-        assert(td);
-        if (td->onemember &&
-            (fd = td->onemember->isFuncDeclaration()) != NULL)
+        AggregateDeclaration *ad = s->isAggregateDeclaration();
+        if (ad)
         {
-            if (((TypeFunction *)fd->type)->isproperty ||
-                (fd->storage_class2 & STCproperty) ||
-                (td->_scope->stc & STCproperty))
+            s = ad->aliasthis;
+            if (s && s->isVarDeclaration())
             {
-                return resolveProperties(sc, e1);
+                TupleDeclaration *td = s->isVarDeclaration()->toAlias()->isTupleDeclaration();
+                if (td && td->isexp)
+                    return td;
             }
-        }
-    }
-    else if (e1->op == TOKdotvar && e1->type->ty == Tfunction)
-    {
-        DotVarExp *dve = (DotVarExp *)e1;
-        fd = dve->var->isFuncDeclaration();
-        goto Lfd;
-    }
-    else if (e1->op == TOKvar && e1->type->ty == Tfunction &&
-        (sc->intypeof || !((VarExp *)e1)->var->needThis()))
-    {
-        fd = ((VarExp *)e1)->var->isFuncDeclaration();
-    Lfd:
-        assert(fd);
-        if (((TypeFunction *)fd->type)->isproperty)
-            return resolveProperties(sc, e1);
-    }
-    return e1;
-}
-
-
-// TODO: merge with Scope::search::searchScopes()
-static Dsymbol *searchScopes(Scope *sc, Loc loc, Identifier *ident, int flags)
-{
-    Dsymbol *s = NULL;
-    for (Scope *scx = sc; scx; scx = scx->enclosing)
-    {
-        if (!scx->scopesym)
-            continue;
-        if (scx->scopesym->isModule())
-            flags |= SearchUnqualifiedModule;    // tell Module.search() that SearchLocalsOnly is to be obeyed
-        s = scx->scopesym->search(loc, ident, flags);
-        if (s)
-        {
-            // overload set contains only module scope symbols.
-            if (s->isOverloadSet())
-                break;
-            // selective/renamed imports also be picked up
-            if (AliasDeclaration *ad = s->isAliasDeclaration())
+            if (Type *att = t->aliasthisOf())
             {
-                if (ad->_import)
-                    break;
+                t = att;
+                goto Lagain;
             }
-            // See only module scope symbols for UFCS target.
-            Dsymbol *p = s->toParent2();
-            if (p && p->isModule())
-                break;
         }
-        s = NULL;
-
-        // Stop when we hit a module, but keep going if that is not just under the global scope
-        if (scx->scopesym->isModule() && !(scx->enclosing && !scx->enclosing->enclosing))
-            break;
     }
-    return s;
+    return NULL;
 }
 
-/******************************
- * Find symbol in accordance with the UFCS name look up rule
- */
-
-static Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident)
+int expandAliasThisTuples(Expressions *exps, size_t starti)
 {
-    //printf("searchUFCS(ident = %s)\n", ident->toChars());
-    Loc loc = ue->loc;
-    int flags = 0;
-    Dsymbol *s = NULL;
-
-    if (sc->flags & SCOPEignoresymbolvisibility)
-        flags |= IgnoreSymbolVisibility;
-
-    // First look in local scopes
-    s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly);
-    if (!s)
-    {
-        // Second look in imported modules
-        s = searchScopes(sc, loc, ident, flags | SearchImportsOnly);
-    }
-
-    if (!s)
-        return ue->e1->type->Type::getProperty(loc, ident, 0);
+    if (!exps || exps->length == 0)
+        return -1;
 
-    FuncDeclaration *f = s->isFuncDeclaration();
-    if (f)
+    for (size_t u = starti; u < exps->length; u++)
     {
-        TemplateDeclaration *td = getFuncTemplateDecl(f);
-        if (td)
-        {
-            if (td->overroot)
-                td = td->overroot;
-            s = td;
-        }
-    }
-
-    if (ue->op == TOKdotti)
-    {
-        DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue;
-        TemplateInstance *ti = new TemplateInstance(loc, s->ident);
-        ti->tiargs = dti->ti->tiargs;   // for better diagnostic message
-        if (!ti->updateTempDecl(sc, s))
-            return new ErrorExp();
-        return new ScopeExp(loc, ti);
-    }
-    else
-    {
-        //printf("-searchUFCS() %s\n", s->toChars());
-        return new DsymbolExp(loc, s);
-    }
-}
-
-/******************************
- * check e is exp.opDispatch!(tiargs) or not
- * It's used to switch to UFCS the semantic analysis path
- */
-
-bool isDotOpDispatch(Expression *e)
-{
-    return e->op == TOKdotti &&
-           ((DotTemplateInstanceExp *)e)->ti->name == Id::opDispatch;
-}
-
-/******************************
- * Pull out callable entity with UFCS.
- */
-
-Expression *resolveUFCS(Scope *sc, CallExp *ce)
-{
-    Loc loc = ce->loc;
-    Expression *eleft;
-    Expression *e;
-
-    if (ce->e1->op == TOKdotid)
-    {
-        DotIdExp *die = (DotIdExp *)ce->e1;
-        Identifier *ident = die->ident;
-
-        Expression *ex = semanticX(die, sc);
-        if (ex != die)
-        {
-            ce->e1 = ex;
-            return NULL;
-        }
-        eleft = die->e1;
-
-        Type *t = eleft->type->toBasetype();
-        if (t->ty == Tarray || t->ty == Tsarray ||
-            t->ty == Tnull  || (t->isTypeBasic() && t->ty != Tvoid))
-        {
-            /* Built-in types and arrays have no callable properties, so do shortcut.
-             * It is necessary in: e.init()
-             */
-        }
-        else if (t->ty == Taarray)
-        {
-            if (ident == Id::remove)
-            {
-                /* Transform:
-                 *  aa.remove(arg) into delete aa[arg]
-                 */
-                if (!ce->arguments || ce->arguments->length != 1)
-                {
-                    ce->error("expected key as argument to aa.remove()");
-                    return new ErrorExp();
-                }
-                if (!eleft->type->isMutable())
-                {
-                    ce->error("cannot remove key from %s associative array %s",
-                            MODtoChars(t->mod), eleft->toChars());
-                    return new ErrorExp();
-                }
-                Expression *key = (*ce->arguments)[0];
-                key = expressionSemantic(key, sc);
-                key = resolveProperties(sc, key);
-
-                TypeAArray *taa = (TypeAArray *)t;
-                key = key->implicitCastTo(sc, taa->index);
-
-                if (key->checkValue())
-                    return new ErrorExp();
-
-                semanticTypeInfo(sc, taa->index);
-
-                return new RemoveExp(loc, eleft, key);
-            }
-        }
-        else
-        {
-            if (Expression *ey = semanticY(die, sc, 1))
-            {
-                if (ey->op == TOKerror)
-                    return ey;
-                ce->e1 = ey;
-                if (isDotOpDispatch(ey))
-                {
-                    unsigned errors = global.startGagging();
-                    e = expressionSemantic(ce->syntaxCopy(), sc);
-                    if (!global.endGagging(errors))
-                        return e;
-                    /* fall down to UFCS */
-                }
-                else
-                    return NULL;
-            }
-        }
-        e = searchUFCS(sc, die, ident);
-    }
-    else if (ce->e1->op == TOKdotti)
-    {
-        DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1;
-        if (Expression *ey = semanticY(dti, sc, 1))
-        {
-            ce->e1 = ey;
-            return NULL;
-        }
-        eleft = dti->e1;
-        e = searchUFCS(sc, dti, dti->ti->name);
-    }
-    else
-        return NULL;
-
-    // Rewrite
-    ce->e1 = e;
-    if (!ce->arguments)
-        ce->arguments = new Expressions();
-    ce->arguments->shift(eleft);
-
-    return NULL;
-}
-
-/******************************
- * Pull out property with UFCS.
- */
-
-Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL)
-{
-    Loc loc = e1->loc;
-    Expression *eleft;
-    Expression *e;
-
-    if (e1->op == TOKdotid)
-    {
-        DotIdExp *die = (DotIdExp *)e1;
-        eleft = die->e1;
-        e = searchUFCS(sc, die, die->ident);
-    }
-    else if (e1->op == TOKdotti)
-    {
-        DotTemplateInstanceExp *dti;
-        dti = (DotTemplateInstanceExp *)e1;
-        eleft = dti->e1;
-        e = searchUFCS(sc, dti, dti->ti->name);
-    }
-    else
-        return NULL;
-
-    if (e == NULL)
-        return NULL;
-
-    // Rewrite
-    if (e2)
-    {
-        // run semantic without gagging
-        e2 = expressionSemantic(e2, sc);
-
-        /* f(e1) = e2
-         */
-        Expression *ex = e->copy();
-        Expressions *a1 = new Expressions();
-        a1->setDim(1);
-        (*a1)[0] = eleft;
-        ex = new CallExp(loc, ex, a1);
-        ex = trySemantic(ex, sc);
-
-        /* f(e1, e2)
-         */
-        Expressions *a2 = new Expressions();
-        a2->setDim(2);
-        (*a2)[0] = eleft;
-        (*a2)[1] = e2;
-        e = new CallExp(loc, e, a2);
-        if (ex)
-        {   // if fallback setter exists, gag errors
-            e = trySemantic(e, sc);
-            if (!e)
-            {   checkPropertyCall(ex);
-                ex = new AssignExp(loc, ex, e2);
-                return expressionSemantic(ex, sc);
-            }
-        }
-        else
-        {   // strict setter prints errors if fails
-            e = expressionSemantic(e, sc);
-        }
-        checkPropertyCall(e);
-        return e;
-    }
-    else
-    {
-        /* f(e1)
-         */
-        Expressions *arguments = new Expressions();
-        arguments->setDim(1);
-        (*arguments)[0] = eleft;
-        e = new CallExp(loc, e, arguments);
-        e = expressionSemantic(e, sc);
-        checkPropertyCall(e);
-        return expressionSemantic(e, sc);
-    }
-}
-
-/******************************
- * Perform semantic() on an array of Expressions.
- */
-
-bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors)
-{
-    bool err = false;
-    if (exps)
-    {
-        for (size_t i = 0; i < exps->length; i++)
-        {
-            Expression *e = (*exps)[i];
-            if (e)
-            {
-                e = expressionSemantic(e, sc);
-                if (e->op == TOKerror)
-                    err = true;
-                if (preserveErrors || e->op != TOKerror)
-                    (*exps)[i] = e;
-            }
-        }
-    }
-    return err;
-}
-
-/****************************************
- * Expand tuples.
- * Input:
- *      exps    aray of Expressions
- * Output:
- *      exps    rewritten in place
- */
-
-void expandTuples(Expressions *exps)
-{
-    //printf("expandTuples()\n");
-    if (exps)
-    {
-        for (size_t i = 0; i < exps->length; i++)
-        {
-            Expression *arg = (*exps)[i];
-            if (!arg)
-                continue;
-
-            // Look for tuple with 0 members
-            if (arg->op == TOKtype)
-            {
-                TypeExp *e = (TypeExp *)arg;
-                if (e->type->toBasetype()->ty == Ttuple)
-                {
-                    TypeTuple *tt = (TypeTuple *)e->type->toBasetype();
-
-                    if (!tt->arguments || tt->arguments->length == 0)
-                    {
-                        exps->remove(i);
-                        if (i == exps->length)
-                            return;
-                        i--;
-                        continue;
-                    }
-                }
-            }
-
-            // Inline expand all the tuples
-            while (arg->op == TOKtuple)
-            {
-                TupleExp *te = (TupleExp *)arg;
-                exps->remove(i);                // remove arg
-                exps->insert(i, te->exps);      // replace with tuple contents
-                if (i == exps->length)
-                    return;             // empty tuple, no more arguments
-                (*exps)[i] = Expression::combine(te->e0, (*exps)[i]);
-                arg = (*exps)[i];
-            }
-        }
-    }
-}
-
-/****************************************
- * Expand alias this tuples.
- */
-
-TupleDeclaration *isAliasThisTuple(Expression *e)
-{
-    if (!e->type)
-        return NULL;
-
-    Type *t = e->type->toBasetype();
-Lagain:
-    if (Dsymbol *s = t->toDsymbol(NULL))
-    {
-        AggregateDeclaration *ad = s->isAggregateDeclaration();
-        if (ad)
-        {
-            s = ad->aliasthis;
-            if (s && s->isVarDeclaration())
-            {
-                TupleDeclaration *td = s->isVarDeclaration()->toAlias()->isTupleDeclaration();
-                if (td && td->isexp)
-                    return td;
-            }
-            if (Type *att = t->aliasthisOf())
-            {
-                t = att;
-                goto Lagain;
-            }
-        }
-    }
-    return NULL;
-}
-
-int expandAliasThisTuples(Expressions *exps, size_t starti)
-{
-    if (!exps || exps->length == 0)
-        return -1;
-
-    for (size_t u = starti; u < exps->length; u++)
-    {
-        Expression *exp = (*exps)[u];
-        TupleDeclaration *td = isAliasThisTuple(exp);
+        Expression *exp = (*exps)[u];
+        TupleDeclaration *td = isAliasThisTuple(exp);
         if (td)
         {
             exps->remove(u);
@@ -1061,907 +256,130 @@  int expandAliasThisTuples(Expressions *exps, size_t starti)
         }
     }
 
-    return -1;
-}
-
-/****************************************
- * The common type is determined by applying ?: to each pair.
- * Output:
- *      exps[]  properties resolved, implicitly cast to common type, rewritten in place
- *      *pt     if pt is not NULL, set to the common type
- * Returns:
- *      true    a semantic error was detected
- */
-
-bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
-{
-    /* Still have a problem with:
-     *  ubyte[][] = [ cast(ubyte[])"hello", [1]];
-     * which works if the array literal is initialized top down with the ubyte[][]
-     * type, but fails with this function doing bottom up typing.
-     */
-    //printf("arrayExpressionToCommonType()\n");
-    IntegerExp integerexp(0);
-    CondExp condexp(Loc(), &integerexp, NULL, NULL);
-
-    Type *t0 = NULL;
-    Expression *e0 = NULL;      // dead-store to prevent spurious warning
-    size_t j0 = ~0;             // dead-store to prevent spurious warning
-    bool foundType = false;
-
-    for (size_t i = 0; i < exps->length; i++)
-    {
-        Expression *e = (*exps)[i];
-        if (!e)
-            continue;
-
-        e = resolveProperties(sc, e);
-        if (!e->type)
-        {
-            e->error("%s has no value", e->toChars());
-            t0 = Type::terror;
-            continue;
-        }
-        if (e->op == TOKtype)
-        {
-            foundType = true;   // do not break immediately, there might be more errors
-            e->checkValue();    // report an error "type T has no value"
-            t0 = Type::terror;
-            continue;
-        }
-        if (e->type->ty == Tvoid)
-        {
-            // void expressions do not concur to the determination of the common
-            // type.
-            continue;
-        }
-        if (checkNonAssignmentArrayOp(e))
-        {
-            t0 = Type::terror;
-            continue;
-        }
-
-        e = doCopyOrMove(sc, e);
-
-        if (!foundType && t0 && !t0->equals(e->type))
-        {
-            /* This applies ?: to merge the types. It's backwards;
-             * ?: should call this function to merge types.
-             */
-            condexp.type = NULL;
-            condexp.e1 = e0;
-            condexp.e2 = e;
-            condexp.loc = e->loc;
-            Expression *ex = expressionSemantic(&condexp, sc);
-            if (ex->op == TOKerror)
-                e = ex;
-            else
-            {
-                (*exps)[j0] = condexp.e1;
-                e = condexp.e2;
-            }
-        }
-        j0 = i;
-        e0 = e;
-        t0 = e->type;
-        if (e->op != TOKerror)
-            (*exps)[i] = e;
-    }
-
-    if (!t0)
-        t0 = Type::tvoid;               // [] is typed as void[]
-    else if (t0->ty != Terror)
-    {
-        for (size_t i = 0; i < exps->length; i++)
-        {
-            Expression *e = (*exps)[i];
-            if (!e)
-                continue;
-
-            e = e->implicitCastTo(sc, t0);
-            //assert(e->op != TOKerror);
-            if (e->op == TOKerror)
-            {
-                /* Bugzilla 13024: a workaround for the bug in typeMerge -
-                 * it should paint e1 and e2 by deduced common type,
-                 * but doesn't in this particular case.
-                 */
-                t0 = Type::terror;
-                break;
-            }
-            (*exps)[i] = e;
-        }
-    }
-    if (pt)
-        *pt = t0;
-
-    return (t0 == Type::terror);
-}
-
-/****************************************
- * Get TemplateDeclaration enclosing FuncDeclaration.
- */
-
-TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s)
-{
-    FuncDeclaration *f = s->isFuncDeclaration();
-    if (f && f->parent)
-    {
-        TemplateInstance *ti = f->parent->isTemplateInstance();
-        if (ti && !ti->isTemplateMixin() &&
-            ti->tempdecl && ((TemplateDeclaration *)ti->tempdecl)->onemember &&
-            ti->tempdecl->ident == f->ident)
-        {
-            return (TemplateDeclaration *)ti->tempdecl;
-        }
-    }
-    return NULL;
-}
-
-/************************************************
- * If we want the value of this expression, but do not want to call
- * the destructor on it.
- */
-
-Expression *valueNoDtor(Expression *e)
-{
-    if (e->op == TOKcall)
-    {
-        /* The struct value returned from the function is transferred
-         * so do not call the destructor on it.
-         * Recognize:
-         *       ((S _ctmp = S.init), _ctmp).this(...)
-         * and make sure the destructor is not called on _ctmp
-         * BUG: if e is a CommaExp, we should go down the right side.
-         */
-        CallExp *ce = (CallExp *)e;
-        if (ce->e1->op == TOKdotvar)
-        {
-            DotVarExp *dve = (DotVarExp *)ce->e1;
-            if (dve->var->isCtorDeclaration())
-            {
-                // It's a constructor call
-                if (dve->e1->op == TOKcomma)
-                {
-                    CommaExp *comma = (CommaExp *)dve->e1;
-                    if (comma->e2->op == TOKvar)
-                    {
-                        VarExp *ve = (VarExp *)comma->e2;
-                        VarDeclaration *ctmp = ve->var->isVarDeclaration();
-                        if (ctmp)
-                        {
-                            ctmp->storage_class |= STCnodtor;
-                            assert(!ce->isLvalue());
-                        }
-                    }
-                }
-            }
-        }
-    }
-    else if (e->op == TOKvar)
-    {
-        VarDeclaration *vtmp = ((VarExp *)e)->var->isVarDeclaration();
-        if (vtmp && vtmp->storage_class & STCrvalue)
-        {
-            vtmp->storage_class |= STCnodtor;
-        }
-    }
-    return e;
-}
-
-/********************************************
- * Issue an error if default construction is disabled for type t.
- * Default construction is required for arrays and 'out' parameters.
- * Returns:
- *      true    an error was issued
- */
-bool checkDefCtor(Loc loc, Type *t)
-{
-    t = t->baseElemOf();
-    if (t->ty == Tstruct)
-    {
-        StructDeclaration *sd = ((TypeStruct *)t)->sym;
-        if (sd->noDefaultCtor)
-        {
-            sd->error(loc, "default construction is disabled");
-            return true;
-        }
-    }
-    return false;
-}
-
-/*********************************************
- * If e is an instance of a struct, and that struct has a copy constructor,
- * rewrite e as:
- *    (tmp = e),tmp
- * Input:
- *      sc      just used to specify the scope of created temporary variable
- */
-Expression *callCpCtor(Scope *sc, Expression *e)
-{
-    Type *tv = e->type->baseElemOf();
-    if (tv->ty == Tstruct)
-    {
-        StructDeclaration *sd = ((TypeStruct *)tv)->sym;
-        if (sd->postblit)
-        {
-            /* Create a variable tmp, and replace the argument e with:
-             *      (tmp = e),tmp
-             * and let AssignExp() handle the construction.
-             * This is not the most efficent, ideally tmp would be constructed
-             * directly onto the stack.
-             */
-            VarDeclaration *tmp = copyToTemp(STCrvalue, "__copytmp", e);
-            tmp->storage_class |= STCnodtor;
-            dsymbolSemantic(tmp, sc);
-            Expression *de = new DeclarationExp(e->loc, tmp);
-            Expression *ve = new VarExp(e->loc, tmp);
-            de->type = Type::tvoid;
-            ve->type = e->type;
-            e = Expression::combine(de, ve);
-        }
-    }
-    return e;
-}
-
-/************************************************
- * Handle the postblit call on lvalue, or the move of rvalue.
- */
-Expression *doCopyOrMove(Scope *sc, Expression *e)
-{
-    if (e->op == TOKquestion)
-    {
-        CondExp *ce = (CondExp *)e;
-        ce->e1 = doCopyOrMove(sc, ce->e1);
-        ce->e2 = doCopyOrMove(sc, ce->e2);
-    }
-    else
-    {
-        e = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
-    }
-    return e;
-}
-
-/****************************************
- * Now that we know the exact type of the function we're calling,
- * the arguments[] need to be adjusted:
- *      1. implicitly convert argument to the corresponding parameter type
- *      2. add default arguments for any missing arguments
- *      3. do default promotions on arguments corresponding to ...
- *      4. add hidden _arguments[] argument
- *      5. call copy constructor for struct value arguments
- * Input:
- *      tf      type of the function
- *      fd      the function being called, NULL if called indirectly
- * Output:
- *      *prettype return type of function
- *      *peprefix expression to execute before arguments[] are evaluated, NULL if none
- * Returns:
- *      true    errors happened
- */
-
-bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
-        Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix)
-{
-    //printf("functionParameters()\n");
-    assert(arguments);
-    assert(fd || tf->next);
-    size_t nargs = arguments ? arguments->length : 0;
-    size_t nparams = tf->parameterList.length();
-    unsigned olderrors = global.errors;
-    bool err = false;
-    *prettype = Type::terror;
-    Expression *eprefix = NULL;
-    *peprefix = NULL;
-
-    if (nargs > nparams && tf->parameterList.varargs == VARARGnone)
-    {
-        error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars());
-        return true;
-    }
-
-    // If inferring return type, and semantic3() needs to be run if not already run
-    if (!tf->next && fd->inferRetType)
-    {
-        fd->functionSemantic();
-    }
-    else if (fd && fd->parent)
-    {
-        TemplateInstance *ti = fd->parent->isTemplateInstance();
-        if (ti && ti->tempdecl)
-        {
-            fd->functionSemantic3();
-        }
-    }
-    bool isCtorCall = fd && fd->needThis() && fd->isCtorDeclaration();
-
-    size_t n = (nargs > nparams) ? nargs : nparams;   // n = max(nargs, nparams)
-
-    /* If the function return type has wildcards in it, we'll need to figure out the actual type
-     * based on the actual argument types.
-     */
-    MOD wildmatch = 0;
-    if (tthis && tf->isWild() && !isCtorCall)
-    {
-        Type *t = tthis;
-        if (t->isImmutable())
-            wildmatch = MODimmutable;
-        else if (t->isWildConst())
-            wildmatch = MODwildconst;
-        else if (t->isWild())
-            wildmatch = MODwild;
-        else if (t->isConst())
-            wildmatch = MODconst;
-        else
-            wildmatch = MODmutable;
-    }
-
-    int done = 0;
-    for (size_t i = 0; i < n; i++)
-    {
-        Expression *arg;
-
-        if (i < nargs)
-            arg = (*arguments)[i];
-        else
-            arg = NULL;
-
-        if (i < nparams)
-        {
-            Parameter *p = tf->parameterList[i];
-
-            if (!arg)
-            {
-                if (!p->defaultArg)
-                {
-                    if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
-                        goto L2;
-                    error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
-                    return true;
-                }
-                arg = p->defaultArg;
-                arg = inlineCopy(arg, sc);
-                // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
-                arg = arg->resolveLoc(loc, sc);
-                arguments->push(arg);
-                nargs++;
-            }
-
-            if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
-            {
-                //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
-                {
-                    MATCH m;
-                    if ((m = arg->implicitConvTo(p->type)) > MATCHnomatch)
-                    {
-                        if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
-                            goto L2;
-                        else if (nargs != nparams)
-                        {   error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
-                            return true;
-                        }
-                        goto L1;
-                    }
-                }
-             L2:
-                Type *tb = p->type->toBasetype();
-                Type *tret = p->isLazyArray();
-                switch (tb->ty)
-                {
-                    case Tsarray:
-                    case Tarray:
-                    {
-                        /* Create a static array variable v of type arg->type:
-                         *  T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
-                         *
-                         * The array literal in the initializer of the hidden variable
-                         * is now optimized. See Bugzilla 2356.
-                         */
-                        Type *tbn = ((TypeArray *)tb)->next;
-
-                        Expressions *elements = new Expressions();
-                        elements->setDim(nargs - i);
-                        for (size_t u = 0; u < elements->length; u++)
-                        {
-                            Expression *a = (*arguments)[i + u];
-                            if (tret && a->implicitConvTo(tret))
-                            {
-                                a = a->implicitCastTo(sc, tret);
-                                a = a->optimize(WANTvalue);
-                                a = toDelegate(a, a->type, sc);
-                            }
-                            else
-                                a = a->implicitCastTo(sc, tbn);
-                            (*elements)[u] = a;
-                        }
-                        // Bugzilla 14395: Convert to a static array literal, or its slice.
-                        arg = new ArrayLiteralExp(loc, tbn->sarrayOf(nargs - i), elements);
-                        if (tb->ty == Tarray)
-                        {
-                            arg = new SliceExp(loc, arg, NULL, NULL);
-                            arg->type = p->type;
-                        }
-                        break;
-                    }
-                    case Tclass:
-                    {
-                        /* Set arg to be:
-                         *      new Tclass(arg0, arg1, ..., argn)
-                         */
-                        Expressions *args = new Expressions();
-                        args->setDim(nargs - i);
-                        for (size_t u = i; u < nargs; u++)
-                            (*args)[u - i] = (*arguments)[u];
-                        arg = new NewExp(loc, NULL, NULL, p->type, args);
-                        break;
-                    }
-                    default:
-                        if (!arg)
-                        {
-                            error(loc, "not enough arguments");
-                            return true;
-                        }
-                        break;
-                }
-                arg = expressionSemantic(arg, sc);
-                //printf("\targ = '%s'\n", arg->toChars());
-                arguments->setDim(i + 1);
-                (*arguments)[i] =  arg;
-                nargs = i + 1;
-                done = 1;
-            }
-
-        L1:
-            if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
-            {
-                bool isRef = (p->storageClass & (STCref | STCout)) != 0;
-                if (unsigned char wm = arg->type->deduceWild(p->type, isRef))
-                {
-                    if (wildmatch)
-                        wildmatch = MODmerge(wildmatch, wm);
-                    else
-                        wildmatch = wm;
-                    //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch);
-                }
-            }
-        }
-        if (done)
-            break;
-    }
-    if ((wildmatch == MODmutable || wildmatch == MODimmutable) &&
-        tf->next->hasWild() &&
-        (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf())))
-    {
-        if (fd)
-        {
-            /* If the called function may return the reference to
-             * outer inout data, it should be rejected.
-             *
-             * void foo(ref inout(int) x) {
-             *   ref inout(int) bar(inout(int)) { return x; }
-             *   struct S { ref inout(int) bar() inout { return x; } }
-             *   bar(int.init) = 1;  // bad!
-             *   S().bar() = 1;      // bad!
-             * }
-             */
-            Dsymbol *s = NULL;
-            if (fd->isThis() || fd->isNested())
-                s = fd->toParent2();
-            for (; s; s = s->toParent2())
-            {
-                if (AggregateDeclaration *ad = s->isAggregateDeclaration())
-                {
-                    if (ad->isNested())
-                        continue;
-                    break;
-                }
-                if (FuncDeclaration *ff = s->isFuncDeclaration())
-                {
-                    if (((TypeFunction *)ff->type)->iswild)
-                        goto Linouterr;
-
-                    if (ff->isNested() || ff->isThis())
-                        continue;
-                }
-                break;
-            }
-        }
-        else if (tf->isWild())
-        {
-        Linouterr:
-            const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch);
-            error(loc, "modify inout to %s is not allowed inside inout function", s);
-            return true;
-        }
-    }
-
-    assert(nargs >= nparams);
-    for (size_t i = 0; i < nargs; i++)
-    {
-        Expression *arg = (*arguments)[i];
-        assert(arg);
-        if (i < nparams)
-        {
-            Parameter *p = tf->parameterList[i];
-
-            if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
-            {
-                Type *tprm = p->type;
-                if (p->type->hasWild())
-                    tprm = p->type->substWildTo(wildmatch);
-                if (!tprm->equals(arg->type))
-                {
-                    //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
-                    arg = arg->implicitCastTo(sc, tprm);
-                    arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
-                }
-            }
-            if (p->storageClass & STCref)
-            {
-                arg = arg->toLvalue(sc, arg);
-
-                // Look for mutable misaligned pointer, etc., in @safe mode
-                err |= checkUnsafeAccess(sc, arg, false, true);
-            }
-            else if (p->storageClass & STCout)
-            {
-                Type *t = arg->type;
-                if (!t->isMutable() || !t->isAssignable())  // check blit assignable
-                {
-                    arg->error("cannot modify struct %s with immutable members", arg->toChars());
-                    err = true;
-                }
-                else
-                {
-                    // Look for misaligned pointer, etc., in @safe mode
-                    err |= checkUnsafeAccess(sc, arg, false, true);
-                    err |= checkDefCtor(arg->loc, t);   // t must be default constructible
-                }
-                arg = arg->toLvalue(sc, arg);
-            }
-            else if (p->storageClass & STClazy)
-            {
-                // Convert lazy argument to a delegate
-                if (p->type->ty == Tvoid)
-                    arg = toDelegate(arg, p->type, sc);
-                else
-                    arg = toDelegate(arg, arg->type, sc);
-            }
-
-            //printf("arg: %s\n", arg->toChars());
-            //printf("type: %s\n", arg->type->toChars());
-            if (tf->parameterEscapes(p))
-            {
-                /* Argument value can escape from the called function.
-                 * Check arg to see if it matters.
-                 */
-                if (global.params.vsafe)
-                    err |= checkParamArgumentEscape(sc, fd, p->ident, arg, false);
-            }
-            else
-            {
-                /* Argument value cannot escape from the called function.
-                 */
-                Expression *a = arg;
-                if (a->op == TOKcast)
-                    a = ((CastExp *)a)->e1;
-
-                if (a->op == TOKfunction)
-                {
-                    /* Function literals can only appear once, so if this
-                     * appearance was scoped, there cannot be any others.
-                     */
-                    FuncExp *fe = (FuncExp *)a;
-                    fe->fd->tookAddressOf = 0;
-                }
-                else if (a->op == TOKdelegate)
-                {
-                    /* For passing a delegate to a scoped parameter,
-                     * this doesn't count as taking the address of it.
-                     * We only worry about 'escaping' references to the function.
-                     */
-                    DelegateExp *de = (DelegateExp *)a;
-                    if (de->e1->op == TOKvar)
-                    {   VarExp *ve = (VarExp *)de->e1;
-                        FuncDeclaration *f = ve->var->isFuncDeclaration();
-                        if (f)
-                        {   f->tookAddressOf--;
-                            //printf("tookAddressOf = %d\n", f->tookAddressOf);
-                        }
-                    }
-                }
-            }
-            arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
-        }
-        else
-        {
-            // These will be the trailing ... arguments
-
-            // If not D linkage, do promotions
-            if (tf->linkage != LINKd)
-            {
-                // Promote bytes, words, etc., to ints
-                arg = integralPromotions(arg, sc);
-
-                // Promote floats to doubles
-                switch (arg->type->ty)
-                {
-                    case Tfloat32:
-                        arg = arg->castTo(sc, Type::tfloat64);
-                        break;
-
-                    case Timaginary32:
-                        arg = arg->castTo(sc, Type::timaginary64);
-                        break;
-                }
-
-                if (tf->parameterList.varargs == VARARGvariadic)
-                {
-                    const char *p = tf->linkage == LINKc ? "extern(C)" : "extern(C++)";
-                    if (arg->type->ty == Tarray)
-                    {
-                        arg->error("cannot pass dynamic arrays to %s vararg functions", p);
-                        err = true;
-                    }
-                    if (arg->type->ty == Tsarray)
-                    {
-                        arg->error("cannot pass static arrays to %s vararg functions", p);
-                        err = true;
-                    }
-                }
-            }
-
-            // Do not allow types that need destructors
-            if (arg->type->needsDestruction())
-            {
-                arg->error("cannot pass types that need destruction as variadic arguments");
-                err = true;
-            }
-
-            // Convert static arrays to dynamic arrays
-            // BUG: I don't think this is right for D2
-            Type *tb = arg->type->toBasetype();
-            if (tb->ty == Tsarray)
-            {
-                TypeSArray *ts = (TypeSArray *)tb;
-                Type *ta = ts->next->arrayOf();
-                if (ts->size(arg->loc) == 0)
-                    arg = new NullExp(arg->loc, ta);
-                else
-                    arg = arg->castTo(sc, ta);
-            }
-            if (tb->ty == Tstruct)
-            {
-                //arg = callCpCtor(sc, arg);
-            }
-
-            // Give error for overloaded function addresses
-            if (arg->op == TOKsymoff)
-            {   SymOffExp *se = (SymOffExp *)arg;
-                if (se->hasOverloads &&
-                    !se->var->isFuncDeclaration()->isUnique())
-                {   arg->error("function %s is overloaded", arg->toChars());
-                    err = true;
-                }
-            }
-            if (arg->checkValue())
-                err = true;
-            arg = arg->optimize(WANTvalue);
-        }
-        (*arguments)[i] = arg;
-    }
-
-    /* Remaining problems:
-     * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
-     *    implemented by calling a function) we'll defer this for now.
-     * 2. value structs (or static arrays of them) that need to be copy constructed
-     * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
-     *    function gets called (functions normally destroy their parameters)
-     * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
-     * up properly. Pushing arguments on the stack then cannot fail.
-     */
-    if (1)
-    {
-        /* TODO: tackle problem 1)
-         */
-        const bool leftToRight = true; // TODO: something like !fd.isArrayOp
-        if (!leftToRight)
-            assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
+    return -1;
+}
 
-        const ptrdiff_t start = (leftToRight ? 0 : (ptrdiff_t)nargs - 1);
-        const ptrdiff_t end = (leftToRight ? (ptrdiff_t)nargs : -1);
-        const ptrdiff_t step = (leftToRight ? 1 : -1);
+/****************************************
+ * Get TemplateDeclaration enclosing FuncDeclaration.
+ */
 
-        /* Compute indices of last throwing argument and first arg needing destruction.
-         * Used to not set up destructors unless an arg needs destruction on a throw
-         * in a later argument.
-         */
-        ptrdiff_t lastthrow = -1;
-        ptrdiff_t firstdtor = -1;
-        for (ptrdiff_t i = start; i != end; i += step)
+TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s)
+{
+    FuncDeclaration *f = s->isFuncDeclaration();
+    if (f && f->parent)
+    {
+        TemplateInstance *ti = f->parent->isTemplateInstance();
+        if (ti && !ti->isTemplateMixin() &&
+            ti->tempdecl && ((TemplateDeclaration *)ti->tempdecl)->onemember &&
+            ti->tempdecl->ident == f->ident)
         {
-            Expression *arg = (*arguments)[i];
-            if (canThrow(arg, sc->func, false))
-                lastthrow = i;
-            if (firstdtor == -1 && arg->type->needsDestruction())
-            {
-                Parameter *p = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
-                if (!(p && (p->storageClass & (STClazy | STCref | STCout))))
-                    firstdtor = i;
-            }
+            return (TemplateDeclaration *)ti->tempdecl;
         }
+    }
+    return NULL;
+}
 
-        /* Does problem 3) apply to this call?
-         */
-        const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0
-            && (lastthrow - firstdtor) * step > 0);
+/************************************************
+ * If we want the value of this expression, but do not want to call
+ * the destructor on it.
+ */
 
-        /* If so, initialize 'eprefix' by declaring the gate
+Expression *valueNoDtor(Expression *e)
+{
+    if (e->op == TOKcall)
+    {
+        /* The struct value returned from the function is transferred
+         * so do not call the destructor on it.
+         * Recognize:
+         *       ((S _ctmp = S.init), _ctmp).this(...)
+         * and make sure the destructor is not called on _ctmp
+         * BUG: if e is a CommaExp, we should go down the right side.
          */
-        VarDeclaration *gate = NULL;
-        if (needsPrefix)
-        {
-            // eprefix => bool __gate [= false]
-            Identifier *idtmp = Identifier::generateId("__gate");
-            gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
-            gate->storage_class |= STCtemp | STCctfe | STCvolatile;
-            dsymbolSemantic(gate, sc);
-
-            Expression *ae = new DeclarationExp(loc, gate);
-            eprefix = expressionSemantic(ae, sc);
-        }
-
-        for (ptrdiff_t i = start; i != end; i += step)
+        CallExp *ce = (CallExp *)e;
+        if (ce->e1->op == TOKdotvar)
         {
-            Expression *arg = (*arguments)[i];
-
-            Parameter *parameter = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
-            const bool isRef = (parameter && (parameter->storageClass & (STCref | STCout)));
-            const bool isLazy = (parameter && (parameter->storageClass & STClazy));
-
-            /* Skip lazy parameters
-             */
-            if (isLazy)
-                continue;
-
-            /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg.
-             * Declare a temporary variable for this arg and append that declaration to 'eprefix',
-             * which will implicitly take care of potential problem 2) for this arg.
-             * 'eprefix' will therefore finally contain all args up to and including the last
-             * potentially throwing arg, excluding all lazy parameters.
-             */
-            if (gate)
+            DotVarExp *dve = (DotVarExp *)ce->e1;
+            if (dve->var->isCtorDeclaration())
             {
-                const bool needsDtor = (!isRef && arg->type->needsDestruction() && i != lastthrow);
-
-                /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
-                 */
-                VarDeclaration *tmp = copyToTemp(0,
-                    needsDtor ? "__pfx" : "__pfy",
-                    !isRef ? arg : arg->addressOf());
-                dsymbolSemantic(tmp, sc);
-
-                /* Modify the destructor so it only runs if gate==false, i.e.,
-                 * only if there was a throw while constructing the args
-                 */
-                if (!needsDtor)
+                // It's a constructor call
+                if (dve->e1->op == TOKcomma)
                 {
-                    if (tmp->edtor)
+                    CommaExp *comma = (CommaExp *)dve->e1;
+                    if (comma->e2->op == TOKvar)
                     {
-                        assert(i == lastthrow);
-                        tmp->edtor = NULL;
+                        VarExp *ve = (VarExp *)comma->e2;
+                        VarDeclaration *ctmp = ve->var->isVarDeclaration();
+                        if (ctmp)
+                        {
+                            ctmp->storage_class |= STCnodtor;
+                            assert(!ce->isLvalue());
+                        }
                     }
                 }
-                else
-                {
-                    // edtor => (__gate || edtor)
-                    assert(tmp->edtor);
-                    Expression *e = tmp->edtor;
-                    e = new LogicalExp(e->loc, TOKoror, new VarExp(e->loc, gate), e);
-                    tmp->edtor = expressionSemantic(e, sc);
-                    //printf("edtor: %s\n", tmp->edtor->toChars());
-                }
-
-                // eprefix => (eprefix, auto __pfx/y = arg)
-                DeclarationExp *ae = new DeclarationExp(loc, tmp);
-                eprefix = Expression::combine(eprefix, expressionSemantic(ae, sc));
-
-                // arg => __pfx/y
-                arg = new VarExp(loc, tmp);
-                arg = expressionSemantic(arg, sc);
-                if (isRef)
-                {
-                    arg = new PtrExp(loc, arg);
-                    arg = expressionSemantic(arg, sc);
-                }
-
-                /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
-                 * i.e., disable the dtors right after constructing the last throwing arg.
-                 * From now on, the callee will take care of destructing the args because
-                 * the args are implicitly moved into function parameters.
-                 *
-                 * Set gate to null to let the next iterations know they don't need to
-                 * append to eprefix anymore.
-                 */
-                if (i == lastthrow)
-                {
-                    Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
-                    eprefix = Expression::combine(eprefix, expressionSemantic(e, sc));
-                    gate = NULL;
-                }
-            }
-            else
-            {
-                /* No gate, no prefix to append to.
-                 * Handle problem 2) by calling the copy constructor for value structs
-                 * (or static arrays of them) if appropriate.
-                 */
-                Type *tv = arg->type->baseElemOf();
-                if (!isRef && tv->ty == Tstruct)
-                    arg = doCopyOrMove(sc, arg);
             }
-
-            (*arguments)[i] = arg;
         }
     }
-    //if (eprefix) printf("eprefix: %s\n", eprefix->toChars());
-
-    // If D linkage and variadic, add _arguments[] as first argument
-    if (tf->isDstyleVariadic())
+    else if (e->op == TOKvar)
     {
-        assert(arguments->length >= nparams);
-
-        Parameters *args = new Parameters;
-        args->setDim(arguments->length - nparams);
-        for (size_t i = 0; i < arguments->length - nparams; i++)
+        VarDeclaration *vtmp = ((VarExp *)e)->var->isVarDeclaration();
+        if (vtmp && vtmp->storage_class & STCrvalue)
         {
-            Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL, NULL);
-            (*args)[i] = arg;
+            vtmp->storage_class |= STCnodtor;
         }
-
-        TypeTuple *tup = new TypeTuple(args);
-        Expression *e = new TypeidExp(loc, tup);
-        e = expressionSemantic(e, sc);
-        arguments->insert(0, e);
     }
+    return e;
+}
 
-    Type *tret = tf->next;
-    if (isCtorCall)
+/*********************************************
+ * If e is an instance of a struct, and that struct has a copy constructor,
+ * rewrite e as:
+ *    (tmp = e),tmp
+ * Input:
+ *      sc      just used to specify the scope of created temporary variable
+ */
+Expression *callCpCtor(Scope *sc, Expression *e)
+{
+    Type *tv = e->type->baseElemOf();
+    if (tv->ty == Tstruct)
     {
-        //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(),
-        //    wildmatch, tf->isWild(), fd->isolateReturn());
-        if (!tthis)
-        {
-            assert(sc->intypeof || global.errors);
-            tthis = fd->isThis()->type->addMod(fd->type->mod);
-        }
-        if (tf->isWild() && !fd->isolateReturn())
+        StructDeclaration *sd = ((TypeStruct *)tv)->sym;
+        if (sd->postblit)
         {
-            if (wildmatch)
-                tret = tret->substWildTo(wildmatch);
-            int offset;
-            if (!tret->implicitConvTo(tthis) &&
-                !(MODimplicitConv(tret->mod, tthis->mod) && tret->isBaseOf(tthis, &offset) && offset == 0))
-            {
-                const char* s1 = tret ->isNaked() ? " mutable" : tret ->modToChars();
-                const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars();
-                ::error(loc, "inout constructor %s creates%s object, not%s",
-                        fd->toPrettyChars(), s1, s2);
-                err = true;
-            }
+            /* Create a variable tmp, and replace the argument e with:
+             *      (tmp = e),tmp
+             * and let AssignExp() handle the construction.
+             * This is not the most efficent, ideally tmp would be constructed
+             * directly onto the stack.
+             */
+            VarDeclaration *tmp = copyToTemp(STCrvalue, "__copytmp", e);
+            tmp->storage_class |= STCnodtor;
+            dsymbolSemantic(tmp, sc);
+            Expression *de = new DeclarationExp(e->loc, tmp);
+            Expression *ve = new VarExp(e->loc, tmp);
+            de->type = Type::tvoid;
+            ve->type = e->type;
+            e = Expression::combine(de, ve);
         }
-        tret = tthis;
     }
-    else if (wildmatch && tret)
+    return e;
+}
+
+/************************************************
+ * Handle the postblit call on lvalue, or the move of rvalue.
+ */
+Expression *doCopyOrMove(Scope *sc, Expression *e)
+{
+    if (e->op == TOKquestion)
+    {
+        CondExp *ce = (CondExp *)e;
+        ce->e1 = doCopyOrMove(sc, ce->e1);
+        ce->e2 = doCopyOrMove(sc, ce->e2);
+    }
+    else
     {
-        /* Adjust function return type based on wildmatch
-         */
-        //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
-        tret = tret->substWildTo(wildmatch);
+        e = e->isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e);
     }
-    *prettype = tret;
-    *peprefix = eprefix;
-    return (err || olderrors != global.errors);
+    return e;
 }
 
 /******************************** Expression **************************/
@@ -5288,8 +3706,10 @@  MATCH FuncExp::matchType(Type *to, Scope *sc, FuncExp **presult, int flag)
     }
     else if (!flag)
     {
+        const char *ts[2];
+        toAutoQualChars(ts, tx, to);
         error("cannot implicitly convert expression (%s) of type %s to %s",
-                toChars(), tx->toChars(), to->toChars());
+                toChars(), ts[0], ts[1]);
     }
     return m;
 }
@@ -5644,11 +4064,17 @@  Expression *BinExp::incompatibleTypes()
         error("incompatible types for ((%s) %s (%s)): cannot use `%s` with types",
             e1->toChars(), Token::toChars(thisOp), e2->toChars(), Token::toChars(op));
     }
+    else if (e1->type->equals(e2->type))
+    {
+        error("incompatible types for ((%s) %s (%s)): both operands are of type `%s`",
+            e1->toChars(), Token::toChars(thisOp), e2->toChars(), e1->type->toChars());
+    }
     else
     {
+        const char *ts[2];
+        toAutoQualChars(ts, e1->type, e2->type);
         error("incompatible types for ((%s) %s (%s)): `%s` and `%s`",
-            e1->toChars(), Token::toChars(thisOp), e2->toChars(),
-            e1->type->toChars(), e2->type->toChars());
+            e1->toChars(), Token::toChars(thisOp), e2->toChars(), ts[0], ts[1]);
     }
     return new ErrorExp();
 }
@@ -5693,9 +4119,36 @@  Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *)
 
 /************************************************************/
 
-CompileExp::CompileExp(Loc loc, Expression *e)
-        : UnaExp(loc, TOKmixin, sizeof(CompileExp), e)
+CompileExp::CompileExp(Loc loc, Expressions *exps)
+    : Expression(loc, TOKmixin, sizeof(CompileExp))
+{
+    this->exps = exps;
+}
+
+Expression *CompileExp::syntaxCopy()
+{
+    return new CompileExp(loc, arraySyntaxCopy(exps));
+}
+
+bool CompileExp::equals(RootObject *o)
 {
+    if (this == o)
+        return true;
+    if (o && o->dyncast() == DYNCAST_EXPRESSION && ((Expression *)o)->op == TOKmixin)
+    {
+        CompileExp *ce = (CompileExp *)o;
+        if (exps->length != ce->exps->length)
+            return false;
+        for (size_t i = 0; i < exps->length; i++)
+        {
+            Expression *e1 = (*exps)[i];
+            Expression *e2 = (*ce->exps)[i];
+            if (e1 != e2 && (!e1 || !e2 || !e1->equals(e2)))
+                return false;
+        }
+        return true;
+    }
+    return false;
 }
 
 /************************************************************/
@@ -6362,64 +4815,6 @@  ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1)
 {
 }
 
-Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2)
-{   Expression *e;
-
-    switch (op)
-    {
-        case TOKaddass:   e = new AddExp(loc, e1, e2);  break;
-        case TOKminass:   e = new MinExp(loc, e1, e2);  break;
-        case TOKmulass:   e = new MulExp(loc, e1, e2);  break;
-        case TOKdivass:   e = new DivExp(loc, e1, e2);  break;
-        case TOKmodass:   e = new ModExp(loc, e1, e2);  break;
-        case TOKandass:   e = new AndExp(loc, e1, e2);  break;
-        case TOKorass:    e = new OrExp (loc, e1, e2);  break;
-        case TOKxorass:   e = new XorExp(loc, e1, e2);  break;
-        case TOKshlass:   e = new ShlExp(loc, e1, e2);  break;
-        case TOKshrass:   e = new ShrExp(loc, e1, e2);  break;
-        case TOKushrass:  e = new UshrExp(loc, e1, e2); break;
-        default:        assert(0);
-    }
-    return e;
-}
-
-/*********************
- * Rewrite:
- *    array.length op= e2
- * as:
- *    array.length = array.length op e2
- * or:
- *    auto tmp = &array;
- *    (*tmp).length = (*tmp).length op e2
- */
-
-Expression *ArrayLengthExp::rewriteOpAssign(BinExp *exp)
-{
-    Expression *e;
-
-    assert(exp->e1->op == TOKarraylength);
-    ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
-    if (ale->e1->op == TOKvar)
-    {
-        e = opAssignToOp(exp->loc, exp->op, ale, exp->e2);
-        e = new AssignExp(exp->loc, ale->syntaxCopy(), e);
-    }
-    else
-    {
-        /*    auto tmp = &array;
-         *    (*tmp).length = (*tmp).length op e2
-         */
-        VarDeclaration *tmp = copyToTemp(0, "__arraylength", new AddrExp(ale->loc, ale->e1));
-
-        Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp)));
-        Expression *elvalue = e1->syntaxCopy();
-        e = opAssignToOp(exp->loc, exp->op, e1, exp->e2);
-        e = new AssignExp(exp->loc, elvalue, e);
-        e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e);
-    }
-    return e;
-}
-
 /*********************** IntervalExp ********************************/
 
 // Mainly just a placeholder
@@ -7248,203 +5643,6 @@  Expression *PrettyFuncInitExp::resolveLoc(Loc loc, Scope *sc)
     return e;
 }
 
-/****************************************************************/
-
-Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue)
-{
-    Expression *e0;
-    Expression *e1 = Expression::extractLast(ue->e1, &e0);
-    // Bugzilla 12585: Extract the side effect part if ue->e1 is comma.
-
-    if (!isTrivialExp(e1))
-    {
-        /* Even if opDollar is needed, 'e1' should be evaluate only once. So
-         * Rewrite:
-         *      e1.opIndex( ... use of $ ... )
-         *      e1.opSlice( ... use of $ ... )
-         * as:
-         *      (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
-         *      (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
-         */
-        e1 = extractSideEffect(sc, "__dop", &e0, e1, false);
-        assert(e1->op == TOKvar);
-        VarExp *ve = (VarExp *)e1;
-        ve->var->storage_class |= STCexptemp;     // lifetime limited to expression
-    }
-    ue->e1 = e1;
-    return e0;
-}
-
-/**************************************
- * Runs semantic on ae->arguments. Declares temporary variables
- * if '$' was used.
- */
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0)
-{
-    assert(!ae->lengthVar);
-
-    *pe0 = NULL;
-
-    AggregateDeclaration *ad = isAggregate(ae->e1->type);
-    Dsymbol *slice = search_function(ad, Id::slice);
-    //printf("slice = %s %s\n", slice->kind(), slice->toChars());
-
-    for (size_t i = 0; i < ae->arguments->length; i++)
-    {
-        if (i == 0)
-            *pe0 = extractOpDollarSideEffect(sc, ae);
-
-        Expression *e = (*ae->arguments)[i];
-        if (e->op == TOKinterval && !(slice && slice->isTemplateDeclaration()))
-        {
-        Lfallback:
-            if (ae->arguments->length == 1)
-                return NULL;
-            ae->error("multi-dimensional slicing requires template opSlice");
-            return new ErrorExp();
-        }
-        //printf("[%d] e = %s\n", i, e->toChars());
-
-        // Create scope for '$' variable for this dimension
-        ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
-        sym->loc = ae->loc;
-        sym->parent = sc->scopesym;
-        sc = sc->push(sym);
-        ae->lengthVar = NULL;       // Create it only if required
-        ae->currentDimension = i;   // Dimension for $, if required
-
-        e = expressionSemantic(e, sc);
-        e = resolveProperties(sc, e);
-
-        if (ae->lengthVar && sc->func)
-        {
-            // If $ was used, declare it now
-            Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
-            de = expressionSemantic(de, sc);
-            *pe0 = Expression::combine(*pe0, de);
-        }
-        sc = sc->pop();
-
-        if (e->op == TOKinterval)
-        {
-            IntervalExp *ie = (IntervalExp *)e;
-
-            Objects *tiargs = new Objects();
-            Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
-            edim = expressionSemantic(edim, sc);
-            tiargs->push(edim);
-
-            Expressions *fargs = new Expressions();
-            fargs->push(ie->lwr);
-            fargs->push(ie->upr);
-
-            unsigned xerrors = global.startGagging();
-            sc = sc->push();
-            FuncDeclaration *fslice = resolveFuncCall(ae->loc, sc, slice, tiargs, ae->e1->type, fargs, 1);
-            sc = sc->pop();
-            global.endGagging(xerrors);
-            if (!fslice)
-                goto Lfallback;
-
-            e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
-            e = new CallExp(ae->loc, e, fargs);
-            e = expressionSemantic(e, sc);
-        }
-
-        if (!e->type)
-        {
-            ae->error("%s has no value", e->toChars());
-            e = new ErrorExp();
-        }
-        if (e->op == TOKerror)
-            return e;
-
-        (*ae->arguments)[i] = e;
-    }
-
-    return ae;
-}
-
-/***********************************************************
- * Resolve `exp` as a compile-time known string.
- * Params:
- *  sc  = scope
- *  exp = Expression which expected as a string
- *  s   = What the string is expected for, will be used in error diagnostic.
- * Returns:
- *  String literal, or `null` if error happens.
- */
-StringExp *semanticString(Scope *sc, Expression *exp, const char *s)
-{
-    sc = sc->startCTFE();
-    exp = expressionSemantic(exp, sc);
-    exp = resolveProperties(sc, exp);
-    sc = sc->endCTFE();
-
-    if (exp->op == TOKerror)
-        return NULL;
-
-    Expression *e = exp;
-    if (exp->type->isString())
-    {
-        e = e->ctfeInterpret();
-        if (e->op == TOKerror)
-            return NULL;
-    }
-
-    StringExp *se = e->toStringExp();
-    if (!se)
-    {
-        exp->error("string expected for %s, not (%s) of type %s",
-            s, exp->toChars(), exp->type->toChars());
-        return NULL;
-    }
-    return se;
-}
-
-/**************************************
- * Runs semantic on se->lwr and se->upr. Declares a temporary variable
- * if '$' was used.
- */
-Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0)
-{
-    //assert(!ae->lengthVar);
-    if (!ie)
-        return ae;
-
-    VarDeclaration *lengthVar = ae->lengthVar;
-
-    // create scope for '$'
-    ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
-    sym->loc = ae->loc;
-    sym->parent = sc->scopesym;
-    sc = sc->push(sym);
-
-    for (size_t i = 0; i < 2; ++i)
-    {
-        Expression *e = i == 0 ? ie->lwr : ie->upr;
-        e = expressionSemantic(e, sc);
-        e = resolveProperties(sc, e);
-        if (!e->type)
-        {
-            ae->error("%s has no value", e->toChars());
-            return new ErrorExp();
-        }
-        (i == 0 ? ie->lwr : ie->upr) = e;
-    }
-
-    if (lengthVar != ae->lengthVar && sc->func)
-    {
-        // If $ was used, declare it now
-        Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
-        de = expressionSemantic(de, sc);
-        *pe0 = Expression::combine(*pe0, de);
-    }
-    sc = sc->pop();
-
-    return ae;
-}
-
 Expression *BinExp::reorderSettingAAElem(Scope *sc)
 {
     BinExp *be = this;
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index f0ae2805df4..2ed8fac373e 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -883,10 +883,14 @@  public:
 
 /****************************************************************/
 
-class CompileExp : public UnaExp
+class CompileExp : public Expression
 {
 public:
-    CompileExp(Loc loc, Expression *e);
+    Expressions *exps;
+
+    CompileExp(Loc loc, Expressions *exps);
+    Expression *syntaxCopy();
+    bool equals(RootObject *o);
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -1124,7 +1128,6 @@  class ArrayLengthExp : public UnaExp
 public:
     ArrayLengthExp(Loc loc, Expression *e1);
 
-    static Expression *rewriteOpAssign(BinExp *exp);
     void accept(Visitor *v) { v->visit(this); }
 };
 
diff --git a/gcc/d/dmd/expressionsem.c b/gcc/d/dmd/expressionsem.c
index 7cccd956966..4a37d0fcba2 100644
--- a/gcc/d/dmd/expressionsem.c
+++ b/gcc/d/dmd/expressionsem.c
@@ -47,26 +47,1252 @@  bool symbolIsVisible(Scope *sc, Dsymbol *s);
 VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
 Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expression *e, bool alwaysCopy = false);
 Type *getTypeInfoType(Loc loc, Type *t, Scope *sc);
+char *MODtoChars(MOD mod);
 bool MODimplicitConv(MOD modfrom, MOD modto);
+MOD MODmerge(MOD mod1, MOD mod2);
 MATCH MODmethodConv(MOD modfrom, MOD modto);
 void MODMatchToBuffer(OutBuffer *buf, unsigned char lhsMod, unsigned char rhsMod);
 
 void unSpeculative(Scope *sc, RootObject *o);
-bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt);
-bool checkDefCtor(Loc loc, Type *t);
 bool isDotOpDispatch(Expression *e);
-bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix);
-Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, Expression *e1, Declaration *var, int flag = 0);
 bool isNeedThisScope(Scope *sc, Declaration *d);
-Expression *resolveUFCS(Scope *sc, CallExp *ce);
 bool checkUnsafeAccess(Scope *sc, Expression *e, bool readonly, bool printmsg);
 bool isSafeCast(Expression *e, Type *tfrom, Type *tto);
 FuncDeclaration *isFuncAddress(Expression *e, bool *hasOverloads = NULL);
 Expression *callCpCtor(Scope *sc, Expression *e);
 
 Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
-Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL);
-Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL);
+
+bool checkPrintfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list);
+bool checkScanfFormat(const Loc &loc, const char *format, Expressions &args, bool isVa_list);
+
+/********************************************************
+ * Perform semantic analysis and CTFE on expressions to produce
+ * a string.
+ * Params:
+ *      buf = append generated string to buffer
+ *      sc = context
+ *      exps = array of Expressions
+ * Returns:
+ *      true on error
+ */
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps)
+{
+    if (!exps)
+        return false;
+
+    for (size_t i = 0; i < exps->length; i++)
+    {
+        Expression *ex = (*exps)[i];
+        if (!ex)
+            continue;
+        Scope *sc2 = sc->startCTFE();
+        Expression *e2 = expressionSemantic(ex, sc2);
+        Expression *e3 = resolveProperties(sc2, e2);
+        sc2->endCTFE();
+
+        // allowed to contain types as well as expressions
+        Expression *e4 = ctfeInterpretForPragmaMsg(e3);
+        if (!e4 || e4->op == TOKerror)
+            return true;
+
+        // expand tuple
+        if (TupleExp *te = e4->isTupleExp())
+        {
+            if (expressionsToString(buf, sc, te->exps))
+                return true;
+            continue;
+        }
+        // char literals exp `.toStringExp` return `null` but we cant override it
+        // because in most contexts we don't want the conversion to succeed.
+        IntegerExp *ie = e4->isIntegerExp();
+        const TY ty = (ie && ie->type) ? ie->type->ty : (TY)Terror;
+        if (ty == Tchar || ty == Twchar || ty == Tdchar)
+        {
+            TypeSArray *tsa = new TypeSArray(ie->type, new IntegerExp(ex->loc, 1, Type::tint32));
+            e4 = new ArrayLiteralExp(ex->loc, tsa, ie);
+        }
+
+        if (StringExp *se = e4->toStringExp())
+            buf.writestring(se->toUTF8(sc)->toPtr());
+        else
+            buf.writestring(e4->toChars());
+    }
+    return false;
+}
+
+/***********************************************************
+ * Resolve `exp` as a compile-time known string.
+ * Params:
+ *  sc  = scope
+ *  exp = Expression which expected as a string
+ *  s   = What the string is expected for, will be used in error diagnostic.
+ * Returns:
+ *  String literal, or `null` if error happens.
+ */
+StringExp *semanticString(Scope *sc, Expression *exp, const char *s)
+{
+    sc = sc->startCTFE();
+    exp = expressionSemantic(exp, sc);
+    exp = resolveProperties(sc, exp);
+    sc = sc->endCTFE();
+
+    if (exp->op == TOKerror)
+        return NULL;
+
+    Expression *e = exp;
+    if (exp->type->isString())
+    {
+        e = e->ctfeInterpret();
+        if (e->op == TOKerror)
+            return NULL;
+    }
+
+    StringExp *se = e->toStringExp();
+    if (!se)
+    {
+        exp->error("string expected for %s, not (%s) of type %s",
+            s, exp->toChars(), exp->type->toChars());
+        return NULL;
+    }
+    return se;
+}
+
+/****************************************************************/
+
+static Expression *extractOpDollarSideEffect(Scope *sc, UnaExp *ue)
+{
+    Expression *e0;
+    Expression *e1 = Expression::extractLast(ue->e1, &e0);
+    // Bugzilla 12585: Extract the side effect part if ue->e1 is comma.
+
+    if (!isTrivialExp(e1))
+    {
+        /* Even if opDollar is needed, 'e1' should be evaluate only once. So
+         * Rewrite:
+         *      e1.opIndex( ... use of $ ... )
+         *      e1.opSlice( ... use of $ ... )
+         * as:
+         *      (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
+         *      (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
+         */
+        e1 = extractSideEffect(sc, "__dop", &e0, e1, false);
+        assert(e1->op == TOKvar);
+        VarExp *ve = (VarExp *)e1;
+        ve->var->storage_class |= STCexptemp;     // lifetime limited to expression
+    }
+    ue->e1 = e1;
+    return e0;
+}
+
+/**************************************
+ * Runs semantic on ae->arguments. Declares temporary variables
+ * if '$' was used.
+ */
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, Expression **pe0)
+{
+    assert(!ae->lengthVar);
+
+    *pe0 = NULL;
+
+    AggregateDeclaration *ad = isAggregate(ae->e1->type);
+    Dsymbol *slice = search_function(ad, Id::slice);
+    //printf("slice = %s %s\n", slice->kind(), slice->toChars());
+
+    for (size_t i = 0; i < ae->arguments->length; i++)
+    {
+        if (i == 0)
+            *pe0 = extractOpDollarSideEffect(sc, ae);
+
+        Expression *e = (*ae->arguments)[i];
+        if (e->op == TOKinterval && !(slice && slice->isTemplateDeclaration()))
+        {
+        Lfallback:
+            if (ae->arguments->length == 1)
+                return NULL;
+            ae->error("multi-dimensional slicing requires template opSlice");
+            return new ErrorExp();
+        }
+        //printf("[%d] e = %s\n", i, e->toChars());
+
+        // Create scope for '$' variable for this dimension
+        ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
+        sym->loc = ae->loc;
+        sym->parent = sc->scopesym;
+        sc = sc->push(sym);
+        ae->lengthVar = NULL;       // Create it only if required
+        ae->currentDimension = i;   // Dimension for $, if required
+
+        e = expressionSemantic(e, sc);
+        e = resolveProperties(sc, e);
+
+        if (ae->lengthVar && sc->func)
+        {
+            // If $ was used, declare it now
+            Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
+            de = expressionSemantic(de, sc);
+            *pe0 = Expression::combine(*pe0, de);
+        }
+        sc = sc->pop();
+
+        if (e->op == TOKinterval)
+        {
+            IntervalExp *ie = (IntervalExp *)e;
+
+            Objects *tiargs = new Objects();
+            Expression *edim = new IntegerExp(ae->loc, i, Type::tsize_t);
+            edim = expressionSemantic(edim, sc);
+            tiargs->push(edim);
+
+            Expressions *fargs = new Expressions();
+            fargs->push(ie->lwr);
+            fargs->push(ie->upr);
+
+            unsigned xerrors = global.startGagging();
+            sc = sc->push();
+            FuncDeclaration *fslice = resolveFuncCall(ae->loc, sc, slice, tiargs, ae->e1->type, fargs, 1);
+            sc = sc->pop();
+            global.endGagging(xerrors);
+            if (!fslice)
+                goto Lfallback;
+
+            e = new DotTemplateInstanceExp(ae->loc, ae->e1, slice->ident, tiargs);
+            e = new CallExp(ae->loc, e, fargs);
+            e = expressionSemantic(e, sc);
+        }
+
+        if (!e->type)
+        {
+            ae->error("%s has no value", e->toChars());
+            e = new ErrorExp();
+        }
+        if (e->op == TOKerror)
+            return e;
+
+        (*ae->arguments)[i] = e;
+    }
+
+    return ae;
+}
+
+/**************************************
+ * Runs semantic on se->lwr and se->upr. Declares a temporary variable
+ * if '$' was used.
+ */
+Expression *resolveOpDollar(Scope *sc, ArrayExp *ae, IntervalExp *ie, Expression **pe0)
+{
+    //assert(!ae->lengthVar);
+    if (!ie)
+        return ae;
+
+    VarDeclaration *lengthVar = ae->lengthVar;
+
+    // create scope for '$'
+    ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae);
+    sym->loc = ae->loc;
+    sym->parent = sc->scopesym;
+    sc = sc->push(sym);
+
+    for (size_t i = 0; i < 2; ++i)
+    {
+        Expression *e = i == 0 ? ie->lwr : ie->upr;
+        e = expressionSemantic(e, sc);
+        e = resolveProperties(sc, e);
+        if (!e->type)
+        {
+            ae->error("%s has no value", e->toChars());
+            return new ErrorExp();
+        }
+        (i == 0 ? ie->lwr : ie->upr) = e;
+    }
+
+    if (lengthVar != ae->lengthVar && sc->func)
+    {
+        // If $ was used, declare it now
+        Expression *de = new DeclarationExp(ae->loc, ae->lengthVar);
+        de = expressionSemantic(de, sc);
+        *pe0 = Expression::combine(*pe0, de);
+    }
+    sc = sc->pop();
+
+    return ae;
+}
+
+/******************************
+ * Perform semantic() on an array of Expressions.
+ */
+
+bool arrayExpressionSemantic(Expressions *exps, Scope *sc, bool preserveErrors)
+{
+    bool err = false;
+    if (exps)
+    {
+        for (size_t i = 0; i < exps->length; i++)
+        {
+            Expression *e = (*exps)[i];
+            if (e)
+            {
+                e = expressionSemantic(e, sc);
+                if (e->op == TOKerror)
+                    err = true;
+                if (preserveErrors || e->op != TOKerror)
+                    (*exps)[i] = e;
+            }
+        }
+    }
+    return err;
+}
+
+/******************************
+ * Check the tail CallExp is really property function call.
+ */
+static bool checkPropertyCall(Expression *e)
+{
+    while (e->op == TOKcomma)
+        e = ((CommaExp *)e)->e2;
+
+    if (e->op == TOKcall)
+    {
+        CallExp *ce = (CallExp *)e;
+        TypeFunction *tf;
+        if (ce->f)
+        {
+            tf = (TypeFunction *)ce->f->type;
+            /* If a forward reference to ce->f, try to resolve it
+             */
+            if (!tf->deco && ce->f->semanticRun < PASSsemanticdone)
+            {
+                dsymbolSemantic(ce->f, NULL);
+                tf = (TypeFunction *)ce->f->type;
+            }
+        }
+        else if (ce->e1->type->ty == Tfunction)
+            tf = (TypeFunction *)ce->e1->type;
+        else if (ce->e1->type->ty == Tdelegate)
+            tf = (TypeFunction *)ce->e1->type->nextOf();
+        else if (ce->e1->type->ty == Tpointer && ce->e1->type->nextOf()->ty == Tfunction)
+            tf = (TypeFunction *)ce->e1->type->nextOf();
+        else
+            assert(0);
+    }
+    return false;
+}
+
+// TODO: merge with Scope::search::searchScopes()
+static Dsymbol *searchScopes(Scope *sc, Loc loc, Identifier *ident, int flags)
+{
+    Dsymbol *s = NULL;
+    for (Scope *scx = sc; scx; scx = scx->enclosing)
+    {
+        if (!scx->scopesym)
+            continue;
+        if (scx->scopesym->isModule())
+            flags |= SearchUnqualifiedModule;    // tell Module.search() that SearchLocalsOnly is to be obeyed
+        s = scx->scopesym->search(loc, ident, flags);
+        if (s)
+        {
+            // overload set contains only module scope symbols.
+            if (s->isOverloadSet())
+                break;
+            // selective/renamed imports also be picked up
+            if (AliasDeclaration *ad = s->isAliasDeclaration())
+            {
+                if (ad->_import)
+                    break;
+            }
+            // See only module scope symbols for UFCS target.
+            Dsymbol *p = s->toParent2();
+            if (p && p->isModule())
+                break;
+        }
+        s = NULL;
+
+        // Stop when we hit a module, but keep going if that is not just under the global scope
+        if (scx->scopesym->isModule() && !(scx->enclosing && !scx->enclosing->enclosing))
+            break;
+    }
+    return s;
+}
+
+/******************************
+ * Find symbol in accordance with the UFCS name look up rule
+ */
+
+static Expression *searchUFCS(Scope *sc, UnaExp *ue, Identifier *ident)
+{
+    //printf("searchUFCS(ident = %s)\n", ident->toChars());
+    Loc loc = ue->loc;
+    int flags = 0;
+    Dsymbol *s = NULL;
+
+    if (sc->flags & SCOPEignoresymbolvisibility)
+        flags |= IgnoreSymbolVisibility;
+
+    // First look in local scopes
+    s = searchScopes(sc, loc, ident, flags | SearchLocalsOnly);
+    if (!s)
+    {
+        // Second look in imported modules
+        s = searchScopes(sc, loc, ident, flags | SearchImportsOnly);
+    }
+
+    if (!s)
+        return ue->e1->type->Type::getProperty(loc, ident, 0);
+
+    FuncDeclaration *f = s->isFuncDeclaration();
+    if (f)
+    {
+        TemplateDeclaration *td = getFuncTemplateDecl(f);
+        if (td)
+        {
+            if (td->overroot)
+                td = td->overroot;
+            s = td;
+        }
+    }
+
+    if (ue->op == TOKdotti)
+    {
+        DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ue;
+        TemplateInstance *ti = new TemplateInstance(loc, s->ident);
+        ti->tiargs = dti->ti->tiargs;   // for better diagnostic message
+        if (!ti->updateTempDecl(sc, s))
+            return new ErrorExp();
+        return new ScopeExp(loc, ti);
+    }
+    else
+    {
+        //printf("-searchUFCS() %s\n", s->toChars());
+        return new DsymbolExp(loc, s);
+    }
+}
+
+/******************************
+ * Pull out callable entity with UFCS.
+ */
+
+static Expression *resolveUFCS(Scope *sc, CallExp *ce)
+{
+    Loc loc = ce->loc;
+    Expression *eleft;
+    Expression *e;
+
+    if (ce->e1->op == TOKdotid)
+    {
+        DotIdExp *die = (DotIdExp *)ce->e1;
+        Identifier *ident = die->ident;
+
+        Expression *ex = semanticX(die, sc);
+        if (ex != die)
+        {
+            ce->e1 = ex;
+            return NULL;
+        }
+        eleft = die->e1;
+
+        Type *t = eleft->type->toBasetype();
+        if (t->ty == Tarray || t->ty == Tsarray ||
+            t->ty == Tnull  || (t->isTypeBasic() && t->ty != Tvoid))
+        {
+            /* Built-in types and arrays have no callable properties, so do shortcut.
+             * It is necessary in: e.init()
+             */
+        }
+        else if (t->ty == Taarray)
+        {
+            if (ident == Id::remove)
+            {
+                /* Transform:
+                 *  aa.remove(arg) into delete aa[arg]
+                 */
+                if (!ce->arguments || ce->arguments->length != 1)
+                {
+                    ce->error("expected key as argument to aa.remove()");
+                    return new ErrorExp();
+                }
+                if (!eleft->type->isMutable())
+                {
+                    ce->error("cannot remove key from %s associative array %s",
+                            MODtoChars(t->mod), eleft->toChars());
+                    return new ErrorExp();
+                }
+                Expression *key = (*ce->arguments)[0];
+                key = expressionSemantic(key, sc);
+                key = resolveProperties(sc, key);
+
+                TypeAArray *taa = (TypeAArray *)t;
+                key = key->implicitCastTo(sc, taa->index);
+
+                if (key->checkValue())
+                    return new ErrorExp();
+
+                semanticTypeInfo(sc, taa->index);
+
+                return new RemoveExp(loc, eleft, key);
+            }
+        }
+        else
+        {
+            if (Expression *ey = semanticY(die, sc, 1))
+            {
+                if (ey->op == TOKerror)
+                    return ey;
+                ce->e1 = ey;
+                if (isDotOpDispatch(ey))
+                {
+                    unsigned errors = global.startGagging();
+                    e = expressionSemantic(ce->syntaxCopy(), sc);
+                    if (!global.endGagging(errors))
+                        return e;
+                    /* fall down to UFCS */
+                }
+                else
+                    return NULL;
+            }
+        }
+        e = searchUFCS(sc, die, ident);
+    }
+    else if (ce->e1->op == TOKdotti)
+    {
+        DotTemplateInstanceExp *dti = (DotTemplateInstanceExp *)ce->e1;
+        if (Expression *ey = semanticY(dti, sc, 1))
+        {
+            ce->e1 = ey;
+            return NULL;
+        }
+        eleft = dti->e1;
+        e = searchUFCS(sc, dti, dti->ti->name);
+    }
+    else
+        return NULL;
+
+    // Rewrite
+    ce->e1 = e;
+    if (!ce->arguments)
+        ce->arguments = new Expressions();
+    ce->arguments->shift(eleft);
+
+    return NULL;
+}
+
+/******************************
+ * Pull out property with UFCS.
+ */
+
+static Expression *resolveUFCSProperties(Scope *sc, Expression *e1, Expression *e2 = NULL)
+{
+    Loc loc = e1->loc;
+    Expression *eleft;
+    Expression *e;
+
+    if (e1->op == TOKdotid)
+    {
+        DotIdExp *die = (DotIdExp *)e1;
+        eleft = die->e1;
+        e = searchUFCS(sc, die, die->ident);
+    }
+    else if (e1->op == TOKdotti)
+    {
+        DotTemplateInstanceExp *dti;
+        dti = (DotTemplateInstanceExp *)e1;
+        eleft = dti->e1;
+        e = searchUFCS(sc, dti, dti->ti->name);
+    }
+    else
+        return NULL;
+
+    if (e == NULL)
+        return NULL;
+
+    // Rewrite
+    if (e2)
+    {
+        // run semantic without gagging
+        e2 = expressionSemantic(e2, sc);
+
+        /* f(e1) = e2
+         */
+        Expression *ex = e->copy();
+        Expressions *a1 = new Expressions();
+        a1->setDim(1);
+        (*a1)[0] = eleft;
+        ex = new CallExp(loc, ex, a1);
+        ex = trySemantic(ex, sc);
+
+        /* f(e1, e2)
+         */
+        Expressions *a2 = new Expressions();
+        a2->setDim(2);
+        (*a2)[0] = eleft;
+        (*a2)[1] = e2;
+        e = new CallExp(loc, e, a2);
+        if (ex)
+        {   // if fallback setter exists, gag errors
+            e = trySemantic(e, sc);
+            if (!e)
+            {   checkPropertyCall(ex);
+                ex = new AssignExp(loc, ex, e2);
+                return expressionSemantic(ex, sc);
+            }
+        }
+        else
+        {   // strict setter prints errors if fails
+            e = expressionSemantic(e, sc);
+        }
+        checkPropertyCall(e);
+        return e;
+    }
+    else
+    {
+        /* f(e1)
+         */
+        Expressions *arguments = new Expressions();
+        arguments->setDim(1);
+        (*arguments)[0] = eleft;
+        e = new CallExp(loc, e, arguments);
+        e = expressionSemantic(e, sc);
+        checkPropertyCall(e);
+        return expressionSemantic(e, sc);
+    }
+}
+
+/******************************
+ * If e1 is a property function (template), resolve it.
+ */
+
+Expression *resolvePropertiesOnly(Scope *sc, Expression *e1)
+{
+    //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars());
+    OverloadSet *os;
+    FuncDeclaration *fd;
+    TemplateDeclaration *td;
+
+    if (e1->op == TOKdot)
+    {
+        DotExp *de = (DotExp *)e1;
+        if (de->e2->op == TOKoverloadset)
+        {
+            os = ((OverExp *)de->e2)->vars;
+            goto Los;
+        }
+    }
+    else if (e1->op == TOKoverloadset)
+    {
+        os = ((OverExp *)e1)->vars;
+    Los:
+        assert(os);
+        for (size_t i = 0; i < os->a.length; i++)
+        {
+            Dsymbol *s = os->a[i];
+            fd = s->isFuncDeclaration();
+            td = s->isTemplateDeclaration();
+            if (fd)
+            {
+                if (((TypeFunction *)fd->type)->isproperty)
+                    return resolveProperties(sc, e1);
+            }
+            else if (td && td->onemember &&
+                     (fd = td->onemember->isFuncDeclaration()) != NULL)
+            {
+                if (((TypeFunction *)fd->type)->isproperty ||
+                    (fd->storage_class2 & STCproperty) ||
+                    (td->_scope->stc & STCproperty))
+                {
+                    return resolveProperties(sc, e1);
+                }
+            }
+        }
+    }
+    else if (e1->op == TOKdotti)
+    {
+        DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
+        if (dti->ti->tempdecl && (td = dti->ti->tempdecl->isTemplateDeclaration()) != NULL)
+            goto Ltd;
+    }
+    else if (e1->op == TOKdottd)
+    {
+        td = ((DotTemplateExp *)e1)->td;
+        goto Ltd;
+    }
+    else if (e1->op == TOKscope)
+    {
+        Dsymbol *s = ((ScopeExp *)e1)->sds;
+        TemplateInstance *ti = s->isTemplateInstance();
+        if (ti && !ti->semanticRun && ti->tempdecl)
+        {
+            if ((td = ti->tempdecl->isTemplateDeclaration()) != NULL)
+                goto Ltd;
+        }
+    }
+    else if (e1->op == TOKtemplate)
+    {
+        td = ((TemplateExp *)e1)->td;
+    Ltd:
+        assert(td);
+        if (td->onemember &&
+            (fd = td->onemember->isFuncDeclaration()) != NULL)
+        {
+            if (((TypeFunction *)fd->type)->isproperty ||
+                (fd->storage_class2 & STCproperty) ||
+                (td->_scope->stc & STCproperty))
+            {
+                return resolveProperties(sc, e1);
+            }
+        }
+    }
+    else if (e1->op == TOKdotvar && e1->type->ty == Tfunction)
+    {
+        DotVarExp *dve = (DotVarExp *)e1;
+        fd = dve->var->isFuncDeclaration();
+        goto Lfd;
+    }
+    else if (e1->op == TOKvar && e1->type->ty == Tfunction &&
+        (sc->intypeof || !((VarExp *)e1)->var->needThis()))
+    {
+        fd = ((VarExp *)e1)->var->isFuncDeclaration();
+    Lfd:
+        assert(fd);
+        if (((TypeFunction *)fd->type)->isproperty)
+            return resolveProperties(sc, e1);
+    }
+    return e1;
+}
+
+/*************************************************************
+ * Given var, we need to get the
+ * right 'this' pointer if var is in an outer class, but our
+ * existing 'this' pointer is in an inner class.
+ * Input:
+ *      e1      existing 'this'
+ *      ad      struct or class we need the correct 'this' for
+ *      var     the specific member of ad we're accessing
+ */
+
+static Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
+        Expression *e1, Declaration *var, int flag = 0)
+{
+    //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
+ L1:
+    Type *t = e1->type->toBasetype();
+    //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
+
+    /* If e1 is not the 'this' pointer for ad
+     */
+    if (ad &&
+        !(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
+          ((TypeStruct *)t->nextOf())->sym == ad)
+        &&
+        !(t->ty == Tstruct &&
+          ((TypeStruct *)t)->sym == ad)
+       )
+    {
+        ClassDeclaration *cd = ad->isClassDeclaration();
+        ClassDeclaration *tcd = t->isClassHandle();
+
+        /* e1 is the right this if ad is a base class of e1
+         */
+        if (!cd || !tcd ||
+            !(tcd == cd || cd->isBaseOf(tcd, NULL))
+           )
+        {
+            /* Only classes can be inner classes with an 'outer'
+             * member pointing to the enclosing class instance
+             */
+            if (tcd && tcd->isNested())
+            {
+                /* e1 is the 'this' pointer for an inner class: tcd.
+                 * Rewrite it as the 'this' pointer for the outer class.
+                 */
+
+                e1 = new DotVarExp(loc, e1, tcd->vthis);
+                e1->type = tcd->vthis->type;
+                e1->type = e1->type->addMod(t->mod);
+                // Do not call checkNestedRef()
+                //e1 = expressionSemantic(e1, sc);
+
+                // Skip up over nested functions, and get the enclosing
+                // class type.
+                int n = 0;
+                Dsymbol *s;
+                for (s = tcd->toParent();
+                     s && s->isFuncDeclaration();
+                     s = s->toParent())
+                {
+                    FuncDeclaration *f = s->isFuncDeclaration();
+                    if (f->vthis)
+                    {
+                        //printf("rewriting e1 to %s's this\n", f->toChars());
+                        n++;
+                        e1 = new VarExp(loc, f->vthis);
+                    }
+                    else
+                    {
+                        e1->error("need `this` of type %s to access member %s"
+                                  " from static function %s",
+                            ad->toChars(), var->toChars(), f->toChars());
+                        e1 = new ErrorExp();
+                        return e1;
+                    }
+                }
+                if (s && s->isClassDeclaration())
+                {
+                    e1->type = s->isClassDeclaration()->type;
+                    e1->type = e1->type->addMod(t->mod);
+                    if (n > 1)
+                        e1 = expressionSemantic(e1, sc);
+                }
+                else
+                    e1 = expressionSemantic(e1, sc);
+                goto L1;
+            }
+
+            /* Can't find a path from e1 to ad
+             */
+            if (flag)
+                return NULL;
+            e1->error("this for %s needs to be type %s not type %s",
+                var->toChars(), ad->toChars(), t->toChars());
+            return new ErrorExp();
+        }
+    }
+    return e1;
+}
+
+/***************************************
+ * Pull out any properties.
+ */
+
+static Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
+{
+    //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token::toChars(e1->op), e1->toChars(), e2 ? e2->toChars() : NULL);
+    Loc loc = e1->loc;
+
+    OverloadSet *os;
+    Dsymbol *s;
+    Objects *tiargs;
+    Type *tthis;
+    if (e1->op == TOKdot)
+    {
+        DotExp *de = (DotExp *)e1;
+        if (de->e2->op == TOKoverloadset)
+        {
+            tiargs = NULL;
+            tthis  = de->e1->type;
+            os = ((OverExp *)de->e2)->vars;
+            goto Los;
+        }
+    }
+    else if (e1->op == TOKoverloadset)
+    {
+        tiargs = NULL;
+        tthis  = NULL;
+        os = ((OverExp *)e1)->vars;
+    Los:
+        assert(os);
+        FuncDeclaration *fd = NULL;
+        if (e2)
+        {
+            e2 = expressionSemantic(e2, sc);
+            if (e2->op == TOKerror)
+                return new ErrorExp();
+            e2 = resolveProperties(sc, e2);
+
+            Expressions a;
+            a.push(e2);
+
+            for (size_t i = 0; i < os->a.length; i++)
+            {
+                FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, &a, 1);
+                if (f)
+                {
+                    if (f->errors)
+                        return new ErrorExp();
+                    fd = f;
+                    assert(fd->type->ty == Tfunction);
+                }
+            }
+            if (fd)
+            {
+                Expression *e = new CallExp(loc, e1, e2);
+                return expressionSemantic(e, sc);
+            }
+        }
+        {
+            for (size_t i = 0; i < os->a.length; i++)
+            {
+                FuncDeclaration *f = resolveFuncCall(loc, sc, os->a[i], tiargs, tthis, NULL, 1);
+                if (f)
+                {
+                    if (f->errors)
+                        return new ErrorExp();
+                    fd = f;
+                    assert(fd->type->ty == Tfunction);
+                    TypeFunction *tf = (TypeFunction *)fd->type;
+                    if (!tf->isref && e2)
+                        goto Leproplvalue;
+                }
+            }
+            if (fd)
+            {
+                Expression *e = new CallExp(loc, e1);
+                if (e2)
+                    e = new AssignExp(loc, e, e2);
+                return expressionSemantic(e, sc);
+            }
+        }
+        if (e2)
+            goto Leprop;
+    }
+    else if (e1->op == TOKdotti)
+    {
+        DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1;
+        if (!dti->findTempDecl(sc))
+            goto Leprop;
+        if (!dti->ti->semanticTiargs(sc))
+            goto Leprop;
+        tiargs = dti->ti->tiargs;
+        tthis  = dti->e1->type;
+        if ((os = dti->ti->tempdecl->isOverloadSet()) != NULL)
+            goto Los;
+        if ((s = dti->ti->tempdecl) != NULL)
+            goto Lfd;
+    }
+    else if (e1->op == TOKdottd)
+    {
+        DotTemplateExp *dte = (DotTemplateExp *)e1;
+        s      = dte->td;
+        tiargs = NULL;
+        tthis  = dte->e1->type;
+        goto Lfd;
+    }
+    else if (e1->op == TOKscope)
+    {
+        s = ((ScopeExp *)e1)->sds;
+        TemplateInstance *ti = s->isTemplateInstance();
+        if (ti && !ti->semanticRun && ti->tempdecl)
+        {
+            //assert(ti->needsTypeInference(sc));
+            if (!ti->semanticTiargs(sc))
+                goto Leprop;
+            tiargs = ti->tiargs;
+            tthis  = NULL;
+            if ((os = ti->tempdecl->isOverloadSet()) != NULL)
+                goto Los;
+            if ((s = ti->tempdecl) != NULL)
+                goto Lfd;
+        }
+    }
+    else if (e1->op == TOKtemplate)
+    {
+        s      = ((TemplateExp *)e1)->td;
+        tiargs = NULL;
+        tthis  = NULL;
+        goto Lfd;
+    }
+    else if (e1->op == TOKdotvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+    {
+        DotVarExp *dve = (DotVarExp *)e1;
+        s      = dve->var->isFuncDeclaration();
+        tiargs = NULL;
+        tthis  = dve->e1->type;
+        goto Lfd;
+    }
+    else if (e1->op == TOKvar && e1->type && e1->type->toBasetype()->ty == Tfunction)
+    {
+        s      = ((VarExp *)e1)->var->isFuncDeclaration();
+        tiargs = NULL;
+        tthis  = NULL;
+    Lfd:
+        assert(s);
+        if (e2)
+        {
+            e2 = expressionSemantic(e2, sc);
+            if (e2->op == TOKerror)
+                return new ErrorExp();
+            e2 = resolveProperties(sc, e2);
+
+            Expressions a;
+            a.push(e2);
+
+            FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1);
+            if (fd && fd->type)
+            {
+                if (fd->errors)
+                    return new ErrorExp();
+                assert(fd->type->ty == Tfunction);
+                Expression *e = new CallExp(loc, e1, e2);
+                return expressionSemantic(e, sc);
+            }
+        }
+        {
+            FuncDeclaration *fd = resolveFuncCall(loc, sc, s, tiargs, tthis, NULL, 1);
+            if (fd && fd->type)
+            {
+                if (fd->errors)
+                    return new ErrorExp();
+                assert(fd->type->ty == Tfunction);
+                TypeFunction *tf = (TypeFunction *)fd->type;
+                if (!e2 || tf->isref)
+                {
+                    Expression *e = new CallExp(loc, e1);
+                    if (e2)
+                        e = new AssignExp(loc, e, e2);
+                    return expressionSemantic(e, sc);
+                }
+            }
+        }
+        if (FuncDeclaration *fd = s->isFuncDeclaration())
+        {
+            // Keep better diagnostic message for invalid property usage of functions
+            assert(fd->type->ty == Tfunction);
+            Expression *e = new CallExp(loc, e1, e2);
+            return expressionSemantic(e, sc);
+        }
+        if (e2)
+            goto Leprop;
+    }
+    if (e1->op == TOKvar)
+    {
+        VarExp *ve = (VarExp *)e1;
+        VarDeclaration *v = ve->var->isVarDeclaration();
+        if (v && ve->checkPurity(sc, v))
+            return new ErrorExp();
+    }
+    if (e2)
+        return NULL;
+
+    if (e1->type &&
+        e1->op != TOKtype)      // function type is not a property
+    {
+        /* Look for e1 being a lazy parameter; rewrite as delegate call
+         */
+        if (e1->op == TOKvar)
+        {
+            VarExp *ve = (VarExp *)e1;
+
+            if (ve->var->storage_class & STClazy)
+            {
+                Expression *e = new CallExp(loc, e1);
+                return expressionSemantic(e, sc);
+            }
+        }
+        else if (e1->op == TOKdotvar)
+        {
+            // Check for reading overlapped pointer field in @safe code.
+            if (checkUnsafeAccess(sc, e1, true, true))
+                return new ErrorExp();
+        }
+        else if (e1->op == TOKdot)
+        {
+            e1->error("expression has no value");
+            return new ErrorExp();
+        }
+        else if (e1->op == TOKcall)
+        {
+            CallExp *ce = (CallExp *)e1;
+            // Check for reading overlapped pointer field in @safe code.
+            if (checkUnsafeAccess(sc, ce->e1, true, true))
+                return new ErrorExp();
+        }
+    }
+
+    if (!e1->type)
+    {
+        error(loc, "cannot resolve type for %s", e1->toChars());
+        e1 = new ErrorExp();
+    }
+    return e1;
+
+Leprop:
+    error(loc, "not a property %s", e1->toChars());
+    return new ErrorExp();
+
+Leproplvalue:
+    error(loc, "%s is not an lvalue", e1->toChars());
+    return new ErrorExp();
+}
+
+Expression *resolveProperties(Scope *sc, Expression *e)
+{
+    //printf("resolveProperties(%s)\n", e->toChars());
+
+    e = resolvePropertiesX(sc, e);
+    if (e->checkRightThis(sc))
+        return new ErrorExp();
+    return e;
+}
+
+/****************************************
+ * The common type is determined by applying ?: to each pair.
+ * Output:
+ *      exps[]  properties resolved, implicitly cast to common type, rewritten in place
+ *      *pt     if pt is not NULL, set to the common type
+ * Returns:
+ *      true    a semantic error was detected
+ */
+
+static bool arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
+{
+    /* Still have a problem with:
+     *  ubyte[][] = [ cast(ubyte[])"hello", [1]];
+     * which works if the array literal is initialized top down with the ubyte[][]
+     * type, but fails with this function doing bottom up typing.
+     */
+    //printf("arrayExpressionToCommonType()\n");
+    IntegerExp integerexp(0);
+    CondExp condexp(Loc(), &integerexp, NULL, NULL);
+
+    Type *t0 = NULL;
+    Expression *e0 = NULL;      // dead-store to prevent spurious warning
+    size_t j0 = ~0;             // dead-store to prevent spurious warning
+    bool foundType = false;
+
+    for (size_t i = 0; i < exps->length; i++)
+    {
+        Expression *e = (*exps)[i];
+        if (!e)
+            continue;
+
+        e = resolveProperties(sc, e);
+        if (!e->type)
+        {
+            e->error("%s has no value", e->toChars());
+            t0 = Type::terror;
+            continue;
+        }
+        if (e->op == TOKtype)
+        {
+            foundType = true;   // do not break immediately, there might be more errors
+            e->checkValue();    // report an error "type T has no value"
+            t0 = Type::terror;
+            continue;
+        }
+        if (e->type->ty == Tvoid)
+        {
+            // void expressions do not concur to the determination of the common
+            // type.
+            continue;
+        }
+        if (checkNonAssignmentArrayOp(e))
+        {
+            t0 = Type::terror;
+            continue;
+        }
+
+        e = doCopyOrMove(sc, e);
+
+        if (!foundType && t0 && !t0->equals(e->type))
+        {
+            /* This applies ?: to merge the types. It's backwards;
+             * ?: should call this function to merge types.
+             */
+            condexp.type = NULL;
+            condexp.e1 = e0;
+            condexp.e2 = e;
+            condexp.loc = e->loc;
+            Expression *ex = expressionSemantic(&condexp, sc);
+            if (ex->op == TOKerror)
+                e = ex;
+            else
+            {
+                (*exps)[j0] = condexp.e1;
+                e = condexp.e2;
+            }
+        }
+        j0 = i;
+        e0 = e;
+        t0 = e->type;
+        if (e->op != TOKerror)
+            (*exps)[i] = e;
+    }
+
+    if (!t0)
+        t0 = Type::tvoid;               // [] is typed as void[]
+    else if (t0->ty != Terror)
+    {
+        for (size_t i = 0; i < exps->length; i++)
+        {
+            Expression *e = (*exps)[i];
+            if (!e)
+                continue;
+
+            e = e->implicitCastTo(sc, t0);
+            //assert(e->op != TOKerror);
+            if (e->op == TOKerror)
+            {
+                /* Bugzilla 13024: a workaround for the bug in typeMerge -
+                 * it should paint e1 and e2 by deduced common type,
+                 * but doesn't in this particular case.
+                 */
+                t0 = Type::terror;
+                break;
+            }
+            (*exps)[i] = e;
+        }
+    }
+    if (pt)
+        *pt = t0;
+
+    return (t0 == Type::terror);
+}
+
+static Expression *opAssignToOp(Loc loc, TOK op, Expression *e1, Expression *e2)
+{   Expression *e;
+
+    switch (op)
+    {
+        case TOKaddass:   e = new AddExp(loc, e1, e2);  break;
+        case TOKminass:   e = new MinExp(loc, e1, e2);  break;
+        case TOKmulass:   e = new MulExp(loc, e1, e2);  break;
+        case TOKdivass:   e = new DivExp(loc, e1, e2);  break;
+        case TOKmodass:   e = new ModExp(loc, e1, e2);  break;
+        case TOKandass:   e = new AndExp(loc, e1, e2);  break;
+        case TOKorass:    e = new OrExp (loc, e1, e2);  break;
+        case TOKxorass:   e = new XorExp(loc, e1, e2);  break;
+        case TOKshlass:   e = new ShlExp(loc, e1, e2);  break;
+        case TOKshrass:   e = new ShrExp(loc, e1, e2);  break;
+        case TOKushrass:  e = new UshrExp(loc, e1, e2); break;
+        default:        assert(0);
+    }
+    return e;
+}
+
+/*********************
+ * Rewrite:
+ *    array.length op= e2
+ * as:
+ *    array.length = array.length op e2
+ * or:
+ *    auto tmp = &array;
+ *    (*tmp).length = (*tmp).length op e2
+ */
+
+static Expression *rewriteOpAssign(BinExp *exp)
+{
+    Expression *e;
+
+    assert(exp->e1->op == TOKarraylength);
+    ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1;
+    if (ale->e1->op == TOKvar)
+    {
+        e = opAssignToOp(exp->loc, exp->op, ale, exp->e2);
+        e = new AssignExp(exp->loc, ale->syntaxCopy(), e);
+    }
+    else
+    {
+        /*    auto tmp = &array;
+         *    (*tmp).length = (*tmp).length op e2
+         */
+        VarDeclaration *tmp = copyToTemp(0, "__arraylength", new AddrExp(ale->loc, ale->e1));
+
+        Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp)));
+        Expression *elvalue = e1->syntaxCopy();
+        e = opAssignToOp(exp->loc, exp->op, e1, exp->e2);
+        e = new AssignExp(exp->loc, elvalue, e);
+        e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e);
+    }
+    return e;
+}
 
 /****************************************
  * Preprocess arguments to function.
@@ -76,39 +1302,728 @@  Expression *resolvePropertiesX(Scope *sc, Expression *e1, Expression *e2 = NULL)
  *      true    a semantic error occurred
  */
 
-static bool preFunctionParameters(Scope *sc, Expressions *exps)
-{
-    bool err = false;
-    if (exps)
+static bool preFunctionParameters(Scope *sc, Expressions *exps)
+{
+    bool err = false;
+    if (exps)
+    {
+        expandTuples(exps);
+
+        for (size_t i = 0; i < exps->length; i++)
+        {
+            Expression *arg = (*exps)[i];
+
+            arg = resolveProperties(sc, arg);
+            if (arg->op == TOKtype)
+            {
+                arg->error("cannot pass type %s as a function argument", arg->toChars());
+                arg = new ErrorExp();
+                err = true;
+            }
+            else if (arg->type->toBasetype()->ty == Tfunction)
+            {
+                arg->error("cannot pass type %s as a function argument", arg->toChars());
+                arg = new ErrorExp();
+                err = true;
+            }
+            else if (checkNonAssignmentArrayOp(arg))
+            {
+                arg = new ErrorExp();
+                err = true;
+            }
+            (*exps)[i] = arg;
+        }
+    }
+    return err;
+}
+
+/********************************************
+ * Issue an error if default construction is disabled for type t.
+ * Default construction is required for arrays and 'out' parameters.
+ * Returns:
+ *      true    an error was issued
+ */
+static bool checkDefCtor(Loc loc, Type *t)
+{
+    t = t->baseElemOf();
+    if (t->ty == Tstruct)
+    {
+        StructDeclaration *sd = ((TypeStruct *)t)->sym;
+        if (sd->noDefaultCtor)
+        {
+            sd->error(loc, "default construction is disabled");
+            return true;
+        }
+    }
+    return false;
+}
+
+/****************************************
+ * Now that we know the exact type of the function we're calling,
+ * the arguments[] need to be adjusted:
+ *      1. implicitly convert argument to the corresponding parameter type
+ *      2. add default arguments for any missing arguments
+ *      3. do default promotions on arguments corresponding to ...
+ *      4. add hidden _arguments[] argument
+ *      5. call copy constructor for struct value arguments
+ * Input:
+ *      tf      type of the function
+ *      fd      the function being called, NULL if called indirectly
+ * Output:
+ *      *prettype return type of function
+ *      *peprefix expression to execute before arguments[] are evaluated, NULL if none
+ * Returns:
+ *      true    errors happened
+ */
+
+static bool functionParameters(Loc loc, Scope *sc, TypeFunction *tf,
+        Type *tthis, Expressions *arguments, FuncDeclaration *fd, Type **prettype, Expression **peprefix)
+{
+    //printf("functionParameters()\n");
+    assert(arguments);
+    assert(fd || tf->next);
+    size_t nargs = arguments ? arguments->length : 0;
+    size_t nparams = tf->parameterList.length();
+    unsigned olderrors = global.errors;
+    bool err = false;
+    *prettype = Type::terror;
+    Expression *eprefix = NULL;
+    *peprefix = NULL;
+
+    if (nargs > nparams && tf->parameterList.varargs == VARARGnone)
+    {
+        error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", (ulonglong)nparams, (ulonglong)nargs, tf->toChars());
+        return true;
+    }
+
+    // If inferring return type, and semantic3() needs to be run if not already run
+    if (!tf->next && fd->inferRetType)
+    {
+        fd->functionSemantic();
+    }
+    else if (fd && fd->parent)
+    {
+        TemplateInstance *ti = fd->parent->isTemplateInstance();
+        if (ti && ti->tempdecl)
+        {
+            fd->functionSemantic3();
+        }
+    }
+    bool isCtorCall = fd && fd->needThis() && fd->isCtorDeclaration();
+
+    size_t n = (nargs > nparams) ? nargs : nparams;   // n = max(nargs, nparams)
+
+    /* If the function return type has wildcards in it, we'll need to figure out the actual type
+     * based on the actual argument types.
+     */
+    MOD wildmatch = 0;
+    if (tthis && tf->isWild() && !isCtorCall)
+    {
+        Type *t = tthis;
+        if (t->isImmutable())
+            wildmatch = MODimmutable;
+        else if (t->isWildConst())
+            wildmatch = MODwildconst;
+        else if (t->isWild())
+            wildmatch = MODwild;
+        else if (t->isConst())
+            wildmatch = MODconst;
+        else
+            wildmatch = MODmutable;
+    }
+
+    int done = 0;
+    for (size_t i = 0; i < n; i++)
+    {
+        Expression *arg;
+
+        if (i < nargs)
+            arg = (*arguments)[i];
+        else
+            arg = NULL;
+
+        if (i < nparams)
+        {
+            Parameter *p = tf->parameterList[i];
+
+            if (!arg)
+            {
+                if (!p->defaultArg)
+                {
+                    if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
+                        goto L2;
+                    error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
+                    return true;
+                }
+                arg = p->defaultArg;
+                arg = inlineCopy(arg, sc);
+                // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
+                arg = arg->resolveLoc(loc, sc);
+                arguments->push(arg);
+                nargs++;
+            }
+
+            if (tf->parameterList.varargs == VARARGtypesafe && i + 1 == nparams)
+            {
+                //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
+                {
+                    MATCH m;
+                    if ((m = arg->implicitConvTo(p->type)) > MATCHnomatch)
+                    {
+                        if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
+                            goto L2;
+                        else if (nargs != nparams)
+                        {   error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
+                            return true;
+                        }
+                        goto L1;
+                    }
+                }
+             L2:
+                Type *tb = p->type->toBasetype();
+                Type *tret = p->isLazyArray();
+                switch (tb->ty)
+                {
+                    case Tsarray:
+                    case Tarray:
+                    {
+                        /* Create a static array variable v of type arg->type:
+                         *  T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
+                         *
+                         * The array literal in the initializer of the hidden variable
+                         * is now optimized. See Bugzilla 2356.
+                         */
+                        Type *tbn = ((TypeArray *)tb)->next;
+
+                        Expressions *elements = new Expressions();
+                        elements->setDim(nargs - i);
+                        for (size_t u = 0; u < elements->length; u++)
+                        {
+                            Expression *a = (*arguments)[i + u];
+                            if (tret && a->implicitConvTo(tret))
+                            {
+                                a = a->implicitCastTo(sc, tret);
+                                a = a->optimize(WANTvalue);
+                                a = toDelegate(a, a->type, sc);
+                            }
+                            else
+                                a = a->implicitCastTo(sc, tbn);
+                            (*elements)[u] = a;
+                        }
+                        // Bugzilla 14395: Convert to a static array literal, or its slice.
+                        arg = new ArrayLiteralExp(loc, tbn->sarrayOf(nargs - i), elements);
+                        if (tb->ty == Tarray)
+                        {
+                            arg = new SliceExp(loc, arg, NULL, NULL);
+                            arg->type = p->type;
+                        }
+                        break;
+                    }
+                    case Tclass:
+                    {
+                        /* Set arg to be:
+                         *      new Tclass(arg0, arg1, ..., argn)
+                         */
+                        Expressions *args = new Expressions();
+                        args->setDim(nargs - i);
+                        for (size_t u = i; u < nargs; u++)
+                            (*args)[u - i] = (*arguments)[u];
+                        arg = new NewExp(loc, NULL, NULL, p->type, args);
+                        break;
+                    }
+                    default:
+                        if (!arg)
+                        {
+                            error(loc, "not enough arguments");
+                            return true;
+                        }
+                        break;
+                }
+                arg = expressionSemantic(arg, sc);
+                //printf("\targ = '%s'\n", arg->toChars());
+                arguments->setDim(i + 1);
+                (*arguments)[i] =  arg;
+                nargs = i + 1;
+                done = 1;
+            }
+
+        L1:
+            if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
+            {
+                bool isRef = (p->storageClass & (STCref | STCout)) != 0;
+                if (unsigned char wm = arg->type->deduceWild(p->type, isRef))
+                {
+                    if (wildmatch)
+                        wildmatch = MODmerge(wildmatch, wm);
+                    else
+                        wildmatch = wm;
+                    //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch);
+                }
+            }
+        }
+        if (done)
+            break;
+    }
+    if ((wildmatch == MODmutable || wildmatch == MODimmutable) &&
+        tf->next->hasWild() &&
+        (tf->isref || !tf->next->implicitConvTo(tf->next->immutableOf())))
     {
-        expandTuples(exps);
+        if (fd)
+        {
+            /* If the called function may return the reference to
+             * outer inout data, it should be rejected.
+             *
+             * void foo(ref inout(int) x) {
+             *   ref inout(int) bar(inout(int)) { return x; }
+             *   struct S { ref inout(int) bar() inout { return x; } }
+             *   bar(int.init) = 1;  // bad!
+             *   S().bar() = 1;      // bad!
+             * }
+             */
+            Dsymbol *s = NULL;
+            if (fd->isThis() || fd->isNested())
+                s = fd->toParent2();
+            for (; s; s = s->toParent2())
+            {
+                if (AggregateDeclaration *ad = s->isAggregateDeclaration())
+                {
+                    if (ad->isNested())
+                        continue;
+                    break;
+                }
+                if (FuncDeclaration *ff = s->isFuncDeclaration())
+                {
+                    if (((TypeFunction *)ff->type)->iswild)
+                        goto Linouterr;
 
-        for (size_t i = 0; i < exps->length; i++)
+                    if (ff->isNested() || ff->isThis())
+                        continue;
+                }
+                break;
+            }
+        }
+        else if (tf->isWild())
         {
-            Expression *arg = (*exps)[i];
+        Linouterr:
+            const char *s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch);
+            error(loc, "modify inout to %s is not allowed inside inout function", s);
+            return true;
+        }
+    }
 
-            arg = resolveProperties(sc, arg);
-            if (arg->op == TOKtype)
+    assert(nargs >= nparams);
+    for (size_t i = 0; i < nargs; i++)
+    {
+        Expression *arg = (*arguments)[i];
+        assert(arg);
+        if (i < nparams)
+        {
+            Parameter *p = tf->parameterList[i];
+
+            if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
             {
-                arg->error("cannot pass type %s as a function argument", arg->toChars());
-                arg = new ErrorExp();
+                Type *tprm = p->type;
+                if (p->type->hasWild())
+                    tprm = p->type->substWildTo(wildmatch);
+                if (!tprm->equals(arg->type))
+                {
+                    //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
+                    arg = arg->implicitCastTo(sc, tprm);
+                    arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
+                }
+            }
+            if (p->storageClass & STCref)
+            {
+                arg = arg->toLvalue(sc, arg);
+
+                // Look for mutable misaligned pointer, etc., in @safe mode
+                err |= checkUnsafeAccess(sc, arg, false, true);
+            }
+            else if (p->storageClass & STCout)
+            {
+                Type *t = arg->type;
+                if (!t->isMutable() || !t->isAssignable())  // check blit assignable
+                {
+                    arg->error("cannot modify struct %s with immutable members", arg->toChars());
+                    err = true;
+                }
+                else
+                {
+                    // Look for misaligned pointer, etc., in @safe mode
+                    err |= checkUnsafeAccess(sc, arg, false, true);
+                    err |= checkDefCtor(arg->loc, t);   // t must be default constructible
+                }
+                arg = arg->toLvalue(sc, arg);
+            }
+            else if (p->storageClass & STClazy)
+            {
+                // Convert lazy argument to a delegate
+                if (p->type->ty == Tvoid)
+                    arg = toDelegate(arg, p->type, sc);
+                else
+                    arg = toDelegate(arg, arg->type, sc);
+            }
+
+            //printf("arg: %s\n", arg->toChars());
+            //printf("type: %s\n", arg->type->toChars());
+            if (tf->parameterEscapes(p))
+            {
+                /* Argument value can escape from the called function.
+                 * Check arg to see if it matters.
+                 */
+                if (global.params.vsafe)
+                    err |= checkParamArgumentEscape(sc, fd, p->ident, arg, false);
+            }
+            else
+            {
+                /* Argument value cannot escape from the called function.
+                 */
+                Expression *a = arg;
+                if (a->op == TOKcast)
+                    a = ((CastExp *)a)->e1;
+
+                if (a->op == TOKfunction)
+                {
+                    /* Function literals can only appear once, so if this
+                     * appearance was scoped, there cannot be any others.
+                     */
+                    FuncExp *fe = (FuncExp *)a;
+                    fe->fd->tookAddressOf = 0;
+                }
+                else if (a->op == TOKdelegate)
+                {
+                    /* For passing a delegate to a scoped parameter,
+                     * this doesn't count as taking the address of it.
+                     * We only worry about 'escaping' references to the function.
+                     */
+                    DelegateExp *de = (DelegateExp *)a;
+                    if (de->e1->op == TOKvar)
+                    {   VarExp *ve = (VarExp *)de->e1;
+                        FuncDeclaration *f = ve->var->isFuncDeclaration();
+                        if (f)
+                        {   f->tookAddressOf--;
+                            //printf("tookAddressOf = %d\n", f->tookAddressOf);
+                        }
+                    }
+                }
+            }
+            arg = arg->optimize(WANTvalue, (p->storageClass & (STCref | STCout)) != 0);
+        }
+        else
+        {
+            // These will be the trailing ... arguments
+
+            // If not D linkage, do promotions
+            if (tf->linkage != LINKd)
+            {
+                // Promote bytes, words, etc., to ints
+                arg = integralPromotions(arg, sc);
+
+                // Promote floats to doubles
+                switch (arg->type->ty)
+                {
+                    case Tfloat32:
+                        arg = arg->castTo(sc, Type::tfloat64);
+                        break;
+
+                    case Timaginary32:
+                        arg = arg->castTo(sc, Type::timaginary64);
+                        break;
+                }
+
+                if (tf->parameterList.varargs == VARARGvariadic)
+                {
+                    const char *p = tf->linkage == LINKc ? "extern(C)" : "extern(C++)";
+                    if (arg->type->ty == Tarray)
+                    {
+                        arg->error("cannot pass dynamic arrays to %s vararg functions", p);
+                        err = true;
+                    }
+                    if (arg->type->ty == Tsarray)
+                    {
+                        arg->error("cannot pass static arrays to %s vararg functions", p);
+                        err = true;
+                    }
+                }
+            }
+
+            // Do not allow types that need destructors
+            if (arg->type->needsDestruction())
+            {
+                arg->error("cannot pass types that need destruction as variadic arguments");
                 err = true;
             }
-            else if (arg->type->toBasetype()->ty == Tfunction)
+
+            // Convert static arrays to dynamic arrays
+            // BUG: I don't think this is right for D2
+            Type *tb = arg->type->toBasetype();
+            if (tb->ty == Tsarray)
             {
-                arg->error("cannot pass type %s as a function argument", arg->toChars());
-                arg = new ErrorExp();
+                TypeSArray *ts = (TypeSArray *)tb;
+                Type *ta = ts->next->arrayOf();
+                if (ts->size(arg->loc) == 0)
+                    arg = new NullExp(arg->loc, ta);
+                else
+                    arg = arg->castTo(sc, ta);
+            }
+            if (tb->ty == Tstruct)
+            {
+                //arg = callCpCtor(sc, arg);
+            }
+
+            // Give error for overloaded function addresses
+            if (arg->op == TOKsymoff)
+            {   SymOffExp *se = (SymOffExp *)arg;
+                if (se->hasOverloads &&
+                    !se->var->isFuncDeclaration()->isUnique())
+                {   arg->error("function %s is overloaded", arg->toChars());
+                    err = true;
+                }
+            }
+            if (arg->checkValue())
                 err = true;
+            arg = arg->optimize(WANTvalue);
+        }
+        (*arguments)[i] = arg;
+    }
+
+    /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
+     */
+    const bool isVa_list = tf->parameterList.varargs == VARARGnone;
+    if (fd && (fd->flags & FUNCFLAGprintf))
+    {
+        if (StringExp *se = (*arguments)[nparams - 1 - isVa_list]->isStringExp())
+        {
+            Expressions argslice;
+            argslice.reserve(nargs - nparams);
+            for (size_t i = nparams; i < nargs; i++)
+                argslice.push((*arguments)[i]);
+            checkPrintfFormat(se->loc, se->toPtr(), argslice, isVa_list);
+        }
+    }
+    else if (fd && (fd->flags & FUNCFLAGscanf))
+    {
+        if (StringExp *se = (*arguments)[nparams - 1 - isVa_list]->isStringExp())
+        {
+            Expressions argslice;
+            argslice.reserve(nargs - nparams);
+            for (size_t i = nparams; i < nargs; i++)
+                argslice.push((*arguments)[i]);
+            checkPrintfFormat(se->loc, se->toPtr(), argslice, isVa_list);
+        }
+    }
+
+    /* Remaining problems:
+     * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
+     *    implemented by calling a function) we'll defer this for now.
+     * 2. value structs (or static arrays of them) that need to be copy constructed
+     * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
+     *    function gets called (functions normally destroy their parameters)
+     * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
+     * up properly. Pushing arguments on the stack then cannot fail.
+     */
+    if (1)
+    {
+        /* TODO: tackle problem 1)
+         */
+        const bool leftToRight = true; // TODO: something like !fd.isArrayOp
+        if (!leftToRight)
+            assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
+
+        const ptrdiff_t start = (leftToRight ? 0 : (ptrdiff_t)nargs - 1);
+        const ptrdiff_t end = (leftToRight ? (ptrdiff_t)nargs : -1);
+        const ptrdiff_t step = (leftToRight ? 1 : -1);
+
+        /* Compute indices of last throwing argument and first arg needing destruction.
+         * Used to not set up destructors unless an arg needs destruction on a throw
+         * in a later argument.
+         */
+        ptrdiff_t lastthrow = -1;
+        ptrdiff_t firstdtor = -1;
+        for (ptrdiff_t i = start; i != end; i += step)
+        {
+            Expression *arg = (*arguments)[i];
+            if (canThrow(arg, sc->func, false))
+                lastthrow = i;
+            if (firstdtor == -1 && arg->type->needsDestruction())
+            {
+                Parameter *p = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
+                if (!(p && (p->storageClass & (STClazy | STCref | STCout))))
+                    firstdtor = i;
             }
-            else if (checkNonAssignmentArrayOp(arg))
+        }
+
+        /* Does problem 3) apply to this call?
+         */
+        const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0
+            && (lastthrow - firstdtor) * step > 0);
+
+        /* If so, initialize 'eprefix' by declaring the gate
+         */
+        VarDeclaration *gate = NULL;
+        if (needsPrefix)
+        {
+            // eprefix => bool __gate [= false]
+            Identifier *idtmp = Identifier::generateId("__gate");
+            gate = new VarDeclaration(loc, Type::tbool, idtmp, NULL);
+            gate->storage_class |= STCtemp | STCctfe | STCvolatile;
+            dsymbolSemantic(gate, sc);
+
+            Expression *ae = new DeclarationExp(loc, gate);
+            eprefix = expressionSemantic(ae, sc);
+        }
+
+        for (ptrdiff_t i = start; i != end; i += step)
+        {
+            Expression *arg = (*arguments)[i];
+
+            Parameter *parameter = (i >= (ptrdiff_t)nparams ? NULL : tf->parameterList[i]);
+            const bool isRef = (parameter && (parameter->storageClass & (STCref | STCout)));
+            const bool isLazy = (parameter && (parameter->storageClass & STClazy));
+
+            /* Skip lazy parameters
+             */
+            if (isLazy)
+                continue;
+
+            /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg.
+             * Declare a temporary variable for this arg and append that declaration to 'eprefix',
+             * which will implicitly take care of potential problem 2) for this arg.
+             * 'eprefix' will therefore finally contain all args up to and including the last
+             * potentially throwing arg, excluding all lazy parameters.
+             */
+            if (gate)
             {
-                arg = new ErrorExp();
+                const bool needsDtor = (!isRef && arg->type->needsDestruction() && i != lastthrow);
+
+                /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
+                 */
+                VarDeclaration *tmp = copyToTemp(0,
+                    needsDtor ? "__pfx" : "__pfy",
+                    !isRef ? arg : arg->addressOf());
+                dsymbolSemantic(tmp, sc);
+
+                /* Modify the destructor so it only runs if gate==false, i.e.,
+                 * only if there was a throw while constructing the args
+                 */
+                if (!needsDtor)
+                {
+                    if (tmp->edtor)
+                    {
+                        assert(i == lastthrow);
+                        tmp->edtor = NULL;
+                    }
+                }
+                else
+                {
+                    // edtor => (__gate || edtor)
+                    assert(tmp->edtor);
+                    Expression *e = tmp->edtor;
+                    e = new LogicalExp(e->loc, TOKoror, new VarExp(e->loc, gate), e);
+                    tmp->edtor = expressionSemantic(e, sc);
+                    //printf("edtor: %s\n", tmp->edtor->toChars());
+                }
+
+                // eprefix => (eprefix, auto __pfx/y = arg)
+                DeclarationExp *ae = new DeclarationExp(loc, tmp);
+                eprefix = Expression::combine(eprefix, expressionSemantic(ae, sc));
+
+                // arg => __pfx/y
+                arg = new VarExp(loc, tmp);
+                arg = expressionSemantic(arg, sc);
+                if (isRef)
+                {
+                    arg = new PtrExp(loc, arg);
+                    arg = expressionSemantic(arg, sc);
+                }
+
+                /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true),
+                 * i.e., disable the dtors right after constructing the last throwing arg.
+                 * From now on, the callee will take care of destructing the args because
+                 * the args are implicitly moved into function parameters.
+                 *
+                 * Set gate to null to let the next iterations know they don't need to
+                 * append to eprefix anymore.
+                 */
+                if (i == lastthrow)
+                {
+                    Expression *e = new AssignExp(gate->loc, new VarExp(gate->loc, gate), new IntegerExp(gate->loc, 1, Type::tbool));
+                    eprefix = Expression::combine(eprefix, expressionSemantic(e, sc));
+                    gate = NULL;
+                }
+            }
+            else
+            {
+                /* No gate, no prefix to append to.
+                 * Handle problem 2) by calling the copy constructor for value structs
+                 * (or static arrays of them) if appropriate.
+                 */
+                Type *tv = arg->type->baseElemOf();
+                if (!isRef && tv->ty == Tstruct)
+                    arg = doCopyOrMove(sc, arg);
+            }
+
+            (*arguments)[i] = arg;
+        }
+    }
+    //if (eprefix) printf("eprefix: %s\n", eprefix->toChars());
+
+    // If D linkage and variadic, add _arguments[] as first argument
+    if (tf->isDstyleVariadic())
+    {
+        assert(arguments->length >= nparams);
+
+        Parameters *args = new Parameters;
+        args->setDim(arguments->length - nparams);
+        for (size_t i = 0; i < arguments->length - nparams; i++)
+        {
+            Parameter *arg = new Parameter(STCin, (*arguments)[nparams + i]->type, NULL, NULL, NULL);
+            (*args)[i] = arg;
+        }
+
+        TypeTuple *tup = new TypeTuple(args);
+        Expression *e = new TypeidExp(loc, tup);
+        e = expressionSemantic(e, sc);
+        arguments->insert(0, e);
+    }
+
+    Type *tret = tf->next;
+    if (isCtorCall)
+    {
+        //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(),
+        //    wildmatch, tf->isWild(), fd->isolateReturn());
+        if (!tthis)
+        {
+            assert(sc->intypeof || global.errors);
+            tthis = fd->isThis()->type->addMod(fd->type->mod);
+        }
+        if (tf->isWild() && !fd->isolateReturn())
+        {
+            if (wildmatch)
+                tret = tret->substWildTo(wildmatch);
+            int offset;
+            if (!tret->implicitConvTo(tthis) &&
+                !(MODimplicitConv(tret->mod, tthis->mod) && tret->isBaseOf(tthis, &offset) && offset == 0))
+            {
+                const char* s1 = tret ->isNaked() ? " mutable" : tret ->modToChars();
+                const char* s2 = tthis->isNaked() ? " mutable" : tthis->modToChars();
+                ::error(loc, "inout constructor %s creates%s object, not%s",
+                        fd->toPrettyChars(), s1, s2);
                 err = true;
             }
-            (*exps)[i] = arg;
         }
+        tret = tthis;
     }
-    return err;
+    else if (wildmatch && tret)
+    {
+        /* Adjust function return type based on wildmatch
+         */
+        //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars());
+        tret = tret->substWildTo(wildmatch);
+    }
+    *prettype = tret;
+    *peprefix = eprefix;
+    return (err || olderrors != global.errors);
 }
 
 /**
@@ -134,6 +2049,8 @@  Package *resolveIsPackage(Dsymbol *sym)
         }
         pkg = imp->pkg;
     }
+    else if (Module *mod = sym->isModule())
+        pkg = mod->isPackageFile ? mod->pkg : sym->isPackage();
     else
         pkg = sym->isPackage();
     if (pkg)
@@ -141,6 +2058,25 @@  Package *resolveIsPackage(Dsymbol *sym)
     return pkg;
 }
 
+static Module *loadStdMath()
+{
+  static Import *impStdMath = NULL;
+  if (!impStdMath)
+    {
+      Identifiers *a = new Identifiers();
+      a->push(Id::std);
+      Import *s = new Import(Loc(), a, Id::math, NULL, false);
+      s->load(NULL);
+      if (s->mod)
+      {
+          s->mod->importAll(NULL);
+          dsymbolSemantic(s->mod, NULL);
+      }
+      impStdMath = s;
+    }
+  return impStdMath->mod;
+}
+
 class ExpressionSemanticVisitor : public Visitor
 {
 public:
@@ -1938,7 +3874,7 @@  public:
 
     void visit(HaltExp *e)
     {
-        e->type = Type::tvoid;
+        e->type = Type::tnoreturn;
         result = e;
     }
 
@@ -1959,7 +3895,9 @@  public:
         Type *tded = NULL;
         if (e->tok2 == TOKpackage || e->tok2 == TOKmodule) // These is() expressions are special because they can work on modules, not just types.
         {
+            const unsigned oldErrors = global.startGagging();
             Dsymbol *sym = e->targ->toDsymbol(sc);
+            global.endGagging(oldErrors);
             if (sym == NULL)
                 goto Lno;
             Package *p = resolveIsPackage(sym);
@@ -2292,7 +4230,7 @@  public:
         if (exp->e1->op == TOKarraylength)
         {
             // arr.length op= e2;
-            e = ArrayLengthExp::rewriteOpAssign(exp);
+            e = rewriteOpAssign(exp);
             e = expressionSemantic(e, sc);
             result = e;
             return;
@@ -2382,27 +4320,39 @@  public:
         result = ((BinExp *)e)->reorderSettingAAElem(sc);
     }
 
-    void visit(CompileExp *exp)
+private:
+    Expression *compileIt(CompileExp *exp)
     {
-        StringExp *se = semanticString(sc, exp->e1, "argument to mixin");
-        if (!se)
-            return setError();
-        se = se->toUTF8(sc);
+        OutBuffer buf;
+        if (expressionsToString(buf, sc, exp->exps))
+            return NULL;
+
         unsigned errors = global.errors;
-        Parser p(exp->loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+        const size_t len = buf.length();
+        const char *str = buf.extractChars();
+        Parser p(exp->loc, sc->_module, (const utf8_t *)str, len, false);
         p.nextToken();
         //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
         Expression *e = p.parseExpression();
-        if (p.errors)
-        {
-            assert(global.errors != errors);        // should have caught all these cases
-            return setError();
-        }
+        if (global.errors != errors)
+            return NULL;
+
         if (p.token.value != TOKeof)
         {
-            exp->error("incomplete mixin expression (%s)", se->toChars());
-            return setError();
+            exp->error("incomplete mixin expression (%s)", str);
+            return NULL;
         }
+        return e;
+    }
+
+public:
+    void visit(CompileExp *exp)
+    {
+        //printf("CompileExp::semantic('%s')\n", exp->toChars());
+        Expression *e = compileIt(exp);
+        if (!e)
+            return setError();
         result = expressionSemantic(e, sc);
     }
 
@@ -2508,6 +4458,8 @@  public:
 
         if (exp->e1->isBool(false))
         {
+            /* This is an `assert(0)` which means halt program execution
+             */
             FuncDeclaration *fd = sc->parent->isFuncDeclaration();
             if (fd)
                 fd->hasReturnExp |= 4;
@@ -2525,8 +4477,10 @@  public:
                 result = e;
                 return;
             }
+            exp->type = Type::tnoreturn;
         }
-        exp->type = Type::tvoid;
+        else
+            exp->type = Type::tvoid;
         result = exp;
     }
 
@@ -3484,7 +5438,8 @@  public:
                 return setError();
             }
 
-            if (!tf->callMatch(NULL, exp->arguments))
+            const char *failMessage = NULL;
+            if (!tf->callMatch(NULL, exp->arguments, 0, &failMessage))
             {
                 OutBuffer buf;
 
@@ -3495,10 +5450,11 @@  public:
                     tthis->modToBuffer(&buf);
 
                 //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
-                ::error(exp->loc, "%s %s %s is not callable using argument types %s",
+                ::error(exp->loc, "%s `%s%s` is not callable using argument types `%s`",
                         p, exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
                         buf.peekChars());
-
+                if (failMessage)
+                    errorSupplemental(exp->loc, failMessage);
                 return setError();
             }
 
@@ -3553,13 +5509,14 @@  public:
             assert(exp->f);
             tiargs = NULL;
 
-            if (ve->hasOverloads)
+            if (exp->f->overnext)
                 exp->f = resolveFuncCall(exp->loc, sc, exp->f, tiargs, NULL, exp->arguments, 2);
             else
             {
                 exp->f = exp->f->toAliasFunc();
                 TypeFunction *tf = (TypeFunction *)exp->f->type;
-                if (!tf->callMatch(NULL, exp->arguments))
+                const char *failMessage = NULL;
+                if (!tf->callMatch(NULL, exp->arguments, 0, &failMessage))
                 {
                     OutBuffer buf;
 
@@ -3568,10 +5525,11 @@  public:
                     buf.writeByte(')');
 
                     //printf("tf = %s, args = %s\n", tf->deco, (*exp->arguments)[0]->type->deco);
-                    ::error(exp->loc, "%s %s is not callable using argument types %s",
-                            exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
+                    ::error(exp->loc, "%s `%s%s` is not callable using argument types `%s`",
+                            exp->f->kind(), exp->e1->toChars(), parametersTypeToChars(tf->parameterList),
                             buf.peekChars());
-
+                    if (failMessage)
+                        errorSupplemental(exp->loc, failMessage);
                     exp->f = NULL;
                 }
             }
@@ -3954,6 +5912,10 @@  public:
                 exp->e1 = exp->e1->castTo(sc, exp->type->pointerTo());
                 break;
 
+            case Tnull:
+                exp->type = Type::tnoreturn;    // typeof(*null) is bottom type
+                break;
+
             default:
                 exp->error("can only * a pointer, not a `%s`", exp->e1->type->toChars());
                 /* fall through */
@@ -7109,25 +9071,6 @@  public:
         result = exp;
     }
 
-    Module *loadStdMath()
-    {
-        static Import *impStdMath = NULL;
-        if (!impStdMath)
-        {
-            Identifiers *a = new Identifiers();
-            a->push(Id::std);
-            Import *s = new Import(Loc(), a, Id::math, NULL, false);
-            s->load(NULL);
-            if (s->mod)
-            {
-                s->mod->importAll(NULL);
-                dsymbolSemantic(s->mod, NULL);
-            }
-            impStdMath = s;
-        }
-        return impStdMath->mod;
-    }
-
     void visit(PowExp *exp)
     {
         if (exp->type)
@@ -7579,7 +9522,7 @@  public:
             exp->error("%s is not an expression", exp->e2->toChars());
             return setError();
         }
-        if (e1x->op == TOKerror)
+        if (e1x->op == TOKerror || e1x->type->ty == Tnoreturn)
         {
             result = e1x;
             return;
@@ -8032,10 +9975,18 @@  public:
 
         Type *t1 = exp->e1->type;
         Type *t2 = exp->e2->type;
+        if (t1->ty == Tnoreturn)
+        {
+            exp->type = t2;
+        }
+        else if (t2->ty == Tnoreturn)
+        {
+            exp->type = t1;
+        }
         // If either operand is void the result is void, we have to cast both
         // the expression to void so that we explicitly discard the expression
         // value if any (bugzilla 16598)
-        if (t1->ty == Tvoid || t2->ty == Tvoid)
+        else if (t1->ty == Tvoid || t2->ty == Tvoid)
         {
             exp->type = Type::tvoid;
             exp->e1 = exp->e1->castTo(sc, exp->type);
diff --git a/gcc/d/dmd/func.c b/gcc/d/dmd/func.c
index 7a216a97941..b8e1e318376 100644
--- a/gcc/d/dmd/func.c
+++ b/gcc/d/dmd/func.c
@@ -1473,7 +1473,8 @@  FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
     memset(&m, 0, sizeof(m));
     m.last = MATCHnomatch;
 
-    functionResolve(&m, s, loc, sc, tiargs, tthis, fargs);
+    const char *failMessage = NULL;
+    functionResolve(&m, s, loc, sc, tiargs, tthis, fargs, &failMessage);
 
     if (m.last > MATCHnomatch && m.lastf)
     {
@@ -1555,20 +1556,23 @@  FuncDeclaration *resolveFuncCall(Loc loc, Scope *sc, Dsymbol *s,
                     ::error(loc, "none of the overloads of `%s` are callable using a %sobject, candidates are:",
                         fd->ident->toChars(), thisBuf.peekChars());
                 else
-                    ::error(loc, "%smethod %s is not callable using a %sobject",
+                    ::error(loc, "%smethod `%s` is not callable using a %sobject",
                         funcBuf.peekChars(), fd->toPrettyChars(), thisBuf.peekChars());
             }
             else
             {
                 //printf("tf = %s, args = %s\n", tf->deco, (*fargs)[0]->type->deco);
                 if (hasOverloads)
-                    ::error(loc, "none of the overloads of `%s` are callable using argument types %s, candidates are:",
+                    ::error(loc, "none of the overloads of `%s` are callable using argument types `%s`, candidates are:",
                             fd->ident->toChars(), fargsBuf.peekChars());
                 else
-                    fd->error(loc, "%s%s is not callable using argument types %s",
-                        parametersTypeToChars(tf->parameterList),
-                        tf->modToChars(),
-                        fargsBuf.peekChars());
+                {
+                    fd->error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
+                        fd->kind(), fd->toPrettyChars(), parametersTypeToChars(tf->parameterList),
+                        tf->modToChars(), fargsBuf.peekChars());
+                    if (failMessage)
+                        errorSupplemental(loc, failMessage);
+                }
             }
 
             // Display candidate functions
diff --git a/gcc/d/dmd/hdrgen.c b/gcc/d/dmd/hdrgen.c
index a11c9c353d9..9eba88f1118 100644
--- a/gcc/d/dmd/hdrgen.c
+++ b/gcc/d/dmd/hdrgen.c
@@ -122,7 +122,7 @@  public:
     void visit(CompileStatement *s)
     {
         buf->writestring("mixin(");
-        s->exp->accept(this);
+        argsToBuffer(s->exps);
         buf->writestring(");");
         if (!hgs->forStmtInit)
             buf->writenl();
@@ -1104,6 +1104,18 @@  public:
         buf->writestring("typeof(null)");
     }
 
+    void visit(TypeMixin *t)
+    {
+        buf->writestring("mixin(");
+        argsToBuffer(t->exps);
+        buf->writeByte(')');
+    }
+
+    void visit(TypeNoreturn *)
+    {
+        buf->writestring("noreturn");
+    }
+
     ////////////////////////////////////////////////////////////////////////////
 
     void visit(Dsymbol *s)
@@ -1418,7 +1430,7 @@  public:
     void visit(CompileDeclaration *d)
     {
         buf->writestring("mixin(");
-        d->exp->accept(this);
+        argsToBuffer(d->exps);
         buf->writestring(");");
         buf->writenl();
     }
@@ -2408,8 +2420,15 @@  public:
                     buf->writeByte(')');
                     if (target.ptrsize == 8)
                         goto L4;
-                    else
+                    else if (target.ptrsize == 4 ||
+                             target.ptrsize == 2)
                         goto L3;
+                    else
+                        assert(0);
+
+                case Tvoid:
+                    buf->writestring("cast(void)0");
+                    break;
 
                 default:
                     /* This can happen if errors, such as
@@ -2822,7 +2841,7 @@  public:
     void visit(CompileExp *e)
     {
         buf->writestring("mixin(");
-        expToBuffer(e->e1, PREC_assign);
+        argsToBuffer(e->exps);
         buf->writeByte(')');
     }
 
@@ -3528,6 +3547,13 @@  void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects)
     }
 }
 
+/*************************************************************
+ * Pretty print function parameters.
+ * Params:
+ *  parameters = parameters to print, such as TypeFunction.parameters.
+ *  varargs = kind of varargs, see TypeFunction.varargs.
+ * Returns: Null-terminated string representing parameters.
+ */
 const char *parametersTypeToChars(ParameterList pl)
 {
     OutBuffer buf;
@@ -3536,3 +3562,26 @@  const char *parametersTypeToChars(ParameterList pl)
     v.parametersToBuffer(pl.parameters, pl.varargs);
     return buf.extractChars();
 }
+
+/*************************************************************
+ * Pretty print function parameter.
+ * Params:
+ *  parameter = parameter to print.
+ *  tf = TypeFunction which holds parameter.
+ *  fullQual = whether to fully qualify types.
+ * Returns: Null-terminated string representing parameters.
+ */
+const char *parameterToChars(Parameter *parameter, TypeFunction *tf, bool fullQual)
+{
+    OutBuffer buf;
+    HdrGenState hgs;
+    hgs.fullQual = fullQual;
+    PrettyPrintVisitor v(&buf, &hgs);
+
+    parameter->accept(&v);
+    if (tf->parameterList.varargs == 2 && parameter == tf->parameterList[tf->parameterList.parameters->length - 1])
+    {
+        buf.writestring("...");
+    }
+    return buf.extractChars();
+}
diff --git a/gcc/d/dmd/hdrgen.h b/gcc/d/dmd/hdrgen.h
index d464d4aa618..6822aaf44a9 100644
--- a/gcc/d/dmd/hdrgen.h
+++ b/gcc/d/dmd/hdrgen.h
@@ -47,6 +47,7 @@  void arrayObjectsToBuffer(OutBuffer *buf, Objects *objects);
 void moduleToBuffer(OutBuffer *buf, Module *m);
 
 const char *parametersTypeToChars(ParameterList pl);
+const char *parameterToChars(Parameter *parameter, TypeFunction *tf, bool fullQual);
 
 bool stcToBuffer(OutBuffer *buf, StorageClass stc);
 const char *stcToChars(StorageClass& stc);
diff --git a/gcc/d/dmd/idgen.c b/gcc/d/dmd/idgen.c
index 59faa993b9b..0740653709a 100644
--- a/gcc/d/dmd/idgen.c
+++ b/gcc/d/dmd/idgen.c
@@ -86,10 +86,16 @@  Msgtable msgtable[] =
     { "__c_longlong", NULL },
     { "__c_ulonglong", NULL },
     { "__c_long_double", NULL },
+    { "__c_wchar_t", NULL },
+    { "__c_complex_float", NULL },
+    { "__c_complex_double", NULL },
+    { "__c_complex_real", NULL },
     { "cpp_type_info_ptr", "__cpp_type_info_ptr" },
     { "_assert", "assert" },
     { "_unittest", "unittest" },
     { "_body", "body" },
+    { "printf", NULL },
+    { "scanf", NULL },
 
     { "TypeInfo", NULL },
     { "TypeInfo_Class", NULL },
@@ -395,7 +401,6 @@  Msgtable msgtable[] =
     { "derivedMembers", NULL },
     { "isSame", NULL },
     { "compiles", NULL },
-    { "parameters", NULL },
     { "getAliasThis", NULL },
     { "getAttributes", NULL },
     { "getFunctionAttributes", NULL },
@@ -411,6 +416,7 @@  Msgtable msgtable[] =
     { "getLocation", NULL },
     { "hasPostblit", NULL },
     { "isCopyable", NULL },
+    { "toType", NULL },
 
     // For C++ mangling
     { "allocator", NULL },
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
index e49ad15c2d3..07fb32aa070 100644
--- a/gcc/d/dmd/import.h
+++ b/gcc/d/dmd/import.h
@@ -47,6 +47,7 @@  public:
     Dsymbol *syntaxCopy(Dsymbol *s);    // copy only syntax trees
     void load(Scope *sc);
     void importAll(Scope *sc);
+    void addPackageAccess(ScopeDsymbol *scopesym);
     Dsymbol *toAlias();
     void addMember(Scope *sc, ScopeDsymbol *sds);
     void setScope(Scope* sc);
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index 03078b5e833..1664492bc2d 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -75,6 +75,7 @@  public:
     unsigned numlines;  // number of lines in source file
     int isDocFile;      // if it is a documentation input file, not D source
     bool isPackageFile; // if it is a package.d
+    Package *pkg;       // if isPackageFile is true, the Package that contains this package.d
     Strings contentImportedFiles;  // array of files whose content was imported
     int needmoduleinfo;
 
diff --git a/gcc/d/dmd/mtype.c b/gcc/d/dmd/mtype.c
index c1071b2f278..6b01999bc7c 100644
--- a/gcc/d/dmd/mtype.c
+++ b/gcc/d/dmd/mtype.c
@@ -39,6 +39,7 @@  Expression *extractSideEffect(Scope *sc, const char *name, Expression **e0, Expr
 Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
 Expression *typeToExpression(Type *t);
 Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc);
 
 /***************************** Type *****************************/
 
@@ -93,6 +94,7 @@  Type *Type::tdchar;
 Type *Type::tshiftcnt;
 Type *Type::terror;
 Type *Type::tnull;
+Type *Type::tnoreturn;
 
 Type *Type::tsize_t;
 Type *Type::tptrdiff_t;
@@ -195,6 +197,8 @@  void Type::_init()
     sizeTy[Tnull] = sizeof(TypeNull);
     sizeTy[Tvector] = sizeof(TypeVector);
     sizeTy[Ttraits] = sizeof(TypeTraits);
+    sizeTy[Tmixin] = sizeof(TypeMixin);
+    sizeTy[Tnoreturn] = sizeof(TypeNoreturn);
 
     initTypeMangle();
 
@@ -216,6 +220,10 @@  void Type::_init()
     }
     basic[Terror] = new TypeError();
 
+    tnoreturn = new TypeNoreturn();
+    tnoreturn->deco = tnoreturn->merge()->deco;
+    basic[Tnoreturn] = tnoreturn;
+
     tvoid = basic[Tvoid];
     tint8 = basic[Tint8];
     tuns8 = basic[Tuns8];
@@ -246,7 +254,7 @@  void Type::_init()
 
     tshiftcnt = tint32;
     terror = basic[Terror];
-    tnull = basic[Tnull];
+    tnoreturn = basic[Tnoreturn];
     tnull = new TypeNull();
     tnull->deco = tnull->merge()->deco;
 
@@ -2079,7 +2087,7 @@  Expression *Type::getProperty(Loc loc, Identifier *ident, int flag)
         if (this != Type::terror)
         {
             if (s)
-                error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident->toChars(), toChars(), s->toChars());
+                error(loc, "no property `%s` for type `%s`, did you mean `%s`?", ident->toChars(), toChars(), s->toPrettyChars());
             else
                 error(loc, "no property `%s` for type `%s`", ident->toChars(), toChars());
         }
@@ -2413,6 +2421,16 @@  TypeTraits *Type::isTypeTraits()
     return ty == Ttraits ? (TypeTraits *)this : NULL;
 }
 
+TypeMixin *Type::isTypeMixin()
+{
+    return ty == Tmixin ? (TypeMixin *)this : NULL;
+}
+
+TypeNoreturn *Type::isTypeNoreturn()
+{
+    return ty == Tnoreturn ? (TypeNoreturn *)this : NULL;
+}
+
 TypeFunction *Type::toTypeFunction()
 {
     if (ty != Tfunction)
@@ -5175,16 +5193,47 @@  void TypeFunction::purityLevel()
     tf->purity = purity;
 }
 
+// arguments get specially formatted
+static const char *getParamError(TypeFunction *tf, Expression *arg, Parameter *par)
+{
+    if (global.gag && !global.params.showGaggedErrors)
+        return NULL;
+    // show qualification when toChars() is the same but types are different
+    const char *at = arg->type->toChars();
+    bool qual = !arg->type->equals(par->type) && strcmp(at, par->type->toChars()) == 0;
+    if (qual)
+        at = arg->type->toPrettyChars(true);
+    OutBuffer buf;
+    // only mention rvalue if it's relevant
+    const bool rv = !arg->isLvalue() && (par->storageClass & (STCref | STCout)) != 0;
+    buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
+        rv ? "rvalue " : "", arg->toChars(), at,
+        parameterToChars(par, tf, qual));
+    return buf.extractChars();
+}
+
+static const char *getMatchError(const char *format, ...)
+{
+    if (global.gag && !global.params.showGaggedErrors)
+        return NULL;
+    OutBuffer buf;
+    va_list ap;
+    va_start(ap, format);
+    buf.vprintf(format, ap);
+    return buf.extractChars();
+}
+
 /********************************
  * 'args' are being matched to function 'this'
  * Determine match level.
  * Input:
  *      flag    1       performing a partial ordering match
+ *      pMessage        address to store error message, or null
  * Returns:
  *      MATCHxxxx
  */
 
-MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
+MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag, const char **pMessage)
 {
     //printf("TypeFunction::callMatch() %s\n", toChars());
     MATCH match = MATCHexact;           // assume exact match
@@ -5221,12 +5270,15 @@  MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
 
     size_t nparams = parameterList.length();
     size_t nargs = args ? args->length : 0;
-    if (nparams == nargs)
-        ;
-    else if (nargs > nparams)
+    if (nargs > nparams)
     {
         if (parameterList.varargs == VARARGnone)
-            goto Nomatch;               // too many args; no match
+        {
+            // suppress early exit if an error message is wanted,
+            // so we can check any matching args are valid
+            if (!pMessage)
+                goto Nomatch;           // too many args; no match
+        }
         match = MATCHconvert;           // match ... with a "conversion" match level
     }
 
@@ -5309,7 +5361,10 @@  MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
                 if (m && !arg->isLvalue())
                 {
                     if (p->storageClass & STCout)
+                    {
+                        if (pMessage) *pMessage = getParamError(this, arg, p);
                         goto Nomatch;
+                    }
 
                     if (arg->op == TOKstring && tp->ty == Tsarray)
                     {
@@ -5331,7 +5386,10 @@  MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
                         }
                     }
                     else
+                    {
+                        if (pMessage) *pMessage = getParamError(this, arg, p);
                         goto Nomatch;
+                    }
                 }
 
                 /* Find most derived alias this type being matched.
@@ -5351,7 +5409,10 @@  MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
                  *  ref T[dim] <- an lvalue of const(T[dim]) argument
                  */
                 if (!ta->constConv(tp))
+                {
+                    if (pMessage) *pMessage = getParamError(this, arg, p);
                     goto Nomatch;
+                }
             }
         }
 
@@ -5377,7 +5438,11 @@  MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
                     tsa = (TypeSArray *)tb;
                     sz = tsa->dim->toInteger();
                     if (sz != nargs - u)
+                    {
+                        if (pMessage)
+                            *pMessage = getMatchError("expected %llu variadic argument(s), not %zu", sz, nargs - u);
                         goto Nomatch;
+                    }
                     /* fall through */
                 case Tarray:
                     {
@@ -5408,7 +5473,10 @@  MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
                                 m = arg->implicitConvTo(ta->next);
 
                             if (m == MATCHnomatch)
+                            {
+                                if (pMessage) *pMessage = getParamError(this, arg, p);
                                 goto Nomatch;
+                            }
                             if (m < match)
                                 match = m;
                         }
@@ -5420,9 +5488,14 @@  MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
                     goto Ldone;
 
                 default:
-                    goto Nomatch;
+                    break;
                 }
             }
+            if (pMessage && u < nargs)
+                *pMessage = getParamError(this, (*args)[u], p);
+            else if (pMessage)
+                *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
+                    u + 1, parameterToChars(p, this, false));
             goto Nomatch;
         }
         if (m < match)
@@ -5430,6 +5503,12 @@  MATCH TypeFunction::callMatch(Type *tthis, Expressions *args, int flag)
     }
 
 Ldone:
+    if (pMessage && !parameterList.varargs && nargs > nparams)
+    {
+        // all parameters had a match, but there are surplus args
+        *pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs);
+        goto Nomatch;
+    }
     //printf("match = %d\n", match);
     return match;
 
@@ -5797,6 +5876,20 @@  Type *TypeTraits::syntaxCopy()
     return tt;
 }
 
+Dsymbol *TypeTraits::toDsymbol(Scope *sc)
+{
+    Type *t = NULL;
+    Expression *e = NULL;
+    Dsymbol *s = NULL;
+    resolve(loc, sc, &e, &t, &s);
+    if (t && t->ty != Terror)
+        s = t->toDsymbol(sc);
+    else if (e)
+        s = getDsymbol(e);
+
+    return s;
+}
+
 void TypeTraits::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool)
 {
     *pt = NULL;
@@ -5816,6 +5909,90 @@  d_uns64 TypeTraits::size(Loc)
     return SIZE_INVALID;
 }
 
+/***************************** TypeMixin *****************************/
+
+/******
+ * Implements mixin types.
+ *
+ * Semantic analysis will convert it to a real type.
+ */
+TypeMixin::TypeMixin(const Loc &loc, Expressions *exps)
+    : Type(Tmixin)
+{
+    this->loc = loc;
+    this->exps = exps;
+    this->obj = NULL; // cached result of semantic analysis.
+}
+
+const char *TypeMixin::kind()
+{
+    return "mixin";
+}
+
+Type *TypeMixin::syntaxCopy()
+{
+    return new TypeMixin(loc, Expression::arraySyntaxCopy(exps));
+}
+
+Dsymbol *TypeMixin::toDsymbol(Scope *sc)
+{
+    Type *t = NULL;
+    Expression *e = NULL;
+    Dsymbol *s = NULL;
+    resolve(loc, sc, &e, &t, &s);
+    if (t)
+        s = t->toDsymbol(sc);
+    else if (e)
+        s = getDsymbol(e);
+
+    return s;
+}
+
+void TypeMixin::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid)
+{
+    // if already resolved just set pe/pt/ps and return.
+    if (obj)
+    {
+        *pe = isExpression(obj);
+        *pt = isType(obj);
+        *ps = isDsymbol(obj);
+        return;
+    }
+
+    RootObject *o = compileTypeMixin(this, loc, sc);
+    if (Type *t = isType(o))
+    {
+        t->resolve(loc, sc, pe, pt, ps, intypeid);
+        if (*pt)
+            (*pt) = (*pt)->addMod(mod);
+    }
+    else if (Expression *e = isExpression(o))
+    {
+        e = expressionSemantic(e, sc);
+        if (TypeExp *et = e->isTypeExp())
+        {
+            *pe = NULL;
+            *pt = et->type->addMod(mod);
+            *ps = NULL;
+        }
+        else
+        {
+            *pe = e;
+            *pt = NULL;
+            *ps = NULL;
+        }
+    }
+    else
+    {
+        *pe = NULL;
+        *pt = Type::terror;
+        *ps = NULL;
+    }
+
+    // save the result
+    obj = *pe ? (RootObject *)*pe : (*pt ? (RootObject *)*pt : (RootObject *)*ps);
+}
+
 /***************************** TypeQualified *****************************/
 
 TypeQualified::TypeQualified(TY ty, Loc loc)
@@ -6003,11 +6180,25 @@  void TypeQualified::resolveHelper(Loc loc, Scope *sc,
 
             Type *t = s->getType();     // type symbol, type alias, or type tuple?
             unsigned errorsave = global.errors;
-            Dsymbol *sm = s->searchX(loc, sc, id);
-            if (sm && !(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+            int flags = t == NULL ? SearchLocalsOnly : IgnorePrivateImports;
+            Dsymbol *sm = s->searchX(loc, sc, id, flags);
+            if (sm)
             {
-                ::error(loc, "`%s` is not visible from module `%s`", sm->toPrettyChars(), sc->_module->toChars());
-                sm = NULL;
+                if (!(sc->flags & SCOPEignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+                {
+                    ::error(loc, "`%s` is not visible from module `%s`", sm->toPrettyChars(), sc->_module->toChars());
+                    sm = NULL;
+                }
+                // Same check as in Expression::semanticY(DotIdExp)
+                else if (sm->isPackage() && checkAccess(sc, (Package *)sm))
+                {
+                    // @@@DEPRECATED_2.096@@@
+                    // Should be an error in 2.106. Just remove the deprecation call
+                    // and uncomment the null assignment
+                    ::deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'",
+                         sm->kind(), sm->toPrettyChars(), sm->toPrettyChars());
+                    //sm = null;
+                }
             }
             if (global.errors != errorsave)
             {
@@ -6052,7 +6243,7 @@  void TypeQualified::resolveHelper(Loc loc, Scope *sc,
                     sm = t->toDsymbol(sc);
                     if (sm && id->dyncast() == DYNCAST_IDENTIFIER)
                     {
-                        sm = sm->search(loc, (Identifier *)id);
+                        sm = sm->search(loc, (Identifier *)id, IgnorePrivateImports);
                         if (sm)
                             goto L2;
                     }
@@ -8177,6 +8368,49 @@  Expression *TypeNull::defaultInit(Loc)
     return new NullExp(Loc(), Type::tnull);
 }
 
+/***************************** TypeNoreturn *****************************/
+
+TypeNoreturn::TypeNoreturn()
+    : Type(Tnoreturn)
+{
+    //printf("TypeNoreturn %p\n", this);
+}
+
+const char *TypeNoreturn::kind()
+{
+    return "noreturn";
+}
+
+Type *TypeNoreturn::syntaxCopy()
+{
+    // No semantic analysis done, no need to copy
+    return this;
+}
+
+MATCH TypeNoreturn::implicitConvTo(Type *to)
+{
+    //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
+    //printf("from: %s\n", toChars());
+    //printf("to  : %s\n", to.toChars());
+    MATCH m = Type::implicitConvTo(to);
+    return (m == MATCHexact) ? MATCHexact : MATCHconvert;
+}
+
+bool TypeNoreturn::isBoolean()
+{
+    return true;  // bottom type can be implicitly converted to any other type
+}
+
+d_uns64 TypeNoreturn::size(Loc)
+{
+    return 0;
+}
+
+unsigned TypeNoreturn::alignsize()
+{
+    return 0;
+}
+
 /***********************************************************
  * Encapsulate Parameters* so .length and [i] can be used on it.
  * https://dlang.org/spec/function.html#ParameterList
@@ -8472,3 +8706,25 @@  bool Parameter::isCovariantScope(bool returnByRef, StorageClass from, StorageCla
 
     return covariant[SR::buildSR(returnByRef, from)][SR::buildSR(returnByRef, to)];
 }
+
+/**
+ * For printing two types with qualification when necessary.
+ * Params:
+ *    t1 = The first type to receive the type name for
+ *    t2 = The second type to receive the type name for
+ * Returns:
+ *    The fully-qualified names of both types if the two type names are not the same,
+ *    or the unqualified names of both types if the two type names are the same.
+ */
+void toAutoQualChars(const char **result, Type *t1, Type *t2)
+{
+    const char *s1 = t1->toChars();
+    const char *s2 = t2->toChars();
+    if (strcmp(s1, s2) == 0)
+    {
+        s1 = t1->toPrettyChars(true);
+        s2 = t2->toPrettyChars(true);
+    }
+    result[0] = s1;
+    result[1] = s2;
+}
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 083d707f8f3..3687053488d 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -96,6 +96,8 @@  enum ENUMTY
     Tint128,
     Tuns128,
     Ttraits,
+    Tmixin,
+    Tnoreturn,
     TMAX
 };
 typedef unsigned char TY;       // ENUMTY
@@ -201,6 +203,7 @@  public:
     static Type *tdstring;              // immutable(dchar)[]
     static Type *terror;                // for error recovery
     static Type *tnull;                 // for null type
+    static Type *tnoreturn;             // for bottom type typeof(*null)
 
     static Type *tsize_t;               // matches size_t alias
     static Type *tptrdiff_t;            // matches ptrdiff_t alias
@@ -367,7 +370,9 @@  public:
     TypeTuple *isTypeTuple();
     TypeSlice *isTypeSlice();
     TypeNull *isTypeNull();
+    TypeMixin *isTypeMixin();
     TypeTraits *isTypeTraits();
+    TypeNoreturn *isTypeNoreturn();
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -686,7 +691,7 @@  public:
     int attributesApply(void *param, int (*fp)(void *, const char *), TRUSTformat trustFormat = TRUSTformatDefault);
 
     Type *substWildTo(unsigned mod);
-    MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0);
+    MATCH callMatch(Type *tthis, Expressions *toargs, int flag = 0, const char **pMessage = NULL);
     bool checkRetType(Loc loc);
 
     Expression *defaultInit(Loc loc) /*const*/;
@@ -726,11 +731,27 @@  public:
 
     TypeTraits(const Loc &loc, TraitsExp *exp);
     Type *syntaxCopy();
+    Dsymbol *toDsymbol(Scope *sc);
     void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
     d_uns64 size(Loc loc);
     void accept(Visitor *v) { v->visit(this); }
 };
 
+class TypeMixin : public Type
+{
+public:
+    Loc loc;
+    Expressions *exps;
+    RootObject *obj;
+
+    TypeMixin(const Loc &loc, Expressions *exps);
+    const char *kind();
+    Type *syntaxCopy();
+    Dsymbol *toDsymbol(Scope *sc);
+    void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps, bool intypeid = false);
+    void accept(Visitor *v) { v->visit(this); }
+};
+
 class TypeQualified : public Type
 {
 public:
@@ -966,6 +987,21 @@  public:
     void accept(Visitor *v) { v->visit(this); }
 };
 
+class TypeNoreturn : public Type
+{
+public:
+    TypeNoreturn();
+    const char *kind();
+
+    Type *syntaxCopy();
+    MATCH implicitConvTo(Type *to);
+    bool isBoolean() /*const*/;
+
+    d_uns64 size(Loc loc) /*const*/;
+    unsigned alignsize();
+    void accept(Visitor *v) { v->visit(this); }
+};
+
 /**************************************************************/
 
 bool arrayTypeCompatible(Loc loc, Type *t1, Type *t2);
diff --git a/gcc/d/dmd/parse.c b/gcc/d/dmd/parse.c
index c050b050404..e1f13214d58 100644
--- a/gcc/d/dmd/parse.c
+++ b/gcc/d/dmd/parse.c
@@ -328,11 +328,9 @@  Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes
                     {
                         // mixin(string)
                         nextToken();
-                        check(TOKlparen, "mixin");
-                        Expression *e = parseAssignExp();
-                        check(TOKrparen);
+                        Expressions *exps = parseArguments();
                         check(TOKsemicolon);
-                        s = new CompileDeclaration(loc, e);
+                        s = new CompileDeclaration(loc, exps);
                         break;
                     }
                     case TOKtemplate:
@@ -1336,7 +1334,7 @@  LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle, bool *pc
                             }
                             else if (!Identifier::isValidIdentifier(name))
                             {
-                                error("expected valid identifer for C++ namespace but got `%s`", name);
+                                error("expected valid identifier for C++ namespace but got `%s`", name);
                                 idents = NULL;
                                 break;
                             }
@@ -2922,6 +2920,18 @@  Objects *Parser::parseTemplateArguments()
     return tiargs;
 }
 
+/***************************************
+ * Parse a Type or an Expression
+ * Returns:
+ *  RootObject representing the AST
+ */
+RootObject *Parser::parseTypeOrAssignExp(TOK endtoken)
+{
+    return isDeclaration(&token, 0, endtoken, NULL)
+        ? (RootObject *)parseType()           // argument is a type
+        : (RootObject *)parseAssignExp();     // argument is an expression
+}
+
 /******************************************
  * Parse template argument list.
  * Input:
@@ -2942,20 +2952,10 @@  Objects *Parser::parseTemplateArgumentList()
     // Get TemplateArgumentList
     while (token.value != endtok)
     {
-            // See if it is an Expression or a Type
-            if (isDeclaration(&token, 0, TOKreserved, NULL))
-            {   // Template argument is a type
-                Type *ta = parseType();
-                tiargs->push(ta);
-            }
-            else
-            {   // Template argument is an expression
-                Expression *ea = parseAssignExp();
-                tiargs->push(ea);
-            }
-            if (token.value != TOKcomma)
-                break;
-            nextToken();
+        tiargs->push(parseTypeOrAssignExp());
+        if (token.value != TOKcomma)
+            break;
+        nextToken();
     }
     check(endtok, "template argument list");
     return tiargs;
@@ -3288,6 +3288,15 @@  Type *Parser::parseBasicType(bool dontLookDotIdents)
             }
             break;
 
+        case TOKmixin:
+            // https://dlang.org/spec/expression.html#mixin_types
+            loc = token.loc;
+            nextToken();
+            if (token.value != TOKlparen)
+                error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`");
+            t = new TypeMixin(loc, parseArguments());
+            break;
+
         case TOKdot:
             // Leading . as in .foo
             t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
@@ -3602,7 +3611,7 @@  Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
             if (pident)
                 *pident = token.ident;
             else
-                error("unexpected identifer `%s` in declarator", token.ident->toChars());
+                error("unexpected identifier `%s` in declarator", token.ident->toChars());
             ts = t;
             nextToken();
             break;
@@ -3863,6 +3872,21 @@  void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
     }
 }
 
+static void parseAttributes(Parser *p, bool &hasParsedAttributes,
+    StorageClass &storage_class, LINK &link, bool &setAlignment,
+    Expression *&ealign, Expressions *&udas)
+{
+    if (hasParsedAttributes) // only parse once
+        return;
+    hasParsedAttributes = true;
+    udas = NULL;
+    storage_class = STCundefined;
+    link = p->linkage;
+    setAlignment = false;
+    ealign = NULL;
+    p->parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
+}
+
 /**********************************
  * Parse Declarations.
  * These can be:
@@ -3936,26 +3960,48 @@  Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
                 bool hasParsedAttributes = false;
                 if (token.value == TOKat)
                 {
-                    if (!hasParsedAttributes)
-                    {
-                        hasParsedAttributes = true;
-                        storage_class = STCundefined;
-                        link = linkage;
-                        setAlignment = false;
-                        ealign = NULL;
-                        udas = NULL;
-                        parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
-                    }
+                    parseAttributes(this, hasParsedAttributes,
+                        storage_class, link, setAlignment, ealign, udas);
                 }
 
                 Declaration *v;
-                if (token.value == TOKfunction ||
+                Dsymbol *s;
+
+                // try to parse function type:
+                // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
+                bool attributesAppended = false;
+                const StorageClass funcStc = parseTypeCtor();
+                Token *tlu = &token;
+                if (token.value != TOKfunction &&
+                    token.value != TOKdelegate &&
+                    isBasicType(&tlu) && tlu &&
+                    tlu->value == TOKlparen)
+                {
+                    VarArg vargs;
+                    Type *tret = parseBasicType();
+                    Parameters *prms = parseParameters(&vargs);
+                    ParameterList pl = ParameterList(prms, vargs);
+
+                    parseAttributes(this, hasParsedAttributes,
+                        storage_class, link, setAlignment, ealign, udas);
+                    if (udas)
+                        error("user-defined attributes not allowed for `alias` declarations");
+
+                    attributesAppended = true;
+                    storage_class = appendStorageClass(storage_class, funcStc);
+                    Type *tf = new TypeFunction(pl, tret, link, storage_class);
+                    v = new AliasDeclaration(loc, ident, tf);
+                }
+                else if (token.value == TOKfunction ||
                     token.value == TOKdelegate ||
                     (token.value == TOKlparen &&
                      skipAttributes(peekPastParen(&token), &tk) &&
                      (tk->value == TOKgoesto || tk->value == TOKlcurly)) ||
                     token.value == TOKlcurly ||
-                    (token.value == TOKidentifier && peekNext() == TOKgoesto))
+                    (token.value == TOKidentifier && peekNext() == TOKgoesto) ||
+                    (token.value == TOKref && peekNext() == TOKlparen &&
+                     skipAttributes(peekPastParen(peek(&token)), &tk) &&
+                     (tk->value == TOKgoesto || tk->value == TOKlcurly)))
                 {
                     // function (parameters) { statements... }
                     // delegate (parameters) { statements... }
@@ -3963,8 +4009,10 @@  Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
                     // (parameters) => expression
                     // { statements... }
                     // identifier => expression
+                    // ref (parameters) { statements... }
+                    // ref (parameters) => expression
 
-                    Dsymbol *s = parseFunctionLiteral();
+                    s = parseFunctionLiteral();
 
                     if (udas != NULL)
                     {
@@ -3985,26 +4033,19 @@  Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, con
                 else
                 {
                     // StorageClasses type
-                    if (!hasParsedAttributes)
-                    {
-                        hasParsedAttributes = true;
-                        storage_class = STCundefined;
-                        link = linkage;
-                        setAlignment = false;
-                        ealign = NULL;
-                        udas = NULL;
-                        parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
-                    }
-
+                    parseAttributes(this, hasParsedAttributes,
+                        storage_class, link, setAlignment, ealign, udas);
                     if (udas)
                         error("user-defined attributes not allowed for %s declarations", Token::toChars(tok));
 
                     t = parseType();
                     v = new AliasDeclaration(loc, ident, t);
                 }
+                if (!attributesAppended)
+                    storage_class = appendStorageClass(storage_class, funcStc);
                 v->storage_class = storage_class;
 
-                Dsymbol *s = v;
+                s = v;
                 if (tpl)
                 {
                     Dsymbols *a2 = new Dsymbols();
@@ -4358,6 +4399,13 @@  Dsymbol *Parser::parseFunctionLiteral()
         case TOKdelegate:
             save = token.value;
             nextToken();
+            if (token.value == TOKref)
+            {
+                // function ref (parameters) { statements... }
+                // delegate ref (parameters) { statements... }
+                stc = STCref;
+                nextToken();
+            }
             if (token.value != TOKlparen && token.value != TOKlcurly)
             {
                 // function type (parameters) { statements... }
@@ -4377,14 +4425,22 @@  Dsymbol *Parser::parseFunctionLiteral()
                 // delegate { statements... }
                 break;
             }
-            /* fall through */
+            goto LTOKlparen;
+
+        case TOKref:
+            // ref (parameters) => expression
+            // ref (parameters) { statements... }
+            stc = STCref;
+            nextToken();
+            goto LTOKlparen;
 
         case TOKlparen:
+        LTOKlparen:
         {
             // (parameters) => expression
             // (parameters) { statements... }
             parameters = parseParameters(&varargs, &tpl);
-            stc = parsePostfix(STCundefined, NULL);
+            stc = parsePostfix(stc, NULL);
             if (StorageClass modStc = stc & STC_TYPECTOR)
             {
                 if (save == TOKfunction)
@@ -5093,7 +5149,7 @@  Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl)
         check(TOKrparen);
         Loc endloc;
         Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
-        if (isRange) 
+        if (isRange)
             *isRange = false;
         return new ForeachStatement(loc, op, parameters, aggr, body, endloc);
     }
@@ -5378,15 +5434,19 @@  Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc
         }
 
         case TOKmixin:
-        {   Token *t = peek(&token);
+        {
+            if (isDeclaration(&token, 3, TOKreserved, NULL))
+                goto Ldeclaration;
+            Token *t = peek(&token);
             if (t->value == TOKlparen)
-            {   // mixin(string)
+            {
+                // mixin(string)
                 Expression *e = parseAssignExp();
                 check(TOKsemicolon);
                 if (e->op == TOKmixin)
                 {
                     CompileExp *cpe = (CompileExp *)e;
-                    s = new CompileStatement(loc, cpe->e1);
+                    s = new CompileStatement(loc, cpe->exps);
                 }
                 else
                 {
@@ -6332,6 +6392,7 @@  bool Parser::isBasicType(Token **pt)
 
         case TOKtypeof:
         case TOKvector:
+        case TOKmixin:
             /* typeof(exp).identifier...
              */
             t = peek(t);
@@ -6592,9 +6653,11 @@  bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, boo
             case TOKin:
             case TOKout:
             case TOKdo:
+            LTOKdo:
                 // The !parens is to disallow unnecessary parentheses
                 if (!parens && (endtok == TOKreserved || endtok == t->value))
-                {   *pt = t;
+                {
+                    *pt = t;
                     return true;
                 }
                 return false;
@@ -6602,6 +6665,12 @@  bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, boo
             case TOKif:
                 return haveTpl ? true : false;
 
+            // Used for mixin type parsing
+            case TOKeof:
+                if (endtok == TOKeof)
+                    goto LTOKdo;
+                return false;
+
             default:
             Ldefault:
                 return false;
@@ -7229,15 +7298,7 @@  Expression *Parser::parsePrimaryExp()
         {
             nextToken();
             check(TOKlparen, "typeid");
-            RootObject *o;
-            if (isDeclaration(&token, 0, TOKreserved, NULL))
-            {   // argument is a type
-                o = parseType();
-            }
-            else
-            {   // argument is an expression
-                o = parseAssignExp();
-            }
+            RootObject *o = parseTypeOrAssignExp();
             check(TOKrparen);
             e = new TypeidExp(loc, o);
             break;
@@ -7279,6 +7340,14 @@  Expression *Parser::parsePrimaryExp()
             if (token.value == TOKlparen)
             {
                 nextToken();
+                if (token.value == TOKidentifier && peekNext() == TOKlparen)
+                {
+                    error(loc, "unexpected `(` after `%s`, inside `is` expression. Try enclosing the contents of `is` with a `typeof` expression", token.toChars());
+                    nextToken();
+                    Token *tempTok = peekPastParen(&token);
+                    memcpy(&token, tempTok, sizeof(Token));
+                    goto Lerr;
+                }
                 targ = parseType(&ident);
                 if (token.value == TOKcolon || token.value == TOKequal)
                 {
@@ -7357,11 +7426,11 @@  Expression *Parser::parsePrimaryExp()
 
         case TOKmixin:
         {
+            // https://dlang.org/spec/expression.html#mixin_expressions
             nextToken();
-            check(TOKlparen, "mixin");
-            e = parseAssignExp();
-            check(TOKrparen);
-            e = new CompileExp(loc, e);
+            if (token.value != TOKlparen)
+                error("found `%s` when expecting `%s` following %s", token.toChars(), Token::toChars(TOKlparen), "`mixin`");
+            e = new CompileExp(loc, parseArguments());
             break;
         }
 
@@ -7379,6 +7448,24 @@  Expression *Parser::parsePrimaryExp()
             e = parseNewExp(NULL);
             break;
 
+        case TOKref:
+        {
+            if (peekNext() == TOKlparen)
+            {
+                Token *tk = peekPastParen(peek(&token));
+                if (skipAttributes(tk, &tk) &&
+                    (tk->value == TOKgoesto || tk->value == TOKlcurly))
+                {
+                    // ref (arguments) => expression
+                    // ref (arguments) { statements... }
+                    goto case_delegate;
+                }
+            }
+            nextToken();
+            error("found `%s` when expecting function literal following `ref`", token.toChars());
+            goto Lerr;
+        }
+
         case TOKlparen:
         {
             Token *tk = peekPastParen(&token);
diff --git a/gcc/d/dmd/parse.h b/gcc/d/dmd/parse.h
index 82ce3254607..a2ad47882ef 100644
--- a/gcc/d/dmd/parse.h
+++ b/gcc/d/dmd/parse.h
@@ -83,6 +83,7 @@  public:
     TemplateParameters *parseTemplateParameterList(int flag = 0);
     Dsymbol *parseMixin();
     Objects *parseTemplateArguments();
+    RootObject *parseTypeOrAssignExp(TOK endtoken = TOKreserved);
     Objects *parseTemplateArgumentList();
     Objects *parseTemplateSingleArgument();
     StaticAssert *parseStaticAssert();
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index ea3bf3874e1..ea3061b8fa6 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -66,6 +66,10 @@  enum PINLINE;
 #define SCOPEfullinst       0x10000 // fully instantiate templates
 #define SCOPEalias          0x20000 // inside alias declaration
 
+// The following are mutually exclusive
+#define SCOPEprintf         0x40000 // printf-style function
+#define SCOPEscanf          0x80000 // scanf-style function
+
 struct Scope
 {
     Scope *enclosing;           // enclosing Scope
diff --git a/gcc/d/dmd/semantic2.c b/gcc/d/dmd/semantic2.c
index 7bcf6ce4f33..194a3fb9661 100644
--- a/gcc/d/dmd/semantic2.c
+++ b/gcc/d/dmd/semantic2.c
@@ -163,6 +163,15 @@  public:
         if (vd->_init && !vd->toParent()->isFuncDeclaration())
         {
             vd->inuse++;
+
+            /* https://issues.dlang.org/show_bug.cgi?id=20280
+             *
+             * Template instances may import modules that have not
+             * finished semantic1.
+             */
+            if (!vd->type)
+                dsymbolSemantic(vd, sc);
+
             // Bugzilla 14166: Don't run CTFE for the temporary variables inside typeof
             vd->_init = initializerSemantic(vd->_init, sc, vd->type, sc->intypeof == 1 ? INITnointerpret : INITinterpret);
             vd->inuse--;
@@ -265,6 +274,17 @@  public:
     {
         if (fd->semanticRun >= PASSsemantic2done)
             return;
+
+        if (fd->semanticRun < PASSsemanticdone && !fd->errors)
+        {
+            /* https://issues.dlang.org/show_bug.cgi?id=21614
+             *
+             * Template instances may import modules that have not
+             * finished semantic1.
+             */
+            dsymbolSemantic(fd, sc);
+        }
+
         assert(fd->semanticRun <= PASSsemantic2);
         fd->semanticRun = PASSsemantic2;
 
diff --git a/gcc/d/dmd/semantic3.c b/gcc/d/dmd/semantic3.c
index 304eaeeb119..6bd9a6d2e27 100644
--- a/gcc/d/dmd/semantic3.c
+++ b/gcc/d/dmd/semantic3.c
@@ -850,32 +850,18 @@  public:
                     }
                     assert(!funcdecl->returnLabel);
                 }
+                else if (f->next->ty == Tnoreturn)
+                {
+                }
                 else
                 {
                     const bool inlineAsm = (funcdecl->hasReturnExp & 8) != 0;
                     if ((blockexit & BEfallthru) && f->next->ty != Tvoid && !inlineAsm)
                     {
-                        Expression *e;
                         if (!funcdecl->hasReturnExp)
-                            funcdecl->error("has no return statement, but is expected to return a value of type %s", f->next->toChars());
-                        else
-                            funcdecl->error("no return exp; or assert(0); at end of function");
-                        if (global.params.useAssert == CHECKENABLEon &&
-                            !global.params.useInline)
-                        {
-                            /* Add an assert(0, msg); where the missing return
-                             * should be.
-                             */
-                            e = new AssertExp(funcdecl->endloc,
-                                              new IntegerExp(0),
-                                              new StringExp(funcdecl->loc, const_cast<char *>("missing return expression")));
-                        }
+                            funcdecl->error("has no `return` statement, but is expected to return a value of type `%s`", f->next->toChars());
                         else
-                            e = new HaltExp(funcdecl->endloc);
-                        e = new CommaExp(Loc(), e, f->next->defaultInit());
-                        e = expressionSemantic(e, sc2);
-                        Statement *s = new ExpStatement(Loc(), e);
-                        funcdecl->fbody = new CompoundStatement(Loc(), funcdecl->fbody, s);
+                            funcdecl->error("no `return exp;` or `assert(0);` at end of function");
                     }
                 }
 
@@ -1162,15 +1148,7 @@  public:
 
                     if (cd)
                     {
-                        if (!global.params.is64bit &&
-                            global.params.isWindows &&
-                            !funcdecl->isStatic() && !sbody->usesEH() && !global.params.trace)
-                        {
-                            /* The back end uses the "jmonitor" hack for syncing;
-                             * no need to do the sync at this level.
-                             */
-                        }
-                        else
+                        if (target.libraryObjectMonitors(funcdecl, sbody))
                         {
                             Expression *vsync;
                             if (funcdecl->isStatic())
diff --git a/gcc/d/dmd/statement.c b/gcc/d/dmd/statement.c
index 2f7b7e13ffc..1f8e5122b1a 100644
--- a/gcc/d/dmd/statement.c
+++ b/gcc/d/dmd/statement.c
@@ -31,6 +31,7 @@  StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration *f);
 bool checkEscapeRef(Scope *sc, Expression *e, bool gag);
 VarDeclaration *copyToTemp(StorageClass stc, const char *name, Expression *e);
 Statement *makeTupleForeachStatic(Scope *sc, ForeachStatement *fs, bool needExpansion);
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
 
 Identifier *fixupLabelName(Scope *sc, Identifier *ident)
 {
@@ -504,12 +505,19 @@  Statement *DtorExpStatement::syntaxCopy()
 CompileStatement::CompileStatement(Loc loc, Expression *exp)
     : Statement(loc)
 {
-    this->exp = exp;
+    this->exps = new Expressions();
+    this->exps->push(exp);
+}
+
+CompileStatement::CompileStatement(Loc loc, Expressions *exps)
+    : Statement(loc)
+{
+    this->exps = exps;
 }
 
 Statement *CompileStatement::syntaxCopy()
 {
-    return new CompileStatement(loc, exp->syntaxCopy());
+    return new CompileStatement(loc, Expression::arraySyntaxCopy(exps));
 }
 
 static Statements *errorStatements()
@@ -519,32 +527,36 @@  static Statements *errorStatements()
     return a;
 }
 
-Statements *CompileStatement::flatten(Scope *sc)
+static Statements *compileIt(CompileStatement *cs, Scope *sc)
 {
-    //printf("CompileStatement::flatten() %s\n", exp->toChars());
-    StringExp *se = semanticString(sc, exp, "argument to mixin");
-    if (!se)
+    //printf("CompileStatement::compileIt() %s\n", exp->toChars());
+    OutBuffer buf;
+    if (expressionsToString(buf, sc, cs->exps))
         return errorStatements();
-    se = se->toUTF8(sc);
 
     unsigned errors = global.errors;
-    Parser p(loc, sc->_module, (utf8_t *)se->string, se->len, 0);
+    const size_t len = buf.length();
+    const char *str = buf.extractChars();
+    Parser p(cs->loc, sc->_module, (const utf8_t *)str, len, false);
     p.nextToken();
 
     Statements *a = new Statements();
     while (p.token.value != TOKeof)
     {
         Statement *s = p.parseStatement(PSsemi | PScurlyscope);
-        if (!s || p.errors)
-        {
-            assert(!p.errors || global.errors != errors); // make sure we caught all the cases
+        if (!s || global.errors != errors)
             return errorStatements();
-        }
         a->push(s);
     }
     return a;
 }
 
+Statements *CompileStatement::flatten(Scope *sc)
+{
+    //printf("CompileStatement::flatten() %s\n", exp->toChars());
+    return compileIt(this, sc);
+}
+
 /******************************** CompoundStatement ***************************/
 
 CompoundStatement::CompoundStatement(Loc loc, Statements *s)
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index 2d8b46c9487..c64e51a5be7 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -173,9 +173,10 @@  public:
 class CompileStatement : public Statement
 {
 public:
-    Expression *exp;
+    Expressions *exps;
 
     CompileStatement(Loc loc, Expression *exp);
+    CompileStatement(Loc loc, Expressions *exps);
     Statement *syntaxCopy();
     Statements *flatten(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/statementsem.c b/gcc/d/dmd/statementsem.c
index 5579c1ca893..491d9c9bce9 100644
--- a/gcc/d/dmd/statementsem.c
+++ b/gcc/d/dmd/statementsem.c
@@ -581,7 +581,7 @@  public:
                         {
                             fs->error("constant value %s cannot be ref", ie->toChars());
                         }
-                        else 
+                        else
                         {
                             fs->error("constant value %s cannot be ref", ident->toChars());
                         }
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index a91880fd0fc..f8f977c9aea 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -21,6 +21,7 @@  class Dsymbol;
 class Expression;
 class FuncDeclaration;
 class Parameter;
+class Statement;
 class Type;
 class TypeFunction;
 class TypeTuple;
@@ -30,6 +31,7 @@  struct TargetC
 {
     unsigned longsize;            // size of a C 'long' or 'unsigned long' type
     unsigned long_doublesize;     // size of a C 'long double'
+    Type *twchar_t;               // C 'wchar_t' type
 };
 
 struct TargetCPP
@@ -44,6 +46,7 @@  struct TargetCPP
     const char *typeMangle(Type *t);
     Type *parameterType(Parameter *p);
     bool fundamentalType(const Type *t, bool& isFundamental);
+    unsigned derivedClassOffset(ClassDeclaration *baseClass);
 };
 
 struct TargetObjC
@@ -108,6 +111,7 @@  public:
     TypeTuple *toArgTypes(Type *t);
     bool isReturnOnStack(TypeFunction *tf, bool needsThis);
     Expression *getTargetInfo(const char* name, const Loc& loc);
+    bool libraryObjectMonitors(FuncDeclaration *fd, Statement *fbody);
 };
 
 extern Target target;
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index dac1e85b433..fb842ac5b76 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -78,6 +78,7 @@  public:
     bool ismixin;               // template declaration is only to be used as a mixin
     bool isstatic;              // this is static template declaration
     Prot protection;
+    int inuse;                  // for recursive expansion detection
 
     TemplatePrevious *previous;         // threaded list of previous instantiation attempts on stack
 
diff --git a/gcc/d/dmd/templateparamsem.c b/gcc/d/dmd/templateparamsem.c
index 11cd52e351b..d3e9b2390e9 100644
--- a/gcc/d/dmd/templateparamsem.c
+++ b/gcc/d/dmd/templateparamsem.c
@@ -25,7 +25,7 @@  public:
     {
         this->sc = sc;
         this->parameters = parameters;
-	this->result = false;
+        this->result = false;
     }
 
     void visit(TemplateTypeParameter *ttp)
diff --git a/gcc/d/dmd/traits.c b/gcc/d/dmd/traits.c
index b7c612c2af2..99b5457f031 100644
--- a/gcc/d/dmd/traits.c
+++ b/gcc/d/dmd/traits.c
@@ -40,6 +40,8 @@  void freeFieldinit(Scope *sc);
 Expression *resolve(Loc loc, Scope *sc, Dsymbol *s, bool hasOverloads);
 Package *resolveIsPackage(Dsymbol *sym);
 Expression *typeToExpression(Type *t);
+Type *decoToType(const char *deco);
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
 
 
 /************************************************
@@ -442,7 +444,6 @@  TraitsInitializer::TraitsInitializer()
         "derivedMembers",
         "isSame",
         "compiles",
-        "parameters",
         "getAliasThis",
         "getAttributes",
         "getFunctionAttributes",
@@ -1032,6 +1033,34 @@  Expression *semanticTraits(TraitsExp *e, Scope *sc)
         ex = expressionSemantic(ex, sc);
         return ex;
     }
+    else if (e->ident == Id::toType)
+    {
+        if (dim != 1)
+            return dimError(e, 1, dim);
+
+        Expression *ex = isExpression((*e->args)[0]);
+        if (!ex)
+        {
+            e->error("expression expected as second argument of __traits `%s`", e->ident->toChars());
+            return new ErrorExp();
+        }
+        ex = ex->ctfeInterpret();
+
+        StringExp *se = semanticString(sc, ex, "__traits(toType, string)");
+        if (!se)
+        {
+            return new ErrorExp();
+        }
+        Type *t = decoToType(se->toUTF8(sc)->toPtr());
+        if (!t)
+        {
+            e->error("cannot determine `%s`", e->toChars());
+            return new ErrorExp();
+        }
+        ex = new TypeExp(e->loc, t);
+        ex = expressionSemantic(ex, sc);
+        return ex;
+    }
     else if (e->ident == Id::hasMember ||
              e->ident == Id::getMember ||
              e->ident == Id::getOverloads ||
@@ -1674,33 +1703,67 @@  Expression *semanticTraits(TraitsExp *e, Scope *sc)
 
             RootObject *o = (*e->args)[i];
             Type *t = isType(o);
-            Expression *ex = t ? typeToExpression(t) : isExpression(o);
-            if (!ex && t)
+            while (t)
             {
-                Dsymbol *s;
-                t->resolve(e->loc, sc2, &ex, &t, &s);
-                if (t)
+                if (TypeMixin *tm = t->isTypeMixin())
                 {
-                    typeSemantic(t, e->loc, sc2);
-                    if (t->ty == Terror)
+                    /* The mixin string could be a type or an expression.
+                     * Have to try compiling it to see.
+                     */
+                    OutBuffer buf;
+                    if (expressionsToString(buf, sc, tm->exps))
+                    {
+                        err = true;
+                        break;
+                    }
+                    const size_t len = buf.length();
+                    const char *str = buf.extractChars();
+                    Parser p(e->loc, sc->_module, (const utf8_t *)str, len, false);
+                    p.nextToken();
+                    //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
+                    o = p.parseTypeOrAssignExp(TOKeof);
+                    if (p.errors || p.token.value != TOKeof)
+                    {
                         err = true;
+                        break;
+                    }
+                    t = isType(o);
                 }
-                else if (s && s->errors)
-                    err = true;
+                else
+                    break;
             }
-            if (ex)
+
+            if (!err)
             {
-                ex = expressionSemantic(ex, sc2);
-                ex = resolvePropertiesOnly(sc2, ex);
-                ex = ex->optimize(WANTvalue);
-                if (sc2->func && sc2->func->type->ty == Tfunction)
+                Expression *ex = t ? typeToExpression(t) : isExpression(o);
+                if (!ex && t)
                 {
-                    TypeFunction *tf = (TypeFunction *)sc2->func->type;
-                    canThrow(ex, sc2->func, tf->isnothrow);
+                    Dsymbol *s;
+                    t->resolve(e->loc, sc2, &ex, &t, &s);
+                    if (t)
+                    {
+                        typeSemantic(t, e->loc, sc2);
+                        if (t->ty == Terror)
+                            err = true;
+                    }
+                    else if (s && s->errors)
+                        err = true;
+                }
+                if (ex)
+                {
+                    ex = expressionSemantic(ex, sc2);
+                    ex = resolvePropertiesOnly(sc2, ex);
+                    ex = ex->optimize(WANTvalue);
+                    if (sc2->func && sc2->func->type->ty == Tfunction)
+                    {
+                        TypeFunction *tf = (TypeFunction *)sc2->func->type;
+                        canThrow(ex, sc2->func, tf->isnothrow);
+                    }
+                    ex = checkGC(sc2, ex);
+                    if (ex->op == TOKerror)
+                        err = true;
                 }
-                ex = checkGC(sc2, ex);
-                if (ex->op == TOKerror)
-                    err = true;
             }
 
             // Carefully detach the scope from the parent and throw it away as
diff --git a/gcc/d/dmd/typesem.c b/gcc/d/dmd/typesem.c
index 496cfe3a855..670144d1282 100644
--- a/gcc/d/dmd/typesem.c
+++ b/gcc/d/dmd/typesem.c
@@ -18,6 +18,7 @@ 
 #include "hdrgen.h"
 #include "id.h"
 #include "init.h"
+#include "parse.h"
 #include "scope.h"
 #include "target.h"
 #include "template.h"
@@ -25,6 +26,7 @@ 
 
 Expression *typeToExpression(Type *t);
 Expression *typeToExpressionHelper(TypeQualified *t, Expression *e, size_t i = 0);
+bool expressionsToString(OutBuffer &buf, Scope *sc, Expressions *exps);
 char *MODtoChars(MOD mod);
 
 class TypeToExpressionVisitor : public Visitor
@@ -76,6 +78,11 @@  public:
     {
         result = typeToExpressionHelper(t, new ScopeExp(t->loc, t->tempinst));
     }
+
+    void visit(TypeMixin *t)
+    {
+        result = new TypeExp(t->loc, t);
+    }
 };
 
 /* We've mistakenly parsed this as a type.
@@ -84,6 +91,8 @@  public:
  */
 Expression *typeToExpression(Type *t)
 {
+    if (t->mod)
+        return NULL;
     TypeToExpressionVisitor v = TypeToExpressionVisitor(t);
     t->accept(&v);
     return v.result;
@@ -177,6 +186,48 @@  static Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *ex
     return exp;
 }
 
+/******************************************
+ * Compile the MixinType, returning the type or expression AST.
+ *
+ * Doesn't run semantic() on the returned object.
+ * Params:
+ *      tm = mixin to compile as a type or expression
+ *      loc = location for error messages
+ *      sc = context
+ * Return:
+ *      null if error, else RootObject AST as parsed
+ */
+RootObject *compileTypeMixin(TypeMixin *tm, Loc loc, Scope *sc)
+{
+    OutBuffer buf;
+    if (expressionsToString(buf, sc, tm->exps))
+        return NULL;
+
+    const unsigned errors = global.errors;
+    const size_t len = buf.length();
+    const char *str = buf.extractChars();
+    Parser p(loc, sc->_module, (const utf8_t *)str, len, false);
+    p.nextToken();
+    //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
+    RootObject *o = p.parseTypeOrAssignExp(TOKeof);
+    if (errors != global.errors)
+    {
+        assert(global.errors != errors); // should have caught all these cases
+        return NULL;
+    }
+    if (p.token.value != TOKeof)
+    {
+        ::error(loc, "incomplete mixin type `%s`", str);
+        return NULL;
+    }
+
+    Type *t = isType(o);
+    Expression *e = t ? typeToExpression(t) : isExpression(o);
+
+    return (!e && t) ? (RootObject *)t : (RootObject *)e;
+}
+
 /******************************************
  * Perform semantic analysis on a type.
  * Params:
@@ -440,7 +491,7 @@  Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
             // Deal with the case where we thought the index was a type, but
             // in reality it was an expression.
             if (mtype->index->ty == Tident || mtype->index->ty == Tinstance || mtype->index->ty == Tsarray ||
-                mtype->index->ty == Ttypeof || mtype->index->ty == Treturn)
+                mtype->index->ty == Ttypeof || mtype->index->ty == Treturn || mtype->index->ty == Tmixin)
             {
                 Expression *e;
                 Type *t;
@@ -1072,6 +1123,7 @@  Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
                 mtype->exp->ident != Id::getMember &&
                 mtype->exp->ident != Id::parent &&
                 mtype->exp->ident != Id::child &&
+                mtype->exp->ident != Id::toType &&
                 mtype->exp->ident != Id::getOverloads &&
                 mtype->exp->ident != Id::getVirtualFunctions &&
                 mtype->exp->ident != Id::getVirtualMethods &&
@@ -1275,7 +1327,7 @@  Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
 
         void visit(TypeStruct *mtype)
         {
-            //printf("TypeStruct::semantic('%s')\n", mtype->sym->toChars());
+            //printf("TypeStruct::semantic('%s')\n", mtype->toChars());
             if (mtype->deco)
             {
                 if (sc && sc->cppmangle != CPPMANGLEdefault)
@@ -1304,7 +1356,7 @@  Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
 
         void visit(TypeClass *mtype)
         {
-            //printf("TypeClass::semantic(%s)\n", mtype->sym->toChars());
+            //printf("TypeClass::semantic(%s)\n", mtype->toChars());
             if (mtype->deco)
             {
                 if (sc && sc->cppmangle != CPPMANGLEdefault)
@@ -1386,6 +1438,25 @@  Type *typeSemantic(Type *type, const Loc &loc, Scope *sc)
             Type *t = new TypeTuple(args);
             result = typeSemantic(t, loc, sc);
         }
+
+        void visit(TypeMixin *mtype)
+        {
+            //printf("TypeMixin::semantic() %s\n", mtype->toChars());
+
+            Expression *e = NULL;
+            Type *t = NULL;
+            Dsymbol *s = NULL;
+            mtype->resolve(loc, sc, &e, &t, &s);
+
+            if (t && t->ty != Terror)
+            {
+                result = t;
+                return;
+            }
+
+            ::error(mtype->loc, "`mixin(%s)` does not give a valid type", mtype->obj->toChars());
+            return error();
+        }
     };
     TypeSemanticVisitor v(loc, sc);
     type->accept(&v);
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index a274e6f083e..09ba2024e30 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -81,7 +81,9 @@  class TypeClass;
 class TypeTuple;
 class TypeSlice;
 class TypeNull;
+class TypeNoreturn;
 class TypeTraits;
+class TypeMixin;
 
 class Dsymbol;
 
@@ -374,7 +376,9 @@  public:
     virtual void visit(TypeTuple *t) { visit((Type *)t); }
     virtual void visit(TypeSlice *t) { visit((TypeNext *)t); }
     virtual void visit(TypeNull *t) { visit((Type *)t); }
+    virtual void visit(TypeNoreturn *t) { visit((Type *)t); }
     virtual void visit(TypeTraits *t) { visit((Type *)t); }
+    virtual void visit(TypeMixin *t) { visit((Type *)t); }
 
     virtual void visit(Dsymbol *) { assert(0); }
 
diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc
index ee3e3d5bdd5..41d07a7b70e 100644
--- a/gcc/d/toir.cc
+++ b/gcc/d/toir.cc
@@ -1068,6 +1068,13 @@  public:
 
 	add_stmt (return_expr (decl));
       }
+    else if (tf->next->ty == Tnoreturn)
+      {
+	/* Returning an expression that has no value, but has a side effect
+	   that should never return.  */
+	add_stmt (build_expr_dtor (s->exp));
+	add_stmt (return_expr (NULL_TREE));
+      }
     else
       {
 	/* Convert for initializing the DECL_RESULT.  */
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 3cddfc5dd46..924d8298211 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -603,6 +603,12 @@  public:
     t->ctype = ptr_type_node;
   }
 
+  /* Bottom type used for functions that never return.  */
+
+  void visit (TypeNoreturn *t)
+  {
+    t->ctype = void_type_node;
+  }
 
   /* Basic Data Types.  */
 
@@ -852,7 +858,46 @@  public:
     tree basetype = (t->sym->memtype)
       ? build_ctype (t->sym->memtype) : void_type_node;
 
-    if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
+    if (t->sym->isSpecial ())
+      {
+	/* Special enums are opaque types that bind to C types.  */
+	const char *ident = t->toChars ();
+	Type *underlying = NULL;
+
+	/* Skip over the prefixing `__c_'.  */
+	gcc_assert (strncmp (ident, "__c_", strlen ("__c_")) == 0);
+	ident = ident + strlen ("__c_");
+
+	/* To keep things compatible within the code generation we stick to
+	   mapping to equivalent D types.  However it should be OK to use the
+	   GCC provided C types here as the front-end enforces that everything
+	   must be explicitly cast from a D type to any of the opaque types.  */
+	if (strcmp (ident, "long") == 0)
+	  underlying = build_frontend_type (long_integer_type_node);
+	else if (strcmp (ident, "ulong") == 0)
+	  underlying = build_frontend_type (long_unsigned_type_node);
+	else if (strcmp (ident, "wchar_t") == 0)
+	  underlying = target.c.twchar_t;
+	else if (strcmp (ident, "longlong") == 0)
+	  underlying = build_frontend_type (long_long_integer_type_node);
+	else if (strcmp (ident, "ulonglong") == 0)
+	  underlying = build_frontend_type (long_long_unsigned_type_node);
+	else if (strcmp (ident, "long_double") == 0)
+	  underlying = build_frontend_type (long_double_type_node);
+	else if (strcmp (ident, "complex_real") == 0)
+	  underlying = build_frontend_type (complex_long_double_type_node);
+	else if (strcmp (ident, "complex_float") == 0)
+	  underlying = build_frontend_type (complex_float_type_node);
+	else if (strcmp (ident, "complex_double") == 0)
+	  underlying = build_frontend_type (complex_double_type_node);
+
+	/* Conversion failed or there's an unhandled special type.  */
+	gcc_assert (underlying != NULL);
+
+	t->ctype = build_variant_type_copy (build_ctype (underlying));
+	build_type_decl (t->ctype, t->sym);
+      }
+    else if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
       {
 	/* Enums in D2 can have a base type that is not necessarily integral.
 	   For these, we simplify this a little by using the base type directly