diff --git a/libcxx/include/__locale b/libcxx/include/__locale
index d382e4d8a94be..6aeddf29ecbe2 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -1352,6 +1352,32 @@ struct _LIBCPP_TEMPLATE_VIS __narrow_to_utf8<32>
     }
 };
 
+template<class _InternT, class _ExternT, class _StateT, class _OutputIterator>
+inline _LIBCPP_INLINE_VISIBILITY
+_OutputIterator 
+__widen_using_codecvt(codecvt<_InternT, _ExternT, _StateT> const& __cvt, 
+                             _OutputIterator __s, 
+                             const char* __nb, const char* __ne)
+{
+    codecvt_base::result __r = codecvt_base::ok;
+    mbstate_t __mb;
+    while (__nb < __ne && __r != codecvt_base::error)
+    {
+        const int __sz = 32;
+        _InternT __buf[__sz];
+        _InternT* __bn;
+        const char* __nn = __nb;
+        __r = __cvt.in(__mb, __nb, __ne - __nb > __sz ? __nb+__sz : __ne, __nn,
+                    __buf, __buf+__sz, __bn);
+        if (__r == codecvt_base::error || __nn == __nb)
+            __throw_runtime_error("locale not supported");
+        for (const _InternT* __p = __buf; __p < __bn; ++__p, ++__s)
+            *__s = (wchar_t)*__p;
+        __nb = __nn;
+    }
+    return __s;
+}
+
 template <size_t _Np>
 struct __widen_from_utf8
 {
@@ -1388,23 +1414,7 @@ struct _LIBCPP_TEMPLATE_VIS __widen_from_utf8<16>
     _OutputIterator
     operator()(_OutputIterator __s, const char* __nb, const char* __ne) const
     {
-        result __r = ok;
-        mbstate_t __mb;
-        while (__nb < __ne && __r != error)
-        {
-            const int __sz = 32;
-            char16_t __buf[__sz];
-            char16_t* __bn;
-            const char* __nn = __nb;
-            __r = do_in(__mb, __nb, __ne - __nb > __sz ? __nb+__sz : __ne, __nn,
-                        __buf, __buf+__sz, __bn);
-            if (__r == codecvt_base::error || __nn == __nb)
-                __throw_runtime_error("locale not supported");
-            for (const char16_t* __p = __buf; __p < __bn; ++__p, ++__s)
-                *__s = (wchar_t)*__p;
-            __nb = __nn;
-        }
-        return __s;
+        return __widen_using_codecvt(*this, __s, __nb, __ne);
     }
 };
 
@@ -1422,23 +1432,7 @@ struct _LIBCPP_TEMPLATE_VIS __widen_from_utf8<32>
     _OutputIterator
     operator()(_OutputIterator __s, const char* __nb, const char* __ne) const
     {
-        result __r = ok;
-        mbstate_t __mb;
-        while (__nb < __ne && __r != error)
-        {
-            const int __sz = 32;
-            char32_t __buf[__sz];
-            char32_t* __bn;
-            const char* __nn = __nb;
-            __r = do_in(__mb, __nb, __ne - __nb > __sz ? __nb+__sz : __ne, __nn,
-                        __buf, __buf+__sz, __bn);
-            if (__r == codecvt_base::error || __nn == __nb)
-                __throw_runtime_error("locale not supported");
-            for (const char32_t* __p = __buf; __p < __bn; ++__p, ++__s)
-                *__s = (wchar_t)*__p;
-            __nb = __nn;
-        }
-        return __s;
+        return __widen_using_codecvt(*this, __s, __nb, __ne);
     }
 };
 
diff --git a/libcxx/include/filesystem b/libcxx/include/filesystem
index 3aaa7988a8722..29d3a44ec2039 100644
--- a/libcxx/include/filesystem
+++ b/libcxx/include/filesystem
@@ -735,11 +735,111 @@ struct _PathCVT<char> {
   }
 };
 
+inline _LIBCPP_INLINE_VISIBILITY
+wstring __widen_from_char_iter_pair(const char* __b, const char* __e, const locale& __loc) {
+  wstring __r;
+  if (!has_facet<codecvt<wchar_t, char, mbstate_t>>(__loc))
+    return __r;
+  __r.reserve(__e - __b);
+  __widen_using_codecvt(use_facet<codecvt<wchar_t, char, mbstate_t>>(__loc) , back_inserter(__r), __b, __e);
+  return __r;
+}
+
+template <class _InputIt, 
+         class = typename enable_if<!is_constructible<const char*, _InputIt>::value>::type>
+inline _LIBCPP_INLINE_VISIBILITY
+wstring __widen_from_char_iter_pair(_InputIt __b, _InputIt __e, const locale& __loc) {
+  const string __s(__b, __e);
+  return __widen_from_char_iter_pair(__s.data(), __s.data() + __s.size(), __loc);
+}
+
+template <class _Tp>
+struct __is_widenable_from_char_string : public false_type {};
+
+template <class _Traits, class _Alloc>
+struct __is_widenable_from_char_string<
+    basic_string<char, _Traits, _Alloc>>
+    : true_type {
+  using _Str = basic_string<char, _Traits, _Alloc>; 
+
+  static wstring __convert(_Str const& __s, const locale& __loc) {
+    return __widen_from_char_iter_pair(__s.data(), __s.data() + __s.size(), __loc);
+  }
+};
+
+template <class _Traits>
+struct __is_widenable_from_char_string<
+    basic_string_view<char, _Traits>>
+    : true_type {
+  using _Str = basic_string_view<char, _Traits>; 
+  static wstring __convert(_Str const& __sv, const locale& __loc) {
+    return __widen_from_char_iter_pair(__sv.data(), __sv.data() + __sv.size(), __loc);
+  }
+};
+
+template <class _Source, class _DS = typename decay<_Source>::type,
+          class _UnqualPtrType =
+              typename remove_const<typename remove_pointer<_DS>::type>::type>
+struct __is_widenable_from_char_array : false_type {};
+
+template <class _Source, class _ECharT>
+struct __is_widenable_from_char_array<_Source, _ECharT*, char>
+    : true_type {
+
+  static wstring __convert(const char* __b, const locale& __loc) {
+    const char __sentinal = char{};
+    const char* __e = __b;
+    for (; *__e != __sentinal; ++__e)
+      ;
+    return __widen_from_char_iter_pair(__b, __e, __loc);
+  }
+};
+
+template <class _Iter, bool _IsIt = __is_input_iterator<_Iter>::value,
+          class = char>
+struct __is_widenable_from_char_iter : false_type {};
+
+template <class _Iter>
+struct __is_widenable_from_char_iter <
+    _Iter, true,
+    typename remove_reference<typename iterator_traits<_Iter>::value_type>::type >
+    : true_type {
+
+  static wstring __convert(_Iter __i, const locale& __loc) {
+    const char __sentinal = char{};
+    string __s;
+    for (; *__i != __sentinal; ++__i)
+      __s.push_back(*__i);
+    return __widen_from_char_iter_pair(__s.data(), __s.data() + __s.size(), __loc);
+  }
+};
+
+template <class _Tp, bool _IsStringT = __is_widenable_from_char_string<_Tp>::value,
+          bool IsCharArray = __is_widenable_from_char_array<_Tp>::value,
+          bool _IsIterT = !IsCharArray && __is_widenable_from_char_iter<_Tp>::value>
+struct __is_widenable_from_char_source : false_type {
+  static_assert(!_IsStringT && !IsCharArray && !_IsIterT, "Must all be false");
+};
+
+template <class _Tp>
+struct __is_widenable_from_char_source<_Tp, true, false, false> : __is_widenable_from_char_string<_Tp> {};
+
+template <class _Tp>
+struct __is_widenable_from_char_source<_Tp, false, true, false> : __is_widenable_from_char_array<_Tp> {
+};
+
+template <class _Tp>
+struct __is_widenable_from_char_source<_Tp, false, false, true> : __is_widenable_from_char_iter<_Tp> {};
+
 class _LIBCPP_TYPE_VIS path {
   template <class _SourceOrIter, class _Tp = path&>
   using _EnableIfPathable =
       typename enable_if<__is_pathable<_SourceOrIter>::value, _Tp>::type;
 
+  template <class _SourceOrIter, class _Tp = path&>
+  using _EnableIfWidenableFromCharSource =
+      typename enable_if<__is_widenable_from_char_source<_SourceOrIter>::value, _Tp>::type;
+  
   template <class _Tp>
   using _SourceChar = typename __is_pathable<_Tp>::__char_type;
 
@@ -779,12 +879,18 @@ public:
     _PathCVT<_ItVal>::__append_range(__pn_, __first, __last);
   }
 
-  // TODO Implement locale conversions.
-  template <class _Source, class = _EnableIfPathable<_Source, void> >
-  path(const _Source& __src, const locale& __loc, format = format::auto_format);
+  template <class _Source, class = _EnableIfWidenableFromCharSource<_Source> >
+  path(const _Source& __src, const locale& __loc, 
+       format = format::auto_format) {
+    using _Widener = __is_widenable_from_char_source<_Source>;
+    _SourceCVT<_VSTD::wstring>::__append_source(__pn_, _Widener::__convert(__src, __loc));
+  }
+
   template <class _InputIt>
-  path(_InputIt __first, _InputIt _last, const locale& __loc,
-       format = format::auto_format);
+  path(_InputIt __first, _InputIt __last, const locale& __loc,
+       format = format::auto_format) {
+    _SourceCVT<_VSTD::wstring>::__append_source(__pn_, __widen_from_char_iter_pair(__first, __last, __loc));
+  }
 
   _LIBCPP_INLINE_VISIBILITY
   ~path() = default;
diff --git a/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source_and_locale.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source_and_locale.pass.cpp
new file mode 100644
index 0000000000000..1de00e824e7d1
--- /dev/null
+++ b/libcxx/test/std/input.output/filesystems/class.path/path.member/path.construct/source_and_locale.pass.cpp
@@ -0,0 +1,164 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <filesystem>
+
+// class path
+
+// template <class Source>
+//      path(const Source& source);
+// template <class InputIterator>
+//      path(InputIterator first, InputIterator last);
+
+
+#include "filesystem_include.hpp"
+#include <locale>
+#include <type_traits>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_iterators.h"
+#include "min_allocator.h"
+#include "filesystem_test_helper.hpp"
+
+template <class ...Args>
+void RunTestCase(const char* TestPath, const char* Expect, std::locale Locale, Args... args) {
+  using namespace fs;
+  const char* TestPathEnd = StrEnd(TestPath);
+  const std::size_t Size = TestPathEnd - TestPath;
+  const std::size_t SSize = StrEnd(Expect) - Expect;
+  assert(Size == SSize);
+  // StringTypes
+  {
+    const std::string S(TestPath);
+    path p(S, Locale, args...); 
+    assert(p.native() == Expect);
+    assert(p.string<char>() == Expect);
+  }
+  {
+    const std::string_view S(TestPath);
+    path p(S, Locale, args...); 
+    assert(p.native() == Expect);
+    assert(p.string<char>() == Expect);
+  }
+  // Char* pointers
+  {
+    path p(TestPath, Locale, args...);
+    assert(p.native() == Expect);
+    assert(p.string<char>() == Expect);
+  }
+  {
+    path p(TestPath, TestPathEnd, Locale, args...);
+    assert(p.native() == Expect);
+    assert(p.string<char>() == Expect);
+  }
+  // Iterators
+  {
+    using It = input_iterator<const char*>;
+    path p(It{TestPath}, Locale, args...);
+    assert(p.native() == Expect);
+    assert(p.string<char>() == Expect);
+  }
+  {
+    using It = input_iterator<const char*>;
+    path p(It{TestPath}, It{TestPathEnd}, Locale, args...);
+    assert(p.native() == Expect);
+    assert(p.string<char>() == Expect);
+  }
+}
+
+void test_sfinae() {
+  using namespace fs;
+  {
+    using It = const char* const;
+    static_assert(std::is_constructible<path, It, std::locale>::value, "");
+  }
+  {
+    using It = input_iterator<const char*>;
+    static_assert(std::is_constructible<path, It, std::locale>::value, "");
+  }
+  {
+    struct Traits {
+      using iterator_category = std::input_iterator_tag;
+      using value_type = const char;
+      using pointer = const char*;
+      using reference = const char&;
+      using difference_type = std::ptrdiff_t;
+    };
+    using It = input_iterator<const char*, Traits>;
+    static_assert(std::__is_input_iterator<It>::value, "");
+    //static_assert(std::is_constructible<path, It, std::locale>::value, "");
+  }
+  {
+    using It = const wchar_t* const;
+    static_assert(!std::is_constructible<path, It, std::locale>::value, "");
+  }
+  {
+    using It = input_iterator<const wchar_t*>;
+    static_assert(!std::is_constructible<path, It, std::locale>::value, "");
+  }
+  {
+    struct Traits {
+      using iterator_category = std::input_iterator_tag;
+      using value_type = const wchar_t;
+      using pointer = const wchar_t*;
+      using reference = const wchar_t&;
+      using difference_type = std::ptrdiff_t;
+    };
+    using It = input_iterator<const wchar_t*, Traits>;
+    static_assert(!std::is_constructible<path, It, std::locale>::value, "");
+  }
+  {
+    using It = output_iterator<const char*>;
+    static_assert(!std::is_constructible<path, It, std::locale>::value, "");
+  }
+  {
+    static_assert(!std::is_constructible<path, int*, std::locale>::value, "");
+  }
+}
+
+struct CustomCodeCvt : std::codecvt<wchar_t, char, std::mbstate_t> {
+protected:
+  result do_in(state_type&,
+               const extern_type* from, const extern_type* from_end, const extern_type*& from_next,
+               intern_type* to, intern_type* to_end, intern_type*& to_next) const override {
+    for (; from < from_end && to < to_end; ++from, ++to)
+      *to = 'o';
+    
+    from_next = from;
+    to_next = to;
+
+    return result::ok;
+  }
+};
+
+int main(int, char**) {
+  std::locale Locale;
+
+  // Ensure std::codecvt<wchar_t, char, std::mbstate_t> is used.
+  std::locale CustomLocale(Locale, new CustomCodeCvt());
+  std::string TestPath("aaaa");
+  std::string Expect("oooo");
+  RunTestCase(TestPath.c_str(), Expect.c_str(), CustomLocale);
+  RunTestCase(TestPath.c_str(), Expect.c_str(), CustomLocale, fs::path::format::auto_format);
+  RunTestCase(TestPath.c_str(), Expect.c_str(), CustomLocale, fs::path::format::native_format);
+  RunTestCase(TestPath.c_str(), Expect.c_str(), CustomLocale, fs::path::format::generic_format);
+
+  for (auto const& MS : PathList) {
+    RunTestCase(MS, MS, Locale);
+    RunTestCase(MS, MS, Locale, fs::path::format::auto_format);
+    RunTestCase(MS, MS, Locale, fs::path::format::native_format);
+    RunTestCase(MS, MS, Locale, fs::path::format::generic_format);
+  }
+
+  test_sfinae();
+
+  return 0;
+}