Implement <filesystem>

This patch implements the <filesystem> header and uses that
to provide <experimental/filesystem>.

Unlike other standard headers, the symbols needed for <filesystem>
have not yet been placed in libc++.so. Instead they live in the
new libc++fs.a library. Users of filesystem are required to link this
library. (Also note that libc++experimental no longer contains the
definition of <experimental/filesystem>, which now requires linking libc++fs).

The reason for keeping <filesystem> out of the dylib for now is that
it's still somewhat experimental, and the possibility of requiring an
ABI breaking change is very real. In the future the symbols will likely
be moved into the dylib, or the dylib will be made to link libc++fs automagically).

Note that moving the symbols out of libc++experimental may break user builds
until they update to -lc++fs. This should be OK, because the experimental
library provides no stability guarantees. However, I plan on looking into
ways we can force libc++experimental to automagically link libc++fs.

In order to use a single implementation and set of tests for <filesystem>, it
has been placed in a special `__fs` namespace. This namespace is inline in
C++17 onward, but not before that. As such implementation is available
in C++11 onward, but no filesystem namespace is present "directly", and
as such name conflicts shouldn't occur in C++11 or C++14.

llvm-svn: 338093
Cr-Mirrored-From: sso://chromium.googlesource.com/_direct/external/github.com/llvm/llvm-project
Cr-Mirrored-Commit: 998a5c88312066fcc2b2de1358edc76587611354
diff --git a/include/fstream b/include/fstream
index 8b9aefa..332b474 100644
--- a/include/fstream
+++ b/include/fstream
@@ -38,6 +38,7 @@
     bool is_open() const;
     basic_filebuf* open(const char* s, ios_base::openmode mode);
     basic_filebuf* open(const string& s, ios_base::openmode mode);
+    basic_filebuf* open(const filesystem::path& p, ios_base::openmode mode); // C++17
     basic_filebuf* close();
 
 protected:
@@ -77,6 +78,8 @@
     basic_ifstream();
     explicit basic_ifstream(const char* s, ios_base::openmode mode = ios_base::in);
     explicit basic_ifstream(const string& s, ios_base::openmode mode = ios_base::in);
+    explicit basic_ifstream(const filesystem::path& p,
+                            ios_base::openmode mode = ios_base::in); // C++17
     basic_ifstream(basic_ifstream&& rhs);
 
     basic_ifstream& operator=(basic_ifstream&& rhs);
@@ -86,6 +89,8 @@
     bool is_open() const;
     void open(const char* s, ios_base::openmode mode = ios_base::in);
     void open(const string& s, ios_base::openmode mode = ios_base::in);
+    void open(const filesystem::path& s, ios_base::openmode mode = ios_base::in); // C++17
+
     void close();
 };
 
@@ -110,6 +115,8 @@
     basic_ofstream();
     explicit basic_ofstream(const char* s, ios_base::openmode mode = ios_base::out);
     explicit basic_ofstream(const string& s, ios_base::openmode mode = ios_base::out);
+    explicit basic_ofstream(const filesystem::path& p,
+                            ios_base::openmode mode = ios_base::out); // C++17
     basic_ofstream(basic_ofstream&& rhs);
 
     basic_ofstream& operator=(basic_ofstream&& rhs);
@@ -119,6 +126,9 @@
     bool is_open() const;
     void open(const char* s, ios_base::openmode mode = ios_base::out);
     void open(const string& s, ios_base::openmode mode = ios_base::out);
+    void open(const filesystem::path& p,
+              ios_base::openmode mode = ios_base::out); // C++17
+
     void close();
 };
 
@@ -143,6 +153,8 @@
     basic_fstream();
     explicit basic_fstream(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
     explicit basic_fstream(const string& s, ios_base::openmode mode = ios_base::in|ios_base::out);
+    explicit basic_fstream(const filesystem::path& p,
+                           ios_base::openmode mode = ios_base::in|ios_base::out); C++17
     basic_fstream(basic_fstream&& rhs);
 
     basic_fstream& operator=(basic_fstream&& rhs);
@@ -152,6 +164,9 @@
     bool is_open() const;
     void open(const char* s, ios_base::openmode mode = ios_base::in|ios_base::out);
     void open(const string& s, ios_base::openmode mode = ios_base::in|ios_base::out);
+    void open(const filesystem::path& s,
+              ios_base::openmode mode = ios_base::in|ios_base::out); // C++17
+
     void close();
 };
 
@@ -171,6 +186,7 @@
 #include <__locale>
 #include <cstdio>
 #include <cstdlib>
+#include <filesystem>
 
 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
 #pragma GCC system_header
@@ -219,6 +235,12 @@
     _LIBCPP_INLINE_VISIBILITY
     basic_filebuf* open(const string& __s, ios_base::openmode __mode);
 
+#if _LIBCPP_STD_VER >= 17
+    _LIBCPP_INLINE_VISIBILITY
+    basic_filebuf* open(const _VSTD_FS::path& __p, ios_base::openmode __mode) {
+      return open(__p.c_str(), __mode);
+    }
+#endif
     _LIBCPP_INLINE_VISIBILITY
     basic_filebuf* __open(int __fd, ios_base::openmode __mode);
 #endif
@@ -1128,6 +1150,11 @@
 #endif
     _LIBCPP_INLINE_VISIBILITY
     explicit basic_ifstream(const string& __s, ios_base::openmode __mode = ios_base::in);
+#if _LIBCPP_STD_VER >= 17
+    _LIBCPP_INLINE_VISIBILITY
+    explicit basic_ifstream(const filesystem::path& __p, ios_base::openmode __mode = ios_base::in)
+      : basic_ifstream(__p.c_str(), __mode) {}
+#endif // _LIBCPP_STD_VER >= 17
 #endif
 #ifndef _LIBCPP_CXX03_LANG
     _LIBCPP_INLINE_VISIBILITY
@@ -1149,6 +1176,13 @@
     void open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in);
 #endif
     void open(const string& __s, ios_base::openmode __mode = ios_base::in);
+#if _LIBCPP_STD_VER >= 17
+    _LIBCPP_INLINE_VISIBILITY
+    void open(const filesystem::path& __p,
+              ios_base::openmode __mode = ios_base::in) {
+      return open(__p.c_str(), __mode);
+    }
+#endif // _LIBCPP_STD_VER >= 17
 
     _LIBCPP_INLINE_VISIBILITY
     void __open(int __fd, ios_base::openmode __mode);
@@ -1329,6 +1363,13 @@
 #endif
     _LIBCPP_INLINE_VISIBILITY
     explicit basic_ofstream(const string& __s, ios_base::openmode __mode = ios_base::out);
+
+#if _LIBCPP_STD_VER >= 17
+    _LIBCPP_INLINE_VISIBILITY
+    explicit basic_ofstream(const filesystem::path& __p, ios_base::openmode __mode = ios_base::out)
+      : basic_ofstream(__p.c_str(), __mode) {}
+#endif // _LIBCPP_STD_VER >= 17
+
 #ifndef _LIBCPP_CXX03_LANG
     _LIBCPP_INLINE_VISIBILITY
     basic_ofstream(basic_ofstream&& __rhs);
@@ -1350,6 +1391,12 @@
 #endif
     void open(const string& __s, ios_base::openmode __mode = ios_base::out);
 
+#if _LIBCPP_STD_VER >= 17
+    _LIBCPP_INLINE_VISIBILITY
+    void open(const filesystem::path& __p, ios_base::openmode __mode = ios_base::out)
+    { return open(__p.c_str(), __mode); }
+#endif // _LIBCPP_STD_VER >= 17
+
     _LIBCPP_INLINE_VISIBILITY
     void __open(int __fd, ios_base::openmode __mode);
 #endif
@@ -1530,6 +1577,13 @@
 #endif
     _LIBCPP_INLINE_VISIBILITY
     explicit basic_fstream(const string& __s, ios_base::openmode __mode = ios_base::in | ios_base::out);
+
+#if _LIBCPP_STD_VER >= 17
+    _LIBCPP_INLINE_VISIBILITY
+    explicit basic_fstream(const filesystem::path& __p, ios_base::openmode __mode = ios_base::in | ios_base::out)
+      : basic_fstream(__p.c_str(), __mode) {}
+#endif // _LIBCPP_STD_VER >= 17
+
 #endif
 #ifndef _LIBCPP_CXX03_LANG
     _LIBCPP_INLINE_VISIBILITY
@@ -1551,6 +1605,13 @@
     void open(const wchar_t* __s, ios_base::openmode __mode = ios_base::in | ios_base::out);
 #endif
     void open(const string& __s, ios_base::openmode __mode = ios_base::in | ios_base::out);
+
+#if _LIBCPP_STD_VER >= 17
+    _LIBCPP_INLINE_VISIBILITY
+    void open(const filesystem::path& __p, ios_base::openmode __mode = ios_base::in|ios_base::out)
+    { return open(__p.c_str(), __mode); }
+#endif // _LIBCPP_STD_VER >= 17
+
 #endif
     _LIBCPP_INLINE_VISIBILITY
     void close();