diff mbox series

[committed] d: Merge dmd, druntime ceff48bf7d, phobos dcbfbd43a

Message ID 20240225231015.580225-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge dmd, druntime ceff48bf7d, phobos dcbfbd43a | expand

Commit Message

Iain Buclaw Feb. 25, 2024, 11:10 p.m. UTC
Hi,

This patch merges the D front-end and runtime library with upstream dmd
ceff48bf7d, and the standard library with phobos dcbfbd43a.

D front-end changes:

	-   Import latest fixes from dmd v2.107.1-rc.1.

D runtime changes:

	-   Import latest fixes from druntime v2.107.1-rc.1.

Phobos changes:

	-   Import latest fixes from phobos v2.107.1-rc.1.

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

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd ceff48bf7d.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime ceff48bf7d.
	* libdruntime/Makefile.am (DRUNTIME_DSOURCES_FREEBSD): Add
	core/sys/freebsd/net/if_.d.
	* libdruntime/Makefile.in: Regenerate.
	* src/MERGE: Merge upstream phobos dcbfbd43a.
---
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/arrayop.d                           |   2 +-
 gcc/d/dmd/ast_node.h                          |   2 +-
 gcc/d/dmd/common/file.d                       |  89 ++--
 gcc/d/dmd/common/smallbuffer.d                |  30 +-
 gcc/d/dmd/cparse.d                            | 150 +++++-
 gcc/d/dmd/dimport.d                           | 109 +---
 gcc/d/dmd/dmodule.d                           |  32 +-
 gcc/d/dmd/dsymbolsem.d                        |  97 ++++
 gcc/d/dmd/expression.d                        |   4 +-
 gcc/d/dmd/expression.h                        |   2 +-
 gcc/d/dmd/expressionsem.d                     |  97 ++++
 gcc/d/dmd/func.d                              | 394 +-------------
 gcc/d/dmd/funcsem.d                           | 390 ++++++++++++++
 gcc/d/dmd/identifier.h                        |   2 +-
 gcc/d/dmd/importc.d                           |   7 +-
 gcc/d/dmd/mtype.d                             |   1 -
 gcc/d/dmd/parse.d                             |  48 +-
 gcc/d/dmd/root/array.h                        |   3 +-
 gcc/d/dmd/root/bitarray.h                     |   1 -
 gcc/d/dmd/{root/object.h => rootobject.h}     |   6 +-
 gcc/d/dmd/statementsem.d                      |   2 +-
 gcc/d/dmd/staticcond.d                        | 107 ----
 gcc/d/dmd/template.h                          |   2 +-
 .../gdc.test/compilable/imports/defines.c     |  25 +
 .../gdc.test/compilable/testdefines.d         |  10 +
 .../gdc.test/fail_compilation/warn13679.d     |   4 +-
 libphobos/libdruntime/MERGE                   |   2 +-
 libphobos/libdruntime/Makefile.am             |  22 +-
 libphobos/libdruntime/Makefile.in             |  31 +-
 .../libdruntime/core/sys/freebsd/ifaddrs.d    |   3 +-
 .../libdruntime/core/sys/freebsd/net/if_.d    | 493 ++++++++++++++++++
 .../libdruntime/core/sys/linux/sys/socket.d   |   1 -
 libphobos/libdruntime/core/thread/fiber.d     |   2 +-
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/std/typecons.d                  |  35 +-
 36 files changed, 1417 insertions(+), 792 deletions(-)
 rename gcc/d/dmd/{root/object.h => rootobject.h} (91%)
 create mode 100644 libphobos/libdruntime/core/sys/freebsd/net/if_.d
diff mbox series

Patch

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 021149aabc7..f11c5fbfb0b 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-9471b25db9ed44d71e0e27956430c0c6a09c16db
+ceff48bf7db05503117f54fdc0cefcb89b711136
 
 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/arrayop.d b/gcc/d/dmd/arrayop.d
index afe6054f4aa..af3875ea6c5 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -22,7 +22,7 @@  import dmd.dsymbol;
 import dmd.errors;
 import dmd.expression;
 import dmd.expressionsem;
-import dmd.func;
+import dmd.funcsem;
 import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
diff --git a/gcc/d/dmd/ast_node.h b/gcc/d/dmd/ast_node.h
index a24218a86d0..db8608e7cdd 100644
--- a/gcc/d/dmd/ast_node.h
+++ b/gcc/d/dmd/ast_node.h
@@ -10,7 +10,7 @@ 
 
 #pragma once
 
-#include "root/object.h"
+#include "rootobject.h"
 
 class Visitor;
 
diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d
index 8a284241fc2..80677f66ff8 100644
--- a/gcc/d/dmd/common/file.d
+++ b/gcc/d/dmd/common/file.d
@@ -16,24 +16,37 @@  module dmd.common.file;
 
 import core.stdc.errno : errno;
 import core.stdc.stdio : fprintf, remove, rename, stderr;
-import core.stdc.stdlib : exit;
-import core.stdc.string : strerror, strlen;
-import core.sys.windows.winbase;
-import core.sys.windows.winnt;
-import core.sys.posix.fcntl;
-import core.sys.posix.unistd;
+import core.stdc.stdlib;
+import core.stdc.string : strerror, strlen, memcpy;
 
 import dmd.common.smallbuffer;
 
-nothrow:
-
 version (Windows)
 {
+    import core.sys.windows.winbase;
     import core.sys.windows.winnls : CP_ACP;
+    import core.sys.windows.winnt;
+
+    enum CodePage = CP_ACP; // assume filenames encoded in system default Windows ANSI code page
+    enum invalidHandle = INVALID_HANDLE_VALUE;
+}
+else version (Posix)
+{
+    import core.sys.posix.fcntl;
+    import core.sys.posix.sys.mman;
+    import core.sys.posix.sys.stat;
+    import core.sys.posix.unistd;
+    import core.sys.posix.utime;
 
-    // assume filenames encoded in system default Windows ANSI code page
-    enum CodePage = CP_ACP;
+    enum invalidHandle = -1;
 }
+else
+    static assert(0);
+
+
+
+
+nothrow:
 
 /**
 Encapsulated management of a memory-mapped file.
@@ -48,9 +61,6 @@  struct FileMapping(Datum)
     static assert(__traits(isPOD, Datum) && Datum.sizeof == 1,
         "Not tested with other data types yet. Add new types with care.");
 
-    version(Posix) enum invalidHandle = -1;
-    else version(Windows) enum invalidHandle = INVALID_HANDLE_VALUE;
-
     // state {
     /// Handle of underlying file
     private auto handle = invalidHandle;
@@ -82,9 +92,6 @@  struct FileMapping(Datum)
     {
         version (Posix)
         {
-            import core.sys.posix.sys.mman;
-            import core.sys.posix.fcntl : open, O_CREAT, O_RDONLY, O_RDWR, S_IRGRP, S_IROTH, S_IRUSR, S_IWUSR;
-
             handle = open(filename, is(Datum == const) ? O_RDONLY : (O_CREAT | O_RDWR),
                 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 
@@ -150,9 +157,6 @@  struct FileMapping(Datum)
         // Save the name for later. Technically there's no need: on Linux one can use readlink on /proc/self/fd/NNN.
         // On BSD and OSX one can use fcntl with F_GETPATH. On Windows one can use GetFileInformationByHandleEx.
         // But just saving the name is simplest, fastest, and most portable...
-        import core.stdc.string : strlen;
-        import core.stdc.stdlib : malloc;
-        import core.stdc.string : memcpy;
         const totalNameLength = filename.strlen() + 1;
         auto namex = cast(char*) malloc(totalNameLength);
         if (!namex)
@@ -224,9 +228,6 @@  struct FileMapping(Datum)
         fakePure({
             version (Posix)
             {
-                import core.sys.posix.sys.mman : munmap;
-                import core.sys.posix.unistd : close;
-
                 // Cannot call fprintf from inside a destructor, so exiting silently.
 
                 if (data.ptr && munmap(cast(void*) data.ptr, data.length) != 0)
@@ -234,7 +235,7 @@  struct FileMapping(Datum)
                     exit(1);
                 }
                 data = null;
-                if (handle != invalidHandle && close(handle) != 0)
+                if (handle != invalidHandle && .close(handle) != 0)
                 {
                     exit(1);
                 }
@@ -303,7 +304,6 @@  struct FileMapping(Datum)
         // In-memory resource freed, now get rid of the underlying temp file.
         version(Posix)
         {
-            import core.sys.posix.unistd : unlink;
             if (unlink(deleteme) != 0)
             {
                 fprintf(stderr, "unlink(\"%s\") failed: %s\n", filename, strerror(errno));
@@ -312,7 +312,6 @@  struct FileMapping(Datum)
         }
         else version(Windows)
         {
-            import core.sys.windows.winbase;
             if (deleteme[0 .. strlen(deleteme)].extendedPathThen!(p => DeleteFileW(p.ptr)) == 0)
             {
                 fprintf(stderr, "DeleteFileW error %d\n", GetLastError());
@@ -361,9 +360,6 @@  struct FileMapping(Datum)
         fakePure({
             version(Posix)
             {
-                import core.sys.posix.unistd : ftruncate;
-                import core.sys.posix.sys.mman;
-
                 if (data.length)
                 {
                     assert(data.ptr, "Corrupt memory mapping");
@@ -431,7 +427,6 @@  struct FileMapping(Datum)
 
         // Fetch the name and then set it to `null` so it doesn't get deallocated
         auto oldname = name;
-        import core.stdc.stdlib;
         scope(exit) free(cast(void*) oldname);
         name = null;
         close();
@@ -447,7 +442,6 @@  struct FileMapping(Datum)
         }
         else version(Windows)
         {
-            import core.sys.windows.winbase;
             auto r = oldname[0 .. strlen(oldname)].extendedPathThen!(
                 p1 => filename[0 .. strlen(filename)].extendedPathThen!(p2 => MoveFileExW(p1.ptr, p2.ptr, MOVEFILE_REPLACE_EXISTING))
             );
@@ -527,8 +521,6 @@  bool touchFile(const char* namez)
         GetSystemTime(&st);
         SystemTimeToFileTime(&st, &ft);
 
-        import core.stdc.string : strlen;
-
         // get handle to file
         HANDLE h = namez[0 .. namez.strlen()].extendedPathThen!(p => CreateFile(p.ptr,
             FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE,
@@ -546,7 +538,6 @@  bool touchFile(const char* namez)
     }
     else version (Posix)
     {
-        import core.sys.posix.utime;
         return utime(namez, null) == 0;
     }
     else
@@ -560,24 +551,28 @@  Params: fd = file handle
 Returns: file size in bytes, or `ulong.max` on any error.
 */
 version (Posix)
-private ulong fileSize(int fd)
 {
-    import core.sys.posix.sys.stat;
-    stat_t buf;
-    if (fstat(fd, &buf) == 0)
-        return buf.st_size;
-    return ulong.max;
+    private ulong fileSize(int fd)
+    {
+        stat_t buf;
+        if (fstat(fd, &buf) == 0)
+            return buf.st_size;
+        return ulong.max;
+    }
 }
-
-/// Ditto
-version (Windows)
-private ulong fileSize(HANDLE fd)
+else version (Windows)
 {
-    ulong result;
-    if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
-        return result;
-    return ulong.max;
+    /// Ditto
+    private ulong fileSize(HANDLE fd)
+    {
+        ulong result;
+        if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
+            return result;
+        return ulong.max;
+    }
 }
+else
+    static assert(0);
 
 /**
 Runs a non-pure function or delegate as pure code. Use with caution.
diff --git a/gcc/d/dmd/common/smallbuffer.d b/gcc/d/dmd/common/smallbuffer.d
index c6aa7abbc60..608ecc8c6b6 100644
--- a/gcc/d/dmd/common/smallbuffer.d
+++ b/gcc/d/dmd/common/smallbuffer.d
@@ -107,28 +107,30 @@  unittest
 }
 
 /**
-(Windows only) Converts a narrow string to a wide string using `buffer` as strorage. Returns a slice managed by
-`buffer` containing the converted string. The terminating zero is not part of the returned slice,
-but is guaranteed to follow it.
+ * (Windows only) Converts a narrow string to a wide string using `buffer` as strorage.
+ * Params:
+ *    narrow = string to be converted
+ *    buffer = where to place the converted string
+ * Returns: a slice of `buffer` containing the converted string. A zero follows the slice.
 */
 version(Windows) wchar[] toWStringz(scope const(char)[] narrow, ref SmallBuffer!wchar buffer) nothrow
 {
-    import core.sys.windows.winnls : MultiByteToWideChar;
-    import dmd.common.file : CodePage;
-
     if (narrow is null)
         return null;
 
-    size_t length;
-    int i;
-    while (1)
+    size_t charsToWchars(scope const(char)[] narrow, scope wchar[] buffer)
     {
         // https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar
-        length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
-        if (length < buffer.length)
-            break;
-        buffer.create(length + 1);
-        assert(++i == 1);   // ensure loop should only execute once or twice
+        import core.sys.windows.winnls : MultiByteToWideChar, CP_ACP;
+        return MultiByteToWideChar(CP_ACP, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length);
+    }
+
+    size_t length = charsToWchars(narrow, buffer[]);
+    if (length >= buffer.length) // not enough room in buffer[]
+    {
+        buffer.create(length + 1); // extend buffer length
+        length = charsToWchars(narrow, buffer[]);  // try again
+        assert(length < buffer.length);
     }
     buffer[length] = 0;
     return buffer[0 .. length];
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 536a212536d..e917d2cb7e7 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -1682,9 +1682,12 @@  final class CParser(AST) : Parser!AST
         AST.ParameterList parameterList;
         StorageClass stc = 0;
         const loc = token.loc;
+        auto symbolsSave = symbols;
+        symbols = new AST.Dsymbols();
         typedefTab.push(null);
         auto fbody = cparseStatement(ParseStatementFlags.scope_);
         typedefTab.pop();                                        // end of function scope
+        symbols = symbolsSave;
 
         // Rewrite last ExpStatement (if there is one) as a ReturnStatement
         auto ss = fbody.isScopeStatement();
@@ -1693,8 +1696,11 @@  final class CParser(AST) : Parser!AST
         if (const len = (*cs.statements).length)
         {
             auto s = (*cs.statements)[len - 1];
-            if (auto es = s.isExpStatement())
-                (*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp);
+            if (s)   // error recovery should be with ErrorStatement, not null
+            {
+                if (auto es = s.isExpStatement())
+                    (*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp);
+            }
         }
 
         auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
@@ -5520,7 +5526,7 @@  final class CParser(AST) : Parser!AST
                 defines.writeByte('#');
                 defines.writestring(n.ident.toString());
                 skipToNextLine(defines);
-                defines.writeByte('\n');
+                defines.writeByte(0);           // each #define line is 0 terminated
                 return true;
             }
             else if (n.ident == Id.__pragma)
@@ -5840,7 +5846,8 @@  final class CParser(AST) : Parser!AST
         const length = buf.length;
         buf.writeByte(0);
         auto slice = buf.peekChars()[0 .. length];
-        resetDefineLines(slice);                // reset lexer
+        auto scanlocSave = scanloc;
+        resetDefineLines(slice);        // reset lexer
         auto save = eSink;
         auto eLatch = new ErrorSinkLatch();
         eSink = eLatch;
@@ -5865,12 +5872,14 @@  final class CParser(AST) : Parser!AST
                 (*symbols)[*pd] = s;
                 return;
             }
+            assert(symbols, "symbols is null");
             defineTab[cast(void*)s.ident] = symbols.length;
             symbols.push(s);
         }
 
         while (p < endp)
         {
+            //printf("|%s|\n", p);
             if (p[0 .. 7] == "#define")
             {
                 p += 7;
@@ -5884,10 +5893,11 @@  final class CParser(AST) : Parser!AST
 
                     AST.Type t;
 
+                Lswitch:
                     switch (token.value)
                     {
-                        case TOK.endOfLine:     // #define identifier
-                            nextDefineLine();
+                        case TOK.endOfFile:     // #define identifier
+                            ++p;
                             continue;
 
                         case TOK.int32Literal:
@@ -5901,7 +5911,7 @@  final class CParser(AST) : Parser!AST
                         Linteger:
                             const intvalue = token.intvalue;
                             nextToken();
-                            if (token.value == TOK.endOfLine)
+                            if (token.value == TOK.endOfFile)
                             {
                                 /* Declare manifest constant:
                                  *  enum id = intvalue;
@@ -5909,7 +5919,7 @@  final class CParser(AST) : Parser!AST
                                 AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
                                 auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
                                 addVar(v);
-                                nextDefineLine();
+                                ++p;
                                 continue;
                             }
                             break;
@@ -5924,7 +5934,7 @@  final class CParser(AST) : Parser!AST
                         Lfloat:
                             const floatvalue = token.floatvalue;
                             nextToken();
-                            if (token.value == TOK.endOfLine)
+                            if (token.value == TOK.endOfFile)
                             {
                                 /* Declare manifest constant:
                                  *  enum id = floatvalue;
@@ -5932,7 +5942,7 @@  final class CParser(AST) : Parser!AST
                                 AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
                                 auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
                                 addVar(v);
-                                nextDefineLine();
+                                ++p;
                                 continue;
                             }
                             break;
@@ -5942,7 +5952,7 @@  final class CParser(AST) : Parser!AST
                             const len = token.len;
                             const postfix = token.postfix;
                             nextToken();
-                            if (token.value == TOK.endOfLine)
+                            if (token.value == TOK.endOfFile)
                             {
                                 /* Declare manifest constant:
                                  *  enum id = "string";
@@ -5950,19 +5960,20 @@  final class CParser(AST) : Parser!AST
                                 AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
                                 auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
                                 addVar(v);
-                                nextDefineLine();
+                                ++p;
                                 continue;
                             }
                             break;
 
                         case TOK.leftParenthesis:
+                        {
                             /* Look for:
                              *  #define ID ( expression )
                              * and rewrite it to a template function:
                              *  auto ID()() { return expression; }
                              */
                             if (params)
-                                break;                  // no parameters
+                                goto caseFunctionLike;        // version with parameters
                             nextToken();
                             eLatch.sawErrors = false;
                             auto exp = cparseExpression();
@@ -5971,7 +5982,7 @@  final class CParser(AST) : Parser!AST
                             if (token.value != TOK.rightParenthesis)
                                 break;
                             nextToken();
-                            if (token.value != TOK.endOfLine)
+                            if (token.value != TOK.endOfFile)
                                 break;
                             auto ret = new AST.ReturnStatement(exp.loc, exp);
                             auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0);
@@ -5985,26 +5996,115 @@  final class CParser(AST) : Parser!AST
                             AST.Expression constraint = null;
                             auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
                             addVar(tempdecl);
-                            nextDefineLine();
+                            ++p;
                             continue;
+                        }
+
+                        caseFunctionLike:
+                        {
+                            /* Parse `( a, b ) expression`
+                             * Create template function:
+                             *    auto id(__MP1, __MP2)(__MP1 a, __MP1 b) { return expression; }
+                             */
+                            //printf("functionlike %s\n", id.toChars());
+
+                            // Capture the parameter list
+                            VarArg varargs = VarArg.none;
+                            auto parameters = new AST.Parameters();
+                            nextToken();        // skip past `(`
+                        Lwhile:
+                            while (1)
+                            {
+                                if (token.value == TOK.rightParenthesis)
+                                    break;
+                                if (token.value == TOK.dotDotDot)
+                                {
+                                    static if (0)       // variadic macros not supported yet
+                                    {
+                                        varargs = AST.VarArg.variadic;  // C-style variadics
+                                        nextToken();
+                                        if (token.value == TOK.rightParenthesis)
+                                            break Lwhile;
+                                    }
+                                    break Lswitch;
+                                }
+
+                                if (token.value != TOK.identifier)
+                                    break Lswitch;
+                                auto param = new AST.Parameter(token.loc, 0, null, token.ident, null, null);
+                                parameters.push(param);
+                                nextToken();
+                                if (token.value == TOK.comma)
+                                {
+                                    nextToken();
+                                    continue;
+                                }
+                                break;
+                            }
+                            if (token.value != TOK.rightParenthesis)
+                                break;
+
+                            //auto pstart = p;
+                            nextToken();
+                            auto parameterList = AST.ParameterList(parameters, varargs, 0);
+                            /* Create a type for each parameter. Add it to the template parameter list,
+                             * and the parameter list.
+                             */
+                            auto tpl = new AST.TemplateParameters();
+                            foreach (param; (*parameters)[])
+                            {
+                                auto idtype = Identifier.generateId("__MP");
+                                auto loc = param.loc;
+                                auto tp = new AST.TemplateTypeParameter(loc, idtype, null, null);
+                                tpl.push(tp);
+
+                                auto at = new AST.TypeIdentifier(loc, idtype);
+                                param.type = at;
+                            }
+
+                            eLatch.sawErrors = false;
+                            auto exp = cparseExpression();
+
+                            //printf("exp: %s tok: %s\n", exp.toChars(), Token.toChars(token.value));
+                            //printf("parsed: '%.*s'\n", cast(int)(p - pstart), pstart);
+                            assert(symbols);
+
+                            if (eLatch.sawErrors)   // parsing errors
+                                break;              // abandon this #define
+
+                            if (token.value != TOK.endOfFile)   // did not consume the entire line
+                                break;
+
+                            // Generate function
+                            auto ret = new AST.ReturnStatement(exp.loc, exp);
+                            StorageClass stc = STC.auto_;
+                            auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
+                            auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0);
+                            fd.fbody = ret;
+
+                            // Wrap it in an eponymous template
+                            AST.Dsymbols* decldefs = new AST.Dsymbols();
+                            decldefs.push(fd);
+                            auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false);
+                            addVar(tempdecl);
+
+                            ++p;
+                            continue;
+                        }
 
                         default:
                             break;
                     }
                 }
-                skipToNextLine();
-            }
-            else
-            {
-                scan(&token);
-                if (token.value != TOK.endOfLine)
-                {
-                    skipToNextLine();
-                }
             }
-            nextDefineLine();
+            // scan to end of line
+            while (*p)
+                ++p;
+            ++p; // advance to start of next line
+            scanloc.linnum = scanloc.linnum + 1;
         }
 
+        scanloc = scanlocSave;
         eSink = save;
         defines = buf;
     }
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index b083c03aebe..2efdd31bbba 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -12,21 +12,13 @@ 
 module dmd.dimport;
 
 import dmd.arraytypes;
-import dmd.astenums;
-import dmd.declaration;
 import dmd.dmodule;
-import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
 import dmd.errors;
-import dmd.expression;
-import dmd.globals;
 import dmd.identifier;
 import dmd.location;
-import dmd.mtype;
 import dmd.visitor;
 
-import core.stdc.stdio;
 /***********************************************************
  */
 extern (C++) final class Import : Dsymbol
@@ -76,6 +68,8 @@  extern (C++) final class Import : Dsymbol
         assert(id);
         version (none)
         {
+            import core.stdc.stdio;
+
             printf("Import::Import(");
             foreach (id; packages)
             {
@@ -123,105 +117,6 @@  extern (C++) final class Import : Dsymbol
         return si;
     }
 
-    /*******************************
-     * Load this module.
-     * Returns:
-     *  true for errors, false for success
-     */
-    extern (D) bool load(Scope* sc)
-    {
-        //printf("Import::load('%s') %p\n", toPrettyChars(), this);
-        // See if existing module
-        const errors = global.errors;
-        DsymbolTable dst = Package.resolve(packages, null, &pkg);
-        version (none)
-        {
-            if (pkg && pkg.isModule())
-            {
-                .error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars());
-                mod = pkg.isModule(); // Error recovery - treat as import of that module
-                return true;
-            }
-        }
-        Dsymbol s = dst.lookup(id);
-        if (s)
-        {
-            if (s.isModule())
-                mod = cast(Module)s;
-            else
-            {
-                if (s.isAliasDeclaration())
-                {
-                    .error(loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), id.toChars());
-                }
-                else if (Package p = s.isPackage())
-                {
-                    if (p.isPkgMod == PKG.unknown)
-                    {
-                        uint preverrors = global.errors;
-                        mod = Module.load(loc, packages, id);
-                        if (!mod)
-                            p.isPkgMod = PKG.package_;
-                        else
-                        {
-                            // mod is a package.d, or a normal module which conflicts with the package name.
-                            if (mod.isPackageFile)
-                                mod.tag = p.tag; // reuse the same package tag
-                            else
-                            {
-                                // show error if Module.load does not
-                                if (preverrors == global.errors)
-                                    .error(loc, "%s `%s` from file %s conflicts with %s `%s`", mod.kind(), mod.toPrettyChars(), mod.srcfile.toChars, p.kind(), p.toPrettyChars());
-                                return true;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        mod = p.isPackageMod();
-                    }
-                    if (!mod)
-                    {
-                        .error(loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), id.toChars());
-                    }
-                }
-                else if (pkg)
-                {
-                    .error(loc, "can only import from a module, not from package `%s.%s`", pkg.toPrettyChars(), id.toChars());
-                }
-                else
-                {
-                    .error(loc, "can only import from a module, not from package `%s`", id.toChars());
-                }
-            }
-        }
-        if (!mod)
-        {
-            // Load module
-            mod = Module.load(loc, packages, id);
-            if (mod)
-            {
-                // id may be different from mod.ident, if so then insert alias
-                dst.insert(id, mod);
-            }
-        }
-        if (mod && !mod.importedFrom)
-            mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule;
-        if (!pkg)
-        {
-            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);
-        return global.errors != errors;
-    }
-
     /*******************************
      * Mark the imported packages as accessible from the current
      * scope. This access check is necessary when using FQN b/c
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 07d5077ee49..a77e4f303cd 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -16,12 +16,14 @@  module dmd.dmodule;
 import core.stdc.stdio;
 import core.stdc.stdlib;
 import core.stdc.string;
+
 import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astcodegen;
 import dmd.astenums;
+import dmd.common.outbuffer;
 import dmd.compiler;
-import dmd.gluelayer;
+import dmd.cparse;
 import dmd.dimport;
 import dmd.dmacro;
 import dmd.doc;
@@ -35,25 +37,37 @@  import dmd.expressionsem;
 import dmd.file_manager;
 import dmd.func;
 import dmd.globals;
+import dmd.gluelayer;
 import dmd.id;
 import dmd.identifier;
 import dmd.location;
 import dmd.parse;
-import dmd.cparse;
 import dmd.root.array;
 import dmd.root.file;
 import dmd.root.filename;
-import dmd.common.outbuffer;
 import dmd.root.port;
 import dmd.root.rmem;
-import dmd.rootobject;
 import dmd.root.string;
+import dmd.rootobject;
 import dmd.semantic2;
 import dmd.semantic3;
 import dmd.target;
 import dmd.utils;
 import dmd.visitor;
 
+version (Windows)
+{
+    import core.sys.windows.winbase : getpid = GetCurrentProcessId;
+    enum PathSeparator = '\\';
+}
+else version (Posix)
+{
+    import core.sys.posix.unistd : getpid;
+    enum PathSeparator = '/';
+}
+else
+    static assert(0);
+
 version (IN_GCC) {}
 else version (IN_LLVM) {}
 else version = MARS;
@@ -141,11 +155,7 @@  private const(char)[] getFilename(Identifier[] packages, Identifier ident) nothr
         buf.writestring(p);
         if (modAliases.length)
             checkModFileAlias(p);
-        version (Windows)
-            enum FileSeparator = '\\';
-        else
-            enum FileSeparator = '/';
-        buf.writeByte(FileSeparator);
+        buf.writeByte(PathSeparator);
     }
     buf.writestring(filename);
     if (modAliases.length)
@@ -558,10 +568,6 @@  extern (C++) final class Module : Package
             OutBuffer buf;
             if (arg == "__stdin.d")
             {
-                version (Posix)
-                    import core.sys.posix.unistd : getpid;
-                else version (Windows)
-                    import core.sys.windows.winbase : getpid = GetCurrentProcessId;
                 buf.printf("__stdin_%d.d", getpid());
                 arg = buf[];
             }
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index c15d925ce0a..bb0a1d6e2cc 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -6916,6 +6916,103 @@  extern(C++) class ImportAllVisitor : Visitor
     override void visit(StaticForeachDeclaration _) {}
 }
 
+/*******************************
+    * Load module.
+    * Returns:
+    *  true for errors, false for success
+    */
+extern (D) bool load(Import imp, Scope* sc)
+{
+    // See if existing module
+    const errors = global.errors;
+    DsymbolTable dst = Package.resolve(imp.packages, null, &imp.pkg);
+    version (none)
+    {
+        if (pkg && pkg.isModule())
+        {
+            .error(loc, "can only import from a module, not from a member of module `%s`. Did you mean `import %s : %s`?", pkg.toChars(), pkg.toPrettyChars(), id.toChars());
+            mod = pkg.isModule(); // Error recovery - treat as import of that module
+            return true;
+        }
+    }
+    Dsymbol s = dst.lookup(imp.id);
+    if (s)
+    {
+        if (s.isModule())
+            imp.mod = cast(Module)s;
+        else
+        {
+            if (s.isAliasDeclaration())
+            {
+                .error(imp.loc, "%s `%s` conflicts with `%s`", s.kind(), s.toPrettyChars(), imp.id.toChars());
+            }
+            else if (Package p = s.isPackage())
+            {
+                if (p.isPkgMod == PKG.unknown)
+                {
+                    uint preverrors = global.errors;
+                    imp.mod = Module.load(imp.loc, imp.packages, imp.id);
+                    if (!imp.mod)
+                        p.isPkgMod = PKG.package_;
+                    else
+                    {
+                        // imp.mod is a package.d, or a normal module which conflicts with the package name.
+                        if (imp.mod.isPackageFile)
+                            imp.mod.tag = p.tag; // reuse the same package tag
+                        else
+                        {
+                            // show error if Module.load does not
+                            if (preverrors == global.errors)
+                                .error(imp.loc, "%s `%s` from file %s conflicts with %s `%s`", imp.mod.kind(), imp.mod.toPrettyChars(), imp.mod.srcfile.toChars, p.kind(), p.toPrettyChars());
+                            return true;
+                        }
+                    }
+                }
+                else
+                {
+                    imp.mod = p.isPackageMod();
+                }
+                if (!imp.mod)
+                {
+                    .error(imp.loc, "can only import from a module, not from package `%s.%s`", p.toPrettyChars(), imp.id.toChars());
+                }
+            }
+            else if (imp.pkg)
+            {
+                .error(imp.loc, "can only import from a module, not from package `%s.%s`", imp.pkg.toPrettyChars(), imp.id.toChars());
+            }
+            else
+            {
+                .error(imp.loc, "can only import from a module, not from package `%s`", imp.id.toChars());
+            }
+        }
+    }
+    if (!imp.mod)
+    {
+        // Load module
+        imp.mod = Module.load(imp.loc, imp.packages, imp.id);
+        if (imp.mod)
+        {
+            // imp.id may be different from mod.ident, if so then insert alias
+            dst.insert(imp.id, imp.mod);
+        }
+    }
+    if (imp.mod && !imp.mod.importedFrom)
+        imp.mod.importedFrom = sc ? sc._module.importedFrom : Module.rootModule;
+    if (!imp.pkg)
+    {
+        if (imp.mod && imp.mod.isPackageFile)
+        {
+            // one level depth package.d file (import pkg; ./pkg/package.d)
+            // it's necessary to use the wrapping Package already created
+            imp.pkg = imp.mod.pkg;
+        }
+        else
+            imp.pkg = imp.mod;
+    }
+    return global.errors != errors;
+}
+
 void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion)
 {
     scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion);
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index bc907cfd2f4..479ad3ade5f 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -314,6 +314,7 @@  extern (C++) abstract class Expression : ASTNode
     Type type;      // !=null means that semantic() has been run
     Loc loc;        // file location
     const EXP op;   // to minimize use of dynamic_cast
+    bool parens;    // if this is a parenthesized expression
 
     extern (D) this(const ref Loc loc, EXP op) scope @safe
     {
@@ -1310,7 +1311,6 @@  extern (C++) final class ComplexExp : Expression
 extern (C++) class IdentifierExp : Expression
 {
     Identifier ident;
-    bool parens;        // if it appears as (identifier)
 
     extern (D) this(const ref Loc loc, Identifier ident) scope @safe
     {
@@ -2432,8 +2432,6 @@  extern (C++) final class CompoundLiteralExp : Expression
  */
 extern (C++) final class TypeExp : Expression
 {
-    bool parens;    // if this is a parenthesized expression
-
     extern (D) this(const ref Loc loc, Type type) @safe
     {
         super(loc, EXP.type);
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 3bd8ca7568e..9cd73a965ba 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -90,6 +90,7 @@  public:
     Type *type;                 // !=NULL means that semantic() has been run
     Loc loc;                    // file location
     EXP op;                     // to minimize use of dynamic_cast
+    d_bool parens;              // if this is a parenthesized expression
 
     size_t size() const;
     static void _init();
@@ -300,7 +301,6 @@  class IdentifierExp : public Expression
 {
 public:
     Identifier *ident;
-    d_bool parens;
 
     static IdentifierExp *create(const Loc &loc, Identifier *ident);
     bool isLvalue() override final;
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index cc589b991d1..b4d5274e7c3 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -16628,3 +16628,100 @@  Expression toBoolean(Expression exp, Scope* sc)
             return e;
     }
 }
+
+/********************************************
+ * Semantically analyze and then evaluate a static condition at compile time.
+ * This is special because short circuit operators &&, || and ?: at the top
+ * level are not semantically analyzed if the result of the expression is not
+ * necessary.
+ * Params:
+ *      sc  = instantiating scope
+ *      original = original expression, for error messages
+ *      e =  resulting expression
+ *      errors = set to `true` if errors occurred
+ *      negatives = array to store negative clauses
+ * Returns:
+ *      true if evaluates to true
+ */
+bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null)
+{
+    if (negatives)
+        negatives.setDim(0);
+
+    bool impl(Expression e)
+    {
+        if (e.isNotExp())
+        {
+            NotExp ne = cast(NotExp)e;
+            return !impl(ne.e1);
+        }
+
+        if (e.op == EXP.andAnd || e.op == EXP.orOr)
+        {
+            LogicalExp aae = cast(LogicalExp)e;
+            bool result = impl(aae.e1);
+            if (errors)
+                return false;
+            if (e.op == EXP.andAnd)
+            {
+                if (!result)
+                    return false;
+            }
+            else
+            {
+                if (result)
+                    return true;
+            }
+            result = impl(aae.e2);
+            return !errors && result;
+        }
+
+        if (e.op == EXP.question)
+        {
+            CondExp ce = cast(CondExp)e;
+            bool result = impl(ce.econd);
+            if (errors)
+                return false;
+            Expression leg = result ? ce.e1 : ce.e2;
+            result = impl(leg);
+            return !errors && result;
+        }
+
+        Expression before = e;
+        const uint nerrors = global.errors;
+
+        sc = sc.startCTFE();
+        sc.flags |= SCOPE.condition;
+
+        e = e.expressionSemantic(sc);
+        e = resolveProperties(sc, e);
+        e = e.toBoolean(sc);
+
+        sc = sc.endCTFE();
+        e = e.optimize(WANTvalue);
+
+        if (nerrors != global.errors ||
+            e.isErrorExp() ||
+            e.type.toBasetype() == Type.terror)
+        {
+            errors = true;
+            return false;
+        }
+
+        e = e.ctfeInterpret();
+
+        const opt = e.toBool();
+        if (opt.isEmpty())
+        {
+            if (!e.type.isTypeError())
+                error(e.loc, "expression `%s` is not constant", e.toChars());
+            errors = true;
+            return false;
+        }
+
+        if (negatives && !opt.get())
+            negatives.push(before);
+        return opt.get();
+    }
+    return impl(e);
+}
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 4881ad6c020..d890811115c 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -58,7 +58,6 @@  import dmd.semantic3;
 import dmd.statement_rewrite_walker;
 import dmd.statement;
 import dmd.statementsem;
-import dmd.templatesem;
 import dmd.tokens;
 import dmd.typesem;
 import dmd.visitor;
@@ -2925,395 +2924,6 @@  unittest
     assert(mismatches.isMutable);
 }
 
-/// Flag used by $(LREF resolveFuncCall).
-enum FuncResolveFlag : ubyte
-{
-    standard = 0,       /// issue error messages, solve the call.
-    quiet = 1,          /// do not issue error message on no match, just return `null`.
-    overloadOnly = 2,   /// only resolve overloads, i.e. do not issue error on ambiguous
-                        /// matches and need explicit this.
-    ufcs = 4,           /// trying to resolve UFCS call
-}
-
-/*******************************************
- * Given a symbol that could be either a FuncDeclaration or
- * a function template, resolve it to a function symbol.
- * Params:
- *      loc =           instantiation location
- *      sc =            instantiation scope
- *      s =             instantiation symbol
- *      tiargs =        initial list of template arguments
- *      tthis =         if !NULL, the `this` argument type
- *      argumentList =  arguments to function
- *      flags =         see $(LREF FuncResolveFlag).
- * Returns:
- *      if match is found, then function symbol, else null
- */
-FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
-    Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
-{
-    auto fargs = argumentList.arguments;
-    if (!s)
-        return null; // no match
-
-    version (none)
-    {
-        printf("resolveFuncCall('%s')\n", s.toChars());
-        if (tthis)
-            printf("\tthis: %s\n", tthis.toChars());
-        if (fargs)
-        {
-            for (size_t i = 0; i < fargs.length; i++)
-            {
-                Expression arg = (*fargs)[i];
-                assert(arg.type);
-                printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
-            }
-        }
-        printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
-    }
-
-    if (tiargs && arrayObjectIsError(*tiargs))
-        return null;
-    if (fargs !is null)
-        foreach (arg; *fargs)
-            if (isError(arg))
-                return null;
-
-    MatchAccumulator m;
-    functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
-    auto orig_s = s;
-
-    if (m.last > MATCH.nomatch && m.lastf)
-    {
-        if (m.count == 1) // exactly one match
-        {
-            if (!(flags & FuncResolveFlag.quiet))
-                functionSemantic(m.lastf);
-            return m.lastf;
-        }
-        if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
-        {
-            return m.lastf;
-        }
-    }
-
-    /* Failed to find a best match.
-     * Do nothing or print error.
-     */
-    if (m.last == MATCH.nomatch)
-    {
-        // error was caused on matched function, not on the matching itself,
-        // so return the function to produce a better diagnostic
-        if (m.count == 1)
-            return m.lastf;
-    }
-
-    // We are done at this point, as the rest of this function generate
-    // a diagnostic on invalid match
-    if (flags & FuncResolveFlag.quiet)
-        return null;
-
-    auto fd = s.isFuncDeclaration();
-    auto od = s.isOverDeclaration();
-    auto td = s.isTemplateDeclaration();
-    if (td && td.funcroot)
-        s = fd = td.funcroot;
-
-    OutBuffer tiargsBuf;
-    arrayObjectsToBuffer(tiargsBuf, tiargs);
-
-    OutBuffer fargsBuf;
-    fargsBuf.writeByte('(');
-    argExpTypesToCBuffer(fargsBuf, fargs);
-    fargsBuf.writeByte(')');
-    if (tthis)
-        tthis.modToBuffer(fargsBuf);
-
-    // The call is ambiguous
-    if (m.lastf && m.nextf)
-    {
-        TypeFunction tf1 = m.lastf.type.toTypeFunction();
-        TypeFunction tf2 = m.nextf.type.toTypeFunction();
-        const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
-        const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
-
-        .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s:     `%s%s%s`\nand:\n%s:     `%s%s%s`",
-            s.parent.toPrettyChars(), s.ident.toChars(),
-            fargsBuf.peekChars(),
-            m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
-            m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
-        return null;
-    }
-
-    // no match, generate an error messages
-    if (flags & FuncResolveFlag.ufcs)
-    {
-        auto arg = (*fargs)[0];
-        .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars());
-        .errorSupplemental(loc, "the following error occured while looking for a UFCS match");
-    }
-
-    if (!fd)
-    {
-        // all of overloads are templates
-        if (td)
-        {
-            if (!od && !td.overnext)
-            {
-                .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`",
-                   td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
-            }
-            else
-            {
-                .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
-                   td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
-                   tiargsBuf.peekChars(), fargsBuf.peekChars());
-            }
-
-
-            if (!global.gag || global.params.v.showGaggedErrors)
-                printCandidates(loc, td, sc.isDeprecated());
-            return null;
-        }
-        /* This case used to happen when several ctors are mixed in an agregate.
-           A (bad) error message is already generated in overloadApply().
-           see https://issues.dlang.org/show_bug.cgi?id=19729
-           and https://issues.dlang.org/show_bug.cgi?id=17259
-        */
-        if (!od)
-            return null;
-    }
-
-    if (od)
-    {
-        .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
-               od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
-        return null;
-    }
-
-    // remove when deprecation period of class allocators and deallocators is over
-    if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
-        return null;
-
-    bool hasOverloads = fd.overnext !is null;
-    auto tf = fd.type.isTypeFunction();
-    // if type is an error, the original type should be there for better diagnostics
-    if (!tf)
-        tf = fd.originalType.toTypeFunction();
-
-    // modifier mismatch
-    if (tthis && (fd.isCtorDeclaration() ?
-        !MODimplicitConv(tf.mod, tthis.mod) :
-        !MODimplicitConv(tthis.mod, tf.mod)))
-    {
-        OutBuffer thisBuf, funcBuf;
-        MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
-        auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
-        if (hasOverloads)
-        {
-            OutBuffer buf;
-            buf.argExpTypesToCBuffer(fargs);
-            if (fd.isCtorDeclaration())
-                .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
-                    fd.toChars(), thisBuf.peekChars(), buf.peekChars());
-            else
-                .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
-                    fd.toChars(), thisBuf.peekChars(), buf.peekChars());
-
-            if (!global.gag || global.params.v.showGaggedErrors)
-                printCandidates(loc, fd, sc.isDeprecated());
-            return null;
-        }
-
-        bool calledHelper;
-        void errorHelper(const(char)* failMessage) scope
-        {
-            .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
-                   fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
-                   tf.modToChars(), fargsBuf.peekChars());
-            errorSupplemental(loc, failMessage);
-            calledHelper = true;
-        }
-
-        functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper);
-        if (calledHelper)
-            return null;
-
-        if (fd.isCtorDeclaration())
-            .error(loc, "%s%s `%s` cannot construct a %sobject",
-                   funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
-        else
-            .error(loc, "%smethod `%s` is not callable using a %sobject",
-                   funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
-
-        if (mismatches.isNotShared)
-            .errorSupplemental(fd.loc, "Consider adding `shared` here");
-        else if (mismatches.isMutable)
-            .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
-        return null;
-    }
-
-    //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`",
-               fd.toChars(), fargsBuf.peekChars());
-        if (!global.gag || global.params.v.showGaggedErrors)
-            printCandidates(loc, fd, sc.isDeprecated());
-        return null;
-    }
-
-    .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
-           fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
-           tf.modToChars(), fargsBuf.peekChars());
-
-    // re-resolve to check for supplemental message
-    if (!global.gag || global.params.v.showGaggedErrors)
-    {
-        if (tthis)
-        {
-            if (auto classType = tthis.isTypeClass())
-            {
-                if (auto baseClass = classType.sym.baseClass)
-                {
-                    if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
-                    {
-                        MatchAccumulator mErr;
-                        functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
-                        if (mErr.last > MATCH.nomatch && mErr.lastf)
-                        {
-                            errorSupplemental(loc, "%s `%s` hides base class function `%s`",
-                                    fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
-                            errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
-                                    fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
-                            return null;
-                        }
-                    }
-                }
-            }
-        }
-
-        void errorHelper2(const(char)* failMessage) scope
-        {
-            errorSupplemental(loc, failMessage);
-        }
-
-        functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
-    }
-    return null;
-}
-
-/*******************************************
- * Prints template and function overload candidates as supplemental errors.
- * Params:
- *      loc =            instantiation location
- *      declaration =    the declaration to print overload candidates for
- *      showDeprecated = If `false`, `deprecated` function won't be shown
- */
-private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
-if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
-{
-    // max num of overloads to print (-v or -verror-supplements overrides this).
-    const uint DisplayLimit = global.params.v.errorSupplementCount();
-    const(char)* constraintsTip;
-    // determine if the first candidate was printed
-    int printed;
-
-    bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
-    {
-        if (auto fd = s.isFuncDeclaration())
-        {
-            // Don't print overloads which have errors.
-            // Not that if the whole overload set has errors, we'll never reach
-            // this point so there's no risk of printing no candidate
-            if (fd.errors || fd.type.ty == Terror)
-                return false;
-            // Don't print disabled functions, or `deprecated` outside of deprecated scope
-            if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
-                return false;
-            if (!print)
-                return true;
-            auto tf = cast(TypeFunction) fd.type;
-            OutBuffer buf;
-            buf.writestring(fd.toPrettyChars());
-            buf.writestring(parametersTypeToChars(tf.parameterList));
-            if (tf.mod)
-            {
-                buf.writeByte(' ');
-                buf.MODtoBuffer(tf.mod);
-            }
-            .errorSupplemental(fd.loc,
-                printed ? "                `%s`" :
-                single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
-        }
-        else if (auto td = s.isTemplateDeclaration())
-        {
-            import dmd.staticcond;
-
-            if (!print)
-                return true;
-            OutBuffer buf;
-            HdrGenState hgs;
-            hgs.skipConstraints = true;
-            toCharsMaybeConstraints(td, buf, hgs);
-            const tmsg = buf.peekChars();
-            const cmsg = td.getConstraintEvalError(constraintsTip);
-
-            // add blank space if there are multiple candidates
-            // the length of the blank space is `strlen("Candidates are: ")`
-
-            if (cmsg)
-            {
-                .errorSupplemental(td.loc,
-                        printed ? "                `%s`\n%s" :
-                        single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
-                        tmsg, cmsg);
-            }
-            else
-            {
-                .errorSupplemental(td.loc,
-                        printed ? "                `%s`" :
-                        single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
-                        tmsg);
-            }
-        }
-        return true;
-    }
-    // determine if there's > 1 candidate
-    int count = 0;
-    overloadApply(declaration, (s) {
-        if (matchSymbol(s, false))
-            count++;
-        return count > 1;
-    });
-    int skipped = 0;
-    overloadApply(declaration, (s) {
-        if (global.params.v.verbose || printed < DisplayLimit)
-        {
-            if (matchSymbol(s, true, count == 1))
-                printed++;
-        }
-        else
-        {
-            // Too many overloads to sensibly display.
-            // Just show count of remaining overloads.
-            if (matchSymbol(s, false))
-                skipped++;
-        }
-        return 0;
-    });
-    if (skipped > 0)
-        .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
-
-    // Nothing was displayed, all overloads are either disabled or deprecated
-    if (!printed)
-        .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
-    // should be only in verbose mode
-    if (constraintsTip)
-        .tip(constraintsTip);
-}
-
 /**************************************
  * Returns an indirect type one step from t.
  */
@@ -4336,9 +3946,9 @@  bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)
             return false;
         if (sc.func.isSafeBypassingInference())
         {
-            if (!gag)
+            if (!gag && !sc.isDeprecated())
             {
-                warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+                deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
             }
         }
         else if (!sc.func.safetyViolation)
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
index 49da6b20136..b8b185c94f3 100644
--- a/gcc/d/dmd/funcsem.d
+++ b/gcc/d/dmd/funcsem.d
@@ -60,6 +60,7 @@  import dmd.statement_rewrite_walker;
 import dmd.statement;
 import dmd.statementsem;
 import dmd.target;
+import dmd.templatesem;
 import dmd.tokens;
 import dmd.typesem;
 import dmd.visitor;
@@ -1365,3 +1366,392 @@  BaseClass* overrideInterface(FuncDeclaration fd)
     }
     return null;
 }
+
+/// Flag used by $(LREF resolveFuncCall).
+enum FuncResolveFlag : ubyte
+{
+    standard = 0,       /// issue error messages, solve the call.
+    quiet = 1,          /// do not issue error message on no match, just return `null`.
+    overloadOnly = 2,   /// only resolve overloads, i.e. do not issue error on ambiguous
+                        /// matches and need explicit this.
+    ufcs = 4,           /// trying to resolve UFCS call
+}
+
+/*******************************************
+ * Given a symbol that could be either a FuncDeclaration or
+ * a function template, resolve it to a function symbol.
+ * Params:
+ *      loc =           instantiation location
+ *      sc =            instantiation scope
+ *      s =             instantiation symbol
+ *      tiargs =        initial list of template arguments
+ *      tthis =         if !NULL, the `this` argument type
+ *      argumentList =  arguments to function
+ *      flags =         see $(LREF FuncResolveFlag).
+ * Returns:
+ *      if match is found, then function symbol, else null
+ */
+FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
+    Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags)
+{
+    auto fargs = argumentList.arguments;
+    if (!s)
+        return null; // no match
+
+    version (none)
+    {
+        printf("resolveFuncCall('%s')\n", s.toChars());
+        if (tthis)
+            printf("\tthis: %s\n", tthis.toChars());
+        if (fargs)
+        {
+            for (size_t i = 0; i < fargs.length; i++)
+            {
+                Expression arg = (*fargs)[i];
+                assert(arg.type);
+                printf("\t%s: %s\n", arg.toChars(), arg.type.toChars());
+            }
+        }
+        printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
+    }
+
+    if (tiargs && arrayObjectIsError(*tiargs))
+        return null;
+    if (fargs !is null)
+        foreach (arg; *fargs)
+            if (isError(arg))
+                return null;
+
+    MatchAccumulator m;
+    functionResolve(m, s, loc, sc, tiargs, tthis, argumentList);
+    auto orig_s = s;
+
+    if (m.last > MATCH.nomatch && m.lastf)
+    {
+        if (m.count == 1) // exactly one match
+        {
+            if (!(flags & FuncResolveFlag.quiet))
+                functionSemantic(m.lastf);
+            return m.lastf;
+        }
+        if ((flags & FuncResolveFlag.overloadOnly) && !tthis && m.lastf.needThis())
+        {
+            return m.lastf;
+        }
+    }
+
+    /* Failed to find a best match.
+     * Do nothing or print error.
+     */
+    if (m.last == MATCH.nomatch)
+    {
+        // error was caused on matched function, not on the matching itself,
+        // so return the function to produce a better diagnostic
+        if (m.count == 1)
+            return m.lastf;
+    }
+
+    // We are done at this point, as the rest of this function generate
+    // a diagnostic on invalid match
+    if (flags & FuncResolveFlag.quiet)
+        return null;
+
+    auto fd = s.isFuncDeclaration();
+    auto od = s.isOverDeclaration();
+    auto td = s.isTemplateDeclaration();
+    if (td && td.funcroot)
+        s = fd = td.funcroot;
+
+    OutBuffer tiargsBuf;
+    arrayObjectsToBuffer(tiargsBuf, tiargs);
+
+    OutBuffer fargsBuf;
+    fargsBuf.writeByte('(');
+    argExpTypesToCBuffer(fargsBuf, fargs);
+    fargsBuf.writeByte(')');
+    if (tthis)
+        tthis.modToBuffer(fargsBuf);
+
+    // The call is ambiguous
+    if (m.lastf && m.nextf)
+    {
+        TypeFunction tf1 = m.lastf.type.toTypeFunction();
+        TypeFunction tf2 = m.nextf.type.toTypeFunction();
+        const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
+        const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
+
+        .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s:     `%s%s%s`\nand:\n%s:     `%s%s%s`",
+            s.parent.toPrettyChars(), s.ident.toChars(),
+            fargsBuf.peekChars(),
+            m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
+            m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
+        return null;
+    }
+
+    // no match, generate an error messages
+    if (flags & FuncResolveFlag.ufcs)
+    {
+        auto arg = (*fargs)[0];
+        .error(loc, "no property `%s` for `%s` of type `%s`", s.ident.toChars(), arg.toChars(), arg.type.toChars());
+        .errorSupplemental(loc, "the following error occured while looking for a UFCS match");
+    }
+
+    if (!fd)
+    {
+        // all of overloads are templates
+        if (td)
+        {
+            if (!od && !td.overnext)
+            {
+                .error(loc, "%s `%s` is not callable using argument types `!(%s)%s`",
+                   td.kind(), td.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
+            }
+            else
+            {
+                .error(loc, "none of the overloads of %s `%s.%s` are callable using argument types `!(%s)%s`",
+                   td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
+                   tiargsBuf.peekChars(), fargsBuf.peekChars());
+            }
+
+
+            if (!global.gag || global.params.v.showGaggedErrors)
+                printCandidates(loc, td, sc.isDeprecated());
+            return null;
+        }
+        /* This case used to happen when several ctors are mixed in an agregate.
+           A (bad) error message is already generated in overloadApply().
+           see https://issues.dlang.org/show_bug.cgi?id=19729
+           and https://issues.dlang.org/show_bug.cgi?id=17259
+        */
+        if (!od)
+            return null;
+    }
+
+    if (od)
+    {
+        .error(loc, "none of the overloads of `%s` are callable using argument types `!(%s)%s`",
+               od.ident.toChars(), tiargsBuf.peekChars(), fargsBuf.peekChars());
+        return null;
+    }
+
+    // remove when deprecation period of class allocators and deallocators is over
+    if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
+        return null;
+
+    bool hasOverloads = fd.overnext !is null;
+    auto tf = fd.type.isTypeFunction();
+    // if type is an error, the original type should be there for better diagnostics
+    if (!tf)
+        tf = fd.originalType.toTypeFunction();
+
+    // modifier mismatch
+    if (tthis && (fd.isCtorDeclaration() ?
+        !MODimplicitConv(tf.mod, tthis.mod) :
+        !MODimplicitConv(tthis.mod, tf.mod)))
+    {
+        OutBuffer thisBuf, funcBuf;
+        MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
+        auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
+        if (hasOverloads)
+        {
+            OutBuffer buf;
+            buf.argExpTypesToCBuffer(fargs);
+            if (fd.isCtorDeclaration())
+                .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
+                    fd.toChars(), thisBuf.peekChars(), buf.peekChars());
+            else
+                .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
+                    fd.toChars(), thisBuf.peekChars(), buf.peekChars());
+
+            if (!global.gag || global.params.v.showGaggedErrors)
+                printCandidates(loc, fd, sc.isDeprecated());
+            return null;
+        }
+
+        bool calledHelper;
+        void errorHelper(const(char)* failMessage) scope
+        {
+            .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
+                   fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
+                   tf.modToChars(), fargsBuf.peekChars());
+            errorSupplemental(loc, failMessage);
+            calledHelper = true;
+        }
+
+        functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper);
+        if (calledHelper)
+            return null;
+
+        if (fd.isCtorDeclaration())
+            .error(loc, "%s%s `%s` cannot construct a %sobject",
+                   funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
+        else
+            .error(loc, "%smethod `%s` is not callable using a %sobject",
+                   funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
+
+        if (mismatches.isNotShared)
+            .errorSupplemental(fd.loc, "Consider adding `shared` here");
+        else if (mismatches.isMutable)
+            .errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
+        return null;
+    }
+
+    //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`",
+               fd.toChars(), fargsBuf.peekChars());
+        if (!global.gag || global.params.v.showGaggedErrors)
+            printCandidates(loc, fd, sc.isDeprecated());
+        return null;
+    }
+
+    .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
+           fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
+           tf.modToChars(), fargsBuf.peekChars());
+
+    // re-resolve to check for supplemental message
+    if (!global.gag || global.params.v.showGaggedErrors)
+    {
+        if (tthis)
+        {
+            if (auto classType = tthis.isTypeClass())
+            {
+                if (auto baseClass = classType.sym.baseClass)
+                {
+                    if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident))
+                    {
+                        MatchAccumulator mErr;
+                        functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList);
+                        if (mErr.last > MATCH.nomatch && mErr.lastf)
+                        {
+                            errorSupplemental(loc, "%s `%s` hides base class function `%s`",
+                                    fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars());
+                            errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets",
+                                    fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars());
+                            return null;
+                        }
+                    }
+                }
+            }
+        }
+
+        void errorHelper2(const(char)* failMessage) scope
+        {
+            errorSupplemental(loc, failMessage);
+        }
+
+        functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
+    }
+    return null;
+}
+
+/*******************************************
+ * Prints template and function overload candidates as supplemental errors.
+ * Params:
+ *      loc =            instantiation location
+ *      declaration =    the declaration to print overload candidates for
+ *      showDeprecated = If `false`, `deprecated` function won't be shown
+ */
+private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated)
+if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
+{
+    // max num of overloads to print (-v or -verror-supplements overrides this).
+    const uint DisplayLimit = global.params.v.errorSupplementCount();
+    const(char)* constraintsTip;
+    // determine if the first candidate was printed
+    int printed;
+
+    bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false)
+    {
+        if (auto fd = s.isFuncDeclaration())
+        {
+            // Don't print overloads which have errors.
+            // Not that if the whole overload set has errors, we'll never reach
+            // this point so there's no risk of printing no candidate
+            if (fd.errors || fd.type.ty == Terror)
+                return false;
+            // Don't print disabled functions, or `deprecated` outside of deprecated scope
+            if (fd.storage_class & STC.disable || (fd.isDeprecated() && !showDeprecated))
+                return false;
+            if (!print)
+                return true;
+            auto tf = cast(TypeFunction) fd.type;
+            OutBuffer buf;
+            buf.writestring(fd.toPrettyChars());
+            buf.writestring(parametersTypeToChars(tf.parameterList));
+            if (tf.mod)
+            {
+                buf.writeByte(' ');
+                buf.MODtoBuffer(tf.mod);
+            }
+            .errorSupplemental(fd.loc,
+                printed ? "                `%s`" :
+                single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
+        }
+        else if (auto td = s.isTemplateDeclaration())
+        {
+            import dmd.staticcond;
+
+            if (!print)
+                return true;
+            OutBuffer buf;
+            HdrGenState hgs;
+            hgs.skipConstraints = true;
+            toCharsMaybeConstraints(td, buf, hgs);
+            const tmsg = buf.peekChars();
+            const cmsg = td.getConstraintEvalError(constraintsTip);
+
+            // add blank space if there are multiple candidates
+            // the length of the blank space is `strlen("Candidates are: ")`
+
+            if (cmsg)
+            {
+                .errorSupplemental(td.loc,
+                        printed ? "                `%s`\n%s" :
+                        single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s",
+                        tmsg, cmsg);
+            }
+            else
+            {
+                .errorSupplemental(td.loc,
+                        printed ? "                `%s`" :
+                        single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`",
+                        tmsg);
+            }
+        }
+        return true;
+    }
+    // determine if there's > 1 candidate
+    int count = 0;
+    overloadApply(declaration, (s) {
+        if (matchSymbol(s, false))
+            count++;
+        return count > 1;
+    });
+    int skipped = 0;
+    overloadApply(declaration, (s) {
+        if (global.params.v.verbose || printed < DisplayLimit)
+        {
+            if (matchSymbol(s, true, count == 1))
+                printed++;
+        }
+        else
+        {
+            // Too many overloads to sensibly display.
+            // Just show count of remaining overloads.
+            if (matchSymbol(s, false))
+                skipped++;
+        }
+        return 0;
+    });
+    if (skipped > 0)
+        .errorSupplemental(loc, "... (%d more, -v to show) ...", skipped);
+
+    // Nothing was displayed, all overloads are either disabled or deprecated
+    if (!printed)
+        .errorSupplemental(loc, "All possible candidates are marked as `deprecated` or `@disable`");
+    // should be only in verbose mode
+    if (constraintsTip)
+        .tip(constraintsTip);
+}
diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h
index afd3664bfa8..4f26801356e 100644
--- a/gcc/d/dmd/identifier.h
+++ b/gcc/d/dmd/identifier.h
@@ -11,7 +11,7 @@ 
 #pragma once
 
 #include "root/dcompat.h"
-#include "root/object.h"
+#include "rootobject.h"
 
 class Identifier final : public RootObject
 {
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
index e4d5aa2cae1..ece56c8d1bc 100644
--- a/gcc/d/dmd/importc.d
+++ b/gcc/d/dmd/importc.d
@@ -243,16 +243,15 @@  Expression castCallAmbiguity(Expression e, Scope* sc)
 
             case EXP.call:
                 auto ce = (*pe).isCallExp();
-                auto ie = ce.e1.isIdentifierExp();
-                if (ie && ie.parens)
+                if (ce.e1.parens)
                 {
-                    ce.e1 = expressionSemantic(ie, sc);
+                    ce.e1 = expressionSemantic(ce.e1, sc);
                     if (ce.e1.op == EXP.type)
                     {
                         const numArgs = ce.arguments ? ce.arguments.length : 0;
                         if (numArgs >= 1)
                         {
-                            ie.parens = false;
+                            ce.e1.parens = false;
                             Expression arg;
                             foreach (a; (*ce.arguments)[])
                             {
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 09ed630fe8b..843c402031d 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -30,7 +30,6 @@  import dmd.dtemplate;
 import dmd.enumsem;
 import dmd.errors;
 import dmd.expression;
-import dmd.func;
 import dmd.funcsem;
 import dmd.globals;
 import dmd.hdrgen;
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 9c446eb1bf3..646c4b7d3db 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -7130,7 +7130,7 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
 
     private void checkParens(TOK value, AST.Expression e)
     {
-        if (precedence[e.op] == PREC.rel)
+        if (precedence[e.op] == PREC.rel && !e.parens)
             error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(value));
     }
 
@@ -8550,6 +8550,7 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 // ( expression )
                 nextToken();
                 e = parseExpression();
+                e.parens = true;
                 check(loc, TOK.rightParenthesis);
                 break;
             }
@@ -8874,9 +8875,9 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                                         nextToken();
                                         return AST.ErrorExp.get();
                                     }
-                                    auto te = new AST.TypeExp(loc, t);
-                                    te.parens = true;
-                                    e = parsePostExp(te);
+                                    e = new AST.TypeExp(loc, t);
+                                    e.parens = true;
+                                    e = parsePostExp(e);
                                 }
                                 else if (token.value == TOK.leftParenthesis ||
                                     token.value == TOK.plusPlus || token.value == TOK.minusMinus)
@@ -9193,18 +9194,14 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
     private AST.Expression parseAndExp()
     {
         Loc loc = token.loc;
-        bool parens = token.value == TOK.leftParenthesis;
         auto e = parseCmpExp();
         while (token.value == TOK.and)
         {
-            if (!parens)
-                checkParens(TOK.and, e);
-            parens = nextToken() == TOK.leftParenthesis;
+            checkParens(TOK.and, e);
+            nextToken();
             auto e2 = parseCmpExp();
-            if (!parens)
-                checkParens(TOK.and, e2);
+            checkParens(TOK.and, e2);
             e = new AST.AndExp(loc, e, e2);
-            parens = true;              // don't call checkParens() for And
             loc = token.loc;
         }
         return e;
@@ -9212,42 +9209,32 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
 
     private AST.Expression parseXorExp()
     {
-        Loc loc = token.loc;
+        const loc = token.loc;
 
-        bool parens = token.value == TOK.leftParenthesis;
         auto e = parseAndExp();
         while (token.value == TOK.xor)
         {
-            if (!parens)
-                checkParens(TOK.xor, e);
-            parens = nextToken() == TOK.leftParenthesis;
+            checkParens(TOK.xor, e);
+            nextToken();
             auto e2 = parseAndExp();
-            if (!parens)
-                checkParens(TOK.xor, e2);
+            checkParens(TOK.xor, e2);
             e = new AST.XorExp(loc, e, e2);
-            parens = true;
-            loc = token.loc;
         }
         return e;
     }
 
     private AST.Expression parseOrExp()
     {
-        Loc loc = token.loc;
+        const loc = token.loc;
 
-        bool parens = token.value == TOK.leftParenthesis;
         auto e = parseXorExp();
         while (token.value == TOK.or)
         {
-            if (!parens)
-                checkParens(TOK.or, e);
-            parens = nextToken() == TOK.leftParenthesis;
+            checkParens(TOK.or, e);
+            nextToken();
             auto e2 = parseXorExp();
-            if (!parens)
-                checkParens(TOK.or, e2);
+            checkParens(TOK.or, e2);
             e = new AST.OrExp(loc, e, e2);
-            parens = true;
-            loc = token.loc;
         }
         return e;
     }
@@ -9298,7 +9285,6 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
 
     AST.Expression parseAssignExp()
     {
-        bool parens = token.value == TOK.leftParenthesis;
         AST.Expression e;
         e = parseCondExp();
         if (e is null)
@@ -9307,7 +9293,7 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         // require parens for e.g. `t ? a = 1 : b = 2`
         void checkRequiredParens()
         {
-            if (e.op == EXP.question && !parens)
+            if (e.op == EXP.question && !e.parens)
                 eSink.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
                     e.toChars(), Token.toChars(token.value));
         }
diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h
index 1033b22237a..3e2880431e9 100644
--- a/gcc/d/dmd/root/array.h
+++ b/gcc/d/dmd/root/array.h
@@ -9,7 +9,6 @@ 
 #pragma once
 
 #include "dsystem.h"
-#include "object.h"
 #include "rmem.h"
 
 template <typename TYPE>
@@ -44,7 +43,7 @@  struct Array
         d_size_t len = 2;
         for (d_size_t u = 0; u < length; u++)
         {
-            buf[u] = ((RootObject *)data.ptr[u])->toChars();
+            buf[u] = ((TYPE)data.ptr[u])->toChars();
             len += strlen(buf[u]) + 1;
         }
         char *str = (char *)mem.xmalloc(len);
diff --git a/gcc/d/dmd/root/bitarray.h b/gcc/d/dmd/root/bitarray.h
index 2cd7152f725..2a827033587 100644
--- a/gcc/d/dmd/root/bitarray.h
+++ b/gcc/d/dmd/root/bitarray.h
@@ -9,7 +9,6 @@ 
 #pragma once
 
 #include "dsystem.h"
-#include "object.h"
 #include "rmem.h"
 
 struct BitArray
diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/rootobject.h
similarity index 91%
rename from gcc/d/dmd/root/object.h
rename to gcc/d/dmd/rootobject.h
index f56cb176017..718a54f0275 100644
--- a/gcc/d/dmd/root/object.h
+++ b/gcc/d/dmd/rootobject.h
@@ -4,13 +4,13 @@ 
  * https://www.digitalmars.com
  * Distributed under the Boost Software License, Version 1.0.
  * https://www.boost.org/LICENSE_1_0.txt
- * https://github.com/dlang/dmd/blob/master/src/dmd/root/object.h
+ * https://github.com/dlang/dmd/blob/master/src/dmd/rootobject.h
  */
 
 #pragma once
 
-#include "dsystem.h"
-#include "dcompat.h"
+#include "root/dsystem.h"
+#include "root/dcompat.h"
 
 typedef size_t hash_t;
 
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 5013c569933..1bf36e3082d 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -1196,7 +1196,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
             }
         case Taarray:
             if (fs.op == TOK.foreach_reverse_)
-                warning(fs.loc, "cannot use `foreach_reverse` with an associative array");
+                error(fs.loc, "cannot use `foreach_reverse` with an associative array");
             if (checkForArgTypes(fs))
                 return retError();
 
diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d
index 72afe029641..3ab6885586a 100644
--- a/gcc/d/dmd/staticcond.d
+++ b/gcc/d/dmd/staticcond.d
@@ -11,120 +11,13 @@ 
 
 module dmd.staticcond;
 
-import dmd.arraytypes;
-import dmd.dinterpret;
-import dmd.dmodule;
-import dmd.dscope;
-import dmd.dsymbol;
-import dmd.errors;
 import dmd.expression;
-import dmd.expressionsem;
-import dmd.globals;
-import dmd.identifier;
-import dmd.mtype;
-import dmd.optimize;
 import dmd.root.array;
 import dmd.common.outbuffer;
 import dmd.tokens;
 
 
 
-/********************************************
- * Semantically analyze and then evaluate a static condition at compile time.
- * This is special because short circuit operators &&, || and ?: at the top
- * level are not semantically analyzed if the result of the expression is not
- * necessary.
- * Params:
- *      sc  = instantiating scope
- *      original = original expression, for error messages
- *      e =  resulting expression
- *      errors = set to `true` if errors occurred
- *      negatives = array to store negative clauses
- * Returns:
- *      true if evaluates to true
- */
-bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool errors, Expressions* negatives = null)
-{
-    if (negatives)
-        negatives.setDim(0);
-
-    bool impl(Expression e)
-    {
-        if (e.isNotExp())
-        {
-            NotExp ne = cast(NotExp)e;
-            return !impl(ne.e1);
-        }
-
-        if (e.op == EXP.andAnd || e.op == EXP.orOr)
-        {
-            LogicalExp aae = cast(LogicalExp)e;
-            bool result = impl(aae.e1);
-            if (errors)
-                return false;
-            if (e.op == EXP.andAnd)
-            {
-                if (!result)
-                    return false;
-            }
-            else
-            {
-                if (result)
-                    return true;
-            }
-            result = impl(aae.e2);
-            return !errors && result;
-        }
-
-        if (e.op == EXP.question)
-        {
-            CondExp ce = cast(CondExp)e;
-            bool result = impl(ce.econd);
-            if (errors)
-                return false;
-            Expression leg = result ? ce.e1 : ce.e2;
-            result = impl(leg);
-            return !errors && result;
-        }
-
-        Expression before = e;
-        const uint nerrors = global.errors;
-
-        sc = sc.startCTFE();
-        sc.flags |= SCOPE.condition;
-
-        e = e.expressionSemantic(sc);
-        e = resolveProperties(sc, e);
-        e = e.toBoolean(sc);
-
-        sc = sc.endCTFE();
-        e = e.optimize(WANTvalue);
-
-        if (nerrors != global.errors ||
-            e.isErrorExp() ||
-            e.type.toBasetype() == Type.terror)
-        {
-            errors = true;
-            return false;
-        }
-
-        e = e.ctfeInterpret();
-
-        const opt = e.toBool();
-        if (opt.isEmpty())
-        {
-            if (!e.type.isTypeError())
-                error(e.loc, "expression `%s` is not constant", e.toChars());
-            errors = true;
-            return false;
-        }
-
-        if (negatives && !opt.get())
-            negatives.push(before);
-        return opt.get();
-    }
-    return impl(e);
-}
 
 /********************************************
  * Format a static condition as a tree-like structure, marking failed and
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 6f12ac3eb1f..0f96a1b3b09 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -36,7 +36,7 @@  public:
     // kludge for template.isType()
     DYNCAST dyncast() const override { return DYNCAST_TUPLE; }
 
-    const char *toChars() const override { return objects.toChars(); }
+    const char *toChars() const override;
 };
 
 struct TemplatePrevious
diff --git a/gcc/testsuite/gdc.test/compilable/imports/defines.c b/gcc/testsuite/gdc.test/compilable/imports/defines.c
index 8a5601a2d08..6b0746f8ff9 100644
--- a/gcc/testsuite/gdc.test/compilable/imports/defines.c
+++ b/gcc/testsuite/gdc.test/compilable/imports/defines.c
@@ -30,3 +30,28 @@  _Static_assert(SSS[0] == 'h', "10");
 #define ABC 12
 #define GHI (size) abbadabba
 #define DEF (ABC + 5)
+
+#define ADD(a, b) a + b
+#define SUB() 3 - 2
+
+#define NO_BODY()
+#define NO_BODY_PARAMS(a, b)
+#define DO_WHILE() do { } while(0)
+
+#define pr16199_trigger(cond,func,args) _Generic (cond, default: func args)
+#define pr16199_skipped1(a) (1)
+#define pr16199_skipped2(b) (2)
+#define pr16199_ice         0x3
+
+#define M16199Ea(TYPE) (TYPE __x;)
+#define M16199E(X,S,M) ({ M16199Ea(S *); })
+
+#define M16199Da(TYPE,VAR) ((TYPE)(VAR))
+#define M16199D(X,S,M) ({ int *__x = (X); M16199Da(S *, __x); })
+int pr16199d() { return 7; }
+
+#define M16199C(X,S,M) ({ int __x; })
+int pr16199c()
+{
+    return 8;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testdefines.d b/gcc/testsuite/gdc.test/compilable/testdefines.d
index 9dd8cf2af8d..060e962920a 100644
--- a/gcc/testsuite/gdc.test/compilable/testdefines.d
+++ b/gcc/testsuite/gdc.test/compilable/testdefines.d
@@ -15,3 +15,13 @@  static assert(SSS == "hello");
 
 static assert(ABC == 12);
 static assert(DEF == 17);
+
+static assert(ADD(3, 4) == 7);
+static assert(SUB() == 1);
+
+static assert(pr16199_skipped1(5) == 1);
+static assert(pr16199_skipped2(6) == 2);
+static assert(pr16199_ice == 3);
+
+static assert(pr16199d() == 7);
+static assert(pr16199c() == 8);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/warn13679.d b/gcc/testsuite/gdc.test/fail_compilation/warn13679.d
index 74d45643c8d..22910390497 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/warn13679.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/warn13679.d
@@ -3,9 +3,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/warn13679.d(15): Warning: cannot use `foreach_reverse` with an associative array
-Error: warnings are treated as errors
-       Use -wi if you wish to treat warnings only as informational.
+fail_compilation/warn13679.d(13): Error: cannot use `foreach_reverse` with an associative array
 ---
 */
 
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 021149aabc7..f11c5fbfb0b 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-9471b25db9ed44d71e0e27956430c0c6a09c16db
+ceff48bf7db05503117f54fdc0cefcb89b711136
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index d2fb6e218c1..f17d8beb96b 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -266,17 +266,17 @@  DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d
 DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
 	core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \
 	core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \
-	core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \
-	core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \
-	core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \
-	core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \
-	core/sys/freebsd/sys/elf.d core/sys/freebsd/sys/elf32.d \
-	core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \
-	core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \
-	core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \
-	core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \
-	core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \
-	core/sys/freebsd/unistd.d
+	core/sys/freebsd/net/if_.d core/sys/freebsd/net/if_dl.d \
+	core/sys/freebsd/netinet/in_.d core/sys/freebsd/pthread_np.d \
+	core/sys/freebsd/stdlib.d core/sys/freebsd/string.d \
+	core/sys/freebsd/sys/_bitset.d core/sys/freebsd/sys/_cpuset.d \
+	core/sys/freebsd/sys/cdefs.d core/sys/freebsd/sys/elf.d \
+	core/sys/freebsd/sys/elf32.d core/sys/freebsd/sys/elf64.d \
+	core/sys/freebsd/sys/elf_common.d core/sys/freebsd/sys/event.d \
+	core/sys/freebsd/sys/link_elf.d core/sys/freebsd/sys/mman.d \
+	core/sys/freebsd/sys/mount.d core/sys/freebsd/sys/socket.d \
+	core/sys/freebsd/sys/sysctl.d core/sys/freebsd/sys/types.d \
+	core/sys/freebsd/time.d core/sys/freebsd/unistd.d
 
 DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
 	core/sys/linux/dlfcn.d core/sys/linux/elf.d core/sys/linux/epoll.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 3e3ab567a82..b6d90362f0b 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -329,10 +329,10 @@  am__objects_11 = core/sys/bionic/err.lo core/sys/bionic/fcntl.lo \
 @DRUNTIME_OS_ANDROID_TRUE@am__objects_12 = $(am__objects_11)
 am__objects_13 = core/sys/freebsd/config.lo core/sys/freebsd/dlfcn.lo \
 	core/sys/freebsd/err.lo core/sys/freebsd/execinfo.lo \
-	core/sys/freebsd/ifaddrs.lo core/sys/freebsd/net/if_dl.lo \
-	core/sys/freebsd/netinet/in_.lo core/sys/freebsd/pthread_np.lo \
-	core/sys/freebsd/stdlib.lo core/sys/freebsd/string.lo \
-	core/sys/freebsd/sys/_bitset.lo \
+	core/sys/freebsd/ifaddrs.lo core/sys/freebsd/net/if_.lo \
+	core/sys/freebsd/net/if_dl.lo core/sys/freebsd/netinet/in_.lo \
+	core/sys/freebsd/pthread_np.lo core/sys/freebsd/stdlib.lo \
+	core/sys/freebsd/string.lo core/sys/freebsd/sys/_bitset.lo \
 	core/sys/freebsd/sys/_cpuset.lo core/sys/freebsd/sys/cdefs.lo \
 	core/sys/freebsd/sys/elf.lo core/sys/freebsd/sys/elf32.lo \
 	core/sys/freebsd/sys/elf64.lo \
@@ -943,17 +943,17 @@  DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d
 DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
 	core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \
 	core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \
-	core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \
-	core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \
-	core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \
-	core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \
-	core/sys/freebsd/sys/elf.d core/sys/freebsd/sys/elf32.d \
-	core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \
-	core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \
-	core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \
-	core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \
-	core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \
-	core/sys/freebsd/unistd.d
+	core/sys/freebsd/net/if_.d core/sys/freebsd/net/if_dl.d \
+	core/sys/freebsd/netinet/in_.d core/sys/freebsd/pthread_np.d \
+	core/sys/freebsd/stdlib.d core/sys/freebsd/string.d \
+	core/sys/freebsd/sys/_bitset.d core/sys/freebsd/sys/_cpuset.d \
+	core/sys/freebsd/sys/cdefs.d core/sys/freebsd/sys/elf.d \
+	core/sys/freebsd/sys/elf32.d core/sys/freebsd/sys/elf64.d \
+	core/sys/freebsd/sys/elf_common.d core/sys/freebsd/sys/event.d \
+	core/sys/freebsd/sys/link_elf.d core/sys/freebsd/sys/mman.d \
+	core/sys/freebsd/sys/mount.d core/sys/freebsd/sys/socket.d \
+	core/sys/freebsd/sys/sysctl.d core/sys/freebsd/sys/types.d \
+	core/sys/freebsd/time.d core/sys/freebsd/unistd.d
 
 DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
 	core/sys/linux/dlfcn.d core/sys/linux/elf.d core/sys/linux/epoll.d \
@@ -1613,6 +1613,7 @@  core/sys/freebsd/ifaddrs.lo: core/sys/freebsd/$(am__dirstamp)
 core/sys/freebsd/net/$(am__dirstamp):
 	@$(MKDIR_P) core/sys/freebsd/net
 	@: > core/sys/freebsd/net/$(am__dirstamp)
+core/sys/freebsd/net/if_.lo: core/sys/freebsd/net/$(am__dirstamp)
 core/sys/freebsd/net/if_dl.lo: core/sys/freebsd/net/$(am__dirstamp)
 core/sys/freebsd/netinet/$(am__dirstamp):
 	@$(MKDIR_P) core/sys/freebsd/netinet
diff --git a/libphobos/libdruntime/core/sys/freebsd/ifaddrs.d b/libphobos/libdruntime/core/sys/freebsd/ifaddrs.d
index aa39ac4bb49..a08b8edab11 100644
--- a/libphobos/libdruntime/core/sys/freebsd/ifaddrs.d
+++ b/libphobos/libdruntime/core/sys/freebsd/ifaddrs.d
@@ -3,7 +3,7 @@ 
 /++
     D header file for FreeBSD's ifaddrs.h.
 
-    Copyright: Copyright 2023
+    Copyright: Copyright 2023 - 2024
     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
     Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
  +/
@@ -23,6 +23,7 @@  struct ifaddrs
     uint      ifa_flags;
     sockaddr* ifa_addr;
     sockaddr* ifa_netmask;
+    alias ifa_broadaddr = ifa_dstaddr;
     sockaddr* ifa_dstaddr;
     void*     ifa_data;
 }
diff --git a/libphobos/libdruntime/core/sys/freebsd/net/if_.d b/libphobos/libdruntime/core/sys/freebsd/net/if_.d
new file mode 100644
index 00000000000..e050f1bd418
--- /dev/null
+++ b/libphobos/libdruntime/core/sys/freebsd/net/if_.d
@@ -0,0 +1,493 @@ 
+//Written in the D programming language
+
+/++
+    D header file for FreeBSD's net/if.h.
+
+    Copyright: Copyright 2024
+    License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
+    Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
+ +/
+module core.sys.freebsd.net.if_;
+
+public import core.sys.posix.net.if_;
+
+version (FreeBSD):
+extern(C):
+@nogc:
+nothrow:
+
+import core.stdc.config;
+import core.sys.freebsd.sys.types : caddr_t;
+import core.sys.posix.sys.socket : sockaddr;
+import core.sys.posix.sys.time : time_t, timeval;
+
+enum IF_MAXUNIT = 0x7fff;
+
+struct if_clonereq
+{
+    int    ifcr_total;
+    int    ifcr_count;
+    ubyte* ifcr_buffer;
+}
+
+struct if_data
+{
+    ubyte  ifi_type;
+    ubyte  ifi_physical;
+    ubyte  ifi_addrlen;
+    ubyte  ifi_hdrlen;
+    ubyte  ifi_link_state;
+    ubyte  ifi_vhid;
+    ushort ifi_datalen;
+    uint   ifi_mtu;
+    uint   ifi_metric;
+    ulong  ifi_baudrate;
+
+    ulong ifi_ipackets;
+    ulong ifi_ierrors;
+    ulong ifi_opackets;
+    ulong ifi_oerrors;
+    ulong ifi_collisions;
+    ulong ifi_ibytes;
+    ulong ifi_obytes;
+    ulong ifi_imcasts;
+    ulong ifi_omcasts;
+    ulong ifi_iqdrops;
+    ulong ifi_oqdrops;
+    ulong ifi_noproto;
+    ulong ifi_hwassist;
+
+    union
+    {
+        time_t ifi_epoch;
+        private ulong  ph;
+    }
+
+    union
+    {
+        timeval ifi_lastchange;
+        struct
+        {
+            private ulong ph1;
+            private ulong ph2;
+        }
+    }
+}
+
+enum IFF_UP          = 0x1;
+enum IFF_BROADCAST   = 0x2;
+enum IFF_DEBUG       = 0x4;
+enum IFF_LOOPBACK    = 0x8;
+enum IFF_POINTOPOINT = 0x10;
+enum IFF_NEEDSEPOCH  = 0x20;
+enum IFF_DRV_RUNNING = 0x40;
+enum IFF_NOARP       = 0x80;
+enum IFF_PROMISC     = 0x100;
+enum IFF_ALLMULTI    = 0x200;
+enum IFF_DRV_OACTIVE = 0x400;
+enum IFF_SIMPLEX     = 0x800;
+enum IFF_LINK0       = 0x1000;
+enum IFF_LINK1       = 0x2000;
+enum IFF_LINK2       = 0x4000;
+enum IFF_ALTPHYS     = IFF_LINK2;
+enum IFF_MULTICAST   = 0x8000;
+enum IFF_CANTCONFIG  = 0x10000;
+enum IFF_PPROMISC    = 0x20000;
+enum IFF_MONITOR     = 0x40000;
+enum IFF_STATICARP   = 0x80000;
+enum IFF_STICKYARP   = 0x100000;
+enum IFF_DYING       = 0x200000;
+enum IFF_RENAMING    = 0x400000;
+enum IFF_SPARE       = 0x800000;
+enum IFF_NETLINK_1   = 0x1000000;
+
+enum IFF_RUNNING = IFF_DRV_RUNNING;
+enum IFF_OACTIVE = IFF_DRV_OACTIVE;
+
+enum IFF_CANTCHANGE = IFF_BROADCAST |
+                      IFF_POINTOPOINT |
+                      IFF_DRV_RUNNING |
+                      IFF_DRV_OACTIVE |
+                      IFF_SIMPLEX |
+                      IFF_MULTICAST |
+                      IFF_ALLMULTI |
+                      IFF_PROMISC |
+                      IFF_DYING |
+                      IFF_CANTCONFIG |
+                      IFF_NEEDSEPOCH;
+
+enum LINK_STATE_UNKNOWN = 0;
+enum LINK_STATE_DOWN    = 1;
+enum LINK_STATE_UP      = 2;
+
+auto IF_Kbps(T)(T x) { return uintmax_t(x) * 1000; }
+auto IF_Mbps(T)(T x) { return IF_Kbps(x * 1000); }
+auto IF_Gbps(T)(T x) { return IF_Mbps(x * 1000); }
+
+enum IFCAP_B_RXCSUM         = 0;
+enum IFCAP_B_TXCSUM         = 1;
+enum IFCAP_B_NETCONS        = 2;
+enum IFCAP_B_VLAN_MTU       = 3;
+enum IFCAP_B_VLAN_HWTAGGING = 4;
+enum IFCAP_B_JUMBO_MTU      = 5;
+enum IFCAP_B_POLLING        = 6;
+enum IFCAP_B_VLAN_HWCSUM    = 7;
+enum IFCAP_B_TSO4           = 8;
+enum IFCAP_B_TSO6           = 9;
+enum IFCAP_B_LRO            = 10;
+enum IFCAP_B_WOL_UCAST      = 11;
+enum IFCAP_B_WOL_MCAST      = 12;
+enum IFCAP_B_WOL_MAGIC      = 13;
+enum IFCAP_B_TOE4           = 14;
+enum IFCAP_B_TOE6           = 15;
+enum IFCAP_B_VLAN_HWFILTER  = 16;
+enum IFCAP_B_NV             = 17;
+enum IFCAP_B_VLAN_HWTSO     = 18;
+enum IFCAP_B_LINKSTATE      = 19;
+enum IFCAP_B_NETMAP         = 20;
+enum IFCAP_B_RXCSUM_IPV6    = 21;
+enum IFCAP_B_TXCSUM_IPV6    = 22;
+enum IFCAP_B_HWSTATS        = 23;
+enum IFCAP_B_TXRTLMT        = 24;
+enum IFCAP_B_HWRXTSTMP      = 25;
+enum IFCAP_B_MEXTPG         = 26;
+enum IFCAP_B_TXTLS4         = 27;
+enum IFCAP_B_TXTLS6         = 28;
+enum IFCAP_B_VXLAN_HWCSUM   = 29;
+enum IFCAP_B_VXLAN_HWTSO    = 30;
+enum IFCAP_B_TXTLS_RTLMT    = 31;
+enum IFCAP_B_RXTLS4         = 32;
+enum IFCAP_B_RXTLS6         = 33;
+enum __IFCAP_B_SIZE         = 34;
+
+// IFCAP_B_MAX is defined in net/if.h, but __IFCAP_B_MAX doesn't seem to be defined anywhere.
+// enum IFCAP_B_MAX = __IFCAP_B_MAX - 1;
+enum IFCAP_B_SIZE = __IFCAP_B_SIZE;
+
+auto IFCAP_BIT(T)(T x) { return 1 << x; }
+
+enum IFCAP_RXCSUM         = IFCAP_BIT(IFCAP_B_RXCSUM);
+enum IFCAP_TXCSUM         = IFCAP_BIT(IFCAP_B_TXCSUM);
+enum IFCAP_NETCONS        = IFCAP_BIT(IFCAP_B_NETCONS);
+enum IFCAP_VLAN_MTU       = IFCAP_BIT(IFCAP_B_VLAN_MTU);
+enum IFCAP_VLAN_HWTAGGING = IFCAP_BIT(IFCAP_B_VLAN_HWTAGGING);
+enum IFCAP_JUMBO_MTU      = IFCAP_BIT(IFCAP_B_JUMBO_MTU);
+enum IFCAP_POLLING        = IFCAP_BIT(IFCAP_B_POLLING);
+enum IFCAP_VLAN_HWCSUM    = IFCAP_BIT(IFCAP_B_VLAN_HWCSUM);
+enum IFCAP_TSO4           = IFCAP_BIT(IFCAP_B_TSO4);
+enum IFCAP_TSO6           = IFCAP_BIT(IFCAP_B_TSO6);
+enum IFCAP_LRO            = IFCAP_BIT(IFCAP_B_LRO);
+enum IFCAP_WOL_UCAST      = IFCAP_BIT(IFCAP_B_WOL_UCAST);
+enum IFCAP_WOL_MCAST      = IFCAP_BIT(IFCAP_B_WOL_MCAST);
+enum IFCAP_WOL_MAGIC      = IFCAP_BIT(IFCAP_B_WOL_MAGIC);
+enum IFCAP_TOE4           = IFCAP_BIT(IFCAP_B_TOE4);
+enum IFCAP_TOE6           = IFCAP_BIT(IFCAP_B_TOE6);
+enum IFCAP_VLAN_HWFILTER  = IFCAP_BIT(IFCAP_B_VLAN_HWFILTER);
+enum IFCAP_NV             = IFCAP_BIT(IFCAP_B_NV);
+enum IFCAP_VLAN_HWTSO     = IFCAP_BIT(IFCAP_B_VLAN_HWTSO);
+enum IFCAP_LINKSTATE      = IFCAP_BIT(IFCAP_B_LINKSTATE);
+enum IFCAP_NETMAP         = IFCAP_BIT(IFCAP_B_NETMAP);
+enum IFCAP_RXCSUM_IPV6    = IFCAP_BIT(IFCAP_B_RXCSUM_IPV6);
+enum IFCAP_TXCSUM_IPV6    = IFCAP_BIT(IFCAP_B_TXCSUM_IPV6);
+enum IFCAP_HWSTATS        = IFCAP_BIT(IFCAP_B_HWSTATS);
+enum IFCAP_TXRTLMT        = IFCAP_BIT(IFCAP_B_TXRTLMT);
+enum IFCAP_HWRXTSTMP      = IFCAP_BIT(IFCAP_B_HWRXTSTMP);
+enum IFCAP_MEXTPG         = IFCAP_BIT(IFCAP_B_MEXTPG);
+enum IFCAP_TXTLS4         = IFCAP_BIT(IFCAP_B_TXTLS4);
+enum IFCAP_TXTLS6         = IFCAP_BIT(IFCAP_B_TXTLS6);
+enum IFCAP_VXLAN_HWCSUM   = IFCAP_BIT(IFCAP_B_VXLAN_HWCSUM);
+enum IFCAP_VXLAN_HWTSO    = IFCAP_BIT(IFCAP_B_VXLAN_HWTSO);
+enum IFCAP_TXTLS_RTLMT    = IFCAP_BIT(IFCAP_B_TXTLS_RTLMT);
+
+enum IFCAP2_RXTLS4 = IFCAP_B_RXTLS4 - 32;
+enum IFCAP2_RXTLS6 = IFCAP_B_RXTLS6 - 32;
+
+auto IFCAP2_BIT(T)(T x) { return 1UL << x; }
+
+enum IFCAP_HWCSUM_IPV6 = IFCAP_RXCSUM_IPV6 | IFCAP_TXCSUM_IPV6;
+
+enum IFCAP_HWCSUM = IFCAP_RXCSUM | IFCAP_TXCSUM;
+enum IFCAP_TSO    = IFCAP_TSO4 | IFCAP_TSO6;
+enum IFCAP_WOL    = IFCAP_WOL_UCAST | IFCAP_WOL_MCAST | IFCAP_WOL_MAGIC;
+enum IFCAP_TOE    = IFCAP_TOE4 | IFCAP_TOE6;
+enum IFCAP_TXTLS  = IFCAP_TXTLS4 | IFCAP_TXTLS6;
+
+enum IFCAP_CANTCHANGE = IFCAP_NETMAP | IFCAP_NV;
+enum IFCAP_ALLCAPS    = 0xffffffff;
+
+enum IFQ_MAXLEN   = 50;
+enum IFNET_SLOWHZ = 1;
+
+struct if_msghdr
+{
+    ushort  ifm_msglen;
+    ubyte   ifm_version;
+    ubyte   ifm_type;
+    int     ifm_addrs;
+    int     ifm_flags;
+    ushort  ifm_index;
+    ushort  _ifm_spare1;
+    if_data ifm_data;
+}
+
+auto IF_MSGHDRL_IFM_DATA(T)(T _l) { return cast(if_data*) (cast(ubyte*) _l + _l.ifm_data_off); }
+
+auto IF_MSGHDRL_RTA(T)(T_l) { return cast(void*) (cast(uintptr_t) _l + _l.ifm_len); }
+
+struct if_msghdrl
+{
+    ushort  ifm_msglen;
+    ubyte   ifm_version;
+    ubyte   ifm_type;
+    int     ifm_addrs;
+    int     ifm_flags;
+    ushort  ifm_index;
+    ushort  _ifm_spare1;
+    ushort  ifm_len;
+    ushort  ifm_data_off;
+    int     _ifm_spare2;
+    if_data ifm_data;
+}
+
+struct ifa_msghdr
+{
+    ushort ifam_msglen;
+    ubyte  ifam_version;
+    ubyte  ifam_type;
+    int    ifam_addrs;
+    int    ifam_flags;
+    ushort ifam_index;
+    ushort _ifam_spare1;
+    int    ifam_metric;
+}
+
+auto IFA_MSGHDRL_IFAM_DATA(T)(T _l) { return cast(if_data*) (cast(ubyte*) _l + _l.ifam_data_off); }
+
+auto IFA_MSGHDRL_RTA(T)(T _l) { return cast(void*) (cast(uintptr_t) _l + _l.ifam_len); }
+
+struct ifa_msghdrl
+{
+    ushort  ifam_msglen;
+    ubyte   ifam_version;
+    ubyte   ifam_type;
+    int     ifam_addrs;
+    int     ifam_flags;
+    ushort  ifam_index;
+    ushort  _ifam_spare1;
+    ushort  ifam_len;
+    ushort  ifam_data_off;
+    int     ifam_metric;
+    if_data ifam_data;
+}
+
+struct ifma_msghdr
+{
+    ushort ifmam_msglen;
+    ubyte  ifmam_version;
+    ubyte  ifmam_type;
+    int    ifmam_addrs;
+    int    ifmam_flags;
+    ushort ifmam_index;
+    ushort _ifmam_spare1;
+}
+
+struct if_announcemsghdr
+{
+    ushort            ifan_msglen;
+    ubyte             ifan_version;
+    ubyte             ifan_type;
+    ushort            ifan_index;
+    char[IF_NAMESIZE] ifan_name;
+    ushort            ifan_what;
+}
+
+enum IFAN_ARRIVAL   = 0;
+enum IFAN_DEPARTURE = 1;
+
+struct ifreq_buffer
+{
+    size_t length;
+    void*  buffer;
+}
+
+struct ifreq_nv_req
+{
+    uint  buf_length;
+    uint  length;
+    void* buffer;
+}
+
+enum IFR_CAP_NV_MAXBUFSIZE = 2 * 1024 * 1024;
+
+struct ifreq
+{
+    char[IF_NAMESIZE] ifr_name;
+
+    union
+    {
+        sockaddr         ifr_addr;
+        sockaddr         ifr_dstaddr;
+        sockaddr         ifr_broadaddr;
+        ifreq_buffer     ifr_buffer;
+        private short[2] ifru_flags;
+        short            ifr_index;
+        int              ifr_jid;
+        int              ifr_metric;
+        int              ifr_mtu;
+        int              ifr_phys;
+        int              ifr_media;
+        caddr_t          ifr_data;
+        private int[2]   ifru_cap;
+        uint             ifr_fib;
+        ubyte            ifr_vlan_pcp;
+        ifreq_nv_req     ifr_cap_nv;
+    }
+
+    @property ref ifr_flags()     { return ifru_flags[0]; }
+    @property ref ifr_flagshigh() { return ifru_flags[1]; }
+    @property ref ifr_reqcap()    { return ifru_cap[0]; }
+    @property ref ifr_curcap()    { return ifru_cap[1]; }
+    alias ifr_lan_pcp = ifr_vlan_pcp;
+}
+
+auto _SIZEOF_ADDR_IFREQ(T)(T ifr) { return ifr.ifr_addr.sa_len > sockaddr.sizeof ?
+                                           ifreq.sizeof - sockaddr.sizeof + ifr.ifr_addr.sa_len :
+                                           ifreq.sizeof; }
+
+struct ifaliasreq
+{
+    char[IF_NAMESIZE] ifra_name;
+    sockaddr          ifra_addr;
+    sockaddr          ifra_broadaddr;
+    sockaddr          ifra_mask;
+    int               ifra_vhid;
+}
+
+struct oifaliasreq
+{
+    char[IF_NAMESIZE] ifra_name;
+    sockaddr          ifra_addr;
+    sockaddr          ifra_broadaddr;
+    sockaddr          ifra_mask;
+ }
+
+struct ifmediareq
+{
+    char[IF_NAMESIZE] ifm_name;
+    int               ifm_current;
+    int               ifm_mask;
+    int               ifm_status;
+    int               ifm_active;
+    int               ifm_count;
+    int*              ifm_ulist;
+}
+
+struct ifdrv
+{
+    char[IF_NAMESIZE] ifd_name;
+    c_ulong           ifd_cmd;
+    size_t            ifd_len;
+    void*             ifd_data;
+}
+
+enum IFSTATMAX = 800;
+struct ifstat
+{
+    char[IF_NAMESIZE]   ifs_name;
+    char[IFSTATMAX + 1] ascii;
+}
+
+struct ifconf
+{
+    int ifc_len;
+    union
+    {
+        caddr_t ifc_buf;
+        ifreq*  ifc_req;
+    }
+}
+
+enum IFG_ALL = "all";
+enum IFG_EGRESS = "egress";
+
+struct ifg_req
+{
+    union
+    {
+        char[IF_NAMESIZE] ifgrq_group;
+        char[IF_NAMESIZE] ifgrq_member;
+    }
+}
+
+struct ifgroupreq
+{
+    char[IF_NAMESIZE] ifgr_name;
+    uint              ifgr_len;
+    union
+    {
+        char[IF_NAMESIZE] ifgr_group;
+        ifg_req*          ifgr_groups;
+    }
+}
+
+struct ifi2creq
+{
+    ubyte    dev_addr;
+    ubyte    offset;
+    ubyte    len;
+    ubyte    spare0;
+    uint     spare1;
+    ubyte[8] data;
+}
+
+enum RSS_FUNC_NONE     = 0;
+enum RSS_FUNC_PRIVATE  = 1;
+enum RSS_FUNC_TOEPLITZ = 2;
+
+enum RSS_TYPE_IPV4        = 0x00000001;
+enum RSS_TYPE_TCP_IPV4    = 0x00000002;
+enum RSS_TYPE_IPV6        = 0x00000004;
+enum RSS_TYPE_IPV6_EX     = 0x00000008;
+enum RSS_TYPE_TCP_IPV6    = 0x00000010;
+enum RSS_TYPE_TCP_IPV6_EX = 0x00000020;
+enum RSS_TYPE_UDP_IPV4    = 0x00000040;
+enum RSS_TYPE_UDP_IPV6    = 0x00000080;
+enum RSS_TYPE_UDP_IPV6_EX = 0x00000100;
+
+enum RSS_KEYLEN = 128;
+
+struct ifrsskey
+{
+    char[IF_NAMESIZE]  ifrk_name;
+    ubyte              ifrk_func;
+    ubyte              ifrk_spare0;
+    ushort             ifrk_keylen;
+    ubyte[RSS_KEYLEN]  ifrk_key;
+}
+
+struct ifrsshash
+{
+    char[IF_NAMESIZE] ifrh_name;
+    ubyte             ifrh_func;
+    ubyte             ifrh_spare0;
+    ushort            ifrh_spare1;
+    uint              ifrh_types;
+}
+
+enum IFNET_PCP_NONE = 0xff;
+
+enum IFDR_MSG_SIZE      = 64;
+enum IFDR_REASON_MSG    = 1;
+enum IFDR_REASON_VENDOR = 2;
+
+struct ifdownreason
+{
+    char[IF_NAMESIZE]   ifdr_name;
+    uint                ifdr_reason;
+    uint                ifdr_vendor;
+    char[IFDR_MSG_SIZE] ifdr_msg;
+}
+
+// FIXME It's not clear where ifnet is supposed to be coming from, so this is
+// commented out for now.
+//alias if_t = ifnet*;
diff --git a/libphobos/libdruntime/core/sys/linux/sys/socket.d b/libphobos/libdruntime/core/sys/linux/sys/socket.d
index 339a6022dc8..dc274e4d702 100644
--- a/libphobos/libdruntime/core/sys/linux/sys/socket.d
+++ b/libphobos/libdruntime/core/sys/linux/sys/socket.d
@@ -71,7 +71,6 @@  enum
     AF_BRIDGE     = PF_BRIDGE,
     AF_ATMPVC     = PF_ATMPVC,
     AF_X25        = PF_X25,
-    AF_INET6      = PF_INET6,
     AF_ROSE       = PF_ROSE,
     AF_DECnet     = PF_DECnet,
     AF_NETBEUI    = PF_NETBEUI,
diff --git a/libphobos/libdruntime/core/thread/fiber.d b/libphobos/libdruntime/core/thread/fiber.d
index dd2462fbca1..48b6f9ef006 100644
--- a/libphobos/libdruntime/core/thread/fiber.d
+++ b/libphobos/libdruntime/core/thread/fiber.d
@@ -1393,7 +1393,7 @@  private:
             // At present, it is not safe to migrate fibers between threads, but if that
             // changes, then updating the value of R13 will also need to be handled.
             version (PPC64)
-              *cast(size_t*)(pstack + wsize) = cast(size_t) Thread.getThis().m_addr;
+              *cast(size_t*)(pstack + wsize) = cast(size_t) ThreadBase.getThis().m_addr;
             assert( (cast(size_t) pstack & 0x0f) == 0 );
         }
         else version (AsmMIPS_O32_Posix)
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 4125fd717f4..50d71f59154 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-5478868465ae1ad743ff76ac5bb92691463ffec5
+dcbfbd43ac321e81af60afd795bd0f3c3f47cfa0
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index 13ae2941296..5fac1c9cca4 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -3276,7 +3276,9 @@  struct Nullable(T)
         {
             if (!_isNull)
             {
-                destroy(_value.payload);
+                import std.traits : Unqual;
+                auto ptr = () @trusted { return cast(Unqual!T*) &_value.payload; }();
+                destroy!false(*ptr);
             }
         }
     }
@@ -4319,6 +4321,37 @@  auto nullable(T)(T t)
     assert(b.empty);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24403
+@safe unittest
+{
+    static bool destroyed;
+    static struct S { ~this() { destroyed = true; } }
+
+    {
+        Nullable!S s = S.init;
+        destroyed = false;
+    }
+    assert(destroyed);
+
+    {
+        Nullable!(const S) s = S.init;
+        destroyed = false;
+    }
+    assert(destroyed);
+
+    {
+        Nullable!(immutable S) s = S.init;
+        destroyed = false;
+    }
+    assert(destroyed);
+
+    {
+        Nullable!(shared S) s = S.init;
+        destroyed = false;
+    }
+    assert(destroyed);
+}
+
 /**
 Just like `Nullable!T`, except that the null state is defined as a
 particular value. For example, $(D Nullable!(uint, uint.max)) is an