summaryrefslogtreecommitdiffstats
path: root/PATCHES
diff options
context:
space:
mode:
authorJoerg Koenig <Joerg.Koenig@techsat.com>2019-05-30 14:53:28 (GMT)
committerJoerg Koenig <Joerg.Koenig@techsat.com>2019-05-30 14:53:28 (GMT)
commitfb4009e29d14b8ad1b3945225451dc964e248660 (patch)
treedfbfa106f07e305f27f2bc7487cfc6b22e1ef9a8 /PATCHES
parentc75756608d1d3fe2158da5b549fd63ba96ec1c36 (diff)
downloadgcc-compiler-suite-fb4009e29d14b8ad1b3945225451dc964e248660.zip
gcc-compiler-suite-fb4009e29d14b8ad1b3945225451dc964e248660.tar.gz
gcc-compiler-suite-fb4009e29d14b8ad1b3945225451dc964e248660.tar.bz2
New version 1.3.0refs/changes/89/7689/1
windows nativ: - using posix thread model - with dwarf2 - added mingw tools Resolves: :jira:<issue> See also: :jira:<issue> Change-Id: I198fe988f0945db58f65be47dbb87cb9d00c2992
Diffstat (limited to 'PATCHES')
-rw-r--r--PATCHES/0002-Relocate-libintl.patch855
-rw-r--r--PATCHES/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch130
-rw-r--r--PATCHES/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch60
-rw-r--r--PATCHES/0005-Windows-Don-t-ignore-native-system-header-dir.patch28
-rw-r--r--PATCHES/0006-Windows-New-feature-to-allow-overriding.patch44
-rw-r--r--PATCHES/0008-Prettify-linking-no-undefined.patch41
-rw-r--r--PATCHES/0010-Fix-using-large-PCH.patch154
-rw-r--r--PATCHES/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch109
-rw-r--r--PATCHES/0019-gcc-8-branch-Backport-patches-for-std-filesystem-from-master.patch2760
-rw-r--r--PATCHES/mingw-tools-widl-realloc.patch11
-rw-r--r--PATCHES/windows-lrealpath-no-force-lowercase-nor-backslash.patch34
11 files changed, 4192 insertions, 34 deletions
diff --git a/PATCHES/0002-Relocate-libintl.patch b/PATCHES/0002-Relocate-libintl.patch
new file mode 100644
index 0000000..0d44a6e
--- /dev/null
+++ b/PATCHES/0002-Relocate-libintl.patch
@@ -0,0 +1,855 @@
+From b00d99e8c5b045acdacae73d946dd8147a8885c8 Mon Sep 17 00:00:00 2001
+From: Erwin Waterlander <waterlan@xs4all.nl>
+Date: Wed, 5 Aug 2015 23:36:03 +0100
+Subject: [PATCH 02/15] Relocate libintl
+
+The relocatex-libintl patch adds builtin relocation for executables to the
+libintl dll. With this patch the programs are automatically relocatable. There
+is no need anymore to add relocation code to your program when you use this
+libintl DLL.
+
+The patch was ported from the GnuWin32 port of libintl, which has also builtin
+relacation support.
+
+At the moment the relocation support is only active if you compile with MinGW
+for Windows. If you compile for Unix/Linux/Cygwin the functionality is
+unchanged.
+
+See also:
+http://waterlan.home.xs4all.nl/libintl.html
+http://sourceforge.net/tracker/?func=detail&atid=302435&aid=3003879&group_id=2435
+GnuWin32: http://gnuwin32.sourceforge.net/
+
+Great thanks to GnuWin32 maintainer Kees Zeelenberg.
+
+Erwin Waterlander
+waterlan@xs4all.nl
+http://waterlan.home.xs4all.nl/
+
+Additional "bogus paths for *nix-style paths" fix by Alexey Pavlov
+
+[jes: fix for 64-bit]
+
+Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
+---
+ intl/Makefile.in | 8 +-
+ intl/bindtextdom.c | 22 ++++
+ intl/canonicalize.c | 343 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ intl/canonicalize.h | 18 +++
+ intl/relocatex.c | 284 +++++++++++++++++++++++++++++++++++++++++++
+ intl/relocatex.h | 41 +++++++
+ 6 files changed, 715 insertions(+), 1 deletion(-)
+ create mode 100644 intl/canonicalize.c
+ create mode 100644 intl/canonicalize.h
+ create mode 100644 intl/relocatex.c
+ create mode 100644 intl/relocatex.h
+
+diff --git a/intl/Makefile.in b/intl/Makefile.in
+index 3dd0b7f..e2b8666 100644
+--- a/intl/Makefile.in
++++ b/intl/Makefile.in
+@@ -53,6 +53,7 @@ DEFS = -DHAVE_CONFIG_H
+ COMPILE = $(CC) -c $(CPPFLAGS) $(CFLAGS) $(DEFS) $(DEFS-$@) $(INCLUDES)
+
+ HEADERS = \
++ canonicalize.h \
+ gmo.h \
+ gettextP.h \
+ hash-string.h \
+@@ -61,6 +62,7 @@ HEADERS = \
+ eval-plural.h \
+ localcharset.h \
+ relocatable.h \
++ relocatex.h \
+ libgnuintl.h
+ SOURCES = \
+ bindtextdom.c \
+@@ -81,6 +83,8 @@ SOURCES = \
+ plural-exp.c \
+ localcharset.c \
+ relocatable.c \
++ relocatex.c \
++ canonicalize.c \
+ localename.c \
+ log.c \
+ osdep.c \
+@@ -104,6 +108,8 @@ OBJECTS = \
+ plural-exp.o \
+ localcharset.o \
+ relocatable.o \
++ relocatex.o \
++ canonicalize.o \
+ localename.o \
+ log.o \
+ osdep.o \
+@@ -158,7 +164,7 @@ install-info install-dvi install-ps install-pdf install-html:
+ $(OBJECTS): config.h libintl.h
+ bindtextdom.o dcgettext.o dcigettext.o dcngettext.o dgettext.o \
+ dngettext.o finddomain.o gettext.o intl-compat.o loadmsgcat.o \
+-localealias.o ngettext.o textdomain.o: gettextP.h gmo.h loadinfo.h
++localealias.o ngettext.o textdomain.o: gettextP.h gmo.h loadinfo.h relocatex.h
+ dcigettext.o loadmsgcat.o: hash-string.h
+ explodename.o l10nflist.o: loadinfo.h
+ dcigettext.o loadmsgcat.o plural.o plural-exp.o: plural-exp.h
+diff --git a/intl/bindtextdom.c b/intl/bindtextdom.c
+index 6faac57..b7a62d5 100644
+--- a/intl/bindtextdom.c
++++ b/intl/bindtextdom.c
+@@ -23,6 +23,7 @@
+ #include <stddef.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <unistd.h>
+
+ #ifdef _LIBC
+ # include <libintl.h>
+@@ -91,6 +92,12 @@ static void set_binding_values PARAMS ((const char *domainname,
+ const char **dirnamep,
+ const char **codesetp));
+
++#if ENABLE_RELOCATABLE
++# include "relocatex.h"
++#else
++# define relocate(pathname) (pathname)
++#endif
++
+ /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
+ to be used for the DOMAINNAME message catalog.
+ If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
+@@ -352,8 +359,23 @@ BINDTEXTDOMAIN (domainname, dirname)
+ const char *domainname;
+ const char *dirname;
+ {
++/*
+ set_binding_values (domainname, &dirname, NULL);
+ return (char *) dirname;
++*/
++ if (!access (dirname, R_OK)) {
++ set_binding_values (domainname, &dirname, NULL);
++ return (char *) dirname;
++ } else {
++ char *locale_dirname, *installdir = strdup (dirname), *s;
++ if ((s = strrchr (installdir, '/'))) *s = '\0';
++ if ((s = strrchr (installdir, '/'))) *s = '\0';
++ locale_dirname = relocatex (installdir, dirname);
++ set_binding_values (domainname, (const char **) &locale_dirname, NULL);
++ if (installdir)
++ free (installdir);
++ return (char *) locale_dirname;
++ }
+ }
+
+ /* Specify the character encoding in which the messages from the
+diff --git a/intl/canonicalize.c b/intl/canonicalize.c
+new file mode 100644
+index 0000000..5217f30
+--- /dev/null
++++ b/intl/canonicalize.c
+@@ -0,0 +1,343 @@
++/* Return the canonical absolute name of a given file.
++ Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
++ This file is part of the GNU C Library.
++
++ The GNU C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GNU C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GNU C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <limits.h>
++#include <sys/param.h>
++#include <sys/stat.h>
++#include <errno.h>
++#include <stddef.h>
++#include <malloc.h>
++#ifdef __WIN32__
++# include <stdio.h>
++# include <windows.h>
++//# include <gw32.h>
++#endif /* __WIN32__ */
++#include "canonicalize.h"
++
++#ifndef MAXSYMLINKS
++# define MAXSYMLINKS 20
++#endif
++
++#ifndef __set_errno
++# define __set_errno(Val) errno = (Val)
++#endif
++
++# ifdef VMS
++ /* We want the directory in Unix syntax, not in VMS syntax. */
++# define __getcwd(buf, max) getcwd (buf, max, 0)
++# else
++# define __getcwd getcwd
++# endif
++
++#define weak_alias(local, symbol)
++
++#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
++ /* Win32, Cygwin, OS/2, DOS */
++# define ISDIRSEP(C) ((C) == '/' || (C) == '\\')
++#else
++ /* Unix */
++# define ISDIRSEP(C) ((C) == '/')
++#endif
++
++#ifdef __WIN32__
++char *win2unixpath (char *FileName)
++{
++ char *s = FileName;
++ while (*s) {
++ if (*s == '\\')
++ *s = '/';
++ *s++;
++ }
++ return FileName;
++}
++#endif
++
++/* Return the canonical absolute name of file NAME. A canonical name
++ does not contain any `.', `..' components nor any repeated path
++ separators ('/') or symlinks. All path components must exist. If
++ RESOLVED is null, the result is malloc'd; otherwise, if the
++ canonical name is PATH_MAX chars or more, returns null with `errno'
++ set to ENAMETOOLONG; if the name fits in fewer than PATH_MAX chars,
++ returns the name in RESOLVED. If the name cannot be resolved and
++ RESOLVED is non-NULL, it contains the path of the first component
++ that cannot be resolved. If the path can be resolved, RESOLVED
++ holds the same value as the value returned.
++ RESOLVED must be at least PATH_MAX long */
++
++static char *
++canonicalize (const char *name, char *resolved)
++{
++ char *rpath, *dest, *extra_buf = NULL;
++ const char *start, *end, *rpath_limit;
++ long int path_max;
++ int num_links = 0, old_errno;
++
++ if (name == NULL)
++ {
++ /* As per Single Unix Specification V2 we must return an error if
++ either parameter is a null pointer. We extend this to allow
++ the RESOLVED parameter to be NULL in case the we are expected to
++ allocate the room for the return value. */
++ __set_errno (EINVAL);
++ return NULL;
++ }
++
++ if (name[0] == '\0')
++ {
++ /* As per Single Unix Specification V2 we must return an error if
++ the name argument points to an empty string. */
++ __set_errno (ENOENT);
++ return NULL;
++ }
++#ifdef __WIN32__
++ {
++ char *lpFilePart;
++ int len;
++// fprintf(stderr, "name: %s\n", name);
++ rpath = resolved ? __builtin_alloca (MAX_PATH) : malloc (MAX_PATH);
++// unix2winpath (name);
++// fprintf(stderr, "name: %s\n", name);
++len = GetFullPathName(name, MAX_PATH, rpath, &lpFilePart);
++/* GetFullPathName returns bogus paths for *nix-style paths, like
++ * /foo/bar - it just prepends current drive to them. Keep them
++ * intact (they need to be for relocation to work!).
++ */
++if (name[0] == '/') {
++ strncpy (rpath, name, MAX_PATH - 1);
++ rpath[MAX_PATH - 1] = '\0';
++ len = strlen (rpath);
++}
++// fprintf(stderr, "rpath: %s\n", rpath);
++ if (len == 0) {
++ //set_werrno;
++ return NULL;
++ }
++ if (len > MAX_PATH) {
++ if (resolved)
++ __set_errno(ENAMETOOLONG);
++ else {
++ rpath = realloc(rpath, len + 2);
++ GetFullPathName(name, len, rpath, &lpFilePart);
++// fprintf(stderr, "rpath: %s\n", rpath);
++ }
++ }
++// if ( ISDIRSEP(name[strlen(name)]) && !ISDIRSEP(rpath[len]) ) {
++// rpath[len] = '\\';
++// rpath[len + 1] = 0;
++// }
++ old_errno = errno;
++ //if (!access (rpath, D_OK) && !ISDIRSEP(rpath[len - 1]) ){
++ if (!access (rpath, R_OK) && !ISDIRSEP(rpath[len - 1]) ){
++ rpath[len] = '\\';
++ rpath[len + 1] = 0;
++ }
++ errno = old_errno;
++ win2unixpath (rpath);
++// fprintf(stderr, "rpath: %s\n", rpath);
++ return resolved ? strcpy(resolved, rpath) : rpath ;
++ }
++#else /* __WIN32__ */
++
++#ifdef PATH_MAX
++ path_max = PATH_MAX;
++#else
++ path_max = pathconf (name, _PC_PATH_MAX);
++ if (path_max <= 0)
++ path_max = 1024;
++#endif
++
++ rpath = resolved ? __builtin_alloca (path_max) : malloc (path_max);
++ rpath_limit = rpath + path_max;
++
++ if (name[0] != '/')
++ {
++ if (!__getcwd (rpath, path_max))
++ {
++ rpath[0] = '\0';
++ goto error;
++ }
++ dest = strchr (rpath, '\0');
++ }
++ else
++ {
++ rpath[0] = '/';
++ dest = rpath + 1;
++ }
++
++ for (start = end = name; *start; start = end)
++ {
++#ifdef _LIBC
++ struct stat64 st;
++#else
++ struct stat st;
++#endif
++ int n;
++
++ /* Skip sequence of multiple path-separators. */
++ while (*start == '/')
++ ++start;
++
++ /* Find end of path component. */
++ for (end = start; *end && *end != '/'; ++end)
++ /* Nothing. */;
++
++ if (end - start == 0)
++ break;
++ else if (end - start == 1 && start[0] == '.')
++ /* nothing */;
++ else if (end - start == 2 && start[0] == '.' && start[1] == '.')
++ {
++ /* Back up to previous component, ignore if at root already. */
++ if (dest > rpath + 1)
++ while ((--dest)[-1] != '/');
++ }
++ else
++ {
++ size_t new_size;
++
++ if (dest[-1] != '/')
++ *dest++ = '/';
++
++ if (dest + (end - start) >= rpath_limit)
++ {
++ ptrdiff_t dest_offset = dest - rpath;
++
++ if (resolved)
++ {
++ __set_errno (ENAMETOOLONG);
++ if (dest > rpath + 1)
++ dest--;
++ *dest = '\0';
++ goto error;
++ }
++ new_size = rpath_limit - rpath;
++ if (end - start + 1 > path_max)
++ new_size += end - start + 1;
++ else
++ new_size += path_max;
++ rpath = realloc (rpath, new_size);
++ rpath_limit = rpath + new_size;
++ if (rpath == NULL)
++ return NULL;
++
++ dest = rpath + dest_offset;
++ }
++
++#ifdef _LIBC
++ dest = __mempcpy (dest, start, end - start);
++#else
++ memcpy (dest, start, end - start);
++ dest += end - start;
++#endif
++ *dest = '\0';
++
++#ifdef _LIBC
++ if (__lxstat64 (_STAT_VER, rpath, &st) < 0)
++#else
++ if (lstat (rpath, &st) < 0)
++#endif
++ goto error;
++
++#if HAVE_READLINK
++ if (S_ISLNK (st.st_mode))
++ {
++ char *buf = __builtin_alloca (path_max);
++ size_t len;
++
++ if (++num_links > MAXSYMLINKS)
++ {
++ __set_errno (ELOOP);
++ goto error;
++ }
++
++ n = __readlink (rpath, buf, path_max);
++ if (n < 0)
++ goto error;
++ buf[n] = '\0';
++
++ if (!extra_buf)
++ extra_buf = __builtin_alloca (path_max);
++
++ len = strlen (end);
++ if ((long int) (n + len) >= path_max)
++ {
++ __set_errno (ENAMETOOLONG);
++ goto error;
++ }
++
++ /* Careful here, end may be a pointer into extra_buf... */
++ memmove (&extra_buf[n], end, len + 1);
++ name = end = memcpy (extra_buf, buf, n);
++
++ if (buf[0] == '/')
++ dest = rpath + 1; /* It's an absolute symlink */
++ else
++ /* Back up to previous component, ignore if at root already: */
++ if (dest > rpath + 1)
++ while ((--dest)[-1] != '/');
++ }
++#endif
++ }
++ }
++ if (dest > rpath + 1 && dest[-1] == '/')
++ --dest;
++ *dest = '\0';
++
++ return resolved ? memcpy (resolved, rpath, dest - rpath + 1) : rpath;
++
++error:
++ if (resolved)
++ strcpy (resolved, rpath);
++ else
++ free (rpath);
++ return NULL;
++
++#endif /* __WIN32__ */
++}
++
++
++char *
++__realpath (const char *name, char *resolved)
++{
++ if (resolved == NULL)
++ {
++ __set_errno (EINVAL);
++ return NULL;
++ }
++
++ return canonicalize (name, resolved);
++}
++weak_alias (__realpath, realpath)
++
++
++char *
++__canonicalize_file_name (const char *name)
++{
++ return canonicalize (name, NULL);
++}
++weak_alias (__canonicalize_file_name, canonicalize_file_name)
++
++char *
++canonicalize_file_name (const char *name)
++{
++ return canonicalize (name, NULL);
++}
+diff --git a/intl/canonicalize.h b/intl/canonicalize.h
+new file mode 100644
+index 0000000..ea707bf
+--- /dev/null
++++ b/intl/canonicalize.h
+@@ -0,0 +1,18 @@
++#ifndef __CANONICALIZE_H__
++#define __CANONICALIZE_H__ 1
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++char *canonicalize_file_name (const char *name);
++
++#ifdef __WIN32__
++char *win2unixpath (char *path);
++#endif
++
++#ifdef __cplusplus
++}
++#endif
++
++#endif /* __CANONICALIZE_H__ */
+diff --git a/intl/relocatex.c b/intl/relocatex.c
+new file mode 100644
+index 0000000..a2b7438
+--- /dev/null
++++ b/intl/relocatex.c
+@@ -0,0 +1,284 @@
++/* Provide relocatable packages.
++ Copyright (C) 2003 Free Software Foundation, Inc.
++ Written by Bruno Haible <bruno@clisp.org>, 2003.
++
++ This program is free software; you can redistribute it and/or modify it
++ under the terms of the GNU Library General Public License as published
++ by the Free Software Foundation; either version 2, or (at your option)
++ any later version.
++
++ This program is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Library General Public License for more details.
++
++ You should have received a copy of the GNU Library General Public
++ License along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
++ USA. */
++
++
++/* Specification. */
++#include <errno.h>
++#define _GNU_SOURCE
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++#include <unistd.h>
++/* #include <path.h> */
++#include "relocatex.h"
++#include "canonicalize.h"
++/* #include <gw32.h> */
++
++
++#if defined _WIN32 || defined __WIN32__
++# define WIN32_LEAN_AND_MEAN
++# include <windows.h>
++//# define __GW32__
++//# include <winx/errnox.h>
++#endif
++#define set_werrno
++
++#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
++ /* Win32, Cygwin, OS/2, DOS */
++# define ISDIRSEP(C) ((C) == '/' || (C) == '\\')
++#else
++ /* Unix */
++# define ISDIRSEP(C) ((C) == '/')
++#endif
++
++/* Original installation prefix. */
++static char *orig_prefix = NULL;
++static size_t orig_prefix_len = 0;
++/* Current installation prefix. */
++static char *curr_prefix = NULL;
++static size_t curr_prefix_len = 0;
++/* These prefixes do not end in a slash. Anything that will be concatenated
++ to them must start with a slash. */
++
++
++int win2posixpath (const char *winpath, char *posixpath)
++{
++ strcpy (posixpath, winpath);
++ win2unixpath (posixpath);
++ return 0;
++}
++
++
++/* Sets the original and the current installation prefix of this module.
++ Relocation simply replaces a pathname starting with the original prefix
++ by the corresponding pathname with the current prefix instead. Both
++ prefixes should be directory names without trailing slash (i.e. use ""
++ instead of "/"). */
++static char *
++set_orig_prefix (const char *orig_prefix_arg)
++{
++ char *memory;
++// printf ("orig_prefix_arg: %s\n", orig_prefix_arg);
++ if (!orig_prefix_arg) {
++ orig_prefix = NULL;
++ orig_prefix_len = 0;
++ return NULL;
++ }
++ if (orig_prefix)
++ free (orig_prefix);
++
++ memory = canonicalize_file_name (orig_prefix_arg);
++// printf ("memory: %s\n", memory);
++// memory = (char *) malloc (orig_prefix_len + 1);
++ if (!memory) {
++ set_werrno;
++ orig_prefix = NULL;
++ orig_prefix_len = 0;
++ return NULL;
++ }
++ win2unixpath (memory);
++// win2posixpath (orig_prefix_arg, memory);
++ orig_prefix = memory;
++ orig_prefix_len = strlen (orig_prefix);
++// printf ("orig_prefix: %s\n", orig_prefix);
++ if (ISDIRSEP (orig_prefix[orig_prefix_len-1])) {
++ orig_prefix[orig_prefix_len-1] = '\0';
++ orig_prefix_len--;
++ }
++// printf ("orig_prefix: %s\n", orig_prefix);
++// printf ("orig_prefix_len: %d\n", orig_prefix_len);
++ return orig_prefix;
++}
++
++#if defined __WIN32__
++static char *
++set_current_prefix (const char *ModuleName)
++{
++ LPTSTR curr_prefix_arg, q, lpFilePart;
++ DWORD len;
++ int nDIRSEP = 0;
++
++ if (curr_prefix)
++ free (curr_prefix);
++ curr_prefix_arg = malloc (MAX_PATH * sizeof (TCHAR));
++ if (!curr_prefix_arg) {
++ set_werrno;
++ curr_prefix = NULL;
++ curr_prefix_len = 0;
++ return NULL;
++ }
++ if (ModuleName) {
++// printf ("ModuleName: %s\n", ModuleName);
++ len = SearchPath (NULL, ModuleName, ".DLL", MAX_PATH, curr_prefix_arg, &lpFilePart);
++ if (len) {
++// printf ("ModulePath: %s\n", curr_prefix_arg);
++// printf ("FilePart: %s\n", lpFilePart);
++ }
++ }
++ if (!ModuleName || !len) {
++ len = GetModuleFileName (NULL, curr_prefix_arg, MAX_PATH);
++ if (!len) {
++ set_werrno;
++ curr_prefix = NULL;
++ curr_prefix_len = 0;
++ return NULL;
++ }
++ }
++// strncpy (curr_prefix_arg, ModuleName, MAX_PATH);
++// printf ("curr_prefix_arg: %s\n", curr_prefix_arg);
++ win2posixpath (curr_prefix_arg, curr_prefix_arg);
++ curr_prefix = curr_prefix_arg;
++ q = curr_prefix_arg + len - 1;
++ /* strip name of executable and its directory */
++ while (!ISDIRSEP (*q) && (q > curr_prefix_arg) && nDIRSEP < 2) {
++ q--;
++ if (ISDIRSEP (*q)) {
++ *q = '\0';
++ nDIRSEP++;
++ }
++ }
++ curr_prefix_len = q - curr_prefix_arg;
++// printf ("curr_prefix: %s\n", curr_prefix);
++// printf ("curr_prefix_len: %d\n", curr_prefix_len);
++ return curr_prefix;
++}
++
++char *getshortpath (const char *longpath)
++{
++ char *shortpath = NULL;
++ DWORD len, res;
++
++// printf ("longpath: %s\n", longpath);
++ len = GetShortPathName(longpath, shortpath, 0);
++// printf ("len: %ld\n", len);
++ if (!len) {
++// WinErr ("getshortpath: len = 0");
++ set_werrno;
++ return (char *) longpath;
++ }
++ shortpath = (char *) malloc (len + 1);
++ if (!shortpath) {
++// WinErr ("getshortpath: malloc");
++ set_werrno;
++ return (char *) longpath;
++ }
++ res = GetShortPathName(longpath, shortpath, len);
++// printf ("res: %ld\n", res);
++ if (!res) {
++// WinErr ("getshortpath: res = 0");
++ free (shortpath);
++ set_werrno;
++ return (char *) longpath;
++ }
++// printf ("shortpath: %s\n", shortpath);
++ return shortpath;
++}
++
++char *relocaten (const char *ModuleName, const char *path)
++{
++ char *relative_path, *relocated_path, *relocated_short_path;
++ int relative_path_len;
++
++ if (!curr_prefix)
++ set_current_prefix (ModuleName);
++// printf ("path: %s\n", path);
++// printf ("orig_prefix: %s\n", orig_prefix);
++// printf ("curr_prefix: %s\n", curr_prefix);
++// if (strncmp (orig_prefix, path, orig_prefix_len))
++// if (strcmp (orig_prefix, path))
++// return (char *) path;
++ relative_path = (char *) path + orig_prefix_len;
++// printf ("relative_path: %s\n", relative_path);
++ relative_path_len = strlen (relative_path);
++ relocated_path = malloc (curr_prefix_len + relative_path_len + 1);
++ strcpy (relocated_path, curr_prefix);
++ strcat (relocated_path, relative_path);
++// printf ("relocated_path: %s\n", relocated_path);
++ relocated_short_path = getshortpath (relocated_path);
++// printf ("relocated_short_path: %s\n", relocated_short_path);
++ if (relocated_short_path) {
++ if (relocated_short_path != relocated_path)
++ free (relocated_path);
++ return relocated_short_path;
++ } else
++ return relocated_path;
++}
++
++#else // __WIN32__
++char *relocaten (const char *ModuleName, const char *path)
++{
++ // dummy function for Unix/Linux
++ return (char *)path;
++}
++#endif
++
++char *relocaten2 (const char *ModuleName, const char *installdir, const char *path)
++{
++ set_orig_prefix (installdir);
++ return relocaten (ModuleName, path);
++}
++
++char *relocatenx (const char *ModuleName, const char *installdir, const char *path)
++{
++ char *p;
++
++ set_orig_prefix (installdir);
++ if (access (path, R_OK))
++ p = relocaten (ModuleName, path);
++ else
++ p = (char *) path;
++// printf ("relocatenx: %s\n", p);
++ return p;
++}
++
++char *relocate2 (const char *installdir, const char *path)
++{
++ return relocaten2 (NULL, installdir, path);
++}
++
++char *relocatex (const char *installdir, const char *path)
++{
++ return relocatenx (NULL, installdir, path);
++}
++
++char *relocatepx (const char *cprefix, const char *installdir, const char *path)
++{
++ if (curr_prefix)
++ free (curr_prefix);
++ curr_prefix = strdup (cprefix);
++ return relocatex (installdir, path);
++}
++
++static char *get_orig_prefix (void)
++{
++ return orig_prefix;
++}
++
++static char *get_curr_prefix (void)
++{
++ return curr_prefix;
++}
++
++static char *set_curr_prefix (const char *ModuleName)
++{
++ if (curr_prefix)
++ free (curr_prefix);
++ set_current_prefix (ModuleName);
++ return curr_prefix;
++}
+diff --git a/intl/relocatex.h b/intl/relocatex.h
+new file mode 100644
+index 0000000..5cc7c51
+--- /dev/null
++++ b/intl/relocatex.h
+@@ -0,0 +1,41 @@
++/*
++ Copyright (C) 2006 Free Software Foundation, Inc.
++ This file is part of the GnuWin C Library.
++
++ The GnuWin C Library is free software; you can redistribute it and/or
++ modify it under the terms of the GNU Lesser General Public
++ License as published by the Free Software Foundation; either
++ version 2.1 of the License, or (at your option) any later version.
++
++ The GnuWin C Library is distributed in the hope that it will be useful,
++ but WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ Lesser General Public License for more details.
++
++ You should have received a copy of the GNU Lesser General Public
++ License along with the GnuWin32 C Library; if not, write to the Free
++ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
++ 02111-1307 USA. */
++
++#ifndef __RELOCATE_H__
++#define __RELOCATE_H__ 1
++
++/* #include <libc-dll.h> */
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++char *relocaten (const char *ModuleName, const char *path);
++char *relocaten2 (const char *ModuleName, const char *installdir, const char *path);
++char *relocatenx (const char *ModuleName, const char *installdir, const char *path);
++char *relocate2 (const char *installdir, const char *path);
++char *relocatex (const char *installdir, const char *path);
++
++#ifdef __cplusplus
++}
++#endif
++
++//#endif /* __GW32__ */
++
++#endif /* __RELOCATE_H__ */
+--
+2.8.1
+
diff --git a/PATCHES/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch b/PATCHES/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch
new file mode 100644
index 0000000..f4ce341
--- /dev/null
+++ b/PATCHES/0003-Windows-Follow-Posix-dir-exists-semantics-more-close.patch
@@ -0,0 +1,130 @@
+From 9f49390e2cd9085ca1cc03906a146861dbe8135f Mon Sep 17 00:00:00 2001
+From: Ray Donnelly <mingw.android@gmail.com>
+Date: Wed, 5 Aug 2015 23:36:07 +0100
+Subject: [PATCH 03/15] Windows: Follow Posix dir-exists semantics more closely
+
+Make Windows behave the same as Posix in the consideration
+of whether folder "/doesnt-exist/.." is a valid
+path. In Posix, it isn't.
+
+A concrete instance of when this matters is when cross
+compiling GNU/Linux glibc on Windows.
+---
+ libcpp/files.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 87 insertions(+)
+
+diff --git a/libcpp/files.c b/libcpp/files.c
+index ea2cc23..ac17272 100644
+--- a/libcpp/files.c
++++ b/libcpp/files.c
+@@ -30,6 +30,13 @@ along with this program; see the file COPYING3. If not see
+ #include "md5.h"
+ #include <dirent.h>
+
++/* Needed for stat_st_mode_symlink below */
++#if defined(_WIN32)
++# include <windows.h>
++# define S_IFLNK 0xF000
++# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
++#endif
++
+ /* Variable length record files on VMS will have a stat size that includes
+ record control characters that won't be included in the read size. */
+ #ifdef VMS
+@@ -198,6 +205,49 @@ static int pchf_save_compare (const void *e1, const void *e2);
+ static int pchf_compare (const void *d_p, const void *e_p);
+ static bool check_file_against_entries (cpp_reader *, _cpp_file *, bool);
+
++#if defined(_WIN32)
++
++static int stat_st_mode_symlink (char const* path, struct stat* buf)
++{
++ WIN32_FILE_ATTRIBUTE_DATA attr;
++ memset(buf,0,sizeof(*buf));
++ int err = GetFileAttributesExA (path, GetFileExInfoStandard, &attr) ? 0 : 1;
++ if (!err)
++ {
++ WIN32_FIND_DATAA finddata;
++ HANDLE h = FindFirstFileA (path, &finddata);
++ if (h != INVALID_HANDLE_VALUE)
++ {
++ FindClose (h);
++ if ((finddata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
++ (finddata.dwReserved0 == IO_REPARSE_TAG_SYMLINK))
++ buf->st_mode = S_IFLNK;
++ else if (finddata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
++ buf->st_mode = S_IFDIR;
++ else if (finddata.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE)
++ buf->st_mode = S_IFDIR;
++ else
++ buf->st_mode = S_IFREG;
++ buf->st_mode |= S_IREAD;
++ if (!(finddata.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
++ buf->st_mode |= S_IWRITE;
++ }
++ else
++ {
++ buf->st_mode = S_IFDIR;
++ }
++ return 0;
++ }
++ return -1;
++}
++
++#else
++
++#define stat_st_mode_symlink (_name, _buf) stat ((_name), (_buf))
++
++#endif
++
++
+ /* Given a filename in FILE->PATH, with the empty string interpreted
+ as <stdin>, open it.
+
+@@ -227,6 +277,43 @@ open_file (_cpp_file *file)
+ }
+ else
+ file->fd = open (file->path, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
++#if defined(_WIN32) || defined(__CYGWIN__)
++ /* Windows and Posix differ in the face of paths of the form:
++ nonexistantdir/.. in that Posix will return ENOENT whereas
++ Windows won't care that we stepped into a non-existant dir
++ Only do these slow checks if ".." appears in file->path.
++ Cygwin also suffers from the same problem (but doesn't need
++ a new stat function):
++ http://cygwin.com/ml/cygwin/2013-05/msg00222.html
++ */
++ if (file->fd > 0)
++ {
++ char filepath[MAX_PATH];
++ strncpy (filepath, file->path, sizeof(filepath) - 1);
++ char* dirsep = &filepath[0];
++ while ( (dirsep = strchr (dirsep, '\\')) != NULL)
++ *dirsep = '/';
++ if (strstr(file->path, "/../"))
++ {
++ dirsep = &filepath[0];
++ char dirsepc;
++ /* Check each directory in the chain. */
++ while ( (dirsep = strpbrk (dirsep, "\\/")) != NULL)
++ {
++ dirsepc = *(++dirsep);
++ *dirsep = '\0';
++ if (stat_st_mode_symlink (filepath, &file->st) == -1)
++ {
++ *dirsep = dirsepc;
++ close (file->fd);
++ file->fd = -1;
++ return false;
++ }
++ *dirsep++ = dirsepc;
++ }
++ }
++ }
++#endif
+
+ if (file->fd != -1)
+ {
+--
+2.8.1
+
diff --git a/PATCHES/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch b/PATCHES/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch
new file mode 100644
index 0000000..7b6a6be
--- /dev/null
+++ b/PATCHES/0004-Windows-Use-not-in-progpath-and-leave-case-as-is.patch
@@ -0,0 +1,60 @@
+From 233bc23e32c5213255d8391dede53aa0b61ec23f Mon Sep 17 00:00:00 2001
+From: Ray Donnelly <mingw.android@gmail.com>
+Date: Wed, 5 Aug 2015 23:36:09 +0100
+Subject: [PATCH 04/15] Windows: Use '/' not '\' in progpath and leave case
+ as-is
+
+Windows can handle both '/' and '\' dirseps. GCC will
+have been built using Cygwin, MSYS* or cross-compiled
+from a system where dirsep is '/' so it is cleaner to
+force the dirseps to be '/' and keep the case as-is.
+
+This way, the value will be consistent with the build
+system and string operations, be they internal to GCC
+or external to it (e.g. processing map files with sed)
+have a better chance of working as expected.
+
+A concrete instance of when this matters is when cross
+compiling GNU/Linux glibc on Windows.
+---
+ libiberty/lrealpath.c | 19 +++++++++++++++----
+ 1 file changed, 15 insertions(+), 4 deletions(-)
+
+diff --git a/libiberty/lrealpath.c b/libiberty/lrealpath.c
+index b27c8de..8165984 100644
+--- a/libiberty/lrealpath.c
++++ b/libiberty/lrealpath.c
+@@ -138,15 +138,26 @@ lrealpath (const char *filename)
+ {
+ char buf[MAX_PATH];
+ char* basename;
++ char* slash;
+ DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename);
+ if (len == 0 || len > MAX_PATH - 1)
+ return strdup (filename);
+ else
+ {
+- /* The file system is case-preserving but case-insensitive,
+- Canonicalize to lowercase, using the codepage associated
+- with the process locale. */
+- CharLowerBuff (buf, len);
++ /* Turn all back slashes back into forward slashes
++ and don't make it lowercase.
++ Rationale:
++ Windows is as happy with / as it is with \. This will
++ have been built using Cygwin, MSYS* or cross-compiled
++ from a system where dirsep is / so it is cleaner just
++ to keep the dirseps as / (and the case un-modified).
++ This way, the value will be consistent with the build
++ system and string operations (be they internal to this
++ software or external to it, e.g. processing map files
++ with sed) work as expected. */
++ slash = buf;
++ while ((slash = strchr(slash,'\\')) != NULL)
++ *slash = '/';
+ return strdup (buf);
+ }
+ }
+--
+2.8.1
+
diff --git a/PATCHES/0005-Windows-Don-t-ignore-native-system-header-dir.patch b/PATCHES/0005-Windows-Don-t-ignore-native-system-header-dir.patch
new file mode 100644
index 0000000..7d9e9c8
--- /dev/null
+++ b/PATCHES/0005-Windows-Don-t-ignore-native-system-header-dir.patch
@@ -0,0 +1,28 @@
+From a2bc77d0e198659e72c9addb89a993007de99fe7 Mon Sep 17 00:00:00 2001
+From: Ray Donnelly <mingw.android@gmail.com>
+Date: Wed, 5 Aug 2015 23:36:11 +0100
+Subject: [PATCH 05/15] Windows: Don't ignore native system header dir
+
+---
+ gcc/config.gcc | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/gcc/config.gcc b/gcc/config.gcc
+index c835734..4638567 100644
+--- a/gcc/config.gcc
++++ b/gcc/config.gcc
+@@ -1699,7 +1699,10 @@ i[34567]86-*-mingw* | x86_64-*-mingw*)
+ tmake_file="${tmake_file} i386/t-mingw-w32"
+ ;;
+ esac
+- native_system_header_dir=/mingw/include
++ # Don't ignore values passed in to configure via --native-system-header-dir
++ if test x$native_system_header_dir = x ; then
++ native_system_header_dir=/mingw/include
++ fi
+ target_gtfiles="\$(srcdir)/config/i386/winnt.c"
+ extra_options="${extra_options} i386/cygming.opt i386/mingw.opt"
+ case ${target} in
+--
+2.8.1
+
diff --git a/PATCHES/0006-Windows-New-feature-to-allow-overriding.patch b/PATCHES/0006-Windows-New-feature-to-allow-overriding.patch
new file mode 100644
index 0000000..9899224
--- /dev/null
+++ b/PATCHES/0006-Windows-New-feature-to-allow-overriding.patch
@@ -0,0 +1,44 @@
+From d8cd8d0211dcd606a3753a6b3c36c19a7b1672dc Mon Sep 17 00:00:00 2001
+From: Ray Donnelly <mingw.android@gmail.com>
+Date: Wed, 5 Aug 2015 23:36:13 +0100
+Subject: [PATCH 05/19] master Windows: New feature to allow overriding
+ -lmsvcrt
+
+Added in support of the MinGW-w64 WIP feature "agile mscvrt dll" where
+a process' loaded msvc runtime is used by a newly loaded DLL rather than
+always using msvcrt.dll
+---
+ gcc/config/i386/cygming.opt | 3 +++
+ gcc/config/i386/mingw32.h | 2 +-
+ 2 files changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/gcc/config/i386/cygming.opt b/gcc/config/i386/cygming.opt
+index a9074bf..e1d89e2 100644
+--- a/gcc/config/i386/cygming.opt
++++ b/gcc/config/i386/cygming.opt
+@@ -22,6 +22,9 @@ mconsole
+ Target RejectNegative
+ Create console application.
+
++mcrtdll=
++Target RejectNegative Joined
++
+ mdll
+ Target RejectNegative
+ Generate code for a DLL.
+diff --git a/gcc/config/i386/mingw32.h b/gcc/config/i386/mingw32.h
+index 4ac5f68..f875e7b 100644
+--- a/gcc/config/i386/mingw32.h
++++ b/gcc/config/i386/mingw32.h
+@@ -140,7 +140,7 @@ along with GCC; see the file COPYING3. If not see
+ #define REAL_LIBGCC_SPEC \
+ "%{mthreads:-lmingwthrd} -lmingw32 \
+ " SHARED_LIBGCC_SPEC " \
+- -lmoldname -lmingwex -lmsvcrt"
++ -lmoldname -lmingwex %{!mcrtdll=*:-lmsvcrt} %{mcrtdll=*:-l%*}"
+
+ #undef STARTFILE_SPEC
+ #define STARTFILE_SPEC "%{shared|mdll:dllcrt2%O%s} \
+--
+2.7.1
+
diff --git a/PATCHES/0008-Prettify-linking-no-undefined.patch b/PATCHES/0008-Prettify-linking-no-undefined.patch
new file mode 100644
index 0000000..a8ed4bd
--- /dev/null
+++ b/PATCHES/0008-Prettify-linking-no-undefined.patch
@@ -0,0 +1,41 @@
+From cfe4caf51c829a6bd746566a0b205354fa042dc3 Mon Sep 17 00:00:00 2001
+From: Alexey Pavlov <alexey.pawlow@gmail.com>
+Date: Wed, 5 Aug 2015 23:36:19 +0100
+Subject: [PATCH 08/15] Prettify linking -no-undefined
+
+It might be better to put this change in a
+conditional block for Windows only?
+---
+ libgfortran/Makefile.am | 2 +-
+ libgfortran/Makefile.in | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libgfortran/Makefile.am b/libgfortran/Makefile.am
+index 31eb986..f8ef020 100644
+--- a/libgfortran/Makefile.am
++++ b/libgfortran/Makefile.am
+@@ -50,7 +50,7 @@ libgfortranbegin_la_LINK = $(LINK) $(libgfortranbegin_la_LDFLAGS)
+ cafexeclib_LTLIBRARIES = libcaf_single.la
+ cafexeclibdir = $(libdir)/gcc/$(target_alias)/$(gcc_version)$(MULTISUBDIR)
+ libcaf_single_la_SOURCES = caf/single.c
+-libcaf_single_la_LDFLAGS = -static
++libcaf_single_la_LDFLAGS = -static -no-undefined
+ libcaf_single_la_DEPENDENCIES = caf/libcaf.h
+ libcaf_single_la_LINK = $(LINK) $(libcaf_single_la_LDFLAGS)
+
+diff --git a/libgfortran/Makefile.in b/libgfortran/Makefile.in
+index 0f60e6e..8473026 100644
+--- a/libgfortran/Makefile.in
++++ b/libgfortran/Makefile.in
+@@ -615,7 +615,7 @@ libgfortranbegin_la_LINK = $(LINK) $(libgfortranbegin_la_LDFLAGS)
+ cafexeclib_LTLIBRARIES = libcaf_single.la
+ cafexeclibdir = $(libdir)/gcc/$(target_alias)/$(gcc_version)$(MULTISUBDIR)
+ libcaf_single_la_SOURCES = caf/single.c
+-libcaf_single_la_LDFLAGS = -static
++libcaf_single_la_LDFLAGS = -static -no-undefined
+ libcaf_single_la_DEPENDENCIES = caf/libcaf.h
+ libcaf_single_la_LINK = $(LINK) $(libcaf_single_la_LDFLAGS)
+ @IEEE_SUPPORT_TRUE@fincludedir = $(libdir)/gcc/$(target_alias)/$(gcc_version)$(MULTISUBDIR)/finclude
+--
+2.8.1
+
diff --git a/PATCHES/0010-Fix-using-large-PCH.patch b/PATCHES/0010-Fix-using-large-PCH.patch
new file mode 100644
index 0000000..af8ebec
--- /dev/null
+++ b/PATCHES/0010-Fix-using-large-PCH.patch
@@ -0,0 +1,154 @@
+From 22a67f6b18d2854bcdf740833cf4e1a0555c7295 Mon Sep 17 00:00:00 2001
+From: Martin Richter <xricht17@stud.fit.vutbr.cz>
+Date: Wed, 5 Aug 2015 23:36:25 +0100
+Subject: [PATCH 10/15] Fix using large PCH
+
+The following patch fixes segfault when gt_pch_use_address
+fails (returns -1). fatal_error now correctly shows an error
+message and terminates the program.
+I have basicly only reordered reads, and placed them after
+the file mapping itself. Global pointers are changed only
+after gt_pch_use_address succeeds, so in case of failure
+they still contain valid addresses.
+
+This patch is meant for the master branch. However, it
+should not be hard to modify it for others.
+
+https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14940
+https://sourceforge.net/p/mingw-w64/bugs/382/
+---
+ gcc/config/i386/host-mingw32.c | 10 ++-------
+ gcc/ggc-common.c | 51 +++++++++++++++++++++++++++++++++---------
+ 2 files changed, 42 insertions(+), 19 deletions(-)
+
+diff --git a/gcc/config/i386/host-mingw32.c b/gcc/config/i386/host-mingw32.c
+index aa17378..631d9c4 100644
+--- a/gcc/config/i386/host-mingw32.c
++++ b/gcc/config/i386/host-mingw32.c
+@@ -42,9 +42,6 @@ static size_t mingw32_gt_pch_alloc_granularity (void);
+
+ static inline void w32_error(const char*, const char*, int, const char*);
+
+-/* FIXME: Is this big enough? */
+-static const size_t pch_VA_max_size = 128 * 1024 * 1024;
+-
+ /* Granularity for reserving address space. */
+ static size_t va_granularity = 0x10000;
+
+@@ -86,9 +83,6 @@ static void *
+ mingw32_gt_pch_get_address (size_t size, int)
+ {
+ void* res;
+- size = (size + va_granularity - 1) & ~(va_granularity - 1);
+- if (size > pch_VA_max_size)
+- return NULL;
+
+ /* FIXME: We let system determine base by setting first arg to NULL.
+ Allocating at top of available address space avoids unnecessary
+@@ -98,7 +92,7 @@ mingw32_gt_pch_get_address (size_t size, int)
+ If we allocate at bottom we need to reserve the address as early
+ as possible and at the same point in each invocation. */
+
+- res = VirtualAlloc (NULL, pch_VA_max_size,
++ res = VirtualAlloc (NULL, size,
+ MEM_RESERVE | MEM_TOP_DOWN,
+ PAGE_NOACCESS);
+ if (!res)
+@@ -148,7 +142,7 @@ mingw32_gt_pch_use_address (void *addr, size_t size, int fd,
+
+ /* Offset must be also be a multiple of allocation granularity for
+ this to work. We can't change the offset. */
+- if ((offset & (va_granularity - 1)) != 0 || size > pch_VA_max_size)
++ if ((offset & (va_granularity - 1)) != 0)
+ return -1;
+
+
+diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c
+index 03fbe7d..3a5df8a 100644
+--- a/gcc/ggc-common.c
++++ b/gcc/ggc-common.c
+@@ -603,7 +603,9 @@ gt_pch_restore (FILE *f)
+ size_t i;
+ struct mmap_info mmi;
+ int result;
+-
++ long pch_tabs_off;
++ long pch_data_off;
++
+ /* Delete any deletable objects. This makes ggc_pch_read much
+ faster, as it can be sure that no GCable objects remain other
+ than the ones just read in. */
+@@ -611,20 +613,24 @@ gt_pch_restore (FILE *f)
+ for (rti = *rt; rti->base != NULL; rti++)
+ memset (rti->base, 0, rti->stride);
+
+- /* Read in all the scalar variables. */
++ /* We need to read tables after mapping, or fatal_error will
++ segfault when gt_pch_use_address returns -1. Skip them for now. */
++ pch_tabs_off = ftell(f);
++
++ /* Skip all the scalar variables. */
+ for (rt = gt_pch_scalar_rtab; *rt; rt++)
+ for (rti = *rt; rti->base != NULL; rti++)
+- if (fread (rti->base, rti->stride, 1, f) != 1)
+- fatal_error (input_location, "can%'t read PCH file: %m");
++ if (fseek (f, rti->stride, SEEK_CUR) != 0)
++ fatal_error (input_location, "can%'t read PCH file: %m");
+
+- /* Read in all the global pointers, in 6 easy loops. */
++ /* Skip all the global pointers. */
+ for (rt = gt_ggc_rtab; *rt; rt++)
+ for (rti = *rt; rti->base != NULL; rti++)
+ for (i = 0; i < rti->nelt; i++)
+- if (fread ((char *)rti->base + rti->stride * i,
+- sizeof (void *), 1, f) != 1)
+- fatal_error (input_location, "can%'t read PCH file: %m");
+-
++ if (fseek (f, sizeof (void *), SEEK_CUR) != 0)
++ fatal_error (input_location, "can%'t read PCH file: %m");
++
++ /* mmi still has to be read now. */
+ if (fread (&mmi, sizeof (mmi), 1, f) != 1)
+ fatal_error (input_location, "can%'t read PCH file: %m");
+
+@@ -635,12 +641,35 @@ gt_pch_restore (FILE *f)
+ if (result == 0)
+ {
+ if (fseek (f, mmi.offset, SEEK_SET) != 0
+- || fread (mmi.preferred_base, mmi.size, 1, f) != 1)
+- fatal_error (input_location, "can%'t read PCH file: %m");
++ || fread (mmi.preferred_base, mmi.size, 1, f) != 1)
++ fatal_error (input_location, "can%'t read PCH file: %m");
+ }
+ else if (fseek (f, mmi.offset + mmi.size, SEEK_SET) != 0)
+ fatal_error (input_location, "can%'t read PCH file: %m");
++
++ /* File mapping done, read tables now. */
++ pch_data_off = ftell(f);
++
++ if (fseek (f, pch_tabs_off, SEEK_SET) != 0)
++ fatal_error (input_location, "can%'t read PCH file: %m");
+
++ /* Read in all the scalar variables. */
++ for (rt = gt_pch_scalar_rtab; *rt; rt++)
++ for (rti = *rt; rti->base != NULL; rti++)
++ if (fread (rti->base, rti->stride, 1, f) != 1)
++ fatal_error (input_location, "can%'t read PCH file: %m");
++
++ /* Read in all the global pointers, in 6 easy loops. */
++ for (rt = gt_ggc_rtab; *rt; rt++)
++ for (rti = *rt; rti->base != NULL; rti++)
++ for (i = 0; i < rti->nelt; i++)
++ if (fread ((char *)rti->base + rti->stride * i,
++ sizeof (void *), 1, f) != 1)
++ fatal_error (input_location, "can%'t read PCH file: %m");
++
++ if (fseek (f, pch_data_off, SEEK_SET) != 0)
++ fatal_error (input_location, "can%'t read PCH file: %m");
++
+ ggc_pch_read (f, mmi.preferred_base);
+
+ gt_pch_restore_stringpool ();
+--
+2.8.1
+
diff --git a/PATCHES/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch b/PATCHES/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch
new file mode 100644
index 0000000..e196f24
--- /dev/null
+++ b/PATCHES/0014-clone_function_name_1-Retain-any-stdcall-suffix.patch
@@ -0,0 +1,109 @@
+From 558617be42604d5a98938f153e990aec5b8484ed Mon Sep 17 00:00:00 2001
+From: Ray Donnelly <mingw.android@gmail.com>
+Date: Mon, 17 Aug 2015 22:57:46 +0100
+Subject: [PATCH] clone_function_name_1: Retain any stdcall suffix
+
+Previously, clone_function_name_1 would add a suffix after
+any existing stdcall suffix, for example ipa-split.c would
+clone test@4 as test@4.part.0.
+
+Later, i386_pe_strip_name_encoding_full would come along
+and strip off everything from the last @ onwards which had
+the effect of generating incorrect section names which
+would then fall over with errors such as:
+
+error: void test() causes a section type conflict with \
+ void test@4.part.0()
+
+The following testcase, reduced from Firefox can be used
+to reproduce this.
+
+test.ii:
+class ClassA {
+public:
+ virtual int __attribute__((__stdcall__)) Dispatch() = 0;
+};
+class ClassB {
+public:
+ ClassA* __attribute__((__stdcall__)) operator->();
+};
+class ClassC : ClassA {
+ int *some_int_ptr_variable;
+ int __attribute__((__stdcall__)) Dispatch() {
+ return some_int_ptr_variable
+ ? 42
+ : m_ClassInstanceB->Dispatch();
+ }
+ ClassB m_ClassInstanceB;
+};
+ClassC ClassInstanceC;
+
+Compile for i686-w64-mingw32 with:
+cc1plus -O -fpartial-inlining -fdevirtualize \
+ -fdevirtualize-speculatively test.ii
+
+Outputs:
+test.ii: In member function 'virtual int ClassC::Dispatch()':
+test.ii:11:36: error: virtual int ClassC::Dispatch() causes \
+ a section type conflict with int ClassC::_ZN6ClassC8DispatchEv@4.part.0()
+ int __attribute__((CALLTYPE)) Dispatch() {
+ ^
+test.ii:11:36: note: \
+ 'int ClassC::_ZN6ClassC8DispatchEv@4.part.0()' was declared here
+---
+ gcc/cgraphclones.c | 13 ++++++++++++-
+ gcc/defaults.h | 2 +-
+ 2 files changed, 13 insertions(+), 2 deletions(-)
+
+diff --git a/gcc/cgraphclones.c b/gcc/cgraphclones.c
+index 07ceb1a..a2930a0 100644
+--- a/gcc/cgraphclones.c
++++ b/gcc/cgraphclones.c
+@@ -501,19 +501,30 @@ cgraph_node::create_clone (tree new_decl, gcov_type gcov_count, int freq,
+ static GTY(()) unsigned int clone_fn_id_num;
+
+ /* Return a new assembler name for a clone with SUFFIX of a decl named
+- NAME. */
++ NAME. Final stdcall @N suffixes are maintained. */
+
+ tree
+ clone_function_name_1 (const char *name, const char *suffix)
+ {
+ size_t len = strlen (name);
+ char *tmp_name, *prefix;
++ const char *at_suffix = NULL;
+
+ prefix = XALLOCAVEC (char, len + strlen (suffix) + 2);
++ /* name + 1 to skip fastcall which begins with '@' */
++ at_suffix = strchr (name + 1, '@');
++ size_t at_suffix_len = 0;
++ if (at_suffix)
++ {
++ at_suffix_len = strlen (at_suffix);
++ len -= at_suffix_len;
++ }
+ memcpy (prefix, name, len);
+ strcpy (prefix + len + 1, suffix);
+ prefix[len] = symbol_table::symbol_suffix_separator ();
+ ASM_FORMAT_PRIVATE_NAME (tmp_name, prefix, clone_fn_id_num++);
++ if (at_suffix)
++ strcat (tmp_name, at_suffix);
+ return get_identifier (tmp_name);
+ }
+
+diff --git a/gcc/defaults.h b/gcc/defaults.h
+index 3e18338..45d7192 100644
+--- a/gcc/defaults.h
++++ b/gcc/defaults.h
+@@ -51,7 +51,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ # define ASM_FORMAT_PRIVATE_NAME(OUTPUT, NAME, LABELNO) \
+ do { const char *const name_ = (NAME); \
+ char *const output_ = (OUTPUT) = \
+- (char *) alloca (strlen (name_) + 32); \
++ (char *) alloca (strlen (name_) + 35); \
+ sprintf (output_, ASM_PN_FORMAT, name_, (unsigned long)(LABELNO)); \
+ } while (0)
+ #endif
+--
+2.7.4.windows.1
+
diff --git a/PATCHES/0019-gcc-8-branch-Backport-patches-for-std-filesystem-from-master.patch b/PATCHES/0019-gcc-8-branch-Backport-patches-for-std-filesystem-from-master.patch
new file mode 100644
index 0000000..41969cf
--- /dev/null
+++ b/PATCHES/0019-gcc-8-branch-Backport-patches-for-std-filesystem-from-master.patch
@@ -0,0 +1,2760 @@
+From eda88e06651c9293012212b665ca592c85bef645 Mon Sep 17 00:00:00 2001
+From: Liu Hao <lh_mouse@126.com>
+Date: Sat, 26 Jan 2019 15:14:38 +0800
+Subject: [PATCH] Backport patches for std::filesystem from master.
+
+This is done by running the following commands on `gcc-8-branch`:
+
+ git cherry-pick 861db1097d3f 2fd48392d0a4 70fea18e0bbb d4fd5c4964cf
+ git checkout master -- libstdc++-v3/src/filesystem/ \
+ libstdc++-v3/include/bits/fs_\* libstdc++-v3/include/std/filesystem
+
+Testsuites and change logs were discarded to reduce the amount of
+modification.
+
+Signed-off-by: Liu Hao <lh_mouse@126.com>
+---
+ libstdc++-v3/config.h.in | 12 +
+ libstdc++-v3/config/io/basic_file_stdio.cc | 33 ++
+ libstdc++-v3/config/io/basic_file_stdio.h | 5 +
+ libstdc++-v3/configure | 35 ++
+ libstdc++-v3/configure.ac | 2 +
+ libstdc++-v3/crossconfig.m4 | 1 +
+ libstdc++-v3/include/bits/fs_dir.h | 14 +-
+ libstdc++-v3/include/bits/fs_path.h | 250 +++++++-------
+ libstdc++-v3/include/bits/fstream.tcc | 36 ++
+ .../include/experimental/bits/fs_path.h | 74 ++--
+ libstdc++-v3/include/std/fstream | 119 +++++++
+ libstdc++-v3/src/filesystem/dir-common.h | 56 ++-
+ libstdc++-v3/src/filesystem/dir.cc | 5 +-
+ libstdc++-v3/src/filesystem/ops-common.h | 105 +++++-
+ libstdc++-v3/src/filesystem/ops.cc | 186 +++++-----
+ libstdc++-v3/src/filesystem/path.cc | 24 +-
+ libstdc++-v3/src/filesystem/std-dir.cc | 5 +-
+ libstdc++-v3/src/filesystem/std-ops.cc | 318 ++++++++++--------
+ libstdc++-v3/src/filesystem/std-path.cc | 123 ++++---
+ 19 files changed, 942 insertions(+), 461 deletions(-)
+
+diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in
+index 765cedc6edf..3fb685ce9aa 100644
+--- a/libstdc++-v3/config.h.in
++++ b/libstdc++-v3/config.h.in
+@@ -264,6 +264,9 @@
+ /* Only used in build directory testsuite_hooks.h. */
+ #undef HAVE_LIMIT_VMEM
+
++/* Define to 1 if you have the `link' function. */
++#undef HAVE_LINK
++
+ /* Define if futex syscall is available. */
+ #undef HAVE_LINUX_FUTEX
+
+@@ -339,6 +342,9 @@
+ /* Define to 1 if you have the `quick_exit' function. */
+ #undef HAVE_QUICK_EXIT
+
++/* Define to 1 if you have the `readlink' function. */
++#undef HAVE_READLINK
++
+ /* Define to 1 if you have the `setenv' function. */
+ #undef HAVE_SETENV
+
+@@ -408,6 +414,9 @@
+ /* Define if strxfrm_l is available in <string.h>. */
+ #undef HAVE_STRXFRM_L
+
++/* Define to 1 if you have the `symlink' function. */
++#undef HAVE_SYMLINK
++
+ /* Define to 1 if the target runtime linker supports binding the same symbol
+ to different versions. */
+ #undef HAVE_SYMVER_SYMBOL_RENAMING_RUNTIME_SUPPORT
+@@ -706,6 +715,9 @@
+ /* Define to 1 if you have the `_tanl' function. */
+ #undef HAVE__TANL
+
++/* Define to 1 if you have the `_wfopen' function. */
++#undef HAVE__WFOPEN
++
+ /* Define to 1 if you have the `__cxa_thread_atexit' function. */
+ #undef HAVE___CXA_THREAD_ATEXIT
+
+diff --git a/libstdc++-v3/config/io/basic_file_stdio.cc b/libstdc++-v3/config/io/basic_file_stdio.cc
+index a46814802cd..09ccd6a4788 100644
+--- a/libstdc++-v3/config/io/basic_file_stdio.cc
++++ b/libstdc++-v3/config/io/basic_file_stdio.cc
+@@ -249,6 +249,39 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ return __ret;
+ }
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ __basic_file<char>*
++ __basic_file<char>::open(const wchar_t* __name, ios_base::openmode __mode)
++ {
++ __basic_file* __ret = NULL;
++ const char* __c_mode = fopen_mode(__mode);
++ if (__c_mode && !this->is_open())
++ {
++ wchar_t __wc_mode[4] = { };
++ int __i = 0;
++ do
++ {
++ switch(__c_mode[__i]) {
++ case 'a': __wc_mode[__i] = L'a'; break;
++ case 'b': __wc_mode[__i] = L'b'; break;
++ case 'r': __wc_mode[__i] = L'r'; break;
++ case 'w': __wc_mode[__i] = L'w'; break;
++ case '+': __wc_mode[__i] = L'+'; break;
++ default: return __ret;
++ }
++ }
++ while (__c_mode[++__i]);
++
++ if ((_M_cfile = _wfopen(__name, __wc_mode)))
++ {
++ _M_cfile_created = true;
++ __ret = this;
++ }
++ }
++ return __ret;
++ }
++#endif
++
+ bool
+ __basic_file<char>::is_open() const throw ()
+ { return _M_cfile != 0; }
+diff --git a/libstdc++-v3/config/io/basic_file_stdio.h b/libstdc++-v3/config/io/basic_file_stdio.h
+index 58f24f670f6..3c857272c57 100644
+--- a/libstdc++-v3/config/io/basic_file_stdio.h
++++ b/libstdc++-v3/config/io/basic_file_stdio.h
+@@ -84,6 +84,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ __basic_file*
+ open(const char* __name, ios_base::openmode __mode, int __prot = 0664);
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ __basic_file*
++ open(const wchar_t* __name, ios_base::openmode __mode);
++#endif
++
+ __basic_file*
+ sys_open(__c_file* __file, ios_base::openmode);
+
+diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
+index 5535bfa2b5a..b9883d413f6 100755
+--- a/libstdc++-v3/configure
++++ b/libstdc++-v3/configure
+@@ -28127,6 +28127,17 @@ eval as_val=\$$as_ac_var
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+
++fi
++done
++
++ for ac_func in _wfopen
++do :
++ ac_fn_c_check_func "$LINENO" "_wfopen" "ac_cv_func__wfopen"
++if test "x$ac_cv_func__wfopen" = x""yes; then :
++ cat >>confdefs.h <<_ACEOF
++#define HAVE__WFOPEN 1
++_ACEOF
++
+ fi
+ done
+
+@@ -66122,6 +66133,17 @@ eval as_val=\$$as_ac_var
+ #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+ _ACEOF
+
++fi
++done
++
++ for ac_func in _wfopen
++do :
++ ac_fn_c_check_func "$LINENO" "_wfopen" "ac_cv_func__wfopen"
++if test "x$ac_cv_func__wfopen" = x""yes; then :
++ cat >>confdefs.h <<_ACEOF
++#define HAVE__WFOPEN 1
++_ACEOF
++
+ fi
+ done
+
+@@ -80025,6 +80047,19 @@ _ACEOF
+
+ fi
+
++done
++
++for ac_func in link readlink symlink
++do :
++ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
++ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
++eval as_val=\$$as_ac_var
++ if test "x$as_val" = x""yes; then :
++ cat >>confdefs.h <<_ACEOF
++#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
++_ACEOF
++
++fi
+ done
+
+
+diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
+index 0ef96270c9c..dde1c4da944 100644
+--- a/libstdc++-v3/configure.ac
++++ b/libstdc++-v3/configure.ac
+@@ -263,6 +263,7 @@ if $GLIBCXX_IS_NATIVE; then
+
+ AC_CHECK_FUNCS(__cxa_thread_atexit_impl __cxa_thread_atexit)
+ AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
++ AC_CHECK_FUNCS(_wfopen)
+
+ # For iconv support.
+ AM_ICONV
+@@ -419,6 +420,7 @@ GLIBCXX_CHECK_GTHREADS
+
+ # For Filesystem TS.
+ AC_CHECK_HEADERS([fcntl.h dirent.h sys/statvfs.h utime.h])
++AC_CHECK_FUNCS(link readlink symlink)
+ GLIBCXX_ENABLE_FILESYSTEM_TS
+ GLIBCXX_CHECK_FILESYSTEM_DEPS
+
+diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4
+index cb6e3afff3d..669d87f7602 100644
+--- a/libstdc++-v3/crossconfig.m4
++++ b/libstdc++-v3/crossconfig.m4
+@@ -199,6 +199,7 @@ case "${host}" in
+ GLIBCXX_CHECK_MATH_SUPPORT
+ GLIBCXX_CHECK_STDLIB_SUPPORT
+ AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
++ AC_CHECK_FUNCS(_wfopen)
+ ;;
+ *-netbsd*)
+ SECTION_FLAGS='-ffunction-sections -fdata-sections'
+diff --git a/libstdc++-v3/include/bits/fs_dir.h b/libstdc++-v3/include/bits/fs_dir.h
+index 9ee1cb66b61..6b332e171cf 100644
+--- a/libstdc++-v3/include/bits/fs_dir.h
++++ b/libstdc++-v3/include/bits/fs_dir.h
+@@ -138,13 +138,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ refresh(__ec);
+ }
+
+- void
+- refresh()
+- { _M_type = symlink_status().type(); }
+-
+- void
+- refresh(error_code& __ec) noexcept
+- { _M_type = symlink_status(__ec).type(); }
++ void refresh() { _M_type = symlink_status().type(); }
++ void refresh(error_code& __ec) { _M_type = symlink_status(__ec).type(); }
+
+ // observers
+ const filesystem::path& path() const noexcept { return _M_path; }
+@@ -318,10 +313,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ _M_file_type(error_code& __ec) const noexcept
+ {
+ if (_M_type != file_type::none && _M_type != file_type::symlink)
+- {
+- __ec.clear();
+- return _M_type;
+- }
++ return _M_type;
+ return status(__ec).type();
+ }
+
+diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
+index fb85d489fd8..e3938d06d59 100644
+--- a/libstdc++-v3/include/bits/fs_path.h
++++ b/libstdc++-v3/include/bits/fs_path.h
+@@ -37,11 +37,11 @@
+ #include <vector>
+ #include <locale>
+ #include <iosfwd>
++#include <iomanip>
+ #include <codecvt>
+ #include <string_view>
+ #include <system_error>
+ #include <bits/stl_algobase.h>
+-#include <bits/quoted_string.h>
+ #include <bits/locale_conv.h>
+
+ #if defined(_WIN32) && !defined(__CYGWIN__)
+@@ -65,8 +65,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ /// A filesystem path.
+ class path
+ {
+- template<typename _CharT>
+- struct __is_encoded_char : std::false_type { };
++ template<typename _CharT, typename _Ch = remove_const_t<_CharT>>
++ using __is_encoded_char
++ = __or_<is_same<_Ch, char>, is_same<_Ch, wchar_t>,
++ is_same<_Ch, char16_t>, is_same<_Ch, char32_t>>;
+
+ template<typename _Iter,
+ typename _Iter_traits = std::iterator_traits<_Iter>>
+@@ -106,8 +108,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+ template<typename _Tp1, typename _Tp2 = void>
+ using _Path = typename
+- std::enable_if<__and_<__not_<is_same<remove_cv_t<_Tp1>, path>>,
+- __not_<is_void<_Tp1>>,
++ std::enable_if<__and_<__not_<is_same<_Tp1, path>>,
+ __constructible_from<_Tp1, _Tp2>>::value,
+ path>::type;
+
+@@ -145,7 +146,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
+ typename _Val = typename std::iterator_traits<_Iter>::value_type>
+ using __value_type_is_char
+- = typename std::enable_if<std::is_same<_Val, char>::value>::type;
++ = std::enable_if_t<std::is_same_v<std::remove_const_t<_Val>, char>>;
+
+ public:
+ #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+@@ -231,37 +232,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+ // appends
+
+- path& operator/=(const path& __p)
+- {
+-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+- if (__p.is_absolute()
+- || (__p.has_root_name() && __p.root_name() != root_name()))
+- operator=(__p);
+- else
+- {
+- string_type __pathname;
+- if (__p.has_root_directory())
+- __pathname = root_name().native();
+- else if (has_filename() || (!has_root_directory() && is_absolute()))
+- __pathname = _M_pathname + preferred_separator;
+- __pathname += __p.relative_path().native(); // XXX is this right?
+- _M_pathname.swap(__pathname);
+- _M_split_cmpts();
+- }
+-#else
+- // Much simpler, as any path with root-name or root-dir is absolute.
+- if (__p.is_absolute())
+- operator=(__p);
+- else
+- {
+- if (has_filename() || (_M_type == _Type::_Root_name))
+- _M_pathname += preferred_separator;
+- _M_pathname += __p.native();
+- _M_split_cmpts();
+- }
+-#endif
+- return *this;
+- }
++ path& operator/=(const path& __p);
+
+ template <class _Source>
+ _Path<_Source>&
+@@ -377,7 +348,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ bool has_filename() const;
+ bool has_stem() const;
+ bool has_extension() const;
+- bool is_absolute() const { return has_root_directory(); }
++ bool is_absolute() const;
+ bool is_relative() const { return !is_absolute(); }
+
+ // generation
+@@ -392,6 +363,40 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ iterator begin() const;
+ iterator end() const;
+
++ /// Write a path to a stream
++ template<typename _CharT, typename _Traits>
++ friend std::basic_ostream<_CharT, _Traits>&
++ operator<<(std::basic_ostream<_CharT, _Traits>& __os, const path& __p)
++ {
++ __os << std::quoted(__p.string<_CharT, _Traits>());
++ return __os;
++ }
++
++ /// Read a path from a stream
++ template<typename _CharT, typename _Traits>
++ friend std::basic_istream<_CharT, _Traits>&
++ operator>>(std::basic_istream<_CharT, _Traits>& __is, path& __p)
++ {
++ std::basic_string<_CharT, _Traits> __tmp;
++ if (__is >> std::quoted(__tmp))
++ __p = std::move(__tmp);
++ return __is;
++ }
++
++ // Create a basic_string by reading until a null character.
++ template<typename _InputIterator,
++ typename _Traits = std::iterator_traits<_InputIterator>,
++ typename _CharT
++ = typename std::remove_cv_t<typename _Traits::value_type>>
++ static std::basic_string<_CharT>
++ _S_string_from_iter(_InputIterator __source)
++ {
++ std::basic_string<_CharT> __str;
++ for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
++ __str.push_back(__ch);
++ return __str;
++ }
++
+ private:
+ enum class _Type : unsigned char {
+ _Multi, _Root_name, _Root_dir, _Filename
+@@ -404,19 +409,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+ enum class _Split { _Stem, _Extension };
+
+- path&
+- _M_append(path __p)
+- {
+- if (__p.is_absolute())
+- operator=(std::move(__p));
+-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+- else if (__p.has_root_name() && __p.root_name() != root_name())
+- operator=(std::move(__p));
+-#endif
+- else
+- operator/=(const_cast<const path&>(__p));
+- return *this;
+- }
++ path& _M_append(path __p);
+
+ pair<const string_type*, size_t> _M_find_extension() const;
+
+@@ -444,11 +437,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ static string_type
+ _S_convert(_InputIterator __src, __null_terminated)
+ {
+- using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
+- std::basic_string<typename remove_cv<_Tp>::type> __tmp;
+- for (; *__src != _Tp{}; ++__src)
+- __tmp.push_back(*__src);
+- return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
++ auto __s = _S_string_from_iter(__src);
++ return _S_convert(__s.c_str(), __s.c_str() + __s.size());
+ }
+
+ static string_type
+@@ -468,10 +458,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ _S_convert_loc(_InputIterator __src, __null_terminated,
+ const std::locale& __loc)
+ {
+- std::string __tmp;
+- while (*__src != '\0')
+- __tmp.push_back(*__src++);
+- return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc);
++ std::string __s = _S_string_from_iter(__src);
++ return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
+ }
+
+ template<typename _CharT, typename _Traits, typename _Allocator>
+@@ -501,25 +489,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ _Type _M_type = _Type::_Filename;
+ };
+
+- template<>
+- struct path::__is_encoded_char<char> : std::true_type
+- { using value_type = char; };
+-
+- template<>
+- struct path::__is_encoded_char<wchar_t> : std::true_type
+- { using value_type = wchar_t; };
+-
+- template<>
+- struct path::__is_encoded_char<char16_t> : std::true_type
+- { using value_type = char16_t; };
+-
+- template<>
+- struct path::__is_encoded_char<char32_t> : std::true_type
+- { using value_type = char32_t; };
+-
+- template<typename _Tp>
+- struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { };
+-
+ inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
+
+ size_t hash_value(const path& __p) noexcept;
+@@ -556,58 +525,50 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ return __result;
+ }
+
+- /// Write a path to a stream
+- template<typename _CharT, typename _Traits>
+- basic_ostream<_CharT, _Traits>&
+- operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
+- {
+- auto __tmp = __p.string<_CharT, _Traits>();
+- using __quoted_string
+- = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
+- __os << __quoted_string{__tmp, '"', '\\'};
+- return __os;
+- }
+-
+- /// Read a path from a stream
+- template<typename _CharT, typename _Traits>
+- basic_istream<_CharT, _Traits>&
+- operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
+- {
+- basic_string<_CharT, _Traits> __tmp;
+- using __quoted_string
+- = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
+- if (__is >> __quoted_string{ __tmp, '"', '\\' })
+- __p = std::move(__tmp);
+- return __is;
+- }
+-
+- template<typename _Source>
++ template<typename _InputIterator>
+ inline auto
+- u8path(const _Source& __source)
+- -> decltype(filesystem::path(__source, std::locale::classic()))
++ u8path(_InputIterator __first, _InputIterator __last)
++ -> decltype(filesystem::path(__first, __last, std::locale::classic()))
+ {
+ #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+- const std::string __u8str{__source};
+- return std::filesystem::u8path(__u8str.begin(), __u8str.end());
++ codecvt_utf8<path::value_type> __cvt;
++ path::string_type __tmp;
++ if constexpr (is_pointer_v<_InputIterator>)
++ {
++ if (__str_codecvt_in(__first, __last, __tmp, __cvt))
++ return path{ __tmp };
++ }
++ else
++ {
++ const std::string __u8str{__first, __last};
++ const char* const __ptr = __u8str.data();
++ if (__str_codecvt_in(__ptr, __ptr + __u8str.size(), __tmp, __cvt))
++ return path{ __tmp };
++ }
++ return {};
+ #else
+- return path{ __source };
++ return path{ __first, __last };
+ #endif
+ }
+
+- template<typename _InputIterator>
++ template<typename _Source>
+ inline auto
+- u8path(_InputIterator __first, _InputIterator __last)
+- -> decltype(filesystem::path(__first, __last, std::locale::classic()))
++ u8path(const _Source& __source)
++ -> decltype(filesystem::path(__source, std::locale::classic()))
+ {
+ #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+- codecvt_utf8<value_type> __cvt;
+- string_type __tmp;
+- if (__str_codecvt_in(__first, __last, __tmp, __cvt))
+- return path{ __tmp };
++ if constexpr (is_convertible_v<const _Source&, std::string_view>)
++ {
++ const std::string_view __s = __source;
++ return filesystem::u8path(__s.data(), __s.data() + __s.size());
++ }
+ else
+- return {};
++ {
++ std::string __s = path::_S_string_from_iter(__source);
++ return filesystem::u8path(__s.data(), __s.data() + __s.size());
++ }
+ #else
+- return path{ __first, __last };
++ return path{ __source };
+ #endif
+ }
+
+@@ -916,11 +877,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ path::string(const _Allocator& __a) const
+ {
+ if constexpr (is_same_v<_CharT, value_type>)
++ {
+ #if _GLIBCXX_USE_CXX11_ABI
+- return { _M_pathname, __a };
++ return { _M_pathname, __a };
+ #else
+- return { _M_pathname, string_type::size_type(0), __a };
++ if constexpr (is_same_v<_Allocator, string_type::allocator_type>)
++ return _M_pathname;
++ else
++ return { _M_pathname, string_type::size_type(0), __a };
+ #endif
++ }
+ else
+ return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
+ }
+@@ -1072,6 +1038,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ return ext.first && ext.second != string_type::npos;
+ }
+
++ inline bool
++ path::is_absolute() const
++ {
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ return has_root_name() && has_root_directory();
++#else
++ return has_root_directory();
++#endif
++ }
++
+ inline path::iterator
+ path::begin() const
+ {
+@@ -1088,6 +1064,38 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ return iterator(this, true);
+ }
+
++#ifndef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ inline path& path::operator/=(const path& __p)
++ {
++ // Much simpler than the specification in the standard,
++ // as any path with root-name or root-dir is absolute.
++ if (__p.is_absolute())
++ operator=(__p);
++ else
++ {
++ if (has_filename() || (_M_type == _Type::_Root_name))
++ _M_pathname += preferred_separator;
++ _M_pathname += __p.native();
++ _M_split_cmpts();
++ }
++ return *this;
++ }
++#endif
++
++ inline path&
++ path::_M_append(path __p)
++ {
++ if (__p.is_absolute())
++ operator=(std::move(__p));
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ else if (__p.has_root_name() && __p.root_name() != root_name())
++ operator=(std::move(__p));
++#endif
++ else
++ operator/=(const_cast<const path&>(__p));
++ return *this;
++ }
++
+ inline path::iterator&
+ path::iterator::operator++()
+ {
+diff --git a/libstdc++-v3/include/bits/fstream.tcc b/libstdc++-v3/include/bits/fstream.tcc
+index f23ff7af4eb..d9eff00823a 100644
+--- a/libstdc++-v3/include/bits/fstream.tcc
++++ b/libstdc++-v3/include/bits/fstream.tcc
+@@ -207,6 +207,42 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ return __ret;
+ }
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ template<typename _CharT, typename _Traits>
++ basic_filebuf<_CharT, _Traits>*
++ basic_filebuf<_CharT, _Traits>::
++ open(const wchar_t* __s, ios_base::openmode __mode)
++ {
++ __filebuf_type *__ret = 0;
++ if (!this->is_open())
++ {
++ _M_file.open(__s, __mode);
++ if (this->is_open())
++ {
++ _M_allocate_internal_buffer();
++ _M_mode = __mode;
++
++ // Setup initial buffer to 'uncommitted' mode.
++ _M_reading = false;
++ _M_writing = false;
++ _M_set_buffer(-1);
++
++ // Reset to initial state.
++ _M_state_last = _M_state_cur = _M_state_beg;
++
++ // 27.8.1.3,4
++ if ((__mode & ios_base::ate)
++ && this->seekoff(0, ios_base::end, __mode)
++ == pos_type(off_type(-1)))
++ this->close();
++ else
++ __ret = this;
++ }
++ }
++ return __ret;
++ }
++#endif // HAVE__WFOPEN && USE_WCHAR_T
++
+ template<typename _CharT, typename _Traits>
+ typename basic_filebuf<_CharT, _Traits>::__filebuf_type*
+ basic_filebuf<_CharT, _Traits>::
+diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
+index 088d62f8f43..340cc59d541 100644
+--- a/libstdc++-v3/include/experimental/bits/fs_path.h
++++ b/libstdc++-v3/include/experimental/bits/fs_path.h
+@@ -79,8 +79,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ /// A filesystem path.
+ class path
+ {
+- template<typename _CharT>
+- struct __is_encoded_char : std::false_type { };
++ template<typename _CharT,
++ typename _Ch = typename remove_const<_CharT>::type>
++ using __is_encoded_char
++ = __or_<is_same<_Ch, char>, is_same<_Ch, wchar_t>,
++ is_same<_Ch, char16_t>, is_same<_Ch, char32_t>>;
+
+ template<typename _Iter,
+ typename _Iter_traits = std::iterator_traits<_Iter>>
+@@ -163,8 +166,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ template<typename _Tp,
+ typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
+ typename _Val = typename std::iterator_traits<_Iter>::value_type>
+- using __value_type_is_char
+- = typename std::enable_if<std::is_same<_Val, char>::value>::type;
++ using __value_type_is_char = typename std::enable_if<
++ std::is_same<typename std::remove_const<_Val>::type, char>::value
++ >::type;
+
+ public:
+ #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+@@ -370,7 +374,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ bool has_filename() const;
+ bool has_stem() const;
+ bool has_extension() const;
+- bool is_absolute() const { return has_root_directory(); }
++ bool is_absolute() const;
+ bool is_relative() const { return !is_absolute(); }
+
+ // iterators
+@@ -380,6 +384,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ iterator begin() const;
+ iterator end() const;
+
++ // Create a basic_string by reading until a null character.
++ template<typename _InputIterator,
++ typename _Traits = std::iterator_traits<_InputIterator>,
++ typename _CharT
++ = typename std::remove_cv<typename _Traits::value_type>::type>
++ static std::basic_string<_CharT>
++ _S_string_from_iter(_InputIterator __source)
++ {
++ std::basic_string<_CharT> __str;
++ for (_CharT __ch = *__source; __ch != _CharT(); __ch = *++__source)
++ __str.push_back(__ch);
++ return __str;
++ }
++
+ private:
+ enum class _Type : unsigned char {
+ _Multi, _Root_name, _Root_dir, _Filename
+@@ -429,11 +447,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ static string_type
+ _S_convert(_InputIterator __src, __null_terminated)
+ {
+- using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
+- std::basic_string<typename remove_cv<_Tp>::type> __tmp;
+- for (; *__src != _Tp{}; ++__src)
+- __tmp.push_back(*__src);
+- return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
++ auto __s = _S_string_from_iter(__src);
++ return _S_convert(__s.c_str(), __s.c_str() + __s.size());
+ }
+
+ static string_type
+@@ -453,10 +468,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ _S_convert_loc(_InputIterator __src, __null_terminated,
+ const std::locale& __loc)
+ {
+- std::string __tmp;
+- while (*__src != '\0')
+- __tmp.push_back(*__src++);
+- return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc);
++ std::string __s = _S_string_from_iter(__src);
++ return _S_convert_loc(__s.data(), __s.data() + __s.size(), __loc);
+ }
+
+ bool _S_is_dir_sep(value_type __ch)
+@@ -526,7 +539,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ auto __tmp = __p.string<_CharT, _Traits>();
+ using __quoted_string
+ = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
+- __os << __quoted_string{__tmp, '"', '\\'};
++ __os << __quoted_string{__tmp, _CharT('"'), _CharT('\\')};
+ return __os;
+ }
+
+@@ -538,7 +551,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ basic_string<_CharT, _Traits> __tmp;
+ using __quoted_string
+ = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
+- if (__is >> __quoted_string{ __tmp, '"', '\\' })
++ if (__is >> __quoted_string{ __tmp, _CharT('"'), _CharT('\\') })
+ __p = std::move(__tmp);
+ return __is;
+ }
+@@ -596,25 +609,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ std::string _M_what = _M_gen_what();
+ };
+
+- template<>
+- struct path::__is_encoded_char<char> : std::true_type
+- { using value_type = char; };
+-
+- template<>
+- struct path::__is_encoded_char<wchar_t> : std::true_type
+- { using value_type = wchar_t; };
+-
+- template<>
+- struct path::__is_encoded_char<char16_t> : std::true_type
+- { using value_type = char16_t; };
+-
+- template<>
+- struct path::__is_encoded_char<char32_t> : std::true_type
+- { using value_type = char32_t; };
+-
+- template<typename _Tp>
+- struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { };
+-
+ struct path::_Cmpt : path
+ {
+ _Cmpt(string_type __s, _Type __t, size_t __pos)
+@@ -1001,6 +995,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ return ext.first && ext.second != string_type::npos;
+ }
+
++ inline bool
++ path::is_absolute() const
++ {
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ return has_root_name() && has_root_directory();
++#else
++ return has_root_directory();
++#endif
++ }
++
+ inline path::iterator
+ path::begin() const
+ {
+diff --git a/libstdc++-v3/include/std/fstream b/libstdc++-v3/include/std/fstream
+index 3a5895d68b0..740d12d3bb6 100644
+--- a/libstdc++-v3/include/std/fstream
++++ b/libstdc++-v3/include/std/fstream
+@@ -304,6 +304,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ __filebuf_type*
+ open(const char* __s, ios_base::openmode __mode);
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ /**
++ * @brief Opens an external file.
++ * @param __s The name of the file, as a wide character string.
++ * @param __mode The open mode flags.
++ * @return @c this on success, NULL on failure
++ */
++ __filebuf_type*
++ open(const wchar_t* __s, ios_base::openmode __mode);
++#endif
++
+ #if __cplusplus >= 201103L
+ /**
+ * @brief Opens an external file.
+@@ -517,6 +528,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ this->open(__s, __mode);
+ }
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ /**
++ * @param Create an input file stream.
++ * @param __s Wide string specifying the filename.
++ * @param __mode Open file in specified mode (see std::ios_base).
++ *
++ * @c ios_base::in is automatically included in @a __mode.
++ */
++ basic_ifstream(const wchar_t* __s,
++ ios_base::openmode __mode = ios_base::in)
++ : __istream_type(), _M_filebuf()
++ {
++ this->init(&_M_filebuf);
++ this->open(__s, __mode);
++ }
++#endif
++
+ #if __cplusplus >= 201103L
+ /**
+ * @brief Create an input file stream.
+@@ -632,6 +660,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ this->clear();
+ }
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ /**
++ * @brief Opens an external file.
++ * @param __s The name of the file, as a wide character string.
++ * @param __mode The open mode flags.
++ *
++ * Calls @c std::basic_filebuf::open(__s,__mode|in). If that function
++ * fails, @c failbit is set in the stream's error state.
++ */
++ void
++ open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in)
++ {
++ if (!_M_filebuf.open(__s, __mode | ios_base::in))
++ this->setstate(ios_base::failbit);
++ else
++ this->clear();
++ }
++#endif
++
+ #if __cplusplus >= 201103L
+ /**
+ * @brief Opens an external file.
+@@ -743,6 +790,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ this->open(__s, __mode);
+ }
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ /**
++ * @param Create an output file stream.
++ * @param __s Wide string specifying the filename.
++ * @param __mode Open file in specified mode (see std::ios_base).
++ *
++ * @c ios_base::out | @c ios_base::trunc is automatically included in
++ * @a __mode.
++ */
++ basic_ofstream(const wchar_t* __s,
++ ios_base::openmode __mode = ios_base::out|ios_base::trunc)
++ : __ostream_type(), _M_filebuf()
++ {
++ this->init(&_M_filebuf);
++ this->open(__s, __mode);
++ }
++#endif
++
+ #if __cplusplus >= 201103L
+ /**
+ * @brief Create an output file stream.
+@@ -858,6 +923,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ this->clear();
+ }
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ /**
++ * @brief Opens an external file.
++ * @param __s The name of the file.
++ * @param __mode The open mode flags.
++ *
++ * Calls @c std::basic_filebuf::open(__s,__mode|out). If that
++ * function fails, @c failbit is set in the stream's error state.
++ */
++ void
++ open(const wchar_t* __s, ios_base::openmode __mode = ios_base::out)
++ {
++ if (!_M_filebuf.open(__s, __mode | ios_base::out))
++ this->setstate(ios_base::failbit);
++ else
++ this->clear();
++ }
++#endif
++
+ #if __cplusplus >= 201103L
+ /**
+ * @brief Opens an external file.
+@@ -969,6 +1053,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ this->open(__s, __mode);
+ }
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ /**
++ * @param Create an input/output file stream.
++ * @param __s Wide string specifying the filename.
++ * @param __mode Open file in specified mode (see std::ios_base).
++ */
++ basic_fstream(const wchar_t* __s,
++ ios_base::openmode __mode = ios_base::in | ios_base::out)
++ : __iostream_type(0), _M_filebuf()
++ {
++ this->init(&_M_filebuf);
++ this->open(__s, __mode);
++ }
++#endif
++
+ #if __cplusplus >= 201103L
+ /**
+ * @brief Create an input/output file stream.
+@@ -1081,6 +1180,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ this->clear();
+ }
+
++#if _GLIBCXX_HAVE__WFOPEN && _GLIBCXX_USE_WCHAR_T
++ /**
++ * @brief Opens an external file.
++ * @param __s The name of the file.
++ * @param __mode The open mode flags.
++ *
++ * Calls @c std::basic_filebuf::open(__s,__mode). If that
++ * function fails, @c failbit is set in the stream's error state.
++ */
++ void
++ open(const wchar_t* __s,
++ ios_base::openmode __mode = ios_base::in | ios_base::out)
++ {
++ if (!_M_filebuf.open(__s, __mode))
++ this->setstate(ios_base::failbit);
++ else
++ this->clear();
++ }
++#endif
++
+ #if __cplusplus >= 201103L
+ /**
+ * @brief Opens an external file.
+diff --git a/libstdc++-v3/src/filesystem/dir-common.h b/libstdc++-v3/src/filesystem/dir-common.h
+index 21ba01ca970..03875819d04 100644
+--- a/libstdc++-v3/src/filesystem/dir-common.h
++++ b/libstdc++-v3/src/filesystem/dir-common.h
+@@ -26,6 +26,9 @@
+ #define _GLIBCXX_DIR_COMMON_H 1
+
+ #include <string.h> // strcmp
++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
++#include <wchar.h> // wcscmp
++#endif
+ #ifdef _GLIBCXX_HAVE_DIRENT_H
+ # ifdef _GLIBCXX_HAVE_SYS_TYPES_H
+ # include <sys/types.h>
+@@ -35,26 +38,42 @@
+ # error "the <dirent.h> header is needed to build the Filesystem TS"
+ #endif
+
+-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+-# undef opendir
+-# define opendir _wopendir
+-#endif
+-
+ namespace std _GLIBCXX_VISIBILITY(default)
+ {
+ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace filesystem
+ {
++namespace __gnu_posix
++{
++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
++// Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*.
++using char_type = wchar_t;
++using DIR = ::_WDIR;
++using dirent = _wdirent;
++inline DIR* opendir(const wchar_t* path) { return ::_wopendir(path); }
++inline dirent* readdir(DIR* dir) { return ::_wreaddir(dir); }
++inline int closedir(DIR* dir) { return ::_wclosedir(dir); }
++#else
++using char_type = char;
++using DIR = ::DIR;
++typedef struct ::dirent dirent;
++using ::opendir;
++using ::readdir;
++using ::closedir;
++#endif
++} // namespace __gnu_posix
++
++namespace posix = __gnu_posix;
+
+ struct _Dir_base
+ {
+- _Dir_base(DIR* dirp = nullptr) : dirp(dirp) { }
++ _Dir_base(posix::DIR* dirp = nullptr) : dirp(dirp) { }
+
+ // If no error occurs then dirp is non-null,
+ // otherwise null (whether error ignored or not).
+- _Dir_base(const char* p, bool skip_permission_denied,
++ _Dir_base(const posix::char_type* pathname, bool skip_permission_denied,
+ error_code& ec) noexcept
+- : dirp(::opendir(p))
++ : dirp(posix::opendir(pathname))
+ {
+ if (dirp)
+ ec.clear();
+@@ -72,22 +91,22 @@ struct _Dir_base
+
+ _Dir_base& operator=(_Dir_base&&) = delete;
+
+- ~_Dir_base() { if (dirp) ::closedir(dirp); }
++ ~_Dir_base() { if (dirp) posix::closedir(dirp); }
+
+- const struct ::dirent*
++ const posix::dirent*
+ advance(bool skip_permission_denied, error_code& ec) noexcept
+ {
+ ec.clear();
+
+ int err = std::exchange(errno, 0);
+- const struct ::dirent* entp = readdir(dirp);
++ const posix::dirent* entp = posix::readdir(dirp);
+ // std::swap cannot be used with Bionic's errno
+ err = std::exchange(errno, err);
+
+ if (entp)
+ {
+ // skip past dot and dot-dot
+- if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, ".."))
++ if (is_dot_or_dotdot(entp->d_name))
+ return advance(skip_permission_denied, ec);
+ return entp;
+ }
+@@ -105,15 +124,24 @@ struct _Dir_base
+ }
+ }
+
+- DIR* dirp;
++ static bool is_dot_or_dotdot(const char* s) noexcept
++ { return !strcmp(s, ".") || !strcmp(s, ".."); }
++
++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ static bool is_dot_or_dotdot(const wchar_t* s) noexcept
++ { return !wcscmp(s, L".") || !wcscmp(s, L".."); }
++#endif
++
++ posix::DIR* dirp;
+ };
+
+ } // namespace filesystem
+
+ // BEGIN/END macros must be defined before including this file.
+ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
++
+ inline file_type
+-get_file_type(const ::dirent& d __attribute__((__unused__)))
++get_file_type(const std::filesystem::__gnu_posix::dirent& d [[gnu::unused]])
+ {
+ #ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
+ switch (d.d_type)
+diff --git a/libstdc++-v3/src/filesystem/dir.cc b/libstdc++-v3/src/filesystem/dir.cc
+index 7e712c553c3..01c3decaba6 100644
+--- a/libstdc++-v3/src/filesystem/dir.cc
++++ b/libstdc++-v3/src/filesystem/dir.cc
+@@ -37,6 +37,7 @@
+ #include "dir-common.h"
+
+ namespace fs = std::experimental::filesystem;
++namespace posix = std::filesystem::__gnu_posix;
+
+ struct fs::_Dir : std::filesystem::_Dir_base
+ {
+@@ -47,7 +48,7 @@ struct fs::_Dir : std::filesystem::_Dir_base
+ path = p;
+ }
+
+- _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
++ _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
+
+ _Dir(_Dir&&) = default;
+
+@@ -185,7 +186,7 @@ recursive_directory_iterator(const path& p, directory_options options,
+ {
+ if (ec)
+ ec->clear();
+- if (DIR* dirp = ::opendir(p.c_str()))
++ if (posix::DIR* dirp = posix::opendir(p.c_str()))
+ {
+ auto sp = std::make_shared<_Dir_stack>();
+ sp->push(_Dir{ dirp, p });
+diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h
+index bc186836bd4..c1b817189a9 100644
+--- a/libstdc++-v3/src/filesystem/ops-common.h
++++ b/libstdc++-v3/src/filesystem/ops-common.h
+@@ -34,12 +34,103 @@
+ # include <sys/stat.h>
+ # endif
+ #endif
++#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
++# include <utime.h> // utime
++#endif
++
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++# include <wchar.h>
++#endif
+
+ namespace std _GLIBCXX_VISIBILITY(default)
+ {
+ _GLIBCXX_BEGIN_NAMESPACE_VERSION
+ namespace filesystem
+ {
++namespace __gnu_posix
++{
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++// Adapt the Windows _wxxx functions to look like POSIX xxx, but for wchar_t*.
++ inline int open(const wchar_t* path, int flags)
++ { return ::_wopen(path, flags); }
++
++ inline int open(const wchar_t* path, int flags, int mode)
++ { return ::_wopen(path, flags, mode); }
++
++ inline int close(int fd)
++ { return ::_close(fd); }
++
++ typedef struct ::_stat stat_type;
++
++ inline int stat(const wchar_t* path, stat_type* buffer)
++ { return ::_wstat(path, buffer); }
++
++ inline lstat(const wchar_t* path, stat_type* buffer)
++ {
++ // TODO symlinks not currently supported
++ return stat(path, buffer);
++ }
++
++ using ::mode_t;
++
++ inline int chmod(const wchar_t* path, mode_t mode)
++ { return ::_wchmod(path, mode); }
++
++ inline int mkdir(const wchar_t* path, mode_t)
++ { return ::_wmkdir(path); }
++
++ inline wchar_t* getcwd(wchar_t* buf, size_t size)
++ { return ::_wgetcwd(buf, size > (size_t)INT_MAX ? INT_MAX : (int)size); }
++
++ inline int chdir(const wchar_t* path)
++ { return ::_wchdir(path); }
++
++#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
++ using utimbuf = _utimbuf;
++
++ inline int utime(const wchar_t* path, utimbuf* times)
++ { return ::_wutime(path, times); }
++#endif
++
++ inline int rename(const wchar_t* oldname, const wchar_t* newname)
++ { return _wrename(oldname, newname); }
++
++ inline int truncate(const wchar_t* path, _off64_t length)
++ {
++ const int fd = ::_wopen(path, _O_BINARY|_O_RDWR);
++ if (fd == -1)
++ return fd;
++ const int ret = ::ftruncate64(fd, length);
++ int err;
++ ::_get_errno(&err);
++ ::_close(fd);
++ ::_set_errno(err);
++ return ret;
++ }
++ using char_type = wchar_t;
++#else // _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ using ::open;
++ using ::close;
++#ifdef _GLIBCXX_HAVE_SYS_STAT_H
++ typedef struct ::stat stat_type;
++ using ::stat;
++ using ::lstat;
++#endif
++ using ::mode_t;
++ using ::chmod;
++ using ::mkdir;
++ using ::getcwd;
++ using ::chdir;
++#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
++ using ::utimbuf;
++ using ::utime;
++#endif
++ using ::rename;
++ using ::truncate;
++ using char_type = char;
++#endif // _GLIBCXX_FILESYSTEM_IS_WINDOWS
++} // namespace __gnu_posix
++
+ template<typename Bitmask>
+ inline bool is_set(Bitmask obj, Bitmask bits)
+ {
+@@ -53,7 +144,7 @@ namespace filesystem
+ }
+
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+- typedef struct ::stat stat_type;
++ using __gnu_posix::stat_type;
+
+ inline std::chrono::system_clock::time_point
+ file_time(const stat_type& st, std::error_code& ec) noexcept
+@@ -82,11 +173,17 @@ namespace filesystem
+ };
+
+ bool
+- do_copy_file(const char* from, const char* to,
++ do_copy_file(const __gnu_posix::char_type* from,
++ const __gnu_posix::char_type* to,
+ copy_options_existing_file options,
+ stat_type* from_st, stat_type* to_st,
+ std::error_code& ec) noexcept;
+
++ void
++ do_space(const __gnu_posix::char_type* pathname,
++ uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
++ std::error_code&);
++
+ #endif // _GLIBCXX_HAVE_SYS_STAT_H
+
+ } // namespace filesystem
+@@ -95,7 +192,7 @@ namespace filesystem
+ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
+
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+- typedef struct ::stat stat_type;
++ using std::filesystem::__gnu_posix::stat_type;
+
+ inline file_type
+ make_file_type(const stat_type& st) noexcept
+@@ -111,8 +208,10 @@ _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
+ return file_type::block;
+ else if (S_ISFIFO(st.st_mode))
+ return file_type::fifo;
++#ifdef S_ISLNK // not present in mingw
+ else if (S_ISLNK(st.st_mode))
+ return file_type::symlink;
++#endif
+ #ifdef S_ISSOCK // not present until POSIX:2001
+ else if (S_ISSOCK(st.st_mode))
+ return file_type::socket;
+diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc
+index de290625e54..40cadbf6270 100644
+--- a/libstdc++-v3/src/filesystem/ops.cc
++++ b/libstdc++-v3/src/filesystem/ops.cc
+@@ -47,20 +47,17 @@
+ #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+ # include <utime.h> // utime
+ #endif
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++# include <windows.h>
++#endif
+
+ #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
+ namespace experimental { namespace filesystem {
+ #define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
+ #include "ops-common.h"
+
+-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+-# undef utime
+-# define utime _wutime
+-# undef chmod
+-# define chmod _wchmod
+-#endif
+-
+ namespace fs = std::experimental::filesystem;
++namespace posix = std::filesystem::__gnu_posix;
+
+ fs::path
+ fs::absolute(const path& p, const path& base)
+@@ -109,7 +106,7 @@ namespace
+ void operator()(void* p) const { ::free(p); }
+ };
+
+- using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
++ using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
+ }
+
+ fs::path
+@@ -122,7 +119,8 @@ fs::canonical(const path& p, const path& base, error_code& ec)
+ char_ptr buf{ nullptr };
+ # if _XOPEN_VERSION < 700
+ // Not safe to call realpath(path, NULL)
+- buf.reset( (char*)::malloc(PATH_MAX) );
++ using char_type = fs::path::value_type;
++ buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
+ # endif
+ if (char* rp = ::realpath(pa.c_str(), buf.get()))
+ {
+@@ -241,12 +239,13 @@ namespace
+ using std::filesystem::is_set;
+
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+- typedef struct ::stat stat_type;
++ using posix::stat_type;
+
+ using std::filesystem::is_not_found_errno;
+ using std::filesystem::file_time;
+ using std::filesystem::do_copy_file;
+ #endif // _GLIBCXX_HAVE_SYS_STAT_H
++
+ } // namespace
+
+ void
+@@ -263,15 +262,15 @@ fs::copy(const path& from, const path& to, copy_options options,
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2681. filesystem::copy() cannot copy symlinks
+ if (use_lstat || copy_symlinks
+- ? ::lstat(from.c_str(), &from_st)
+- : ::stat(from.c_str(), &from_st))
++ ? posix::lstat(from.c_str(), &from_st)
++ : posix::stat(from.c_str(), &from_st))
+ {
+ ec.assign(errno, std::generic_category());
+ return;
+ }
+ if (use_lstat
+- ? ::lstat(to.c_str(), &to_st)
+- : ::stat(to.c_str(), &to_st))
++ ? posix::lstat(to.c_str(), &to_st)
++ : posix::stat(to.c_str(), &to_st))
+ {
+ if (!is_not_found_errno(errno))
+ {
+@@ -424,19 +423,6 @@ fs::create_directories(const path& p, error_code& ec) noexcept
+ ec = std::make_error_code(errc::invalid_argument);
+ return false;
+ }
+-
+- file_status st = symlink_status(p, ec);
+- if (is_directory(st))
+- return false;
+- else if (ec && !status_known(st))
+- return false;
+- else if (exists(st))
+- {
+- if (!ec)
+- ec = std::make_error_code(std::errc::not_a_directory);
+- return false;
+- }
+-
+ std::stack<path> missing;
+ path pp = p;
+
+@@ -445,29 +431,24 @@ fs::create_directories(const path& p, error_code& ec) noexcept
+ ec.clear();
+ const auto& filename = pp.filename();
+ if (!is_dot(filename) && !is_dotdot(filename))
+- {
+- missing.push(std::move(pp));
+- pp = missing.top().parent_path();
+- }
+- else
+- pp = pp.parent_path();
++ missing.push(pp);
++ pp.remove_filename();
+ }
+
+ if (ec || missing.empty())
+ return false;
+
+- bool created;
+ do
+ {
+ const path& top = missing.top();
+- created = create_directory(top, ec);
+- if (ec)
+- return false;
++ create_directory(top, ec);
++ if (ec && is_directory(top))
++ ec.clear();
+ missing.pop();
+ }
+- while (!missing.empty());
++ while (!missing.empty() && !ec);
+
+- return created;
++ return missing.empty();
+ }
+
+ namespace
+@@ -477,8 +458,8 @@ namespace
+ {
+ bool created = false;
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+- ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
+- if (::mkdir(p.c_str(), mode))
++ posix::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
++ if (posix::mkdir(p.c_str(), mode))
+ {
+ const int err = errno;
+ if (err != EEXIST || !is_directory(p, ec))
+@@ -531,7 +512,7 @@ fs::create_directory(const path& p, const path& attributes,
+ {
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ stat_type st;
+- if (::stat(attributes.c_str(), &st))
++ if (posix::stat(attributes.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+@@ -580,11 +561,16 @@ void
+ fs::create_hard_link(const path& to, const path& new_hard_link,
+ error_code& ec) noexcept
+ {
+-#ifdef _GLIBCXX_HAVE_UNISTD_H
++#ifdef _GLIBCXX_HAVE_LINK
+ if (::link(to.c_str(), new_hard_link.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
++#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
++ ec.clear();
++ else
++ ec.assign((int)GetLastError(), generic_category());
+ #else
+ ec = std::make_error_code(std::errc::not_supported);
+ #endif
+@@ -604,7 +590,7 @@ void
+ fs::create_symlink(const path& to, const path& new_symlink,
+ error_code& ec) noexcept
+ {
+-#ifdef _GLIBCXX_HAVE_UNISTD_H
++#ifdef _GLIBCXX_HAVE_SYMLINK
+ if (::symlink(to.c_str(), new_symlink.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+@@ -614,7 +600,6 @@ fs::create_symlink(const path& to, const path& new_symlink,
+ #endif
+ }
+
+-
+ fs::path
+ fs::current_path()
+ {
+@@ -630,8 +615,8 @@ fs::current_path(error_code& ec)
+ {
+ path p;
+ #ifdef _GLIBCXX_HAVE_UNISTD_H
+-#ifdef __GLIBC__
+- if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
++#if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
+ {
+ p.assign(cwd.get());
+ ec.clear();
+@@ -639,6 +624,7 @@ fs::current_path(error_code& ec)
+ else
+ ec.assign(errno, std::generic_category());
+ #else
++#ifdef _PC_PATH_MAX
+ long path_max = pathconf(".", _PC_PATH_MAX);
+ size_t size;
+ if (path_max == -1)
+@@ -647,9 +633,15 @@ fs::current_path(error_code& ec)
+ size = 10240;
+ else
+ size = path_max;
++#elif defined(PATH_MAX)
++ size_t size = PATH_MAX;
++#else
++ size_t size = 1024;
++#endif
+ for (char_ptr buf; p.empty(); size *= 2)
+ {
+- buf.reset((char*)malloc(size));
++ using char_type = fs::path::value_type;
++ buf.reset((char_type*)malloc(size * sizeof(char_type)));
+ if (buf)
+ {
+ if (getcwd(buf.get(), size))
+@@ -689,7 +681,7 @@ void
+ fs::current_path(const path& p, error_code& ec) noexcept
+ {
+ #ifdef _GLIBCXX_HAVE_UNISTD_H
+- if (::chdir(p.c_str()))
++ if (posix::chdir(p.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+@@ -716,14 +708,14 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
+ int err = 0;
+ file_status s1, s2;
+ stat_type st1, st2;
+- if (::stat(p1.c_str(), &st1) == 0)
++ if (posix::stat(p1.c_str(), &st1) == 0)
+ s1 = make_file_status(st1);
+ else if (is_not_found_errno(errno))
+ s1.type(file_type::not_found);
+ else
+ err = errno;
+
+- if (::stat(p2.c_str(), &st2) == 0)
++ if (posix::stat(p2.c_str(), &st2) == 0)
+ s2 = make_file_status(st2);
+ else if (is_not_found_errno(errno))
+ s2.type(file_type::not_found);
+@@ -773,7 +765,7 @@ namespace
+ {
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ stat_type st;
+- if (::stat(p.c_str(), &st))
++ if (posix::stat(p.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return deflt;
+@@ -823,7 +815,7 @@ fs::hard_link_count(const path& p)
+ std::uintmax_t
+ fs::hard_link_count(const path& p, error_code& ec) noexcept
+ {
+- return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
++ return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
+ static_cast<uintmax_t>(-1));
+ }
+
+@@ -899,11 +891,11 @@ fs::last_write_time(const path& p __attribute__((__unused__)),
+ else
+ ec.clear();
+ #elif _GLIBCXX_HAVE_UTIME_H
+- ::utimbuf times;
++ posix::utimbuf times;
+ times.modtime = s.count();
+ times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
+ times.modtime);
+- if (::utime(p.c_str(), &times))
++ if (posix::utime(p.c_str(), &times))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+@@ -956,7 +948,7 @@ fs::permissions(const path& p, perms prms, error_code& ec) noexcept
+ #else
+ if (nofollow && is_symlink(st))
+ ec = std::make_error_code(std::errc::operation_not_supported);
+- else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
++ else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
+ err = errno;
+ #endif
+
+@@ -976,10 +968,10 @@ fs::read_symlink(const path& p)
+ return tgt;
+ }
+
+-fs::path fs::read_symlink(const path& p, error_code& ec)
++fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
+ {
+ path result;
+-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
++#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
+ stat_type st;
+ if (::lstat(p.c_str(), &st))
+ {
+@@ -1033,6 +1025,19 @@ fs::remove(const path& p)
+ bool
+ fs::remove(const path& p, error_code& ec) noexcept
+ {
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ if (exists(symlink_status(p, ec)))
++ {
++ if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
++ || DeleteFileW(p.c_str()))
++ {
++ ec.clear();
++ return true;
++ }
++ else if (!ec)
++ ec.assign((int)GetLastError(), generic_category());
++ }
++#else
+ if (::remove(p.c_str()) == 0)
+ {
+ ec.clear();
+@@ -1042,6 +1047,7 @@ fs::remove(const path& p, error_code& ec) noexcept
+ ec.clear();
+ else
+ ec.assign(errno, std::generic_category());
++#endif
+ return false;
+ }
+
+@@ -1095,7 +1101,7 @@ fs::rename(const path& from, const path& to)
+ void
+ fs::rename(const path& from, const path& to, error_code& ec) noexcept
+ {
+- if (::rename(from.c_str(), to.c_str()))
++ if (posix::rename(from.c_str(), to.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+@@ -1116,7 +1122,7 @@ fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
+ #ifdef _GLIBCXX_HAVE_UNISTD_H
+ if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
+ ec.assign(EINVAL, std::generic_category());
+- else if (::truncate(p.c_str(), size))
++ else if (posix::truncate(p.c_str(), size))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+@@ -1144,23 +1150,14 @@ fs::space(const path& p, error_code& ec) noexcept
+ static_cast<uintmax_t>(-1),
+ static_cast<uintmax_t>(-1)
+ };
+-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+- struct ::statvfs f;
+- if (::statvfs(p.c_str(), &f))
+- ec.assign(errno, std::generic_category());
+- else
+- {
+- uintmax_t fragment_size = f.f_frsize;
+- info = space_info{
+- f.f_blocks * fragment_size,
+- f.f_bfree * fragment_size,
+- f.f_bavail * fragment_size
+- };
+- ec.clear();
+- }
++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ path dir = absolute(p);
++ dir.remove_filename();
++ auto str = dir.c_str();
+ #else
+- ec = std::make_error_code(std::errc::not_supported);
++ auto str = p.c_str();
+ #endif
++ std::filesystem::do_space(str, info.capacity, info.free, info.available, ec);
+ return info;
+ }
+
+@@ -1170,7 +1167,7 @@ fs::status(const fs::path& p, error_code& ec) noexcept
+ {
+ file_status status;
+ stat_type st;
+- if (::stat(p.c_str(), &st))
++ if (posix::stat(p.c_str(), &st))
+ {
+ int err = errno;
+ ec.assign(err, std::generic_category());
+@@ -1194,7 +1191,7 @@ fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
+ {
+ file_status status;
+ stat_type st;
+- if (::lstat(p.c_str(), &st))
++ if (posix::lstat(p.c_str(), &st))
+ {
+ int err = errno;
+ ec.assign(err, std::generic_category());
+@@ -1269,27 +1266,38 @@ fs::path fs::temp_directory_path()
+
+ fs::path fs::temp_directory_path(error_code& ec)
+ {
++ path p;
+ #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+- ec = std::make_error_code(std::errc::not_supported);
+- return {}; // TODO
++ unsigned len = 1024;
++ std::wstring buf;
++ do
++ {
++ buf.resize(len);
++ len = GetTempPathW(buf.size(), buf.data());
++ } while (len > buf.size());
++
++ if (len == 0)
++ {
++ ec.assign((int)GetLastError(), std::system_category());
++ return p;
++ }
++ buf.resize(len);
++ p = std::move(buf);
+ #else
+ const char* tmpdir = nullptr;
+ const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
+ for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
+ tmpdir = ::getenv(*e);
+- path p = tmpdir ? tmpdir : "/tmp";
++ p = tmpdir ? tmpdir : "/tmp";
+ auto st = status(p, ec);
+- if (!ec)
++ if (ec)
++ p.clear();
++ else if (!is_directory(st))
+ {
+- if (is_directory(st))
+- {
+- ec.clear();
+- return p;
+- }
+- else
+- ec = std::make_error_code(std::errc::not_a_directory);
++ p.clear();
++ ec = std::make_error_code(std::errc::not_a_directory);
+ }
+- return {};
+ #endif
++ return p;
+ }
+
+diff --git a/libstdc++-v3/src/filesystem/path.cc b/libstdc++-v3/src/filesystem/path.cc
+index 899d94e0067..fb70d30fdca 100644
+--- a/libstdc++-v3/src/filesystem/path.cc
++++ b/libstdc++-v3/src/filesystem/path.cc
+@@ -61,6 +61,12 @@ path::replace_filename(const path& replacement)
+ return *this;
+ }
+
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++const fs::path::value_type dot = L'.';
++#else
++const fs::path::value_type dot = '.';
++#endif
++
+ path&
+ path::replace_extension(const path& replacement)
+ {
+@@ -78,8 +84,8 @@ path::replace_extension(const path& replacement)
+ _M_pathname.erase(back._M_pos + ext.second);
+ }
+ }
+- if (!replacement.empty() && replacement.native()[0] != '.')
+- _M_pathname += '.';
++ if (!replacement.empty() && replacement.native()[0] != dot)
++ _M_pathname += dot;
+ _M_pathname += replacement.native();
+ _M_split_cmpts();
+ return *this;
+@@ -297,7 +303,7 @@ path::has_filename() const
+ std::pair<const path::string_type*, std::size_t>
+ path::_M_find_extension() const
+ {
+- const std::string* s = nullptr;
++ const string_type* s = nullptr;
+
+ if (_M_type != _Type::_Multi)
+ s = &_M_pathname;
+@@ -312,14 +318,14 @@ path::_M_find_extension() const
+ {
+ if (auto sz = s->size())
+ {
+- if (sz <= 2 && (*s)[0] == '.')
++ if (sz <= 2 && (*s)[0] == dot)
+ {
+- if (sz == 1 || (*s)[1] == '.') // filename is "." or ".."
++ if (sz == 1 || (*s)[1] == dot) // filename is "." or ".."
+ return { s, string_type::npos };
+ else
+ return { s, 0 }; // filename is like ".?"
+ }
+- return { s, s->rfind('.') };
++ return { s, s->rfind(dot) };
+ }
+ }
+ return {};
+@@ -405,7 +411,7 @@ path::_M_split_cmpts()
+ {
+ const auto& last = _M_cmpts.back();
+ pos = last._M_pos + last._M_pathname.size();
+- _M_cmpts.emplace_back(string_type(1, '.'), _Type::_Filename, pos);
++ _M_cmpts.emplace_back(string_type(1, dot), _Type::_Filename, pos);
+ }
+ }
+
+@@ -495,8 +501,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+ std::string filesystem_error::_M_gen_what()
+ {
+ using std::filesystem::fs_err_concat;
+- return fs_err_concat(system_error::what(), _M_path1.native(),
+- _M_path2.native());
++ return fs_err_concat(system_error::what(), _M_path1.u8string(),
++ _M_path2.u8string());
+ }
+
+ _GLIBCXX_END_NAMESPACE_CXX11
+diff --git a/libstdc++-v3/src/filesystem/std-dir.cc b/libstdc++-v3/src/filesystem/std-dir.cc
+index 98eb22ab920..4c9a287ad80 100644
+--- a/libstdc++-v3/src/filesystem/std-dir.cc
++++ b/libstdc++-v3/src/filesystem/std-dir.cc
+@@ -37,6 +37,7 @@
+ #include "dir-common.h"
+
+ namespace fs = std::filesystem;
++namespace posix = std::filesystem::__gnu_posix;
+
+ struct fs::_Dir : _Dir_base
+ {
+@@ -47,7 +48,7 @@ struct fs::_Dir : _Dir_base
+ path = p;
+ }
+
+- _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
++ _Dir(posix::DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
+
+ _Dir(_Dir&&) = default;
+
+@@ -180,7 +181,7 @@ recursive_directory_iterator(const path& p, directory_options options,
+ error_code* ecptr)
+ : _M_options(options), _M_pending(true)
+ {
+- if (DIR* dirp = ::opendir(p.c_str()))
++ if (posix::DIR* dirp = posix::opendir(p.c_str()))
+ {
+ if (ecptr)
+ ecptr->clear();
+diff --git a/libstdc++-v3/src/filesystem/std-ops.cc b/libstdc++-v3/src/filesystem/std-ops.cc
+index c0742d73b5c..e266fa6d3f8 100644
+--- a/libstdc++-v3/src/filesystem/std-ops.cc
++++ b/libstdc++-v3/src/filesystem/std-ops.cc
+@@ -25,6 +25,7 @@
+ #ifndef _GLIBCXX_USE_CXX11_ABI
+ # define _GLIBCXX_USE_CXX11_ABI 1
+ # define NEED_DO_COPY_FILE
++# define NEED_DO_SPACE
+ #endif
+
+ #include <filesystem>
+@@ -52,19 +53,16 @@
+ #if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+ # include <utime.h> // utime
+ #endif
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++# include <windows.h>
++#endif
+
+ #define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
+ #define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
+ #include "ops-common.h"
+
+-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+-# undef utime
+-# define utime _wutime
+-# undef chmod
+-# define chmod _wchmod
+-#endif
+-
+ namespace fs = std::filesystem;
++namespace posix = std::filesystem::__gnu_posix;
+
+ fs::path
+ fs::absolute(const path& p)
+@@ -74,7 +72,7 @@ fs::absolute(const path& p)
+ path ret = absolute(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p,
+- std::make_error_code(errc::not_supported)));
++ ec));
+ return ret;
+ #else
+ return current_path() / p;
+@@ -90,17 +88,28 @@ fs::absolute(const path& p, error_code& ec)
+ ec = make_error_code(std::errc::no_such_file_or_directory);
+ return ret;
+ }
+- if (p.is_absolute())
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ const wstring& s = p.native();
++ uint32_t len = 1024;
++ wstring buf;
++ do
+ {
+- ec.clear();
+- ret = p;
+- return ret;
++ buf.resize(len);
++ len = GetFullPathNameW(s.c_str(), len, buf.data(), nullptr);
+ }
++ while (len > buf.size());
+
+-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+- ec = std::make_error_code(errc::not_supported);
++ if (len == 0)
++ ec.assign((int)GetLastError(), std::system_category());
++ else
++ {
++ ec.clear();
++ buf.resize(len);
++ ret = std::move(buf);
++ }
+ #else
+- ret = current_path(ec);
++ ec.clear();
++ ret = current_path();
+ ret /= p;
+ #endif
+ return ret;
+@@ -131,7 +140,7 @@ namespace
+ void operator()(void* p) const { ::free(p); }
+ };
+
+- using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
++ using char_ptr = std::unique_ptr<fs::path::value_type[], free_as_in_malloc>;
+ }
+
+ fs::path
+@@ -146,7 +155,8 @@ fs::canonical(const path& p, error_code& ec)
+ char_ptr buf{ nullptr };
+ # if _XOPEN_VERSION < 700
+ // Not safe to call realpath(path, NULL)
+- buf.reset( (char*)::malloc(PATH_MAX) );
++ using char_type = fs::path::value_type;
++ buf.reset( (char_type*)::malloc(PATH_MAX * sizeof(char_type)) );
+ # endif
+ if (char* rp = ::realpath(pa.c_str(), buf.get()))
+ {
+@@ -267,7 +277,7 @@ namespace std::filesystem
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ #ifdef NEED_DO_COPY_FILE
+ bool
+-fs::do_copy_file(const char* from, const char* to,
++fs::do_copy_file(const path::value_type* from, const path::value_type* to,
+ copy_options_existing_file options,
+ stat_type* from_st, stat_type* to_st,
+ std::error_code& ec) noexcept
+@@ -277,7 +287,7 @@ fs::do_copy_file(const char* from, const char* to,
+
+ if (to_st == nullptr)
+ {
+- if (::stat(to, &st1))
++ if (posix::stat(to, &st1))
+ {
+ const int err = errno;
+ if (!is_not_found_errno(err))
+@@ -299,7 +309,7 @@ fs::do_copy_file(const char* from, const char* to,
+
+ if (from_st == nullptr)
+ {
+- if (::stat(from, &st2))
++ if (posix::stat(from, &st2))
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+@@ -357,12 +367,12 @@ fs::do_copy_file(const char* from, const char* to,
+ }
+
+ struct CloseFD {
+- ~CloseFD() { if (fd != -1) ::close(fd); }
+- bool close() { return ::close(std::exchange(fd, -1)) == 0; }
++ ~CloseFD() { if (fd != -1) posix::close(fd); }
++ bool close() { return posix::close(std::exchange(fd, -1)) == 0; }
+ int fd;
+ };
+
+- CloseFD in = { ::open(from, O_RDONLY) };
++ CloseFD in = { posix::open(from, O_RDONLY) };
+ if (in.fd == -1)
+ {
+ ec.assign(errno, std::generic_category());
+@@ -373,7 +383,7 @@ fs::do_copy_file(const char* from, const char* to,
+ oflag |= O_TRUNC;
+ else
+ oflag |= O_EXCL;
+- CloseFD out = { ::open(to, oflag, S_IWUSR) };
++ CloseFD out = { posix::open(to, oflag, S_IWUSR) };
+ if (out.fd == -1)
+ {
+ if (errno == EEXIST && options.skip)
+@@ -383,12 +393,12 @@ fs::do_copy_file(const char* from, const char* to,
+ return false;
+ }
+
+-#ifdef _GLIBCXX_USE_FCHMOD
++#if defined _GLIBCXX_USE_FCHMOD && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (::fchmod(out.fd, from_st->st_mode))
+-#elif defined _GLIBCXX_USE_FCHMODAT
++#elif defined _GLIBCXX_USE_FCHMODAT && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
+ #else
+- if (::chmod(to, from_st->st_mode))
++ if (posix::chmod(to, from_st->st_mode))
+ #endif
+ {
+ ec.assign(errno, std::generic_category());
+@@ -396,7 +406,7 @@ fs::do_copy_file(const char* from, const char* to,
+ }
+
+ size_t count = from_st->st_size;
+-#ifdef _GLIBCXX_USE_SENDFILE
++#if defined _GLIBCXX_USE_SENDFILE && ! defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ off_t offset = 0;
+ ssize_t n = ::sendfile(out.fd, in.fd, &offset, count);
+ if (n < 0 && errno != ENOSYS && errno != EINVAL)
+@@ -475,15 +485,15 @@ fs::copy(const path& from, const path& to, copy_options options,
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2681. filesystem::copy() cannot copy symlinks
+ if (use_lstat || copy_symlinks
+- ? ::lstat(from.c_str(), &from_st)
+- : ::stat(from.c_str(), &from_st))
++ ? posix::lstat(from.c_str(), &from_st)
++ : posix::stat(from.c_str(), &from_st))
+ {
+ ec.assign(errno, std::generic_category());
+ return;
+ }
+ if (use_lstat
+- ? ::lstat(to.c_str(), &to_st)
+- : ::stat(to.c_str(), &to_st))
++ ? posix::lstat(to.c_str(), &to_st)
++ : posix::stat(to.c_str(), &to_st))
+ {
+ if (!is_not_found_errno(errno))
+ {
+@@ -636,74 +646,38 @@ fs::create_directories(const path& p, error_code& ec)
+ ec = std::make_error_code(errc::invalid_argument);
+ return false;
+ }
+-
+- file_status st = symlink_status(p, ec);
+- if (is_directory(st))
+- return false;
+- else if (ec && !status_known(st))
+- return false;
+- else if (exists(st))
+- {
+- if (!ec)
+- ec = std::make_error_code(std::errc::not_a_directory);
+- return false;
+- }
+-
+ std::stack<path> missing;
+ path pp = p;
+
+- // Strip any trailing slash
+- if (pp.has_relative_path() && !pp.has_filename())
+- pp = pp.parent_path();
+-
+- do
++ while (pp.has_filename() && status(pp, ec).type() == file_type::not_found)
+ {
++ ec.clear();
+ const auto& filename = pp.filename();
+- if (is_dot(filename) || is_dotdot(filename))
+- pp = pp.parent_path();
+- else
+- {
+- missing.push(std::move(pp));
+- if (missing.size() > 1000) // sanity check
+- {
+- ec = std::make_error_code(std::errc::filename_too_long);
+- return false;
+- }
+- pp = missing.top().parent_path();
+- }
++ if (!is_dot(filename) && !is_dotdot(filename))
++ missing.push(pp);
++ pp = pp.parent_path();
+
+- if (pp.empty())
+- break;
+-
+- st = status(pp, ec);
+- if (exists(st))
++ if (missing.size() > 1000) // sanity check
+ {
+- if (ec)
+- return false;
+- if (!is_directory(st))
+- {
+- ec = std::make_error_code(std::errc::not_a_directory);
+- return false;
+- }
++ ec = std::make_error_code(std::errc::filename_too_long);
++ return false;
+ }
+-
+- if (ec && exists(st))
+- return false;
+ }
+- while (st.type() == file_type::not_found);
+
+- bool created;
++ if (ec || missing.empty())
++ return false;
++
+ do
+ {
+ const path& top = missing.top();
+- created = create_directory(top, ec);
+- if (ec)
+- return false;
++ create_directory(top, ec);
++ if (ec && is_directory(top))
++ ec.clear();
+ missing.pop();
+ }
+- while (!missing.empty());
++ while (!missing.empty() && !ec);
+
+- return created;
++ return missing.empty();
+ }
+
+ namespace
+@@ -713,8 +687,9 @@ namespace
+ {
+ bool created = false;
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+- ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
+- if (::mkdir(p.c_str(), mode))
++ posix::mode_t mode
++ = static_cast<std::underlying_type_t<fs::perms>>(perm);
++ if (posix::mkdir(p.c_str(), mode))
+ {
+ const int err = errno;
+ if (err != EEXIST || !is_directory(p, ec))
+@@ -767,7 +742,7 @@ fs::create_directory(const path& p, const path& attributes,
+ {
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ stat_type st;
+- if (::stat(attributes.c_str(), &st))
++ if (posix::stat(attributes.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+@@ -809,18 +784,23 @@ fs::create_hard_link(const path& to, const path& new_hard_link)
+ create_hard_link(to, new_hard_link, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
+- to, new_hard_link, ec));
++ to, new_hard_link, ec));
+ }
+
+ void
+ fs::create_hard_link(const path& to, const path& new_hard_link,
+ error_code& ec) noexcept
+ {
+-#ifdef _GLIBCXX_HAVE_UNISTD_H
++#ifdef _GLIBCXX_HAVE_LINK
+ if (::link(to.c_str(), new_hard_link.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
++#elif defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ if (CreateHardLinkW(new_hard_link.c_str(), to.c_str(), NULL))
++ ec.clear();
++ else
++ ec.assign((int)GetLastError(), generic_category());
+ #else
+ ec = std::make_error_code(std::errc::not_supported);
+ #endif
+@@ -840,7 +820,7 @@ void
+ fs::create_symlink(const path& to, const path& new_symlink,
+ error_code& ec) noexcept
+ {
+-#ifdef _GLIBCXX_HAVE_UNISTD_H
++#ifdef _GLIBCXX_HAVE_SYMLINK
+ if (::symlink(to.c_str(), new_symlink.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+@@ -866,8 +846,8 @@ fs::current_path(error_code& ec)
+ {
+ path p;
+ #ifdef _GLIBCXX_HAVE_UNISTD_H
+-#ifdef __GLIBC__
+- if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
++#if defined __GLIBC__ || defined _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ if (char_ptr cwd = char_ptr{posix::getcwd(nullptr, 0)})
+ {
+ p.assign(cwd.get());
+ ec.clear();
+@@ -875,6 +855,7 @@ fs::current_path(error_code& ec)
+ else
+ ec.assign(errno, std::generic_category());
+ #else
++#ifdef _PC_PATH_MAX
+ long path_max = pathconf(".", _PC_PATH_MAX);
+ size_t size;
+ if (path_max == -1)
+@@ -883,9 +864,15 @@ fs::current_path(error_code& ec)
+ size = 10240;
+ else
+ size = path_max;
++#elif defined(PATH_MAX)
++ size_t size = PATH_MAX;
++#else
++ size_t size = 1024;
++#endif
+ for (char_ptr buf; p.empty(); size *= 2)
+ {
+- buf.reset((char*)malloc(size));
++ using char_type = fs::path::value_type;
++ buf.reset((char_type*)malloc(size * sizeof(char_type)));
+ if (buf)
+ {
+ if (getcwd(buf.get(), size))
+@@ -925,7 +912,7 @@ void
+ fs::current_path(const path& p, error_code& ec) noexcept
+ {
+ #ifdef _GLIBCXX_HAVE_UNISTD_H
+- if (::chdir(p.c_str()))
++ if (posix::chdir(p.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+@@ -952,14 +939,14 @@ fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
+ int err = 0;
+ file_status s1, s2;
+ stat_type st1, st2;
+- if (::stat(p1.c_str(), &st1) == 0)
++ if (posix::stat(p1.c_str(), &st1) == 0)
+ s1 = make_file_status(st1);
+ else if (is_not_found_errno(errno))
+ s1.type(file_type::not_found);
+ else
+ err = errno;
+
+- if (::stat(p2.c_str(), &st2) == 0)
++ if (posix::stat(p2.c_str(), &st2) == 0)
+ s2 = make_file_status(st2);
+ else if (is_not_found_errno(errno))
+ s2.type(file_type::not_found);
+@@ -1008,8 +995,8 @@ namespace
+ do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
+ {
+ #ifdef _GLIBCXX_HAVE_SYS_STAT_H
+- fs::stat_type st;
+- if (::stat(p.c_str(), &st))
++ posix::stat_type st;
++ if (posix::stat(p.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return deflt;
+@@ -1059,7 +1046,7 @@ fs::hard_link_count(const path& p)
+ std::uintmax_t
+ fs::hard_link_count(const path& p, error_code& ec) noexcept
+ {
+- return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
++ return do_stat(p, ec, std::mem_fn(&stat_type::st_nlink),
+ static_cast<uintmax_t>(-1));
+ }
+
+@@ -1135,11 +1122,11 @@ fs::last_write_time(const path& p __attribute__((__unused__)),
+ else
+ ec.clear();
+ #elif _GLIBCXX_HAVE_UTIME_H
+- ::utimbuf times;
++ posix::utimbuf times;
+ times.modtime = s.count();
+ times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
+ times.modtime);
+- if (::utime(p.c_str(), &times))
++ if (posix::utime(p.c_str(), &times))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+@@ -1194,7 +1181,7 @@ fs::permissions(const path& p, perms prms, perm_options opts,
+ #else
+ if (nofollow && is_symlink(st))
+ ec = std::make_error_code(std::errc::operation_not_supported);
+- else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
++ else if (posix::chmod(p.c_str(), static_cast<mode_t>(prms)))
+ err = errno;
+ #endif
+
+@@ -1234,10 +1221,10 @@ fs::read_symlink(const path& p)
+ return tgt;
+ }
+
+-fs::path fs::read_symlink(const path& p, error_code& ec)
++fs::path fs::read_symlink(const path& p [[gnu::unused]], error_code& ec)
+ {
+ path result;
+-#ifdef _GLIBCXX_HAVE_SYS_STAT_H
++#if defined(_GLIBCXX_HAVE_READLINK) && defined(_GLIBCXX_HAVE_SYS_STAT_H)
+ stat_type st;
+ if (::lstat(p.c_str(), &st))
+ {
+@@ -1310,6 +1297,19 @@ fs::remove(const path& p)
+ bool
+ fs::remove(const path& p, error_code& ec) noexcept
+ {
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ if (exists(symlink_status(p, ec)))
++ {
++ if ((is_directory(p, ec) && RemoveDirectoryW(p.c_str()))
++ || DeleteFileW(p.c_str()))
++ {
++ ec.clear();
++ return true;
++ }
++ else if (!ec)
++ ec.assign((int)GetLastError(), generic_category());
++ }
++#else
+ if (::remove(p.c_str()) == 0)
+ {
+ ec.clear();
+@@ -1319,6 +1319,7 @@ fs::remove(const path& p, error_code& ec) noexcept
+ ec.clear();
+ else
+ ec.assign(errno, std::generic_category());
++#endif
+ return false;
+ }
+
+@@ -1372,7 +1373,7 @@ fs::rename(const path& from, const path& to)
+ void
+ fs::rename(const path& from, const path& to, error_code& ec) noexcept
+ {
+- if (::rename(from.c_str(), to.c_str()))
++ if (posix::rename(from.c_str(), to.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+@@ -1393,7 +1394,7 @@ fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
+ #ifdef _GLIBCXX_HAVE_UNISTD_H
+ if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
+ ec.assign(EINVAL, std::generic_category());
+- else if (::truncate(p.c_str(), size))
++ else if (posix::truncate(p.c_str(), size))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+@@ -1413,31 +1414,67 @@ fs::space(const path& p)
+ return s;
+ }
+
+-fs::space_info
+-fs::space(const path& p, error_code& ec) noexcept
++#ifdef NEED_DO_SPACE
++void
++fs::do_space(const __gnu_posix::char_type* pathname,
++ uintmax_t& capacity, uintmax_t& free, uintmax_t& available,
++ std::error_code& ec)
+ {
+- space_info info = {
+- static_cast<uintmax_t>(-1),
+- static_cast<uintmax_t>(-1),
+- static_cast<uintmax_t>(-1)
+- };
+ #ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+ struct ::statvfs f;
+- if (::statvfs(p.c_str(), &f))
++ if (::statvfs(pathname, &f))
+ ec.assign(errno, std::generic_category());
+ else
+ {
+- uintmax_t fragment_size = f.f_frsize;
+- info = space_info{
+- f.f_blocks * fragment_size,
+- f.f_bfree * fragment_size,
+- f.f_bavail * fragment_size
+- };
++ if (f.f_frsize != (unsigned long)-1)
++ {
++ const uintmax_t fragment_size = f.f_frsize;
++ const fsblkcnt_t unknown = -1;
++ if (f.f_blocks != unknown)
++ capacity = f.f_blocks * fragment_size;
++ if (f.f_bfree != unknown)
++ free = f.f_bfree * fragment_size;
++ if (f.f_bavail != unknown)
++ available = f.f_bavail * fragment_size;
++ }
+ ec.clear();
+ }
++#elif _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ ULARGE_INTEGER bytes_avail = {}, bytes_total = {}, bytes_free = {};
++ if (GetDiskFreeSpaceExW(pathname, &bytes_avail, &bytes_total, &bytes_free))
++ {
++ if (bytes_total.QuadPart != 0)
++ capacity = bytes_total.QuadPart;
++ if (bytes_free.QuadPart != 0)
++ free = bytes_free.QuadPart;
++ if (bytes_avail.QuadPart != 0)
++ available = bytes_avail.QuadPart;
++ ec.clear();
++ }
++ else
++ ec.assign((int)GetLastError(), std::system_category());
+ #else
+ ec = std::make_error_code(std::errc::not_supported);
+ #endif
++}
++#endif // NEED_DO_SPACE
++
++fs::space_info
++fs::space(const path& p, error_code& ec) noexcept
++{
++ space_info info = {
++ static_cast<uintmax_t>(-1),
++ static_cast<uintmax_t>(-1),
++ static_cast<uintmax_t>(-1)
++ };
++#if _GLIBCXX_FILESYSTEM_IS_WINDOWS
++ path dir = absolute(p);
++ dir.remove_filename();
++ auto str = dir.c_str();
++#else
++ auto str = p.c_str();
++#endif
++ do_space(str, info.capacity, info.free, info.available, ec);
+ return info;
+ }
+
+@@ -1447,7 +1484,7 @@ fs::status(const fs::path& p, error_code& ec) noexcept
+ {
+ file_status status;
+ stat_type st;
+- if (::stat(p.c_str(), &st))
++ if (posix::stat(p.c_str(), &st))
+ {
+ int err = errno;
+ ec.assign(err, std::generic_category());
+@@ -1471,7 +1508,7 @@ fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
+ {
+ file_status status;
+ stat_type st;
+- if (::lstat(p.c_str(), &st))
++ if (posix::lstat(p.c_str(), &st))
+ {
+ int err = errno;
+ ec.assign(err, std::generic_category());
+@@ -1518,28 +1555,39 @@ fs::path fs::temp_directory_path()
+
+ fs::path fs::temp_directory_path(error_code& ec)
+ {
++ path p;
+ #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+- ec = std::make_error_code(std::errc::not_supported);
+- return {}; // TODO
++ unsigned len = 1024;
++ std::wstring buf;
++ do
++ {
++ buf.resize(len);
++ len = GetTempPathW(buf.size(), buf.data());
++ } while (len > buf.size());
++
++ if (len == 0)
++ {
++ ec.assign((int)GetLastError(), std::system_category());
++ return p;
++ }
++ buf.resize(len);
++ p = std::move(buf);
+ #else
+ const char* tmpdir = nullptr;
+ const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
+ for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
+ tmpdir = ::getenv(*e);
+- path p = tmpdir ? tmpdir : "/tmp";
++ p = tmpdir ? tmpdir : "/tmp";
++#endif
+ auto st = status(p, ec);
+- if (!ec)
++ if (ec)
++ p.clear();
++ else if (!is_directory(st))
+ {
+- if (is_directory(st))
+- {
+- ec.clear();
+- return p;
+- }
+- else
+- ec = std::make_error_code(std::errc::not_a_directory);
++ p.clear();
++ ec = std::make_error_code(std::errc::not_a_directory);
+ }
+- return {};
+-#endif
++ return p;
+ }
+
+ fs::path
+diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc
+index c5bf8099036..f6c0b8bb0f6 100644
+--- a/libstdc++-v3/src/filesystem/std-path.cc
++++ b/libstdc++-v3/src/filesystem/std-path.cc
+@@ -38,6 +38,66 @@ fs::filesystem_error::~filesystem_error() = default;
+
+ constexpr path::value_type path::preferred_separator;
+
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++path&
++path::operator/=(const path& __p)
++{
++ if (__p.is_absolute()
++ || (__p.has_root_name() && __p.root_name() != root_name()))
++ return operator=(__p);
++
++ basic_string_view<value_type> __lhs = _M_pathname;
++ bool __add_sep = false;
++
++ if (__p.has_root_directory())
++ {
++ // Remove any root directory and relative path
++ if (_M_type != _Type::_Root_name)
++ {
++ if (!_M_cmpts.empty()
++ && _M_cmpts.front()._M_type == _Type::_Root_name)
++ __lhs = _M_cmpts.front()._M_pathname;
++ else
++ __lhs = {};
++ }
++ }
++ else if (has_filename() || (!has_root_directory() && is_absolute()))
++ __add_sep = true;
++
++ basic_string_view<value_type> __rhs = __p._M_pathname;
++ // Omit any root-name from the generic format pathname:
++ if (__p._M_type == _Type::_Root_name)
++ __rhs = {};
++ else if (!__p._M_cmpts.empty()
++ && __p._M_cmpts.front()._M_type == _Type::_Root_name)
++ __rhs.remove_prefix(__p._M_cmpts.front()._M_pathname.size());
++
++ const size_t __len = __lhs.size() + (int)__add_sep + __rhs.size();
++ const size_t __maxcmpts = _M_cmpts.size() + __p._M_cmpts.size();
++ if (_M_pathname.capacity() < __len || _M_cmpts.capacity() < __maxcmpts)
++ {
++ // Construct new path and swap (strong exception-safety guarantee).
++ string_type __tmp;
++ __tmp.reserve(__len);
++ __tmp = __lhs;
++ if (__add_sep)
++ __tmp += preferred_separator;
++ __tmp += __rhs;
++ path __newp = std::move(__tmp);
++ swap(__newp);
++ }
++ else
++ {
++ _M_pathname = __lhs;
++ if (__add_sep)
++ _M_pathname += preferred_separator;
++ _M_pathname += __rhs;
++ _M_split_cmpts();
++ }
++ return *this;
++}
++#endif
++
+ path&
+ path::remove_filename()
+ {
+@@ -74,6 +134,12 @@ path::replace_filename(const path& replacement)
+ return *this;
+ }
+
++#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
++const fs::path::value_type dot = L'.';
++#else
++const fs::path::value_type dot = '.';
++#endif
++
+ path&
+ path::replace_extension(const path& replacement)
+ {
+@@ -85,18 +151,17 @@ path::replace_extension(const path& replacement)
+ _M_pathname.erase(ext.second);
+ else
+ {
+- auto& back = _M_cmpts.back();
++ const auto& back = _M_cmpts.back();
+ if (ext.first != &back._M_pathname)
+ _GLIBCXX_THROW_OR_ABORT(
+ std::logic_error("path::replace_extension failed"));
+- back._M_pathname.erase(ext.second);
+ _M_pathname.erase(back._M_pos + ext.second);
+ }
+ }
+ // If replacement is not empty and does not begin with a dot character,
+ // a dot character is appended
+- if (!replacement.empty() && replacement.native()[0] != '.')
+- _M_pathname += '.';
++ if (!replacement.empty() && replacement.native()[0] != dot)
++ _M_pathname += dot;
+ operator+=(replacement);
+ return *this;
+ }
+@@ -333,11 +398,7 @@ path::has_filename() const
+
+ namespace
+ {
+-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+- inline bool is_dot(wchar_t c) { return c == L'.'; }
+-#else
+- inline bool is_dot(char c) { return c == '.'; }
+-#endif
++ inline bool is_dot(fs::path::value_type c) { return c == dot; }
+
+ inline bool is_dot(const fs::path& path)
+ {
+@@ -377,7 +438,7 @@ path::lexically_normal() const
+ {
+ #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ // Replace each slash character in the root-name
+- if (p._M_type == _Type::_Root_name || p._M_type == _Type::_Root_dir)
++ if (p._M_type == _Type::_Root_name)
+ {
+ string_type s = p.native();
+ std::replace(s.begin(), s.end(), L'/', L'\\');
+@@ -397,8 +458,7 @@ path::lexically_normal() const
+ }
+ else if (!ret.has_relative_path())
+ {
+- // remove a dot-dot filename immediately after root-directory
+- if (!ret.has_root_directory())
++ if (!ret.is_absolute())
+ ret /= p;
+ }
+ else
+@@ -406,30 +466,15 @@ path::lexically_normal() const
+ // Got a path with a relative path (i.e. at least one non-root
+ // element) and no filename at the end (i.e. empty last element),
+ // so must have a trailing slash. See what is before it.
+- auto elem = ret._M_cmpts.end() - 2;
++ auto elem = std::prev(ret.end(), 2);
+ if (elem->has_filename() && !is_dotdot(*elem))
+ {
+ // Remove the filename before the trailing slash
+ // (equiv. to ret = ret.parent_path().remove_filename())
+-
+- if (elem == ret._M_cmpts.begin())
+- ret.clear();
+- else
+- {
+- ret._M_pathname.erase(elem->_M_pos);
+- // Remove empty filename at the end:
+- ret._M_cmpts.pop_back();
+- // If we still have a trailing non-root dir separator
+- // then leave an empty filename at the end:
+- if (std::prev(elem)->_M_type == _Type::_Filename)
+- elem->clear();
+- else // remove the component completely:
+- ret._M_cmpts.pop_back();
+- }
++ ret._M_pathname.erase(elem._M_cur->_M_pos);
++ ret._M_cmpts.erase(elem._M_cur, ret._M_cmpts.end());
+ }
+- else
+- // Append the ".." to something ending in "../" which happens
+- // when normalising paths like ".././.." and "../a/../.."
++ else // ???
+ ret /= p;
+ }
+ }
+@@ -475,12 +520,10 @@ path::lexically_relative(const path& base) const
+ const path& p = *b;
+ if (is_dotdot(p))
+ --n;
+- else if (!p.empty() && !is_dot(p))
++ else if (!is_dot(p))
+ ++n;
+ }
+- if (n == 0 && (a == end() || a->empty()))
+- ret = ".";
+- else if (n >= 0)
++ if (n >= 0)
+ {
+ const path dotdot("..");
+ while (n--)
+@@ -504,7 +547,7 @@ path::lexically_proximate(const path& base) const
+ std::pair<const path::string_type*, std::size_t>
+ path::_M_find_extension() const
+ {
+- const std::string* s = nullptr;
++ const string_type* s = nullptr;
+
+ if (_M_type == _Type::_Filename)
+ s = &_M_pathname;
+@@ -519,9 +562,9 @@ path::_M_find_extension() const
+ {
+ if (auto sz = s->size())
+ {
+- if (sz <= 2 && (*s)[0] == '.')
++ if (sz <= 2 && (*s)[0] == dot)
+ return { s, string_type::npos };
+- const auto pos = s->rfind('.');
++ const auto pos = s->rfind(dot);
+ return { s, pos ? pos : string_type::npos };
+ }
+ }
+@@ -722,8 +765,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+ std::string filesystem_error::_M_gen_what()
+ {
+- return fs_err_concat(system_error::what(), _M_path1.native(),
+- _M_path2.native());
++ return fs_err_concat(system_error::what(), _M_path1.u8string(),
++ _M_path2.u8string());
+ }
+
+ _GLIBCXX_END_NAMESPACE_CXX11
+--
+2.20.1
+
diff --git a/PATCHES/mingw-tools-widl-realloc.patch b/PATCHES/mingw-tools-widl-realloc.patch
new file mode 100644
index 0000000..9bbc038
--- /dev/null
+++ b/PATCHES/mingw-tools-widl-realloc.patch
@@ -0,0 +1,11 @@
+--- configure.ac.orig 2019-05-29 13:55:23.831832920 +0200
++++ configure.ac 2019-05-29 13:55:35.659368564 +0200
+@@ -48,7 +48,7 @@
+ # Checks for library functions.
+ AC_FUNC_ERROR_AT_LINE
+ AC_FUNC_MALLOC
+-AC_FUNC_REALLOC
++#AC_FUNC_REALLOC
+ AC_FUNC_STRTOD
+ AC_CHECK_FUNCS([atexit gettimeofday getopt_long_only memmove memset mkstemps strcasecmp strchr strdup strerror strncasecmp strrchr strtol strtoul strtoull])
+
diff --git a/PATCHES/windows-lrealpath-no-force-lowercase-nor-backslash.patch b/PATCHES/windows-lrealpath-no-force-lowercase-nor-backslash.patch
deleted file mode 100644
index 697469d..0000000
--- a/PATCHES/windows-lrealpath-no-force-lowercase-nor-backslash.patch
+++ /dev/null
@@ -1,34 +0,0 @@
-diff -ruNb gcc-7.1.0.orig/libiberty/lrealpath.c gcc-7.1.0/libiberty/lrealpath.c
---- gcc-7.1.0.orig/libiberty/lrealpath.c 2017-01-04 12:30:51.000000000 +0100
-+++ gcc-7.1.0/libiberty/lrealpath.c 2017-05-28 00:13:05.844315144 +0200
-@@ -138,15 +138,26 @@
- {
- char buf[MAX_PATH];
- char* basename;
-+ char* slash;
- DWORD len = GetFullPathName (filename, MAX_PATH, buf, &basename);
- if (len == 0 || len > MAX_PATH - 1)
- return strdup (filename);
- else
- {
-- /* The file system is case-preserving but case-insensitive,
-- Canonicalize to lowercase, using the codepage associated
-- with the process locale. */
-- CharLowerBuff (buf, len);
-+ /* Turn all back slashes back back into forward slashes
-+ and don't make it all lowercase.
-+ Rationale:
-+ Windows is as happy with / as it is with \. This will
-+ have been built using Cygwin, MSYS* or cross-compiled
-+ from a system where dirsep is / so it is cleaner just
-+ to keep the dirseps as / (and the case un-modified).
-+ This way, the value will be consistent with the build
-+ system and string operations (be they internal to this
-+ software or external to it, e.g. processing map files
-+ with sed) work as expected. */
-+ slash = buf;
-+ while ((slash = strchr(slash,'\\')) != NULL)
-+ *slash = '/';
- return strdup (buf);
- }
- }